WindowsXP-SP1/shell/shell32/mtptmgmt2.cpp

1669 lines
44 KiB
C++

#include "shellprv.h"
#pragma hdrstop
#include "mtpt.h"
#include "mtptl.h"
#include "mtptr.h"
#include "hwcmmn.h"
#include "clsobj.h"
#include <cfgmgr32.h>
HDPA CMountPoint::_hdpaMountPoints = NULL;
HDPA CMountPoint::_hdpaVolumes = NULL;
HDPA CMountPoint::_hdpaShares = NULL;
CMtPtLocal* CMountPoint::_rgMtPtDriveLetterLocal[26] = {0};
CMtPtRemote* CMountPoint::_rgMtPtDriveLetterNet[26] = {0};
CCriticalSection CMountPoint::_csLocalMtPtHDPA;
CCriticalSection CMountPoint::_csDL;
BOOL CMountPoint::_fShuttingDown = FALSE;
BOOL CMountPoint::_fNetDrivesInited = FALSE;
BOOL CMountPoint::_fLocalDrivesInited = FALSE;
BOOL CMountPoint::_fNoVolLocalDrivesInited = FALSE;
DWORD CMountPoint::_dwTickCountTriedAndFailed = 0;
DWORD CMountPoint::_dwAdviseToken = -1;
BOOL CMountPoint::_fCanRegisterWithShellService = FALSE;
CRegSupport CMountPoint::_rsMtPtsLocalDL;
CRegSupport CMountPoint::_rsMtPtsLocalMOF;
CRegSupport CMountPoint::_rsMtPtsRemote;
DWORD CMountPoint::_dwRemoteDriveAutorun = 0;
static WCHAR g_szCrossProcessCacheMtPtsLocalDLKey[] = TEXT("CPC\\LocalDL");
static WCHAR g_szCrossProcessCacheMtPtsRemoteKey[] = TEXT("CPC\\Remote");
static WCHAR g_szCrossProcessCacheMtPtsLocalMOFKey[] = TEXT("CPC\\LocalMOF");
HANDLE CMountPoint::_hThreadSCN = NULL;
DWORD CMountPoint::_dwRememberedNetDrivesMask = 0;
///////////////////////////////////////////////////////////////////////////////
// Public
///////////////////////////////////////////////////////////////////////////////
//static
CMountPoint* CMountPoint::GetMountPoint(int iDrive, BOOL fCreateNew,
BOOL fOKToHitNet)
{
CMountPoint* pMtPt = NULL;
if (iDrive >= 0 && iDrive < 26)
{
_csDL.Enter();
if (!_fShuttingDown)
{
pMtPt = _GetMountPointDL(iDrive, fCreateNew);
}
_csDL.Leave();
}
else
{
TraceMsg(TF_MOUNTPOINT,
"CMountPoint::GetMountPoint: Requested invalid mtpt '%d'",
iDrive);
}
return pMtPt;
}
//static
CMountPoint* CMountPoint::GetMountPoint(LPCTSTR pszName, BOOL fCreateNew)
{
CMountPoint* pMtPt = NULL;
// Sometimes we receive an empty string (go figure)
// Check '\' for UNC and \\?\VolumeGUID which we do not support
// (they're not mountpoints)
if (pszName && *pszName && (TEXT('\\') != *pszName))
{
if (InRange(*pszName , TEXT('a'), TEXT('z')) ||
InRange(*pszName , TEXT('A'), TEXT('Z')))
{
_csDL.Enter();
if (!_fShuttingDown)
{
if (!_IsDriveLetter(pszName))
{
BOOL fNetDrive = _IsNetDriveLazyLoadNetDLLs(DRIVEID(pszName));
if (!fNetDrive)
{
TCHAR szClosestMtPt[MAX_PATH];
if (_StripToClosestMountPoint(pszName, szClosestMtPt,
ARRAYSIZE(szClosestMtPt)))
{
if (!_IsDriveLetter(szClosestMtPt))
{
pMtPt = _GetStoredMtPtMOF(szClosestMtPt);
}
else
{
pMtPt = _GetMountPointDL(DRIVEID(pszName), fCreateNew);
}
}
}
else
{
// Net drives can only be mounted on drive letter
pMtPt = _GetMountPointDL(DRIVEID(pszName), fCreateNew);
}
}
else
{
pMtPt = _GetMountPointDL(DRIVEID(pszName), fCreateNew);
}
}
_csDL.Leave();
}
else
{
TraceMsg(TF_MOUNTPOINT,
"CMountPoint::GetMountPoint: Requested invalid mtpt '%s'",
pszName);
}
}
else
{
TraceMsg(TF_MOUNTPOINT, "CMountPoint::GetMountPoint: Requested invalid mtpt '%s'",
pszName);
}
return pMtPt;
}
//static
CMountPoint* CMountPoint::GetSimulatedMountPointFromVolumeGuid(LPCTSTR pszVolumeGuid)
{
CMountPoint* pMtPt = NULL;
static const TCHAR szWackWackVolume[] = TEXT("\\\\?\\Volume");
// Check for "\\?\Volume"
if (pszVolumeGuid && 0 == lstrncmp( pszVolumeGuid, szWackWackVolume, ARRAYSIZE(szWackWackVolume) - sizeof("") ) )
{
_csDL.Enter();
CMtPtLocal::_CreateMtPtLocalFromVolumeGuid( pszVolumeGuid, &pMtPt );
if ( !pMtPt )
{
TraceMsg(TF_MOUNTPOINT, "CMountPoint::GetMountPoint: Out of memory" );
}
_csDL.Leave();
}
else
{
TraceMsg(TF_MOUNTPOINT, "CMountPoint::GetSimulatedMountPointFromVolumeGuid: Request is not a volume guid '%ws'",
pszVolumeGuid);
}
return pMtPt;
}
// static
BOOL CMountPoint::_LocalDriveIsCoveredByNetDrive(LPCWSTR pszDriveLetter)
{
BOOL fCovered = FALSE;
CMountPoint* pmtpt = GetMountPoint(DRIVEID(pszDriveLetter), FALSE, FALSE);
if (pmtpt)
{
if (pmtpt->_IsRemote())
{
fCovered = TRUE;
}
pmtpt->Release();
}
return fCovered;
}
///////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////
// pszSource must be a path including a trailing backslash
// if returns TRUE, then pszDest contains the path to the closest MountPoint
//static
BOOL CMountPoint::_StripToClosestMountPoint(LPCTSTR pszSource, LPTSTR pszDest,
DWORD cchDest)
{
BOOL fFound = GetVolumePathName(pszSource, pszDest, cchDest);
if (fFound)
{
PathAddBackslash(pszDest);
}
return fFound;
}
///////////////////////////////////////////////////////////////////////////////
// Drive letter: DL
///////////////////////////////////////////////////////////////////////////////
//static
CMountPoint* CMountPoint::_GetMountPointDL(int iDrive, BOOL fCreateNew)
{
ASSERT(_csDL.IsInside());
CMountPoint* pmtpt = NULL;
// Determine if it's a net drive
BOOL fNetDrive = _IsNetDriveLazyLoadNetDLLs(iDrive);
if (fNetDrive)
{
if (!_fNetDrivesInited)
{
_InitNetDrives();
}
pmtpt = _rgMtPtDriveLetterNet[iDrive];
}
else
{
if (!_fLocalDrivesInited)
{
_InitLocalDrives();
}
pmtpt = _rgMtPtDriveLetterLocal[iDrive];
if (!_Shell32LoadedInDesktop())
{
DWORD dwAllDrives = GetLogicalDrives();
if (pmtpt)
{
// make sure it still exist
if (!(dwAllDrives & (1 << iDrive)))
{
// its' gone!
_rgMtPtDriveLetterLocal[iDrive]->Release();
_rgMtPtDriveLetterLocal[iDrive] = NULL;
pmtpt = NULL;
}
if (pmtpt && (pmtpt->_NeedToRefresh()))
{
CVolume* pvol;
HRESULT hr;
WCHAR szMountPoint[4];
_rgMtPtDriveLetterLocal[iDrive]->Release();
_rgMtPtDriveLetterLocal[iDrive] = NULL;
PathBuildRoot(szMountPoint, iDrive);
pvol = CMtPtLocal::_GetVolumeByMtPt(szMountPoint);
if (pvol)
{
hr = CMtPtLocal::_CreateMtPtLocalWithVolume(szMountPoint,
pvol);
pvol->Release();
}
else
{
hr = CMtPtLocal::_CreateMtPtLocal(szMountPoint);
}
if (SUCCEEDED(hr))
{
pmtpt = _rgMtPtDriveLetterLocal[iDrive];
}
else
{
pmtpt = NULL;
}
}
}
else
{
// maybe it arrived after we enumerated
if (dwAllDrives & (1 << iDrive))
{
WCHAR szMtPt[4];
// Is it a non-net drive?
UINT uDriveType = GetDriveType(PathBuildRoot(szMtPt, iDrive));
if ((DRIVE_FIXED == uDriveType) || (DRIVE_CDROM == uDriveType) ||
(DRIVE_REMOVABLE == uDriveType) || (DRIVE_RAMDISK == uDriveType))
{
// indeed
CVolume* pvolNew;
HRESULT hrTmp = CMtPtLocal::_CreateVolumeFromReg(szMtPt, &pvolNew);
if (SUCCEEDED(hrTmp))
{
CMtPtLocal::_CreateMtPtLocalWithVolume(szMtPt, pvolNew);
pvolNew->Release();
}
else
{
CMtPtLocal::_CreateMtPtLocal(szMtPt);
}
pmtpt = _rgMtPtDriveLetterNet[iDrive];
}
}
}
}
}
if (pmtpt)
{
pmtpt->AddRef();
}
return pmtpt;
}
///////////////////////////////////////////////////////////////////////////////
// Mounted On Folder: MOF
///////////////////////////////////////////////////////////////////////////////
//static
CMtPtLocal* CMountPoint::_GetStoredMtPtMOFFromHDPA(LPTSTR pszPathWithBackslash)
{
CMtPtLocal* pmtptl = NULL;
if (_hdpaMountPoints)
{
int n = DPA_GetPtrCount(_hdpaMountPoints);
for (int i = 0; i < n; ++i)
{
pmtptl = (CMtPtLocal*)DPA_GetPtr(_hdpaMountPoints, i);
if (pmtptl)
{
if (!lstrcmpi(pmtptl->_GetName(), pszPathWithBackslash))
{
break;
}
else
{
pmtptl = NULL;
}
}
}
}
return pmtptl;
}
//static
CMtPtLocal* CMountPoint::_GetStoredMtPtMOF(LPTSTR pszPathWithBackslash)
{
ASSERT(_csDL.IsInside());
_csLocalMtPtHDPA.Enter();
if (!_fLocalDrivesInited)
{
_InitLocalDrives();
}
CMtPtLocal* pmtptl = _GetStoredMtPtMOFFromHDPA(pszPathWithBackslash);
if (!_Shell32LoadedInDesktop())
{
BOOL fExist = _CheckLocalMtPtsMOF(pszPathWithBackslash);
if (pmtptl)
{
if (fExist)
{
if (pmtptl->_NeedToRefresh())
{
CVolume* pvol = CMtPtLocal::_GetVolumeByMtPt(pszPathWithBackslash);
pmtptl = NULL;
if (pvol)
{
HRESULT hr = CMtPtLocal::_CreateMtPtLocalWithVolume(
pszPathWithBackslash, pvol);
if (SUCCEEDED(hr))
{
pmtptl = _GetStoredMtPtMOFFromHDPA(pszPathWithBackslash);
}
pvol->Release();
}
else
{
// if we can't get a volume, we don't care about drive mounted on folder
}
}
}
else
{
// its' gone!
_RemoveLocalMountPoint(pszPathWithBackslash);
pmtptl = NULL;
}
}
else
{
// maybe it arrived after we enumerated
if (fExist)
{
CVolume* pvolNew;
HRESULT hrTmp = CMtPtLocal::_CreateVolumeFromReg(pszPathWithBackslash,
&pvolNew);
if (SUCCEEDED(hrTmp))
{
hrTmp = CMtPtLocal::_CreateMtPtLocalWithVolume(pszPathWithBackslash, pvolNew);
if (SUCCEEDED(hrTmp))
{
pmtptl = _GetStoredMtPtMOFFromHDPA(pszPathWithBackslash);
}
pvolNew->Release();
}
else
{
// if we can't get a volume, we don't care about drive mounted on folder
}
}
}
}
if (pmtptl)
{
pmtptl->AddRef();
}
_csLocalMtPtHDPA.Leave();
return pmtptl;
}
//static
BOOL CMountPoint::_StoreMtPtMOF(CMtPtLocal* pmtptl)
{
HRESULT hr;
_csLocalMtPtHDPA.Enter();
if (!_hdpaMountPoints && !_fShuttingDown)
{
_hdpaMountPoints = DPA_Create(2);
}
if (_hdpaMountPoints)
{
if (-1 == DPA_AppendPtr(_hdpaMountPoints, pmtptl))
{
hr = E_OUTOFMEMORY;
}
else
{
hr = S_OK;
}
}
else
{
hr = E_OUTOFMEMORY;
}
_csLocalMtPtHDPA.Leave();
return hr;
}
//static
BOOL CMountPoint::_IsDriveLetter(LPCTSTR pszName)
{
// Is this a drive mounted on a drive letter only (e.g. 'a:' or 'a:\')?
return (!pszName[2] || !pszName[3]);
}
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
//static
HRESULT CMountPoint::_InitNetDrivesHelper(DWORD dwScope)
{
HRESULT hr = S_FALSE;
HANDLE hEnum;
DWORD dwErr = WNetOpenEnum(dwScope, RESOURCETYPE_DISK, 0, NULL, &hEnum);
if (WN_SUCCESS == dwErr)
{
DWORD cbBuf = 4096 * 4; // Recommended size from docs
PBYTE pbBuf = (PBYTE)LocalAlloc(LPTR, cbBuf);
if (pbBuf)
{
// return as many entries as possible
DWORD dwEntries = (DWORD)-1;
dwErr = WNetEnumResource(hEnum, &dwEntries, pbBuf, &cbBuf);
if (dwErr == ERROR_MORE_DATA)
{
if (pbBuf)
{
LocalFree(pbBuf);
}
// cbBuf contains required size
pbBuf = (PBYTE)LocalAlloc(LPTR, cbBuf);
if (pbBuf)
{
dwErr = WNetEnumResource(hEnum, &dwEntries, pbBuf, &cbBuf);
}
else
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
}
if (dwErr == WN_SUCCESS)
{
UINT i;
NETRESOURCE* pnr = (NETRESOURCE*)pbBuf;
for (i = 0; SUCCEEDED(hr) && (i < dwEntries); ++i)
{
// Is it mapped or just net used
if (pnr->lpLocalName)
{
// Remembered drives and connected drives list overlaps
if (!_rgMtPtDriveLetterNet[DRIVEID(pnr->lpLocalName)])
{
hr = CMtPtRemote::_CreateMtPtRemote(pnr->lpLocalName,
pnr->lpRemoteName,
(dwScope == RESOURCE_CONNECTED));
if (RESOURCE_REMEMBERED == dwScope)
{
_dwRememberedNetDrivesMask |= (1 << DRIVEID(pnr->lpLocalName));
}
}
}
pnr++;
}
}
//
// BUGBUG (stephstm) - do we really want to return S_FALSE if WNetEnumResource fails?!?
//
if (pbBuf)
{
LocalFree(pbBuf);
}
}
WNetCloseEnum(hEnum);
}
//
// BUGBUG (stephstm) - do we really want to return S_FALSE if WNetOpenEnum fails?!?
//
// else if (ERROR_NO_NETWORK == dwErr)
return hr;
}
//static
HRESULT CMountPoint::_ReInitNetDrives()
{
ASSERT(_csDL.IsInside());
CMtPtRemote::_DeleteAllMtPtsAndShares();
_fNetDrivesInited = FALSE;
CMountPoint::_InitNetDrives();
return S_OK;
}
//static
HRESULT CMountPoint::_InitNetDrives()
{
ASSERT(_csDL.IsInside());
HRESULT hr;
if (!_fNetDrivesInited)
{
if (!_fShuttingDown)
{
if (!_hdpaShares)
{
_hdpaShares = DPA_Create(3);
}
}
if (_hdpaShares)
{
hr = _InitNetDrivesHelper(RESOURCE_CONNECTED);
if (SUCCEEDED(hr))
{
hr = _InitNetDrivesHelper(RESOURCE_REMEMBERED);
}
if (SUCCEEDED(hr))
{
DWORD dwLogicalDrives = GetLogicalDrives();
for (DWORD dw = 0; dw < 26; ++dw)
{
if (dwLogicalDrives & (1 << dw))
{
if (!(_rgMtPtDriveLetterNet[dw]))
{
WCHAR szDrive[4];
PathBuildRoot(szDrive, dw);
if (DRIVE_REMOTE == GetDriveType(szDrive))
{
// This must be a weird System mapped drive
// which is not enumerated by the per-user
// WNetEnumResource...
hr = CMtPtRemote::_CreateMtPtRemoteWithoutShareName(szDrive);
}
}
}
}
_fNetDrivesInited = TRUE;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = S_FALSE;
}
if (_Shell32LoadedInDesktop())
{
DWORD dwRemoteDrives = 0;
for (DWORD dw = 0; dw < 26; ++dw)
{
if (_rgMtPtDriveLetterNet[dw])
{
dwRemoteDrives |= (1 << dw);
}
}
}
return hr;
}
inline void _CoTaskMemFree(void* pv)
{
if (pv)
{
CoTaskMemFree(pv);
}
}
const GUID guidVolumeClass =
{0x53f5630d, 0xb6bf, 0x11d0,
{0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b}};
//static
HRESULT CMountPoint::_EnumVolumes(IHardwareDevices* pihwdevs)
{
ASSERT(_csDL.IsInside());
HRESULT hr;
if (_Shell32LoadedInDesktop())
{
// Synchro
IHardwareDevicesVolumesEnum* penum;
hr = pihwdevs->EnumVolumes(HWDEV_GETCUSTOMPROPERTIES, &penum);
ASSERTMSG(NULL != _hdpaVolumes, "_hdpaVolumes should not be NULL at this point, some code found its way here without calling InitLocalDrives");
if (SUCCEEDED(hr))
{
do
{
VOLUMEINFO volinfo;
hr = penum->Next(&volinfo);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
CVolume* pvolNew;
if (SUCCEEDED(CMtPtLocal::_CreateVolume(&volinfo, &pvolNew)))
{
CMtPtLocal::_UpdateVolumeRegInfo(&volinfo);
pvolNew->Release();
}
CoTaskMemFree(volinfo.pszDeviceIDVolume);
CoTaskMemFree(volinfo.pszVolumeGUID);
CoTaskMemFree(volinfo.pszLabel);
CoTaskMemFree(volinfo.pszFileSystem);
CoTaskMemFree(volinfo.pszAutorunIconLocation);
CoTaskMemFree(volinfo.pszAutorunLabel);
CoTaskMemFree(volinfo.pszIconLocationFromService);
CoTaskMemFree(volinfo.pszNoMediaIconLocationFromService);
CoTaskMemFree(volinfo.pszLabelFromService);
}
}
while (SUCCEEDED(hr) && (S_FALSE != hr));
penum->Release();
}
}
else
{
ULONG ulSize;
ULONG ulFlags = CM_GET_DEVICE_INTERFACE_LIST_PRESENT;
CONFIGRET cr = CM_Get_Device_Interface_List_Size_Ex(&ulSize,
(GUID*)&guidVolumeClass, NULL, ulFlags, NULL);
if ((CR_SUCCESS == cr) && (ulSize > 1))
{
LPWSTR pszVolumes = (LPWSTR)LocalAlloc(LPTR, ulSize * sizeof(WCHAR));
if (pszVolumes)
{
cr = CM_Get_Device_Interface_List_Ex((GUID*)&guidVolumeClass,
NULL, pszVolumes, ulSize, ulFlags, NULL);
if (CR_SUCCESS == cr)
{
for (LPWSTR psz = pszVolumes; *psz; psz += lstrlen(psz) + 1)
{
CVolume* pvolNew;
HRESULT hrTmp = CMtPtLocal::_CreateVolumeFromReg(psz,
&pvolNew);
if (SUCCEEDED(hrTmp))
{
pvolNew->Release();
}
}
hr = S_OK;
}
else
{
hr = S_FALSE;
}
LocalFree(pszVolumes);
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = S_FALSE;
}
}
return hr;
}
//static
HRESULT CMountPoint::_EnumMountPoints(IHardwareDevices* pihwdevs)
{
ASSERT(_csDL.IsInside());
HRESULT hr;
if (_Shell32LoadedInDesktop())
{
IHardwareDevicesMountPointsEnum* penum;
hr = pihwdevs->EnumMountPoints(&penum);
if (SUCCEEDED(hr))
{
LPWSTR pszMountPoint;
LPWSTR pszDeviceIDVolume;
while (SUCCEEDED(hr = penum->Next(&pszMountPoint, &pszDeviceIDVolume)) &&
(S_FALSE != hr))
{
CVolume* pvol = CMtPtLocal::_GetVolumeByID(pszDeviceIDVolume);
if (pvol)
{
CMtPtLocal::_CreateMtPtLocalWithVolume(pszMountPoint, pvol);
pvol->Release();
}
if (!_IsDriveLetter(pszMountPoint))
{
_rsMtPtsLocalMOF.RSSetTextValue(NULL, pszMountPoint, TEXT(""));
}
CoTaskMemFree(pszMountPoint);
CoTaskMemFree(pszDeviceIDVolume);
}
penum->Release();
}
}
else
{
hr = S_OK;
if (_hdpaVolumes)
{
DWORD c = DPA_GetPtrCount(_hdpaVolumes);
for (int i = c - 1; i >= 0; --i)
{
CVolume* pvol = (CVolume*)DPA_GetPtr(_hdpaVolumes, i);
if (pvol)
{
DWORD cch;
if (GetVolumePathNamesForVolumeName(pvol->pszVolumeGUID,
NULL, 0, &cch))
{
// no mountpoint, we're done
}
else
{
// Expected, even wanted...
if (ERROR_MORE_DATA == GetLastError())
{
LPWSTR pszMtPts = (LPWSTR)LocalAlloc(LPTR,
cch * sizeof(WCHAR));
if (pszMtPts)
{
if (GetVolumePathNamesForVolumeName(
pvol->pszVolumeGUID, pszMtPts, cch, &cch))
{
for (LPWSTR psz = pszMtPts; *psz;
psz += lstrlen(psz) + 1)
{
CMtPtLocal::_CreateMtPtLocalWithVolume(
psz, pvol);
}
}
LocalFree(pszMtPts);
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = S_FALSE;
}
}
}
}
}
}
// We don't care about the prev hr. I'll clean this up when moving the
// volume information from the Shell Service. (stephstm, 2001/03/13)
DWORD dwLogicalDrives = GetLogicalDrives();
DWORD dwLocalDrives = 0;
for (DWORD dw = 0; dw < 26; ++dw)
{
if (dwLogicalDrives & (1 << dw))
{
if (_rgMtPtDriveLetterLocal[dw])
{
dwLocalDrives |= (1 << dw);
}
else
{
WCHAR szDrive[4];
PathBuildRoot(szDrive, dw);
if (DRIVE_REMOTE != GetDriveType(szDrive))
{
// This is a "subst" drive or something like this.
// It only appears in the per-user drive map, not the
// per-machine. Let's create a mountpoint for it.
CMtPtLocal::_CreateMtPtLocal(szDrive);
dwLocalDrives |= (1 << dw);
}
}
}
}
return hr;
}
//static
HRESULT CMountPoint::_DeleteVolumeInfo()
{
ASSERT(_csDL.IsInside());
if (_hdpaVolumes)
{
DWORD c = DPA_GetPtrCount(_hdpaVolumes);
for (int i = c - 1; i >= 0; --i)
{
CVolume* pvol = (CVolume*)DPA_GetPtr(_hdpaVolumes, i);
if (pvol)
{
pvol->Release();
}
DPA_DeletePtr(_hdpaVolumes, i);
}
DPA_Destroy(_hdpaVolumes);
_hdpaVolumes = NULL;
}
return S_OK;
}
//static
HRESULT CMountPoint::_DeleteLocalMtPts()
{
ASSERT(_csDL.IsInside());
for (DWORD dw = 0; dw < 26; ++dw)
{
CMtPtLocal* pmtptl = (CMtPtLocal*)_rgMtPtDriveLetterLocal[dw];
if (pmtptl)
{
pmtptl->Release();
_rgMtPtDriveLetterLocal[dw] = 0;
}
}
_csLocalMtPtHDPA.Enter();
if (_hdpaMountPoints)
{
int n = DPA_GetPtrCount(_hdpaMountPoints);
for (int i = n - 1; i >= 0; --i)
{
CMtPtLocal* pmtptl = (CMtPtLocal*)DPA_GetPtr(_hdpaMountPoints, i);
if (pmtptl)
{
pmtptl->Release();
DPA_DeletePtr(_hdpaMountPoints, i);
}
}
DPA_Destroy(_hdpaMountPoints);
}
_csLocalMtPtHDPA.Leave();
return S_OK;
}
// static
HRESULT CMountPoint::_GetMountPointsForVolume(LPCWSTR pszDeviceIDVolume,
HDPA hdpaMtPts)
{
ASSERT(!_csDL.IsInside());
_csDL.Enter();
for (DWORD dw = 0; dw < 26; ++dw)
{
CMtPtLocal* pmtptl = (CMtPtLocal*)_rgMtPtDriveLetterLocal[dw];
if (pmtptl && pmtptl->_pvol)
{
if (!lstrcmpi(pmtptl->_pvol->pszDeviceIDVolume, pszDeviceIDVolume))
{
LPCWSTR pszMtPt = StrDup(pmtptl->_szName);
if (pszMtPt)
{
if (-1 == DPA_AppendPtr(hdpaMtPts, (void*)pszMtPt))
{
LocalFree((HLOCAL)pszMtPt);
}
}
// Volumes can be mounted on only one drive letter
break;
}
}
}
_csDL.Leave();
_csLocalMtPtHDPA.Enter();
if (_hdpaMountPoints)
{
int n = DPA_GetPtrCount(_hdpaMountPoints);
for (int i = n - 1; i >= 0; --i)
{
CMtPtLocal* pmtptl = (CMtPtLocal*)DPA_GetPtr(_hdpaMountPoints, i);
if (pmtptl && pmtptl->_pvol)
{
if (!lstrcmpi(pmtptl->_pvol->pszDeviceIDVolume, pszDeviceIDVolume))
{
LPCWSTR pszMtPt = StrDup(pmtptl->_szName);
if (pszMtPt)
{
if (-1 == DPA_AppendPtr(hdpaMtPts, (void*)pszMtPt))
{
LocalFree((HLOCAL)pszMtPt);
}
}
}
}
}
}
_csLocalMtPtHDPA.Leave();
return S_OK;
}
//static
HRESULT CMountPoint::_CleanupLocalMtPtInfo()
{
_csDL.Enter();
// We should Unadvise here but there's two problems: the ref counting
// and we are probably here because CoUninitialize has been called, so
// creating the IHardwareDevices interface'c component would probably fail
_DeleteLocalMtPts();
_DeleteVolumeInfo();
_csDL.Leave();
return S_OK;
}
// static
HRESULT CMountPoint::_InitLocalDriveHelper()
{
#ifdef DEBUG
// We should not try to enter the Drive Letter critical section on this thread.
// We've already entered it on the thread that launched us, and
// we should still be in there. The thread that launched us is waiting for
// this thread to finish before going on. Trying to re-enter this critical
// section from this thread will deadlock.
DWORD dwThreadID = GetCurrentThreadId();
_csDL.SetThreadIDToCheckForEntrance(dwThreadID);
_csDL.FakeEnter();
#endif
IHardwareDevices* pihwdevs;
HRESULT hr;
BOOL fLoadedInDesktop = _Shell32LoadedInDesktop();
if (fLoadedInDesktop)
{
hr = _GetHardwareDevices(&pihwdevs);
}
else
{
hr = S_FALSE;
}
if (SUCCEEDED(hr))
{
if (!_hdpaVolumes && !_fShuttingDown)
{
_hdpaVolumes = DPA_Create(3);
}
if (_hdpaVolumes)
{
if (SUCCEEDED(hr))
{
hr = _EnumVolumes(pihwdevs);
if (SUCCEEDED(hr))
{
hr = _EnumMountPoints(pihwdevs);
if (SUCCEEDED(hr))
{
_fLocalDrivesInited = TRUE;
}
else
{
_DeleteVolumeInfo();
}
}
}
}
else
{
hr = E_OUTOFMEMORY;
}
if (fLoadedInDesktop)
{
pihwdevs->Release();
}
}
#ifdef DEBUG
_csDL.FakeLeave();
_csDL.SetThreadIDToCheckForEntrance(0);
#endif
return hr;
}
DWORD WINAPI _FirstHardwareEnumThreadProc(void* pv)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
hr = CMountPoint::_InitLocalDriveHelper();
CoUninitialize();
}
return (DWORD)hr;
}
BOOL _InsideLoaderLock()
{
return (NtCurrentTeb()->ClientId.UniqueThread ==
((PRTL_CRITICAL_SECTION)(NtCurrentPeb()->LoaderLock))->OwningThread);
}
//static
BOOL CMountPoint::_CanRegister()
{
if (!CMountPoint::_fCanRegisterWithShellService)
{
HANDLE hCanRegister = OpenEvent(SYNCHRONIZE, FALSE, TEXT("_fCanRegisterWithShellService"));
if (hCanRegister)
{
CloseHandle(hCanRegister);
}
else
{
CMountPoint::_fCanRegisterWithShellService = TRUE;
}
}
return CMountPoint::_fCanRegisterWithShellService;
}
//static
HRESULT CMountPoint::_InitLocalDrives()
{
ASSERT(_csDL.IsInside());
HRESULT hr = E_FAIL;
BOOL fTryFullInit = FALSE;
if (CMountPoint::_CanRegister())
{
if (!_dwTickCountTriedAndFailed)
{
// We didn't try full init yet
fTryFullInit = TRUE;
}
else
{
// We already tried and failed doing a full init. Try again only if
// it's been more than 5 seconds.
if ((GetTickCount() - _dwTickCountTriedAndFailed) >
(5 * 1000))
{
fTryFullInit = TRUE;
}
}
if (fTryFullInit)
{
if (_Shell32LoadedInDesktop())
{
HANDLE hThread = CreateThread(NULL, 0, _FirstHardwareEnumThreadProc, NULL, 0, NULL);
if (hThread)
{
DWORD dwWait = WaitForSingleObject(hThread, INFINITE);
if (WAIT_FAILED != dwWait)
{
DWORD dwExitCode;
if (GetExitCodeThread(hThread, &dwExitCode))
{
hr = (HRESULT)dwExitCode;
}
}
CloseHandle(hThread);
}
if (SUCCEEDED(hr))
{
_dwTickCountTriedAndFailed = 0;
}
else
{
_dwTickCountTriedAndFailed = GetTickCount();
}
}
else
{
hr = _InitLocalDriveHelper();
_dwTickCountTriedAndFailed = 0;
}
}
}
if (FAILED(hr))
{
if (!_fNoVolLocalDrivesInited)
{
DWORD dwLogicalDrives = GetLogicalDrives();
for (DWORD dw = 0; dw < 26; ++dw)
{
if (dwLogicalDrives & (1 << dw))
{
WCHAR szDrive[4];
int iDriveType = GetDriveType(PathBuildRoot(szDrive, dw));
if ((DRIVE_REMOTE != iDriveType) && (DRIVE_UNKNOWN != iDriveType) &&
(DRIVE_NO_ROOT_DIR != iDriveType))
{
hr = CMtPtLocal::_CreateMtPtLocal(szDrive);
}
}
}
_fNoVolLocalDrivesInited = TRUE;
}
else
{
hr = S_FALSE;
}
}
return hr;
}
//static
DWORD CMountPoint::GetDrivesMask()
{
HRESULT hr = S_FALSE;
DWORD dwMask = 0;
_csDL.Enter();
if (!_fNetDrivesInited)
{
hr = _InitNetDrives();
}
if (!_fLocalDrivesInited)
{
hr = _InitLocalDrives();
}
if (SUCCEEDED(hr))
{
if (_Shell32LoadedInDesktop())
{
for (DWORD dw = 0; dw < 26; ++dw)
{
if (_rgMtPtDriveLetterLocal[dw] || _rgMtPtDriveLetterNet[dw])
{
dwMask |= (1 << dw);
}
}
}
else
{
dwMask = GetLogicalDrives() | _dwRememberedNetDrivesMask;
}
}
_csDL.Leave();
return dwMask;
}
//static
void CMountPoint::Initialize()
{
_csLocalMtPtHDPA.Init();
_csDL.Init();
_rsMtPtsLocalDL.RSInitRoot(HKEY_CURRENT_USER, REGSTR_MTPT_ROOTKEY2,
g_szCrossProcessCacheMtPtsLocalDLKey, REG_OPTION_VOLATILE);
_rsMtPtsRemote.RSInitRoot(HKEY_CURRENT_USER, REGSTR_MTPT_ROOTKEY2,
g_szCrossProcessCacheMtPtsRemoteKey, REG_OPTION_VOLATILE);
_rsMtPtsLocalMOF.RSInitRoot(HKEY_CURRENT_USER, REGSTR_MTPT_ROOTKEY2,
g_szCrossProcessCacheMtPtsLocalMOFKey, REG_OPTION_VOLATILE);
}
///////////////////////////////////////////////////////////////////////////////
// For C caller
///////////////////////////////////////////////////////////////////////////////
STDAPI_(void) CMtPt_FinalCleanUp()
{
CMountPoint::FinalCleanUp();
CMtPtLocal::FinalCleanUp();
}
STDAPI_(void) CMtPt_Initialize()
{
CMountPoint::Initialize();
CMtPtLocal::Initialize();
}
//static
void CMountPoint::FinalCleanUp()
{
if (_csDL.IsInitialized() && _csLocalMtPtHDPA.IsInitialized())
{
_csDL.Enter();
_fShuttingDown = TRUE;
_csLocalMtPtHDPA.Enter();
_DeleteLocalMtPts();
_DeleteVolumeInfo();
CMtPtRemote::_DeleteAllMtPtsAndShares();
_fNetDrivesInited = FALSE;
_csLocalMtPtHDPA._fShuttingDown = TRUE;
_csDL._fShuttingDown = TRUE;
_csLocalMtPtHDPA.Leave();
_csDL.Leave();
_csLocalMtPtHDPA.Delete();
_csDL.Delete();
CSniffDrive::CleanUp();
if (_hThreadSCN)
{
CloseHandle(_hThreadSCN);
_hThreadSCN = NULL;
}
}
if (_Shell32LoadedInDesktop())
{
_rsMtPtsLocalDL.RSDeleteKey();
_rsMtPtsLocalMOF.RSDeleteKey();
_rsMtPtsRemote.RSDeleteKey();
}
}
//static
BOOL CMountPoint::_IsNetDriveLazyLoadNetDLLs(int iDrive)
{
ASSERT(_csDL.IsInside());
BOOL fNetDrive = FALSE;
if (!_fNetDrivesInited)
{
HRESULT hr = S_FALSE;
WCHAR szPath[4];
// Try to avoid loading the net dlls
UINT uDriveType = GetDriveType(PathBuildRoot(szPath, iDrive));
if (DRIVE_NO_ROOT_DIR == uDriveType)
{
// This happens for Remembered drives
hr = _InitNetDrives();
if (SUCCEEDED(hr))
{
fNetDrive = BOOLFROMPTR(_rgMtPtDriveLetterNet[iDrive]);
}
}
else
{
if (DRIVE_REMOTE == uDriveType)
{
fNetDrive = TRUE;
}
}
}
else
{
fNetDrive = BOOLFROMPTR(_rgMtPtDriveLetterNet[iDrive]);
if (!_Shell32LoadedInDesktop())
{
DWORD dwAllDrives = GetLogicalDrives() | _dwRememberedNetDrivesMask;
if (fNetDrive)
{
// make sure it still exist
if (!(dwAllDrives & (1 << iDrive)))
{
// its' gone!
fNetDrive = FALSE;
}
else
{
WCHAR szPath[4];
// There's still a drive there, make sure it's not a local one
if (!(_dwRememberedNetDrivesMask & (1 << iDrive)) &&
!(GetDriveType(PathBuildRoot(szPath, iDrive)) == DRIVE_REMOTE))
{
fNetDrive = FALSE;
}
}
if (!fNetDrive && (_rgMtPtDriveLetterNet[iDrive]))
{
_rgMtPtDriveLetterNet[iDrive]->Release();
_rgMtPtDriveLetterNet[iDrive] = NULL;
}
}
else
{
// maybe it arrived after we enumerated
if (dwAllDrives & (1 << iDrive))
{
WCHAR szPath[4];
// Is it a remote drive?
if ((_dwRememberedNetDrivesMask & (1 << iDrive)) ||
(GetDriveType(PathBuildRoot(szPath, iDrive)) == DRIVE_REMOTE))
{
// indeed
_ReInitNetDrives();
fNetDrive = TRUE;
}
}
}
}
}
return fNetDrive;
}
// static
HRESULT CMountPoint::_RemoveLocalMountPoint(LPCWSTR pszMountPoint)
{
if (_IsDriveLetter(pszMountPoint))
{
_csDL.Enter();
int iDrive = DRIVEID(pszMountPoint);
CMtPtLocal* pmtptl = (CMtPtLocal*)_rgMtPtDriveLetterLocal[iDrive];
if (pmtptl)
{
_rgMtPtDriveLetterLocal[iDrive] = 0;
pmtptl->Release();
}
_csDL.Leave();
}
else
{
_csLocalMtPtHDPA.Enter();
if (_hdpaMountPoints)
{
DWORD c = DPA_GetPtrCount(_hdpaMountPoints);
for (int i = c - 1; i >= 0; --i)
{
CMtPtLocal* pmtptl = (CMtPtLocal*)DPA_GetPtr(_hdpaMountPoints, i);
if (pmtptl)
{
if (!lstrcmpi(pmtptl->_szName, pszMountPoint))
{
DPA_DeletePtr(_hdpaMountPoints, i);
pmtptl->Release();
break;
}
}
}
}
if (_Shell32LoadedInDesktop())
{
_rsMtPtsLocalMOF.RSDeleteValue(NULL, pszMountPoint);
}
_csLocalMtPtHDPA.Leave();
}
return S_OK;
}
// static
HRESULT CMountPoint::_RemoveNetMountPoint(LPCWSTR pszMountPoint)
{
_csDL.Enter();
int iDrive = DRIVEID(pszMountPoint);
if (_rgMtPtDriveLetterNet[iDrive])
{
_rgMtPtDriveLetterNet[iDrive]->Release();
_rgMtPtDriveLetterNet[iDrive] = 0;
}
_csDL.Leave();
return S_OK;
}
// static
BOOL CMountPoint::_CheckLocalMtPtsMOF(LPCWSTR pszMountPoint)
{
ASSERT(!_Shell32LoadedInDesktop());
return _rsMtPtsLocalMOF.RSValueExist(NULL, pszMountPoint);
}
//
// This needs to be called from the thread that will be used for APCs callbacks
// (stephstm: 2001/03/31)
// static
DWORD WINAPI CMountPoint::_RegisterThreadProc(void* pv)
{
ASSERT(_Shell32LoadedInDesktop());
HANDLE hThread = (HANDLE)pv;
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IHardwareDevices* pihwdevs;
hr = _GetHardwareDevices(&pihwdevs);
if (SUCCEEDED(hr))
{
hr = pihwdevs->Advise(GetCurrentProcessId(), (ULONG_PTR)hThread,
(ULONG_PTR)CMountPoint::_EventAPCProc, &_dwAdviseToken);
pihwdevs->Release();
}
CoUninitialize();
}
return (DWORD)hr;
}
// static
HRESULT CMountPoint::RegisterForHardwareNotifications()
{
HRESULT hr;
if (_Shell32LoadedInDesktop() && (-1 == _dwAdviseToken))
{
HANDLE hPseudoProcess = GetCurrentProcess();
// See comment above!
HANDLE hPseudoThread = GetCurrentThread();
hr = E_FAIL;
if (DuplicateHandle(hPseudoProcess, hPseudoThread, hPseudoProcess,
&_hThreadSCN, DUPLICATE_SAME_ACCESS, FALSE, 0))
{
HANDLE hThread = CreateThread(NULL, 0, _RegisterThreadProc, (void*)_hThreadSCN, 0, NULL);
CSniffDrive::Init(_hThreadSCN);
if (hThread)
{
DWORD dwWait = WaitForSingleObject(hThread, INFINITE);
if (WAIT_FAILED != dwWait)
{
DWORD dwExitCode;
if (GetExitCodeThread(hThread, &dwExitCode))
{
hr = (HRESULT)dwExitCode;
}
}
CloseHandle(hThread);
}
else
{
// We want to keep the handle around we'll uise it for something else.
}
}
}
else
{
hr = S_FALSE;
}
return hr;
}