BCC(Borland C++ Compiler)编译 ISAPI 扩展或者用MinGW也行

来源:互联网 发布:淘宝在哪里交保证金 编辑:程序博客网 时间:2024/06/05 08:56

今天突发神经,要写个ISAPI扩展,找了一下编译器,发现VS 2017的大小>VS 2015 > VS 2013 > VS 2010 > VS 6 & SP6>BCC,于是下了个BCC,很久没用过BCC,不知道它居然升级了,从2000年的Borland C++ 5.5.1升级到了2016年的Embarcadero C++ 7.20,编译器名称也改了。

bcc32.exe -> bcc32c.exe

brcc32.exe -> rc.exe

所以在Code::Blocks里面,Auto-detect不了7.2版本的,只有再下了个5.5的。下载完了,发现忘记怎么写ISAPI了,幸好以前的马甲在CSDN里留了个BCC编译ISAPI的文章,还能baidu到,于是照本宣科,结果却编译不了,经过N次调试,总算成功了,于是总结一下以免备忘,万一以后还要BCC写ISAPI呢。

1,下载Borland C++ Compiler 5.5,解压到D:\Borland\BCC55

2、下载Code::Blocks 16.01,安装完后打开CodeBlocks,先不管默认编译器,进入IDE界面

打开菜单Settings-Compiler...

Selected Compiler选择Borland C++ Compiler (5.5 - 5.82)

Search Directories 选项卡里,Compiler添加D:\Borland\BCC55\Include,Linker添加D:\Borland\BCC55\Lib和D:\Borland\BCC55\Lib\PSDK

Toolchain executables 选项卡里,Compiler's installation directory输入D:\Borland\BCC55

Other settings 选项卡里,点击Advanced options,弹出一个窗口

Commands 选项卡里,Command选择Link object files to dynamic library,Command line macro里将宏改一下,添加一个$def_input变量

原来的宏:$linker -q $libdirs -Tpd $link_options $link_objects,$exe_output,,$libs,,$link_resobjects

改变的宏:$linker -q $libdirs -Tpd $link_options $link_objects,$exe_output,,$libs,$def_input,$link_resobjects

OK - OK,保存设置

3,打开菜单File - New - Project...,选择Shared Library,下一步,选择C,下一步,填写工程名,比如:test,下一步,OK

4,打开main.c,编写代码,其实我是复制微软官网的代码,改了一下, 能编译通过就行

#define WIN32_LEAN_AND_MEAN#include <stdio.h>#include <httpext.h>#ifndef   HSE_REQ_SET_FLUSH_FLAG#define   HSE_REQ_SET_FLUSH_FLAG                   (HSE_REQ_END_RESERVED+43)#endifDWORD SendOutputToClient(IN EXTENSION_CONTROL_BLOCK  *pecb, IN DWORD msecDelay);DWORD SendOutputToClient(IN EXTENSION_CONTROL_BLOCK  *pecb, IN DWORD msecDelay, char *szBuffering) ;BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer){    FILE *fp = fopen("e:\\www\\cgi-bin\\log.txt", "rw");    if (fp) {        fprintf(fp, "hello");        fclose(fp);    }pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);lstrcpyn((LPSTR) pVer->lpszExtensionDesc, "ISAPI Tester", HSE_MAX_EXT_DLL_NAME_LEN);return TRUE;}DWORD WINAPI HttpExtensionProc(IN EXTENSION_CONTROL_BLOCK *pECB){DWORD hseStatus;DWORD msecDelay;char *pszBuffering;pszBuffering = "default (on)";msecDelay=25;if ( (char)*(pECB->lpszQueryString) != '\0' ){pszBuffering="off";    pECB->ServerSupportFunction (pECB->ConnID,HSE_REQ_SET_FLUSH_FLAG,(LPVOID) TRUE,NULL,NULL);}hseStatus = SendOutputToClient(pECB, msecDelay, pszBuffering);return hseStatus;}BOOL WINAPI TerminateExtension(IN DWORD dwFlags){return TRUE;}DWORD SendHeaderToClient(IN EXTENSION_CONTROL_BLOCK *pecb, IN LPCSTR pszErrorMsg){HSE_SEND_HEADER_EX_INFO SendHeaderExInfo;char szStatus[] = "200 OK";char szHeader[1024];wsprintf(szHeader, "Content-Type: text/plain\r\n\r\n");SendHeaderExInfo.pszStatus = szStatus;SendHeaderExInfo.pszHeader = szHeader;SendHeaderExInfo.cchStatus = lstrlen(szStatus);SendHeaderExInfo.cchHeader = lstrlen(szHeader);SendHeaderExInfo.fKeepConn = FALSE;if (!pecb->ServerSupportFunction(pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &SendHeaderExInfo, NULL, NULL))   return HSE_STATUS_ERROR;return HSE_STATUS_SUCCESS;}DWORD SendOutput(IN EXTENSION_CONTROL_BLOCK  *pecb, IN DWORD msecDelay) {CHAR pchOutput[1024];DWORD hseStatus = HSE_STATUS_SUCCESS;int i;DWORD len;for( i=0; i < 10 ; i++ ) {len = wsprintfA(pchOutput, "WriteClient output %d\n", i);if ( !pecb->WriteClient(pecb->ConnID, pchOutput, &len, HSE_IO_SYNC) ){hseStatus = HSE_STATUS_ERROR;break;}Sleep(msecDelay);}return hseStatus;}DWORD SendOutputToClient(IN EXTENSION_CONTROL_BLOCK  *pecb, IN DWORD msecDelay, char *szBuffering) {CHAR    pchBuffer[1024];DWORD   hseStatus = HSE_STATUS_SUCCESS;wsprintfA(pchBuffer, "WriteClient buffering %s", szBuffering);hseStatus = SendHeaderToClient(pecb, pchBuffer);if (hseStatus == HSE_STATUS_SUCCESS) {hseStatus = SendOutput(pecb, msecDelay );if (hseStatus != HSE_STATUS_SUCCESS) {wsprintfA(pchBuffer, "Send Failed: Error (%d)<\br>", GetLastError());SendHeaderToClient(pecb, pchBuffer);}}pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_DONE_WITH_SESSION, NULL, NULL, NULL);return (hseStatus);}

