One problem that has frustrated me is the difficulty of building a large object on the SQL/MTS
server and then using DCOM to deliver all that stuff to the client. The objective was to submit a
query to the server which would then process through the database , build a complex object, that
is an object with nested maps, lists and arrays of other objects, and return the whole result in
usable form to the client.
The semantics of using a SAFEARRAY or a large set of COM properties is daunting to me. Since
I don't need to make these complex objects available to VB or Java applications I can keep all the
code in C++.
This approach takes advantage of the simple design of a BSTR which, as I understand it, is just a
long pointer. What it points to is the address between a long int and a block of memory, actually
the first byte of the memory block. The long int preceding the string memory contains the byte
length of the memory block. Usually the memory block contains a null terminated array of 2 byte
characters, but it can actually contain anything. Since COM/DCOM know how to marshall
BSTRs across the network and process boundaries, anything that can be packed into a BSTR can
be marshalled across.
The first step is to get the arbitrarily complex object packed into the BSTR. I used a CMemFile to
receive the serialized object, then stuff the CMemFile into the BSTR.
The code looks like this:
BSTR CMyView::FetchObject(long lParam)
{
MyComplexClass *p_mCC;
BSTR bstrHoldThis;
CMemFile mfFile;
CArchive ar((CFile*)&mfFile, CArchive::store);
p_mCC = new MyComplexObject(lParam);
p_mCC->Serialize(ar);
ar.Flush();
mfFile.Flush();
ULONG lArchiveLength = mfFile.GetLength();
bstrHoldThis = SysAllocStringByteLen((const char*)mfFile.Detach(),
lArchiveLength);
delete p_mCC;
return bstrHoldThis;
}
Now the caller needs to be able to unpack the BSTR and re-create the object. This is just the
reverse of the steps above and I'd leave it as an exercise for the reader but I actually got it to work
so here it is.
Void CMyView::OnButton1()
{
BSTR bstrA;
MyComplexClass mRC;
CMemFile mfFile;
BstrA = FetchObject(m_lTestVal);
ULONG *p_lLength = (ULONG*) bstrA;
--p_lLength;
mfFile.Attach((unsigned char*) bstrA, *p_lLength);
CArchive ar(&mfFile, CArchive::load);
mRC.Serialize(ar);
SysFreeString(bstrA);
}
One could combine this method with others on a more general COM interface and agree to limit
its use to MFC C++ clients (more non-portable ugliness). The challenge is to get all the
serialization parts right for the array, maps, lists etc