CreateStdDispatch 如何知道要调用哪个方法?

发布于 2024-11-17 07:58:18 字数 3375 浏览 3 评论 0原文

我面临着实施 IDispatch界面。有四种方法,幸运的是其中 3 个很简单:

function TIEEventsSink.GetTypeInfoCount(...): HResult;
{
   Result := E_NOTIMPL;
}

function TIEEventsSink.GetTypeInfo(...): HResult;
{
   Result := E_NOTIMPL;
}

function TIEEventsSink.GetIDsOfNames(...): HResult;
{
   Result := E_NOTIMPL;
}

最后一个方法 Invoke 比较困难。在这里,我面临着必须实际处理 DispID 的情况,并调用我适当的方法;从变体数组中解组参数。

function Invoke(  
  dispIdMember: DISPID;
  riid: REFIID;
  lcid: LCID;
  wFlags: WORD;
  var pDispParams: DISPPARAMS;
  var pVarResult: VARIANT;
  var pExcepInfo: EXCEPINFO;
  var puArgErr: DWORD
): HRESULT;

不想编写所有繁琐的样板代码,我确信会有错误,所以我去谷歌搜索 - 而不是做任何工作。

我在IDispatch.Invoke的MSDN文档中找到了这个片段

一般来说,您不应该直接实现Invoke

出色的!反正我不想实施它!继续阅读:

相反,使用调度接口创建函数 CreateStdDispatch 和 < a href="http://msdn.microsoft.com/en-us/library/ms221366.aspx" rel="nofollow">DispInvoke。有关详细信息,请参阅 CreateStdDispatchDispInvoke创建 IDispatch 接口公开 ActiveX 对象

创建 IDispatch Interface 链接显示:

您可以通过以下任一方式实现 IDispatch:

  • [剪断]
  • 调用 CreateStdDispatch 函数。这种方法是最简单的,但它不提供丰富的错误处理或多种国家语言。
  • [剪断]

非常好,CreateStdDispatch 它是:

通过单个函数调用创建 IDispatch 接口的标准实现。这简化了通过自动化公开对象的过程。

HRESULT CreateStdDispatch(  
  IUnknown FAR* 朋克外在,        
  void FAR* pvThis,               
  ITypeInfo FAR* ptinfo,          
  IUnknown 远* 远* ppunkStdDisp  
);

我打算这样称呼它:

CreateStdDispatch(
    myUnk,          //Pointer to the object's IUnknown implementation.
    anotherObject,  //Pointer to the object to expose.
    nil             //Pointer to the type information that describes the exposed object (i has no type info)
    dispInterface   //the IUnknown of the object that implements IDispatch for me
);

我无法弄清楚的是 CreateStdDispatch 的 Windows API 实现如何知道在我的对象上调用什么方法 - 特别是因为 CreateStdDispatch 不知道知道我正在使用什么面向对象语言,或其调用约定。

CreateStdDispatch 如何知道

  • 为给定的 dispid 调用什么方法?
  • 我的语言的调用约定?
  • 如何处理我的面向对象对象编写语言的异常?

注意:我别无选择,只能实现一个dispinterface;我没有定义接口 。我希望它是一个简单的早期绑定 IUnknown,但事实并非如此。

i'm faced with implementing an IDispatch interface. There are four methods, and fortunately 3 of them are easy:

function TIEEventsSink.GetTypeInfoCount(...): HResult;
{
   Result := E_NOTIMPL;
}

function TIEEventsSink.GetTypeInfo(...): HResult;
{
   Result := E_NOTIMPL;
}

function TIEEventsSink.GetIDsOfNames(...): HResult;
{
   Result := E_NOTIMPL;
}

It's the last method, Invoke that is difficult. Here i am faced with having to actually case the DispID, and call my appropriate method; unmarhsalling parameters from a variant array.

