comobj.pp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321
  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. {define DEBUG_COM}
  17. uses
  18. Windows,Types,Variants,Sysutils,ActiveX,classes;
  19. type
  20. EOleError = class(Exception);
  21. EOleSysError = class(EOleError)
  22. private
  23. FErrorCode: HRESULT;
  24. public
  25. constructor Create(const Msg: string; aErrorCode: HRESULT;aHelpContext: Integer);
  26. property ErrorCode: HRESULT read FErrorCode write FErrorCode;
  27. end;
  28. EOleException = class(EOleSysError)
  29. private
  30. FHelpFile: string;
  31. FSource: string;
  32. public
  33. constructor Create(const Msg: string; aErrorCode: HRESULT;const aSource,aHelpFile: string;aHelpContext: Integer);
  34. property HelpFile: string read FHelpFile write FHelpFile;
  35. property Source: string read FSource write FSource;
  36. end;
  37. EOleRegistrationError = class(EOleError);
  38. TComServerObject = class(TObject)
  39. protected
  40. function CountObject(Created: Boolean): Integer; virtual; abstract;
  41. function CountFactory(Created: Boolean): Integer; virtual; abstract;
  42. function GetHelpFileName: string; virtual; abstract;
  43. function GetServerFileName: string; virtual; abstract;
  44. function GetServerKey: string; virtual; abstract;
  45. function GetServerName: string; virtual; abstract;
  46. function GetStartSuspended: Boolean; virtual; abstract;
  47. function GetTypeLib: ITypeLib; virtual; abstract;
  48. procedure SetHelpFileName(const Value: string); virtual; abstract;
  49. public
  50. property HelpFileName: string read GetHelpFileName write SetHelpFileName;
  51. property ServerFileName: string read GetServerFileName;
  52. property ServerKey: string read GetServerKey;
  53. property ServerName: string read GetServerName;
  54. property TypeLib: ITypeLib read GetTypeLib;
  55. property StartSuspended: Boolean read GetStartSuspended;
  56. end;
  57. TComObjectFactory = class;
  58. TFactoryProc = procedure(Factory: TComObjectFactory) of object;
  59. { TComClassManager }
  60. TComClassManager = class(TObject)
  61. private
  62. fClassFactoryList: TList;
  63. public
  64. constructor Create;
  65. destructor Destroy; override;
  66. procedure AddObjectFactory(factory: TComObjectFactory);
  67. procedure RemoveObjectFactory(factory: TComObjectFactory);
  68. procedure ForEachFactory(ComServer: TComServerObject; FactoryProc: TFactoryProc);
  69. function GetFactoryFromClass(ComClass: TClass): TComObjectFactory;
  70. function GetFactoryFromClassID(const ClassID: TGUID): TComObjectFactory;
  71. end;
  72. IServerExceptionHandler = interface
  73. ['{6A8D432B-EB81-11D1-AAB1-00C04FB16FBC}']
  74. procedure OnException(const ServerClass, ExceptionClass, ErrorMessage: WideString;
  75. ExceptAddr: PtrInt; const ErrorIID, ProgID: WideString; var Handled: Integer; var Result: HResult); dispid 2;
  76. end;
  77. TComObject = class(TObject, IUnknown, ISupportErrorInfo)
  78. private
  79. FController : Pointer;
  80. FFactory : TComObjectFactory;
  81. FRefCount : Integer;
  82. FServerExceptionHandler : IServerExceptionHandler;
  83. FCounted : Boolean;
  84. function GetController : IUnknown;
  85. protected
  86. { IUnknown }
  87. function IUnknown.QueryInterface = ObjQueryInterface;
  88. function IUnknown._AddRef = ObjAddRef;
  89. function IUnknown._Release = ObjRelease;
  90. { IUnknown methods for other interfaces }
  91. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  92. function _AddRef: Integer; stdcall;
  93. function _Release: Integer; stdcall;
  94. { ISupportErrorInfo }
  95. function InterfaceSupportsErrorInfo(const iid: TIID): HResult; stdcall;
  96. public
  97. constructor Create;
  98. constructor CreateAggregated(const Controller: IUnknown);
  99. constructor CreateFromFactory(Factory: TComObjectFactory; const Controller: IUnknown);
  100. destructor Destroy; override;
  101. procedure Initialize; virtual;
  102. function ObjAddRef: Integer; virtual; stdcall;
  103. function ObjQueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
  104. function ObjRelease: Integer; virtual; stdcall;
  105. function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; override;
  106. property Controller: IUnknown read GetController;
  107. property Factory: TComObjectFactory read FFactory;
  108. property RefCount: Integer read FRefCount;
  109. property ServerExceptionHandler: IServerExceptionHandler read FServerExceptionHandler write FServerExceptionHandler;
  110. end;
  111. TComClass = class of TComObject;
  112. TClassInstancing = (ciInternal, ciSingleInstance, ciMultiInstance);
  113. TThreadingModel = (tmSingle, tmApartment, tmFree, tmBoth, tmNeutral);
  114. TComObjectFactory = class(TObject, IUnknown, IClassFactory, IClassFactory2)
  115. private
  116. FRefCount : Integer;
  117. //Next: TComObjectFactory;
  118. FComServer: TComServerObject;
  119. FComClass: TClass;
  120. FClassID: TGUID;
  121. FClassName: string;
  122. FDescription: string;
  123. FErrorIID: TGUID;
  124. FInstancing: TClassInstancing;
  125. FLicString: WideString;
  126. //FRegister: Longint;
  127. FShowErrors: Boolean;
  128. FSupportsLicensing: Boolean;
  129. FThreadingModel: TThreadingModel;
  130. function GetProgID: string;
  131. protected
  132. { IUnknown }
  133. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  134. function _AddRef: Integer; stdcall;
  135. function _Release: Integer; stdcall;
  136. { IClassFactory }
  137. function CreateInstance(const UnkOuter: IUnknown; const IID: TGUID;
  138. out Obj): HResult; stdcall;
  139. function LockServer(fLock: BOOL): HResult; stdcall;
  140. { IClassFactory2 }
  141. function GetLicInfo(var licInfo: TLicInfo): HResult; stdcall;
  142. function RequestLicKey(dwResrved: DWORD; out bstrKey: WideString): HResult; stdcall;
  143. function CreateInstanceLic(const unkOuter: IUnknown; const unkReserved: IUnknown;
  144. const iid: TIID; const bstrKey: WideString; out vObject): HResult; stdcall;
  145. public
  146. constructor Create(ComServer: TComServerObject; ComClass: TComClass;
  147. const ClassID: TGUID; const Name, Description: string;
  148. Instancing: TClassInstancing; ThreadingModel: TThreadingModel = tmSingle);
  149. destructor Destroy; override;
  150. function CreateComObject(const Controller: IUnknown): TComObject; virtual;
  151. procedure RegisterClassObject;
  152. procedure UpdateRegistry(Register: Boolean); virtual;
  153. property ClassID: TGUID read FClassID;
  154. property ClassName: string read FClassName;
  155. property ComClass: TClass read FComClass;
  156. property ComServer: TComServerObject read FComServer;
  157. property Description: string read FDescription;
  158. property ErrorIID: TGUID read FErrorIID write FErrorIID;
  159. property LicString: WideString read FLicString write FLicString;
  160. property ProgID: string read GetProgID;
  161. property Instancing: TClassInstancing read FInstancing;
  162. property ShowErrors: Boolean read FShowErrors write FShowErrors;
  163. property SupportsLicensing: Boolean read FSupportsLicensing write FSupportsLicensing;
  164. property ThreadingModel: TThreadingModel read FThreadingModel;
  165. end;
  166. { TTypedComObject }
  167. TTypedComObject = class(TComObject, IProvideClassInfo)
  168. function GetClassInfo(out pptti : ITypeInfo):HResult; StdCall;
  169. end;
  170. TTypedComClass = class of TTypedComObject;
  171. { TTypedComObjectFactory }
  172. TTypedComObjectFactory = class(TComObjectFactory)
  173. private
  174. FClassInfo: ITypeInfo;
  175. public
  176. constructor Create(AComServer: TComServerObject; TypedComClass: TTypedComClass; const AClassID: TGUID;
  177. AInstancing: TClassInstancing; AThreadingModel: TThreadingModel = tmSingle);
  178. function GetInterfaceTypeInfo(TypeFlags: Integer) : ITypeInfo;
  179. procedure UpdateRegistry(Register: Boolean);override;
  180. property ClassInfo : ITypeInfo read FClassInfo;
  181. end;
  182. function CreateClassID : ansistring;
  183. function CreateComObject(const ClassID: TGUID) : IUnknown;
  184. function CreateRemoteComObject(const MachineName : WideString;const ClassID : TGUID) : IUnknown;
  185. function CreateOleObject(const ClassName : string) : IDispatch;
  186. function GetActiveOleObject(const ClassName: string) : IDispatch;
  187. procedure OleCheck(Value : HResult);inline;
  188. procedure OleError(Code: HResult);
  189. function ProgIDToClassID(const id : string) : TGUID;
  190. function ClassIDToProgID(const classID: TGUID): string;
  191. procedure DispatchInvoke(const Dispatch: IDispatch; CallDesc: PCallDesc;
  192. DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  193. procedure DispatchInvokeError(Status: HRESULT; const ExceptInfo: TExcepInfo);
  194. function HandleSafeCallException(ExceptObject: TObject; ExceptAddr: Pointer; const ErrorIID: TGUID; const ProgID,
  195. HelpFileName: WideString): HResult;
  196. function ComClassManager : TComClassManager;
  197. type
  198. TCoCreateInstanceExProc = function(const clsid: TCLSID; unkOuter: IUnknown; dwClsCtx: DWORD; ServerInfo: PCoServerInfo;
  199. dwCount: ULONG; rgmqResults: PMultiQIArray): HResult stdcall;
  200. TCoInitializeExProc = function (pvReserved: Pointer;
  201. coInit: DWORD): HResult; stdcall;
  202. TCoAddRefServerProcessProc = function : ULONG; stdcall;
  203. TCoReleaseServerProcessProc = function : ULONG; stdcall;
  204. TCoResumeClassObjectsProc = function : HResult; stdcall;
  205. TCoSuspendClassObjectsProc = function : HResult; stdcall;
  206. const
  207. CoCreateInstanceEx : TCoCreateInstanceExProc = nil;
  208. CoInitializeEx : TCoInitializeExProc = nil;
  209. CoAddRefServerProcess : TCoAddRefServerProcessProc = nil;
  210. CoReleaseServerProcess : TCoReleaseServerProcessProc = nil;
  211. CoResumeClassObjects : TCoResumeClassObjectsProc = nil;
  212. CoSuspendClassObjects : TCoSuspendClassObjectsProc = nil;
  213. CoInitFlags : Longint = -1;
  214. implementation
  215. uses
  216. ComConst,Ole2, Registry;
  217. var
  218. Uninitializing : boolean;
  219. function HandleSafeCallException(ExceptObject: TObject; ExceptAddr: Pointer; const ErrorIID: TGUID; const ProgID,
  220. HelpFileName: WideString): HResult;
  221. {$ifndef wince}
  222. var
  223. _CreateErrorInfo : ICreateErrorInfo;
  224. ErrorInfo : IErrorInfo;
  225. {$endif wince}
  226. begin
  227. Result:=E_UNEXPECTED;
  228. {$ifndef wince}
  229. if Succeeded(CreateErrorInfo(_CreateErrorInfo)) then
  230. begin
  231. _CreateErrorInfo.SetGUID(ErrorIID);
  232. if ProgID<>'' then
  233. _CreateErrorInfo.SetSource(PWidechar(ProgID));
  234. if HelpFileName<>'' then
  235. _CreateErrorInfo.SetHelpFile(PWidechar(HelpFileName));
  236. if ExceptObject is Exception then
  237. begin
  238. _CreateErrorInfo.SetDescription(PWidechar(Widestring(Exception(ExceptObject).Message)));
  239. _CreateErrorInfo.SetHelpContext(Exception(ExceptObject).HelpContext);
  240. if (ExceptObject is EOleSyserror) and (EOleSysError(ExceptObject).ErrorCode<0) then
  241. Result:=EOleSysError(ExceptObject).ErrorCode
  242. end;
  243. if _CreateErrorInfo.QueryInterface(IErrorInfo,ErrorInfo)=S_OK then
  244. SetErrorInfo(0,ErrorInfo);
  245. end;
  246. {$endif wince}
  247. end;
  248. constructor EOleSysError.Create(const Msg: string; aErrorCode: HRESULT; aHelpContext: Integer);
  249. var
  250. m : string;
  251. begin
  252. if Msg='' then
  253. m:=SysErrorMessage(aErrorCode)
  254. else
  255. m:=Msg;
  256. inherited CreateHelp(m,HelpContext);
  257. FErrorCode:=aErrorCode;
  258. end;
  259. constructor EOleException.Create(const Msg: string; aErrorCode: HRESULT;const aSource,aHelpFile: string; aHelpContext: Integer);
  260. begin
  261. inherited Create(Msg,aErrorCode,aHelpContext);
  262. FHelpFile:=aHelpFile;
  263. FSource:=aSource;
  264. end;
  265. {$define FPC_COMOBJ_HAS_CREATE_CLASS_ID}
  266. function CreateClassID : ansistring;
  267. var
  268. ClassID : TCLSID;
  269. p : PWideChar;
  270. begin
  271. CoCreateGuid(ClassID);
  272. StringFromCLSID(ClassID,p);
  273. result:=p;
  274. CoTaskMemFree(p);
  275. end;
  276. function CreateComObject(const ClassID : TGUID) : IUnknown;
  277. begin
  278. OleCheck(CoCreateInstance(ClassID,nil,CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,IUnknown,result));
  279. end;
  280. function CreateRemoteComObject(const MachineName : WideString;const ClassID : TGUID) : IUnknown;
  281. var
  282. flags : DWORD;
  283. localhost : array[0..MAX_COMPUTERNAME_LENGTH] of WideChar;
  284. server : TCoServerInfo;
  285. mqi : TMultiQI;
  286. size : DWORD;
  287. begin
  288. if not(assigned(CoCreateInstanceEx)) then
  289. raise Exception.CreateRes(@SDCOMNotInstalled);
  290. FillChar(server,sizeof(server),0);
  291. server.pwszName:=PWideChar(MachineName);
  292. FillChar(mqi,sizeof(mqi),0);
  293. mqi.iid:=@IID_IUnknown;
  294. flags:=CLSCTX_LOCAL_SERVER or CLSCTX_REMOTE_SERVER or CLSCTX_INPROC_SERVER;
  295. { actually a remote call? }
  296. {$ifndef wince}
  297. //roozbeh although there is a way to retrive computer name...HKLM\Ident\Name..but are they same?
  298. size:=sizeof(localhost);
  299. if (MachineName<>'') and
  300. (not(GetComputerNameW(localhost,size)) or
  301. (WideCompareText(localhost,MachineName)<>0)) then
  302. flags:=CLSCTX_REMOTE_SERVER;
  303. {$endif}
  304. OleCheck(CoCreateInstanceEx(ClassID,nil,flags,@server,1,@mqi));
  305. OleCheck(mqi.hr);
  306. Result:=mqi.itf;
  307. end;
  308. function CreateOleObject(const ClassName : string) : IDispatch;
  309. var
  310. id : TCLSID;
  311. begin
  312. id:=ProgIDToClassID(ClassName);
  313. OleCheck(CoCreateInstance(id,nil,CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,IDispatch,result));
  314. end;
  315. function GetActiveOleObject(const ClassName : string) : IDispatch;
  316. {$ifndef wince}
  317. var
  318. intf : IUnknown;
  319. id : TCLSID;
  320. begin
  321. id:=ProgIDToClassID(ClassName);
  322. OleCheck(GetActiveObject(id,nil,intf));
  323. OleCheck(intf.QueryInterface(IDispatch,Result));
  324. end;
  325. {$else}
  326. begin
  327. Result:=nil;
  328. end;
  329. {$endif wince}
  330. procedure OleError(Code: HResult);
  331. begin
  332. raise EOleSysError.Create('',Code,0);
  333. end;
  334. procedure OleCheck(Value : HResult);inline;
  335. begin
  336. if not(Succeeded(Value)) then
  337. OleError(Value);
  338. end;
  339. function ProgIDToClassID(const id : string) : TGUID;
  340. begin
  341. OleCheck(CLSIDFromProgID(PWideChar(WideString(id)),result));
  342. end;
  343. function ClassIDToProgID(const classID: TGUID): string;
  344. var
  345. progid : LPOLESTR;
  346. begin
  347. OleCheck(ProgIDFromCLSID(@classID,progid));
  348. result:=progid;
  349. CoTaskMemFree(progid);
  350. end;
  351. procedure SafeCallErrorHandler(err : HResult;addr : pointer);
  352. {$ifndef wince}
  353. var
  354. info : IErrorInfo;
  355. descr,src,helpfile : widestring;
  356. helpctx : DWORD;
  357. {$endif wince}
  358. begin
  359. {$ifndef wince}
  360. if GetErrorInfo(0,info)=S_OK then
  361. begin
  362. info.GetDescription(descr);
  363. info.GetSource(src);
  364. info.GetHelpFile(helpfile);
  365. info.GetHelpContext(helpctx);
  366. raise EOleException.Create(descr,err,src,helpfile,helpctx) at addr;
  367. end
  368. else
  369. {$endif wince}
  370. raise EOleException.Create('',err,'','',0) at addr;
  371. end;
  372. procedure DispatchInvokeError(Status: HRESULT; const ExceptInfo: TExcepInfo);
  373. begin
  374. if Status=DISP_E_EXCEPTION then
  375. raise EOleException.Create(ExceptInfo.Description,ExceptInfo.scode,ExceptInfo.Source,
  376. ExceptInfo.HelpFile,ExceptInfo.dwHelpContext)
  377. else
  378. raise EOleSysError.Create('',Status,0);
  379. end;
  380. var
  381. _ComClassManager : TComClassManager;
  382. function ComClassManager: TComClassManager;
  383. begin
  384. if not(assigned(_ComClassManager)) then
  385. _ComClassManager:=TComClassManager.Create;
  386. Result:=_ComClassManager;
  387. end;
  388. constructor TComClassManager.Create;
  389. begin
  390. fClassFactoryList := TList.create({true});
  391. end;
  392. destructor TComClassManager.Destroy;
  393. var i : integer;
  394. begin
  395. if fClassFactoryList.count>0 Then
  396. begin
  397. for i:=fClassFactoryList.count-1 downto 0 do
  398. tobject(fClassFactoryList[i]).Free;
  399. end;
  400. fClassFactoryList.Free;
  401. end;
  402. procedure TComClassManager.AddObjectFactory(factory: TComObjectFactory);
  403. begin
  404. {$ifdef DEBUG_COM}
  405. WriteLn('AddObjectFactory: ', GUIDToString(factory.FClassID), ' ', factory.FClassName);
  406. {$endif}
  407. fClassFactoryList.Add(factory);
  408. end;
  409. procedure TComClassManager.RemoveObjectFactory(
  410. factory: TComObjectFactory);
  411. begin
  412. fClassFactoryList.Remove(factory);
  413. end;
  414. procedure TComClassManager.ForEachFactory(ComServer: TComServerObject;
  415. FactoryProc: TFactoryProc);
  416. var
  417. i: Integer;
  418. obj: TComObjectFactory;
  419. begin
  420. {$ifdef DEBUG_COM}
  421. WriteLn('ForEachFactory');
  422. {$endif}
  423. for i := 0 to fClassFactoryList.Count - 1 do
  424. begin
  425. obj := TComObjectFactory(fClassFactoryList[i]);
  426. if obj.ComServer = ComServer then
  427. FactoryProc(obj);
  428. end;
  429. end;
  430. function TComClassManager.GetFactoryFromClass(ComClass: TClass
  431. ): TComObjectFactory;
  432. var
  433. i: Integer;
  434. begin
  435. {$ifdef DEBUG_COM}
  436. WriteLn('GetFactoryFromClass: ', ComClass.ClassName);
  437. {$endif}
  438. for i := 0 to fClassFactoryList.Count - 1 do
  439. begin
  440. Result := TComObjectFactory(fClassFactoryList[i]);
  441. if ComClass = Result.ComClass then
  442. Exit();
  443. end;
  444. Result := nil;
  445. end;
  446. function TComClassManager.GetFactoryFromClassID(const ClassID: TGUID
  447. ): TComObjectFactory;
  448. var
  449. i: Integer;
  450. begin
  451. {$ifdef DEBUG_COM}
  452. WriteLn('GetFactoryFromClassID: ', GUIDToString(ClassId));
  453. {$endif}
  454. for i := 0 to fClassFactoryList.Count - 1 do
  455. begin
  456. Result := TComObjectFactory(fClassFactoryList[i]);
  457. if IsEqualGUID(ClassID, Result.ClassID) then
  458. Exit();
  459. end;
  460. {$ifdef DEBUG_COM}
  461. WriteLn('GetFactoryFromClassID not found: ', GUIDToString(ClassId));
  462. {$endif}
  463. Result := nil;
  464. end;
  465. function TComObject.GetController: IUnknown;
  466. begin
  467. Result:=IUnknown(Controller);
  468. end;
  469. function TComObject.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  470. begin
  471. if assigned(FController) then
  472. Result:=IUnknown(FController).QueryInterface(IID,Obj)
  473. else
  474. Result:=ObjQueryInterface(IID,Obj);
  475. end;
  476. function TComObject._AddRef: Integer; stdcall;
  477. begin
  478. if assigned(FController) then
  479. Result:=IUnknown(FController)._AddRef
  480. else
  481. Result:=ObjAddRef;
  482. end;
  483. function TComObject._Release: Integer; stdcall;
  484. begin
  485. if assigned(FController) then
  486. Result:=IUnknown(FController)._Release
  487. else
  488. Result:=ObjRelease;
  489. end;
  490. function TComObject.InterfaceSupportsErrorInfo(const iid: TIID): HResult; stdcall;
  491. begin
  492. if assigned(GetInterfaceEntry(iid)) then
  493. Result:=S_OK
  494. else
  495. Result:=S_FALSE;
  496. end;
  497. constructor TComObject.Create;
  498. begin
  499. CreateFromFactory(ComClassManager.GetFactoryFromClass(ClassType),nil);
  500. end;
  501. constructor TComObject.CreateAggregated(const Controller: IUnknown);
  502. begin
  503. CreateFromFactory(ComClassManager.GetFactoryFromClass(ClassType),Controller);
  504. end;
  505. constructor TComObject.CreateFromFactory(Factory: TComObjectFactory;
  506. const Controller: IUnknown);
  507. begin
  508. FFactory:=Factory;
  509. FRefCount:=1;
  510. FController:=Pointer(Controller);
  511. FFactory.Comserver.CountObject(True);
  512. FCounted:=true;
  513. Initialize;
  514. Dec(FRefCount);
  515. end;
  516. destructor TComObject.Destroy;
  517. begin
  518. if not(Uninitializing) then
  519. begin
  520. if assigned(FFactory) and FCounted then
  521. FFactory.Comserver.CountObject(false);
  522. {$ifndef wince}
  523. if FRefCount>0 then
  524. CoDisconnectObject(Self,0);
  525. {$endif wince}
  526. end;
  527. end;
  528. procedure TComObject.Initialize;
  529. begin
  530. end;
  531. function TComObject.ObjAddRef: Integer; stdcall;
  532. begin
  533. Result:=InterlockedIncrement(FRefCount);
  534. end;
  535. function TComObject.ObjQueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  536. begin
  537. if GetInterface(IID,Obj) then
  538. Result:=S_OK
  539. else
  540. Result:=E_NOINTERFACE;
  541. end;
  542. function TComObject.ObjRelease: Integer; stdcall;
  543. begin
  544. Result:=InterlockedDecrement(FRefCount);
  545. if Result=0 then
  546. Self.Destroy;
  547. end;
  548. function TComObject.SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult;
  549. var
  550. Message: string;
  551. Handled: Integer;
  552. begin
  553. Handled:=0;
  554. Result:=0;
  555. if assigned(ServerExceptionHandler) then
  556. begin
  557. if ExceptObject is Exception then
  558. Message:=Exception(ExceptObject).Message;
  559. ServerExceptionHandler.OnException(ClassName,ExceptObject.ClassName,
  560. Message,PtrInt(ExceptAddr),WideString(GUIDToString(FFactory.ErrorIID)),
  561. FFactory.ProgID,Handled,Result);
  562. end;
  563. if Handled=0 then
  564. Result:=HandleSafeCallException(ExceptObject,ExceptAddr,FFactory.ErrorIID,
  565. FFactory.ProgID,FFactory.ComServer.HelpFileName);
  566. end;
  567. function TComObjectFactory.GetProgID: string;
  568. begin
  569. RunError(217);
  570. end;
  571. function TComObjectFactory.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  572. begin
  573. if GetInterface(IID,Obj) then
  574. Result:=S_OK
  575. else
  576. Result:=E_NOINTERFACE;
  577. end;
  578. function TComObjectFactory._AddRef: Integer; stdcall;
  579. begin
  580. Result:=InterlockedIncrement(FRefCount);
  581. end;
  582. function TComObjectFactory._Release: Integer; stdcall;
  583. begin
  584. Result:=InterlockedDecrement(FRefCount);
  585. if Result=0 then
  586. Self.Destroy;
  587. end;
  588. function TComObjectFactory.CreateInstance(const UnkOuter: IUnknown;
  589. const IID: TGUID; out Obj): HResult; stdcall;
  590. var
  591. comObject: TComObject;
  592. begin
  593. {$ifdef DEBUG_COM}
  594. WriteLn('CreateInstance: ', GUIDToString(IID));
  595. {$endif}
  596. comObject := CreateComObject(UnkOuter);
  597. if comObject.GetInterface(IID, Obj) then
  598. Result := S_OK
  599. else
  600. Result := E_NOINTERFACE;
  601. end;
  602. function TComObjectFactory.LockServer(fLock: BOOL): HResult; stdcall;
  603. begin
  604. {$ifdef DEBUG_COM}
  605. WriteLn('LockServer: ', fLock);
  606. {$endif}
  607. RunError(217);
  608. end;
  609. function TComObjectFactory.GetLicInfo(var licInfo: TLicInfo): HResult; stdcall;
  610. begin
  611. {$ifdef DEBUG_COM}
  612. WriteLn('GetLicInfo');
  613. {$endif}
  614. RunError(217);
  615. end;
  616. function TComObjectFactory.RequestLicKey(dwResrved: DWORD; out bstrKey: WideString): HResult; stdcall;
  617. begin
  618. {$ifdef DEBUG_COM}
  619. WriteLn('RequestLicKey');
  620. {$endif}
  621. RunError(217);
  622. end;
  623. function TComObjectFactory.CreateInstanceLic(const unkOuter: IUnknown;
  624. const unkReserved: IUnknown; const iid: TIID; const bstrKey: WideString; out
  625. vObject): HResult; stdcall;
  626. begin
  627. {$ifdef DEBUG_COM}
  628. WriteLn('CreateInstanceLic');
  629. {$endif}
  630. RunError(217);
  631. end;
  632. constructor TComObjectFactory.Create(ComServer: TComServerObject;
  633. ComClass: TComClass; const ClassID: TGUID; const Name,
  634. Description: string; Instancing: TClassInstancing;
  635. ThreadingModel: TThreadingModel);
  636. begin
  637. {$ifdef DEBUG_COM}
  638. WriteLn('TComObjectFactory.Create');
  639. {$endif}
  640. FRefCount := 1;
  641. FClassID := ClassID;
  642. FThreadingModel := ThreadingModel;
  643. FDescription := Description;
  644. FClassName := Name;
  645. FComServer := ComServer;
  646. FComClass := ComClass;
  647. FInstancing := Instancing;;
  648. ComClassManager.AddObjectFactory(Self);
  649. end;
  650. destructor TComObjectFactory.Destroy;
  651. begin
  652. ComClassManager.RemoveObjectFactory(Self);
  653. //RunError(217);
  654. end;
  655. function TComObjectFactory.CreateComObject(const Controller: IUnknown
  656. ): TComObject;
  657. begin
  658. {$ifdef DEBUG_COM}
  659. WriteLn('TComObjectFactory.CreateComObject');
  660. {$endif}
  661. Result := TComClass(FComClass).Create();
  662. end;
  663. procedure TComObjectFactory.RegisterClassObject;
  664. begin
  665. RunError(217);
  666. end;
  667. (* Copy from Sample.RGS (http://www.codeproject.com/KB/atl/RegistryMap.aspx)
  668. HKCR
  669. {
  670. %PROGID%.%VERSION% = s '%DESCRIPTION%'
  671. {
  672. CLSID = s '%CLSID%'
  673. }
  674. %PROGID% = s '%DESCRIPTION%'
  675. {
  676. CLSID = s '%CLSID%'
  677. CurVer = s '%PROGID%.%VERSION%'
  678. }
  679. NoRemove CLSID
  680. {
  681. ForceRemove %CLSID% = s '%DESCRIPTION%'
  682. {
  683. ProgID = s '%PROGID%.%VERSION%'
  684. VersionIndependentProgID = s '%PROGID%'
  685. ForceRemove 'Programmable'
  686. InprocServer32 = s '%MODULE%'
  687. {
  688. val ThreadingModel = s '%THREADING%'
  689. }
  690. 'TypeLib' = s '%LIBID%'
  691. }
  692. }
  693. }
  694. *)
  695. procedure TComObjectFactory.UpdateRegistry(Register: Boolean);
  696. var
  697. reg: TRegistry;
  698. begin
  699. RunError(217);
  700. //todo: finish this
  701. if Register then
  702. begin
  703. reg := TRegistry.Create;
  704. reg.RootKey := HKEY_CLASSES_ROOT;
  705. reg.OpenKey(FClassName + '.1', True);
  706. reg.WriteString('', Description);
  707. reg.WriteString('CLSID', GUIDToString(ClassID));
  708. reg.CloseKey;
  709. reg.OpenKey(FClassName, True);
  710. reg.WriteString('', Description);
  711. reg.WriteString('CLSID', GUIDToString(ClassID));
  712. reg.WriteString('CurVer', FClassName + '.1');
  713. reg.CloseKey;
  714. reg.OpenKey('CLSID\' + GUIDToString(ClassID), True);
  715. reg.WriteString('', Description);
  716. reg.WriteString('ProgID', FClassName);
  717. reg.WriteString('VersionIndependentProgID', FClassName);
  718. reg.WriteString('InprocServer32', 'MODULENAME');
  719. reg.CloseKey;
  720. reg.Free;
  721. end;
  722. //This should be in typedcomobject
  723. //reg.WriteString('TypeLib', FClassName);
  724. end;
  725. { $define DEBUG_COMDISPATCH}
  726. procedure DispatchInvoke(const Dispatch: IDispatch; CallDesc: PCallDesc;
  727. DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  728. var
  729. { we can't pass pascal ansistrings to COM routines so we've to convert them
  730. to/from widestring. This array contains the mapping to do so
  731. }
  732. StringMap : array[0..255] of record passtr : pansistring; comstr : pwidechar; end;
  733. invokekind,
  734. i : longint;
  735. invokeresult : HResult;
  736. exceptioninfo : TExcepInfo;
  737. dispparams : TDispParams;
  738. NextString : SizeInt;
  739. Arguments : array[0..255] of TVarData;
  740. CurrType : byte;
  741. MethodID : TDispID;
  742. begin
  743. NextString:=0;
  744. fillchar(dispparams,sizeof(dispparams),0);
  745. try
  746. {$ifdef DEBUG_COMDISPATCH}
  747. writeln('DispatchInvoke: Got ',CallDesc^.ArgCount,' arguments NamedArgs = ',CallDesc^.NamedArgCount);
  748. {$endif DEBUG_COMDISPATCH}
  749. { copy and prepare arguments }
  750. for i:=0 to CallDesc^.ArgCount-1 do
  751. begin
  752. {$ifdef DEBUG_COMDISPATCH}
  753. writeln('DispatchInvoke: Params = ',hexstr(PtrInt(Params),SizeOf(Pointer)*2));
  754. {$endif DEBUG_COMDISPATCH}
  755. { get plain type }
  756. CurrType:=CallDesc^.ArgTypes[i] and $3f;
  757. { by reference? }
  758. if (CallDesc^.ArgTypes[i] and $80)<>0 then
  759. begin
  760. case CurrType of
  761. varStrArg:
  762. begin
  763. {$ifdef DEBUG_COMDISPATCH}
  764. writeln('Translating var ansistring argument ',PString(Params^)^);
  765. {$endif DEBUG_COMDISPATCH}
  766. StringMap[NextString].ComStr:=StringToOleStr(PString(Params^)^);
  767. StringMap[NextString].PasStr:=PString(Params^);
  768. Arguments[i].VType:=varOleStr or varByRef;
  769. Arguments[i].VPointer:=StringMap[NextString].ComStr;
  770. inc(NextString);
  771. inc(PPointer(Params));
  772. end;
  773. varVariant:
  774. begin
  775. {$ifdef DEBUG_COMDISPATCH}
  776. writeln('Got ref. variant containing type: ',PVarData(PPointer(Params)^)^.VType);
  777. {$endif DEBUG_COMDISPATCH}
  778. if PVarData(PPointer(Params)^)^.VType=varString then
  779. begin
  780. {$ifdef DEBUG_COMDISPATCH}
  781. writeln(' Casting nested varString: ',Ansistring(PVarData(Params^)^.vString));
  782. {$endif DEBUG_COMDISPATCH}
  783. VarCast(PVariant(Params^)^,PVariant(Params^)^,varOleStr);
  784. end;
  785. Arguments[i].VType:=varVariant or varByRef;
  786. Arguments[i].VPointer:=PPointer(Params)^;
  787. inc(PPointer(Params));
  788. end
  789. else
  790. begin
  791. {$ifdef DEBUG_COMDISPATCH}
  792. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  793. case CurrType of
  794. varOleStr:
  795. write(' Value = ',pwidestring(PPointer(Params)^)^);
  796. end;
  797. writeln;
  798. {$endif DEBUG_COMDISPATCH}
  799. Arguments[i].VType:=CurrType or VarByRef;
  800. Arguments[i].VPointer:=PPointer(Params)^;
  801. inc(PPointer(Params));
  802. end;
  803. end
  804. end
  805. else
  806. case CurrType of
  807. varStrArg:
  808. begin
  809. {$ifdef DEBUG_COMDISPATCH}
  810. writeln('Translating ansistring argument ',PString(Params)^);
  811. {$endif DEBUG_COMDISPATCH}
  812. StringMap[NextString].ComStr:=StringToOleStr(PString(Params)^);
  813. StringMap[NextString].PasStr:=nil;
  814. Arguments[i].VType:=varOleStr;
  815. Arguments[i].VPointer:=StringMap[NextString].ComStr;
  816. inc(NextString);
  817. inc(PPointer(Params));
  818. end;
  819. varVariant:
  820. begin
  821. {$ifdef DEBUG_COMDISPATCH}
  822. writeln('Unimplemented variant dispatch');
  823. {$endif DEBUG_COMDISPATCH}
  824. end;
  825. varCurrency,
  826. varDouble,
  827. VarDate:
  828. begin
  829. {$ifdef DEBUG_COMDISPATCH}
  830. writeln('Got 8 byte float argument');
  831. {$endif DEBUG_COMDISPATCH}
  832. Arguments[i].VType:=CurrType;
  833. move(PPointer(Params)^,Arguments[i].VDouble,sizeof(Double));
  834. inc(PDouble(Params));
  835. end;
  836. else
  837. begin
  838. {$ifdef DEBUG_COMDISPATCH}
  839. write('DispatchInvoke: Got argument with type ',CurrType);
  840. case CurrType of
  841. varOleStr:
  842. write(' Value = ',pwidestring(Params)^);
  843. else
  844. write(' Value = ',hexstr(PtrInt(PPointer(Params)^),SizeOf(Pointer)*2));
  845. end;
  846. writeln;
  847. {$endif DEBUG_COMDISPATCH}
  848. Arguments[i].VType:=CurrType;
  849. Arguments[i].VPointer:=PPointer(Params)^;
  850. inc(PPointer(Params));
  851. end;
  852. end;
  853. end;
  854. { finally prepare the call }
  855. with DispParams do
  856. begin
  857. rgvarg:=@Arguments;
  858. cNamedArgs:=CallDesc^.NamedArgCount;
  859. if cNamedArgs=0 then
  860. rgdispidNamedArgs:=nil
  861. else
  862. rgdispidNamedArgs:=@DispIDs^[1];
  863. cArgs:=CallDesc^.ArgCount;
  864. end;
  865. InvokeKind:=CallDesc^.CallType;
  866. MethodID:=DispIDs^[0];
  867. case InvokeKind of
  868. DISPATCH_PROPERTYPUT:
  869. begin
  870. if (Arguments[0].VType and varTypeMask) = varDispatch then
  871. InvokeKind:=DISPATCH_PROPERTYPUTREF;
  872. { first name is actually the name of the property to set }
  873. DispIDs^[0]:=DISPID_PROPERTYPUT;
  874. DispParams.rgdispidNamedArgs:=@DispIDs^[0];
  875. inc(DispParams.cNamedArgs);
  876. end;
  877. DISPATCH_METHOD:
  878. if assigned(Result) and (CallDesc^.ArgCount=0) then
  879. InvokeKind:=DISPATCH_METHOD or DISPATCH_PROPERTYGET;
  880. end;
  881. {$ifdef DEBUG_COMDISPATCH}
  882. writeln('DispatchInvoke: MethodID: ',MethodID,' InvokeKind: ',InvokeKind);
  883. {$endif DEBUG_COMDISPATCH}
  884. { do the call and check the result }
  885. invokeresult:=Dispatch.Invoke(MethodID,GUID_NULL,0,InvokeKind,DispParams,result,@exceptioninfo,nil);
  886. if invokeresult<>0 then
  887. DispatchInvokeError(invokeresult,exceptioninfo);
  888. { translate strings back }
  889. for i:=0 to NextString-1 do
  890. if assigned(StringMap[i].passtr) then
  891. OleStrToStrVar(StringMap[i].comstr,StringMap[i].passtr^);
  892. finally
  893. for i:=0 to NextString-1 do
  894. SysFreeString(StringMap[i].ComStr);
  895. end;
  896. end;
  897. procedure SearchIDs(const DispatchInterface : IDispatch; Names: PChar;
  898. Count: Integer; IDs: PDispIDList);
  899. var
  900. res : HRESULT;
  901. NamesArray : ^PWideChar;
  902. NamesData : PWideChar;
  903. OrigNames : PChar;
  904. NameCount,
  905. NameLen,
  906. NewNameLen,
  907. CurrentNameDataUsed,
  908. CurrentNameDataSize : SizeInt;
  909. i : longint;
  910. begin
  911. getmem(NamesArray,Count*sizeof(PWideChar));
  912. CurrentNameDataSize:=256;
  913. CurrentNameDataUsed:=0;
  914. getmem(NamesData,CurrentNameDataSize);
  915. NameCount:=0;
  916. OrigNames:=Names;
  917. {$ifdef DEBUG_COMDISPATCH}
  918. writeln('SearchIDs: Searching ',Count,' IDs');
  919. {$endif DEBUG_COMDISPATCH}
  920. for i:=1 to Count do
  921. begin
  922. NameLen:=strlen(Names);
  923. {$ifdef DEBUG_COMDISPATCH}
  924. writeln('SearchIDs: Original name: ',Names,' Len: ',NameLen);
  925. {$endif DEBUG_COMDISPATCH}
  926. NewNameLen:=MultiByteToWideChar(0,0,Names,NameLen,nil,0)+1;
  927. if (CurrentNameDataUsed+NewNameLen)*2>CurrentNameDataSize then
  928. begin
  929. inc(CurrentNameDataSize,256);
  930. reallocmem(NamesData,CurrentNameDataSize);
  931. end;
  932. NamesArray[i-1]:=@NamesData[CurrentNameDataUsed];
  933. MultiByteToWideChar(0,0,Names,NameLen,@NamesData[CurrentNameDataUsed],NewNameLen);
  934. NamesData[CurrentNameDataUsed+NewNameLen-1]:=#0;
  935. {$ifdef DEBUG_COMDISPATCH}
  936. writeln('SearchIDs: Translated name: ',WideString(PWideChar(@NamesData[CurrentNameDataUsed])));
  937. {$endif DEBUG_COMDISPATCH}
  938. inc(CurrentNameDataUsed,NewNameLen);
  939. inc(Names,NameLen+1);
  940. inc(NameCount);
  941. end;
  942. res:=DispatchInterface.GetIDsOfNames(GUID_NULL,NamesArray,NameCount,
  943. {$ifdef wince}
  944. LOCALE_SYSTEM_DEFAULT
  945. {$else wince}
  946. GetThreadLocale
  947. {$endif wince}
  948. ,IDs);
  949. {$ifdef DEBUG_COMDISPATCH}
  950. writeln('SearchIDs: GetIDsOfNames result = ',hexstr(res,SizeOf(HRESULT)*2));
  951. for i:=0 to Count-1 do
  952. writeln('SearchIDs: ID[',i,'] = ',ids^[i]);
  953. {$endif DEBUG_COMDISPATCH}
  954. if res=DISP_E_UNKNOWNNAME then
  955. raise EOleError.createresfmt(@snomethod,[OrigNames])
  956. else
  957. OleCheck(res);
  958. freemem(NamesArray);
  959. freemem(NamesData);
  960. end;
  961. procedure ComObjDispatchInvoke(dest : PVariant;const source : Variant;
  962. calldesc : pcalldesc;params : pointer);cdecl;
  963. var
  964. dispatchinterface : pointer;
  965. ids : array[0..255] of TDispID;
  966. begin
  967. fillchar(ids,sizeof(ids),0);
  968. {$ifdef DEBUG_COMDISPATCH}
  969. writeln('ComObjDispatchInvoke called');
  970. writeln('ComObjDispatchInvoke: @CallDesc = $',hexstr(PtrInt(CallDesc),SizeOf(Pointer)*2),' CallDesc^.ArgCount = ',CallDesc^.ArgCount);
  971. {$endif DEBUG_COMDISPATCH}
  972. if tvardata(source).vtype=VarDispatch then
  973. dispatchinterface:=tvardata(source).vdispatch
  974. else if tvardata(source).vtype=(VarDispatch or VarByRef) then
  975. dispatchinterface:=pvardata(tvardata(source).vpointer)^.vdispatch
  976. else
  977. raise eoleerror.createres(@SVarNotObject);
  978. SearchIDs(IDispatch(dispatchinterface),@CallDesc^.ArgTypes[CallDesc^.ArgCount],
  979. CallDesc^.NamedArgCount+1,@ids);
  980. if assigned(dest) then
  981. VarClear(dest^);
  982. DispatchInvoke(IDispatch(dispatchinterface),calldesc,@ids,params,dest);
  983. end;
  984. { $define DEBUG_DISPATCH}
  985. procedure DoDispCallByID(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  986. var
  987. exceptioninfo : TExcepInfo;
  988. dispparams : TDispParams;
  989. flags : WORD;
  990. invokeresult : HRESULT;
  991. preallocateddata : array[0..15] of TVarData;
  992. Arguments : ^TVarData;
  993. NamedArguments : PPointer;
  994. CurrType : byte;
  995. namedcount,i : byte;
  996. begin
  997. { use preallocated space, i.e. can we avoid a getmem call? }
  998. if desc^.calldesc.argcount<=Length(preallocateddata) then
  999. Arguments:=@preallocateddata
  1000. else
  1001. GetMem(Arguments,desc^.calldesc.argcount*sizeof(TVarData));
  1002. { prepare parameters }
  1003. for i:=0 to desc^.CallDesc.ArgCount-1 do
  1004. begin
  1005. {$ifdef DEBUG_DISPATCH}
  1006. writeln('DoDispCallByID: Params = ',hexstr(PtrInt(Params),SizeOf(Pointer)*2));
  1007. {$endif DEBUG_DISPATCH}
  1008. { get plain type }
  1009. CurrType:=desc^.CallDesc.ArgTypes[i] and $3f;
  1010. { by reference? }
  1011. if (desc^.CallDesc.ArgTypes[i] and $80)<>0 then
  1012. begin
  1013. {$ifdef DEBUG_DISPATCH}
  1014. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  1015. writeln;
  1016. {$endif DEBUG_DISPATCH}
  1017. Arguments[i].VType:=CurrType or VarByRef;
  1018. Arguments[i].VPointer:=PPointer(Params)^;
  1019. inc(PPointer(Params));
  1020. end
  1021. else
  1022. begin
  1023. {$ifdef DEBUG_DISPATCH}
  1024. writeln('DispatchInvoke: Got ref argument with type = ',CurrType);
  1025. {$endif DEBUG_DISPATCH}
  1026. case CurrType of
  1027. varVariant:
  1028. begin
  1029. Arguments[i].VType:=CurrType;
  1030. move(PVarData(Params)^,Arguments[i],sizeof(TVarData));
  1031. inc(PVarData(Params));
  1032. end;
  1033. varCurrency,
  1034. varDouble,
  1035. VarDate:
  1036. begin
  1037. {$ifdef DEBUG_DISPATCH}
  1038. writeln('DispatchInvoke: Got 8 byte float argument');
  1039. {$endif DEBUG_DISPATCH}
  1040. Arguments[i].VType:=CurrType;
  1041. move(PPointer(Params)^,Arguments[i].VDouble,sizeof(Double));
  1042. inc(PDouble(Params));
  1043. end;
  1044. else
  1045. begin
  1046. {$ifdef DEBUG_DISPATCH}
  1047. writeln('DispatchInvoke: Got argument with type ',CurrType);
  1048. {$endif DEBUG_DISPATCH}
  1049. Arguments[i].VType:=CurrType;
  1050. Arguments[i].VPointer:=PPointer(Params)^;
  1051. inc(PPointer(Params));
  1052. end;
  1053. end;
  1054. end;
  1055. end;
  1056. dispparams.cArgs:=desc^.calldesc.argcount;
  1057. dispparams.rgvarg:=pointer(Arguments);
  1058. { handle properties properly here ! }
  1059. namedcount:=desc^.calldesc.namedargcount;
  1060. if desc^.calldesc.calltype=DISPATCH_PROPERTYPUT then
  1061. inc(namedcount)
  1062. else
  1063. NamedArguments:=@desc^.CallDesc.ArgTypes[desc^.CallDesc.ArgCount];
  1064. dispparams.cNamedArgs:=namedcount;
  1065. dispparams.rgdispidNamedArgs:=pointer(NamedArguments);
  1066. flags:=0;
  1067. invokeresult:=disp.Invoke(
  1068. desc^.DispId, { DispID: LongInt; }
  1069. GUID_NULL, { const iid : TGUID; }
  1070. 0, { LocaleID : longint; }
  1071. flags, { Flags: Word; }
  1072. dispparams, { var params; }
  1073. res,@exceptioninfo,nil { VarResult,ExcepInfo,ArgErr : pointer) }
  1074. );
  1075. if invokeresult<>0 then
  1076. DispatchInvokeError(invokeresult,exceptioninfo);
  1077. if desc^.calldesc.argcount>Length(preallocateddata) then
  1078. FreeMem(Arguments);
  1079. end;
  1080. { TTypedComObject }
  1081. function TTypedComObject.GetClassInfo(out pptti: ITypeInfo): HResult;stdcall;
  1082. begin
  1083. Result:=S_OK;
  1084. pptti:=TTypedComObjectFactory(factory).classinfo;
  1085. end;
  1086. { TTypedComObjectFactory }
  1087. constructor TTypedComObjectFactory.Create(AComServer: TComServerObject; TypedComClass: TTypedComClass; const AClassID: TGUID;
  1088. AInstancing: TClassInstancing; AThreadingModel: TThreadingModel = tmSingle);
  1089. var
  1090. TypedName, TypedDescription: WideString;
  1091. begin
  1092. //TDB get name and description from typelib (check if this is a valid guid)
  1093. OleCheck(AComServer.GetTypeLib.GetTypeInfoOfGuid(AClassID, FClassInfo));
  1094. //bug FPC 0010569 - http://msdn2.microsoft.com/en-us/library/ms221396(VS.85).aspx
  1095. OleCheck(FClassInfo.GetDocumentation(-1, TypedName, TypedDescription, PLongWord(nil)^, PWideString(nil)^));
  1096. inherited Create(AComServer, TypedComClass, AClassID, TypedName, TypedDescription, AInstancing, AThreadingModel);
  1097. end;
  1098. function TTypedComObjectFactory.GetInterfaceTypeInfo(TypeFlags: Integer): ITypeInfo;
  1099. begin
  1100. RunError(217);
  1101. end;
  1102. procedure TTypedComObjectFactory.UpdateRegistry(Register: Boolean);
  1103. begin
  1104. inherited UpdateRegistry(Register);
  1105. // 'TypeLib' = s '%LIBID%' missing ??? or does TComServer register it ?
  1106. //un/register typed library
  1107. RunError(217);
  1108. end;
  1109. const
  1110. Initialized : boolean = false;
  1111. var
  1112. Ole32Dll : HModule;
  1113. initialization
  1114. Uninitializing:=false;
  1115. _ComClassManager:=nil;
  1116. Ole32Dll:=GetModuleHandle('ole32.dll');
  1117. if Ole32Dll<>0 then
  1118. begin
  1119. Pointer(CoCreateInstanceEx):=GetProcAddress(Ole32Dll,'CoCreateInstanceEx');
  1120. Pointer(CoInitializeEx):=GetProcAddress(Ole32Dll,'CoInitializeEx');
  1121. Pointer(CoAddRefServerProcess):=GetProcAddress(Ole32Dll,'CoAddRefServerProcess');
  1122. Pointer(CoReleaseServerProcess):=GetProcAddress(Ole32Dll,'CoReleaseServerProcess');
  1123. Pointer(CoResumeClassObjects):=GetProcAddress(Ole32Dll,'CoResumeClassObjects');
  1124. Pointer(CoSuspendClassObjects):=GetProcAddress(Ole32Dll,'CoSuspendClassObjects');
  1125. end;
  1126. if not(IsLibrary) then
  1127. {$ifndef wince}
  1128. if (CoInitFlags=-1) or not(assigned(comobj.CoInitializeEx)) then
  1129. Initialized:=Succeeded(CoInitialize(nil))
  1130. else
  1131. {$endif wince}
  1132. Initialized:=Succeeded(comobj.CoInitializeEx(nil, CoInitFlags));
  1133. SafeCallErrorProc:=@SafeCallErrorHandler;
  1134. VarDispProc:=@ComObjDispatchInvoke;
  1135. DispCallByIDProc:=@DoDispCallByID;
  1136. finalization
  1137. Uninitializing:=true;
  1138. _ComClassManager.Free;
  1139. VarDispProc:=nil;
  1140. SafeCallErrorProc:=nil;
  1141. if Initialized then
  1142. CoUninitialize;
  1143. end.