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