Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

873 lines
26 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: O N C O M M A N D . C P P
  7. //
  8. // Contents: Command handlers for the context menus, etc.
  9. //
  10. // Notes:
  11. //
  12. // Author: jeffspr 4 Nov 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "upsres.h"
  18. #include "oncommand.h"
  19. #if DBG // Debug menu commands
  20. #include "oncommand_dbg.h" //
  21. #endif
  22. #include "shutil.h"
  23. #include <upsres.h>
  24. #include "tfind.h"
  25. //---[ Externs ]--------------------------------------------------------------
  26. extern const WCHAR c_szUPnPUIDll[];
  27. extern const TCHAR c_sztUPnPUIDll[];
  28. //---[ Prototypes ]-----------------------------------------------------------
  29. HRESULT HrCreateDevicePropertySheets(
  30. HWND hwndOwner,
  31. NewDeviceNode * pNDN);
  32. //---[ Constants ]------------------------------------------------------------
  33. HRESULT HrCommandHandlerThread(
  34. FOLDERONCOMMANDPROC pfnCommandHandler,
  35. LPITEMIDLIST * apidl,
  36. ULONG cidl,
  37. HWND hwndOwner,
  38. LPSHELLFOLDER psf)
  39. {
  40. HRESULT hr = S_OK;
  41. LPITEMIDLIST * apidlCopy = NULL;
  42. ULONG cidlCopy = 0;
  43. // If there are pidls to copy, copy them
  44. //
  45. if (apidl)
  46. {
  47. hr = HrCloneRgIDL((LPCITEMIDLIST *) apidl, cidl, &apidlCopy, &cidlCopy);
  48. }
  49. // If either there were no pidls, or the Clone succeeded, then we want to continue
  50. //
  51. if (SUCCEEDED(hr))
  52. {
  53. PFOLDONCOMMANDPARAMS pfocp = new FOLDONCOMMANDPARAMS;
  54. if (pfocp)
  55. {
  56. pfocp->pfnfocp = pfnCommandHandler;
  57. pfocp->apidl = apidlCopy;
  58. pfocp->cidl = cidlCopy;
  59. pfocp->hwndOwner = hwndOwner;
  60. pfocp->psf = psf;
  61. pfocp->hInstFolder = NULL;
  62. // This should be Release'd in the thread called.
  63. //
  64. psf->AddRef();
  65. // This will always succeed in retail, but will test the flag in debug
  66. //
  67. if (!FIsDebugFlagSet (dfidDisableShellThreading))
  68. {
  69. // Run in a thread using the QueueUserWorkItem
  70. //
  71. HANDLE hthrd = NULL;
  72. HINSTANCE hInstFolder = LoadLibrary(c_sztUPnPUIDll);
  73. if (hInstFolder)
  74. {
  75. pfocp->hInstFolder = hInstFolder;
  76. DWORD dwThreadId;
  77. hthrd = CreateThread(NULL, 0,
  78. (LPTHREAD_START_ROUTINE)FolderCommandHandlerThreadProc,
  79. (LPVOID)pfocp, 0, &dwThreadId);
  80. }
  81. if (NULL != hthrd)
  82. {
  83. CloseHandle(hthrd);
  84. }
  85. else
  86. {
  87. pfocp->hInstFolder = NULL;
  88. FolderCommandHandlerThreadProc(pfocp);
  89. }
  90. }
  91. else
  92. {
  93. // Run directly in this same thread
  94. //
  95. FolderCommandHandlerThreadProc((PVOID) pfocp);
  96. }
  97. }
  98. else
  99. {
  100. hr = E_OUTOFMEMORY;
  101. }
  102. }
  103. // Don't release the psf here. This should have been taken care of by the called ThreadProc
  104. //
  105. TraceError("HrCommandHandlerThread", hr);
  106. return hr;
  107. }
  108. DWORD WINAPI FolderCommandHandlerThreadProc(LPVOID lpParam)
  109. {
  110. HRESULT hr = S_OK;
  111. PFOLDONCOMMANDPARAMS pfocp = (PFOLDONCOMMANDPARAMS) lpParam;
  112. BOOL fCoInited = FALSE;
  113. Assert(pfocp);
  114. hr = CoInitializeEx (NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
  115. if (SUCCEEDED(hr))
  116. {
  117. // We don't care if this is S_FALSE or not, since we'll soon
  118. // overwrite the hr. If it's already initialized, great...
  119. fCoInited = TRUE;
  120. // Call the specific handler
  121. //
  122. hr = pfocp->pfnfocp(
  123. pfocp->apidl,
  124. pfocp->cidl,
  125. pfocp->hwndOwner,
  126. pfocp->psf);
  127. }
  128. // Remove the ref that we have on this object. The thread handler would have addref'd
  129. // this before queueing our action
  130. //
  131. if (pfocp->psf)
  132. {
  133. ReleaseObj(pfocp->psf);
  134. }
  135. // Release apidl
  136. //
  137. if (pfocp->apidl)
  138. {
  139. FreeRgIDL(pfocp->cidl, pfocp->apidl);
  140. }
  141. // Remove this object. We're responsible for this now.
  142. //
  143. HINSTANCE hInstFolder = pfocp->hInstFolder;
  144. pfocp->hInstFolder = NULL;
  145. delete pfocp;
  146. if (fCoInited)
  147. {
  148. CoUninitialize();
  149. }
  150. if (hInstFolder)
  151. {
  152. FreeLibraryAndExitThread(hInstFolder, hr);
  153. }
  154. return hr;
  155. }
  156. //+---------------------------------------------------------------------------
  157. //
  158. // Function: HrFolderCommandHandler
  159. //
  160. // Purpose: Command handler switch -- all commands come through this
  161. // point.
  162. //
  163. // Arguments:
  164. // uiCommand [in] The command-id that's been invoked.
  165. // apidl [in] PIDL array (item 0 is our item to work on)
  166. // cidl [in] Size of the array
  167. // lpici [in] Command context info
  168. // hwndOwner [in] Owner hwnd
  169. //
  170. // Returns:
  171. //
  172. // Author: jeffspr 11 Feb 1998
  173. //
  174. // Notes:
  175. //
  176. HRESULT HrFolderCommandHandler(
  177. UINT uiCommand,
  178. LPITEMIDLIST * apidl,
  179. ULONG cidl,
  180. HWND hwndOwner,
  181. LPCMINVOKECOMMANDINFO lpici,
  182. LPSHELLFOLDER psf)
  183. {
  184. HRESULT hr = S_OK;
  185. CWaitCursor wc; // Bring up wait cursor now. Remove when we go out of scope.
  186. #if 0
  187. // refresh all permission so subsequent calls can use cached value
  188. RefreshAllPermission();
  189. #endif
  190. switch(uiCommand)
  191. {
  192. case CMIDM_INVOKE:
  193. Assert(apidl);
  194. hr = HrCommandHandlerThread(HrOnCommandInvoke, apidl, cidl, hwndOwner, psf);
  195. break;
  196. case CMIDM_ARRANGE_BY_NAME:
  197. ShellFolderView_ReArrange(hwndOwner, ICOL_NAME);
  198. break;
  199. case CMIDM_ARRANGE_BY_URL:
  200. ShellFolderView_ReArrange(hwndOwner, ICOL_URL);
  201. break;
  202. case CMIDM_CREATE_SHORTCUT:
  203. Assert(apidl);
  204. hr = HrCommandHandlerThread(HrOnCommandCreateShortcut, apidl, cidl, hwndOwner, psf);
  205. break;
  206. case CMIDM_DELETE:
  207. Assert(apidl);
  208. hr = HrCommandHandlerThread(HrOnCommandDelete, apidl, cidl, hwndOwner, psf);
  209. break;
  210. case CMIDM_PROPERTIES:
  211. Assert(apidl);
  212. hr = HrCommandHandlerThread(HrOnCommandProperties, apidl, cidl, hwndOwner, psf);
  213. break;
  214. #if DBG
  215. case CMIDM_DEBUG_TRACING:
  216. hr = HrOnCommandDebugTracing(apidl, cidl, hwndOwner, psf);
  217. break;
  218. case CMIDM_DEBUG_REFRESH:
  219. hr = HrOnCommandDebugRefresh(apidl, cidl, hwndOwner, psf);
  220. break;
  221. case CMIDM_DEBUG_TESTASYNCFIND:
  222. hr = HrOnCommandDebugTestAsyncFind(apidl, cidl, hwndOwner, psf);
  223. break;
  224. #endif
  225. default:
  226. AssertSz(FALSE, "Unknown command in HrFolderCommandHandler");
  227. hr = E_FAIL;
  228. }
  229. TraceHr(ttidError, FAL, hr, FALSE, "HrFolderCommandHandler");
  230. return hr;
  231. }
  232. //+---------------------------------------------------------------------------
  233. //
  234. // Function: HrOnCommandInvoke
  235. //
  236. // Purpose: Command handler for CMIDM_INVOKE
  237. //
  238. // Arguments:
  239. // apidl [in] PIDL array (item 0 is our item to work on)
  240. // cidl [in] Size of the array
  241. // hwndOwner [in] Owner hwnd
  242. // psf [in] Our IShellFolder *
  243. //
  244. // Returns:
  245. //
  246. // Author: jeffspr 8 Sep 1999
  247. //
  248. // Notes:
  249. //
  250. HRESULT HrOnCommandInvoke(
  251. LPITEMIDLIST * apidl,
  252. ULONG cidl,
  253. HWND hwndOwner,
  254. LPSHELLFOLDER psf)
  255. {
  256. HRESULT hr = S_OK;
  257. BOOL fResult = FALSE;
  258. PUPNPDEVICEFOLDPIDL pudfp = ConvertToUPnPDevicePIDL(apidl[0]);
  259. IUPnPDeviceFinder * pdf = NULL;
  260. LPTSTR szUrl = NULL;
  261. Assert(pudfp);
  262. Assert(cidl > 0);
  263. hr = CoCreateInstance(CLSID_UPnPDeviceFinder, NULL, CLSCTX_INPROC_SERVER,
  264. IID_IUPnPDeviceFinder, (LPVOID *)&pdf);
  265. if (SUCCEEDED(hr))
  266. {
  267. IUPnPDevice * pdev = NULL;
  268. CUPnPDeviceFoldPidl udfp;
  269. hr = udfp.HrInit(pudfp);
  270. if (SUCCEEDED(hr))
  271. {
  272. PCWSTR szUDN = udfp.PszGetUDNPointer();
  273. Assert(szUDN);
  274. BSTR bstrUDN = ::SysAllocString(szUDN);
  275. if (bstrUDN)
  276. {
  277. hr = pdf->FindByUDN(bstrUDN, &pdev);
  278. if (S_OK == hr)
  279. {
  280. BSTR bstrUrl;
  281. hr = pdev->get_PresentationURL(&bstrUrl);
  282. if (SUCCEEDED(hr))
  283. {
  284. // Note: PresentationURL might be NULL
  285. if (S_OK == hr)
  286. {
  287. Assert(bstrUrl);
  288. szUrl = TszFromWsz(bstrUrl);
  289. }
  290. SysFreeString(bstrUrl);
  291. }
  292. ReleaseObj(pdev);
  293. }
  294. else if (hr == S_FALSE)
  295. {
  296. PTSTR pszText = NULL;
  297. PTSTR pszTitle = NULL;
  298. pszText = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_DEVICE_OFFLINE_MSG));
  299. pszTitle = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_DEVICE_OFFLINE_TITLE));
  300. if( pszText && pszTitle )
  301. {
  302. MessageBox(hwndOwner, pszText, pszTitle, MB_OK | MB_ICONWARNING );
  303. }
  304. delete pszText;
  305. delete pszTitle;
  306. TraceTag(ttidError,
  307. "Can not bring up control page for device UDN=%S because FindByUDN returns S_FALSE.",
  308. szUDN);
  309. }
  310. ::SysFreeString(bstrUDN);
  311. }
  312. else
  313. {
  314. hr = E_OUTOFMEMORY;
  315. TraceError("HrOnCommandInvoke: SysAllocString", hr);
  316. }
  317. }
  318. ReleaseObj(pdf);
  319. }
  320. if (szUrl)
  321. {
  322. SHELLEXECUTEINFO sei = {0};
  323. // Check these masks if we ever need to use different icons and such
  324. // for the instances that we launch. SEE_MASK_ICON is a possibility.
  325. // SEE_MASK_FLAG_NO_UI can be used if we don't want to show an error
  326. // on failure.
  327. //
  328. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  329. sei.fMask = SEE_MASK_FLAG_DDEWAIT;
  330. sei.hwnd = hwndOwner;
  331. sei.lpFile = szUrl;
  332. sei.nShow = SW_SHOW;
  333. fResult = ShellExecuteEx(&sei);
  334. if (!fResult)
  335. {
  336. hr = HrFromLastWin32Error();
  337. }
  338. delete [] szUrl;
  339. }
  340. TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandInvoke");
  341. return hr;
  342. }
  343. //+---------------------------------------------------------------------------
  344. //
  345. // Function: HrOnCommandProperties
  346. //
  347. // Purpose: Command handler for the CMIDM_PROPERTIES command
  348. //
  349. // Arguments:
  350. // apidl [in] PIDL array (item 0 is our item to work on)
  351. // cidl [in] Size of the array
  352. // hwndOwner [in] Owner hwnd
  353. //
  354. // Returns:
  355. //
  356. // Author: jeffspr 4 Nov 1997
  357. //
  358. // Notes:
  359. //
  360. HRESULT HrOnCommandProperties(
  361. LPITEMIDLIST * apidl,
  362. ULONG cidl,
  363. HWND hwndOwner,
  364. LPSHELLFOLDER psf)
  365. {
  366. HRESULT hr = S_OK;
  367. PUPNPDEVICEFOLDPIDL pudfp = ConvertToUPnPDevicePIDL(apidl[0]);
  368. IUPnPDeviceFinder * pdf = NULL;
  369. Assert(pudfp);
  370. Assert(cidl > 0);
  371. // instantiate device finder
  372. hr = CoCreateInstance(
  373. CLSID_UPnPDeviceFinder,
  374. NULL,
  375. CLSCTX_INPROC_SERVER,
  376. IID_IUPnPDeviceFinder,
  377. (LPVOID *)&pdf
  378. );
  379. if (SUCCEEDED(hr))
  380. {
  381. CUPnPDeviceFoldPidl udfp;
  382. hr = udfp.HrInit(pudfp);
  383. if (SUCCEEDED(hr))
  384. {
  385. // retrieve the device object associated with UDN
  386. IUPnPDevice * pdev = NULL;
  387. PCWSTR szUDN = udfp.PszGetUDNPointer();
  388. Assert(szUDN);
  389. BSTR bstrUDN = ::SysAllocString(szUDN);
  390. if (bstrUDN)
  391. {
  392. hr = pdf->FindByUDN(bstrUDN, &pdev);
  393. if (hr == S_OK)
  394. {
  395. NewDeviceNode * pNDN = NULL;
  396. // convert device object to device node
  397. hr = HrCreateDeviceNodeFromDevice(pdev, &pNDN);
  398. if (SUCCEEDED(hr))
  399. {
  400. // display property pages for given device node
  401. hr = HrCreateDevicePropertySheets(hwndOwner, pNDN);
  402. // nuke device node
  403. delete pNDN;
  404. }
  405. ReleaseObj(pdev);
  406. }
  407. else if (hr == S_FALSE)
  408. {
  409. PTSTR pszText = NULL;
  410. PTSTR pszTitle = NULL;
  411. pszText = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_DEVICE_OFFLINE_MSG));
  412. pszTitle = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_DEVICE_OFFLINE_TITLE));
  413. if( pszText && pszTitle )
  414. {
  415. MessageBox(hwndOwner, pszText, pszTitle, MB_OK | MB_ICONWARNING);
  416. }
  417. delete pszText;
  418. delete pszTitle;
  419. TraceTag(ttidError,
  420. "Can not bring up property for device UDN=%S because"
  421. " FindByUDN returns S_FALSE.",
  422. szUDN);
  423. }
  424. ::SysFreeString(bstrUDN);
  425. }
  426. else
  427. {
  428. hr = E_OUTOFMEMORY;
  429. TraceError("HrOnCommandInvoke: SysAllocString", hr);
  430. }
  431. }
  432. ReleaseObj(pdf);
  433. }
  434. TraceHr(ttidError, FAL, hr, FALSE, "HrOnCommandProperties");
  435. return hr;
  436. }
  437. //+---------------------------------------------------------------------------
  438. //
  439. // Function: HrOnCommandDelete
  440. //
  441. // Purpose: Command handler for the CMIDM_DELETE command
  442. //
  443. // Arguments:
  444. // apidl [in] PIDL array (item 0 is our item to work on)
  445. // cidl [in] Size of the array
  446. // hwndOwner [in] Owner hwnd
  447. // psf [in] Our folder
  448. //
  449. // Returns:
  450. //
  451. // Author: jeffspr 3 Dec 1997
  452. //
  453. // Notes:
  454. //
  455. HRESULT HrOnCommandDelete(
  456. LPITEMIDLIST * apidl,
  457. ULONG cidl,
  458. HWND hwndOwner,
  459. LPSHELLFOLDER psf)
  460. {
  461. HRESULT hr = S_OK;
  462. DWORD dwLoop = 0;
  463. INT iMBResult = 0;
  464. #if 0
  465. // Bring up the prompt for the delete
  466. //
  467. if (cidl > 1)
  468. {
  469. WCHAR wszItemCount[8];
  470. // Convert the item count to a string
  471. //
  472. _itow( cidl, wszItemCount, 10 );
  473. // Bring up the message box
  474. //
  475. iMBResult = NcMsgBox(
  476. _Module.GetResourceInstance(),
  477. NULL,
  478. IDS_CONFOLD_DELETE_CONFIRM_MULTI_CAPTION,
  479. IDS_CONFOLD_DELETE_CONFIRM_MULTI,
  480. MB_YESNO | MB_ICONQUESTION,
  481. wszItemCount);
  482. }
  483. else if (cidl == 1)
  484. {
  485. PCCONFOLDENTRY pccfe = NULL;
  486. // Convert the pidl to a confoldentry, and use the name
  487. // to bring up the confirm message box
  488. //
  489. hr = HrPidlToCConFoldEntry(apidl[0], &pccfe);
  490. if (SUCCEEDED(hr))
  491. {
  492. // Don't let them try to delete a wizard
  493. //
  494. if (pccfe->m_fWizard)
  495. {
  496. NcMsgBox(
  497. _Module.GetResourceInstance(),
  498. NULL,
  499. IDS_CONFOLD_ERROR_DELETE_CAPTION,
  500. IDS_CONFOLD_ERROR_DELETE_WIZARD,
  501. MB_ICONEXCLAMATION);
  502. delete pccfe;
  503. goto Exit;
  504. }
  505. else
  506. {
  507. // Check to see if this connection is in the process of activating.
  508. // If so, then we won't allow the delete.
  509. //
  510. hr = HrCheckForActivation(NULL, pccfe, &fActivating);
  511. if (S_OK == hr)
  512. {
  513. if (!fActivating)
  514. {
  515. if ((pccfe->m_ncs == NCS_CONNECTING) ||
  516. (pccfe->m_ncs == NCS_CONNECTED) ||
  517. (pccfe->m_ncs == NCS_DISCONNECTING))
  518. {
  519. // You can't delete an active connection
  520. //
  521. NcMsgBox(
  522. _Module.GetResourceInstance(),
  523. NULL,
  524. IDS_CONFOLD_ERROR_DELETE_CAPTION,
  525. IDS_CONFOLD_ERROR_DELETE_ACTIVE,
  526. MB_ICONEXCLAMATION);
  527. delete pccfe;
  528. goto Exit;
  529. }
  530. else
  531. {
  532. // Ask for delete confirmation
  533. //
  534. iMBResult = NcMsgBox(
  535. _Module.GetResourceInstance(),
  536. NULL,
  537. IDS_CONFOLD_DELETE_CONFIRM_SINGLE_CAPTION,
  538. IDS_CONFOLD_DELETE_CONFIRM_SINGLE,
  539. MB_YESNO | MB_ICONQUESTION,
  540. pccfe->m_pszName);
  541. }
  542. }
  543. else
  544. {
  545. // Bring up the MB about "Hey, you can't delete while
  546. // the connection is activating."
  547. //
  548. iMBResult = NcMsgBox(
  549. _Module.GetResourceInstance(),
  550. NULL,
  551. IDS_CONFOLD_ERROR_DELETE_CAPTION,
  552. IDS_CONFOLD_ERROR_DELETE_ACTIVE,
  553. MB_ICONEXCLAMATION);
  554. delete pccfe;
  555. goto Exit;
  556. }
  557. }
  558. else
  559. {
  560. // If the connection wasn't found, then we should just drop out of here
  561. // because we sure can't delete it.
  562. //
  563. if (S_FALSE == hr)
  564. {
  565. delete pccfe;
  566. goto Exit;
  567. }
  568. }
  569. delete pccfe;
  570. pccfe = NULL;
  571. }
  572. }
  573. else
  574. {
  575. AssertSz(FALSE, "Couldn't get ConFoldEntry from pidl in HrOnCommandDelete");
  576. goto Exit;
  577. }
  578. }
  579. else
  580. {
  581. // No connections were specified. Take a hike.
  582. //
  583. goto Exit;
  584. }
  585. // If the user said "Yes" to the prompt
  586. //
  587. if (iMBResult == IDYES)
  588. {
  589. CConnectionFolder * pcf = static_cast<CConnectionFolder *>(psf);
  590. LPITEMIDLIST pidlFolder = pcf ? pcf->PidlGetFolderRoot() : NULL;
  591. BOOL fShowActivationWarning = FALSE;
  592. BOOL fShowNotDeletableWarning = FALSE;
  593. Assert(pidlFolder);
  594. for (dwLoop = 0; dwLoop < cidl; dwLoop++)
  595. {
  596. PCCONFOLDENTRY pccfe = NULL;
  597. hr = HrPidlToCConFoldEntry(apidl[dwLoop], &pccfe);
  598. if (SUCCEEDED(hr))
  599. {
  600. // If this is a LAN connection the user doesn't have rights
  601. //
  602. if ((NCM_LAN == pccfe->m_ncm) || (pccfe->m_fWizard))
  603. {
  604. fShowNotDeletableWarning = TRUE;
  605. continue;
  606. }
  607. // If this is a RAS connection and the user doesn't have rights
  608. // then skip
  609. //
  610. if (NCM_LAN != pccfe->m_ncm)
  611. {
  612. if ((!FHasPermission(NCPERM_DeleteConnection)) ||
  613. ((pccfe->m_dwCharacteristics & NCCF_ALL_USERS) &&
  614. !FHasPermission(NCPERM_DeleteAllUserConnection)))
  615. {
  616. fShowNotDeletableWarning = TRUE;
  617. continue;
  618. }
  619. }
  620. hr = HrCheckForActivation(NULL, pccfe, &fActivating);
  621. if (S_OK == hr)
  622. {
  623. // Only allow deletion if this connection is inactive and
  624. // it allows removal.
  625. //
  626. if (fActivating || (pccfe->m_ncs == NCS_CONNECTING) ||
  627. (pccfe->m_ncs == NCS_CONNECTED) ||
  628. (pccfe->m_ncs == NCS_DISCONNECTING))
  629. {
  630. fShowActivationWarning = TRUE;
  631. }
  632. else if (pccfe->m_dwCharacteristics & NCCF_ALLOW_REMOVAL)
  633. {
  634. hr = HrNetConFromPidl(apidl[dwLoop], &pNetCon);
  635. if (SUCCEEDED(hr))
  636. {
  637. hr = pNetCon->Delete();
  638. if (SUCCEEDED(hr) && pcf)
  639. {
  640. hr = HrDeleteFromCclAndNotifyShell(pidlFolder, apidl[dwLoop], pccfe);
  641. }
  642. ReleaseObj(pNetCon);
  643. }
  644. }
  645. else
  646. {
  647. // The selected item is not deletable
  648. //
  649. fShowNotDeletableWarning = TRUE;
  650. }
  651. }
  652. }
  653. }
  654. if (fShowNotDeletableWarning)
  655. {
  656. // You can't delete an item that doesn't support it
  657. //
  658. NcMsgBox(
  659. _Module.GetResourceInstance(),
  660. NULL,
  661. IDS_CONFOLD_ERROR_DELETE_CAPTION,
  662. (1 == cidl) ?
  663. IDS_CONFOLD_ERROR_DELETE_NOSUPPORT :
  664. IDS_CONFOLD_ERROR_DELETE_NOSUPPORT_MULTI,
  665. MB_ICONEXCLAMATION);
  666. }
  667. else if (fShowActivationWarning)
  668. {
  669. // You can't delete an active connection. Note, if more
  670. // than one are being deleted, then we put up the warning
  671. // that says 'one or more are being ignored'.
  672. //
  673. NcMsgBox(
  674. _Module.GetResourceInstance(),
  675. NULL,
  676. IDS_CONFOLD_ERROR_DELETE_CAPTION,
  677. (1 == cidl) ?
  678. IDS_CONFOLD_ERROR_DELETE_ACTIVE :
  679. IDS_CONFOLD_ERROR_DELETE_ACTIVE_MULTI,
  680. MB_ICONEXCLAMATION);
  681. }
  682. }
  683. Exit:
  684. #endif
  685. TraceError("HrOnCommandDelete", hr);
  686. return hr;
  687. }
  688. HRESULT HrCreateShortcutWithPath(
  689. LPITEMIDLIST * apidl,
  690. ULONG cidl,
  691. HWND hwndOwner,
  692. LPSHELLFOLDER psf,
  693. PCWSTR pszDir)
  694. {
  695. HRESULT hr = S_OK;
  696. LPDATAOBJECT pdtobj = NULL;
  697. LPITEMIDLIST * apidlInternal = NULL;
  698. ULONG cidlInternal = 0;
  699. DWORD dwLoop = 0;
  700. if (cidl > 0)
  701. {
  702. apidlInternal = new LPITEMIDLIST[cidl];
  703. if (apidlInternal)
  704. {
  705. for (;dwLoop < cidl; dwLoop++)
  706. {
  707. apidlInternal[cidlInternal++] = apidl[dwLoop];
  708. }
  709. hr = psf->GetUIObjectOf(
  710. hwndOwner,
  711. cidlInternal,
  712. (LPCITEMIDLIST *) apidlInternal,
  713. IID_IDataObject,
  714. NULL,
  715. (LPVOID *) &pdtobj);
  716. if (SUCCEEDED(hr))
  717. {
  718. SHCreateLinks(hwndOwner, pszDir, pdtobj,
  719. SHCL_USEDESKTOP | SHCL_USETEMPLATE | SHCL_CONFIRM,
  720. NULL);
  721. ReleaseObj(pdtobj);
  722. }
  723. delete apidlInternal;
  724. }
  725. }
  726. TraceError("HrCreateShortcutWithPath", hr);
  727. return hr;
  728. }
  729. //+---------------------------------------------------------------------------
  730. //
  731. // Function: HrOnCommandCreateShortcut
  732. //
  733. // Purpose: Command handler for the CMIDM_CREATE_SHORTCUT command.
  734. //
  735. // Arguments:
  736. // apidl [in] PIDL array (item 0 is our item to work on)
  737. // cidl [in] Size of the array
  738. // hwndOwner [in] Owner hwnd
  739. //
  740. // Returns:
  741. //
  742. // Author: jeffspr 13 Mar 1998
  743. //
  744. // Notes:
  745. //
  746. HRESULT HrOnCommandCreateShortcut(
  747. LPITEMIDLIST * apidl,
  748. ULONG cidl,
  749. HWND hwndOwner,
  750. LPSHELLFOLDER psf)
  751. {
  752. HRESULT hr = S_OK;
  753. hr = HrCreateShortcutWithPath( apidl,
  754. cidl,
  755. hwndOwner,
  756. psf,
  757. NULL);
  758. TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnCommandCreateShortcut");
  759. return hr;
  760. }