Программно изменить ассоциации расширений файлов с помощью MF C? - PullRequest
1 голос
/ 09 мая 2020

Я могу использовать этот код в 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 но как мне тогда справиться с обновлением ассоциаций файлов (при условии, что пользователь согласен с предложением установить связь)?

1 Ответ

1 голос
/ 09 мая 2020

Первый шаг - создать установщик 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""";

Затем в MF C запускаем наш инструмент, например:

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;
}

Вуаля! Обновляет реестр.

...