#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())); } 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 StringCchCopy(szTempUNCPath, ARRAYSIZE(szTempUNCPath), _GetUNCName()); 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) { StringCchCopy(pszLabel, cchLabel, pszLabel2); 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; fSucceeded = SUCCEEDED(StringCchCopy(pgfagvicall->szDrive, ARRAYSIZE(pgfagvicall->szDrive), _GetName())); } } } } } 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) { fRet = SUCCEEDED(StringCchCopy(pszLabel, cchLabel, _pshare->szLabel)); } } // 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) { fRet = SUCCEEDED(StringCchCopy(pszFileSysName, cchFileSysName, _pshare->szFileSysName)); } } 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()) { hr = StringCchCopy(pszLabel, cchLabel, _pshare->szLabel); } 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) { HRESULT hr = E_FAIL; *pszPath = 0; if (!_pshare->fFake && _pshare->pszRemoteName[0]) { hr = StringCchCopy(pszPath, cchPath, _pshare->pszRemoteName); } return hr; } /////////////////////////////////////////////////////////////////////////////// // 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; } hr = StringCchCopy(_szName, ARRAYSIZE(_szName), pszName); if (SUCCEEDED(hr)) { 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); } } 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; }