Я написал C ++ MFC DLL, которая вызывает приложение SDI, которое является очень устаревшим OLE-сервером. (У меня нет выбора в использовании этого OLE-сервера, поэтому я должен заставить его работать.)
Я обращаюсь к этой C ++ DLL из C #.
У меня все «работает». Я могу вызывать методы DLL, правильно реализовал делегаты C # и т. Д.
Я могу вызывать методы OLE-сервера непосредственно в C ++ и экспортировать их, чтобы мое приложение C # вызывало их тоже. Это мой «Hello World» за полный доступ к функциональности OLE-сервера из C #.
Все идет нормально.
Следующий шаг — сделать эту C ++ DLL как можно более «сквозной», чтобы разработчики на C # могли писать бизнес-логику вокруг этого OLE-сервера. Если изменения или обновления происходят от создателя OLE-сервера, нам не нужно обновлять код C ++, мы хотим реагировать на изменения в C #.
Поэтому, хотя я могу реализовать методы в C ++, используя импортированный класс из файла OLEServer.tlb и передать их в 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 (см. Первый комментарий) я вижу то, что мне не хватало. К сожалению, я получил нижестоящий результат исправления этого. ВАРИАНТ «pResult» возвращается пустым. Я буду продолжать выслеживать это сейчас, но любые мысли приветствуются 🙂
Задача ещё не решена.