apache module开发--c调com
2013-06-01 12:07
543 查看
最近在公司作了一套算法---大数据量下求两点间的最短距离。之前是用c++写了个com让前台去(c#)调用,不过是基于C/S的,现在是公司需要将这个算法发布成服务,使得web也可以调用。一开始是考虑使用java调同样的com,这样我就不用做任何修改
,但是同事说java调com不稳定。所以就考虑使用apache来发布服务,将算法打包成apache的一个module,于是开始着手研究。
apache可以在官网上下:http://httpd.apache.org/已经更新到2.4.4,不过我用的是,2.0版本的,只是测试用无所谓(2.0的系统进程是apache.exe,2.2就变成httpd.exe了。);我下载的是msi文件直接安装,不需要重新编译。生成模块文件(.so文件)还需要apxs。下面是摘录自http://man.chinaunix.net/newsoft/ApacheMenual_CN_2.2new/programs/apxs.html的一段介绍,我就不废话了。
因此,要使用这个扩展机制,你的平台必须支持DSO特性,而且Apache
该命令的输出列表中应该有
其中的参数files可以是任何C源程序文件(.c)、目标代码文件(.o)、甚至是一个库(.a)。
自己安装的apache 没有apxs,需要自己安装。下载:http://www.apachelounge.com/download/
安装 apxs
1.解压apxs.zip,如C:\apxs
2.打开命令提示符,切换当前目录到解压的路径C:\apxs
3.输入
perl Configure.pl --with-apache2=\Path\to\Apache2 --with-apache-prog=httpd.exe (apache2.0为apache.exe)
其中\Path\to\Apache2需要替换为Apache的安装路径
如果提示perl为不可执行程序的话,需要安装Perl,如Strawberry Perl(自己下一个就行)
4.切换到Apache安装目录下的bin文件夹中,输入apxs,如有解释apxs用法的文本出现,则表明安装完成。
最好将apxs所在目录加到环境变量里面,方便以后编译。
使用apxs在windows下编译模块
1.修改在apache下的build目录中config_vars.mk文件
将CC = gcc 的gcc改为cl.exe ,LD = g 的g 改为link.exe,CPP = gcc-E的gcc-E删掉
2.打开VS2008命令提示符(或者进入命令提示符,执行X:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat)
3.运行apxs -g -n helloworld(helloworld为模块名),会生成一个叫helloworld的目录和模板代码(一般放在命令提示符当前目录下),-g表示generate
产生代码,-n即name,指定模块的名称。此名称会在以后访问url中使用。
4.cd helloworld,进入helloworld目录,你会发现自动生成了一个mod_helloworld.c的源文件。也就是你要添加代码的地方。
5.运行apxs -c -i -a mod_helloworld.c libhttpd.lib 便会生成mod_helloworld.so、mod_helloworld.lib文件。并分别自动放到apache安装目录下的modules和lib目录下。
6.最后一步,需要修改conf目录下的httpd.conf文件,增加
<Location /helloworld>
setHandler helloworld
</Location>
重启apache服务,打开IE,输入:http://127.0.0.1/helloworld。就可以看到输出内容了。
自此,测试通过,下面进入主题。
模块开发指南》中确实指出支持c++的,但是并没有告诉具体方法,在网上也没有找到相关资料(如果哪位大牛做过的,不妨通知小弟,谢谢)。忽然,灵光一闪直接用c调原来的com不就完了嘛。于是又在网上找如何用c调com,可是找到的结果是不能,很多论坛里面都说c调用不了com,这下有点心灰意冷。难道真要用c再写一遍么,我比较懒,不到万不得已真的不想这么做,我不信就找不到办法。在网上找到一篇博客给了我希望,http://www.oldlinux.org/oldlinux/viewthread.php?tid=7865。但是,这片博客里面也没有提到具体调用的方法,虽然给出了源代码,但是并不适用我这个项目。
按照他里面提的方法,自己先写了代码测试一下,(因为自己写的com,可以直接获得头文件,不需要是用midl.exe导出)。
这里,我以项目中用到的另一个com为例(des解密),com头文件
于是傻不拉几按照c++方式走了一遍
发现根本编译不过去,仔细研究了一些头文件,发现头文件本身就提供了c调用的方法。将interface和class都定义成了struct,并重新定义了一个结构体 IToolLabVtbl,并将其作为IToolLab的一个成员。这里的interface即struct,在<objbase.h>中有定义。
-c :编译;
-i :将生成的so文件放到module目录下;
-a:自动增加一个
-I:添加自定义目录,这是头文件所在目录.
libhttpd.lib是每次编译必须的,会加载apache本身的函数。
-Wl,Zi -Wc,/DEBUG 是启动调试模式,可以在vs2008中跟踪调试。只需要用vs打开源文件,
选择-Debug--attach to process --选择Apache.exe(ID号大的)
如果是2.2以上版本选择httpd.exe(ID号小的))。然后,在IE中输入:http://127.0.0.1/helloworld即可以进到断点中。
自此就把问题都解决了,第一次发博客,有问题还请大家指正,我会细心修改,谢谢大家。
,但是同事说java调com不稳定。所以就考虑使用apache来发布服务,将算法打包成apache的一个module,于是开始着手研究。
一、apache module开发。
apache之前么有接触过,只是上学时用tomcat做过几个网页。对于module开发更是没有听说过,于是开始在网上各种找。相关方面的资料有,但是不是很多,而且都是大同小异并没有太多深入。更主要的是都是在linux下的开发,并且是基于c的。先不管这些,自己摸索着把环境搭起来,做个简单的例子测试一下。apache可以在官网上下:http://httpd.apache.org/已经更新到2.4.4,不过我用的是,2.0版本的,只是测试用无所谓(2.0的系统进程是apache.exe,2.2就变成httpd.exe了。);我下载的是msi文件直接安装,不需要重新编译。生成模块文件(.so文件)还需要apxs。下面是摘录自http://man.chinaunix.net/newsoft/ApacheMenual_CN_2.2new/programs/apxs.html的一段介绍,我就不废话了。
apxs是一个为Apache HTTP服务器编译和安装扩展模块的工具,用于编译一个或多个源程序或目标代码文件为动态共享对象,使之可以用由
mod_so提供的
LoadModule指令在运行时加载到Apache服务器中。
因此,要使用这个扩展机制,你的平台必须支持DSO特性,而且Apache
httpd必须内建了
mod_so模块。
apxs工具能自动探测是否具备这样的条件,你也可以自己用这个命令手动探测:
$ httpd -l
该命令的输出列表中应该有
mod_so模块。如果所有这些条件均已具备,则可以很容易地借助
apxs安装你自己的DSO模块以扩展Apache服务器的功能:
$ apxs -i -a -c mod_foo.c gcc -fpic -DSHARED_MODULE -I/path/to/apache/include -c mod_foo.c ld -Bshareable -o mod_foo.so mod_foo.o cp mod_foo.so /path/to/apache/modules/mod_foo.so chmod 755 /path/to/apache/modules/mod_foo.so [activating module 'foo' in /path/to/apache/etc/httpd.conf] $ apachectl restart /path/to/apache/sbin/apachectl restart: httpd not running, trying to start [Tue Mar 31 11:27:55 1998] [debug] mod_so.c(303): loaded module foo_module /path/to/apache/sbin/apachectl restart: httpd started $ _
其中的参数files可以是任何C源程序文件(.c)、目标代码文件(.o)、甚至是一个库(.a)。
apxs工具会根据其后缀自动编译C源程序或者连接目标代码和库。但是,使用预编译的目标代码时,必须保证它们是地址独立代码(PIC),使之能被动态地加载。如果使用GCC编译,则应该使用
-fpic参数;如果使用其他C编译器,则应该查阅其手册,为
apxs使用相应的编译参数。
自己安装的apache 没有apxs,需要自己安装。下载:http://www.apachelounge.com/download/
安装 apxs
1.解压apxs.zip,如C:\apxs
2.打开命令提示符,切换当前目录到解压的路径C:\apxs
3.输入
perl Configure.pl --with-apache2=\Path\to\Apache2 --with-apache-prog=httpd.exe (apache2.0为apache.exe)
其中\Path\to\Apache2需要替换为Apache的安装路径
如果提示perl为不可执行程序的话,需要安装Perl,如Strawberry Perl(自己下一个就行)
4.切换到Apache安装目录下的bin文件夹中,输入apxs,如有解释apxs用法的文本出现,则表明安装完成。
最好将apxs所在目录加到环境变量里面,方便以后编译。
使用apxs在windows下编译模块
1.修改在apache下的build目录中config_vars.mk文件
将CC = gcc 的gcc改为cl.exe ,LD = g 的g 改为link.exe,CPP = gcc-E的gcc-E删掉
2.打开VS2008命令提示符(或者进入命令提示符,执行X:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat)
3.运行apxs -g -n helloworld(helloworld为模块名),会生成一个叫helloworld的目录和模板代码(一般放在命令提示符当前目录下),-g表示generate
产生代码,-n即name,指定模块的名称。此名称会在以后访问url中使用。
4.cd helloworld,进入helloworld目录,你会发现自动生成了一个mod_helloworld.c的源文件。也就是你要添加代码的地方。
5.运行apxs -c -i -a mod_helloworld.c libhttpd.lib 便会生成mod_helloworld.so、mod_helloworld.lib文件。并分别自动放到apache安装目录下的modules和lib目录下。
6.最后一步,需要修改conf目录下的httpd.conf文件,增加
<Location /helloworld>
setHandler helloworld
</Location>
重启apache服务,打开IE,输入:http://127.0.0.1/helloworld。就可以看到输出内容了。
自此,测试通过,下面进入主题。
二、在c中调用com
原本的com是封装的c++类,但是apache的默认源码是c的,不能识别类文件,如果是用c再重新写一遍实在太费劲了(里面用到很多c++的东西,需要修改很多)。于是想能不能用c++编译module,将源文件强行改为.cpp结果编译不了,尝试修改config_vars.mk文件也没有好的结果,而在《Apache模块开发指南》中确实指出支持c++的,但是并没有告诉具体方法,在网上也没有找到相关资料(如果哪位大牛做过的,不妨通知小弟,谢谢)。忽然,灵光一闪直接用c调原来的com不就完了嘛。于是又在网上找如何用c调com,可是找到的结果是不能,很多论坛里面都说c调用不了com,这下有点心灰意冷。难道真要用c再写一遍么,我比较懒,不到万不得已真的不想这么做,我不信就找不到办法。在网上找到一篇博客给了我希望,http://www.oldlinux.org/oldlinux/viewthread.php?tid=7865。但是,这片博客里面也没有提到具体调用的方法,虽然给出了源代码,但是并不适用我这个项目。
按照他里面提的方法,自己先写了代码测试一下,(因为自己写的com,可以直接获得头文件,不需要是用midl.exe导出)。
这里,我以项目中用到的另一个com为例(des解密),com头文件
#ifdef __cplusplus extern "C"{ #endif /* Forward Declarations */ #ifndef __IToolLab_FWD_DEFINED__ #define __IToolLab_FWD_DEFINED__ typedef interface IToolLab IToolLab; #endif /* __IToolLab_FWD_DEFINED__ */ #ifdef __cplusplus typedef class ToolLab ToolLab; #else typedef struct ToolLab ToolLab; #endif /* __cplusplus */ #endif /* __ToolLab_FWD_DEFINED__ */ ... EXTERN_C const IID LIBID_PXGISLib; EXTERN_C const IID IID_IToolLab; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("F12EC292-117C-4C1F-B346-FE2BDB542466") IToolLab : public IDispatch { public: ... virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE DesDecryptEx( /* [in] */ BSTR bstrInBuffer, /* [in] */ BSTR bstrLicense, /* [retval][out] */ BSTR __RPC_FAR *bstrOutBuffer) = 0; ... }; #else /* C style interface */ typedef struct IToolLabVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( IToolLab __RPC_FAR * This, /* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( IToolLab __RPC_FAR * This); ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( IToolLab __RPC_FAR * This); ... /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE __RPC_FAR *DesDecryptEx )( IToolLab __RPC_FAR * This, /* [in] */ BSTR bstrInBuffer, /* [in] */ BSTR bstrLicense, /* [retval][out] */ BSTR __RPC_FAR *bstrOutBuffer); ... END_INTERFACE } IToolLabVtbl; interface IToolLab { CONST_VTBL struct IToolLabVtbl __RPC_FAR *lpVtbl; }; #ifdef COBJMACROS #define IToolLab_QueryInterface(This,riid,ppvObject) \ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) #define IToolLab_AddRef(This) \ (This)->lpVtbl -> AddRef(This) #define IToolLab_Release(This) \ (This)->lpVtbl -> Release(This) ... #define IToolLab_DesDecryptEx(This,bstrInBuffer,bstrLicense,bstrOutBuffer) \ (This)->lpVtbl -> DesDecryptEx(This,bstrInBuffer,bstrLicense,bstrOutBuffer) ... #endif /* COBJMACROS */ #endif /* C style interface */ ... /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IToolLab_DesDecryptEx_Proxy( IToolLab __RPC_FAR * This, /* [in] */ BSTR bstrInBuffer, /* [in] */ BSTR bstrLicense, /* [retval][out] */ BSTR __RPC_FAR *bstrOutBuffer); void __RPC_STUB IToolLab_DesDecryptEx_Stub( IRpcStubBuffer *This, IRpcChannelBuffer *_pRpcChannelBuffer, PRPC_MESSAGE _pRpcMessage, DWORD *_pdwStubPhase); ... #endif /* __IToolLab_INTERFACE_DEFINED__ */ EXTERN_C const CLSID CLSID_ToolLab; #ifdef __cplusplus class DECLSPEC_UUID("103BBE93-8B87-4284-B5B7-1C787C6F68E3") ToolLab; #endif #endif /* __PXGISLib_LIBRARY_DEFINED__ */ /* Additional Prototypes for ALL interfaces */ /* end of Additional Prototypes */ #ifdef __cplusplus } #endif #endif
于是傻不拉几按照c++方式走了一遍
h = CoInitialize(NULL); if (FAILED(h)) { return -1; } h = CoCreateInstance(CLSID_ToolLab,NULL,1,IID_IToolLab,(void **)&lab); if(FAILED(h)) { return -1; } BSTR res = lab->DesDecryptEx(cipher,L"TJPxdlGisLicense"); lab->Release(); CoUninitialize();
发现根本编译不过去,仔细研究了一些头文件,发现头文件本身就提供了c调用的方法。将interface和class都定义成了struct,并重新定义了一个结构体 IToolLabVtbl,并将其作为IToolLab的一个成员。这里的interface即struct,在<objbase.h>中有定义。
interface IToolLab { CONST_VTBL struct IToolLabVtbl __RPC_FAR *lpVtbl; };于是,修改代码,下面是写的一个函数的全部代码
//解密 int decrpt_text(char * cipher_text,char **plain_text) { IToolLab* lab = NULL; HRESULT h; BSTR res,cipher; size_t len,num; wchar_t * wct = NULL; len = strlen(cipher_text)+1; wct = (wchar_t *)malloc(len*sizeof(wchar_t)); mbstowcs_s(&num,wct,len,cipher_text,_TRUNCATE); cipher = SysAllocString(wct); h = CoInitialize(NULL); if (FAILED(h)) { return -1; } h = CoCreateInstance(&CLSID_ToolLab,NULL,1,&IID_IToolLab,(void **)&lab); if(FAILED(h)) { return -1; } lab->lpVtbl->DesDecryptEx(lab,cipher,L"TJPxdlGisLicense",&res); SysFreeString(cipher); free(wct); wct = res; len = wcslen(wct) + 1; *plain_text = (char*)malloc(len); wcstombs_s(&num,*plain_text,len,wct,_TRUNCATE); (*plain_text)[len - 1] = '\0'; lab->lpVtbl->Release(lab); CoUninitialize(); return 1; }编译,还是错误,但是已经不是语法错误。是因为c调用CoInitialize()需要库文件ole32.lib,因为我还用到了SysFreeString()所以还需要库文件oleaut32.lib.重新编译
apxs -c -i -a -Wl,Zi -Wc,/DEBUG -I "头文件所在目录" mod_helloworld.c ole32.lib oleaut32.lib libhttpd.lib
-c :编译;
-i :将生成的so文件放到module目录下;
-a:自动增加一个
LoadModule行到
httpd.conf文件中,以激活此模块,或者,如果此行已经存在,则启用之。
-I:添加自定义目录,这是头文件所在目录.
-Wc:compiler-flags此选项用于向编译命令
libtool --mode=compile中附加compiler-flags ,以增加编译器特有的选项。
-Wl:linker-flags此选项用于向连接命令
libtool --mode=link中附加linker-flags ,以增加连接器特有的选项.
libhttpd.lib是每次编译必须的,会加载apache本身的函数。
-Wl,Zi -Wc,/DEBUG 是启动调试模式,可以在vs2008中跟踪调试。只需要用vs打开源文件,
选择-Debug--attach to process --选择Apache.exe(ID号大的)
如果是2.2以上版本选择httpd.exe(ID号小的))。然后,在IE中输入:http://127.0.0.1/helloworld即可以进到断点中。
自此就把问题都解决了,第一次发博客,有问题还请大家指正,我会细心修改,谢谢大家。
相关文章推荐
- apache 模块开发提示错误Cant locate api module
- Apache模块开发/用C语言扩展apache(3:一个非常简单的apache module)
- c apache module 开发入门(访问mysql)
- c apache module 开发入门
- Apache Module 开发后记
- Apache模块开发/用C语言扩展apache(3:一个非常简单的apache module)
- apache module 开发调试 基本流程
- Apache模块开发/用C语言扩展apache(4:一个生产环境使用的apache module)
- C 杂谈之 Apache的模块开发 (一)
- PHP开发网站,第一步环境配置Apache2.4服务器
- Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。
- 使用 Apache Wink、Eclipse 和 Maven 开发 RESTful Web 服务
- 关于Wavecom OpenAT 开发平台
- macOS 下配置 MAMP 开发环境(Mac + Apache + Mysql + PHP)
- iOS开发之Xcode8打印台[NWConcrete_nw_endpoint_proxy cancelWithHandler:forced:] [7 api.weibo.com:443 cancell
- org.apache.ibatis.binding.BindingException: Mapper method 'com... has an unsupported return type
- 试用EF开发WEB应用程序(10): 配置Apache
- eclipse提示Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-com
- Apache模块开发/用C语言扩展apache(1:简述)
- 笔记:Apache Chemistry OpenCMIS Client端开发