Reputation: 51
I am working on an application, which connects to a COM object and calls methods and gets properties from this object etc. I can connect and call the members, that is not the issue. I cannot however figure out, how to call a method, which has an output parameter, for instance (pseudo code):
int GetAppVersion(bsRetMsg [out, optional]).
This functions return int as the version and can also return a string representation of the version via the output parameter.
What I've tried:
(1)
VARIANT result;
DISPPARAMS params = {NULL, NULL, 0, 0};
VARIANTARG args[1];
BSTR str = SysAllocString(L"longerfoostring");
VariantInit(&args[0]);
args[0].vt = VT_BSTR | VT_BYREF;
args[0].bstrVal = str;
params.rgvarg = args;
params.cArgs = 1;
res = dispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL,
NULL);
if (SUCCEEDED(res)) { // here it failed: Not enough storage is available to complete this operation.
std::cout << result.intVal << std::endl;
...
(2)
VARIANT result;
DISPPARAMS params = {NULL, NULL, 0, 0};
VARIANTARG args[1];
BSTR str = SysAllocString(L""); // change: empty string
VariantInit(&args[0]);
args[0].vt = VT_BSTR | VT_BYREF;
args[0].bstrVal = str;
params.rgvarg = args;
params.cArgs = 1;
res = dispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL,
NULL);
if (SUCCEEDED(res)) { // here it failed: Not enough storage is available to complete this operation.
std::cout << result.intVal << std::endl;
...
(3)
...
BSTR str = SysAllocString(L"longerfoostring");
VariantInit(&args[0]);
args[0].vt = VT_BSTR; // change: no BYREF
args[0].bstrVal = str;
params.rgvarg = args;
params.cArgs = 1;
... invoke is the same...
res = dispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL,
NULL);
if (SUCCEEDED(res)) {
std::cout << result.intVal << std::endl; // this number is correct - version in int
printf("'%S'", params.rgvarg[0].bstrVal); // prints 'longerfoostring' instead of version, ie. '2.0.5...'
(4)
BSTR *str;
VariantInit(&args[0]);
args[0].vt = VT_BSTR | VT_PTR; // change: different VT
args[0].pbstrVal = str; //change: different type
params.rgvarg = args;
params.cArgs = 1;
... invoke failes with Bad variable type.
So the question is: How to pass a string (or any type) as an input/output parameter to a COM method and correctly get the output from this parameter?
Upvotes: 1
Views: 2097
Reputation: 201
Since you want to get back the data, you have to provide the address of a BSTR
BSTR str;
VariantInit(&args[0]);
args[0].vt = VT_BSTR | VT_BYREF; // it's a BSTR and it's by ref
args[0].pbstrVal = &str; // give address of variable
params.rgvarg = args;
params.cArgs = 1;
now call invoke and don't forget to free the returned BSTR.
Upvotes: 2