[Windows Shell] 遍历并执行某文件右键菜单并执行

陪她去流浪 桃子 2016年09月27日 编辑 阅读次数:2650

前一篇文章介绍了如何获取 IShellDispatch 指针的多种方法。接下来我就用刚才拿到的 IShellDispatch 指针来获取指定文件夹下指定文件的右键菜单列表并执行。

有以下几个步骤:

  1. 通过 IShellDispatch::NameSpace() 拿到文件夹的 Shell 命名空间 Folder
  2. 通过 Folder::ParseName() 拿到文件夹内某一文件对应的对象 FolderItem
  3. 通过 FolderItem::Verbs() 拿到该文件的右键菜单动作列表 FolderItemVerbs
  4. 调用 FolderItemVerbs::get_Count() 拿到动作列表内动作的个数;
  5. 遍历 FolderItemVerbs::Item() 拿到某一个单独的动作对象 FolderItemVerb

拿到该动作对象后,就可以调用 FolderItemVerb::get_Name() 取得在菜单里面的名字,调用 FolderItemVerb::DoIt() 即可执行动作命令。

以下是部分示例源代码:(完整源代码:Source.cpp

bool ListShellVerb(IShellDispatch* pShellDispatch, const wchar_t* dir, const wchar_t* file)
{
    HRESULT hr;

    CComVariant varFolder(dir);
    CComPtr<Folder> spFolder;

    // 拿到目录
    hr = pShellDispatch->NameSpace(varFolder, &spFolder);

    if (FAILED(hr) || !spFolder)
        return false;

    CComBSTR bstrFile(file);
    CComPtr<FolderItem> spFolderItem;

    // 拿到文件
    hr = spFolder->ParseName(bstrFile, &spFolderItem);

    if (FAILED(hr) || !spFolderItem)
        return false;

    CComPtr<FolderItemVerbs> spVerbs;

    // 拿到动作列表
    hr = spFolderItem->Verbs(&spVerbs);

    if (FAILED(hr) || !spVerbs)
        return false;

    long nItems = 0;
    spVerbs->get_Count(&nItems);

    // 遍历并获取每个动作的名字
    for (long i = 0; i < nItems; i++) {
        CComBSTR bsName;
        CComPtr<FolderItemVerb> spVerb;

        hr = spVerbs->Item(CComVariant(i), &spVerb);

        if (SUCCEEDED(hr) && spVerb) {
            spVerb->get_Name(&bsName);

            std::wcout << (const wchar_t*)bsName << std::endl;

            // 执行动作命令
            // spVerb->DoIt();
        }
    }

    return true;
}

int main()
{
    // 控制台支持 Unicode 输出
    std::wcout.imbue(std::locale("chs"));

    CoInitialize(nullptr);

    // 版本1
    CComPtr<IShellDispatch> spShellDispatch1 = GetShellDispatch_v1();
    ListShellVerb(spShellDispatch1, LR"(C:\Windows\System32)", L"notepad.exe");

    std::wcout << L"-----------------------------------------------------------\n";

    // 版本2
    CComPtr<IShellDispatch> spShellDispatch2 = GetShellDispatch_v2();
    ListShellVerb(spShellDispatch2, LR"(C:\Windows\System32)", L"notepad.exe");

    CoUninitialize();

    return 0;
}

以下是示例输出结果(英文版 Win10 操作系统),有些有弹出子菜单的不知道为啥没显示出来,也并不是所有菜单项都显示出来了,不知道原因:

&Open
Run as &administrator
Open with Code




Restore previous &versions


Cu&t
&Copy
Create &shortcut
&Delete
Rena&me
P&roperties
-----------------------------------------------------------
&Open
Run as &administrator
Open with Code
&Pin to Start



Scan with Windows Defender...
Pin to tas&kbar

Restore previous &versions


Cu&t
&Copy
Create &shortcut
&Delete
Rena&me
P&roperties

可以看到,虽然都不完整,但前面的比后面的这个更少,少了“附加到开始菜单”、“附加到任务栏”等等。

标签:Windows Shell