Leaked source code of windows server 2003
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.

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