comobj.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006 by Florian Klaempfl
  4. member of the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$H+}
  13. {$inline on}
  14. unit comobj;
  15. interface
  16. uses
  17. Windows,Types,Variants,Sysutils,ActiveX;
  18. type
  19. EOleError = class(Exception);
  20. EOleSysError = class(EOleError)
  21. private
  22. FErrorCode: HRESULT;
  23. public
  24. constructor Create(const Msg: string; aErrorCode: HRESULT;aHelpContext: Integer);
  25. property ErrorCode: HRESULT read FErrorCode write FErrorCode;
  26. end;
  27. EOleException = class(EOleSysError)
  28. private
  29. FHelpFile: string;
  30. FSource: string;
  31. public
  32. constructor Create(const Msg: string; aErrorCode: HRESULT;const aSource,aHelpFile: string;aHelpContext: Integer);
  33. property HelpFile: string read FHelpFile write FHelpFile;
  34. property Source: string read FSource write FSource;
  35. end;
  36. EOleRegistrationError = class(EOleError);
  37. TComServerObject = class(TObject)
  38. protected
  39. function CountObject(Created: Boolean): Integer; virtual; abstract;
  40. function CountFactory(Created: Boolean): Integer; virtual; abstract;
  41. function GetHelpFileName: string; virtual; abstract;
  42. function GetServerFileName: string; virtual; abstract;
  43. function GetServerKey: string; virtual; abstract;
  44. function GetServerName: string; virtual; abstract;
  45. function GetStartSuspended: Boolean; virtual; abstract;
  46. function GetTypeLib: ITypeLib; virtual; abstract;
  47. procedure SetHelpFileName(const Value: string); virtual; abstract;
  48. public
  49. property HelpFileName: string read GetHelpFileName write SetHelpFileName;
  50. property ServerFileName: string read GetServerFileName;
  51. property ServerKey: string read GetServerKey;
  52. property ServerName: string read GetServerName;
  53. property TypeLib: ITypeLib read GetTypeLib;
  54. property StartSuspended: Boolean read GetStartSuspended;
  55. end;
  56. {
  57. TComObject = class(TObject, IUnknown, ISupportErrorInfo)
  58. protected
  59. { IUnknown }
  60. function IUnknown.QueryInterface = ObjQueryInterface;
  61. function IUnknown._AddRef = ObjAddRef;
  62. function IUnknown._Release = ObjRelease;
  63. { IUnknown methods for other interfaces }
  64. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  65. function _AddRef: Integer; stdcall;
  66. function _Release: Integer; stdcall;
  67. { ISupportErrorInfo }
  68. function InterfaceSupportsErrorInfo(const iid: TIID): HResult; stdcall;
  69. public
  70. constructor Create;
  71. constructor CreateAggregated(const Controller: IUnknown);
  72. constructor CreateFromFactory(Factory: TComObjectFactory; const Controller: IUnknown);
  73. destructor Destroy; override;
  74. procedure Initialize; virtual;
  75. function ObjAddRef: Integer; virtual; stdcall;
  76. function ObjQueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
  77. function ObjRelease: Integer; virtual; stdcall;
  78. function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; override;
  79. property Controller: IUnknown;
  80. property Factory: TComObjectFactory;
  81. property RefCount: Integer;
  82. property ServerExceptionHandler: IServerExceptionHandler;
  83. end;
  84. }
  85. function CreateClassID : ansistring;
  86. function CreateComObject(const ClassID: TGUID) : IUnknown;
  87. function CreateRemoteComObject(const MachineName : WideString;const ClassID : TGUID) : IUnknown;
  88. function CreateOleObject(const ClassName : string) : IDispatch;
  89. function GetActiveOleObject(const ClassName: string) : IDispatch;
  90. procedure OleCheck(Value : HResult);inline;
  91. procedure OleError(Code: HResult);
  92. function ProgIDToClassID(const id : string) : TGUID;
  93. procedure DispatchInvoke(const Dispatch: IDispatch; CallDesc: PCallDesc;
  94. DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  95. procedure DispatchInvokeError(Status: HRESULT; const ExceptInfo: TExcepInfo);
  96. type
  97. TCoCreateInstanceExProc = function(const clsid: TCLSID; unkOuter: IUnknown; dwClsCtx: DWORD; ServerInfo: PCoServerInfo;
  98. dwCount: ULONG; rgmqResults: PMultiQIArray): HResult stdcall;
  99. TCoInitializeExProc = function (pvReserved: Pointer;
  100. coInit: DWORD): HResult; stdcall;
  101. TCoAddRefServerProcessProc = function : ULONG; stdcall;
  102. TCoReleaseServerProcessProc = function : ULONG; stdcall;
  103. TCoResumeClassObjectsProc = function : HResult; stdcall;
  104. TCoSuspendClassObjectsProc = function : HResult; stdcall;
  105. const
  106. CoCreateInstanceEx : TCoCreateInstanceExProc = nil;
  107. CoInitializeEx : TCoInitializeExProc = nil;
  108. CoAddRefServerProcess : TCoAddRefServerProcessProc = nil;
  109. CoReleaseServerProcess : TCoReleaseServerProcessProc = nil;
  110. CoResumeClassObjects : TCoResumeClassObjectsProc = nil;
  111. CoSuspendClassObjects : TCoSuspendClassObjectsProc = nil;
  112. implementation
  113. uses
  114. ComConst,Ole2;
  115. constructor EOleSysError.Create(const Msg: string; aErrorCode: HRESULT; aHelpContext: Integer);
  116. var
  117. m : string;
  118. begin
  119. if Msg='' then
  120. m:=SysErrorMessage(aErrorCode)
  121. else
  122. m:=Msg;
  123. inherited CreateHelp(m,HelpContext);
  124. FErrorCode:=aErrorCode;
  125. end;
  126. constructor EOleException.Create(const Msg: string; aErrorCode: HRESULT;const aSource,aHelpFile: string; aHelpContext: Integer);
  127. begin
  128. inherited Create(Msg,aErrorCode,aHelpContext);
  129. FHelpFile:=aHelpFile;
  130. FSource:=aSource;
  131. end;
  132. {$define FPC_COMOBJ_HAS_CREATE_CLASS_ID}
  133. function CreateClassID : ansistring;
  134. var
  135. ClassID : TCLSID;
  136. p : PWideChar;
  137. begin
  138. CoCreateGuid(ClassID);
  139. StringFromCLSID(ClassID,p);
  140. result:=p;
  141. CoTaskMemFree(p);
  142. end;
  143. function CreateComObject(const ClassID : TGUID) : IUnknown;
  144. begin
  145. OleCheck(CoCreateInstance(ClassID,nil,CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,IUnknown,result));
  146. end;
  147. function CreateRemoteComObject(const MachineName : WideString;const ClassID : TGUID) : IUnknown;
  148. var
  149. flags : DWORD;
  150. localhost : array[0..MAX_COMPUTERNAME_LENGTH] of WideChar;
  151. server : TCoServerInfo;
  152. mqi : TMultiQI;
  153. size : DWORD;
  154. begin
  155. if not(assigned(CoCreateInstanceEx)) then
  156. raise Exception.CreateRes(@SDCOMNotInstalled);
  157. FillChar(server,sizeof(server),0);
  158. server.pwszName:=PWideChar(MachineName);
  159. FillChar(mqi,sizeof(mqi),0);
  160. mqi.iid:=@IID_IUnknown;
  161. flags:=CLSCTX_LOCAL_SERVER or CLSCTX_REMOTE_SERVER or CLSCTX_INPROC_SERVER;
  162. { actually a remote call? }
  163. {$ifndef wince}
  164. //roozbeh although there is a way to retrive computer name...HKLM\Ident\Name..but are they same?
  165. size:=sizeof(localhost);
  166. if (MachineName<>'') and
  167. (not(GetComputerNameW(localhost,size)) or
  168. (WideCompareText(localhost,MachineName)<>0)) then
  169. flags:=CLSCTX_REMOTE_SERVER;
  170. {$endif}
  171. OleCheck(CoCreateInstanceEx(ClassID,nil,flags,@server,1,@mqi));
  172. OleCheck(mqi.hr);
  173. Result:=mqi.itf;
  174. end;
  175. function CreateOleObject(const ClassName : string) : IDispatch;
  176. var
  177. id : TCLSID;
  178. begin
  179. id:=ProgIDToClassID(ClassName);
  180. OleCheck(CoCreateInstance(id,nil,CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,IDispatch,result));
  181. end;
  182. function GetActiveOleObject(const ClassName : string) : IDispatch;
  183. var
  184. intf : IUnknown;
  185. id : TCLSID;
  186. begin
  187. id:=ProgIDToClassID(ClassName);
  188. OleCheck(GetActiveObject(id,nil,intf));
  189. OleCheck(intf.QueryInterface(IDispatch,Result));
  190. end;
  191. procedure OleError(Code: HResult);
  192. begin
  193. raise EOleSysError.Create('',Code,0);
  194. end;
  195. procedure OleCheck(Value : HResult);inline;
  196. begin
  197. if not(Succeeded(Value)) then
  198. OleError(Value);
  199. end;
  200. function ProgIDToClassID(const id : string) : TGUID;
  201. begin
  202. OleCheck(CLSIDFromProgID(PWideChar(WideString(id)),result));
  203. end;
  204. procedure SafeCallErrorHandler(err : HResult;addr : pointer);
  205. var
  206. info : IErrorInfo;
  207. descr,src,helpfile : widestring;
  208. helpctx : DWORD;
  209. begin
  210. if GetErrorInfo(0,info)=S_OK then
  211. begin
  212. info.GetDescription(descr);
  213. info.GetSource(src);
  214. info.GetHelpFile(helpfile);
  215. info.GetHelpContext(helpctx);
  216. raise EOleException.Create(descr,err,src,helpfile,helpctx) at addr;
  217. end
  218. else
  219. raise EOleException.Create('',err,'','',0) at addr;
  220. end;
  221. procedure DispatchInvokeError(Status: HRESULT; const ExceptInfo: TExcepInfo);
  222. begin
  223. if Status=DISP_E_EXCEPTION then
  224. raise EOleException.Create(ExceptInfo.Description,ExceptInfo.scode,ExceptInfo.Source,
  225. ExceptInfo.HelpFile,ExceptInfo.dwHelpContext)
  226. else
  227. raise EOleSysError.Create('',Status,0);
  228. end;
  229. { $define DEBUG_COMDISPATCH}
  230. procedure DispatchInvoke(const Dispatch: IDispatch; CallDesc: PCallDesc;
  231. DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  232. var
  233. { we can't pass pascal ansistrings to COM routines so we've to convert them
  234. to/from widestring. This array contains the mapping to do so
  235. }
  236. StringMap : array[0..255] of record passtr : pansistring; comstr : pwidechar; end;
  237. invokekind,
  238. i : longint;
  239. invokeresult : HResult;
  240. exceptioninfo : TExcepInfo;
  241. dispparams : TDispParams;
  242. NextString : SizeInt;
  243. Arguments : array[0..255] of TVarData;
  244. CurrType : byte;
  245. MethodID : TDispID;
  246. begin
  247. NextString:=0;
  248. fillchar(dispparams,sizeof(dispparams),0);
  249. try
  250. {$ifdef DEBUG_COMDISPATCH}
  251. writeln('DispatchInvoke: Got ',CallDesc^.ArgCount,' arguments NamedArgs = ',CallDesc^.NamedArgCount);
  252. {$endif DEBUG_COMDISPATCH}
  253. { copy and prepare arguments }
  254. for i:=0 to CallDesc^.ArgCount-1 do
  255. begin
  256. {$ifdef DEBUG_COMDISPATCH}
  257. writeln('DispatchInvoke: Params = ',hexstr(PtrInt(Params),SizeOf(Pointer)*2));
  258. {$endif DEBUG_COMDISPATCH}
  259. { get plain type }
  260. CurrType:=CallDesc^.ArgTypes[i] and $3f;
  261. { by reference? }
  262. if (CallDesc^.ArgTypes[i] and $80)<>0 then
  263. begin
  264. case CurrType of
  265. varStrArg:
  266. begin
  267. {$ifdef DEBUG_COMDISPATCH}
  268. writeln('Translating var ansistring argument ',PString(Params^)^);
  269. {$endif DEBUG_COMDISPATCH}
  270. StringMap[NextString].ComStr:=StringToOleStr(PString(Params^)^);
  271. StringMap[NextString].PasStr:=PString(Params^);
  272. Arguments[i].VType:=varOleStr or varByRef;
  273. Arguments[i].VPointer:=StringMap[NextString].ComStr;
  274. inc(NextString);
  275. inc(PPointer(Params));
  276. end;
  277. varVariant:
  278. begin
  279. {$ifdef DEBUG_COMDISPATCH}
  280. writeln('Got ref. variant containing type: ',PVarData(PPointer(Params)^)^.VType);
  281. {$endif DEBUG_COMDISPATCH}
  282. if PVarData(PPointer(Params)^)^.VType=varString then
  283. begin
  284. {$ifdef DEBUG_COMDISPATCH}
  285. writeln(' Casting nested varString: ',Ansistring(PVarData(Params^)^.vString));
  286. {$endif DEBUG_COMDISPATCH}
  287. VarCast(PVariant(Params^)^,PVariant(Params^)^,varOleStr);
  288. end;
  289. Arguments[i].VType:=varVariant or varByRef;
  290. Arguments[i].VPointer:=PPointer(Params)^;
  291. inc(PPointer(Params));
  292. end
  293. else
  294. begin
  295. {$ifdef DEBUG_COMDISPATCH}
  296. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  297. case CurrType of
  298. varOleStr:
  299. write(' Value = ',pwidestring(PPointer(Params)^)^);
  300. end;
  301. writeln;
  302. {$endif DEBUG_COMDISPATCH}
  303. Arguments[i].VType:=CurrType or VarByRef;
  304. Arguments[i].VPointer:=PPointer(Params)^;
  305. inc(PPointer(Params));
  306. end;
  307. end
  308. end
  309. else
  310. case CurrType of
  311. varStrArg:
  312. begin
  313. {$ifdef DEBUG_COMDISPATCH}
  314. writeln('Translating ansistring argument ',PString(Params)^);
  315. {$endif DEBUG_COMDISPATCH}
  316. StringMap[NextString].ComStr:=StringToOleStr(PString(Params)^);
  317. StringMap[NextString].PasStr:=nil;
  318. Arguments[i].VType:=varOleStr;
  319. Arguments[i].VPointer:=StringMap[NextString].ComStr;
  320. inc(NextString);
  321. inc(PPointer(Params));
  322. end;
  323. varVariant:
  324. begin
  325. {$ifdef DEBUG_COMDISPATCH}
  326. writeln('Unimplemented variant dispatch');
  327. {$endif DEBUG_COMDISPATCH}
  328. end;
  329. varCurrency,
  330. varDouble,
  331. VarDate:
  332. begin
  333. {$ifdef DEBUG_COMDISPATCH}
  334. writeln('Got 8 byte float argument');
  335. {$endif DEBUG_COMDISPATCH}
  336. Arguments[i].VType:=CurrType;
  337. move(PPointer(Params)^,Arguments[i].VDouble,sizeof(Double));
  338. inc(PDouble(Params));
  339. end;
  340. else
  341. begin
  342. {$ifdef DEBUG_COMDISPATCH}
  343. write('DispatchInvoke: Got argument with type ',CurrType);
  344. case CurrType of
  345. varOleStr:
  346. write(' Value = ',pwidestring(Params)^);
  347. else
  348. write(' Value = ',hexstr(PtrInt(PPointer(Params)^),SizeOf(Pointer)*2));
  349. end;
  350. writeln;
  351. {$endif DEBUG_COMDISPATCH}
  352. Arguments[i].VType:=CurrType;
  353. Arguments[i].VPointer:=PPointer(Params)^;
  354. inc(PPointer(Params));
  355. end;
  356. end;
  357. end;
  358. { finally prepare the call }
  359. with DispParams do
  360. begin
  361. rgvarg:=@Arguments;
  362. cNamedArgs:=CallDesc^.NamedArgCount;
  363. if cNamedArgs=0 then
  364. rgdispidNamedArgs:=nil
  365. else
  366. rgdispidNamedArgs:=@DispIDs^[1];
  367. cArgs:=CallDesc^.ArgCount;
  368. end;
  369. InvokeKind:=CallDesc^.CallType;
  370. MethodID:=DispIDs^[0];
  371. {$ifdef DEBUG_COMDISPATCH}
  372. writeln('DispatchInvoke: MethodID: ',MethodID,' InvokeKind: ',InvokeKind);
  373. {$endif DEBUG_COMDISPATCH}
  374. { do the call and check the result }
  375. invokeresult:=Dispatch.Invoke(MethodID,GUID_NULL,0,InvokeKind,DispParams,result,@exceptioninfo,nil);
  376. if invokeresult<>0 then
  377. DispatchInvokeError(invokeresult,exceptioninfo);
  378. { translate strings back }
  379. for i:=0 to NextString-1 do
  380. if assigned(StringMap[i].passtr) then
  381. OleStrToStrVar(StringMap[i].comstr,StringMap[i].passtr^);
  382. finally
  383. for i:=0 to NextString-1 do
  384. SysFreeString(StringMap[i].ComStr);
  385. end;
  386. end;
  387. procedure SearchIDs(const DispatchInterface : IDispatch; Names: PChar;
  388. Count: Integer; IDs: PDispIDList);
  389. var
  390. res : HRESULT;
  391. NamesArray : ^PWideChar;
  392. NamesData : PWideChar;
  393. OrigNames : PChar;
  394. NameCount,
  395. NameLen,
  396. NewNameLen,
  397. CurrentNameDataUsed,
  398. CurrentNameDataSize : SizeInt;
  399. i : longint;
  400. begin
  401. getmem(NamesArray,Count*sizeof(PWideChar));
  402. CurrentNameDataSize:=256;
  403. CurrentNameDataUsed:=0;
  404. getmem(NamesData,CurrentNameDataSize);
  405. NameCount:=0;
  406. OrigNames:=Names;
  407. {$ifdef DEBUG_COMDISPATCH}
  408. writeln('SearchIDs: Searching ',Count,' IDs');
  409. {$endif DEBUG_COMDISPATCH}
  410. for i:=1 to Count do
  411. begin
  412. NameLen:=strlen(Names);
  413. {$ifdef DEBUG_COMDISPATCH}
  414. writeln('SearchIDs: Original name: ',Names,' Len: ',NameLen);
  415. {$endif DEBUG_COMDISPATCH}
  416. NewNameLen:=MultiByteToWideChar(0,0,Names,NameLen,nil,0)+1;
  417. if (CurrentNameDataUsed+NewNameLen)*2>CurrentNameDataSize then
  418. begin
  419. inc(CurrentNameDataSize,256);
  420. reallocmem(NamesData,CurrentNameDataSize);
  421. end;
  422. NamesArray[i-1]:=@NamesData[CurrentNameDataUsed];
  423. MultiByteToWideChar(0,0,Names,NameLen,@NamesData[CurrentNameDataUsed],NewNameLen);
  424. NamesData[CurrentNameDataUsed+NewNameLen-1]:=#0;
  425. {$ifdef DEBUG_COMDISPATCH}
  426. writeln('SearchIDs: Translated name: ',WideString(PWideChar(@NamesData[CurrentNameDataUsed])));
  427. {$endif DEBUG_COMDISPATCH}
  428. inc(CurrentNameDataUsed,NewNameLen);
  429. inc(Names,NameLen+1);
  430. inc(NameCount);
  431. end;
  432. res:=DispatchInterface.GetIDsOfNames(GUID_NULL,NamesArray,NameCount,
  433. {$ifdef wince}
  434. LOCALE_SYSTEM_DEFAULT
  435. {$else wince}
  436. GetThreadLocale
  437. {$endif wince}
  438. ,IDs);
  439. {$ifdef DEBUG_COMDISPATCH}
  440. writeln('SearchIDs: GetIDsOfNames result = ',hexstr(res,SizeOf(HRESULT)*2));
  441. for i:=0 to Count-1 do
  442. writeln('SearchIDs: ID[',i,'] = ',ids^[i]);
  443. {$endif DEBUG_COMDISPATCH}
  444. if res=DISP_E_UNKNOWNNAME then
  445. raise EOleError.createresfmt(@snomethod,[OrigNames])
  446. else
  447. OleCheck(res);
  448. freemem(NamesArray);
  449. freemem(NamesData);
  450. end;
  451. procedure ComObjDispatchInvoke(dest : PVariant;const source : Variant;
  452. calldesc : pcalldesc;params : pointer);cdecl;
  453. var
  454. dispatchinterface : pointer;
  455. ids : array[0..255] of TDispID;
  456. begin
  457. fillchar(ids,sizeof(ids),0);
  458. {$ifdef DEBUG_COMDISPATCH}
  459. writeln('ComObjDispatchInvoke called');
  460. writeln('ComObjDispatchInvoke: @CallDesc = $',hexstr(PtrInt(CallDesc),SizeOf(Pointer)*2),' CallDesc^.ArgCount = ',CallDesc^.ArgCount);
  461. {$endif DEBUG_COMDISPATCH}
  462. if tvardata(source).vtype=VarDispatch then
  463. dispatchinterface:=tvardata(source).vdispatch
  464. else if tvardata(source).vtype=(VarDispatch or VarByRef) then
  465. dispatchinterface:=pvardata(tvardata(source).vpointer)^.vdispatch
  466. else
  467. raise eoleerror.createres(@SVarNotObject);
  468. SearchIDs(IDispatch(dispatchinterface),@CallDesc^.ArgTypes[CallDesc^.ArgCount],
  469. CallDesc^.NamedArgCount+1,@ids);
  470. if assigned(dest) then
  471. VarClear(dest^);
  472. DispatchInvoke(IDispatch(dispatchinterface),calldesc,@ids,params,dest);
  473. end;
  474. { $define DEBUG_DISPATCH}
  475. procedure DoDispCallByID(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  476. var
  477. exceptioninfo : TExcepInfo;
  478. dispparams : TDispParams;
  479. flags : WORD;
  480. invokeresult : HRESULT;
  481. preallocateddata : array[0..15] of TVarData;
  482. Arguments : ^TVarData;
  483. NamedArguments : PPointer;
  484. CurrType : byte;
  485. namedcount,i : byte;
  486. begin
  487. { use preallocated space, i.e. can we avoid a getmem call? }
  488. if desc^.calldesc.argcount<=Length(preallocateddata) then
  489. Arguments:=@preallocateddata
  490. else
  491. GetMem(Arguments,desc^.calldesc.argcount*sizeof(TVarData));
  492. { prepare parameters }
  493. for i:=0 to desc^.CallDesc.ArgCount-1 do
  494. begin
  495. {$ifdef DEBUG_DISPATCH}
  496. writeln('DoDispCallByID: Params = ',hexstr(PtrInt(Params),SizeOf(Pointer)*2));
  497. {$endif DEBUG_DISPATCH}
  498. { get plain type }
  499. CurrType:=desc^.CallDesc.ArgTypes[i] and $3f;
  500. { by reference? }
  501. if (desc^.CallDesc.ArgTypes[i] and $80)<>0 then
  502. begin
  503. {$ifdef DEBUG_DISPATCH}
  504. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  505. writeln;
  506. {$endif DEBUG_DISPATCH}
  507. Arguments[i].VType:=CurrType or VarByRef;
  508. Arguments[i].VPointer:=PPointer(Params)^;
  509. inc(PPointer(Params));
  510. end
  511. else
  512. begin
  513. {$ifdef DEBUG_DISPATCH}
  514. writeln('DispatchInvoke: Got ref argument with type = ',CurrType);
  515. {$endif DEBUG_DISPATCH}
  516. case CurrType of
  517. varVariant:
  518. begin
  519. Arguments[i].VType:=CurrType;
  520. move(PVarData(Params)^,Arguments[i],sizeof(TVarData));
  521. inc(PVarData(Params));
  522. end;
  523. varCurrency,
  524. varDouble,
  525. VarDate:
  526. begin
  527. {$ifdef DEBUG_DISPATCH}
  528. writeln('DispatchInvoke: Got 8 byte float argument');
  529. {$endif DEBUG_DISPATCH}
  530. Arguments[i].VType:=CurrType;
  531. move(PPointer(Params)^,Arguments[i].VDouble,sizeof(Double));
  532. inc(PDouble(Params));
  533. end;
  534. else
  535. begin
  536. {$ifdef DEBUG_DISPATCH}
  537. writeln('DispatchInvoke: Got argument with type ',CurrType);
  538. {$endif DEBUG_DISPATCH}
  539. Arguments[i].VType:=CurrType;
  540. Arguments[i].VPointer:=PPointer(Params)^;
  541. inc(PPointer(Params));
  542. end;
  543. end;
  544. end;
  545. end;
  546. dispparams.cArgs:=desc^.calldesc.argcount;
  547. dispparams.rgvarg:=pointer(Arguments);
  548. { handle properties properly here ! }
  549. namedcount:=desc^.calldesc.namedargcount;
  550. if desc^.calldesc.calltype=DISPATCH_PROPERTYPUT then
  551. inc(namedcount)
  552. else
  553. NamedArguments:=@desc^.CallDesc.ArgTypes[desc^.CallDesc.ArgCount];
  554. dispparams.cNamedArgs:=namedcount;
  555. dispparams.rgdispidNamedArgs:=pointer(NamedArguments);
  556. flags:=0;
  557. invokeresult:=disp.Invoke(
  558. desc^.DispId, { DispID: LongInt; }
  559. GUID_NULL, { const iid : TGUID; }
  560. 0, { LocaleID : longint; }
  561. flags, { Flags: Word; }
  562. dispparams, { var params; }
  563. res,@exceptioninfo,nil { VarResult,ExcepInfo,ArgErr : pointer) }
  564. );
  565. if invokeresult<>0 then
  566. DispatchInvokeError(invokeresult,exceptioninfo);
  567. if desc^.calldesc.argcount>Length(preallocateddata) then
  568. FreeMem(Arguments);
  569. end;
  570. const
  571. Initialized : boolean = false;
  572. var
  573. Ole32Dll : HModule;
  574. initialization
  575. Ole32Dll:=GetModuleHandle('ole32.dll');
  576. if Ole32Dll<>0 then
  577. begin
  578. Pointer(CoCreateInstanceEx):=GetProcAddress(Ole32Dll,'CoCreateInstanceExProc');
  579. Pointer(CoInitializeEx):=GetProcAddress(Ole32Dll,'CoInitializeExProc');
  580. Pointer(CoAddRefServerProcess):=GetProcAddress(Ole32Dll,'CoAddRefServerProcessProc');
  581. Pointer(CoReleaseServerProcess):=GetProcAddress(Ole32Dll,'CoReleaseServerProcessProc');
  582. Pointer(CoResumeClassObjects):=GetProcAddress(Ole32Dll,'CoResumeClassObjectsProc');
  583. Pointer(CoSuspendClassObjects):=GetProcAddress(Ole32Dll,'CoSuspendClassObjectsProc');
  584. end;
  585. if not(IsLibrary) then
  586. Initialized:=Succeeded(CoInitialize(nil));
  587. SafeCallErrorProc:=@SafeCallErrorHandler;
  588. VarDispProc:=@ComObjDispatchInvoke;
  589. DispCallByIDProc:=@DoDispCallByID;
  590. finalization
  591. VarDispProc:=nil;
  592. SafeCallErrorProc:=nil;
  593. if Initialized then
  594. CoUninitialize;
  595. end.