Passing a Safearray of UDTs

For passing a safearrray of UDTs, the designer of the server describes the data types of the UDT in a IDL file. The client needs the type library to fetch the IRecordInfo Interface. The safearray is then created with SafeArrayCreateEx.

The following is the IDL for a safearray of UDTs to be passed:

library Student
{
importlib("stdole2.tlb");
typedef enum tagclassification {school_Bully, class_Clown, teachers_Favorite} classification;
typedef [uuid(D8B3861A-74C6-11d2-A0D6-00C04FB17CDB)] struct tagStudentStruct {
      BSTR name;
      short grade;
      classification  type;
      VARIANT_BOOL   graduate;
} StudentStruct;
[
object,
uuid(D50BD660-7471-11d2-9A80-006097DA88F5),         // IID_IStudent
helpstring("User Defined Data Server"),
dual,
pointer_default(unique)
]
interface IStudent : IDispatch
{
import "unknwn.idl";
typedef IStudent* LPSTUDENT;

HRESULT Test2([in,out] SAFEARRAY(StudentStruct));
};

For passing a safearray of UDTs the type library is necessary for fetching the IRecordInfo Interface. The type library of the UDT is first loaded by calling LoadRegTypeLib and the type information of the UDT is obtained with GetTypeInfoOfGuid. The GetRecordInfoFromTypeInfo function is then called to obtain the record information from the type information of the UDT. At this point the record information is returned to pRecInfo.

LPTYPEINF pTypeInfo = NULL;
LPTYPELIB pTypelib = NULL;
LPSAFEARRAY psaStudent = NULL;
SAFEARRAYBOUND rgbounds = { 4, 0 };
StudentStruct *pStudentStruct = NULL;
IRecordInfo* pRecInfo = NULL;

// Fetch the IRecordInfo interface describing the UDT
hr = LoadRegTypeLib(LIBID_Student, 1, 0, GetUserDefaultLCID(), &pTypelib);
_ASSERT(SUCCEEDED(hr) && pTypelib);

hr = pTypelib->GetTypeInfoOfGuid(UUID_StudentStruct, &pTypeInfo);
_ASSERT(SUCCEEDED(hr) && pTypeInfo);
hr = GetRecordInfoFromTypeInfo(pTypeInfo, &pRecInfo);
_ASSERT(SUCCEEDED(hr) && pRecInfo);
RELEASEINTERFACE(pTypeInfo);
RELEASEINTERFACE(pTypelib);

After pRecInfo is obtained from the type library, SafeArrayCreateEx is called to create the safearray, where its last parameter is pRecInfo. SafeArrayAccessData is then called to increment the lock count of the array.

psaStudent = SafeArrayCreateEx(VT_RECORD, 1, &rgbounds, pRecInfo);
RELEASEINTERFACE(pRecInfo);
_ASSERT(psaStudent);
hr = SafeArrayAccessData(psaStudent, reinterpret_cast<PVOID*>(&amp;pStudentStruct));
_ASSERT(SUCCEEDED(hr) &amp;&amp; pStudentStruct);

Then the StudentStruct safearray of UDTs is declared and assigned some values:

pStudentStruct[0].grade = 3;
pStudentStruct[0].name = SysAllocString(L"Shaun");
pStudentStruct[0].type = class_Clown;
pStudentStruct[1].grade = 8;
pStudentStruct[1].name = SysAllocString(L"Fred");
pStudentStruct[1].type = school_Bully;
pStudentStruct[2].grade = 12;
pStudentStruct[2].name = SysAllocString(L"Steve");
pStudentStruct[2].type = teachers_Favorite;
pStudentStruct[3].grade = 3;
pStudentStruct[3].name = SysAllocString(L"Linda");
pStudentStruct[3].type = teachers_Favorite;

SafeArrayUnaccessData is then called to decrement the lock count of the array, and invalidate the pointer retrieved by SafeArrayAccessData:

hr = SafeArrayUnaccessData(psaStudent);
_ASSERT(SUCCEEDED(hr));

The safearray is then passed to the Test2 method:

hr = pStudent->Test2(psaStudent);

SafeArrayGetRecordInfo

SafeArraySetRecordInfo

SafeArrayAllocDescriptorEx

ITypeLib::GetTypeInfoOfGuid

SafeArrayCreateEx

SafeArrayCreateVectorEx

SafeArrayUnaccessData

SafeArrayAccessData