Всем привет, у одного из драйверов есть COM оболочка , на которой все написано, частью методов пользовались частью нет, и вот понадобилось воспользоваться методом который возвращает SAFEARRAY и возникла проблема.
Изначально студия сгенерировала MFC оболочку на основе COleDispatchDriver выглядит примерно так:
class CFptr : public COleDispatchDriver
{
public:
CFptr() {} // Calls COleDispatchDriver default constructor
CFptr(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
CFptr(const CFptr& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
...
CString getParamStr(long paramId) {
CString result;
static BYTE parms[] = VTS_I4;
InvokeHelper(0x18, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, paramId);
return result;
}
SAFEARRAY * getParamByteArray(long paramId)
{
static BYTE parms[] = VTS_I4;
InvokeHelper(0x1a, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, paramId);
}
Сам студийный генератор в оболочку сгенерировал ошибку в методе getParamByteArray. Вообще с SAFEARRAY я работал раньше, но не через InvokeHelper, тут я перепробовал различные варианты, но результат один исключение во время вызова.Пробовал написать вот таким образом, но результат тот же, исключение:
SAFEARRAY * getParamByteArray(long paramId) {
CComSafeArray<BYTE> arr(1024);
static BYTE parms[] = VTS_PI4;
InvokeHelper(0x1a, DISPATCH_METHOD, VT_ARRAY, (void*)&arr, parms, paramId);
return arr.Detach();
}
С помощью OleView создал idl-file этого COM, этот метод выглядит вот таким образом:
[id(0x0000001a)]
HRESULT getParamByteArray(
[in] long paramId,
[out, retval] SAFEARRAY(unsigned char)* value)
Подскажите кто в курсе как получить SAFEARRAY c помощью InvokeHelper?
Тогда пробую по другому и так IDL :
HRESULT getParamByteArray(
[in] long paramId,
[out, retval] SAFEARRAY(unsigned char)* value);
У COleDispatchDriver есть поле m_lpDispatch типа IDispatch пробуем:
Вызов метода:
CComSafeArray<BYTE> array(1024);
m_error = p->getParamByteArray(param::LIBFPTR_PARAM_OFD_FISCAL_SIGN, array.GetSafeArrayPtr());
long getParamByteArray(long paramId, SAFEARRAY **parray) {
DISPPARAMS dispparams;
VARIANTARG varArgIn;
VARIANTARG varArgResult;
varArgResult.parray =*parray;
VariantInit(&varArgIn);
VariantInit(&varArgResult);
V_VT(&varArgIn) = (VT_INT);
V_VT(&varArgResult) = (VT_ARRAY | VT_UI1);
memset(&dispparams, 0, sizeof(DISPPARAMS));
dispparams.rgvarg = &varArgIn;
dispparams.cArgs = 1;
UINT nErrArg;
EXCEPINFO excepinfo;
HRESULT hr = m_lpDispatch->Invoke(0x1a, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, &varArgResult, &excepinfo, &nErrArg);
return hr;
}
Запускаем, исключения нет, hr равен S_OK, но массив пуст... Это метод глючит или я что то неправильно делаю... ???
Здравствуйте, _agg, Вы писали:
По поводу первого сообщения:
InvokeHelper(0x1a, DISPATCH_METHOD, VT_ARRAY, (void*)&arr, parms, paramId);
В
документации говорится, что InvokeHelper не понимает такой тип. Можно, конечно, попробовать скормить ему VT_ARRAY|VT_UI1, наверное, с тем же эффектом. Так что остаётся вариант с VT_VARIANT и приведением массивов как показано ниже.
_>У COleDispatchDriver есть поле m_lpDispatch типа IDispatch пробуем:
_>Вызов метода:
_>CComSafeArray<BYTE> array(1024);
_>m_error = p->getParamByteArray(param::LIBFPTR_PARAM_OFD_FISCAL_SIGN, array.GetSafeArrayPtr());
_> long getParamByteArray(long paramId, SAFEARRAY **parray) {
_> DISPPARAMS dispparams;
_> VARIANTARG varArgIn;
_> VARIANTARG varArgResult;
_> varArgResult.parray =*parray;
_> VariantInit(&varArgIn);
_> VariantInit(&varArgResult);
_> V_VT(&varArgIn) = (VT_INT);
_> V_VT(&varArgResult) = (VT_ARRAY | VT_UI1);
_> memset(&dispparams, 0, sizeof(DISPPARAMS));
_> dispparams.rgvarg = &varArgIn;
_> dispparams.cArgs = 1;
_> UINT nErrArg;
_> EXCEPINFO excepinfo;
_> HRESULT hr = m_lpDispatch->Invoke(0x1a, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, &varArgResult, &excepinfo, &nErrArg);
_> return hr;
_> }
_>Запускаем, исключения нет, hr равен S_OK, но массив пуст... Это метод глючит или я что то неправильно делаю... ???
Параметр же out, retval, так что все выкрутасы с V_VT(&varArgResult) = (VT_ARRAY|VT_UI1) и varArgResult.parray =*parray не пройдут. Нужно просто принять вариант из метода и вернуть его значение в требуемой форме.
VARIANTARG varArgResult;
VariantInit(&varArgResult);
HRESULT hr = m_lpDispatch->Invoke(0x1a, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, &varArgResult, &excepinfo, &nErrArg);
if (SUCCEEDED(hr))
parray[0] = V_ARRAY(&varArgResult);
PS
Вместо VT_INT лучше использовать VT_I4.