windows-nt/Source/XPSP1/NT/shell/shell32/mtptevnt.cpp
2020-09-26 16:20:57 +08:00

977 lines
25 KiB
C++

#include "shellprv.h"
#pragma hdrstop
#include "mtpt.h"
#include "mtptl.h"
#include "mtptr.h"
#include "hwcmmn.h"
#include "cdburn.h"
#include "mixctnt.h"
#include "regsuprt.h"
// Misc comments:
// (1) Do a DoAutorun for all new drives except network ones. These will be
// generated externally...
// static
void CMountPoint::WantAutorunUI(LPCWSTR pszDrive)
{
int iDrive = DRIVEID(pszDrive);
CMountPoint::_dwRemoteDriveAutorun |= (1 << iDrive);
}
BOOL _Shell32LoadedInDesktop()
{
static BOOL fLoadedInExplorer = -1;
if (-1 == fLoadedInExplorer)
{
fLoadedInExplorer = BOOLFROMPTR(GetModuleHandle(TEXT("EXPLORER.EXE")));
}
return fLoadedInExplorer;
}
// static
void CMountPoint::OnNetShareArrival(LPCWSTR pszDrive)
{
_csDL.Enter();
if (!_fNetDrivesInited)
{
_InitNetDrives();
}
_csDL.Leave();
if (_fNetDrivesInited)
{
WCHAR szDriveNoSlash[] = TEXT("A:");
WCHAR szRemoteName[MAX_PATH];
DWORD cchRemoteName = ARRAYSIZE(szRemoteName);
HRESULT hr;
int iDrive = DRIVEID(pszDrive);
szDriveNoSlash[0] = *pszDrive;
DWORD dw = WNetGetConnection(szDriveNoSlash, szRemoteName, &cchRemoteName);
if (NO_ERROR == dw)
{
hr = CMtPtRemote::_CreateMtPtRemote(pszDrive, szRemoteName,
TRUE);
}
else
{
DWORD dwGLD = GetLogicalDrives();
if (dwGLD & (1 << iDrive))
{
// This must be a weird System mapped drive
// which WNet... fcts don't like
hr = CMtPtRemote::_CreateMtPtRemoteWithoutShareName(pszDrive);
}
else
{
hr = E_FAIL;
}
}
if (SUCCEEDED(hr))
{
SHChangeNotify(SHCNE_DRIVEADD, SHCNF_PATH, pszDrive, NULL);
if (CMountPoint::_dwRemoteDriveAutorun & (1 << iDrive))
{
DoAutorun(pszDrive, AUTORUNFLAG_MTPTARRIVAL);
CMountPoint::_dwRemoteDriveAutorun &= ~(1 << iDrive);
}
}
}
}
// static
void CMountPoint::OnNetShareRemoval(LPCWSTR pszDrive)
{
_csDL.Enter();
if (!_fNetDrivesInited)
{
_InitNetDrives();
}
_csDL.Leave();
if (_fNetDrivesInited)
{
_RemoveNetMountPoint(pszDrive);
SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATH, pszDrive, NULL);
// There's a possibility that this net drive was covering a local drive
// with the same drive letter
CMountPoint* pmtpt = CMountPoint::GetMountPoint(pszDrive);
if (pmtpt)
{
if (CMountPoint::_IsDriveLetter(pszDrive))
{
CDBurn_OnDeviceChange(TRUE, pszDrive);
}
SHChangeNotify(SHCNE_DRIVEADD, SHCNF_PATH, pszDrive, NULL);
pmtpt->Release();
}
}
}
// static
void CMountPoint::OnMediaArrival(LPCWSTR pszDrive)
{
// Check if this local drive letter is not "covered" by a net
// drive letter
if (!_LocalDriveIsCoveredByNetDrive(pszDrive))
{
BOOL fDriveLetter = CMountPoint::_IsDriveLetter(pszDrive);
if (fDriveLetter)
{
CDBurn_OnMediaChange(TRUE, pszDrive);
}
SHChangeNotify(SHCNE_MEDIAINSERTED, SHCNF_PATH, pszDrive, NULL);
// for now do it only for drive letter mounted stuff
if (fDriveLetter)
{
// Send one of these for all media arrival events
DoAutorun(pszDrive, AUTORUNFLAG_MEDIAARRIVAL);
}
// for the non net case force these through right away to make those
// cd-rom autorun things come up faster
SHChangeNotify(0, SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, NULL, NULL);
}
}
// static
void CMountPoint::OnMountPointArrival(LPCWSTR pszDrive)
{
// Check if this local drive letter is not "covered" by a net
// drive letter
_csDL.Enter();
if (!_IsDriveLetter(pszDrive))
{
_rsMtPtsLocalMOF.RSSetTextValue(NULL, pszDrive, TEXT(""));
}
_csDL.Leave();
if (!_LocalDriveIsCoveredByNetDrive(pszDrive))
{
BOOL fDriveLetter = CMountPoint::_IsDriveLetter(pszDrive);
LONG lEvent;
if (fDriveLetter)
{
CDBurn_OnDeviceChange(TRUE, pszDrive);
lEvent = SHCNE_DRIVEADD;
}
else
{
lEvent = SHCNE_UPDATEITEM;
}
SHChangeNotify(lEvent, SHCNF_PATH, pszDrive, NULL);
if (fDriveLetter)
{
// If the DBTF_MEDIA is not set, do not send this notification for CDROM
// or Removable as they may have come from a new device and not have any
// media in them. Also, when inserting a floppy drive (not media) in a
// laptop, this would pop up a window.
CMountPoint* pmtpt = CMountPoint::GetMountPoint(pszDrive);
if (pmtpt)
{
if (pmtpt->_IsRemote() || pmtpt->_IsFixedDisk() ||
(pmtpt->_IsRemovableDevice() && !pmtpt->_IsFloppy()))
{
DoAutorun(pszDrive, AUTORUNFLAG_MTPTARRIVAL);
}
pmtpt->Release();
}
}
// for the non net case force these through right away to make those
// cd-rom autorun things come up faster
SHChangeNotify(0, SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, NULL, NULL);
}
}
void _CloseAutoplayPrompt(LPCWSTR pszDriveOrDeviceID)
{
HWND hwnd;
if (_GetAutoplayPromptHWND(pszDriveOrDeviceID, &hwnd))
{
_RemoveFromAutoplayPromptHDPA(pszDriveOrDeviceID);
EndDialog(hwnd, IDCANCEL);
}
}
// static
void CMountPoint::OnMediaRemoval(LPCWSTR pszDrive)
{
// Check if this local drive letter is not "covered" by a net
// drive letter
if (!_LocalDriveIsCoveredByNetDrive(pszDrive))
{
if (CMountPoint::_IsDriveLetter(pszDrive))
{
CDBurn_OnMediaChange(FALSE, pszDrive);
}
SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATH, pszDrive, NULL);
_CloseAutoplayPrompt(pszDrive);
}
}
// static
void CMountPoint::OnMountPointRemoval(LPCWSTR pszDrive)
{
// Check if this local drive letter is not "covered" by a net
// drive letter
_csDL.Enter();
if (!_IsDriveLetter(pszDrive))
{
_rsMtPtsLocalMOF.RSSetTextValue(NULL, pszDrive, TEXT(""));
}
_csDL.Leave();
if (!_LocalDriveIsCoveredByNetDrive(pszDrive))
{
LONG lEvent;
if (CMountPoint::_IsDriveLetter(pszDrive))
{
CDBurn_OnDeviceChange(FALSE, pszDrive);
lEvent = SHCNE_DRIVEREMOVED;
}
else
{
lEvent = SHCNE_UPDATEITEM;
}
SHChangeNotify(lEvent, SHCNF_PATH, pszDrive, NULL);
_CloseAutoplayPrompt(pszDrive);
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// static
HRESULT CMountPoint::_MediaArrivalRemovalHelper(LPCWSTR pszDeviceIDVolume,
BOOL fArrived)
{
ASSERT(!_csDL.IsInside());
HRESULT hr;
HDPA hdpaPaths = DPA_Create(4);
if (hdpaPaths)
{
hr = _GetMountPointsForVolume(pszDeviceIDVolume, hdpaPaths);
if (SUCCEEDED(hr))
{
int n = DPA_GetPtrCount(hdpaPaths);
for (int i = n - 1; i >= 0; --i)
{
LPCWSTR pszMtPt = (LPCWSTR)DPA_GetPtr(hdpaPaths, i);
// We don't want to call OnMediaXxxal within the critical
// sections
ASSERT(!_csDL.IsInside());
if (fArrived)
{
CMountPoint::OnMediaArrival(pszMtPt);
}
else
{
CMountPoint::OnMediaRemoval(pszMtPt);
}
LocalFree((HLOCAL)pszMtPt);
DPA_DeletePtr(hdpaPaths, i);
}
}
DPA_Destroy(hdpaPaths);
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
// static
HRESULT CMountPoint::_VolumeAddedOrUpdated(BOOL fAdded,
VOLUMEINFO2* pvolinfo2)
{
HRESULT hr = S_FALSE;
HDPA hdpaMtPtsOld = NULL;
CVolume* pvolOld = NULL;
CVolume* pvolNew = NULL;
BOOL fMediaPresenceChanged = FALSE;
BOOL fMediaArrived;
_csDL.Enter();
if (!fAdded)
{
// Updated
// That's a volume that some code might have a ptr to. We need to drop
// it from the list and create a new one.
hdpaMtPtsOld = DPA_Create(3);
if (hdpaMtPtsOld)
{
hr = CMtPtLocal::_GetAndRemoveVolumeAndItsMtPts(
pvolinfo2->szDeviceIDVolume, &pvolOld, hdpaMtPtsOld);
}
else
{
hr = E_OUTOFMEMORY;
}
}
// Common to Add and Update
if (SUCCEEDED(hr))
{
CMtPtLocal::_UpdateVolumeRegInfo2(pvolinfo2);
hr = CMtPtLocal::_CreateVolumeFromVOLUMEINFO2(pvolinfo2, &pvolNew);
}
if (SUCCEEDED(hr))
{
if (!fAdded)
{
BOOL fLabelChanged;
if (lstrcmp(pvolOld->pszLabel, pvolNew->pszLabel))
{
fLabelChanged = TRUE;
}
else
{
fLabelChanged = FALSE;
}
if (hdpaMtPtsOld)
{
// Create new MtPts from old ones
int n = DPA_GetPtrCount(hdpaMtPtsOld);
for (int i = 0; i < n; ++i)
{
CMtPtLocal* pmtptl = (CMtPtLocal*)DPA_GetPtr(hdpaMtPtsOld, i);
if (pmtptl)
{
WCHAR szMountPoint[MAX_PATH];
HRESULT hrTmp = pmtptl->GetMountPointName(szMountPoint,
ARRAYSIZE(szMountPoint));
if (SUCCEEDED(hrTmp))
{
CMtPtLocal::_CreateMtPtLocalWithVolume(szMountPoint, pvolNew);
// for now don't care about return value
if (fLabelChanged)
{
SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_PATH,
szMountPoint, szMountPoint);
}
if (pvolOld->dwMediaState != pvolNew->dwMediaState)
{
fMediaPresenceChanged = TRUE;
fMediaArrived = !!(HWDMS_PRESENT & pvolNew->dwMediaState);
}
}
// Get rid of old mtptl
pmtptl->Release();
}
}
SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD,
IntToPtr(pvolOld->iShellImageForUpdateImage), NULL);
DPA_Destroy(hdpaMtPtsOld);
}
if (pvolOld)
{
pvolOld->Release();
}
}
pvolNew->Release();
}
_csDL.Leave();
// Outside of the crit sect.
if (fMediaPresenceChanged)
{
_MediaArrivalRemovalHelper(pvolinfo2->szDeviceIDVolume, fMediaArrived);
}
return hr;
}
// In theory, we should do the same as for VolumeUpdated, i.e. remove the volume
// from the DPA and all the mtpts, so that code which already has a pointer to it,
// will not see a change. But the change we need to do is so tiny, that it would
// be overkill. We're just going to flip a bit.
// static
HRESULT CMountPoint::_VolumeMountingEvent(LPCWSTR pszDeviceIDVolume, DWORD dwEvent)
{
_csDL.Enter();
CVolume* pvol = CMtPtLocal::_GetVolumeByID(pszDeviceIDVolume);
_csDL.Leave();
if (pvol)
{
if (SHHARDWAREEVENT_VOLUMEDISMOUNTED == dwEvent)
{
pvol->dwVolumeFlags |= HWDVF_STATE_DISMOUNTED;
_MediaArrivalRemovalHelper(pszDeviceIDVolume, FALSE);
}
else
{
ASSERT(SHHARDWAREEVENT_VOLUMEMOUNTED == dwEvent);
pvol->dwVolumeFlags &= ~HWDVF_STATE_DISMOUNTED;
}
pvol->Release();
}
return S_OK;
}
// static
HRESULT CMountPoint::_VolumeRemoved(
LPCWSTR pszDeviceIDVolume)
{
CVolume* pvol = CMtPtLocal::_GetAndRemoveVolumeByID(pszDeviceIDVolume);
if (pvol)
{
CMtPtLocal::_rsVolumes.RSDeleteSubKey(pvol->pszVolumeGUID +
OFFSET_GUIDWITHINVOLUMEGUID);
// Final release
pvol->Release();
}
return S_OK;
}
HRESULT CMountPoint::_MountPointAdded(
LPCWSTR pszMountPoint, // "c:\", or "d:\MountFolder\"
LPCWSTR pszDeviceIDVolume)// \\?\STORAGE#Volume#...{...GUID...}
{
HRESULT hrCreateMtPt;
BOOL fCallOnMountPointArrival = TRUE;
_csDL.Enter();
CVolume* pvol = CMtPtLocal::_GetVolumeByID(pszDeviceIDVolume);
CMtPtLocal* pMtPtLocal = CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(pszMountPoint)];
if (pMtPtLocal && pMtPtLocal->_IsMiniMtPt())
{
// The WM_DEVICECHANGE message beated us, do not do the notif
fCallOnMountPointArrival = FALSE;
}
if (pvol)
{
hrCreateMtPt = CMtPtLocal::_CreateMtPtLocalWithVolume(pszMountPoint, pvol);
}
_csDL.Leave();
if (pvol)
{
if (SUCCEEDED(hrCreateMtPt) && fCallOnMountPointArrival)
{
CMountPoint::OnMountPointArrival(pszMountPoint);
}
pvol->Release();
}
else
{
hrCreateMtPt = E_FAIL;
}
return hrCreateMtPt;
}
HRESULT CMountPoint::_MountPointRemoved(
LPCWSTR pszMountPoint)
{
HRESULT hr;
BOOL fCallOnMountPointRemoval = TRUE;
_csDL.Enter();
if (CMountPoint::_IsDriveLetter(pszMountPoint))
{
CMtPtLocal* pmtptl = CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(pszMountPoint)];
if (!pmtptl || pmtptl->_IsMiniMtPt())
{
// The WM_DEVICECHANGE message beated us, do not do the notif
fCallOnMountPointRemoval = FALSE;
}
}
hr = CMountPoint::_RemoveLocalMountPoint(pszMountPoint);
_csDL.Leave();
if (SUCCEEDED(hr) && fCallOnMountPointRemoval)
{
CMountPoint::OnMountPointRemoval(pszMountPoint);
}
return hr;
}
HRESULT CMountPoint::_DeviceAdded(
LPCWSTR pszDeviceID, GUID guidDeviceID)
{
return S_FALSE;
}
HRESULT CMountPoint::_DeviceUpdated(
LPCWSTR pszDeviceID)
{
return S_FALSE;
}
// Both for devices and volumes
HRESULT CMountPoint::_DeviceRemoved(
LPCWSTR pszDeviceID)
{
return S_FALSE;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//static
void CMountPoint::HandleMountPointNetEvent(LPCWSTR pszDrive, BOOL fArrival)
{
// These we need to send even if Shell Service is running
if (fArrival)
{
CMountPoint::OnNetShareArrival(pszDrive);
}
else
{
CMountPoint::OnNetShareRemoval(pszDrive);
}
}
struct HANDLEMOUNTPOINTLOCALEVENTSTRUCT
{
WCHAR szDrive[4]; // can only be drive letter
BOOL fMediaEvent;
};
// static
DWORD WINAPI CMountPoint::HandleMountPointLocalEventThreadProc(void* pv)
{
HANDLEMOUNTPOINTLOCALEVENTSTRUCT* phmle =
(HANDLEMOUNTPOINTLOCALEVENTSTRUCT*)pv;
Sleep(3000);
if (phmle->fMediaEvent)
{
// Nothing to do, we're not doing anything fancy in safe boot
// mode, so no cache to reset, icons no change...
// This is common to both Shell Service and non-Shell Service
// notification, so do anything non Shell Service notif sepcific
// above
BOOL fIsMiniMtPt = FALSE;
_csDL.Enter();
CMtPtLocal* pMtPtLocal =
CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(phmle->szDrive)];
if (pMtPtLocal)
{
fIsMiniMtPt = pMtPtLocal->_IsMiniMtPt();
}
_csDL.Leave();
if (fIsMiniMtPt)
{
HRESULT hr = SHCoInitialize();
if (SUCCEEDED(hr))
{
CMountPoint::OnMediaArrival(phmle->szDrive);
}
SHCoUninitialize(hr);
}
}
else
{
_csDL.Enter();
CMtPtLocal* pMtPtLocal =
CMountPoint::_rgMtPtDriveLetterLocal[DRIVEID(phmle->szDrive)];
if (!pMtPtLocal)
{
// New local drive
CMtPtLocal::_CreateMtPtLocal(phmle->szDrive);
}
_csDL.Leave();
// Can check if pMtMtLocal is NULL or not, but cannot use it
// might already have been freed.
if (!pMtPtLocal)
{
HRESULT hr = SHCoInitialize();
if (SUCCEEDED(hr))
{
// See comment above (This is common...)
CMountPoint::OnMountPointArrival(phmle->szDrive);
}
SHCoUninitialize(hr);
}
}
LocalFree((HLOCAL)phmle);
return 0;
}
// fMedia: TRUE -> Media
// FALSE -> Drive
//static
void CMountPoint::HandleMountPointLocalEvent(LPCWSTR pszDrive, BOOL fArrival,
BOOL fMediaEvent)
{
if (fArrival)
{
// We might be racing with the shell service notification.
HANDLEMOUNTPOINTLOCALEVENTSTRUCT* phmle = (HANDLEMOUNTPOINTLOCALEVENTSTRUCT*)LocalAlloc(LPTR,
sizeof(HANDLEMOUNTPOINTLOCALEVENTSTRUCT));
if (phmle)
{
lstrcpy(phmle->szDrive, pszDrive);
phmle->fMediaEvent = fMediaEvent;
if (!SHQueueUserWorkItem(HandleMountPointLocalEventThreadProc, phmle,
0, (DWORD_PTR)0, (DWORD_PTR*)NULL, NULL, 0))
{
LocalFree((HLOCAL)phmle);
}
}
}
else
{
if (fMediaEvent)
{
// Nothing to do, we're not doing anything fancy in safe boot
// mode, so no cache to reset, icons no change...
// See comment above (This is common...)
CMountPoint::OnMediaRemoval(pszDrive);
}
else
{
int iDrive = DRIVEID(pszDrive);
BOOL fCallOnMountPointRemoval = TRUE;
_csDL.Enter();
if (_rgMtPtDriveLetterLocal[iDrive])
{
_rgMtPtDriveLetterLocal[iDrive]->Release();
_rgMtPtDriveLetterLocal[iDrive] = NULL;
}
else
{
fCallOnMountPointRemoval = FALSE;
}
_csDL.Leave();
// Can check if pMtMtLocal is NULL or not, but cannot use it
// might already have been freed.
if (fCallOnMountPointRemoval)
{
// See comment above (This is common...)
CMountPoint::OnMountPointRemoval(pszDrive);
}
}
}
}
//static
void CMountPoint::HandleWMDeviceChange(ULONG_PTR code, DEV_BROADCAST_HDR* pbh)
{
if (DBT_DEVTYP_VOLUME == pbh->dbch_devicetype)
{
if ((DBT_DEVICEREMOVECOMPLETE == code) ||
(DBT_DEVICEARRIVAL == code))
{
DEV_BROADCAST_VOLUME* pbv = (DEV_BROADCAST_VOLUME*)pbh;
BOOL fIsNetEvent = !!(pbv->dbcv_flags & DBTF_NET);
BOOL fIsMediaEvent = !!(pbv->dbcv_flags & DBTF_MEDIA);
for (int iDrive = 0; iDrive < 26; ++iDrive)
{
if ((1 << iDrive) & pbv->dbcv_unitmask)
{
TCHAR szPath[4];
if (DBT_DEVICEARRIVAL == code)
{
// Subst drive have the netevent flag on: bad.
PathBuildRoot(szPath, iDrive);
// Check if this is the arrival of a subst drive
if (DRIVE_REMOTE != GetDriveType(szPath))
{
// Yep.
fIsNetEvent = FALSE;
}
else
{
fIsNetEvent = TRUE;
}
}
else
{
_csDL.Enter();
CMtPtLocal* pMtPtLocal =
CMountPoint::_rgMtPtDriveLetterLocal[iDrive];
if (pMtPtLocal)
{
fIsNetEvent = FALSE;
}
_csDL.Leave();
}
if (fIsNetEvent)
{
HandleMountPointNetEvent(PathBuildRoot(szPath, iDrive),
DBT_DEVICEARRIVAL == code);
}
else
{
HandleMountPointLocalEvent(PathBuildRoot(szPath, iDrive),
DBT_DEVICEARRIVAL == code, fIsMediaEvent);
}
}
}
}
}
}
// static
void CMountPoint::NotifyUnavailableNetDriveGone(LPCWSTR pszMountPoint)
{
CMountPoint::_RemoveNetMountPoint(pszMountPoint);
}
// static
void CMountPoint::NotifyReconnectedNetDrive(LPCWSTR pszMountPoint)
{
CMtPtRemote::_NotifyReconnectedNetDrive(pszMountPoint);
}
// static
DWORD CALLBACK CMountPoint::_EventProc(void* pv)
{
SHHARDWAREEVENT* pshhe = (SHHARDWAREEVENT*)pv;
BOOL fLocalDrivesInited;
_csDL.Enter();
fLocalDrivesInited = _fLocalDrivesInited;
_csDL.Leave();
// If the Local Drives info was not initialized there's nothing to update.
if (fLocalDrivesInited)
{
switch (pshhe->dwEvent)
{
case SHHARDWAREEVENT_VOLUMEARRIVED:
case SHHARDWAREEVENT_VOLUMEUPDATED:
{
VOLUMEINFO2* pvolinfo2 = (VOLUMEINFO2*)pshhe->rgbPayLoad;
CMountPoint::_VolumeAddedOrUpdated(
(SHHARDWAREEVENT_VOLUMEARRIVED == pshhe->dwEvent), pvolinfo2);
break;
}
case SHHARDWAREEVENT_VOLUMEREMOVED:
{
LPCWSTR pszDeviceIDVolume = (LPCWSTR)pshhe->rgbPayLoad;
CMountPoint::_VolumeRemoved(pszDeviceIDVolume);
break;
}
case SHHARDWAREEVENT_MOUNTPOINTARRIVED:
{
MTPTADDED* pmtptadded = (MTPTADDED*)pshhe->rgbPayLoad;
CMountPoint::_MountPointAdded(pmtptadded->szMountPoint,
pmtptadded->szDeviceIDVolume);
break;
}
case SHHARDWAREEVENT_MOUNTPOINTREMOVED:
{
LPCWSTR pszMountPoint = (LPCWSTR)pshhe->rgbPayLoad;
CMountPoint::_MountPointRemoved(pszMountPoint);
break;
}
case SHHARDWAREEVENT_VOLUMEDISMOUNTED:
case SHHARDWAREEVENT_VOLUMEMOUNTED:
{
LPCWSTR pszDeviceIDVolume = (LPCWSTR)pshhe->rgbPayLoad;
CMountPoint::_VolumeMountingEvent(pszDeviceIDVolume, pshhe->dwEvent);
break;
}
}
}
switch (pshhe->dwEvent)
{
case SHHARDWAREEVENT_DEVICEARRIVED:
case SHHARDWAREEVENT_DEVICEUPDATED:
case SHHARDWAREEVENT_DEVICEREMOVED:
{
HWDEVICEINFO* phwdevinfo = (HWDEVICEINFO*)pshhe->rgbPayLoad;
if (SHHARDWAREEVENT_DEVICEARRIVED == pshhe->dwEvent)
{
if (HWDDF_HASDEVICEHANDLER & phwdevinfo->dwDeviceFlags)
{
CCrossThreadFlag* pDeviceGoneFlag = new CCrossThreadFlag();
if (pDeviceGoneFlag)
{
if (pDeviceGoneFlag->Init())
{
AttachGoneFlagForDevice(phwdevinfo->szDeviceIntfID, pDeviceGoneFlag);
DoDeviceNotification(phwdevinfo->szDeviceIntfID, TEXT("DeviceArrival"),
pDeviceGoneFlag);
}
pDeviceGoneFlag->Release();
}
}
}
else
{
if (SHHARDWAREEVENT_DEVICEREMOVED == pshhe->dwEvent)
{
CCrossThreadFlag* pDeviceGoneFlag;
if (GetGoneFlagForDevice(phwdevinfo->szDeviceIntfID, &pDeviceGoneFlag))
{
pDeviceGoneFlag->Signal();
pDeviceGoneFlag->Release();
}
_CloseAutoplayPrompt(phwdevinfo->szDeviceIntfID);
}
}
LPITEMIDLIST pidl;
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidl)))
{
// wait for WIA to do its stuff
Sleep(5000);
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, NULL);
ILFree(pidl);
}
break;
}
default:
// That's no good
break;
}
VirtualFree(pv, 0, MEM_RELEASE);
return 0;
}
// static
void CALLBACK CMountPoint::_EventAPCProc(ULONG_PTR ulpParam)
{
if (!SHCreateThread(CMountPoint::_EventProc, (void*)ulpParam, CTF_COINIT | CTF_REF_COUNTED, NULL))
{
VirtualFree((void*)ulpParam, 0, MEM_RELEASE);
}
}