1 /*
2  * PROJECT:     ReactOS Compatibility Layer Shell Extension
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     CLayerUIPropPage implementation
5  * COPYRIGHT:   Copyright 2015-2017 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 #include <shlwapi.h>
11 #include <shellapi.h>
12 #include <shellutils.h>
13 #include <strsafe.h>
14 #include <apphelp.h>
15 #include <windowsx.h>
16 #include <sfc.h>
17 
18 const GUID CLSID_CLayerUIPropPage = { 0x513D916F, 0x2A8E, 0x4F51, { 0xAE, 0xAB, 0x0C, 0xBC, 0x76, 0xFB, 0x1A, 0xF8 } };
19 #define ACP_WNDPROP L"{513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8}.Prop"
20 
21 #define GPLK_USER 1
22 #define GPLK_MACHINE 2
23 #define MAX_LAYER_LENGTH 256
24 
25 static struct {
26     const PCWSTR Display;
27     const PCWSTR Name;
28 } g_CompatModes[] = {
29     { L"Windows 95", L"WIN95" },
30     { L"Windows 98/ME", L"WIN98" },
31     { L"Windows NT 4.0 (SP5)", L"NT4SP5" },
32     { L"Windows 2000", L"WIN2000" },
33     { L"Windows XP (SP2)", L"WINXPSP2" },
34     { L"Windows XP (SP3)", L"WINXPSP3" },
35     { L"Windows Server 2003 (SP1)", L"WINSRV03SP1" },
36 #if 0
37     { L"Windows Server 2008 (SP1)", L"WINSRV08SP1" },
38     { L"Windows Vista", L"VISTARTM" },
39     { L"Windows Vista (SP1)", L"VISTASP1" },
40     { L"Windows Vista (SP2)", L"VISTASP2" },
41     { L"Windows 7", L"WIN7RTM" },
42 #endif
43     { NULL, NULL }
44 };
45 
46 static struct {
47     const PCWSTR Name;
48     DWORD Id;
49 } g_Layers[] = {
50     { L"256COLOR", IDC_CHKRUNIN256COLORS },
51     { L"640X480", IDC_CHKRUNIN640480RES },
52     { L"DISABLETHEMES", IDC_CHKDISABLEVISUALTHEMES },
53 #if 0
54     { L"DISABLEDWM", IDC_??, TRUE },
55     { L"HIGHDPIAWARE", IDC_??, TRUE },
56     { L"RUNASADMIN", IDC_??, TRUE },
57 #endif
58     { NULL, 0 }
59 };
60 
61 static const WCHAR* g_AllowedExtensions[] = {
62     L".exe",
63     L".msi",
64     L".pif",
65     L".bat",
66     L".cmd",
67     0
68 };
69 
70 
71 void ACDBG_FN(PCSTR FunctionName, PCWSTR Format, ...)
72 {
73     WCHAR Buffer[512];
74     WCHAR* Current = Buffer;
75     size_t Length = _countof(Buffer);
76 
77     StringCchPrintfExW(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, L"[%-20S] ", FunctionName);
78     va_list ArgList;
79     va_start(ArgList, Format);
80     StringCchVPrintfExW(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
81     va_end(ArgList);
82     OutputDebugStringW(Buffer);
83 }
84 
85 #define ACDBG(fmt, ...)  ACDBG_FN(__FUNCTION__, fmt, ##__VA_ARGS__ )
86 
87 
88 
89 CLayerUIPropPage::CLayerUIPropPage()
90 : m_IsSfcProtected(FALSE)
91 , m_AllowPermLayer(FALSE)
92 , m_LayerQueryFlags(GPLK_USER)  /* TODO: When do we read from HKLM? */
93 , m_RegistryOSMode(0)
94 , m_OSMode(0)
95 , m_RegistryEnabledLayers(0)
96 , m_EnabledLayers(0)
97 {
98 }
99 
100 CLayerUIPropPage::~CLayerUIPropPage()
101 {
102 }
103 
104 HRESULT CLayerUIPropPage::InitFile(PCWSTR Filename)
105 {
106     CString ExpandedFilename;
107     DWORD dwRequired = ExpandEnvironmentStringsW(Filename, NULL, 0);
108     if (dwRequired > 0)
109     {
110         LPWSTR Buffer = ExpandedFilename.GetBuffer(dwRequired);
111         DWORD dwReturned = ExpandEnvironmentStringsW(Filename, Buffer, dwRequired);
112         if (dwRequired == dwReturned)
113         {
114             ExpandedFilename.ReleaseBufferSetLength(dwReturned - 1);
115             ACDBG(L"Expanded '%s' => '%s'\r\n", Filename, (PCWSTR)ExpandedFilename);
116         }
117         else
118         {
119             ExpandedFilename.ReleaseBufferSetLength(0);
120             ExpandedFilename = Filename;
121             ACDBG(L"Failed during expansion '%s'\r\n", Filename);
122         }
123     }
124     else
125     {
126         ACDBG(L"Failed to expand '%s'\r\n", Filename);
127         ExpandedFilename = Filename;
128     }
129     PCWSTR pwszExt = PathFindExtensionW(ExpandedFilename);
130     if (!pwszExt)
131     {
132         ACDBG(L"Failed to find an extension: '%s'\r\n", (PCWSTR)ExpandedFilename);
133         return E_FAIL;
134     }
135     if (!wcsicmp(pwszExt, L".lnk"))
136     {
137         WCHAR Buffer[MAX_PATH];
138         if (!GetExeFromLnk(ExpandedFilename, Buffer, _countof(Buffer)))
139         {
140             ACDBG(L"Failed to read link target from: '%s'\r\n", (PCWSTR)ExpandedFilename);
141             return E_FAIL;
142         }
143         if (!wcsicmp(Buffer, ExpandedFilename))
144         {
145             ACDBG(L"Link redirects to itself: '%s'\r\n", (PCWSTR)ExpandedFilename);
146             return E_FAIL;
147         }
148         return InitFile(Buffer);
149     }
150 
151     CString tmp;
152     if (tmp.GetEnvironmentVariable(L"SystemRoot"))
153     {
154         tmp += L"\\System32";
155         if (ExpandedFilename.GetLength() >= tmp.GetLength() &&
156             ExpandedFilename.Left(tmp.GetLength()).MakeLower() == tmp.MakeLower())
157         {
158             ACDBG(L"Ignoring System32: %s\r\n", (PCWSTR)ExpandedFilename);
159             return E_FAIL;
160         }
161         tmp.GetEnvironmentVariable(L"SystemRoot");
162         tmp += L"\\WinSxs";
163         if (ExpandedFilename.GetLength() >= tmp.GetLength() &&
164             ExpandedFilename.Left(tmp.GetLength()).MakeLower() == tmp.MakeLower())
165         {
166             ACDBG(L"Ignoring WinSxs: %s\r\n", (PCWSTR)ExpandedFilename);
167             return E_FAIL;
168         }
169     }
170 
171     for (size_t n = 0; g_AllowedExtensions[n]; ++n)
172     {
173         if (!wcsicmp(g_AllowedExtensions[n], pwszExt))
174         {
175             m_Filename = ExpandedFilename;
176             ACDBG(L"Got: %s\r\n", (PCWSTR)ExpandedFilename);
177             m_IsSfcProtected = SfcIsFileProtected(NULL, m_Filename);
178             m_AllowPermLayer = AllowPermLayer(ExpandedFilename);
179             return S_OK;
180         }
181     }
182     ACDBG(L"Extension not included: '%s'\r\n", pwszExt);
183     return E_FAIL;
184 }
185 
186 static BOOL GetLayerInfo(PCWSTR Filename, DWORD QueryFlags, PDWORD OSMode, PDWORD Enabledlayers, CSimpleArray<CString>& customLayers)
187 {
188     WCHAR wszLayers[MAX_LAYER_LENGTH] = { 0 };
189     DWORD dwBytes = sizeof(wszLayers);
190 
191     *OSMode = *Enabledlayers = 0;
192     customLayers.RemoveAll();
193     if (!SdbGetPermLayerKeys(Filename, wszLayers, &dwBytes, QueryFlags))
194         return FALSE;
195 
196     for (PWCHAR Layer = wcstok(wszLayers, L" "); Layer; Layer = wcstok(NULL, L" "))
197     {
198         size_t n;
199         for (n = 0; g_Layers[n].Name; ++n)
200         {
201             if (!wcsicmp(g_Layers[n].Name, Layer))
202             {
203                 *Enabledlayers |= (1<<n);
204                 break;
205             }
206         }
207         /* Did we find it? */
208         if (g_Layers[n].Name)
209             continue;
210 
211         for (n = 0; g_CompatModes[n].Name; ++n)
212         {
213             if (!wcsicmp(g_CompatModes[n].Name, Layer))
214             {
215                 *OSMode = n+1;
216                 break;
217             }
218         }
219         /* Did we find it? */
220         if (g_CompatModes[n].Name)
221             continue;
222 
223         /* Must be a 'custom' layer */
224         customLayers.Add(Layer);
225     }
226     return TRUE;
227 }
228 
229 int CLayerUIPropPage::OnSetActive()
230 {
231     if (!GetLayerInfo(m_Filename, m_LayerQueryFlags, &m_RegistryOSMode, &m_RegistryEnabledLayers, m_RegistryCustomLayers))
232         m_RegistryOSMode = m_RegistryEnabledLayers = 0;
233 
234     for (size_t n = 0; g_Layers[n].Name; ++n)
235         CheckDlgButton(g_Layers[n].Id, (m_RegistryEnabledLayers & (1<<n)) ? BST_CHECKED : BST_UNCHECKED);
236 
237     CheckDlgButton(IDC_CHKRUNCOMPATIBILITY, m_RegistryOSMode ? BST_CHECKED : BST_UNCHECKED);
238 
239     if (m_RegistryOSMode)
240         ComboBox_SetCurSel(GetDlgItem(IDC_COMPATIBILITYMODE), m_RegistryOSMode-1);
241 
242     m_CustomLayers = m_RegistryCustomLayers;
243 
244     /* TODO: visualize 'custom' layers! */
245 
246     UpdateControls();
247 
248     return 0;
249 }
250 
251 
252 static BOOL ArrayEquals(const CSimpleArray<CString>& lhs, const CSimpleArray<CString>& rhs)
253 {
254     if (lhs.GetSize() != rhs.GetSize())
255         return FALSE;
256 
257     for (int n = 0; n < lhs.GetSize(); ++n)
258     {
259         if (lhs[n] != rhs[n])
260             return FALSE;
261     }
262     return TRUE;
263 }
264 
265 BOOL CLayerUIPropPage::HasChanges() const
266 {
267     if (m_RegistryEnabledLayers != m_EnabledLayers)
268         return TRUE;
269 
270     if (m_RegistryOSMode != m_OSMode)
271         return TRUE;
272 
273     if (!ArrayEquals(m_RegistryCustomLayers, m_CustomLayers))
274         return TRUE;
275 
276     return FALSE;
277 }
278 
279 int CLayerUIPropPage::OnApply()
280 {
281     if (HasChanges())
282     {
283         BOOL bMachine = m_LayerQueryFlags == GPLK_MACHINE;
284 
285         for (size_t n = 0; g_CompatModes[n].Name; ++n)
286             SetPermLayerState(m_Filename, g_CompatModes[n].Name, 0, bMachine, (n+1) == m_OSMode);
287 
288         for (size_t n = 0; g_Layers[n].Name; ++n)
289         {
290             SetPermLayerState(m_Filename, g_Layers[n].Name, 0, bMachine, ((1<<n) & m_EnabledLayers) != 0);
291         }
292 
293         /* Disable all old values */
294         for (int j = 0; j < m_RegistryCustomLayers.GetSize(); j++)
295         {
296             SetPermLayerState(m_Filename, m_RegistryCustomLayers[j].GetString(), 0, bMachine, FALSE);
297         }
298 
299         /* Enable all new values */
300         for (int j = 0; j < m_CustomLayers.GetSize(); j++)
301         {
302             SetPermLayerState(m_Filename, m_CustomLayers[j].GetString(), 0, bMachine, TRUE);
303         }
304 
305         SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, (PCWSTR)m_Filename, NULL);
306     }
307 
308     return PSNRET_NOERROR;
309 }
310 
311 LRESULT CLayerUIPropPage::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
312 {
313     HWND cboMode = GetDlgItem(IDC_COMPATIBILITYMODE);
314     for (size_t n = 0; g_CompatModes[n].Display; ++n)
315         ComboBox_AddString(cboMode, g_CompatModes[n].Display);
316     ComboBox_SetCurSel(cboMode, 5);
317 
318     CComBSTR explanation;
319     if (!m_AllowPermLayer)
320     {
321         explanation.LoadString(g_hModule, IDS_FAILED_NETWORK);
322         DisableControls();
323         ACDBG(L"AllowPermLayer returned FALSE\r\n");
324     }
325     else if (m_IsSfcProtected)
326     {
327         explanation.LoadString(g_hModule, IDS_FAILED_PROTECTED);
328         DisableControls();
329         ACDBG(L"Protected OS file\r\n");
330     }
331     else
332     {
333         return TRUE;
334     }
335     SetDlgItemTextW(IDC_EXPLANATION, explanation);
336     return TRUE;
337 }
338 
339 INT_PTR CLayerUIPropPage::DisableControls()
340 {
341     ::EnableWindow(GetDlgItem(IDC_COMPATIBILITYMODE), 0);
342     ::EnableWindow(GetDlgItem(IDC_CHKRUNCOMPATIBILITY), 0);
343     for (size_t n = 0; g_Layers[n].Name; ++n)
344         ::EnableWindow(GetDlgItem(g_Layers[n].Id), 0);
345     ::EnableWindow(GetDlgItem(IDC_EDITCOMPATIBILITYMODES), 0);
346     return TRUE;
347 }
348 
349 void CLayerUIPropPage::UpdateControls()
350 {
351     m_OSMode = 0, m_EnabledLayers = 0;
352     BOOL ModeEnabled = IsDlgButtonChecked(IDC_CHKRUNCOMPATIBILITY);
353     if (ModeEnabled)
354         m_OSMode = ComboBox_GetCurSel(GetDlgItem(IDC_COMPATIBILITYMODE))+1;
355     ::EnableWindow(GetDlgItem(IDC_COMPATIBILITYMODE), ModeEnabled);
356 
357     for (size_t n = 0; g_Layers[n].Name; ++n)
358     {
359         m_EnabledLayers |= IsDlgButtonChecked(g_Layers[n].Id) ? (1<<n) : 0;
360         ::ShowWindow(GetDlgItem(g_Layers[n].Id), SW_SHOW);
361     }
362 
363     SetModified(HasChanges());
364 }
365 
366 LRESULT CLayerUIPropPage::OnCtrlCommand(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
367 {
368     UpdateControls();
369     return 0;
370 }
371 
372 LRESULT CLayerUIPropPage::OnEditModes(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
373 {
374     if (DialogBoxParam(g_hModule, MAKEINTRESOURCE(IDD_EDITCOMPATIBILITYMODES), m_hWnd, EditModesProc, (LPARAM)this) == IDOK)
375         UpdateControls();
376     return 0;
377 }
378 
379 LRESULT CLayerUIPropPage::OnClickNotify(INT uCode, LPNMHDR hdr, BOOL& bHandled)
380 {
381     if (hdr->idFrom == IDC_INFOLINK)
382         ShellExecute(NULL, L"open", L"https://www.reactos.org/forum/viewforum.php?f=4", NULL, NULL, SW_SHOW);
383     return 0;
384 }
385 
386 static void ListboxChanged(HWND hWnd)
387 {
388     int Sel = ListBox_GetCurSel(GetDlgItem(hWnd, IDC_COMPATIBILITYMODE));
389     EnableWindow(GetDlgItem(hWnd, IDC_EDIT), Sel >= 0);
390     EnableWindow(GetDlgItem(hWnd, IDC_DELETE), Sel >= 0);
391 }
392 
393 static void OnAdd(HWND hWnd)
394 {
395     HWND Combo = GetDlgItem(hWnd, IDC_NEWCOMPATIBILITYMODE);
396 
397     int Length = ComboBox_GetTextLength(Combo);
398     CComBSTR Str(Length);
399     ComboBox_GetText(Combo, Str, Length+1);
400     HWND List = GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
401     int Index = ListBox_FindStringExact(List, -1, Str);
402     if (Index == LB_ERR)
403         Index = ListBox_AddString(List, Str);
404     ListBox_SetCurSel(List, Index);
405     ListboxChanged(hWnd);
406     ComboBox_SetCurSel(Combo, -1);
407     SetFocus(Combo);
408 }
409 
410 static BOOL ComboHasData(HWND hWnd)
411 {
412     HWND Combo = GetDlgItem(hWnd, IDC_NEWCOMPATIBILITYMODE);
413     if (ComboBox_GetCurSel(Combo) >= 0)
414         return TRUE;
415     ULONG Len = ComboBox_GetTextLength(Combo);
416     return Len > 0;
417 }
418 
419 INT_PTR CALLBACK CLayerUIPropPage::EditModesProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
420 {
421     CLayerUIPropPage* page = NULL;
422 
423     switch (uMsg)
424     {
425     case WM_INITDIALOG:
426         page = (CLayerUIPropPage*)lParam;
427         page->AddRef();
428         ::SetProp(hWnd, ACP_WNDPROP, page);
429         {
430             HWND Combo = ::GetDlgItem(hWnd, IDC_NEWCOMPATIBILITYMODE);
431             CComObject<CLayerStringList> pList;
432 
433             while (TRUE)
434             {
435                 CComHeapPtr<OLECHAR> str;
436                 HRESULT hr = pList.Next(1, &str, NULL);
437                 if (hr != S_OK)
438                     break;
439                 ComboBox_AddString(Combo, str);
440             }
441 
442             HWND List = ::GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
443             for (int n = 0; n < page->m_CustomLayers.GetSize(); ++n)
444             {
445                 const WCHAR* Str = page->m_CustomLayers[n].GetString();
446                 int Index = ListBox_FindStringExact(List, -1, Str);
447                 if (Index == LB_ERR)
448                     Index = ListBox_AddString(List, Str);
449             }
450         }
451         break;
452     case WM_ENDSESSION:
453     case WM_DESTROY:
454         page = (CLayerUIPropPage*)::GetProp(hWnd, ACP_WNDPROP);
455         ::RemoveProp(hWnd, ACP_WNDPROP);
456         page->Release();
457         break;
458 
459     case WM_COMMAND:
460         switch(LOWORD(wParam))
461         {
462         case IDC_ADD:
463             OnAdd(hWnd);
464             break;
465         case IDC_EDIT:
466         {
467             HWND List = ::GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
468             int Cur = ListBox_GetCurSel(List);
469             int Length = ListBox_GetTextLen(List, Cur);
470             CComBSTR Str(Length);
471             ListBox_GetText(List, Cur, Str);
472             ListBox_DeleteString(List, Cur);
473             HWND Combo = ::GetDlgItem(hWnd, IDC_NEWCOMPATIBILITYMODE);
474             ComboBox_SetCurSel(Combo, -1);
475             ::SetWindowText(Combo,Str);
476             ListboxChanged(hWnd);
477             ComboBox_SetEditSel(Combo, 30000, 30000);
478             ::SetFocus(Combo);
479         }
480             break;
481         case IDC_DELETE:
482         {
483             HWND List = ::GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
484             ListBox_DeleteString(List, ListBox_GetCurSel(List));
485             ListboxChanged(hWnd);
486         }
487             break;
488         case IDC_COMPATIBILITYMODE:
489             ListboxChanged(hWnd);
490             break;
491         case IDC_NEWCOMPATIBILITYMODE:
492         {
493             ::EnableWindow(::GetDlgItem(hWnd, IDC_ADD), ComboHasData(hWnd));
494         }
495             break;
496         case IDOK:
497             /* Copy from list! */
498         {
499             if (ComboHasData(hWnd))
500             {
501                 CComBSTR question, title;
502                 title.LoadString(g_hModule, IDS_TABTITLE);
503                 question.LoadString(g_hModule, IDS_YOU_DID_NOT_ADD);
504                 int result = ::MessageBoxW(hWnd, question, title, MB_YESNOCANCEL | MB_ICONQUESTION);
505                 switch (result)
506                 {
507                 case IDYES:
508                     OnAdd(hWnd);
509                     break;
510                 case IDNO:
511                     break;
512                 case IDCANCEL:
513                     return FALSE;
514                 }
515             }
516 
517             page = (CLayerUIPropPage*)::GetProp(hWnd, ACP_WNDPROP);
518 
519             HWND List = ::GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
520             int Count = ListBox_GetCount(List);
521             page->m_CustomLayers.RemoveAll();
522             for (int Cur = 0; Cur < Count; ++Cur)
523             {
524                 int Length = ListBox_GetTextLen(List, Cur);
525                 CString Str;
526                 LPWSTR Buffer = Str.GetBuffer(Length + 1);
527                 ListBox_GetText(List, Cur, Buffer);
528                 Str.ReleaseBuffer(Length);
529                 page->m_CustomLayers.Add(Str);
530             }
531         }
532         /* Fall trough */
533         case IDCANCEL:
534             ::EndDialog(hWnd, LOWORD(wParam));
535             break;
536         }
537         break;
538     case WM_CLOSE:
539         ::EndDialog(hWnd, IDCANCEL);
540         break;
541     }
542     return FALSE;
543 }
544 
545 static BOOL DisableShellext()
546 {
547     HKEY hkey;
548     LSTATUS ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Policies\\Microsoft\\Windows\\AppCompat", 0, KEY_QUERY_VALUE, &hkey);
549     BOOL Disable = FALSE;
550     if (ret == ERROR_SUCCESS)
551     {
552         DWORD dwValue = 0;
553         DWORD type, size = sizeof(dwValue);
554         ret = RegQueryValueExW(hkey, L"DisableEngine", NULL, &type, (PBYTE)&dwValue, &size);
555         if (ret == ERROR_SUCCESS && type == REG_DWORD)
556         {
557             Disable = !!dwValue;
558         }
559         if (!Disable)
560         {
561             size = sizeof(dwValue);
562             ret = RegQueryValueExW(hkey, L"DisablePropPage", NULL, &type, (PBYTE)&dwValue, &size);
563             if (ret == ERROR_SUCCESS && type == REG_DWORD)
564             {
565                 Disable = !!dwValue;
566             }
567         }
568 
569         RegCloseKey(hkey);
570     }
571     return Disable;
572 }
573 
574 STDMETHODIMP CLayerUIPropPage::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hkeyProgID)
575 {
576     FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
577     STGMEDIUM stg;
578 
579     if (DisableShellext())
580         return E_ACCESSDENIED;
581 
582     HRESULT hr = pDataObj->GetData(&etc, &stg);
583     if (FAILED(hr))
584     {
585         ACDBG(L"Failed to retrieve Data from pDataObj.\r\n");
586         return E_INVALIDARG;
587     }
588     hr = E_FAIL;
589     HDROP hdrop = (HDROP)GlobalLock(stg.hGlobal);
590     if (hdrop)
591     {
592         UINT uNumFiles = DragQueryFileW(hdrop, 0xFFFFFFFF, NULL, 0);
593         if (uNumFiles == 1)
594         {
595             WCHAR szFile[MAX_PATH * 2];
596             if (DragQueryFileW(hdrop, 0, szFile, _countof(szFile)))
597             {
598                 this->AddRef();
599                 hr = InitFile(szFile);
600             }
601             else
602             {
603                 ACDBG(L"Failed to query the file.\r\n");
604             }
605         }
606         else
607         {
608             ACDBG(L"Invalid number of files: %d\r\n", uNumFiles);
609         }
610         GlobalUnlock(stg.hGlobal);
611     }
612     else
613     {
614         ACDBG(L"Could not lock stg.hGlobal\r\n");
615     }
616     ReleaseStgMedium(&stg);
617     return hr;
618 }
619