barrett
asked on
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;
VARIANTARG vtArgs[2];
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?
IID_NULL,
GetUserDefaultLCID(),
DISPATCH_METHOD,
&dispParams,
NULL,
NULL,
NULL );
I get back 0xc0000005 (Access Violation) in hr. How do I set up dispParams 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;
VARIANTARG vtArgs[2];
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?
IID_NULL,
GetUserDefaultLCID(),
DISPATCH_METHOD,
&dispParams,
NULL,
NULL,
NULL );
I get back 0xc0000005 (Access Violation) in hr. How do I set up dispParams correctly?
ASKER
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...
OLECHAR* szName = L"GetSessionID";
The example I was using wanted it to look like:
OLECHAR* szName = _T( "GetSessionID" );
but that wouldn't compile...
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
VT_DISPATH | 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
VT_DISPATH | VT_BYREF.
ASKER
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(Record set) );
_RecordsetPtr pErrorsRS(__uuidof(Records et) );
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!
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(Record
_RecordsetPtr pErrorsRS(__uuidof(Records
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!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
The most common mistake I've seen with GetIDsOfNames is not converting the name you want to find to a proper OLE string.