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 an unknown pidl here!\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 452 /* HACK: We should use callbacks from CDefaultContextMenu instead of creating one on our own */ 453 BOOL bHasCpl = FALSE; 454 for (UINT i = 0; i < cidl; i++) 455 { 456 if(_ILIsCPanelStruct(apidl[i])) 457 { 458 bHasCpl = TRUE; 459 } 460 } 461 462 if (bHasCpl) 463 hr = ShellObjectCreatorInit<CCPLItemMenu>(cidl, apidl, riid, &pObj); 464 else 465 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 466 } else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1)) { 467 hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 468 } else if ((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1)) { 469 if (_ILGetCPanelPointer(apidl[0])) 470 hr = CCPLExtractIcon_CreateInstance(this, apidl[0], riid, &pObj); 471 else 472 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 473 } else { 474 hr = E_NOINTERFACE; 475 } 476 477 if (SUCCEEDED(hr) && !pObj) 478 hr = E_OUTOFMEMORY; 479 480 *ppvOut = pObj; 481 } 482 TRACE("(%p)->hr=0x%08x\n", this, hr); 483 return hr; 484 } 485 486 /************************************************************************** 487 * CControlPanelFolder::GetDisplayNameOf 488 */ 489 HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 490 { 491 if (!pidl) 492 return S_FALSE; 493 494 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl); 495 496 if (pCPanel) 497 { 498 return SHSetStrRet(strRet, pCPanel->szName + pCPanel->offsDispName); 499 } 500 else if (_ILIsSpecialFolder(pidl)) 501 { 502 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet); 503 } 504 505 return E_FAIL; 506 } 507 508 /************************************************************************** 509 * CControlPanelFolder::SetNameOf 510 * Changes the name of a file object or subfolder, possibly changing its item 511 * identifier in the process. 512 * 513 * PARAMETERS 514 * HWND hwndOwner, //[in ] Owner window for output 515 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change 516 * LPCOLESTR lpszName, //[in ] the items new display name 517 * DWORD dwFlags, //[in ] SHGNO formatting flags 518 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned 519 */ 520 HRESULT WINAPI CControlPanelFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */ 521 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 522 { 523 FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut); 524 return E_FAIL; 525 } 526 527 HRESULT WINAPI CControlPanelFolder::GetDefaultSearchGUID(GUID *pguid) 528 { 529 FIXME("(%p)\n", this); 530 return E_NOTIMPL; 531 } 532 533 HRESULT WINAPI CControlPanelFolder::EnumSearches(IEnumExtraSearch **ppenum) 534 { 535 FIXME("(%p)\n", this); 536 return E_NOTIMPL; 537 } 538 539 HRESULT WINAPI CControlPanelFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 540 { 541 TRACE("(%p)\n", this); 542 543 if (pSort) *pSort = 0; 544 if (pDisplay) *pDisplay = 0; 545 return S_OK; 546 } 547 548 HRESULT WINAPI CControlPanelFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 549 { 550 TRACE("(%p)\n", this); 551 552 if (!pcsFlags || iColumn >= CONTROLPANEL_COL_COUNT) 553 return E_INVALIDARG; 554 *pcsFlags = ControlPanelSFHeader[iColumn].pcsFlags; 555 return S_OK; 556 } 557 558 HRESULT WINAPI CControlPanelFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) 559 { 560 FIXME("(%p)\n", this); 561 return E_NOTIMPL; 562 } 563 564 HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 565 { 566 if (!psd || iColumn >= CONTROLPANEL_COL_COUNT) 567 return E_INVALIDARG; 568 569 if (!pidl) 570 { 571 psd->fmt = ControlPanelSFHeader[iColumn].fmt; 572 psd->cxChar = ControlPanelSFHeader[iColumn].cxChar; 573 return SHSetStrRet(&psd->str, shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid); 574 } 575 else if (_ILIsSpecialFolder(pidl)) 576 { 577 return m_regFolder->GetDetailsOf(pidl, iColumn, psd); 578 } 579 else 580 { 581 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl); 582 583 if (!pCPanel) 584 return E_FAIL; 585 586 switch(iColumn) 587 { 588 case CONTROLPANEL_COL_NAME: 589 return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsDispName); 590 case CONTROLPANEL_COL_COMMENT: 591 return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsComment); 592 } 593 } 594 595 return E_FAIL; 596 } 597 598 HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 599 { 600 FIXME("(%p)\n", this); 601 return E_NOTIMPL; 602 } 603 604 /************************************************************************ 605 * CControlPanelFolder::GetClassID 606 */ 607 HRESULT WINAPI CControlPanelFolder::GetClassID(CLSID *lpClassId) 608 { 609 TRACE("(%p)\n", this); 610 611 if (!lpClassId) 612 return E_POINTER; 613 *lpClassId = CLSID_ControlPanel; 614 615 return S_OK; 616 } 617 618 /************************************************************************ 619 * CControlPanelFolder::Initialize 620 * 621 * NOTES: it makes no sense to change the pidl 622 */ 623 HRESULT WINAPI CControlPanelFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 624 { 625 if (pidlRoot) 626 SHFree((LPVOID)pidlRoot); 627 628 pidlRoot = ILClone(pidl); 629 630 /* Create the inner reg folder */ 631 HRESULT hr; 632 hr = CRegFolder_CreateInstance(&CLSID_ControlPanel, 633 pidlRoot, 634 L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", 635 L"ControlPanel", 636 IID_PPV_ARG(IShellFolder2, &m_regFolder)); 637 if (FAILED_UNEXPECTEDLY(hr)) 638 return hr; 639 640 return S_OK; 641 } 642 643 /************************************************************************** 644 * CControlPanelFolder::GetCurFolder 645 */ 646 HRESULT WINAPI CControlPanelFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 647 { 648 TRACE("(%p)->(%p)\n", this, pidl); 649 650 if (!pidl) 651 return E_POINTER; 652 *pidl = ILClone(pidlRoot); 653 return S_OK; 654 } 655 656 CCPLItemMenu::CCPLItemMenu() 657 { 658 m_apidl = NULL; 659 m_cidl = 0; 660 } 661 662 HRESULT WINAPI CCPLItemMenu::Initialize(UINT cidl, PCUITEMID_CHILD_ARRAY apidl) 663 { 664 m_cidl = cidl; 665 m_apidl = _ILCopyaPidl(apidl, m_cidl); 666 if (m_cidl && !m_apidl) 667 return E_OUTOFMEMORY; 668 669 return S_OK; 670 } 671 672 CCPLItemMenu::~CCPLItemMenu() 673 { 674 _ILFreeaPidl(m_apidl, m_cidl); 675 } 676 677 HRESULT WINAPI CCPLItemMenu::QueryContextMenu( 678 HMENU hMenu, 679 UINT indexMenu, 680 UINT idCmdFirst, 681 UINT idCmdLast, 682 UINT uFlags) 683 { 684 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst, MFT_STRING, MAKEINTRESOURCEW(IDS_OPEN), MFS_DEFAULT); 685 _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDC_STATIC, MFT_SEPARATOR, NULL, MFS_ENABLED); 686 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + 1, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED); 687 688 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 2); 689 } 690 691 EXTERN_C 692 void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow); 693 694 /************************************************************************** 695 * ICPanel_IContextMenu_InvokeCommand() 696 */ 697 HRESULT WINAPI CCPLItemMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) 698 { 699 HRESULT hResult; 700 701 PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(m_apidl[0]); 702 if(!pCPanel) 703 return E_FAIL; 704 705 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd); 706 707 if (lpcmi->lpVerb == MAKEINTRESOURCEA(0)) 708 { 709 /* Hardcode the command here; Executing a cpl file would be fine but we also need to run things like console.dll */ 710 WCHAR wszParams[MAX_PATH]; 711 PCWSTR wszFile = L"rundll32.exe"; 712 PCWSTR wszFormat = L"shell32.dll,Control_RunDLL %s,%s"; 713 714 wsprintfW(wszParams, wszFormat, pCPanel->szName, pCPanel->szName + pCPanel->offsDispName); 715 716 /* Note: we pass the applet name to Control_RunDLL to distinguish between multiple applets in one .cpl file */ 717 ShellExecuteW(NULL, NULL, wszFile, wszParams, NULL, 0); 718 } 719 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(1)) //FIXME 720 { 721 CComPtr<IDataObject> pDataObj; 722 LPITEMIDLIST pidl = _ILCreateControlPanel(); 723 724 hResult = SHCreateDataObject(pidl, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj)); 725 if (FAILED(hResult)) 726 return hResult; 727 728 SHFree(pidl); 729 730 //FIXME: Use SHCreateLinks 731 CComPtr<IShellFolder> psf; 732 CComPtr<IDropTarget> pDT; 733 734 hResult = SHGetDesktopFolder(&psf); 735 if (FAILED(hResult)) 736 return hResult; 737 738 hResult = psf->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pDT)); 739 if (FAILED(hResult)) 740 return hResult; 741 742 SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL); 743 } 744 return S_OK; 745 } 746 747 /************************************************************************** 748 * ICPanel_IContextMenu_GetCommandString() 749 * 750 */ 751 HRESULT WINAPI CCPLItemMenu::GetCommandString( 752 UINT_PTR idCommand, 753 UINT uFlags, 754 UINT* lpReserved, 755 LPSTR lpszName, 756 UINT uMaxNameLen) 757 { 758 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); 759 760 FIXME("unknown command string\n"); 761 return E_FAIL; 762 } 763 764 /************************************************************************** 765 * ICPanel_IContextMenu_HandleMenuMsg() 766 */ 767 HRESULT WINAPI CCPLItemMenu::HandleMenuMsg( 768 UINT uMsg, 769 WPARAM wParam, 770 LPARAM lParam) 771 { 772 TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam); 773 774 return E_NOTIMPL; 775 } 776