comobj.pp 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  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. TComObjectFactory = class;
  57. TFactoryProc = procedure(Factory: TComObjectFactory) of object;
  58. TComClassManager = class(TObject)
  59. constructor Create;
  60. destructor Destroy; override;
  61. procedure ForEachFactory(ComServer: TComServerObject; FactoryProc: TFactoryProc);
  62. function GetFactoryFromClass(ComClass: TClass): TComObjectFactory;
  63. function GetFactoryFromClassID(const ClassID: TGUID): TComObjectFactory;
  64. end;
  65. IServerExceptionHandler = interface
  66. ['{6A8D432B-EB81-11D1-AAB1-00C04FB16FBC}']
  67. procedure OnException(const ServerClass, ExceptionClass, ErrorMessage: WideString;
  68. ExceptAddr: PtrInt; const ErrorIID, ProgID: WideString; var Handled: Integer; var Result: HResult); dispid 2;
  69. end;
  70. TComObject = class(TObject, IUnknown, ISupportErrorInfo)
  71. private
  72. FController : Pointer;
  73. FFactory : TComObjectFactory;
  74. FRefCount : Integer;
  75. FServerExceptionHandler : IServerExceptionHandler;
  76. FCounted : Boolean;
  77. function GetController : IUnknown;
  78. protected
  79. { IUnknown }
  80. function IUnknown.QueryInterface = ObjQueryInterface;
  81. function IUnknown._AddRef = ObjAddRef;
  82. function IUnknown._Release = ObjRelease;
  83. { IUnknown methods for other interfaces }
  84. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  85. function _AddRef: Integer; stdcall;
  86. function _Release: Integer; stdcall;
  87. { ISupportErrorInfo }
  88. function InterfaceSupportsErrorInfo(const iid: TIID): HResult; stdcall;
  89. public
  90. constructor Create;
  91. constructor CreateAggregated(const Controller: IUnknown);
  92. constructor CreateFromFactory(Factory: TComObjectFactory; const Controller: IUnknown);
  93. destructor Destroy; override;
  94. procedure Initialize; virtual;
  95. function ObjAddRef: Integer; virtual; stdcall;
  96. function ObjQueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
  97. function ObjRelease: Integer; virtual; stdcall;
  98. function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; override;
  99. property Controller: IUnknown read GetController;
  100. property Factory: TComObjectFactory read FFactory;
  101. property RefCount: Integer read FRefCount;
  102. property ServerExceptionHandler: IServerExceptionHandler read FServerExceptionHandler write FServerExceptionHandler;
  103. end;
  104. TComClass = class of TComObject;
  105. TClassInstancing = (ciInternal, ciSingleInstance, ciMultiInstance);
  106. TThreadingModel = (tmSingle, tmApartment, tmFree, tmBoth, tmNeutral);
  107. TComObjectFactory = class(TObject, IUnknown, IClassFactory, IClassFactory2)
  108. private
  109. Next: TComObjectFactory;
  110. FComServer: TComServerObject;
  111. FComClass: TClass;
  112. FClassID: TGUID;
  113. FClassName: string;
  114. FDescription: string;
  115. FErrorIID: TGUID;
  116. FInstancing: TClassInstancing;
  117. FLicString: WideString;
  118. FRegister: Longint;
  119. FShowErrors: Boolean;
  120. FSupportsLicensing: Boolean;
  121. FThreadingModel: TThreadingModel;
  122. function GetProgID: string;
  123. protected
  124. { IUnknown }
  125. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  126. function _AddRef: Integer; stdcall;
  127. function _Release: Integer; stdcall;
  128. { IClassFactory }
  129. function CreateInstance(const UnkOuter: IUnknown; const IID: TGUID;
  130. out Obj): HResult; stdcall;
  131. function LockServer(fLock: BOOL): HResult; stdcall;
  132. { IClassFactory2 }
  133. function GetLicInfo(var licInfo: TLicInfo): HResult; stdcall;
  134. function RequestLicKey(dwResrved: DWORD; out bstrKey: WideString): HResult; stdcall;
  135. function CreateInstanceLic(const unkOuter: IUnknown; const unkReserved: IUnknown;
  136. const iid: TIID; const bstrKey: WideString; out vObject): HResult; stdcall;
  137. public
  138. constructor Create(ComServer: TComServerObject; ComClass: TComClass;
  139. const ClassID: TGUID; const Name, Description: string;
  140. Instancing: TClassInstancing; ThreadingModel: TThreadingModel = tmSingle);
  141. destructor Destroy; override;
  142. function CreateComObject(const Controller: IUnknown): TComObject; virtual;
  143. procedure RegisterClassObject;
  144. procedure UpdateRegistry(Register: Boolean); virtual;
  145. property ClassID: TGUID read FClassID;
  146. property ClassName: string read FClassName;
  147. property ComClass: TClass read FComClass;
  148. property ComServer: TComServerObject read FComServer;
  149. property Description: string read FDescription;
  150. property ErrorIID: TGUID read FErrorIID write FErrorIID;
  151. property LicString: WideString read FLicString write FLicString;
  152. property ProgID: string read GetProgID;
  153. property Instancing: TClassInstancing read FInstancing;
  154. property ShowErrors: Boolean read FShowErrors write FShowErrors;
  155. property SupportsLicensing: Boolean read FSupportsLicensing write FSupportsLicensing;
  156. property ThreadingModel: TThreadingModel read FThreadingModel;
  157. end;
  158. function CreateClassID : ansistring;
  159. function CreateComObject(const ClassID: TGUID) : IUnknown;
  160. function CreateRemoteComObject(const MachineName : WideString;const ClassID : TGUID) : IUnknown;
  161. function CreateOleObject(const ClassName : string) : IDispatch;
  162. function GetActiveOleObject(const ClassName: string) : IDispatch;
  163. procedure OleCheck(Value : HResult);inline;
  164. procedure OleError(Code: HResult);
  165. function ProgIDToClassID(const id : string) : TGUID;
  166. procedure DispatchInvoke(const Dispatch: IDispatch; CallDesc: PCallDesc;
  167. DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  168. procedure DispatchInvokeError(Status: HRESULT; const ExceptInfo: TExcepInfo);
  169. function HandleSafeCallException(ExceptObject: TObject; ExceptAddr: Pointer; const ErrorIID: TGUID; const ProgID,
  170. HelpFileName: WideString): HResult;
  171. function ComClassManager : TComClassManager;
  172. type
  173. TCoCreateInstanceExProc = function(const clsid: TCLSID; unkOuter: IUnknown; dwClsCtx: DWORD; ServerInfo: PCoServerInfo;
  174. dwCount: ULONG; rgmqResults: PMultiQIArray): HResult stdcall;
  175. TCoInitializeExProc = function (pvReserved: Pointer;
  176. coInit: DWORD): HResult; stdcall;
  177. TCoAddRefServerProcessProc = function : ULONG; stdcall;
  178. TCoReleaseServerProcessProc = function : ULONG; stdcall;
  179. TCoResumeClassObjectsProc = function : HResult; stdcall;
  180. TCoSuspendClassObjectsProc = function : HResult; stdcall;
  181. const
  182. CoCreateInstanceEx : TCoCreateInstanceExProc = nil;
  183. CoInitializeEx : TCoInitializeExProc = nil;
  184. CoAddRefServerProcess : TCoAddRefServerProcessProc = nil;
  185. CoReleaseServerProcess : TCoReleaseServerProcessProc = nil;
  186. CoResumeClassObjects : TCoResumeClassObjectsProc = nil;
  187. CoSuspendClassObjects : TCoSuspendClassObjectsProc = nil;
  188. implementation
  189. uses
  190. ComConst,Ole2;
  191. var
  192. Uninitializing : boolean;
  193. function HandleSafeCallException(ExceptObject: TObject; ExceptAddr: Pointer; const ErrorIID: TGUID; const ProgID,
  194. HelpFileName: WideString): HResult;
  195. var
  196. _CreateErrorInfo : ICreateErrorInfo;
  197. ErrorInfo : IErrorInfo;
  198. begin
  199. Result:=E_UNEXPECTED;
  200. if Succeeded(CreateErrorInfo(_CreateErrorInfo)) then
  201. begin
  202. _CreateErrorInfo.SetGUID(ErrorIID);
  203. if ProgID<>'' then
  204. _CreateErrorInfo.SetSource(PWidechar(ProgID));
  205. if HelpFileName<>'' then
  206. _CreateErrorInfo.SetHelpFile(PWidechar(HelpFileName));
  207. if ExceptObject is Exception then
  208. begin
  209. _CreateErrorInfo.SetDescription(PWidechar(Widestring(Exception(ExceptObject).Message)));
  210. _CreateErrorInfo.SetHelpContext(Exception(ExceptObject).HelpContext);
  211. if (ExceptObject is EOleSyserror) and (EOleSysError(ExceptObject).ErrorCode<0) then
  212. Result:=EOleSysError(ExceptObject).ErrorCode
  213. end;
  214. if _CreateErrorInfo.QueryInterface(IErrorInfo,ErrorInfo)=S_OK then
  215. SetErrorInfo(0,ErrorInfo);
  216. end;
  217. end;
  218. constructor EOleSysError.Create(const Msg: string; aErrorCode: HRESULT; aHelpContext: Integer);
  219. var
  220. m : string;
  221. begin
  222. if Msg='' then
  223. m:=SysErrorMessage(aErrorCode)
  224. else
  225. m:=Msg;
  226. inherited CreateHelp(m,HelpContext);
  227. FErrorCode:=aErrorCode;
  228. end;
  229. constructor EOleException.Create(const Msg: string; aErrorCode: HRESULT;const aSource,aHelpFile: string; aHelpContext: Integer);
  230. begin
  231. inherited Create(Msg,aErrorCode,aHelpContext);
  232. FHelpFile:=aHelpFile;
  233. FSource:=aSource;
  234. end;
  235. {$define FPC_COMOBJ_HAS_CREATE_CLASS_ID}
  236. function CreateClassID : ansistring;
  237. var
  238. ClassID : TCLSID;
  239. p : PWideChar;
  240. begin
  241. CoCreateGuid(ClassID);
  242. StringFromCLSID(ClassID,p);
  243. result:=p;
  244. CoTaskMemFree(p);
  245. end;
  246. function CreateComObject(const ClassID : TGUID) : IUnknown;
  247. begin
  248. OleCheck(CoCreateInstance(ClassID,nil,CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,IUnknown,result));
  249. end;
  250. function CreateRemoteComObject(const MachineName : WideString;const ClassID : TGUID) : IUnknown;
  251. var
  252. flags : DWORD;
  253. localhost : array[0..MAX_COMPUTERNAME_LENGTH] of WideChar;
  254. server : TCoServerInfo;
  255. mqi : TMultiQI;
  256. size : DWORD;
  257. begin
  258. if not(assigned(CoCreateInstanceEx)) then
  259. raise Exception.CreateRes(@SDCOMNotInstalled);
  260. FillChar(server,sizeof(server),0);
  261. server.pwszName:=PWideChar(MachineName);
  262. FillChar(mqi,sizeof(mqi),0);
  263. mqi.iid:=@IID_IUnknown;
  264. flags:=CLSCTX_LOCAL_SERVER or CLSCTX_REMOTE_SERVER or CLSCTX_INPROC_SERVER;
  265. { actually a remote call? }
  266. {$ifndef wince}
  267. //roozbeh although there is a way to retrive computer name...HKLM\Ident\Name..but are they same?
  268. size:=sizeof(localhost);
  269. if (MachineName<>'') and
  270. (not(GetComputerNameW(localhost,size)) or
  271. (WideCompareText(localhost,MachineName)<>0)) then
  272. flags:=CLSCTX_REMOTE_SERVER;
  273. {$endif}
  274. OleCheck(CoCreateInstanceEx(ClassID,nil,flags,@server,1,@mqi));
  275. OleCheck(mqi.hr);
  276. Result:=mqi.itf;
  277. end;
  278. function CreateOleObject(const ClassName : string) : IDispatch;
  279. var
  280. id : TCLSID;
  281. begin
  282. id:=ProgIDToClassID(ClassName);
  283. OleCheck(CoCreateInstance(id,nil,CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,IDispatch,result));
  284. end;
  285. function GetActiveOleObject(const ClassName : string) : IDispatch;
  286. var
  287. intf : IUnknown;
  288. id : TCLSID;
  289. begin
  290. id:=ProgIDToClassID(ClassName);
  291. OleCheck(GetActiveObject(id,nil,intf));
  292. OleCheck(intf.QueryInterface(IDispatch,Result));
  293. end;
  294. procedure OleError(Code: HResult);
  295. begin
  296. raise EOleSysError.Create('',Code,0);
  297. end;
  298. procedure OleCheck(Value : HResult);inline;
  299. begin
  300. if not(Succeeded(Value)) then
  301. OleError(Value);
  302. end;
  303. function ProgIDToClassID(const id : string) : TGUID;
  304. begin
  305. OleCheck(CLSIDFromProgID(PWideChar(WideString(id)),result));
  306. end;
  307. procedure SafeCallErrorHandler(err : HResult;addr : pointer);
  308. var
  309. info : IErrorInfo;
  310. descr,src,helpfile : widestring;
  311. helpctx : DWORD;
  312. begin
  313. if GetErrorInfo(0,info)=S_OK then
  314. begin
  315. info.GetDescription(descr);
  316. info.GetSource(src);
  317. info.GetHelpFile(helpfile);
  318. info.GetHelpContext(helpctx);
  319. raise EOleException.Create(descr,err,src,helpfile,helpctx) at addr;
  320. end
  321. else
  322. raise EOleException.Create('',err,'','',0) at addr;
  323. end;
  324. procedure DispatchInvokeError(Status: HRESULT; const ExceptInfo: TExcepInfo);
  325. begin
  326. if Status=DISP_E_EXCEPTION then
  327. raise EOleException.Create(ExceptInfo.Description,ExceptInfo.scode,ExceptInfo.Source,
  328. ExceptInfo.HelpFile,ExceptInfo.dwHelpContext)
  329. else
  330. raise EOleSysError.Create('',Status,0);
  331. end;
  332. var
  333. _ComClassManager : TComClassManager;
  334. function ComClassManager: TComClassManager;
  335. begin
  336. if not(assigned(_ComClassManager)) then
  337. _ComClassManager:=TComClassManager.Create;
  338. Result:=_ComClassManager;
  339. end;
  340. constructor TComClassManager.Create;
  341. begin
  342. RunError(217);
  343. end;
  344. destructor TComClassManager.Destroy;
  345. begin
  346. RunError(217);
  347. end;
  348. procedure TComClassManager.ForEachFactory(ComServer: TComServerObject;
  349. FactoryProc: TFactoryProc);
  350. begin
  351. RunError(217);
  352. end;
  353. function TComClassManager.GetFactoryFromClass(ComClass: TClass
  354. ): TComObjectFactory;
  355. begin
  356. RunError(217);
  357. end;
  358. function TComClassManager.GetFactoryFromClassID(const ClassID: TGUID
  359. ): TComObjectFactory;
  360. begin
  361. RunError(217);
  362. end;
  363. function TComObject.GetController: IUnknown;
  364. begin
  365. Result:=IUnknown(Controller);
  366. end;
  367. function TComObject.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  368. begin
  369. if assigned(FController) then
  370. Result:=IUnknown(FController).QueryInterface(IID,Obj)
  371. else
  372. Result:=ObjQueryInterface(IID,Obj);
  373. end;
  374. function TComObject._AddRef: Integer; stdcall;
  375. begin
  376. if assigned(FController) then
  377. Result:=IUnknown(FController)._AddRef
  378. else
  379. Result:=ObjAddRef;
  380. end;
  381. function TComObject._Release: Integer; stdcall;
  382. begin
  383. if assigned(FController) then
  384. Result:=IUnknown(FController)._Release
  385. else
  386. Result:=ObjRelease;
  387. end;
  388. function TComObject.InterfaceSupportsErrorInfo(const iid: TIID): HResult; stdcall;
  389. begin
  390. if assigned(GetInterfaceEntry(iid)) then
  391. Result:=S_OK
  392. else
  393. Result:=S_FALSE;
  394. end;
  395. constructor TComObject.Create;
  396. begin
  397. CreateFromFactory(ComClassManager.GetFactoryFromClass(ClassType),nil);
  398. end;
  399. constructor TComObject.CreateAggregated(const Controller: IUnknown);
  400. begin
  401. CreateFromFactory(ComClassManager.GetFactoryFromClass(ClassType),Controller);
  402. end;
  403. constructor TComObject.CreateFromFactory(Factory: TComObjectFactory;
  404. const Controller: IUnknown);
  405. begin
  406. FFactory:=Factory;
  407. FRefCount:=1;
  408. FController:=Pointer(Controller);
  409. FFactory.Comserver.CountObject(True);
  410. FCounted:=true;
  411. Initialize;
  412. Dec(FRefCount);
  413. end;
  414. destructor TComObject.Destroy;
  415. begin
  416. if not(Uninitializing) then
  417. begin
  418. if assigned(FFactory) and FCounted then
  419. FFactory.Comserver.CountObject(false);
  420. if FRefCount>0 then
  421. CoDisconnectObject(Self,0);
  422. end;
  423. end;
  424. procedure TComObject.Initialize;
  425. begin
  426. end;
  427. function TComObject.ObjAddRef: Integer; stdcall;
  428. begin
  429. Result:=InterlockedIncrement(FRefCount);
  430. end;
  431. function TComObject.ObjQueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  432. begin
  433. if GetInterface(IID,Obj) then
  434. Result:=S_OK
  435. else
  436. Result:=E_NOINTERFACE;
  437. end;
  438. function TComObject.ObjRelease: Integer; stdcall;
  439. begin
  440. Result:=InterlockedDecrement(FRefCount);
  441. if Result=0 then
  442. Self.Destroy;
  443. end;
  444. function TComObject.SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult;
  445. var
  446. Message: string;
  447. Handled: Integer;
  448. begin
  449. Handled:=0;
  450. Result:=0;
  451. if assigned(ServerExceptionHandler) then
  452. begin
  453. if ExceptObject is Exception then
  454. Message:=Exception(ExceptObject).Message;
  455. ServerExceptionHandler.OnException(ClassName,ExceptObject.ClassName,
  456. Message,PtrInt(ExceptAddr),WideString(GUIDToString(FFactory.ErrorIID)),
  457. FFactory.ProgID,Handled,Result);
  458. end;
  459. if Handled=0 then
  460. Result:=HandleSafeCallException(ExceptObject,ExceptAddr,FFactory.ErrorIID,
  461. FFactory.ProgID,FFactory.ComServer.HelpFileName);
  462. end;
  463. function TComObjectFactory.GetProgID: string;
  464. begin
  465. RunError(217);
  466. end;
  467. function TComObjectFactory.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  468. begin
  469. RunError(217);
  470. end;
  471. function TComObjectFactory._AddRef: Integer; stdcall;
  472. begin
  473. RunError(217);
  474. end;
  475. function TComObjectFactory._Release: Integer; stdcall;
  476. begin
  477. RunError(217);
  478. end;
  479. function TComObjectFactory.CreateInstance(const UnkOuter: IUnknown;
  480. const IID: TGUID; out Obj): HResult; stdcall;
  481. begin
  482. RunError(217);
  483. end;
  484. function TComObjectFactory.LockServer(fLock: BOOL): HResult; stdcall;
  485. begin
  486. RunError(217);
  487. end;
  488. function TComObjectFactory.GetLicInfo(var licInfo: TLicInfo): HResult; stdcall;
  489. begin
  490. RunError(217);
  491. end;
  492. function TComObjectFactory.RequestLicKey(dwResrved: DWORD; out bstrKey: WideString): HResult; stdcall;
  493. begin
  494. RunError(217);
  495. end;
  496. function TComObjectFactory.CreateInstanceLic(const unkOuter: IUnknown;
  497. const unkReserved: IUnknown; const iid: TIID; const bstrKey: WideString; out
  498. vObject): HResult; stdcall;
  499. begin
  500. RunError(217);
  501. end;
  502. constructor TComObjectFactory.Create(ComServer: TComServerObject;
  503. ComClass: TComClass; const ClassID: TGUID; const Name,
  504. Description: string; Instancing: TClassInstancing;
  505. ThreadingModel: TThreadingModel);
  506. begin
  507. RunError(217);
  508. end;
  509. destructor TComObjectFactory.Destroy;
  510. begin
  511. RunError(217);
  512. end;
  513. function TComObjectFactory.CreateComObject(const Controller: IUnknown
  514. ): TComObject;
  515. begin
  516. RunError(217);
  517. end;
  518. procedure TComObjectFactory.RegisterClassObject;
  519. begin
  520. RunError(217);
  521. end;
  522. procedure TComObjectFactory.UpdateRegistry(Register: Boolean);
  523. begin
  524. RunError(217);
  525. end;
  526. { $define DEBUG_COMDISPATCH}
  527. procedure DispatchInvoke(const Dispatch: IDispatch; CallDesc: PCallDesc;
  528. DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  529. var
  530. { we can't pass pascal ansistrings to COM routines so we've to convert them
  531. to/from widestring. This array contains the mapping to do so
  532. }
  533. StringMap : array[0..255] of record passtr : pansistring; comstr : pwidechar; end;
  534. invokekind,
  535. i : longint;
  536. invokeresult : HResult;
  537. exceptioninfo : TExcepInfo;
  538. dispparams : TDispParams;
  539. NextString : SizeInt;
  540. Arguments : array[0..255] of TVarData;
  541. CurrType : byte;
  542. MethodID : TDispID;
  543. begin
  544. NextString:=0;
  545. fillchar(dispparams,sizeof(dispparams),0);
  546. try
  547. {$ifdef DEBUG_COMDISPATCH}
  548. writeln('DispatchInvoke: Got ',CallDesc^.ArgCount,' arguments NamedArgs = ',CallDesc^.NamedArgCount);
  549. {$endif DEBUG_COMDISPATCH}
  550. { copy and prepare arguments }
  551. for i:=0 to CallDesc^.ArgCount-1 do
  552. begin
  553. {$ifdef DEBUG_COMDISPATCH}
  554. writeln('DispatchInvoke: Params = ',hexstr(PtrInt(Params),SizeOf(Pointer)*2));
  555. {$endif DEBUG_COMDISPATCH}
  556. { get plain type }
  557. CurrType:=CallDesc^.ArgTypes[i] and $3f;
  558. { by reference? }
  559. if (CallDesc^.ArgTypes[i] and $80)<>0 then
  560. begin
  561. case CurrType of
  562. varStrArg:
  563. begin
  564. {$ifdef DEBUG_COMDISPATCH}
  565. writeln('Translating var ansistring argument ',PString(Params^)^);
  566. {$endif DEBUG_COMDISPATCH}
  567. StringMap[NextString].ComStr:=StringToOleStr(PString(Params^)^);
  568. StringMap[NextString].PasStr:=PString(Params^);
  569. Arguments[i].VType:=varOleStr or varByRef;
  570. Arguments[i].VPointer:=StringMap[NextString].ComStr;
  571. inc(NextString);
  572. inc(PPointer(Params));
  573. end;
  574. varVariant:
  575. begin
  576. {$ifdef DEBUG_COMDISPATCH}
  577. writeln('Got ref. variant containing type: ',PVarData(PPointer(Params)^)^.VType);
  578. {$endif DEBUG_COMDISPATCH}
  579. if PVarData(PPointer(Params)^)^.VType=varString then
  580. begin
  581. {$ifdef DEBUG_COMDISPATCH}
  582. writeln(' Casting nested varString: ',Ansistring(PVarData(Params^)^.vString));
  583. {$endif DEBUG_COMDISPATCH}
  584. VarCast(PVariant(Params^)^,PVariant(Params^)^,varOleStr);
  585. end;
  586. Arguments[i].VType:=varVariant or varByRef;
  587. Arguments[i].VPointer:=PPointer(Params)^;
  588. inc(PPointer(Params));
  589. end
  590. else
  591. begin
  592. {$ifdef DEBUG_COMDISPATCH}
  593. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  594. case CurrType of
  595. varOleStr:
  596. write(' Value = ',pwidestring(PPointer(Params)^)^);
  597. end;
  598. writeln;
  599. {$endif DEBUG_COMDISPATCH}
  600. Arguments[i].VType:=CurrType or VarByRef;
  601. Arguments[i].VPointer:=PPointer(Params)^;
  602. inc(PPointer(Params));
  603. end;
  604. end
  605. end
  606. else
  607. case CurrType of
  608. varStrArg:
  609. begin
  610. {$ifdef DEBUG_COMDISPATCH}
  611. writeln('Translating ansistring argument ',PString(Params)^);
  612. {$endif DEBUG_COMDISPATCH}
  613. StringMap[NextString].ComStr:=StringToOleStr(PString(Params)^);
  614. StringMap[NextString].PasStr:=nil;
  615. Arguments[i].VType:=varOleStr;
  616. Arguments[i].VPointer:=StringMap[NextString].ComStr;
  617. inc(NextString);
  618. inc(PPointer(Params));
  619. end;
  620. varVariant:
  621. begin
  622. {$ifdef DEBUG_COMDISPATCH}
  623. writeln('Unimplemented variant dispatch');
  624. {$endif DEBUG_COMDISPATCH}
  625. end;
  626. varCurrency,
  627. varDouble,
  628. VarDate:
  629. begin
  630. {$ifdef DEBUG_COMDISPATCH}
  631. writeln('Got 8 byte float argument');
  632. {$endif DEBUG_COMDISPATCH}
  633. Arguments[i].VType:=CurrType;
  634. move(PPointer(Params)^,Arguments[i].VDouble,sizeof(Double));
  635. inc(PDouble(Params));
  636. end;
  637. else
  638. begin
  639. {$ifdef DEBUG_COMDISPATCH}
  640. write('DispatchInvoke: Got argument with type ',CurrType);
  641. case CurrType of
  642. varOleStr:
  643. write(' Value = ',pwidestring(Params)^);
  644. else
  645. write(' Value = ',hexstr(PtrInt(PPointer(Params)^),SizeOf(Pointer)*2));
  646. end;
  647. writeln;
  648. {$endif DEBUG_COMDISPATCH}
  649. Arguments[i].VType:=CurrType;
  650. Arguments[i].VPointer:=PPointer(Params)^;
  651. inc(PPointer(Params));
  652. end;
  653. end;
  654. end;
  655. { finally prepare the call }
  656. with DispParams do
  657. begin
  658. rgvarg:=@Arguments;
  659. cNamedArgs:=CallDesc^.NamedArgCount;
  660. if cNamedArgs=0 then
  661. rgdispidNamedArgs:=nil
  662. else
  663. rgdispidNamedArgs:=@DispIDs^[1];
  664. cArgs:=CallDesc^.ArgCount;
  665. end;
  666. InvokeKind:=CallDesc^.CallType;
  667. MethodID:=DispIDs^[0];
  668. {$ifdef DEBUG_COMDISPATCH}
  669. writeln('DispatchInvoke: MethodID: ',MethodID,' InvokeKind: ',InvokeKind);
  670. {$endif DEBUG_COMDISPATCH}
  671. { do the call and check the result }
  672. invokeresult:=Dispatch.Invoke(MethodID,GUID_NULL,0,InvokeKind,DispParams,result,@exceptioninfo,nil);
  673. if invokeresult<>0 then
  674. DispatchInvokeError(invokeresult,exceptioninfo);
  675. { translate strings back }
  676. for i:=0 to NextString-1 do
  677. if assigned(StringMap[i].passtr) then
  678. OleStrToStrVar(StringMap[i].comstr,StringMap[i].passtr^);
  679. finally
  680. for i:=0 to NextString-1 do
  681. SysFreeString(StringMap[i].ComStr);
  682. end;
  683. end;
  684. procedure SearchIDs(const DispatchInterface : IDispatch; Names: PChar;
  685. Count: Integer; IDs: PDispIDList);
  686. var
  687. res : HRESULT;
  688. NamesArray : ^PWideChar;
  689. NamesData : PWideChar;
  690. OrigNames : PChar;
  691. NameCount,
  692. NameLen,
  693. NewNameLen,
  694. CurrentNameDataUsed,
  695. CurrentNameDataSize : SizeInt;
  696. i : longint;
  697. begin
  698. getmem(NamesArray,Count*sizeof(PWideChar));
  699. CurrentNameDataSize:=256;
  700. CurrentNameDataUsed:=0;
  701. getmem(NamesData,CurrentNameDataSize);
  702. NameCount:=0;
  703. OrigNames:=Names;
  704. {$ifdef DEBUG_COMDISPATCH}
  705. writeln('SearchIDs: Searching ',Count,' IDs');
  706. {$endif DEBUG_COMDISPATCH}
  707. for i:=1 to Count do
  708. begin
  709. NameLen:=strlen(Names);
  710. {$ifdef DEBUG_COMDISPATCH}
  711. writeln('SearchIDs: Original name: ',Names,' Len: ',NameLen);
  712. {$endif DEBUG_COMDISPATCH}
  713. NewNameLen:=MultiByteToWideChar(0,0,Names,NameLen,nil,0)+1;
  714. if (CurrentNameDataUsed+NewNameLen)*2>CurrentNameDataSize then
  715. begin
  716. inc(CurrentNameDataSize,256);
  717. reallocmem(NamesData,CurrentNameDataSize);
  718. end;
  719. NamesArray[i-1]:=@NamesData[CurrentNameDataUsed];
  720. MultiByteToWideChar(0,0,Names,NameLen,@NamesData[CurrentNameDataUsed],NewNameLen);
  721. NamesData[CurrentNameDataUsed+NewNameLen-1]:=#0;
  722. {$ifdef DEBUG_COMDISPATCH}
  723. writeln('SearchIDs: Translated name: ',WideString(PWideChar(@NamesData[CurrentNameDataUsed])));
  724. {$endif DEBUG_COMDISPATCH}
  725. inc(CurrentNameDataUsed,NewNameLen);
  726. inc(Names,NameLen+1);
  727. inc(NameCount);
  728. end;
  729. res:=DispatchInterface.GetIDsOfNames(GUID_NULL,NamesArray,NameCount,
  730. {$ifdef wince}
  731. LOCALE_SYSTEM_DEFAULT
  732. {$else wince}
  733. GetThreadLocale
  734. {$endif wince}
  735. ,IDs);
  736. {$ifdef DEBUG_COMDISPATCH}
  737. writeln('SearchIDs: GetIDsOfNames result = ',hexstr(res,SizeOf(HRESULT)*2));
  738. for i:=0 to Count-1 do
  739. writeln('SearchIDs: ID[',i,'] = ',ids^[i]);
  740. {$endif DEBUG_COMDISPATCH}
  741. if res=DISP_E_UNKNOWNNAME then
  742. raise EOleError.createresfmt(@snomethod,[OrigNames])
  743. else
  744. OleCheck(res);
  745. freemem(NamesArray);
  746. freemem(NamesData);
  747. end;
  748. procedure ComObjDispatchInvoke(dest : PVariant;const source : Variant;
  749. calldesc : pcalldesc;params : pointer);cdecl;
  750. var
  751. dispatchinterface : pointer;
  752. ids : array[0..255] of TDispID;
  753. begin
  754. fillchar(ids,sizeof(ids),0);
  755. {$ifdef DEBUG_COMDISPATCH}
  756. writeln('ComObjDispatchInvoke called');
  757. writeln('ComObjDispatchInvoke: @CallDesc = $',hexstr(PtrInt(CallDesc),SizeOf(Pointer)*2),' CallDesc^.ArgCount = ',CallDesc^.ArgCount);
  758. {$endif DEBUG_COMDISPATCH}
  759. if tvardata(source).vtype=VarDispatch then
  760. dispatchinterface:=tvardata(source).vdispatch
  761. else if tvardata(source).vtype=(VarDispatch or VarByRef) then
  762. dispatchinterface:=pvardata(tvardata(source).vpointer)^.vdispatch
  763. else
  764. raise eoleerror.createres(@SVarNotObject);
  765. SearchIDs(IDispatch(dispatchinterface),@CallDesc^.ArgTypes[CallDesc^.ArgCount],
  766. CallDesc^.NamedArgCount+1,@ids);
  767. if assigned(dest) then
  768. VarClear(dest^);
  769. DispatchInvoke(IDispatch(dispatchinterface),calldesc,@ids,params,dest);
  770. end;
  771. { $define DEBUG_DISPATCH}
  772. procedure DoDispCallByID(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  773. var
  774. exceptioninfo : TExcepInfo;
  775. dispparams : TDispParams;
  776. flags : WORD;
  777. invokeresult : HRESULT;
  778. preallocateddata : array[0..15] of TVarData;
  779. Arguments : ^TVarData;
  780. NamedArguments : PPointer;
  781. CurrType : byte;
  782. namedcount,i : byte;
  783. begin
  784. { use preallocated space, i.e. can we avoid a getmem call? }
  785. if desc^.calldesc.argcount<=Length(preallocateddata) then
  786. Arguments:=@preallocateddata
  787. else
  788. GetMem(Arguments,desc^.calldesc.argcount*sizeof(TVarData));
  789. { prepare parameters }
  790. for i:=0 to desc^.CallDesc.ArgCount-1 do
  791. begin
  792. {$ifdef DEBUG_DISPATCH}
  793. writeln('DoDispCallByID: Params = ',hexstr(PtrInt(Params),SizeOf(Pointer)*2));
  794. {$endif DEBUG_DISPATCH}
  795. { get plain type }
  796. CurrType:=desc^.CallDesc.ArgTypes[i] and $3f;
  797. { by reference? }
  798. if (desc^.CallDesc.ArgTypes[i] and $80)<>0 then
  799. begin
  800. {$ifdef DEBUG_DISPATCH}
  801. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  802. writeln;
  803. {$endif DEBUG_DISPATCH}
  804. Arguments[i].VType:=CurrType or VarByRef;
  805. Arguments[i].VPointer:=PPointer(Params)^;
  806. inc(PPointer(Params));
  807. end
  808. else
  809. begin
  810. {$ifdef DEBUG_DISPATCH}
  811. writeln('DispatchInvoke: Got ref argument with type = ',CurrType);
  812. {$endif DEBUG_DISPATCH}
  813. case CurrType of
  814. varVariant:
  815. begin
  816. Arguments[i].VType:=CurrType;
  817. move(PVarData(Params)^,Arguments[i],sizeof(TVarData));
  818. inc(PVarData(Params));
  819. end;
  820. varCurrency,
  821. varDouble,
  822. VarDate:
  823. begin
  824. {$ifdef DEBUG_DISPATCH}
  825. writeln('DispatchInvoke: Got 8 byte float argument');
  826. {$endif DEBUG_DISPATCH}
  827. Arguments[i].VType:=CurrType;
  828. move(PPointer(Params)^,Arguments[i].VDouble,sizeof(Double));
  829. inc(PDouble(Params));
  830. end;
  831. else
  832. begin
  833. {$ifdef DEBUG_DISPATCH}
  834. writeln('DispatchInvoke: Got argument with type ',CurrType);
  835. {$endif DEBUG_DISPATCH}
  836. Arguments[i].VType:=CurrType;
  837. Arguments[i].VPointer:=PPointer(Params)^;
  838. inc(PPointer(Params));
  839. end;
  840. end;
  841. end;
  842. end;
  843. dispparams.cArgs:=desc^.calldesc.argcount;
  844. dispparams.rgvarg:=pointer(Arguments);
  845. { handle properties properly here ! }
  846. namedcount:=desc^.calldesc.namedargcount;
  847. if desc^.calldesc.calltype=DISPATCH_PROPERTYPUT then
  848. inc(namedcount)
  849. else
  850. NamedArguments:=@desc^.CallDesc.ArgTypes[desc^.CallDesc.ArgCount];
  851. dispparams.cNamedArgs:=namedcount;
  852. dispparams.rgdispidNamedArgs:=pointer(NamedArguments);
  853. flags:=0;
  854. invokeresult:=disp.Invoke(
  855. desc^.DispId, { DispID: LongInt; }
  856. GUID_NULL, { const iid : TGUID; }
  857. 0, { LocaleID : longint; }
  858. flags, { Flags: Word; }
  859. dispparams, { var params; }
  860. res,@exceptioninfo,nil { VarResult,ExcepInfo,ArgErr : pointer) }
  861. );
  862. if invokeresult<>0 then
  863. DispatchInvokeError(invokeresult,exceptioninfo);
  864. if desc^.calldesc.argcount>Length(preallocateddata) then
  865. FreeMem(Arguments);
  866. end;
  867. const
  868. Initialized : boolean = false;
  869. var
  870. Ole32Dll : HModule;
  871. initialization
  872. Uninitializing:=false;
  873. _ComClassManager:=nil;
  874. Ole32Dll:=GetModuleHandle('ole32.dll');
  875. if Ole32Dll<>0 then
  876. begin
  877. Pointer(CoCreateInstanceEx):=GetProcAddress(Ole32Dll,'CoCreateInstanceExProc');
  878. Pointer(CoInitializeEx):=GetProcAddress(Ole32Dll,'CoInitializeExProc');
  879. Pointer(CoAddRefServerProcess):=GetProcAddress(Ole32Dll,'CoAddRefServerProcessProc');
  880. Pointer(CoReleaseServerProcess):=GetProcAddress(Ole32Dll,'CoReleaseServerProcessProc');
  881. Pointer(CoResumeClassObjects):=GetProcAddress(Ole32Dll,'CoResumeClassObjectsProc');
  882. Pointer(CoSuspendClassObjects):=GetProcAddress(Ole32Dll,'CoSuspendClassObjectsProc');
  883. end;
  884. if not(IsLibrary) then
  885. Initialized:=Succeeded(CoInitialize(nil));
  886. SafeCallErrorProc:=@SafeCallErrorHandler;
  887. VarDispProc:=@ComObjDispatchInvoke;
  888. DispCallByIDProc:=@DoDispCallByID;
  889. finalization
  890. Uninitializing:=true;
  891. _ComClassManager.Free;
  892. VarDispProc:=nil;
  893. SafeCallErrorProc:=nil;
  894. if Initialized then
  895. CoUninitialize;
  896. end.