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