【发布时间】:2023-01-18 07:10:56
【问题描述】:
我有一个公开函数的 COM 对象。我想将参数传递给此函数并接收返回值。我将 C++ 与 CoCreateInstance 一起使用。我收到的错误是hr = 0x8002000e : 参数数量无效.
我有理由相信我有正确的数字参数,我可以在 OleView 中查看:
[id(0x68030001), propget]
double My_function(
[in, out] double* PdblPrice,
[in, out] DATE* PdateStartDate,
[in, out] short* PintFlag,
[in, out] VARIANT_BOOL* PbolXP,
[in, out] SAFEARRAY(double)* PdblScale);
我的代码摘要如下,它的工作原理如下所示:
#include <windows.h>
#include <objbase.h>
#include <comutil.h>
#include <vector>
#include <atlcomcli.h>
int main()
{
HRESULT hr;
// Create an instance of COM object
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
CLSID clsid;
HRESULT nResult1 = CLSIDFromProgID(OLESTR("My_Library.clsMy_Library"), &clsid);
IUnknown* pUnknown;
hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&pUnknown);
// Get the IDispatch interface
IDispatch* pDispatch;
hr = pUnknown->QueryInterface(IID_IDispatch, (void**)&pDispatch);
// Call the Invoke method
DISPID dispid;
BSTR bstrFunction = SysAllocString(L"My_function");
hr = pDispatch->GetIDsOfNames(IID_NULL, &bstrFunction, 1, LOCALE_USER_DEFAULT, &dispid);
// ALL OF THE ABOVE WORKS.
// Prepare the arguments for the method call
// first convert a std::vector to SAFEARRAY
std::vector<double> _PdblScale = { 0, 0.25, 0.5, 0.75, 1.0, 0, 0, 0.5, 1, 1 };
SAFEARRAY* psa = SafeArrayCreateVector(VT_R8, 0, _PdblScale.size());
int* pData;
HRESULT hr_ = SafeArrayAccessData(psa, (void**)&pData);
if (SUCCEEDED(hr_))
{
for (unsigned int i = 0; i < _PdblScale.size(); i++)
{
pData[i] = _PdblScale[i];
}
SafeArrayUnaccessData(psa);
}
DISPPARAMS dispparams;
dispparams.cArgs = 5;
dispparams.rgvarg = new VARIANT[5];
dispparams.cNamedArgs = 5;
VARIANT PdblPrice;
PdblPrice.vt = VT_R8;
PdblPrice.dblVal = 28.0;
dispparams.rgvarg[0] = PdblPrice;
VARIANT PdateStartDate;
PdateStartDate.vt = VT_DATE;
PdateStartDate.date = 41052;
dispparams.rgvarg[1] = PdateStartDate;
VARIANT PintFlag;
PintFlag.vt = VT_I2;
PintFlag.iVal = 1;
dispparams.rgvarg[2] = PintFlag;
VARIANT PbolXP;
PbolXP.vt = VT_BOOL;
PbolXP.boolVal = false;
dispparams.rgvarg[3] = PbolXP;
VARIANT PdblScale;
PdblScale.vt = VT_SAFEARRAY;
PdblScale.pvRecord = psa;
dispparams.rgvarg[4] = PdblScale;
VARIANT varResult;
VariantInit(&varResult);
EXCEPINFO excepinfo;
memset(&excepinfo, 0, sizeof(excepinfo));
UINT nArgErr = (UINT)-1;
// Invoke the method ## THIS IS WHERE hr returns 0x8002000e : Invalid number of parameters
hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, &varResult, &excepinfo, &nArgErr);
if (FAILED(hr))
{
printf("Failed to invoke method.");
pDispatch->Release();
pUnknown->Release();
CoUninitialize();
return 1;
}
// Print the result
printf("Result: %d\n", varResult.intVal);
// Clean up
VariantClear(&varResult);
pDispatch->Release();
pUnknown->Release();
CoUninitialize();
return 0;
}
我从https://stackoverflow.com/questions/65253592/idispatch-invoke-returns-type-mismatch 看到参数应该是相反的顺序。我试过了,即。使用 [4]、[3]、[2] 等而不是上面的 [0]、[1] 等,但这仍然会出错。
关于我可能哪里出错的任何建议?
顺便说一句,COM 来自 32 位 DLL,我正在将我的代码编译为 x86。
谢谢!!
【问题讨论】:
-
在顶部,您传递的是
DISPATCH_METHOD而不是DISPATCH_PROPERTYGET。观察该函数在 IDL 中被标记为propget。 -
您声称要传递 5 个命名参数,但未设置
DISPPARAMS的rgdispidNamedArgs成员。您可能希望将cNamedArgs设置为 0。 -
参数必须以相反的顺序放入
dispparams.rgvarg:最右边的参数在索引 0,最左边的在cArgs-1 -
[in, out] double* PdblPrice必须作为VT_R8 | VT_BYREF传递,double*指针在VARIANT::pdblVal成员中。与所有其他[in, out]参数相同。 -
@Gary 你需要使用这样的东西:
DOUBLE value = 28.0; VARIANT dblPrice; dblPrice.vt = VT_R8 | VT_BYREF; dblPrice.pdblVal = &value; dispparams.rgvarg[28] = dblPrice;同样适用于所有其他VT_BYREF值。
标签: c++ com invoke safearray idispatch