1 /* smplayer, GUI front-end for mplayer.
2 Copyright (C) 2006-2014 Ricardo Villalba <rvm@users.sourceforge.net>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 Winfileassoc.cpp
19
20 Handles file associations in Windows 7/Vista/XP/2000.
21 We assume that the code is run without administrator privileges, so the associations are done for current user only.
22 System-wide associations require writing to HKEY_CLASSES_ROOT and we don't want to get our hands dirty with that.
23 Each user on the computer can configure his own set of file associations for SMPlayer, which is extremely cool.
24
25 Optionally, during uninstall, it would be a good idea to call RestoreFileAssociations for all media types so
26 that we can clean up the registry and restore the old associations for current user.
27
28 Vista:
29 The code can only register the app as default program for selected extensions and check if it is the default.
30 It cannot restore 'old' default application, since this doesn't seem to be possible with the current Vista API.
31
32 Add libole32.a library if compiling with MinGW. In smplayer.pro, under 'win32 {': LIBS += libole32
33
34 Tested on: WinXP, Vista, Win7.
35
36 Author: Florin Braghis (florin@libertv.ro)
37 */
38
39 /*
40 main changes compared to SMPlayer:
41 replaced SMPlayer by Qmmp
42 added icon cache update
43 removed xp support
44 */
45
46
47 #include "winfileassoc.h"
48 #include <QSettings>
49 #include <QApplication>
50 #include <QFileInfo>
51 #include <windows.h>
52 #include <shlobj.h>
53
54 #ifndef SHCNE_ASSOCHANGED
55 #define SHCNE_ASSOCHANGED __MSABI_LONG(0x08000000)
56 #endif
57
WinFileAssoc(const QString AppName)58 WinFileAssoc::WinFileAssoc(const QString AppName) : m_AppName(AppName)
59 {}
60
61 // Associates all extensions in the fileExtensions list with current app.
62 // Returns number of extensions processed successfully.
CreateFileAssociations(const QStringList & fileExtensions)63 int WinFileAssoc::CreateFileAssociations(const QStringList &fileExtensions)
64 {
65 return VistaSetAppsAsDefault(fileExtensions);
66 }
67
68 // Checks if extensions in extensionsToCheck are registered with this application. Returns a list of registered extensions.
69 // Returns false if there was an error accessing the registry.
70 // Returns true and 0 elements in registeredExtensions if no extension is associated with current app.
GetRegisteredExtensions(const QStringList & extensionsToCheck,QStringList & registeredExtensions)71 bool WinFileAssoc::GetRegisteredExtensions(const QStringList &extensionsToCheck, QStringList ®isteredExtensions)
72 {
73 registeredExtensions.clear();
74 return VistaGetDefaultApps(extensionsToCheck, registeredExtensions);
75 }
76
77 // Windows Vista specific implementation
78
79 #if !defined(IApplicationAssociationRegistration)
80
81 typedef enum tagASSOCIATIONLEVEL {
82 AL_MACHINE,
83 AL_EFFECTIVE,
84 AL_USER
85 } ASSOCIATIONLEVEL;
86
87 typedef enum tagASSOCIATIONTYPE {
88 AT_FILEEXTENSION,
89 AT_URLPROTOCOL,
90 AT_STARTMENUCLIENT,
91 AT_MIMETYPE
92 } ASSOCIATIONTYPE;
93
94 MIDL_INTERFACE("4e530b0a-e611-4c77-a3ac-9031d022281b")
95 IApplicationAssociationRegistration :
96 public IUnknown {
97 public:
98 virtual HRESULT STDMETHODCALLTYPE QueryCurrentDefault(LPCWSTR pszQuery,
99 ASSOCIATIONTYPE atQueryType,
100 ASSOCIATIONLEVEL alQueryLevel,
101 LPWSTR * ppszAssociation) = 0;
102 virtual HRESULT STDMETHODCALLTYPE QueryAppIsDefault(LPCWSTR pszQuery,
103 ASSOCIATIONTYPE atQueryType,
104 ASSOCIATIONLEVEL alQueryLevel,
105 LPCWSTR pszAppRegistryName,
106 BOOL * pfDefault) = 0;
107 virtual HRESULT STDMETHODCALLTYPE QueryAppIsDefaultAll(ASSOCIATIONLEVEL alQueryLevel,
108 LPCWSTR pszAppRegistryName,
109 BOOL * pfDefault) = 0;
110 virtual HRESULT STDMETHODCALLTYPE SetAppAsDefault(LPCWSTR pszAppRegistryName,
111 LPCWSTR pszSet,
112 ASSOCIATIONTYPE atSetType) = 0;
113 virtual HRESULT STDMETHODCALLTYPE SetAppAsDefaultAll(LPCWSTR pszAppRegistryName) = 0;
114 virtual HRESULT STDMETHODCALLTYPE ClearUserAssociations(void) = 0;
115 };
116 #endif
117
118 static const CLSID CLSID_ApplicationAssociationReg = {0x591209C7, 0x767B, 0x42B2, {0x9F, 0xBA, 0x44, 0xEE, 0x46, 0x15, 0xF2, 0xC7}};
119 static const IID IID_IApplicationAssociationReg = {0x4e530b0a, 0xe611, 0x4c77, {0xa3, 0xac, 0x90, 0x31, 0xd0, 0x22, 0x28, 0x1b}};
120
121 int WinFileAssoc::VistaSetAppsAsDefault(const QStringList &fileExtensions)
122 {
123 IApplicationAssociationRegistration *pAAR;
124 HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationReg,
125 NULL, CLSCTX_INPROC, IID_IApplicationAssociationReg, (void **)&pAAR);
126
127 int count = 0;
128
129 if (SUCCEEDED(hr) && (pAAR != NULL)) {
130 for(const QString &fileExtension : qAsConst(fileExtensions)) {
131 hr = pAAR->SetAppAsDefault((const WCHAR *)m_AppName.utf16(),
132 (const WCHAR *)QString("." + fileExtension).utf16(),
133 AT_FILEEXTENSION);
134
135 if (SUCCEEDED(hr))
136 count++;
137 }
138 pAAR->Release();
139 }
140
141 return count;
142 }
143
144 bool WinFileAssoc::VistaGetDefaultApps(const QStringList &extensions, QStringList ®isteredExt)
145 {
146 IApplicationAssociationRegistration *pAAR;
147
148 HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationReg,
149 NULL, CLSCTX_INPROC, IID_IApplicationAssociationReg, (void **)&pAAR);
150
151 if (SUCCEEDED(hr) && (pAAR != NULL)) {
152 for(const QString &fileExtension : qAsConst(extensions)) {
153 BOOL bIsDefault = false;
154 hr = pAAR->QueryAppIsDefault((const WCHAR *)QString("." + fileExtension).utf16(),
155 AT_FILEEXTENSION,
156 AL_EFFECTIVE,
157 (const WCHAR *)m_AppName.utf16(),
158 &bIsDefault);
159
160 if (SUCCEEDED(hr) && bIsDefault) {
161 registeredExt.append(fileExtension);
162 }
163 }
164
165 pAAR->Release();
166 return true;
167 }
168
169 return false;
170 }
171