从C++桌面应用转向基于Web的应用
我们有一个成熟的Windows桌面应用程序,是用C++写的。这个应用的界面是建立在一个Windows DLL之上的,这个DLL负责处理大部分的工作(可以理解为它是应用的引擎)。这个DLL也是用C++写的。我们正在考虑将这个Windows应用转变为一个基于网页的应用,原因有很多。
我希望避免的是用C++来编写这个网页应用的CGI。也就是说,我更希望能使用像Python或.NET这样的高级语言来创建这个网页版本的应用。
所以,我的问题是:考虑到我需要在后台使用C++ DLL来完成应用的工作,你会推荐什么技术组合来连接用户的浏览器和我们的C++ DLL?我们可以假设网络服务器将运行在Windows上。
一些选项:
- 在Windows DLL上写一个COM层,这样就可以通过.NET访问,并使用ASP.NET来处理界面。
- 直接从.NET访问导出的DLL接口,并使用ASP.NET来处理界面。
- 编写一个自定义的Python库,将Windows DLL封装起来,这样其余的代码就可以用Python写。
- 使用C++和一个基于C++的MVC框架(比如Wt)来编写CGI。
担忧:
- 如果可以避免,我更不想在网页框架中使用C++——我觉得像Python和C#这样的语言在开发时间上更强大和高效。
- 我担心在.NET解决方案中混合使用托管和非托管代码会引发很多小问题,这些问题很难调试(这只是个人经验)。
- 使用Python层也是一样。任何稍微偏离常规的做法让我担心,因为我没有太多证据证明这是否是一个可行的长期解决方案。
4 个回答
我觉得选择第二个选项比较好。只要你在 .Net 中为你的 DLL 创建一个接口,确保在需要的时候正确释放内存等,我觉得就没什么问题。如果你能在 DLL 中重用你的业务逻辑,并且基本上通过网络调用你的 DLL,那就太好了。
我唯一担心的是你 DLL 的 API。ASP.Net 显然是一个支持多个用户和多线程的应用程序。你的 API 有没有考虑到这一点?因为大多数 Windows 窗体应用程序通常只有一个用户在使用(想象一下,如果你应用中的每个窗体都可以被多个用户同时打开会是什么样子)。
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()
抱歉,没有好的解决方案,只有不那么糟糕的选择……
首先,既然你已经在为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了解不多,不过如果你还没有相关技能,我建议你继续使用微软的技术栈,因为你已经熟悉微软的调试工具等)
(我认为将复杂应用程序迁移到网络上是一个非常大的痛苦,尽量避免痛苦是最好的,但有时你别无选择,只能尽量减少痛苦。如果你从未参与过大型应用程序的迁移(通常需要很多年的工作),你就不知道自己在做什么!)