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.

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