我编写了一个c ++ MFC DLL,它启动了一个非常传统的OLE服务器SDI应用程序。 (我没有选择使用这个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 []”类型和值,其中包含“Type Mismatch”错误和“Null Reference Pointers”的变化
.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”作为参数传递,但我只是对它进行硬编码以使这个简单的方法正常工作。一旦我使用了这个和其他一些方法,我就打算通过IDispatch来处理COM接口实现的任何方法。
任何帮助都会受到赞赏,主要是为了让这个工作,但我也很感激有关改进代码的任何指示,我有用C ++学习的东西
感谢您!
BTW,如果这有助于澄清事情,那么App.pTriadView-> pTriadItem->目录就是我正在实施的COM类
编辑:
感谢@HansPassant(见第一条评论)我看到了我所缺少的东西。不幸的是,我已经找到了修复它的下游结果。 VARIANT“pResult”空无一人。我现在将继续追捕,但任何想法都会受到欢迎:)