1 // RegistryAssociations.cpp
2
3 #include "StdAfx.h"
4
5 #include "RegistryAssociations.h"
6
7 #include "Common/IntToString.h"
8 #include "Common/StringConvert.h"
9 #include "Common/StringToInt.h"
10
11 #include "Windows/Registry.h"
12 #include "Windows/Synchronization.h"
13
14 #include "StringUtils.h"
15
16 using namespace NWindows;
17 using namespace NRegistry;
18
19 namespace NRegistryAssociations {
20
21 static NSynchronization::CCriticalSection g_CriticalSection;
22
23 #define REG_PATH_FM TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-ZIP") TEXT(STRING_PATH_SEPARATOR) TEXT("FM")
24
25 static const TCHAR *kCUKeyPath = REG_PATH_FM;
26 static const WCHAR *kExtPlugins = L"Plugins";
27 static const TCHAR *kExtEnabled = TEXT("Enabled");
28
29 #define kAssociations TEXT("Associations")
30 #define kAssociationsPath REG_PATH_FM TEXT(STRING_PATH_SEPARATOR) kAssociations
31
ReadInternalAssociation(const wchar_t * ext,CExtInfo & extInfo)32 bool ReadInternalAssociation(const wchar_t *ext, CExtInfo &extInfo)
33 {
34 NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
35 CKey key;
36 if (key.Open(HKEY_CURRENT_USER,
37 CSysString(kAssociationsPath TEXT(STRING_PATH_SEPARATOR)) +
38 GetSystemString(ext), KEY_READ) != ERROR_SUCCESS)
39 return false;
40 UString pluginsString;
41 key.QueryValue(kExtPlugins, pluginsString);
42 SplitString(pluginsString, extInfo.Plugins);
43 return true;
44 }
45
ReadInternalAssociations(CObjectVector<CExtInfo> & items)46 void ReadInternalAssociations(CObjectVector<CExtInfo> &items)
47 {
48 items.Clear();
49 NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
50 CKey associationsKey;
51 if (associationsKey.Open(HKEY_CURRENT_USER, kAssociationsPath, KEY_READ) != ERROR_SUCCESS)
52 return;
53 CSysStringVector extNames;
54 associationsKey.EnumKeys(extNames);
55 for(int i = 0; i < extNames.Size(); i++)
56 {
57 const CSysString extName = extNames[i];
58 CExtInfo extInfo;
59 // extInfo.Enabled = false;
60 extInfo.Ext = GetUnicodeString(extName);
61 CKey key;
62 if (key.Open(associationsKey, extName, KEY_READ) != ERROR_SUCCESS)
63 return;
64 UString pluginsString;
65 key.QueryValue(kExtPlugins, pluginsString);
66 SplitString(pluginsString, extInfo.Plugins);
67 /*
68 if (key.QueryValue(kExtEnabled, extInfo.Enabled) != ERROR_SUCCESS)
69 extInfo.Enabled = false;
70 */
71 items.Add(extInfo);
72 }
73 }
74
WriteInternalAssociations(const CObjectVector<CExtInfo> & items)75 void WriteInternalAssociations(const CObjectVector<CExtInfo> &items)
76 {
77 NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
78 CKey mainKey;
79 mainKey.Create(HKEY_CURRENT_USER, kCUKeyPath);
80 mainKey.RecurseDeleteKey(kAssociations);
81 CKey associationsKey;
82 associationsKey.Create(mainKey, kAssociations);
83 for(int i = 0; i < items.Size(); i++)
84 {
85 const CExtInfo &extInfo = items[i];
86 CKey key;
87 key.Create(associationsKey, GetSystemString(extInfo.Ext));
88 key.SetValue(kExtPlugins, JoinStrings(extInfo.Plugins));
89 // key.SetValue(kExtEnabled, extInfo.Enabled);
90 }
91 }
92
93 ///////////////////////////////////
94 // External
95
96 static const TCHAR *kShellNewKeyName = TEXT("ShellNew");
97 static const TCHAR *kShellNewDataValueName = TEXT("Data");
98
99 static const TCHAR *kDefaultIconKeyName = TEXT("DefaultIcon");
100 static const TCHAR *kShellKeyName = TEXT("shell");
101 static const TCHAR *kOpenKeyName = TEXT("open");
102 static const TCHAR *kCommandKeyName = TEXT("command");
103
GetExtensionKeyName(const CSysString & extension)104 static CSysString GetExtensionKeyName(const CSysString &extension)
105 {
106 return CSysString(TEXT(".")) + extension;
107 }
108
GetExtProgramKeyName(const CSysString & extension)109 static CSysString GetExtProgramKeyName(const CSysString &extension)
110 {
111 return CSysString(TEXT("7-Zip.")) + extension;
112 }
113
CheckShellExtensionInfo2(const CSysString & extension,UString & iconPath,int & iconIndex)114 static bool CheckShellExtensionInfo2(const CSysString &extension, UString &iconPath, int &iconIndex)
115 {
116 iconIndex = -1;
117 iconPath.Empty();
118 NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
119 CKey extKey;
120 if (extKey.Open(HKEY_CLASSES_ROOT, GetExtensionKeyName(extension), KEY_READ) != ERROR_SUCCESS)
121 return false;
122 CSysString programNameValue;
123 if (extKey.QueryValue(NULL, programNameValue) != ERROR_SUCCESS)
124 return false;
125 CSysString extProgramKeyName = GetExtProgramKeyName(extension);
126 UString programNameValueU = GetUnicodeString(programNameValue);
127 if (programNameValueU.CompareNoCase(GetUnicodeString(extProgramKeyName)) != 0)
128 return false;
129 CKey iconKey;
130 if (extKey.Open(HKEY_CLASSES_ROOT, extProgramKeyName + CSysString(TEXT(CHAR_PATH_SEPARATOR)) + kDefaultIconKeyName, KEY_READ) != ERROR_SUCCESS)
131 return false;
132 UString value;
133 if (extKey.QueryValue(NULL, value) == ERROR_SUCCESS)
134 {
135 int pos = value.ReverseFind(L',');
136 iconPath = value;
137 if (pos >= 0)
138 {
139 const wchar_t *end;
140 UInt64 index = ConvertStringToUInt64((const wchar_t *)value + pos + 1, &end);
141 if (*end == 0)
142 {
143 iconIndex = (int)index;
144 iconPath = value.Left(pos);
145 }
146 }
147 }
148 return true;
149 }
150
CheckShellExtensionInfo(const CSysString & extension,UString & iconPath,int & iconIndex)151 bool CheckShellExtensionInfo(const CSysString &extension, UString &iconPath, int &iconIndex)
152 {
153 NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
154 if (!CheckShellExtensionInfo2(extension, iconPath, iconIndex))
155 return false;
156 CKey extProgKey;
157 return (extProgKey.Open(HKEY_CLASSES_ROOT, GetExtProgramKeyName(extension), KEY_READ) == ERROR_SUCCESS);
158 }
159
DeleteShellExtensionKey(const CSysString & extension)160 static void DeleteShellExtensionKey(const CSysString &extension)
161 {
162 NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
163 CKey rootKey;
164 rootKey.Attach(HKEY_CLASSES_ROOT);
165 rootKey.RecurseDeleteKey(GetExtensionKeyName(extension));
166 rootKey.Detach();
167 }
168
DeleteShellExtensionProgramKey(const CSysString & extension)169 static void DeleteShellExtensionProgramKey(const CSysString &extension)
170 {
171 NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
172 CKey rootKey;
173 rootKey.Attach(HKEY_CLASSES_ROOT);
174 rootKey.RecurseDeleteKey(GetExtProgramKeyName(extension));
175 rootKey.Detach();
176 }
177
DeleteShellExtensionInfo(const CSysString & extension)178 void DeleteShellExtensionInfo(const CSysString &extension)
179 {
180 UString iconPath;
181 int iconIndex;
182 if (CheckShellExtensionInfo2(extension, iconPath, iconIndex))
183 DeleteShellExtensionKey(extension);
184 DeleteShellExtensionProgramKey(extension);
185 }
186
AddShellExtensionInfo(const CSysString & extension,const UString & programTitle,const UString & programOpenCommand,const UString & iconPath,int iconIndex,const void * shellNewData,int shellNewDataSize)187 void AddShellExtensionInfo(const CSysString &extension,
188 const UString &programTitle,
189 const UString &programOpenCommand,
190 const UString &iconPath, int iconIndex,
191 const void *shellNewData, int shellNewDataSize)
192 {
193 DeleteShellExtensionKey(extension);
194 DeleteShellExtensionProgramKey(extension);
195 NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
196 CSysString programKeyName = GetExtProgramKeyName(extension);
197 {
198 CKey extKey;
199 extKey.Create(HKEY_CLASSES_ROOT, GetExtensionKeyName(extension));
200 extKey.SetValue(NULL, programKeyName);
201 if (shellNewData != NULL)
202 {
203 CKey shellNewKey;
204 shellNewKey.Create(extKey, kShellNewKeyName);
205 shellNewKey.SetValue(kShellNewDataValueName, shellNewData, shellNewDataSize);
206 }
207 }
208 CKey programKey;
209 programKey.Create(HKEY_CLASSES_ROOT, programKeyName);
210 programKey.SetValue(NULL, programTitle);
211 {
212 CKey iconKey;
213 iconKey.Create(programKey, kDefaultIconKeyName);
214 UString iconPathFull = iconPath;
215 if (iconIndex >= 0)
216 {
217 iconPathFull += L",";
218 wchar_t s[16];
219 ConvertUInt32ToString(iconIndex, s);
220 iconPathFull += s;
221 }
222 iconKey.SetValue(NULL, iconPathFull);
223 }
224
225 CKey shellKey;
226 shellKey.Create(programKey, kShellKeyName);
227 shellKey.SetValue(NULL, TEXT(""));
228
229 CKey openKey;
230 openKey.Create(shellKey, kOpenKeyName);
231 openKey.SetValue(NULL, TEXT(""));
232
233 CKey commandKey;
234 commandKey.Create(openKey, kCommandKeyName);
235
236 commandKey.SetValue(NULL, programOpenCommand);
237 }
238
239 ///////////////////////////
240 // ContextMenu
241 /*
242
243 static const TCHAR *kContextMenuKeyName = TEXT("\\shellex\\ContextMenuHandlers\\7-ZIP");
244 static const TCHAR *kContextMenuHandlerCLASSIDValue =
245 TEXT("{23170F69-40C1-278A-1000-000100020000}");
246 static const TCHAR *kRootKeyNameForFile = TEXT("*");
247 static const TCHAR *kRootKeyNameForFolder = TEXT("Folder");
248
249 static CSysString GetFullContextMenuKeyName(const CSysString &aKeyName)
250 { return (aKeyName + kContextMenuKeyName); }
251
252 static bool CheckContextMenuHandlerCommon(const CSysString &aKeyName)
253 {
254 NSynchronization::CCriticalSectionLock lock(&g_CriticalSection, true);
255 CKey aKey;
256 if (aKey.Open(HKEY_CLASSES_ROOT, GetFullContextMenuKeyName(aKeyName), KEY_READ)
257 != ERROR_SUCCESS)
258 return false;
259 CSysString aValue;
260 if (aKey.QueryValue(NULL, aValue) != ERROR_SUCCESS)
261 return false;
262 return (aValue.CompareNoCase(kContextMenuHandlerCLASSIDValue) == 0);
263 }
264
265 bool CheckContextMenuHandler()
266 {
267 return CheckContextMenuHandlerCommon(kRootKeyNameForFile) &&
268 CheckContextMenuHandlerCommon(kRootKeyNameForFolder);
269 }
270
271 static void DeleteContextMenuHandlerCommon(const CSysString &aKeyName)
272 {
273 CKey rootKey;
274 rootKey.Attach(HKEY_CLASSES_ROOT);
275 rootKey.RecurseDeleteKey(GetFullContextMenuKeyName(aKeyName));
276 rootKey.Detach();
277 }
278
279 void DeleteContextMenuHandler()
280 {
281 DeleteContextMenuHandlerCommon(kRootKeyNameForFile);
282 DeleteContextMenuHandlerCommon(kRootKeyNameForFolder);
283 }
284
285 static void AddContextMenuHandlerCommon(const CSysString &aKeyName)
286 {
287 DeleteContextMenuHandlerCommon(aKeyName);
288 NSynchronization::CCriticalSectionLock lock(&g_CriticalSection, true);
289 CKey aKey;
290 aKey.Create(HKEY_CLASSES_ROOT, GetFullContextMenuKeyName(aKeyName));
291 aKey.SetValue(NULL, kContextMenuHandlerCLASSIDValue);
292 }
293
294 void AddContextMenuHandler()
295 {
296 AddContextMenuHandlerCommon(kRootKeyNameForFile);
297 AddContextMenuHandlerCommon(kRootKeyNameForFolder);
298 }
299 */
300
301 }
302