使用 MFC 以编程方式更改文件扩展名关联?
Changing file extension associations programatically using MFC?
我可以在 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
但是我如何处理更新文件关联(假设用户对关联提示说是)?
第一步是创建一个 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;
}
瞧!它更新注册表。
我可以在 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
但是我如何处理更新文件关联(假设用户对关联提示说是)?
第一步是创建一个 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;
}
瞧!它更新注册表。