1 /* 2 * Control panel folder 3 * 4 * Copyright 2003 Martin Fuchs 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(shell); 25 26 /*********************************************************************** 27 * control panel implementation in shell namespace 28 */ 29 30 class CControlPanelEnum : 31 public CEnumIDListBase 32 { 33 public: 34 CControlPanelEnum(); 35 ~CControlPanelEnum(); 36 HRESULT WINAPI Initialize(DWORD dwFlags, IEnumIDList* pRegEnumerator); 37 BOOL RegisterCPanelApp(LPCWSTR path); 38 int RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath); 39 BOOL CreateCPanelEnumList(DWORD dwFlags); 40 41 BEGIN_COM_MAP(CControlPanelEnum) 42 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 43 END_COM_MAP() 44 }; 45 46 /*********************************************************************** 47 * IShellFolder [ControlPanel] implementation 48 */ 49 50 static const shvheader ControlPanelSFHeader[] = { 51 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},/*FIXME*/ 52 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 80},/*FIXME*/ 53 }; 54 55 enum controlpanel_columns 56 { 57 CONTROLPANEL_COL_NAME, 58 CONTROLPANEL_COL_COMMENT, 59 CONTROLPANEL_COL_COUNT, 60 }; 61 62 CControlPanelEnum::CControlPanelEnum() 63 { 64 } 65 66 CControlPanelEnum::~CControlPanelEnum() 67 { 68 } 69 70 HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags, IEnumIDList* pRegEnumerator) 71 { 72 if (CreateCPanelEnumList(dwFlags) == FALSE) 73 return E_FAIL; 74 AppendItemsFromEnumerator(pRegEnumerator); 75 return S_OK; 76 } 77 78 static LPITEMIDLIST _ILCreateCPanelApplet(LPCWSTR pszName, LPCWSTR pszDisplayName, LPCWSTR pszComment, int iIconIdx) 79 { 80 PIDLCPanelStruct *pCP; 81 LPITEMIDLIST pidl; 82 LPPIDLDATA pData; 83 int cchName, cchDisplayName, cchComment, cbData; 84 85 /* Calculate lengths of given strings */ 86 cchName = wcslen(pszName); 87 cchDisplayName = wcslen(pszDisplayName); 88 cchComment = wcslen(pszComment); 89 90 /* Allocate PIDL */ 91 cbData = sizeof(pidl->mkid.cb) + sizeof(pData->type) + sizeof(pData->u.cpanel) - sizeof(pData->u.cpanel.szName) 92 + (cchName + cchDisplayName + cchComment + 3) * sizeof(WCHAR); 93 pidl = (LPITEMIDLIST)SHAlloc(cbData + sizeof(WORD)); 94 if (!pidl) 95 return NULL; 96 97 /* Copy data to allocated memory */ 98 pidl->mkid.cb = cbData; 99 pData = (PIDLDATA *)pidl->mkid.abID; 100 pData->type = PT_CPLAPPLET; 101 102 pCP = &pData->u.cpanel; 103 pCP->dummy = 0; 104 pCP->iconIdx = iIconIdx; 105 wcscpy(pCP->szName, pszName); 106 pCP->offsDispName = cchName + 1; 107 wcscpy(pCP->szName + pCP->offsDispName, pszDisplayName); 108 pCP->offsComment = pCP->offsDispName + cchDisplayName + 1; 109 wcscpy(pCP->szName + pCP->offsComment, pszComment); 110 111 /* Add PIDL NULL terminator */ 112 *(WORD*)(pCP->szName + pCP->offsComment + cchComment + 1) = 0; 113 114 pcheck(pidl); 115 116 return pidl; 117 } 118 119 /************************************************************************** 120 * _ILGetCPanelPointer() 121 * gets a pointer to the control panel struct stored in the pidl 122 */ 123 static PIDLCPanelStruct *_ILGetCPanelPointer(LPCITEMIDLIST pidl) 124 { 125 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 126 127 if (pdata && pdata->type == PT_CPLAPPLET) 128 return (PIDLCPanelStruct *) & (pdata->u.cpanel); 129 130 return NULL; 131 } 132 133 HRESULT CCPLExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut) 134 { 135 PIDLCPanelStruct *pData = _ILGetCPanelPointer(pidl); 136 if (!pData) 137 return E_FAIL; 138 139 CComPtr<IDefaultExtractIconInit> initIcon; 140 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon)); 141 if (FAILED_UNEXPECTEDLY(hr)) 142 return hr; 143 144 initIcon->SetNormalIcon(pData->szName, (int)pData->iconIdx != -1 ? pData->iconIdx : 0); 145 146 return initIcon->QueryInterface(riid, ppvOut); 147 } 148 149 BOOL CControlPanelEnum::RegisterCPanelApp(LPCWSTR wpath) 150 { 151 CPlApplet* applet = Control_LoadApplet(0, wpath, NULL); 152 int iconIdx; 153 154 if (applet) 155 { 156 for (UINT i = 0; i < applet->count; ++i) 157 { 158 if (applet->info[i].idIcon > 0) 159 iconIdx = -applet->info[i].idIcon; /* negative icon index instead of icon number */ 160 else 161 iconIdx = 0; 162 163 LPITEMIDLIST pidl = _ILCreateCPanelApplet(wpath, 164 applet->info[i].name, 165 applet->info[i].info, 166 iconIdx); 167 168 if (pidl) 169 AddToEnumList(pidl); 170 } 171 Control_UnloadApplet(applet); 172 } 173 return TRUE; 174 } 175 176 int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath) 177 { 178 WCHAR name[MAX_PATH]; 179 WCHAR value[MAX_PATH]; 180 HKEY hkey; 181 182 int cnt = 0; 183 184 if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS) 185 { 186 int idx = 0; 187 188 for(; ; idx++) 189 { 190 DWORD nameLen = MAX_PATH; 191 DWORD valueLen = MAX_PATH; 192 WCHAR buffer[MAX_PATH]; 193 194 if (RegEnumValueW(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS) 195 break; 196 197 if (ExpandEnvironmentStringsW(value, buffer, MAX_PATH)) 198 { 199 wcscpy(value, buffer); 200 } 201 202 if (RegisterCPanelApp(value)) 203 ++cnt; 204 } 205 RegCloseKey(hkey); 206 } 207 208 return cnt; 209 } 210 211 /************************************************************************** 212 * CControlPanelEnum::CreateCPanelEnumList() 213 */ 214 BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags) 215 { 216 WCHAR szPath[MAX_PATH]; 217 WIN32_FIND_DATAW wfd; 218 HANDLE hFile; 219 220 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags); 221 222 /* enumerate the control panel applets */ 223 if (dwFlags & SHCONTF_NONFOLDERS) 224 { 225 LPWSTR p; 226 227 GetSystemDirectoryW(szPath, MAX_PATH); 228 p = PathAddBackslashW(szPath); 229 wcscpy(p, L"*.cpl"); 230 231 hFile = FindFirstFileW(szPath, &wfd); 232 233 if (hFile != INVALID_HANDLE_VALUE) 234 { 235 do 236 { 237 if (!(dwFlags & SHCONTF_INCLUDEHIDDEN) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) 238 continue; 239 240 if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { 241 wcscpy(p, wfd.cFileName); 242 if (wcscmp(wfd.cFileName, L"ncpa.cpl")) 243 RegisterCPanelApp(szPath); 244 } 245 } while(FindNextFileW(hFile, &wfd)); 246 FindClose(hFile); 247 } 248 249 RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"); 250 RegisterRegistryCPanelApps(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"); 251 } 252 return TRUE; 253 } 254 255 CControlPanelFolder::CControlPanelFolder() 256 { 257 pidlRoot = NULL; /* absolute pidl */ 258 } 259 260 CControlPanelFolder::~CControlPanelFolder() 261 { 262 TRACE("-- destroying IShellFolder(%p)\n", this); 263 SHFree(pidlRoot); 264 } 265 266 /************************************************************************** 267 * CControlPanelFolder::ParseDisplayName 268 */ 269 HRESULT WINAPI CControlPanelFolder::ParseDisplayName( 270 HWND hwndOwner, 271 LPBC pbc, 272 LPOLESTR lpszDisplayName, 273 DWORD *pchEaten, 274 PIDLIST_RELATIVE *ppidl, 275 DWORD *pdwAttributes) 276 { 277 /* We only support parsing guid names */ 278 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes); 279 } 280 281 /************************************************************************** 282 * CControlPanelFolder::EnumObjects 283 */ 284 HRESULT WINAPI CControlPanelFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 285 { 286 CComPtr<IEnumIDList> pRegEnumerator; 287 m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator); 288 289 return ShellObjectCreatorInit<CControlPanelEnum>(dwFlags, pRegEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 290 } 291 292 /************************************************************************** 293 * CControlPanelFolder::BindToObject 294 */ 295 HRESULT WINAPI CControlPanelFolder::BindToObject( 296 PCUIDLIST_RELATIVE pidl, 297 LPBC pbcReserved, 298 REFIID riid, 299 LPVOID *ppvOut) 300 { 301 return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut); 302 } 303 304 /************************************************************************** 305 * CControlPanelFolder::BindToStorage 306 */ 307 HRESULT WINAPI CControlPanelFolder::BindToStorage( 308 PCUIDLIST_RELATIVE pidl, 309 LPBC pbcReserved, 310 REFIID riid, 311 LPVOID *ppvOut) 312 { 313 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut); 314 315 *ppvOut = NULL; 316 return E_NOTIMPL; 317 } 318 319 /************************************************************************** 320 * CControlPanelFolder::CompareIDs 321 */ 322 HRESULT WINAPI CControlPanelFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 323 { 324 /* Dont use SHELL32_CompareGuidItems because it would cause guid items to come first */ 325 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2)) 326 { 327 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2); 328 } 329 PIDLCPanelStruct *pData1 = _ILGetCPanelPointer(pidl1); 330 PIDLCPanelStruct *pData2 = _ILGetCPanelPointer(pidl2); 331 332 if (!pData1 || !pData2 || LOWORD(lParam) >= CONTROLPANEL_COL_COUNT) 333 return E_INVALIDARG; 334 335 int result; 336 switch(LOWORD(lParam)) 337 { 338 case CONTROLPANEL_COL_NAME: 339 result = wcsicmp(pData1->szName + pData1->offsDispName, pData2->szName + pData2->offsDispName); 340 break; 341 case CONTROLPANEL_COL_COMMENT: 342 result = wcsicmp(pData1->szName + pData1->offsComment, pData2->szName + pData2->offsComment); 343 break; 344 default: 345 ERR("Got wrong lParam!\n"); 346 return E_INVALIDARG; 347 } 348 349 return MAKE_COMPARE_HRESULT(result); 350 } 351 352 /************************************************************************** 353 * CControlPanelFolder::CreateViewObject 354 */ 355 HRESULT WINAPI CControlPanelFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut) 356 { 357 CComPtr<IShellView> pShellView; 358 HRESULT hr = E_INVALIDARG; 359 360 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid(&riid), ppvOut); 361 362 if (ppvOut) { 363 *ppvOut = NULL; 364 365 if (IsEqualIID(riid, IID_IDropTarget)) { 366 WARN("IDropTarget not implemented\n"); 367 hr = E_NOTIMPL; 368 } else if (IsEqualIID(riid, IID_IContextMenu)) { 369 WARN("IContextMenu not implemented\n"); 370 hr = E_NOTIMPL; 371 } else if (IsEqualIID(riid, IID_IShellView)) { 372 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; 373 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 374 } 375 } 376 TRACE("--(%p)->(interface=%p)\n", this, ppvOut); 377 return hr; 378 } 379 380 /************************************************************************** 381 * CControlPanelFolder::GetAttributesOf 382 */ 383 HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut) 384 { 385 HRESULT hr = S_OK; 386 static const DWORD dwControlPanelAttributes = 387 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK; 388 389 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", 390 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0); 391 392 if (!rgfInOut) 393 return E_INVALIDARG; 394 if (cidl && !apidl) 395 return E_INVALIDARG; 396 397 if (*rgfInOut == 0) 398 *rgfInOut = ~0; 399 400 if (!cidl) 401 { 402 *rgfInOut &= dwControlPanelAttributes; 403 } 404 else 405 { 406 while(cidl > 0 && *apidl) 407 { 408 pdump(*apidl); 409 if (_ILIsCPanelStruct(*apidl)) 410 *rgfInOut &= SFGAO_CANLINK; 411 else if (_ILIsSpecialFolder(*apidl)) 412 m_regFolder->GetAttributesOf(1, apidl, rgfInOut); 413 else 414 ERR("Got unknown pidl\n"); 415 apidl++; 416 cidl--; 417 } 418 } 419 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 420 *rgfInOut &= ~SFGAO_VALIDATE; 421 422 TRACE("-- result=0x%08x\n", *rgfInOut); 423 return hr; 424 } 425 426 /************************************************************************** 427 * CControlPanelFolder::GetUIObjectOf 428 * 429 * PARAMETERS 430 * HWND hwndOwner, //[in ] Parent window for any output 431 * UINT cidl, //[in ] array size 432 * LPCITEMIDLIST* apidl, //[in ] simple pidl array 433 * REFIID riid, //[in ] Requested Interface 434 * UINT* prgfInOut, //[ ] reserved 435 * LPVOID* ppvObject) //[out] Resulting Interface 436 * 437 */ 438 HRESULT WINAPI CControlPanelFolder::GetUIObjectOf(HWND hwndOwner, 439 UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) 440 { 441 LPVOID pObj = NULL; 442 HRESULT hr = E_INVALIDARG; 443 444 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", 445 this, hwndOwner, cidl, apidl, shdebugstr_guid(&riid), prgfInOut, ppvOut); 446 447 if (ppvOut) { 448 *ppvOut = NULL; 449 450 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1)) { 451 /* HACK: We should use callbacks from CDefaultContextMenu instead of creating one on our own */ 452 BOOL bHasCpl = FALSE; 453 for (UINT i = 0; i < cidl; i++) 454 { 455 if(_ILIsCPanelStruct(apidl[i])) 456 { 457 bHasCpl = TRUE; 458 } 459 } 460 461 if (bHasCpl) 462 hr = ShellObjectCreatorInit<CCPLItemMenu>(cidl, apidl, riid, &pObj); 463 else 464 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 465 } else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1)) { 466 hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 467 } else if ((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1)) { 468 if (_ILGetCPanelPointer(apidl[0])) 469 hr = CCPLExtractIcon_CreateInstance(this, apidl[0], riid, &pObj); 470 else 471 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 472 } else { 473 hr = E_NOINTERFACE; 474 } 475 476 if (SUCCEEDED(hr) && !pObj) 477 hr = E_OUTOFMEMORY; 478 479 *ppvOut = pObj; 480 } 481 TRACE("(%p)->hr=0x%08x\n", this, hr); 482 return hr; 483 } 484 485 /************************************************************************** 486 * CControlPanelFolder::GetDisplayNameOf 487 */ 488 HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 489 { 490 if (!pidl) 491 return S_FALSE; 492 493 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl); 494 495 if (pCPanel) 496 { 497 return SHSetStrRet(strRet, pCPanel->szName + pCPanel->offsDispName); 498 } 499 else if (_ILIsSpecialFolder(pidl)) 500 { 501 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet); 502 } 503 504 return E_FAIL; 505 } 506 507 /************************************************************************** 508 * CControlPanelFolder::SetNameOf 509 * Changes the name of a file object or subfolder, possibly changing its item 510 * identifier in the process. 511 * 512 * PARAMETERS 513 * HWND hwndOwner, //[in ] Owner window for output 514 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change 515 * LPCOLESTR lpszName, //[in ] the items new display name 516 * DWORD dwFlags, //[in ] SHGNO formatting flags 517 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned 518 */ 519 HRESULT WINAPI CControlPanelFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */ 520 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 521 { 522 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut); 523 return E_FAIL; 524 } 525 526 HRESULT WINAPI CControlPanelFolder::GetDefaultSearchGUID(GUID *pguid) 527 { 528 FIXME("(%p)\n", this); 529 return E_NOTIMPL; 530 } 531 532 HRESULT WINAPI CControlPanelFolder::EnumSearches(IEnumExtraSearch **ppenum) 533 { 534 FIXME("(%p)\n", this); 535 return E_NOTIMPL; 536 } 537 538 HRESULT WINAPI CControlPanelFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 539 { 540 TRACE("(%p)\n", this); 541 542 if (pSort) *pSort = 0; 543 if (pDisplay) *pDisplay = 0; 544 return S_OK; 545 } 546 547 HRESULT WINAPI CControlPanelFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 548 { 549 TRACE("(%p)\n", this); 550 551 if (!pcsFlags || iColumn >= CONTROLPANEL_COL_COUNT) 552 return E_INVALIDARG; 553 *pcsFlags = ControlPanelSFHeader[iColumn].colstate; 554 return S_OK; 555 } 556 557 HRESULT WINAPI CControlPanelFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) 558 { 559 FIXME("(%p)\n", this); 560 return E_NOTIMPL; 561 } 562 563 HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 564 { 565 if (!psd || iColumn >= CONTROLPANEL_COL_COUNT) 566 return E_INVALIDARG; 567 568 if (!pidl) 569 { 570 psd->fmt = ControlPanelSFHeader[iColumn].fmt; 571 psd->cxChar = ControlPanelSFHeader[iColumn].cxChar; 572 return SHSetStrRet(&psd->str, shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid); 573 } 574 else if (_ILIsSpecialFolder(pidl)) 575 { 576 return m_regFolder->GetDetailsOf(pidl, iColumn, psd); 577 } 578 else 579 { 580 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl); 581 582 if (!pCPanel) 583 return E_FAIL; 584 585 switch(iColumn) 586 { 587 case CONTROLPANEL_COL_NAME: 588 return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsDispName); 589 case CONTROLPANEL_COL_COMMENT: 590 return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsComment); 591 } 592 } 593 594 return E_FAIL; 595 } 596 597 HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 598 { 599 FIXME("(%p)\n", this); 600 return E_NOTIMPL; 601 } 602 603 /************************************************************************ 604 * CControlPanelFolder::GetClassID 605 */ 606 HRESULT WINAPI CControlPanelFolder::GetClassID(CLSID *lpClassId) 607 { 608 TRACE("(%p)\n", this); 609 610 if (!lpClassId) 611 return E_POINTER; 612 *lpClassId = CLSID_ControlPanel; 613 614 return S_OK; 615 } 616 617 /************************************************************************ 618 * CControlPanelFolder::Initialize 619 * 620 * NOTES: it makes no sense to change the pidl 621 */ 622 HRESULT WINAPI CControlPanelFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 623 { 624 if (pidlRoot) 625 SHFree((LPVOID)pidlRoot); 626 627 pidlRoot = ILClone(pidl); 628 629 /* Create the inner reg folder */ 630 HRESULT hr; 631 hr = CRegFolder_CreateInstance(&CLSID_ControlPanel, 632 pidlRoot, 633 L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", 634 L"ControlPanel", 635 IID_PPV_ARG(IShellFolder2, &m_regFolder)); 636 if (FAILED_UNEXPECTEDLY(hr)) 637 return hr; 638 639 return S_OK; 640 } 641 642 /************************************************************************** 643 * CControlPanelFolder::GetCurFolder 644 */ 645 HRESULT WINAPI CControlPanelFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 646 { 647 TRACE("(%p)->(%p)\n", this, pidl); 648 649 if (!pidl) 650 return E_POINTER; 651 *pidl = ILClone(pidlRoot); 652 return S_OK; 653 } 654 655 CCPLItemMenu::CCPLItemMenu() 656 { 657 m_apidl = NULL; 658 m_cidl = 0; 659 } 660 661 HRESULT WINAPI CCPLItemMenu::Initialize(UINT cidl, PCUITEMID_CHILD_ARRAY apidl) 662 { 663 m_cidl = cidl; 664 m_apidl = _ILCopyaPidl(apidl, m_cidl); 665 if (m_cidl && !m_apidl) 666 return E_OUTOFMEMORY; 667 668 return S_OK; 669 } 670 671 CCPLItemMenu::~CCPLItemMenu() 672 { 673 _ILFreeaPidl(m_apidl, m_cidl); 674 } 675 676 HRESULT WINAPI CCPLItemMenu::QueryContextMenu( 677 HMENU hMenu, 678 UINT indexMenu, 679 UINT idCmdFirst, 680 UINT idCmdLast, 681 UINT uFlags) 682 { 683 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst, MFT_STRING, MAKEINTRESOURCEW(IDS_OPEN), MFS_DEFAULT); 684 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDC_STATIC, MFT_SEPARATOR, NULL, MFS_ENABLED); 685 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + 1, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED); 686 687 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 2); 688 } 689 690 EXTERN_C 691 void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow); 692 693 /************************************************************************** 694 * ICPanel_IContextMenu_InvokeCommand() 695 */ 696 HRESULT WINAPI CCPLItemMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) 697 { 698 HRESULT hResult; 699 700 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(m_apidl[0]); 701 if(!pCPanel) 702 return E_FAIL; 703 704 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd); 705 706 if (lpcmi->lpVerb == MAKEINTRESOURCEA(0)) 707 { 708 /* Hardcode the command here; Executing a cpl file would be fine but we also need to run things like console.dll */ 709 WCHAR wszParams[MAX_PATH]; 710 PCWSTR wszFile = L"rundll32.exe"; 711 PCWSTR wszFormat = L"shell32.dll,Control_RunDLL %s,%s"; 712 713 wsprintfW(wszParams, wszFormat, pCPanel->szName, pCPanel->szName + pCPanel->offsDispName); 714 715 /* Note: we pass the applet name to Control_RunDLL to distinguish between multiple applets in one .cpl file */ 716 ShellExecuteW(NULL, NULL, wszFile, wszParams, NULL, 0); 717 } 718 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(1)) //FIXME 719 { 720 CComPtr<IDataObject> pDataObj; 721 LPITEMIDLIST pidl = _ILCreateControlPanel(); 722 723 hResult = SHCreateDataObject(pidl, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj)); 724 if (FAILED(hResult)) 725 return hResult; 726 727 SHFree(pidl); 728 729 //FIXME: Use SHCreateLinks 730 CComPtr<IShellFolder> psf; 731 CComPtr<IDropTarget> pDT; 732 733 hResult = SHGetDesktopFolder(&psf); 734 if (FAILED(hResult)) 735 return hResult; 736 737 hResult = psf->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pDT)); 738 if (FAILED(hResult)) 739 return hResult; 740 741 SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL); 742 } 743 return S_OK; 744 } 745 746 /************************************************************************** 747 * ICPanel_IContextMenu_GetCommandString() 748 * 749 */ 750 HRESULT WINAPI CCPLItemMenu::GetCommandString( 751 UINT_PTR idCommand, 752 UINT uFlags, 753 UINT* lpReserved, 754 LPSTR lpszName, 755 UINT uMaxNameLen) 756 { 757 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); 758 759 FIXME("unknown command string\n"); 760 return E_FAIL; 761 } 762 763 /************************************************************************** 764 * ICPanel_IContextMenu_HandleMenuMsg() 765 */ 766 HRESULT WINAPI CCPLItemMenu::HandleMenuMsg( 767 UINT uMsg, 768 WPARAM wParam, 769 LPARAM lParam) 770 { 771 TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam); 772 773 return E_NOTIMPL; 774 } 775 776 /************************************************************************** 777 * COpenControlPanel 778 */ 779 780 static HRESULT GetParsingName(PCIDLIST_ABSOLUTE pidl, PWSTR*Name) 781 { 782 PIDLIST_ABSOLUTE pidlFree = NULL; 783 if (IS_INTRESOURCE(pidl)) 784 { 785 HRESULT hr = SHGetSpecialFolderLocation(NULL, (UINT)(SIZE_T)pidl, &pidlFree); 786 if (FAILED(hr)) 787 return hr; 788 pidl = pidlFree; 789 } 790 HRESULT hr = SHGetNameFromIDList(pidl, SIGDN_DESKTOPABSOLUTEPARSING, Name); 791 ILFree(pidlFree); 792 return hr; 793 } 794 795 static HRESULT CreateCplAbsoluteParsingPath(LPCWSTR Prefix, LPCWSTR InFolderParse, PWSTR Buf, UINT cchBuf) 796 { 797 PWSTR cpfolder; 798 HRESULT hr = GetParsingName((PCIDLIST_ABSOLUTE)CSIDL_CONTROLS, &cpfolder); 799 if (SUCCEEDED(hr)) 800 { 801 hr = StringCchPrintfW(Buf, cchBuf, L"%s\\%s%s", cpfolder, Prefix, InFolderParse); 802 SHFree(cpfolder); 803 } 804 return hr; 805 } 806 807 static HRESULT FindExeCplClass(LPCWSTR Canonical, HKEY hKey, BOOL Wow64, LPWSTR clsid) 808 { 809 HRESULT hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); 810 HKEY hNSKey; 811 WCHAR key[MAX_PATH], buf[MAX_PATH]; 812 wsprintfW(key, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\%s\\NameSpace", 813 Wow64 ? L"ControlPanelWOW64" : L"ControlPanel"); 814 LSTATUS error = RegOpenKeyExW(hKey, key, 0, KEY_READ, &hNSKey); 815 if (error) 816 return HRESULT_FROM_WIN32(error); 817 for (DWORD i = 0; RegEnumKeyW(hNSKey, i, key, _countof(key)) == ERROR_SUCCESS; ++i) 818 { 819 IID validate; 820 if (SUCCEEDED(IIDFromString(key, &validate))) 821 { 822 wsprintfW(buf, L"CLSID\\%s", key); 823 DWORD cb = sizeof(buf); 824 if (RegGetValueW(HKEY_CLASSES_ROOT, buf, L"System.ApplicationName", 825 RRF_RT_REG_SZ, NULL, buf, &cb) == ERROR_SUCCESS) 826 { 827 if (!lstrcmpiW(buf, Canonical)) 828 { 829 lstrcpyW(clsid, key); 830 hr = S_OK; 831 } 832 } 833 } 834 } 835 RegCloseKey(hNSKey); 836 return hr; 837 } 838 839 static HRESULT FindExeCplClass(LPCWSTR Canonical, LPWSTR clsid) 840 { 841 HRESULT hr = E_FAIL; 842 if (FAILED(hr)) 843 hr = FindExeCplClass(Canonical, HKEY_CURRENT_USER, FALSE, clsid); 844 if (FAILED(hr)) 845 hr = FindExeCplClass(Canonical, HKEY_CURRENT_USER, TRUE, clsid); 846 if (FAILED(hr)) 847 hr = FindExeCplClass(Canonical, HKEY_LOCAL_MACHINE, FALSE, clsid); 848 if (FAILED(hr)) 849 hr = FindExeCplClass(Canonical, HKEY_LOCAL_MACHINE, TRUE, clsid); 850 return hr; 851 } 852 853 HRESULT WINAPI COpenControlPanel::Open(LPCWSTR pszName, LPCWSTR pszPage, IUnknown *punkSite) 854 { 855 WCHAR path[MAX_PATH], clspath[MAX_PATH]; 856 HRESULT hr = S_OK; 857 SHELLEXECUTEINFOW sei = { sizeof(sei), SEE_MASK_FLAG_DDEWAIT }; 858 sei.lpFile = path; 859 sei.nShow = SW_SHOW; 860 if (!pszName) 861 { 862 GetSystemDirectoryW(path, _countof(path)); 863 PathAppendW(path, L"control.exe"); 864 } 865 else 866 { 867 LPWSTR clsid = clspath + wsprintfW(clspath, L"CLSID\\"); 868 if (SUCCEEDED(hr = FindExeCplClass(pszName, clsid))) 869 { 870 if (SUCCEEDED(hr = CreateCplAbsoluteParsingPath(L"::", clsid, path, _countof(path)))) 871 { 872 // NT6 will execute "::{26EE0668-A00A-44D7-9371-BEB064C98683}\0\::{clsid}[\pszPage]" 873 // but we don't support parsing that so we force the class instead. 874 sei.fMask |= SEE_MASK_CLASSNAME; 875 sei.lpClass = clspath; 876 } 877 } 878 } 879 880 if (SUCCEEDED(hr)) 881 { 882 DWORD error = ShellExecuteExW(&sei) ? ERROR_SUCCESS : GetLastError(); 883 hr = HRESULT_FROM_WIN32(error); 884 } 885 return hr; 886 } 887 888 HRESULT WINAPI COpenControlPanel::GetPath(LPCWSTR pszName, LPWSTR pszPath, UINT cchPath) 889 { 890 HRESULT hr; 891 if (!pszName) 892 { 893 PWSTR cpfolder; 894 if (SUCCEEDED(hr = GetParsingName((PCIDLIST_ABSOLUTE)CSIDL_CONTROLS, &cpfolder))) 895 { 896 hr = StringCchCopyW(pszPath, cchPath, cpfolder); 897 SHFree(cpfolder); 898 } 899 } 900 else 901 { 902 WCHAR clsid[38 + 1]; 903 if (SUCCEEDED(hr = FindExeCplClass(pszName, clsid))) 904 { 905 hr = CreateCplAbsoluteParsingPath(L"::", clsid, pszPath, cchPath); 906 } 907 } 908 return hr; 909 } 910 911 HRESULT WINAPI COpenControlPanel::GetCurrentView(CPVIEW *pView) 912 { 913 *pView = CPVIEW_CLASSIC; 914 return S_OK; 915 } 916