mirror of https://github.com/lianthony/NT4.0
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
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
|