c# - 使用可移植类库作为 COM 接口(interface)

标签 c# c++ visual-studio-2015 com portable-class-library

我有适用于 Windows 8.1 和 Windows Phone 8.1 的 C# 可移植类库。 我想编写一个使用此库的 native (非托管)C++ Windows 应用程序。 据我所知,最佳做法是将我的库公开为 COM 接口(interface)。

这似乎是一个简单的解决方案,但是当我创建可移植类库项目时,“使程序集 COM 可见”和“注册 COM 互操作”复选框被禁用。可移植类库不可能吗?

我尝试过的:

  1. 我手动添加了条目 <RegisterForComInterop>true</RegisterForComInterop>我的项目和 visual studio 构建了我的 .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 文件看起来还不错 - here it is in a gist . 但是当我尝试运行这段代码时,它失败了,但有一个异常(exception):

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 手动注册程序集

一切似乎都很好,但异常仍然是一样的。真的不可能吗?我应该制作一个不可移植的图书馆吗?这将是浪费时间,因为我的库使用可移植的类...

最佳答案

PCL 库的设计初衷就是可移植性,因此它们实现了满足所有目标平台的最大功能集。不幸的是,这不包括 COM(即 Mac OS 上没有 COM,因此具有 COM 依赖项会使 Portable 脱离 PCL)。

RegisterForcomInterop 只解决了一半的问题,您仍然需要处理 ComVisible,这可能是您的 TypeInitializationException 的原因。米ore info here.

这有点开销,但为了省去一些麻烦,将您的 PCL 包装在一个实现相同接口(interface)的标准类库中,并且只调用 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();
     }
}

关于c# - 使用可移植类库作为 COM 接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38772090/

相关文章:

c# - 在 CRM Online 中动态使用 GetAttributeValue<T>

asp.net - 来自 ASP.NET Core 的 wwwroot 的文件夹类型并在 MVC 5 中使用它

c++ - 如何撤销 glTranslatef 的效果

c++ - 在 Visual Studio 2015 中使用 QtAddIn 调试 Visual Studio 2013 运行时

c# - Visual Studio 2015 Community Edition 下载新许可证失败

c# - 非静态方法需要 PropertyInfo.SetValue 中的目标

c# - 错误 CS1069 : The type name 'SqlConnection' could not be found in the namespace 'System.Data.SqlClient'

c# - 从另一个 Controller 调用 Controller 时的依赖注入(inject)

c++ - COleDateTime 在使用 time_t 构造时添加一个小时

c++ - Fstream 不保存文件中的最后一个单词,也不从文件中读取