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.
 
 
 
 
 
 

3139 lines
92 KiB

#include "vol.h"
#include "hwdev.h"
#include "hnotif.h"
#include "mtpts.h"
#include "regnotif.h"
#include "drvbase.h"
#include "dtctreg.h"
#include "users.h"
//
// ISSUE-2001/01/08-StephStm that's bad, vol should not depend on dtct...
//
#include "dtct.h"
#include "reg.h"
#include "sfstr.h"
#include "misc.h"
#pragma warning(disable: 4201)
#include <winioctl.h>
#pragma warning(default: 4201)
#include <ntddcdrm.h>
#include <ntddmmc.h>
#include <ioevent.h>
#include <shpriv.h>
#include <setupapi.h>
#include "mischlpr.h"
#include "dbg.h"
#include <strsafe.h>
#define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
#define STATE_DRIVETYPE 0x00000001
#define STATE_UPDATECONSTINFO 0x00000002
#define STATE_DEVICENUMBERINFO 0x00000004
#define STATE_DEVICEINST 0x00000008
#define STATE_HWDEVICEINST 0x00000010
#define STATE_MEDIAINFO 0x00000020
#define STATE_GVIFAILED 0x10000000
#define STATE_GFAFAILED 0x20000000
#define STATE_UPDATEHASMEDIAFAILED 0x40000000
#define INVALID_DWORD ((DWORD)-1)
#define MPFE_UNDETERMINED ((DWORD)0x0DEF0DEF)
#define MPFE_FALSE ((DWORD)0)
#define MPFE_TRUE ((DWORD)1)
///////////////////////////////////////////////////////////////////////////////
// Public
// No need for the critical section, since it will not be added to the
// NamedList until init is finsihed and has succeeded. Until it's in the
// namedlist, no code can grab a pointer to this object and call it.
HRESULT CVolume::Init(LPCWSTR pszElemName)
{
HRESULT hres = _cs.Init();
if (SUCCEEDED(hres))
{
hres = _SetName(pszElemName);
if (SUCCEEDED(hres))
{
CImpersonateEveryone* pieo;
hres = CHWEventDetectorHelper::GetImpersonateEveryone(&pieo);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
hres = pieo->Impersonate();
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
hres = _InitHelper(pszElemName);
pieo->RevertToSelf();
}
pieo->RCRelease();
}
}
}
return hres;
}
HRESULT _IsDeviceFullyInstalled(LPCWSTR pszDeviceIntfID, BOOL* pfDeviceFullyInstalled)
{
HRESULT hr = E_FAIL;
HDEVINFO hdevinfo = SetupDiCreateDeviceInfoList(NULL, NULL);
*pfDeviceFullyInstalled = FALSE;
if (INVALID_HANDLE_VALUE != hdevinfo)
{
SP_DEVICE_INTERFACE_DATA sdid = {0};
sdid.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (SetupDiOpenDeviceInterface(hdevinfo, pszDeviceIntfID, 0, &sdid))
{
DWORD cbsdidd = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) +
(MAX_DEVICE_ID_LEN * sizeof(WCHAR));
SP_DEVINFO_DATA sdd = {0};
SP_DEVICE_INTERFACE_DETAIL_DATA* psdidd =
(SP_DEVICE_INTERFACE_DETAIL_DATA*)LocalAlloc(LPTR, cbsdidd);
if (psdidd)
{
psdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
sdd.cbSize = sizeof(SP_DEVINFO_DATA);
// SetupDiGetDeviceInterfaceDetail (below) requires that the
// cbSize member of SP_DEVICE_INTERFACE_DETAIL_DATA be set
// to the size of the fixed part of the structure, and to pass
// the size of the full thing as the 4th param.
if (SetupDiGetDeviceInterfaceDetail(hdevinfo, &sdid, psdidd,
cbsdidd, NULL, &sdd))
{
DWORD dw;
if (SetupDiGetDeviceRegistryProperty(hdevinfo, &sdd,
SPDRP_INSTALL_STATE, 0, (PBYTE)&dw, sizeof(dw), NULL))
{
TRACE(TF_VOLUME, TEXT(">>>> Got SPDRP_INSTALL_STATE property: 0x%08X"), dw);
if (CM_INSTALL_STATE_INSTALLED == dw)
{
*pfDeviceFullyInstalled = TRUE;
}
hr = S_OK;
}
}
LocalFree((HLOCAL)psdidd);
}
SetupDiDeleteDeviceInterfaceData(hdevinfo, &sdid);
}
SetupDiDestroyDeviceInfoList(hdevinfo);
}
return hr;
}
HRESULT CVolume::_InitHelper(LPCWSTR pszElemName)
{
BOOL fDeviceFullyInstalled;
HRESULT hres = _IsDeviceFullyInstalled(_pszElemName, &fDeviceFullyInstalled);
if (SUCCEEDED(hres))
{
if (!fDeviceFullyInstalled)
{
TRACE(TF_VOLUME,
TEXT("!!!!!!!!!!!! Device not fully installed!\n %s"),
pszElemName);
hres = E_FAIL;
}
else
{
HANDLE hDevice;
BOOL fCloseHandle = TRUE;
hres = _GetDeviceHandleSafe(&hDevice, FALSE);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
hres = _InitDriveType(hDevice);
if (SUCCEEDED(hres))
{
_dwState |= STATE_DRIVETYPE;
hres = S_OK;
if ((HWDTS_FIXEDDISK != _dwDriveType) &&
(HWDTS_FLOPPY35 != _dwDriveType) &&
(HWDTS_FLOPPY525 != _dwDriveType))
{
_CloseDeviceHandleSafe(hDevice);
fCloseHandle = FALSE;
// Removable disk drives + CD require access to
// the media to query all the required info
hres = _GetDeviceHandleSafe(&hDevice, TRUE);
}
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
hres = _UpdateConstInfo(hDevice);
if (SUCCEEDED(hres))
{
_dwState |= STATE_UPDATECONSTINFO;
}
if ((HWDTS_FLOPPY35 != _dwDriveType) &&
(HWDTS_FLOPPY525 != _dwDriveType))
{
if (SUCCEEDED(hres))
{
fCloseHandle = TRUE;
hres = _GetDeviceNumberInfoFromHandle(hDevice,
&_devtype, &_ulDeviceNumber,
&_ulPartitionNumber);
if (SUCCEEDED(hres))
{
if (S_FALSE != hres)
{
_dwState |= STATE_DEVICENUMBERINFO;
}
GUID guidDummy;
hres = _GetDeviceInstance(pszElemName,
&_devinst, &guidDummy);
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
_dwState |= STATE_DEVICEINST;
hres = _InitHWDeviceInst();
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
hres = _UpdateSoftEjectCaps();
if (SUCCEEDED(hres))
{
hres = _UpdateRemovableDevice();
}
}
}
}
// We need to do this anyway, even if the
// DeviceNumber stuff and/or the deviceInst stuff
// fails. Otherwise we'll have a very sorry volume.
if (SUCCEEDED(hres))
{
hres = _UpdateMediaInfo(hDevice, FALSE);
if (SUCCEEDED(hres))
{
if (S_FALSE != hres)
{
_dwState |= STATE_MEDIAINFO;
}
hres = _RegisterNotif();
}
}
}
}
if (SUCCEEDED(hres))
{
hres = _CreateMountPoints();
}
}
else
{
_HandleAccessDenied();
}
}
if (fCloseHandle)
{
_CloseDeviceHandleSafe(hDevice);
}
}
else
{
_HandleAccessDenied();
}
}
}
return hres;
}
void CVolume::_HandleAccessDenied()
{
if (ERROR_ACCESS_DENIED == GetLastError())
{
_dwVolumeFlags |= HWDVF_STATE_ACCESSDENIED;
}
}
// *pdwFloppy
// 0: not a floppy
// 35: 3.5" flopy
// 525: 5.25" floppy
HRESULT _DeviceIsFloppy(HANDLE hDevice, DWORD* pdwFloppy, BOOL* pfFloppySupportsSoftEject)
{
HRESULT hres = S_FALSE;
DISK_GEOMETRY dg[12] = {0};
DWORD cbBuf = sizeof(dg);
DWORD dwReturned;
*pdwFloppy = 0;
*pfFloppySupportsSoftEject = FALSE;
// Should be IOCTL_..._DISK_GEOMETRY...
if (DeviceIoControl(hDevice, IOCTL_DISK_GET_MEDIA_TYPES,
NULL, 0, dg, cbBuf, &dwReturned, NULL))
{
DWORD cMediaInfo = dwReturned / sizeof(DISK_GEOMETRY);
for (DWORD dw = 0; !(*pdwFloppy) && (dw < cMediaInfo); ++dw)
{
switch (dg[dw].MediaType)
{
case F5_1Pt2_512: // Cap: 1200
case F5_360_512: // Cap: 360
case F5_320_512: // Cap: 360
case F5_320_1024: // Cap: 360
case F5_180_512: // Cap: 360
case F5_160_512: // Cap: 360
*pdwFloppy = 525;
break;
case F3_120M_512: // Cap: 120MB
*pfFloppySupportsSoftEject = TRUE;
case F3_1Pt44_512: // Cap: 1440
case F3_2Pt88_512: // Cap: 2880
case F3_20Pt8_512: // Cap: 2880
case F3_720_512: // Cap: 720
*pdwFloppy = 35;
break;
//
// Japanese specific device types from here.
//
case F5_1Pt23_1024: // Cap: 1200
case F5_640_512: // Cap: 260
case F5_720_512: // Cap: 360
*pdwFloppy = 525;
break;
case F3_640_512: // Cap: 720
case F3_1Pt2_512: // Cap: 1440
case F3_1Pt23_1024: // Cap: 1440
*pdwFloppy = 35;
break;
case F3_128Mb_512: // Cap: ?
case F3_230Mb_512: // Cap: ?
case F3_200Mb_512:
*pdwFloppy = 35;
break;
}
if (*pdwFloppy)
{
hres = S_OK;
}
}
}
return hres;
}
HRESULT _GetDriveTypeInfo(HANDLE hDevice, DWORD* pdwDriveType, BOOL* pfFloppy);
HRESULT CVolume::_InitDriveType(HANDLE hDevice)
{
BOOL fFloppy = FALSE;
HRESULT hr = _GetDriveTypeInfo(hDevice, &_dwDriveType, &fFloppy);
if (SUCCEEDED(hr))
{
if (fFloppy)
{
DWORD dwFloppy;
BOOL fFloppySupportsSoftEject;
hr = _DeviceIsFloppy(hDevice, &dwFloppy, &fFloppySupportsSoftEject);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
if (fFloppySupportsSoftEject)
{
_dwDriveCap |= HWDDC_FLOPPYSOFTEJECT;
}
switch (dwFloppy)
{
case 35:
_dwDriveType = HWDTS_FLOPPY35;
break;
case 525:
_dwDriveType = HWDTS_FLOPPY525;
}
}
}
}
return hr;
}
HRESULT _GetRemovableDeviceInstRecurs(DEVINST devinst,
DEVINST* pdevinst)
{
BOOL fRemovable;
HRESULT hres = _DeviceInstIsRemovable(devinst, &fRemovable);
if (SUCCEEDED(hres))
{
if (fRemovable)
{
// Found it!
*pdevinst = devinst;
}
else
{
// Recurse
DEVINST devinstParent;
CONFIGRET cr = CM_Get_Parent_Ex(&devinstParent, devinst, 0,
NULL);
if (CR_SUCCESS == cr)
{
hres = _GetRemovableDeviceInstRecurs(devinstParent, pdevinst);
}
else
{
hres = S_FALSE;
}
}
}
return hres;
}
HRESULT CVolume::_GetDeviceIDDisk(LPWSTR pszDeviceIDDisk,
DWORD cchDeviceIDDisk)
{
HRESULT hr;
_cs.Enter();
if (_szDeviceIDDisk[0])
{
hr = SafeStrCpyN(pszDeviceIDDisk, _szDeviceIDDisk, cchDeviceIDDisk);
}
else
{
if (((ULONG)-1) != _ulDeviceNumber)
{
CNamedElemList* pnel;
hr = CHWEventDetectorHelper::GetList(HWEDLIST_DISK, &pnel);
if (S_OK == hr)
{
CNamedElemEnum* penum;
hr = pnel->GetEnum(&penum);
if (SUCCEEDED(hr))
{
CNamedElem* pelem;
BOOL fFoundIt = FALSE;
while (!fFoundIt && SUCCEEDED(hr = penum->Next(&pelem)) &&
(S_FALSE != hr))
{
CDisk* pdisk = (CDisk*)pelem;
ULONG ulDeviceNumber;
hr = pdisk->GetDeviceNumber(&ulDeviceNumber);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
if (_ulDeviceNumber == ulDeviceNumber)
{
DEVICE_TYPE devtype;
hr = pdisk->GetDeviceType(&devtype);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
if (_devtype == devtype)
{
// Use me!
DWORD cchReq;
hr = pelem->GetName(pszDeviceIDDisk,
cchDeviceIDDisk, &cchReq);
fFoundIt = TRUE;
}
}
}
}
pelem->RCRelease();
}
penum->RCRelease();
}
pnel->RCRelease();
}
}
else
{
hr = S_FALSE;
}
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
if (FAILED(SafeStrCpyN(_szDeviceIDDisk, pszDeviceIDDisk,
ARRAYSIZE(_szDeviceIDDisk))))
{
_szDeviceIDDisk[0] = 0;
}
}
}
_cs.Leave();
return hr;
}
HRESULT CVolume::_InitHWDeviceInst()
{
WCHAR szDeviceIDDisk[MAX_DEVICEID];
HRESULT hr = _GetDeviceIDDisk(szDeviceIDDisk, ARRAYSIZE(szDeviceIDDisk));
if (SUCCEEDED(hr))
{
DEVINST devinstFinal = 0;
GUID guidDummy;
if (S_FALSE != hr)
{
DEVINST devinstDisk;
hr = _GetDeviceInstance(szDeviceIDDisk, &devinstDisk, &guidDummy);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
hr = _GetRemovableDeviceInstRecurs(devinstDisk, &devinstFinal);
if (SUCCEEDED(hr))
{
if (S_FALSE == hr)
{
// Maybe this is not a removable device (not talking
// about removable disk).
BOOL fFoundProp;
WCHAR szProp[1];
ULONG ulData = sizeof(szProp);
// First check if the disk interface has customn properties associated with it.
CONFIGRET cr = CM_Get_DevNode_Custom_Property(devinstDisk, TEXT("DeviceGroup"),
NULL, (PBYTE)szProp, &ulData, 0);
if ((CR_SUCCESS == cr) || (CR_BUFFER_SMALL == cr))
{
fFoundProp = TRUE;
}
else
{
ulData = sizeof(szProp);
cr = CM_Get_DevNode_Custom_Property(devinstDisk, TEXT("Icons"),
NULL, (PBYTE)szProp, &ulData, 0);
if ((CR_SUCCESS == cr) || (CR_BUFFER_SMALL == cr))
{
fFoundProp = TRUE;
}
else
{
fFoundProp = FALSE;
}
}
if (fFoundProp)
{
devinstFinal = devinstDisk;
hr = S_OK;
}
else
{
// Let's get the parent devinst of this devinst.
if (CR_SUCCESS == CM_Get_Parent_Ex(&devinstFinal,
devinstDisk, 0, NULL))
{
hr = S_OK;
DIAGNOSTIC((TEXT("[0303]Got DeviceInst from parent of disk")));
TRACE(TF_VOLUME,
TEXT("HWDevInst: Got devinst from parent of Disk for Disk\n %s"),
_pszElemName);
}
}
}
else
{
DIAGNOSTIC((TEXT("[0302]Got DeviceInst from Removable Device")));
TRACE(TF_VOLUME,
TEXT("HWDevInst: Got devinst from Removable Device for Volume\n %s"),
_pszElemName);
}
}
}
else
{
DIAGNOSTIC((TEXT("[0304]Did NOT get DeviceInst from the disk")));
TRACE(TF_VOLUME,
TEXT("HWDevInst: Did not get a devinst from the Disk for Volume\n %s"),
_pszElemName);
}
}
else
{
DIAGNOSTIC((TEXT("[0305]Got DeviceInst from Volume itself")));
TRACE(TF_VOLUME,
TEXT("HWDevInst: Did not get a Disk, get devinst from Volume itself for Volume\n (%s)"),
_pszElemName);
// We did not get a device number for the volume
// Let's get the device instance from the volume then, maybe there's no
// volume-disk-device hierarchy
hr = _GetDeviceInstance(_pszElemName, &devinstFinal, &guidDummy);
}
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
hr = _hwdevinst.Init(devinstFinal);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
hr = _hwdevinst.InitInterfaceGUID(&guidVolumeClass);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
_fHWDevInstInited = TRUE;
}
}
}
}
return hr;
}
HRESULT CVolume::GetHWDeviceInst(CHWDeviceInst** pphwdevinst)
{
HRESULT hr;
if (_fHWDevInstInited)
{
*pphwdevinst = &_hwdevinst;
hr = S_OK;
}
else
{
*pphwdevinst = NULL;
hr = S_FALSE;
}
return hr;
}
HRESULT CVolume::_ShouldTryAutoplay(BOOL* pfTry)
{
HRESULT hr;
if (_dwMediaState & HWDMS_PRESENT)
{
if (_dwMediaState & HWDMS_FORMATTED)
{
if (!(_dwMediaCap & HWDMC_HASDVDMOVIE))
{
if (!(_dwMediaCap & HWDMC_HASAUTORUNINF) ||
(_dwMediaCap & HWDMC_HASUSEAUTOPLAY))
{
WCHAR szVolumeGUID[MAX_PATH + 50];
LPWSTR pszFile;
if (_dwMediaCap & HWDMC_HASUSEAUTOPLAY)
{
DIAGNOSTIC((TEXT("[0316]Autorun.inf, BUT as a UseAutoPLAY entry -> try Autoplay!")));
}
hr = SafeStrCpyN(szVolumeGUID, _szVolumeGUID,
ARRAYSIZE(szVolumeGUID));
*pfTry = TRUE;
if (SUCCEEDED(hr))
{
HKEY hkey;
pszFile = szVolumeGUID + lstrlen(szVolumeGUID);
TRACE(TF_LEAK, TEXT("Special files - BEGIN"));
hr = _RegOpenKey(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\CancelAutoplay\\Files"),
&hkey);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
DWORD dwIndex = 0;
while ((*pfTry) && SUCCEEDED(hr = _RegEnumStringValue(hkey, dwIndex, pszFile,
(DWORD)(ARRAYSIZE(szVolumeGUID) - (pszFile - szVolumeGUID)))) &&
(S_FALSE != hr))
{
WIN32_FIND_DATA w32fd;
HANDLE h;
h = FindFirstFile(szVolumeGUID, &w32fd);
if (INVALID_HANDLE_VALUE != h)
{
FindClose(h);
*pfTry = FALSE;
DIAGNOSTIC((TEXT("[0307]Detected special file : '%s' (%s) -> No Autoplay!"),
w32fd.cFileName, pszFile));
TRACE(TF_VOLUME,
TEXT("Detected %s (%s) -> No Autoplay!"),
w32fd.cFileName , pszFile);
}
++dwIndex;
}
_RegCloseKey(hkey);
}
TRACE(TF_LEAK, TEXT("Special files - END"));
}
}
else
{
DIAGNOSTIC((TEXT("[0313]Autorun.inf -> No Content Autoplay!")));
hr = S_OK;
*pfTry = FALSE;
}
}
else
{
DIAGNOSTIC((TEXT("[0312]DVD Movie -> No Content Autoplay!")));
hr = S_OK;
*pfTry = FALSE;
}
}
else
{
DIAGNOSTIC((TEXT("[0317]Media *NOT* formatted -> No Content Autoplay!")));
hr = S_OK;
*pfTry = FALSE;
}
}
else
{
DIAGNOSTIC((TEXT("[0306]NO media -> No Content Autoplay!")));
hr = S_OK;
*pfTry = FALSE;
}
return hr;
}
HRESULT CVolume::_HandleMediaArrival()
{
DIAGNOSTIC((TEXT("[0002]Processing Media Arrival Event: %s"), _pszElemName));
_dwMediaPresentFromEvent = MPFE_TRUE;
_cs.Enter();
HRESULT hr = _UpdateMediaInfo(INVALID_HANDLE_VALUE, TRUE);
_cs.Leave();
if (SUCCEEDED(hr))
{
if (_fHWDevInstInited)
{
// Try Autoplay?
BOOL fTryAutoplay;
hr = _ShouldTryAutoplay(&fTryAutoplay);
if (SUCCEEDED(hr))
{
if (fTryAutoplay)
{
BOOL fHasHandler;
hr = CHWEventDetectorImpl::HandleVolumeMediaEvent(
_pszElemName, &_hwdevinst, TEXT("MediaArrival"),
&fHasHandler);
if (SUCCEEDED(hr) && fHasHandler)
{
_dwVolumeFlags |= HWDVF_STATE_HASAUTOPLAYHANDLER;
}
}
else
{
_dwVolumeFlags |= HWDVF_STATE_DONOTSNIFFCONTENT;
}
}
}
else
{
DIAGNOSTIC((TEXT("[0308]Cannot find hardware device for this volume -> No Autoplay!")));
}
if (SUCCEEDED(hr))
{
_AdviseVolumeChangeHelper(FALSE);
}
}
else
{
hr = S_FALSE;
}
return hr;
}
HRESULT CVolume::_AdviseVolumeMountingEvent(DWORD dwEvent)
{
return CHardwareDevicesImpl::_AdviseVolumeMountingEvent(_pszElemName,
dwEvent);
}
HRESULT CVolume::_AdviseVolumeChangeHelper(BOOL fAdded)
{
HRESULT hr;
VOLUMEINFO2* pvolinfo2;
_cs.Enter();
hr = _GetVOLUMEINFO2(&pvolinfo2);
_cs.Leave();
if (SUCCEEDED(hr))
{
LPWSTR pszMtPts;
DWORD cchMtPts;
hr = _GetMountPoints(&pszMtPts, &cchMtPts);
if (SUCCEEDED(hr))
{
CHardwareDevicesImpl::_AdviseVolumeArrivedOrUpdated(pvolinfo2,
pszMtPts, cchMtPts, fAdded);
if (S_FALSE != hr)
{
LocalFree((HLOCAL)pszMtPts);
}
}
_FreeMemoryChunk<VOLUMEINFO2*>(pvolinfo2);
}
return hr;
}
HRESULT CVolume::_HandleMediaRemoval()
{
HRESULT hr;
DIAGNOSTIC((TEXT("[0003]Processing Media Removal Event: %s"), _pszElemName));
_dwMediaPresentFromEvent = MPFE_FALSE;
_cs.Enter();
hr = _UpdateMediaInfoOnRemove();
_cs.Leave();
if (SUCCEEDED(hr))
{
_AdviseVolumeChangeHelper(FALSE);
if (_fHWDevInstInited)
{
// Useless in this case, since there's no content, so we won't sniff
BOOL fHasHandler;
hr = CHWEventDetectorImpl::HandleVolumeMediaEvent(_pszElemName,
&_hwdevinst, TEXT("MediaRemoval"), &fHasHandler);
}
else
{
DIAGNOSTIC((TEXT("[0309]Cannot find hardware device for this volume -> No Autoplay!")));
}
}
return hr;
}
HRESULT CVolume::_HandleVolumeChange()
{
HRESULT hr;
_cs.Enter();
hr = _UpdateMediaInfo(INVALID_HANDLE_VALUE, TRUE);
_cs.Leave();
if (SUCCEEDED(hr))
{
_AdviseVolumeChangeHelper(FALSE);
}
else
{
hr = S_FALSE;
}
return hr;
}
HRESULT CVolume::HNTHandleEvent(DEV_BROADCAST_HANDLE* pdbh,
DWORD dwEventType)
{
HRESULT hres = S_OK;
if (DBT_CUSTOMEVENT == dwEventType)
{
if (GUID_IO_MEDIA_ARRIVAL == pdbh->dbch_eventguid)
{
// This notification arrive very soon when the media is inserted
// in the device. Often the Volume driver has not been loaded on
// the drive and calls like GetVolumeInformation will fail.
// Instead of doing something right now, flag the event, and
// process on the first GUID_IO_VOLUME_MOUNT below.
TRACE(TF_SHHWDTCTDTCT,
TEXT("****CVolume GUID_IO_MEDIA_ARRIVAL"));
hres = _HandleMediaArrival();
}
else if (GUID_IO_MEDIA_REMOVAL == pdbh->dbch_eventguid)
{
TRACE(TF_SHHWDTCTDTCT,
TEXT("****CVolume GUID_IO_MEDIA_REMOVAL"));
hres = _HandleMediaRemoval();
}
else if (GUID_IO_VOLUME_MOUNT == pdbh->dbch_eventguid)
{
TRACE(TF_SHHWDTCTDTCT,
TEXT("****CVolume GUID_IO_VOLUME_MOUNT"));
if (_dwVolumeFlags & HWDVF_STATE_DISMOUNTED)
{
_dwVolumeFlags &= ~HWDVF_STATE_DISMOUNTED;
hres = _AdviseVolumeMountingEvent(
SHHARDWAREEVENT_VOLUMEMOUNTED);
_HandleVolumeChange();
}
}
else if (GUID_IO_VOLUME_NAME_CHANGE == pdbh->dbch_eventguid)
{
TRACE(TF_SHHWDTCTDTCT,
TEXT("****CVolume GUID_IO_VOLUME_NAME_CHANGE"));
_cs.Enter();
hres = _UpdateMountPoints();
_cs.Leave();
}
else if (GUID_IO_VOLUME_CHANGE == pdbh->dbch_eventguid)
{
TRACE(TF_SHHWDTCTDTCT,
TEXT("****CVolume GUID_IO_VOLUME_CHANGE"));
_cs.Enter();
// This is for bug 645878. Basically, it's to cover the case of a
// volume mounted on another volume's folder and then transfered
// to another clustered machine. We use to miss the volume
// mounted on the folder. Even thought the right event to send
// would have been GUID_IO_VOLUME_NAME_CHANGE, it swas not
// possible unless the cluster guys would have unmounted the volume
// from the folder and remounted it, which is overkill just for an
// icon.
hres = _UpdateMountPoints();
_cs.Leave();
hres = _HandleVolumeChange();
}
else if (GUID_IO_VOLUME_DISMOUNT == pdbh->dbch_eventguid)
{
_dwVolumeFlags |= HWDVF_STATE_DISMOUNTED;
hres = _AdviseVolumeMountingEvent(
SHHARDWAREEVENT_VOLUMEDISMOUNTED);
}
else if (GUID_IO_VOLUME_DISMOUNT_FAILED == pdbh->dbch_eventguid)
{
_dwVolumeFlags &= ~HWDVF_STATE_DISMOUNTED;
hres = _AdviseVolumeMountingEvent(
SHHARDWAREEVENT_VOLUMEMOUNTED);
}
}
return hres;
}
HRESULT CVolume::_GetDeviceHandleSafe(HANDLE* phDevice,
BOOL fGenericReadRequired)
{
ASSERT(!_hdevnotify);
HRESULT hr;
HANDLE hDevice = _GetDeviceHandle(_pszElemName,
fGenericReadRequired ? GENERIC_READ : FILE_READ_ATTRIBUTES);
*phDevice = INVALID_HANDLE_VALUE;
if (INVALID_HANDLE_VALUE != hDevice)
{
DEV_BROADCAST_HANDLE dbhNotifFilter = {0};
dbhNotifFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
dbhNotifFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
dbhNotifFilter.dbch_handle = hDevice;
hr = CHWEventDetectorHelper::RegisterDeviceNotification(
&dbhNotifFilter, &_hdevnotify, FALSE);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
*phDevice = hDevice;
#ifdef DEBUG
_fGenericReadRequired = fGenericReadRequired;
#endif
}
else
{
_CloseDeviceHandle(hDevice);
}
}
else
{
hr = S_FALSE;
}
return hr;
}
HRESULT CVolume::_CloseDeviceHandleSafe(HANDLE hDevice)
{
ASSERT(_hdevnotify);
_CloseDeviceHandle(hDevice);
UnregisterDeviceNotification(_hdevnotify);
_hdevnotify = NULL;
return S_OK;
}
HRESULT CVolume::_UnregisterNotif()
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_HANDLENOTIF,
&pnel);
if (S_OK == hres)
{
hres = pnel->Remove(_pszElemName);
if (_szDeviceIDDisk[0])
{
hres = pnel->Remove(_szDeviceIDDisk);
}
pnel->RCRelease();
}
return hres;
}
HRESULT CVolume::_RegisterNotif()
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_HANDLENOTIF,
&pnel);
if (S_OK == hres)
{
CNamedElem* pelem;
// register for handle notification
hres = pnel->GetOrAdd(_pszElemName, &pelem);
// Was it already there or added?
if (SUCCEEDED(hres) && (S_FALSE == hres))
{
// Added. Initialize it.
CHandleNotif* phnotif = (CHandleNotif*)pelem;
hres = phnotif->InitNotif(this);
if (SUCCEEDED(hres))
{
if (HWDTS_REMOVABLEDISK == _dwDriveType)
{
// Removable disk drives receive their notifications for
// media arrival/removal on the disk interface, not the
// volume one, so register for this too.
WCHAR szDeviceIDDisk[MAX_DEVICEID];
hres = _GetDeviceIDDisk(szDeviceIDDisk,
ARRAYSIZE(szDeviceIDDisk));
if (SUCCEEDED(hres) && (S_FALSE != hres))
{
CNamedElem* pelem2;
// register for handle notification
hres = pnel->GetOrAdd(szDeviceIDDisk, &pelem2);
// Was it already there or added?
if (SUCCEEDED(hres) && (S_FALSE == hres))
{
// Added. Initialize it.
CHandleNotif* phnotif2 = (CHandleNotif*)pelem2;
hres = phnotif2->InitNotif(this);
if (FAILED(hres))
{
pnel->Remove(szDeviceIDDisk);
}
pelem2->RCRelease();
}
}
}
}
if (FAILED(hres))
{
pnel->Remove(_pszElemName);
}
pelem->RCRelease();
}
pnel->RCRelease();
}
return hres;
}
HRESULT CVolume::_RemoveMtPt(LPWSTR pszMtPt)
{
CNamedElemList* pnel;
HRESULT hr = CHWEventDetectorHelper::GetList(HWEDLIST_MTPT, &pnel);
if (S_OK == hr)
{
hr = pnel->Remove(pszMtPt);
pnel->RCRelease();
}
return hr;
}
HRESULT CVolume::_CreateMtPt(LPWSTR pszMtPt)
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_MTPT, &pnel);
if (S_OK == hres)
{
CNamedElem* pelem;
hres = pnel->GetOrAdd(pszMtPt, &pelem);
if (SUCCEEDED(hres))
{
// Init one way or the other
CMtPt* pmtpt = (CMtPt*)pelem;
hres = pmtpt->InitVolume(_pszElemName);
if (FAILED(hres))
{
pnel->Remove(pszMtPt);
}
pelem->RCRelease();
}
pnel->RCRelease();
}
return hres;
}
HRESULT CVolume::_AdviseMountPointHelper(LPCWSTR pszMountPoint, BOOL fAdded)
{
// I'd like to not call this from outside the crit sect
ASSERT(_cs.IsInside());
WCHAR szDeviceIDVolume[MAX_DEVICEID];
DWORD cchReq;
HRESULT hr = GetName(szDeviceIDVolume, ARRAYSIZE(szDeviceIDVolume), &cchReq);
if (SUCCEEDED(hr))
{
CHardwareDevicesImpl::_AdviseMountPointHelper(pszMountPoint,
szDeviceIDVolume, fAdded);
}
return hr;
}
HRESULT CVolume::_UpdateMountPoints()
{
LPWSTR pszMtPtNew;
DWORD cchMtPtNew;
HRESULT hr = _GetMountPoints(&pszMtPtNew, &cchMtPtNew);
#ifdef DEBUG
if (_pszMountPoints)
{
TRACE(TF_VOLUME, TEXT("_UpdateMountPoints: OLD mountPoints for %s:"), _pszElemName);
for (LPWSTR psz = _pszMountPoints; *psz; psz += lstrlen(psz) + 1)
{
TRACE(TF_VOLUME, TEXT(" %s"), psz);
}
}
#endif
if (SUCCEEDED(hr))
{
if (S_FALSE != hr)
{
#ifdef DEBUG
TRACE(TF_VOLUME, TEXT("_UpdateMountPoints: NEW mountPoints:"));
for (LPWSTR psz = pszMtPtNew; *psz; psz += lstrlen(psz) + 1)
{
TRACE(TF_VOLUME, TEXT(" %s"), psz);
}
#endif
// Was there at least one?
if (_pszMountPoints)
{
// Yep, find the removed ones
for (LPWSTR pszOld = _pszMountPoints; *pszOld;
pszOld += lstrlen(pszOld) + 1)
{
BOOL fFoundInNew = FALSE;
for (LPWSTR pszNew = pszMtPtNew; !fFoundInNew && *pszNew;
pszNew += lstrlen(pszNew) + 1)
{
if (!lstrcmpi(pszNew, pszOld))
{
fFoundInNew = TRUE;
}
}
if (!fFoundInNew)
{
TRACE(TF_VOLUME, TEXT("_UpdateMountPoints: Found DELETED one: %s"), pszOld);
// That's a deleted one
_RemoveMtPt(pszOld);
_AdviseMountPointHelper(pszOld, FALSE);
}
}
}
else
{
TRACE(TF_VOLUME, TEXT("_UpdateMountPoints: There was NO mountpoints before"));
}
// Find the new ones
for (LPWSTR pszNew = pszMtPtNew; *pszNew;
pszNew += lstrlen(pszNew) + 1)
{
BOOL fFoundInOld = FALSE;
if (_pszMountPoints)
{
for (LPWSTR pszOld = _pszMountPoints;
!fFoundInOld && *pszOld; pszOld += lstrlen(pszOld) + 1)
{
if (!lstrcmpi(pszNew, pszOld))
{
fFoundInOld = TRUE;
}
}
}
if (!fFoundInOld)
{
TRACE(TF_VOLUME, TEXT("_UpdateMountPoints: Found ADDED one: %s"), pszNew);
// That's a new one
_CreateMtPt(pszNew);
_AdviseMountPointHelper(pszNew, TRUE);
}
}
LocalFree(_pszMountPoints);
_pszMountPoints = pszMtPtNew;
_cchMountPoints = cchMtPtNew;
}
else
{
TRACE(TF_VOLUME, TEXT("_UpdateMountPoints: NO MountPoints left, remove all old ones"));
if (_pszMountPoints && *_pszMountPoints)
{
for (LPWSTR pszOld = _pszMountPoints; *pszOld;
pszOld += lstrlen(pszOld) + 1)
{
_RemoveMtPt(pszOld);
_AdviseMountPointHelper(pszOld, FALSE);
}
LocalFree(_pszMountPoints);
_pszMountPoints = NULL;
_cchMountPoints = 0;
}
}
}
return hr;
}
HRESULT CVolume::_CreateMountPoints()
{
HRESULT hr = _GetMountPoints(&_pszMountPoints, &_cchMountPoints);
if (SUCCEEDED(hr))
{
if (S_FALSE != hr)
{
for (LPWSTR psz = _pszMountPoints; *psz;
psz += lstrlen(psz) + 1)
{
_CreateMtPt(psz);
// go on even if error
}
}
else
{
hr = S_OK;
}
}
return hr;
}
// Caller must free returned data using LocalFree
HRESULT CVolume::_GetMountPoints(LPWSTR* ppsz, DWORD* pcch)
{
HRESULT hr;
LPWSTR psz = NULL;
DWORD cch;
*ppsz = NULL;
*pcch = 0;
if (GetVolumePathNamesForVolumeName(_szVolumeGUID, NULL, 0, &cch))
{
// no mountpoint, we're done
hr = S_FALSE;
}
else
{
// Expected, even wanted...
if (ERROR_MORE_DATA == GetLastError())
{
psz = (LPWSTR)LocalAlloc(LPTR, cch * sizeof(WCHAR));
if (psz)
{
if (GetVolumePathNamesForVolumeName(_szVolumeGUID,
psz, cch, &cch))
{
*ppsz = psz;
*pcch = cch;
hr = S_OK;
}
else
{
LocalFree(psz);
hr = S_FALSE;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = S_FALSE;
}
}
return hr;
}
HRESULT _DeviceMediaIsAccessible(HANDLE hDevice, BOOL* pfAccessible)
{
HRESULT hres = S_FALSE;
DWORD dwDummy;
*pfAccessible = FALSE;
// requires GENERIC_READ access on the handle
BOOL b = DeviceIoControl(hDevice, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &dwDummy, NULL);
if (ERROR_MEDIA_CHANGED == GetLastError())
{
// try one more time, ERROR_MEDIA_CHANGED means it's still pending for a little bit.
b = DeviceIoControl(hDevice, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &dwDummy, NULL);
}
if (b)
{
*pfAccessible = TRUE;
hres = S_OK;
}
else
{
// ERROR_NOT_READY == GetLastError() means no media
if (ERROR_NOT_READY == GetLastError())
{
hres = S_OK;
}
else
{
hres = S_FALSE;
}
}
return hres;
}
HRESULT CVolume::_UpdateHasMedia(HANDLE hDevice)
{
HRESULT hr = S_FALSE;
switch (_dwDriveType)
{
case HWDTS_FIXEDDISK:
_dwMediaState |= HWDMS_PRESENT;
hr = S_OK;
break;
case HWDTS_REMOVABLEDISK:
case HWDTS_CDROM:
{
#if 0
This does not work on my laptop
if (_dwDriveCap & HWDDC_CAPABILITY_SUPPORTDETECTION)
{
// It's MMC2
if (_dwMediaCap & (HWDMC_CDROM | HWDMC_CDRECORDABLE |
HWDMC_CDREWRITABLE | HWDMC_DVDROM | HWDMC_DVDRECORDABLE |
HWDMC_DVDRAM))
{
_dwMediaState |= HWDMS_PRESENT;
}
else
{
_dwMediaState &= ~HWDMS_PRESENT;
}
}
else
#endif
if (MPFE_UNDETERMINED != _dwMediaPresentFromEvent)
{
hr = S_OK;
if (MPFE_TRUE == _dwMediaPresentFromEvent)
{
_dwMediaState |= HWDMS_PRESENT;
}
else
{
_dwMediaState &= ~HWDMS_PRESENT;
}
}
else
{
BOOL fAccessible;
ASSERT(_fGenericReadRequired);
hr = _DeviceMediaIsAccessible(hDevice, &fAccessible);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
if (fAccessible)
{
_dwMediaState |= HWDMS_PRESENT;
}
else
{
_dwMediaState &= ~HWDMS_PRESENT;
}
}
else
{
_dwMediaState &= ~HWDMS_PRESENT;
}
}
break;
}
default:
// ISSUE-2000/10/23-StephStm: We do not handle CD Changer, maybe we should
//
// case HWDTS_CDCHANGER:
case HWDTS_FLOPPY35:
case HWDTS_FLOPPY525:
_dwMediaState &= ~HWDMS_PRESENT;
break;
}
return hr;
}
HRESULT CVolume::_ExtractAutorunIconAndLabel()
{
WCHAR szInfFile[MAX_PATH + 50];
LPWSTR pszNext;
DWORD cchLeft;
HRESULT hr = SafeStrCpyNEx(szInfFile, _szVolumeGUID, ARRAYSIZE(szInfFile),
&pszNext, &cchLeft);
if (SUCCEEDED(hr))
{
hr = SafeStrCpyN(pszNext, TEXT("Autorun.inf"), cchLeft);
if (SUCCEEDED(hr))
{
WCHAR szDummy[4];
#if defined(_X86_)
LPWSTR pszSection = TEXT("AutoRun.x86");
#elif defined(_AMD64_)
LPWSTR pszSection = TEXT("AutoRun.Amd64");
#elif defined(_IA64_)
LPWSTR pszSection = TEXT("AutoRun.Ia64");
#else
#error "No Target Architecture"
#endif
// Flush some buffer somewhere
WritePrivateProfileString(NULL, NULL, NULL, szInfFile);
if (!GetPrivateProfileString(pszSection, TEXT("Icon"), TEXT(""),
_szAutorunIconLocation, ARRAYSIZE(_szAutorunIconLocation),
szInfFile))
{
pszSection = TEXT("AutoRun");
_HandleAccessDenied();
if (!GetPrivateProfileString(pszSection, TEXT("Icon"),
TEXT(""), _szAutorunIconLocation,
ARRAYSIZE(_szAutorunIconLocation), szInfFile))
{
_szAutorunIconLocation[0] = 0;
_HandleAccessDenied();
}
}
if (!GetPrivateProfileString(pszSection, TEXT("Label"), TEXT(""),
_szAutorunLabel, ARRAYSIZE(_szAutorunLabel), szInfFile))
{
_szAutorunLabel[0] = 0;
_HandleAccessDenied();
}
if (GetPrivateProfileString(pszSection, TEXT("Open"), TEXT(""),
szDummy, ARRAYSIZE(szDummy), szInfFile) ||
GetPrivateProfileString(pszSection, TEXT("ShellExecute"), TEXT(""),
szDummy, ARRAYSIZE(szDummy), szInfFile))
{
_dwMediaCap |= HWDMC_HASAUTORUNCOMMAND;
}
else
{
_HandleAccessDenied();
}
if (GetPrivateProfileString(pszSection, TEXT("UseAutoPLAY"), TEXT(""),
szDummy, ARRAYSIZE(szDummy), szInfFile))
{
_dwMediaCap |= HWDMC_HASUSEAUTOPLAY;
}
else
{
_HandleAccessDenied();
}
}
}
return hr;
}
HRESULT CVolume::_UpdateSpecialFilePresence()
{
struct SPECIALFILEINFO
{
LPCWSTR pszFile;
DWORD dwCapBit;
};
HRESULT hr;
WCHAR szPath[50 + 1 + ARRAYSIZE(TEXT("video_ts\\video_ts.ifo"))];
static const SPECIALFILEINFO rgsfi[] =
{
{ TEXT("autorun.inf"), HWDMC_HASAUTORUNINF },
{ TEXT("desktop.ini"), HWDMC_HASDESKTOPINI },
{ TEXT("video_ts\\video_ts.ifo"), HWDMC_HASDVDMOVIE },
};
LPWSTR pszNext;
DWORD cchLeft;
hr = SafeStrCpyNEx(szPath, _szVolumeGUID,
ARRAYSIZE(szPath), &pszNext, &cchLeft);
if (SUCCEEDED(hr))
{
for (DWORD dw = 0; dw < ARRAYSIZE(rgsfi); ++dw)
{
hr = SafeStrCpyN(pszNext, rgsfi[dw].pszFile, cchLeft);
if (SUCCEEDED(hr))
{
DWORD dwGFA = GetFileAttributes(szPath);
if (-1 != dwGFA)
{
_dwMediaCap |= (rgsfi[dw].dwCapBit);
}
else
{
_HandleAccessDenied();
}
}
}
}
// To fix bug 425431
if (HWDMC_HASDVDMOVIE & _dwMediaCap)
{
// This better be a CD/DVD drive.
if (HWDTS_CDROM != _dwDriveType)
{
// No. Remove the flag otherwise, Hard Disks get a Play verb
// when they have the ts_video\video_ts.ifo file in their root.
_dwMediaCap &= ~HWDMC_HASDVDMOVIE;
}
}
return hr;
}
#define TRACK_TYPE_MASK 0x04
#define AUDIO_TRACK 0x00
#define DATA_TRACK 0x04
HRESULT CVolume::_UpdateTrackInfo(HANDLE hDevice)
{
HRESULT hr;
ASSERT(!(_dwMediaCap & (HWDMC_HASDATATRACKS | HWDMC_HASAUDIOTRACKS)));
hr = S_OK;
// To be compatible with Win95, we'll only return TRUE from this
// function if the disc has ONLY audio tracks (and NO data tracks).
// FEATURE: Post NT-SUR beta 1, we should consider adding a new
// DriveType flag for "contains data tracks" and revamp the commands
// available on a CD-ROM drive. The current code doesn't handle
// mixed audio/data and audio/autorun discs very usefully. --JonBe
// First try the new IOCTL which gives us a ULONG with bits indicating
// the presence of either/both data & audio tracks
CDROM_DISK_DATA data;
DWORD dwDummy;
// Requires GENERIC_READ access on the handle
if (DeviceIoControl(hDevice, IOCTL_CDROM_DISK_TYPE, NULL, 0, &data,
sizeof(data), &dwDummy, NULL))
{
if (data.DiskData & CDROM_DISK_AUDIO_TRACK)
{
_dwMediaCap |= HWDMC_HASAUDIOTRACKS;
}
if (data.DiskData & CDROM_DISK_DATA_TRACK)
{
_dwMediaCap |= HWDMC_HASDATATRACKS;
}
}
else
{
// else that failed, so try to look for audio tracks the old way, by
// looking throught the table of contents manually. Note that data tracks
// are supposed to be hidden in the TOC by CDFS now on mixed audio/data
// discs (at least if the data tracks follow the audio tracks).
CDROM_TOC toc = {0};
if (!DeviceIoControl(hDevice, IOCTL_CDROM_READ_TOC, NULL, 0, &toc,
sizeof(toc), &dwDummy, NULL))
{
SUB_Q_CHANNEL_DATA subq = {0};
CDROM_SUB_Q_DATA_FORMAT df = {0};
// We might not have been able to read the TOC because the drive
// was busy playing audio. Lets try querying the audio position.
df.Format = IOCTL_CDROM_CURRENT_POSITION;
df.Track = 0;
if (DeviceIoControl(hDevice, IOCTL_CDROM_READ_Q_CHANNEL, &df,
sizeof(df), &subq, sizeof(subq), &dwDummy, NULL))
{
if (AUDIO_DATA_TRACK & subq.CurrentPosition.Control)
{
_dwMediaCap |= HWDMC_HASDATATRACKS;
}
else
{
_dwMediaCap |= HWDMC_HASAUDIOTRACKS;
}
}
// Is there the equivalent of IOCTL_CDROM_READ_Q_CHANNEL for data?
_dwMediaCap |= HWDMC_HASDATATRACKS_UNDETERMINED;
}
else
{
int nTracks = (toc.LastTrack - toc.FirstTrack) + 1;
int iTrack = 0;
// Now iterate through the tracks looking for Audio data
while ((iTrack < nTracks) &&
((_dwMediaCap & (HWDMC_HASDATATRACKS | HWDMC_HASDATATRACKS)) !=
(HWDMC_HASDATATRACKS | HWDMC_HASDATATRACKS))
)
{
if ((toc.TrackData[iTrack].Control & TRACK_TYPE_MASK) == AUDIO_TRACK)
{
_dwMediaCap |= HWDMC_HASAUDIOTRACKS;
}
else
{
if ((toc.TrackData[iTrack].Control & TRACK_TYPE_MASK) == DATA_TRACK)
{
_dwMediaCap |= HWDMC_HASDATATRACKS;
}
}
++iTrack;
}
}
}
return hr;
}
HRESULT CVolume::_UpdateMediaInfoOnRemove()
{
_dwMediaCap = 0;
_dwMediaState = 0;
_szAutorunIconLocation[0] = 0;
_szAutorunLabel[0] = 0;
_dwSerialNumber = 0xBADBADBD;
SafeStrCpyN(_szLabel, TEXT("Invalid"), ARRAYSIZE(_szLabel));
SafeStrCpyN(_szFileSystem, TEXT("Invalid"), ARRAYSIZE(_szFileSystem));
_dwRootAttributes = 0xBADBADBD;
_dwMaxFileNameLen = 0xBADBADBD;
_dwFileSystemFlags = 0xBADBADBD;
_dwVolumeFlags &= ~(HWDVF_STATE_HASAUTOPLAYHANDLER |
HWDVF_STATE_DONOTSNIFFCONTENT | HWDVF_STATE_JUSTDOCKED);
return S_OK;
}
inline BOOL _XOR(BOOL bA, BOOL bB)
{
return (bA && !bB) || (!bA && bB);
}
HRESULT CVolume::_UpdateMediaInfo(HANDLE hDevice, BOOL fGetYourOwnHandle)
{
HRESULT hr;
CImpersonateEveryone* pieo = NULL;
ASSERT(_XOR((hDevice != INVALID_HANDLE_VALUE), fGetYourOwnHandle));
if (fGetYourOwnHandle)
{
hr = CHWEventDetectorHelper::GetImpersonateEveryone(&pieo);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
hr = pieo->Impersonate();
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
hr = _GetDeviceHandleSafe(&hDevice, TRUE);
if (FAILED(hr) || (S_FALSE == hr))
{
pieo->RCRelease();
pieo = NULL;
}
}
}
}
else
{
hr = S_OK;
}
_dwVolumeFlags &= ~(HWDVF_STATE_HASAUTOPLAYHANDLER |
HWDVF_STATE_DONOTSNIFFCONTENT | HWDVF_STATE_JUSTDOCKED);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
if (HWDTS_CDROM == _dwDriveType)
{
ASSERT(_fGenericReadRequired);
// optimization
if (_fFirstTime)
{
// already updated by _UpdateConstInfo
_fFirstTime = FALSE;
}
else
{
_dwMediaCap = 0;
hr = _UpdateMMC2CDInfo(hDevice);
}
}
else
{
_dwMediaCap = 0;
}
if (SUCCEEDED(hr))
{
hr = _UpdateHasMedia(hDevice);
if (SUCCEEDED(hr) && (_dwMediaState & HWDMS_PRESENT))
{
if (GetVolumeInformation(_szVolumeGUID, _szLabel,
ARRAYSIZE(_szLabel), &_dwSerialNumber,
&_dwMaxFileNameLen, &_dwFileSystemFlags, _szFileSystem,
ARRAYSIZE(_szFileSystem)))
{
// use this?
// UINT err = SetErrorMode(SEM_FAILCRITICALERRORS);
// Root folder attributes
_dwRootAttributes = GetFileAttributes(_szVolumeGUID);
if (-1 != _dwRootAttributes)
{
// File presence
hr = _UpdateSpecialFilePresence();
if (SUCCEEDED(hr))
{
if (HWDTS_CDROM == _dwDriveType)
{
hr = _UpdateTrackInfo(hDevice);
}
if (HWDMC_HASAUTORUNINF & _dwMediaCap)
{
hr = _ExtractAutorunIconAndLabel();
// not critical
if (FAILED(hr))
{
hr = S_FALSE;
}
}
}
}
else
{
_HandleAccessDenied();
_dwState |= STATE_GFAFAILED;
hr = S_FALSE;
}
_dwMediaState |= HWDMS_FORMATTED;
}
else
{
if (ERROR_NOT_READY == GetLastError())
{
// We get this for offline cluster volumes. Setting
// dismounted gets us the right Shell behavior.
_dwVolumeFlags |= HWDVF_STATE_DISMOUNTED;
}
else
{
_HandleAccessDenied();
_dwMediaState &= ~HWDMS_FORMATTED;
}
// To help us debug, even in retail
_dwState |= STATE_GVIFAILED;
_dwSerialNumber = GetLastError();
hr = S_FALSE;
}
}
else
{
_dwState |= STATE_UPDATEHASMEDIAFAILED;
_dwMediaCap = 0;
hr = S_FALSE;
}
}
if (S_FALSE == hr)
{
// We don't care if they fail
SafeStrCpyN(_szLabel, TEXT("Invalid"), ARRAYSIZE(_szLabel));
SafeStrCpyN(_szFileSystem, TEXT("Invalid"), ARRAYSIZE(_szFileSystem));
_dwRootAttributes = 0xBADBADBD;
_dwMaxFileNameLen = 0xBADBADBD;
_dwFileSystemFlags = 0xBADBADBD;
}
if (fGetYourOwnHandle)
{
_CloseDeviceHandleSafe(hDevice);
pieo->RevertToSelf();
pieo->RCRelease();
}
}
return hr;
}
const FEATURE_NUMBER _rgfnInteresting[] =
{
// FeatureProfileList needs to remain the first one
FeatureProfileList, // = 0x0000,
FeatureCdRead, // = 0x001e,
FeatureDvdRead, // = 0x001f,
FeatureRandomWritable, // = 0x0020,
FeatureIncrementalStreamingWritable, // = 0x0021,
FeatureFormattable, // = 0x0023,
FeatureDefectManagement, // = 0x0024,
FeatureRestrictedOverwrite, // = 0x0026,
FeatureCdTrackAtOnce, // = 0x002d,
FeatureCdMastering, // = 0x002e,
FeatureDvdRecordableWrite, // = 0x002f,
FeatureCDAudioAnalogPlay, // = 0x0103,
};
struct CAPABILITYFEATURESMAP
{
DWORD dwCapability;
DWORD dwCapabilityDependent;
const FEATURE_NUMBER* prgFeature;
DWORD cFeature;
};
const FEATURE_NUMBER rgfnWRITECAP[] =
{
FeatureProfileList,
};
const FEATURE_NUMBER rgfnCDROM[] =
{
FeatureCdRead,
};
const FEATURE_NUMBER rgfnCDRECORDABLE[] =
{
FeatureIncrementalStreamingWritable,
FeatureCdTrackAtOnce,
FeatureCdMastering,
};
const FEATURE_NUMBER rgfnCDREWRITABLE[] =
{
FeatureFormattable,
};
const FEATURE_NUMBER rgfnDVDROM[] =
{
FeatureDvdRead,
};
const FEATURE_NUMBER rgfnDVDRECORDABLE[] =
{
FeatureDvdRecordableWrite,
};
const FEATURE_NUMBER rgfnDVDREWRITABLE[] =
{
FeatureFormattable,
};
const FEATURE_NUMBER rgfnDVDRAM[] =
{
FeatureRandomWritable,
FeatureDefectManagement,
};
const FEATURE_NUMBER rgfnANALOGAUDIOOUT[] =
{
FeatureCDAudioAnalogPlay,
};
const CAPABILITYFEATURESMAP _rgcapfeaturemap[] =
{
{
HWDMC_WRITECAPABILITY_SUPPORTDETECTION,
0,
rgfnWRITECAP,
ARRAYSIZE(rgfnWRITECAP),
},
{
HWDMC_CDROM,
HWDMC_WRITECAPABILITY_SUPPORTDETECTION,
rgfnCDROM,
ARRAYSIZE(rgfnCDROM),
},
{
HWDMC_CDRECORDABLE,
HWDMC_WRITECAPABILITY_SUPPORTDETECTION,
rgfnCDRECORDABLE,
ARRAYSIZE(rgfnCDRECORDABLE),
},
{
HWDMC_CDREWRITABLE,
HWDMC_CDRECORDABLE,
rgfnCDREWRITABLE,
ARRAYSIZE(rgfnCDREWRITABLE),
},
{
HWDMC_DVDROM,
HWDMC_WRITECAPABILITY_SUPPORTDETECTION,
rgfnDVDROM,
ARRAYSIZE(rgfnDVDROM),
},
{
HWDMC_DVDRECORDABLE,
HWDMC_WRITECAPABILITY_SUPPORTDETECTION,
rgfnDVDRECORDABLE,
ARRAYSIZE(rgfnDVDRECORDABLE),
},
{
HWDMC_DVDREWRITABLE,
HWDMC_DVDRECORDABLE,
rgfnDVDREWRITABLE,
ARRAYSIZE(rgfnDVDREWRITABLE),
},
{
HWDMC_DVDRAM,
HWDMC_DVDROM,
rgfnDVDRAM,
ARRAYSIZE(rgfnDVDRAM),
},
{
HWDMC_ANALOGAUDIOOUT,
HWDMC_WRITECAPABILITY_SUPPORTDETECTION,
rgfnANALOGAUDIOOUT,
ARRAYSIZE(rgfnANALOGAUDIOOUT),
},
};
#define MMC2_NOTSUPPORTED 0
#define MMC2_DRIVESUPPORTED 1
#define MMC2_MEDIASUPPORTED 2
HRESULT CVolume::_FillMMC2CD(HANDLE hDevice)
{
HRESULT hr;
if (!_prgMMC2Features)
{
_prgMMC2Features = (DWORD*)LocalAlloc(LPTR,
ARRAYSIZE(_rgfnInteresting) * sizeof(DWORD));
}
if (_prgMMC2Features)
{
DWORD cbHeader = sizeof(GET_CONFIGURATION_HEADER) +
sizeof(FEATURE_HEADER);
GET_CONFIGURATION_HEADER* pheader = (GET_CONFIGURATION_HEADER*)
LocalAlloc(LPTR, cbHeader);
if (pheader)
{
GET_CONFIGURATION_IOCTL_INPUT gcii;
gcii.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE;
gcii.Reserved[0] = NULL;
gcii.Reserved[1] = NULL;
for (DWORD dw = 0; dw < ARRAYSIZE(_rgfnInteresting); ++dw)
{
FEATURE_HEADER* pfh;
DWORD cbReturned;
gcii.Feature = _rgfnInteresting[dw];
_prgMMC2Features[dw] = MMC2_NOTSUPPORTED;
// Requires GENERIC_READ access on the handle
if (DeviceIoControl(hDevice, IOCTL_CDROM_GET_CONFIGURATION,
&gcii, sizeof(GET_CONFIGURATION_IOCTL_INPUT), pheader,
cbHeader, &cbReturned, NULL))
{
pfh = (FEATURE_HEADER*)(pheader->Data);
WORD w = (pfh->FeatureCode[0]) << 8 | (pfh->FeatureCode[1]);
if (w == _rgfnInteresting[dw])
{
_prgMMC2Features[dw] = MMC2_DRIVESUPPORTED;
if (pfh->Current)
{
_prgMMC2Features[dw] |= MMC2_MEDIASUPPORTED;
}
else
{
_prgMMC2Features[dw] &= ~MMC2_MEDIASUPPORTED;
}
}
}
}
LocalFree(pheader);
}
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
// Rainier drive exposes features which perfectly matches DVD-RAM
// required feature set. But they are CD-R/RW. For drives
// we think are DVD-RAM, check if they also expose a DVD_RAM profile.
// We cannot use profiles all the way because they are not reliable.
// The same Rainier drive that expose bug 446652 exposes only
// the CDRewritable profile but it does support CDRecordable and
// CD-ROM.
HRESULT CVolume::_DVDRAMHack(HANDLE hDevice)
{
BOOL fSupported = FALSE;
BOOL fCurrent = FALSE;
if (HWDDC_DVDRAM & _dwDriveCap)
{
// Do the check
const DWORD cbHeaderInitial = sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER);
DWORD cbReturned;
DWORD cbHeader = cbHeaderInitial;
BYTE rgbBuffer[cbHeaderInitial];
GET_CONFIGURATION_IOCTL_INPUT input;
GET_CONFIGURATION_HEADER* pheader = (GET_CONFIGURATION_HEADER*)rgbBuffer;
ZeroMemory(&input, sizeof(GET_CONFIGURATION_IOCTL_INPUT));
ZeroMemory(rgbBuffer, sizeof(rgbBuffer));
// Ask for the profile list
input.Feature = FeatureProfileList;
// We want only this feature back
input.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL;
BOOL f = DeviceIoControl(hDevice,
IOCTL_CDROM_GET_CONFIGURATION,
&input,
sizeof(GET_CONFIGURATION_IOCTL_INPUT),
pheader,
cbHeader,
&cbReturned,
NULL);
if (f)
{
cbHeader = pheader->DataLength[0] << 24 |
pheader->DataLength[1] << 16 |
pheader->DataLength[2] << 8 |
pheader->DataLength[3] << 0;
GET_CONFIGURATION_HEADER* pheader2 = (GET_CONFIGURATION_HEADER*)LocalAlloc(LPTR,
cbHeader);
if (pheader2)
{
// We want all the profiles back
input.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL;
f = DeviceIoControl(hDevice,
IOCTL_CDROM_GET_CONFIGURATION,
&input,
sizeof(GET_CONFIGURATION_IOCTL_INPUT),
pheader2,
cbHeader,
&cbReturned,
NULL);
if (f)
{
FEATURE_DATA_PROFILE_LIST* pproflist =
(FEATURE_DATA_PROFILE_LIST*)pheader2->Data;
for (DWORD dw = 0; dw < (DWORD)(pproflist->Header.AdditionalLength / 4); ++dw)
{
FEATURE_DATA_PROFILE_LIST_EX* pprofile = &(pproflist->Profiles[dw]);
if (ProfileDvdRam == (pprofile->ProfileNumber[0] << 8 |
pprofile->ProfileNumber[1] << 0))
{
// It does support it! Is it current?
fSupported = TRUE;
if (pprofile->Current)
{
fCurrent = TRUE;
}
break;
}
}
}
LocalFree(pheader2);
}
}
if (fSupported)
{
if (!fCurrent)
{
_dwMediaCap &= ~HWDMC_DVDRAM;
}
}
else
{
_dwDriveCap &= ~HWDDC_DVDRAM;
_dwMediaCap &= ~HWDMC_DVDRAM;
}
}
return S_OK;
}
// Not worth updating only Const Info vs Media Info, do both
HRESULT CVolume::_UpdateMMC2CDInfo(HANDLE hDevice)
{
HRESULT hr = _FillMMC2CD(hDevice);
if (SUCCEEDED(hr))
{
for (DWORD dwCap = 0; dwCap < ARRAYSIZE(_rgcapfeaturemap); ++dwCap)
{
DWORD dwGoOn = MMC2_NOTSUPPORTED;
if (_rgcapfeaturemap[dwCap].dwCapabilityDependent)
{
// This capability is dependent on another one, let's
// check if the other is on
if (_dwDriveCap &
_rgcapfeaturemap[dwCap].dwCapabilityDependent)
{
dwGoOn |= MMC2_DRIVESUPPORTED;
if (_dwMediaCap &
_rgcapfeaturemap[dwCap].dwCapabilityDependent)
{
dwGoOn |= MMC2_MEDIASUPPORTED;
}
}
}
else
{
dwGoOn = MMC2_DRIVESUPPORTED | MMC2_MEDIASUPPORTED;
}
for (DWORD dwFeature = 0;
dwFeature < (_rgcapfeaturemap[dwCap].cFeature);
++dwFeature)
{
for (DWORD dwFeatureOn = 0; (MMC2_DRIVESUPPORTED & dwGoOn) &&
(dwFeatureOn < ARRAYSIZE(_rgfnInteresting));
++dwFeatureOn)
{
if (_rgfnInteresting[dwFeatureOn] ==
_rgcapfeaturemap[dwCap].prgFeature[dwFeature])
{
if (_prgMMC2Features[dwFeatureOn] &
MMC2_DRIVESUPPORTED)
{
if (!(dwGoOn & MMC2_MEDIASUPPORTED) ||
!(_prgMMC2Features[dwFeatureOn] &
MMC2_MEDIASUPPORTED))
{
dwGoOn &= ~MMC2_MEDIASUPPORTED;
}
}
else
{
dwGoOn = MMC2_NOTSUPPORTED;
}
break;
}
}
if (MMC2_DRIVESUPPORTED & dwGoOn)
{
_dwDriveCap |= _rgcapfeaturemap[dwCap].dwCapability;
if (MMC2_MEDIASUPPORTED & dwGoOn)
{
_dwMediaCap |= _rgcapfeaturemap[dwCap].
dwCapability;
}
else
{
_dwMediaCap &= ~(_rgcapfeaturemap[dwCap].
dwCapability);
}
}
else
{
_dwDriveCap &= ~(_rgcapfeaturemap[dwCap].dwCapability);
_dwMediaCap &= ~(_rgcapfeaturemap[dwCap].dwCapability);
}
}
}
}
_DVDRAMHack(hDevice);
return hr;
}
HRESULT CVolume::_UpdateRemovableDevice()
{
HRESULT hr = S_OK;
if (_fHWDevInstInited)
{
BOOL fRemovable;
hr = _hwdevinst.IsRemovableDevice(&fRemovable);
if (SUCCEEDED(hr))
{
if (fRemovable)
{
_dwDriveCap |= HWDDC_REMOVABLEDEVICE;
}
}
}
return hr;
}
HRESULT CVolume::_UpdateSoftEjectCaps()
{
HRESULT hr = S_OK;
if (_fHWDevInstInited)
{
DWORD dw;
DWORD dwType;
hr = _GetDevicePropertyGeneric(&_hwdevinst, TEXT("NoSoftEject"),
FALSE, &dwType, (PBYTE)&dw, sizeof(dw));
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
hr = S_OK;
if (REG_DWORD == dwType)
{
if (1 == dw)
{
_dwDriveCap |= HWDDC_NOSOFTEJECT;
}
}
}
}
return hr;
}
HRESULT CVolume::_UpdateConstInfo(HANDLE hDevice)
{
HRESULT hr;
_dwVolumeFlags = 0;
if (HWDTS_CDROM == _dwDriveType)
{
_dwVolumeFlags = HWDVF_STATE_SUPPORTNOTIFICATION;
hr = _UpdateMMC2CDInfo(hDevice);
}
else
{
if (HWDTS_REMOVABLEDISK == _dwDriveType)
{
_dwVolumeFlags = HWDVF_STATE_SUPPORTNOTIFICATION;
}
else
{
if ((HWDTS_FLOPPY35 != _dwDriveType) &&
(HWDTS_FLOPPY525 != _dwDriveType))
{
// Do something for the 120MB floppy
_dwVolumeFlags = HWDVF_STATE_SUPPORTNOTIFICATION;
}
}
hr = S_OK;
}
if (SUCCEEDED(hr))
{
hr = _GetVolumeName(_pszElemName, _szVolumeGUID,
ARRAYSIZE(_szVolumeGUID));
}
if (SUCCEEDED(hr))
{
if (HWDTS_CDROM != _dwDriveType)
{
_dwDriveCap |= HWDMC_WRITECAPABILITY_SUPPORTDETECTION |
HWDDC_RANDOMWRITE;
}
}
return hr;
}
HRESULT CVolume::GetVolumeConstInfo(LPWSTR pszVolumeGUID, DWORD cchVolumeGUID,
DWORD* pdwVolumeFlags, DWORD* pdwDriveType, DWORD* pdwDriveCap)
{
HRESULT hr;
_cs.Enter();
hr = SafeStrCpyN(pszVolumeGUID, _szVolumeGUID, cchVolumeGUID);
if (SUCCEEDED(hr))
{
if (!(_dwVolumeFlags & HWDVF_STATE_ACCESSDENIED))
{
*pdwVolumeFlags = _dwVolumeFlags;
*pdwDriveType = _dwDriveType;
*pdwDriveCap = _dwDriveCap;
}
else
{
*pdwVolumeFlags = HWDVF_STATE_ACCESSDENIED;
*pdwDriveType = 0xBADBADBD;
*pdwDriveCap = 0xBADBADBD;
}
}
_cs.Leave();
return hr;
}
HRESULT CVolume::GetVolumeMediaInfo(LPWSTR pszLabel, DWORD cchLabel,
LPWSTR pszFileSystem, DWORD cchFileSystem, DWORD* pdwFileSystemFlags,
DWORD* pdwMaxFileNameLen, DWORD* pdwRootAttributes, DWORD* pdwSerialNumber,
DWORD* pdwDriveState, DWORD* pdwMediaState, DWORD* pdwMediaCap)
{
HRESULT hr;
_cs.Enter();
if (!(_dwVolumeFlags & HWDVF_STATE_ACCESSDENIED))
{
if (_dwMediaState & HWDMS_PRESENT)
{
hr = SafeStrCpyN(pszLabel, _szLabel, cchLabel);
if (SUCCEEDED(hr))
{
hr = SafeStrCpyN(pszFileSystem, _szFileSystem, cchFileSystem);
}
if (SUCCEEDED(hr))
{
*pdwFileSystemFlags = _dwFileSystemFlags;
*pdwMaxFileNameLen = _dwMaxFileNameLen;
*pdwRootAttributes = _dwRootAttributes;
*pdwSerialNumber = _dwSerialNumber;
*pdwDriveState = _dwDriveState;
*pdwMediaState = _dwMediaState;
}
}
else
{
*pdwMediaState = _dwMediaState;
// We don't care if they fail
SafeStrCpyN(pszLabel, TEXT("Invalid"), cchLabel);
SafeStrCpyN(pszFileSystem, TEXT("Invalid"), cchFileSystem);
*pdwSerialNumber = 0xBADBADBD;
*pdwMaxFileNameLen = 0xBADBADBD;
*pdwFileSystemFlags = 0xBADBADBD;
*pdwRootAttributes = 0xBADBADBD;
*pdwDriveState = 0xBADBADBD;
hr = S_OK;
}
*pdwMediaCap = _dwMediaCap;
}
else
{
*pdwMediaState = 0xBADBADBD;
// We don't care if they fail
SafeStrCpyN(pszLabel, TEXT("Access Denied"), cchLabel);
SafeStrCpyN(pszFileSystem, TEXT("Access Denied"), cchFileSystem);
*pdwSerialNumber = 0xBADBADBD;
*pdwMaxFileNameLen = 0xBADBADBD;
*pdwFileSystemFlags = 0xBADBADBD;
*pdwRootAttributes = 0xBADBADBD;
*pdwDriveState = 0xBADBADBD;
*pdwMediaCap = 0xBADBADBD;
hr = S_OK;
}
_cs.Leave();
return hr;
}
HRESULT CVolume::GetIconAndLabelInfo(LPWSTR pszAutorunIconLocation,
DWORD cchAutorunIconLocation, LPWSTR pszAutorunLabel, DWORD cchAutorunLabel,
LPWSTR pszIconLocationFromService, DWORD cchIconLocationFromService,
LPWSTR pszNoMediaIconLocationFromService, DWORD cchNoMediaIconLocationFromService,
LPWSTR pszLabelFromService, DWORD cchLabelFromService)
{
HRESULT hrTmp;
*pszAutorunIconLocation = NULL;
*pszAutorunLabel = NULL;
*pszIconLocationFromService = NULL;
*pszNoMediaIconLocationFromService = NULL;
*pszLabelFromService = NULL;
_cs.Enter();
if (!(_dwVolumeFlags & HWDVF_STATE_ACCESSDENIED))
{
if (_dwMediaCap & HWDMC_HASAUTORUNINF)
{
if (_szAutorunIconLocation[0])
{
hrTmp = SafeStrCpyN(pszAutorunIconLocation, _szAutorunIconLocation,
cchAutorunIconLocation);
if (FAILED(hrTmp))
{
*pszAutorunIconLocation = 0;
}
}
if (_szAutorunLabel[0])
{
hrTmp = SafeStrCpyN(pszAutorunLabel, _szAutorunLabel,
cchAutorunLabel);
if (FAILED(hrTmp))
{
*pszAutorunLabel = 0;
}
}
}
if (_fHWDevInstInited)
{
WORD_BLOB* pblob;
hrTmp = _GetDevicePropertyGenericAsMultiSz(&_hwdevinst, TEXT("Icons"),
TRUE, &pblob);
if (SUCCEEDED(hrTmp) && (S_FALSE != hrTmp))
{
hrTmp = SafeStrCpyN(pszIconLocationFromService, pblob->asData,
cchIconLocationFromService);
if (FAILED(hrTmp))
{
*pszIconLocationFromService = 0;
}
CoTaskMemFree(pblob);
}
else
{
*pszIconLocationFromService = 0;
hrTmp = S_FALSE;
}
hrTmp = _GetDevicePropertyGenericAsMultiSz(&_hwdevinst, TEXT("NoMediaIcons"),
TRUE, &pblob);
if (SUCCEEDED(hrTmp) && (S_FALSE != hrTmp))
{
hrTmp = SafeStrCpyN(pszNoMediaIconLocationFromService, pblob->asData,
cchNoMediaIconLocationFromService);
if (FAILED(hrTmp))
{
*pszNoMediaIconLocationFromService = 0;
}
CoTaskMemFree(pblob);
}
else
{
*pszNoMediaIconLocationFromService = 0;
hrTmp = S_FALSE;
}
if (SUCCEEDED(hrTmp))
{
hrTmp = _GetDevicePropertyAsString(&_hwdevinst, TEXT("Label"),
pszLabelFromService, cchLabelFromService);
if (FAILED(hrTmp) || (S_FALSE == hrTmp))
{
*pszLabelFromService = 0;
}
}
}
}
_cs.Leave();
return S_OK;
}
HRESULT CVolume::_GetVOLUMEINFO2(VOLUMEINFO2** ppvolinfo2)
{
ASSERT(_cs.IsInside());
DWORD cchReq;
// We allocate this buffer just to be stack friendly, otherwise it could
// have been on the stack
VOLUMEINFO2* pvolinfo2;
const DWORD cbvolinfo2 = MAX_VOLUMEINFO2;
HRESULT hr = _AllocMemoryChunk<VOLUMEINFO2*>(cbvolinfo2, &pvolinfo2);
*ppvolinfo2 = NULL;
if (SUCCEEDED(hr))
{
pvolinfo2->cbSize = MAX_VOLUMEINFO2;
hr = GetName(pvolinfo2->szDeviceIDVolume,
ARRAYSIZE(pvolinfo2->szDeviceIDVolume), &cchReq);
if (SUCCEEDED(hr))
{
// Const info
hr = SafeStrCpyN(pvolinfo2->szVolumeGUID, _szVolumeGUID,
ARRAYSIZE(pvolinfo2->szVolumeGUID));
if (_dwVolumeFlags & HWDVF_STATE_ACCESSDENIED)
{
pvolinfo2->dwVolumeFlags = HWDVF_STATE_ACCESSDENIED;
}
else
{
if (SUCCEEDED(hr))
{
pvolinfo2->dwVolumeFlags = _dwVolumeFlags;
pvolinfo2->dwDriveType = _dwDriveType;
pvolinfo2->dwDriveCapability = _dwDriveCap;
}
pvolinfo2->dwState = _dwState;
// Media info
if (SUCCEEDED(hr))
{
// This fct should be called from within the Volume critsect
if (_dwMediaState & HWDMS_PRESENT)
{
hr = SafeStrCpyN(pvolinfo2->szLabel, _szLabel,
ARRAYSIZE(pvolinfo2->szLabel));
if (SUCCEEDED(hr))
{
hr = SafeStrCpyN(pvolinfo2->szFileSystem, _szFileSystem,
ARRAYSIZE(pvolinfo2->szFileSystem));
}
if (SUCCEEDED(hr))
{
pvolinfo2->dwFileSystemFlags = _dwFileSystemFlags;
pvolinfo2->dwMaxFileNameLen = _dwMaxFileNameLen;
pvolinfo2->dwRootAttributes = _dwRootAttributes;
pvolinfo2->dwSerialNumber = _dwSerialNumber;
pvolinfo2->dwDriveState = _dwDriveState;
pvolinfo2->dwMediaCap = _dwMediaCap;
pvolinfo2->dwMediaState = _dwMediaState;
}
}
else
{
pvolinfo2->dwMediaState = _dwMediaState;
// We don't care if they fail
SafeStrCpyN(pvolinfo2->szLabel, TEXT("Invalid"),
ARRAYSIZE(pvolinfo2->szLabel));
SafeStrCpyN(pvolinfo2->szFileSystem, TEXT("Invalid"),
ARRAYSIZE(pvolinfo2->szFileSystem));
pvolinfo2->dwSerialNumber = 0xBADBADBD;
pvolinfo2->dwMaxFileNameLen = 0xBADBADBD;
pvolinfo2->dwFileSystemFlags = 0xBADBADBD;
pvolinfo2->dwRootAttributes = 0xBADBADBD;
pvolinfo2->dwDriveState = 0xBADBADBD;
hr = S_OK;
}
pvolinfo2->dwMediaCap = _dwMediaCap;
}
if (SUCCEEDED(hr))
{
WCHAR szAutorunIconLocation[MAX_ICONLOCATION];
WCHAR szAutorunLabel[MAX_LABEL];
WCHAR szIconLocationFromService[MAX_ICONLOCATION];
WCHAR szNoMediaIconLocationFromService[MAX_ICONLOCATION];
// We can now have a @%SystemRoot%\system32\shell32.dll,-1785 for MUI stuff
WCHAR szLabelFromService[MAX_ICONLOCATION];
pvolinfo2->oAutorunIconLocation = INVALID_DWORD;
pvolinfo2->oAutorunLabel = INVALID_DWORD;
pvolinfo2->oIconLocationFromService = INVALID_DWORD;
pvolinfo2->oNoMediaIconLocationFromService = INVALID_DWORD;
pvolinfo2->oLabelFromService = INVALID_DWORD;
hr = GetIconAndLabelInfo(szAutorunIconLocation,
ARRAYSIZE(szAutorunIconLocation), szAutorunLabel,
ARRAYSIZE(szAutorunLabel), szIconLocationFromService,
ARRAYSIZE(szIconLocationFromService), szNoMediaIconLocationFromService,
ARRAYSIZE(szNoMediaIconLocationFromService), szLabelFromService,
ARRAYSIZE(szLabelFromService));
if (SUCCEEDED(hr))
{
LPWSTR pszNext = pvolinfo2->szOptionalStrings;
size_t cchLeft = (cbvolinfo2 - sizeof(*pvolinfo2) +
sizeof(pvolinfo2->szOptionalStrings)) / sizeof(WCHAR);
size_t cchLeftBeginWith = cchLeft;
// The following five strings are optional
if (szAutorunIconLocation[0])
{
pvolinfo2->oAutorunIconLocation = (DWORD)(cchLeftBeginWith - cchLeft);
hr = StringCchCopyEx(pszNext, cchLeft, szAutorunIconLocation, &pszNext, &cchLeft, 0);
++pszNext;
--cchLeft;
}
if (SUCCEEDED(hr) && szAutorunLabel[0])
{
pvolinfo2->oAutorunLabel = (DWORD)(cchLeftBeginWith - cchLeft);
hr = StringCchCopyEx(pszNext, cchLeft, szAutorunLabel, &pszNext, &cchLeft, 0);
++pszNext;
--cchLeft;
}
if (SUCCEEDED(hr) && szIconLocationFromService[0])
{
pvolinfo2->oIconLocationFromService = (DWORD)(cchLeftBeginWith - cchLeft);
hr = StringCchCopyEx(pszNext, cchLeft, szIconLocationFromService, &pszNext, &cchLeft, 0);
++pszNext;
--cchLeft;
}
if (SUCCEEDED(hr) && szNoMediaIconLocationFromService[0])
{
pvolinfo2->oNoMediaIconLocationFromService = (DWORD)(cchLeftBeginWith - cchLeft);
hr = StringCchCopyEx(pszNext, cchLeft, szNoMediaIconLocationFromService, &pszNext, &cchLeft, 0);
++pszNext;
--cchLeft;
}
if (SUCCEEDED(hr) && szLabelFromService[0])
{
pvolinfo2->oLabelFromService = (DWORD)(cchLeftBeginWith - cchLeft);
hr = StringCchCopy(pszNext, cchLeft, szLabelFromService);
}
}
}
}
}
if (SUCCEEDED(hr))
{
*ppvolinfo2 = pvolinfo2;
}
else
{
_FreeMemoryChunk<VOLUMEINFO2*>(pvolinfo2);
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT CVolume::HandleRemoval()
{
WCHAR szDeviceIDVolume[MAX_DEVICEID];
DWORD cchReq;
HRESULT hr = GetName(szDeviceIDVolume, ARRAYSIZE(szDeviceIDVolume), &cchReq);
if (SUCCEEDED(hr))
{
// This will launch a thread
CHardwareDevicesImpl::_AdviseVolumeRemoved(szDeviceIDVolume,
_pszMountPoints, _cchMountPoints);
}
return hr;
}
HRESULT CVolume::HandleArrival()
{
BOOL fJustDocked = FALSE;
HRESULT hr = CHWEventDetectorHelper::DockStateChanged(&fJustDocked);
if (SUCCEEDED(hr))
{
//
// ISSUE-2001/01/13-StephStm Pass the Docking change in there so
// that the Shell knows if it should
// Autorun or not.
//
if (_fHWDevInstInited)
{
BOOL fTryAutoplay = TRUE;
if ((_dwDriveType & HWDTS_CDROM) ||
(_dwDriveType & HWDTS_REMOVABLEDISK))
{
if (_dwMediaState & HWDMS_PRESENT)
{
// Not removable disk, but device
BOOL fRemovable;
hr = _hwdevinst.IsRemovableDevice(&fRemovable);
if (SUCCEEDED(hr))
{
if (fRemovable)
{
// We need to Autoplay these since cameras
// are removable-disk devices. And we want
// to autorun them when they come in.
fTryAutoplay = TRUE;
}
else
{
// For removable-disk drives/CD drives with
// media inserted when they are plugged,
// we do not Autoplay.
fTryAutoplay = FALSE;
DIAGNOSTIC((TEXT("[0311]Non removable device plugged with media in it -> No Autoplay!")));
}
}
}
}
if (!fJustDocked && fTryAutoplay)
{
HANDLE hDevice;
// Get a handle to regsiter for notification so that the
// FindFirstFile does not veto a PnP/Driver transition
hr = _GetDeviceHandleSafe(&hDevice, FALSE);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
hr = _ShouldTryAutoplay(&fTryAutoplay);
if (SUCCEEDED(hr))
{
if (fTryAutoplay)
{
BOOL fHasHandler;
hr = CHWEventDetectorImpl::HandleVolumeMediaEvent(
_pszElemName, &_hwdevinst, TEXT("DeviceArrival"),
&fHasHandler);
if (SUCCEEDED(hr) && fHasHandler)
{
_dwVolumeFlags |= HWDVF_STATE_HASAUTOPLAYHANDLER;
}
}
else
{
_dwVolumeFlags |= HWDVF_STATE_DONOTSNIFFCONTENT;
}
}
_CloseDeviceHandleSafe(hDevice);
}
}
else
{
if (fJustDocked)
{
DIAGNOSTIC((TEXT("[0301]Just docked -> No Autoplay!")));
TRACE(TF_VOLUME, TEXT("Just docked -> No Autoplay!"));
_dwVolumeFlags |= HWDVF_STATE_JUSTDOCKED;
}
}
}
else
{
DIAGNOSTIC((TEXT("[0310]Cannot find hardware device for this volume -> No Autoplay!")));
hr = S_FALSE;
}
if (SUCCEEDED(hr))
{
_AdviseVolumeChangeHelper(TRUE);
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
CVolume::CVolume() : _dwMediaState(0),
_devtype((DEVICE_TYPE)-1), _ulDeviceNumber((ULONG)-1),
_ulPartitionNumber((ULONG)-1), _fHWDevInstInited(FALSE), _dwDriveType(0),
_dwDriveCap(0), _dwVolumeFlags(0), _prgMMC2Features(NULL),
_fFirstTime(TRUE), _dwMediaCap(0), _pszMountPoints(NULL), _dwDriveState(0),
_hdevnotify(NULL), _dwState(0),
_dwMediaPresentFromEvent(MPFE_UNDETERMINED)
{
_szVolumeGUID[0] = 0;
_szDeviceIDDisk[0] = 0;
}
CVolume::~CVolume()
{
_UnregisterNotif();
if (_pszMountPoints)
{
CNamedElemList* pnel;
HRESULT hres = CHWEventDetectorHelper::GetList(HWEDLIST_MTPT, &pnel);
if (S_OK == hres)
{
for (LPWSTR psz = _pszMountPoints; *psz; psz += (lstrlen(psz) + 1))
{
hres = pnel->Remove(psz);
}
pnel->RCRelease();
}
LocalFree(_pszMountPoints);
}
if (_prgMMC2Features)
{
LocalFree(_prgMMC2Features);
}
_cs.Delete();
}
///////////////////////////////////////////////////////////////////////////////
//
//static
HRESULT CVolume::Create(CNamedElem** ppelem)
{
HRESULT hres = S_OK;
*ppelem = new CVolume();
if (!(*ppelem))
{
hres = E_OUTOFMEMORY;
}
return hres;
}
//static
HRESULT CVolume::GetFillEnum(CFillEnum** ppfillenum)
{
HRESULT hres;
CVolumeFillEnum* pfillenum = new CVolumeFillEnum();
if (pfillenum)
{
hres = pfillenum->_Init();
if (FAILED(hres))
{
delete pfillenum;
pfillenum = NULL;
}
}
else
{
hres = E_OUTOFMEMORY;
}
*ppfillenum = pfillenum;
return hres;
}
///////////////////////////////////////////////////////////////////////////////
//
HRESULT CVolumeFillEnum::Next(LPWSTR pszElemName, DWORD cchElemName,
DWORD* pcchRequired)
{
return _intffillenum.Next(pszElemName, cchElemName, pcchRequired);
}
HRESULT CVolumeFillEnum::_Init()
{
return _intffillenum._Init(&guidVolumeClass, NULL);
}