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