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