在存储过程中调用外部的动态连接库2002-03-28··ac952_z_cn··vckbase问题的提出:一般我们要根据数据库的纪录变化时,进行某种操作。我们习惯的操作方式是在程序中不停的查询表,判断是否有新纪录。这样耗费的资源就很高,如何提高这种效率,我想在表中创建触发器,在触发器中调用外部动态连接库通过消息或事件通知应用程序就可实现。而master的存储过程中最好能调用外部的动态连接库,我们在触发器中调用master的存储过程即可。说明:VC6需要安装较新的PlatformSDK才能顺利编译本代码,VC.Net可以直接编译本代码。另外还需要连接Opends60.lib为了使没有较新PlatformSDK的朋友也能编译本例子,已经将VC.Net中的Srv.h和Opends60.lib放到压缩包中程序实现:我们来实现一个存储过程中调用外部的dll(storeproc.dll)的函数SetFileName和addLine。存储过程如下(需放到master库中):CREATEPROCEDUREsp_testdllASexecsp_addextendedproc''SetFileName'',''storeproc.dll''--声明函数execsp_addextendedproc''addLine'',''storeproc.dll''declare@szFileNamevarchar(200)declare@szTextvarchar(200)declare@rtintSelect@szFileName=''c:\welcome.txt''EXEC@rt=SetFileName@szFileName--调用SetFileName函数,参数为--szFileName;if@rt=0beginselect@szText=''welcome01''Exec@rt=addLine@szText--调用addLineselect@szText=''welcome02''Exec@rt=addLine@szTextendexecsp_dropextendedproc''SetFileName''execsp_dropextendedproc''addLine''dbccSetFileName(free)dbccaddLine(free)动态连接库的实现:这种动态连接库和普通的有所不同。该动态连接库要放入SQL的执行目录下,或直接放到Window的System32目录下,并重起SQL-Server#include#include//要加入这个.h文件#defineXP_NOERROR0#defineXP_ERROR1#ifndef_DEBUG#define_DEBUG#endifcharszFileName[MAX_PATH+1];voidWriteInfo(constchar*str);externCSRVRETCODEWINAPISetFileName(SRV_PROC*pSrvProc){WriteInfo(SetFileNamestart);intparamCount=srv_rpcparams(pSrvProc);if(paramCount!=1){WriteInfo(ParamErrstart);returnXP_ERROR;}BYTEbType;unsignedlongcbMaxLen;unsignedlongcbActualLen;BOOLfNull;intret=srv_paraminfo(pSrvProc,1,&bType,&cbMaxLen,&cbActualLen,NULL,&fNull);if(cbActualLen){ZeroMemory(szFileName,MAX_PATH+1);memcpy(szFileName,srv_paramdata(pSrvProc,1),cbActualLen);WriteInfo(Setfilenameok);return(XP_NOERROR);}else{WriteInfo(Setfilenameparamfailed);returnXP_ERROR;}}externCSRVRETCODEWINAPIaddLine(SRV_PROC*pSrvProc){WriteInfo(addlinestart);intparamCount=srv_rpcparams(pSrvProc);if(paramCount!=1){WriteInfo(addlineparamerr);returnXP_ERROR;}BYTEbType;unsignedlongcbMaxLen;unsignedlongcbActualLen;BOOLfNull;boolrt=false;intret=srv_paraminfo(pSrvProc,1,&bType,&cbMaxLen,&cbActualLen,NULL,&fNull);if(cbActualLen){intn;charsrt[3]={0x0d,0x0a,0};char*c=newchar[cbActualLen+3];if(!c)returnXP_ERROR;ZeroMemory(c,cbActualLen+3);memcpy(c,srv_paramdata(pSrvProc,1),cbActualLen);memcpy(c+cbActualLen,srt,3);HANDLEhf=CreateFile(szFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,OPEN_ALWAYS,0,NULL);if(hf==INVALID_HANDLE_VALUE){WriteInfo(addlinecreatefileerr);delete[]c;returnXP_ERROR;}WriteInfo(addlinecreatefileok);DWORDdwWt;n=strlen(c);SetFilePointer(hf,0,NULL,FILE_END);if(WriteFile(hf,c,n,&dwWt,NULL)&&dwWt==n){WriteInfo(addlinewritefileok);rt=true;}delete[]c;CloseHandle(hf);}returnrt?XP_NOERROR:XP_ERROR;}inlinevoidWriteInfo(constchar*str){#ifdef_DEBUGcharsrt[3]={0x0d,0x0a,0};HANDLEhf=CreateFile(c:\\storeproc.log,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,OPEN_ALWAYS,0,NULL);if(hf!=INVALID_HANDLE_VALUE){SetFilePointer(hf,0,NULL,FILE_END);DWORDdwWt;WriteFile(hf,str,strlen(str),&dwWt,NULL);WriteFile(hf,srt,strlen(srt),&dwWt,NULL);CloseHandle(hf);}else{MessageBox(NULL,Writeinfoerr,Message,MB_OK|MB_ICONINFORMATION);}#endif}BOOLWINAPIDllMain(HINSTANCEhinstDLL,DWORDfdwReason,LPVOIDlpReserved){returnTRUE;}编译完成后,把动态链接库放到WINNT/System32目录下,启动SQLServer。我们可以打开SQLServerQueryAnalyzer调用存储过程sp_testdll以测试其运行是否正确。具体可参考SQL-Server的在线帮助。笔者环境:win2000professional+SQL-Server7.0(2000也可)VC6.0+SP5+PlatformSDK20001.8VC知识库测试环境:win2000professional+SQL-Server7.0+VC.Net【