0

我已经编写了一个 c++ MFC DLL,它提供了一个 SDI 应用程序,它是一个非常旧的 OLE 服务器。(我没有选择使用这个 OLE 服务器,所以我必须让它工作。)

我正在从 C# 访问这个 c++ DLL。

我有一切“工作”。我可以调用 DLL 的方法,我已经正确实现了 C# 委托,等等。

我可以直接在 C++ 中调用 OLE 服务器的方法并导出这些方法,以便我的 C# 应用程序调用也调用它们。这是我的“Hello World”,用于从 C# 访问 OLE 服务器的全部功能。

到目前为止,一切都很好。

下一步是使这个 C++ DLL 尽可能多地成为“传递”,以便 C# 开发人员可以围绕这个 OLE 服务器编写业务逻辑。如果 OLE 服务器的制造商发生更改或更新,我们不想更新 C++ 代码,我们希望响应 C# 中的更改。

因此,即使我可以使用从 OLEServer.tlb 文件中导入的类在 C++ 中实现方法并将这些方法传递给 C#,我们最终也不希望这样做。我试图通过 IDispatch 接口调用方法,但我遇到了我不太理解的困难。

我将 Visual Studio 2010 用于非托管 C++ 和 C#。

VARIANT LaserCat::LaserCatCommand(LPCTSTR* p_pMethodNameAndParamsInReverseOrder, UINT p_Count)
{
  AFX_MANAGE_STATE(AfxGetStaticModuleState());
  VARIANT result;
  VARIANT* pResult = NULL;
  VariantInit(&result);
  HRESULT hr = NULL;
  DISPID dispid;
  const IID IID_ITriad = {0x60EE772D,0xE076,0x4F58,{0xA8,0xB4,0x2F,0x7A,0x29,0xBB,0x02,0x50}};
  COleException* pError = NULL;
  BOOL HasDispatch = theApp.pTriadView->pTriadItem->Catalog.CreateDispatch(IID_ITriad, pError);
  LPDISPATCH iDisp = theApp.pTriadView->pTriadItem->Catalog.m_lpDispatch;
  LPOLESTR Names[1] = {(LPOLESTR)L"GetInterfaceVersion"};
  hr = iDisp->GetIDsOfNames(IID_NULL, Names, 1, LOCALE_SYSTEM_DEFAULT, &dispid);

  if (hr != S_OK) return result;

  DISPPARAMS* pParams = new DISPPARAMS();
  short maj = 0;
  short min = 0;
  short* nMajor = &maj;
  short* nMinor = &min;
  VARIANTARG Args[2];
  VariantInit(&Args[0]);
  VariantInit(&Args[1]);
  Args[0].piVal = nMinor;
  Args[0].vt = VT_BYREF;
  Args[1].piVal = nMajor;
  Args[1].vt = VT_BYREF;
  pParams->rgvarg = Args;
  pParams->cNamedArgs = 0;
  pParams->cArgs = 2;
  pParams->rgdispidNamedArgs = NULL;
  EXCEPINFO* pExcept = NULL;
  UINT* pArgErrorIndex = NULL;
  LPCTSTR Error = NULL;

  hr = iDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, pParams, pResult, pExcept, pArgErrorIndex);
  if (pExcept != NULL || pArgErrorIndex != NULL || hr != S_OK)
  {
    Error = _T("Error");
    return result;
  }
  result = *pResult;
  return result;
}

上面的以下行给了我一个“错误的变量类型”错误:

  hr = iDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, pParams, pResult, pExcept, pArgErrorIndex);

顺便说一句,我确信代码可以大大改进,自从我用 C++ 编写以来已经有好几年了,这只是让它工作的“第一步”,所以没有真正的错误处理等。

我玩弄了“Args []”类型和值,其中包含“类型不匹配”错误和“空引用指针”的变体

.tlb 文件导入的函数如下所示:

  short GetInterfaceVersion(short * nMajor, short * nMinor)
  {
    short result;
    static BYTE parms[] = VTS_PI2 VTS_PI2 ;
    InvokeHelper(0x178, DISPATCH_METHOD, VT_I2, (void*)&result, parms, nMajor, nMinor);
    return result;
  }

哦,虽然我将“pMethodNameAndParamsInReverseOrder”作为参数传递,但我只是对其进行硬编码以使这个简单的方法起作用。一旦我使用了这个和其他一些方法,我计划让这个通用来处理 COM 接口通过 IDispatch 实现的任何方法。

任何帮助将不胜感激,主要是为了让这个工作,但我也很感激任何关于改进代码的指针,我有很多东西要在 C++ 中学习

谢谢你!

顺便说一句,如果这有助于澄清事情,那么 App.pTriadView->pTriadItem->Catalog 是我正在实现的 COM 类

编辑:

感谢@HansPassant(见第一条评论)我明白了我错过了什么。不幸的是,我遇到了修复该问题的下游结果。VARIANT“pResult”返回为空。我现在将继续追捕,但欢迎任何想法:)

4

0 回答 0