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 } 652