SQL Server 的扩展存储过程,其实就是一个普通的 Windows DLL,只不过按照某种规则实现了某些函数而已。 {!) zo:
SQL Server 的扩展存储过程,其实就是一个普通的 Windows DLL,只不过按照某种规则实现了某些函数而已。 {!) zo:
4.9T?(glL~
近日在写一个扩展存储过程时,发现再写这类动态库时,还是有一些需要特别注意的地方。之所以会特别注意,是因为DLL运行于SQL Server的地址空间,而SQL Server到底是怎么进行线程调度的,却不是我们能了解的,即便了解也无法控制。 {Y 15TgL
at;W_CpU
我们写动态库一般是自己用,即便给别人用,也很少像SQL Server这样,一个动态库很有可能加载多次,并且都是加载到一个进程的地址空间中。我们知道,当一个动态库加载到进程的地址空间时,DLL所有全局与局部变量初始化且仅初始化一次,以后再次调用 LoadLibrary函数时,仅仅增加其引用计数而已,那么很显然,假如有一全局 int ,初始化为0,调用一个函数另其自加,此时其值为1,然后再调用LoadLibray,并利用返回的句柄调用输出函数输出该值,虽然调用者觉得自己加载后立即输出,然后该值确实1而不是0。windows是进程独立的,而在线程方面,假如不注意,上面的情况很可能会程序员带来麻烦。 (/bLSW
nYFSWF,
介绍一下我的扩展存储过程,该动态库导出了三个函数: Init,work,Final,Init读文件,存储信息于内存,work简单的只是向该内存检索信息,Final回收内存。如上所说,假如不考虑同一进程空间多次加载问题,两次调用Init将造成无谓的浪费,因为我第一次已经读进了内存,要是通过堆分配内存,还会造成内存泄露。 Dsx^4,Ej
-iLrd Q
我使用的引用计数解决的该问题,代码很短,直接贴上来: #H>yx~Xz+
@5%8~{wJ
#include "stdafx.h" `'+G`Xv
#include <string> \+ s Cq
using namespace std; uh>3jLB3
extern "C" { 'L_&[[s
RETCODE __declspec(dllexport) xp_part_init(SRV_PROC *srvproc); ]7 z'H
RETCODE __declspec(dllexport) xp_part_process(SRV_PROC *srvproc); <yvd %W
RETCODE __declspec(dllexport) xp_part_finalize(SRV_PROC *srvproc); RP~>o{op
} cL%dfj
#define XP_NOERROR 0 Hge^7I
#define XP_ERROR 1 Bg=[a#
HINSTANCE hInst = NULL; gM>/9
int nRef = 0; XE%N}k2
void printError (SRV_PROC *pSrvProc, CHAR* szErrorMsg); %fhp%e+1]]
ULONG __GetXpVersion(){ return ODS_VERSION;} {'|b;tV 4A
SRVRETCODE xp_part_init(SRV_PROC* pSrvProc){ EEDN:B3V
typedef bool (*Func)(); %mQgBrD
if(nRef == 0){ u\.7!
hInst = ::LoadLibrary("part.dll"); dv-JE :
if(hInst == NULL){ Q\yZlz#H
printError(pSrvProc,"不能加载part.dll"); =eLTm&!,$
return XP_ERROR; XQ!JS
} -qjpV7<LE
Func theFunc = (Func)::GetProcAddress(hInst,"Init"); =*: A>'/
if(!theFunc()){ 0@'B"0a(
::FreeLibrary(hInst); ?/ \|sV:JH
printError(pSrvProc,"不能获得分类号与专辑的对应表"); +DUp0\5s
return XP_ERROR; VnzEF0)
} s )O6U<
} SFH:T7 !g
++ nRef; 7:1ADUfu?
return (XP_NOERROR); ATnWb"V@
} C ML^]wz+
SRVRETCODE xp_part_process(SRV_PROC* pSrvProc){ n); ?b
typedef bool (*Func)(char*); .Dsz6<;
if(nRef == 0){ Au0`vhs}
printError(pSrvProc,"函数尚未初始化,请首先调用xp_part_init"); T TwvGniS
return XP_ERROR; y?'bKMG<>
} bdC`!\k.
Func theFunc = (Func)::GetProcAddress(hInst,"Get"); + ;] k`r
BYTE bType; X`LaH:n+
ULONG cbMaxLen,cbActualLen; Wq,wf ^OL
BOOL fNull; Sl8$^=>
char szInput[256] = {0}; Lg<c~DdT
if (srv_paraminfo(pSrvProc, 1, &bType, (ULONG*)&cbMaxLen, (ULONG*)&cbActualLen, (BYTE*)szInput, &fNull) == FAIL){ A:B(5gk
printError(pSrvProc,"srv_paraminfo 返回 FAIL"); o MSDV>
return XP_ERROR; 7S}% Huj
} d;-L+%qu