comobj.pp 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  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. case InvokeKind of
  669. DISPATCH_PROPERTYPUT:
  670. begin
  671. { !! FIXME}
  672. end;
  673. DISPATCH_METHOD:
  674. if assigned(Result) and (CallDesc^.ArgCount=0) then
  675. InvokeKind:=DISPATCH_METHOD or DISPATCH_PROPERTYGET;
  676. end;
  677. {$ifdef DEBUG_COMDISPATCH}
  678. writeln('DispatchInvoke: MethodID: ',MethodID,' InvokeKind: ',InvokeKind);
  679. {$endif DEBUG_COMDISPATCH}
  680. { do the call and check the result }
  681. invokeresult:=Dispatch.Invoke(MethodID,GUID_NULL,0,InvokeKind,DispParams,result,@exceptioninfo,nil);
  682. if invokeresult<>0 then
  683. DispatchInvokeError(invokeresult,exceptioninfo);
  684. { translate strings back }
  685. for i:=0 to NextString-1 do
  686. if assigned(StringMap[i].passtr) then
  687. OleStrToStrVar(StringMap[i].comstr,StringMap[i].passtr^);
  688. finally
  689. for i:=0 to NextString-1 do
  690. SysFreeString(StringMap[i].ComStr);
  691. end;
  692. end;
  693. procedure SearchIDs(const DispatchInterface : IDispatch; Names: PChar;
  694. Count: Integer; IDs: PDispIDList);
  695. var
  696. res : HRESULT;
  697. NamesArray : ^PWideChar;
  698. NamesData : PWideChar;
  699. OrigNames : PChar;
  700. NameCount,
  701. NameLen,
  702. NewNameLen,
  703. CurrentNameDataUsed,
  704. CurrentNameDataSize : SizeInt;
  705. i : longint;
  706. begin
  707. getmem(NamesArray,Count*sizeof(PWideChar));
  708. CurrentNameDataSize:=256;
  709. CurrentNameDataUsed:=0;
  710. getmem(NamesData,CurrentNameDataSize);
  711. NameCount:=0;
  712. OrigNames:=Names;
  713. {$ifdef DEBUG_COMDISPATCH}
  714. writeln('SearchIDs: Searching ',Count,' IDs');
  715. {$endif DEBUG_COMDISPATCH}
  716. for i:=1 to Count do
  717. begin
  718. NameLen:=strlen(Names);
  719. {$ifdef DEBUG_COMDISPATCH}
  720. writeln('SearchIDs: Original name: ',Names,' Len: ',NameLen);
  721. {$endif DEBUG_COMDISPATCH}
  722. NewNameLen:=MultiByteToWideChar(0,0,Names,NameLen,nil,0)+1;
  723. if (CurrentNameDataUsed+NewNameLen)*2>CurrentNameDataSize then
  724. begin
  725. inc(CurrentNameDataSize,256);
  726. reallocmem(NamesData,CurrentNameDataSize);
  727. end;
  728. NamesArray[i-1]:=@NamesData[CurrentNameDataUsed];
  729. MultiByteToWideChar(0,0,Names,NameLen,@NamesData[CurrentNameDataUsed],NewNameLen);
  730. NamesData[CurrentNameDataUsed+NewNameLen-1]:=#0;
  731. {$ifdef DEBUG_COMDISPATCH}
  732. writeln('SearchIDs: Translated name: ',WideString(PWideChar(@NamesData[CurrentNameDataUsed])));
  733. {$endif DEBUG_COMDISPATCH}
  734. inc(CurrentNameDataUsed,NewNameLen);
  735. inc(Names,NameLen+1);
  736. inc(NameCount);
  737. end;
  738. res:=DispatchInterface.GetIDsOfNames(GUID_NULL,NamesArray,NameCount,
  739. {$ifdef wince}
  740. LOCALE_SYSTEM_DEFAULT
  741. {$else wince}
  742. GetThreadLocale
  743. {$endif wince}
  744. ,IDs);
  745. {$ifdef DEBUG_COMDISPATCH}
  746. writeln('SearchIDs: GetIDsOfNames result = ',hexstr(res,SizeOf(HRESULT)*2));
  747. for i:=0 to Count-1 do
  748. writeln('SearchIDs: ID[',i,'] = ',ids^[i]);
  749. {$endif DEBUG_COMDISPATCH}
  750. if res=DISP_E_UNKNOWNNAME then
  751. raise EOleError.createresfmt(@snomethod,[OrigNames])
  752. else
  753. OleCheck(res);
  754. freemem(NamesArray);
  755. freemem(NamesData);
  756. end;
  757. procedure ComObjDispatchInvoke(dest : PVariant;const source : Variant;
  758. calldesc : pcalldesc;params : pointer);cdecl;
  759. var
  760. dispatchinterface : pointer;
  761. ids : array[0..255] of TDispID;
  762. begin
  763. fillchar(ids,sizeof(ids),0);
  764. {$ifdef DEBUG_COMDISPATCH}
  765. writeln('ComObjDispatchInvoke called');
  766. writeln('ComObjDispatchInvoke: @CallDesc = $',hexstr(PtrInt(CallDesc),SizeOf(Pointer)*2),' CallDesc^.ArgCount = ',CallDesc^.ArgCount);
  767. {$endif DEBUG_COMDISPATCH}
  768. if tvardata(source).vtype=VarDispatch then
  769. dispatchinterface:=tvardata(source).vdispatch
  770. else if tvardata(source).vtype=(VarDispatch or VarByRef) then
  771. dispatchinterface:=pvardata(tvardata(source).vpointer)^.vdispatch
  772. else
  773. raise eoleerror.createres(@SVarNotObject);
  774. SearchIDs(IDispatch(dispatchinterface),@CallDesc^.ArgTypes[CallDesc^.ArgCount],
  775. CallDesc^.NamedArgCount+1,@ids);
  776. if assigned(dest) then
  777. VarClear(dest^);
  778. DispatchInvoke(IDispatch(dispatchinterface),calldesc,@ids,params,dest);
  779. end;
  780. { $define DEBUG_DISPATCH}
  781. procedure DoDispCallByID(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  782. var
  783. exceptioninfo : TExcepInfo;
  784. dispparams : TDispParams;
  785. flags : WORD;
  786. invokeresult : HRESULT;
  787. preallocateddata : array[0..15] of TVarData;
  788. Arguments : ^TVarData;
  789. NamedArguments : PPointer;
  790. CurrType : byte;
  791. namedcount,i : byte;
  792. begin
  793. { use preallocated space, i.e. can we avoid a getmem call? }
  794. if desc^.calldesc.argcount<=Length(preallocateddata) then
  795. Arguments:=@preallocateddata
  796. else
  797. GetMem(Arguments,desc^.calldesc.argcount*sizeof(TVarData));
  798. { prepare parameters }
  799. for i:=0 to desc^.CallDesc.ArgCount-1 do
  800. begin
  801. {$ifdef DEBUG_DISPATCH}
  802. writeln('DoDispCallByID: Params = ',hexstr(PtrInt(Params),SizeOf(Pointer)*2));
  803. {$endif DEBUG_DISPATCH}
  804. { get plain type }
  805. CurrType:=desc^.CallDesc.ArgTypes[i] and $3f;
  806. { by reference? }
  807. if (desc^.CallDesc.ArgTypes[i] and $80)<>0 then
  808. begin
  809. {$ifdef DEBUG_DISPATCH}
  810. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  811. writeln;
  812. {$endif DEBUG_DISPATCH}
  813. Arguments[i].VType:=CurrType or VarByRef;
  814. Arguments[i].VPointer:=PPointer(Params)^;
  815. inc(PPointer(Params));
  816. end
  817. else
  818. begin
  819. {$ifdef DEBUG_DISPATCH}
  820. writeln('DispatchInvoke: Got ref argument with type = ',CurrType);
  821. {$endif DEBUG_DISPATCH}
  822. case CurrType of
  823. varVariant:
  824. begin
  825. Arguments[i].VType:=CurrType;
  826. move(PVarData(Params)^,Arguments[i],sizeof(TVarData));
  827. inc(PVarData(Params));
  828. end;
  829. varCurrency,
  830. varDouble,
  831. VarDate:
  832. begin
  833. {$ifdef DEBUG_DISPATCH}
  834. writeln('DispatchInvoke: Got 8 byte float argument');
  835. {$endif DEBUG_DISPATCH}
  836. Arguments[i].VType:=CurrType;
  837. move(PPointer(Params)^,Arguments[i].VDouble,sizeof(Double));
  838. inc(PDouble(Params));
  839. end;
  840. else
  841. begin
  842. {$ifdef DEBUG_DISPATCH}
  843. writeln('DispatchInvoke: Got argument with type ',CurrType);
  844. {$endif DEBUG_DISPATCH}
  845. Arguments[i].VType:=CurrType;
  846. Arguments[i].VPointer:=PPointer(Params)^;
  847. inc(PPointer(Params));
  848. end;
  849. end;
  850. end;
  851. end;
  852. dispparams.cArgs:=desc^.calldesc.argcount;
  853. dispparams.rgvarg:=pointer(Arguments);
  854. { handle properties properly here ! }
  855. namedcount:=desc^.calldesc.namedargcount;
  856. if desc^.calldesc.calltype=DISPATCH_PROPERTYPUT then
  857. inc(namedcount)
  858. else
  859. NamedArguments:=@desc^.CallDesc.ArgTypes[desc^.CallDesc.ArgCount];
  860. dispparams.cNamedArgs:=namedcount;
  861. dispparams.rgdispidNamedArgs:=pointer(NamedArguments);
  862. flags:=0;
  863. invokeresult:=disp.Invoke(
  864. desc^.DispId, { DispID: LongInt; }
  865. GUID_NULL, { const iid : TGUID; }
  866. 0, { LocaleID : longint; }
  867. flags, { Flags: Word; }
  868. dispparams, { var params; }
  869. res,@exceptioninfo,nil { VarResult,ExcepInfo,ArgErr : pointer) }
  870. );
  871. if invokeresult<>0 then
  872. DispatchInvokeError(invokeresult,exceptioninfo);
  873. if desc^.calldesc.argcount>Length(preallocateddata) then
  874. FreeMem(Arguments);
  875. end;
  876. const
  877. Initialized : boolean = false;
  878. var
  879. Ole32Dll : HModule;
  880. initialization
  881. Uninitializing:=false;
  882. _ComClassManager:=nil;
  883. Ole32Dll:=GetModuleHandle('ole32.dll');
  884. if Ole32Dll<>0 then
  885. begin
  886. Pointer(CoCreateInstanceEx):=GetProcAddress(Ole32Dll,'CoCreateInstanceExProc');
  887. Pointer(CoInitializeEx):=GetProcAddress(Ole32Dll,'CoInitializeExProc');
  888. Pointer(CoAddRefServerProcess):=GetProcAddress(Ole32Dll,'CoAddRefServerProcessProc');
  889. Pointer(CoReleaseServerProcess):=GetProcAddress(Ole32Dll,'CoReleaseServerProcessProc');
  890. Pointer(CoResumeClassObjects):=GetProcAddress(Ole32Dll,'CoResumeClassObjectsProc');
  891. Pointer(CoSuspendClassObjects):=GetProcAddress(Ole32Dll,'CoSuspendClassObjectsProc');
  892. end;
  893. if not(IsLibrary) then
  894. Initialized:=Succeeded(CoInitialize(nil));
  895. SafeCallErrorProc:=@SafeCallErrorHandler;
  896. VarDispProc:=@ComObjDispatchInvoke;
  897. DispCallByIDProc:=@DoDispCallByID;
  898. finalization
  899. Uninitializing:=true;
  900. _ComClassManager.Free;
  901. VarDispProc:=nil;
  902. SafeCallErrorProc:=nil;
  903. if Initialized then
  904. CoUninitialize;
  905. end.