comobj.pp 68 KB

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