| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- {******************************************************************************}
- { CnPack For Delphi/C++Builder }
- { 中国人自己的开放源码第三方开发包 }
- { (C)Copyright 2001-2018 CnPack 开发组 }
- { ------------------------------------ }
- { }
- { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
- { 改和重新发布这一程序。 }
- { }
- { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
- { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
- { }
- { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
- { 还没有,可访问我们的网站: }
- { }
- { 网站地址:http://www.cnpack.org }
- { 电子邮件:master@cnpack.org }
- { }
- {******************************************************************************}
- unit CnASIDispatchProxy;
- {* |<PRE>
- ================================================================================
- * 软件名称:不可视工具组件包
- * 单元名称:ActiveScript Host 对象 IDispatch 代理接口单元
- * 单元作者:周劲羽 (zjy@cnpack.org)
- * 备 注:
- * 开发平台:PWin2K SP3 + Delphi 7
- * 兼容测试:PWin9X/2000/XP + Delphi 6/7 C++Builder 6
- * 本 地 化:该单元中的字符串均符合本地化处理方式
- * 单元标识:$Id$
- * 修改记录:2003.07.11
- * 创建单元
- ================================================================================
- |</PRE>}
- interface
- {$I CnPack.inc}
- {$IFNDEF COMPILER6_UP}
- 'Error: This unit can used only for Delphi / C++Builder 6 or up.'
- {$ENDIF COMPILER6_UP}
- uses
- Windows, Classes, TypInfo;
- type
- {$M+}
- IActiveScriptInvokable = interface(IUnknown)
- end;
- {$M-}
- function GetIDispatchProxy(AItemObject: TObject; IntfTypeInfo: PTypeInfo): IDispatch;
- implementation
- uses
- Sysutils, ActiveX, Variants, CnASInvoker;
- type
- { TIDispatchProxy }
- TIDispatchProxy = class(TInterfacedObject, IDispatch)
- protected
- FObject: TObject;
- FIntf: IUnknown;
- FIntfMD: TIntfMetaData;
- function GetTypeInfoCount(out Count: Integer): hResult; stdcall;
- function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): hResult; stdcall;
- function GetIDsOfNames(const IID: TGUID; Names: Pointer;
- NameCount, LocaleID: Integer; DispIDs: Pointer): hResult; stdcall;
- function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
- Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): hResult;
- stdcall;
- public
- constructor Create(AItemObject: TObject; IntfTypeInfo: PTypeInfo);
- destructor Destroy; override;
- property ItemObject: TObject read FObject write FObject;
- end;
- function GetIDispatchProxy(AItemObject: TObject; IntfTypeInfo: PTypeInfo): IDispatch;
- begin
- Result := TIDispatchProxy.Create(AItemObject, IntfTypeInfo) as IDispatch;
- end;
- constructor TIDispatchProxy.Create(AItemObject: TObject; IntfTypeInfo: PTypeInfo);
- resourcestring
- SNoInterfaceGUID = 'Class %s does not implement interface GUID %s';
- begin
- Assert(Assigned(AItemObject));
- Assert(Assigned(IntfTypeInfo));
- inherited Create;
- FObject := AItemObject;
- GetIntfMetaData(IntfTypeInfo, FIntfMD, True);
- // 保存一个接口引用
- if not FObject.GetInterface(FIntfMD.IID, FIntf) then
- raise Exception.CreateFmt(SNoInterfaceGUID,
- [FObject.ClassName, GuidToString(FIntfMD.IID)]);
- end;
- destructor TIDispatchProxy.Destroy;
- begin
- FIntf := nil;
- inherited;
- end;
- function TIDispatchProxy.GetIDsOfNames(const IID: TGUID; Names: Pointer;
- NameCount, LocaleID: Integer; DispIDs: Pointer): hResult;
- type
- TDispIDsArray = array[0..0] of TDispID;
- PDispIDsArray = ^TDispIDsArray;
- var
- IDs: PDispIDsArray absolute DispIDs;
- i: Integer;
- Name: WideString;
- Id: Integer;
- begin
- if NameCount > 1 then
- Result := DISP_E_UNKNOWNNAME
- else if NameCount < 1 then
- Result := E_INVALIDARG
- else
- Result := S_OK;
-
- for i := 0 to NameCount - 1 do
- IDs[i] := DISPID_UNKNOWN;
-
- if NameCount = 1 then
- begin
- Name := PWideChar(Names^);
- //Name := UpperCase(Name);
- Id := GetMethNum(FIntfMD, Name);
- if Id <> 0 then
- begin
- IDs[0] := Id;
- end
- else
- begin
- Result := DISP_E_UNKNOWNNAME;
- end;
- end;
- end;
- function TIDispatchProxy.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo):
- hResult;
- begin
- Pointer(TypeInfo) := nil;
- Result := E_NOTIMPL;
- end;
- function TIDispatchProxy.GetTypeInfoCount(out Count: Integer): hResult;
- begin
- Count := 0;
- Result := S_OK;
- end;
- function TIDispatchProxy.Invoke(DispID: Integer; const IID: TGUID;
- LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
- ArgErr: Pointer): hResult;
- var
- DispParams: TDispParams;
- MethEntry: TIntfMethEntry;
- V: OleVariant;
- i: Integer;
- Context: TInvContext;
- begin
- if (DispID >= Low(FIntfMD.MDA)) and (DispID <= High(FIntfMD.MDA)) then
- begin
- try
- MethEntry := FIntfMD.MDA[DispID];
- DispParams := TDispParams(Params);
- // 允许后面几个参数使用默认值
- if DispParams.cArgs <= MethEntry.ParamCount then
- begin
- // Var 或 Out 类型的参数不能省略
- for i := DispParams.cArgs to MethEntry.ParamCount - 1 do
- if [pfVar, pfOut] * MethEntry.Params[i].Flags <> [] then
- begin
- Result := DISP_E_BADPARAMCOUNT;
- Exit;
- end;
- Context := TInvContext.Create;
- try
- Context.SetMethodInfo(MethEntry);
- Context.AllocServerData(MethEntry);
-
- // 调用方法前转换 OleVariant 参数为方法参数
- for i := 0 to MethEntry.ParamCount - 1 do
- begin
- // 如果参数转换出错,此处定义出错的参数序号
- PInteger(ArgErr)^ := i;
- // 传进来的参数和定义的顺序相反
- if i < DispParams.cArgs then
- V := OleVariant(DispParams.rgvarg^[DispParams.cArgs - 1 - i])
- else
- V := Null;
- TypeTranslator.CastVariantToNative(MethEntry.Params[i].Info,
- V, Context.GetParamPointer(i));
- end;
- // 调用接口方法
- InterfaceInvoker.Invoke(FObject, FIntfMD, DispID, Context);
- // 调用完成后转换 var 和 out 参数为 OleVariant 参数
- { TODO : JScript 和 VBScript 似乎不支持变量参数? }
- for i := 0 to DispParams.cArgs - 1 do
- if [pfVar, pfOut] * MethEntry.Params[i].Flags <> [] then
- begin
- // 如果参数转换出错,此处定义出错的参数序号
- PInteger(ArgErr)^ := i;
- // 传进来的参数和定义的顺序相反
- TypeTranslator.CastNativeToVariant(MethEntry.Params[i].Info,
- V, Context.GetParamPointer(i));
- OleVariant(DispParams.rgvarg^[DispParams.cArgs - 1 - i]) := V;
- end;
- PInteger(ArgErr)^ := 0;
-
- // 返回方法执行结果
- if Assigned(MethEntry.ResultInfo) and Assigned(VarResult) then
- begin
- TypeTranslator.CastNativeToVariant(MethEntry.ResultInfo,
- V, Context.GetResultPointer);
- OleVariant(VarResult^) := V;
- end
- else if Assigned(VarResult) then
- OleVariant(VarResult^) := Null;
- finally
- Context.Free;
- end;
- Result := S_OK;
- end
- else
- Result := DISP_E_BADPARAMCOUNT;
- except
- on E: Exception do
- begin
- if E is ETypeTransException then
- Result := DISP_E_TYPEMISMATCH
- else if E is EInvalidCast then
- Result := DISP_E_TYPEMISMATCH
- else if E is EConvertError then
- Result := DISP_E_TYPEMISMATCH
- else if E is EOverflow then
- Result := DISP_E_OVERFLOW
- else
- begin
- Result := DISP_E_EXCEPTION;
- { TODO -oyygw : 返回异常时的错误信息 }
- end;
- end;
- end;
- end
- else
- Result := DISP_E_MEMBERNOTFOUND;
- end;
- end.
|