5,工程根目录下新建test.def文件

LIBRARY "test"EXPORTS    GetExtensionVersion    HttpExtensionProc    TerminateExtension

6,菜单点击Project - Properties...

Build targets 选项卡里,右边大概中间位置的output filename将bin\debug\libtest.dll改为bin\debug\test.dll,然后Release版本的也这样改

左边中下位置,点击Build options,弹出窗口

新窗口的左边列表框里选中工程名,这样debug和release版本都能用同样的编译选项了。

Compiler settings 选项卡里,Compiler flags子选项卡中,Target组里面选中.DLL executable (-tWD)和32-bit multi-threaded (-tWM)

Linker settings 选项卡里,Link libraries里,添加user32,添加kernel32,添加import32,添加cw32mt,cw32mt是静态链接库,cw32mti是动态链接库,需要BCC的dll文件才行,所以我选择了cw32mt,将包含的函数编译进工程里,但这样远远还不够,还需要obj支持

于是other linker options里面,添加

-Gi c0d32.obj

这个是动态链接库支持文件,没有它cw32mt里有两个函数就无法连接,但在工程里如果取消标准库里的一些函数,比如strcpy、strlen,cw32mt就可以不用,但是dll文件会在IIS里奔溃,同时将IIS程序池也搞奔溃掉,我摆渡了很久才找到这个选项

最后,Custom variables选项卡里,添加key = def_input,value = test.def,这样开始在Link object files to dynamic library的宏里面设置的$def_input就有了实例

OK - OK,保存设置

7,Ctrl + F9,工程进行Build,在bin\debug或者bin\release目录下就生成了test.dll,将test.dll放入IIS里设置的可执行目录下,就能运行看到结果了。

——————追加:第二天继续MinGW编译ISAPI的测试——————

因为机器里已经安装了Cygwin和MSYS2,所以首先用Cygwin里的gcc编译项目,gcc版本6.40,编译项目成功,但是用VS的dumpbin -exports dll文件却找不到函数地址

于是使用MSYS2,并在MSYS2模拟器中安装了gcc 7.2,编译 项目成功,同样dumpbin找不到函数地址

dumpbin是VS的dll工具,就是说它能找到地址,那么IIS同样也能找到地址,它找不到IIS也找不到,所以在IIS中,ISAPI扩展会返回500错误

这个问题把我折腾惨了,最后鬼使神差下载了单独版本的MinGW,安装完GCC后,编译项目成功,用dumpbin也能找到函数地址

于是对比了一下,发现GCC线程模式不一样,Cygwin和MSYS2里的gcc都是posix线程,而MinGW里的却是win32线程,所以能用,总算吸取了教训,涨了点姿势。

命令行编译

gcc -c test.cdllwrap --def test.def -o test.dll test.odumpbin -exports test.dll

如果是用CodeBlocks,那么还是要更改一下配置

Settings-Compiler,选择GNU GCC Compiler,Other settings-Advanced options
Commands 选项卡里,Command选择Link object files to dynamic library,Command line macro里将宏改一下,在$exe_output后面添加一个$def_input变量
原宏:$linker -shared -Wl,--output-def=$def_output -Wl,--out-implib=$static_output -Wl,--dll $libdirs $link_objects $link_resobjects -o $exe_output $link_options $libs
现宏:$linker -shared -Wl,--output-def=$def_output -Wl,--out-implib=$static_output -Wl,--dll $libdirs $link_objects $link_resobjects -o $exe_output $def_input $link_options $libs
因为IDE默认是g++最终生成DLL,所以不知为何会带上一个动态链接库,使用dumpbin查看,是一个名为libgcc_s_dw2-1.dll的东东,而且附带两个函数:
25  __deregister_frame_info
6A  __register_frame_info
于是Git-bash进入${MINGW_LIB},运行
grep -iaR "__deregister_frame_info" .
最终找到是${MINGW_LIB}/gcc/mingw32/6.3.0/libgcc_eh.a这个文件所持有的函数
于是点击Project - Build options,选中工程名,Linker settings的Other linker options里添加-static-libgcc
重新编译工程,dumpbin发现,libgcc_s_dw2-1.dll不见了,好了,就这样吧,写完手工。

原创粉丝点击