function Invoke(  
  dispIdMember: DISPID;
  riid: REFIID;
  lcid: LCID;
  wFlags: WORD;
  var pDispParams: DISPPARAMS;
  var pVarResult: VARIANT;
  var pExcepInfo: EXCEPINFO;
  var puArgErr: DWORD
): HRESULT;

Not wanting to have to write all the tedious boilerplate code, that i'm sure will have bugs, i went googling - rather than doing any work.

i found this snippit on the MSDN Documentation of IDispatch.Invoke:

Generally, you should not implement Invoke directly.

Excellent! i didn't want to implement it anyway! Continuing reading:

Instead, use the dispatch interface to create functions CreateStdDispatch and DispInvoke. For details, refer to CreateStdDispatch, DispInvoke, Creating the IDispatch Interface and Exposing ActiveX Objects.

The Creating the IDispatch Interface link says:

You can implement IDispatch by any of the following means:

  • [snip]
  • Calling the CreateStdDispatch function. This approach is the simplest, but it does not provide for rich error handling or multiple national languages.
  • [snip]

Excellent, CreateStdDispatch it is:

Creates a standard implementation of the IDispatch interface through a single function call. This simplifies exposing objects through Automation.

HRESULT CreateStdDispatch(  
  IUnknown FAR*  punkOuter,        
  void FAR*  pvThis,               
  ITypeInfo FAR*  ptinfo,          
  IUnknown FAR* FAR* ppunkStdDisp  
);

i was going to call it as:

CreateStdDispatch(
    myUnk,          //Pointer to the object's IUnknown implementation.
    anotherObject,  //Pointer to the object to expose.
    nil             //Pointer to the type information that describes the exposed object (i has no type info)
    dispInterface   //the IUnknown of the object that implements IDispatch for me
);

What i cannot figure out is how the Windows API implemention of CreateStdDispatch knows what methods to call on my object - especially since CreateStdDispatch doesn't know what object-oriented language i'm using, or its calling conventions.

How will CreateStdDispatch know

  • what method to call for a given dispid?
  • the calling convention of my language?
  • how to handle exceptions from the language that my object oriented object is written in?

Note: i have no choice but to implement a dispinterface; i didn't define the interface. i wish it was a simple early bound IUnknown, but it tisn't.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

深爱成瘾 2024-11-24 07:58:18

传递给 CreateStdDispatchITypeInfo 参数是否公开了所有方法信息?

因此,您需要首先调用 CreateDispTypeInfo 创建类型信息,并将其传递给 CreateStdDispatch,然后后者可以使用类型信息来确定自 CreateDispTypeInfo< 以来要调用哪个方法。 /code> 需要 INTERFACEDATA ,其中包含所有这些信息,

我可能是错误的,因为我没有时间研究它,但这对我来说是有意义的。
我稍后会对此进行调查并更新答案。

Doesn't the ITypeInfo parameter passed into CreateStdDispatch expose all of the method information?

So you'd create type info first calling CreateDispTypeInfo and pass that through to CreateStdDispatch which can then use the type information to work out which method to call since CreateDispTypeInfo requires INTERFACEDATA which contains all this information

I could be way wrong since I don't have time to look into it but that would make sense to me.
I'll investigate this later and update the answer.

浴红衣 2024-11-24 07:58:18

您的问题的简短答案是:CreateStdDispatch() 和它创建的 IDispatch 实现都不知道有关要调用的方法的任何事情

您返回的对象仅存储您传递给 CreateStdDispatch() 的参数,对于所有 IDispatch 方法,它仅返回并在 上进行相应的调用您提供的>ITypeInfo。仅此而已。

如果您为 ptinfo 传递 nil(如代码中所示),那么您只会得到 E_INVALIDARG,因为如果没有 ITypeInfo,实现对象根本无法执行任何操作将所有工作委托给它。

如果您检查 oleaut32.dll 中的 CStdDisp 代码,您会发现它调用 API 函数,如 DispInvoke() (也存在于该 DLL 中),而不是调用直接使用 ITypeInfo 方法,但这些函数都是调用 ITypeInfo 方法的简单包装器,没有任何其他功能。

