1 /*
2  *    Virtual MyDocuments Folder
3  *
4  *    Copyright 2007    Johannes Anderwald
5  *    Copyright 2009    Andrew Hill
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <precomp.h>
23 
24 WINE_DEFAULT_DEBUG_CHANNEL (mydocs);
25 
26 CMyDocsFolder::CMyDocsFolder()
27 {
28     m_pidlInner = NULL;
29 }
30 
31 CMyDocsFolder::~CMyDocsFolder()
32 {
33     if(m_pidlInner)
34         SHFree(m_pidlInner);
35 }
36 
37 HRESULT WINAPI CMyDocsFolder::FinalConstruct()
38 {
39     m_pidlInner = _ILCreateMyDocuments();
40 
41     if (!m_pidlInner)
42         return E_OUTOFMEMORY;
43 
44     return S_OK;
45 }
46 
47 HRESULT CMyDocsFolder::EnsureFolder()
48 {
49     ATLASSERT(m_pidlInner);
50 
51     if (m_pisfInner)
52         return S_OK;
53 
54 
55     HRESULT hr = SHELL32_CoCreateInitSF(m_pidlInner,
56                                         &CLSID_ShellFSFolder,
57                                         CSIDL_PERSONAL,
58                                         IID_PPV_ARG(IShellFolder2, &m_pisfInner));
59 
60     if (FAILED_UNEXPECTEDLY(hr))
61         return hr;
62 
63     return S_OK;
64 }
65 
66 HRESULT WINAPI CMyDocsFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
67         ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
68 {
69     HRESULT hr = EnsureFolder();
70     if (FAILED(hr))
71         return hr;
72 
73     return m_pisfInner->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
74 }
75 
76 HRESULT WINAPI CMyDocsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
77 {
78     HRESULT hr = EnsureFolder();
79     if (FAILED(hr))
80         return hr;
81 
82     return m_pisfInner->EnumObjects(hwndOwner, dwFlags, ppEnumIDList);
83 }
84 
85 HRESULT WINAPI CMyDocsFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
86 {
87     HRESULT hr = EnsureFolder();
88     if (FAILED(hr))
89         return hr;
90 
91     return m_pisfInner->BindToObject(pidl, pbcReserved, riid, ppvOut);
92 }
93 
94 HRESULT WINAPI CMyDocsFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
95 {
96     HRESULT hr = EnsureFolder();
97     if (FAILED(hr))
98         return hr;
99 
100     return m_pisfInner->BindToStorage(pidl, pbcReserved, riid, ppvOut);
101 }
102 
103 HRESULT WINAPI CMyDocsFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
104 {
105     HRESULT hr = EnsureFolder();
106     if (FAILED(hr))
107         return hr;
108 
109     return m_pisfInner->CompareIDs(lParam, pidl1, pidl2);
110 }
111 
112 HRESULT WINAPI CMyDocsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
113 {
114     HRESULT hr = EnsureFolder();
115     if (FAILED(hr))
116         return hr;
117 
118     return m_pisfInner->CreateViewObject(hwndOwner, riid, ppvOut);
119 }
120 
121 HRESULT WINAPI CMyDocsFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
122 {
123     static const DWORD dwMyDocumentsAttributes =
124         SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_CANCOPY |
125         SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
126 
127     HRESULT hr = EnsureFolder();
128     if (FAILED(hr))
129         return hr;
130 
131     if(cidl)
132         return m_pisfInner->GetAttributesOf(cidl, apidl, rgfInOut);
133 
134     if (!rgfInOut)
135         return E_INVALIDARG;
136 
137     if (*rgfInOut == 0)
138         *rgfInOut = ~0;
139 
140     *rgfInOut &= dwMyDocumentsAttributes;
141 
142     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
143     *rgfInOut &= ~SFGAO_VALIDATE;
144 
145     return S_OK;
146 }
147 
148 HRESULT WINAPI CMyDocsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
149         REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
150 {
151     HRESULT hr = EnsureFolder();
152     if (FAILED(hr))
153         return hr;
154 
155     return m_pisfInner->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
156 }
157 
158 HRESULT WINAPI CMyDocsFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
159 {
160     if (!strRet || !pidl)
161         return E_INVALIDARG;
162 
163     HRESULT hr = EnsureFolder();
164     if (FAILED(hr))
165         return hr;
166 
167     /* If we got an fs item just forward to the fs folder */
168     if (!_ILIsSpecialFolder(pidl))
169         return m_pisfInner->GetDisplayNameOf(pidl, dwFlags, strRet);
170 
171     /* The caller wants our path. Let fs folder handle it */
172     if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
173         (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
174     {
175         /* Give an empty pidl to the fs folder to make it tell us its path */
176         if (pidl->mkid.cb)
177             pidl = ILGetNext(pidl);
178         return m_pisfInner->GetDisplayNameOf(pidl, dwFlags, strRet);
179     }
180 
181     ERR("Got empty pidl without SHGDN_FORPARSING\n");
182     return E_INVALIDARG;
183 }
184 
185 HRESULT WINAPI CMyDocsFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,    /* simple pidl */
186         LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
187 {
188     HRESULT hr = EnsureFolder();
189     if (FAILED(hr))
190         return hr;
191 
192     return m_pisfInner->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
193 }
194 
195 HRESULT WINAPI CMyDocsFolder::GetDefaultSearchGUID(GUID *pguid)
196 {
197     HRESULT hr = EnsureFolder();
198     if (FAILED(hr))
199         return hr;
200 
201     return m_pisfInner->GetDefaultSearchGUID(pguid);
202 }
203 
204 HRESULT WINAPI CMyDocsFolder::EnumSearches(IEnumExtraSearch ** ppenum)
205 {
206     HRESULT hr = EnsureFolder();
207     if (FAILED(hr))
208         return hr;
209 
210     return m_pisfInner->EnumSearches(ppenum);
211 }
212 
213 HRESULT WINAPI CMyDocsFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
214 {
215     HRESULT hr = EnsureFolder();
216     if (FAILED(hr))
217         return hr;
218 
219     return m_pisfInner->GetDefaultColumn(dwRes, pSort, pDisplay);
220 }
221 
222 HRESULT WINAPI CMyDocsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
223 {
224     HRESULT hr = EnsureFolder();
225     if (FAILED(hr))
226         return hr;
227 
228     return m_pisfInner->GetDefaultColumnState(iColumn, pcsFlags);
229 }
230 
231 HRESULT WINAPI CMyDocsFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
232 {
233     HRESULT hr = EnsureFolder();
234     if (FAILED(hr))
235         return hr;
236 
237     return m_pisfInner->GetDetailsEx(pidl, pscid, pv);
238 }
239 
240 HRESULT WINAPI CMyDocsFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
241 {
242     HRESULT hr = EnsureFolder();
243     if (FAILED(hr))
244         return hr;
245 
246     return m_pisfInner->GetDetailsOf(pidl, iColumn, psd);
247 }
248 
249 HRESULT WINAPI CMyDocsFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
250 {
251     HRESULT hr = EnsureFolder();
252     if (FAILED(hr))
253         return hr;
254 
255     return m_pisfInner->MapColumnToSCID(column, pscid);
256 }
257 
258 HRESULT WINAPI CMyDocsFolder::GetClassID(CLSID *lpClassId)
259 {
260     if (!lpClassId)
261         return E_POINTER;
262 
263     memcpy(lpClassId, &CLSID_MyDocuments, sizeof(GUID));
264 
265     return S_OK;
266 }
267 
268 HRESULT WINAPI CMyDocsFolder::Initialize(PCIDLIST_ABSOLUTE pidl)
269 {
270     if (m_pisfInner)
271         return E_INVALIDARG;
272 
273     if (m_pidlInner)
274         SHFree(m_pidlInner);
275 
276     m_pidlInner = ILClone(pidl);
277 
278     if (!m_pidlInner)
279         return E_OUTOFMEMORY;
280 
281     return EnsureFolder();
282 }
283 
284 HRESULT WINAPI CMyDocsFolder::GetCurFolder(PIDLIST_ABSOLUTE *pidl)
285 {
286     if (!pidl)
287         return E_POINTER;
288     *pidl = ILClone(m_pidlInner);
289     return S_OK;
290 }
291