在.NET中使用IUnknown派生的ATL COM对象



我的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:试图读取或写入受保护的内存…"。为什么?

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

int Hoop();

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

void Hoop();

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

*更新*

根据MSDN的说法,默认情况下,主应用程序线程被初始化为"MTA"。您的对象CSimpleObject已配置为驻留在"STA"中。为了进行跨代理调用,COM运行时将使用您的代理/存根实现来整理相应的数据。

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

您已将"Hoop"函数标记为"Local"。这意味着MIDL将不会为此方法生成任何编组代码,这就是为什么会出现异常的原因。

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

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

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

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

最新更新