c # — использовать Portable Class Library в качестве COM-интерфейса

У меня есть C # портативная библиотека классов для Windows 8.1 и Windows Phone 8.1.
Я хочу написать родное (неуправляемое) приложение C ++ для Windows, которое использует эту библиотеку.
Насколько я видел, лучшая практика — выставлять мою библиотеку как интерфейс COM.

Это кажется простым решением, но когда я создаю проект Portable Class Library, флажки «Сделать сборку COM видимой» и «Зарегистрироваться для взаимодействия COM» отключены. Это невозможно для Portable Class Library?

Что я пробовал:

  1. Я вручную добавил запись <RegisterForComInterop>true</RegisterForComInterop> В мой проект и визуальную студию встроил мне файл .tlb без ошибок.

  2. Я добавил его в свой проект C ++:

#include "stdafx.h"#import "COM\MyLib.tlb"#include<iostream>
using namespace MyLib;
using namespace std;

int main()
{
CoInitialize(NULL);   //Initialize all COM Components

IPayMeLogicPtr core = IPayMeLogicPtr(_uuidof(ComPayMeLogic));
LoginStatus res = core->Login("myLogin", "myPassword", false, PayMeSDK::Language::Language_ru, true, "");

cout << res;
return 0;
}

Сгенерированный файл .tlh выглядит довольно хорошо — вот в чем суть.
Но когда я пытаюсь запустить этот код, он терпит неудачу за исключением:

exception at memory location 0x74A5DAE8 (KernelBase.dll) in PayMeDemo.ComConsoleDemo.exe: 0xE0434352 (0x80131534, 0x00000000, 0x00000000, 0x00000000, 0x73A10000).
exception at memory location 0x74A5DAE8 in PayMeDemo.ComConsoleDemo.exe:  Microsoft C++ exception: _com_error at location 0x00BBFADC.

Похоже, это происходит в четвертой строке кода в .tli (_hr не удается):

inline enum LoginStatus IPayMeLogic::Login ( _bstr_t Login, _bstr_t password, VARIANT_BOOL testEnviroment, enum Language locale, VARIANT_BOOL savePassword, _bstr_t applicationToken ) {
enum LoginStatus _result;
HRESULT _hr = raw_Login(Login, password, testEnviroment, locale, savePassword, applicationToken, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}

_hr невероятно похож на 0x80131534 error (TypeInitializationException)

Однако я не могу представить, какие типы могут быть неправильными. Функция входа выглядит так:

    LoginStatus Login(string login, string password, bool testEnviroment, Language locale, bool savePassword, string applicationToken = null);

Я уже пыталась

  1. Добавить сборку в GAC
  2. Зарегистрировать сборку вручную с помощью Regasm.exe

Все выглядит хорошо, но исключение остается прежним. Это действительно невозможно? Должен ли я сделать непереносимую библиотеку? Это было бы пустой тратой времени, потому что моя библиотека использует классы из портативных …

1

Решение

Библиотеки PCL были разработаны так, чтобы быть просто переносимыми, поэтому они реализовали самый большой набор функций, которые удовлетворяют всем целевым платформам. К сожалению, это исключает COM (т. Е. В Mac OS нет COM, поэтому наличие зависимостей COM приведет к переносу Portable из PCL).

RegisterForcomInterop решает только половину проблемы, вам все равно нужно иметь дело с ComVisible, возможно, причиной вашего исключения TypeInitializationException. MИнформация о руде здесь.

Это немного накладные расходы, но чтобы избежать некоторой боли, лучше всего обернуть PCL в стандартную библиотеку классов, реализующую тот же интерфейс и просто вызывать методы PCL в качестве прохода. Тогда используйте стандартный ComVisible и т. Д.

Вот некоторый псевдокод, который нужно объяснить в сборке PCL:

IMyPclInterface
{
void DoSomeWork();
}

public class MyPclImplementation : IMyPclInterface
{
public void DoSomeWork()
{
....
....
....
}
}

В стандартной библиотеке классов укажите вашу библиотеку PCL и:

public class MyComImplementation : IMyPclInterface
{
MyPclInstance myPclInstance;

public MyComImplementation()
{
myPclInstance = new MyPclInstance();
}

public void DoSomeWork()
{
myPclInstance.DoSomeWork();
}
}
1

Другие решения

Как Мюррей Фоккрофт отметил, что можно сделать копию библиотеки PCL, скомпилированной как стандартная библиотека классов. Кроме того, можно добавить зависимости PCL для стандартной библиотеки классов, и это будет работать.

Тем не менее, вам не нужно делать это. Несмотря на то, что Visual Studio не предоставляет вам флажок для COM, вы все равно можете добавить атрибут вручную, как указано в вопросе или запустить Regasm.exe smth.dll /tlb вручную, и вы получите действительную библиотеку COM. Это действительно сложно отладить, но Ганс Пассант оставил несколько хороших советов:

Оболочки, созданные директивой #import, превращают коды ошибок COM.
в исключения C ++. Если вы хотите диагностировать ошибку, а не просто
после сбоя программы вы должны написать try / catch (_com_error&
ex) {} чтобы сообщить об этом. Измените Тип отладчика с Авто на Смешанный, чтобы
вам будет гораздо легче справляться с проблемами C #,
TypeInitializationException требует такой помощи. И написать C #
модульный тест, чтобы вы получили основные проблемы, прежде чем пытаться вызвать его
из C ++

0

По вопросам рекламы [email protected]