DragDropComObj.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. unit DragDropComObj;
  2. // -----------------------------------------------------------------------------
  3. // Project: Drag and Drop Component Suite.
  4. // Module: DragDropComObj
  5. // Description: Implements misc COM support classes.
  6. // Version: 4.0
  7. // Date: 18-MAY-2001
  8. // Target: Win32, Delphi 5-6
  9. // Authors: Anders Melander, anders@melander.dk, http://www.melander.dk
  10. // Copyright © 1997-2001 Angus Johnson & Anders Melander
  11. // -----------------------------------------------------------------------------
  12. interface
  13. uses
  14. ComObj,
  15. Classes,
  16. ActiveX;
  17. {$include DragDrop.inc}
  18. ////////////////////////////////////////////////////////////////////////////////
  19. //
  20. // TVCLComObject
  21. //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // Based on TVCLAutoObject.
  24. ////////////////////////////////////////////////////////////////////////////////
  25. type
  26. TVCLComObject = class(TComObject, IVCLComObject, IUnknown)
  27. private
  28. FComponent: TComponent;
  29. FOwnsComponent: Boolean;
  30. protected
  31. // IVCLComObject implementation
  32. procedure FreeOnRelease;
  33. function Invoke(DispID: Integer; const IID: TGUID;
  34. LocaleID: Integer; Flags: Word; var Params;
  35. VarResult, ExcepInfo, ArgErr: Pointer): HResult; virtual; stdcall;
  36. function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  37. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; virtual; stdcall;
  38. function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; virtual; stdcall;
  39. function GetTypeInfoCount(out Count: Integer): HResult; virtual; stdcall;
  40. public
  41. // TODO : For now, please ignore linker warning about TVCLComObject.Create
  42. constructor Create(Factory: TComObjectFactory; Component: TComponent);
  43. destructor Destroy; override;
  44. procedure Initialize; override;
  45. function ObjQueryInterface(const IID: TGUID; out Obj): HResult; override;
  46. end;
  47. ////////////////////////////////////////////////////////////////////////////////
  48. //
  49. // TVCLComObjectFactory
  50. //
  51. ////////////////////////////////////////////////////////////////////////////////
  52. // Class factory for component based COM classes.
  53. // Does not require a type library.
  54. // Based on TComponentFactory and TComObjectFactory.
  55. ////////////////////////////////////////////////////////////////////////////////
  56. type
  57. TVCLComObjectFactory = class(TComObjectFactory, IClassFactory)
  58. private
  59. protected
  60. function CreateInstance(const UnkOuter: IUnknown; const IID: TGUID;
  61. out Obj): HResult; stdcall;
  62. public
  63. constructor Create(ComServer: TComServerObject; ComponentClass: TComponentClass;
  64. const ClassID: TGUID; const ClassName, Description: string;
  65. Instancing: TClassInstancing);
  66. function CreateComObject(const Controller: IUnknown): TComObject; override;
  67. procedure UpdateRegistry(Register: Boolean); override;
  68. end;
  69. ////////////////////////////////////////////////////////////////////////////////
  70. //
  71. // TShellExtFactory
  72. //
  73. ////////////////////////////////////////////////////////////////////////////////
  74. // Class factory for component based COM classes.
  75. // Specialized for Shell Extensions.
  76. ////////////////////////////////////////////////////////////////////////////////
  77. TShellExtFactory = class(TVCLComObjectFactory)
  78. private
  79. FFileExtension: string;
  80. FFileClass: string;
  81. protected
  82. public
  83. constructor Create(ComServer: TComServerObject; ComponentClass: TComponentClass;
  84. const ClassID: TGUID; const ClassName, Description, AFileClass,
  85. AFileExtension: string; Instancing: TClassInstancing);
  86. procedure UpdateRegistry(Register: Boolean); override;
  87. property FileClass: string read FFileClass write FFileClass;
  88. property FileExtension: string read FFileExtension write FFileExtension;
  89. end;
  90. ////////////////////////////////////////////////////////////////////////////////
  91. ////////////////////////////////////////////////////////////////////////////////
  92. //
  93. // IMPLEMENTATION
  94. //
  95. ////////////////////////////////////////////////////////////////////////////////
  96. ////////////////////////////////////////////////////////////////////////////////
  97. implementation
  98. uses
  99. Windows;
  100. ////////////////////////////////////////////////////////////////////////////////
  101. //
  102. // TVCLComObject
  103. //
  104. ////////////////////////////////////////////////////////////////////////////////
  105. constructor TVCLComObject.Create(Factory: TComObjectFactory;
  106. Component: TComponent);
  107. begin
  108. FComponent := Component;
  109. CreateFromFactory(Factory, nil);
  110. end;
  111. destructor TVCLComObject.Destroy;
  112. begin
  113. if FComponent <> nil then
  114. begin
  115. FComponent.VCLComObject := nil;
  116. if FOwnsComponent then
  117. FComponent.Free;
  118. end;
  119. inherited Destroy;
  120. end;
  121. procedure TVCLComObject.FreeOnRelease;
  122. begin
  123. FOwnsComponent := True;
  124. end;
  125. function TVCLComObject.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  126. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
  127. begin
  128. Result := E_NOTIMPL;
  129. end;
  130. function TVCLComObject.GetTypeInfo(Index, LocaleID: Integer;
  131. out TypeInfo): HResult;
  132. begin
  133. Pointer(TypeInfo) := nil;
  134. Result := E_NOTIMPL;
  135. end;
  136. function TVCLComObject.GetTypeInfoCount(out Count: Integer): HResult;
  137. begin
  138. Count := 0;
  139. Result := E_NOTIMPL;
  140. end;
  141. procedure TVCLComObject.Initialize;
  142. begin
  143. inherited Initialize;
  144. if FComponent = nil then
  145. begin
  146. FComponent := TComponentClass(Factory.ComClass).Create(nil);
  147. FOwnsComponent := True;
  148. end;
  149. FComponent.VCLComObject := Pointer(IVCLComObject(Self));
  150. end;
  151. function TVCLComObject.Invoke(DispID: Integer; const IID: TGUID;
  152. LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  153. ArgErr: Pointer): HResult;
  154. begin
  155. Result := E_NOTIMPL;
  156. end;
  157. function TVCLComObject.ObjQueryInterface(const IID: TGUID;
  158. out Obj): HResult;
  159. begin
  160. Result := inherited ObjQueryInterface(IID, Obj);
  161. if (Result <> 0) and (FComponent <> nil) then
  162. if FComponent.GetInterface(IID, Obj) then
  163. Result := 0;
  164. end;
  165. ////////////////////////////////////////////////////////////////////////////////
  166. //
  167. // TApartmentThread
  168. //
  169. ////////////////////////////////////////////////////////////////////////////////
  170. // Copied from VCLCom unit.
  171. ////////////////////////////////////////////////////////////////////////////////
  172. type
  173. TApartmentThread = class(TThread)
  174. private
  175. FFactory: IClassFactory2;
  176. FUnkOuter: IUnknown;
  177. FIID: TGuid;
  178. FSemaphore: THandle;
  179. FStream: Pointer;
  180. FCreateResult: HResult;
  181. protected
  182. procedure Execute; override;
  183. public
  184. constructor Create(Factory: IClassFactory2; UnkOuter: IUnknown; IID: TGuid);
  185. destructor Destroy; override;
  186. property Semaphore: THandle read FSemaphore;
  187. property CreateResult: HResult read FCreateResult;
  188. property ObjStream: Pointer read FStream;
  189. end;
  190. constructor TApartmentThread.Create(Factory: IClassFactory2;
  191. UnkOuter: IUnknown; IID: TGuid);
  192. begin
  193. FFactory := Factory;
  194. FUnkOuter := UnkOuter;
  195. FIID := IID;
  196. FSemaphore := CreateSemaphore(nil, 0, 1, nil);
  197. FreeOnTerminate := True;
  198. inherited Create(False);
  199. end;
  200. destructor TApartmentThread.Destroy;
  201. begin
  202. CloseHandle(FSemaphore);
  203. inherited Destroy;
  204. end;
  205. procedure TApartmentThread.Execute;
  206. var
  207. msg: TMsg;
  208. Unk: IUnknown;
  209. begin
  210. try
  211. CoInitialize(nil);
  212. try
  213. FCreateResult := FFactory.CreateInstanceLic(FUnkOuter, nil, FIID, '', Unk);
  214. FUnkOuter := nil;
  215. FFactory := nil;
  216. if FCreateResult = S_OK then
  217. CoMarshalInterThreadInterfaceInStream(FIID, Unk, IStream(FStream));
  218. ReleaseSemaphore(FSemaphore, 1, nil);
  219. if FCreateResult = S_OK then
  220. while GetMessage(msg, 0, 0, 0) do
  221. begin
  222. DispatchMessage(msg);
  223. Unk._AddRef;
  224. if Unk._Release = 1 then break;
  225. end;
  226. finally
  227. Unk := nil;
  228. CoUninitialize;
  229. end;
  230. except
  231. { No exceptions should go unhandled }
  232. end;
  233. end;
  234. ////////////////////////////////////////////////////////////////////////////////
  235. //
  236. // TVCLComObjectFactory
  237. //
  238. ////////////////////////////////////////////////////////////////////////////////
  239. constructor TVCLComObjectFactory.Create(ComServer: TComServerObject;
  240. ComponentClass: TComponentClass; const ClassID: TGUID; const ClassName,
  241. Description: string; Instancing: TClassInstancing);
  242. begin
  243. inherited Create(ComServer, TComClass(ComponentClass), ClassID, ClassName,
  244. Description, Instancing, tmApartment);
  245. end;
  246. function TVCLComObjectFactory.CreateComObject(const Controller: IUnknown): TComObject;
  247. begin
  248. Result := TVCLComObject.CreateFromFactory(Self, Controller);
  249. end;
  250. function TVCLComObjectFactory.CreateInstance(const UnkOuter: IUnknown;
  251. const IID: TGUID; out Obj): HResult;
  252. begin
  253. if not IsLibrary then
  254. begin
  255. LockServer(True);
  256. try
  257. with TApartmentThread.Create(Self, UnkOuter, IID) do
  258. begin
  259. if WaitForSingleObject(Semaphore, INFINITE) = WAIT_OBJECT_0 then
  260. begin
  261. Result := CreateResult;
  262. if Result <> S_OK then Exit;
  263. Result := CoGetInterfaceAndReleaseStream(IStream(ObjStream), IID, Obj);
  264. end else
  265. Result := E_FAIL
  266. end;
  267. finally
  268. LockServer(False);
  269. end;
  270. end else
  271. Result := inherited CreateInstance(UnkOuter, IID, Obj);
  272. end;
  273. type
  274. TComponentProtectedAccess = class(TComponent);
  275. TComponentProtectedAccessClass = class of TComponentProtectedAccess;
  276. procedure TVCLComObjectFactory.UpdateRegistry(Register: Boolean);
  277. begin
  278. if Register then
  279. inherited UpdateRegistry(Register);
  280. TComponentProtectedAccessClass(ComClass).UpdateRegistry(Register,
  281. GUIDToString(ClassID), ProgID);
  282. if not Register then
  283. inherited UpdateRegistry(Register);
  284. end;
  285. ////////////////////////////////////////////////////////////////////////////////
  286. //
  287. // TShellExtFactory
  288. //
  289. ////////////////////////////////////////////////////////////////////////////////
  290. constructor TShellExtFactory.Create(ComServer: TComServerObject;
  291. ComponentClass: TComponentClass; const ClassID: TGUID; const ClassName,
  292. Description, AFileClass, AFileExtension: string; Instancing: TClassInstancing);
  293. begin
  294. inherited Create(ComServer, ComponentClass, ClassID, ClassName,
  295. Description, Instancing);
  296. FFileClass := AFileClass;
  297. FFileExtension := AFileExtension;
  298. end;
  299. procedure TShellExtFactory.UpdateRegistry(Register: Boolean);
  300. begin
  301. if Register then
  302. begin
  303. inherited UpdateRegistry(Register);
  304. if (FileExtension <> '') then
  305. CreateRegKey(FileExtension, '', FileClass);
  306. end else
  307. begin
  308. if (FileExtension <> '') then
  309. RegDeleteKey(HKEY_CLASSES_ROOT, PChar(FileExtension));
  310. inherited UpdateRegistry(Register);
  311. end;
  312. end;
  313. end.