1

私の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、WindowsVistax64を使用しています。C ++およびC#プロジェクトにはx86構成があります。

4

1 に答える 1

0
int Hoop();

IDL宣言のC#への誤った変換です。正しいものは

void Hoop();

.NETは、COM結果コード(HRESULT)を対応するC#例外にラップします。たとえば、C ++コードでE_NOTIMPLを返す場合、.NETランタイムはNotImplementedExceptionクラスのインスタンスをスローします

*更新*

MSDNによると、メインアプリケーションスレッドはデフォルトで「MTA」に初期化されています。オブジェクトCSimpleObjectは、「STA」に常駐するように構成されています。アパルトマン間呼び出しを行うために、COMランタイムは、プロキシ/スタブの実装を使用して、対応するデータをマーシャリングします。

ランタイムには、IDLファイルからMIDLによって生成される有効なプロキシ/スタブ実装が必要です。

「フープ」機能を「ローカル」としてマークしました。これは、MIDLがこのメソッドのマーシャリングコードを生成しないことを意味します。そのため、例外が発生します。

'local'属性は、オブジェクトが実装されているサーバー内でのみ使用されるように設計されているため、削除する必要があります。しかし、考えられる解決策として、STAで実行するように構成されたスレッドのオブジェクトを使用することをお勧めします。とにかく、これは悪いアプローチです。マーシャリングが含まれないことを保証するものではないからです。

次のように、メインスレッドをSTAで実行するようにマークできます。

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

これが問題の解決に役立つことを願っています。

于 2012-03-23T16:14:14.907 に答える