Как правильно вызвать IDispatch::Invoke с обязательным параметром BSTR*

Существует множество примеров вызова IDispatch::Invoke с параметром BSTR*. У меня это работает со многими другими параметрами «SomeType*», но что бы я ни пытался, я либо получаю HRESULT несоответствия типа, E_OUTOFMEMORY, либо нарушение прав доступа. Мне кажется, что я делаю что-то не так с памятью, но я следую различным найденным примерам... В качестве примечания: последний аргумент "[out] UINT puArgErr" никогда не заполняется индексом аргумента, который вызывает проблему. Однако я знаю, что это третий аргумент типа BSTR (я успешно вызвал другой метод, который принимает два предыдущих аргумента).

VARIANTARG* v = new VARIANTARG[3];
//...Init my first 2 args
//Code omitted for initializing args 1 and 2 and wrapping everything up to call IDispatch->Invoke

//... Variation 1
VariantInit(v[2]);
BSTR val = SysAllocString(L"");
v[2].vt = VT_BSTR | BT_BYREF;
v[2].pbstrVal = &val;
//When I wrap everything up in the call to IDispatch::Invoke 
//this yields a HRESULT of Type Mismatch

*

//...Variation 2
VariantInit(v[2]);
BSTR val = SysAllocString(L"");
v[2].vt = VT_BSTR | BT_BYREF;
v[2].bstrVal = val;
//When I wrap everything up in the call to IDispatch::Invoke 
//this yields a HRESULT of E_OUTOFMEMORY

*

//...Variation 3
VariantInit(v[2]);
BSTR val = SysAllocString(L"RandomStringLargerThanTheMethodWillPlaceInTheOutParam");
v[2].vt = VT_BSTR | BT_BYREF;
v[2].bstrVal = val;
//When I wrap everything up in the call to IDispatch::Invoke 
//this yields an access violation

*

//...Variation 4
VariantInit(v[2]);
BSTR val = 0;
v[2].vt = VT_BSTR | BT_BYREF;
v[2].bstrVal = val;
//When I wrap everything up in the call to IDispatch::Invoke 
//this yields and HRESULT of 0x800706f4 A null reference pointer 
//was passed to the stub. 

Я не понимаю, почему, когда я следую другим примерам параметров BTR*, это происходит... Кроме того, у меня есть много других успешных вызовов IDispatch::Invoke, но этот BTR* останавливает меня.

ОТЧАСТНО, ПОМОГИТЕ ПОЖАЛУЙСТА!

Добавление:

IDL: [id(0x00000171)] короткая GetCategory( короткая nIndx, короткая* nCat, BSTR* bszName);


person user3739214    schedule 09.07.2014    source источник
comment
Я считаю, что Variation 1 правильно. Вы говорите, что это приводит к несоответствию типов — покажите объявление IDL метода, который вы пытаетесь вызвать. Похоже, объект на самом деле не ожидает параметра BSTR*.   -  person Igor Tandetnik    schedule 09.07.2014
comment
Трудно ответить, почему у вас возникают проблемы, если вы не показываете определение метода, который пытаетесь вызвать, чтобы мы знали, какие типы параметров он ожидает.   -  person Ken White    schedule 09.07.2014
comment
Я был почти уверен, что вариант 1 был правильным, но он дает несоответствие типа [id (0x00000171)] short GetCategory (short nIndx, short* nCat, BSTR* bszName);   -  person user3739214    schedule 09.07.2014
comment
Argh, извините, напортачил форматирование комментария с IDL: [id(0x00000171)] short GetCategory( short nIndx, short* nCat, BSTR* bszName);   -  person user3739214    schedule 09.07.2014
comment
Обычно это возвращаемое значение, украшенное [out,retval]. Требование использования аргумента pVarResult Invoke. Высокие шансы, что это сократится и умрет на 2-м аргументе, массивы не так просто получить правильно. Написание кода IDispatch вручную — это жестокое и необычное наказание, которое лучше оставить машине, использующей библиотеку типов. Попробуйте, скажем, мастер MFC.   -  person Hans Passant    schedule 09.07.2014
comment
При добавлении информации отредактируйте свой вопрос и добавьте его туда. Мало того, что там больше места, вы также можете правильно отформатировать его, чтобы код был читабельным, вы могли добавить больше деталей и, что наиболее важно, он был виден тем, кто читает ваш вопрос и может ответить на него. :-)   -  person Ken White    schedule 09.07.2014
comment
@KenWhite Ах! Спасибо за совет! У меня есть ответ на мою проблему, основанный на подсказках в комментариях. Как мне лучше всего дать этот ответ из-за моего низкого представителя SO новичка?   -  person user3739214    schedule 09.07.2014
comment
Вы можете опубликовать ответ самостоятельно (используя область «Ваш ответ» ниже), чтобы предоставить информацию будущим читателям. Здесь это вполне приемлемо; см. эту страницу [помощь/самостоятельный ответ].   -  person Ken White    schedule 09.07.2014
comment
Я буду. Не позволю мне опубликовать ответ еще около 6 часов из-за моего представителя;), но я готов его вставить, когда мне будет разрешено.   -  person user3739214    schedule 10.07.2014
comment
Параметры упаковываются в DISPPARAMS в обратном порядке - самый правый первый, самый левый последний. bszName будет в v[0], а не v[2].   -  person Igor Tandetnik    schedule 10.07.2014


Ответы (1)


Вы все были на правильном пути. Комментарий @HansPassant указал мне на момент «эврики» «пощечины по лбу», когда его предположение об этом взорвалось по другому параметру. 1-й и 2-й параметры относятся к разным типам. Передаваемые в обратном порядке для ::Invoke, они на самом деле являются 2-м и 3-м параметрами. Так что на моем «1-м» параметре он фактически взрывался из-за несоответствия типов.

В моей первоначальной версии для проверки концепции я вручную передавал параметры и целенаправленно передавал параметры правильно в обратном порядке, как того требует IDispatch::Invoke. В процессе преобразования этого в более общий подход, перебирающий массив параметров, переданных от вызывающей стороны, я изменил порядок параметров ПОСЛЕ вызова IDispatch::Invoke, когда я возвращаю их в вызывающее приложение, однако я забыл изменить их их на пути до вызова Invoke.

Святые «сам-знаешь-что», ошибки настолько эзотеричны для тех, у кого нет тонны опыта в этом деле!

Как только я исправил порядок параметров, все пошло именно так, как ожидалось. «Вариант 1» из моего вопроса, конечно, был правильным способом обработки параметра BSTR *. Для ясности, вот правильный способ инициализации параметра варианта для параметра BSTR*, вызываемого IDispatch::Invoke (в моем случае есть 2 других параметра, которые здесь не показаны)

VARIANTARG* v = new VARIANTARG[3];
//...Init my first 2 args IN REVERSE (not shown here)

//Init my third arg which is the BSTR* parameter
VariantInit(v[0]);
BSTR val = SysAllocString(L"");
v[0].vt = VT_BSTR | VT_BYREF;
v[0].pbstrVal = &val;
person user3739214    schedule 10.07.2014
comment
Я думаю, что эта строка: v[0].vt = VT_BSTR | BT_BYREF должна читаться как VT_BSTR | VT_BYREF (VT_, а не BT_) - person transistor1; 31.01.2017