Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

832 lines
24 KiB

#include "shellprv.h"
#pragma hdrstop
TCHAR const c_szAutoRunInf[] = TEXT("AutoRun.inf"); // don't internationalize these
const TCHAR c_szAutoRun[] = TEXT("AutoRun");
#ifdef WINNT
#if defined(_X86_)
const TCHAR c_szAutoRunDotPlatform[] = TEXT("AutoRun.x86");
#elif defined(_MIPS_)
const TCHAR c_szAutoRunDotPlatform[] = TEXT("AutoRun.Mips");
#elif defined(_ALPHA_)
const TCHAR c_szAutoRunDotPlatform[] = TEXT("AutoRun.Alpha");
#elif defined(_PPC_)
const TCHAR c_szAutoRunDotPlatform[] = TEXT("AutoRun.Ppc");
#endif
#endif // WINNT
TCHAR const c_szShellAutoRun[] = TEXT("shell\\AutoRun");
TCHAR const c_szShellAutoRunCommand[] = TEXT("shell\\AutoRun\\command");
TCHAR const c_szAutoRunD[] = TEXT("AutoRun\\%d");
TCHAR const c_szIcon[] = TEXT("Icon");
TCHAR const c_szAudioCDShell[] = TEXT("AudioCD\\shell");
extern TCHAR const c_szOpen[];
extern TCHAR const c_szShell[];
extern TCHAR const c_szDefaultIcon[];
BOOL IsAutoRunDrive(int iDrive); // in this file
static int rgiDriveType[26] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1
};
// A corresponding array which indicates whether or not
// the drivetype cache has the LFN and ACL bits.
static int rgiHasNetFlags[26] = { 0 };
// get connection information including disconnected drives
//
// in:
// lpDev device name "A:" "LPT1:", etc.
// bConvertClosed
// if FALSE closed or error drives will be converted to
// WN_SUCCESS return codes. if TRUE return not connected
// and error state values (ie, the caller knows about not
// connected and error state drives)
//
// BUGBUG: we need to add cbPath to the output buffer
// out:
// lpPath filled with net name if return is WN_SUCCESS (or not connected/error)
// returns:
// WN_* error code
DWORD GetConnection(LPCTSTR lpDev, LPTSTR lpPath, UINT cchPath, BOOL bConvertClosed)
{
DWORD err;
int iType;
iType = DriveType(DRIVEID(lpDev));
if (iType == DRIVE_CDROM)
return WN_NOT_CONNECTED;
err = WNetGetConnection((LPTSTR)lpDev, lpPath, &cchPath);
if (!bConvertClosed)
if (err == WN_CONNECTION_CLOSED || err == WN_DEVICE_ERROR)
err = WN_SUCCESS;
return err;
}
// this is called for every drive at init time so it must
// be sure to not trigget things like the phantom B: drive support
//
// in:
// iDrive zero based drive number (0 = A, 1 = B)
//
// returns:
// 0 not a net drive
// 1 is a net drive, properly connected
// 2 disconnected/error state connection
int WINAPI IsNetDrive(int iDrive)
{
DWORD err;
TCHAR szDrive[4];
TCHAR szConn[MAX_PATH]; // this really should be WNBD_MAX_LENGTH
// but this change would have to be many everywhere
PathBuildRoot(szDrive, iDrive);
err = GetConnection(szDrive, szConn, ARRAYSIZE(szConn), TRUE);
if (err == WN_SUCCESS)
return 1;
if (err == WN_CONNECTION_CLOSED || err == WN_DEVICE_ERROR)
if ((GetLogicalDrives() & (1 << iDrive)) == 0)
return 2;
return 0;
}
// ask the share provider if this path is shared
BOOL IsShared(LPNCTSTR pszPath, BOOL fUpdateCache)
{
ShareDLL_Init();
#ifdef ALIGNMENT_SCENARIO
{
TCHAR szTmp[MAX_PATH];
ualstrcpyn(szTmp, pszPath, ARRAYSIZE(szTmp));
if (g_pfnIsPathShared)
{
return g_pfnIsPathShared(szTmp, fUpdateCache);
}
}
#else
{
if (g_pfnIsPathShared) {
return g_pfnIsPathShared(pszPath, fUpdateCache);
}
}
#endif
return FALSE;
}
//
// cache DriveTypeFlags calls for speed
//
// input: 0 - 25
// returns: drive type flags
//
// DRIVE_SLOW - drive is on a slow link
// DRIVE_LFN - drive is a LFN capable drive
// DRIVE_NETUNAVAIL - drive is unavailable net drive
// DRIVE_AUDIOCD - drive has a AudioCD inserted
// DRIVE_AUTORUN - drive has a AutoRun.inf in the root
// DRIVE_AUTOOPEN - drive should be open'ed by default
// DRIVE_SHELLOPEN - drive should be open'ed only if shell has focus
// DRIVE_SECURITY - drive supports security (ACLs)
//
#undef DriveTypeFlags
int RealDriveTypeFlags(int iDrive, BOOL fOKToHitNet)
{
int iDriveType;
int iHasNetFlag;
BOOL fDoNetFlags;
BOOL fDoNonNetFlags;
if (iDrive < 0 || iDrive >= 26)
return(0);
// Grab these two values inside the critical section so they're
// guaranteed to be in sync with each other
ENTERCRITICAL
iDriveType = rgiDriveType[iDrive];
iHasNetFlag = rgiHasNetFlags[iDrive];
LEAVECRITICAL
//
// If we have the info already just return it, unless we are now
// looking for net-specific flags (LFN, SECURITY) and the cached
// copy doesn't have the net flags. This could happen if someone
// previously called with fOKToHitNet = FALSE and we loaded the
// cache from that call.
//
fDoNonNetFlags = ((iDriveType & ~DRIVE_TYPE) == ~DRIVE_TYPE);
fDoNetFlags = ((TRUE == fOKToHitNet) && (FALSE == iHasNetFlag));
if (fDoNonNetFlags || fDoNetFlags)
{
TCHAR szDrive[40];
int type;
DWORD speed = 0;
PathBuildRoot(szDrive, iDrive);
type = DriveType(iDrive);
// We only reset the DriveType flags if we're filling the
// first level cache (non-net flags) or both caches. If we're only
// filling in the second level cache (net flags), we will just OR in
// the appropriate bits to the existing DriveType value. This way
// we avoid recomputing all the non-net flags (which is not only
// expensive, but invites race conditions during notifications)
if (fDoNonNetFlags)
{
// Essentially, clear out everything but the low nibble
// (which may have just been updated by DriveType)
iDriveType = type;
}
//
// We only go and grok the net if the caller explicitly says we can.
// All of the old callers that used to get here by calling "DriveType"
// (which used to call us) now get fOKToHitNet passed as TRUE on their
// behalf.
//
if (fDoNetFlags && (type != DRIVE_REMOVABLE))
{
DWORD maxlen=13;
DWORD dwFlags;
if (GetVolumeInformation(szDrive, NULL, 0, NULL, &maxlen, &dwFlags, NULL, 0))
{
// If this is a drive which supports compression, we go off to find out
// if the root is compressed
if (dwFlags & FS_FILE_COMPRESSION)
{
DWORD dwAttrib = GetFileAttributes(szDrive);
// Drive may be compressed
iDriveType |= DRIVE_ISCOMPRESSIBLE;
// Now lets see if it is actually compressed or not
if (0xFFFFFFFF != dwAttrib && dwAttrib & FILE_ATTRIBUTE_COMPRESSED)
{
iDriveType |= DRIVE_COMPRESSED;
}
}
if (maxlen > 12)
iDriveType |= DRIVE_LFN;
if (dwFlags & FS_PERSISTENT_ACLS)
iDriveType |= DRIVE_SECURITY;
// We now have the net flags for this drive, so mark the cache
// appropriately
iHasNetFlag = TRUE;
// BUGBUG Bogus: In order to avoid an inifite recursion below
// in IsAutoRunDrive (which in some circumstances will call
// IsLFNDrive, which in turn calls RealDriveTypeFlags), I'll
// write out the partial results (most importantly, the
// DRIVE_LFN bit at this point. This leaves a short window
// where another thread could get stale, incomplete info --
// but it's no worse than the release Win95 code.
// We really ought to rewrite all of GetDriveType[Flags] after
// this beta. This is a difficult-to-debug mess.
ENTERCRITICAL
rgiDriveType[iDrive] = iDriveType;
rgiHasNetFlags[iDrive] = iHasNetFlag;
LEAVECRITICAL
}
}
if (fDoNonNetFlags)
{
BOOL fDisconnected = FALSE;
// If we don't know what it is, than see if it is a
// persistent drive that we could not restore previously...
if (type < DRIVE_REMOVABLE)
{
if (IsUnavailableNetDrive(iDrive))
{
iDriveType |= DRIVE_NETUNAVAIL;
fDisconnected = TRUE;
}
} else {
if (type == DRIVE_REMOTE)
fDisconnected = IsDisconnectedNetDrive(iDrive);
}
if (!fDisconnected && type == DRIVE_REMOTE)
{
speed = GetPathSpeed(szDrive);
if (speed != 0 && speed <= SPEED_SLOW)
iDriveType |= DRIVE_SLOW;
}
//
// by default every drive type is ShellOpen, except CD-ROMs
//
if (type != DRIVE_CDROM)
{
iDriveType |= DRIVE_SHELLOPEN;
}
//
// check for a Audio Disc
//
if (type == DRIVE_CDROM && IsAudioDisc(iDrive))
{
TCHAR ach[80];
UINT cb;
iDriveType |= DRIVE_AUDIOCD;
//
// get the default verb for AudioCD
//
ach[0] = 0;
cb = SIZEOF(ach);
RegQueryValue(HKEY_CLASSES_ROOT, c_szAudioCDShell, ach, &cb);
//
// we should only set AUTOOPEN if there is a default verb on AudioCD
//
if (ach[0])
iDriveType |= DRIVE_AUTOOPEN;
}
if (!fDisconnected && IsAutoRunDrive(iDrive))
{
iDriveType |= DRIVE_AUTORUN;
//BUGBUG should we set AUTOOPEN based on a flag in the
//BUGBUG AutoRun.inf???
iDriveType |= DRIVE_AUTOOPEN;
}
}
// Set these two values inside the critical section so they're
// guaranteed to be in sync with each other
ENTERCRITICAL
rgiDriveType[iDrive] = iDriveType;
rgiHasNetFlags[iDrive] = iHasNetFlag;
LEAVECRITICAL
#ifdef DEBUG
DebugMsg(DM_TRACE, TEXT("DriveTypeFlags: %s"), szDrive);
if (rgiDriveType[iDrive] & DRIVE_SLOW) DebugMsg(DM_TRACE, TEXT(" drive is slow (speed=%d)"),speed);
if (rgiDriveType[iDrive] & DRIVE_LFN) DebugMsg(DM_TRACE, TEXT(" drive is LFN"));
if (rgiDriveType[iDrive] & DRIVE_AUDIOCD) DebugMsg(DM_TRACE, TEXT(" drive is Audio Disc"));
if (rgiDriveType[iDrive] & DRIVE_NETUNAVAIL) DebugMsg(DM_TRACE, TEXT(" drive is Unavalable Net"));
if (rgiDriveType[iDrive] & DRIVE_AUTORUN) DebugMsg(DM_TRACE, TEXT(" drive has a AutoRun.inf"));
if (rgiDriveType[iDrive] & DRIVE_AUTOOPEN)DebugMsg(DM_TRACE, TEXT(" drive is AutoOpen"));
if (rgiDriveType[iDrive] & DRIVE_SHELLOPEN)DebugMsg(DM_TRACE,TEXT(" drive is ShellOpen"));
#endif
}
return rgiDriveType[iDrive];
}
// We need RealDriveTypeFlags so that internal callers can get there
// without being diverted by the macro which is also named DriveTypeFlags,
// while others remain diverted off to DriveType, which calls this
// DriveTypeFlags after modifying the iDrive index. Sigh.
int DriveTypeFlags(int iDrive, BOOL fOKToHitNet)
{
return RealDriveTypeFlags(iDrive, fOKToHitNet);
}
//
// cache GetDriveType calls for speed
//
// input: 0 - 25
// returns: drive type
//
// input: 'A' - 'Z'
// returns: drive type + flags
//
// DRIVE_SLOW - drive is on a slow link
// DRIVE_LFN - drive is a LFN capable drive
// DRIVE_NETUNAVAIL - drive is unavailable net drive
// DRIVE_AUDIOCD - drive has a AudioCD inserted
// DRIVE_AUTORUN - drive has a AutoRun.inf in the root
// DRIVE_AUTOOPEN - drive should be open'ed by default
// DRIVE_SHELLOPEN - drive should be open'ed only if shell has focus
//
int WINAPI RealDriveType(int iDrive, BOOL fOKToHitNet)
{
if (iDrive >= TEXT('A') && iDrive <= TEXT('Z'))
return DriveTypeFlags(iDrive - TEXT('A'), fOKToHitNet);
else if (iDrive < 0 || iDrive >= 26)
return(0); // GetDriveType rets 0 on invalid drives
//
// if we miss our cache compute all the info *once*
//
if ((rgiDriveType[iDrive] & DRIVE_TYPE) == DRIVE_TYPE)
{
TCHAR szDrive[40];
PathBuildRoot(szDrive, iDrive);
rgiDriveType[iDrive] &= ~DRIVE_TYPE;
rgiDriveType[iDrive] |= GetDriveType(szDrive);
#ifdef DEBUG
DebugMsg(DM_TRACE, TEXT("DriveType: %s"), szDrive);
switch(rgiDriveType[iDrive] & DRIVE_TYPE)
{
default:
case DRIVE_UNKNOWN: DebugMsg(DM_TRACE, TEXT(" Unknown")); break;
case DRIVE_REMOVABLE: DebugMsg(DM_TRACE, TEXT(" Removable"));break;
case DRIVE_FIXED: DebugMsg(DM_TRACE, TEXT(" Fixed")); break;
case DRIVE_REMOTE: DebugMsg(DM_TRACE, TEXT(" Remote")); break;
case DRIVE_CDROM: DebugMsg(DM_TRACE, TEXT(" CD-ROM")); break;
case DRIVE_RAMDISK: DebugMsg(DM_TRACE, TEXT(" RAM-DISK")); break;
}
#endif
}
return rgiDriveType[iDrive] & DRIVE_TYPE;
}
// What is now RealDriveType used to be DriveType, so this stub calls
// the new RealDriveType with fOKToHitNet = TRUE, which was the behavior
// of the old DriveType call.
int WINAPI DriveType(int iDrive)
{
return RealDriveType(iDrive, TRUE);
}
// invalidate the DriveType cache for one entry, or all
void WINAPI InvalidateDriveType(int iDrive)
{
int i;
if (iDrive < 0)
{
//
// invalidate all drives
//
#ifndef DEBUG
RegDeleteKey(HKEY_CLASSES_ROOT, c_szAutoRun);
#endif
// Clear these values under the critical section, so any pair will
// always be in sync
ENTERCRITICAL
for (i = 0; i < 26; i++)
{
rgiDriveType[i] = -1;
rgiHasNetFlags[i] = FALSE;
}
LEAVECRITICAL
}
else if (iDrive < 26)
{
TCHAR szDrive[10];
SHFILEINFO sfi;
int iIcon=0;
//
// invalidate a single drive, if the icon for a drive changes
// send a notify so links can update.. Handle the case where
// the drive was a unavailable net drive...
//
if ((rgiDriveType[iDrive] != -1) &&
((rgiDriveType[iDrive] & ~DRIVE_TYPE) != ~DRIVE_TYPE) &&
(((rgiDriveType[iDrive] & DRIVE_TYPE) >= DRIVE_REMOVABLE)
|| (rgiDriveType[iDrive] & DRIVE_NETUNAVAIL)))
{
PathBuildRoot(szDrive, iDrive);
SHGetFileInfo(szDrive, 0, &sfi, SIZEOF(sfi), SHGFI_SYSICONINDEX);
iIcon = sfi.iIcon;
}
// Clear these values under the critical section, so they'll always
// be in sync with each other
ENTERCRITICAL
rgiDriveType[iDrive] = -1;
rgiHasNetFlags[iDrive] = FALSE;
LEAVECRITICAL
if (iIcon != 0)
{
SHGetFileInfo(szDrive, 0, &sfi, SIZEOF(sfi), SHGFI_SYSICONINDEX);
if (iIcon != sfi.iIcon &&
(rgiDriveType[iDrive] & ~DRIVE_TYPE) != ~DRIVE_TYPE &&
(rgiDriveType[iDrive] & DRIVE_TYPE) >= DRIVE_REMOVABLE)
{
DebugMsg(DM_TRACE, TEXT("InvalidateDriveType: sending icon change for %s (%d => %d)"), szDrive, iIcon, sfi.iIcon);
SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)iIcon, NULL);
}
}
}
// Invalidate the Drive Name Cache for each of the drives...
InvalidateDriveNameCache(iDrive);
}
//
// This function tries to take care of the case that a command was registered
// in the autrun file of a cdrom. If the command is relative than see if the
// command exists on the CDROM
void QualifyCommandToCDRomDrive(int iDrive, LPTSTR pszCommand)
{
TCHAR szWorkingDir[MAX_PATH];
TCHAR szImage[MAX_PATH];
LPTSTR aszDirs[] = {szWorkingDir, NULL};
LPTSTR pszArgs;
lstrcpy(szImage, pszCommand);
PathRemoveArgs(szImage);
PathUnquoteSpaces(szImage);
if (!PathIsRelative(szImage))
return;
PathBuildRoot(szWorkingDir, iDrive);
PathResolve(szImage, aszDirs, PRF_TRYPROGRAMEXTENSIONS|PRF_VERIFYEXISTS|PRF_FIRSTDIRDEF);
PathQuoteSpaces(szImage);
pszArgs = PathGetArgs(pszCommand);
if (pszArgs && *pszArgs)
lstrcat(szImage, pszArgs-1);
lstrcpy(pszCommand, szImage);
}
//
// if a drive has a AutoRun.inf file and AutoRun is not restricted in
// the registry. copy the AutoRun info into a key in the registry.
//
// HKEY_CLASSES_ROOT\AutoRun\0 (0=A,1=B,...)
//
// the key is a standard ProgID key, has DefaultIcon, shell, shellex, ...
//
// the autorun file looks like this....
//
// [AutoRun]
// key = value
// key = value
// key = value
//
// examples:
//
// [AutoRun]
// DefaultIcon = foo.exe,1
// shell=myverb
// shell\myverb = &MyVerb
// shell\myverb\command = myexe.exe
//
// will give the drive a icon from 'foo.exe'
// add a verb called myverb (with name "&My Verb")
// and make myverb default.
//
// [AutoRun]
// shell\myverb = &MyVerb
// shell\myverb\command = myexe.exe
//
// add a verb called myverb (with name "&My Verb")
// verb will not be default.
//
// any thing they add will be copied over, they can add wacky things
// like CLSID's or shellx\ContextMenuHandlers and it will work.
//
// or they can just copy over data the app will look at later.
//
// the following special cases will be supported....
//
// [AutoRun]
// Open = command.exe /params
// Icon = iconfile, iconnumber
//
// will be treated like:
//
// [AutoRun]
// DefaultIcon = iconfile, iconnumber
// shell = AutoRun
// shell\AutoRun = Auto&Play
// shell\AutoRun\command = command.exe /params
//
BOOL IsAutoRunDrive(int iDrive)
{
TCHAR szInfFile[5 + ARRAYSIZE(c_szAutoRunInf)];
TCHAR szKeys[512];
TCHAR szValue[MAX_PATH];
TCHAR szIcon[80];
TCHAR *szKey;
HKEY hkey;
UINT err;
int i;
#if defined(DEBUG) || defined(TEST)
//
// for testing read the name of the AutoRun section from WIN.INI
//
TCHAR szSection[80];
GetProfileString(c_szAutoRun, c_szOpen, c_szAutoRun, szSection, ARRAYSIZE(szSection));
#else
#ifdef WINNT
const TCHAR *szSection = c_szAutoRunDotPlatform;
#else
const TCHAR *szSection = c_szAutoRun;
#endif // !WINNT
#endif // !(DEBUG || TEST)
// Restrict auto-run's to particular drives.
if (SHRestricted(REST_NODRIVEAUTORUN) & (1 << iDrive))
return FALSE;
// Restrict auto-run's to particular types of drives.
if (SHRestricted(REST_NODRIVETYPEAUTORUN) & (1 << DriveType(iDrive)))
return FALSE;
if (DriveType(iDrive) == DRIVE_UNKNOWN)
return FALSE;
// build abs path to AutoRun.inf
PathBuildRoot(szInfFile, iDrive);
lstrcat(szInfFile, c_szAutoRunInf);
//
// make sure a file exists before calling GetPrivateProfileString
// because for some media this check might take a long long time
// and we dont want to have kernel wait wiht the Win16Lock
//
err = SetErrorMode(SEM_FAILCRITICALERRORS);
if (!PathFileExists(szInfFile))
{
SetErrorMode(err);
return FALSE;
}
//
// get all the keys in the [AutoRun] section
//
// Flush the INI cache, or this may fail during a Device broadcast
WritePrivateProfileString(NULL, NULL, NULL, szInfFile);
i = GetPrivateProfileString(szSection, NULL, c_szNULL, szKeys, ARRAYSIZE(szKeys), szInfFile);
#ifdef WINNT
// On NT, if we fail to find a platform-specific AutoRun section, fall
// back to looking for the naked "AutoRun" section.
if (0 == i)
{
#if DEBUG
lstrcpy(szSection, c_szAutoRun);
#else
szSection = c_szAutoRun;
#endif
i = GetPrivateProfileString(szSection, NULL, c_szNULL, szKeys, ARRAYSIZE(szKeys), szInfFile);
}
#endif
SetErrorMode(err);
if (i < 4)
{
return FALSE;
}
//
// make sure the external strings are what we think.
//
Assert(lstrcmpi(c_szOpen,TEXT("open")) == 0);
Assert(lstrcmpi(c_szShell, TEXT("shell")) == 0);
Assert(lstrcmpi(c_szDefaultIcon, TEXT("DefaultIcon")) == 0);
//
// open the key for this drive.
//
wsprintf(szValue, c_szAutoRunD, iDrive);
SHRegDeleteKey(HKEY_CLASSES_ROOT, szValue);
if (RegCreateKey(HKEY_CLASSES_ROOT, szValue, &hkey) != ERROR_SUCCESS)
{
return FALSE;
}
//
// now walk all the keys in the .inf file and copy them to
// the registry.
//
for (szKey = szKeys; *szKey; szKey+=lstrlen(szKey)+1)
{
GetPrivateProfileString(szSection, szKey,
c_szNULL, szValue, ARRAYSIZE(szValue), szInfFile);
//
// special case open =
//
if (lstrcmpi(szKey, c_szOpen) == 0)
{
RegSetValue(hkey, c_szShell, REG_SZ, c_szAutoRun, lstrlen(c_szAutoRun));
QualifyCommandToCDRomDrive(iDrive, szValue);
RegSetValue(hkey, c_szShellAutoRunCommand, REG_SZ, szValue, lstrlen(szValue));
LoadString(HINST_THISDLL, IDS_MENUAUTORUN, szValue, ARRAYSIZE(szValue));
RegSetValue(hkey, c_szShellAutoRun, REG_SZ, szValue, lstrlen(szValue));
}
//
// special case icon =
// make sure the icon file has a full path...
//
else if (lstrcmpi(szKey, c_szIcon) == 0)
{
PathBuildRoot(szIcon, iDrive);
PathAppend(szIcon, szValue);
RegSetValue(hkey, c_szDefaultIcon, REG_SZ, szIcon, lstrlen(szIcon) * SIZEOF(TCHAR));
}
//
// it is just a key/value pair copy it over.
//
else
{
if (lstrcmpi(PathFindFileName(szKey), c_szCommand) == 0)
QualifyCommandToCDRomDrive(iDrive, szValue);
RegSetValue(hkey, szKey, REG_SZ, szValue, lstrlen(szValue));
}
}
RegCloseKey(hkey);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#ifdef TRACK_DEFAULT_DRIVE
// we may want to instance this data in the future
// so keep it in this structure
typedef struct {
PHASHITEM rphiPaths[27]; // [26] is for the no default drive case
int iDefaultDrive;
} CURRENTDIR_DATA, *LPCURRENTDIR_DATA;
CURRENTDIR_DATA cdd = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, -1
};
// returns:
// the default drive 0 = A, 1 = B, 2 = C... or
// -1 if the default is a UNC type name (no drive associated)
// if no default was previously set the
// window drive is used as the default
int WINAPI GetDefaultDrive(void)
{
return cdd.iDefaultDrive;
}
// in:
// iDrive number 0 = A, 1 = B, 2 = C to set as default
// -1 for no default drive (UNC name is default)
//
// returns:
// previous default drive
//
int WINAPI SetDefaultDrive(int iDrive)
{
int iOldDrive;
iOldDrive = GetDefaultDrive();
if (iDrive >= 0 && iDrive < 26)
cdd.iDefaultDrive = iDrive;
else
cdd.iDefaultDrive = -1;
return iOldDrive;
}
// in:
// iDrive 0 = A, 1 = B, ... or
// -1 for UNC type path
// returns:
// lpPath fully qualified path (ANSI string)
//
void WINAPI GetDefaultDirectory(int iDrive, LPTSTR lpPath)
{
if (iDrive < 0 || iDrive >= 26)
iDrive = 26;
if (cdd.rphiPaths[iDrive])
GetHashItemName(NULL, cdd.rphiPaths[iDrive], lpPath, MAX_PATH);
else
PathBuildRoot(lpPath, iDrive);
}
// in:
// lpPath fully qualified path (ANSI string)
// note:
// this does not set the default drive, if you
// need to change that it must be done explicitly
//
int WINAPI SetDefaultDirectory(LPCTSTR lpPath)
{
PHASHITEM phiPath;
int iDrive;
iDrive = DRIVEID(lpPath);
if (iDrive < 0 || iDrive >= 26)
iDrive = 26;
phiPath = AddHashItem(NULL, lpPath);
if (phiPath) {
if (cdd.rphiPaths[iDrive])
DeleteHashItem(NULL, cdd.rphiPaths[iDrive]);
cdd.rphiPaths[iDrive] = phiPath;
return TRUE;
}
return FALSE;
}
#endif