During one of my recent projects I came across a typical problem of passing user-defined types from my COM component. The problem I had was that I was using Attributed ATL (one which even Microsoft seems to have abandoned 😉 ). I came up with the following way to expose UDT from COM. Beware though, passing UDT supporting IDispatch interface is a different ball-game altogether and scripting languages don’t readily support UDT’s.
The way to send UDT using IDispatch involves wrapping it in a VARIANT but again for scripting, its a no-no. Passing UDT as an array is slightly more complicated. I will write about these some time in the near future.
There are various good articles on the net about this, but here is a simple, to the point approach.
First Declare your type in your header file, like this
[ uuid("FD27CE79-9C08-4afa-AEB0-BB5B3E2F6DEA")]
struct MiscInformation
{
BSTR Name;
BSTR Status;
BSTR Source;
INT Priority;
};
Now you will have to declare the type in your IDL file. But, because its an attributed project, here is how you do it.
Create a new idl file in you project and name it, for example structures.idl. The make an entry in the IDL file as follows:
[ uuid("FD27CE79-9C08-4afa-AEB0-BB5B3E2F6DEA")]
struct MiscInformation
{
BSTR Name;
BSTR Status;
BSTR Source;
INT Priority;
}
[ version(1.0), uuid(5C6ADADA-1583-4DCB-8F14-4CF9F5BC048C), helpstring("Test UDT 1.0 Type Library") ]
library TestUDT
{
struct MiscInformation;
}
Once this is done you have to include this IDL file in the generated IDL file. Here is how I do it. In my main .cpp file I insert the line [importidl] on top. Like this:
[importidl("structures.idl")];
// The module attribute causes DllMain, DllRegisterServer and DllUnregisterServer to be automatically implemented for you[ module(dll, uuid = "{5C6ADADA-1583-4DCB-8F14-4CF9F5BC048C}",
name = "TestUDT",
helpstring = "TestUDT 1.0 Type Library",
resource_name = "IDR_TESTUDT") ]
class CTestUDTModule
{
public:
// Override CAtlDllModuleT members
};
This takes care to compile the right Type Information.
Now to use this UDT simply do it like this, for example:
[id(33), helpstring("method GetMiscInformation")]
HRESULT GetMiscInformation([out,retval] MiscInformation* pMiscInfo);
For creating a VARIANT type for the structure, I use the following function:
VARIANT GetVariantForStruct(REFGUID rGuidTypeInfo, void* data)
{
VARIANT vnt;
IRecordInfo *pRI;
HRESULT hr;
hr = GetRecordInfoFromGuids(LIBID_TestUDT, 1, 0, 0x409, rGuidTypeInfo, &pRI);
VariantInit(&vnt);
vnt.vt = VT_RECORD;
vnt.pvRecord = data;
vnt.pRecInfo = pRI;
pRI = NULL;
return vnt;
}
This can take care of wrapping structure in a variant. Of-course there are other things to talk about like passing UDT in a SAFEARRAY, but I will talk about them sometime in future.
Any suggestions/comments are welcome.