The key to getting Explorer to do your dirty work lies in the IShellDispatch2 interface. Particular, the ShellExecute method.
IShellDispatch2 is one of the shell automation objects used to support scripting languages. However, that doesn’t mean you have to use VBScript to gain some value from it. In this case, IShellDispatch2::ShellExecute is exactly what we want, because it wraps the normal ShellExecute call but runs it from the context of the object implementing the interface - in this case, we want the IShellDispatch2 associated with the desktop shell.
Knowing this is only half the battle, though. The next trick is to figure out just how to get to the right IShellDispatch2 object (the one for the desktop shell instance of Explorer.exe).
Fortunately, one of our architects, Chris Guzak (seen on C9 here), was able to point me in the right direction and connect up all the dots.
Our hunt begins with the IShellWindows interface, which can be used not only to reliably find the HWND for the desktop shell window, but also to get an IDispatch interface for it:
IShellWindows *psw;
HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));
if (SUCCEEDED(hr))
{
HWND hwnd;
IDispatch* pdisp;
VARIANT vEmpty = {}; // VT_EMPTY
if (S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, (long*)&hwnd, SWFO_NEEDDISPATCH, &pdisp))
{
Next, we need the IShellBrowser interface, and we get that by querying for IServiceProvider and asking the SID_STopLevelBrowser service for an IShellBrowser interface. And from there we can get the IShellView.
IShellBrowser *psb;
hr = IUnknown_QueryService(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
if (SUCCEEDED(hr))
{
IShellView *psv;
hr = psb->QueryActiveShellView(&psv);
From there we need to get to that IShellDispatch2 interface that started this whole adventure.
IDispatch *pdispBackground;
HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
if (SUCCEEDED(hr))
{
IShellFolderViewDual *psfvd;
hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
if (SUCCEEDED(hr))
{
IDispatch *pdisp;
hr = psfvd->get_Application(&pdisp);
if (SUCCEEDED(hr))
{
IShellDispatch2 *psd;
hr = pdisp->QueryInterface(IID_PPV_ARGS(&psd));
At this point you should be able to figure out where to go from here.
If that’s not easy enough, watch out for Part 3 of this series in the next day or two. It will contain a sample and describe how the Start++ installer makes use of it.
[powered by WordPress.]
Hi. I'm Brandon. I'm a geek, and I work on Search technology for Windows at Microsoft. This is my blog.
The views expressed within my blog are my own - and are not in any way indicative of those of the company I work for, Microsoft, or it's employees. No warranties or other guarantees will be offered as to the quality of the opinions or anything else offered here.