ADO Recordsets as DISPPARAMS in C++?

I have an MTS component authored in VB (it's a remote server), and I'd like to call methods on it from C++ (ATL). I can get an IUnknown pointer from CoCreateInstance, then an IDispatch pointer from CComQIPtr, then I can get the dispId of a method from pDisp->GetIDsOfNames (dispId comes back as 0x60030003), but I don't know how to set up the DISPPARAMS to call Invoke correctly.

The signature of the method is:
GetSessionID( [out] _Recordset** ppSessionRS, [out] _Recordset** ppErrorRS) in IDL style, or

GetSessionID( Recordset SessionRS, Recordset ppErrorRS) in VB style.

So I'm setting up my DISPPARAMS like this:

DISPPARAMS dispParams;
dispParams.rgvarg = vtArgs;
dispParams.rgvarg[0] = VT_DISPATCH; // do I need | VT_BYREF?
dispParams.rgvarg[1] = VT_DISPATCH;
dispParams.cArgs = 2;
dispParams.cArgs = 0; // 2?

hr = pDisp->Invoke( dispID // 0x6003003, a reasonable value?
                    NULL );

I get back 0xc0000005 (Access Violation) in hr. How do I set up dispParams correctly?

Who is Participating?
basantConnect With a Mentor Commented:
What about points.
0x60030003 is an odd value for a dispid.  What HRESULT is GetIDsOfNames returning?  If it's not S_OK, then you cannot use the dispid returned.

The most common mistake I've seen with GetIDsOfNames is not converting the name you want to find to a proper OLE string.
barrettAuthor Commented:
GetIDsOfNames is returning S_OK, although I though that dispId looked weird as well. Here's my declaration for the name:

OLECHAR* szName = L"GetSessionID";

The example I was using wanted it to look like:

OLECHAR* szName = _T( "GetSessionID" );

but that wouldn't compile...
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

I'd have to conclude that if GetIDsOfNames is returning S_OK, that it's the right dispid.  Have you looked at the object in the OLE Viewer and check the dispids?
> do I need | VT_BYREF?

Yes, you have to.
Since it is an out pointer to pointer.
So you have to pass reference.

> dispParams.cArgs = 2;

It should be 2.

> I get back 0xc0000005 (Access >Violation) in hr. How do I set up >dispParams correctly?

The following problems can happen.

You should Initialize the variant to
VT_EMPTY for being safe side though
it is not an input parameter.

You are getting access violation
as you are not using the

barrettAuthor Commented:
Unfortunately, I still get the same behavior when I use VT_DISPATCH | VT_BYREF.

In answer to jhance's question, when I look at the object in the OLE/COM Viewer, the dispId is, in fact, 0x60030003, so that much is working correctly.

I just discovered the solution, however. I've declared two Recordset objects:

_RecordsetPtr pSessionRS(__uuidof(Recordset) );

_RecordsetPtr pErrorsRS(__uuidof(Recordset) );

In addition to setting the variant type to VT_DISPATCH|VT_BYREF, I need to set the ppdispVal value, like so:

vtArgs[0].ppdispVal = (IDispatch**)&pSessionRS;
vtArgs[1].ppdispVal = (IDispatch**)&pErrorsRS;

Now the Invoke call succeeds. Seems rather obvious now...

Thanks for the help, everybody!
All Courses

From novice to tech pro — start learning today.