Implementing IShellExtInit

To initialize an instance of a user interface extension, the system uses one of two interfaces: IShellExtInit or IPersistFile. You must use the IShellExtInit interface to initialize context menu handlers, drag-and-drop handlers, and property sheet handlers.

Like all COM interfaces, IShellExtInit supports the three standard IUnknown member functions—QueryInterface, AddRef, and Release—as shown in the PROPEXT sample. (If the syntax looks a little odd, remember that this sample was written in MFC and uses the built-in macros that support COM objects and nested objects.)

// IUnknown for IShellExtInit
STDMETHODIMP CPropExt::XShellInit::QueryInterface (
REFIID riid, void **ppv)
{
METHOD_PROLOGUE (CPropExt, ShellInit);
TRACE ("CPropExt::XShellInit::QueryInterface\n");
return pThis->ExternalQueryInterface (&riid, ppv);
}

STDMETHODIMP_(ULONG) CPropExt::XShellInit::AddRef (void)
{
METHOD_PROLOGUE (CPropExt, ShellInit);
return pThis->ExternalAddRef ();
}

STDMETHODIMP_(ULONG) CPropExt::XShellInit::Release (void)
{
METHOD_PROLOGUE (CPropExt, ShellInit);
return pThis->ExternalRelease ();
}

When you use the IShellExtInit interface, you must also implement the Initialize member function.

Initialize

This member function is passed a pointer to the IDataObject that represents the file object(s) being manipulated. My initialization code gets the name of the selected file. Because the system stores that filename in the same way that the filename is stored during a drag procedure, I can get the file by using the DragQueryFile function. The filename is saved in a member variable for the extension object.

STDMETHODIMP CPropExt::XShellInit::Initialize (
LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
{
METHOD_PROLOGUE (CPropExt, ShellInit);
TRACE ("CPropExt::XShellInit::Intialize\n");

HRESULT hres = E_FAIL;
FORMATETC fmte =
{
CF_HDROP, // use CF_HDROP format
NULL, // no specific device required
DVASPECT_CONTENT, // embedded object
-1, // must be -1 for DVASPECT_CONTENT
TYMED_HGLOBAL // how to transfer data
};
STGMEDIUM medium;

// No data object
if (pdobj == NULL)
{
TRACE ("CPropExt::XShellInit::Initialize() no data object");
return E_FAIL;
}

// Use the given IDataObject to get a list of filenames (CF_HDROP).
hres = pdobj->GetData (&fmte, &medium);

if (FAILED (hres))
{
TRACE ("CPropExt::XShellInit::Initialize() can't get data");
return E_FAIL;
}

// HDROP can contain more than one file. If the user selects
// multiple files and brings up a context menu, your handler
// will be called. Not all files will be your type! Only the
// first one will be that type.
if (DragQueryFile ((HDROP)medium.hGlobal, (UINT)(-1), NULL, 0) == 1)
{
DragQueryFile ((HDROP)medium.hGlobal, 0, pThis->m_szFileName,
sizeof (pThis->m_szFileName));
hres = S_OK;
}
else
hres = E_FAIL;

// Release the data.
ReleaseStgMedium (&medium);

return hres;
}