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