Использование производного IUnknown COM-объекта ATL в .NET - PullRequest
1 голос
/ 23 марта 2012

Мой 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.

1 Ответ

0 голосов
/ 23 марта 2012
int Hoop();

- неправильный перевод декларации IDL на C #. Правильный будет

void Hoop();

.NET упаковывает коды результата COM (HRESULT) в соответствующие исключения C #. Например, если вы вернете E_NOTIMPL в коде C ++, среда выполнения .NET выдаст экземпляр класса NotImplementedException

* UPDATE *

В соответствии с MSDN основной поток приложения по умолчанию инициализируется в 'MTA'. Ваш объект CSimpleObject сконфигурирован для размещения в «STA». Для выполнения вызовов между квартирами среда выполнения COM будет использовать вашу реализацию прокси / заглушки для маршалла соответствующих данных.

Среда выполнения нуждается в правильной реализации прокси / заглушки, которая генерируется MIDL из вашего файла IDL.

Вы пометили функцию «Обруч» как «Локальная». Это означает, что MIDL не будет генерировать какой-либо код сортировки для этого метода, поэтому вы получаете исключение.

Следует удалить атрибут «local», поскольку он предназначен для использования только внутри сервера, на котором реализован объект. Но в качестве возможного решения я могу предложить вам использовать объект из потока, настроенного для работы в STA. В любом случае, это плохой подход, так как он не гарантирует, что никакая сортировка не будет задействована.

Вы можете пометить ваш основной поток для работы в STA следующим образом:

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

Надеюсь, это поможет вам решить проблему.

...