BCC(Borland C++ Compiler)编译 ISAPI 扩展或者用MinGW也行
今天突發神經,要寫個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" EXPORTSGetExtensionVersionHttpExtensionProcTerminateExtension
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.c dllwrap --def test.def -o test.dll test.o dumpbin -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不見了,好了,就這樣吧,寫完手工。
總結
以上是生活随笔為你收集整理的BCC(Borland C++ Compiler)编译 ISAPI 扩展或者用MinGW也行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openstack 逻辑构架真相
- 下一篇: 【灵动MM32-DMA传输-GPS解算】