Com Interop 声明顺序

发布于 2024-08-17 03:12:04 字数 1438 浏览 3 评论 0原文

我有一个这样的接口声明:

[ComImport]
[Guid("79EAC9E4-BAF9-11CE-8C82-00AA004BA90B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInternetProtocol {
    //IInternetProtcolRoot
    void Start(
        [ MarshalAs(UnmanagedType.LPWStr) ] string szURL, 
        IInternetProtocolSink Sink, 
        IInternetBindInfo pOIBindInfo, 
        UInt32 grfPI, 
        UInt32 dwReserved);
    void Continue(ref _tagPROTOCOLDATA pProtocolData);
    void Abort(Int32 hrReason, UInt32 dwOptions);
    void Terminate(UInt32 dwOptions);
    void Suspend();
    void Resume();
    //IInternetProtocol
    [PreserveSig()] UInt32 Read(IntPtr pv, UInt32 cb, out UInt32 pcbRead);
    void Seek(_LARGE_INTEGER dlibMove, UInt32 dwOrigin, out _ULARGE_INTEGER plibNewPosition);
    void LockRequest(UInt32 dwOptions);
    void UnlockRequest();
}

实现此接口的对象应该调用它的 Start 方法。然而,这并没有发生。但奇怪的是,我发现 Terminate 方法被调用了,如果我在 Terminate 方法上设置一个断点,然后查看 dwOptions 参数,它实际上包含一个可以转换为字符串的 IntPtr - 这恰好是包含 Start 的第一个参数。

我认为这与声明的顺序有关,尽管上面的声明是我在各处看到的规范声明。

另外,我发现如果我将任意 IntPtr 参数添加到 Terminate 的定义中,那么它看起来像这样:

Terminate(IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6)

该方法仍然可以成功地被调用,并且字符串作为 a1 中的指针,并且其他字段填充为 13 0 或看起来像另一个内存地址。

知道这是怎么回事吗? Start 方法仅需要 5 个参数。然而在这里,我已经用 6 声明了 Terminate,但它仍然在预期调用 Start 的地方被调用。

I have an interface declaration like this:

[ComImport]
[Guid("79EAC9E4-BAF9-11CE-8C82-00AA004BA90B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInternetProtocol {
    //IInternetProtcolRoot
    void Start(
        [ MarshalAs(UnmanagedType.LPWStr) ] string szURL, 
        IInternetProtocolSink Sink, 
        IInternetBindInfo pOIBindInfo, 
        UInt32 grfPI, 
        UInt32 dwReserved);
    void Continue(ref _tagPROTOCOLDATA pProtocolData);
    void Abort(Int32 hrReason, UInt32 dwOptions);
    void Terminate(UInt32 dwOptions);
    void Suspend();
    void Resume();
    //IInternetProtocol
    [PreserveSig()] UInt32 Read(IntPtr pv, UInt32 cb, out UInt32 pcbRead);
    void Seek(_LARGE_INTEGER dlibMove, UInt32 dwOrigin, out _ULARGE_INTEGER plibNewPosition);
    void LockRequest(UInt32 dwOptions);
    void UnlockRequest();
}

The object that implements this interface is supposed to have it's Start method called. However, that is not happening. But curiously, I find that the Terminate method is being called instead, and if I set a break point on the Terminate method, and then look at the dwOptions parameter, it actually contains an IntPtr which can be cast into a string - which happens to contain what would be first parameter to Start.

I assume this has something to do with the order of declaration, even though the above declaration is the canonical one I've seen everywhere.

Also, I find that if I add arbitrary IntPtr arguments to the definition of Terminate so it looks like this:

Terminate(IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6)

the method is still successfully being called with the string as a pointer in a1 and other fields being populated with either 13 0 or what looks like another memory address.

Any idea what's going on here? The Start method only takes 5 parameters. Yet here, I've declared Terminate with 6 and its still being called in the place where Start is expected to be called.

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

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

发布评论

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

评论(2

羞稚 2024-08-24 03:12:04

通过将生成的可调用包装器与 IDL 文件进行比较,确保调度 ID (dispid) 设置正确。

Make sure that the dispatch ids (dispid) are set correctly by comparing the generated callable wrapper with the IDL file.

抚你发端 2024-08-24 03:12:04

你忘记了 3 个 IUnknown 方法。 IInternetProtocolRoot::Start() 是 vtable 中的第四个方法。

You forgot the 3 IUnknown methods. IInternetProtocolRoot::Start() is the 4th method in the vtable.

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