c++windowscomimapi

How do I use IFileSystemImage2's put_BootImageOptionsArray from IMAPI2 (getting E_NOINTERFACE)?


I am trying to use the IFileSystemImage2 interface to create an ISO with multiple boot records using Imapi2.

To do this, I should be able to use put_BootImageOptionsArray passing in SAFEARRAY* of VT_DISPATCH type, i.e. COM pointers of type IBootOptions for each boot options configuration. As a short demo, I have the following code (I only created one IBootOptions in this case):

SAFEARRAYBOUND bounds[1];
bounds[0].cElements = 1;
bounds[1].lLbound = 0;
IBootOptions* BootOptionsArrayData = NULL;


SAFEARRAY* Array = SafeArrayCreateEx(VT_DISPATCH, 
                                     1, 
                                     bounds, 
                                     (void*) &IID_IBootOptions);
hr = SafeArrayAccessData(Array, 
                         reinterpret_cast<void**>(&BootOptionsArrayData));

BootOptionsArrayData = BootOptions; // BootOptions = IBootOptions*
hr = SafeArrayUnaccessData(Array);

hr = IsoImage->put_BootImageOptionsArray(Array);

However, every time I call put_BootImageOptionsArray I get E_NOINTERFACE returned.

IsoImage is being created as you'd expect:

hr = CoCreateInstance(CLSID_MsftFileSystemImage, 
                      NULL, 
                      CLSCTX_ALL, 
                      __uuidof(IFileSystemImage2), 
                      (void**) &IsoImage);

Using IFileSystemImage2 any inherited functionality from IFileSystemImage works fine. Likewise, I can CoCreateInstance a IFileSystemImage instead, and this interface can be used just fine.

I have attached to my process in WinDbg and set a breakpoint in CMsftFileSystemImage::put_BootOptionsArray, however, this function (the underlying implementation) simply isn't being called.

My question, therefore is simple: the implementation appears to be there, but I don't seem to be able to call it. Does anyone have any experience of using this particular bit of functionality and if so how did you get it to work?


Solution

  • The documentation stipulates the SAFEARRAY must be an array of VARIANT that contain IDispatch interface pointers, so you could do something like this (I'm using smart pointers which is easier...):

    CComPtr<IFileSystemImage2> image;
    CComPtr<IBootOptions> options;
    
    image.CoCreateInstance(CLSID_MsftFileSystemImage);
    options.CoCreateInstance(CLSID_BootOptions);
    
    // set various options here...
    options->put_Manufacturer(CComBSTR(L"joe"));
    
    // create a SAFEARRAY of VARIANT
    CComSafeArray<VARIANT> a(1);
    
    // create a VARIANT of type VT_UNKNONW (or VT_DISPATCH)
    CComVariant v(options);
    
    // put it in the array
    a.SetAt(0, v);
    
    HRESULT hr = pImage->put_BootImageOptionsArray(a.m_psa);