从使用C++编写的桌面应用转向基于Web的应用程序

5
我们有一款成熟的Windows桌面应用程序,使用C++编写。该应用程序的GUI位于一个Windows DLL之上,该DLL完成了大部分GUI工作(它是引擎)。它也是用C++编写的。出于各种原因,我们正在考虑将Windows应用程序转换为基于Web的应用程序。
我想避免的是必须用C++编写此Web应用程序的CGI。也就是说,我更愿意使用像Python或.NET语言这样的4G语言来创建此应用程序的Web版本。
因此,问题是:假设我需要在后端使用C++ DLL来完成应用程序的工作,那么你会推荐哪些技术栈来连接用户的浏览器和我们的C++ dll?我们可以假设Web服务器将是Windows。
一些选项:
  1. 编写一个基于Windows DLL的COM层,然后可以通过.NET访问并使用ASP.NET进行UI
  2. 直接从.NET访问导出的DLL接口,并使用ASP.NET进行UI。
  3. 编写一个自定义的Python库,包装Windows DLL,以便其余代码可以编写。
  4. 使用C++编写CGI和基于C++的MVC框架(如Wt

问题:

  • 如果可以避免,我宁愿不使用C++作为Web框架 - 我认为像Python和C#这样的语言在开发时间方面更加强大和高效。
  • 我担心在使用.NET解决方案之一时混合托管和非托管代码会导致许多难以调试的小问题(这只是纯粹的个人经验)
  • 对于使用Python层也是如此。类似这样稍微偏离常规的事情让我担心,因为我没有太多证据表明这是可行的长期解决方案。

您所说的“Web应用程序”,是指HTML/CSS/JavaScript,而不是像Flash或Silverlight这样的RIA吗? - Dimitri C.
我是的。最终的应用程序可以包含一些Flash/SL元素,但它们不应该是基础。 - Karim
4个回答

10

参见 如何将庞大的现有应用程序移植到Web? 怎么做?

对不起,没有好的解决方案,只有相对较差的解决方案...

首先,由于您已经开发了Windows应用程序,我假设您已经习惯于使用Microsoft开发工具。如果是从unix(或Mac)转移桌面应用程序,我的答案可能会有所不同。

以下是一些随机的想法和指针。

  • 我很可能会使用Asp.net,最可能是Aps.net MVC。
  • 我会尝试在一些漂亮的高级.NET类中包装C ++类,可能使用Managed C++ / CLI
  • 在C ++方面,使用COM可能需要大量的工作,并且不会使.NET易于使用,因此我会避免使用COM,而转而使用托管的C ++或PInvoke。(但是,如果您已经在C ++方面使用COM,则它是一个选项,前提是您使用VB6可以处理的COM子集。)
  • .NET无法访问非托管的C ++对象,但它可以使用PInvoke访问简单的C函数,因此无论您做什么,在C ++站点上都需要某种桥接层。
  • 如果能够使用Silverlight而不是Web,则查看一下,如果能够使用(安装问题等),将节省大量开发时间。 (并让您瞄准Microsoft手机)
  • 检查“移植到Web”的业务案例是否非常强大,并且将需要比您想象的时间更长! 针对您的客户,终端服务器等托管是否可行?
  • 考虑线程和多用户访问,例如,您的dll是否假定只由一个用户使用?
  • 即使您正在开发新的Web版本,您仍然会有客户要求更改桌面版,即使您已经发布了Web版本。我发现过去的客户并不总是希望转移到Web应用程序。
  • (抱歉,我对Python不太了解,但如果您还没有相关技能,我会建议您坚持使用Microsoft堆栈,因为您已经了解Microsoft调试器等工具)


    (我认为将复杂的应用程序移植到Web上是一件非常麻烦的事情,尽可能避免痛苦是最好的选择,但有时候您别无选择,只能尽量减少痛苦。如果您从未处理正在移植到Web的大型应用程序(通常需要多年时间),则您不知道自己要做出什么!)


    好的观点。考虑使用Web应用程序路径,因为1)更容易部署给客户2)更容易升级3)GUI更改的开发周期更快。Silverlight不是我想考虑的东西 - 应该是基于HTML / JS的UI,以避免不稳定的浏览器/平台依赖性。 - Karim
    使用基于HTML/JS的用户界面是我知道的获得浏览器依赖关系最少的最佳方式。 - rpg
    完全重写应用程序并不是我正在做的事情,谢天谢地。只是用户和引擎之间的薄层。这就是整个问题所在。如果我从头开始重写,我就不需要担心找到与C++ DLL兼容的东西了。 - Karim
    +1 for "it will take a lot longer than you think". 但是没有人愿意接受这一点:既不是管理层,也不是开发人员自己。 - Dimitri C.
    +1 但还有一个补充:您可以使用 C++/CLI 包装器来包装未经管理的 C++ 类。这就是我们将未经管理的遗留代码连接到 .NET 世界的方式。 - Thorsten79

    4

    3- Python是解决方案。

    在Python中创建一个单一入口点接口,只需传递函数名称和要传递给函数本身的参数列表。您将有一些东西可以立即开始实验,并查看哪些DLL函数对于第一个功能性Web原型真正需要。

    单个函数模块的存根为

    #include <Python.h>
    #include <string.h>
    
    int int_function(int a){
        return a +=1;
    }
    
    static PyObject *
    exec_lib(PyObject *self, PyObject *args)
    {
        char *fun_name;
        PyObject *func_name = PyTuple_GetSlice(args, 0,1);
        PyObject *res;
    
        if (!PyArg_ParseTuple(func_name, "s", &fun_name))
             return NULL;
        Py_DECREF(func_name);
        if (strncmp("int_function", fun_name, 1024) == 0)
        {
            int i;
            PyObject *fun_args = PyTuple_GetSlice(args, 1,20);
            if (!PyArg_ParseTuple(fun_args, "i", &i))
                return NULL;
            Py_DECREF(fun_args);
            res = Py_BuildValue( "i", int_function(i));
        } else {
            Py_INCREF(Py_None);
            res = Py_None;
        }
    
        return res;
    }
    
    
    
    PyMethodDef methods[] = {
        {"exec_lib", exec_lib, METH_VARARGS, " Returns"},
        {NULL, NULL, 0, NULL}
    };
    
    PyMODINIT_FUNC 
    initlibwrap()
    {
        (void) Py_InitModule("libwrap", methods);
    }
    

    可以使用setup.py文件进行编译

    from distutils.core import setup, Extension
    
    setup(name = "libwrap",
          version = "1.0",
          ext_modules = [Extension("libwrap", ["my_library_wrap.cpp"])])
    

    并且可以在像简单的Web服务器中使用

    from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
    import libwrap
    
    
    def int_function(value):
        return libwrap.exec_lib("int_function", value)
    
    print int_function(10)
    
    class MyHandler(BaseHTTPRequestHandler):
    
        def do_GET(self):
            self.send_response(200)
            value = 'Error'
            try:
                value = int_function()
            except:
                import traceback
                traceback.print_stack()
            self.wfile.write(value)
    
    def main():
        try:
            ip ='localhost'
            port = 8080
            server = HTTPServer((ip,port), MyHandler)
            server.serve_forever()
        except KeyboardInterrupt:
            server.socket.close()
    
    if __name__ == '__main__':
        main()
    

    2

    我认为选项2是可行的。只要您在.Net中创建一个接口来确保在需要时正确释放内存等,我不认为会有问题。如果您可以在DLL中重用业务逻辑并基本上通过Web调用进入DLL,则非常好。

    我唯一的担忧是您的DLL的API。显然,ASP.Net是一个多用户多线程的应用程序。考虑到大多数Windows窗体应用程序只有一个用户驱动它们(想象一下您的应用程序中的每个表单都可以同时被多个用户打开),您的API是否已经设计好了呢?


    1

    既然没有人提到它,那么怎么样考虑Wt呢?

    如果你不想要基于浏览器的用户界面,有很多C++库可以让你将本地应用程序扩展为基于Web的应用程序,POCO就是其中之一。如果你坚持使用Windows平台,WWSAPI对于C/C++开发人员来说真的很酷。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接