comobj.pp 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  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. { $define DEBUG_COMDISPATCH}
  18. {$ifdef wince}
  19. {$define DUMMY_REG}
  20. {$endif}
  21. uses
  22. Windows,Types,Variants,Sysutils,ActiveX,classes;
  23. type
  24. EOleError = class(Exception);
  25. // apparantly used by axctrls.
  26. // http://lazarus.freepascal.org/index.php/topic,11612.0.html
  27. TConnectEvent = procedure(const Sink: IUnknown; Connecting: Boolean) of object;
  28. EOleSysError = class(EOleError)
  29. private
  30. FErrorCode: HRESULT;
  31. public
  32. constructor Create(const Msg: string; aErrorCode: HRESULT;aHelpContext: Integer);
  33. property ErrorCode: HRESULT read FErrorCode write FErrorCode;
  34. end;
  35. EOleException = class(EOleSysError)
  36. private
  37. FHelpFile: string;
  38. FSource: string;
  39. public
  40. constructor Create(const Msg: string; aErrorCode: HRESULT;const aSource,aHelpFile: string;aHelpContext: Integer);
  41. property HelpFile: string read FHelpFile write FHelpFile;
  42. property Source: string read FSource write FSource;
  43. end;
  44. EOleRegistrationError = class(EOleSysError);
  45. TOleStream = Class(TProxyStream)
  46. procedure Check(err:integer);override;
  47. end;
  48. TComServerObject = class(TObject)
  49. protected
  50. function CountObject(Created: Boolean): Integer; virtual; abstract;
  51. function CountFactory(Created: Boolean): Integer; virtual; abstract;
  52. function GetHelpFileName: string; virtual; abstract;
  53. function GetServerFileName: string; virtual; abstract;
  54. function GetServerKey: string; virtual; abstract;
  55. function GetServerName: string; virtual; abstract;
  56. function GetStartSuspended: Boolean; virtual; abstract;
  57. function GetTypeLib: ITypeLib; virtual; abstract;
  58. procedure SetHelpFileName(const Value: string); virtual; abstract;
  59. public
  60. property HelpFileName: string read GetHelpFileName write SetHelpFileName;
  61. property ServerFileName: string read GetServerFileName;
  62. property ServerKey: string read GetServerKey;
  63. property ServerName: string read GetServerName;
  64. property TypeLib: ITypeLib read GetTypeLib;
  65. property StartSuspended: Boolean read GetStartSuspended;
  66. end;
  67. TComObjectFactory = class;
  68. TFactoryProc = procedure(Factory: TComObjectFactory) of object;
  69. { TComClassManager }
  70. TComClassManager = class(TObject)
  71. private
  72. fClassFactoryList: TList;
  73. public
  74. constructor Create;
  75. destructor Destroy; override;
  76. procedure AddObjectFactory(factory: TComObjectFactory);
  77. procedure RemoveObjectFactory(factory: TComObjectFactory);
  78. procedure ForEachFactory(ComServer: TComServerObject; FactoryProc: TFactoryProc);
  79. function GetFactoryFromClass(ComClass: TClass): TComObjectFactory;
  80. function GetFactoryFromClassID(const ClassID: TGUID): TComObjectFactory;
  81. end;
  82. IServerExceptionHandler = interface
  83. ['{6A8D432B-EB81-11D1-AAB1-00C04FB16FBC}']
  84. procedure OnException(const ServerClass, ExceptionClass, ErrorMessage: WideString;
  85. ExceptAddr: PtrInt; const ErrorIID, ProgID: WideString; var Handled: Integer; var Result: HResult); dispid 2;
  86. end;
  87. TComObject = class(TObject, IUnknown, ISupportErrorInfo)
  88. private
  89. FController : Pointer;
  90. FFactory : TComObjectFactory;
  91. FRefCount : Integer;
  92. FServerExceptionHandler : IServerExceptionHandler;
  93. FCounted : Boolean;
  94. function GetController : IUnknown;
  95. protected
  96. { IUnknown }
  97. function IUnknown.QueryInterface = ObjQueryInterface;
  98. function IUnknown._AddRef = ObjAddRef;
  99. function IUnknown._Release = ObjRelease;
  100. { IUnknown methods for other interfaces }
  101. function QueryInterface(constref IID: TGUID; out Obj): HResult; stdcall;
  102. function _AddRef: Integer; stdcall;
  103. function _Release: Integer; stdcall;
  104. { ISupportErrorInfo }
  105. function InterfaceSupportsErrorInfo(const iid: TIID): HResult; stdcall;
  106. public
  107. constructor Create;
  108. constructor CreateAggregated(const Controller: IUnknown);
  109. constructor CreateFromFactory(Factory: TComObjectFactory; const Controller: IUnknown);
  110. destructor Destroy; override;
  111. procedure Initialize; virtual;
  112. function ObjAddRef: Integer; virtual; stdcall;
  113. function ObjQueryInterface(constref IID: TGUID; out Obj): HResult; virtual; stdcall;
  114. function ObjRelease: Integer; virtual; stdcall;
  115. function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; override;
  116. property Controller: IUnknown read GetController;
  117. property Factory: TComObjectFactory read FFactory;
  118. property RefCount: Integer read FRefCount;
  119. property ServerExceptionHandler: IServerExceptionHandler read FServerExceptionHandler write FServerExceptionHandler;
  120. end;
  121. TComClass = class of TComObject;
  122. TClassInstancing = (ciInternal, ciSingleInstance, ciMultiInstance);
  123. TThreadingModel = (tmSingle, tmApartment, tmFree, tmBoth, tmNeutral);
  124. { TComObjectFactory }
  125. TComObjectFactory = class(TObject, IUnknown, IClassFactory, IClassFactory2)
  126. private
  127. FRefCount : Integer;
  128. //Next: TComObjectFactory;
  129. FComServer: TComServerObject;
  130. FComClass: TClass;
  131. FClassID: TGUID;
  132. FClassName: string;
  133. FClassVersion : String;
  134. FDescription: string;
  135. FErrorIID: TGUID;
  136. FInstancing: TClassInstancing;
  137. FLicString: WideString;
  138. //FRegister: Longint;
  139. FShowErrors: Boolean;
  140. FSupportsLicensing: Boolean;
  141. FThreadingModel: TThreadingModel;
  142. function GetProgID: string;
  143. protected
  144. { IUnknown }
  145. function QueryInterface(constref IID: TGUID; out Obj): HResult; stdcall;
  146. function _AddRef: Integer; stdcall;
  147. function _Release: Integer; stdcall;
  148. { IClassFactory }
  149. function CreateInstance(const UnkOuter: IUnknown; const IID: TGUID;
  150. out Obj): HResult; stdcall;
  151. function LockServer(fLock: BOOL): HResult; stdcall;
  152. { IClassFactory2 }
  153. function GetLicInfo(var licInfo: TLicInfo): HResult; stdcall;
  154. function RequestLicKey(dwResrved: DWORD; out bstrKey: WideString): HResult; stdcall;
  155. function CreateInstanceLic(const unkOuter: IUnknown; const unkReserved: IUnknown;
  156. const iid: TIID; const bstrKey: WideString; out vObject): HResult; stdcall;
  157. public
  158. constructor Create(ComServer: TComServerObject; ComClass: TComClass;
  159. const ClassID: TGUID; const Name, Description: string;
  160. Instancing: TClassInstancing; ThreadingModel: TThreadingModel = tmSingle);
  161. constructor Create(ComServer: TComServerObject; ComClass: TComClass;
  162. const ClassID: TGUID; const Name, Version, Description: string;
  163. Instancing: TClassInstancing; ThreadingModel: TThreadingModel = tmSingle);
  164. destructor Destroy; override;
  165. function CreateComObject(const Controller: IUnknown): TComObject; virtual;
  166. procedure RegisterClassObject;
  167. procedure UpdateRegistry(Register: Boolean); virtual;
  168. property ClassID: TGUID read FClassID;
  169. property ClassName: string read FClassName;
  170. property ClassVersion: string read FClassVersion;
  171. property ComClass: TClass read FComClass;
  172. property ComServer: TComServerObject read FComServer;
  173. property Description: string read FDescription;
  174. property ErrorIID: TGUID read FErrorIID write FErrorIID;
  175. property LicString: WideString read FLicString write FLicString;
  176. property ProgID: string read GetProgID;
  177. property Instancing: TClassInstancing read FInstancing;
  178. property ShowErrors: Boolean read FShowErrors write FShowErrors;
  179. property SupportsLicensing: Boolean read FSupportsLicensing write FSupportsLicensing;
  180. property ThreadingModel: TThreadingModel read FThreadingModel;
  181. end;
  182. { TTypedComObject }
  183. TTypedComObject = class(TComObject, IProvideClassInfo)
  184. function GetClassInfo(out pptti : ITypeInfo):HResult; StdCall;
  185. end;
  186. TTypedComClass = class of TTypedComObject;
  187. { TTypedComObjectFactory }
  188. TTypedComObjectFactory = class(TComObjectFactory)
  189. private
  190. FClassInfo: ITypeInfo;
  191. FTypeInfoCount:integer;
  192. public
  193. constructor Create(AComServer: TComServerObject; TypedComClass: TTypedComClass; const AClassID: TGUID;
  194. AInstancing: TClassInstancing; AThreadingModel: TThreadingModel = tmSingle);
  195. function GetInterfaceTypeInfo(TypeFlags: Integer) : ITypeInfo;
  196. procedure UpdateRegistry(Register: Boolean);override;
  197. property ClassInfo : ITypeInfo read FClassInfo;
  198. end;
  199. { TAutoObject }
  200. TAutoObject = class(TTypedComObject, IDispatch)
  201. protected
  202. { IDispatch }
  203. function GetTypeInfoCount(out count : longint) : HResult;stdcall;
  204. function GetTypeInfo(Index,LocaleID : longint; out TypeInfo): HResult;stdcall;
  205. function GetIDsOfNames(const iid: TGUID; names: Pointer; NameCount, LocaleID: LongInt; DispIDs: Pointer) : HResult;stdcall;
  206. function Invoke(DispID: LongInt;const iid : TGUID; LocaleID : longint; Flags: Word;var params; VarResult,ExcepInfo,ArgErr : pointer) : HResult;stdcall;
  207. public
  208. end;
  209. TAutoClass = class of TAutoObject;
  210. { TAutoObjectFactory }
  211. TAutoObjectFactory = class(TTypedComObjectFactory)
  212. private
  213. FDispIntfEntry: PInterfaceEntry;
  214. FDispTypeInfo: ITypeInfo;
  215. public
  216. constructor Create(AComServer: TComServerObject; AutoClass: TAutoClass; const AClassID: TGUID;
  217. AInstancing: TClassInstancing; AThreadingModel: TThreadingModel = tmSingle);
  218. function GetIntfEntry(Guid: TGUID): PInterfaceEntry; virtual;
  219. property DispIntfEntry: PInterfaceEntry read FDispIntfEntry;
  220. property DispTypeInfo: ITypeInfo read FDispTypeInfo;
  221. end;
  222. { TAutoIntfObject }
  223. //example of how to implement IDispatch: http://www.opensource.apple.com/source/vim/vim-34/vim/src/if_ole.cpp
  224. TAutoIntfObject = class(TInterfacedObject, IDispatch, ISupportErrorInfo)
  225. private
  226. fTypeInfo: ITypeInfo;
  227. fInterfacePointer: Pointer;
  228. protected
  229. { IDispatch }
  230. function GetTypeInfoCount(out count : longint) : HResult;stdcall;
  231. function GetTypeInfo(Index,LocaleID : longint; out TypeInfo): HResult;stdcall;
  232. function GetIDsOfNames(const iid: TGUID; names: Pointer; NameCount, LocaleID: LongInt; DispIDs: Pointer) : HResult;stdcall;
  233. function Invoke(DispID: LongInt;const iid : TGUID; LocaleID : longint; Flags: Word;var params; VarResult,ExcepInfo,ArgErr : pointer) : HResult;stdcall;
  234. { ISupportErrorInfo }
  235. function InterfaceSupportsErrorInfo(CONST riid: TIID):HResult;StdCall;
  236. public
  237. function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; override;
  238. constructor Create(TypeLib: ITypeLib; const Guid: TGuid);
  239. end;
  240. function CreateClassID : ansistring;
  241. function CreateComObject(const ClassID: TGUID) : IUnknown;
  242. function CreateRemoteComObject(const MachineName : WideString;const ClassID : TGUID) : IUnknown;
  243. function CreateOleObject(const ClassName : string) : IDispatch;
  244. function GetActiveOleObject(const ClassName: string) : IDispatch;
  245. procedure OleCheck(Value : HResult);inline;
  246. procedure OleError(Code: HResult);
  247. function ProgIDToClassID(const id : string) : TGUID;
  248. function ClassIDToProgID(const classID: TGUID): string;
  249. function StringToLPOLESTR(const Source: string): POLEStr;
  250. procedure InterfaceConnect(const Source: IUnknown; const IID: TIID; const Sink: IUnknown; var Connection: DWORD);
  251. procedure InterfaceDisconnect(const Source: IUnknown; const IID: TIID; var Connection: DWORD);
  252. procedure DispatchInvoke(const Dispatch: IDispatch; CallDesc: PCallDesc;
  253. DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  254. procedure DispatchInvokeError(Status: HRESULT; const ExceptInfo: TExcepInfo);
  255. function HandleSafeCallException(ExceptObject: TObject; ExceptAddr: Pointer; const ErrorIID: TGUID; const ProgID,
  256. HelpFileName: WideString): HResult;
  257. function ComClassManager : TComClassManager;
  258. procedure CreateRegKey(const Key, ValueName, Value: string; RootKey: HKey= HKEY_CLASSES_ROOT);
  259. procedure DeleteRegKey(const Key: string; RootKey: HKey = HKEY_CLASSES_ROOT);
  260. function GetRegStringValue(const Key, ValueName: string; RootKey: HKey = HKEY_CLASSES_ROOT): string;
  261. type
  262. TCoCreateInstanceExProc = function(const clsid: TCLSID; unkOuter: IUnknown; dwClsCtx: DWORD; ServerInfo: PCoServerInfo;
  263. dwCount: ULONG; rgmqResults: PMultiQIArray): HResult stdcall;
  264. TCoInitializeExProc = function (pvReserved: Pointer;
  265. coInit: DWORD): HResult; stdcall;
  266. TCoAddRefServerProcessProc = function : ULONG; stdcall;
  267. TCoReleaseServerProcessProc = function : ULONG; stdcall;
  268. TCoResumeClassObjectsProc = function : HResult; stdcall;
  269. TCoSuspendClassObjectsProc = function : HResult; stdcall;
  270. const
  271. CoCreateInstanceEx : TCoCreateInstanceExProc = nil;
  272. CoInitializeEx : TCoInitializeExProc = nil;
  273. CoAddRefServerProcess : TCoAddRefServerProcessProc = nil;
  274. CoReleaseServerProcess : TCoReleaseServerProcessProc = nil;
  275. CoResumeClassObjects : TCoResumeClassObjectsProc = nil;
  276. CoSuspendClassObjects : TCoSuspendClassObjectsProc = nil;
  277. CoInitFlags : Longint = -1;
  278. {$ifdef DEBUG_COM}
  279. var printcom : boolean=true;
  280. {$endif}
  281. implementation
  282. uses
  283. ComConst, Ole2, {$ifndef dummy_reg} Registry, {$endif} RtlConsts;
  284. var
  285. Uninitializing : boolean;
  286. function HandleSafeCallException(ExceptObject: TObject; ExceptAddr: Pointer; const ErrorIID: TGUID; const ProgID,
  287. HelpFileName: WideString): HResult;
  288. {$ifndef wince}
  289. var
  290. _CreateErrorInfo : ICreateErrorInfo;
  291. ErrorInfo : IErrorInfo;
  292. {$endif wince}
  293. begin
  294. Result:=E_UNEXPECTED;
  295. {$ifndef wince}
  296. if Succeeded(CreateErrorInfo(_CreateErrorInfo)) then
  297. begin
  298. _CreateErrorInfo.SetGUID(ErrorIID);
  299. if ProgID<>'' then
  300. _CreateErrorInfo.SetSource(PWidechar(ProgID));
  301. if HelpFileName<>'' then
  302. _CreateErrorInfo.SetHelpFile(PWidechar(HelpFileName));
  303. if ExceptObject is Exception then
  304. begin
  305. _CreateErrorInfo.SetDescription(PWidechar(Widestring(Exception(ExceptObject).Message)));
  306. _CreateErrorInfo.SetHelpContext(Exception(ExceptObject).HelpContext);
  307. if (ExceptObject is EOleSyserror) and (EOleSysError(ExceptObject).ErrorCode<0) then
  308. Result:=EOleSysError(ExceptObject).ErrorCode
  309. end;
  310. if _CreateErrorInfo.QueryInterface(IErrorInfo,ErrorInfo)=S_OK then
  311. SetErrorInfo(0,ErrorInfo);
  312. end;
  313. {$endif wince}
  314. end;
  315. constructor EOleSysError.Create(const Msg: string; aErrorCode: HRESULT; aHelpContext: Integer);
  316. var
  317. m : string;
  318. begin
  319. if Msg='' then
  320. m:=SysErrorMessage(aErrorCode)
  321. else
  322. m:=Msg;
  323. inherited CreateHelp(m,HelpContext);
  324. FErrorCode:=aErrorCode;
  325. end;
  326. constructor EOleException.Create(const Msg: string; aErrorCode: HRESULT;const aSource,aHelpFile: string; aHelpContext: Integer);
  327. begin
  328. inherited Create(Msg,aErrorCode,aHelpContext);
  329. FHelpFile:=aHelpFile;
  330. FSource:=aSource;
  331. end;
  332. {$define FPC_COMOBJ_HAS_CREATE_CLASS_ID}
  333. function CreateClassID : ansistring;
  334. var
  335. ClassID : TCLSID;
  336. p : PWideChar;
  337. begin
  338. CoCreateGuid(ClassID);
  339. StringFromCLSID(ClassID,p);
  340. result:=p;
  341. CoTaskMemFree(p);
  342. end;
  343. function CreateComObject(const ClassID : TGUID) : IUnknown;
  344. begin
  345. OleCheck(CoCreateInstance(ClassID,nil,CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,IUnknown,result));
  346. end;
  347. function CreateRemoteComObject(const MachineName : WideString;const ClassID : TGUID) : IUnknown;
  348. var
  349. flags : DWORD;
  350. localhost : array[0..MAX_COMPUTERNAME_LENGTH] of WideChar;
  351. server : TCoServerInfo;
  352. mqi : TMultiQI;
  353. size : DWORD;
  354. begin
  355. if not(assigned(CoCreateInstanceEx)) then
  356. raise Exception.CreateRes(@SDCOMNotInstalled);
  357. FillChar(server,sizeof(server),0);
  358. server.pwszName:=PWideChar(MachineName);
  359. FillChar(mqi,sizeof(mqi),0);
  360. mqi.iid:=@IID_IUnknown;
  361. flags:=CLSCTX_LOCAL_SERVER or CLSCTX_REMOTE_SERVER or CLSCTX_INPROC_SERVER;
  362. { actually a remote call? }
  363. {$ifndef wince}
  364. //roozbeh although there is a way to retrive computer name...HKLM\Ident\Name..but are they same?
  365. size:=sizeof(localhost);
  366. if (MachineName<>'') and
  367. (not(GetComputerNameW(localhost,size)) or
  368. (WideCompareText(localhost,MachineName)<>0)) then
  369. flags:=CLSCTX_REMOTE_SERVER;
  370. {$endif}
  371. OleCheck(CoCreateInstanceEx(ClassID,nil,flags,@server,1,@mqi));
  372. OleCheck(mqi.hr);
  373. Result:=mqi.itf;
  374. end;
  375. function CreateOleObject(const ClassName : string) : IDispatch;
  376. var
  377. id : TCLSID;
  378. begin
  379. id:=ProgIDToClassID(ClassName);
  380. OleCheck(CoCreateInstance(id,nil,CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER,IDispatch,result));
  381. end;
  382. function GetActiveOleObject(const ClassName : string) : IDispatch;
  383. {$ifndef wince}
  384. var
  385. intf : IUnknown;
  386. id : TCLSID;
  387. begin
  388. id:=ProgIDToClassID(ClassName);
  389. OleCheck(GetActiveObject(id,nil,intf));
  390. OleCheck(intf.QueryInterface(IDispatch,Result));
  391. end;
  392. {$else}
  393. begin
  394. Result:=nil;
  395. end;
  396. {$endif wince}
  397. procedure CreateRegKey(const Key, ValueName, Value: string; RootKey: HKEY = HKEY_CLASSES_ROOT);
  398. {$ifndef DUMMY_REG}
  399. var
  400. Reg: TRegistry;
  401. {$endif}
  402. begin
  403. {$ifdef DEBUG_COM}
  404. if printcom then
  405. WriteLn('CreateRegKey: ', Key, ': ', ValueName, ': ', Value );
  406. {$endif}
  407. {$ifndef DUMMY_REG}
  408. Reg := TRegistry.Create;
  409. try
  410. Reg.RootKey := RootKey;
  411. if Reg.OpenKey(Key, True) then
  412. begin
  413. try
  414. Reg.WriteString(ValueName, Value);
  415. finally
  416. Reg.CloseKey;
  417. end;
  418. end
  419. else
  420. raise EOleRegistrationError.CreateResFmt(@SRegCreateFailed,[Key]);
  421. finally
  422. Reg.Free;
  423. end;
  424. {$endif}
  425. {$ifdef DEBUG_COM}
  426. if printcom then
  427. WriteLn('CreateRegKey exit: ', Key, ': ', ValueName, ': ', Value );
  428. {$endif}
  429. end;
  430. procedure DeleteRegKey(const Key: string; RootKey: HKEY = HKEY_CLASSES_ROOT);
  431. {$ifndef DUMMY_REG}
  432. var
  433. Reg: TRegistry;
  434. {$endif}
  435. begin
  436. {$ifdef DEBUG_COM}
  437. if printcom then
  438. WriteLn('DeleteRegKey: ', Key);
  439. {$endif}
  440. {$ifndef DUMMY_REG}
  441. Reg := TRegistry.Create;
  442. try
  443. Reg.RootKey := RootKey;
  444. Reg.DeleteKey(Key);
  445. finally
  446. Reg.Free;
  447. end;
  448. {$endif}
  449. end;
  450. function GetRegStringValue(const Key, ValueName: string; RootKey: HKEY = HKEY_CLASSES_ROOT): string;
  451. {$ifndef DUMMY_REG}
  452. var
  453. Reg: TRegistry;
  454. {$endif}
  455. begin
  456. {$ifndef DUMMY_REG}
  457. Reg := TRegistry.Create();
  458. try
  459. Reg.RootKey := RootKey;
  460. if Reg.OpenKeyReadOnly(Key) then
  461. begin
  462. try
  463. Result := Reg.ReadString(ValueName)
  464. finally
  465. Reg.CloseKey;
  466. end;
  467. end
  468. else
  469. Result := '';
  470. finally
  471. Reg.Free;
  472. end;
  473. {$endif}
  474. end;
  475. procedure OleError(Code: HResult);
  476. begin
  477. raise EOleSysError.Create('',Code,0);
  478. end;
  479. procedure OleCheck(Value : HResult);inline;
  480. begin
  481. if not(Succeeded(Value)) then
  482. OleError(Value);
  483. end;
  484. function ProgIDToClassID(const id : string) : TGUID;
  485. begin
  486. OleCheck(CLSIDFromProgID(PWideChar(WideString(id)),result));
  487. end;
  488. function ClassIDToProgID(const classID: TGUID): string;
  489. var
  490. progid : LPOLESTR;
  491. begin
  492. OleCheck(ProgIDFromCLSID(@classID,progid));
  493. result:=progid;
  494. CoTaskMemFree(progid);
  495. end;
  496. function StringToLPOLESTR(const Source: string): POLEStr;
  497. var
  498. Src: WideString;
  499. begin
  500. Src := WideString(Source);
  501. Result := CoTaskMemAlloc((Length(Src)+1) * SizeOf(WideChar));
  502. if Result <> nil then
  503. Move(PWideChar(Src)^, Result^, (Length(Src)+1) * SizeOf(WideChar));
  504. end;
  505. procedure InterfaceConnect(const Source: IUnknown; const IID: TIID; const Sink: IUnknown; var Connection: DWORD);
  506. var
  507. CPC: IConnectionPointContainer;
  508. CP: IConnectionPoint;
  509. i: hresult;
  510. begin
  511. Connection := 0;
  512. if Succeeded(Source.QueryInterface(IConnectionPointContainer, CPC)) then
  513. if Succeeded(CPC.FindConnectionPoint(IID, CP)) then
  514. i:=CP.Advise(Sink, Connection);
  515. end;
  516. procedure InterfaceDisconnect(const Source: IUnknown; const IID: TIID; var Connection: DWORD);
  517. var
  518. CPC: IConnectionPointContainer;
  519. CP: IConnectionPoint;
  520. i: hresult;
  521. begin
  522. if Connection <> 0 then
  523. if Succeeded(Source.QueryInterface(IConnectionPointContainer, CPC)) then
  524. if Succeeded(CPC.FindConnectionPoint(IID, CP)) then
  525. begin
  526. i:=CP.Unadvise(Connection);
  527. if Succeeded(i) then Connection := 0;
  528. end;
  529. end;
  530. procedure SafeCallErrorHandler(err : HResult;addr : pointer);
  531. {$ifndef wince}
  532. var
  533. info : IErrorInfo;
  534. descr,src,helpfile : widestring;
  535. helpctx : DWORD;
  536. {$endif wince}
  537. begin
  538. {$ifndef wince}
  539. if GetErrorInfo(0,info)=S_OK then
  540. begin
  541. info.GetDescription(descr);
  542. info.GetSource(src);
  543. info.GetHelpFile(helpfile);
  544. info.GetHelpContext(helpctx);
  545. raise EOleException.Create(descr,err,src,helpfile,helpctx) at addr;
  546. end
  547. else
  548. {$endif wince}
  549. raise EOleException.Create('',err,'','',0) at addr;
  550. end;
  551. procedure DispatchInvokeError(Status: HRESULT; const ExceptInfo: TExcepInfo);
  552. begin
  553. if Status=DISP_E_EXCEPTION then
  554. raise EOleException.Create(ExceptInfo.Description,ExceptInfo.scode,ExceptInfo.Source,
  555. ExceptInfo.HelpFile,ExceptInfo.dwHelpContext)
  556. else
  557. raise EOleSysError.Create('',Status,0);
  558. end;
  559. var
  560. _ComClassManager : TComClassManager;
  561. function ComClassManager: TComClassManager;
  562. begin
  563. if not(assigned(_ComClassManager)) then
  564. _ComClassManager:=TComClassManager.Create;
  565. Result:=_ComClassManager;
  566. end;
  567. constructor TComClassManager.Create;
  568. begin
  569. fClassFactoryList := TList.create({true});
  570. end;
  571. destructor TComClassManager.Destroy;
  572. var i : integer;
  573. begin
  574. if fClassFactoryList.count>0 Then
  575. begin
  576. for i:=fClassFactoryList.count-1 downto 0 do
  577. tobject(fClassFactoryList[i]).Free;
  578. end;
  579. fClassFactoryList.Free;
  580. end;
  581. procedure TComClassManager.AddObjectFactory(factory: TComObjectFactory);
  582. begin
  583. {$ifdef DEBUG_COM}
  584. if printcom then
  585. WriteLn('AddObjectFactory: ', GUIDToString(factory.FClassID), ' ', factory.FClassName);
  586. {$endif}
  587. fClassFactoryList.Add(factory);
  588. end;
  589. procedure TComClassManager.RemoveObjectFactory(
  590. factory: TComObjectFactory);
  591. begin
  592. fClassFactoryList.Remove(factory);
  593. end;
  594. procedure TComClassManager.ForEachFactory(ComServer: TComServerObject;
  595. FactoryProc: TFactoryProc);
  596. var
  597. i: Integer;
  598. obj: TComObjectFactory;
  599. begin
  600. {$ifdef DEBUG_COM}
  601. if printcom then
  602. WriteLn('ForEachFactory');
  603. {$endif}
  604. for i := 0 to fClassFactoryList.Count - 1 do
  605. begin
  606. obj := TComObjectFactory(fClassFactoryList[i]);
  607. if obj.ComServer = ComServer then
  608. FactoryProc(obj);
  609. end;
  610. end;
  611. function TComClassManager.GetFactoryFromClass(ComClass: TClass
  612. ): TComObjectFactory;
  613. var
  614. i: Integer;
  615. begin
  616. {$ifdef DEBUG_COM}
  617. if printcom then
  618. WriteLn('GetFactoryFromClass: ', ComClass.ClassName);
  619. {$endif}
  620. for i := 0 to fClassFactoryList.Count - 1 do
  621. begin
  622. Result := TComObjectFactory(fClassFactoryList[i]);
  623. if ComClass = Result.ComClass then
  624. Exit();
  625. end;
  626. Result := nil;
  627. end;
  628. function TComClassManager.GetFactoryFromClassID(const ClassID: TGUID
  629. ): TComObjectFactory;
  630. var
  631. i: Integer;
  632. begin
  633. {$ifdef DEBUG_COM}
  634. if printcom then
  635. WriteLn('GetFactoryFromClassID: ', GUIDToString(ClassId));
  636. {$endif}
  637. for i := 0 to fClassFactoryList.Count - 1 do
  638. begin
  639. Result := TComObjectFactory(fClassFactoryList[i]);
  640. if IsEqualGUID(ClassID, Result.ClassID) then
  641. Exit();
  642. end;
  643. {$ifdef DEBUG_COM}
  644. if printcom then
  645. WriteLn('GetFactoryFromClassID not found: ', GUIDToString(ClassId));
  646. {$endif}
  647. Result := nil;
  648. end;
  649. function TComObject.GetController: IUnknown;
  650. begin
  651. Result:=IUnknown(Controller);
  652. end;
  653. function TComObject.QueryInterface(constref IID: TGUID; out Obj): HResult; stdcall;
  654. begin
  655. if assigned(FController) then
  656. Result:=IUnknown(FController).QueryInterface(IID,Obj)
  657. else
  658. Result:=ObjQueryInterface(IID,Obj);
  659. end;
  660. function TComObject._AddRef: Integer; stdcall;
  661. begin
  662. if assigned(FController) then
  663. Result:=IUnknown(FController)._AddRef
  664. else
  665. Result:=ObjAddRef;
  666. end;
  667. function TComObject._Release: Integer; stdcall;
  668. begin
  669. if assigned(FController) then
  670. Result:=IUnknown(FController)._Release
  671. else
  672. Result:=ObjRelease;
  673. end;
  674. function TComObject.InterfaceSupportsErrorInfo(const iid: TIID): HResult; stdcall;
  675. begin
  676. if assigned(GetInterfaceEntry(iid)) then
  677. Result:=S_OK
  678. else
  679. Result:=S_FALSE;
  680. end;
  681. constructor TComObject.Create;
  682. begin
  683. CreateFromFactory(ComClassManager.GetFactoryFromClass(ClassType),nil);
  684. end;
  685. constructor TComObject.CreateAggregated(const Controller: IUnknown);
  686. begin
  687. CreateFromFactory(ComClassManager.GetFactoryFromClass(ClassType),Controller);
  688. end;
  689. constructor TComObject.CreateFromFactory(Factory: TComObjectFactory;
  690. const Controller: IUnknown);
  691. begin
  692. FFactory:=Factory;
  693. FRefCount:=1;
  694. FController:=Pointer(Controller);
  695. FFactory.Comserver.CountObject(True);
  696. FCounted:=true;
  697. Initialize;
  698. Dec(FRefCount);
  699. end;
  700. destructor TComObject.Destroy;
  701. begin
  702. if not(Uninitializing) then
  703. begin
  704. if assigned(FFactory) and FCounted then
  705. FFactory.Comserver.CountObject(false);
  706. {$ifndef wince}
  707. if FRefCount>0 then
  708. CoDisconnectObject(Self,0);
  709. {$endif wince}
  710. end;
  711. end;
  712. procedure TComObject.Initialize;
  713. begin
  714. end;
  715. function TComObject.ObjAddRef: Integer; stdcall;
  716. begin
  717. Result:=InterlockedIncrement(FRefCount);
  718. end;
  719. function TComObject.ObjQueryInterface(constref IID: TGUID; out Obj): HResult; stdcall;
  720. begin
  721. if GetInterface(IID,Obj) then
  722. Result:=S_OK
  723. else
  724. Result:=E_NOINTERFACE;
  725. end;
  726. function TComObject.ObjRelease: Integer; stdcall;
  727. begin
  728. Result:=InterlockedDecrement(FRefCount);
  729. if Result=0 then
  730. Self.Destroy;
  731. end;
  732. function TComObject.SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult;
  733. var
  734. Message: string;
  735. Handled: Integer;
  736. begin
  737. Handled:=0;
  738. Result:=0;
  739. if assigned(ServerExceptionHandler) then
  740. begin
  741. if ExceptObject is Exception then
  742. Message:=Exception(ExceptObject).Message;
  743. ServerExceptionHandler.OnException(ClassName,ExceptObject.ClassName,
  744. Message,PtrInt(ExceptAddr),WideString(GUIDToString(FFactory.ErrorIID)),
  745. FFactory.ProgID,Handled,Result);
  746. end;
  747. if Handled=0 then
  748. Result:=HandleSafeCallException(ExceptObject,ExceptAddr,FFactory.ErrorIID,
  749. FFactory.ProgID,FFactory.ComServer.HelpFileName);
  750. end;
  751. function TComObjectFactory.GetProgID: string;
  752. begin
  753. Result := FComServer.GetServerName + '.' + FClassName;
  754. end;
  755. function TComObjectFactory.QueryInterface(constref IID: TGUID; out Obj): HResult; stdcall;
  756. begin
  757. if GetInterface(IID,Obj) then
  758. Result:=S_OK
  759. else
  760. Result:=E_NOINTERFACE;
  761. end;
  762. function TComObjectFactory._AddRef: Integer; stdcall;
  763. begin
  764. Result:=InterlockedIncrement(FRefCount);
  765. end;
  766. function TComObjectFactory._Release: Integer; stdcall;
  767. begin
  768. Result:=InterlockedDecrement(FRefCount);
  769. if Result=0 then
  770. Self.Destroy;
  771. end;
  772. function TComObjectFactory.CreateInstance(const UnkOuter: IUnknown;
  773. const IID: TGUID; out Obj): HResult; stdcall;
  774. var
  775. comObject: TComObject;
  776. begin
  777. {$ifdef DEBUG_COM}
  778. if printcom then
  779. WriteLn('CreateInstance: ', GUIDToString(IID));
  780. {$endif}
  781. comObject := CreateComObject(UnkOuter);
  782. if comObject.GetInterface(IID, Obj) then
  783. Result := S_OK
  784. else
  785. Result := E_NOINTERFACE;
  786. end;
  787. function TComObjectFactory.LockServer(fLock: BOOL): HResult; stdcall;
  788. begin
  789. {$ifdef DEBUG_COM}
  790. if printcom then
  791. WriteLn('LockServer: ', fLock);
  792. {$endif}
  793. RunError(217);
  794. Result:=0;
  795. end;
  796. function TComObjectFactory.GetLicInfo(var licInfo: TLicInfo): HResult; stdcall;
  797. begin
  798. {$ifdef DEBUG_COM}
  799. if printcom then
  800. WriteLn('GetLicInfo');
  801. {$endif}
  802. RunError(217);
  803. Result:=0;
  804. end;
  805. function TComObjectFactory.RequestLicKey(dwResrved: DWORD; out bstrKey: WideString): HResult; stdcall;
  806. begin
  807. {$ifdef DEBUG_COM}
  808. if printcom then
  809. WriteLn('RequestLicKey');
  810. {$endif}
  811. RunError(217);
  812. Result:=0;
  813. end;
  814. function TComObjectFactory.CreateInstanceLic(const unkOuter: IUnknown;
  815. const unkReserved: IUnknown; const iid: TIID; const bstrKey: WideString; out
  816. vObject): HResult; stdcall;
  817. begin
  818. {$ifdef DEBUG_COM}
  819. if printcom then
  820. WriteLn('CreateInstanceLic');
  821. {$endif}
  822. RunError(217);
  823. Result:=0;
  824. end;
  825. constructor TComObjectFactory.Create(ComServer: TComServerObject;
  826. ComClass: TComClass; const ClassID: TGUID; const Name,
  827. Description: string; Instancing: TClassInstancing;
  828. ThreadingModel: TThreadingModel);
  829. begin
  830. Create(ComServer, ComClass, ClassID, Name, '', Description, Instancing, ThreadingModel);
  831. end;
  832. constructor TComObjectFactory.Create(ComServer: TComServerObject;
  833. ComClass: TComClass; const ClassID: TGUID; const Name, Version, Description: string; Instancing: TClassInstancing;
  834. ThreadingModel: TThreadingModel);
  835. begin
  836. {$ifdef DEBUG_COM}
  837. if printcom then
  838. WriteLn('TComObjectFactory.Create');
  839. {$endif}
  840. FRefCount := 1;
  841. FClassID := ClassID;
  842. FThreadingModel := ThreadingModel;
  843. FDescription := Description;
  844. FClassName := Name;
  845. FClassVersion := Version;
  846. FComServer := ComServer;
  847. FComClass := ComClass;
  848. FInstancing := Instancing;;
  849. ComClassManager.AddObjectFactory(Self);
  850. end;
  851. destructor TComObjectFactory.Destroy;
  852. begin
  853. ComClassManager.RemoveObjectFactory(Self);
  854. //RunError(217);
  855. end;
  856. function TComObjectFactory.CreateComObject(const Controller: IUnknown
  857. ): TComObject;
  858. begin
  859. {$ifdef DEBUG_COM}
  860. if printcom then
  861. WriteLn('TComObjectFactory.CreateComObject');
  862. {$endif}
  863. Result := TComClass(FComClass).Create();
  864. end;
  865. procedure TComObjectFactory.RegisterClassObject;
  866. begin
  867. {$ifdef DEBUG_COM}
  868. if printcom then
  869. WriteLn('TComObjectFactory.RegisterClassObject');
  870. {$endif}
  871. RunError(217);
  872. end;
  873. (* Copy from Sample.RGS (http://www.codeproject.com/KB/atl/RegistryMap.aspx)
  874. HKCR
  875. {
  876. %PROGID%.%VERSION% = s '%DESCRIPTION%'
  877. {
  878. CLSID = s '%CLSID%'
  879. }
  880. %PROGID% = s '%DESCRIPTION%'
  881. {
  882. CLSID = s '%CLSID%'
  883. CurVer = s '%PROGID%.%VERSION%'
  884. }
  885. NoRemove CLSID
  886. {
  887. ForceRemove %CLSID% = s '%DESCRIPTION%'
  888. {
  889. ProgID = s '%PROGID%.%VERSION%'
  890. VersionIndependentProgID = s '%PROGID%'
  891. ForceRemove 'Programmable'
  892. InprocServer32 = s '%MODULE%'
  893. {
  894. val ThreadingModel = s '%THREADING%'
  895. }
  896. 'TypeLib' = s '%LIBID%'
  897. }
  898. }
  899. }
  900. *)
  901. procedure TComObjectFactory.UpdateRegistry(Register: Boolean);
  902. var
  903. classidguid: String;
  904. function ThreadModelToString(model: TThreadingModel): String;
  905. begin
  906. case model of
  907. tmSingle: Result := '';
  908. tmApartment: Result := 'Apartment';
  909. tmFree: Result := 'Free';
  910. tmBoth: Result := 'Both';
  911. tmNeutral: Result := 'Neutral';
  912. end;
  913. end;
  914. begin
  915. {$ifndef DUMMY_REG}
  916. {$ifdef DEBUG_COM}
  917. if printcom then
  918. WriteLn('UpdateRegistry begin');
  919. {$endif}
  920. if Instancing = ciInternal then Exit;
  921. if Register then
  922. begin
  923. classidguid := GUIDToString(ClassID);
  924. CreateRegKey('CLSID\' + classidguid + '\InprocServer32', '', FComServer.ServerFileName);
  925. //tmSingle, tmApartment, tmFree, tmBoth, tmNeutral
  926. CreateRegKey('CLSID\' + classidguid + '\InprocServer32', 'ThreadingModel', ThreadModelToString(ThreadingModel));
  927. CreateRegKey('CLSID\' + classidguid, '', Description);
  928. if ClassName <> '' then
  929. begin
  930. if ClassVersion <> '' then
  931. begin
  932. CreateRegKey('CLSID\' + classidguid + '\ProgID', '', ProgID + '.' + ClassVersion);
  933. CreateRegKey('CLSID\' + classidguid + '\VersionIndependentProgID', '', ProgID);
  934. end
  935. else
  936. CreateRegKey('CLSID\' + classidguid + '\ProgID', '', ProgID);
  937. CreateRegKey(ProgID, '', Description);
  938. CreateRegKey(ProgID + '\CLSID', '', GUIDToString(ClassID));
  939. if ClassVersion <> '' then
  940. begin
  941. CreateRegKey(ProgID + '\CurVer', '', ProgID + '.' + ClassVersion);
  942. CreateRegKey(ProgID + '.' + ClassVersion, '', Description);
  943. CreateRegKey(ProgID + '.' + ClassVersion + '\CLSID', '', GUIDToString(ClassID));
  944. end;
  945. end;
  946. end else
  947. begin
  948. classidguid := GUIDToString(ClassID);
  949. DeleteRegKey('CLSID\' + classidguid + '\InprocServer32');
  950. DeleteRegKey('CLSID\' + classidguid + '\VersionIndependentProgID');
  951. if ClassName <> '' then
  952. begin
  953. DeleteRegKey('CLSID\' + classidguid + '\ProgID');
  954. DeleteRegKey(ProgID + '\CLSID');
  955. if ClassVersion <> '' then
  956. begin
  957. DeleteRegKey(ProgID + '\CurVer');
  958. DeleteRegKey(ProgID + '.' + ClassVersion + '\CLSID');
  959. DeleteRegKey(ProgID + '.' + ClassVersion);
  960. end;
  961. DeleteRegKey(ProgID);
  962. end;
  963. DeleteRegKey('CLSID\' + classidguid);
  964. end;
  965. {$ifdef DEBUG_COM}
  966. if printcom then
  967. WriteLn('UpdateRegistry end');
  968. {$endif}
  969. {$endif DUMMY_REG}
  970. end;
  971. procedure DispatchInvoke(const Dispatch: IDispatch; CallDesc: PCallDesc;
  972. DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  973. var
  974. { we can't pass pascal ansistrings to COM routines so we've to convert them
  975. to/from widestring. This array contains the mapping to do so
  976. }
  977. StringMap : array[0..255] of record passtr : pansistring; comstr : pwidechar; end;
  978. invokekind,
  979. i : longint;
  980. invokeresult : HResult;
  981. exceptioninfo : TExcepInfo;
  982. dispparams : TDispParams;
  983. NextString : SizeInt;
  984. Arguments : array[0..255] of TVarData;
  985. CurrType : byte;
  986. MethodID : TDispID;
  987. begin
  988. NextString:=0;
  989. fillchar(dispparams,sizeof(dispparams),0);
  990. try
  991. {$ifdef DEBUG_COMDISPATCH}
  992. if printcom then
  993. writeln('DispatchInvoke: Got ',CallDesc^.ArgCount,' arguments NamedArgs = ',CallDesc^.NamedArgCount);
  994. {$endif DEBUG_COMDISPATCH}
  995. { copy and prepare arguments }
  996. for i:=0 to CallDesc^.ArgCount-1 do
  997. begin
  998. {$ifdef DEBUG_COMDISPATCH}
  999. if printcom then
  1000. writeln('DispatchInvoke: Params = ',hexstr(Params));
  1001. {$endif DEBUG_COMDISPATCH}
  1002. { get plain type }
  1003. CurrType:=CallDesc^.ArgTypes[i] and $3f;
  1004. { a skipped parameter? Don't increment Params pointer if so. }
  1005. if CurrType=varError then
  1006. begin
  1007. Arguments[i].vType:=varError;
  1008. Arguments[i].vError:=DISP_E_PARAMNOTFOUND;
  1009. continue;
  1010. end;
  1011. { by reference? }
  1012. if (CallDesc^.ArgTypes[i] and $80)<>0 then
  1013. begin
  1014. case CurrType of
  1015. varStrArg:
  1016. begin
  1017. {$ifdef DEBUG_COMDISPATCH}
  1018. if printcom then
  1019. writeln('Translating var ansistring argument ',PString(Params^)^);
  1020. {$endif DEBUG_COMDISPATCH}
  1021. StringMap[NextString].ComStr:=StringToOleStr(PString(Params^)^);
  1022. StringMap[NextString].PasStr:=PString(Params^);
  1023. Arguments[i].VType:=varOleStr or varByRef;
  1024. Arguments[i].VPointer:=StringMap[NextString].ComStr;
  1025. inc(NextString);
  1026. inc(PPointer(Params));
  1027. end;
  1028. varVariant:
  1029. begin
  1030. {$ifdef DEBUG_COMDISPATCH}
  1031. if printcom then
  1032. writeln('Got ref. variant containing type: ',PVarData(PPointer(Params)^)^.VType);
  1033. {$endif DEBUG_COMDISPATCH}
  1034. if PVarData(PPointer(Params)^)^.VType=varString then
  1035. begin
  1036. {$ifdef DEBUG_COMDISPATCH}
  1037. if printcom then
  1038. writeln(' Casting nested varString: ',Ansistring(PVarData(Params^)^.vString));
  1039. {$endif DEBUG_COMDISPATCH}
  1040. VarCast(PVariant(Params^)^,PVariant(Params^)^,varOleStr);
  1041. end;
  1042. Arguments[i].VType:=varVariant or varByRef;
  1043. Arguments[i].VPointer:=PPointer(Params)^;
  1044. inc(PPointer(Params));
  1045. end
  1046. else
  1047. begin
  1048. {$ifdef DEBUG_COMDISPATCH}
  1049. if printcom then
  1050. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  1051. case CurrType of
  1052. varOleStr: if printcom then
  1053. write(' Value = ',pwidestring(PPointer(Params)^)^);
  1054. end;
  1055. if printcom then
  1056. writeln;
  1057. {$endif DEBUG_COMDISPATCH}
  1058. Arguments[i].VType:=CurrType or VarByRef;
  1059. Arguments[i].VPointer:=PPointer(Params)^;
  1060. inc(PPointer(Params));
  1061. end;
  1062. end
  1063. end
  1064. else { by-value argument }
  1065. case CurrType of
  1066. varStrArg:
  1067. begin
  1068. {$ifdef DEBUG_COMDISPATCH}
  1069. if printcom then
  1070. writeln('Translating ansistring argument ',PString(Params)^);
  1071. {$endif DEBUG_COMDISPATCH}
  1072. StringMap[NextString].ComStr:=StringToOleStr(PString(Params)^);
  1073. StringMap[NextString].PasStr:=nil;
  1074. Arguments[i].VType:=varOleStr;
  1075. Arguments[i].VPointer:=StringMap[NextString].ComStr;
  1076. inc(NextString);
  1077. inc(PPointer(Params));
  1078. end;
  1079. varVariant:
  1080. begin
  1081. {$ifdef DEBUG_COMDISPATCH}
  1082. if printcom then
  1083. writeln('By-value Variant, making a copy');
  1084. {$endif DEBUG_COMDISPATCH}
  1085. { Codegen always passes a pointer to variant,
  1086. *unlike* Delphi which pushes the entire TVarData }
  1087. Arguments[i]:=PVarData(PPointer(Params)^)^;
  1088. Inc(PPointer(Params));
  1089. end;
  1090. varCurrency,
  1091. varDouble,
  1092. varInt64,
  1093. varQWord,
  1094. varDate:
  1095. begin
  1096. {$ifdef DEBUG_COMDISPATCH}
  1097. if printcom then
  1098. writeln('Got 8 byte argument');
  1099. {$endif DEBUG_COMDISPATCH}
  1100. Arguments[i].VType:=CurrType;
  1101. Arguments[i].VDouble:=PDouble(Params)^;
  1102. inc(PDouble(Params));
  1103. end;
  1104. else
  1105. begin
  1106. {$ifdef DEBUG_COMDISPATCH}
  1107. if printcom then
  1108. write('DispatchInvoke: Got argument with type ',CurrType);
  1109. case CurrType of
  1110. varOleStr: if printcom then
  1111. write(' Value = ',pwidestring(Params)^);
  1112. else
  1113. if printcom then
  1114. write(' Value = ',hexstr(PtrInt(PPointer(Params)^),SizeOf(Pointer)*2));
  1115. end;
  1116. writeln;
  1117. {$endif DEBUG_COMDISPATCH}
  1118. Arguments[i].VType:=CurrType;
  1119. Arguments[i].VPointer:=PPointer(Params)^;
  1120. inc(PPointer(Params));
  1121. end;
  1122. end;
  1123. end;
  1124. { finally prepare the call }
  1125. with DispParams do
  1126. begin
  1127. rgvarg:=@Arguments;
  1128. cNamedArgs:=CallDesc^.NamedArgCount;
  1129. if cNamedArgs=0 then
  1130. rgdispidNamedArgs:=nil
  1131. else
  1132. rgdispidNamedArgs:=@DispIDs^[1];
  1133. cArgs:=CallDesc^.ArgCount;
  1134. end;
  1135. InvokeKind:=CallDesc^.CallType;
  1136. MethodID:=DispIDs^[0];
  1137. case InvokeKind of
  1138. DISPATCH_PROPERTYPUT:
  1139. begin
  1140. if (Arguments[0].VType and varTypeMask) = varDispatch then
  1141. InvokeKind:=DISPATCH_PROPERTYPUTREF;
  1142. { first name is actually the name of the property to set }
  1143. DispIDs^[0]:=DISPID_PROPERTYPUT;
  1144. DispParams.rgdispidNamedArgs:=@DispIDs^[0];
  1145. inc(DispParams.cNamedArgs);
  1146. end;
  1147. DISPATCH_METHOD:
  1148. { It appears that certain COM servers expect both DISPATCH_METHOD and DISPATCH_PROPERTYGET
  1149. flags for anything returning a result, see bug #24352 }
  1150. if assigned(Result) then
  1151. InvokeKind:=DISPATCH_METHOD or DISPATCH_PROPERTYGET;
  1152. end;
  1153. {$ifdef DEBUG_COMDISPATCH}
  1154. if printcom then
  1155. writeln('DispatchInvoke: MethodID: ',MethodID,' InvokeKind: ',InvokeKind);
  1156. {$endif DEBUG_COMDISPATCH}
  1157. { do the call and check the result }
  1158. invokeresult:=Dispatch.Invoke(MethodID,GUID_NULL,0,InvokeKind,DispParams,result,@exceptioninfo,nil);
  1159. if invokeresult<>0 then
  1160. DispatchInvokeError(invokeresult,exceptioninfo);
  1161. { translate strings back }
  1162. for i:=0 to NextString-1 do
  1163. if assigned(StringMap[i].passtr) then
  1164. OleStrToStrVar(StringMap[i].comstr,StringMap[i].passtr^);
  1165. finally
  1166. for i:=0 to NextString-1 do
  1167. SysFreeString(StringMap[i].ComStr);
  1168. end;
  1169. end;
  1170. procedure SearchIDs(const DispatchInterface : IDispatch; Names: PChar;
  1171. Count: Integer; IDs: PDispIDList);
  1172. var
  1173. res : HRESULT;
  1174. NamesArray : ^PWideChar;
  1175. NamesData : PWideChar;
  1176. OrigNames : PChar;
  1177. NameCount,
  1178. NameLen,
  1179. NewNameLen,
  1180. CurrentNameDataUsed,
  1181. CurrentNameDataSize : SizeInt;
  1182. i : longint;
  1183. begin
  1184. getmem(NamesArray,Count*sizeof(PWideChar));
  1185. CurrentNameDataSize:=256;
  1186. CurrentNameDataUsed:=0;
  1187. getmem(NamesData,CurrentNameDataSize);
  1188. NameCount:=0;
  1189. OrigNames:=Names;
  1190. {$ifdef DEBUG_COMDISPATCH}
  1191. if printcom then
  1192. writeln('SearchIDs: Searching ',Count,' IDs');
  1193. {$endif DEBUG_COMDISPATCH}
  1194. for i:=1 to Count do
  1195. begin
  1196. NameLen:=strlen(Names);
  1197. {$ifdef DEBUG_COMDISPATCH}
  1198. if printcom then
  1199. writeln('SearchIDs: Original name: ',Names,' Len: ',NameLen);
  1200. {$endif DEBUG_COMDISPATCH}
  1201. NewNameLen:=MultiByteToWideChar(0,0,Names,NameLen,nil,0)+1;
  1202. if (CurrentNameDataUsed+NewNameLen)*2>CurrentNameDataSize then
  1203. begin
  1204. inc(CurrentNameDataSize,256);
  1205. reallocmem(NamesData,CurrentNameDataSize);
  1206. end;
  1207. NamesArray[i-1]:=@NamesData[CurrentNameDataUsed];
  1208. MultiByteToWideChar(0,0,Names,NameLen,@NamesData[CurrentNameDataUsed],NewNameLen);
  1209. NamesData[CurrentNameDataUsed+NewNameLen-1]:=#0;
  1210. {$ifdef DEBUG_COMDISPATCH}
  1211. if printcom then
  1212. writeln('SearchIDs: Translated name: ',WideString(PWideChar(@NamesData[CurrentNameDataUsed])));
  1213. {$endif DEBUG_COMDISPATCH}
  1214. inc(CurrentNameDataUsed,NewNameLen);
  1215. inc(Names,NameLen+1);
  1216. inc(NameCount);
  1217. end;
  1218. res:=DispatchInterface.GetIDsOfNames(GUID_NULL,NamesArray,NameCount,
  1219. {$ifdef wince}
  1220. LOCALE_SYSTEM_DEFAULT
  1221. {$else wince}
  1222. GetThreadLocale
  1223. {$endif wince}
  1224. ,IDs);
  1225. {$ifdef DEBUG_COMDISPATCH}
  1226. if printcom then
  1227. writeln('SearchIDs: GetIDsOfNames result = ',hexstr(res,SizeOf(HRESULT)*2));
  1228. for i:=0 to Count-1 do
  1229. writeln('SearchIDs: ID[',i,'] = ',ids^[i]);
  1230. {$endif DEBUG_COMDISPATCH}
  1231. if res=DISP_E_UNKNOWNNAME then
  1232. raise EOleError.createresfmt(@snomethod,[OrigNames])
  1233. else
  1234. OleCheck(res);
  1235. freemem(NamesArray);
  1236. freemem(NamesData);
  1237. end;
  1238. procedure ComObjDispatchInvoke(dest : PVariant;const source : Variant;
  1239. calldesc : pcalldesc;params : pointer);cdecl;
  1240. var
  1241. dispatchinterface : pointer;
  1242. ids : array[0..255] of TDispID;
  1243. begin
  1244. fillchar(ids,sizeof(ids),0);
  1245. {$ifdef DEBUG_COMDISPATCH}
  1246. if printcom then
  1247. writeln('ComObjDispatchInvoke called');
  1248. if printcom then
  1249. writeln('ComObjDispatchInvoke: @CallDesc = $',hexstr(PtrInt(CallDesc),SizeOf(Pointer)*2),' CallDesc^.ArgCount = ',CallDesc^.ArgCount);
  1250. {$endif DEBUG_COMDISPATCH}
  1251. if tvardata(source).vtype=VarDispatch then
  1252. dispatchinterface:=tvardata(source).vdispatch
  1253. else if tvardata(source).vtype=(VarDispatch or VarByRef) then
  1254. dispatchinterface:=pvardata(tvardata(source).vpointer)^.vdispatch
  1255. else
  1256. raise eoleerror.createres(@SVarNotObject);
  1257. SearchIDs(IDispatch(dispatchinterface),@CallDesc^.ArgTypes[CallDesc^.ArgCount],
  1258. CallDesc^.NamedArgCount+1,@ids);
  1259. if assigned(dest) then
  1260. VarClear(dest^);
  1261. DispatchInvoke(IDispatch(dispatchinterface),calldesc,@ids,params,dest);
  1262. end;
  1263. { $define DEBUG_DISPATCH}
  1264. procedure DoDispCallByID(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  1265. var
  1266. exceptioninfo : TExcepInfo;
  1267. dispparams : TDispParams;
  1268. flags : WORD;
  1269. invokeresult : HRESULT;
  1270. preallocateddata : array[0..15] of TVarData;
  1271. Arguments : PVarData;
  1272. CurrType, i : byte;
  1273. dispidNamed: TDispID;
  1274. begin
  1275. { use preallocated space, i.e. can we avoid a getmem call? }
  1276. if desc^.calldesc.argcount<=Length(preallocateddata) then
  1277. Arguments:=@preallocateddata
  1278. else
  1279. GetMem(Arguments,desc^.calldesc.argcount*sizeof(TVarData));
  1280. { prepare parameters }
  1281. if desc^.CallDesc.ArgCount > 0 then
  1282. for i:=0 to desc^.CallDesc.ArgCount-1 do
  1283. begin
  1284. {$ifdef DEBUG_DISPATCH}
  1285. writeln('DoDispCallByID: Params = ',hexstr(Params));
  1286. {$endif DEBUG_DISPATCH}
  1287. { get plain type }
  1288. CurrType:=desc^.CallDesc.ArgTypes[i] and $3f;
  1289. { by reference? }
  1290. if (desc^.CallDesc.ArgTypes[i] and $80)<>0 then
  1291. begin
  1292. {$ifdef DEBUG_DISPATCH}
  1293. write('DispatchInvoke: Got ref argument with type = ',CurrType);
  1294. writeln;
  1295. {$endif DEBUG_DISPATCH}
  1296. Arguments[i].VType:=CurrType or VarByRef;
  1297. Arguments[i].VPointer:=PPointer(Params)^;
  1298. inc(PPointer(Params));
  1299. end
  1300. else
  1301. begin
  1302. {$ifdef DEBUG_DISPATCH}
  1303. writeln('DispatchInvoke: Got value argument with type = ',CurrType);
  1304. {$endif DEBUG_DISPATCH}
  1305. case CurrType of
  1306. varVariant:
  1307. begin
  1308. { Codegen always passes a pointer to variant,
  1309. *unlike* Delphi which pushes the entire TVarData }
  1310. Arguments[i]:=PVarData(PPointer(Params)^)^;
  1311. inc(PPointer(Params));
  1312. end;
  1313. varCurrency,
  1314. varDouble,
  1315. varInt64,
  1316. varQWord,
  1317. varDate:
  1318. begin
  1319. {$ifdef DEBUG_DISPATCH}
  1320. writeln('DispatchInvoke: Got 8 byte argument');
  1321. {$endif DEBUG_DISPATCH}
  1322. Arguments[i].VType:=CurrType;
  1323. Arguments[i].VDouble:=PDouble(Params)^;
  1324. inc(PDouble(Params));
  1325. end;
  1326. else
  1327. begin
  1328. {$ifdef DEBUG_DISPATCH}
  1329. writeln('DispatchInvoke: Got argument with type ',CurrType);
  1330. {$endif DEBUG_DISPATCH}
  1331. Arguments[i].VType:=CurrType;
  1332. Arguments[i].VPointer:=PPointer(Params)^;
  1333. inc(PPointer(Params));
  1334. end;
  1335. end;
  1336. end;
  1337. end;
  1338. dispparams.cArgs:=desc^.calldesc.argcount;
  1339. dispparams.rgvarg:=pointer(Arguments);
  1340. dispparams.cNamedArgs:=desc^.calldesc.namedargcount;
  1341. dispparams.rgdispidNamedArgs:=@desc^.CallDesc.ArgTypes[desc^.CallDesc.ArgCount];
  1342. flags:=desc^.calldesc.calltype;
  1343. case flags of
  1344. DISPATCH_PROPERTYPUT:
  1345. begin
  1346. inc(dispparams.cNamedArgs);
  1347. if (Arguments[0].VType and varTypeMask) = varDispatch then
  1348. flags:=DISPATCH_PROPERTYPUTREF;
  1349. dispidNamed:=DISPID_PROPERTYPUT;
  1350. DispParams.rgdispidNamedArgs:=@dispidNamed;
  1351. end;
  1352. DISPATCH_METHOD:
  1353. { It appears that certain COM servers expect both DISPATCH_METHOD and DISPATCH_PROPERTYGET
  1354. flags for anything returning a result, see bug #24352 }
  1355. if assigned(res) then
  1356. flags:=DISPATCH_METHOD or DISPATCH_PROPERTYGET;
  1357. end;
  1358. invokeresult:=disp.Invoke(
  1359. desc^.DispId, { DispID: LongInt; }
  1360. GUID_NULL, { const iid : TGUID; }
  1361. 0, { LocaleID : longint; }
  1362. flags, { Flags: Word; }
  1363. dispparams, { var params; }
  1364. res,@exceptioninfo,nil { VarResult,ExcepInfo,ArgErr : pointer) }
  1365. );
  1366. if invokeresult<>0 then
  1367. DispatchInvokeError(invokeresult,exceptioninfo);
  1368. if desc^.calldesc.argcount>Length(preallocateddata) then
  1369. FreeMem(Arguments);
  1370. end;
  1371. { TTypedComObject }
  1372. function TTypedComObject.GetClassInfo(out pptti: ITypeInfo): HResult;stdcall;
  1373. begin
  1374. Result:=S_OK;
  1375. pptti:=TTypedComObjectFactory(factory).classinfo;
  1376. end;
  1377. { TTypedComObjectFactory }
  1378. constructor TTypedComObjectFactory.Create(AComServer: TComServerObject; TypedComClass: TTypedComClass; const AClassID: TGUID;
  1379. AInstancing: TClassInstancing; AThreadingModel: TThreadingModel = tmSingle);
  1380. var
  1381. TypedName, TypedDescription, TypedVersion: WideString;
  1382. ppTypeAttr: lpTYPEATTR;
  1383. begin
  1384. //TDB get name and description from typelib (check if this is a valid guid)
  1385. OleCheck(AComServer.GetTypeLib.GetTypeInfoOfGuid(AClassID, FClassInfo));
  1386. //bug FPC 0010569 - http://msdn2.microsoft.com/en-us/library/ms221396(VS.85).aspx
  1387. OleCheck(FClassInfo.GetDocumentation(-1, @TypedName, @TypedDescription, nil, nil));
  1388. FClassInfo.GetTypeAttr(ppTypeAttr);
  1389. try
  1390. FTypeInfoCount := ppTypeAttr^.cImplTypes;
  1391. TypedVersion := '';
  1392. if (ppTypeAttr^.wMajorVerNum <> 0) or (ppTypeAttr^.wMinorVerNum <> 0) then
  1393. begin
  1394. TypedVersion := IntToStr(ppTypeAttr^.wMajorVerNum);
  1395. if ppTypeAttr^.wMinorVerNum <> 0 then
  1396. TypedVersion := TypedVersion + '.' + IntToStr(ppTypeAttr^.wMinorVerNum)
  1397. end;
  1398. finally
  1399. FClassInfo.ReleaseTypeAttr(ppTypeAttr);
  1400. end;
  1401. inherited Create(AComServer, TypedComClass, AClassID, TypedName, TypedVersion, TypedDescription, AInstancing, AThreadingModel);
  1402. end;
  1403. function TTypedComObjectFactory.GetInterfaceTypeInfo(TypeFlags: Integer): ITypeInfo;
  1404. var
  1405. index, ImplTypeFlags: Integer;
  1406. RefType: HRefType;
  1407. begin
  1408. Result := nil;
  1409. for index := 0 to FTypeInfoCount - 1 do
  1410. begin
  1411. OleCheck(ClassInfo.GetImplTypeFlags(index, ImplTypeFlags));
  1412. if ImplTypeFlags = TypeFlags then
  1413. begin
  1414. OleCheck(ClassInfo.GetRefTypeOfImplType(index, RefType));
  1415. OleCheck(ClassInfo.GetRefTypeInfo(RefType, Result));
  1416. break;
  1417. end;
  1418. end;
  1419. end;
  1420. procedure TTypedComObjectFactory.UpdateRegistry(Register: Boolean);
  1421. var
  1422. ptla: PTLibAttr;
  1423. begin
  1424. if Instancing = ciInternal then
  1425. Exit;
  1426. if Register then
  1427. begin
  1428. inherited UpdateRegistry(Register);
  1429. //http://www.experts-exchange.com/Programming/Misc/Q_20634807.html
  1430. //There seems to also be Version according to Process Monitor
  1431. //http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx
  1432. if FComServer.TypeLib = nil then
  1433. raise Exception.Create('TypeLib is not set!');
  1434. OleCheck(FComServer.TypeLib.GetLibAttr(ptla));
  1435. try
  1436. CreateRegKey('CLSID\' + GUIDToString(ClassID) + '\TypeLib', '', GUIDToString(ptla^.GUID));
  1437. finally
  1438. FComServer.TypeLib.ReleaseTLibAttr(ptla);
  1439. end;
  1440. end else
  1441. begin
  1442. DeleteRegKey('CLSID\' + GUIDToString(ClassID) + '\TypeLib');
  1443. inherited UpdateRegistry(Register);
  1444. end;
  1445. end;
  1446. { TAutoIntfObject }
  1447. function TAutoIntfObject.GetTypeInfoCount(out count: longint): HResult; stdcall;
  1448. begin
  1449. {$ifdef DEBUG_COM}
  1450. if printcom then
  1451. WriteLn('TAutoIntfObject.GetTypeInfoCount');
  1452. {$endif}
  1453. count := 1;
  1454. Result := S_OK;
  1455. end;
  1456. function TAutoIntfObject.GetTypeInfo(Index, LocaleID: longint; out TypeInfo
  1457. ): HResult; stdcall;
  1458. begin
  1459. {$ifdef DEBUG_COM}
  1460. if printcom then
  1461. WriteLn('TAutoIntfObject.GetTypeInfo: ', Index);
  1462. {$endif}
  1463. if Index <> 0 then
  1464. Result := DISP_E_BADINDEX
  1465. else
  1466. begin
  1467. ITypeInfo(TypeInfo) := fTypeInfo;
  1468. Result := S_OK;
  1469. end;
  1470. end;
  1471. function TAutoIntfObject.GetIDsOfNames(const iid: TGUID; names: Pointer;
  1472. NameCount, LocaleID: LongInt; DispIDs: Pointer): HResult; stdcall;
  1473. begin
  1474. {$ifdef DEBUG_COM}
  1475. if printcom then
  1476. WriteLn('TAutoIntfObject.GetIDsOfNames: ', GUIDToString(iid));
  1477. {$endif}
  1478. //return typeinfo->GetIDsOfNames(names, n, dispids);
  1479. Result := fTypeInfo.GetIDsOfNames(names, NameCount, lpDISPID(DispIDs)^);
  1480. end;
  1481. function TAutoIntfObject.Invoke(DispID: LongInt; const iid: TGUID;
  1482. LocaleID: longint; Flags: Word; var params; VarResult, ExcepInfo,
  1483. ArgErr: pointer): HResult; stdcall;
  1484. begin
  1485. {$ifdef DEBUG_COM}
  1486. if printcom then
  1487. WriteLn('TAutoIntfObject.Invoke: ', DispID, ': ', Flags, ': ', TDispParams(params).cArgs, ': ', GUIDToString(iid));
  1488. //WriteLn('TAutoIntfObject.Invoke: ', DispID, ': ', Flags, ': ', TDispParams(params).cArgs, ': ', TDispParams(params).rgvarg^, ': ', GUIDToString(iid));
  1489. {$endif}
  1490. if not IsEqualGUID(iid, GUID_NULL) then
  1491. Result := DISP_E_UNKNOWNINTERFACE
  1492. else
  1493. // Function Invoke(pvInstance: Pointer; memid: MEMBERID; wFlags: WORD; VAR pDispParams: DISPPARAMS; OUT pVarResult: VARIANT; OUT pExcepInfo: EXCEPINFO; OUT puArgErr: UINT):HResult;StdCall;
  1494. // Result := fTypeInfo.Invoke(IDispatch(Self), DispID, Flags, TDispParams(params), PVariant(VarResult)^, PExcepInfo(ExcepInfo)^, PUINT(ArgErr)^);
  1495. Result := fTypeInfo.Invoke(fInterfacePointer, DispID, Flags, TDispParams(params), VarResult, ExcepInfo, ArgErr);
  1496. end;
  1497. function TAutoIntfObject.InterfaceSupportsErrorInfo(const riid: TIID): HResult;
  1498. StdCall;
  1499. begin
  1500. {$ifdef DEBUG_COM}
  1501. if printcom then
  1502. WriteLn('TAutoIntfObject.InterfaceSupportsErrorInfo: ', GUIDToString(riid));
  1503. {$endif}
  1504. if assigned(GetInterfaceEntry(riid)) then
  1505. Result:=S_OK
  1506. else
  1507. Result:=S_FALSE;
  1508. end;
  1509. function TAutoIntfObject.SafeCallException(ExceptObject: TObject;
  1510. ExceptAddr: Pointer): HResult;
  1511. var
  1512. //Message: string;
  1513. Handled: Integer;
  1514. begin
  1515. {$ifdef DEBUG_COM}
  1516. if printcom then
  1517. WriteLn('TAutoIntfObject.SafeCallException');
  1518. {$endif}
  1519. Handled:=0;
  1520. Result:=0;
  1521. //TODO: DO WE NEED THIS ?
  1522. //if assigned(ServerExceptionHandler) then
  1523. // begin
  1524. // if ExceptObject is Exception then
  1525. // Message:=Exception(ExceptObject).Message;
  1526. //
  1527. // ServerExceptionHandler.OnException(ClassName,ExceptObject.ClassName,
  1528. // Message,PtrInt(ExceptAddr),WideString(GUIDToString(FFactory.ErrorIID)),
  1529. // FFactory.ProgID,Handled,Result);
  1530. // end;
  1531. if Handled=0 then
  1532. Result:=HandleSafeCallException(ExceptObject,ExceptAddr,StringToGuid('{7C538328-8A75-4EC4-A02E-FB3B27FAA411}'),
  1533. '','');
  1534. end;
  1535. constructor TAutoIntfObject.Create(TypeLib: ITypeLib; const Guid: TGuid);
  1536. begin
  1537. {$ifdef DEBUG_COM}
  1538. if printcom then
  1539. WriteLn('TAutoIntfObject.Create: ', GUIDToString(Guid));
  1540. {$endif}
  1541. OleCheck(TypeLib.GetTypeInfoOfGuid(Guid, fTypeInfo));
  1542. OleCheck(QueryInterface(Guid, fInterfacePointer));
  1543. end;
  1544. { TAutoObject }
  1545. function TAutoObject.GetTypeInfoCount(out count: longint): HResult; stdcall;
  1546. begin
  1547. {$ifdef DEBUG_COM}
  1548. if printcom then
  1549. WriteLn('TAutoObject.GetTypeInfoCount');
  1550. {$endif}
  1551. count := 1;
  1552. Result := S_OK;
  1553. end;
  1554. function TAutoObject.GetTypeInfo(Index, LocaleID: longint; out TypeInfo
  1555. ): HResult; stdcall;
  1556. begin
  1557. {$ifdef DEBUG_COM}
  1558. if printcom then
  1559. WriteLn('TAutoIntfObject.GetTypeInfo: ', Index);
  1560. {$endif}
  1561. if Index <> 0 then
  1562. Result := DISP_E_BADINDEX
  1563. else
  1564. begin
  1565. ITypeInfo(TypeInfo) := TAutoObjectFactory(Factory).ClassInfo;
  1566. Result := S_OK;
  1567. end;
  1568. end;
  1569. function TAutoObject.GetIDsOfNames(const iid: TGUID; names: Pointer; NameCount,
  1570. LocaleID: LongInt; DispIDs: Pointer): HResult; stdcall;
  1571. begin
  1572. {$ifdef DEBUG_COM}
  1573. if printcom then
  1574. WriteLn('TAutoIntfObject.GetIDsOfNames: ', GUIDToString(iid));
  1575. {$endif}
  1576. //return typeinfo->GetIDsOfNames(names, n, dispids);
  1577. Result := TAutoObjectFactory(Factory).ClassInfo.GetIDsOfNames(names, NameCount, lpDISPID(DispIDs)^);
  1578. end;
  1579. function TAutoObject.Invoke(DispID: LongInt; const iid: TGUID;
  1580. LocaleID: longint; Flags: Word; var params; VarResult, ExcepInfo,
  1581. ArgErr: pointer): HResult; stdcall;
  1582. begin
  1583. {$ifdef DEBUG_COM}
  1584. if printcom then
  1585. WriteLn('TAutoIntfObject.Invoke: ', DispID, ': ', Flags, ': ', TDispParams(params).cArgs, ': ', GUIDToString(iid));
  1586. //WriteLn('TAutoIntfObject.Invoke: ', DispID, ': ', Flags, ': ', TDispParams(params).cArgs, ': ', TDispParams(params).rgvarg^, ': ', GUIDToString(iid));
  1587. {$endif}
  1588. if not IsEqualGUID(iid, GUID_NULL) then
  1589. Result := DISP_E_UNKNOWNINTERFACE
  1590. else
  1591. begin
  1592. Result := TAutoObjectFactory(Factory).DispTypeInfo.Invoke(Pointer(
  1593. PtrUint(Self) + TAutoObjectFactory(Factory).DispIntfEntry^.IOffset),
  1594. DispID, Flags, TDispParams(Params), VarResult, ExcepInfo, ArgErr);
  1595. end;
  1596. end;
  1597. { TAutoObjectFactory }
  1598. constructor TAutoObjectFactory.Create(AComServer: TComServerObject;
  1599. AutoClass: TAutoClass; const AClassID: TGUID; AInstancing: TClassInstancing;
  1600. AThreadingModel: TThreadingModel);
  1601. var
  1602. ppTypeAttr: lpTYPEATTR;
  1603. begin
  1604. inherited Create(AComServer, AutoClass, AClassID, AInstancing, AThreadingModel);
  1605. FDispTypeInfo := GetInterfaceTypeInfo(IMPLTYPEFLAG_FDEFAULT);
  1606. OleCheck(FDispTypeInfo.GetTypeAttr(ppTypeAttr));
  1607. try
  1608. FDispIntfEntry := GetIntfEntry(ppTypeAttr^.guid);
  1609. finally
  1610. FDispTypeInfo.ReleaseTypeAttr(ppTypeAttr);
  1611. end;
  1612. end;
  1613. function TAutoObjectFactory.GetIntfEntry(Guid: TGUID): PInterfaceEntry;
  1614. begin
  1615. Result := FComClass.GetInterfaceEntry(Guid);
  1616. end;
  1617. procedure TOleStream.Check(err:integer);
  1618. begin
  1619. OleCheck(err);
  1620. end;
  1621. const
  1622. Initialized : boolean = false;
  1623. var
  1624. Ole32Dll : HModule;
  1625. initialization
  1626. Uninitializing:=false;
  1627. _ComClassManager:=nil;
  1628. Ole32Dll:=GetModuleHandle('ole32.dll');
  1629. if Ole32Dll<>0 then
  1630. begin
  1631. Pointer(CoCreateInstanceEx):=GetProcAddress(Ole32Dll,'CoCreateInstanceEx');
  1632. Pointer(CoInitializeEx):=GetProcAddress(Ole32Dll,'CoInitializeEx');
  1633. Pointer(CoAddRefServerProcess):=GetProcAddress(Ole32Dll,'CoAddRefServerProcess');
  1634. Pointer(CoReleaseServerProcess):=GetProcAddress(Ole32Dll,'CoReleaseServerProcess');
  1635. Pointer(CoResumeClassObjects):=GetProcAddress(Ole32Dll,'CoResumeClassObjects');
  1636. Pointer(CoSuspendClassObjects):=GetProcAddress(Ole32Dll,'CoSuspendClassObjects');
  1637. end;
  1638. if not(IsLibrary) then
  1639. {$ifndef wince}
  1640. if (CoInitFlags=-1) or not(assigned(comobj.CoInitializeEx)) then
  1641. Initialized:=Succeeded(CoInitialize(nil))
  1642. else
  1643. {$endif wince}
  1644. Initialized:=Succeeded(comobj.CoInitializeEx(nil, CoInitFlags));
  1645. SafeCallErrorProc:=@SafeCallErrorHandler;
  1646. VarDispProc:=@ComObjDispatchInvoke;
  1647. DispCallByIDProc:=@DoDispCallByID;
  1648. finalization
  1649. Uninitializing:=true;
  1650. _ComClassManager.Free;
  1651. VarDispProc:=nil;
  1652. SafeCallErrorProc:=nil;
  1653. if Initialized then
  1654. CoUninitialize;
  1655. end.