Fix modifying file type associations under MSW as non-admin

The existing code tried writing to HKEY_CLASSES_ROOT which doesn't work, in
general, for normal, i.e. non administrator, users, under any post-XP versions
of Windows.

Fix it to write to HKEY_CURRENT_USER\Software\Classes, which is the part of
HKEY_CLASSES_ROOT for the current user and to which we do have write access,
and only continue to use HKEY_CLASSES_ROOT itself for reading.

(this is a backport of 0ed580f451 from master)
This commit is contained in:
Vadim Zeitlin
2015-12-02 23:29:10 +01:00
parent f5e966deeb
commit a487dc88c1
2 changed files with 29 additions and 15 deletions

View File

@@ -634,6 +634,7 @@ wxMSW:
- Fix RegisterHotKey() with negative IDs (troelsk).
- Fix event object type for wxEVT_SPINCTRL events.
- Fix bug if wxToolBar tool was deleted from its own handler (Artur Wieczorek).
- Fix creating or modifying file associations under recent Windows versions.
wxOSX:

View File

@@ -66,6 +66,17 @@ class WXDLLIMPEXP_FWD_CORE wxIcon;
// to open/print the file (the positional parameters are introduced by %1,
// %2, ... in these strings, we change them to %s ourselves)
// Notice that HKCR can be used only when reading from the registry, when
// writing to it, we need to write to HKCU\Software\Classes instead as HKCR is
// a merged view of that location and HKLM\Software\Classes that we generally
// wouldn't have the write permissions to but writing to HKCR will try writing
// to the latter unless the key being written to already exists under the
// former, resulting in a "Permission denied" error without administrative
// permissions. So the right thing to do is to use HKCR when reading, to
// respect both per-user and machine-global associations, but only write under
// HKCU.
static const wxChar *CLASSES_ROOT_KEY = wxS("Software\\Classes\\");
// although I don't know of any official documentation which mentions this
// location, uses it, so it isn't likely to change
static const wxChar *MIME_DATABASE_KEY = wxT("MIME\\Database\\Content Type\\");
@@ -190,7 +201,7 @@ size_t wxFileTypeImpl::GetAllCommands(wxArrayString *verbs,
bool wxFileTypeImpl::EnsureExtKeyExists()
{
wxRegKey rkey(wxRegKey::HKCR, m_ext);
wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + m_ext);
if ( !rkey.Exists() )
{
if ( !rkey.Create() || !rkey.SetValue(wxEmptyString, m_strFileType) )
@@ -577,11 +588,11 @@ wxFileType *wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
extWithDot = wxT('.');
extWithDot += ext;
// start by setting the HKCR\\.ext entries
// start by setting the entries under ".ext"
// default is filetype; content type is mimetype
const wxString& filetypeOrig = ftInfo.GetShortDesc();
wxRegKey key(wxRegKey::HKCR, extWithDot);
wxRegKey key(wxRegKey::HKCU, CLASSES_ROOT_KEY + extWithDot);
if ( !key.Exists() )
{
// create the mapping from the extension to the filetype
@@ -629,7 +640,7 @@ wxFileType *wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
// create the MIME key
wxString strKey = MIME_DATABASE_KEY;
strKey << mimetype;
wxRegKey keyMIME(wxRegKey::HKCR, strKey);
wxRegKey keyMIME(wxRegKey::HKCU, CLASSES_ROOT_KEY + strKey);
ok = keyMIME.Create();
if ( ok )
@@ -650,7 +661,7 @@ wxFileType *wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
extWithDot = wxT('.');
extWithDot += ext;
wxRegKey key2(wxRegKey::HKCR, extWithDot);
wxRegKey key2(wxRegKey::HKCU, CLASSES_ROOT_KEY + extWithDot);
if ( !key2.Exists() )
key2.Create();
key2.SetValue(wxEmptyString, filetype);
@@ -667,7 +678,7 @@ wxFileType *wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
// create the MIME key
wxString strKey = MIME_DATABASE_KEY;
strKey << mimetype2;
wxRegKey keyMIME(wxRegKey::HKCR, strKey);
wxRegKey keyMIME(wxRegKey::HKCU, CLASSES_ROOT_KEY + strKey);
ok = keyMIME.Create();
if ( ok )
@@ -678,11 +689,11 @@ wxFileType *wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
}
}
} // end of for loop; all extensions now point to HKCR\.ext\Default
} // end of for loop; all extensions now point to .ext\Default
// create the filetype key itself (it will be empty for now, but
// SetCommand(), SetDefaultIcon() &c will use it later)
wxRegKey keyFT(wxRegKey::HKCR, filetype);
wxRegKey keyFT(wxRegKey::HKCU, CLASSES_ROOT_KEY + filetype);
keyFT.Create();
wxFileType *ft = CreateFileType(filetype, extWithDot);
@@ -710,7 +721,7 @@ bool wxFileTypeImpl::SetCommand(const wxString& cmd,
if ( !EnsureExtKeyExists() )
return false;
wxRegKey rkey(wxRegKey::HKCR, GetVerbPath(verb));
wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + GetVerbPath(verb));
// TODO:
// 1. translate '%s' to '%1' instead of always adding it
@@ -728,7 +739,8 @@ bool wxFileTypeImpl::SetDefaultIcon(const wxString& cmd, int index)
if ( !EnsureExtKeyExists() )
return false;
wxRegKey rkey(wxRegKey::HKCR, m_strFileType + wxT("\\DefaultIcon"));
wxRegKey rkey(wxRegKey::HKCU,
CLASSES_ROOT_KEY + m_strFileType + wxT("\\DefaultIcon"));
return rkey.Create() &&
rkey.SetValue(wxEmptyString,
@@ -743,7 +755,7 @@ bool wxFileTypeImpl::SetDescription (const wxString& desc)
if ( !EnsureExtKeyExists() )
return false;
wxRegKey rkey(wxRegKey::HKCR, m_strFileType );
wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + m_strFileType );
return rkey.Create() &&
rkey.SetValue(wxEmptyString, desc);
@@ -778,7 +790,7 @@ bool wxFileTypeImpl::RemoveCommand(const wxString& verb)
wxCHECK_MSG( !m_ext.empty() && !verb.empty(), false,
wxT("RemoveCommand() needs an extension and a verb") );
wxRegKey rkey(wxRegKey::HKCR, GetVerbPath(verb));
wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + GetVerbPath(verb));
// if the key already doesn't exist, it's a success
return !rkey.Exists() || rkey.DeleteSelf();
@@ -788,7 +800,7 @@ bool wxFileTypeImpl::RemoveMimeType()
{
wxCHECK_MSG( !m_ext.empty(), false, wxT("RemoveMimeType() needs extension") );
wxRegKey rkey(wxRegKey::HKCR, m_ext);
wxRegKey rkey(wxRegKey::HKCU, CLASSES_ROOT_KEY + m_ext);
return !rkey.Exists() || rkey.DeleteSelf();
}
@@ -797,7 +809,8 @@ bool wxFileTypeImpl::RemoveDefaultIcon()
wxCHECK_MSG( !m_ext.empty(), false,
wxT("RemoveDefaultIcon() needs extension") );
wxRegKey rkey (wxRegKey::HKCR, m_strFileType + wxT("\\DefaultIcon"));
wxRegKey rkey (wxRegKey::HKCU,
CLASSES_ROOT_KEY + m_strFileType + wxT("\\DefaultIcon"));
return !rkey.Exists() || rkey.DeleteSelf();
}
@@ -806,7 +819,7 @@ bool wxFileTypeImpl::RemoveDescription()
wxCHECK_MSG( !m_ext.empty(), false,
wxT("RemoveDescription() needs extension") );
wxRegKey rkey (wxRegKey::HKCR, m_strFileType );
wxRegKey rkey (wxRegKey::HKCU, CLASSES_ROOT_KEY + m_strFileType );
return !rkey.Exists() || rkey.DeleteSelf();
}