CnASIDispatchProxy.pas 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnASIDispatchProxy;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:不可视工具组件包
  24. * 单元名称:ActiveScript Host 对象 IDispatch 代理接口单元
  25. * 单元作者:周劲羽 (zjy@cnpack.org)
  26. * 备 注:
  27. * 开发平台:PWin2K SP3 + Delphi 7
  28. * 兼容测试:PWin9X/2000/XP + Delphi 6/7 C++Builder 6
  29. * 本 地 化:该单元中的字符串均符合本地化处理方式
  30. * 单元标识:$Id$
  31. * 修改记录:2003.07.11
  32. * 创建单元
  33. ================================================================================
  34. |</PRE>}
  35. interface
  36. {$I CnPack.inc}
  37. {$IFNDEF COMPILER6_UP}
  38. 'Error: This unit can used only for Delphi / C++Builder 6 or up.'
  39. {$ENDIF COMPILER6_UP}
  40. uses
  41. Windows, Classes, TypInfo;
  42. type
  43. {$M+}
  44. IActiveScriptInvokable = interface(IUnknown)
  45. end;
  46. {$M-}
  47. function GetIDispatchProxy(AItemObject: TObject; IntfTypeInfo: PTypeInfo): IDispatch;
  48. implementation
  49. uses
  50. Sysutils, ActiveX, Variants, CnASInvoker;
  51. type
  52. { TIDispatchProxy }
  53. TIDispatchProxy = class(TInterfacedObject, IDispatch)
  54. protected
  55. FObject: TObject;
  56. FIntf: IUnknown;
  57. FIntfMD: TIntfMetaData;
  58. function GetTypeInfoCount(out Count: Integer): hResult; stdcall;
  59. function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): hResult; stdcall;
  60. function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  61. NameCount, LocaleID: Integer; DispIDs: Pointer): hResult; stdcall;
  62. function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  63. Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): hResult;
  64. stdcall;
  65. public
  66. constructor Create(AItemObject: TObject; IntfTypeInfo: PTypeInfo);
  67. destructor Destroy; override;
  68. property ItemObject: TObject read FObject write FObject;
  69. end;
  70. function GetIDispatchProxy(AItemObject: TObject; IntfTypeInfo: PTypeInfo): IDispatch;
  71. begin
  72. Result := TIDispatchProxy.Create(AItemObject, IntfTypeInfo) as IDispatch;
  73. end;
  74. constructor TIDispatchProxy.Create(AItemObject: TObject; IntfTypeInfo: PTypeInfo);
  75. resourcestring
  76. SNoInterfaceGUID = 'Class %s does not implement interface GUID %s';
  77. begin
  78. Assert(Assigned(AItemObject));
  79. Assert(Assigned(IntfTypeInfo));
  80. inherited Create;
  81. FObject := AItemObject;
  82. GetIntfMetaData(IntfTypeInfo, FIntfMD, True);
  83. // 保存一个接口引用
  84. if not FObject.GetInterface(FIntfMD.IID, FIntf) then
  85. raise Exception.CreateFmt(SNoInterfaceGUID,
  86. [FObject.ClassName, GuidToString(FIntfMD.IID)]);
  87. end;
  88. destructor TIDispatchProxy.Destroy;
  89. begin
  90. FIntf := nil;
  91. inherited;
  92. end;
  93. function TIDispatchProxy.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  94. NameCount, LocaleID: Integer; DispIDs: Pointer): hResult;
  95. type
  96. TDispIDsArray = array[0..0] of TDispID;
  97. PDispIDsArray = ^TDispIDsArray;
  98. var
  99. IDs: PDispIDsArray absolute DispIDs;
  100. i: Integer;
  101. Name: WideString;
  102. Id: Integer;
  103. begin
  104. if NameCount > 1 then
  105. Result := DISP_E_UNKNOWNNAME
  106. else if NameCount < 1 then
  107. Result := E_INVALIDARG
  108. else
  109. Result := S_OK;
  110. for i := 0 to NameCount - 1 do
  111. IDs[i] := DISPID_UNKNOWN;
  112. if NameCount = 1 then
  113. begin
  114. Name := PWideChar(Names^);
  115. //Name := UpperCase(Name);
  116. Id := GetMethNum(FIntfMD, Name);
  117. if Id <> 0 then
  118. begin
  119. IDs[0] := Id;
  120. end
  121. else
  122. begin
  123. Result := DISP_E_UNKNOWNNAME;
  124. end;
  125. end;
  126. end;
  127. function TIDispatchProxy.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo):
  128. hResult;
  129. begin
  130. Pointer(TypeInfo) := nil;
  131. Result := E_NOTIMPL;
  132. end;
  133. function TIDispatchProxy.GetTypeInfoCount(out Count: Integer): hResult;
  134. begin
  135. Count := 0;
  136. Result := S_OK;
  137. end;
  138. function TIDispatchProxy.Invoke(DispID: Integer; const IID: TGUID;
  139. LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  140. ArgErr: Pointer): hResult;
  141. var
  142. DispParams: TDispParams;
  143. MethEntry: TIntfMethEntry;
  144. V: OleVariant;
  145. i: Integer;
  146. Context: TInvContext;
  147. begin
  148. if (DispID >= Low(FIntfMD.MDA)) and (DispID <= High(FIntfMD.MDA)) then
  149. begin
  150. try
  151. MethEntry := FIntfMD.MDA[DispID];
  152. DispParams := TDispParams(Params);
  153. // 允许后面几个参数使用默认值
  154. if DispParams.cArgs <= MethEntry.ParamCount then
  155. begin
  156. // Var 或 Out 类型的参数不能省略
  157. for i := DispParams.cArgs to MethEntry.ParamCount - 1 do
  158. if [pfVar, pfOut] * MethEntry.Params[i].Flags <> [] then
  159. begin
  160. Result := DISP_E_BADPARAMCOUNT;
  161. Exit;
  162. end;
  163. Context := TInvContext.Create;
  164. try
  165. Context.SetMethodInfo(MethEntry);
  166. Context.AllocServerData(MethEntry);
  167. // 调用方法前转换 OleVariant 参数为方法参数
  168. for i := 0 to MethEntry.ParamCount - 1 do
  169. begin
  170. // 如果参数转换出错,此处定义出错的参数序号
  171. PInteger(ArgErr)^ := i;
  172. // 传进来的参数和定义的顺序相反
  173. if i < DispParams.cArgs then
  174. V := OleVariant(DispParams.rgvarg^[DispParams.cArgs - 1 - i])
  175. else
  176. V := Null;
  177. TypeTranslator.CastVariantToNative(MethEntry.Params[i].Info,
  178. V, Context.GetParamPointer(i));
  179. end;
  180. // 调用接口方法
  181. InterfaceInvoker.Invoke(FObject, FIntfMD, DispID, Context);
  182. // 调用完成后转换 var 和 out 参数为 OleVariant 参数
  183. { TODO : JScript 和 VBScript 似乎不支持变量参数? }
  184. for i := 0 to DispParams.cArgs - 1 do
  185. if [pfVar, pfOut] * MethEntry.Params[i].Flags <> [] then
  186. begin
  187. // 如果参数转换出错,此处定义出错的参数序号
  188. PInteger(ArgErr)^ := i;
  189. // 传进来的参数和定义的顺序相反
  190. TypeTranslator.CastNativeToVariant(MethEntry.Params[i].Info,
  191. V, Context.GetParamPointer(i));
  192. OleVariant(DispParams.rgvarg^[DispParams.cArgs - 1 - i]) := V;
  193. end;
  194. PInteger(ArgErr)^ := 0;
  195. // 返回方法执行结果
  196. if Assigned(MethEntry.ResultInfo) and Assigned(VarResult) then
  197. begin
  198. TypeTranslator.CastNativeToVariant(MethEntry.ResultInfo,
  199. V, Context.GetResultPointer);
  200. OleVariant(VarResult^) := V;
  201. end
  202. else if Assigned(VarResult) then
  203. OleVariant(VarResult^) := Null;
  204. finally
  205. Context.Free;
  206. end;
  207. Result := S_OK;
  208. end
  209. else
  210. Result := DISP_E_BADPARAMCOUNT;
  211. except
  212. on E: Exception do
  213. begin
  214. if E is ETypeTransException then
  215. Result := DISP_E_TYPEMISMATCH
  216. else if E is EInvalidCast then
  217. Result := DISP_E_TYPEMISMATCH
  218. else if E is EConvertError then
  219. Result := DISP_E_TYPEMISMATCH
  220. else if E is EOverflow then
  221. Result := DISP_E_OVERFLOW
  222. else
  223. begin
  224. Result := DISP_E_EXCEPTION;
  225. { TODO -oyygw : 返回异常时的错误信息 }
  226. end;
  227. end;
  228. end;
  229. end
  230. else
  231. Result := DISP_E_MEMBERNOTFOUND;
  232. end;
  233. end.