class factories, IMoniker, etc.
Hmm. I've been trying to write some COM wrapper objects for some
custom data structures I am storing in the HDF5 format
(www.hdfgroup.org if you're interested... portable & pretty sweet for
technical datasets... but my Q isn't about HDF5) and I feel like I'm
dancing around how to properly instantiate an object that has been
stored in a particular way that the object would know about but the OS
I think I know how to do this, but I'm not sure and would appreciate
any design suggestions.
Specifically I have a file in this magic HDF5 format, and a string
identifier which tells where in the file it's located, and I figure
the file probably needs to contain in a well-known place any CLSID's
of the objects used at the time the file was stored. That way, if I
upgrade my objects to new ones with different CLSIDs & want to be able
to access the old files later, I can still do so as long as the
corresponding COM server are still available.
To reload my data structure, I would like it to work something like
this (names changed, error-checking removed for clarity/brevity):
// (1) naively instantiate the most recent file object available
HRESULT hr =
// (2) try to open the file & get the data structure
hr = pmdf->GetObject("c:/path/to/my/file.hdf5","/path/within/file",
&vmydata); // *** see comments below
// (3) pull out my interface from the variant
hr = V_UNKNOWN(&vmydata)->QueryInterface(&pmydata);
// (4) now I can use it again.
In step #2, the MyDataFactory object will find the file in question,
look for the path within the file, and do something like this:
HRESULT CMyDataFactory::GetObject(BSTR filepath, BSTR subfilepath,
// CLSIDs match so this is a current version of the object; create
it & init normally.
hr = CComObject<CMyData>::CreateInstance(&pmydata_local);
pmydata_local->QueryInterface(pmydata); // stabilize reference
hr = pmydata_local->Init(filepath, subfilepath);
if (!SUCCEEDED(hr)) return hr; // uh oh. error. pmydata will be be
hr = pmydata->QueryInterface(&V_UNKNOWN(prv));
if (SUCCEEDED(prv)) // hmm, why would we fail?!
V_VT(prv) = VT_UNKNOWN;
// old version! we need to let the appropriate factory create it.
hr = potherdf.CreateInstance(clsid_mydatafactory);
if (!SUCCEEDED(hr)) return hr;
return potherdf->GetObject(filepath, subfilepath,prv);
So I guess here's my main question; which of the following makes the
(1) do I create two regular COM objects, one called MyData and the
other MyDataFactory? (using the above technique)
(2) do I create one regular COM object MyData and have its class
factory be a custom class factory that takes arguments? (I'm not quite
sure how to do this or what the pitfalls are)
(3) do I try to use monikers and write a COM object to encapsulate the
file and then use an Item moniker and BindToObject to create the
object that represents my data within the file? (this sounds
(4) is there some other well-known method? (IPersistStream and
IPersistStorage won't work since IStream isn't appropriate for the
HDF5 file and I don't feel like trying to implement IStorage)