end;
procedure TMTSDemo.SaveDemoData(vData: OleVariant);
begin
with ClIEntDataSet1 do begin
Data:=vData;
SaveToFile('MyHandPhone.XML');
end;
end;
initialization
TComponentFactory.Create(ComServer, TMTSDemo,
Class_MTSDemo, ciMultiInstance, tmApartment);
end.
這段代碼中只是簡單在服務器端實現了GetDemoData和SaveDemoData兩個接口方法,
分別用於獲取服務器端的數據和將數據保存至服務器。數據文件是MyHandPhone.XML,
從文件名上大家也能看出這是一個不能再簡單的電話簿。這個文件可以直接由TClIEntDataset
的屬性編輯器生成,生成過程就不詳細介紹了,大家可以在MTS數據模塊中的TClIEntDataset
控件上右鍵點擊觀查其功能菜單項。
服務器代碼非常簡單相信方家不值一曬。
============================
下面是客戶端的代碼,客戶端的GUI上只是一個DBGird控件和幾個TButton,用於浏覽和
調用遠程服務器上的方法。比較特殊的是,為了觀察接口的引用計數,我在GUI上放了個TTimer
控件,用於監視接口的引用計數。
GUI主窗體的代碼如下:
unit MTSDemoClnt platform;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, DBGrids, DB, DBClIEnt, MConnect, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
DataSource1: TDataSource;
ClientDataSet1: TClIEntDataSet;
DBGrid1: TDBGrid;
btGetData: TButton;
btSaveData: TButton;
btExit: TButton;
edRef: TEdit;
Timer1: TTimer;
procedure btGetDataClick(Sender: TObject);
procedure btSaveDataClick(Sender: TObject);
procedure btExitClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses comobj,MTSDemoSvr_TLB, uRmtObj;
{$R *.dfm}
var
it{,it2,it3,it4}:IMTSDemoDisp;
procedure TForm1.btGetDataClick(Sender: TObject);
var
tmp:OleVariant;
//IID_IUnknown:TGUID;
begin
//IID_IUnknown:=IUnknown;
it:=IMTSDemoDisp(DoConnect(
@CLASS_MTSDemo,@IID_IMTSDemo,'omiga','ibrow','ibrow'));
it.GetDemoData(tmp);
ClIEntDataSet1.Data:=tmp;
// it2:=it;
// it3:=it;
// it4:=it;
end;
procedure TForm1.btSaveDataClick(Sender: TObject);
begin
if Assigned(it) then begin
it.SaveDemoData(ClIEntDataset1.data);
end;
end;
procedure TForm1.btExitClick(Sender: TObject);
begin
it:=nil;//主動清除接口引用,用於測試關閒接口時,遠程服務器上的認證反應
close;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i:integer;
begin
if Assigned(it) then begin
i:=IUnknown(it)._AddRef;
i:=IUnknown(it)._Release;
edRef.Text:=inttostr(i);
end;
end;
end.
主窗體代碼中需要說明的的代碼是 btGetDataClick(Sender: TObject),其中我用
自編的過程DoConnect()來獲取遠程計算機上的dispinterface接口,這裡的關鍵點就在
DoConnect()上,該過程在uRmtObj單位無中實現,其代碼如下:
unit uRmtObj platform;
interface
uses Windows,comobj,activex;
type
pUnShort=^Word;
pCoAuthIdentity=^_CoAuthIdentity;
_CoAuthIdentity=record
user:PWideChar;
UserLength:ULONG;
Domain:PWideChar;
DomainLength:Ulong;
passWord:PWideChar;
PassWordLength:ulong;
Flags:ulong;
end;
_CoAuthInfo=record
dwAuthnSvc:DWord;
dwAuthzSvc:DWord;
pwszServerPrincName:PWideChar;
dwAuthnLevel:DWord;
dwImpersonationLevel:DWord;
pAuthIdentityData:pCoAuthIdentity;
dwCapabilitIEs:DWord;
end;
Function MySetBlanket(var itf: IUnknown; const vCai: _CoAuthInfo):HRESULT;
function DoConnect(const Class_IID,itf_iid:PIID; computer,username,psw:WideString):IUnknown;
implementation
Function MySetBlanket(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;
function DoConnect(const Class_IID,itf_iid:PIID; computer,username,psw:WideString):IUnknown;
var
FCai:_CoAuthInfo;
FCid:_CoAuthIdentity;
FSvInfo:COSERVERINFO;
//tmpCmpName:widestring;
//IID_IUnknown:TGUID;
//iiu:IDispatch;
Mqi:MULTI_QI;
Size: DWord;
LocalMachine: array [0..MAX_COMPUTERNAME_LENGTH] of char;
//qr:HRESULT;
begin
Result:=nil;
if Length(computer)>0 then begin
size:=sizeof(LocalMachine);
if GetComputerName(LocalMachine,size) and (computer <> LocalMachine) then
begin
FillMemory(@Fcai,sizeof(Fcai),0);
FillMemory(@FCid,sizeof(FCid),0);
FillMemory(@FSvInfo,sizeof(FSvInfo),0);
with fcid do begin
user:=pwideChar(userName);//pUnshort(@userName[1]);
UserLength:=length(username);
Domain:=pWideChar(Computer);//pUnshort(@computer[1]);
DomainLength:=length(computer);
passWord:=pWideChar(psw);//pUnShort(@psw[1]);
PassWordLength:=length(psw);
Flags:=2;//Unicode 字符串
end;
with FCai do begin
dwAuthnSvc:=10;//RPC_C_AUTHN_WINNT NTML認證服務
dwAuthzSvc:=0;// RPC_C_AUTHZ_NONE
dwAuthnLevel:=0;//RPC_C_AUTHN_LEVEL_DEFAULT 默認級別
dwImpersonationLevel:=3;//身份模擬