IDispatch::Invoke 将 typedef 结构的指针作为参数传递
IDispatch::Invoke pass pointer of typedef struct as argument
我需要调用函数GetRect,它的参数是结构EdmRect的指针,它没有GUID:
typedef struct tagEdmRect {
long mlLeft;
long mlTop;
long mlRight;
long mlBottom;
} EdmRect;
[
odl,
uuid(60F6AEB0-7AEA-49F5-A4EF-DCBB1F2E6284),
helpstring("IEdmState7 Interface"),
dual,
oleautomation
]
interface IEdmState7 : IEdmState6 {
[id(0x0000000e), helpstring("GetRect")]
HRESULT GetRect([out] EdmRect* poRect);
};
请告诉我如何做正确?
现在我做不到了,因为总是收到 E_INVALIDARG.
首先我尝试使用 VT_RECORD 作为 VARTYPE:
GUID LIBID_RecInf1Lib = { 0x5fa2c692, 0x8393, 0x4f31, { 0x9b, 0xdb, 0x05, 0xe6, 0xf8, 0x07, 0xd0, 0xd3 } };
ITypeLib* typeLib = nullptr;
hRes = LoadRegTypeLib(LIBID_RecInf1Lib, 5, 17, LOCALE_SYSTEM_DEFAULT, &typeLib);
if (FAILED(hRes))
_com_issue_error(hRes);
uint typeCount = typeLib->GetTypeInfoCount();
for (uint i = 0; i < typeCount; ++i)
{
BSTR name;
typeLib->GetDocumentation(i, &name, NULL, NULL, NULL);
if (wcscmp(name, L"EdmRect") == 0)
{
ITypeInfo* typeInfo = nullptr;
hRes = typeLib->GetTypeInfo(i, &typeInfo);
if (FAILED(hRes))
_com_issue_error(hRes);
IRecordInfo* erRecInfo = nullptr;
hRes = GetRecordInfoFromTypeInfo(typeInfo, &erRecInfo);
qDebug() << erRecInfo;
if (FAILED(hRes))
_com_issue_error(hRes);
EdmRect rect = { 0 };
VARIANTARG* v = new VARIANTARG[1];
VariantInit(&v[0]);
v[0].vt = VT_RECORD;
v[0].pvRecord = ▭
v[0].pRecInfo = erRecInfo;
DISPPARAMS i_params = {v, NULL, 1, 0};
auto func_id = dispIDofName("GetRect", disp); // This line correct
hRes = disp->Invoke(func_id, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &i_params, NULL, NULL, NULL);
if (FAILED(hRes))
_com_issue_error(hRes);
break;
}
}
但是函数GetRecordInfoFromTypeInforeturnE_INVALIDARG
我也尝试使用 VT_PTR 和 VT_PTR | VT_BYREF 和 VT_USERDEFINED 并将指针设置为 VARIANT::byref,无效。
请帮忙。
IDispatch 仅支持自动化兼容类型。此处或多或少描述了列表:
因此,有 I8、I4、I2、I1、INT、UI8、UI4、UI2、UI1、UINT、R8、R4、CY、ERROR、BOOL、DECIMAL、NULL、EMPTY、DATE、BSTR、UNKNOWN , DISPATCH, BYREFs and SAFEARRAYs of all these, and RECORD (which was the latest additional historically).
就是这样。没有原始 C 结构,没有 VT_PTR,等等
其他 VT_* 是为 PROPVARIANT 保留的,它是一种类似但完全不同的野兽,不受 IDispatch 支持(它适用于 blittable 兼容类型)。
因此您可以使用 C 结构,但它必须在类型库中正确定义(or/and在注册表中).如果已定义,则可以将其称为 Automation UDT(用户定义类型)。
To pass single UDTs or safearrays of UDTs through type-library driven
marshaling for v-table binding, C and C++ Automation clients need the
header file generated from the IDL that describes the UDT
Visual Basic clients require the type library generated from the IDL
file. However to pass single UDTs or safearrays of UDTs for late
binding, the Automation client must have the information necessary to
store the type information of the UDT into a VARIANT (and if
late-binding, the UDT must be self-described).
你是这样描述的UDT within .IDL files
library udttest
{
typedef [uuid(C1D3A8C0-A4AA-11D0-819C-00A0C90FFFC3)]
struct_tagUDT
{
unsigned long a1;
BSTR pbstr;
} UDT;
}
由于 EdmRect 不是 UDT(好吧,看起来不是,但我手头没有原始的 tlb 来确认),你只能调用它使用早期绑定,类似的东西:
IEdmState7 *pState;
disp->QueryInterface(IID_IIEdmState7, (void**)&pState);
EdmRect rect;
pState->GetRect(&rect);
...
因此您需要一个用于 IEdmState7 的 .H 头文件。如果供应商没有提供(恕我直言,他 应该 ,或者源 .IDL),但是你有一个 TLB,那么所有的希望都不会丢失。
一种解决方案是使用 Visual Studio #import directive (there's the community edition that everyone can use), keep the .TLH and .TLI generated files and adapt them to your compiler (in this case, I suggest you use raw_interfaces_only).
另一种解决方案是使用 OLE/COM Object Viewer (run as admin...) or a tool called OleWoo,这是旧版本的一个很好的替代品。
它应该从 the.TLB 创建一个 .H 文件。注意你只需要不支持IDispatch的接口,你不需要整个.H文件,如果IDispatch方便的话。
我需要调用函数GetRect,它的参数是结构EdmRect的指针,它没有GUID:
typedef struct tagEdmRect {
long mlLeft;
long mlTop;
long mlRight;
long mlBottom;
} EdmRect;
[
odl,
uuid(60F6AEB0-7AEA-49F5-A4EF-DCBB1F2E6284),
helpstring("IEdmState7 Interface"),
dual,
oleautomation
]
interface IEdmState7 : IEdmState6 {
[id(0x0000000e), helpstring("GetRect")]
HRESULT GetRect([out] EdmRect* poRect);
};
请告诉我如何做正确?
现在我做不到了,因为总是收到 E_INVALIDARG.
首先我尝试使用 VT_RECORD 作为 VARTYPE:
GUID LIBID_RecInf1Lib = { 0x5fa2c692, 0x8393, 0x4f31, { 0x9b, 0xdb, 0x05, 0xe6, 0xf8, 0x07, 0xd0, 0xd3 } };
ITypeLib* typeLib = nullptr;
hRes = LoadRegTypeLib(LIBID_RecInf1Lib, 5, 17, LOCALE_SYSTEM_DEFAULT, &typeLib);
if (FAILED(hRes))
_com_issue_error(hRes);
uint typeCount = typeLib->GetTypeInfoCount();
for (uint i = 0; i < typeCount; ++i)
{
BSTR name;
typeLib->GetDocumentation(i, &name, NULL, NULL, NULL);
if (wcscmp(name, L"EdmRect") == 0)
{
ITypeInfo* typeInfo = nullptr;
hRes = typeLib->GetTypeInfo(i, &typeInfo);
if (FAILED(hRes))
_com_issue_error(hRes);
IRecordInfo* erRecInfo = nullptr;
hRes = GetRecordInfoFromTypeInfo(typeInfo, &erRecInfo);
qDebug() << erRecInfo;
if (FAILED(hRes))
_com_issue_error(hRes);
EdmRect rect = { 0 };
VARIANTARG* v = new VARIANTARG[1];
VariantInit(&v[0]);
v[0].vt = VT_RECORD;
v[0].pvRecord = ▭
v[0].pRecInfo = erRecInfo;
DISPPARAMS i_params = {v, NULL, 1, 0};
auto func_id = dispIDofName("GetRect", disp); // This line correct
hRes = disp->Invoke(func_id, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &i_params, NULL, NULL, NULL);
if (FAILED(hRes))
_com_issue_error(hRes);
break;
}
}
但是函数GetRecordInfoFromTypeInforeturnE_INVALIDARG
我也尝试使用 VT_PTR 和 VT_PTR | VT_BYREF 和 VT_USERDEFINED 并将指针设置为 VARIANT::byref,无效。
请帮忙。
IDispatch 仅支持自动化兼容类型。此处或多或少描述了列表:
因此,有 I8、I4、I2、I1、INT、UI8、UI4、UI2、UI1、UINT、R8、R4、CY、ERROR、BOOL、DECIMAL、NULL、EMPTY、DATE、BSTR、UNKNOWN , DISPATCH, BYREFs and SAFEARRAYs of all these, and RECORD (which was the latest additional historically).
就是这样。没有原始 C 结构,没有 VT_PTR,等等
其他 VT_* 是为 PROPVARIANT 保留的,它是一种类似但完全不同的野兽,不受 IDispatch 支持(它适用于 blittable 兼容类型)。
因此您可以使用 C 结构,但它必须在类型库中正确定义(or/and在注册表中).如果已定义,则可以将其称为 Automation UDT(用户定义类型)。
To pass single UDTs or safearrays of UDTs through type-library driven marshaling for v-table binding, C and C++ Automation clients need the header file generated from the IDL that describes the UDT
Visual Basic clients require the type library generated from the IDL file. However to pass single UDTs or safearrays of UDTs for late binding, the Automation client must have the information necessary to store the type information of the UDT into a VARIANT (and if late-binding, the UDT must be self-described).
你是这样描述的UDT within .IDL files
library udttest
{
typedef [uuid(C1D3A8C0-A4AA-11D0-819C-00A0C90FFFC3)]
struct_tagUDT
{
unsigned long a1;
BSTR pbstr;
} UDT;
}
由于 EdmRect 不是 UDT(好吧,看起来不是,但我手头没有原始的 tlb 来确认),你只能调用它使用早期绑定,类似的东西:
IEdmState7 *pState;
disp->QueryInterface(IID_IIEdmState7, (void**)&pState);
EdmRect rect;
pState->GetRect(&rect);
...
因此您需要一个用于 IEdmState7 的 .H 头文件。如果供应商没有提供(恕我直言,他 应该 ,或者源 .IDL),但是你有一个 TLB,那么所有的希望都不会丢失。
一种解决方案是使用 Visual Studio #import directive (there's the community edition that everyone can use), keep the .TLH and .TLI generated files and adapt them to your compiler (in this case, I suggest you use raw_interfaces_only).
另一种解决方案是使用 OLE/COM Object Viewer (run as admin...) or a tool called OleWoo,这是旧版本的一个很好的替代品。
它应该从 the.TLB 创建一个 .H 文件。注意你只需要不支持IDispatch的接口,你不需要整个.H文件,如果IDispatch方便的话。