【问题标题】:Using IUnknown derived ATL COM object in .NET在 .NET 中使用 IUnknown 派生的 ATL COM 对象
【发布时间】:2012-04-08 04:38:33
【问题描述】:

我的 IDL:

[
    object,
    uuid(52D64BCC-03F1-442B-BED1-70992111E2B1),
    helpstring("ISimpleObject Interface"),
    pointer_default(unique)
]
interface ISimpleObject : IUnknown{
    [helpstring("method Hoop"), local] HRESULT Hoop(void);
};
[
    uuid(3D9ABD55-3C84-43C8-9C34-3915B6B34989),
    version(1.0),
    helpstring("ComServer 1.0 Type Library")
]
library ComServerLib
{
    importlib("stdole2.tlb");
    [
        uuid(42E2236D-1DA0-455F-9EF4-31A4A1E04F47),
        helpstring("SimpleObject Class")
    ]
    coclass SimpleObject
    {
        [default] interface ISimpleObject;
    };
};

我的 COM 类:

class ATL_NO_VTABLE CSimpleObject :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CSimpleObject, &CLSID_SimpleObject>,
    public ISimpleObject
{
public:
    CSimpleObject()
    {
    }

DECLARE_REGISTRY_RESOURCEID(IDR_SIMPLEOBJECT)

BEGIN_COM_MAP(CSimpleObject)
    COM_INTERFACE_ENTRY(ISimpleObject)
END_COM_MAP()

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }

public:
    // ISimpleObject
    STDMETHOD(Hoop)(void)
    {
        return S_OK;
    }
};

OBJECT_ENTRY_AUTO(__uuidof(SimpleObject), CSimpleObject)

我的 .NET 客户端:

[ComImport]
[Guid("52D64BCC-03F1-442B-BED1-70992111E2B1")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISimpleObject
{
    [PreserveSig]
    int Hoop();
}

[ComImport]
[Guid("42E2236D-1DA0-455F-9EF4-31A4A1E04F47")]
public class SimpleObject
{
}

class Program
{
    static void Main(string[] args)
    {
        SimpleObject simpleObject = new SimpleObject();

        ISimpleObject simpleObjectInterface = (ISimpleObject)simpleObject;

        int returnValue = simpleObjectInterface.Hoop(); // Error!
    }
}

客户端收到异常“System.AccessViolationException: Attempted to read or write protected memory...”。为什么?

我正在使用 Visual Studio 2008、Windows Vista x64。 C++ 和 C# 项目具有 x86 配置。

【问题讨论】:

    标签: .net com atl vtable iunknown


    【解决方案1】:
    int Hoop();
    

    是 IDL 声明到 C# 的错误翻译。 正确的应该是

    void Hoop();
    

    .NET 将 COM 结果代码 (HRESULT) 包装到对应的 C# 异常中。例如,如果您在 C++ 代码中返回 E_NOTIMPL,.NET 运行时将抛出 NotImplementedException 类的实例

    *更新*

    根据MSDN,主应用程序线程默认初始化为'MTA'。您的对象 CSimpleObject 配置为驻留在“STA”中。为了进行跨单元调用,COM 运行时将使用your implementation of the proxy/stub to marshall 对应的数据。

    运行时需要一个有效的代理/存根实现,它由 MIDL 从您的 IDL 文件生成。

    您已将“Hoop”功能标记为“Local”。这意味着 MIDL 不会为此方法生成任何编组代码,这就是您得到异常的原因。

    应该删除“本地”属性,因为它被设计为仅在实现对象的服务器内部使用。 但作为一种可能的解决方案,我可能会建议您使用配置为在 STA 中运行的线程中的对象。无论如何,这是一种不好的方法,因为它不能保证不涉及编组。

    您可以将主线程标记为在 STA 中运行,如下所示:

    [STAThread()]
    static void Main(string[] args)
    {
        ...
    }
    

    我希望这能帮助您解决问题。

    【讨论】:

    • 不幸的是,这不起作用。 PreserveSigAttribute 属性允许通过返回值获取结果代码(HRESULT)。
    • vpp,对不起,我没有注意到这个属性。我已经更新了答案
    猜你喜欢
    • 2011-09-09
    • 2014-09-20
    • 2010-09-16
    • 2011-05-09
    • 2011-01-07
    • 2013-09-19
    • 1970-01-01
    • 2016-08-12
    • 2010-12-11
    相关资源
    最近更新 更多