2

There are many examples of how to call IDispatch::Invoke with a BSTR* parameter. I have this working with many other "SomeType*" parameter but no matter what I try, I either get HRESULT of Type Mismatch, E_OUTOFMEMORY or an access violation. It seems to me I am doing something wrong with memory but I am following the different examples I have found... As a side note, the final "[out] UINT puArgErr" argument is never filled with the argument index that is causing the problem. However, I know it is the 3rd argument of type BSTR (I have successfully called another method that takes the 2 previous arguments.)

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. 

I don't understand why when I am following other examples of BTR* parameters this is happening... Furthermore I have many other successful calls to IDispatch::Invoke but this BTR* has me ground to a halt.

DESPERATE, PLEASE HELP!

Addition:

IDL is: [id(0x00000171)] short GetCategory( short nIndx, short* nCat, BSTR* bszName);

user3739214
  • 81
  • 1
  • 6
  • 1
    I believe `Variation 1` is correct. You say it results in "type mismatch" - show the IDL declaration of the method you are trying to call. Looks like the object does not in fact expect a `BSTR*` parameter. – Igor Tandetnik Jul 09 '14 at 17:43
  • It's difficult to answer why you're having problems when you don't show the definition of the method you're trying to call so we know what parameter types it expects. – Ken White Jul 09 '14 at 17:44
  • I was pretty sure Variation 1 was the correct one yet it yields the Type Mismatch[id(0x00000171)] short GetCategory( short nIndx, short* nCat, BSTR* bszName); – user3739214 Jul 09 '14 at 17:46
  • Argh, sorry, screwed up the formatting for the comment with the IDL: [id(0x00000171)] short GetCategory( short nIndx, short* nCat, BSTR* bszName); – user3739214 Jul 09 '14 at 18:18
  • 1
    That's normally the return value, decorated with [out,retval]. Requiring the use of Invoke's pVarResult argument. High odds that this shrivels up and dies on the 2nd argument, arrays are not that easy to get right. Writing IDispatch code by hand is cruel and unusual punishment, best left to a machine that uses the type library. Give, say, the MFC wizard a spin. – Hans Passant Jul 09 '14 at 18:27
  • When adding information, please [edit] your question and add it there. Not only is there more space, but you can properly format it so that the code is readable, you can add more details, and most importantly it is visible to those reading your question that might be able to answer it. :-) – Ken White Jul 09 '14 at 18:32
  • @KenWhite Ah! Thanks for the tip! I have an answer for my problem based on hints in comments. What is the best way for me to provide this answer due to my low SO newbie rep? – user3739214 Jul 09 '14 at 19:19
  • You can post an answer yourself (using the "Your Answer" area below) to provide the information for future readers. It's perfectly acceptable to do so here; see this [help/self-answer] page. – Ken White Jul 09 '14 at 19:30
  • I will. Won't let me post an answer for about another 6 hours due to my rep ;) but I have it ready to be pasted in when I am allowed. – user3739214 Jul 09 '14 at 21:30
  • Parameters are packed into `DISPPARAMS` backwards - rightmost first, leftmost last. `bszName` would be at `v[0]`, not `v[2]`. – Igor Tandetnik Jul 10 '14 at 14:13

1 Answers1

3

You were all on the right track. @HansPassant comment pointed me to the "forehead-slap" "eureka" moment with his surmising about it blowing up on a different parameter. The 1st and 2nd parameters are of a different type. Passed in reverse for ::Invoke they are actually the 2nd and 3rd parameters. So it was actually blowing up on my "1st" parameter with a type mismatch.

In my initial proof-of-concept version I was manually passing parameters and I was purposefully passing the parameters correctly in reverse order as required by IDispatch::Invoke. In the process of converting this to a more generic approach looping through an array of parameters passed from the caller I reversed the parameter order AFTER the call to IDispatch::Invoke when I am returning them to the calling app, however, I forgot to reverse them on the way in prior to the call to Invoke.

Holy "you-know-what" the errors are so esoteric to someone without a ton of experience with this stuff!

Once I fixed the order of parameters everything behaved exactly as expected. "Variation 1" from my question was, of course, the correct way to handle the BSTR* parameter. For clarity, here is the correct way to initialize a variant parameter for a BSTR* parameter being called by IDispatch::Invoke (in my case there are 2 other parameters that are not shown here)

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;
manuell
  • 7,528
  • 5
  • 31
  • 58
user3739214
  • 81
  • 1
  • 6