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)
#endif

DWORD 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.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不见了,好了,就这样吧,写完手工。

Borland C++3.1 神话般的经典开发工具 带有传奇色彩的BORLAND公司,见证了美国软件技术市场上波澜壮阔、激动人心的技术大战和产品大战,最为经典的成功范例就是Borland C++3.1! Borland是中国程序员最为景仰的公司之一,特别是对于资格老一点的程序员而言,他们学习编程的起步就是Borland. 以下是Borland c++入门指南中摘录的一些信息 Borlandc++适用于需要一个专业化、优化的编译器的C++和C程序员,它同时适用于A&T公司的C++2.1版和ANSIC的程序员。它快速而有效,据此用户可以创建包括Microsoft Windows应用程序在内的任何应用程序。 Borland C++3.0可以在DOS的环境下运,更可以在Windows下运,在Windows之下的Borland C工作环境更亲切,将使您开发程序更得心应手。 C++是一个面向对象(OOP)的程序设计语言.使用户能充分利用OOP的先进设计方法和省时效率高的特点,它是C语言的进一步发展,它是可移植的,所以用户可以很容易地将一个由C++编写的应用程序从—个系统移植到另一个系统。在任何地方,都可以用C++从事任何编程工作。 Borland C++特色 1. Borland C++3.0及3.1可供程序设计人员开发C++及c程序。其中的c++是依照AT&T2.1标准设计的,而C则是ANSI C。因此让您开发的程序兼容性高.移植性(Portable)也更强。 2.全局的优化(Global Optimization):为程序编译出最优的目的码,使执时间减少,使目的码变小。 3.缩短编译时间:由于编译器及工具的使用,大大减少了编译时间。 4.集成开发可境:(即IDE,Integrated Development Environment),本产品提供一完整的工作平台(Platform),使程序的编写编译、调试、分析、运相当完整且方便。 5.窗口程序开发:本产品可以开发出Microsoft Windows程序,还包括完整的工具程序:窗口资源编译器(Resource Compiler),在线帮助编译器(Help Compiler)及窗口资源工作程序(Resource Workshop)。 6. DPMI编译器:DPMI (DOS Protected Mode Interface)使编译器可以在DOS或Windows386的保护模式下运,因此开发大型的程序不用担心内存不足。 7. Easywin:或将DOS程序直接转成Window。程序的功能,不需要改半令。 8. WinSight:窗口信息跟踪程序,使我们看到程序与Windows之间的联系息。 9.在线帮助,在IDE环境下,任何错误都可由在线帮助得到说明或者想要任何时间查询函数或其他说明,都可使用此项功能。 10.虚拟Run - time面向对象存储管理功能(VROOMM,Virtual Run-time Object-Oriented Memory Manager)。当程序设计人员选定目的码的覆盖功能后,VRAOOMM会处理一切事情,即使程序超过640K。 11.丰富的类库,本产品提供常用的数据结构,例如List, Queue, Qegue, Stack, Array. . 等。 12.丰富的函数库:本产品提供4, 5百个函数,可以说无所不包了。 1.2.1. Borland C++3.1新功能 1. 3.1版将Turbo C++ for Window。改名为Borland C++for Windows, 2. 3.1版配合Windows 3.1版,增加多媒体(Multi-Media)、笔(Pen)和MCI (Media Control Interface)之控制接口。 3. 新增Win Spector I具程序,此工具程序是当Windows程序发生General Protection Faults时,提供发生此错误的地方,及当时机器的状态。 4. 在Borland C++ for Window,提供最优化的选项。 5. 彩色语法高亮显示(Color Syntax Highlighting),在源程序中设置不同的显示的颜 色。可在DOS IDE内的Options I Environment I Colors I Edit及Windows IDE内的Options Environment I Highlight内设置。 6. 可利用参数(-3)或IDC内的Options I Compiler I Advanced Coded Generation 80368设置产生386的目的码。 7. 可在程序内控制最大打开文件数,在_NFILE. H内#DEFINE_NFILE_n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值