September 20th, 2012

How do I invoke a verb on an IShellItemArray?

A customer wanted to invoke a command on multiple items at once.

I have an IShellItemArray, and I want to invoke a verb with that array as the parameter. I know that I can invoke a verb on a single IShellItem by the code below, but how do I pass an entire array?

void InvokeVerbOnItem(__in IShellItem *psi,
                      __in_opt PCWSTR pszVerb)
{
 PIDLIST_ABSOLUTE pidl;
 HRESULT hr = SHGetIDListFromObject(psi, &pidl);
 if (SUCCEEDED(hr)) {
  SHELLEXECUTEINFO sei = { sizeof(sei) };
  sei.fMask = SEE_MASK_UNICODE |
              SEE_MASK_INVOKEIDLIST |
              SEE_MASK_IDLIST;
  sei.lpIDList = pidl;
  sei.lpVerb = pszVerb;
  sei.nShow = SW_SHOWNORMAL;
  ShellExecuteEx(&sei);
  CoTaskMemFree(pidl);
 }
}

The function Invoke­Verb­On­Item invokes the command by extracting the pidl, then asking Shell­Execute­Ex to invoke the command on the pidl. A limitation of Shell­Execute* is that it can invoke on only one pidl. What if you want to invoke it on a bunch of pidls at once? (Doing it all at once gives the target program the opportunity to optimize the multi-target invoke.)

As noted in the documentation, passing SEE_MASK_INVOKE­ID­LIST flag tells the Shell­Execute­Ex to “use the IContextMenu interface of the selected item’s shortcut menu handler.”

So if you are frustrated by the limitations of the middle man, then cut out the middle man!

void InvokeVerbOnItemArray(__in IShellItemArray *psia,
                           __in_opt PCWSTR pszVerb)
{
 IContextMenu *pcm;
 HRESULT hr = psia->BindToHandler(BHID_SFUIObject,
                                  IID_PPV_ARGS(&pcm));
 if (SUCCEEDED(hr)) {
  ... context menu invoke incorporated by reference ...
  pcm->Release();
 }
}

If you think about it, the original Invoke­Verb­On­Item function could’ve avoid the middle man too. It converted an IShellItem (a live object which encapsulates an IShell­Folder and a child pidl) into an absolute pidl (a dead object), which then passed it to Shell­Execute­Ex, which had to reanimate the object back into an IShell­Folder and child pidl so it could call Get­UI­Object­Of.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.