在存储过程中调用外部的ActiveX DLL程序    有些特殊的情况下,我们可能会需要调用外部的ActiveX DLL程序,这个时候就需要使用到系统的存储过 
程sp_OACreate以及其他的相关系统存储过程,都是以sp_OA开头的存储过程,可以自由的在自己的存储 
过程当中调用ActiveX DLL的各种方法和属性。比如下面的例子:    DECLARE @object int    DECLARE @hr int    DECLARE @property varchar(255)    DECLARE @return varchar(255)    DECLARE @src varchar(255), @desc varchar(255)    -- 建立一个对象(SQLDMO.SQLServer).    EXEC @hr = sp_OACreate 'SQLDMO.SQLServer', @object  
OUT    IF @hr <> 0    BEGIN       EXEC sp_OAGetErrorInfo @object, @src OUT, @desc  
OUT        SELECT hr=convert(varbinary(4),@hr), Source=@sr 
c, Description=@desc        RETURN    END    -- 设置对象的属性.    EXEC @hr = sp_OASetProperty @object, 'HostName', 'G 
izmo'    IF @hr <> 0    BEGIN       EXEC sp_OAGetErrorInfo @object, @src OUT, @desc  
OUT        SELECT hr=convert(varbinary(4),@hr), Source=@sr 
c, Description=@desc        RETURN    END    -- 通过OUTPUT参数获取对象的属性值.    EXEC @hr = sp_OAGetProperty @object, 'HostName', @p 
roperty OUT    IF @hr <> 0    BEGIN       EXEC sp_OAGetErrorInfo @object, @src OUT, @desc  
OUT        SELECT hr=convert(varbinary(4),@hr), Source=@sr 
c, Description=@desc        RETURN    END    PRINT @property    -- 调用对象的方法    EXEC @hr = sp_OAMethod @object, 'Connect', NULL, 'm 
y_server', 'my_login', 'my_password'    IF @hr <> 0    BEGIN       EXEC sp_OAGetErrorInfo @object, @src OUT, @desc  
OUT        SELECT hr=convert(varbinary(4),@hr), Source=@sr 
c, Description=@desc        RETURN    END    -- 销毁已经创建的ActiveX对象    EXEC @hr = sp_OADestroy @object    IF @hr <> 0    BEGIN       EXEC sp_OAGetErrorInfo @object, @src OUT, @desc  
OUT        SELECT hr=convert(varbinary(4),@hr), Source=@sr 
c, Description=@desc        RETURN    END

