eventsink.pp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. {$IFNDEF FPC_DOTTEDUNITS}
  2. unit EventSink;
  3. {$ENDIF FPC_DOTTEDUNITS}
  4. {$mode objfpc}{$H+}
  5. { COM EventSink.
  6. Copyright (C) 2011 Ludo Brands
  7. This library is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU Library General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at your
  10. option) any later version with the following modification:
  11. As a special exception, the copyright holders of this library give you
  12. permission to link this library with independent modules to produce an
  13. executable, regardless of the license terms of these independent modules,and
  14. to copy and distribute the resulting executable under terms of your choice,
  15. provided that you also meet, for each linked independent module, the terms
  16. and conditions of the license of that module. An independent module is a
  17. module which is not derived from or based on this library. If you modify
  18. this library, you may extend this exception to your version of the library,
  19. but you are not obligated to do so. If you do not wish to do so, delete this
  20. exception statement from your version.
  21. This program is distributed in the hope that it will be useful, but WITHOUT
  22. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  23. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  24. for more details.
  25. You should have received a copy of the GNU Library General Public License
  26. along with this library; if not, write to the Free Software Foundation,
  27. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  28. }
  29. interface
  30. {$IFDEF FPC_DOTTEDUNITS}
  31. uses
  32. WinApi.Windows, System.SysUtils, System.Classes, WinApi.Activex;
  33. {$ELSE FPC_DOTTEDUNITS}
  34. uses
  35. Windows, SysUtils, Classes, ActiveX;
  36. {$ENDIF FPC_DOTTEDUNITS}
  37. type
  38. TInvokeEvent = procedure(Sender: TObject; DispID: Integer;
  39. const IID: TGUID; LocaleID: Integer; Flags: Word;
  40. Params: TDispParams; VarResult, ExcepInfo, ArgErr: Pointer) of object;
  41. { TAbstractEventSink }
  42. TAbstractEventSink = class(TObject, IDispatch,IUnknown) // see mantis #22156
  43. private
  44. FDispatch: IDispatch;
  45. FDispIntfIID: TGUID;
  46. FConnection: DWORD;
  47. FOwner: TComponent;
  48. protected
  49. { IUnknown }
  50. frefcount : longint;
  51. function QueryInterface(constref IID: TGUID; out Obj): HRESULT; stdcall;
  52. function _AddRef : longint;stdcall;
  53. function _Release : longint;stdcall;
  54. { IDispatch }
  55. function GetTypeInfoCount(out Count: Integer): HRESULT; stdcall;
  56. function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HRESULT; stdcall;
  57. function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  58. NameCount, LocaleID: Integer; DispIDs: Pointer): HRESULT; stdcall;
  59. function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  60. Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT; stdcall;
  61. public
  62. constructor Create(AOwner: TComponent);
  63. destructor Destroy; override;
  64. procedure Connect(AnAppDispatch: IDispatch; const AnAppDispIntfIID: TGUID);
  65. procedure Disconnect;
  66. end;
  67. TEventSink = class(TComponent)
  68. private
  69. FSink: TAbstractEventSink;
  70. FOnInvoke: TInvokeEvent;
  71. protected
  72. procedure DoInvoke(DispID: Integer; const IID: TGUID;
  73. LocaleID: Integer; Flags: Word; var Params;
  74. VarResult, ExcepInfo, ArgErr: Pointer); virtual;
  75. public
  76. constructor Create(AOwner: TComponent); override;
  77. destructor Destroy; override;
  78. procedure Connect(AnAppDispatch: IDispatch; const AnAppDispIntfIID: TGUID);
  79. procedure Disconnect;
  80. published
  81. property OnInvoke: TInvokeEvent read FOnInvoke write FOnInvoke;
  82. end;
  83. implementation
  84. {$IFDEF FPC_DOTTEDUNITS}
  85. uses
  86. WinApi.Comobj;
  87. {$ELSE FPC_DOTTEDUNITS}
  88. uses
  89. ComObj;
  90. {$ENDIF FPC_DOTTEDUNITS}
  91. { TAbstractEventSink }
  92. constructor TAbstractEventSink.Create(AOwner: TComponent);
  93. begin
  94. inherited Create;
  95. FOwner := AOwner;
  96. end;
  97. destructor TAbstractEventSink.Destroy;
  98. var p:pointer;
  99. begin
  100. inherited Destroy;
  101. end;
  102. function TAbstractEventSink.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  103. NameCount, LocaleID: Integer; DispIDs: Pointer): HRESULT; stdcall;
  104. begin
  105. Result := E_NOTIMPL;
  106. end;
  107. function TAbstractEventSink.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HRESULT; stdcall;
  108. begin
  109. Result := E_NOTIMPL;
  110. end;
  111. function TAbstractEventSink.GetTypeInfoCount(out Count: Integer): HRESULT; stdcall;
  112. begin
  113. Count := 0;
  114. Result := S_OK;
  115. end;
  116. function TAbstractEventSink.Invoke(DispID: Integer; const IID: TGUID;
  117. LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  118. ArgErr: Pointer): HRESULT; stdcall;
  119. begin
  120. (FOwner as TEventSink).DoInvoke(DispID, IID, LocaleID, Flags,
  121. Params, VarResult, ExcepInfo, ArgErr);
  122. Result := S_OK;
  123. end;
  124. function TAbstractEventSink.QueryInterface(constref IID: TGUID; out Obj): HRESULT; stdcall;
  125. begin
  126. // We need to return the event interface when it's asked for
  127. Result := E_NOINTERFACE;
  128. if GetInterface(IID,Obj) then
  129. Result := S_OK;
  130. if IsEqualGUID(IID, FDispIntfIID) and GetInterface(IDispatch,Obj) then
  131. Result := S_OK;
  132. end;
  133. function TAbstractEventSink._AddRef: longint; stdcall;
  134. begin
  135. frefcount:=frefcount+1;
  136. _addref:=frefcount;
  137. end;
  138. function TAbstractEventSink._Release: longint; stdcall;
  139. begin
  140. frefcount:=frefcount-1;
  141. _Release:=frefcount;
  142. if frefcount=0 then
  143. self.destroy;
  144. end;
  145. procedure TAbstractEventSink.Connect(AnAppDispatch: IDispatch;
  146. const AnAppDispIntfIID: TGUID);
  147. begin
  148. FDispIntfIID := AnAppDispIntfIID;
  149. FDispatch := AnAppDispatch;
  150. // Hook the sink up to the automation server
  151. InterfaceConnect(FDispatch, FDispIntfIID, Self, FConnection);
  152. end;
  153. procedure TAbstractEventSink.Disconnect;
  154. begin
  155. if Assigned(FDispatch) then begin
  156. // Unhook the sink from the automation server
  157. Self._addRef;
  158. InterfaceDisconnect(FDispatch, FDispIntfIID, FConnection);
  159. FDispatch := nil;
  160. FConnection := 0;
  161. self._Release;
  162. end;
  163. end;
  164. { TEventSink }
  165. procedure TEventSink.Connect(AnAppDispatch: IDispatch;
  166. const AnAppDispIntfIID: TGUID);
  167. begin
  168. FSink.Connect(AnAppDispatch, AnAppDispIntfIID);
  169. end;
  170. procedure TEventSink.Disconnect;
  171. begin
  172. FSink.Disconnect;
  173. end;
  174. constructor TEventSink.Create(AOwner: TComponent);
  175. begin
  176. inherited Create(AOwner);
  177. FSink := TAbstractEventSink.Create(self);
  178. end;
  179. destructor TEventSink.Destroy;
  180. begin
  181. FSink.Disconnect; // reference count will destroy FSink
  182. // calling FSink.Destroy will raise error 204 since refcount=1 (not disconnected yet)
  183. // FSink.Destroy;
  184. inherited Destroy;
  185. end;
  186. procedure TEventSink.DoInvoke(DispID: Integer; const IID: TGUID;
  187. LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  188. ArgErr: Pointer);
  189. begin
  190. if Assigned(FOnInvoke) then
  191. FOnInvoke(self, DispID, IID, LocaleID, Flags, TDispParams(Params),
  192. VarResult, ExcepInfo, ArgErr);
  193. end;
  194. end.