Есть программка на VB — последовательно зовутся несколько функций COM-объекта, поддерживающего OLE-автоматизацию.
Переписал это все на VC++, одна функция не хочет работать. Ее отличие от других — ей передается строка по ссылке, и в эту строку возвращается значение — это точно.
На VB все работает. Кода COM-класса нет, делали не мы.
Может быть, кто-нибудь подскажет методы — как разбираться с подобного рода проблемами?
Спасибо.
Здравствуйте, 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, ¶ms, &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, ¶ms, &varResult, NULL, NULL);
В res, правда, возвращается какой-то exception
, но функция отрабатывает – я это знаю точно (иначе, если бы туда передавались бы некорректные строки, на экран бы выдавалось окошко с полями для ввода логина и пароля).
Здравствуйте, 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, ¶ms, &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;
Здравствуйте, 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'ы пропали.