Прошу помощи в получении SAFEARRAY с помощью InvokeHelper
От: _agg  
Дата: 22.04.20 04:33
Оценка:
Всем привет, у одного из драйверов есть 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?
Отредактировано 22.04.2020 5:30 _agg . Предыдущая версия .
Re: Прошу помощи в получении SAFEARRAY с помощью InvokeHelper
От: _agg  
Дата: 22.04.20 10:02
Оценка:
Тогда пробую по другому и так 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, но массив пуст... Это метод глючит или я что то неправильно делаю... ???
Re[2]: Прошу помощи в получении SAFEARRAY с помощью InvokeHe
От: Vi2 Удмуртия http://www.adem.ru
Дата: 30.04.20 07:26
Оценка:
Здравствуйте, _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.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Отредактировано 30.04.2020 7:28 Vi2 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.