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