#include "shellprv.h" #pragma hdrstop #include #include "fstreex.h" #include "views.h" #include "drives.h" #include "propsht.h" #include "infotip.h" #include "datautil.h" #include "netview.h" #include "bitbuck.h" #include "drawpie.h" #include "shitemid.h" #include "devguid.h" #include "ids.h" #include "idldrop.h" #include "util.h" #include "shcombox.h" #include "hwcmmn.h" #include "prop.h" #include "mtpt.h" #include "ftascstr.h" // for CFTAssocStore #include "ascstr.h" // for IAssocInfo class #include "apdlg.h" #include "cdburn.h" #define REL_KEY_DEFRAG TEXT("MyComputer\\defragpath") #define REL_KEY_BACKUP TEXT("MyComputer\\backuppath") /////////////////////////////////////////////////////////////////////////////// // Begin: Old C fct required externally /////////////////////////////////////////////////////////////////////////////// STDAPI_(int) RealDriveTypeFlags(int iDrive, BOOL fOKToHitNet) { int iType = DRIVE_NO_ROOT_DIR; CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive, TRUE, fOKToHitNet); if (pMtPt) { WCHAR szDrive[4]; iType = GetDriveType(PathBuildRoot(szDrive, iDrive)); iType |= pMtPt->GetDriveFlags(); iType |= pMtPt->GetVolumeFlags(); pMtPt->Release(); } return iType; } STDAPI_(int) RealDriveType(int iDrive, BOOL fOKToHitNet) { WCHAR szDrive[4]; return GetDriveType(PathBuildRoot(szDrive, iDrive)) & DRIVE_TYPE; } STDAPI_(int) DriveType(int iDrive) { return RealDriveType(iDrive, TRUE); } STDAPI_(DWORD) PathGetClusterSize(LPCTSTR pszPath) { static TCHAR s_szRoot[MAX_PATH] = {'\0'}; static int s_nszRootLen = 0; static DWORD s_dwSize = 0; DWORD dwSize = 0; // Do we have a cache hit? No need to hit the net if we can avoid it... if (s_nszRootLen) { ENTERCRITICAL; if (wcsncmp(pszPath, s_szRoot, s_nszRootLen) == 0) { dwSize = s_dwSize; } LEAVECRITICAL; } if (0 == dwSize) { TCHAR szRoot[MAX_PATH]; StringCchCopy(szRoot, ARRAYSIZE(szRoot), pszPath); PathStripToRoot(szRoot); if (PathIsUNC(szRoot)) { DWORD dwSecPerClus, dwBytesPerSec, dwClusters, dwTemp; if (PathAddBackslash(szRoot)) { if (GetDiskFreeSpace(szRoot, &dwSecPerClus, &dwBytesPerSec, &dwTemp, &dwClusters)) { dwSize = dwSecPerClus * dwBytesPerSec; } } // else dwSize which will get fixed below and the string compare-N above // will still be reasonable. } else { CMountPoint* pMtPt = CMountPoint::GetMountPoint(pszPath); if (pMtPt) { dwSize = pMtPt->GetClusterSize(); pMtPt->Release(); } } // Sometimes on Millennium, we get 0 as the cluster size. // Reason unknown. Sanitize the value so we don't go insane. if (dwSize == 0) dwSize = 512; // Remember this for later - chances are we'll be queried for the same drive again ENTERCRITICAL; StringCchCopy(s_szRoot, ARRAYSIZE(s_szRoot), szRoot); s_nszRootLen = lstrlen(s_szRoot); s_dwSize = dwSize; LEAVECRITICAL; } return dwSize; } STDAPI_(UINT) GetMountedVolumeIcon(LPCTSTR pszMountPoint, LPTSTR pszModule, DWORD cchModule) { UINT iIcon = II_FOLDER; // zero-init string if (pszModule) *pszModule = 0; CMountPoint* pMtPt = CMountPoint::GetMountPoint(pszMountPoint); if (pMtPt) { iIcon = pMtPt->GetIcon(pszModule, cchModule); pMtPt->Release(); } return iIcon; } STDAPI_(BOOL) IsDisconnectedNetDrive(int iDrive) { BOOL fDisc = 0; CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive); if (pMtPt) { fDisc = pMtPt->IsDisconnectedNetDrive(); pMtPt->Release(); } return fDisc; } STDAPI_(BOOL) IsUnavailableNetDrive(int iDrive) { BOOL fUnAvail = 0; CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive); if (pMtPt) { fUnAvail = pMtPt->IsUnavailableNetDrive(); pMtPt->Release(); } return fUnAvail; } STDMETHODIMP SetDriveLabel(HWND hwnd, IUnknown* punkEnableModless, int iDrive, LPCTSTR pszDriveLabel) { HRESULT hr = E_FAIL; CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive); if (pMtPt) { hr = pMtPt->SetDriveLabel(hwnd, pszDriveLabel); pMtPt->Release(); } return hr; } STDMETHODIMP GetDriveComment(int iDrive, LPTSTR pszComment, int cchComment) { HRESULT hr = E_FAIL; CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive); if (pMtPt) { hr = pMtPt->GetComment(pszComment, cchComment); pMtPt->Release(); } return hr; } /////////////////////////////////////////////////////////////////////////////// // End: Old C fct required externally /////////////////////////////////////////////////////////////////////////////// // // fDoIt -- TRUE, if we make connections; FALSE, if just querying. // BOOL _MakeConnection(IDataObject *pDataObj, BOOL fDoIt) { STGMEDIUM medium; FORMATETC fmte = {g_cfNetResource, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; BOOL fAnyConnectable = FALSE; if (SUCCEEDED(pDataObj->GetData(&fmte, &medium))) { LPNETRESOURCE pnr = (LPNETRESOURCE)LocalAlloc(LPTR, 1024); if (pnr) { UINT iItem, cItems = SHGetNetResource(medium.hGlobal, (UINT)-1, NULL, 0); for (iItem = 0; iItem < cItems; iItem++) { if (SHGetNetResource(medium.hGlobal, iItem, pnr, 1024) && pnr->dwUsage & RESOURCEUSAGE_CONNECTABLE && !(pnr->dwType & RESOURCETYPE_PRINT)) { fAnyConnectable = TRUE; if (fDoIt) { SHNetConnectionDialog(NULL, pnr->lpRemoteName, pnr->dwType); SHChangeNotifyHandleEvents(); } else { break; // We are just querying. } } } LocalFree(pnr); } ReleaseStgMedium(&medium); } return fAnyConnectable; } // // the entry of "make connection thread" // DWORD WINAPI MakeConnectionThreadProc(void *pv) { IDataObject *pdtobj; if (SUCCEEDED(CoGetInterfaceAndReleaseStream((IStream *)pv, IID_PPV_ARG(IDataObject, &pdtobj)))) { _MakeConnection(pdtobj, TRUE); pdtobj->Release(); } return 0; } STDAPI CDrivesDropTarget_Create(HWND hwnd, LPCITEMIDLIST pidl, IDropTarget **ppdropt); class CDrivesDropTarget : public CIDLDropTarget { friend HRESULT CDrivesDropTarget_Create(HWND hwnd, LPCITEMIDLIST pidl, IDropTarget **ppdropt); public: CDrivesDropTarget(HWND hwnd) : CIDLDropTarget(hwnd) { }; // IDropTarget methods overwirte STDMETHODIMP DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); STDMETHODIMP Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); }; STDAPI CDrivesDropTarget_Create(HWND hwnd, LPCITEMIDLIST pidl, IDropTarget **ppdropt) { *ppdropt = NULL; HRESULT hr; CDrivesDropTarget *pCIDLDT = new CDrivesDropTarget(hwnd); if (pCIDLDT) { hr = pCIDLDT->_Init(pidl); if (SUCCEEDED(hr)) pCIDLDT->QueryInterface(IID_PPV_ARG(IDropTarget, ppdropt)); pCIDLDT->Release(); } else hr = E_OUTOFMEMORY; return hr; } // // puts DROPEFFECT_LINK in *pdwEffect, only if the data object // contains one or more net resource. // STDMETHODIMP CDrivesDropTarget::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { // Call the base class first. CIDLDropTarget::DragEnter(pDataObj, grfKeyState, pt, pdwEffect); *pdwEffect &= _MakeConnection(pDataObj, FALSE) ? DROPEFFECT_LINK : DROPEFFECT_NONE; m_dwEffectLastReturned = *pdwEffect; return S_OK; // Notes: we should NOT return hr as it. } // // creates a connection to a dropped net resource object. // STDMETHODIMP CDrivesDropTarget::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { HRESULT hr; if (m_dwData & DTID_NETRES) { *pdwEffect = DROPEFFECT_LINK; hr = CIDLDropTarget::DragDropMenu(DROPEFFECT_LINK, pDataObj, pt, pdwEffect, NULL, NULL, POPUP_DRIVES_NONDEFAULTDD, grfKeyState); if (hr == S_FALSE) { // we create another thread to avoid blocking the source thread. IStream *pstm; if (S_OK == CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObj, &pstm)) { if (SHCreateThread(MakeConnectionThreadProc, pstm, CTF_COINIT, NULL)) { hr = S_OK; } else { pstm->Release(); hr = E_OUTOFMEMORY; } } } } else { // // Because QueryGetData() failed, we don't call CIDLDropTarget_ // DragDropMenu(). Therefore, we must call this explicitly. // DAD_DragLeave(); hr = E_FAIL; } CIDLDropTarget::DragLeave(); return hr; } STDAPI_(DWORD) DrivesPropertiesThreadProc(void *pv) { PROPSTUFF *pps = (PROPSTUFF *)pv; STGMEDIUM medium; ULONG_PTR dwCookie = 0; BOOL bDidActivate = FALSE; // // This __try/__finally block is to ensure that the activation context gets // removed, even if there's an assertion elsewhere in this code. A missing // DeactivateActCtx will lead to a very strange-looking assertion in one of // the RtlpDeactivateActCtx-variant functions from the caller. Old code // was missing the deactivate in all circumstances. // // (jonwis) 1/2/2001 // __try { bDidActivate = ActivateActCtx(NULL, &dwCookie); LPIDA pida = DataObj_GetHIDA(pps->pdtobj, &medium); BOOL bMountedDriveInfo = FALSE; // Were we able to get data for a HIDA? if (!pida) { // No, pida is first choice, but if not present check for mounteddrive info FORMATETC fmte; fmte.cfFormat = g_cfMountedVolume; fmte.ptd = NULL; fmte.dwAspect = DVASPECT_CONTENT; fmte.lindex = -1; fmte.tymed = TYMED_HGLOBAL; // Is data available for the MountedVolume format? if (SUCCEEDED(pps->pdtobj->GetData(&fmte, &medium))) // Yes bMountedDriveInfo = TRUE; } // Do we have data for a HIDA or a mountedvolume? if (pida || bMountedDriveInfo) { // Yes TCHAR szCaption[MAX_PATH]; LPTSTR pszCaption = NULL; if (pida) { pszCaption = SHGetCaption(medium.hGlobal); } else { TCHAR szMountPoint[MAX_PATH]; TCHAR szVolumeGUID[MAX_PATH]; DragQueryFile((HDROP)medium.hGlobal, 0, szMountPoint, ARRAYSIZE(szMountPoint)); GetVolumeNameForVolumeMountPoint(szMountPoint, szVolumeGUID, ARRAYSIZE(szVolumeGUID)); szCaption[0] = 0; GetVolumeInformation(szVolumeGUID, szCaption, ARRAYSIZE(szCaption), NULL, NULL, NULL, NULL, 0); if (!(*szCaption)) LoadString(HINST_THISDLL, IDS_UNLABELEDVOLUME, szCaption, ARRAYSIZE(szCaption)); PathRemoveBackslash(szMountPoint); // Fix 330388 // If the szMountPoint is not a valid local path, do not // display it in the properties dialog title: if (-1 != PathGetDriveNumber(szMountPoint)) { int nCaptionLength = lstrlen(szCaption) ; StringCchPrintf(szCaption + nCaptionLength, ARRAYSIZE(szCaption) - nCaptionLength, TEXT(" (%s)"), szMountPoint); } pszCaption = szCaption; } // NOTE - if we pass the name of the drive then we can get a lot more keys... HKEY rgk[MAX_ASSOC_KEYS]; DWORD ck = CDrives_GetKeys(NULL, rgk, ARRAYSIZE(rgk)); SHOpenPropSheet(pszCaption, rgk, ck, &CLSID_ShellDrvDefExt, pps->pdtobj, NULL, pps->pStartPage); SHRegCloseKeys(rgk, ck); if (pida && pszCaption) SHFree(pszCaption); if (pida) HIDA_ReleaseStgMedium(pida, &medium); else ReleaseStgMedium(&medium); } else { TraceMsg(DM_TRACE, "no HIDA in data obj nor Mounted drive info"); } } __finally { if ( bDidActivate ) { DeactivateActCtx( 0, dwCookie ); } } return 0; } // // To be called back from within CDefFolderMenu // STDAPI CDrives_DFMCallBack(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK; switch (uMsg) { case DFM_MERGECONTEXTMENU: if (pdtobj) { FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; // Check if only file system objects are selected. if (pdtobj->QueryGetData(&fmte) == S_OK) { #define pqcm ((LPQCMINFO)lParam) STGMEDIUM medium; // Yes, only file system objects are selected. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium); if (pida) { LPIDDRIVE pidd = (LPIDDRIVE)IDA_GetIDListPtr(pida, 0); if (pidd) { int iDrive = DRIVEID(pidd->cName); UINT idCmdBase = pqcm->idCmdFirst; // store it away BOOL fIsEjectable = FALSE; CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_DRIVES_ITEM, 0, pqcm); CMountPoint* pmtpt = CMountPoint::GetMountPoint(DRIVEID(pidd->cName)); if (pmtpt) { if (!pmtpt->IsRemote() || SHRestricted( REST_NONETCONNECTDISCONNECT )) { DeleteMenu(pqcm->hmenu, idCmdBase + FSIDM_DISCONNECT, MF_BYCOMMAND); } if ((pida->cidl != 1) || (!pmtpt->IsFormattable())) { // Don't even try to format more than one disk // Or a net drive, or a CD-ROM, or a RAM drive ... // Note we are going to show the Format command on the // boot drive, Windows drive, System drive, compressed // drives, etc. An appropriate error should be shown // after the user chooses this command DeleteMenu(pqcm->hmenu, idCmdBase + FSIDM_FORMAT, MF_BYCOMMAND); } if (pmtpt->IsEjectable()) fIsEjectable = TRUE; pmtpt->Release(); } if ((pida->cidl != 1) || (iDrive < 0) || !fIsEjectable) DeleteMenu(pqcm->hmenu, idCmdBase + FSIDM_EJECT, MF_BYCOMMAND); } HIDA_ReleaseStgMedium(pida, &medium); } #undef pqcm } } // Note that we always return S_OK from this function so that // default processing of menu items will occur ASSERT(hr == S_OK); break; case DFM_GETHELPTEXT: LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));; break; case DFM_GETHELPTEXTW: LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));; break; case DFM_MAPCOMMANDNAME: if (lstrcmpi((LPCTSTR)lParam, TEXT("eject")) == 0) *(int *)wParam = FSIDM_EJECT; else if (lstrcmpi((LPCTSTR)lParam, TEXT("format")) == 0) *(int *)wParam = FSIDM_FORMAT; else hr = E_FAIL; // command not found break; case DFM_INVOKECOMMAND: switch (wParam) { case DFM_CMD_PROPERTIES: // lParam contains the page name to open hr = SHLaunchPropSheet(DrivesPropertiesThreadProc, pdtobj, (LPCTSTR)lParam, NULL, NULL); break; case FSIDM_EJECT: case FSIDM_FORMAT: { STGMEDIUM medium; LPIDA pida = DataObj_GetHIDA(pdtobj, &medium); ASSERT(HIDA_GetCount(medium.hGlobal) == 1); LPIDDRIVE pidd = (LPIDDRIVE)IDA_GetIDListPtr(pida, 0); if (pidd) { UINT iDrive = DRIVEID(pidd->cName); ASSERT((int)iDrive >= 0); switch (wParam) { case FSIDM_FORMAT: SHFormatDriveAsync(hwnd, iDrive, SHFMT_ID_DEFAULT, 0); break; case FSIDM_EJECT: { CDBurn_OnEject(hwnd, iDrive); CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive); if (pMtPt) { pMtPt->Eject(hwnd); pMtPt->Release(); } break; } } } HIDA_ReleaseStgMedium(pida, &medium); break; } case FSIDM_DISCONNECT: if (pdtobj) { STGMEDIUM medium; LPIDA pida = DataObj_GetHIDA(pdtobj, &medium); if (pida) { DISCDLGSTRUCT discd = { sizeof(discd), // cbStructure hwnd, // hwndOwner NULL, // lpLocalName NULL, // lpRemoteName DISC_UPDATE_PROFILE // dwFlags }; for (UINT iidl = 0; iidl < pida->cidl; iidl++) { LPIDDRIVE pidd = (LPIDDRIVE)IDA_GetIDListPtr(pida, iidl); CMountPoint* pmtpt = CMountPoint::GetMountPoint(DRIVEID(pidd->cName)); if (pmtpt) { if (pmtpt->IsRemote()) { TCHAR szPath[4], szDrive[4]; BOOL fUnavailable = pmtpt->IsUnavailableNetDrive(); SHAnsiToTChar(pidd->cName, szPath, ARRAYSIZE(szPath)); SHAnsiToTChar(pidd->cName, szDrive, ARRAYSIZE(szDrive)); szDrive[2] = 0; // remove slash discd.lpLocalName = szDrive; if (SHWNetDisconnectDialog1(&discd) == WN_SUCCESS) { // If it is a unavailable drive we get no // file system notification and as such // the drive will not disappear, so lets // set up to do it ourself... if (fUnavailable) { CMountPoint::NotifyUnavailableNetDriveGone(szPath); // Do we need this if we have the above? SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATH, szPath, NULL); } } } pmtpt->Release(); } } // flush them altogether SHChangeNotifyHandleEvents(); HIDA_ReleaseStgMedium(pida, &medium); } } break; case FSIDM_CONNECT_PRN: SHNetConnectionDialog(hwnd, NULL, RESOURCETYPE_PRINT); break; case FSIDM_DISCONNECT_PRN: WNetDisconnectDialog(hwnd, RESOURCETYPE_PRINT); break; default: // This is one of view menu items, use the default code. hr = S_FALSE; break; } break; default: hr = E_NOTIMPL; break; } return hr; } void _DrvPrshtSetSpaceValues(DRIVEPROPSHEETPAGE *pdpsp) { LPITEMIDLIST pidl; TCHAR szFormat[30]; TCHAR szTemp[30]; TCHAR szBuffer[64]; // needs to be big enough to hold "99,999,999,999,999 bytes" + room for localization // reset the total/free values to start with pdpsp->qwTot = pdpsp->qwFree = 0; // lets try to ask the shellfolder for this information! HRESULT hr = SHILCreateFromPath(pdpsp->szDrive, &pidl, NULL); if (SUCCEEDED(hr)) { IShellFolder2 *psf2; LPCITEMIDLIST pidlLast; hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder2, &psf2), &pidlLast); if (SUCCEEDED(hr)) { ULONGLONG ullFree; hr = GetLongProperty(psf2, pidlLast, &SCID_FREESPACE, &ullFree); if (SUCCEEDED(hr)) { ULONGLONG ullTotal; hr = GetLongProperty(psf2, pidlLast, &SCID_CAPACITY, &ullTotal); if (SUCCEEDED(hr)) { pdpsp->qwTot = ullTotal; pdpsp->qwFree = ullFree; } } psf2->Release(); } ILFree(pidl); } // we want to use the IShellFolder stuff above so cdrom burning will be happy. However, the // above code fails for removable drives that have no media, so we need a fallback if (FAILED(hr)) { ULARGE_INTEGER qwFreeUser; ULARGE_INTEGER qwTotal; ULARGE_INTEGER qwTotalFree; if (SHGetDiskFreeSpaceEx(pdpsp->szDrive, &qwFreeUser, &qwTotal, &qwTotalFree)) { // Save away to use when drawing the pie pdpsp->qwTot = qwTotal.QuadPart; pdpsp->qwFree = qwFreeUser.QuadPart; } } LoadString(HINST_THISDLL, IDS_BYTES, szFormat, ARRAYSIZE(szFormat)); // NT must be able to display 64-bit numbers; at least as much // as is realistic. We've made the decision // that volumes up to 100 Terrabytes will display the byte value // and the short-format value. Volumes of greater size will display // "---" in the byte field and the short-format value. Note that the // short format is always displayed. const _int64 MaxDisplayNumber = 99999999999999; // 100TB - 1. if ((pdpsp->qwTot - pdpsp->qwFree) <= MaxDisplayNumber) { StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat, AddCommas64(pdpsp->qwTot - pdpsp->qwFree, szTemp, ARRAYSIZE(szTemp))); SetDlgItemText(pdpsp->hDlg, IDC_DRV_USEDBYTES, szBuffer); } if (pdpsp->qwFree <= MaxDisplayNumber) { StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat, AddCommas64(pdpsp->qwFree, szTemp, ARRAYSIZE(szTemp))); SetDlgItemText(pdpsp->hDlg, IDC_DRV_FREEBYTES, szBuffer); } if (pdpsp->qwTot <= MaxDisplayNumber) { StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat, AddCommas64(pdpsp->qwTot, szTemp, ARRAYSIZE(szTemp))); SetDlgItemText(pdpsp->hDlg, IDC_DRV_TOTBYTES, szBuffer); } ShortSizeFormat64(pdpsp->qwTot-pdpsp->qwFree, szBuffer, ARRAYSIZE(szBuffer)); SetDlgItemText(pdpsp->hDlg, IDC_DRV_USEDMB, szBuffer); ShortSizeFormat64(pdpsp->qwFree, szBuffer, ARRAYSIZE(szBuffer)); SetDlgItemText(pdpsp->hDlg, IDC_DRV_FREEMB, szBuffer); ShortSizeFormat64(pdpsp->qwTot, szBuffer, ARRAYSIZE(szBuffer)); SetDlgItemText(pdpsp->hDlg, IDC_DRV_TOTMB, szBuffer); } void _DrvPrshtGetPieShadowHeight(DRIVEPROPSHEETPAGE* pdpsp) { SIZE size; HDC hDC = GetDC(pdpsp->hDlg); // some bizzare black magic calculation for the pie size... GetTextExtentPoint(hDC, TEXT("W"), 1, &size); pdpsp->dwPieShadowHgt = size.cy * 2 / 3; ReleaseDC(pdpsp->hDlg, hDC); } void _DrvPrshtSetDriveIcon(DRIVEPROPSHEETPAGE* pdpsp, CMountPoint* pMtPt) { TCHAR szModule[MAX_PATH]; if (pMtPt) { UINT uIcon = pMtPt->GetIcon(szModule, ARRAYSIZE(szModule)); if (uIcon) { HIMAGELIST hIL = NULL; Shell_GetImageLists(&hIL, NULL); if (hIL) { int iIndex = Shell_GetCachedImageIndex(szModule[0] ? szModule : c_szShell32Dll, uIcon, 0); HICON hIcon = ImageList_ExtractIcon(g_hinst, hIL, iIndex); if (hIcon) { ReplaceDlgIcon(pdpsp->hDlg, IDC_DRV_ICON, hIcon); } } } } } void _DrvPrshtSetDriveAttributes(DRIVEPROPSHEETPAGE* pdpsp, CMountPoint* pMtPt) { if (pMtPt) { if (pMtPt->IsCompressible()) { // file-based compression is supported (must be NTFS) pdpsp->fIsCompressionAvailable = TRUE; if (pMtPt->IsCompressed()) { // the volume root is compressed pdpsp->asInitial.fCompress = TRUE; // if its compressed, compression better be available ASSERT(pdpsp->fIsCompressionAvailable); } } // // HACK (reinerf) - we dont have a FS_SUPPORTS_INDEXING so we // use the FILE_SUPPORTS_SPARSE_FILES flag, because native index support // appeared first on NTFS5 volumes, at the same time sparse file support // was implemented. // if (pMtPt->IsSupportingSparseFile()) { // yup, we are on NTFS 5 or greater pdpsp->fIsIndexAvailable = TRUE; if (pMtPt->IsContentIndexed()) { pdpsp->asInitial.fIndex = TRUE; } } } else { // if we don't have a mount point, we just leave everything alone } // Set the inital state of the compression / content index checkboxes if (!pdpsp->fIsCompressionAvailable) { // file-based compression is not supported DestroyWindow(GetDlgItem(pdpsp->hDlg, IDD_COMPRESS)); } else { CheckDlgButton(pdpsp->hDlg, IDD_COMPRESS, pdpsp->asInitial.fCompress); } if (!pdpsp->fIsIndexAvailable) { // content index is only supported on NTFS 5 volumes DestroyWindow(GetDlgItem(pdpsp->hDlg, IDD_INDEX)); } else { CheckDlgButton(pdpsp->hDlg, IDD_INDEX, pdpsp->asInitial.fIndex); } } void _DrvPrshtSetFileSystem(DRIVEPROPSHEETPAGE* pdpsp, CMountPoint* pMtPt) { TCHAR szFileSystem[64]; szFileSystem[0] = TEXT('\0'); if (pMtPt) { if (!pMtPt->GetFileSystemName(szFileSystem, ARRAYSIZE(szFileSystem)) || (*szFileSystem == TEXT('\0'))) { if ((pMtPt->IsStrictRemovable() || pMtPt->IsFloppy() || pMtPt->IsCDROM()) && !pMtPt->HasMedia()) { // if this drive has removable media and it is empty, then fall back to "Unknown" LoadString(HINST_THISDLL, IDS_FMT_MEDIA0, szFileSystem, ARRAYSIZE(szFileSystem)); } else { // for fixed drives, leave the text as "RAW" (set by default in dlg template) szFileSystem[0] = TEXT('\0'); } } } if (*szFileSystem) { SetDlgItemText(pdpsp->hDlg, IDC_DRV_FS, szFileSystem); } } void _DrvPrshtSetVolumeLabel(DRIVEPROPSHEETPAGE* pdpsp, CMountPoint* pMtPt) { TCHAR szLabel[MAX_LABEL_NTFS + 1]; UINT cchLabel = MAX_LABEL_FAT; // assume the drive is FAT HWND hwndLabel = GetDlgItem(pdpsp->hDlg, IDC_DRV_LABEL); BOOL bAllowRename = TRUE; HRESULT hr = E_FAIL; szLabel[0] = TEXT('\0'); if (pMtPt) { hr = pMtPt->GetLabelNoFancy(szLabel, ARRAYSIZE(szLabel)); if (pMtPt->IsRemote() || (pMtPt->IsCDROM() && !pMtPt->IsDVDRAMMedia())) { // ISSUE-2000/10/30-StephStm We probably want to distinguish between diff types of cdrom drives bAllowRename = FALSE; } if ( !bAllowRename && pMtPt->IsCDROM( ) ) { // // Check to see if it is CDFS, if not, make no assumptions about // writing the label. // WCHAR szFS[ 10 ]; // random - just more than "CDFS\0" BOOL b = pMtPt->GetFileSystemName( szFS, ARRAYSIZE(szFS) ); if (b && lstrcmpi(szFS, L"CDFS") != 0 ) { // Re-enable the label as we don't know if the FS doesn't support this // until we actually try it. bAllowRename = TRUE; } } if (pMtPt->IsNTFS()) { cchLabel = MAX_LABEL_NTFS; } } SetWindowText(hwndLabel, szLabel); if (FAILED(hr) || !bAllowRename) { Edit_SetReadOnly(hwndLabel, TRUE); } // limit the "Label" edit box based on the filesystem Edit_LimitText(hwndLabel, cchLabel); // make sure we don't recieve an EN_CHANGED message for the volume edit box // because we set it above Edit_SetModify(hwndLabel, FALSE); } void _DrvPrshtSetDriveType(DRIVEPROPSHEETPAGE* pdpsp, CMountPoint* pMtPt) { TCHAR szDriveType[80]; szDriveType[0] = TEXT('\0'); if (pMtPt) { if (pMtPt->IsUnavailableNetDrive()) { LoadString(HINST_THISDLL, IDS_DRIVES_NETUNAVAIL, szDriveType, ARRAYSIZE(szDriveType)); } else { pMtPt->GetTypeString(szDriveType, ARRAYSIZE(szDriveType)); } } SetDlgItemText(pdpsp->hDlg, IDC_DRV_TYPE, szDriveType); } void _DrvPrshtSetDriveLetter(DRIVEPROPSHEETPAGE* pdpsp) { TCHAR szDriveLetterText[80]; TCHAR szFormat[80]; if (pdpsp->fMountedDrive) { TCHAR szLabel[MAX_LABEL_NTFS + 1]; if (GetDlgItemText(pdpsp->hDlg, IDC_DRV_LABEL, szLabel, ARRAYSIZE(szLabel))) { LoadString(HINST_THISDLL, IDS_VOLUMELABEL, szFormat, ARRAYSIZE(szFormat)); StringCchPrintf(szDriveLetterText, ARRAYSIZE(szDriveLetterText), szFormat, szLabel); SetDlgItemText(pdpsp->hDlg, IDC_DRV_LETTER, szDriveLetterText); } } else { LoadString(HINST_THISDLL, IDS_DRIVELETTER, szFormat, ARRAYSIZE(szFormat)); StringCchPrintf(szDriveLetterText, ARRAYSIZE(szDriveLetterText), szFormat, pdpsp->iDrive + TEXT('A')); SetDlgItemText(pdpsp->hDlg, IDC_DRV_LETTER, szDriveLetterText); } } void _DrvPrshtSetDiskCleanup(DRIVEPROPSHEETPAGE* pdpsp) { // if we have a cleanup path in the registry, turn on the Disk Cleanup button on // NOTE: disk cleanup and mounted volumes don't get along to well, so disable it for now. WCHAR szPath[MAX_PATH] = L""; if (!pdpsp->fMountedDrive && GetDiskCleanupPath(szPath, ARRAYSIZE(szPath)) && IsBitBucketableDrive(pdpsp->iDrive)) { ShowWindow(GetDlgItem(pdpsp->hDlg, IDC_DRV_CLEANUP), SW_SHOW); EnableWindow(GetDlgItem(pdpsp->hDlg, IDC_DRV_CLEANUP), TRUE); } else { ShowWindow(GetDlgItem(pdpsp->hDlg, IDC_DRV_CLEANUP), SW_HIDE); EnableWindow(GetDlgItem(pdpsp->hDlg, IDC_DRV_CLEANUP), FALSE); } } void _DrvPrshtInit(DRIVEPROPSHEETPAGE* pdpsp) { HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); // get the MountPoint object for this drive CMountPoint* pMtPt = CMountPoint::GetMountPoint(pdpsp->szDrive); if ( !pMtPt ) { pMtPt = CMountPoint::GetSimulatedMountPointFromVolumeGuid( pdpsp->szDrive ); } _DrvPrshtGetPieShadowHeight(pdpsp); _DrvPrshtSetDriveIcon(pdpsp, pMtPt); _DrvPrshtSetDriveAttributes(pdpsp, pMtPt); _DrvPrshtSetFileSystem(pdpsp, pMtPt); _DrvPrshtSetVolumeLabel(pdpsp, pMtPt); _DrvPrshtSetDriveType(pdpsp, pMtPt); _DrvPrshtSetSpaceValues(pdpsp); _DrvPrshtSetDriveLetter(pdpsp); _DrvPrshtSetDiskCleanup(pdpsp); SetCursor(hcurOld); if (pMtPt) { pMtPt->Release(); } } void _DrvPrshtUpdateInfo(DRIVEPROPSHEETPAGE* pdpsp) { CMountPoint* pMtPt = CMountPoint::GetMountPoint(pdpsp->szDrive); _DrvPrshtSetSpaceValues(pdpsp); _DrvPrshtSetDriveType(pdpsp, pMtPt); if (pMtPt) { pMtPt->Release(); } } const COLORREF c_crPieColors[] = { RGB( 0, 0, 255), // Blue RGB(255, 0, 255), // Red-Blue RGB( 0, 0, 128), // 1/2 Blue RGB(128, 0, 128), // 1/2 Red-Blue }; STDAPI Draw3dPie(HDC hdc, RECT *prc, DWORD dwPer1000, const COLORREF *lpColors); void DrawColorRect(HDC hdc, COLORREF crDraw, const RECT *prc) { HBRUSH hbDraw = CreateSolidBrush(crDraw); if (hbDraw) { HBRUSH hbOld = (HBRUSH)SelectObject(hdc, hbDraw); if (hbOld) { PatBlt(hdc, prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top, PATCOPY); SelectObject(hdc, hbOld); } DeleteObject(hbDraw); } } void _DrvPrshtDrawItem(DRIVEPROPSHEETPAGE *pdpsp, const DRAWITEMSTRUCT * lpdi) { switch (lpdi->CtlID) { case IDC_DRV_PIE: { DWORD dwPctX10 = pdpsp->qwTot ? (DWORD)((__int64)1000 * (pdpsp->qwTot - pdpsp->qwFree) / pdpsp->qwTot) : 1000; #if 1 DrawPie(lpdi->hDC, &lpdi->rcItem, dwPctX10, pdpsp->qwFree==0 || pdpsp->qwFree==pdpsp->qwTot, pdpsp->dwPieShadowHgt, c_crPieColors); #else { RECT rcTemp = lpdi->rcItem; Draw3dPie(lpdi->hDC, &rcTemp, dwPctX10, c_crPieColors); } #endif } break; case IDC_DRV_USEDCOLOR: DrawColorRect(lpdi->hDC, c_crPieColors[DP_USEDCOLOR], &lpdi->rcItem); break; case IDC_DRV_FREECOLOR: DrawColorRect(lpdi->hDC, c_crPieColors[DP_FREECOLOR], &lpdi->rcItem); break; default: break; } } BOOL_PTR CALLBACK DriveAttribsDlgProc(HWND hDlgRecurse, UINT uMessage, WPARAM wParam, LPARAM lParam) { DRIVEPROPSHEETPAGE* pdpsp = (DRIVEPROPSHEETPAGE *)GetWindowLongPtr(hDlgRecurse, DWLP_USER); switch (uMessage) { case WM_INITDIALOG: { TCHAR szTemp[MAX_PATH]; TCHAR szAttribsToApply[MAX_PATH]; TCHAR szDriveText[MAX_PATH]; TCHAR szFormatString[MAX_PATH]; TCHAR szDlgText[MAX_PATH]; int iLength; SetWindowLongPtr(hDlgRecurse, DWLP_USER, lParam); pdpsp = (DRIVEPROPSHEETPAGE *)lParam; // set the initial state of the radio button CheckDlgButton(hDlgRecurse, IDD_RECURSIVE, TRUE); szAttribsToApply[0] = 0; // set the IDD_ATTRIBSTOAPPLY based on what attribs we are applying if (pdpsp->asInitial.fIndex != pdpsp->asCurrent.fIndex) { if (pdpsp->asCurrent.fIndex) { LoadString(HINST_THISDLL, IDS_INDEX, szTemp, ARRAYSIZE(szTemp)); } else { LoadString(HINST_THISDLL, IDS_DISABLEINDEX, szTemp, ARRAYSIZE(szTemp)); } // UI only - don't care if it gets truncated StringCchCat(szAttribsToApply, ARRAYSIZE(szAttribsToApply), szTemp); } if (pdpsp->asInitial.fCompress != pdpsp->asCurrent.fCompress) { if (pdpsp->asCurrent.fCompress) { LoadString(HINST_THISDLL, IDS_COMPRESS, szTemp, ARRAYSIZE(szTemp)); } else { LoadString(HINST_THISDLL, IDS_UNCOMPRESS, szTemp, ARRAYSIZE(szTemp)); } // UI only - don't care if it gets truncated StringCchCat(szAttribsToApply, ARRAYSIZE(szAttribsToApply), szTemp); } // remove the trailing ", " iLength = lstrlen(szAttribsToApply); ASSERT(iLength >= 3); szAttribsToApply[iLength - 2] = 0; SetDlgItemText(hDlgRecurse, IDD_ATTRIBSTOAPPLY, szAttribsToApply); // this dialog was only designed for nice short paths like "c:\" not "\\?\Volume{GUID}\" paths if (lstrlen(pdpsp->szDrive) > 3) { // get the default string LoadString(HINST_THISDLL, IDS_THISVOLUME, szDriveText, ARRAYSIZE(szDriveText)); } else { // Create the string "C:\" StringCchCopy(szDriveText, ARRAYSIZE(szDriveText), pdpsp->szDrive); PathAddBackslash(szDriveText); // sanity check; this better be a drive root! ASSERT(PathIsRoot(szDriveText)); } // set the IDD_RECURSIVE_TXT text to have "C:\" GetDlgItemText(hDlgRecurse, IDD_RECURSIVE_TXT, szFormatString, ARRAYSIZE(szFormatString)); StringCchPrintf(szDlgText, ARRAYSIZE(szDlgText), szFormatString, szDriveText); SetDlgItemText(hDlgRecurse, IDD_RECURSIVE_TXT, szDlgText); // set the IDD_NOTRECURSIVE raido button text to have "C:\" GetDlgItemText(hDlgRecurse, IDD_NOTRECURSIVE, szFormatString, ARRAYSIZE(szFormatString)); StringCchPrintf(szDlgText, ARRAYSIZE(szDlgText), szFormatString, szDriveText); SetDlgItemText(hDlgRecurse, IDD_NOTRECURSIVE, szDlgText); // set the IDD_RECURSIVE raido button text to have "C:\" GetDlgItemText(hDlgRecurse, IDD_RECURSIVE, szFormatString, ARRAYSIZE(szFormatString)); StringCchPrintf(szDlgText, ARRAYSIZE(szDlgText), szFormatString, szDriveText); SetDlgItemText(hDlgRecurse, IDD_RECURSIVE, szDlgText); } break; case WM_COMMAND: { UINT uID = GET_WM_COMMAND_ID(wParam, lParam); switch (uID) { case IDOK: pdpsp->fRecursive = (IsDlgButtonChecked(hDlgRecurse, IDD_RECURSIVE) == BST_CHECKED); // fall through case IDCANCEL: EndDialog(hDlgRecurse, (uID == IDCANCEL) ? FALSE : TRUE); break; } } default: return FALSE; } return TRUE; } BOOL _DrvPrshtApply(DRIVEPROPSHEETPAGE* pdpsp) { BOOL bFctRet; HWND hCtl; // take care of compression / content indexing first pdpsp->asCurrent.fCompress = (IsDlgButtonChecked(pdpsp->hDlg, IDD_COMPRESS) == BST_CHECKED); pdpsp->asCurrent.fIndex = (IsDlgButtonChecked(pdpsp->hDlg, IDD_INDEX) == BST_CHECKED); pdpsp->asCurrent.fRecordingEnabled = (IsDlgButtonChecked(pdpsp->hDlg, IDC_RECORD_ENABLE) == BST_CHECKED); // check to see if something has changed before applying attribs if (memcmp(&pdpsp->asInitial, &pdpsp->asCurrent, sizeof(pdpsp->asInitial)) != 0) { // the user toggled the attributes, so ask them if they want to recurse BOOL_PTR bRet = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_ATTRIBS_RECURSIVE), pdpsp->hDlg, DriveAttribsDlgProc, (LPARAM)pdpsp); if (bRet) { FILEPROPSHEETPAGE fpsp = {0}; fpsp.pfci = Create_FolderContentsInfo(); if (fpsp.pfci) { // we cook up a fpsp and call ApplySingleFileAttributes instead of // rewriting the apply attributes code if (pdpsp->fMountedDrive) { GetVolumeNameForVolumeMountPoint(pdpsp->szDrive, fpsp.szPath, ARRAYSIZE(fpsp.szPath)); } else { StringCchCopy(fpsp.szPath, ARRAYSIZE(fpsp.szPath), pdpsp->szDrive); } fpsp.hDlg = pdpsp->hDlg; fpsp.asInitial = pdpsp->asInitial; fpsp.asCurrent = pdpsp->asCurrent; fpsp.pfci->fIsCompressionAvailable = pdpsp->fIsCompressionAvailable; fpsp.pfci->ulTotalNumberOfBytes.QuadPart = pdpsp->qwTot - pdpsp->qwFree; // for progress calculations fpsp.fIsIndexAvailable = pdpsp->fIsIndexAvailable; fpsp.fRecursive = pdpsp->fRecursive; fpsp.fIsDirectory = TRUE; bRet = ApplySingleFileAttributes(&fpsp); Release_FolderContentsInfo(fpsp.pfci); fpsp.pfci = NULL; // update the free/used space after applying attribs because something could // have changed (eg compression frees up space) _DrvPrshtUpdateInfo(pdpsp); // update the initial attributes to reflect the ones we just applied, regardless // if the operation was sucessful or not. If they hit cancel, then the volume // root was most likely still changed so we need to update. pdpsp->asInitial = pdpsp->asCurrent; } else { bRet = FALSE; } } if (!bRet) { // the user hit cancel somewhere return FALSE; } } hCtl = GetDlgItem(pdpsp->hDlg, IDC_DRV_LABEL); bFctRet = TRUE; if (Edit_GetModify(hCtl)) { bFctRet = FALSE; // assume we fail to set the label TCHAR szLabel[MAX_LABEL_NTFS + 1]; GetWindowText(hCtl, szLabel, ARRAYSIZE(szLabel)); CMountPoint* pMtPt = CMountPoint::GetMountPoint(pdpsp->szDrive); if ( !pMtPt ) { pMtPt = CMountPoint::GetSimulatedMountPointFromVolumeGuid( pdpsp->szDrive ); } if (pMtPt) { if (SUCCEEDED(pMtPt->SetLabel(GetParent(pdpsp->hDlg), szLabel))) bFctRet = TRUE; pMtPt->Release(); } } return bFctRet; } const static DWORD aDrvPrshtHelpIDs[] = { // Context Help IDs IDC_DRV_ICON, IDH_FCAB_DRV_ICON, IDC_DRV_LABEL, IDH_FCAB_DRV_LABEL, IDC_DRV_TYPE_TXT, IDH_FCAB_DRV_TYPE, IDC_DRV_TYPE, IDH_FCAB_DRV_TYPE, IDC_DRV_FS_TXT, IDH_FCAB_DRV_FS, IDC_DRV_FS, IDH_FCAB_DRV_FS, IDC_DRV_USEDCOLOR, IDH_FCAB_DRV_USEDCOLORS, IDC_DRV_USEDBYTES_TXT, IDH_FCAB_DRV_USEDCOLORS, IDC_DRV_USEDBYTES, IDH_FCAB_DRV_USEDCOLORS, IDC_DRV_USEDMB, IDH_FCAB_DRV_USEDCOLORS, IDC_DRV_FREECOLOR, IDH_FCAB_DRV_USEDCOLORS, IDC_DRV_FREEBYTES_TXT, IDH_FCAB_DRV_USEDCOLORS, IDC_DRV_FREEBYTES, IDH_FCAB_DRV_USEDCOLORS, IDC_DRV_FREEMB, IDH_FCAB_DRV_USEDCOLORS, IDC_DRV_TOTSEP, NO_HELP, IDC_DRV_TOTBYTES_TXT, IDH_FCAB_DRV_TOTSEP, IDC_DRV_TOTBYTES, IDH_FCAB_DRV_TOTSEP, IDC_DRV_TOTMB, IDH_FCAB_DRV_TOTSEP, IDC_DRV_PIE, IDH_FCAB_DRV_PIE, IDC_DRV_LETTER, IDH_FCAB_DRV_LETTER, IDC_DRV_CLEANUP, IDH_FCAB_DRV_CLEANUP, IDD_COMPRESS, IDH_FCAB_DRV_COMPRESS, IDD_INDEX, IDH_FCAB_DRV_INDEX, 0, 0 }; // // Descriptions: // This is the dialog procedure for the "general" page of a property sheet. // BOOL_PTR CALLBACK _DrvGeneralDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) { DRIVEPROPSHEETPAGE * pdpsp = (DRIVEPROPSHEETPAGE *)GetWindowLongPtr(hDlg, DWLP_USER); switch (uMessage) { case WM_INITDIALOG: // REVIEW, we should store more state info here, for example // the hIcon being displayed and the FILEINFO pointer, not just // the file name ptr SetWindowLongPtr(hDlg, DWLP_USER, lParam); pdpsp = (DRIVEPROPSHEETPAGE *)lParam; pdpsp->hDlg = hDlg; _DrvPrshtInit(pdpsp); break; case WM_DESTROY: ReplaceDlgIcon(hDlg, IDC_DRV_ICON, NULL); // free the icon break; case WM_ACTIVATE: if (GET_WM_ACTIVATE_STATE(wParam, lParam) != WA_INACTIVE && pdpsp) _DrvPrshtUpdateInfo(pdpsp); return FALSE; // Let DefDlgProc know we did not handle this case WM_DRAWITEM: _DrvPrshtDrawItem(pdpsp, (DRAWITEMSTRUCT *)lParam); break; case WM_HELP: WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aDrvPrshtHelpIDs); break; case WM_CONTEXTMENU: WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(void *)aDrvPrshtHelpIDs); break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_DRV_LABEL: if (GET_WM_COMMAND_CMD(wParam, lParam) != EN_CHANGE) break; // else, fall through case IDD_COMPRESS: case IDD_INDEX: SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0); break; // handle disk cleanup button case IDC_DRV_CLEANUP: LaunchDiskCleanup(hDlg, pdpsp->iDrive, DISKCLEANUP_NOFLAG); break; default: return TRUE; } break; case WM_NOTIFY: switch (((NMHDR *)lParam)->code) { case PSN_SETACTIVE: break; case PSN_APPLY: if (!_DrvPrshtApply(pdpsp)) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); } break; default: return FALSE; } break; default: return FALSE; } return TRUE; } void _DiskToolsPrshtInit(DRIVEPROPSHEETPAGE * pdpsp) { TCHAR szFmt[MAX_PATH + 20]; DWORD cbLen = sizeof(szFmt); BOOL bFoundBackup = SUCCEEDED(SKGetValue(SHELLKEY_HKLM_EXPLORER, REL_KEY_BACKUP, NULL, NULL, szFmt, &cbLen)); // If no backup utility is installed, then remove everything in the backup groupbox if (!bFoundBackup) { DestroyWindow(GetDlgItem(pdpsp->hDlg, IDC_DISKTOOLS_BKPNOW)); DestroyWindow(GetDlgItem(pdpsp->hDlg, IDC_DISKTOOLS_BKPICON)); DestroyWindow(GetDlgItem(pdpsp->hDlg, IDC_DISKTOOLS_BKPDAYS)); DestroyWindow(GetDlgItem(pdpsp->hDlg, IDC_DISKTOOLS_BKPTXT)); } cbLen = sizeof(szFmt); BOOL bFoundFmt = SUCCEEDED(SKGetValue(SHELLKEY_HKLM_EXPLORER, REL_KEY_DEFRAG, NULL, NULL, szFmt, &cbLen)) && szFmt[0]; // If no defrag utility is installed, replace the default defrag text with // the "No defrag installed" message. Also grey out the "defrag now" button. if (!bFoundFmt) { TCHAR szMessage[50]; // WARNING: IDS_DRIVES_NOOPTINSTALLED is currently 47 // characters long. Resize this buffer if // the string resource is lengthened. LoadString(HINST_THISDLL, IDS_DRIVES_NOOPTINSTALLED, szMessage, ARRAYSIZE(szMessage)); SetDlgItemText(pdpsp->hDlg, IDC_DISKTOOLS_OPTDAYS, szMessage); Button_Enable(GetDlgItem(pdpsp->hDlg, IDC_DISKTOOLS_OPTNOW), FALSE); } } const static DWORD aDiskToolsHelpIDs[] = { // Context Help IDs IDC_DISKTOOLS_TRLIGHT, IDH_FCAB_DISKTOOLS_CHKNOW, IDC_DISKTOOLS_CHKDAYS, IDH_FCAB_DISKTOOLS_CHKNOW, IDC_DISKTOOLS_CHKNOW, IDH_FCAB_DISKTOOLS_CHKNOW, IDC_DISKTOOLS_BKPTXT, IDH_FCAB_DISKTOOLS_BKPNOW, IDC_DISKTOOLS_BKPDAYS, IDH_FCAB_DISKTOOLS_BKPNOW, IDC_DISKTOOLS_BKPNOW, IDH_FCAB_DISKTOOLS_BKPNOW, IDC_DISKTOOLS_OPTDAYS, IDH_FCAB_DISKTOOLS_OPTNOW, IDC_DISKTOOLS_OPTNOW, IDH_FCAB_DISKTOOLS_OPTNOW, 0, 0 }; BOOL _DiskToolsCommand(DRIVEPROPSHEETPAGE * pdpsp, WPARAM wParam, LPARAM lParam) { // Add 20 for extra formatting TCHAR szFmt[MAX_PATH + 20]; TCHAR szCmd[MAX_PATH + 20]; LPCTSTR pszRegName, pszDefFmt; int nErrMsg = 0; switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_DISKTOOLS_CHKNOW: SHChkDskDriveEx(pdpsp->hDlg, pdpsp->szDrive); return FALSE; case IDC_DISKTOOLS_OPTNOW: pszRegName = REL_KEY_DEFRAG; if (pdpsp->fMountedDrive) { pszDefFmt = TEXT("defrag.exe"); } else { pszDefFmt = TEXT("defrag.exe %c:"); } nErrMsg = IDS_NO_OPTIMISE_APP; break; case IDC_DISKTOOLS_BKPNOW: pszRegName = REL_KEY_BACKUP; pszDefFmt = TEXT("ntbackup.exe"); nErrMsg = IDS_NO_BACKUP_APP; break; default: return FALSE; } DWORD cbLen = sizeof(szFmt); if (FAILED(SKGetValue(SHELLKEY_HKLM_EXPLORER, pszRegName, NULL, NULL, szFmt, &cbLen))) { // failed to read out the reg value, just use the default StringCchCopy(szFmt, ARRAYSIZE(szFmt), pszDefFmt); } // some apps write REG_SZ keys to the registry even though they have env variables in them ExpandEnvironmentStrings(szFmt, szCmd, ARRAYSIZE(szCmd)); StringCchCopy(szFmt, ARRAYSIZE(szFmt), szCmd); // Plug in the drive letter in case they want it StringCchPrintf(szCmd, ARRAYSIZE(szCmd), szFmt, pdpsp->iDrive + TEXT('A')); if (!ShellExecCmdLine(pdpsp->hDlg, szCmd, NULL, SW_SHOWNORMAL, NULL, SECL_USEFULLPATHDIR | SECL_NO_UI)) { // Something went wrong - app's probably not installed. if (nErrMsg) { ShellMessageBox(HINST_THISDLL, pdpsp->hDlg, MAKEINTRESOURCE(nErrMsg), NULL, MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND); } return FALSE; } return TRUE; } // // Descriptions: // This is the dialog procedure for the "Tools" page of a property sheet. // BOOL_PTR CALLBACK _DiskToolsDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) { DRIVEPROPSHEETPAGE * pdpsp = (DRIVEPROPSHEETPAGE *)GetWindowLongPtr(hDlg, DWLP_USER); switch (uMessage) { case WM_INITDIALOG: // REVIEW, we should store more state info here, for example // the hIcon being displayed and the FILEINFO pointer, not just // the file name ptr SetWindowLongPtr(hDlg, DWLP_USER, lParam); pdpsp = (DRIVEPROPSHEETPAGE *)lParam; pdpsp->hDlg = hDlg; _DiskToolsPrshtInit(pdpsp); break; case WM_ACTIVATE: if (GET_WM_ACTIVATE_STATE(wParam, lParam) != WA_INACTIVE && pdpsp) { _DiskToolsPrshtInit(pdpsp); } return FALSE; // Let DefDlgProc know we did not handle this case WM_HELP: WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aDiskToolsHelpIDs); break; case WM_CONTEXTMENU: WinHelp((HWND)wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(void *)aDiskToolsHelpIDs); break; case WM_COMMAND: return _DiskToolsCommand(pdpsp, wParam, lParam); case WM_NOTIFY: switch (((NMHDR *)lParam)->code) { case PSN_SETACTIVE: break; case PSN_APPLY: return TRUE; default: return FALSE; } break; default: return FALSE; } return TRUE; } // // This is the dialog procedure for the "Hardware" page. // const GUID c_rgguidDevMgr[] = { { 0x4d36e967, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } }, // GUID_DEVCLASS_DISKDRIVE { 0x4d36e980, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } }, // GUID_DEVCLASS_FLOPPYDISK { 0x4d36e965, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } }, // GUID_DEVCLASS_CDROM }; BOOL_PTR CALLBACK _DriveHWDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) { switch (uMessage) { case WM_INITDIALOG: { DRIVEPROPSHEETPAGE * pdpsp = (DRIVEPROPSHEETPAGE *)lParam; HWND hwndHW = DeviceCreateHardwarePageEx(hDlg, c_rgguidDevMgr, ARRAYSIZE(c_rgguidDevMgr), HWTAB_LARGELIST); if (hwndHW) { TCHAR szBuf[MAX_PATH]; LoadString(HINST_THISDLL, IDS_DRIVETSHOOT, szBuf, ARRAYSIZE(szBuf)); SetWindowText(hwndHW, szBuf); LoadString(HINST_THISDLL, IDS_THESEDRIVES, szBuf, ARRAYSIZE(szBuf)); SetDlgItemText(hwndHW, IDC_HWTAB_LVSTATIC, szBuf); } else { DestroyWindow(hDlg); // catastrophic failure } } return FALSE; } return FALSE; } BOOL CDrives_AddPage(LPPROPSHEETPAGE ppsp, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) { BOOL fSuccess; HPROPSHEETPAGE hpage = CreatePropertySheetPage(ppsp); if (hpage) { fSuccess = pfnAddPage(hpage, lParam); if (!fSuccess) { // Couldn't add page DestroyPropertySheetPage(hpage); fSuccess = FALSE; } } else { // Couldn't create page fSuccess = FALSE; } return fSuccess; } HRESULT CDrives_AddPagesHelper(DRIVEPROPSHEETPAGE* pdpsp, int iType, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) { if ((iType == DRIVE_NO_ROOT_DIR) || (iType == DRIVE_REMOTE)) { return S_OK; } CMountPoint* pMtPt = CMountPoint::GetMountPoint(pdpsp->szDrive); if (pMtPt) { if (IsShellServiceRunning()) { if (pMtPt->IsStrictRemovable() || pMtPt->IsCDROM() || (pMtPt->IsFixedDisk() && pMtPt->IsRemovableDevice())) { CAutoPlayDlg* papdlg = new CAutoPlayDlg(); if (papdlg) { // Autoplay pdpsp->psp.pszTemplate = MAKEINTRESOURCE(DLG_AUTOPLAY); pdpsp->psp.pfnDlgProc = CAutoPlayDlg::BaseDlgWndProc; pdpsp->psp.pfnCallback = CBaseDlg::BaseDlgPropSheetCallback; pdpsp->psp.dwFlags = PSP_DEFAULT | PSP_USECALLBACK; papdlg->Init(pdpsp->szDrive, iType); // for now pdpsp->psp.lParam = (LPARAM)(CBaseDlg*)papdlg; if (CDrives_AddPage(&pdpsp->psp, pfnAddPage, lParam)) { papdlg->AddRef(); } pdpsp->psp.lParam = NULL; pdpsp->psp.pfnCallback = NULL; pdpsp->psp.dwFlags = NULL; papdlg->Release(); } } } if ((iType != DRIVE_CDROM) || pMtPt->IsDVDRAMMedia()) { // we add the tools page for non-cdrom and DVD-RAM disks pdpsp->psp.pszTemplate = MAKEINTRESOURCE(DLG_DISKTOOLS); pdpsp->psp.pfnDlgProc = _DiskToolsDlgProc; CDrives_AddPage(&pdpsp->psp, pfnAddPage, lParam); } pMtPt->Release(); } if (!SHRestricted(REST_NOHARDWARETAB)) { pdpsp->psp.pszTemplate = MAKEINTRESOURCE(DLG_DRV_HWTAB); pdpsp->psp.pfnDlgProc = _DriveHWDlgProc; CDrives_AddPage(&pdpsp->psp, pfnAddPage, lParam); } return S_OK; } // // We check if any of the IDList's points to a drive root. If so, we use the // drives property page. // Note that drives should not be mixed with folders and files, even in a // search window. // STDAPI CDrives_AddPages(IDataObject *pdtobj, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) { STGMEDIUM medium; FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; if (SUCCEEDED(pdtobj->GetData(&fmte, &medium))) { TCHAR szPath[MAX_PATH]; int i, cItems = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0); for (i = 0; DragQueryFile((HDROP)medium.hGlobal, i, szPath, ARRAYSIZE(szPath)); i++) { DRIVEPROPSHEETPAGE dpsp = {0}; TCHAR szTitle[80]; if (lstrlen(szPath) > 3) continue; // can't be a drive letter dpsp.psp.dwSize = sizeof(dpsp); // extra data dpsp.psp.dwFlags = PSP_DEFAULT; dpsp.psp.hInstance = HINST_THISDLL; dpsp.psp.pszTemplate = MAKEINTRESOURCE(DLG_DRV_GENERAL); dpsp.psp.pfnDlgProc = _DrvGeneralDlgProc, StringCchCopy(dpsp.szDrive, ARRAYSIZE(dpsp.szDrive), szPath); dpsp.iDrive = DRIVEID(szPath); // if more than one drive selected give each tab the title of the drive // otherwise use "General" if (cItems > 1) { CMountPoint* pMtPt = CMountPoint::GetMountPoint(dpsp.iDrive); if (pMtPt) { dpsp.psp.dwFlags = PSP_USETITLE; dpsp.psp.pszTitle = szTitle; pMtPt->GetDisplayName(szTitle, ARRAYSIZE(szTitle)); pMtPt->Release(); } } if (!CDrives_AddPage(&dpsp.psp, pfnAddPage, lParam)) break; // if only one property page added add the disk tools // and Hardware tab too... if (cItems == 1) { CDrives_AddPagesHelper(&dpsp, RealDriveType(dpsp.iDrive, FALSE /* fOKToHitNet */), pfnAddPage, lParam); } } ReleaseStgMedium(&medium); } else { // try mounteddrive fmte.cfFormat = g_cfMountedVolume; // Can we retrieve the MountedVolume format? if (SUCCEEDED(pdtobj->GetData(&fmte, &medium))) { // Yes DRIVEPROPSHEETPAGE dpsp = {0}; HPROPSHEETPAGE hpage; TCHAR szMountPoint[MAX_PATH]; dpsp.psp.dwSize = sizeof(dpsp); // extra data dpsp.psp.dwFlags = PSP_DEFAULT; dpsp.psp.hInstance = HINST_THISDLL; dpsp.psp.pszTemplate = MAKEINTRESOURCE(DLG_DRV_GENERAL); dpsp.psp.pfnDlgProc = _DrvGeneralDlgProc, dpsp.iDrive = -1; dpsp.fMountedDrive = TRUE; DragQueryFile((HDROP)medium.hGlobal, 0, szMountPoint, ARRAYSIZE(szMountPoint)); StringCchCopy(dpsp.szDrive, ARRAYSIZE(dpsp.szDrive), szMountPoint); hpage = CreatePropertySheetPage(&dpsp.psp); if (hpage) { if (!pfnAddPage(hpage, lParam)) { DestroyPropertySheetPage(hpage); } } // Disk tools page CMountPoint* pMtPt = CMountPoint::GetMountPoint(szMountPoint); if (pMtPt) { CDrives_AddPagesHelper(&dpsp, GetDriveType(szMountPoint), pfnAddPage, lParam); pMtPt->Release(); } ReleaseStgMedium(&medium); } } return S_OK; }