1 // RootFolder.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/MyWindows.h"
6
7 #if defined(__MINGW32__) || defined(__MINGW64__)
8 #include <shlobj.h>
9 #else
10 #include <ShlObj.h>
11 #endif
12
13 #include "../../../Common/StringConvert.h"
14
15 #include "../../../Windows/DLL.h"
16 #include "../../../Windows/FileName.h"
17 #include "../../../Windows/PropVariant.h"
18
19 #include "../../PropID.h"
20
21 #if defined(_WIN32) && !defined(UNDER_CE)
22 #define USE_WIN_PATHS
23 #endif
24
25 static const unsigned kNumRootFolderItems =
26 #ifdef USE_WIN_PATHS
27 4
28 #else
29 1
30 #endif
31 ;
32
33
34 #include "FSFolder.h"
35 #include "LangUtils.h"
36 #ifdef USE_WIN_PATHS
37 #include "NetFolder.h"
38 #include "FSDrives.h"
39 #include "AltStreamsFolder.h"
40 #endif
41 #include "RootFolder.h"
42 #include "SysIconUtils.h"
43
44 #include "resource.h"
45
46 using namespace NWindows;
47
48 static const Byte kProps[] =
49 {
50 kpidName
51 };
52
53 UString RootFolder_GetName_Computer(int &iconIndex);
RootFolder_GetName_Computer(int & iconIndex)54 UString RootFolder_GetName_Computer(int &iconIndex)
55 {
56 #ifdef USE_WIN_PATHS
57 iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES);
58 #else
59 iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY);
60 #endif
61 return LangString(IDS_COMPUTER);
62 }
63
64 UString RootFolder_GetName_Network(int &iconIndex);
RootFolder_GetName_Network(int & iconIndex)65 UString RootFolder_GetName_Network(int &iconIndex)
66 {
67 iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_NETWORK);
68 return LangString(IDS_NETWORK);
69 }
70
71 UString RootFolder_GetName_Documents(int &iconIndex);
RootFolder_GetName_Documents(int & iconIndex)72 UString RootFolder_GetName_Documents(int &iconIndex)
73 {
74 iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_PERSONAL);
75 return LangString(IDS_DOCUMENTS);
76 }
77
78 enum
79 {
80 ROOT_INDEX_COMPUTER = 0
81 #ifdef USE_WIN_PATHS
82 , ROOT_INDEX_DOCUMENTS
83 , ROOT_INDEX_NETWORK
84 , ROOT_INDEX_VOLUMES
85 #endif
86 };
87
88 #ifdef USE_WIN_PATHS
89 static const char * const kVolPrefix = "\\\\.";
90 #endif
91
Init()92 void CRootFolder::Init()
93 {
94 _names[ROOT_INDEX_COMPUTER] = RootFolder_GetName_Computer(_iconIndices[ROOT_INDEX_COMPUTER]);
95 #ifdef USE_WIN_PATHS
96 _names[ROOT_INDEX_DOCUMENTS] = RootFolder_GetName_Documents(_iconIndices[ROOT_INDEX_DOCUMENTS]);
97 _names[ROOT_INDEX_NETWORK] = RootFolder_GetName_Network(_iconIndices[ROOT_INDEX_NETWORK]);
98 _names[ROOT_INDEX_VOLUMES] = kVolPrefix;
99 _iconIndices[ROOT_INDEX_VOLUMES] = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES);
100 #endif
101 }
102
Z7_COM7F_IMF(CRootFolder::LoadItems ())103 Z7_COM7F_IMF(CRootFolder::LoadItems())
104 {
105 Init();
106 return S_OK;
107 }
108
Z7_COM7F_IMF(CRootFolder::GetNumberOfItems (UInt32 * numItems))109 Z7_COM7F_IMF(CRootFolder::GetNumberOfItems(UInt32 *numItems))
110 {
111 *numItems = kNumRootFolderItems;
112 return S_OK;
113 }
114
Z7_COM7F_IMF(CRootFolder::GetProperty (UInt32 itemIndex,PROPID propID,PROPVARIANT * value))115 Z7_COM7F_IMF(CRootFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value))
116 {
117 NCOM::CPropVariant prop;
118 switch (propID)
119 {
120 case kpidIsDir: prop = true; break;
121 case kpidName: prop = _names[itemIndex]; break;
122 }
123 prop.Detach(value);
124 return S_OK;
125 }
126
127 #if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0400 // nt4
128 #define Z7_USE_DYN_SHGetSpecialFolderPath
129 #endif
130
131 #ifdef Z7_USE_DYN_SHGetSpecialFolderPath
132 typedef BOOL (WINAPI *Func_SHGetSpecialFolderPathW)(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate);
133 typedef BOOL (WINAPI *Func_SHGetSpecialFolderPathA)(HWND hwnd, LPSTR pszPath, int csidl, BOOL fCreate);
134 #endif
135
GetMyDocsPath()136 static UString GetMyDocsPath()
137 {
138 UString us;
139 WCHAR s[MAX_PATH + 1];
140 #ifdef Z7_USE_DYN_SHGetSpecialFolderPath
141 #ifdef UNDER_CE
142 #define shell_name TEXT("coredll.dll")
143 #else
144 #define shell_name TEXT("shell32.dll")
145 #endif
146 Func_SHGetSpecialFolderPathW getW = Z7_GET_PROC_ADDRESS(
147 Func_SHGetSpecialFolderPathW, GetModuleHandle(shell_name),
148 "SHGetSpecialFolderPathW");
149 if (getW && getW
150 #else
151 if (SHGetSpecialFolderPathW
152 #endif
153 (NULL, s, CSIDL_PERSONAL, FALSE))
154 us = s;
155 #ifndef _UNICODE
156 else
157 {
158 CHAR s2[MAX_PATH + 1];
159 #ifdef Z7_USE_DYN_SHGetSpecialFolderPath
160 Func_SHGetSpecialFolderPathA getA = Z7_GET_PROC_ADDRESS(
161 Func_SHGetSpecialFolderPathA, ::GetModuleHandleA("shell32.dll"),
162 "SHGetSpecialFolderPathA");
163 if (getA && getA
164 #else
165 if (SHGetSpecialFolderPathA
166 #endif
167 (NULL, s2, CSIDL_PERSONAL, FALSE))
168 us = GetUnicodeString(s2);
169 }
170 #endif
171 NFile::NName::NormalizeDirPathPrefix(us);
172 return us;
173 }
174
Z7_COM7F_IMF(CRootFolder::BindToFolder (UInt32 index,IFolderFolder ** resultFolder))175 Z7_COM7F_IMF(CRootFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
176 {
177 *resultFolder = NULL;
178 CMyComPtr<IFolderFolder> subFolder;
179
180 #ifdef USE_WIN_PATHS
181 if (index == ROOT_INDEX_COMPUTER || index == ROOT_INDEX_VOLUMES)
182 {
183 CFSDrives *fsDrivesSpec = new CFSDrives;
184 subFolder = fsDrivesSpec;
185 fsDrivesSpec->Init(index == ROOT_INDEX_VOLUMES);
186 }
187 else if (index == ROOT_INDEX_NETWORK)
188 {
189 CNetFolder *netFolderSpec = new CNetFolder;
190 subFolder = netFolderSpec;
191 netFolderSpec->Init(NULL, NULL, _names[ROOT_INDEX_NETWORK] + WCHAR_PATH_SEPARATOR);
192 }
193 else if (index == ROOT_INDEX_DOCUMENTS)
194 {
195 UString s = GetMyDocsPath();
196 if (!s.IsEmpty())
197 {
198 NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
199 subFolder = fsFolderSpec;
200 RINOK(fsFolderSpec->Init(us2fs(s)))
201 }
202 }
203 #else
204 if (index == ROOT_INDEX_COMPUTER)
205 {
206 NFsFolder::CFSFolder *fsFolder = new NFsFolder::CFSFolder;
207 subFolder = fsFolder;
208 fsFolder->InitToRoot();
209 }
210 #endif
211 else
212 return E_INVALIDARG;
213
214 *resultFolder = subFolder.Detach();
215 return S_OK;
216 }
217
AreEqualNames(const UString & path,const wchar_t * name)218 static bool AreEqualNames(const UString &path, const wchar_t *name)
219 {
220 unsigned len = MyStringLen(name);
221 if (len > path.Len() || len + 1 < path.Len())
222 return false;
223 if (len + 1 == path.Len() && !IS_PATH_SEPAR(path[len]))
224 return false;
225 return path.IsPrefixedBy(name);
226 }
227
Z7_COM7F_IMF(CRootFolder::BindToFolder (const wchar_t * name,IFolderFolder ** resultFolder))228 Z7_COM7F_IMF(CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder))
229 {
230 *resultFolder = NULL;
231 UString name2 = name;
232 name2.Trim();
233
234 if (name2.IsEmpty())
235 {
236 CRootFolder *rootFolderSpec = new CRootFolder;
237 CMyComPtr<IFolderFolder> rootFolder = rootFolderSpec;
238 rootFolderSpec->Init();
239 *resultFolder = rootFolder.Detach();
240 return S_OK;
241 }
242
243 for (unsigned i = 0; i < kNumRootFolderItems; i++)
244 if (AreEqualNames(name2, _names[i]))
245 return BindToFolder((UInt32)i, resultFolder);
246
247 #ifdef USE_WIN_PATHS
248 if (AreEqualNames(name2, L"My Documents") ||
249 AreEqualNames(name2, L"Documents"))
250 return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder);
251 #else
252 if (name2 == WSTRING_PATH_SEPARATOR)
253 return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder);
254 #endif
255
256 if (AreEqualNames(name2, L"My Computer") ||
257 AreEqualNames(name2, L"Computer"))
258 return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder);
259
260 if (name2 == WSTRING_PATH_SEPARATOR)
261 {
262 CMyComPtr<IFolderFolder> subFolder = this;
263 *resultFolder = subFolder.Detach();
264 return S_OK;
265 }
266
267 if (name2.Len() < 2)
268 return E_INVALIDARG;
269
270 CMyComPtr<IFolderFolder> subFolder;
271
272 #ifdef USE_WIN_PATHS
273 if (name2.IsPrefixedBy_Ascii_NoCase(kVolPrefix))
274 {
275 CFSDrives *folderSpec = new CFSDrives;
276 subFolder = folderSpec;
277 folderSpec->Init(true);
278 }
279 else if (name2.IsEqualTo(NFile::NName::kSuperPathPrefix))
280 {
281 CFSDrives *folderSpec = new CFSDrives;
282 subFolder = folderSpec;
283 folderSpec->Init(false, true);
284 }
285 else if (name2.Back() == ':'
286 && (name2.Len() != 2 || !NFile::NName::IsDrivePath2(name2)))
287 {
288 NAltStreamsFolder::CAltStreamsFolder *folderSpec = new NAltStreamsFolder::CAltStreamsFolder;
289 subFolder = folderSpec;
290 if (folderSpec->Init(us2fs(name2)) != S_OK)
291 return E_INVALIDARG;
292 }
293 else
294 #endif
295 {
296 NFile::NName::NormalizeDirPathPrefix(name2);
297 NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
298 subFolder = fsFolderSpec;
299 if (fsFolderSpec->Init(us2fs(name2)) != S_OK)
300 {
301 #ifdef USE_WIN_PATHS
302 if (IS_PATH_SEPAR(name2[0]))
303 {
304 CNetFolder *netFolderSpec = new CNetFolder;
305 subFolder = netFolderSpec;
306 netFolderSpec->Init(name2);
307 }
308 else
309 #endif
310 return E_INVALIDARG;
311 }
312 }
313
314 *resultFolder = subFolder.Detach();
315 return S_OK;
316 }
317
Z7_COM7F_IMF(CRootFolder::BindToParentFolder (IFolderFolder ** resultFolder))318 Z7_COM7F_IMF(CRootFolder::BindToParentFolder(IFolderFolder **resultFolder))
319 {
320 *resultFolder = NULL;
321 return S_OK;
322 }
323
324 IMP_IFolderFolder_Props(CRootFolder)
325
Z7_COM7F_IMF(CRootFolder::GetFolderProperty (PROPID propID,PROPVARIANT * value))326 Z7_COM7F_IMF(CRootFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
327 {
328 NCOM::CPropVariant prop;
329 switch (propID)
330 {
331 case kpidType: prop = "RootFolder"; break;
332 case kpidPath: prop = ""; break;
333 }
334 prop.Detach(value);
335 return S_OK;
336 }
337
Z7_COM7F_IMF(CRootFolder::GetSystemIconIndex (UInt32 index,Int32 * iconIndex))338 Z7_COM7F_IMF(CRootFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
339 {
340 *iconIndex = _iconIndices[index];
341 return S_OK;
342 }
343