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

1224 lines
28 KiB
C++

#include "shellprv.h"
#pragma hdrstop
#include "shitemid.h"
#include "ids.h"
#include "hwcmmn.h"
#include "mtptr.h"
#ifdef DEBUG
DWORD CMtPtRemote::_cMtPtRemote = 0;
DWORD CShare::_cShare = 0;
#endif
///////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////
HRESULT CMtPtRemote::SetLabel(HWND hwnd, LPCTSTR pszLabel)
{
TraceMsg(TF_MOUNTPOINT, "CMtPtRemote::SetLabel: for '%s'", _GetNameDebug());
RSSetTextValue(NULL, TEXT("_LabelFromReg"), pszLabel,
REG_OPTION_NON_VOLATILE);
// we notify for only the current drive (no folder mounted drive)
SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_PATH, _GetName(), _GetName());
return S_OK;
}
BOOL CMtPtRemote::IsDisconnectedNetDrive()
{
return !_IsConnected();
}
// Expensive, do not call for nothing
BOOL CMtPtRemote::IsFormatted()
{
return (0xFFFFFFFF != GetFileAttributes(_GetNameForFctCall()));
}
BOOL CMtPtRemote::_GetComputerDisplayNameFromReg(LPTSTR pszLabel, DWORD cchLabel)
{
*pszLabel = 0;
return (RSGetTextValue(NULL, TEXT("_ComputerDisplayName"), pszLabel, &cchLabel));
}
HRESULT CMtPtRemote::_GetDefaultUNCDisplayName(LPTSTR pszLabel, DWORD cchLabel)
{
HRESULT hr = E_FAIL;
LPTSTR pszShare, pszT;
TCHAR szTempUNCPath[MAX_PATH];
pszLabel[0] = TEXT('\0');
if (!_pshare->fFake)
{
// Why would it not be a UNC name?
if (PathIsUNC(_GetUNCName()))
{
// Now we need to handle 3 cases.
// The normal case: \\pyrex\user
// The Netware setting root: \\strike\sys\public\dist
// The Netware CD? \\stike\sys \public\dist
lstrcpyn(szTempUNCPath, _GetUNCName(), ARRAYSIZE(szTempUNCPath));
pszT = StrChr(szTempUNCPath, TEXT(' '));
while (pszT)
{
pszT++;
if (*pszT == TEXT('\\'))
{
// The netware case of \\strike\sys \public\dist
*--pszT = 0;
break;
}
pszT = StrChr(pszT, TEXT(' '));
}
pszShare = StrRChr(szTempUNCPath, NULL, TEXT('\\'));
if (pszShare)
{
*pszShare++ = 0;
PathMakePretty(pszShare);
// pszServer should always start at char 2.
if (szTempUNCPath[2])
{
LPTSTR pszServer, pszSlash;
pszServer = &szTempUNCPath[2];
for (pszT = pszServer; pszT != NULL; pszT = pszSlash)
{
pszSlash = StrChr(pszT, TEXT('\\'));
if (pszSlash)
*pszSlash = 0;
PathMakePretty(pszT);
if (pszSlash)
*pszSlash++ = TEXT('\\');
}
TCHAR szDisplay[MAX_PATH];
hr = SHGetComputerDisplayName(pszServer, 0x0, szDisplay, ARRAYSIZE(szDisplay));
if (FAILED(hr))
{
*szDisplay = 0;
}
if (SUCCEEDED(hr))
{
LPTSTR pszLabel2 = ShellConstructMessageString(HINST_THISDLL,
MAKEINTRESOURCE(IDS_UNC_FORMAT), pszShare, szDisplay);
if (pszLabel2)
{
lstrcpyn(pszLabel, pszLabel2, cchLabel);
LocalFree(pszLabel2);
}
else
{
*pszLabel = TEXT('\0');
}
}
}
}
}
}
return hr;
}
int CMtPtRemote::GetDriveFlags()
{
// By default every drive type is ShellOpen, except CD-ROMs
UINT uDriveFlags = DRIVE_SHELLOPEN;
if (_IsAutorun())
{
uDriveFlags |= DRIVE_AUTORUN;
//FEATURE should we set AUTOOPEN based on a flag in the AutoRun.inf???
uDriveFlags |= DRIVE_AUTOOPEN;
}
if (_IsConnected())
{
if ((0 != _dwSpeed) && (_dwSpeed <= SPEED_SLOW))
{
uDriveFlags |= DRIVE_SLOW;
}
}
return TRUE;
}
void CMtPtRemote::_CalcPathSpeed()
{
_dwSpeed = 0;
NETCONNECTINFOSTRUCT nci = {0};
NETRESOURCE nr = {0};
TCHAR szPath[3];
nci.cbStructure = sizeof(nci);
// we are passing in a local drive and MPR does not like us to pass a
// local name as Z:\ but only wants Z:
_GetNameFirstXChar(szPath, 2 + 1);
nr.lpLocalName = szPath;
// dwSpeed is returned by MultinetGetConnectionPerformance
MultinetGetConnectionPerformance(&nr, &nci);
_dwSpeed = nci.dwSpeed;
}
// Imported from fsnotify.c
STDAPI_(void) SHChangeNotifyRegisterAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
//
// If a mount point is for a remote path (UNC), it needs to respond
// to shell changes identified by both UNC and local drive path (L:\).
// This function performs this registration.
//
HRESULT CMtPtRemote::ChangeNotifyRegisterAlias(void)
{
HRESULT hr = E_FAIL;
// Don't wake up sleeping net connections
if (_IsConnected() && !(_pshare->fFake))
{
LPITEMIDLIST pidlLocal = SHSimpleIDListFromPath(_GetName());
if (NULL != pidlLocal)
{
LPITEMIDLIST pidlUNC = SHSimpleIDListFromPath(_GetUNCName());
if (NULL != pidlUNC)
{
SHChangeNotifyRegisterAlias(pidlUNC, pidlLocal);
ILFree(pidlUNC);
hr = NOERROR;
}
ILFree(pidlLocal);
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// Temp /////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void _UpdateGFAAndGVIInfoHelper(LPCWSTR pszDrive, CShare* pshare)
{
pshare->dwGetFileAttributes = GetFileAttributes(pszDrive);
if (-1 != pshare->dwGetFileAttributes)
{
pshare->fGVIRetValue = GetVolumeInformation(pszDrive,
pshare->szLabel, ARRAYSIZE(pshare->szLabel),
&(pshare->dwSerialNumber), &(pshare->dwMaxFileNameLen),
&(pshare->dwFileSystemFlags), pshare->szFileSysName,
ARRAYSIZE(pshare->szFileSysName));
}
}
struct GFAGVICALL
{
HANDLE hEventBegun;
HANDLE hEventFinish;
WCHAR szDrive[4];
CShare* pshare;
};
void _FreeGFAGVICALL(GFAGVICALL* pgfagvicall)
{
if (pgfagvicall->hEventBegun)
{
CloseHandle(pgfagvicall->hEventBegun);
}
if (pgfagvicall->hEventFinish)
{
CloseHandle(pgfagvicall->hEventFinish);
}
if (pgfagvicall->pshare)
{
pgfagvicall->pshare->Release();
}
if (pgfagvicall)
{
LocalFree(pgfagvicall);
}
}
DWORD WINAPI _UpdateGFAAndGVIInfoCB(LPVOID pv)
{
GFAGVICALL* pgfagvicall = (GFAGVICALL*)pv;
SetEvent(pgfagvicall->hEventBegun);
_UpdateGFAAndGVIInfoHelper(pgfagvicall->szDrive, pgfagvicall->pshare);
SetEvent(pgfagvicall->hEventFinish);
_FreeGFAGVICALL(pgfagvicall);
return 0;
}
GFAGVICALL* CMtPtRemote::_PrepareThreadParam(HANDLE* phEventBegun,
HANDLE* phEventFinish)
{
BOOL fSucceeded = FALSE;
*phEventBegun = NULL;
*phEventFinish = NULL;
GFAGVICALL* pgfagvicall = (GFAGVICALL*)LocalAlloc(LPTR,
sizeof(GFAGVICALL));
if (pgfagvicall)
{
pgfagvicall->hEventBegun = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pgfagvicall->hEventBegun)
{
HANDLE hCurrentProcess = GetCurrentProcess();
if (DuplicateHandle(hCurrentProcess, pgfagvicall->hEventBegun,
hCurrentProcess, phEventBegun, 0, FALSE,
DUPLICATE_SAME_ACCESS))
{
pgfagvicall->hEventFinish = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pgfagvicall->hEventFinish)
{
if (DuplicateHandle(hCurrentProcess,
pgfagvicall->hEventFinish, hCurrentProcess,
phEventFinish, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
_pshare->AddRef();
pgfagvicall->pshare = _pshare;
StrCpyN(pgfagvicall->szDrive, _GetName(),
ARRAYSIZE(pgfagvicall->szDrive));
fSucceeded = TRUE;
}
}
}
}
}
if (!fSucceeded)
{
if (*phEventBegun)
{
CloseHandle(*phEventBegun);
}
if (pgfagvicall)
{
_FreeGFAGVICALL(pgfagvicall);
pgfagvicall = NULL;
}
}
return pgfagvicall;
}
// Expiration: 35 secs (what we shipped W2K with)
BOOL CMtPtRemote::_HaveGFAAndGVIExpired(DWORD dwNow)
{
BOOL fExpired = FALSE;
// Check also for the wrapping case first.
if ((_pshare->dwGFAGVILastCall > dwNow) ||
((dwNow - _pshare->dwGFAGVILastCall) > 35 * 1000))
{
fExpired = TRUE;
}
else
{
fExpired = FALSE;
}
return fExpired;
}
// We launch a thread so that we won't be jammed on this for more than 10 sec.
// If the thread times out, we use the cache value but do not reset the cache
// values. They're better than nothing. We do reset the cache last tick count
// so that we do not send another thread to jam here before at least 35 sec.
// Return TRUE or FALSE to tell us if timed out or not. For GFA and GVI
// success/failure check (-1 != dwGetFileAttributes) && (_fGVIRetValue)
BOOL CMtPtRemote::_UpdateGFAAndGVIInfo()
{
BOOL fRet = TRUE;
DWORD dwNow = GetTickCount();
if (_HaveGFAAndGVIExpired(dwNow))
{
_pshare->dwGFAGVILastCall = dwNow;
BOOL fGoSync = TRUE;
HANDLE hEventBegun;
HANDLE hEventFinish;
GFAGVICALL* pgfagvicall = _PrepareThreadParam(&hEventBegun,
&hEventFinish);
if (pgfagvicall)
{
if (SHQueueUserWorkItem(_UpdateGFAAndGVIInfoCB, pgfagvicall,
0, (DWORD_PTR)0, (DWORD_PTR*)NULL, NULL, 0))
{
DWORD dw = WaitForSingleObject(hEventFinish, 10 * 1000);
if (WAIT_TIMEOUT == dw)
{
// we timed out!
fRet = FALSE;
if (WAIT_OBJECT_0 != WaitForSingleObject(
hEventBegun, 0))
{
// since the thread started, we know that
// this call is _really_ slow!
fGoSync = FALSE;
}
else
{
// our work item was never queued, so we
// fall through to the fGoSync case below
}
}
}
else
{
_FreeGFAGVICALL(pgfagvicall);
}
CloseHandle(hEventBegun);
CloseHandle(hEventFinish);
}
if (fGoSync)
{
// we should come here if we failed to create our workitem
// or our workitem was never queued
_UpdateGFAAndGVIInfoHelper(_GetName(), _pshare);
fRet = TRUE;
}
}
return fRet;
}
BOOL CMtPtRemote::_GetFileAttributes(DWORD* pdwAttrib)
{
if (_UpdateGFAAndGVIInfo())
{
*pdwAttrib = _pshare->dwGetFileAttributes;
}
else
{
*pdwAttrib = -1;
}
return (-1 != *pdwAttrib);
}
// { DRIVE_ISCOMPRESSIBLE | DRIVE_LFN | DRIVE_SECURITY }
int CMtPtRemote::_GetGVIDriveFlags()
{
int iFlags = 0;
if (_UpdateGFAAndGVIInfo())
{
if (_pshare->fGVIRetValue)
{
// The file attrib we received at the begginning should be
// valid, do not touch the drive for nothing
if (_pshare->dwFileSystemFlags & FS_FILE_COMPRESSION)
{
iFlags |= DRIVE_ISCOMPRESSIBLE;
}
// Volume supports long filename (greater than 8.3)?
if (_pshare->dwMaxFileNameLen > 12)
{
iFlags |= DRIVE_LFN;
}
// Volume supports security?
if (_pshare->dwFileSystemFlags & FS_PERSISTENT_ACLS)
{
iFlags |= DRIVE_SECURITY;
}
}
}
return iFlags;
}
BOOL CMtPtRemote::_GetSerialNumber(DWORD* pdwSerialNumber)
{
BOOL fRet = FALSE;
if (_UpdateGFAAndGVIInfo())
{
if (_pshare->fGVIRetValue)
{
*pdwSerialNumber = _pshare->dwSerialNumber;
fRet = TRUE;
}
}
// No reg stuff
return fRet;
}
BOOL CMtPtRemote::_GetGVILabel(LPTSTR pszLabel, DWORD cchLabel)
{
BOOL fRet = FALSE;
*pszLabel = 0;
if (_UpdateGFAAndGVIInfo())
{
if (_pshare->fGVIRetValue)
{
lstrcpyn(pszLabel, _pshare->szLabel, cchLabel);
fRet = TRUE;
}
}
// No reg stuff
return fRet;
}
BOOL CMtPtRemote::_GetGVILabelOrMixedCaseFromReg(LPTSTR pszLabel, DWORD cchLabel)
{
return _GetGVILabel(pszLabel, cchLabel);
}
BOOL CMtPtRemote::_GetFileSystemFlags(DWORD* pdwFlags)
{
BOOL fRet = FALSE;
*pdwFlags = 0;
if (_UpdateGFAAndGVIInfo())
{
if (_pshare->fGVIRetValue)
{
*pdwFlags = _pshare->dwFileSystemFlags;
fRet = TRUE;
}
}
return fRet;
}
BOOL CMtPtRemote::_GetFileSystemName(LPTSTR pszFileSysName, DWORD cchFileSysName)
{
BOOL fRet = FALSE;
*pszFileSysName = 0;
if (_UpdateGFAAndGVIInfo())
{
if (_pshare->fGVIRetValue)
{
StrCpyN(pszFileSysName, _pshare->szFileSysName, cchFileSysName);
fRet = TRUE;
}
}
return fRet;
}
DWORD CMtPtRemote::GetShellDescriptionID()
{
return SHDID_COMPUTER_NETDRIVE;
}
///////////////////////////////////////////////////////////////////////////////
// New //////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
UINT CMtPtRemote::_GetAutorunIcon(LPTSTR pszModule, DWORD cchModule)
{
int iIcon = -1;
if (RSGetTextValue(TEXT("_Autorun\\DefaultIcon"), NULL, pszModule,
&cchModule))
{
iIcon = PathParseIconLocation(pszModule);
}
return iIcon;
}
UINT CMtPtRemote::GetIcon(LPTSTR pszModule, DWORD cchModule)
{
BOOL fFoundIt = FALSE;
UINT iIcon = II_DRIVENET;
*pszModule = 0;
// Autorun first
// Fancy icon (Autoplay) second
// Legacy drive icons last
if (_IsAutorun())
{
iIcon = _GetAutorunIcon(pszModule, cchModule);
if (-1 != iIcon)
{
fFoundIt = TRUE;
}
}
if (!fFoundIt)
{
if (_pszLegacyRegIcon)
{
if (RSGetTextValue(TEXT("DefaultIcon"), NULL, pszModule,
&cchModule))
{
iIcon = PathParseIconLocation(pszModule);
}
else
{
*pszModule = 0;
}
}
else
{
if (_IsUnavailableNetDrive())
{
iIcon = II_DRIVENETDISABLED;
}
}
}
if (*pszModule)
TraceMsg(TF_MOUNTPOINT, "CMtPtRemote::GetIcon: for '%s', chose '%s', '%d'", _GetNameDebug(), pszModule, iIcon);
else
TraceMsg(TF_MOUNTPOINT, "CMtPtRemote::GetIcon: for '%s', chose '%d'", _GetNameDebug(), iIcon);
return iIcon;
}
void CMtPtRemote::GetTypeString(LPTSTR pszType, DWORD cchType)
{
int iID;
*pszType = 0;
if (_IsConnected())
{
iID = IDS_DRIVES_NETDRIVE;
}
else
{
iID = IDS_DRIVES_NETUNAVAIL;
}
LoadString(HINST_THISDLL, iID, pszType, cchType);
}
HRESULT CMtPtRemote::GetLabelNoFancy(LPTSTR pszLabel, DWORD cchLabel)
{
HRESULT hr;
if (_UpdateGFAAndGVIInfo())
{
lstrcpyn(pszLabel, _pshare->szLabel, cchLabel);
hr = S_OK;
}
else
{
*pszLabel = 0;
hr = E_FAIL;
}
return hr;
}
HRESULT CMtPtRemote::GetLabel(LPTSTR pszLabel, DWORD cchLabel)
{
HRESULT hres = E_FAIL;
ASSERT(pszLabel);
*pszLabel = 0;
// Do we already have a label from the registry for this volume?
// (the user may have renamed this drive)
if (!_GetLabelFromReg(pszLabel, cchLabel))
{
// No
// Do we have a name from the server?
if (!_GetLabelFromDesktopINI(pszLabel, cchLabel))
{
// No
// We should build up the display name ourselves
hres = _GetDefaultUNCDisplayName(pszLabel, cchLabel);
if (SUCCEEDED(hres) && *pszLabel)
{
hres = S_OK;
}
}
else
{
hres = S_OK;
}
}
else
{
hres = S_OK;
}
if (FAILED(hres))
{
GetTypeString(pszLabel, cchLabel);
hres = S_OK;
}
return hres;
}
HRESULT CMtPtRemote::GetRemotePath(LPWSTR pszPath, DWORD cchPath)
{
*pszPath = 0;
if (!_pshare->fFake)
StrCpyN(pszPath, _pshare->pszRemoteName, cchPath);
return (pszPath[0]) ? S_OK : E_FAIL;
}
///////////////////////////////////////////////////////////////////////////////
// Connection status
///////////////////////////////////////////////////////////////////////////////
// We cannot cache the connection status. This is already cached at the redirector level.
// When calling the WNetGetConnection fcts you get what's cache there, no check is actually
// done on the network to see if this information is accurate (OK/Disconnected/Unavailable).
// The information is updated only when the share is actually accessed (e.g: GetFileAttributes)
//
// So we need to always do the calls (fortunately non-expensive) so that we get the most
// up to date info. Otherwise the following was occuring: A user double click a map drive
// from the Explorer's Listview, WNetConnection gets called and we get the OK cached value
// from the redirector. Some other code actually try to access the share, and the redirector
// realize that the share is not there and set its cache to Disconnected. We are queried
// again for the state of the connection to update the icon, if we cached this info we
// return OK, if we ask for it (0.1 sec after the first call to WNetGetConnection) we get
// Disconnected. (stephstm 06/02/99)
void CMtPtRemote::_UpdateWNetGCStatus()
{
TCHAR szRemoteName[MAX_PATH];
DWORD cchRemoteName = ARRAYSIZE(szRemoteName);
TCHAR szPath[3];
// WNetConnection does not take a trailing slash
_dwWNetGCStatus = WNetGetConnection(
_GetNameFirstXChar(szPath, 2 + 1), szRemoteName, &cchRemoteName);
}
BOOL CMtPtRemote::IsUnavailableNetDrive()
{
return _IsUnavailableNetDrive();
}
BOOL CMtPtRemote::_IsUnavailableNetDrive()
{
BOOL fUnavail = TRUE;
BOOL fPrevUnavail = _IsUnavailableNetDriveFromStateVar();
_UpdateWNetGCStatus();
fUnavail = (ERROR_CONNECTION_UNAVAIL == _dwWNetGCStatus);
if (fPrevUnavail != fUnavail)
{
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, _GetName(), NULL);
}
return fUnavail;
}
BOOL CMtPtRemote::_IsUnavailableNetDriveFromStateVar()
{
return (ERROR_CONNECTION_UNAVAIL == _dwWNetGCStatus);
}
BOOL CMtPtRemote::_IsConnected()
{
BOOL fConnected = TRUE;
_UpdateWNetGCStatus();
// This whole if/else statement is the same thing as
// _IsConnectedFromStateVar() except that we will avoid calling
// WNetGetConnection3 if possible (optimization)
if (NO_ERROR != _dwWNetGCStatus)
{
fConnected = FALSE;
}
else
{
DWORD dwSize = sizeof(_wngcs);
TCHAR szPath[3];
_dwWNetGC3Status = WNetGetConnection3(
_GetNameFirstXChar(szPath, 2 + 1), NULL,
WNGC_INFOLEVEL_DISCONNECTED, &_wngcs, &dwSize);
// Did we succeeded the call to WNetGetConnection 3 and it returned
// disconnected?
if (WN_SUCCESS == _dwWNetGC3Status)
{
if (WNGC_DISCONNECTED == _wngcs.dwState)
{
// Yes
fConnected = FALSE;
}
}
else
{
fConnected = FALSE;
}
}
return fConnected;
}
BOOL CMtPtRemote::_IsMountedOnDriveLetter()
{
return TRUE;
}
void CMtPtRemote::_UpdateLabelFromDesktopINI()
{
WCHAR szLabelFromDesktopINI[MAX_MTPTCOMMENT];
if (!GetShellClassInfo(_GetName(), TEXT("NetShareDisplayName"),
szLabelFromDesktopINI, ARRAYSIZE(szLabelFromDesktopINI)))
{
szLabelFromDesktopINI[0] = 0;
}
RSSetTextValue(NULL, TEXT("_LabelFromDesktopINI"),
szLabelFromDesktopINI, REG_OPTION_NON_VOLATILE);
}
void CMtPtRemote::_UpdateAutorunInfo()
{
_pshare->fAutorun = FALSE;
if (_IsAutoRunDrive())
{
if (_ProcessAutoRunFile())
{
_pshare->fAutorun = TRUE;
}
}
if (!_pshare->fAutorun)
{
// Make sure to delete the shell key
RSDeleteSubKey(TEXT("Shell"));
}
}
CMtPtRemote::CMtPtRemote()
{
#ifdef DEBUG
++_cMtPtRemote;
#endif
}
CMtPtRemote::~CMtPtRemote()
{
if (_pshare)
{
_pshare->Release();
}
#ifdef DEBUG
--_cMtPtRemote;
#endif
}
HRESULT CMtPtRemote::_InitWithoutShareName(LPCWSTR pszName)
{
// Let's make a name
GUID guid;
HRESULT hr = CoCreateGuid(&guid);
if (SUCCEEDED(hr))
{
WCHAR szGUID[sizeof("{00000010-0000-0010-8000-00AA006D2EA4}")];
if (StringFromGUID2(guid, szGUID, ARRAYSIZE(szGUID)))
{
hr = _Init(pszName, szGUID, TRUE);
if (SUCCEEDED(hr))
{
_pshare->fFake = TRUE;
}
}
else
{
hr = E_FAIL;
}
}
return hr;
}
HRESULT CMtPtRemote::_Init(LPCWSTR pszName, LPCWSTR pszShareName,
BOOL fUnavailable)
{
HRESULT hr;
_pshare = _GetOrCreateShareFromID(pszShareName);
if (_pshare)
{
if (fUnavailable)
{
_dwWNetGCStatus = ERROR_CONNECTION_UNAVAIL;
}
lstrcpyn(_szName, pszName, ARRAYSIZE(_szName));
PathAddBackslash(_szName);
// Remote drives uses the Share key for all their stuff. They do not have
// anything interesting specific to the drive letter
RSInitRoot(HKEY_CURRENT_USER, REGSTR_MTPT_ROOTKEY2, _pshare->pszKeyName,
REG_OPTION_NON_VOLATILE);
RSSetTextValue(NULL, TEXT("BaseClass"), TEXT("Drive"));
// Access the drive on first connection of the share
_InitOnlyOnceStuff();
_InitLegacyRegIconAndLabel(FALSE, FALSE);
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
LPCTSTR CMtPtRemote::_GetUNCName()
{
return _pshare->pszRemoteName;
}
void CMtPtRemote::_InitOnlyOnceStuff()
{
if (!RSValueExist(NULL, TEXT("_CommentFromDesktopINI")))
{
// Comment
_UpdateCommentFromDesktopINI();
// Label
_UpdateLabelFromDesktopINI();
// Autorun
_UpdateAutorunInfo();
}
}
int CMtPtRemote::_GetDriveType()
{
return DRIVE_REMOTE;
}
HRESULT CMtPtRemote::GetAssocSystemElement(IAssociationElement **ppae)
{
return AssocElemCreateForClass(&CLSID_AssocSystemElement, L"Drive.Network", ppae);
}
DWORD CMtPtRemote::_GetPathSpeed()
{
if (!_dwSpeed)
{
_CalcPathSpeed();
}
return _dwSpeed;
}
// static
HRESULT CMtPtRemote::_DeleteAllMtPtsAndShares()
{
_csDL.Enter();
for (DWORD dw = 0; dw <26; ++dw)
{
CMtPtRemote* pmtptr = CMountPoint::_rgMtPtDriveLetterNet[dw];
if (pmtptr)
{
pmtptr->Release();
CMountPoint::_rgMtPtDriveLetterNet[dw] = 0;
}
}
if (_hdpaShares)
{
DPA_Destroy(_hdpaShares);
_hdpaShares = NULL;
}
_csDL.Leave();
return S_OK;
}
// static
HRESULT CMtPtRemote::_CreateMtPtRemoteWithoutShareName(LPCWSTR pszMountPoint)
{
HRESULT hr;
CMtPtRemote* pmtptr = new CMtPtRemote();
if (pmtptr)
{
hr = pmtptr->_InitWithoutShareName(pszMountPoint);
if (SUCCEEDED(hr))
{
_csDL.Enter();
CMountPoint::_rgMtPtDriveLetterNet[DRIVEID(pszMountPoint)] =
pmtptr;
_csDL.Leave();
}
else
{
delete pmtptr;
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
// static
HRESULT CMtPtRemote::_CreateMtPtRemote(LPCWSTR pszMountPoint,
LPCWSTR pszShareName, BOOL fUnavailable)
{
HRESULT hr;
CMtPtRemote* pmtptr = new CMtPtRemote();
if (pmtptr)
{
hr = pmtptr->_Init(pszMountPoint, pszShareName, fUnavailable);
if (SUCCEEDED(hr))
{
_csDL.Enter();
CMountPoint::_rgMtPtDriveLetterNet[DRIVEID(pszMountPoint)] =
pmtptr;
_csDL.Leave();
}
else
{
delete pmtptr;
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
// static
CShare* CMtPtRemote::_GetOrCreateShareFromID(LPCWSTR pszShareName)
{
CShare* pshare = NULL;
_csDL.Enter();
DWORD c = DPA_GetPtrCount(_hdpaShares);
for (DWORD dw = 0; dw < c; ++dw)
{
pshare = (CShare*)DPA_GetPtr(_hdpaShares, dw);
if (pshare)
{
if (!lstrcmpi(pshare->pszRemoteName, pszShareName))
{
pshare->AddRef();
break;
}
else
{
pshare = NULL;
}
}
}
if (!pshare)
{
BOOL fSuccess = FALSE;
pshare = new CShare();
if (pshare)
{
pshare->pszRemoteName = StrDup(pszShareName);
if (pshare->pszRemoteName)
{
pshare->pszKeyName = StrDup(pszShareName);
if (pshare->pszKeyName)
{
LPWSTR psz = pshare->pszKeyName;
while (*psz)
{
if (TEXT('\\') == *psz)
{
*psz = TEXT('#');
}
++psz;
}
if (-1 != DPA_AppendPtr(_hdpaShares, pshare))
{
fSuccess = TRUE;
}
}
}
}
if (!fSuccess)
{
if (pshare)
{
if (pshare->pszKeyName)
{
LocalFree(pshare->pszKeyName);
}
if (pshare->pszRemoteName)
{
LocalFree(pshare->pszRemoteName);
}
delete pshare;
pshare = NULL;
}
}
}
_csDL.Leave();
return pshare;
}
HKEY CMtPtRemote::GetRegKey()
{
TraceMsg(TF_MOUNTPOINT, "CMtPtRemote::GetRegKey: for '%s'", _GetNameDebug());
return RSDuplicateRootKey();
}
// static
void CMtPtRemote::_NotifyReconnectedNetDrive(LPCWSTR pszMountPoint)
{
_csDL.Enter();
CMtPtRemote* pmtptr = CMountPoint::_rgMtPtDriveLetterNet[
DRIVEID(pszMountPoint)];
if (pmtptr)
{
pmtptr->_pshare->dwGFAGVILastCall = GetTickCount() - 35001;
}
// ChangeNotify???
_csDL.Leave();
}
// static
HRESULT CMtPtRemote::_RemoveShareFromHDPA(CShare* pshare)
{
_csDL.Enter();
if (_hdpaShares)
{
DWORD c = DPA_GetPtrCount(_hdpaShares);
for (DWORD dw = 0; dw < c; ++dw)
{
CShare* pshare2 = (CShare*)DPA_GetPtr(_hdpaShares, dw);
if (pshare2 && (pshare2 == pshare))
{
DPA_DeletePtr(_hdpaShares, dw);
break;
}
}
}
_csDL.Leave();
return S_OK;
}
DWORD CMtPtRemote::_GetAutorunContentType()
{
return _GetMTPTContentType();
}
DWORD CMtPtRemote::_GetMTPTDriveType()
{
return DT_REMOTE;
}
DWORD CMtPtRemote::_GetMTPTContentType()
{
DWORD dwRet = CT_UNKNOWNCONTENT;
if (_IsAutorun())
{
dwRet |= CT_AUTORUNINF;
}
return dwRet;
}