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.

976 lines
25 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 (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->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. SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD,
  345. IntToPtr(pvolOld->iShellImageForUpdateImage), NULL);
  346. DPA_Destroy(hdpaMtPtsOld);
  347. }
  348. if (pvolOld)
  349. {
  350. pvolOld->Release();
  351. }
  352. }
  353. pvolNew->Release();
  354. }
  355. _csDL.Leave();
  356. // Outside of the crit sect.
  357. if (fMediaPresenceChanged)
  358. {
  359. _MediaArrivalRemovalHelper(pvolinfo2->szDeviceIDVolume, fMediaArrived);
  360. }
  361. return hr;
  362. }
  363. // In theory, we should do the same as for VolumeUpdated, i.e. remove the volume
  364. // from the DPA and all the mtpts, so that code which already has a pointer to it,
  365. // will not see a change. But the change we need to do is so tiny, that it would
  366. // be overkill. We're just going to flip a bit.
  367. // static
  368. HRESULT CMountPoint::_VolumeMountingEvent(LPCWSTR pszDeviceIDVolume, DWORD dwEvent)
  369. {
  370. _csDL.Enter();
  371. CVolume* pvol = CMtPtLocal::_GetVolumeByID(pszDeviceIDVolume);
  372. _csDL.Leave();
  373. if (pvol)
  374. {
  375. if (SHHARDWAREEVENT_VOLUMEDISMOUNTED == dwEvent)
  376. {
  377. pvol->dwVolumeFlags |= HWDVF_STATE_DISMOUNTED;
  378. _MediaArrivalRemovalHelper(pszDeviceIDVolume, FALSE);
  379. }
  380. else
  381. {
  382. ASSERT(SHHARDWAREEVENT_VOLUMEMOUNTED == dwEvent);
  383. pvol->dwVolumeFlags &= ~HWDVF_STATE_DISMOUNTED;
  384. }
  385. pvol->Release();
  386. }
  387. return S_OK;
  388. }
  389. // static
  390. HRESULT CMountPoint::_VolumeRemoved(
  391. LPCWSTR pszDeviceIDVolume)
  392. {
  393. CVolume* pvol = CMtPtLocal::_GetAndRemoveVolumeByID(pszDeviceIDVolume);
  394. if (pvol)
  395. {
  396. CMtPtLocal::_rsVolumes.RSDeleteSubKey(pvol->pszVolumeGUID +
  397. OFFSET_GUIDWITHINVOLUMEGUID);
  398. // Final release
  399. pvol->Release();
  400. }
  401. return S_OK;
  402. }
  403. HRESULT CMountPoint::_MountPointAdded(
  404. LPCWSTR pszMountPoint, // "c:\", or "d:\MountFolder\"
  405. LPCWSTR pszDeviceIDVolume)// \\?\STORAGE#Volume#...{...GUID...}
  406. {
  407. HRESULT hrCreateMtPt;
  408. BOOL fCallOnMountPointArrival = TRUE;
  409. _csDL.Enter();
  410. CVolume* pvol = CMtPtLocal::_GetVolumeByID(pszDeviceIDVolume);
  411. CMtPtLocal* pMtPtLocal = CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(pszMountPoint)];
  412. if (pMtPtLocal && pMtPtLocal->_IsMiniMtPt())
  413. {
  414. // The WM_DEVICECHANGE message beated us, do not do the notif
  415. fCallOnMountPointArrival = FALSE;
  416. }
  417. if (pvol)
  418. {
  419. hrCreateMtPt = CMtPtLocal::_CreateMtPtLocalWithVolume(pszMountPoint, pvol);
  420. }
  421. _csDL.Leave();
  422. if (pvol)
  423. {
  424. if (SUCCEEDED(hrCreateMtPt) && fCallOnMountPointArrival)
  425. {
  426. CMountPoint::OnMountPointArrival(pszMountPoint);
  427. }
  428. pvol->Release();
  429. }
  430. else
  431. {
  432. hrCreateMtPt = E_FAIL;
  433. }
  434. return hrCreateMtPt;
  435. }
  436. HRESULT CMountPoint::_MountPointRemoved(
  437. LPCWSTR pszMountPoint)
  438. {
  439. HRESULT hr;
  440. BOOL fCallOnMountPointRemoval = TRUE;
  441. _csDL.Enter();
  442. if (CMountPoint::_IsDriveLetter(pszMountPoint))
  443. {
  444. CMtPtLocal* pmtptl = CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(pszMountPoint)];
  445. if (!pmtptl || pmtptl->_IsMiniMtPt())
  446. {
  447. // The WM_DEVICECHANGE message beated us, do not do the notif
  448. fCallOnMountPointRemoval = FALSE;
  449. }
  450. }
  451. hr = CMountPoint::_RemoveLocalMountPoint(pszMountPoint);
  452. _csDL.Leave();
  453. if (SUCCEEDED(hr) && fCallOnMountPointRemoval)
  454. {
  455. CMountPoint::OnMountPointRemoval(pszMountPoint);
  456. }
  457. return hr;
  458. }
  459. HRESULT CMountPoint::_DeviceAdded(
  460. LPCWSTR pszDeviceID, GUID guidDeviceID)
  461. {
  462. return S_FALSE;
  463. }
  464. HRESULT CMountPoint::_DeviceUpdated(
  465. LPCWSTR pszDeviceID)
  466. {
  467. return S_FALSE;
  468. }
  469. // Both for devices and volumes
  470. HRESULT CMountPoint::_DeviceRemoved(
  471. LPCWSTR pszDeviceID)
  472. {
  473. return S_FALSE;
  474. }
  475. ///////////////////////////////////////////////////////////////////////////////
  476. ///////////////////////////////////////////////////////////////////////////////
  477. ///////////////////////////////////////////////////////////////////////////////
  478. //static
  479. void CMountPoint::HandleMountPointNetEvent(LPCWSTR pszDrive, BOOL fArrival)
  480. {
  481. // These we need to send even if Shell Service is running
  482. if (fArrival)
  483. {
  484. CMountPoint::OnNetShareArrival(pszDrive);
  485. }
  486. else
  487. {
  488. CMountPoint::OnNetShareRemoval(pszDrive);
  489. }
  490. }
  491. struct HANDLEMOUNTPOINTLOCALEVENTSTRUCT
  492. {
  493. WCHAR szDrive[4]; // can only be drive letter
  494. BOOL fMediaEvent;
  495. };
  496. // static
  497. DWORD WINAPI CMountPoint::HandleMountPointLocalEventThreadProc(void* pv)
  498. {
  499. HANDLEMOUNTPOINTLOCALEVENTSTRUCT* phmle =
  500. (HANDLEMOUNTPOINTLOCALEVENTSTRUCT*)pv;
  501. Sleep(3000);
  502. if (phmle->fMediaEvent)
  503. {
  504. // Nothing to do, we're not doing anything fancy in safe boot
  505. // mode, so no cache to reset, icons no change...
  506. // This is common to both Shell Service and non-Shell Service
  507. // notification, so do anything non Shell Service notif sepcific
  508. // above
  509. BOOL fIsMiniMtPt = FALSE;
  510. _csDL.Enter();
  511. CMtPtLocal* pMtPtLocal =
  512. CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(phmle->szDrive)];
  513. if (pMtPtLocal)
  514. {
  515. fIsMiniMtPt = pMtPtLocal->_IsMiniMtPt();
  516. }
  517. _csDL.Leave();
  518. if (fIsMiniMtPt)
  519. {
  520. HRESULT hr = SHCoInitialize();
  521. if (SUCCEEDED(hr))
  522. {
  523. CMountPoint::OnMediaArrival(phmle->szDrive);
  524. }
  525. SHCoUninitialize(hr);
  526. }
  527. }
  528. else
  529. {
  530. _csDL.Enter();
  531. CMtPtLocal* pMtPtLocal =
  532. CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(phmle->szDrive)];
  533. if (!pMtPtLocal)
  534. {
  535. // New local drive
  536. CMtPtLocal::_CreateMtPtLocal(phmle->szDrive);
  537. }
  538. _csDL.Leave();
  539. // Can check if pMtMtLocal is NULL or not, but cannot use it
  540. // might already have been freed.
  541. if (!pMtPtLocal)
  542. {
  543. HRESULT hr = SHCoInitialize();
  544. if (SUCCEEDED(hr))
  545. {
  546. // See comment above (This is common...)
  547. CMountPoint::OnMountPointArrival(phmle->szDrive);
  548. }
  549. SHCoUninitialize(hr);
  550. }
  551. }
  552. LocalFree((HLOCAL)phmle);
  553. return 0;
  554. }
  555. // fMedia: TRUE -> Media
  556. // FALSE -> Drive
  557. //static
  558. void CMountPoint::HandleMountPointLocalEvent(LPCWSTR pszDrive, BOOL fArrival,
  559. BOOL fMediaEvent)
  560. {
  561. if (fArrival)
  562. {
  563. // We might be racing with the shell service notification.
  564. HANDLEMOUNTPOINTLOCALEVENTSTRUCT* phmle = (HANDLEMOUNTPOINTLOCALEVENTSTRUCT*)LocalAlloc(LPTR,
  565. sizeof(HANDLEMOUNTPOINTLOCALEVENTSTRUCT));
  566. if (phmle)
  567. {
  568. lstrcpy(phmle->szDrive, pszDrive);
  569. phmle->fMediaEvent = fMediaEvent;
  570. if (!SHQueueUserWorkItem(HandleMountPointLocalEventThreadProc, phmle,
  571. 0, (DWORD_PTR)0, (DWORD_PTR*)NULL, NULL, 0))
  572. {
  573. LocalFree((HLOCAL)phmle);
  574. }
  575. }
  576. }
  577. else
  578. {
  579. if (fMediaEvent)
  580. {
  581. // Nothing to do, we're not doing anything fancy in safe boot
  582. // mode, so no cache to reset, icons no change...
  583. // See comment above (This is common...)
  584. CMountPoint::OnMediaRemoval(pszDrive);
  585. }
  586. else
  587. {
  588. int iDrive = DRIVEID(pszDrive);
  589. BOOL fCallOnMountPointRemoval = TRUE;
  590. _csDL.Enter();
  591. if (_rgMtPtDriveLetterLocal[iDrive])
  592. {
  593. _rgMtPtDriveLetterLocal[iDrive]->Release();
  594. _rgMtPtDriveLetterLocal[iDrive] = NULL;
  595. }
  596. else
  597. {
  598. fCallOnMountPointRemoval = FALSE;
  599. }
  600. _csDL.Leave();
  601. // Can check if pMtMtLocal is NULL or not, but cannot use it
  602. // might already have been freed.
  603. if (fCallOnMountPointRemoval)
  604. {
  605. // See comment above (This is common...)
  606. CMountPoint::OnMountPointRemoval(pszDrive);
  607. }
  608. }
  609. }
  610. }
  611. //static
  612. void CMountPoint::HandleWMDeviceChange(ULONG_PTR code, DEV_BROADCAST_HDR* pbh)
  613. {
  614. if (DBT_DEVTYP_VOLUME == pbh->dbch_devicetype)
  615. {
  616. if ((DBT_DEVICEREMOVECOMPLETE == code) ||
  617. (DBT_DEVICEARRIVAL == code))
  618. {
  619. DEV_BROADCAST_VOLUME* pbv = (DEV_BROADCAST_VOLUME*)pbh;
  620. BOOL fIsNetEvent = !!(pbv->dbcv_flags & DBTF_NET);
  621. BOOL fIsMediaEvent = !!(pbv->dbcv_flags & DBTF_MEDIA);
  622. for (int iDrive = 0; iDrive < 26; ++iDrive)
  623. {
  624. if ((1 << iDrive) & pbv->dbcv_unitmask)
  625. {
  626. TCHAR szPath[4];
  627. if (DBT_DEVICEARRIVAL == code)
  628. {
  629. // Subst drive have the netevent flag on: bad.
  630. PathBuildRoot(szPath, iDrive);
  631. // Check if this is the arrival of a subst drive
  632. if (DRIVE_REMOTE != GetDriveType(szPath))
  633. {
  634. // Yep.
  635. fIsNetEvent = FALSE;
  636. }
  637. else
  638. {
  639. fIsNetEvent = TRUE;
  640. }
  641. }
  642. else
  643. {
  644. _csDL.Enter();
  645. CMtPtLocal* pMtPtLocal =
  646. CMountPoint::_rgMtPtDriveLetterLocal[iDrive];
  647. if (pMtPtLocal)
  648. {
  649. fIsNetEvent = FALSE;
  650. }
  651. _csDL.Leave();
  652. }
  653. if (fIsNetEvent)
  654. {
  655. HandleMountPointNetEvent(PathBuildRoot(szPath, iDrive),
  656. DBT_DEVICEARRIVAL == code);
  657. }
  658. else
  659. {
  660. HandleMountPointLocalEvent(PathBuildRoot(szPath, iDrive),
  661. DBT_DEVICEARRIVAL == code, fIsMediaEvent);
  662. }
  663. }
  664. }
  665. }
  666. }
  667. }
  668. // static
  669. void CMountPoint::NotifyUnavailableNetDriveGone(LPCWSTR pszMountPoint)
  670. {
  671. CMountPoint::_RemoveNetMountPoint(pszMountPoint);
  672. }
  673. // static
  674. void CMountPoint::NotifyReconnectedNetDrive(LPCWSTR pszMountPoint)
  675. {
  676. CMtPtRemote::_NotifyReconnectedNetDrive(pszMountPoint);
  677. }
  678. // static
  679. DWORD CALLBACK CMountPoint::_EventProc(void* pv)
  680. {
  681. SHHARDWAREEVENT* pshhe = (SHHARDWAREEVENT*)pv;
  682. BOOL fLocalDrivesInited;
  683. _csDL.Enter();
  684. fLocalDrivesInited = _fLocalDrivesInited;
  685. _csDL.Leave();
  686. // If the Local Drives info was not initialized there's nothing to update.
  687. if (fLocalDrivesInited)
  688. {
  689. switch (pshhe->dwEvent)
  690. {
  691. case SHHARDWAREEVENT_VOLUMEARRIVED:
  692. case SHHARDWAREEVENT_VOLUMEUPDATED:
  693. {
  694. VOLUMEINFO2* pvolinfo2 = (VOLUMEINFO2*)pshhe->rgbPayLoad;
  695. CMountPoint::_VolumeAddedOrUpdated(
  696. (SHHARDWAREEVENT_VOLUMEARRIVED == pshhe->dwEvent), pvolinfo2);
  697. break;
  698. }
  699. case SHHARDWAREEVENT_VOLUMEREMOVED:
  700. {
  701. LPCWSTR pszDeviceIDVolume = (LPCWSTR)pshhe->rgbPayLoad;
  702. CMountPoint::_VolumeRemoved(pszDeviceIDVolume);
  703. break;
  704. }
  705. case SHHARDWAREEVENT_MOUNTPOINTARRIVED:
  706. {
  707. MTPTADDED* pmtptadded = (MTPTADDED*)pshhe->rgbPayLoad;
  708. CMountPoint::_MountPointAdded(pmtptadded->szMountPoint,
  709. pmtptadded->szDeviceIDVolume);
  710. break;
  711. }
  712. case SHHARDWAREEVENT_MOUNTPOINTREMOVED:
  713. {
  714. LPCWSTR pszMountPoint = (LPCWSTR)pshhe->rgbPayLoad;
  715. CMountPoint::_MountPointRemoved(pszMountPoint);
  716. break;
  717. }
  718. case SHHARDWAREEVENT_VOLUMEDISMOUNTED:
  719. case SHHARDWAREEVENT_VOLUMEMOUNTED:
  720. {
  721. LPCWSTR pszDeviceIDVolume = (LPCWSTR)pshhe->rgbPayLoad;
  722. CMountPoint::_VolumeMountingEvent(pszDeviceIDVolume, pshhe->dwEvent);
  723. break;
  724. }
  725. }
  726. }
  727. switch (pshhe->dwEvent)
  728. {
  729. case SHHARDWAREEVENT_DEVICEARRIVED:
  730. case SHHARDWAREEVENT_DEVICEUPDATED:
  731. case SHHARDWAREEVENT_DEVICEREMOVED:
  732. {
  733. HWDEVICEINFO* phwdevinfo = (HWDEVICEINFO*)pshhe->rgbPayLoad;
  734. if (SHHARDWAREEVENT_DEVICEARRIVED == pshhe->dwEvent)
  735. {
  736. if (HWDDF_HASDEVICEHANDLER & phwdevinfo->dwDeviceFlags)
  737. {
  738. CCrossThreadFlag* pDeviceGoneFlag = new CCrossThreadFlag();
  739. if (pDeviceGoneFlag)
  740. {
  741. if (pDeviceGoneFlag->Init())
  742. {
  743. AttachGoneFlagForDevice(phwdevinfo->szDeviceIntfID, pDeviceGoneFlag);
  744. DoDeviceNotification(phwdevinfo->szDeviceIntfID, TEXT("DeviceArrival"),
  745. pDeviceGoneFlag);
  746. }
  747. pDeviceGoneFlag->Release();
  748. }
  749. }
  750. }
  751. else
  752. {
  753. if (SHHARDWAREEVENT_DEVICEREMOVED == pshhe->dwEvent)
  754. {
  755. CCrossThreadFlag* pDeviceGoneFlag;
  756. if (GetGoneFlagForDevice(phwdevinfo->szDeviceIntfID, &pDeviceGoneFlag))
  757. {
  758. pDeviceGoneFlag->Signal();
  759. pDeviceGoneFlag->Release();
  760. }
  761. _CloseAutoplayPrompt(phwdevinfo->szDeviceIntfID);
  762. }
  763. }
  764. LPITEMIDLIST pidl;
  765. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidl)))
  766. {
  767. // wait for WIA to do its stuff
  768. Sleep(5000);
  769. SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, NULL);
  770. ILFree(pidl);
  771. }
  772. break;
  773. }
  774. default:
  775. // That's no good
  776. break;
  777. }
  778. VirtualFree(pv, 0, MEM_RELEASE);
  779. return 0;
  780. }
  781. // static
  782. void CALLBACK CMountPoint::_EventAPCProc(ULONG_PTR ulpParam)
  783. {
  784. if (!SHCreateThread(CMountPoint::_EventProc, (void*)ulpParam, CTF_COINIT | CTF_REF_COUNTED, NULL))
  785. {
  786. VirtualFree((void*)ulpParam, 0, MEM_RELEASE);
  787. }
  788. }