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.

980 lines
27 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "mtpt.h"
  4. #include "mtptl.h"
  5. #include "mtptr.h"
  6. #include "hwcmmn.h"
  7. #include "cdburn.h"
  8. #include "mixctnt.h"
  9. #include "regsuprt.h"
  10. // Misc comments:
  11. // (1) Do a DoAutorun for all new drives except network ones. These will be
  12. // generated externally...
  13. // static
  14. void CMountPoint::WantAutorunUI(LPCWSTR pszDrive)
  15. {
  16. int iDrive = DRIVEID(pszDrive);
  17. CMountPoint::_dwRemoteDriveAutorun |= (1 << iDrive);
  18. }
  19. BOOL _Shell32LoadedInDesktop()
  20. {
  21. static BOOL fLoadedInExplorer = -1;
  22. if (-1 == fLoadedInExplorer)
  23. {
  24. fLoadedInExplorer = BOOLFROMPTR(GetModuleHandle(TEXT("EXPLORER.EXE")));
  25. }
  26. return fLoadedInExplorer;
  27. }
  28. // static
  29. void CMountPoint::OnNetShareArrival(LPCWSTR pszDrive)
  30. {
  31. _csDL.Enter();
  32. if (!_fNetDrivesInited)
  33. {
  34. _InitNetDrives();
  35. }
  36. _csDL.Leave();
  37. if (_fNetDrivesInited)
  38. {
  39. WCHAR szDriveNoSlash[] = TEXT("A:");
  40. WCHAR szRemoteName[MAX_PATH];
  41. DWORD cchRemoteName = ARRAYSIZE(szRemoteName);
  42. HRESULT hr;
  43. int iDrive = DRIVEID(pszDrive);
  44. szDriveNoSlash[0] = *pszDrive;
  45. DWORD dw = WNetGetConnection(szDriveNoSlash, szRemoteName, &cchRemoteName);
  46. if (NO_ERROR == dw)
  47. {
  48. hr = CMtPtRemote::_CreateMtPtRemote(pszDrive, szRemoteName,
  49. TRUE);
  50. }
  51. else
  52. {
  53. DWORD dwGLD = GetLogicalDrives();
  54. if (dwGLD & (1 << iDrive))
  55. {
  56. // This must be a weird System mapped drive
  57. // which WNet... fcts don't like
  58. hr = CMtPtRemote::_CreateMtPtRemoteWithoutShareName(pszDrive);
  59. }
  60. else
  61. {
  62. hr = E_FAIL;
  63. }
  64. }
  65. if (SUCCEEDED(hr))
  66. {
  67. SHChangeNotify(SHCNE_DRIVEADD, SHCNF_PATH, pszDrive, NULL);
  68. if (CMountPoint::_dwRemoteDriveAutorun & (1 << iDrive))
  69. {
  70. DoAutorun(pszDrive, AUTORUNFLAG_MTPTARRIVAL);
  71. CMountPoint::_dwRemoteDriveAutorun &= ~(1 << iDrive);
  72. }
  73. }
  74. }
  75. }
  76. // static
  77. void CMountPoint::OnNetShareRemoval(LPCWSTR pszDrive)
  78. {
  79. _csDL.Enter();
  80. if (!_fNetDrivesInited)
  81. {
  82. _InitNetDrives();
  83. }
  84. _csDL.Leave();
  85. if (_fNetDrivesInited)
  86. {
  87. _RemoveNetMountPoint(pszDrive);
  88. SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATH, pszDrive, NULL);
  89. // There's a possibility that this net drive was covering a local drive
  90. // with the same drive letter
  91. CMountPoint* pmtpt = CMountPoint::GetMountPoint(pszDrive);
  92. if (pmtpt)
  93. {
  94. if (CMountPoint::_IsDriveLetter(pszDrive))
  95. {
  96. CDBurn_OnDeviceChange(TRUE, pszDrive);
  97. }
  98. SHChangeNotify(SHCNE_DRIVEADD, SHCNF_PATH, pszDrive, NULL);
  99. pmtpt->Release();
  100. }
  101. }
  102. }
  103. // static
  104. void CMountPoint::OnMediaArrival(LPCWSTR pszDrive)
  105. {
  106. // Check if this local drive letter is not "covered" by a net
  107. // drive letter
  108. if (!_LocalDriveIsCoveredByNetDrive(pszDrive))
  109. {
  110. BOOL fDriveLetter = CMountPoint::_IsDriveLetter(pszDrive);
  111. if (fDriveLetter)
  112. {
  113. CDBurn_OnMediaChange(TRUE, pszDrive);
  114. }
  115. SHChangeNotify(SHCNE_MEDIAINSERTED, SHCNF_PATH, pszDrive, NULL);
  116. // for now do it only for drive letter mounted stuff
  117. if (fDriveLetter)
  118. {
  119. // Send one of these for all media arrival events
  120. DoAutorun(pszDrive, AUTORUNFLAG_MEDIAARRIVAL);
  121. }
  122. // for the non net case force these through right away to make those
  123. // cd-rom autorun things come up faster
  124. SHChangeNotify(0, SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, NULL, NULL);
  125. }
  126. }
  127. // static
  128. void CMountPoint::OnMountPointArrival(LPCWSTR pszDrive)
  129. {
  130. // Check if this local drive letter is not "covered" by a net
  131. // drive letter
  132. _csDL.Enter();
  133. if (!_IsDriveLetter(pszDrive))
  134. {
  135. _rsMtPtsLocalMOF.RSSetTextValue(NULL, pszDrive, TEXT(""));
  136. }
  137. _csDL.Leave();
  138. if (!_LocalDriveIsCoveredByNetDrive(pszDrive))
  139. {
  140. BOOL fDriveLetter = CMountPoint::_IsDriveLetter(pszDrive);
  141. LONG lEvent;
  142. if (fDriveLetter)
  143. {
  144. CDBurn_OnDeviceChange(TRUE, pszDrive);
  145. lEvent = SHCNE_DRIVEADD;
  146. }
  147. else
  148. {
  149. lEvent = SHCNE_UPDATEITEM;
  150. }
  151. SHChangeNotify(lEvent, SHCNF_PATH, pszDrive, NULL);
  152. if (fDriveLetter)
  153. {
  154. // If the DBTF_MEDIA is not set, do not send this notification for CDROM
  155. // or Removable as they may have come from a new device and not have any
  156. // media in them. Also, when inserting a floppy drive (not media) in a
  157. // laptop, this would pop up a window.
  158. CMountPoint* pmtpt = CMountPoint::GetMountPoint(pszDrive);
  159. if (pmtpt)
  160. {
  161. if (pmtpt->_IsRemote() || pmtpt->_IsFixedDisk() ||
  162. (pmtpt->_IsRemovableDevice() && !pmtpt->_IsFloppy()))
  163. {
  164. DoAutorun(pszDrive, AUTORUNFLAG_MTPTARRIVAL);
  165. }
  166. pmtpt->Release();
  167. }
  168. }
  169. // for the non net case force these through right away to make those
  170. // cd-rom autorun things come up faster
  171. SHChangeNotify(0, SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, NULL, NULL);
  172. }
  173. }
  174. void _CloseAutoplayPrompt(LPCWSTR pszDriveOrDeviceID)
  175. {
  176. HWND hwnd;
  177. if (_GetAutoplayPromptHWND(pszDriveOrDeviceID, &hwnd))
  178. {
  179. _RemoveFromAutoplayPromptHDPA(pszDriveOrDeviceID);
  180. EndDialog(hwnd, IDCANCEL);
  181. }
  182. }
  183. // static
  184. void CMountPoint::OnMediaRemoval(LPCWSTR pszDrive)
  185. {
  186. // Check if this local drive letter is not "covered" by a net
  187. // drive letter
  188. if (!_LocalDriveIsCoveredByNetDrive(pszDrive))
  189. {
  190. if (CMountPoint::_IsDriveLetter(pszDrive))
  191. {
  192. CDBurn_OnMediaChange(FALSE, pszDrive);
  193. }
  194. SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATH, pszDrive, NULL);
  195. _CloseAutoplayPrompt(pszDrive);
  196. }
  197. }
  198. // static
  199. void CMountPoint::OnMountPointRemoval(LPCWSTR pszDrive)
  200. {
  201. // Check if this local drive letter is not "covered" by a net
  202. // drive letter
  203. _csDL.Enter();
  204. if (!_IsDriveLetter(pszDrive))
  205. {
  206. _rsMtPtsLocalMOF.RSSetTextValue(NULL, pszDrive, TEXT(""));
  207. }
  208. _csDL.Leave();
  209. if (!_LocalDriveIsCoveredByNetDrive(pszDrive))
  210. {
  211. LONG lEvent;
  212. if (CMountPoint::_IsDriveLetter(pszDrive))
  213. {
  214. CDBurn_OnDeviceChange(FALSE, pszDrive);
  215. lEvent = SHCNE_DRIVEREMOVED;
  216. }
  217. else
  218. {
  219. lEvent = SHCNE_UPDATEITEM;
  220. }
  221. SHChangeNotify(lEvent, SHCNF_PATH, pszDrive, NULL);
  222. _CloseAutoplayPrompt(pszDrive);
  223. }
  224. }
  225. ///////////////////////////////////////////////////////////////////////////////
  226. ///////////////////////////////////////////////////////////////////////////////
  227. ///////////////////////////////////////////////////////////////////////////////
  228. // static
  229. HRESULT CMountPoint::_MediaArrivalRemovalHelper(LPCWSTR pszDeviceIDVolume,
  230. BOOL fArrived)
  231. {
  232. ASSERT(!_csDL.IsInside());
  233. HRESULT hr;
  234. HDPA hdpaPaths = DPA_Create(4);
  235. if (hdpaPaths)
  236. {
  237. hr = _GetMountPointsForVolume(pszDeviceIDVolume, hdpaPaths);
  238. if (SUCCEEDED(hr))
  239. {
  240. int n = DPA_GetPtrCount(hdpaPaths);
  241. for (int i = n - 1; i >= 0; --i)
  242. {
  243. LPCWSTR pszMtPt = (LPCWSTR)DPA_GetPtr(hdpaPaths, i);
  244. // We don't want to call OnMediaXxxal within the critical
  245. // sections
  246. ASSERT(!_csDL.IsInside());
  247. if (fArrived)
  248. {
  249. CMountPoint::OnMediaArrival(pszMtPt);
  250. }
  251. else
  252. {
  253. CMountPoint::OnMediaRemoval(pszMtPt);
  254. }
  255. LocalFree((HLOCAL)pszMtPt);
  256. DPA_DeletePtr(hdpaPaths, i);
  257. }
  258. }
  259. DPA_Destroy(hdpaPaths);
  260. }
  261. else
  262. {
  263. hr = E_OUTOFMEMORY;
  264. }
  265. return hr;
  266. }
  267. // static
  268. HRESULT CMountPoint::_VolumeAddedOrUpdated(BOOL fAdded,
  269. VOLUMEINFO2* pvolinfo2)
  270. {
  271. HRESULT hr = S_FALSE;
  272. HDPA hdpaMtPtsOld = NULL;
  273. CVolume* pvolOld = NULL;
  274. CVolume* pvolNew = NULL;
  275. BOOL fMediaPresenceChanged = FALSE;
  276. BOOL fMediaArrived;
  277. _csDL.Enter();
  278. if (!fAdded)
  279. {
  280. // Updated
  281. // That's a volume that some code might have a ptr to. We need to drop
  282. // it from the list and create a new one.
  283. hdpaMtPtsOld = DPA_Create(3);
  284. if (hdpaMtPtsOld)
  285. {
  286. hr = CMtPtLocal::_GetAndRemoveVolumeAndItsMtPts(
  287. pvolinfo2->szDeviceIDVolume, &pvolOld, hdpaMtPtsOld);
  288. }
  289. else
  290. {
  291. hr = E_OUTOFMEMORY;
  292. }
  293. }
  294. // Common to Add and Update
  295. if (SUCCEEDED(hr))
  296. {
  297. CMtPtLocal::_UpdateVolumeRegInfo2(pvolinfo2);
  298. hr = CMtPtLocal::_CreateVolumeFromVOLUMEINFO2(pvolinfo2, &pvolNew);
  299. }
  300. if (SUCCEEDED(hr))
  301. {
  302. if (!fAdded)
  303. {
  304. BOOL fLabelChanged;
  305. if (pvolOld && lstrcmp(pvolOld->pszLabel, pvolNew->pszLabel))
  306. {
  307. fLabelChanged = TRUE;
  308. }
  309. else
  310. {
  311. fLabelChanged = FALSE;
  312. }
  313. if (hdpaMtPtsOld)
  314. {
  315. // Create new MtPts from old ones
  316. int n = DPA_GetPtrCount(hdpaMtPtsOld);
  317. for (int i = 0; i < n; ++i)
  318. {
  319. CMtPtLocal* pmtptl = (CMtPtLocal*)DPA_GetPtr(hdpaMtPtsOld, i);
  320. if (pmtptl)
  321. {
  322. WCHAR szMountPoint[MAX_PATH];
  323. HRESULT hrTmp = pmtptl->GetMountPointName(szMountPoint,
  324. ARRAYSIZE(szMountPoint));
  325. if (SUCCEEDED(hrTmp))
  326. {
  327. CMtPtLocal::_CreateMtPtLocalWithVolume(szMountPoint, pvolNew);
  328. // for now don't care about return value
  329. if (fLabelChanged)
  330. {
  331. SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_PATH,
  332. szMountPoint, szMountPoint);
  333. }
  334. if (pvolOld && (pvolOld->dwMediaState != pvolNew->dwMediaState))
  335. {
  336. fMediaPresenceChanged = TRUE;
  337. fMediaArrived = !!(HWDMS_PRESENT & pvolNew->dwMediaState);
  338. }
  339. }
  340. // Get rid of old mtptl
  341. pmtptl->Release();
  342. }
  343. }
  344. if (pvolOld)
  345. {
  346. SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD,
  347. IntToPtr(pvolOld->iShellImageForUpdateImage), NULL);
  348. }
  349. DPA_Destroy(hdpaMtPtsOld);
  350. }
  351. if (pvolOld)
  352. {
  353. pvolOld->Release();
  354. }
  355. }
  356. pvolNew->Release();
  357. }
  358. _csDL.Leave();
  359. // Outside of the crit sect.
  360. if (fMediaPresenceChanged)
  361. {
  362. _MediaArrivalRemovalHelper(pvolinfo2->szDeviceIDVolume, fMediaArrived);
  363. }
  364. return hr;
  365. }
  366. // In theory, we should do the same as for VolumeUpdated, i.e. remove the volume
  367. // from the DPA and all the mtpts, so that code which already has a pointer to it,
  368. // will not see a change. But the change we need to do is so tiny, that it would
  369. // be overkill. We're just going to flip a bit.
  370. // static
  371. HRESULT CMountPoint::_VolumeMountingEvent(LPCWSTR pszDeviceIDVolume, DWORD dwEvent)
  372. {
  373. _csDL.Enter();
  374. CVolume* pvol = CMtPtLocal::_GetVolumeByID(pszDeviceIDVolume);
  375. _csDL.Leave();
  376. if (pvol)
  377. {
  378. if (SHHARDWAREEVENT_VOLUMEDISMOUNTED == dwEvent)
  379. {
  380. pvol->dwVolumeFlags |= HWDVF_STATE_DISMOUNTED;
  381. _csDL.Enter();
  382. // We need to set the label to nothing, so that when the volume
  383. // is mounted back, we compare the old and new label, find them to
  384. // be different and send an SHChangeNotify.
  385. if (pvol->pszLabel)
  386. {
  387. LPWSTR psz = StrDup(TEXT(""));
  388. if (psz)
  389. {
  390. LocalFree(pvol->pszLabel);
  391. // pvol->pszLabel is expected to not be NULL
  392. pvol->pszLabel = psz;
  393. }
  394. }
  395. _csDL.Leave();
  396. _MediaArrivalRemovalHelper(pszDeviceIDVolume, FALSE);
  397. }
  398. else
  399. {
  400. ASSERT(SHHARDWAREEVENT_VOLUMEMOUNTED == dwEvent);
  401. pvol->dwVolumeFlags &= ~HWDVF_STATE_DISMOUNTED;
  402. }
  403. pvol->Release();
  404. }
  405. return S_OK;
  406. }
  407. // static
  408. HRESULT CMountPoint::_VolumeRemoved(
  409. LPCWSTR pszDeviceIDVolume)
  410. {
  411. CVolume* pvol = CMtPtLocal::_GetAndRemoveVolumeByID(pszDeviceIDVolume);
  412. if (pvol)
  413. {
  414. CMtPtLocal::_rsVolumes.RSDeleteSubKey(pvol->pszVolumeGUID +
  415. OFFSET_GUIDWITHINVOLUMEGUID);
  416. // Final release
  417. pvol->Release();
  418. }
  419. return S_OK;
  420. }
  421. HRESULT CMountPoint::_MountPointAdded(
  422. LPCWSTR pszMountPoint, // "c:\", or "d:\MountFolder\"
  423. LPCWSTR pszDeviceIDVolume)// \\?\STORAGE#Volume#...{...GUID...}
  424. {
  425. HRESULT hrCreateMtPt;
  426. BOOL fCallOnMountPointArrival = TRUE;
  427. _csDL.Enter();
  428. CVolume* pvol = CMtPtLocal::_GetVolumeByID(pszDeviceIDVolume);
  429. CMtPtLocal* pMtPtLocal = CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(pszMountPoint)];
  430. if (pMtPtLocal && pMtPtLocal->_IsMiniMtPt())
  431. {
  432. // The WM_DEVICECHANGE message beated us, do not do the notif
  433. fCallOnMountPointArrival = FALSE;
  434. }
  435. if (pvol)
  436. {
  437. hrCreateMtPt = CMtPtLocal::_CreateMtPtLocalWithVolume(pszMountPoint, pvol);
  438. }
  439. _csDL.Leave();
  440. if (pvol)
  441. {
  442. if (SUCCEEDED(hrCreateMtPt) && fCallOnMountPointArrival)
  443. {
  444. CMountPoint::OnMountPointArrival(pszMountPoint);
  445. }
  446. pvol->Release();
  447. }
  448. else
  449. {
  450. hrCreateMtPt = E_FAIL;
  451. }
  452. return hrCreateMtPt;
  453. }
  454. HRESULT CMountPoint::_MountPointRemoved(
  455. LPCWSTR pszMountPoint)
  456. {
  457. HRESULT hr;
  458. BOOL fCallOnMountPointRemoval = TRUE;
  459. _csDL.Enter();
  460. if (CMountPoint::_IsDriveLetter(pszMountPoint))
  461. {
  462. CMtPtLocal* pmtptl = CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(pszMountPoint)];
  463. if (!pmtptl || pmtptl->_IsMiniMtPt())
  464. {
  465. // The WM_DEVICECHANGE message beated us, do not do the notif
  466. fCallOnMountPointRemoval = FALSE;
  467. }
  468. }
  469. hr = CMountPoint::_RemoveLocalMountPoint(pszMountPoint);
  470. _csDL.Leave();
  471. if (SUCCEEDED(hr) && fCallOnMountPointRemoval)
  472. {
  473. CMountPoint::OnMountPointRemoval(pszMountPoint);
  474. }
  475. return hr;
  476. }
  477. ///////////////////////////////////////////////////////////////////////////////
  478. ///////////////////////////////////////////////////////////////////////////////
  479. ///////////////////////////////////////////////////////////////////////////////
  480. //static
  481. void CMountPoint::HandleMountPointNetEvent(LPCWSTR pszDrive, BOOL fArrival)
  482. {
  483. // These we need to send even if Shell Service is running
  484. if (fArrival)
  485. {
  486. CMountPoint::OnNetShareArrival(pszDrive);
  487. }
  488. else
  489. {
  490. CMountPoint::OnNetShareRemoval(pszDrive);
  491. }
  492. }
  493. struct HANDLEMOUNTPOINTLOCALEVENTSTRUCT
  494. {
  495. WCHAR szDrive[4]; // can only be drive letter
  496. BOOL fMediaEvent;
  497. };
  498. // static
  499. DWORD WINAPI CMountPoint::HandleMountPointLocalEventThreadProc(void* pv)
  500. {
  501. HANDLEMOUNTPOINTLOCALEVENTSTRUCT* phmle =
  502. (HANDLEMOUNTPOINTLOCALEVENTSTRUCT*)pv;
  503. Sleep(3000);
  504. if (phmle->fMediaEvent)
  505. {
  506. // Nothing to do, we're not doing anything fancy in safe boot
  507. // mode, so no cache to reset, icons no change...
  508. // This is common to both Shell Service and non-Shell Service
  509. // notification, so do anything non Shell Service notif sepcific
  510. // above
  511. BOOL fIsMiniMtPt = FALSE;
  512. _csDL.Enter();
  513. CMtPtLocal* pMtPtLocal =
  514. CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(phmle->szDrive)];
  515. if (pMtPtLocal)
  516. {
  517. fIsMiniMtPt = pMtPtLocal->_IsMiniMtPt();
  518. }
  519. _csDL.Leave();
  520. if (fIsMiniMtPt)
  521. {
  522. HRESULT hr = SHCoInitialize();
  523. if (SUCCEEDED(hr))
  524. {
  525. CMountPoint::OnMediaArrival(phmle->szDrive);
  526. }
  527. SHCoUninitialize(hr);
  528. }
  529. }
  530. else
  531. {
  532. _csDL.Enter();
  533. CMtPtLocal* pMtPtLocal =
  534. CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(phmle->szDrive)];
  535. if (!pMtPtLocal)
  536. {
  537. // New local drive
  538. CMtPtLocal::_CreateMtPtLocal(phmle->szDrive);
  539. }
  540. _csDL.Leave();
  541. // Can check if pMtMtLocal is NULL or not, but cannot use it
  542. // might already have been freed.
  543. if (!pMtPtLocal)
  544. {
  545. HRESULT hr = SHCoInitialize();
  546. if (SUCCEEDED(hr))
  547. {
  548. // See comment above (This is common...)
  549. CMountPoint::OnMountPointArrival(phmle->szDrive);
  550. }
  551. SHCoUninitialize(hr);
  552. }
  553. }
  554. LocalFree((HLOCAL)phmle);
  555. return 0;
  556. }
  557. // fMedia: TRUE -> Media
  558. // FALSE -> Drive
  559. //static
  560. void CMountPoint::HandleMountPointLocalEvent(LPCWSTR pszDrive, BOOL fArrival,
  561. BOOL fMediaEvent)
  562. {
  563. if (fArrival)
  564. {
  565. // We might be racing with the shell service notification.
  566. HANDLEMOUNTPOINTLOCALEVENTSTRUCT* phmle = (HANDLEMOUNTPOINTLOCALEVENTSTRUCT*)LocalAlloc(LPTR,
  567. sizeof(HANDLEMOUNTPOINTLOCALEVENTSTRUCT));
  568. if (phmle)
  569. {
  570. HRESULT hr = StringCchCopy(phmle->szDrive, ARRAYSIZE(phmle->szDrive), pszDrive);
  571. phmle->fMediaEvent = fMediaEvent;
  572. if (FAILED(hr) || !SHQueueUserWorkItem(HandleMountPointLocalEventThreadProc, phmle,
  573. 0, (DWORD_PTR)0, (DWORD_PTR*)NULL, NULL, 0))
  574. {
  575. LocalFree((HLOCAL)phmle);
  576. }
  577. }
  578. }
  579. else
  580. {
  581. if (fMediaEvent)
  582. {
  583. // Nothing to do, we're not doing anything fancy in safe boot
  584. // mode, so no cache to reset, icons no change...
  585. // See comment above (This is common...)
  586. CMountPoint::OnMediaRemoval(pszDrive);
  587. }
  588. else
  589. {
  590. int iDrive = DRIVEID(pszDrive);
  591. BOOL fCallOnMountPointRemoval = TRUE;
  592. _csDL.Enter();
  593. if (_rgMtPtDriveLetterLocal[iDrive])
  594. {
  595. _rgMtPtDriveLetterLocal[iDrive]->Release();
  596. _rgMtPtDriveLetterLocal[iDrive] = NULL;
  597. }
  598. else
  599. {
  600. fCallOnMountPointRemoval = FALSE;
  601. }
  602. _csDL.Leave();
  603. // Can check if pMtMtLocal is NULL or not, but cannot use it
  604. // might already have been freed.
  605. if (fCallOnMountPointRemoval)
  606. {
  607. // See comment above (This is common...)
  608. CMountPoint::OnMountPointRemoval(pszDrive);
  609. }
  610. }
  611. }
  612. }
  613. //static
  614. void CMountPoint::HandleWMDeviceChange(ULONG_PTR code, DEV_BROADCAST_HDR* pbh)
  615. {
  616. if (DBT_DEVTYP_VOLUME == pbh->dbch_devicetype)
  617. {
  618. if ((DBT_DEVICEREMOVECOMPLETE == code) ||
  619. (DBT_DEVICEARRIVAL == code))
  620. {
  621. DEV_BROADCAST_VOLUME* pbv = (DEV_BROADCAST_VOLUME*)pbh;
  622. BOOL fIsNetEvent = !!(pbv->dbcv_flags & DBTF_NET);
  623. BOOL fIsMediaEvent = !!(pbv->dbcv_flags & DBTF_MEDIA);
  624. for (int iDrive = 0; iDrive < 26; ++iDrive)
  625. {
  626. if ((1 << iDrive) & pbv->dbcv_unitmask)
  627. {
  628. TCHAR szPath[4];
  629. if (DBT_DEVICEARRIVAL == code)
  630. {
  631. // Subst drive have the netevent flag on: bad.
  632. PathBuildRoot(szPath, iDrive);
  633. // Check if this is the arrival of a subst drive
  634. if (DRIVE_REMOTE != GetDriveType(szPath))
  635. {
  636. // Yep.
  637. fIsNetEvent = FALSE;
  638. }
  639. else
  640. {
  641. fIsNetEvent = TRUE;
  642. }
  643. }
  644. else
  645. {
  646. _csDL.Enter();
  647. CMtPtLocal* pMtPtLocal =
  648. CMountPoint::_rgMtPtDriveLetterLocal[iDrive];
  649. if (pMtPtLocal)
  650. {
  651. fIsNetEvent = FALSE;
  652. }
  653. _csDL.Leave();
  654. }
  655. if (fIsNetEvent)
  656. {
  657. HandleMountPointNetEvent(PathBuildRoot(szPath, iDrive),
  658. DBT_DEVICEARRIVAL == code);
  659. }
  660. else
  661. {
  662. HandleMountPointLocalEvent(PathBuildRoot(szPath, iDrive),
  663. DBT_DEVICEARRIVAL == code, fIsMediaEvent);
  664. }
  665. }
  666. }
  667. }
  668. }
  669. }
  670. // static
  671. void CMountPoint::NotifyUnavailableNetDriveGone(LPCWSTR pszMountPoint)
  672. {
  673. CMountPoint::_RemoveNetMountPoint(pszMountPoint);
  674. }
  675. // static
  676. void CMountPoint::NotifyReconnectedNetDrive(LPCWSTR pszMountPoint)
  677. {
  678. CMtPtRemote::_NotifyReconnectedNetDrive(pszMountPoint);
  679. }
  680. // static
  681. DWORD CALLBACK CMountPoint::_EventProc(void* pv)
  682. {
  683. SHHARDWAREEVENT* pshhe = (SHHARDWAREEVENT*)pv;
  684. BOOL fLocalDrivesInited;
  685. _csDL.Enter();
  686. fLocalDrivesInited = _fLocalDrivesInited;
  687. _csDL.Leave();
  688. // If the Local Drives info was not initialized there's nothing to update.
  689. if (fLocalDrivesInited)
  690. {
  691. switch (pshhe->dwEvent)
  692. {
  693. case SHHARDWAREEVENT_VOLUMEARRIVED:
  694. case SHHARDWAREEVENT_VOLUMEUPDATED:
  695. {
  696. VOLUMEINFO2* pvolinfo2 = (VOLUMEINFO2*)pshhe->rgbPayLoad;
  697. CMountPoint::_VolumeAddedOrUpdated(
  698. (SHHARDWAREEVENT_VOLUMEARRIVED == pshhe->dwEvent), pvolinfo2);
  699. break;
  700. }
  701. case SHHARDWAREEVENT_VOLUMEREMOVED:
  702. {
  703. LPCWSTR pszDeviceIDVolume = (LPCWSTR)pshhe->rgbPayLoad;
  704. CMountPoint::_VolumeRemoved(pszDeviceIDVolume);
  705. break;
  706. }
  707. case SHHARDWAREEVENT_MOUNTPOINTARRIVED:
  708. {
  709. MTPTADDED* pmtptadded = (MTPTADDED*)pshhe->rgbPayLoad;
  710. CMountPoint::_MountPointAdded(pmtptadded->szMountPoint,
  711. pmtptadded->szDeviceIDVolume);
  712. break;
  713. }
  714. case SHHARDWAREEVENT_MOUNTPOINTREMOVED:
  715. {
  716. LPCWSTR pszMountPoint = (LPCWSTR)pshhe->rgbPayLoad;
  717. CMountPoint::_MountPointRemoved(pszMountPoint);
  718. break;
  719. }
  720. case SHHARDWAREEVENT_VOLUMEDISMOUNTED:
  721. case SHHARDWAREEVENT_VOLUMEMOUNTED:
  722. {
  723. LPCWSTR pszDeviceIDVolume = (LPCWSTR)pshhe->rgbPayLoad;
  724. CMountPoint::_VolumeMountingEvent(pszDeviceIDVolume, pshhe->dwEvent);
  725. break;
  726. }
  727. }
  728. }
  729. switch (pshhe->dwEvent)
  730. {
  731. case SHHARDWAREEVENT_DEVICEARRIVED:
  732. case SHHARDWAREEVENT_DEVICEUPDATED:
  733. case SHHARDWAREEVENT_DEVICEREMOVED:
  734. {
  735. HWDEVICEINFO* phwdevinfo = (HWDEVICEINFO*)pshhe->rgbPayLoad;
  736. if (SHHARDWAREEVENT_DEVICEARRIVED == pshhe->dwEvent)
  737. {
  738. if (HWDDF_HASDEVICEHANDLER & phwdevinfo->dwDeviceFlags)
  739. {
  740. CCrossThreadFlag* pDeviceGoneFlag = new CCrossThreadFlag();
  741. if (pDeviceGoneFlag)
  742. {
  743. if (pDeviceGoneFlag->Init())
  744. {
  745. AttachGoneFlagForDevice(phwdevinfo->szDeviceIntfID, pDeviceGoneFlag);
  746. DoDeviceNotification(phwdevinfo->szDeviceIntfID, TEXT("DeviceArrival"),
  747. pDeviceGoneFlag);
  748. }
  749. pDeviceGoneFlag->Release();
  750. }
  751. }
  752. }
  753. else
  754. {
  755. if (SHHARDWAREEVENT_DEVICEREMOVED == pshhe->dwEvent)
  756. {
  757. CCrossThreadFlag* pDeviceGoneFlag;
  758. if (GetGoneFlagForDevice(phwdevinfo->szDeviceIntfID, &pDeviceGoneFlag))
  759. {
  760. pDeviceGoneFlag->Signal();
  761. pDeviceGoneFlag->Release();
  762. }
  763. _CloseAutoplayPrompt(phwdevinfo->szDeviceIntfID);
  764. }
  765. }
  766. LPITEMIDLIST pidl;
  767. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidl)))
  768. {
  769. // wait for WIA to do its stuff
  770. Sleep(5000);
  771. SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, NULL);
  772. ILFree(pidl);
  773. }
  774. break;
  775. }
  776. default:
  777. // That's no good
  778. break;
  779. }
  780. VirtualFree(pv, 0, MEM_RELEASE);
  781. return 0;
  782. }
  783. // static
  784. void CALLBACK CMountPoint::_EventAPCProc(ULONG_PTR ulpParam)
  785. {
  786. if (!SHCreateThread(CMountPoint::_EventProc, (void*)ulpParam, CTF_COINIT | CTF_REF_COUNTED, NULL))
  787. {
  788. VirtualFree((void*)ulpParam, 0, MEM_RELEASE);
  789. }
  790. }