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.

1223 lines
28 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "shitemid.h"
  4. #include "ids.h"
  5. #include "hwcmmn.h"
  6. #include "mtptr.h"
  7. #ifdef DEBUG
  8. DWORD CMtPtRemote::_cMtPtRemote = 0;
  9. DWORD CShare::_cShare = 0;
  10. #endif
  11. ///////////////////////////////////////////////////////////////////////////////
  12. // Public methods
  13. ///////////////////////////////////////////////////////////////////////////////
  14. HRESULT CMtPtRemote::SetLabel(HWND hwnd, LPCTSTR pszLabel)
  15. {
  16. TraceMsg(TF_MOUNTPOINT, "CMtPtRemote::SetLabel: for '%s'", _GetNameDebug());
  17. RSSetTextValue(NULL, TEXT("_LabelFromReg"), pszLabel,
  18. REG_OPTION_NON_VOLATILE);
  19. // we notify for only the current drive (no folder mounted drive)
  20. SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_PATH, _GetName(), _GetName());
  21. return S_OK;
  22. }
  23. BOOL CMtPtRemote::IsDisconnectedNetDrive()
  24. {
  25. return !_IsConnected();
  26. }
  27. // Expensive, do not call for nothing
  28. BOOL CMtPtRemote::IsFormatted()
  29. {
  30. return (0xFFFFFFFF != GetFileAttributes(_GetNameForFctCall()));
  31. }
  32. BOOL CMtPtRemote::_GetComputerDisplayNameFromReg(LPTSTR pszLabel, DWORD cchLabel)
  33. {
  34. *pszLabel = 0;
  35. return (RSGetTextValue(NULL, TEXT("_ComputerDisplayName"), pszLabel, &cchLabel));
  36. }
  37. HRESULT CMtPtRemote::_GetDefaultUNCDisplayName(LPTSTR pszLabel, DWORD cchLabel)
  38. {
  39. HRESULT hr = E_FAIL;
  40. LPTSTR pszShare, pszT;
  41. TCHAR szTempUNCPath[MAX_PATH];
  42. pszLabel[0] = TEXT('\0');
  43. if (!_pshare->fFake)
  44. {
  45. // Why would it not be a UNC name?
  46. if (PathIsUNC(_GetUNCName()))
  47. {
  48. // Now we need to handle 3 cases.
  49. // The normal case: \\pyrex\user
  50. // The Netware setting root: \\strike\sys\public\dist
  51. // The Netware CD? \\stike\sys \public\dist
  52. lstrcpyn(szTempUNCPath, _GetUNCName(), ARRAYSIZE(szTempUNCPath));
  53. pszT = StrChr(szTempUNCPath, TEXT(' '));
  54. while (pszT)
  55. {
  56. pszT++;
  57. if (*pszT == TEXT('\\'))
  58. {
  59. // The netware case of \\strike\sys \public\dist
  60. *--pszT = 0;
  61. break;
  62. }
  63. pszT = StrChr(pszT, TEXT(' '));
  64. }
  65. pszShare = StrRChr(szTempUNCPath, NULL, TEXT('\\'));
  66. if (pszShare)
  67. {
  68. *pszShare++ = 0;
  69. PathMakePretty(pszShare);
  70. // pszServer should always start at char 2.
  71. if (szTempUNCPath[2])
  72. {
  73. LPTSTR pszServer, pszSlash;
  74. pszServer = &szTempUNCPath[2];
  75. for (pszT = pszServer; pszT != NULL; pszT = pszSlash)
  76. {
  77. pszSlash = StrChr(pszT, TEXT('\\'));
  78. if (pszSlash)
  79. *pszSlash = 0;
  80. PathMakePretty(pszT);
  81. if (pszSlash)
  82. *pszSlash++ = TEXT('\\');
  83. }
  84. TCHAR szDisplay[MAX_PATH];
  85. hr = SHGetComputerDisplayName(pszServer, 0x0, szDisplay, ARRAYSIZE(szDisplay));
  86. if (FAILED(hr))
  87. {
  88. *szDisplay = 0;
  89. }
  90. if (SUCCEEDED(hr))
  91. {
  92. LPTSTR pszLabel2 = ShellConstructMessageString(HINST_THISDLL,
  93. MAKEINTRESOURCE(IDS_UNC_FORMAT), pszShare, szDisplay);
  94. if (pszLabel2)
  95. {
  96. lstrcpyn(pszLabel, pszLabel2, cchLabel);
  97. LocalFree(pszLabel2);
  98. }
  99. else
  100. {
  101. *pszLabel = TEXT('\0');
  102. }
  103. }
  104. }
  105. }
  106. }
  107. }
  108. return hr;
  109. }
  110. int CMtPtRemote::GetDriveFlags()
  111. {
  112. // By default every drive type is ShellOpen, except CD-ROMs
  113. UINT uDriveFlags = DRIVE_SHELLOPEN;
  114. if (_IsAutorun())
  115. {
  116. uDriveFlags |= DRIVE_AUTORUN;
  117. //FEATURE should we set AUTOOPEN based on a flag in the AutoRun.inf???
  118. uDriveFlags |= DRIVE_AUTOOPEN;
  119. }
  120. if (_IsConnected())
  121. {
  122. if ((0 != _dwSpeed) && (_dwSpeed <= SPEED_SLOW))
  123. {
  124. uDriveFlags |= DRIVE_SLOW;
  125. }
  126. }
  127. return TRUE;
  128. }
  129. void CMtPtRemote::_CalcPathSpeed()
  130. {
  131. _dwSpeed = 0;
  132. NETCONNECTINFOSTRUCT nci = {0};
  133. NETRESOURCE nr = {0};
  134. TCHAR szPath[3];
  135. nci.cbStructure = sizeof(nci);
  136. // we are passing in a local drive and MPR does not like us to pass a
  137. // local name as Z:\ but only wants Z:
  138. _GetNameFirstXChar(szPath, 2 + 1);
  139. nr.lpLocalName = szPath;
  140. // dwSpeed is returned by MultinetGetConnectionPerformance
  141. MultinetGetConnectionPerformance(&nr, &nci);
  142. _dwSpeed = nci.dwSpeed;
  143. }
  144. // Imported from fsnotify.c
  145. STDAPI_(void) SHChangeNotifyRegisterAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
  146. //
  147. // If a mount point is for a remote path (UNC), it needs to respond
  148. // to shell changes identified by both UNC and local drive path (L:\).
  149. // This function performs this registration.
  150. //
  151. HRESULT CMtPtRemote::ChangeNotifyRegisterAlias(void)
  152. {
  153. HRESULT hr = E_FAIL;
  154. // Don't wake up sleeping net connections
  155. if (_IsConnected() && !(_pshare->fFake))
  156. {
  157. LPITEMIDLIST pidlLocal = SHSimpleIDListFromPath(_GetName());
  158. if (NULL != pidlLocal)
  159. {
  160. LPITEMIDLIST pidlUNC = SHSimpleIDListFromPath(_GetUNCName());
  161. if (NULL != pidlUNC)
  162. {
  163. SHChangeNotifyRegisterAlias(pidlUNC, pidlLocal);
  164. ILFree(pidlUNC);
  165. hr = NOERROR;
  166. }
  167. ILFree(pidlLocal);
  168. }
  169. }
  170. return hr;
  171. }
  172. ///////////////////////////////////////////////////////////////////////////////
  173. // Temp /////////////////////////////////////////////////////////////////////
  174. ///////////////////////////////////////////////////////////////////////////////
  175. void _UpdateGFAAndGVIInfoHelper(LPCWSTR pszDrive, CShare* pshare)
  176. {
  177. pshare->dwGetFileAttributes = GetFileAttributes(pszDrive);
  178. if (-1 != pshare->dwGetFileAttributes)
  179. {
  180. pshare->fGVIRetValue = GetVolumeInformation(pszDrive,
  181. pshare->szLabel, ARRAYSIZE(pshare->szLabel),
  182. &(pshare->dwSerialNumber), &(pshare->dwMaxFileNameLen),
  183. &(pshare->dwFileSystemFlags), pshare->szFileSysName,
  184. ARRAYSIZE(pshare->szFileSysName));
  185. }
  186. }
  187. struct GFAGVICALL
  188. {
  189. HANDLE hEventBegun;
  190. HANDLE hEventFinish;
  191. WCHAR szDrive[4];
  192. CShare* pshare;
  193. };
  194. void _FreeGFAGVICALL(GFAGVICALL* pgfagvicall)
  195. {
  196. if (pgfagvicall->hEventBegun)
  197. {
  198. CloseHandle(pgfagvicall->hEventBegun);
  199. }
  200. if (pgfagvicall->hEventFinish)
  201. {
  202. CloseHandle(pgfagvicall->hEventFinish);
  203. }
  204. if (pgfagvicall->pshare)
  205. {
  206. pgfagvicall->pshare->Release();
  207. }
  208. if (pgfagvicall)
  209. {
  210. LocalFree(pgfagvicall);
  211. }
  212. }
  213. DWORD WINAPI _UpdateGFAAndGVIInfoCB(LPVOID pv)
  214. {
  215. GFAGVICALL* pgfagvicall = (GFAGVICALL*)pv;
  216. SetEvent(pgfagvicall->hEventBegun);
  217. _UpdateGFAAndGVIInfoHelper(pgfagvicall->szDrive, pgfagvicall->pshare);
  218. SetEvent(pgfagvicall->hEventFinish);
  219. _FreeGFAGVICALL(pgfagvicall);
  220. return 0;
  221. }
  222. GFAGVICALL* CMtPtRemote::_PrepareThreadParam(HANDLE* phEventBegun,
  223. HANDLE* phEventFinish)
  224. {
  225. BOOL fSucceeded = FALSE;
  226. *phEventBegun = NULL;
  227. *phEventFinish = NULL;
  228. GFAGVICALL* pgfagvicall = (GFAGVICALL*)LocalAlloc(LPTR,
  229. sizeof(GFAGVICALL));
  230. if (pgfagvicall)
  231. {
  232. pgfagvicall->hEventBegun = CreateEvent(NULL, FALSE, FALSE, NULL);
  233. if (pgfagvicall->hEventBegun)
  234. {
  235. HANDLE hCurrentProcess = GetCurrentProcess();
  236. if (DuplicateHandle(hCurrentProcess, pgfagvicall->hEventBegun,
  237. hCurrentProcess, phEventBegun, 0, FALSE,
  238. DUPLICATE_SAME_ACCESS))
  239. {
  240. pgfagvicall->hEventFinish = CreateEvent(NULL, FALSE, FALSE, NULL);
  241. if (pgfagvicall->hEventFinish)
  242. {
  243. if (DuplicateHandle(hCurrentProcess,
  244. pgfagvicall->hEventFinish, hCurrentProcess,
  245. phEventFinish, 0, FALSE, DUPLICATE_SAME_ACCESS))
  246. {
  247. _pshare->AddRef();
  248. pgfagvicall->pshare = _pshare;
  249. StrCpyN(pgfagvicall->szDrive, _GetName(),
  250. ARRAYSIZE(pgfagvicall->szDrive));
  251. fSucceeded = TRUE;
  252. }
  253. }
  254. }
  255. }
  256. }
  257. if (!fSucceeded)
  258. {
  259. if (*phEventBegun)
  260. {
  261. CloseHandle(*phEventBegun);
  262. }
  263. if (pgfagvicall)
  264. {
  265. _FreeGFAGVICALL(pgfagvicall);
  266. pgfagvicall = NULL;
  267. }
  268. }
  269. return pgfagvicall;
  270. }
  271. // Expiration: 35 secs (what we shipped W2K with)
  272. BOOL CMtPtRemote::_HaveGFAAndGVIExpired(DWORD dwNow)
  273. {
  274. BOOL fExpired = FALSE;
  275. // Check also for the wrapping case first.
  276. if ((_pshare->dwGFAGVILastCall > dwNow) ||
  277. ((dwNow - _pshare->dwGFAGVILastCall) > 35 * 1000))
  278. {
  279. fExpired = TRUE;
  280. }
  281. else
  282. {
  283. fExpired = FALSE;
  284. }
  285. return fExpired;
  286. }
  287. // We launch a thread so that we won't be jammed on this for more than 10 sec.
  288. // If the thread times out, we use the cache value but do not reset the cache
  289. // values. They're better than nothing. We do reset the cache last tick count
  290. // so that we do not send another thread to jam here before at least 35 sec.
  291. // Return TRUE or FALSE to tell us if timed out or not. For GFA and GVI
  292. // success/failure check (-1 != dwGetFileAttributes) && (_fGVIRetValue)
  293. BOOL CMtPtRemote::_UpdateGFAAndGVIInfo()
  294. {
  295. BOOL fRet = TRUE;
  296. DWORD dwNow = GetTickCount();
  297. if (_HaveGFAAndGVIExpired(dwNow))
  298. {
  299. _pshare->dwGFAGVILastCall = dwNow;
  300. BOOL fGoSync = TRUE;
  301. HANDLE hEventBegun;
  302. HANDLE hEventFinish;
  303. GFAGVICALL* pgfagvicall = _PrepareThreadParam(&hEventBegun,
  304. &hEventFinish);
  305. if (pgfagvicall)
  306. {
  307. if (SHQueueUserWorkItem(_UpdateGFAAndGVIInfoCB, pgfagvicall,
  308. 0, (DWORD_PTR)0, (DWORD_PTR*)NULL, NULL, 0))
  309. {
  310. DWORD dw = WaitForSingleObject(hEventFinish, 10 * 1000);
  311. if (WAIT_TIMEOUT == dw)
  312. {
  313. // we timed out!
  314. fRet = FALSE;
  315. if (WAIT_OBJECT_0 != WaitForSingleObject(
  316. hEventBegun, 0))
  317. {
  318. // since the thread started, we know that
  319. // this call is _really_ slow!
  320. fGoSync = FALSE;
  321. }
  322. else
  323. {
  324. // our work item was never queued, so we
  325. // fall through to the fGoSync case below
  326. }
  327. }
  328. }
  329. else
  330. {
  331. _FreeGFAGVICALL(pgfagvicall);
  332. }
  333. CloseHandle(hEventBegun);
  334. CloseHandle(hEventFinish);
  335. }
  336. if (fGoSync)
  337. {
  338. // we should come here if we failed to create our workitem
  339. // or our workitem was never queued
  340. _UpdateGFAAndGVIInfoHelper(_GetName(), _pshare);
  341. fRet = TRUE;
  342. }
  343. }
  344. return fRet;
  345. }
  346. BOOL CMtPtRemote::_GetFileAttributes(DWORD* pdwAttrib)
  347. {
  348. if (_UpdateGFAAndGVIInfo())
  349. {
  350. *pdwAttrib = _pshare->dwGetFileAttributes;
  351. }
  352. else
  353. {
  354. *pdwAttrib = -1;
  355. }
  356. return (-1 != *pdwAttrib);
  357. }
  358. // { DRIVE_ISCOMPRESSIBLE | DRIVE_LFN | DRIVE_SECURITY }
  359. int CMtPtRemote::_GetGVIDriveFlags()
  360. {
  361. int iFlags = 0;
  362. if (_UpdateGFAAndGVIInfo())
  363. {
  364. if (_pshare->fGVIRetValue)
  365. {
  366. // The file attrib we received at the begginning should be
  367. // valid, do not touch the drive for nothing
  368. if (_pshare->dwFileSystemFlags & FS_FILE_COMPRESSION)
  369. {
  370. iFlags |= DRIVE_ISCOMPRESSIBLE;
  371. }
  372. // Volume supports long filename (greater than 8.3)?
  373. if (_pshare->dwMaxFileNameLen > 12)
  374. {
  375. iFlags |= DRIVE_LFN;
  376. }
  377. // Volume supports security?
  378. if (_pshare->dwFileSystemFlags & FS_PERSISTENT_ACLS)
  379. {
  380. iFlags |= DRIVE_SECURITY;
  381. }
  382. }
  383. }
  384. return iFlags;
  385. }
  386. BOOL CMtPtRemote::_GetSerialNumber(DWORD* pdwSerialNumber)
  387. {
  388. BOOL fRet = FALSE;
  389. if (_UpdateGFAAndGVIInfo())
  390. {
  391. if (_pshare->fGVIRetValue)
  392. {
  393. *pdwSerialNumber = _pshare->dwSerialNumber;
  394. fRet = TRUE;
  395. }
  396. }
  397. // No reg stuff
  398. return fRet;
  399. }
  400. BOOL CMtPtRemote::_GetGVILabel(LPTSTR pszLabel, DWORD cchLabel)
  401. {
  402. BOOL fRet = FALSE;
  403. *pszLabel = 0;
  404. if (_UpdateGFAAndGVIInfo())
  405. {
  406. if (_pshare->fGVIRetValue)
  407. {
  408. lstrcpyn(pszLabel, _pshare->szLabel, cchLabel);
  409. fRet = TRUE;
  410. }
  411. }
  412. // No reg stuff
  413. return fRet;
  414. }
  415. BOOL CMtPtRemote::_GetGVILabelOrMixedCaseFromReg(LPTSTR pszLabel, DWORD cchLabel)
  416. {
  417. return _GetGVILabel(pszLabel, cchLabel);
  418. }
  419. BOOL CMtPtRemote::_GetFileSystemFlags(DWORD* pdwFlags)
  420. {
  421. BOOL fRet = FALSE;
  422. *pdwFlags = 0;
  423. if (_UpdateGFAAndGVIInfo())
  424. {
  425. if (_pshare->fGVIRetValue)
  426. {
  427. *pdwFlags = _pshare->dwFileSystemFlags;
  428. fRet = TRUE;
  429. }
  430. }
  431. return fRet;
  432. }
  433. BOOL CMtPtRemote::_GetFileSystemName(LPTSTR pszFileSysName, DWORD cchFileSysName)
  434. {
  435. BOOL fRet = FALSE;
  436. *pszFileSysName = 0;
  437. if (_UpdateGFAAndGVIInfo())
  438. {
  439. if (_pshare->fGVIRetValue)
  440. {
  441. StrCpyN(pszFileSysName, _pshare->szFileSysName, cchFileSysName);
  442. fRet = TRUE;
  443. }
  444. }
  445. return fRet;
  446. }
  447. DWORD CMtPtRemote::GetShellDescriptionID()
  448. {
  449. return SHDID_COMPUTER_NETDRIVE;
  450. }
  451. ///////////////////////////////////////////////////////////////////////////////
  452. // New //////////////////////////////////////////////////////////////////////
  453. ///////////////////////////////////////////////////////////////////////////////
  454. UINT CMtPtRemote::_GetAutorunIcon(LPTSTR pszModule, DWORD cchModule)
  455. {
  456. int iIcon = -1;
  457. if (RSGetTextValue(TEXT("_Autorun\\DefaultIcon"), NULL, pszModule,
  458. &cchModule))
  459. {
  460. iIcon = PathParseIconLocation(pszModule);
  461. }
  462. return iIcon;
  463. }
  464. UINT CMtPtRemote::GetIcon(LPTSTR pszModule, DWORD cchModule)
  465. {
  466. BOOL fFoundIt = FALSE;
  467. UINT iIcon = II_DRIVENET;
  468. *pszModule = 0;
  469. // Autorun first
  470. // Fancy icon (Autoplay) second
  471. // Legacy drive icons last
  472. if (_IsAutorun())
  473. {
  474. iIcon = _GetAutorunIcon(pszModule, cchModule);
  475. if (-1 != iIcon)
  476. {
  477. fFoundIt = TRUE;
  478. }
  479. }
  480. if (!fFoundIt)
  481. {
  482. if (_pszLegacyRegIcon)
  483. {
  484. if (RSGetTextValue(TEXT("DefaultIcon"), NULL, pszModule,
  485. &cchModule))
  486. {
  487. iIcon = PathParseIconLocation(pszModule);
  488. }
  489. else
  490. {
  491. *pszModule = 0;
  492. }
  493. }
  494. else
  495. {
  496. if (_IsUnavailableNetDrive())
  497. {
  498. iIcon = II_DRIVENETDISABLED;
  499. }
  500. }
  501. }
  502. if (*pszModule)
  503. TraceMsg(TF_MOUNTPOINT, "CMtPtRemote::GetIcon: for '%s', chose '%s', '%d'", _GetNameDebug(), pszModule, iIcon);
  504. else
  505. TraceMsg(TF_MOUNTPOINT, "CMtPtRemote::GetIcon: for '%s', chose '%d'", _GetNameDebug(), iIcon);
  506. return iIcon;
  507. }
  508. void CMtPtRemote::GetTypeString(LPTSTR pszType, DWORD cchType)
  509. {
  510. int iID;
  511. *pszType = 0;
  512. if (_IsConnected())
  513. {
  514. iID = IDS_DRIVES_NETDRIVE;
  515. }
  516. else
  517. {
  518. iID = IDS_DRIVES_NETUNAVAIL;
  519. }
  520. LoadString(HINST_THISDLL, iID, pszType, cchType);
  521. }
  522. HRESULT CMtPtRemote::GetLabelNoFancy(LPTSTR pszLabel, DWORD cchLabel)
  523. {
  524. HRESULT hr;
  525. if (_UpdateGFAAndGVIInfo())
  526. {
  527. lstrcpyn(pszLabel, _pshare->szLabel, cchLabel);
  528. hr = S_OK;
  529. }
  530. else
  531. {
  532. *pszLabel = 0;
  533. hr = E_FAIL;
  534. }
  535. return hr;
  536. }
  537. HRESULT CMtPtRemote::GetLabel(LPTSTR pszLabel, DWORD cchLabel)
  538. {
  539. HRESULT hres = E_FAIL;
  540. ASSERT(pszLabel);
  541. *pszLabel = 0;
  542. // Do we already have a label from the registry for this volume?
  543. // (the user may have renamed this drive)
  544. if (!_GetLabelFromReg(pszLabel, cchLabel))
  545. {
  546. // No
  547. // Do we have a name from the server?
  548. if (!_GetLabelFromDesktopINI(pszLabel, cchLabel))
  549. {
  550. // No
  551. // We should build up the display name ourselves
  552. hres = _GetDefaultUNCDisplayName(pszLabel, cchLabel);
  553. if (SUCCEEDED(hres) && *pszLabel)
  554. {
  555. hres = S_OK;
  556. }
  557. }
  558. else
  559. {
  560. hres = S_OK;
  561. }
  562. }
  563. else
  564. {
  565. hres = S_OK;
  566. }
  567. if (FAILED(hres))
  568. {
  569. GetTypeString(pszLabel, cchLabel);
  570. hres = S_OK;
  571. }
  572. return hres;
  573. }
  574. HRESULT CMtPtRemote::GetRemotePath(LPWSTR pszPath, DWORD cchPath)
  575. {
  576. *pszPath = 0;
  577. if (!_pshare->fFake)
  578. StrCpyN(pszPath, _pshare->pszRemoteName, cchPath);
  579. return (pszPath[0]) ? S_OK : E_FAIL;
  580. }
  581. ///////////////////////////////////////////////////////////////////////////////
  582. // Connection status
  583. ///////////////////////////////////////////////////////////////////////////////
  584. // We cannot cache the connection status. This is already cached at the redirector level.
  585. // When calling the WNetGetConnection fcts you get what's cache there, no check is actually
  586. // done on the network to see if this information is accurate (OK/Disconnected/Unavailable).
  587. // The information is updated only when the share is actually accessed (e.g: GetFileAttributes)
  588. //
  589. // So we need to always do the calls (fortunately non-expensive) so that we get the most
  590. // up to date info. Otherwise the following was occuring: A user double click a map drive
  591. // from the Explorer's Listview, WNetConnection gets called and we get the OK cached value
  592. // from the redirector. Some other code actually try to access the share, and the redirector
  593. // realize that the share is not there and set its cache to Disconnected. We are queried
  594. // again for the state of the connection to update the icon, if we cached this info we
  595. // return OK, if we ask for it (0.1 sec after the first call to WNetGetConnection) we get
  596. // Disconnected. (stephstm 06/02/99)
  597. void CMtPtRemote::_UpdateWNetGCStatus()
  598. {
  599. TCHAR szRemoteName[MAX_PATH];
  600. DWORD cchRemoteName = ARRAYSIZE(szRemoteName);
  601. TCHAR szPath[3];
  602. // WNetConnection does not take a trailing slash
  603. _dwWNetGCStatus = WNetGetConnection(
  604. _GetNameFirstXChar(szPath, 2 + 1), szRemoteName, &cchRemoteName);
  605. }
  606. BOOL CMtPtRemote::IsUnavailableNetDrive()
  607. {
  608. return _IsUnavailableNetDrive();
  609. }
  610. BOOL CMtPtRemote::_IsUnavailableNetDrive()
  611. {
  612. BOOL fUnavail = TRUE;
  613. BOOL fPrevUnavail = _IsUnavailableNetDriveFromStateVar();
  614. _UpdateWNetGCStatus();
  615. fUnavail = (ERROR_CONNECTION_UNAVAIL == _dwWNetGCStatus);
  616. if (fPrevUnavail != fUnavail)
  617. {
  618. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, _GetName(), NULL);
  619. }
  620. return fUnavail;
  621. }
  622. BOOL CMtPtRemote::_IsUnavailableNetDriveFromStateVar()
  623. {
  624. return (ERROR_CONNECTION_UNAVAIL == _dwWNetGCStatus);
  625. }
  626. BOOL CMtPtRemote::_IsConnected()
  627. {
  628. BOOL fConnected = TRUE;
  629. _UpdateWNetGCStatus();
  630. // This whole if/else statement is the same thing as
  631. // _IsConnectedFromStateVar() except that we will avoid calling
  632. // WNetGetConnection3 if possible (optimization)
  633. if (NO_ERROR != _dwWNetGCStatus)
  634. {
  635. fConnected = FALSE;
  636. }
  637. else
  638. {
  639. DWORD dwSize = sizeof(_wngcs);
  640. TCHAR szPath[3];
  641. _dwWNetGC3Status = WNetGetConnection3(
  642. _GetNameFirstXChar(szPath, 2 + 1), NULL,
  643. WNGC_INFOLEVEL_DISCONNECTED, &_wngcs, &dwSize);
  644. // Did we succeeded the call to WNetGetConnection 3 and it returned
  645. // disconnected?
  646. if (WN_SUCCESS == _dwWNetGC3Status)
  647. {
  648. if (WNGC_DISCONNECTED == _wngcs.dwState)
  649. {
  650. // Yes
  651. fConnected = FALSE;
  652. }
  653. }
  654. else
  655. {
  656. fConnected = FALSE;
  657. }
  658. }
  659. return fConnected;
  660. }
  661. BOOL CMtPtRemote::_IsMountedOnDriveLetter()
  662. {
  663. return TRUE;
  664. }
  665. void CMtPtRemote::_UpdateLabelFromDesktopINI()
  666. {
  667. WCHAR szLabelFromDesktopINI[MAX_MTPTCOMMENT];
  668. if (!GetShellClassInfo(_GetName(), TEXT("NetShareDisplayName"),
  669. szLabelFromDesktopINI, ARRAYSIZE(szLabelFromDesktopINI)))
  670. {
  671. szLabelFromDesktopINI[0] = 0;
  672. }
  673. RSSetTextValue(NULL, TEXT("_LabelFromDesktopINI"),
  674. szLabelFromDesktopINI, REG_OPTION_NON_VOLATILE);
  675. }
  676. void CMtPtRemote::_UpdateAutorunInfo()
  677. {
  678. _pshare->fAutorun = FALSE;
  679. if (_IsAutoRunDrive())
  680. {
  681. if (_ProcessAutoRunFile())
  682. {
  683. _pshare->fAutorun = TRUE;
  684. }
  685. }
  686. if (!_pshare->fAutorun)
  687. {
  688. // Make sure to delete the shell key
  689. RSDeleteSubKey(TEXT("Shell"));
  690. }
  691. }
  692. CMtPtRemote::CMtPtRemote()
  693. {
  694. #ifdef DEBUG
  695. ++_cMtPtRemote;
  696. #endif
  697. }
  698. CMtPtRemote::~CMtPtRemote()
  699. {
  700. if (_pshare)
  701. {
  702. _pshare->Release();
  703. }
  704. #ifdef DEBUG
  705. --_cMtPtRemote;
  706. #endif
  707. }
  708. HRESULT CMtPtRemote::_InitWithoutShareName(LPCWSTR pszName)
  709. {
  710. // Let's make a name
  711. GUID guid;
  712. HRESULT hr = CoCreateGuid(&guid);
  713. if (SUCCEEDED(hr))
  714. {
  715. WCHAR szGUID[sizeof("{00000010-0000-0010-8000-00AA006D2EA4}")];
  716. if (StringFromGUID2(guid, szGUID, ARRAYSIZE(szGUID)))
  717. {
  718. hr = _Init(pszName, szGUID, TRUE);
  719. if (SUCCEEDED(hr))
  720. {
  721. _pshare->fFake = TRUE;
  722. }
  723. }
  724. else
  725. {
  726. hr = E_FAIL;
  727. }
  728. }
  729. return hr;
  730. }
  731. HRESULT CMtPtRemote::_Init(LPCWSTR pszName, LPCWSTR pszShareName,
  732. BOOL fUnavailable)
  733. {
  734. HRESULT hr;
  735. _pshare = _GetOrCreateShareFromID(pszShareName);
  736. if (_pshare)
  737. {
  738. if (fUnavailable)
  739. {
  740. _dwWNetGCStatus = ERROR_CONNECTION_UNAVAIL;
  741. }
  742. lstrcpyn(_szName, pszName, ARRAYSIZE(_szName));
  743. PathAddBackslash(_szName);
  744. // Remote drives uses the Share key for all their stuff. They do not have
  745. // anything interesting specific to the drive letter
  746. RSInitRoot(HKEY_CURRENT_USER, REGSTR_MTPT_ROOTKEY2, _pshare->pszKeyName,
  747. REG_OPTION_NON_VOLATILE);
  748. RSSetTextValue(NULL, TEXT("BaseClass"), TEXT("Drive"));
  749. // Access the drive on first connection of the share
  750. _InitOnlyOnceStuff();
  751. _InitLegacyRegIconAndLabel(FALSE, FALSE);
  752. hr = S_OK;
  753. }
  754. else
  755. {
  756. hr = E_OUTOFMEMORY;
  757. }
  758. return hr;
  759. }
  760. LPCTSTR CMtPtRemote::_GetUNCName()
  761. {
  762. return _pshare->pszRemoteName;
  763. }
  764. void CMtPtRemote::_InitOnlyOnceStuff()
  765. {
  766. if (!RSValueExist(NULL, TEXT("_CommentFromDesktopINI")))
  767. {
  768. // Comment
  769. _UpdateCommentFromDesktopINI();
  770. // Label
  771. _UpdateLabelFromDesktopINI();
  772. // Autorun
  773. _UpdateAutorunInfo();
  774. }
  775. }
  776. int CMtPtRemote::_GetDriveType()
  777. {
  778. return DRIVE_REMOTE;
  779. }
  780. HRESULT CMtPtRemote::GetAssocSystemElement(IAssociationElement **ppae)
  781. {
  782. return AssocElemCreateForClass(&CLSID_AssocSystemElement, L"Drive.Network", ppae);
  783. }
  784. DWORD CMtPtRemote::_GetPathSpeed()
  785. {
  786. if (!_dwSpeed)
  787. {
  788. _CalcPathSpeed();
  789. }
  790. return _dwSpeed;
  791. }
  792. // static
  793. HRESULT CMtPtRemote::_DeleteAllMtPtsAndShares()
  794. {
  795. _csDL.Enter();
  796. for (DWORD dw = 0; dw <26; ++dw)
  797. {
  798. CMtPtRemote* pmtptr = CMountPoint::_rgMtPtDriveLetterNet[dw];
  799. if (pmtptr)
  800. {
  801. pmtptr->Release();
  802. CMountPoint::_rgMtPtDriveLetterNet[dw] = 0;
  803. }
  804. }
  805. if (_hdpaShares)
  806. {
  807. DPA_Destroy(_hdpaShares);
  808. _hdpaShares = NULL;
  809. }
  810. _csDL.Leave();
  811. return S_OK;
  812. }
  813. // static
  814. HRESULT CMtPtRemote::_CreateMtPtRemoteWithoutShareName(LPCWSTR pszMountPoint)
  815. {
  816. HRESULT hr;
  817. CMtPtRemote* pmtptr = new CMtPtRemote();
  818. if (pmtptr)
  819. {
  820. hr = pmtptr->_InitWithoutShareName(pszMountPoint);
  821. if (SUCCEEDED(hr))
  822. {
  823. _csDL.Enter();
  824. CMountPoint::_rgMtPtDriveLetterNet[DRIVEID(pszMountPoint)] =
  825. pmtptr;
  826. _csDL.Leave();
  827. }
  828. else
  829. {
  830. delete pmtptr;
  831. }
  832. }
  833. else
  834. {
  835. hr = E_OUTOFMEMORY;
  836. }
  837. return hr;
  838. }
  839. // static
  840. HRESULT CMtPtRemote::_CreateMtPtRemote(LPCWSTR pszMountPoint,
  841. LPCWSTR pszShareName, BOOL fUnavailable)
  842. {
  843. HRESULT hr;
  844. CMtPtRemote* pmtptr = new CMtPtRemote();
  845. if (pmtptr)
  846. {
  847. hr = pmtptr->_Init(pszMountPoint, pszShareName, fUnavailable);
  848. if (SUCCEEDED(hr))
  849. {
  850. _csDL.Enter();
  851. CMountPoint::_rgMtPtDriveLetterNet[DRIVEID(pszMountPoint)] =
  852. pmtptr;
  853. _csDL.Leave();
  854. }
  855. else
  856. {
  857. delete pmtptr;
  858. }
  859. }
  860. else
  861. {
  862. hr = E_OUTOFMEMORY;
  863. }
  864. return hr;
  865. }
  866. // static
  867. CShare* CMtPtRemote::_GetOrCreateShareFromID(LPCWSTR pszShareName)
  868. {
  869. CShare* pshare = NULL;
  870. _csDL.Enter();
  871. DWORD c = DPA_GetPtrCount(_hdpaShares);
  872. for (DWORD dw = 0; dw < c; ++dw)
  873. {
  874. pshare = (CShare*)DPA_GetPtr(_hdpaShares, dw);
  875. if (pshare)
  876. {
  877. if (!lstrcmpi(pshare->pszRemoteName, pszShareName))
  878. {
  879. pshare->AddRef();
  880. break;
  881. }
  882. else
  883. {
  884. pshare = NULL;
  885. }
  886. }
  887. }
  888. if (!pshare)
  889. {
  890. BOOL fSuccess = FALSE;
  891. pshare = new CShare();
  892. if (pshare)
  893. {
  894. pshare->pszRemoteName = StrDup(pszShareName);
  895. if (pshare->pszRemoteName)
  896. {
  897. pshare->pszKeyName = StrDup(pszShareName);
  898. if (pshare->pszKeyName)
  899. {
  900. LPWSTR psz = pshare->pszKeyName;
  901. while (*psz)
  902. {
  903. if (TEXT('\\') == *psz)
  904. {
  905. *psz = TEXT('#');
  906. }
  907. ++psz;
  908. }
  909. if (-1 != DPA_AppendPtr(_hdpaShares, pshare))
  910. {
  911. fSuccess = TRUE;
  912. }
  913. }
  914. }
  915. }
  916. if (!fSuccess)
  917. {
  918. if (pshare)
  919. {
  920. if (pshare->pszKeyName)
  921. {
  922. LocalFree(pshare->pszKeyName);
  923. }
  924. if (pshare->pszRemoteName)
  925. {
  926. LocalFree(pshare->pszRemoteName);
  927. }
  928. delete pshare;
  929. pshare = NULL;
  930. }
  931. }
  932. }
  933. _csDL.Leave();
  934. return pshare;
  935. }
  936. HKEY CMtPtRemote::GetRegKey()
  937. {
  938. TraceMsg(TF_MOUNTPOINT, "CMtPtRemote::GetRegKey: for '%s'", _GetNameDebug());
  939. return RSDuplicateRootKey();
  940. }
  941. // static
  942. void CMtPtRemote::_NotifyReconnectedNetDrive(LPCWSTR pszMountPoint)
  943. {
  944. _csDL.Enter();
  945. CMtPtRemote* pmtptr = CMountPoint::_rgMtPtDriveLetterNet[
  946. DRIVEID(pszMountPoint)];
  947. if (pmtptr)
  948. {
  949. pmtptr->_pshare->dwGFAGVILastCall = GetTickCount() - 35001;
  950. }
  951. // ChangeNotify???
  952. _csDL.Leave();
  953. }
  954. // static
  955. HRESULT CMtPtRemote::_RemoveShareFromHDPA(CShare* pshare)
  956. {
  957. _csDL.Enter();
  958. if (_hdpaShares)
  959. {
  960. DWORD c = DPA_GetPtrCount(_hdpaShares);
  961. for (DWORD dw = 0; dw < c; ++dw)
  962. {
  963. CShare* pshare2 = (CShare*)DPA_GetPtr(_hdpaShares, dw);
  964. if (pshare2 && (pshare2 == pshare))
  965. {
  966. DPA_DeletePtr(_hdpaShares, dw);
  967. break;
  968. }
  969. }
  970. }
  971. _csDL.Leave();
  972. return S_OK;
  973. }
  974. DWORD CMtPtRemote::_GetAutorunContentType()
  975. {
  976. return _GetMTPTContentType();
  977. }
  978. DWORD CMtPtRemote::_GetMTPTDriveType()
  979. {
  980. return DT_REMOTE;
  981. }
  982. DWORD CMtPtRemote::_GetMTPTContentType()
  983. {
  984. DWORD dwRet = CT_UNKNOWNCONTENT;
  985. if (_IsAutorun())
  986. {
  987. dwRet |= CT_AUTORUNINF;
  988. }
  989. return dwRet;
  990. }