近段时间,我将以前的COM应用中远程激活对象的代码做了整理,并偿试将远程对象激活封装成一个类来简化操作。经本机测试后,代码能够正常激活COM对象,而且在客户端释放后,服务端也正常销毁。但是该代码在激活远程对象后,客户端正常退出,可是服务端却不释放。观查服务端的线程数量,发现每激活一个客户端,服务器均正确的增加一个线程。但释放客户端时,线程数量却没有减少,这意味着服务器端远程对象引用计数未能正确促使对象销毁。本人使用了多种方法仍然无法解决问题。现将代码贴出,请方家指点。
unit RmtComObjectCreater;interfaceuses windows,comobj,activex,sysutils,messages;type
pUnShort=^Word;
pCoAuthIdentity=^_CoAuthIdentity;
_CoAuthIdentity = record
user: pUnShort;
UserLength: ULONG;
Domain: pUnShort;
DomainLength: Ulong;
password: pUnShort;
PasswordLength: ulong;
Flags: ulong;
end; _CoAuthInfo = record
dwAuthnSvc: DWORD;
dwAuthzSvc: DWORD;
pwszServerPrincName: WideString;
dwAuthnLevel: DWORD;
dwImpersonationLevel: DWORD;
pAuthIdentityData: pCoAuthIdentity;
dwCapabilities: DWORD;
end; TRmtComObjectCreater = class(TObject)
private
FAuthnLevel: DWORD;
FAuthnSvc: DWORD;
FAuthzSvc: DWORD;
FCapabilities: DWORD;
FCoAuthIdentity: _CoAuthIdentity;
FCoAuthInfo: _CoAuthInfo;
FComputerName: WideString;
FCoServerInfo: COSERVERINFO;
FImpersonationLevel: DWORD;
FLogPSW: WideString;
FUserName: WideString;
procedure SetAuthnLevel(Value: DWORD);
procedure SetAuthnSvc(Value: DWORD);
procedure SetComputerName(Value: WideString);
procedure SetImpersonationLevel(Value: DWORD);
procedure SetLogPSW(Value: WideString);
procedure SetUserName(Value: WideString);
protected
function InternalCreateRmtComObject(const Class_IID,itf_iid:PIID): IUnknown;
function ItfSetBlanket(var itf: IUnknown; const vCai: _CoAuthInfo): HRESULT;
public
constructor Create;
function CreateRmtComObject(const Class_IID,itf_iid:PIID): IUnknown;
overload;
property AuthnLevel: DWORD read FAuthnLevel write SetAuthnLevel;
property AuthnSvc: DWORD read FAuthnSvc write SetAuthnSvc;
property AuthzSvc: DWORD read FAuthzSvc write FAuthzSvc;
property Capabilities: DWORD read FCapabilities write FCapabilities;
property ComputerName: WideString read FComputerName write SetComputerName;
property ImpersonationLevel: DWORD read FImpersonationLevel write
SetImpersonationLevel;
property LogPSW: WideString read FLogPSW write SetLogPSW;
property UserName: WideString read FUserName write SetUserName;
end;
implementation{
***************************** TRmtComObjectCreater *****************************
}
constructor TRmtComObjectCreater.Create;
begin
inherited Create;
FComputerName:='';//主机名
FUserName:='';//用户登录名
FLogPSW:='';//登录密码
FAuthnSvc:=10;//RPC_C_AUTHN_WINxNT NTML认证服务
FAuthzSvc:=0;// RPC_C_AUTHZ_NONE
FAuthnLevel:=0;//RPC_C_AUTHN_LEVEL_DEFAULT 默认级别
FImpersonationLevel:=3;//身份模拟
FillMemory(@FCoAuthIdentity,SizeOf(FCoAuthIdentity),0);
FillMemory(@FCoAuthInfo,SizeOf(FCoAuthInfo),0);
FillMemory(@FCoServerInfo,SizeOf(FCoServerInfo),0);
FCapabilities:=$0800;//静态跟踪
end;function TRmtComObjectCreater.CreateRmtComObject(const Class_IID,itf_iid:PIID):
IUnknown;
begin
Result:=InternalCreateRmtComObject(Class_IID,Itf_IID);
end;function TRmtComObjectCreater.InternalCreateRmtComObject(const Class_IID,
itf_iid:PIID): IUnknown;
var
Mqi: MULTI_QI;
RemoteComputer: Boolean;
Size: Cardinal;
LocalMachine: array [0..MAX_COMPUTERNAME_LENGTH] of char;
begin
Result:=nil;
RemoteComputer:=False;
if Length(FComputerName)> 0 then
begin
{$IFDEF LOCAL}
Size := Sizeof(LocalMachine); // Win95 is hypersensitive to size
if GetComputerName(LocalMachine, Size) and
(AnsiCompareText(LocalMachine, FComputerName) <> 0) then
{$ENDIF}
RemoteComputer:=true;
end;
if RemoteComputer then begin
with FCoAuthIdentity do begin
user:=pUnshort(FUserName);
UserLength:=length(FUsername);
Domain:=pUnshort(FComputerName);
DomainLength:=length(FComputerName);
password:=pUnShort(FLogPSW);
PasswordLength:=length(FLogPSW);
Flags:=2;//Unicode 字符串
end;
with FCoAuthInfo do begin
dwAuthnSvc:=FAuthnSvc;//RPC_C_AUTHN_WINNT NTML认证服务
dwAuthzSvc:=FauthzSvc;// RPC_C_AUTHZ_NONE
dwAuthnLevel:=FAuthnLevel;//RPC_C_AUTHN_LEVEL_DEFAULT 默认级别
dwImpersonationLevel:=FImpersonationLevel;//身份模拟
pAuthIdentityData:=@FCoAuthIdentity;//主机名/用户名/密码:替换登录用户
dwCapabilities:=FCapabilities;//静态跟踪
end;
FCoServerInfo.pwszName:=PWideChar(FComputerName);
FCoServerInfo.pAuthInfo:=@FCoAuthInfo;
//IID_IUnknown:=IUnknown;
//mqi.IID:=@IID_IUnknown;mqi.Itf:=nil;mqi.hr:=0;
with mqi do begin
iid:=itf_iid;
itf:=nil;
hr:=0;
end;
olecheck(CoCreateInstanceEx(class_iid^,nil,CLSCTX_REMOTE_SERVER,@FCoServerInfo,1,@mqi));
olecheck(mqi.hr);
olecheck(ItfSetBlanket(mqi.Itf,FCoAuthInfo));
//qr:=mqi.Itf.QueryInterface(IID_IMySendKey,result);
//olecheck(qr);
//MySetBlanket(mqi.itf,FCai);
result:=mqi.itf;
end
else
OleCheck(CoCreateInstance(class_iid^, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, itf_iid^, Result));
end;function TRmtComObjectCreater.ItfSetBlanket(var itf: IUnknown; const vCai:
_CoAuthInfo): HRESULT;
begin
with vCai do begin
result:=CoSetProxyBlanket(Itf,dwAuthnSvc,dwAuthzSvc,pwidechar(pAuthIdentityData^.Domain),
dwAuthnLevel,dwImpersonationLevel,pAuthIdentityData,dwCapabilities);
end;
end;procedure TRmtComObjectCreater.SetAuthnLevel(Value: DWORD);
begin
FAuthnLevel := Value;
end;procedure TRmtComObjectCreater.SetAuthnSvc(Value: DWORD);
begin
FAuthnSvc := Value;
end;procedure TRmtComObjectCreater.SetComputerName(Value: WideString);
begin
FComputerName := Value;
end;procedure TRmtComObjectCreater.SetImpersonationLevel(Value: DWORD);
begin
FImpersonationLevel := Value;
end;procedure TRmtComObjectCreater.SetLogPSW(Value: WideString);
begin
FLogPSW := Value;
end;procedure TRmtComObjectCreater.SetUserName(Value: WideString);
begin
FUserName := Value;
end;end. 上述代码中红色部分就是远程激活对象的关键,在这段代码中,我未能发现不正常的增加引用计数的语句。请大家帮忙解决问题。
若能解决,我会将远程发送键盘消息的c/s代码放在BLOG上与大家共议。
unit RmtComObjectCreater;interfaceuses windows,comobj,activex,sysutils,messages;type
pUnShort=^Word;
pCoAuthIdentity=^_CoAuthIdentity;
_CoAuthIdentity = record
user: pUnShort;
UserLength: ULONG;
Domain: pUnShort;
DomainLength: Ulong;
password: pUnShort;
PasswordLength: ulong;
Flags: ulong;
end; _CoAuthInfo = record
dwAuthnSvc: DWORD;
dwAuthzSvc: DWORD;
pwszServerPrincName: WideString;
dwAuthnLevel: DWORD;
dwImpersonationLevel: DWORD;
pAuthIdentityData: pCoAuthIdentity;
dwCapabilities: DWORD;
end; TRmtComObjectCreater = class(TObject)
private
FAuthnLevel: DWORD;
FAuthnSvc: DWORD;
FAuthzSvc: DWORD;
FCapabilities: DWORD;
FCoAuthIdentity: _CoAuthIdentity;
FCoAuthInfo: _CoAuthInfo;
FComputerName: WideString;
FCoServerInfo: COSERVERINFO;
FImpersonationLevel: DWORD;
FLogPSW: WideString;
FUserName: WideString;
procedure SetAuthnLevel(Value: DWORD);
procedure SetAuthnSvc(Value: DWORD);
procedure SetComputerName(Value: WideString);
procedure SetImpersonationLevel(Value: DWORD);
procedure SetLogPSW(Value: WideString);
procedure SetUserName(Value: WideString);
protected
function InternalCreateRmtComObject(const Class_IID,itf_iid:PIID): IUnknown;
function ItfSetBlanket(var itf: IUnknown; const vCai: _CoAuthInfo): HRESULT;
public
constructor Create;
function CreateRmtComObject(const Class_IID,itf_iid:PIID): IUnknown;
overload;
property AuthnLevel: DWORD read FAuthnLevel write SetAuthnLevel;
property AuthnSvc: DWORD read FAuthnSvc write SetAuthnSvc;
property AuthzSvc: DWORD read FAuthzSvc write FAuthzSvc;
property Capabilities: DWORD read FCapabilities write FCapabilities;
property ComputerName: WideString read FComputerName write SetComputerName;
property ImpersonationLevel: DWORD read FImpersonationLevel write
SetImpersonationLevel;
property LogPSW: WideString read FLogPSW write SetLogPSW;
property UserName: WideString read FUserName write SetUserName;
end;
implementation{
***************************** TRmtComObjectCreater *****************************
}
constructor TRmtComObjectCreater.Create;
begin
inherited Create;
FComputerName:='';//主机名
FUserName:='';//用户登录名
FLogPSW:='';//登录密码
FAuthnSvc:=10;//RPC_C_AUTHN_WINxNT NTML认证服务
FAuthzSvc:=0;// RPC_C_AUTHZ_NONE
FAuthnLevel:=0;//RPC_C_AUTHN_LEVEL_DEFAULT 默认级别
FImpersonationLevel:=3;//身份模拟
FillMemory(@FCoAuthIdentity,SizeOf(FCoAuthIdentity),0);
FillMemory(@FCoAuthInfo,SizeOf(FCoAuthInfo),0);
FillMemory(@FCoServerInfo,SizeOf(FCoServerInfo),0);
FCapabilities:=$0800;//静态跟踪
end;function TRmtComObjectCreater.CreateRmtComObject(const Class_IID,itf_iid:PIID):
IUnknown;
begin
Result:=InternalCreateRmtComObject(Class_IID,Itf_IID);
end;function TRmtComObjectCreater.InternalCreateRmtComObject(const Class_IID,
itf_iid:PIID): IUnknown;
var
Mqi: MULTI_QI;
RemoteComputer: Boolean;
Size: Cardinal;
LocalMachine: array [0..MAX_COMPUTERNAME_LENGTH] of char;
begin
Result:=nil;
RemoteComputer:=False;
if Length(FComputerName)> 0 then
begin
{$IFDEF LOCAL}
Size := Sizeof(LocalMachine); // Win95 is hypersensitive to size
if GetComputerName(LocalMachine, Size) and
(AnsiCompareText(LocalMachine, FComputerName) <> 0) then
{$ENDIF}
RemoteComputer:=true;
end;
if RemoteComputer then begin
with FCoAuthIdentity do begin
user:=pUnshort(FUserName);
UserLength:=length(FUsername);
Domain:=pUnshort(FComputerName);
DomainLength:=length(FComputerName);
password:=pUnShort(FLogPSW);
PasswordLength:=length(FLogPSW);
Flags:=2;//Unicode 字符串
end;
with FCoAuthInfo do begin
dwAuthnSvc:=FAuthnSvc;//RPC_C_AUTHN_WINNT NTML认证服务
dwAuthzSvc:=FauthzSvc;// RPC_C_AUTHZ_NONE
dwAuthnLevel:=FAuthnLevel;//RPC_C_AUTHN_LEVEL_DEFAULT 默认级别
dwImpersonationLevel:=FImpersonationLevel;//身份模拟
pAuthIdentityData:=@FCoAuthIdentity;//主机名/用户名/密码:替换登录用户
dwCapabilities:=FCapabilities;//静态跟踪
end;
FCoServerInfo.pwszName:=PWideChar(FComputerName);
FCoServerInfo.pAuthInfo:=@FCoAuthInfo;
//IID_IUnknown:=IUnknown;
//mqi.IID:=@IID_IUnknown;mqi.Itf:=nil;mqi.hr:=0;
with mqi do begin
iid:=itf_iid;
itf:=nil;
hr:=0;
end;
olecheck(CoCreateInstanceEx(class_iid^,nil,CLSCTX_REMOTE_SERVER,@FCoServerInfo,1,@mqi));
olecheck(mqi.hr);
olecheck(ItfSetBlanket(mqi.Itf,FCoAuthInfo));
//qr:=mqi.Itf.QueryInterface(IID_IMySendKey,result);
//olecheck(qr);
//MySetBlanket(mqi.itf,FCai);
result:=mqi.itf;
end
else
OleCheck(CoCreateInstance(class_iid^, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, itf_iid^, Result));
end;function TRmtComObjectCreater.ItfSetBlanket(var itf: IUnknown; const vCai:
_CoAuthInfo): HRESULT;
begin
with vCai do begin
result:=CoSetProxyBlanket(Itf,dwAuthnSvc,dwAuthzSvc,pwidechar(pAuthIdentityData^.Domain),
dwAuthnLevel,dwImpersonationLevel,pAuthIdentityData,dwCapabilities);
end;
end;procedure TRmtComObjectCreater.SetAuthnLevel(Value: DWORD);
begin
FAuthnLevel := Value;
end;procedure TRmtComObjectCreater.SetAuthnSvc(Value: DWORD);
begin
FAuthnSvc := Value;
end;procedure TRmtComObjectCreater.SetComputerName(Value: WideString);
begin
FComputerName := Value;
end;procedure TRmtComObjectCreater.SetImpersonationLevel(Value: DWORD);
begin
FImpersonationLevel := Value;
end;procedure TRmtComObjectCreater.SetLogPSW(Value: WideString);
begin
FLogPSW := Value;
end;procedure TRmtComObjectCreater.SetUserName(Value: WideString);
begin
FUserName := Value;
end;end. 上述代码中红色部分就是远程激活对象的关键,在这段代码中,我未能发现不正常的增加引用计数的语句。请大家帮忙解决问题。
若能解决,我会将远程发送键盘消息的c/s代码放在BLOG上与大家共议。
http://dev.21tx.com/2005/06/18/11039.html
unsinged:http://dev.21tx.com/2005/06/18/11039.html,该文章系本人以前DCOM应用的整理,上述代码是对这些整理代码的OBJECT封装。我不能确定是这段代码引起了资源泄漏,还是我服务端的问题。如果可能,请大家在客户端做下测试,可将结果反馈给我。谢谢