自己定义的结构:
typedef TOPINT (*SVC_PROCESSOR)(HWND hwnd,char * szApp);
typedef struct tagCMD_PROCESSOR
{
HWND hwnd;
TOPUINT cmd;
SVC_PROCESSOR cmd_proc;
}CMD_PROCESSOR,*PCMD_PROCESSOR;
我现在想做一个com接口:initaspcom(参数不知如何定义),给别人使用,想实现如下功能:
//定义回调函数
int aaaFun(HWND hwnd,char* szApp)
{
return 1;
}
定义结构变量
PCMD_PROCESSOR pX = new CMD_PROCESSOR;
pX->hwnd = NULL;
pX->cmd = 1;
pX->cmd_proc = aaaFun;
调用com接口
initaspcom(abc);
其中abc应该怎样来定义,才能够将结构变量pX传人com接口中去?
谢谢各位了!急!!!
typedef TOPINT (*SVC_PROCESSOR)(HWND hwnd,char * szApp);
typedef struct tagCMD_PROCESSOR
{
HWND hwnd;
TOPUINT cmd;
SVC_PROCESSOR cmd_proc;
}CMD_PROCESSOR,*PCMD_PROCESSOR;
我现在想做一个com接口:initaspcom(参数不知如何定义),给别人使用,想实现如下功能:
//定义回调函数
int aaaFun(HWND hwnd,char* szApp)
{
return 1;
}
定义结构变量
PCMD_PROCESSOR pX = new CMD_PROCESSOR;
pX->hwnd = NULL;
pX->cmd = 1;
pX->cmd_proc = aaaFun;
调用com接口
initaspcom(abc);
其中abc应该怎样来定义,才能够将结构变量pX传人com接口中去?
谢谢各位了!急!!!
struct Data
{
DWORD nData1;
float fltData2;
};struct MyStruct
{
int nCount;
[unique, size_is(nCount)] struct Data *aData;
};When passing structs one should be careful what gets transmitted in the marshaling packet. In the above example the whole array of Data structs is transferred. This is expected and well annotated. However, there are bad struct designs as well. Consider the following single-linked list:
struct Node
{
struct Data data;
[unique] struct Node *pNext;
};When the head of the list is passed, all elements in the list are replicated in the marshaling packet. Such architecture needs to be redesigned so the complete list does not get transferred on each method call (a possible design is to hide the list itself behind an object and expose methods on the object's interface for manipulating the list). Rarely, but sometimes nevertheless, pointer aliasing has to be considered as well. In the examples so far no two pointers could point to the same memory address. However, consider this doubly- linked list:
struct Node
{
struct Data data;
[ptr] struct Node *pNext;
[ptr] struct Node *pNext;
};True, this is a bad design, but nonetheless without the pointer type set to [ptr], the result would be disastrous. When a struct is an [in] argument, it doesn't matter how the memory pointed to by the embedded pointers is allocated. However, for [out] and [in, out] arguments all memory pointed to by the embedded pointers of a struct must be allocated via the COM memory allocator (CoTaskMemAlloc). This is necessary so that the marshaling code can deallocate the data at the callee and reallocate it at the caller. A final point: IDL doesn't define the struct packing byte alignment. The default for the VC compiler is 8. However, it is safer to manually inject a #pragma pack statement:
#pragma pack(push, 8)
...
#pragma pack(pop)If you manually set the byte alignment, don't use #import for importing the struct definition from a type library. It adds #pragma pack(push, 8) at the beginning of the generated TLH file. Your pragma is not persisted in the generated type library. Generally, it is not advised to use #import for non-Automation-compatible interfaces. IMPORTANT: since your interfaces are not Automation-compatible, you have to build and register the proxy/stub DLL for their marshaling support!
[uuid(21602F40-CC62-11d4-AA2B-00A0CC39CFE0)]
struct MyStruct
{
[helpstring("A long value")]
long nLongValue; [helpstring("A string")]
BSTR bstrStringValue;
};// Later in the IDL file
[uuid(...), version(...), helpstring(...)]
library MyLib
{
...
struct MyStruct;
};For unknown reason, the MIDL compiler bundled with VC6 has not been updated even in SP4. Therefore, you need the latest Platform SDK installed on your computer (or at least no older than Platform SDK Jul'99) in order to compile the above IDL code and any IDL using structs with Automation. NOTE: The current release of MIDL at the time of writing (5.03.0280) does not support the helpstring() attribute on the struct itself. helpstring() is supported on the struct fields, though.Once your struct is declared as above, you can pass it via Automation- compatible interfaces. Keep in mind, however, that only struct pointers can be passed:
HRESULT SendStruct([in] struct MyStruct *pData);
HRESULT GetStruct([out, retval] struct MyStruct *pData);Structs can also be passed in safe arrays and VARIANTs:
HRESULT SendManyStructs([in] SAFEARRAY(struct MyStruct) *psaData);Neither IDL nor Automation define byte alignment for a struct. VB assumes 4-byte alignment, while #import in VC assumes 8-byte alignment. For most Automation structs this isn't an issue. However, if you use 8-byte types like double, this may make a difference:
[uuid(...), helpstring(...)]
struct BadAlign
{
long nLongValue;
double dblDoubleValue;
};For VB, the double field starts at the fourth byte of the struct, while for VC's #import it starts at the eight byte. This poses a significant problem. It can be solved by adding an inject_statement clause to #import:
#import "My.tlb" inject_statement("#pragma pack(4)")IMPORTANT: Structs cannot be used by scripting clients!Implementing structs in code is usually trivial - just use the struct directly. There are two specific struct uses when the code is fairly non-trivial - when using a safe array of structs and when stuffing the struct into a VARIANT. Let's note first that in Automation any struct is represented via an IRecordInfo interface pointer. The object exposing this interface is implemented by the Automation runtime and is acquired via the following two API functions:
GetRecordinfoFromGuids
GetRecordInfoFromTypeInfoWhen structs are used in say dual interfaces, this detail is hidden from the implementer and the user of the interface. Only the marshaler knows and uses it. However, when we need to pass structs in a VARIANT or a safe array, we have to delve into these details ourselves. Here's the C++ code for populating a VARIANT with a struct (error checking omitted):
VARIANT vnt;
IRecordInfo *pRI;
MyStruct data;
HRESULT hr;data.nLongValue = 5;
data.bstrStringValue = SysAllocString(L"Something");
hr = GetRecordInfoFromGuids(LIBID_MyLib, 1, 0, 0x409, uuidof(MyStruct), &pRI);
VariantInit(&vnt);
vnt.vt = VT_RECORD;
vnt.pvRecord = &data;
vnt.pRecInfo = pRI;
pRI = NULL;Note that the VARIANT doesn't own the storage for the embedded struct, but VariantClear will free the content of the struct by calling IRecordInfo::RecordClear. Note also that the common VARIANT wrapper classes like CComVariant and _variant_t don't support structs. Finally, note that the mechanism for storing struct data in a VARIANT is not fully documented. For example it isn't clear how a struct can be returned in an [out] VARIANT argument without producing memory leaks. Now let's see how to populate a safe array with structs. The following code is a trimmed down version of the MSDN example code (error checking omitted):
SAFEARRAY *psa;
SAFEARRAYBOUND sab = {2, 0};
MyStruct *pData;
IRecordInfo *pRI;
HRESULT hr;hr = GetRecordInfoFromGuids(LIBID_MyLib, 1, 0, 0x409, uuidof(MyStruct), &pRI);
psa = SafeArrayCreateEx(VT_RECORD, 1, &sab, pRI);
pRI->Release();
pRI = NULL;
hr = SafeArrayAccessData(psa, (void**)&pData);
pData[0].nLongValue = 1;
pData[0].bstrStringValue = SysAllocString(L"First");
pData[1].nLongValue = 2;
pData[1].bstrStringValue = SysAllocString(L"Second");
hr = SafeArrayUnaccessData(psa);Unlike a VARIANT, a safe array owns the storage of its structs. The UDT documentation is located at: mk:@MSITStore:D:\MSDN\Automat.Chm::/htm/chap12_3rcj.htm (Copy the link and paste it in the "Jump to URL..." box. Substitute the path with the path to your MSDN files. This link is obtained from MSDN Library Oct'2000.)