使用 MFC 以编程方式更改文件扩展名关联?

Posted

技术标签:

【中文标题】使用 MFC 以编程方式更改文件扩展名关联?【英文标题】:Changing file extension associations programatically using MFC? 【发布时间】:2020-05-09 14:46:22 【问题描述】:

我可以使用InitInstance 中的这段代码来确认哪个可执行文件与给定的扩展关联:

TCHAR szRegisteredEXE[_MAX_PATH];
DWORD dwBufferLen = _MAX_PATH;

HRESULT  hRes = AssocQueryString(ASSOCF_NONE, ASSOCSTR_EXECUTABLE, 
                    _T("MeetSchedAssist.MWB"), NULL, szRegisteredEXE, &dwBufferLen);
if (hRes == S_OK)

    // TODO

效果很好。

我的软件安装了 32 位版本和 64 位版本的可执行文件。因此,如果注册的 exe 不是活动的 exe,我希望代码做的是提示更新关联。

我知道如何获取我的活动 exe 路径以及如何确认它是否与 szRegisteredEXE 匹配,但是我如何处理更新文件关联(假设用户对关联提示说是)?

【问题讨论】:

这很复杂,但可以做到。您需要在HKEY_CLASSES_ROOT 中写入/替换注册表项,但会有许多需要修改相互关联的条目。如果您安装了处理 MWB 扩展的程序,请查看HKEY_CLASSES_ROOT\.MWBHKEY_CLASSES_ROOT\MyDescription 键(其中MyDescription 在第一个键中给出)。 您还需要以提升的权限运行,否则我认为 HKCR 密钥将被虚拟化,并且程序退出后更改将不会保留。 所以,如果您对注册表访问 API 调用感到满意(就像我想象的那样),您可以潜入并尝试!我认为在这个阶段尝试发布代码答案有点过分,但请随时回来询问您是否遇到问题。我很乐意(尝试)提供帮助。 我认为可执行文件必须是“以管理员身份运行”(在清单文件中设置该要求),然后(令人讨厌)每次启动时都会要求输入管理员密码。但我不能 100% 确定 - 它们可能是启动后提升的一种方式(尽管仍然需要管理员密码提示 - 否则这将是一个简单的 O/S hack)。跨度> 您可以构建一个“假”的 MSI 安装程序,您可以从程序中调用它来设置所需的文件关联。 【参考方案1】:

第一步是创建一个 Inno Setup 安装程序,它将为我们管理注册表的调整:

; SignTool parameters
#define SignedDesc "$qMeeting Schedule Assistant File Associations Tool$q"
#define SignedPfx "$q~~~~~$q"
#define SignedTimeStamp "$qhttp://timestamp.verisign.com/scripts/timestamp.dll$q"
#define SignedPw "$q~~~~~$q"

#define AppURL "https://www.publictalksoftware.co.uk"
#define AppPublisher "~~~~~"

#define AppVerText() \
   ParseVersion('..\Meeting Schedule Assistant\Release\Meeting Schedule Assistant.exe', \
       Local[0], Local[1], Local[2], Local[3]), \
   Str(Local[0]) + "." + Str(Local[1]) + "." + Str(Local[2])

[Setup]
DisableReadyPage=True
DisableReadyMemo=True
DisableFinishedPage=True
UsePreviousSetupType=False
UsePreviousTasks=False
UsePreviousLanguage=False
FlatComponentsList=False
AlwaysShowComponentsList=False
ShowComponentSizes=False
AppName=Meeting Schedule Assistant File Associations Tool
AppVersion=#AppVerText
CreateAppDir=False
Uninstallable=no
OutputBaseFilename=MSATweakFileAssociations
SignTool=SignTool /d #SignedDesc /du $q#AppURL$q /f #SignedPfx /p #SignedPw /t #SignedTimeStamp /v $f
AppId=~~~~~

[registry]
Root: HKCR; SubKey: "MeetSchedAssist.MWB\Shell\Open\Command"; ValueType: string; ValueData: """param:ExePath"" ""%1""";
Root: HKCR; SubKey: "MeetSchedAssist.SRR\Shell\Open\Command"; ValueType: string; ValueData: """param:ExePath"" ""%1""";

然后,在 MFC 中,我们运行我们的工具,如下所示:

void COptionsDlg::OnBnClickedMfcbuttonFileAssociations()

    // Try to run the help installer
    CString strSetupExe = _T("~~~~~.exe");
    CString strProgramFolder = theApp.GetProgramPath();
    CString strParams = _T("");

    strParams.Format(_T("/SP- /VERYSILENT /ExePath=\"%s\""), (LPCTSTR)theApp.GetProgramEXE());
    if (!theApp.ExecuteProgram(strProgramFolder + strSetupExe, strParams))
    
        // Problem running the installer
        AfxMessageBox(_T("Unable to change the file associations"), MB_OK | MB_ICONERROR);
        return;
    


BOOL CMeetingScheduleAssistantApp::ExecuteProgram(CString strProgram, CString strArguments)

    SHELLEXECUTEINFO    se =  0 ;
    MSG                 sMessage;
    DWORD               dwResult;

    theApp.SetProgramExecuting(true);

    se.cbSize = sizeof(se);
    se.lpFile = strProgram;
    se.lpParameters = strArguments;
    se.nShow = SW_SHOWDEFAULT;
    se.fMask = SEE_MASK_NOCLOSEPROCESS;
    ShellExecuteEx(&se);

    if (se.hProcess != nullptr)
    
        do
        
            dwResult = ::MsgWaitForMultipleObjects(1, &(se.hProcess), FALSE,
                INFINITE, QS_ALLINPUT);
            if (dwResult != WAIT_OBJECT_0)
            
                while (PeekMessage(&sMessage, nullptr, NULL, NULL, PM_REMOVE))
                
                    TranslateMessage(&sMessage);
                    DispatchMessage(&sMessage);
                
            
         while ((dwResult != WAIT_OBJECT_0) && (dwResult != WAIT_FAILED));

        CloseHandle(se.hProcess);
    

    theApp.SetProgramExecuting(false);

    if ((DWORD_PTR)(se.hInstApp) < 33)
    
        // Throw error
        AfxThrowUserException();
        return FALSE;
    

    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);

    return TRUE;

瞧!它更新注册表。

【讨论】:

对于每个用户设置使用HKEY_CURRENT_USER\Software\Classes。你不需要海拔来做到这一点。 @DanielSęk 我的软件不是为每个用户设计的。但请注意。

以上是关于使用 MFC 以编程方式更改文件扩展名关联?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 MFC 以编程方式更改 ActiveX 控件的属性?

如何以编程方式安装所有VSCode工作区扩展

在 MFC 中注册文件关联在 Windows 7 上不起作用

以编程方式定义通知内容扩展的高度

以编程方式更新具有 SVN 修订号的 MFC 应用程序中的 FILEVERSION

怎样在我的文档里“控制面板里的文件夹选项中创建关联”?