如何确定 shell 动词是否已为给定文件类型注册?

bdo*_*lan 0 shell winapi file-association

给定一个文件扩展名,我如何查询以查看是否注册了任何程序来处理特定的 ShellExecute 动词("print"在我的例子中),而不实际调用所述动词?

And*_*ers 6

#include <windows.h>
#include <Shlwapi.h>
#include <stdio.h>

#if _WIN32_WINNT <= 0x0501
#define ASSOCF_INIT_IGNOREUNKNOWN   0x00000400 
#endif

BOOL AssocExtHasVerb(LPCTSTR dotExt,LPCTSTR verb) 
{
    HKEY hKey;
    HRESULT hr = AssocQueryKey(ASSOCF_INIT_IGNOREUNKNOWN,ASSOCKEY_SHELLEXECCLASS,dotExt,verb,&hKey);
    if (SUCCEEDED(hr)) 
    {
        RegCloseKey(hKey);
        return TRUE;
    }
    return FALSE;
}


void main() 
{
    LPCTSTR ext=".txt",verb="print";
    printf("%s:%s=%d\n",ext,verb,AssocExtHasVerb(ext,verb));
}
Run Code Online (Sandbox Code Playgroud)

如果您想自己查询注册表(为什么?),您需要能够处理几个“重定向”,这超出了我的想象:

  • (Vista+) 首先检查 HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\%.ext%\UserChoice : (REG_SZ) "ProgId"
  • 如果该键为空,则读取 HKCR\%.ext% : (REG_SZ) "" (默认)

您现在应该有一个 ProgId,然后检查 HKCR\%ProgId% : (REG_SZ) "CurVer",如果它存在(并且有一个 shell 子项),您就找到了“真正的”ProgId,如果没有,请继续使用原始 ProgId。

您现在可以检查 HKCR\%ProgId%\shell\%verb% (您确实应该检查它是否具有带有字符串的命令子项,或者 droptarget 或 dde ​​值等)

(XP+) 如果您在 progid 下没有找到动词:

  • 检查 HKCR\SystemFileAssociations\%.ext%\shell\%verb%

(XP+) 如果还没有找到动词,请阅读 HKCR\%.ext% : (REG_SZ) "PerceivedType",如果非空,请检查 HKCR\SystemFileAssociations\%PerceivedType%\shell

如果您仍然没有找到动词,请检查HKCR\*HKCR\AllFilesystemObjectsHKCR\Unknown

(Win7添加了子菜单等,我没有考虑这些,我可能遗漏了一些其他步骤,据我所知,并不是所有这些都被记录下来)


即使您执行了所有这些操作,也可能存在动词而您没有检测到它,shell 扩展可以在运行时添加动词,检查这些动词的唯一方法是在实际文件上使用 IContextMenu...