На VB всё работает, на VC++ одна функция не работает
От: avk-75  
Дата: 14.10.05 13:24
Оценка:
Есть программка на VB — последовательно зовутся несколько функций COM-объекта, поддерживающего OLE-автоматизацию.

Переписал это все на VC++, одна функция не хочет работать. Ее отличие от других — ей передается строка по ссылке, и в эту строку возвращается значение — это точно.

На VB все работает. Кода COM-класса нет, делали не мы.

Может быть, кто-нибудь подскажет методы — как разбираться с подобного рода проблемами?

Спасибо.
Re: На VB всё работает, на VC++ одна функция не работает
От: slava_529872  
Дата: 14.10.05 14:49
Оценка:
A7>Переписал это все на VC++, одна функция не хочет работать. Ее отличие от других — ей передается строка по ссылке, и в эту строку возвращается значение — это точно.

В COM-метод строка по ссылке не может передаваться. Если параметр принимает возвращаемое значение — то он как минимум указатель на BSTR.
Пришли сигнатуру метода (из IDL) и как ты его вызываешь!
Re[2]: На VB всё работает, на VC++ одна функция не работает
От: avk-75  
Дата: 14.10.05 16:22
Оценка:
Здравствуйте, slava_529872, Вы писали:

>Пришли сигнатуру метода (из IDL)...


IDL по-моему нет… (вообще-то я новичок в COM, но все же, как мне кажется, основные принципы понимаю). Может так быть?


>...и как ты его вызываешь!


Вот код на VB (это работает):

Dim locClassName As String
Dim locMethodName As String
Dim locParams As String
Dim Err As String

Set Test = CreateObject("<ObjectName>")
Err = Test.Login("username", "password")
locClassName = "tOrder"
locMethodName = "USRPSetFF_TST"
locParams = ""

Err = Test.CallClassMethod(locClassName, locMethodName, locParams, 1)

Err = Test.ShutdownBOleSrv()
Set Test = Nothing

===============================================================================================================

Вот, как метод описан в документации:

long CallClassMethod(string parClassName, string parMethodName, string* parMethodParams, long parMessageMode)

===============================================================================================================

Вот как я пытаюсь вызвать из VC++:

HRESULT res;

LPOLESTR str3 = OLESTR("CallClassMethod");

wchar_t locClassName[] = L"tOrder";
BSTR locBSTR_ClassName = ::SysAllocString(locClassName);
wchar_t locMethodName[] = L"USRPSetFF_TST";
BSTR locBSTR_MethodName = ::SysAllocString(locMethodName);
wchar_t locNullStr_Smp[] = L"";
BSTR locBSTR_NullStr_Smp = ::SysAllocString(locNullStr_Smp);

VARIANTARG varg[4];
::VariantInit(varg);
VARIANT varResult;
DISPPARAMS params;

varg[0].vt = VT_BSTR;
varg[0].bstrVal = locBSTR_ClassName;
varg[1].vt = VT_BSTR;
varg[1].bstrVal = locBSTR_MethodName;
varg[2].vt = VT_BYREF | VT_BSTR;
varg[2].pbstrVal = &locBSTR_NullStr_Smp;
varg[3].vt = VT_I4;
varg[3].lVal = 1;

VariantClear(&varResult);

params.cArgs = 4;
params.rgvarg = varg;
params.cNamedArgs = 0;
params.rgdispidNamedArgs = NULL;
pDisp->GetIDsOfNames(IID_NULL, &str3, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
res = pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, &argerr);

::SysFreeString(locBSTR_ClassName);
::SysFreeString(locBSTR_MethodName);
::SysFreeString(locBSTR_NullStr_Smp);


res возвращает 0x80020005, что, согласно WINERROR.H означает DISP_E_TYPEMISMATCH – несоответствие типов. Написано, что argerr при этом должен возвращать индекс аргумента, вызвавшего ошибку. В аrgerr возвращается 0x00000000. Ошибка в 1-ом параметре? Но функция Login, также принимающая строки, отрабатывает корректно, вот как я ее зову из VC++ (кусок той же программы):


HRESULT res;

