从C++桌面应用转向基于Web的应用

5 投票
4 回答
1476 浏览
提问于 2025-04-15 16:59

我们有一个成熟的Windows桌面应用程序,是用C++写的。这个应用的界面是建立在一个Windows DLL之上的,这个DLL负责处理大部分的工作(可以理解为它是应用的引擎)。这个DLL也是用C++写的。我们正在考虑将这个Windows应用转变为一个基于网页的应用,原因有很多。

我希望避免的是用C++来编写这个网页应用的CGI。也就是说,我更希望能使用像Python或.NET这样的高级语言来创建这个网页版本的应用。

所以,我的问题是:考虑到我需要在后台使用C++ DLL来完成应用的工作,你会推荐什么技术组合来连接用户的浏览器和我们的C++ DLL?我们可以假设网络服务器将运行在Windows上。

一些选项:

  1. 在Windows DLL上写一个COM层,这样就可以通过.NET访问,并使用ASP.NET来处理界面。
  2. 直接从.NET访问导出的DLL接口,并使用ASP.NET来处理界面。
  3. 编写一个自定义的Python库,将Windows DLL封装起来,这样其余的代码就可以用Python写。
  4. 使用C++和一个基于C++的MVC框架(比如Wt)来编写CGI。

担忧:

  • 如果可以避免,我更不想在网页框架中使用C++——我觉得像Python和C#这样的语言在开发时间上更强大和高效。
  • 我担心在.NET解决方案中混合使用托管和非托管代码会引发很多小问题,这些问题很难调试(这只是个人经验)。
  • 使用Python层也是一样。任何稍微偏离常规的做法让我担心,因为我没有太多证据证明这是否是一个可行的长期解决方案。

4 个回答

2

我觉得选择第二个选项比较好。只要你在 .Net 中为你的 DLL 创建一个接口,确保在需要的时候正确释放内存等,我觉得就没什么问题。如果你能在 DLL 中重用你的业务逻辑,并且基本上通过网络调用你的 DLL,那就太好了。

我唯一担心的是你 DLL 的 API。ASP.Net 显然是一个支持多个用户和多线程的应用程序。你的 API 有没有考虑到这一点?因为大多数 Windows 窗体应用程序通常只有一个用户在使用(想象一下,如果你应用中的每个窗体都可以被多个用户同时打开会是什么样子)。

4

3- Python是解决方案。

在Python中创建一个单一的入口接口,只需要输入函数的名称和要传递给这个函数的参数列表。这样你就可以立即开始实验,看看这个DLL中的哪些函数对于第一个功能性网页原型是必需的。

一个单函数模块的简单示例是

#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"])])

并在一个简单的网页服务器中使用,比如

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()
10

另请参见 一个大型现有应用程序能否迁移到网络上?怎么做?

抱歉,没有好的解决方案,只有不那么糟糕的选择……

首先,既然你已经在为Windows开发,我假设你习惯使用微软的开发工具。如果是从Unix(或Mac)过来的桌面应用,我就不会给出同样的答案。

以下是一些随意的想法和建议。

  • 我会使用Asp.net,可能会选择Asp.net MVC。
  • 我会尝试把C++类封装在一些高级的.net类中,也许会用到 Managed C++ / CLI
  • 使用COM可能会在C++方面花费很多精力,并且对.NET不太友好,所以我会避免使用COM,而选择受管的C++或pinvoke(不过如果你已经在C++中使用COM,这也是一个选项,只要你使用的是VB6可以处理的COM子集)。
  • .NET无法访问非受管的C++对象,但可以通过Pinvoke访问简单的C函数,所以无论你做什么,都需要在C++那边建立某种桥接层。
  • 看看你是否可以使用Silverlight而不是直接上网,如果可以(比如安装问题等),这会节省你很多开发时间。(而且还可以针对微软手机)
  • 确保“迁移到网络”的商业理由非常强大,并且这将比你想象的要花费更长的时间!,对于你的客户来说,使用终端服务器等托管选项是否可行?
  • 考虑线程和多用户访问,比如你的dll是否假设只有一个用户在使用?
  • 即使你正在开发新的网络版本,客户仍然会要求对桌面版本进行更改,即使在你发布了网络版本之后。我过去发现,现有客户并不总是愿意转向网络应用。

(抱歉,我对Python了解不多,不过如果你还没有相关技能,我建议你继续使用微软的技术栈,因为你已经熟悉微软的调试工具等)


(我认为将复杂应用程序迁移到网络上是一个非常大的痛苦,尽量避免痛苦是最好的,但有时你别无选择,只能尽量减少痛苦。如果你从未参与过大型应用程序的迁移(通常需要很多年的工作),你就不知道自己在做什么!)

撰写回答