Как передать HWND с InvokeHelper для вызова .NET COM объекта?

ОБНОВИТЬ

Я сделал тестовый проект для исходного вопроса (который я переместил ниже).
Код C #:

namespace TestManagedCom
{
[ComVisible(true)]
public class DummyObject
{
public void Method1(int value)
{
IntPtr hwnd = new IntPtr(value);
MessageBox.Show(string.Format("[Method1] value={0:X}, hwnd={1}", value, hwnd));
}

public void Method2(long value)
{
IntPtr hwnd = new IntPtr(value);
MessageBox.Show(string.Format("[Method2] value={0:X}, hwnd={1}", value, hwnd));
}
}
}

Код C ++:

class CDispatchWrapper : public COleDispatchDriver
{
public:
CDispatchWrapper(){}
CDispatchWrapper(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
CDispatchWrapper(const CDispatchWrapper& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

void CallMethod(DISPID dwDispID, int value)
{
static BYTE parms[] = VTS_I4;
InvokeHelper(dwDispID, DISPATCH_METHOD, VT_EMPTY, NULL, parms, value);
}

void CallMethod(DISPID dwDispID, long long value)
{
static BYTE parms[] = VTS_I8;
InvokeHelper(dwDispID, DISPATCH_METHOD, VT_EMPTY, NULL, parms, value);
};
};

template <typename T>
void Execute(const CString& progId, const CString& methodName, T value)
{
LPDISPATCH lpEventComponent = NULL;

_com_ptr_t<_com_IIID<IDispatch, &IID_IDispatch> > pCreateComp;
HRESULT hr = pCreateComp.CreateInstance(progId);
if(SUCCEEDED(hr) && pCreateComp != NULL)
{
hr = pCreateComp.QueryInterface(IID_IDispatch, (void**)&lpEventComponent);

if(SUCCEEDED(hr))
{
USES_CONVERSION;

DISPID dwFunctionID = 0;
OLECHAR FAR *szFunc = T2OLE(const_cast<LPTSTR>(methodName.GetString()));

hr = lpEventComponent->GetIDsOfNames(IID_NULL, &szFunc, 1, LOCALE_SYSTEM_DEFAULT, &dwFunctionID);

if(SUCCEEDED(hr) && dwFunctionID != -1)
{
lpEventComponent->AddRef(); // released by the dispatch driver

CDispatchWrapper wrapper(lpEventComponent);
wrapper.CallMethod(dwFunctionID, value);
}
}
}
}

Execute<int>(_T("TestManagedCom.DummyObject"), _T("Method1"), 0x11223344);
Execute<long long>(_T("TestManagedCom.DummyObject"), _T("Method2"), 0x1122334455667788LL);

Это хорошо работает, когда цель x64. Это печатает:

[Method1] значение = 11223344, hwnd = 287454020

[Method2] значение = 1122334455667788, hwnd = 1234605616436508552

Призыв к Method2 выбрасывает исключение, когда целью является x86.

Исключение первого шанса в 0x76A2B727 в TestOleDispatcher.exe:
Исключение Microsoft C ++: EEException в ячейке памяти 0x003FE3C4.

Если есть обработчик для этого исключения, программа может быть безопасно
продолжение.

Я пытался с обоими long long а также __int64 и ошибка, очевидно, то же самое.

Кажется, что как-то не может правильно маршал VTS_I8 params на x86.

Оригинальный вопрос

У меня есть проблемы в каком-то устаревшем коде, вызывающем метод в классе .NET, который представляет COM-объект с COleDispatchDriver::InvokeHelper, Одним из параметров является дескриптор окна.

Код .NET, который выглядел так (упрощенно):

[ComVisible(true)]
public class Sample
{
public void Method1(int hwndParent)
{
}
}

И код C ++

class CSendEventWrapper : public COleDispatchDriver
{
public:
void CallMethod(DISPID dwDispID, long* hwnd)
{
static BYTE parms[] = VTS_PI4;
InvokeHelper(dwDispID, DISPATCH_METHOD, VT_EMPTY, NULL, parms, hwnd);
}
};

HWND hWnd = ...;
long lval = (long)hWnd;
o.CallMethod(dispId, &lval); // snippet for calling the method

Это работало нормально, когда приложение C ++ было только 32-разрядным. Но на 64-битной версии это не правильно, так как HWND является 64-битным и long просто 32-битный, поэтому вы теряете данные.

Поэтому я начал менять код .NET для использования IntPtr вместо int (как и должно было быть в первую очередь).

[ComVisible(true)]
public class Sample
{
public void Method1(IntPtr hwndParent)
{
}
}

Но теперь проблема в том, как я могу назвать это с InvokeHelper, Я пытался сделать что-то вроде этого:

void CallMethod(DISPID dwDispID, INT_PTR hwnd)
{
#ifdef _WIN64
static BYTE parms[] = VTS_PI8;
#else
static BYTE parms[] = VTS_PI4;
#endif
InvokeHelper(dwDispID, DISPATCH_METHOD, VT_EMPTY, NULL, parms, hwnd);
}

HWND hWnd = ...;
INT_PTR lval = (INT_PTR)hWnd; // 32- or 64-bit depending on the platform
o.CallMethod(dispId, &lval); // snippet for calling the method

Однако теперь это приводит к исключению, в котором говорится, что параметр имеет неверный формат. IntPtr должен быть 32-разрядным или 64-разрядным в зависимости от того, является ли процесс 32-разрядным или 64-разрядным. Я не уверен, что не так.

Любая помощь для выяснения, как правильно передать HWND с InvokeHelper как для 32-битных, так и для 64-битных версий. (И нет, я не могу заменить использование COleDispatchDriver).

1

Решение

Похоже, у вас несоответствие типов параметров. Получение дескриптора из c # обычно дает вам дескриптор окна в IntPtr. Это будет фактический дескриптор, а не указатель на дескриптор. Из вашего кода похоже, что вы ожидаете указатель для обработки. Я могу сказать по длинным * hWnd и VTS_PI4.

Если вызов COM действительно хочет INT_PTR (указатель на дескриптор), вам нужно будет сохранить переданную переменную и принять адрес для передачи. Если он принимает дескриптор окна напрямую, вам нужно изменить VTS_PI4 / VTS_PI8 на VTS_I4 / VTS_I8.

0

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

Других решений пока нет …

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