SQL Server 2000 支援通過擴展存儲過程(XP)調用非托管 DLL 代碼。本文展示如何用 Delphi 編寫 DLL,實現接收 3 個字符串參數並逐行返回結果集的擴展存儲過程 xp_EpPackFile,涵蓋參數解析、列描述、行發送、完成標記的完整流程。
| 函數 | 用途 |
|---|---|
| srv_paraminfo | 獲取參數類型、長度、數據指針、是否 NULL |
| srv_rpcparams | 獲取 RPC 參數個數 |
| srv_describe | 定義結果集列元數據 (名稱、類型、長度) |
| srv_setcoldata | 設置當前行某列數據指針 |
| srv_sendrow | 發送當前行到客戶端 |
| srv_senddone | 發送完成狀態 (行計數、更多結果標誌) |
function GetParamStr(pSrvProc: SRV_PROC; Index: Integer; var Param: String): Integer;
var
PType: Byte; cbMaxLen, ParaLen: DWORD; IsNULL: BOOL;
begin
Result := NO_ERROR;
srv_paraminfo(pSrvProc, Index, @PType, @cbMaxLen, @ParaLen, nil, @IsNULL);
{僅處理字符串類型}
if PType in [SRVTEXT, SRVVARCHAR, SRVCHAR, SRVNTEXT,
SRVBIGVARCHAR, SRVBIGCHAR, SRVNVARCHAR, SRVNCHAR] then begin
Param := '';
if ParaLen > 0 then begin
SetLength(Param, ParaLen);
srv_paraminfo(pSrvProc, Index, @PType, @cbMaxLen, @ParaLen, @Param[1], @IsNULL);
end;
end else
Result := -1; {類型不匹配}
end;
function EpPackFile(pSrvProc: SRV_PROC): Integer; cdecl;
var
ls1, ls2, ls3: String;
n: Integer;
begin
Result := 1; {預設失敗}
n := srv_rpcparams(pSrvProc);
if n <> 3 then Exit; {參數個數不符}
if GetParamStr(pSrvProc, 1, ls1) <> NO_ERROR then Exit;
if GetParamStr(pSrvProc, 2, ls2) <> NO_ERROR then Exit;
if GetParamStr(pSrvProc, 3, ls3) <> NO_ERROR then Exit;
{描述結果集:1 列,名為 '參數',類型 SRVBIGVARCHAR}
n := Length(ls1);
srv_describe(pSrvProc, 1, '參數', SRV_NULLTERM, SRVBIGVARCHAR, n, SRVBIGVARCHAR, n, nil);
{發送 3 行}
srv_setcoldata(pSrvProc, 1, @ls1[1]); srv_sendrow(pSrvProc);
srv_setcoldata(pSrvProc, 1, @ls2[1]); srv_sendrow(pSrvProc);
srv_setcoldata(pSrvProc, 1, @ls3[1]); srv_sendrow(pSrvProc);
{發送完成:SRV_DONE_COUNT(返回行計數) | SRV_DONE_MORE(無更多結果集)}
srv_senddone(pSrvProc, (SRV_DONE_COUNT or SRV_DONE_MORE), 0, 1);
Result := 0; {成功}
end;
exports
EpPackFile name 'xp_EpPackFile'; {導出名稱需與 sp_addextendedproc 一致}
USE master;
IF OBJECT_ID('xp_EpPackFile') IS NOT NULL
EXEC sp_dropextendedproc 'xp_EpPackFile';
EXEC sp_addextendedproc 'xp_EpPackFile', 'project1.dll'; {DLL 放入 Binn 目錄}
EXEC master..xp_EpPackFile 'aa', 'bb', 'cc'; {測試調用}
EXEC sp_dropextendedproc 'xp_EpPackFile';
DBCC FREEPROCCACHE; {清理計劃緩存}
參數
------
aa
bb
cc
cdecl(SQL Server 期望 C 調用約定)。SRVNVARCHAR、wchar_t*)。srv_setcoldata 傳遞的指針必須在 srv_sendrow 返回前保持有效,局部 String 變量在函數棧上滿足此條件。Binn 目錄,或在 sp_addextendedproc 指定完整路徑。掌握 srv_paraminfo 參數解析、srv_describe 列定義、srv_sendrow 行發送流程,即可用 Delphi 為 SQL Server 2000 構建高性能擴展存儲過程,實現文件操作、加密算法、外部 API 調用等 T-SQL 難以完成的功能。