如果有人想知道:CreateStdDispatch()CStdDisp 都没有执行任何额外的魔法;它们所做的只是为您提供一个 IDispatch,它可以执行您传入的 ITypeInfo 可以执行的操作。将其视为一种适配器,允许您将 ITypeInfo 插入 IDispatch 套接字。

确实,TAutoIntfObject.Create() 需要类型库。然而,构造函数所做的只是对其调用 GetTypeInfoOfGuid() 以获得类型信息指针,然后对象将与分派事物相关的大部分工作委托给该指针。

Borland 以他们的智慧为类型信息指针创建了成员变量 private,这意味着您确实需要将某个类型库或其他包含相关接口的构造函数交给构造函数,而不是简单地编写另一个构造函数或者重写一些虚函数。另一方面,通过注册表加载类型库或将其部分转储到 TLB 文件应该不会太难。使用 OleView 检查 TLB 可以为您提供实际的可编译 IDL,它通常也是 Borland 可编译的 RIDL。

CreateStdDispatch() 也不知道任何有关异常的信息。捕获从 COM 方法抛出的异常并将其转换为 HRESULT 和/或 IErrorInfo 是由实现方法上的 Delphi safecall 关键字引发的编译器魔法。

当调用在其接口声明中指定为 safecall 的 COM 方法时,HRESULT 到异常的转换也是如此。编译器只是在每次调用 safecall 方法之后插入对 @CheckAutoResult 的调用;该函数检查 HRESULT 并在适当的情况下抛出 EOleSysError

只需将 Delphi 调试器切换到反汇编(“CPU 视图”)即可检查编译器为您所做的所有魔力!

The short answer to your question is: neither CreateStdDispatch() nor the IDispatch implementation it creates knows anything at all about the methods to be called.

The object that you get back simply stores the parameters that you passed to CreateStdDispatch(), and for all IDispatch methods it only turns around and makes the corresponding calls on the ITypeInfo that you gave it. That is all.

If you pass nil for ptinfo as shown in your code then you only get E_INVALIDARG, since the implementing object cannot do anything at all without an ITypeInfo to which to delegate all the work.

If you inspect the code for CStdDisp in oleaut32.dll then you will find that it calls API functions like DispInvoke() (which also live in that DLL) instead of invoking the ITypeInfo methods directly, but these functions are all simple wrappers for calls to the ITypeInfo methods, without any further functionality.

In case anyone wonders: neither CreateStdDispatch() nor CStdDisp performs any additional magic; all they do is give you an IDispatch that does whatever the ITypeInfo that you passed in can do. Think of it as a kind of an adapter that allows you to plug an ITypeInfo into an IDispatch socket.

It is true that TAutoIntfObject.Create() needs a type library. However, all that the constructor does is call GetTypeInfoOfGuid() on it in order to get a type info pointer, to which the object then delegates most of the work related to dispatch things.

Borland in their wisdom made the member variable for the type info pointer private, which means that you really need to hand the constructor some type library or other that contains the interface in question, instead of simply writing another constructor or overriding some virtual function. On the other hand it shouldn't be too hard to load the type library via the registry or to dump parts of it to a TLB file. Inspecting a TLB with OleView gives you actual compilable IDL which is often also Borland-compilable RIDL.

CreateStdDispatch() does not know anything about exceptions either. The catching of exceptions thrown from COM methods and their conversion to HRESULT and/or IErrorInfo is compiler magic induced by Delphi's safecall keyword on the implementing method.

The same goes for the translation of HRESULTs to exceptions when calling COM methods specified as safecall in their interface declarations. The compiler simply inserts a call to @CheckAutoResult after every invocation of a safecall method; this function checks the HRESULT and throws EOleSysError if appropriate.

Simply switch the Delphi debugger to disassembly ('CPU view') to inspect all the magic that the compiler does for you!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文