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.

886 lines
22 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1995.
  5. //
  6. // File: sfolder.cxx
  7. //
  8. // Contents: Implementation of IShellFolder
  9. //
  10. // History: 13-Dec-95 BruceFo Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "headers.hxx"
  14. #pragma hdrstop
  15. #include "dutil.hxx"
  16. #include "enum.hxx"
  17. #include "menuutil.hxx"
  18. #include "menu.hxx"
  19. #include "menusp.hxx"
  20. #include "menubg.hxx"
  21. #include "sdetails.hxx"
  22. #include "sfolder.hxx"
  23. #include "shares.h"
  24. #include "shares.hxx"
  25. #include "util.hxx"
  26. #include "xicon.hxx"
  27. #include "resource.h"
  28. //////////////////////////////////////////////////////////////////////////////
  29. void
  30. FSSetStatusText(
  31. HWND hwndOwner,
  32. LPTSTR* ppszText,
  33. int iStart,
  34. int iEnd);
  35. //////////////////////////////////////////////////////////////////////////////
  36. STDMETHODIMP
  37. CSharesSF::ParseDisplayName(
  38. HWND hwndOwner,
  39. LPBC pbc,
  40. LPOLESTR lpszDisplayName,
  41. ULONG* pchEaten,
  42. LPITEMIDLIST* ppidlOutm,
  43. ULONG* pdwAttributes
  44. )
  45. {
  46. return E_NOTIMPL;
  47. }
  48. STDMETHODIMP
  49. CSharesSF::GetAttributesOf(
  50. UINT cidl,
  51. LPCITEMIDLIST* apidl,
  52. ULONG* pdwInOut
  53. )
  54. {
  55. // There are four types of object: New object, View NetWare, View Mac,
  56. // and regular share. If there is a single selection, then the operations
  57. // possible are:
  58. // New share: open, create shortcut
  59. // View NetWare: open, create shortcut
  60. // View Mac: open, create shortcut
  61. // a share: delete, properties
  62. // If there are different types of objects multiply selected, then
  63. // the items must all be shares, or there are no allowed operations.
  64. // For shares, the only multiple-select operation allowed is delete.
  65. ULONG fMask = 0;
  66. if (cidl == 0)
  67. {
  68. // What things in general can be done in the folder? Return a
  69. // mask of everything possible.
  70. fMask = SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_LINK;
  71. }
  72. else if (cidl == 1)
  73. {
  74. LPIDSHARE pids = (LPIDSHARE)apidl[0];
  75. if (Share_IsShare(pids))
  76. {
  77. fMask = SFGAO_CANDELETE | SFGAO_HASPROPSHEET;
  78. if (!(Share_GetType(pids) & STYPE_SPECIAL))
  79. {
  80. fMask |= SFGAO_CANRENAME;
  81. }
  82. }
  83. else
  84. {
  85. fMask = SFGAO_CANLINK;
  86. }
  87. }
  88. else if (cidl > 1)
  89. {
  90. UINT i;
  91. for (i = 0; i < cidl; i++)
  92. {
  93. LPIDSHARE pids = (LPIDSHARE)apidl[i];
  94. if (!Share_IsShare(pids))
  95. {
  96. break;
  97. }
  98. }
  99. if (i == cidl)
  100. {
  101. fMask |= SFGAO_CANDELETE;
  102. }
  103. }
  104. *pdwInOut &= fMask;
  105. return S_OK;
  106. }
  107. STDMETHODIMP
  108. CSharesSF::GetUIObjectOf(
  109. HWND hwndOwner,
  110. UINT cidl,
  111. LPCITEMIDLIST* apidl,
  112. REFIID riid,
  113. UINT* prgfInOut,
  114. LPVOID* ppvOut
  115. )
  116. {
  117. CShares* This = IMPL(CShares,m_ShellFolder,this);
  118. HRESULT hr = E_NOINTERFACE;
  119. *ppvOut = NULL;
  120. if (cidl == 1 && IsEqualIID(riid, IID_IExtractIcon))
  121. {
  122. LPIDSHARE pids = (LPIDSHARE)apidl[0];
  123. CSharesEI* pObj = new CSharesEI(Share_GetFlags(pids), Share_GetType(pids));
  124. if (NULL == pObj)
  125. {
  126. return E_OUTOFMEMORY;
  127. }
  128. hr = pObj->QueryInterface(riid, ppvOut);
  129. pObj->Release();
  130. }
  131. #ifdef UNICODE
  132. else if (cidl == 1 && IsEqualIID(riid, IID_IExtractIconA))
  133. {
  134. LPIDSHARE pids = (LPIDSHARE)apidl[0];
  135. CSharesEIA* pObj = new CSharesEIA(Share_GetFlags(pids), Share_GetType(pids));
  136. if (NULL == pObj)
  137. {
  138. return E_OUTOFMEMORY;
  139. }
  140. hr = pObj->QueryInterface(riid, ppvOut);
  141. pObj->Release();
  142. }
  143. #endif // UNICODE
  144. else if (cidl > 0 && IsEqualIID(riid, IID_IContextMenu))
  145. {
  146. // Create a context menu for selected items. If there is only one
  147. // item, then the context menu is based on that object and is
  148. // CSharesCM for shares and CSharesCMSpecial for special objects.
  149. // If there is a multiple selection, then the selection must all be
  150. // shares, in which case the context-menu is CSharesCM, else there
  151. // is no context menu!
  152. if (This->m_level < 2)
  153. {
  154. // user has insufficient privilege to perform any operations.
  155. return E_NOINTERFACE;
  156. }
  157. IUnknown* punk = NULL;
  158. if (cidl == 1)
  159. {
  160. LPIDSHARE pids = (LPIDSHARE)apidl[0];
  161. if (Share_IsShare(pids))
  162. {
  163. CSharesCM* pObj = new CSharesCM(hwndOwner);
  164. if (NULL == pObj)
  165. {
  166. return E_OUTOFMEMORY;
  167. }
  168. hr = pObj->InitInstance(This->m_pszMachine, cidl, apidl, this);
  169. if (FAILED(hr))
  170. {
  171. return hr;
  172. }
  173. punk = (IUnknown*)pObj;
  174. }
  175. #ifdef WIZARDS
  176. else
  177. {
  178. CSharesCMSpecial* pObj = new CSharesCMSpecial(hwndOwner);
  179. if (NULL == pObj)
  180. {
  181. return E_OUTOFMEMORY;
  182. }
  183. hr = pObj->InitInstance(This->m_pszMachine, apidl[0], this);
  184. if (FAILED(hr))
  185. {
  186. return hr;
  187. }
  188. punk = (IUnknown*)pObj;
  189. }
  190. #endif // WIZARDS
  191. }
  192. else if (cidl > 1)
  193. {
  194. UINT i;
  195. for (i = 0; i < cidl; i++)
  196. {
  197. LPIDSHARE pids = (LPIDSHARE)apidl[i];
  198. if (!Share_IsShare(pids))
  199. {
  200. break;
  201. }
  202. }
  203. if (i == cidl)
  204. {
  205. CSharesCM* pObj = new CSharesCM(hwndOwner);
  206. if (NULL == pObj)
  207. {
  208. return E_OUTOFMEMORY;
  209. }
  210. hr = pObj->InitInstance(This->m_pszMachine, cidl, apidl, this);
  211. if (FAILED(hr))
  212. {
  213. return hr;
  214. }
  215. punk = (IUnknown*)pObj;
  216. }
  217. else
  218. {
  219. return E_FAIL;
  220. }
  221. }
  222. appAssert(NULL != punk);
  223. hr = punk->QueryInterface(riid, ppvOut);
  224. punk->Release();
  225. }
  226. else if (cidl > 0 && IsEqualIID(riid, IID_IDataObject))
  227. {
  228. hr = CIDLData_CreateFromIDArray(
  229. This->m_pidl,
  230. cidl,
  231. apidl,
  232. (LPDATAOBJECT *)ppvOut);
  233. }
  234. return hr;
  235. }
  236. STDMETHODIMP
  237. CSharesSF::EnumObjects(
  238. HWND hwndOwner,
  239. DWORD grfFlags,
  240. LPENUMIDLIST* ppenumUnknown
  241. )
  242. {
  243. CShares* This = IMPL(CShares,m_ShellFolder,this);
  244. HRESULT hr = E_FAIL;
  245. *ppenumUnknown = NULL;
  246. if (!(grfFlags & SHCONTF_NONFOLDERS))
  247. {
  248. return hr;
  249. }
  250. appAssert(0 != This->m_level);
  251. CSharesEnum* pEnum = new CSharesEnum(This->m_pszMachine, This->m_level);
  252. if (NULL == pEnum)
  253. {
  254. return E_OUTOFMEMORY;
  255. }
  256. hr = pEnum->Init(grfFlags);
  257. if (FAILED(hr))
  258. {
  259. return hr;
  260. }
  261. hr = pEnum->QueryInterface(IID_IEnumIDList, (LPVOID*)ppenumUnknown);
  262. pEnum->Release();
  263. return hr;
  264. }
  265. STDMETHODIMP
  266. CSharesSF::BindToObject(
  267. LPCITEMIDLIST pidl,
  268. LPBC pbc,
  269. REFIID riid,
  270. LPVOID* ppvOut
  271. )
  272. {
  273. //
  274. // Shares folder doesn't contain sub-folders
  275. //
  276. *ppvOut = NULL;
  277. return E_FAIL;
  278. }
  279. // not used in Win95
  280. STDMETHODIMP
  281. CSharesSF::BindToStorage(
  282. LPCITEMIDLIST pidl,
  283. LPBC pbcReserved,
  284. REFIID riid,
  285. LPVOID* ppvOut
  286. )
  287. {
  288. *ppvOut = NULL;
  289. return E_NOTIMPL;
  290. }
  291. #define PlusMinus(x) (((x) < 0) ? -1 : ( ((x) > 0) ? 1 : 0 ))
  292. int
  293. CSharesSF::_CompareOne(
  294. DWORD iCol,
  295. LPIDSHARE pids1,
  296. LPIDSHARE pids2
  297. )
  298. {
  299. switch (iCol)
  300. {
  301. case ICOL2_NAME:
  302. return lstrcmpi(Share_GetName(pids1), Share_GetName(pids2));
  303. case ICOL2_COMMENT:
  304. return lstrcmpi(Share_GetComment(pids1), Share_GetComment(pids2));
  305. case ICOL2_PATH:
  306. return lstrcmpi(Share_GetPath(pids1), Share_GetPath(pids2));
  307. case ICOL2_MAXUSES:
  308. {
  309. DWORD max1 = Share_GetMaxUses(pids1);
  310. DWORD max2 = Share_GetMaxUses(pids2);
  311. if (max1 == SHI_USES_UNLIMITED && max2 == SHI_USES_UNLIMITED)
  312. {
  313. return 0;
  314. }
  315. else if (max1 == SHI_USES_UNLIMITED)
  316. {
  317. return 1;
  318. }
  319. else if (max2 == SHI_USES_UNLIMITED)
  320. {
  321. return -1;
  322. }
  323. else
  324. {
  325. return max1 - max2;
  326. }
  327. }
  328. default: appAssert(!"Illegal column"); return 0;
  329. }
  330. }
  331. STDMETHODIMP
  332. CSharesSF::CompareIDs(
  333. LPARAM iCol,
  334. LPCITEMIDLIST pidl1,
  335. LPCITEMIDLIST pidl2
  336. )
  337. {
  338. CShares* This = IMPL(CShares,m_ShellFolder,this);
  339. // If one item is a special item, then put it ahead of the other one.
  340. // If they are both special items, sort on name.
  341. LPIDSHARE pids1 = (LPIDSHARE)pidl1;
  342. LPIDSHARE pids2 = (LPIDSHARE)pidl2;
  343. int iCmp;
  344. #ifdef WIZARDS
  345. if (Share_IsSpecial(pids1))
  346. {
  347. if (Share_IsSpecial(pids2))
  348. {
  349. // both special; sort on name
  350. return ResultFromShort(lstrcmpi(Share_GetName(pids1),
  351. Share_GetName(pids2)));
  352. }
  353. else
  354. {
  355. return ResultFromShort(-1);
  356. }
  357. }
  358. else if (Share_IsSpecial(pids2))
  359. {
  360. return ResultFromShort(1);
  361. }
  362. #endif // WIZARDS
  363. // Documentation says iCol is always zero, but that is wrong! It will
  364. // be non-zero in case the user has clicked on a column heading to sort
  365. // the column. In general, we want the entire item to be equal before we
  366. // return 0 for equality. To do this, we first check the chosen element.
  367. // If it is not equal, return the value. Otherwise, check all elements in
  368. // this standard order:
  369. // name
  370. // comment
  371. // path
  372. // max uses
  373. // current uses
  374. // Only after all these checks return 0 (equality) do we return 0 (equality)
  375. iCmp = _CompareOne((ULONG)iCol, pids1, pids2);
  376. if (iCmp != 0)
  377. {
  378. return ResultFromShort(PlusMinus(iCmp));
  379. }
  380. // now, check each in turn
  381. iCmp = _CompareOne(ICOL2_NAME, pids1, pids2);
  382. if (iCmp != 0)
  383. {
  384. return ResultFromShort(PlusMinus(iCmp));
  385. }
  386. iCmp = _CompareOne(ICOL2_COMMENT, pids1, pids2);
  387. if (iCmp != 0)
  388. {
  389. return ResultFromShort(PlusMinus(iCmp));
  390. }
  391. if (This->m_level == 2)
  392. {
  393. iCmp = _CompareOne(ICOL2_PATH, pids1, pids2);
  394. if (iCmp != 0)
  395. {
  396. return ResultFromShort(PlusMinus(iCmp));
  397. }
  398. iCmp = _CompareOne(ICOL2_MAXUSES, pids1, pids2);
  399. if (iCmp != 0)
  400. {
  401. return ResultFromShort(PlusMinus(iCmp));
  402. }
  403. }
  404. return 0; // the same!
  405. }
  406. STDMETHODIMP
  407. CSharesSF::CreateViewObject(
  408. HWND hwnd,
  409. REFIID riid,
  410. LPVOID* ppvOut
  411. )
  412. {
  413. CShares* This = IMPL(CShares,m_ShellFolder,this);
  414. HRESULT hr = E_NOINTERFACE;
  415. *ppvOut = NULL;
  416. if (IsEqualIID(riid, IID_IShellView))
  417. {
  418. CSFV csfv =
  419. {
  420. sizeof(CSFV), // cbSize
  421. (IShellFolder*)this, // pshf
  422. NULL, // psvOuter
  423. NULL, // pidl to monitor (NULL == all)
  424. SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_UPDATEITEM, // events
  425. _SFVCallBack, // pfnCallback
  426. FVM_DETAILS
  427. };
  428. hr = SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW *)ppvOut);
  429. }
  430. else if (IsEqualIID(riid, IID_IShellDetails))
  431. {
  432. appAssert(This->m_level != 0);
  433. CSharesSD* pObj = new CSharesSD(hwnd, This->m_level);
  434. if (NULL == pObj)
  435. {
  436. return E_OUTOFMEMORY;
  437. }
  438. hr = pObj->QueryInterface(riid, ppvOut);
  439. pObj->Release();
  440. }
  441. else if (IsEqualIID(riid, IID_IContextMenu))
  442. {
  443. // Create a context menu for the background
  444. CSharesCMBG* pObj = new CSharesCMBG(hwnd, This->m_pszMachine, This->m_level);
  445. if (NULL == pObj)
  446. {
  447. return E_OUTOFMEMORY;
  448. }
  449. hr = pObj->QueryInterface(riid, ppvOut);
  450. pObj->Release();
  451. }
  452. return hr;
  453. }
  454. STDMETHODIMP
  455. CSharesSF::GetDisplayNameOf(
  456. LPCITEMIDLIST pidl,
  457. DWORD uFlags,
  458. LPSTRRET lpName
  459. )
  460. {
  461. CShares* This = IMPL(CShares,m_ShellFolder,this);
  462. LPIDSHARE pids = (LPIDSHARE)pidl;
  463. if (uFlags == SHGDN_FORPARSING)
  464. {
  465. return E_NOTIMPL; // don't support parsing.
  466. }
  467. else if (uFlags == SHGDN_INFOLDER)
  468. {
  469. return STRRETCopy(Share_GetName(pids), lpName);
  470. }
  471. else if (uFlags == SHGDN_NORMAL)
  472. {
  473. if (NULL == This->m_pszMachine)
  474. {
  475. return STRRETCopy(Share_GetName(pids), lpName);
  476. }
  477. else
  478. {
  479. LPWSTR pszMachine = This->m_pszMachine;
  480. if (pszMachine[0] == TEXT('\\') && pszMachine[1] == TEXT('\\'))
  481. {
  482. pszMachine += 2;
  483. }
  484. WCHAR szBuf[MAX_PATH];
  485. szBuf[0] = L'\0';
  486. MyFormatMessage(
  487. MSG_TEMPLATE_WITH_ON,
  488. szBuf,
  489. ARRAYLEN(szBuf),
  490. pszMachine,
  491. Share_GetName(pids));
  492. #ifdef UNICODE
  493. LPTSTR pszCopy = (LPTSTR)SHAlloc((lstrlen(szBuf)+1) * sizeof(TCHAR));
  494. if (pszCopy)
  495. {
  496. wcscpy(pszCopy, szBuf);
  497. lpName->uType = STRRET_OLESTR;
  498. lpName->pOleStr = pszCopy;
  499. }
  500. else
  501. {
  502. lpName->uType = STRRET_CSTR;
  503. lpName->cStr[0] = '\0';
  504. }
  505. #else
  506. lpName->uType = STRRET_CSTR;
  507. lstrcpyn(lpName->cStr, szBuf, ARRAYSIZE(lpName->cStr));
  508. SHFree(pszRet);
  509. #endif
  510. return S_OK;
  511. }
  512. }
  513. else
  514. {
  515. return E_INVALIDARG;
  516. }
  517. }
  518. STDMETHODIMP
  519. CSharesSF::SetNameOf(
  520. HWND hwndOwner,
  521. LPCITEMIDLIST pidl,
  522. LPCOLESTR lpszName,
  523. DWORD uFlags,
  524. LPITEMIDLIST* ppidlOut
  525. )
  526. {
  527. CShares* This = IMPL(CShares,m_ShellFolder,this);
  528. if (uFlags != SHGDN_INFOLDER)
  529. {
  530. return E_NOTIMPL;
  531. }
  532. if (NULL == lpszName || L'\0' == *lpszName)
  533. {
  534. // can't change name to nothing
  535. MessageBeep(0);
  536. return E_FAIL;
  537. }
  538. NET_API_STATUS ret;
  539. WCHAR szBuf[MAX_PATH];
  540. LPSHARE_INFO_502 pInfo;
  541. LPIDSHARE pids = (LPIDSHARE)pidl;
  542. // Get information about the existing share before deleting it.
  543. ret = NetShareGetInfo(This->m_pszMachine, Share_GetName(pids), 502, (LPBYTE*)&pInfo);
  544. if (ret != NERR_Success)
  545. {
  546. DisplayError(hwndOwner, IERR_CANT_DEL_SHARE, ret, Share_GetName(pids));
  547. return HRESULT_FROM_WIN32(ret);
  548. }
  549. // Validate the new share name
  550. // Trying to create a reserved share?
  551. if ( (0 == _wcsicmp(g_szIpcShare, lpszName))
  552. || (0 == _wcsicmp(g_szAdminShare, lpszName)))
  553. {
  554. MyErrorDialog(hwndOwner, MSG_ADDSPECIAL2);
  555. NetApiBufferFree(pInfo);
  556. return E_FAIL;
  557. }
  558. HRESULT hrTemp;
  559. if (!IsValidShareName(lpszName, &hrTemp))
  560. {
  561. MyErrorDialog(hwndOwner, hrTemp);
  562. NetApiBufferFree(pInfo);
  563. return E_FAIL;
  564. }
  565. // Check to see that the same share isn't already used, for either the
  566. // same path or for another path.
  567. SHARE_INFO_2* pInfo2;
  568. ret = NetShareGetInfo(This->m_pszMachine, (LPWSTR)lpszName, 2, (LPBYTE*)&pInfo2);
  569. if (ret == NERR_Success)
  570. {
  571. // Is it already shared for the same path?
  572. if (0 == _wcsicmp(pInfo2->shi2_path, pInfo->shi502_path))
  573. {
  574. MyErrorDialog(hwndOwner, IERR_AlreadyExists, lpszName);
  575. NetApiBufferFree(pInfo);
  576. NetApiBufferFree(pInfo2);
  577. return TRUE;
  578. }
  579. // Shared for a different path. Ask the user if they wish to delete
  580. // the old share and create the new one using the name.
  581. DWORD id = ConfirmReplaceShare(hwndOwner, lpszName, pInfo2->shi2_path, pInfo->shi502_path);
  582. if (id == IDNO || id == IDCANCEL) // FEATURE: should be only yes/no
  583. {
  584. NetApiBufferFree(pInfo);
  585. NetApiBufferFree(pInfo2);
  586. return E_FAIL;
  587. }
  588. // User said to replace the old share. Do it.
  589. ret = NetShareDel(This->m_pszMachine, (LPWSTR)lpszName, 0);
  590. if (ret != NERR_Success)
  591. {
  592. DisplayError(hwndOwner, IERR_CANT_DEL_SHARE, ret, (LPWSTR)lpszName);
  593. NetApiBufferFree(pInfo);
  594. NetApiBufferFree(pInfo2);
  595. return FALSE;
  596. }
  597. else
  598. {
  599. SHChangeNotify(SHCNE_NETUNSHARE, SHCNF_PATH, pInfo2->shi2_path, NULL);
  600. }
  601. NetApiBufferFree(pInfo2);
  602. }
  603. // Check for downlevel accessibility
  604. ULONG nType;
  605. if (NERR_Success != NetpPathType(NULL, (LPWSTR)lpszName, &nType, INPT_FLAGS_OLDPATHS))
  606. {
  607. DWORD id = MyConfirmationDialog(
  608. hwndOwner,
  609. IERR_InaccessibleByDos,
  610. MB_YESNO | MB_ICONEXCLAMATION,
  611. lpszName);
  612. if (id == IDNO)
  613. {
  614. return TRUE;
  615. }
  616. }
  617. // delete the existing share
  618. ret = NetShareDel(This->m_pszMachine, Share_GetName(pids), 0);
  619. if (ret != NERR_Success)
  620. {
  621. NetApiBufferFree(pInfo);
  622. DisplayError(hwndOwner, IERR_CANT_DEL_SHARE, ret, Share_GetName(pids));
  623. return HRESULT_FROM_WIN32(ret);
  624. }
  625. // Create a new share with the new name.
  626. LPWSTR ptmp = pInfo->shi502_netname;
  627. pInfo->shi502_netname = (LPWSTR)lpszName; // cast away const
  628. ret = NetShareAdd(This->m_pszMachine, 502, (LPBYTE)pInfo, NULL);
  629. if (ret != NERR_Success)
  630. {
  631. pInfo->shi502_netname = ptmp;
  632. NetApiBufferFree(pInfo);
  633. DisplayError(hwndOwner, IERR_CANT_ADD_SHARE, ret, (LPWSTR)lpszName); // cast away const
  634. return HRESULT_FROM_WIN32(ret);
  635. }
  636. // Ok, now I've renamed it. So, fill an ID list with the new guy, and
  637. // return it in *ppidlOut.
  638. HRESULT hr = S_OK;
  639. if (NULL != ppidlOut)
  640. {
  641. IDSHARE ids;
  642. FillID2(&ids, (LPSHARE_INFO_2)pInfo); // ignore security at end of level 502
  643. *ppidlOut = ILClone((LPCITEMIDLIST)(&ids));
  644. if (NULL == *ppidlOut)
  645. {
  646. hr = E_OUTOFMEMORY;
  647. }
  648. }
  649. // force a view refresh
  650. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, NULL, 0);
  651. pInfo->shi502_netname = ptmp;
  652. NetApiBufferFree(pInfo);
  653. return hr;
  654. }
  655. //
  656. // Callback from SHCreateShellFolderViewEx
  657. //
  658. HRESULT CALLBACK
  659. CSharesSF::_SFVCallBack(
  660. LPSHELLVIEW psvOuter,
  661. LPSHELLFOLDER psf,
  662. HWND hwndOwner,
  663. UINT uMsg,
  664. WPARAM wParam,
  665. LPARAM lParam
  666. )
  667. {
  668. CShares* This = IMPL(CShares,m_ShellFolder,psf);
  669. HRESULT hr = S_OK; // assume no error
  670. switch (uMsg)
  671. {
  672. case DVM_UPDATESTATUSBAR:
  673. {
  674. IShellBrowser* psb = FileCabinet_GetIShellBrowser(hwndOwner);
  675. UINT cidl = ShellFolderView_GetSelectedCount(hwndOwner);
  676. if (cidl == 1)
  677. {
  678. LPITEMIDLIST *apidl;
  679. LPIDSHARE pids;
  680. LPTSTR lpsz = TEXT("");
  681. ShellFolderView_GetSelectedObjects(hwndOwner, &apidl);
  682. if (apidl)
  683. {
  684. pids = (LPIDSHARE)apidl[0];
  685. if (Share_IsShare(pids))
  686. {
  687. lpsz = Share_GetComment(pids);
  688. }
  689. FSSetStatusText(hwndOwner, &lpsz, 0, 0);
  690. LocalFree(apidl);
  691. }
  692. }
  693. else
  694. {
  695. hr = E_FAIL;
  696. }
  697. break;
  698. }
  699. case DVM_MERGEMENU:
  700. {
  701. appDebugOut((DEB_TRACE, "DVM_MERGEMENU\n"));
  702. appAssert(This->m_pMenuBg == NULL);
  703. hr = psf->CreateViewObject(hwndOwner, IID_IContextMenu, (LPVOID*)&This->m_pMenuBg);
  704. if (SUCCEEDED(hr))
  705. {
  706. LPQCMINFO pqcm = (LPQCMINFO)lParam;
  707. hr = This->m_pMenuBg->QueryContextMenu(
  708. pqcm->hmenu,
  709. pqcm->indexMenu,
  710. pqcm->idCmdFirst,
  711. pqcm->idCmdLast,
  712. CMF_DVFILE);
  713. }
  714. break;
  715. }
  716. case DVM_UNMERGEMENU:
  717. {
  718. appDebugOut((DEB_TRACE, "DVM_UNMERGEMENU\n"));
  719. if (NULL != This->m_pMenuBg)
  720. {
  721. This->m_pMenuBg->Release();
  722. This->m_pMenuBg = NULL;
  723. }
  724. break;
  725. }
  726. case DVM_INVOKECOMMAND:
  727. {
  728. appDebugOut((DEB_TRACE, "DVM_INVOKECOMMAND\n"));
  729. appAssert(This->m_pMenuBg != NULL);
  730. CMINVOKECOMMANDINFO ici =
  731. {
  732. sizeof(ici),
  733. 0, // mask
  734. hwndOwner,
  735. (LPCSTR)wParam,
  736. NULL,
  737. NULL,
  738. 0,
  739. 0,
  740. NULL
  741. };
  742. hr = This->m_pMenuBg->InvokeCommand(&ici);
  743. break;
  744. }
  745. case DVM_GETHELPTEXT:
  746. {
  747. appDebugOut((DEB_TRACE, "DVM_GETHELPTEXT\n"));
  748. hr = This->m_pMenuBg->GetCommandString(LOWORD(wParam), GCS_HELPTEXT, NULL, (LPSTR)lParam, HIWORD(wParam));
  749. break;
  750. }
  751. case DVM_DEFITEMCOUNT:
  752. //
  753. // If DefView times out enumerating items, let it know we probably only
  754. // have about 20 items
  755. //
  756. *(int *)lParam = 20;
  757. break;
  758. case DVM_FSNOTIFY:
  759. {
  760. LPCITEMIDLIST* ppidl = (LPCITEMIDLIST*)wParam;
  761. switch (lParam)
  762. {
  763. case SHCNE_NETSHARE:
  764. case SHCNE_NETUNSHARE:
  765. // a share was added, removed, or changed. Force a view refresh.
  766. // SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, NULL, 0);
  767. return S_OK;
  768. }
  769. break;
  770. }
  771. default:
  772. hr = E_FAIL;
  773. }
  774. return hr;
  775. }