LPOLESTR str = OLESTR("Login");

wchar_t locNullStr_UserName[] = L"username";
BSTR locBSTR_NullStr_UserName = ::SysAllocString(locNullStr_UserName);
wchar_t locNullStr_Password[] = L"password";
BSTR locBSTR_NullStr_Password = ::SysAllocString(locNullStr_Password);

VARIANTARG varg[4];
::VariantInit(varg);
VARIANT varResult;
DISPPARAMS params;

varg[0].vt = VT_BSTR;
varg[0].bstrVal = locBSTR_NullStr_UserName;
varg[1].vt = VT_BSTR;
varg[1].bstrVal = locBSTR_NullStr_Password;

VariantClear(&varResult);

params.cArgs = 2;
params.rgvarg = varg;
params.cNamedArgs = 0;
params.rgdispidNamedArgs = NULL;
pDisp->GetIDsOfNames(IID_NULL, &str, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
res = pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL);


В res, правда, возвращается какой-то exception , но функция отрабатывает – я это знаю точно (иначе, если бы туда передавались бы некорректные строки, на экран бы выдавалось окошко с полями для ввода логина и пароля).
Re[3]: На VB всё работает, на VC++ одна функция не работает
От: algol Россия about:blank
Дата: 16.10.05 13:43
Оценка:
Здравствуйте, avk-75, Вы писали:

A7>Вот как я пытаюсь вызвать из VC++:


Читать весь код не осилил, но стало непонятно, зачем работать через позднее связывание и писать все вручную. Не проще ли воспользоваться директивой #import? Тогда и в коде легче разобраться будет, и лишние заморочки с VARIANT не потребуются.
Re[3]: На VB всё работает, на VC++ одна функция не работает
От: Vi2 Удмуртия http://www.adem.ru
Дата: 17.10.05 04:11
Оценка:
Здравствуйте, avk-75, Вы писали:

A7>long CallClassMethod(string parClassName, string parMethodName, string* parMethodParams, long parMessageMode)

A7>   VARIANTARG varg[4];
A7>   varg[0].vt = VT_BSTR;
A7>   varg[0].bstrVal = locBSTR_ClassName;
A7>   varg[1].vt = VT_BSTR;
A7>   varg[1].bstrVal = locBSTR_MethodName;
A7>   varg[2].vt = VT_BYREF | VT_BSTR;
A7>   varg[2].pbstrVal = &locBSTR_NullStr_Smp;
A7>   varg[3].vt = VT_I4;
A7>   varg[3].lVal = 1;

A7>   params.cArgs = 4;
A7>   params.rgvarg = varg;
A7>   params.cNamedArgs = 0;
A7>   params.rgdispidNamedArgs = NULL;
A7>   pDisp->GetIDsOfNames(IID_NULL, &str3, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
A7>   res = pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, &argerr);

Параметры через Invoke передаются в обратном порядке, смотри Passing Parameters.
   varg[3].bstrVal = locBSTR_ClassName;     varg[3].vt = VT_BSTR;
   varg[2].bstrVal = locBSTR_MethodName;    varg[2].vt = VT_BSTR;
   varg[1].pbstrVal = &locBSTR_NullStr_Smp; varg[1].vt = VT_BYREF | VT_BSTR;
   varg[0].lVal = 1;                        varg[0].vt = VT_I4;
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: На VB всё работает, на VC++ одна функция не работает
От: avk-75  
Дата: 17.10.05 06:31
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Параметры через Invoke передаются в обратном порядке, смотри Passing Parameters.

Vi2>
Vi2>   varg[3].bstrVal = locBSTR_ClassName;     varg[3].vt = VT_BSTR;
Vi2>   varg[2].bstrVal = locBSTR_MethodName;    varg[2].vt = VT_BSTR;
Vi2>   varg[1].pbstrVal = &locBSTR_NullStr_Smp; varg[1].vt = VT_BYREF | VT_BSTR;
Vi2>   varg[0].lVal = 1;                        varg[0].vt = VT_I4;
Vi2>


Спасибо!!! Заработало!
И exception'ы пропали.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.