#include "shellprv.h" #pragma hdrstop #include "shitemid.h" #include "ids.h" #include "oemhard.h" //for IsNEC_9800 #ifdef WINNT #include #else #define Not_VxD #include // DeviceIOCtl calls #endif #include "mtptl.h" TCHAR const c_szAudioCDShell[] = TEXT("AudioCD\\shell"); TCHAR const c_szDVDShell[] = TEXT("DVD\\shell"); #pragma pack(1) // from dos\inc\ioctl.inc typedef struct { TCHAR dmiAllocationLength; // db ? ; length of the buffer provided by caller TCHAR dmiInfoLength; // db ? ; length of information returned TCHAR dmiFlags; // db ? ; DRIVE_MAP_INFO flags TCHAR dmiInt13Unit; // db ? ; int 13 drive number. FFh if the drive // ; does not map to an int 13 drive DWORD dmiAssociatedDriveMap; // dd ? ; bit map of logical drive numbers that // ; are associated with the given drive // ; (i.e. parent/child volumes of compressed // ; volume files) DWORD dmiPartitionStartRBA[2]; // dq ? ; starting RBA offset of the given // ; partition } DRIVE_MAP_INFO; #pragma pack() #define PROT_MODE_EJECT 0x08 // ; indicates a protect mode drive // ; supports electronic eject // Public methods // Label HRESULT CMtPtLocal::SetLabel(LPCTSTR pszLabel) { HRESULT hres = E_FAIL; TraceMsg(TF_MOUNTPOINT, "CMtPtLocal::SetLabel: for '%s'", _GetName()); if (SetVolumeLabel(_GetNameForFctCall(), pszLabel)) { TraceMsg(TF_MOUNTPOINT, " 'SetVolumeLabel' succeeded"); hres = CMountPoint::SetLabel(pszLabel); } else { DWORD dwErr; dwErr = GetLastError(); #ifdef WINNT switch (dwErr) { case NOERROR: break; case ERROR_ACCESS_DENIED: hres = S_FALSE; // don't have permission, shouldn't put them back into editing mode ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE( IDS_ACCESSDENIED ), MAKEINTRESOURCE( IDS_TITLE_VOLUMELABELBAD ), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND); break; case ERROR_WRITE_PROTECT: hres = S_FALSE; // can't write, shouldn't put them back into editing mode ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE( IDS_WRITEPROTECTED ), MAKEINTRESOURCE( IDS_TITLE_VOLUMELABELBAD ), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND); break; case ERROR_LABEL_TOO_LONG: ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE( IDS_ERR_VOLUMELABELBAD ), MAKEINTRESOURCE( IDS_TITLE_VOLUMELABELBAD ), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND); break; default: ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE( IDS_BADLABEL ), MAKEINTRESOURCE( IDS_TITLE_VOLUMELABELBAD ), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND); break; } #else ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE( IDS_ERR_VOLUMELABELBAD ), MAKEINTRESOURCE( IDS_TITLE_VOLUMELABELBAD ), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND); #endif TraceMsg(TF_MOUNTPOINT, " 'SetVolumeLabel' failed"); } return hres; } HRESULT CMtPtLocal::SetDriveLabel(LPCTSTR pszLabel) { HRESULT hres = E_FAIL; if (DRIVE_REMOVABLE == _uDriveType) { // we rename the drive not the media TCHAR szSubKey[MAX_PATH]; wnsprintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons\\%c\\DefaultLabel"), _GetNameFirstChar()); hres = RegSetValueString(HKEY_LOCAL_MACHINE, szSubKey, NULL, pszLabel) ? S_OK : E_FAIL; if (SUCCEEDED(hres)) { CMountPoint::InvalidateMountPoint(_GetName(), NULL, MTPT_INV_LABEL); SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_PATH, _GetName(), _GetName()); } } else { hres = SetLabel(pszLabel); } return hres; } HRESULT CMtPtLocal::GetLabel(LPTSTR pszLabel, DWORD cchLabel, DWORD dwFlags) { HRESULT hres = S_OK; switch(_uDriveType) { case DRIVE_REMOVABLE: { // Do we want fancy name? if (MTPT_LABEL_NOFANCY != dwFlags) { // Yes if (_HasDefaultLabel()) { hres = (_GetDefaultLabel(pszLabel, cchLabel) ? S_OK : E_FAIL); } else { UINT ids = IDS_UNK_FLOPPY_DRIVE; switch (_bFloppyType) { case DEVPB_DEVTYP_525_0360: case DEVPB_DEVTYP_525_1200: ids = _ShowUglyDriveNames() ? IDS_525_FLOPPY_DRIVE_UGLY : IDS_525_FLOPPY_DRIVE; break; case DEVPB_DEVTYP_350_0720: case DEVPB_DEVTYP_350_1440: case DEVPB_DEVTYP_350_2880: case DEVPB_DEVTYP_350_120M: ids = _ShowUglyDriveNames() ? IDS_35_FLOPPY_DRIVE_UGLY : IDS_35_FLOPPY_DRIVE; break; case DEVPB_DEVTYP_NECHACK: ids = IDS_NECUNK_FLOPPY_DRIVE; break; } LoadString(HINST_THISDLL, ids, pszLabel, cchLabel); } } else { // No, just the raw albel from GetVolumeInforamtion if (!_GetGVILabelOrMixedCaseFromReg(pszLabel, cchLabel)) { *pszLabel = 0; hres = E_FAIL; } } break; } // We need to handle both connected and unconnected volumes. However, // for unconncected volumes we have to be careful as a real drive // may have taken it's spot (a new CDROM for example). case DRIVE_NO_ROOT_DIR: case DRIVE_UNKNOWN: break; default: { // Not a removable if (!_GetGVILabelOrMixedCaseFromReg(pszLabel, cchLabel)) { *pszLabel = 0; hres = E_FAIL; } else { if (!*pszLabel) { // We have an empty string for the label, let's see if we have a default label if (_HasDefaultLabel()) { hres = (_GetDefaultLabel(pszLabel, cchLabel) ? S_OK : E_FAIL); } } } break; } } if (FAILED(hres)) { if (MTPT_LABEL_NOFANCY == dwFlags) { *pszLabel = 0; hres = S_OK; } else { if (_HasDefaultLabel()) { hres = (_GetDefaultLabel(pszLabel, cchLabel) ? S_OK : E_FAIL); } if (FAILED(hres)) { GetTypeString(pszLabel, cchLabel); } hres = S_OK; } } return hres; } HRESULT CMtPtLocal::Eject() { TCHAR szNameForError[MAX_DISPLAYNAME]; HRESULT hres = E_FAIL; GetDisplayName(szNameForError, ARRAYSIZE(szNameForError)); hres = _Eject(szNameForError); InvalidateMountPoint(_GetName()); return hres; } BOOL CMtPtLocal::IsEjectable(BOOL fForceCDROM) { BOOL fIsEjectable = FALSE; if (fForceCDROM && (DRIVE_CDROM == _uDriveType)) { fIsEjectable = TRUE; } else { #ifdef WINNT DISK_GEOMETRY disk_g; // Call down to get the drive's geometry. We can then see if it's a // removeable (or ejectable) drive. We can't just use GetDriveType // because it tells us that floppies are removeable, which they aren't // (by software). Doing it this way gives us the information we need // to make the correct determination if (_DriveIOCTL(IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &disk_g, SIZEOF(disk_g))) { fIsEjectable = (disk_g.MediaType == RemovableMedia); // NT5 bug 140923 - if the media was (1) the boot media, or // (2) the pagefile, then ejecting the drive hangs the system // hard. Don't allow eject in these scenarios. if (fIsEjectable) { // BUGBUG: Unfortunately there's no IOCTL to query this. // Comment added to bug and resolved for NT5. Maybe we'll // figure out how to do this at some later date. // Hey, we could check if this is the WINDOWS drive and // not allow eject in that case! Still misses the PAGEFILE case tho... } } #else DRIVE_MAP_INFO dmi; dmi.dmiAllocationLength = SIZEOF(dmi); fIsEjectable = _DriveIOCTL(0x86F, NULL, 0, &dmi, SIZEOF(dmi)) && (dmi.dmiFlags & PROT_MODE_EJECT); // avoid disk hit and say all removable media are ejectable // return IsRemovableDrive(iDrive) || (LockUnlockDrive(iDrive, STATUS) == 0); #endif } return fIsEjectable; } BOOL CMtPtLocal::IsFloppy() { BOOL bRet = FALSE; if (DRIVE_REMOVABLE == _uDriveType) { switch (_bFloppyType) { case DEVPB_DEVTYP_525_0360: case DEVPB_DEVTYP_525_1200: case DEVPB_DEVTYP_350_0720: case DEVPB_DEVTYP_350_1440: case DEVPB_DEVTYP_350_2880: case DEVPB_DEVTYP_350_120M: case DEVPB_DEVTYP_NECHACK: bRet = TRUE; break; } } return bRet; } BOOL CMtPtLocal::IsAudioDisc() { return _sdDriveFlags.Update() && (DRIVE_AUDIOCD & __uDriveFlags); } int CMtPtLocal::GetSHIDType(BOOL fOKToHitNet) { int iFlags = 0; TraceMsg(TF_MOUNTPOINT, "CMtPtLocal::GetSHIDType: for '%s'", _GetName()); iFlags |= SHID_COMPUTER | _uDriveType; switch (iFlags & SHID_TYPEMASK) { case SHID_COMPUTER_REMOVABLE: { switch (_bFloppyType) { case DEVPB_DEVTYP_525_0360: case DEVPB_DEVTYP_525_1200: case DEVPB_DEVTYP_NECHACK: iFlags = SHID_COMPUTER_DRIVE525; break; case DEVPB_DEVTYP_350_0720: case DEVPB_DEVTYP_350_1440: case DEVPB_DEVTYP_350_2880: case DEVPB_DEVTYP_350_120M: iFlags = SHID_COMPUTER_DRIVE35; break; } } break; case SHID_COMPUTER | DRIVE_CDROM: case SHID_COMPUTER | DRIVE_FIXED: break; // Invalid drive gets SHID_COMPUTER_MISC, which others must check for case SHID_COMPUTER | DRIVE_NO_ROOT_DIR: iFlags = SHID_COMPUTER_MISC; break; case SHID_COMPUTER | DRIVE_UNKNOWN: default: iFlags = SHID_COMPUTER_FIXED; break; } return iFlags; } // Name fcts LPCTSTR CMtPtLocal::_GetNameForFctCall() { return _szUniqueID; } LPCTSTR CMtPtLocal::_GetVolumeGUID() { return _GetNameForFctCall(); } void CMtPtLocal::_InvalidateMedia() { CMountPoint::_InvalidateMedia(); } void CMtPtLocal::_InvalidateRefresh() { _sdCommentFromDesktopINI.Invalidate(); _sdHTMLInfoTipFileFromDesktopINI.Invalidate(); CMountPoint::_InvalidateRefresh(); } LPCTSTR CMtPtLocal::_GetUniqueID() { return _szUniqueID; } void CMtPtLocal::_SetUniqueID() { BOOL fDone = FALSE; _szUniqueID[0] = 0; #ifdef WINNT if (g_bRunOnNT5 && GetVolumeNameForVolumeMountPoint(_szName, _szUniqueID, ARRAYSIZE(_szUniqueID))) { fDone = TRUE; } #endif // On Win9X and NT4 we cannot mount a drive on a folder, so the drive letter is a unique ID if (!fDone) { lstrcpyn(_szUniqueID, _szName, ARRAYSIZE(_szUniqueID)); } } // Call Backs BOOL CMtPtLocal::_GetDriveFlagsCB(PVOID pvData) { __uDriveFlags = 0; // Is this a CD/DVD of some sort? if (DRIVE_CDROM == _uDriveType) { // Yes LPCTSTR pszSubKey = NULL; BOOL fAudio = _IsAudioDisc(); BOOL fDVD = _IsDVDDisc(); if (fAudio) { __uDriveFlags |= DRIVE_AUDIOCD; pszSubKey = c_szAudioCDShell; } else { if (fDVD) { __uDriveFlags |= DRIVE_DVD; pszSubKey = c_szDVDShell; } } // Set the AutoOpen stuff, if applicable if (pszSubKey) { TCHAR ach[80]; LONG cb = SIZEOF(ach); ach[0] = 0; // get the default verb for Audio CD/DVD SHRegQueryValue(HKEY_CLASSES_ROOT, pszSubKey, ach, &cb); // we should only set AUTOOPEN if there is a default verb on Audio CD/DVD if (ach[0]) __uDriveFlags |= DRIVE_AUTOOPEN; } } else { // No, by default every drive type is ShellOpen, except CD-ROMs __uDriveFlags |= DRIVE_SHELLOPEN; } if (_sdAutorun.Update() && __fAutorun) { __uDriveFlags |= DRIVE_AUTORUN; //BUGBUG should we set AUTOOPEN based on a flag in the AutoRun.inf??? __uDriveFlags |= DRIVE_AUTOOPEN; } return TRUE; } PBYTE CMtPtLocal::_MakeUniqueBlob(DWORD* pcbSize) { PBYTE pb = NULL; * pcbSize = 0; if ((DRIVE_REMOVABLE != _uDriveType) && (DRIVE_CDROM != _uDriveType)) { GVI* pGVI; *pcbSize = sizeof(GVI); pGVI = (GVI*)LocalAlloc(LPTR, *pcbSize); if (pGVI) { if (!GetVolumeInformation(_GetNameForFctCall(), pGVI->szLabel, ARRAYSIZE(pGVI->szLabel), &pGVI->dwSerialNumber, &pGVI->dwMaxlen, &pGVI->dwFileSysFlags, pGVI->szFileSysName, ARRAYSIZE(pGVI->szFileSysName))) { LocalFree(pGVI); pGVI = NULL; } } pb = (PBYTE)pGVI; } else { UINT* pu; *pcbSize = sizeof(UINT); pu = (UINT*)LocalAlloc(LPTR, *pcbSize); if (pu) { *pu = _uDriveType; } pb = (PBYTE)pu; } return pb; } HRESULT CMtPtLocal::_Initialize(LPCTSTR pszName, BOOL fMountedOnDriveLetter) { HRESULT hres = _InitializeBase(pszName, fMountedOnDriveLetter); if (DRIVE_REMOVABLE == _uDriveType) { _bFloppyType = _CalcFloppyType(); } return hres; } DWORD CMtPtLocal::_GetExpirationInMilliSec() { DWORD dwMaxAgeInMilliSec = EXPIRATION_NEVER; // Special case for floppy with old VolumeInfo ( > 3 sec)? if ((DRIVE_REMOVABLE == _uDriveType)) { if (IsFloppy()) dwMaxAgeInMilliSec = 3000; else dwMaxAgeInMilliSec = 5000; } return dwMaxAgeInMilliSec; } // Helpers typedef MCIERROR (WINAPI *MCISENDSTRINGAFN)(LPCTSTR lpstrCommand, LPTSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback); STDAPI_(HMODULE) LoadMM(); HRESULT CMtPtLocal::_Eject(LPTSTR pszMountPointNameForError) { HRESULT hres = E_FAIL; if (IsEjectable(FALSE)) { // it is a protect mode drive that we can tell directly... #ifdef WINNT if (DRIVE_CDROM == _uDriveType) { _DriveIOCTL(IOCTL_DISK_EJECT_MEDIA, NULL, 0, NULL, 0); hres = S_OK; } else { // For removable drives, we want to do all the calls on a single // handle, thus we can't do lots of calls to _DriveIOCTL. Instead, // use the helper routines to do our work... // Don't bring up any error message if the user already chose to abort. BOOL fAborted; BOOL fFailed; HANDLE hDeviceIOCtl = _Lock(pszMountPointNameForError, &fAborted, &fFailed); if (!fAborted) { if (fFailed) { ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE( IDS_UNMOUNT_TEXT ), MAKEINTRESOURCE( IDS_UNMOUNT_TITLE ), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND, pszMountPointNameForError); } else { PREVENT_MEDIA_REMOVAL pmr; pmr.PreventMediaRemoval = FALSE; // tell the drive to allow removal, then eject if (!_DriveIOCTL(g_bRunOnNT5 ? IOCTL_STORAGE_MEDIA_REMOVAL : IOCTL_DISK_MEDIA_REMOVAL, &pmr, SIZEOF(pmr), NULL, 0, FALSE, hDeviceIOCtl) || !_DriveIOCTL(g_bRunOnNT5 ? IOCTL_STORAGE_EJECT_MEDIA : IOCTL_DISK_EJECT_MEDIA, NULL, 0, NULL, 0, FALSE, hDeviceIOCtl)) { ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE( IDS_EJECT_TEXT ), MAKEINTRESOURCE( IDS_EJECT_TITLE ), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND, pszMountPointNameForError); } else hres = S_OK; CloseHandle(hDeviceIOCtl); } } } #else _DriveIOCTL(0x849, NULL, 0, NULL, 0); hres = S_OK; #endif } else { // else we will let MCICDA try to eject it for us... HMODULE hMM = LoadMM(); if (hMM) { #ifdef UNICODE MCISENDSTRINGAFN pfnMciSendString = (MCISENDSTRINGAFN)GetProcAddress(hMM, "mciSendStringW"); #else MCISENDSTRINGAFN pfnMciSendString = (MCISENDSTRINGAFN)GetProcAddress(hMM, "mciSendStringA"); #endif if (pfnMciSendString) { //BUGBUG: (stephstm) only works for drive mounted on letter TCHAR szMCI[128]; wsprintf(szMCI, TEXT("Open %c: type cdaudio alias foo shareable"), _GetNameFirstChar()); if (pfnMciSendString(szMCI, NULL, 0, 0L) == MMSYSERR_NOERROR) { pfnMciSendString(TEXT("set foo door open"), NULL, 0, 0L); pfnMciSendString(TEXT("close foo"), NULL, 0, 0L); hres = S_OK; } } } } return hres; } #ifdef WINNT #ifndef IDTRYAGAIN #define IDTRYAGAIN 10 #define IDCONTINUE 11 #define MB_CANCELTRYCONTINUE 0x00000006L #endif /* WINVER >= 0x0500 */ HANDLE CMtPtLocal::_Lock(LPTSTR pszMountPointNameForError, BOOL* pfAborted, BOOL* pfFailed) { *pfAborted = FALSE; *pfFailed = FALSE; HANDLE hDeviceIOCtl = NULL; _RETRY_LOCK_VOLUME_: hDeviceIOCtl = _GetIOCTLHandle(GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE); if (INVALID_HANDLE_VALUE != hDeviceIOCtl) { // Now try to lock the drive... // In theory, if no filesystem was mounted, the IOCtl command could go // to the device, which would fail with ERROR_INVALID_FUNCTION. If that // occured, we would still want to proceed, since the device might still // be able to handle the IOCTL_DISK_EJECT_MEDIA command below. if (!_DriveIOCTL(FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, FALSE, hDeviceIOCtl) || (GetLastError() == ERROR_INVALID_FUNCTION)) { // So we can't lock the drive. // If we're running on NT4, just fail the Eject. // If we're running on NT5, bring up a message box to see if user // wants to // 1. Abort. // 2. Retry to lock the drive. // 3. Dismount anyway. if (g_bRunOnNT5) { int iRet = ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE(IDS_RETRY_UNMOUNT_TEXT), MAKEINTRESOURCE(IDS_RETRY_UNMOUNT_TITLE), MB_CANCELTRYCONTINUE | MB_ICONWARNING | MB_SETFOREGROUND, pszMountPointNameForError); switch (iRet) { case IDCANCEL: *pfAborted = TRUE; break; case IDCONTINUE: // send FSCTL_DISMOUNT_VOLUME if (!_DriveIOCTL(FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, FALSE, hDeviceIOCtl)) { TraceMsg(TF_WARNING, "FSCTL_DISMOUNT_VOLUME failed with error %d.", GetLastError()); *pfFailed = TRUE; break; } // We sucessfully dismounted the volume, so the h we have is not valid anymore. We // therefore close it and start the process all over again, hoping to lock the volume before // anyone re-opens a handle to it // (fall through) case IDTRYAGAIN: CloseHandle(hDeviceIOCtl); goto _RETRY_LOCK_VOLUME_; } } else *pfFailed = TRUE; } } else *pfFailed = TRUE; if (*pfAborted || *pfFailed) { if (INVALID_HANDLE_VALUE != hDeviceIOCtl) { CloseHandle(hDeviceIOCtl); hDeviceIOCtl = INVALID_HANDLE_VALUE; } } return hDeviceIOCtl; } #endif // type stuff #ifdef WINNT BYTE _GetSpecialTypeByte(MEDIA_TYPE MediaType) { BYTE byte; switch(MediaType) { case F5_1Pt2_512: byte = DEVPB_DEVTYP_525_1200; break; case F3_1Pt44_512: byte = DEVPB_DEVTYP_350_1440; break; case F3_2Pt88_512: byte = DEVPB_DEVTYP_350_2880; break; case F3_20Pt8_512: byte = DEVPB_DEVTYP_350_2880; break; // Hack case F3_720_512: byte = DEVPB_DEVTYP_350_0720; break; case F5_360_512: byte = DEVPB_DEVTYP_525_0360; break; case F5_320_512: byte = DEVPB_DEVTYP_525_0360; break; // Hack case F5_320_1024: byte = DEVPB_DEVTYP_525_0360; break; // Hack case F5_180_512: byte = DEVPB_DEVTYP_525_0360; break; // Hack case F5_160_512: byte = DEVPB_DEVTYP_525_0360; break; // Hack case RemovableMedia: byte = 0xFF; break; case FixedMedia: byte = DEVPB_DEVTYP_FIXED; break; case F3_120M_512: byte = DEVPB_DEVTYP_350_120M; break; // Japanese specific device types from here. case F3_640_512: byte = DEVPB_DEVTYP_350_0720; break; // Hack case F5_640_512: byte = DEVPB_DEVTYP_525_0360; break; // Hack case F5_720_512: byte = DEVPB_DEVTYP_525_0360; break; // Hack case F3_1Pt2_512: byte = DEVPB_DEVTYP_350_1440; break; // Hack case F3_1Pt23_1024: byte = DEVPB_DEVTYP_350_1440; break; // Hack case F5_1Pt23_1024: byte = DEVPB_DEVTYP_525_1200; break; // Hack case F3_128Mb_512: byte = 0xFF; break; // Hack case F3_230Mb_512: byte = 0xFF; break; // Hack default: byte = 0xFF; break; } return byte; } #endif BYTE CMtPtLocal::_CalcFloppyType() { BYTE byte; #ifdef WINNT int i; DISK_GEOMETRY SupportedGeometry[30]; // s/b big enough for all if (IsNEC_PC9800()) for(i = 0; i < 30; i++) SupportedGeometry[i].MediaType = (MEDIA_TYPE)0xff; if (_DriveIOCTL(IOCTL_DISK_GET_MEDIA_TYPES, NULL, 0, SupportedGeometry, SIZEOF(SupportedGeometry))) { if (IsNEC_PC9800()) { // PC98's floppy.sys supports both 5inch FDD and 3.5inch FDD. // we have to distinguish which one the machine has by // going through the entire array to see if ioctl has returned // 1.44mb or not. byte = 0xff; for (i = 0; i < 30; i++) { if(SupportedGeometry[i].MediaType == F3_1Pt44_512) { byte = DEVPB_DEVTYP_350_1440; break; } } // now go through the array for (i=0; i< 30 && byte == 0xff; i++) byte = _GetSpecialTypeByte(SupportedGeometry[i].MediaType); } else { byte = _GetSpecialTypeByte(SupportedGeometry[0].MediaType); } } else { byte = 0xFF; } #else DevPB devpb; devpb.SplFunctions = 0; // get default (don't hit the drive!) if (!_DriveIOCTL(0x860, NULL, 0, &devpb, SIZEOF(devpb))) byte = 0xFF; byte = devpb.devType; #endif return byte; } BOOL CMtPtLocal::_IsAudioDisc() { BOOL fAudio = FALSE; #ifdef WINNT #define TRACK_TYPE_MASK 0x04 #define AUDIO_TRACK 0x00 #define DATA_TRACK 0x04 // To be compatible with Win95, we'll only return TRUE from this // function if the disc has ONLY audio tracks (and NO data tracks). // BUGBUG: Post NT-SUR beta 1, we should consider adding a new // DriveType flag for "contains data tracks" and revamp the commands // available on a CD-ROM drive. The current code doesn't handle // mixed audio/data and audio/autorun discs very usefully. --JonBe // First try the new IOCTL which gives us a ULONG with bits indicating // the presence of either/both data & audio tracks CDROM_DISK_DATA data; if (_DriveIOCTL(IOCTL_CDROM_DISK_TYPE, NULL, 0, &data, SIZEOF(data), TRUE)) { if ((data.DiskData & CDROM_DISK_AUDIO_TRACK) && !(data.DiskData & CDROM_DISK_DATA_TRACK)) fAudio = TRUE; else fAudio = FALSE; } else { // else that failed, so try to look for audio tracks the old way, by // looking throught the table of contents manually. Note that data tracks // are supposed to be hidden in the TOC by CDFS now on mixed audio/data // discs (at least if the data tracks follow the audio tracks). PCDROM_TOC pTOC = (PCDROM_TOC)LocalAlloc(LPTR, SIZEOF(CDROM_TOC)); if (pTOC) { if (!_DriveIOCTL(IOCTL_CDROM_READ_TOC, NULL, 0, pTOC, SIZEOF(*pTOC), TRUE)) { SUB_Q_CHANNEL_DATA subq; CDROM_SUB_Q_DATA_FORMAT df; LocalFree(pTOC); // We might not have been able to read the TOC because the drive // was busy playing audio. Lets try querying the audio position. df.Format = IOCTL_CDROM_CURRENT_POSITION; fAudio = _DriveIOCTL(IOCTL_CDROM_READ_Q_CHANNEL, &df, SIZEOF(df), &subq, SIZEOF(subq)); } else { INT nTracks = (pTOC->LastTrack - pTOC->FirstTrack) + 1; INT iTrack = 0; // Now iterate through the tracks looking for Audio data while (iTrack < nTracks) { if ((pTOC->TrackData[iTrack].Control & TRACK_TYPE_MASK) == AUDIO_TRACK) fAudio = TRUE; else if ((pTOC->TrackData[iTrack].Control & TRACK_TYPE_MASK) == DATA_TRACK) { fAudio = FALSE; break; } ++iTrack; } LocalFree(pTOC); } } } #else #pragma pack(1) typedef struct { WORD InfoLevel; // information level DWORD SerialNum; // serial number TCHAR VolLabel[11]; // ASCII volume label TCHAR FileSysType[8]; // file system type } MediaID; #pragma pack() MediaID mid; ASSERT(GetDRIVEType(FALSE) == DRIVE_CDROM); mid.FileSysType[0] = 0; _DriveIOCTL(0x0866, NULL, 0, &mid, SIZEOF(mid)); mid.FileSysType[7] = 0; fAudio = (lstrcmp(mid.FileSysType, TEXT("CDAUDIO")) == 0) ? TRUE : FALSE; #endif TraceMsg(TF_MOUNTPOINT, " CMtPtLocal::_CalcAudioDisc: for '%s', result is '%hs'", _GetName(), (fAudio ? "TRUE" : "FALSE")); return fAudio; } BOOL CMtPtLocal::_IsDVDDisc() { TCHAR szDVDFile[MAX_PATH]; UINT err; BOOL fDVD = FALSE; // build abs path to AutoRun.inf lstrcpyn(szDVDFile, _GetName(), ARRAYSIZE(szDVDFile)); PathAddBackslash(szDVDFile); lstrcatn(szDVDFile, TEXT("video_ts\\video_ts.ifo"), ARRAYSIZE(szDVDFile)); err = SetErrorMode(SEM_FAILCRITICALERRORS); // fDVD = PathFileExistsAndAttributes(szDVDFile, NULL); fDVD = PathFileExists(szDVDFile); SetErrorMode(err); return fDVD; }