解决方案 »

  1.   

    在存储过程中调用外部的动态连接库(MS SQL Server7.0/2000环境)
    作者:ac952_z_cn
    问题的提出:
    一般我们要根据数据库的纪录变化时,进行某种操作。我们习惯的操作方式是在程序中不停的查询表,判断是否有新纪录。这样耗费的资源就很高,如何提高这种效率,我想在表中创建触发器,在触发器中调用外部动态连接库通过消息或事件通知应用程序就可实现。而master的存储过程中最好能调用外部的动态连接库,我们在触发器中调用master的存储过程即可。下载源代码 大小:14K说明:VC6需要安装较新的Platform SDK才能顺利编译本代码,VC.Net可以直接编译本代码。另外还需要连接Opends60.lib
    为了使没有较新Platform SDK的朋友也能编译本例子,已经将VC.Net中的Srv.h和Opends60.lib放到压缩包中程序实现:
    我们来实现一个存储过程中调用外部的dll(storeproc.dll)的函数SetFileName和addLine。存储过程如下(需放到master库中): CREATE PROCEDURE sp_testdll ASexec sp_addextendedproc 'SetFileName', 'storeproc.dll' --声明函数
    exec sp_addextendedproc 'addLine', 'storeproc.dll' declare @szFileName varchar(200)
    declare @szText varchar(200)
    declare @rt intSelect @szFileName = 'c:\welcome.txt'EXEC @rt = SetFileName @szFileName --调用SetFileName函数,参数为--szFileName;
    if @rt = 0
    begin
    select @szText = 'welcome 01'
    Exec @rt = addLine @szText --调用addLine
    select @szText = 'welcome 02'
    Exec @rt = addLine @szTextend
    exec sp_dropextendedproc 'SetFileName'
    exec sp_dropextendedproc 'addLine'dbcc SetFileName(free)
    dbcc addLine(free)动态连接库的实现:这种动态连接库和普通的有所不同。该动态连接库要放入SQL的执行目录下,或直接放到Window的System32目录下,并重起SQL-Server #include <windows.h>
    #include <srv.h> //要加入这个.h文件#define XP_NOERROR      0
    #define XP_ERROR        1#ifndef _DEBUG
    #define _DEBUG
    #endifchar szFileName[MAX_PATH+1];void WriteInfo(const char * str);extern "C" SRVRETCODE WINAPI SetFileName(SRV_PROC* pSrvProc)
    {
    WriteInfo("SetFileName start");
    int paramCount = srv_rpcparams(pSrvProc);
    if (paramCount != 1){
    WriteInfo("Param Err start");
    return XP_ERROR;
    } BYTE bType;
    unsigned long cbMaxLen;
    unsigned long cbActualLen;
    BOOL fNull; int ret = srv_paraminfo(pSrvProc, 1, &bType, &cbMaxLen, &cbActualLen,
            NULL, &fNull);
    if (cbActualLen){
    ZeroMemory(szFileName, MAX_PATH+1);
    memcpy(szFileName, srv_paramdata(pSrvProc, 1), cbActualLen);
    WriteInfo("Set filename ok");
    return (XP_NOERROR);
    }
    else {
    WriteInfo("Set filename param failed");
    return XP_ERROR;
    }
    }extern "C" SRVRETCODE WINAPI addLine(SRV_PROC* pSrvProc)
    {
    WriteInfo("addline start");
    int paramCount = srv_rpcparams(pSrvProc);
    if (paramCount != 1){
    WriteInfo("addline param err");
    return XP_ERROR;
    } BYTE         bType;
    unsigned long cbMaxLen;
    unsigned long cbActualLen;
    BOOL fNull;
    bool rt = false; int ret = srv_paraminfo(pSrvProc, 1, &bType, &cbMaxLen, &cbActualLen,
            NULL, &fNull); if (cbActualLen){
    int n;
    char srt[3] = {0x0d, 0x0a, 0}; char * c = new char[cbActualLen + 3];
    if (!c)return XP_ERROR; ZeroMemory(c, cbActualLen + 3);
    memcpy(c, srv_paramdata(pSrvProc, 1), cbActualLen);
    memcpy(c+cbActualLen, srt, 3); HANDLE hf = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, 
              OPEN_ALWAYS, 0, NULL);
    if (hf == INVALID_HANDLE_VALUE){
    WriteInfo("addline create file err ");
    delete []c;
    return XP_ERROR;
    } WriteInfo("addline create file ok ");
    DWORD dwWt;
    n = strlen(c);
    SetFilePointer(hf, 0, NULL, FILE_END);
    if (WriteFile(hf, c, n, &dwWt, NULL) && dwWt == n)
    {
    WriteInfo("addline write file ok ");
    rt = true;
    }
    delete []c;
    CloseHandle(hf);
    }
    return rt ? XP_NOERROR:XP_ERROR;
    }inline void WriteInfo(const char * str){
        #ifdef _DEBUG
    char srt[3] = {0x0d, 0x0a, 0};
    HANDLE hf = 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);
    DWORD dwWt;
    WriteFile(hf, str, strlen(str), &dwWt, NULL);
    WriteFile(hf, srt, strlen(srt), &dwWt, NULL);
    CloseHandle(hf);
    }
    else {
    MessageBox(NULL, "Write info err", "Message", MB_OK|MB_ICONINFORMATION);
    }
    #endif
    }BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved)
    {
    return TRUE;
    }编译完成后,把动态链接库放到WINNT/System32目录下,启动SQL Server。我们可以打开SQL Server Query Analyzer调用存储过程sp_testdll以测试其运行是否正确。具体可参考SQL-Server的在线帮助。
    笔者环境:win2000 professional + SQL-Server7.0(2000也可)
    VC6.0+SP5+Platform SDK 20001.8VC知识库测试环境:win2000 professional + SQL-Server 7.0 + VC.Net