windows-nt/Source/XPSP1/NT/shell/shell32/mtptarun2.cpp
2020-09-26 16:20:57 +08:00

2541 lines
77 KiB
C++

#include "shellprv.h"
#pragma hdrstop
#include "ids.h"
#include "mtptl.h"
#include "hwcmmn.h"
#include "datautil.h"
// for now
#include "mixctnt.h"
#include "filetbl.h"
#include "apprmdlg.h"
#include "views.h"
#include <ddraw.h>
CDPA<PNPNOTIFENTRY> CSniffDrive::_dpaNotifs = NULL;
HANDLE CSniffDrive::_hThreadSCN = NULL;
HWND CSniffDrive::_hwndNotify = NULL;
//
// 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
//
//
// 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 CMountPoint::_QualifyCommandToDrive(LPTSTR pszCommand)
{
// for now we assume that we'll call this only for CD mounted on a drive letter
// (by oppoition to a folder)
if (_IsMountedOnDriveLetter())
{
TCHAR szImage[MAX_PATH];
lstrcpy(szImage, pszCommand);
PathRemoveArgs(szImage);
PathUnquoteSpaces(szImage);
if (PathIsRelative(szImage))
{
TCHAR szFinal[MAX_PATH];
LPTSTR pszTmp = szImage;
lstrcpy(szFinal, _GetName());
// do simple check for command, check for "..\abc" or "../abc"
while ((TEXT('.') == *pszTmp) && (TEXT('.') == *(pszTmp + 1)) &&
((TEXT('\\') == *(pszTmp + 2)) || (TEXT('/') == *(pszTmp + 2))))
{
pszTmp += 3;
}
lstrcatn(szFinal, pszTmp, ARRAYSIZE(szFinal));
// we first check if it exists on the CD
DWORD dwAttrib = GetFileAttributes(szFinal);
if (0xFFFFFFFF == dwAttrib)
{
// It's not on the CD, try appending ".exe"
lstrcatn(szFinal, TEXT(".exe"), ARRAYSIZE(szFinal));
dwAttrib = GetFileAttributes(szFinal);
}
if (0xFFFFFFFF != dwAttrib)
{
// Yes, it's on the CD
PathQuoteSpaces(szFinal);
LPTSTR pszArgs = PathGetArgs(pszCommand);
if (pszArgs && *pszArgs)
lstrcatn(szFinal, pszArgs - 1, ARRAYSIZE(szFinal));
// MAX_PATH: educated guess
lstrcpyn(pszCommand, szFinal, MAX_PATH);
}
else
{
// No, not on the CD
}
}
}
}
// This one does not hit the drive
BOOL CMountPoint::_IsAutoRunDrive()
{
BOOL fRet = TRUE;
// Add support for now drive letter
if (_IsMountedOnDriveLetter())
{
int iDrive = DRIVEID(_GetName());
// Restrict auto-run's to particular drives.
if (SHRestricted(REST_NODRIVEAUTORUN) & (1 << iDrive))
{
fRet = FALSE;
}
}
if (fRet)
{
UINT uDriveType = _GetDriveType();
// Restrict auto-run's to particular types of drives.
if (SHRestricted(REST_NODRIVETYPEAUTORUN) & (1 << (uDriveType & DRIVE_TYPE)))
{
fRet = FALSE;
}
else
{
if (DRIVE_UNKNOWN == (uDriveType & DRIVE_TYPE))
{
fRet = FALSE;
}
}
if (fRet && _IsFloppy())
{
fRet = FALSE;
}
}
return fRet;
}
HRESULT CMountPoint::_AddAutoplayVerb()
{
HRESULT hr = E_FAIL;
if (RSSetTextValue(TEXT("shell\\Autoplay\\DropTarget"), TEXT("CLSID"),
TEXT("{f26a669a-bcbb-4e37-abf9-7325da15f931}"), REG_OPTION_NON_VOLATILE))
{
// IDS_MENUAUTORUN -> 8504
if (RSSetTextValue(TEXT("shell\\Autoplay"), TEXT("MUIVerb"),
TEXT("@shell32.dll,-8504"), REG_OPTION_NON_VOLATILE))
{
if (RSSetTextValue(TEXT("shell"), NULL, TEXT("None"), REG_OPTION_NON_VOLATILE))
{
hr = S_OK;
}
}
}
return hr;
}
HRESULT CMountPoint::_CopyInvokeVerbKey(LPCWSTR pszProgID, LPCWSTR pszVerb)
{
ASSERT(pszProgID);
ASSERT(pszVerb);
WCHAR szKey[MAX_PATH];
HRESULT hr = E_FAIL;
wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("shell\\%s"), pszVerb);
HKEY hkeyNew = RSDuplicateSubKey(szKey, TRUE, FALSE);
if (hkeyNew)
{
wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("%s\\shell\\%s"), pszProgID, pszVerb);
if (ERROR_SUCCESS == SHCopyKey(HKEY_CLASSES_ROOT, szKey, hkeyNew, 0))
{
if (RSSetTextValue(TEXT("shell"), NULL, pszVerb, REG_OPTION_NON_VOLATILE))
{
hr = S_OK;
}
}
RegCloseKey(hkeyNew);
}
return hr;
}
BOOL CMountPoint::_ProcessAutoRunFile()
{
BOOL fRet = TRUE;
if (!_fAutorunFileProcessed)
{
BOOL fProcessFile = FALSE;
if (_IsCDROM())
{
CMtPtLocal* pmtptlocal = (CMtPtLocal*)this;
// not CDs with no media, or no autorun.inf files
if (pmtptlocal->_IsMediaPresent())
{
if (!pmtptlocal->_CanUseVolume())
{
fProcessFile = TRUE;
}
else
{
if ((HWDMC_HASAUTORUNINF & pmtptlocal->_pvol->dwMediaCap) &&
!(HWDMC_HASUSEAUTOPLAY & pmtptlocal->_pvol->dwMediaCap))
{
fProcessFile = TRUE;
}
}
}
}
else
{
if (_IsRemote())
{
fProcessFile = TRUE;
}
else
{
if (_IsFixedDisk())
{
fProcessFile = TRUE;
}
}
}
if (fProcessFile)
{
LPCTSTR pszSection;
TCHAR szInfFile[MAX_PATH];
TCHAR szKeys[512];
TCHAR szValue[MAX_PATH];
TCHAR szIcon[MAX_PATH + 12]; // MAX_PATH + room for ",1000000000" (for icon index part)
LPTSTR pszKey;
int iDrive = 0;
RSDeleteSubKey(TEXT("Shell"));
if (_IsMountedOnDriveLetter())
{
iDrive = DRIVEID(_GetName());
}
// build abs path to AutoRun.inf
lstrcpyn(szInfFile, _GetName(), ARRAYSIZE(szInfFile));
lstrcat(szInfFile, TEXT("AutoRun.inf"));
#if defined(_X86_)
pszSection = TEXT("AutoRun.x86");
#elif defined(_IA64_)
pszSection = TEXT("AutoRun.Ia64");
#elif defined(_AMD64_)
pszSection = TEXT("AutoRun.Amd64");
#endif
//
// 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
//
UINT err = SetErrorMode(SEM_FAILCRITICALERRORS);
if (!PathFileExistsAndAttributes(szInfFile, NULL))
{
SetErrorMode(err);
_fAutorunFileProcessed = TRUE;
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);
#if defined(_X86_)
pszSection = TEXT("AutoRun.x86");
#elif defined(_IA64_)
pszSection = TEXT("AutoRun.Ia64");
#endif
int i = GetPrivateProfileString(pszSection, NULL, c_szNULL, szKeys, ARRAYSIZE(szKeys), szInfFile);
// if we fail to find a platform-specific AutoRun section, fall
// back to looking for the naked "AutoRun" section.
if (0 == i)
{
pszSection = TEXT("AutoRun");
i = GetPrivateProfileString(pszSection, NULL, c_szNULL, szKeys, ARRAYSIZE(szKeys), szInfFile);
}
SetErrorMode(err);
if (i >= 4)
{
//
// make sure the external strings are what we think.
//
ASSERT(lstrcmpi(c_szOpen,TEXT("open")) == 0);
ASSERT(lstrcmpi(c_szShell, TEXT("shell")) == 0);
// now walk all the keys in the .inf file and copy them to the registry.
for (pszKey = szKeys; *pszKey; pszKey += lstrlen(pszKey) + 1)
{
GetPrivateProfileString(pszSection, pszKey,
c_szNULL, szValue, ARRAYSIZE(szValue), szInfFile);
//
// special case open =
//
if (lstrcmpi(pszKey, c_szOpen) == 0)
{
if (_IsMountedOnDriveLetter())
{
RSSetTextValue(c_szShell, NULL, TEXT("AutoRun"));
_QualifyCommandToDrive(szValue);
RSSetTextValue(TEXT("shell\\AutoRun\\command"), NULL, szValue);
LoadString(HINST_THISDLL, IDS_MENUAUTORUN, szValue, ARRAYSIZE(szValue));
RSSetTextValue(TEXT("shell\\AutoRun"), NULL, szValue);
}
}
//
// special case ShellExecute
//
else if (lstrcmpi(pszKey, TEXT("ShellExecute")) == 0)
{
if (_IsMountedOnDriveLetter())
{
TCHAR szPath[MAX_PATH];
StrCpyN(szPath, TEXT("RunDLL32.EXE Shell32.DLL,ShellExec_RunDLL "), ARRAYSIZE(szPath));
StrCatBuff(szPath, szValue, ARRAYSIZE(szPath));
RSSetTextValue(c_szShell, NULL, TEXT("AutoRun"));
RSSetTextValue(TEXT("shell\\AutoRun\\command"), NULL, szPath);
LoadString(HINST_THISDLL, IDS_MENUAUTORUN, szValue, ARRAYSIZE(szValue));
RSSetTextValue(TEXT("shell\\AutoRun"), NULL, szValue);
}
}
//
// special case icon =
// make sure the icon file has a full path...
//
else if (lstrcmpi(pszKey, TEXT("Icon")) == 0)
{
lstrcpyn(szIcon, _GetName(), ARRAYSIZE(szIcon));
lstrcatn(szIcon, szValue, ARRAYSIZE(szIcon));
RSSetTextValue(TEXT("_Autorun\\DefaultIcon"), NULL, szIcon);
}
//
// special case label =
// make sure the label file has a full path...
//
else if (lstrcmpi(pszKey, TEXT("Label")) == 0)
{
RSSetTextValue(TEXT("_Autorun\\DefaultLabel"), NULL, szValue);
}
//
// special case shell = open
// We have an autorun file but this puts open as the default verb
// so we force it to be Autorun
//
else if (!lstrcmpi(pszKey, TEXT("shell")) && !lstrcmpi(szValue, TEXT("open")))
{
if (_IsMountedOnDriveLetter())
{
RSSetTextValue(pszKey, NULL, TEXT("Autorun"));
}
}
//
// it is just a key/value pair copy it over.
//
else
{
if (_IsMountedOnDriveLetter())
{
if (lstrcmpi(PathFindFileName(pszKey), c_szCommand) == 0)
_QualifyCommandToDrive(szValue);
RSSetTextValue(pszKey, NULL, szValue);
}
}
}
}
else
{
fRet = FALSE;
}
}
_fAutorunFileProcessed = TRUE;
}
return fRet;
}
// sends the "QueryCancelAutoPlay" msg to the window to see if it wants
// to cancel the autoplay. useful for dialogs that are prompting for disk
// inserts or cases where the app wants to capture the event and not let
// other apps be run
// static
BOOL CMountPoint::_AppAllowsAutoRun(HWND hwndApp, CMountPoint* pmtpt)
{
ULONG_PTR dwCancel = 0;
DWORD dwType = pmtpt->_GetAutorunContentType();
WCHAR cDrive = pmtpt->_GetNameFirstCharUCase();
int iDrive = cDrive - TEXT('A');
SendMessageTimeout(hwndApp, QueryCancelAutoPlayMsg(), iDrive, dwType, SMTO_NORMAL | SMTO_ABORTIFHUNG,
1000, &dwCancel);
return (dwCancel == 0);
}
STDAPI SHCreateQueryCancelAutoPlayMoniker(IMoniker** ppmoniker)
{
return CreateClassMoniker(CLSID_QueryCancelAutoPlay, ppmoniker);
}
struct QUERRYRUNNINGOBJECTSTRUCT
{
WCHAR szMountPoint[MAX_PATH];
DWORD dwContentType;
WCHAR szLabel[MAX_LABEL];
DWORD dwSerialNumber;
};
BOOL _RegValueExist(HKEY hkey, LPCWSTR pszKey, LPCWSTR pszValue)
{
BOOL fRet = FALSE;
HKEY hkeySub;
if (ERROR_SUCCESS == RegOpenKeyEx(hkey, pszKey, 0, MAXIMUM_ALLOWED, &hkeySub))
{
fRet = (RegQueryValueEx(hkeySub, pszValue, 0, NULL, NULL, NULL) ==
ERROR_SUCCESS);
RegCloseKey(hkeySub);
}
return fRet;
}
BOOL _ShouldQueryMoniker(IMoniker* pmoniker, IBindCtx* pbindctx)
{
BOOL fRet = FALSE;
DWORD dwMkSys;
HRESULT hr = pmoniker->IsSystemMoniker(&dwMkSys);
if (S_OK == hr)
{
// Is it a class moniker?
if (MKSYS_CLASSMONIKER == dwMkSys)
{
// Yes
LPWSTR pszDisplayName;
hr = pmoniker->GetDisplayName(pbindctx, NULL, &pszDisplayName);
if (SUCCEEDED(hr))
{
// We should get a "clsid:331F1768-05A9-4ddd-B86E-DAE34DDC998A:"
// 37, because we do not have brackets and to explicitly truncate the trailing ":"
WCHAR szCLSID[37];
// The "+ 6" skips the "clsid:" part
StrCpyN(szCLSID, pszDisplayName + 6, ARRAYSIZE(szCLSID));
fRet = _RegValueExist(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\CancelAutoplay\\CLSID"),
szCLSID);
CoTaskMemFree(pszDisplayName);
}
}
}
return fRet;
}
DWORD WINAPI _QueryRunningObjectThreadProc(void* pv)
{
QUERRYRUNNINGOBJECTSTRUCT* pqro = (QUERRYRUNNINGOBJECTSTRUCT*)pv;
HRESULT hrRet = S_OK;
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
IRunningObjectTable* prot;
hr = GetRunningObjectTable(0, &prot);
if (SUCCEEDED(hr))
{
IMoniker* pmoniker;
IBindCtx* pbindctx;
hr = CreateBindCtx(0, &pbindctx);
if (SUCCEEDED(hr))
{
BIND_OPTS2 bindopts;
ZeroMemory(&bindopts, sizeof(bindopts));
bindopts.cbStruct = sizeof(bindopts);
bindopts.dwClassContext = CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD;
hr = pbindctx->SetBindOptions(&bindopts);
if (SUCCEEDED(hr))
{
HKEY hkey;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\CancelAutoplay\\CLSID"),
0, MAXIMUM_ALLOWED, &hkey))
{
DWORD dwIndex = 0;
WCHAR szCLSID[39] = TEXT("{");
DWORD cchCLSID = ARRAYSIZE(szCLSID) - 1;
while ((S_FALSE != hrRet) &&
(ERROR_SUCCESS == RegEnumValue(hkey, dwIndex, &(szCLSID[1]),
&cchCLSID, 0, 0, 0, 0)))
{
CLSID clsid;
szCLSID[37] = TEXT('}');
szCLSID[38] = 0;
hr = CLSIDFromString(szCLSID, &clsid);
if (SUCCEEDED(hr))
{
IMoniker* pmoniker;
// Create the moniker that we'll put in the ROT
hr = CreateClassMoniker(clsid, &pmoniker);
if (SUCCEEDED(hr))
{
IUnknown* punk;
hr = prot->GetObject(pmoniker, &punk);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
IQueryCancelAutoPlay* pqca;
hr = punk->QueryInterface(IID_PPV_ARG(IQueryCancelAutoPlay, &pqca));
if (SUCCEEDED(hr))
{
hrRet = pqca->AllowAutoPlay(pqro->szMountPoint, pqro->dwContentType,
pqro->szLabel, pqro->dwSerialNumber);
pqca->Release();
}
punk->Release();
}
pmoniker->Release();
}
}
++dwIndex;
cchCLSID = ARRAYSIZE(szCLSID) - 1;
}
RegCloseKey(hkey);
}
}
pbindctx->Release();
}
if (S_FALSE != hrRet)
{
// This case is to support WMP and CD burning. We did not get to replace
// their cancel logic before shipping.
hr = SHCreateQueryCancelAutoPlayMoniker(&pmoniker);
if (SUCCEEDED(hr))
{
IUnknown* punk;
hr = prot->GetObject(pmoniker, &punk);
if (SUCCEEDED(hr) && (S_FALSE != hr))
{
IQueryCancelAutoPlay* pqca;
hr = punk->QueryInterface(IID_PPV_ARG(IQueryCancelAutoPlay, &pqca));
if (SUCCEEDED(hr))
{
hrRet = pqca->AllowAutoPlay(pqro->szMountPoint, pqro->dwContentType,
pqro->szLabel, pqro->dwSerialNumber);
pqca->Release();
}
punk->Release();
}
pmoniker->Release();
}
}
prot->Release();
}
CoUninitialize();
}
LocalFree((HLOCAL)pqro);
return (DWORD)hrRet;
}
// static
HRESULT CMountPoint::_QueryRunningObject(CMountPoint* pmtpt, DWORD dwAutorunContentType, BOOL* pfAllow)
{
*pfAllow = TRUE;
QUERRYRUNNINGOBJECTSTRUCT *pqro;
HRESULT hr = SHLocalAlloc(sizeof(*pqro), &pqro);
if (SUCCEEDED(hr))
{
WCHAR szLabel[MAX_LABEL];
if (!(ARCONTENT_BLANKCD & dwAutorunContentType) &&
!(ARCONTENT_BLANKDVD & dwAutorunContentType))
{
if (pmtpt->_GetGVILabel(szLabel, ARRAYSIZE(szLabel)))
{
lstrcpyn(pqro->szLabel, szLabel, ARRAYSIZE(pqro->szLabel));
pmtpt->_GetSerialNumber(&(pqro->dwSerialNumber));
}
}
lstrcpyn(pqro->szMountPoint, pmtpt->_GetName(), ARRAYSIZE(pqro->szMountPoint));
pqro->dwContentType = dwAutorunContentType;
HANDLE hThread = CreateThread(NULL, 0, _QueryRunningObjectThreadProc,
pqro, 0, NULL);
if (hThread)
{
// thread now owns these guys, NULL them out to avoid dbl free
pqro = NULL; // don't free this below
hr = S_FALSE;
// Wait 3 sec to see if wants to process it. If not, it's
// fair play for us.
DWORD dwWait = WaitForSingleObject(hThread, 3000);
if (WAIT_OBJECT_0 == dwWait)
{
// Return within time and did not failed
DWORD dwExitCode;
if (GetExitCodeThread(hThread, &dwExitCode))
{
HRESULT hrHandlesEvent = (HRESULT)dwExitCode;
// Will return S_FALSE if they do NOT allow AutoRun
if (SUCCEEDED(hrHandlesEvent) && (S_FALSE == hrHandlesEvent))
{
*pfAllow = FALSE;
}
hr = S_OK;
}
}
CloseHandle(hThread);
}
else
{
hr = E_OUTOFMEMORY;
}
LocalFree((HLOCAL)pqro); // may be NULL
}
return hr;
}
CAutoPlayParams::CAutoPlayParams(LPCWSTR pszDrive, CMountPoint* pMtPt, DWORD dwAutorunFlags)
: _pszDrive(pszDrive),
_pmtpt(pMtPt),
_dwAutorunFlags(dwAutorunFlags),
_state(APS_RESET),
_pdo(NULL),
_fCheckAlwaysDoThisCheckBox(FALSE)
{
_dwDriveType = pMtPt->_GetMTPTDriveType();
_dwContentType = pMtPt->_GetMTPTContentType();
if (DT_ANYLOCALDRIVES & _dwDriveType)
_pmtptl = (CMtPtLocal*)pMtPt;
else
_pmtptl = NULL;
// maybe assert on these?
}
BOOL CAutoPlayParams::_ShouldSniffDrive(BOOL fCheckHandlerDefaults)
{
BOOL fSniff = FALSE;
if (_pmtptl)
{
if (CT_AUTORUNINF & _dwContentType)
{
if (_pmtptl->_CanUseVolume())
{
if (_pmtptl->_pvol->dwMediaCap & HWDMC_HASUSEAUTOPLAY)
{
fSniff = TRUE;
}
}
}
else
{
fSniff = TRUE;
}
if (fSniff)
{
fSniff = FALSE;
if (!((CT_CDAUDIO | CT_DVDMOVIE) & _dwContentType))
{
if (_pmtptl->_CanUseVolume())
{
if (!(HWDVF_STATE_HASAUTOPLAYHANDLER & _pmtptl->_pvol->dwVolumeFlags) &&
!(HWDVF_STATE_DONOTSNIFFCONTENT & _pmtptl->_pvol->dwVolumeFlags))
{
if (AUTORUNFLAG_MENUINVOKED & _dwAutorunFlags)
{
fSniff = TRUE;
}
else if (DT_FIXEDDISK & _dwDriveType)
{
if (HWDDC_REMOVABLEDEVICE & _pmtptl->_pvol->dwDriveCapability)
{
fSniff = TRUE;
}
}
else
{
if (AUTORUNFLAG_MEDIAARRIVAL & _dwAutorunFlags)
{
fSniff = TRUE;
}
else
{
if (AUTORUNFLAG_MTPTARRIVAL & _dwAutorunFlags)
{
if (HWDDC_REMOVABLEDEVICE & _pmtptl->_pvol->dwDriveCapability)
{
fSniff = TRUE;
}
}
}
}
}
}
}
}
}
if (fSniff && fCheckHandlerDefaults)
{
// Let's make sure the user did not pick "Take no action" for all Autoplay
// content types, it would be useless to sniff.
BOOL fAllTakeNoAction = TRUE;
DWORD rgdwContentType[] =
{
CT_AUTOPLAYMUSIC,
CT_AUTOPLAYPIX,
CT_AUTOPLAYMOVIE,
CT_AUTOPLAYMUSIC | CT_AUTOPLAYPIX | CT_AUTOPLAYMOVIE, // Mix content
};
for (DWORD dw = 0; fAllTakeNoAction && (dw < ARRAYSIZE(rgdwContentType)); ++dw)
{
WCHAR szContentTypeHandler[MAX_CONTENTTYPEHANDLER];
DWORD dwMtPtContentType = rgdwContentType[dw];
HRESULT hr = _GetContentTypeHandler(dwMtPtContentType, szContentTypeHandler, ARRAYSIZE(szContentTypeHandler));
if (SUCCEEDED(hr))
{
IAutoplayHandler* piah;
hr = _GetAutoplayHandler(Drive(), TEXT("ContentArrival"), szContentTypeHandler, &piah);
if (SUCCEEDED(hr))
{
LPWSTR pszHandlerDefault;
hr = piah->GetDefaultHandler(&pszHandlerDefault);
if (SUCCEEDED(hr))
{
if (HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED &
HANDLERDEFAULT_GETFLAGS(hr))
{
fAllTakeNoAction = FALSE;
}
else
{
if (lstrcmpi(pszHandlerDefault, TEXT("MSTakeNoAction")))
{
fAllTakeNoAction = FALSE;
}
}
CoTaskMemFree(pszHandlerDefault);
}
piah->Release();
}
}
}
if (fAllTakeNoAction)
{
fSniff = FALSE;
}
}
return fSniff;
}
DWORD CAutoPlayParams::ContentType()
{
return _dwContentType;
}
HRESULT CAutoPlayParams::_InitObjects(IShellFolder **ppsf)
{
HRESULT hr;
if (!_pdo || ppsf)
{
LPITEMIDLIST pidlFolder;
hr = SHParseDisplayName(_pszDrive, NULL, &pidlFolder, 0, NULL);
if (SUCCEEDED(hr))
{
hr = SHGetUIObjectOf(pidlFolder, NULL, IID_PPV_ARG(IDataObject, &_pdo));
ILFree(pidlFolder);
}
}
else
{
hr = S_OK;
}
if (SUCCEEDED(hr) && ppsf)
{
// we need to avoid hitting the burn folder
// so we skip junctions for the sniff
IBindCtx * pbc;
hr = SHCreateSkipBindCtx(NULL, &pbc);
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidlFolder;
hr = SHParseDisplayName(_pszDrive, pbc, &pidlFolder, 0, NULL);
if (SUCCEEDED(hr))
{
hr = SHBindToObjectEx(NULL, pidlFolder, pbc, IID_PPV_ARG(IShellFolder, ppsf));
ILFree(pidlFolder);
}
pbc->Release();
}
}
return hr;
}
HRESULT CAutoPlayParams::_AddWalkToDataObject(INamespaceWalk* pnsw)
{
UINT cidl;
LPITEMIDLIST *apidl;
HRESULT hr = pnsw->GetIDArrayResult(&cidl, &apidl);
if (SUCCEEDED(hr))
{
// we need to add this back in
if (cidl)
{
// ragged array
HIDA hida = HIDA_Create(&c_idlDesktop, cidl, (LPCITEMIDLIST *)apidl);
if (hida)
{
IDLData_InitializeClipboardFormats(); // init our registerd formats
// should we free hida on FAILED?
DataObj_SetGlobal(_pdo, g_cfAutoPlayHIDA, hida);
}
}
FreeIDListArray(apidl, cidl);
}
return hr;
}
HRESULT CAutoPlayParams::_Sniff(DWORD *pdwFound)
{
// we found nothing
HRESULT hr = S_FALSE;
*pdwFound = 0;
if (_pmtptl->_CanUseVolume())
{
// setup the IDataObject and IShellFolder for the walk
IShellFolder *psf;
HRESULT hr = _InitObjects(&psf);
if (SUCCEEDED(hr))
{
INamespaceWalk* pnsw;
hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC, IID_PPV_ARG(INamespaceWalk, &pnsw));
if (SUCCEEDED(hr))
{
CSniffDrive sniff;
hr = sniff.RegisterForNotifs(_pmtptl->_pvol->pszDeviceIDVolume);
if (SUCCEEDED(hr))
{
// We don't care about the return value. WE don't want to stop Autorun for as much.
// If sniffing fail we go on with what we have.
if (SUCCEEDED(pnsw->Walk(psf, NSWF_IGNORE_AUTOPLAY_HIDA | NSWF_DONT_TRAVERSE_LINKS | NSWF_SHOW_PROGRESS, 4, &sniff)))
{
// we keep everything we found
_AddWalkToDataObject(pnsw);
}
sniff.UnregisterForNotifs();
*pdwFound = sniff.Found();
}
pnsw->Release();
}
psf->Release();
}
}
return hr;
}
// BEGIN: Fcts for matrix below
//
BOOL CMountPoint::_acShiftKeyDown(HWND , CAutoPlayParams *)
{
return (GetAsyncKeyState(VK_SHIFT) < 0);
}
BOOL _IsDirectXExclusiveMode()
{
BOOL fRet = FALSE;
// This code determines whether a DirectDraw 7 process (game) is running and
// whether it's exclusively holding the video to the machine in full screen mode.
// The code is probably to be considered untrusted and hence is wrapped in a
// __try / __except block. It could AV and therefore bring down shell
// with it. Not very good. If the code does raise an exception the release
// call is skipped. Tough. Don't trust the release method either.
IDirectDraw7 *pIDirectDraw7 = NULL;
HRESULT hr = CoCreateInstance(CLSID_DirectDraw7, NULL, CLSCTX_INPROC_SERVER,
IID_IDirectDraw7, (void**)&pIDirectDraw7);
if (SUCCEEDED(hr))
{
ASSERT(pIDirectDraw7);
__try
{
hr = IDirectDraw7_Initialize(pIDirectDraw7, NULL);
if (DD_OK == hr)
{
fRet = (IDirectDraw7_TestCooperativeLevel(pIDirectDraw7) ==
DDERR_EXCLUSIVEMODEALREADYSET);
}
IDirectDraw7_Release(pIDirectDraw7);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
return fRet;
}
// From a mail regarding the DirectX fct below:
//
// You can definitely count on the following:
//
// (1) If shadow cursors are on, there is definitely not an exclusive mode app running.
// (2) If hot tracking is on, there is definitely not an exclusive mode app running.
// (3) If message boxes for SEM_NOGPFAULTERRORBOX, SEM_FAILCRITICALERRORS, or
// SEM_NOOPENFILEERRORBOX have not been disabled via SetErrorMode, then there
// is definitely not an exclusive mode app running.
//
// Note: we cannot use (3) since this is per-process.
BOOL CMountPoint::_acDirectXAppRunningFullScreen(HWND hwndForeground, CAutoPlayParams *)
{
BOOL fRet = FALSE;
BOOL fSPI;
if (SystemParametersInfo(SPI_GETCURSORSHADOW, 0, &fSPI, 0) && !fSPI)
{
if (SystemParametersInfo(SPI_GETHOTTRACKING, 0, &fSPI, 0) && !fSPI)
{
// There's a chance that a DirectX app is running full screen. Let's do the
// expensive DirectX calls that will tell us for sure.
fRet = _IsDirectXExclusiveMode();
}
}
return fRet;
}
BOOL CMountPoint::_acCurrentDesktopIsActiveConsole(HWND , CAutoPlayParams *)
{
BOOL fRetValue = FALSE; // block auto-run/auto-play if we can't determine our state.
if (0 == GetSystemMetrics(SM_REMOTESESSION))
{
//
// We are not remoted. See if we are the active console session.
//
BOOL b;
DWORD dwProcessSession;
b = ProcessIdToSessionId(GetCurrentProcessId(), &dwProcessSession);
if (b)
{
DWORD dwConsoleSession = WTSGetActiveConsoleSessionId( );
if ( dwProcessSession == dwConsoleSession )
{
//
// See if the screen saver is running.
//
BOOL b;
BOOL fScreenSaver;
b = SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0, &fScreenSaver, 0 );
if (b)
{
if (!fScreenSaver)
{
//
// We made it here, we must be the active console session without a
// screen saver.
//
HDESK hDesk = OpenInputDesktop( 0, FALSE, DESKTOP_CREATEWINDOW );
if ( NULL != hDesk )
{
//
// We have access to the current desktop which should indicate that
// WinLogon isn't.
//
CloseDesktop( hDesk );
fRetValue = TRUE;
}
// else "WinLogon" has the "desktop"... don't allow auto-run/auto-play.
}
// else a screen saver is running... don't allow auto-run/auto-play.
}
// else we are in an undeterminate state... don't allow auto-run/auto-play.
}
// else we aren't the console... don't allow auto-run/auto-play
}
// else we are in an undeterminate state... don't allow auto-run/auto-play.
}
// else we are remoted... don't allow auto-run/auto-play.
return fRetValue;
}
BOOL CMountPoint::_acDriveIsMountedOnDriveLetter(HWND , CAutoPlayParams *papp)
{
return _IsDriveLetter(papp->Drive());
}
BOOL CMountPoint::_acDriveIsRestricted(HWND , CAutoPlayParams *papp)
{
BOOL fIsRestricted = (SHRestricted(REST_NODRIVES) & (1 << DRIVEID(papp->Drive())));
if (!fIsRestricted)
{
fIsRestricted = !(papp->MountPoint()->_IsAutoRunDrive());
}
return fIsRestricted;
}
BOOL CMountPoint::_acHasAutorunCommand(HWND , CAutoPlayParams *papp)
{
BOOL fRet = FALSE;
if ((papp->IsContentTypePresent(CT_AUTORUNINF)) &&
(DT_ANYLOCALDRIVES & papp->DriveType()))
{
CMtPtLocal* pmtptl = (CMtPtLocal*)papp->MountPoint();
if (pmtptl->_CanUseVolume())
{
if (pmtptl->_pvol->dwMediaCap & HWDMC_HASAUTORUNCOMMAND)
{
fRet = TRUE;
}
}
else
{
fRet = papp->MountPoint()->_IsAutorun();
}
}
else
{
fRet = papp->IsContentTypePresent(CT_AUTORUNINF);
}
return fRet;
}
BOOL CMountPoint::_acHasUseAutoPLAY(HWND , CAutoPlayParams *papp)
{
BOOL fRet = FALSE;
if (papp->IsContentTypePresent(CT_AUTORUNINF) &&
(DT_ANYLOCALDRIVES & papp->DriveType()))
{
CMtPtLocal* pmtptl = (CMtPtLocal*)papp->MountPoint();
if (pmtptl->_CanUseVolume())
{
if (pmtptl->_pvol->dwMediaCap & HWDMC_HASUSEAUTOPLAY)
{
fRet = TRUE;
}
}
else
{
// If we're here, most likely the ShellService is not running, so we won't be able to
// Autoplay anyway.
fRet = FALSE;
}
}
else
{
// not supported for remote drives
}
return fRet;
}
BOOL CMountPoint::_acForegroundAppAllowsAutorun(HWND hwndForeground, CAutoPlayParams *papp)
{
return _AppAllowsAutoRun(hwndForeground, papp->MountPoint());
}
static const TWODWORDS allcontentsVSarcontenttypemappings[] =
{
{ CT_AUTORUNINF , ARCONTENT_AUTORUNINF },
{ CT_CDAUDIO , ARCONTENT_AUDIOCD },
{ CT_DVDMOVIE , ARCONTENT_DVDMOVIE },
{ CT_UNKNOWNCONTENT , ARCONTENT_UNKNOWNCONTENT },
{ CT_BLANKCDR , ARCONTENT_BLANKCD },
{ CT_BLANKCDRW , ARCONTENT_BLANKCD },
{ CT_BLANKDVDR , ARCONTENT_BLANKDVD },
{ CT_BLANKDVDRW , ARCONTENT_BLANKDVD },
{ CT_AUTOPLAYMUSIC , ARCONTENT_AUTOPLAYMUSIC },
{ CT_AUTOPLAYPIX , ARCONTENT_AUTOPLAYPIX },
{ CT_AUTOPLAYMOVIE , ARCONTENT_AUTOPLAYVIDEO },
};
BOOL CMountPoint::_acQueryCancelAutoplayAllowsAutorun(HWND , CAutoPlayParams *papp)
{
BOOL fAllow = TRUE;
DWORD dwAutorunContentType = _DoDWORDMapping(papp->ContentType(),
allcontentsVSarcontenttypemappings, ARRAYSIZE(allcontentsVSarcontenttypemappings),
TRUE);
_QueryRunningObject(papp->MountPoint(), dwAutorunContentType, &fAllow);
return fAllow;
}
BOOL CMountPoint::_acUserHasSelectedApplication(HWND hwndForeground, CAutoPlayParams *papp)
{
BOOL fRet = FALSE;
WCHAR szContentTypeHandler[MAX_CONTENTTYPEHANDLER];
DWORD dwMtPtContentType = papp->ContentType() & ~CT_UNKNOWNCONTENT;
HRESULT hr = _GetContentTypeHandler(dwMtPtContentType, szContentTypeHandler, ARRAYSIZE(szContentTypeHandler));
if (SUCCEEDED(hr))
{
IAutoplayHandler* piah;
hr = _GetAutoplayHandler(papp->Drive(), TEXT("ContentArrival"), szContentTypeHandler, &piah);
if (SUCCEEDED(hr))
{
LPWSTR pszHandlerDefault;
hr = piah->GetDefaultHandler(&pszHandlerDefault);
if (SUCCEEDED(hr))
{
if (HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED &
HANDLERDEFAULT_GETFLAGS(hr))
{
fRet = FALSE;
}
else
{
if (HANDLERDEFAULT_USERCHOSENDEFAULT &
HANDLERDEFAULT_GETFLAGS(hr))
{
fRet = lstrcmpi(pszHandlerDefault, TEXT("MSPromptEachTime"));
}
else
{
fRet = FALSE;
}
}
if (!fRet)
{
if (((HANDLERDEFAULT_USERCHOSENDEFAULT &
HANDLERDEFAULT_GETFLAGS(hr)) ||
(HANDLERDEFAULT_EVENTHANDLERDEFAULT &
HANDLERDEFAULT_GETFLAGS(hr))) &&
!(HANDLERDEFAULT_DEFAULTSAREDIFFERENT &
HANDLERDEFAULT_GETFLAGS(hr)))
{
papp->_fCheckAlwaysDoThisCheckBox = TRUE;
}
}
CoTaskMemFree(pszHandlerDefault);
}
piah->Release();
}
}
return fRet;
}
BOOL CMountPoint::_acShellIsForegroundApp(HWND hwndForeground, CAutoPlayParams *papp)
{
BOOL fRet = FALSE;
WCHAR szModule[MAX_PATH];
if (GetWindowModuleFileName(hwndForeground, szModule, ARRAYSIZE(szModule)))
{
if (!lstrcmpi(PathFindFileName(szModule), TEXT("explorer.exe")))
{
fRet = TRUE;
}
}
return fRet;
}
BOOL CMountPoint::_acOSIsServer(HWND , CAutoPlayParams *papp)
{
return IsOS(OS_ANYSERVER);
}
BOOL CMountPoint::_acIsDockedLaptop(HWND hwndForeground, CAutoPlayParams *papp)
{
return (GMID_DOCKED & SHGetMachineInfo(GMI_DOCKSTATE));
}
BOOL CMountPoint::_acDriveIsFormatted(HWND hwndForeground, CAutoPlayParams *papp)
{
return papp->MountPoint()->IsFormatted();
}
BOOL CMountPoint::_acShellExecuteDriveAutorunINF(HWND hwndForeground, CAutoPlayParams *papp)
{
SHELLEXECUTEINFO ei = {
sizeof(ei), // size
SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI, // flags
NULL,
NULL, // verb
papp->Drive(), // file
papp->Drive(), // params
papp->Drive(), // directory
SW_NORMAL, // show.
NULL, // hinstance
NULL, // IDLIST
NULL, // class name
NULL, // class key
0, // hot key
NULL, // icon
NULL, // hProcess
};
return ShellExecuteEx(&ei);
}
HRESULT _InvokeAutoRunProgid(HKEY hkProgid, LPCWSTR pszVerb, IDataObject *pdo)
{
IShellExtInit *psei;
HRESULT hr = CoCreateInstance(CLSID_ShellFileDefExt, NULL, CLSCTX_INPROC, IID_PPV_ARG(IShellExtInit, &psei));
if (SUCCEEDED(hr))
{
hr = psei->Initialize(NULL, pdo, hkProgid);
if (SUCCEEDED(hr))
{
IContextMenu *pcm;
hr = psei->QueryInterface(IID_PPV_ARG(IContextMenu, &pcm));
if (SUCCEEDED(hr))
{
CHAR szVerb[64];
// maybe hwnd
// maybe punkSite
// maybe ICI flags
SHUnicodeToAnsi(pszVerb, szVerb, ARRAYSIZE(szVerb));
hr = SHInvokeCommandOnContextMenu(NULL, NULL, pcm, 0, szVerb);
pcm->Release();
}
}
psei->Release();
}
return hr;
}
HRESULT _GetProgidAndVerb(DWORD dwContentType, PCWSTR pszHandler, PWSTR pszInvokeProgID,
DWORD cchInvokeProgID, PWSTR pszInvokeVerb, DWORD cchInvokeVerb)
{
HRESULT hr;
if (0 == StrCmpI(pszHandler, TEXT("AutoplayLegacyHandler")) && (dwContentType & (CT_CDAUDIO | CT_DVDMOVIE)))
{
HKEY hkey;
BOOL fGotDefault = FALSE;
if (dwContentType & CT_CDAUDIO)
{
StrCpyN(pszInvokeProgID, TEXT("AudioCD"), cchInvokeProgID);
}
else
{
ASSERT(dwContentType & CT_DVDMOVIE);
StrCpyN(pszInvokeProgID, TEXT("DVD"), cchInvokeProgID);
}
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, pszInvokeProgID, 0, MAXIMUM_ALLOWED,
&hkey))
{
HKEY hkey2;
if (ERROR_SUCCESS == RegOpenKeyEx(hkey, TEXT("shell"), 0, MAXIMUM_ALLOWED,
&hkey2))
{
DWORD cbInvokeVerb = cchInvokeVerb * sizeof(WCHAR);
if (ERROR_SUCCESS == RegQueryValueEx(hkey2, NULL, NULL, NULL, (PBYTE)pszInvokeVerb,
&cbInvokeVerb))
{
if (cbInvokeVerb && *pszInvokeVerb)
{
if (cbInvokeVerb != (cchInvokeVerb * sizeof(WCHAR)))
{
fGotDefault = TRUE;
}
}
}
RegCloseKey(hkey2);
}
RegCloseKey(hkey);
}
if (!fGotDefault)
{
StrCpyN(pszInvokeVerb, TEXT("play"), cchInvokeVerb);
}
hr = S_OK;
}
else
{
hr = _GetHandlerInvokeProgIDAndVerb(pszHandler, pszInvokeProgID,
cchInvokeProgID, pszInvokeVerb, cchInvokeVerb);
}
return hr;
}
BOOL CMountPoint::_ExecuteHelper(LPCWSTR pszHandler, LPCWSTR pszContentTypeHandler,
CAutoPlayParams *papp, DWORD dwMtPtContentType)
{
HRESULT hr;
if (lstrcmpi(pszHandler, TEXT("MSTakeNoAction")))
{
WCHAR szInvokeProgID[260];
WCHAR szInvokeVerb[CCH_KEYMAX];
hr = _GetProgidAndVerb(dwMtPtContentType, pszHandler, szInvokeProgID,
ARRAYSIZE(szInvokeProgID), szInvokeVerb, ARRAYSIZE(szInvokeVerb));
if (SUCCEEDED(hr))
{
HKEY hkey;
if (dwMtPtContentType & (CT_CDAUDIO | CT_DVDMOVIE))
{
hr = papp->MountPoint()->_CopyInvokeVerbKey(szInvokeProgID, szInvokeVerb);
hkey = papp->MountPoint()->RSDuplicateRootKey();
papp->MountPoint()->RSSetTextValue(TEXT("shell"), NULL, szInvokeVerb, REG_OPTION_NON_VOLATILE);
}
else
{
hr = ResultFromWin32(RegOpenKeyExW(HKEY_CLASSES_ROOT, szInvokeProgID, 0, MAXIMUM_ALLOWED, &hkey));
}
if (SUCCEEDED(hr))
{
IDataObject* pdo;
hr = papp->DataObject(&pdo);
if (SUCCEEDED(hr))
{
hr = _InvokeAutoRunProgid(hkey, szInvokeVerb, pdo);
pdo->Release();
}
RegCloseKey(hkey);
}
}
}
else
{
hr = S_FALSE;
}
return SUCCEEDED(hr);
}
BOOL CMountPoint::_acExecuteAutoplayDefault(HWND hwndForeground, CAutoPlayParams *papp)
{
BOOL fRet = FALSE;
if (DT_ANYLOCALDRIVES & papp->DriveType())
{
WCHAR szContentTypeHandler[MAX_CONTENTTYPEHANDLER];
DWORD dwMtPtContentType = papp->ContentType() & ~CT_UNKNOWNCONTENT;
HRESULT hr = _GetContentTypeHandler(dwMtPtContentType, szContentTypeHandler, ARRAYSIZE(szContentTypeHandler));
if (SUCCEEDED(hr))
{
IAutoplayHandler* piah;
hr = _GetAutoplayHandler(papp->Drive(), TEXT("ContentArrival"), szContentTypeHandler, &piah);
if (SUCCEEDED(hr))
{
LPWSTR pszHandlerDefault;
hr = piah->GetDefaultHandler(&pszHandlerDefault);
if (SUCCEEDED(hr))
{
// No need to check for (S_HANDLERS_MORE_RECENT_THAN_USER_SELECTION == hr) here
// It should have been caught by _acUserHasSelectedApplication
fRet = _ExecuteHelper(pszHandlerDefault, szContentTypeHandler, papp, dwMtPtContentType);
}
CoTaskMemFree(pszHandlerDefault);
}
piah->Release();
}
}
return fRet;
}
BOOL CMountPoint::_acWasjustDocked(HWND hwndForeground, CAutoPlayParams *papp)
{
BOOL fRet = FALSE;
if (DT_ANYLOCALDRIVES & papp->DriveType())
{
CMtPtLocal* pmtptl = (CMtPtLocal*)papp->MountPoint();
if (pmtptl->_CanUseVolume())
{
if (pmtptl->_pvol->dwVolumeFlags & HWDVF_STATE_JUSTDOCKED)
{
fRet = TRUE;
}
}
}
return fRet;
}
CRITICAL_SECTION g_csAutoplayPrompt = {0};
HDPA g_hdpaAutoplayPrompt = NULL;
BOOL CMountPoint::_acPromptUser(HWND hwndForeground, CAutoPlayParams *papp)
{
BOOL fRet = FALSE;
BOOL fShowDlg = TRUE;
if (papp->Drive())
{
fShowDlg = _AddAutoplayPrompt(papp->Drive());
}
if (fShowDlg)
{
CBaseContentDlg* pdlg;
papp->ForceSniff();
DWORD dwMtPtContentType = papp->ContentType() & ~CT_UNKNOWNCONTENT;
if (dwMtPtContentType)
{
if (_acIsMixedContent(hwndForeground, papp))
{
pdlg = new CMixedContentDlg();
dwMtPtContentType &= CT_ANYAUTOPLAYCONTENT;
if (pdlg)
{
pdlg->_iResource = DLG_APMIXEDCONTENT;
}
}
else
{
pdlg = new CHWContentPromptDlg();
if (pdlg)
{
pdlg->_iResource = DLG_APPROMPTUSER;
}
}
}
if (pdlg)
{
// Better be a local drive
if (DT_ANYLOCALDRIVES & papp->DriveType())
{
CMtPtLocal* pmtptl = (CMtPtLocal*)papp->MountPoint();
if (pmtptl->_CanUseVolume())
{
HRESULT hr = pdlg->Init(pmtptl->_pvol->pszDeviceIDVolume, papp->Drive(), dwMtPtContentType,
papp->_fCheckAlwaysDoThisCheckBox);
pdlg->_hinst = g_hinst;
pdlg->_hwndParent = NULL;
if (SUCCEEDED(hr))
{
INT_PTR iRet = pdlg->DoModal(pdlg->_hinst, MAKEINTRESOURCE(pdlg->_iResource),
pdlg->_hwndParent);
if (IDOK == iRet)
{
fRet = _ExecuteHelper(pdlg->_szHandler, pdlg->_szContentTypeHandler,
papp, dwMtPtContentType);
}
}
}
}
pdlg->Release();
}
if (papp->Drive())
{
_RemoveFromAutoplayPromptHDPA(papp->Drive());
}
}
return fRet;
}
BOOL CMountPoint::_acIsMixedContent(HWND hwndForeground, CAutoPlayParams *papp)
{
BOOL fRet;
if (papp->IsContentTypePresent(CT_ANYAUTOPLAYCONTENT))
{
fRet = IsMixedContent(papp->ContentType());
}
else
{
fRet = FALSE;
}
return fRet;
}
BOOL CMountPoint::_acAlwaysReturnsTRUE(HWND hwndForeground, CAutoPlayParams *papp)
{
return TRUE;
}
BOOL CMountPoint::_acShouldSniff(HWND hwndForeground, CAutoPlayParams *papp)
{
BOOL fRet = TRUE;
CMtPtLocal* pmtptl = papp->MountPointLocal();
if (pmtptl)
{
if (pmtptl->_CanUseVolume())
{
fRet = !(HWDVF_STATE_DONOTSNIFFCONTENT & pmtptl->_pvol->dwVolumeFlags);
}
}
return fRet;
}
BOOL CMountPoint::_acAddAutoplayVerb(HWND hwndForeground, CAutoPlayParams *papp)
{
CMtPtLocal* pmtptl = papp->MountPointLocal();
if (pmtptl)
{
if (pmtptl->_CanUseVolume())
{
// We don't care about the return value
pmtptl->_AddAutoplayVerb();
}
}
return TRUE;
}
//
// END: Fcts for matrix below
#define SKIPDEPENDENTS_ONFALSE 0x00000001 // Skips dependents
#define SKIPDEPENDENTS_ONTRUE 0x00000002 // Skips dependents
#define CANCEL_AUTOPLAY_ONFALSE 0x00000004
#define CANCEL_AUTOPLAY_ONTRUE 0x00000008
#define NOTAPPLICABLE_ONANY 0x00000010
#define LEVEL_EXECUTE 0x10000000
#define LEVEL_SKIP 0x20000000
#define LEVEL_SPECIALMASK 0x30000000
#define LEVEL_REALLEVELMASK 0x0FFFFFFF
typedef BOOL (AUTORUNFCT)(HWND hwndForeground, CAutoPlayParams *papp);
// fct is called with pszDrive, papp->MountPoint(), hwndForeground, drive type and content type
struct AUTORUNCONDITION
{
DWORD dwNestingLevel;
DWORD dwMtPtDriveType;
DWORD dwMtPtContentType;
DWORD dwReturnValueHandling;
AUTORUNFCT* fct;
#ifdef DEBUG
LPCWSTR pszDebug;
#endif
};
// For this table to be more readable, add the content of \\stephstm\public\usertype.dat to
// %ProgramFiles%\Microsoft Visual Studio\Common\MSDev98\Bin\usertype.dat
// then restart MSDev
// AR_ENTRY -> AUTORUN_ENTRY
#ifdef DEBUG
#define AR_ENTRY(a, b, c, d, e) { (a), (b), (c), (d), CMountPoint::e, TEXT(#a) TEXT(":") TEXT(#b) TEXT(":") TEXT(#c) TEXT(":") TEXT(#d) TEXT(":") TEXT(#e) }
#else
#define AR_ENTRY(a, b, c, d, e) { (a), (b), (c), (d), CMountPoint::e }
#endif
// DT_* -> DriveType
// CT_* -> ContentType
static const AUTORUNCONDITION _rgAutorun[] =
{
// We don't autorun if the drive is not mounted on a drive letter
AR_ENTRY(0, DT_ANYTYPE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acDriveIsMountedOnDriveLetter),
// We don't autorun if this is a restricted drive
AR_ENTRY(0, DT_ANYTYPE & ~DT_REMOTE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acDriveIsRestricted),
// Add the Autoplay Verb
AR_ENTRY(1, DT_ANYTYPE & ~DT_REMOTE, CT_ANYCONTENT & ~CT_AUTORUNINF, SKIPDEPENDENTS_ONFALSE, _acAddAutoplayVerb),
// We don't autorun if the Shift key is down
AR_ENTRY(0, DT_ANYTYPE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acShiftKeyDown),
// We don't autorun if a laptop was just docked. All devices in the craddle come as nhew devices.
AR_ENTRY(0, DT_ANYTYPE & ~DT_REMOTE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acWasjustDocked),
// We don't autorun if the Current Desktop is not the active console desktop
AR_ENTRY(0, DT_ANYTYPE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acCurrentDesktopIsActiveConsole),
// We don't autorun if the Current Desktop is not the active console desktop
AR_ENTRY(0, DT_ANYTYPE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acDirectXAppRunningFullScreen),
// Remote drive always Autorun (mostly opening folder)
AR_ENTRY(1, DT_REMOTE, CT_ANYCONTENT, SKIPDEPENDENTS_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(1, DT_REMOTE, CT_ANYCONTENT, SKIPDEPENDENTS_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(2 | LEVEL_EXECUTE, DT_REMOTE, CT_ANYCONTENT, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
// Autorun.inf
AR_ENTRY(1, DT_ANYTYPE & ~DT_REMOVABLEDISK, CT_AUTORUNINF, SKIPDEPENDENTS_ONFALSE, _acHasAutorunCommand),
AR_ENTRY(2, DT_ANYTYPE & ~DT_REMOVABLEDISK, CT_AUTORUNINF, SKIPDEPENDENTS_ONTRUE, _acHasUseAutoPLAY),
AR_ENTRY(3, DT_ANYTYPE & ~DT_REMOVABLEDISK, CT_AUTORUNINF, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(3, DT_ANYTYPE & ~DT_REMOVABLEDISK, CT_AUTORUNINF, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(4 | LEVEL_EXECUTE, DT_ANYCDDRIVES, CT_AUTORUNINF, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
// CD Audio
AR_ENTRY(1, DT_ANYCDDRIVES, CT_CDAUDIO, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(1, DT_ANYCDDRIVES, CT_CDAUDIO, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(2, DT_ANYCDDRIVES, CT_CDAUDIO, SKIPDEPENDENTS_ONFALSE, _acUserHasSelectedApplication),
AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYCDDRIVES, CT_CDAUDIO, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
AR_ENTRY(LEVEL_EXECUTE | 1, DT_ANYCDDRIVES, CT_CDAUDIO, NOTAPPLICABLE_ONANY, _acPromptUser),
// DVD Movie
AR_ENTRY(1, DT_ANYCDDRIVES, CT_DVDMOVIE, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(1, DT_ANYCDDRIVES, CT_DVDMOVIE, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(2, DT_ANYCDDRIVES, CT_DVDMOVIE, SKIPDEPENDENTS_ONFALSE, _acUserHasSelectedApplication),
AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYCDDRIVES, CT_DVDMOVIE, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
AR_ENTRY(LEVEL_EXECUTE | 1, DT_ANYCDDRIVES, CT_DVDMOVIE, NOTAPPLICABLE_ONANY, _acPromptUser),
// Writable CDs
AR_ENTRY(1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(2, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, SKIPDEPENDENTS_ONFALSE, _acUserHasSelectedApplication),
AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
AR_ENTRY(LEVEL_EXECUTE | 1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, NOTAPPLICABLE_ONANY, _acPromptUser),
// Writable DVDs
AR_ENTRY(LEVEL_SKIP | 1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(LEVEL_SKIP | 1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(LEVEL_SKIP | 2, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, SKIPDEPENDENTS_ONFALSE, _acUserHasSelectedApplication),
AR_ENTRY(LEVEL_SKIP | 3 | LEVEL_EXECUTE, DT_ANYDVDDRIVES, CT_BLANKDVDWRITABLE, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
AR_ENTRY(LEVEL_SKIP | LEVEL_EXECUTE | 1, DT_ANYDVDDRIVES, CT_BLANKDVDWRITABLE, NOTAPPLICABLE_ONANY, _acPromptUser),
// Mixed content
AR_ENTRY(1, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, SKIPDEPENDENTS_ONFALSE, _acIsMixedContent),
AR_ENTRY(2, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, SKIPDEPENDENTS_ONTRUE, _acUserHasSelectedApplication),
AR_ENTRY(3, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(4 | LEVEL_EXECUTE, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acPromptUser),
AR_ENTRY(LEVEL_EXECUTE | 2, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
// Single Autoplay content
AR_ENTRY(1, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(2, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, SKIPDEPENDENTS_ONTRUE, _acUserHasSelectedApplication),
AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acPromptUser),
AR_ENTRY(LEVEL_EXECUTE | 2, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
// Unknown content
AR_ENTRY(1, DT_ANYREMOVABLEMEDIADRIVES, CT_UNKNOWNCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(1, DT_ANYREMOVABLEMEDIADRIVES, CT_UNKNOWNCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
// If we should not sniff, we should not open a folder either
AR_ENTRY(2, DT_ANYREMOVABLEMEDIADRIVES, CT_UNKNOWNCONTENT, SKIPDEPENDENTS_ONFALSE, _acShouldSniff),
AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYREMOVABLEMEDIADRIVES, CT_UNKNOWNCONTENT, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
// Weird CDs have autorun.inf but no autorun command
AR_ENTRY(2, DT_ANYREMOVABLEMEDIADRIVES, CT_AUTORUNINF, SKIPDEPENDENTS_ONTRUE, _acHasAutorunCommand),
AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYREMOVABLEMEDIADRIVES, CT_AUTORUNINF, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
// Former ShellOpen, basically we ShellExecute whatever drives except CD drives if the shell is in the foreground
AR_ENTRY(1, ~DT_ANYCDDRIVES, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, SKIPDEPENDENTS_ONFALSE, _acShellIsForegroundApp),
AR_ENTRY(2, ~DT_ANYCDDRIVES, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acAlwaysReturnsTRUE),
// Additonnal restrictions on Fixed disk drive
AR_ENTRY(3, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acDriveIsFormatted),
AR_ENTRY(4, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acOSIsServer),
AR_ENTRY(5, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acIsDockedLaptop),
AR_ENTRY(6, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(6, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(7 | LEVEL_EXECUTE, DT_ANYTYPE, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
// Non Fixed Disk drives
AR_ENTRY(3, ~DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
AR_ENTRY(3, ~DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
AR_ENTRY(4 | LEVEL_EXECUTE, ~DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
};
// This array will be dumped in the registry under the Volume GUID of the
// drive in a value named _AutorunStatus
//
// Each byte represents an entry in the above table. Following is the
// meaning of each byte:
//
// 01: Condition was TRUE
// 00: Condition was FALSE
// CF: ContentType condition was failed
// DF: DriveType condition was failed
// 5F: Condition was skipped (5 looks like an 'S' :)
// EE: Condition was executed
// FF: Never got there
// Use a struct to avoid alignement issues
#pragma pack(push, 4)
struct AUTORUNSTATUS
{
BYTE _rgbAutorunStatus[ARRAYSIZE(_rgAutorun)];
DWORD dwDriveType;
DWORD dwContentType;
};
#pragma pack(pop)
static AUTORUNSTATUS s_autorunstatus;
// static
void CMountPoint::DoAutorun(LPCWSTR pszDrive, DWORD dwAutorunFlags)
{
CMountPoint* pmtpt = GetMountPoint(pszDrive);
FillMemory(s_autorunstatus._rgbAutorunStatus, sizeof(s_autorunstatus._rgbAutorunStatus), -1);
if (pmtpt)
{
CAutoPlayParams app(pszDrive, pmtpt, dwAutorunFlags);
if (AUTORUNFLAG_MENUINVOKED & dwAutorunFlags)
{
_acPromptUser(GetForegroundWindow(), &app);
}
else
{
_DoAutorunHelper(&app);
}
pmtpt->Release();
}
}
void CAutoPlayParams::_TrySniff()
{
if (!(APS_DID_SNIFF & _state))
{
if (_ShouldSniffDrive(TRUE))
{
DWORD dwFound;
if (SUCCEEDED(_Sniff(&dwFound)))
{
_dwContentType |= dwFound;
}
}
_state |= APS_DID_SNIFF;
}
}
BOOL CAutoPlayParams::IsContentTypePresent(DWORD dwContentType)
{
BOOL fRet;
if (CT_ANYCONTENT == dwContentType)
{
fRet = TRUE;
}
else
{
// We special case this because we do not want to sniff at this point
if ((CT_ANYCONTENT & ~CT_AUTORUNINF) == dwContentType)
{
if (CT_AUTORUNINF == _dwContentType)
{
fRet = FALSE;
}
else
{
// Anything else is good
fRet = TRUE;
}
}
else
{
if (CT_ANYAUTOPLAYCONTENT & dwContentType)
{
_TrySniff();
}
fRet = !!(dwContentType & _dwContentType);
}
}
return fRet;
}
void CAutoPlayParams::ForceSniff()
{
if (AUTORUNFLAG_MENUINVOKED & _dwAutorunFlags)
{
_TrySniff();
}
}
// static
void CMountPoint::_DoAutorunHelper(CAutoPlayParams *papp)
{
DWORD dwMaxLevelToProcess = 0;
BOOL fStop = FALSE;
HWND hwndForeground = GetForegroundWindow();
for (DWORD dwStep = 0; !fStop && (dwStep < ARRAYSIZE(_rgAutorun)); ++dwStep)
{
if (!(_rgAutorun[dwStep].dwNestingLevel & LEVEL_SKIP))
{
if ((_rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK) <= dwMaxLevelToProcess)
{
BOOL fConditionResult = FALSE;
// We do not want to Cancel the whole Autoplay operation if we do not get a
// match for a drive type or content type. We do the Cancel Autoplay only
// if the condition was evaluated.
BOOL fConditionEvaluated = FALSE;
if (_rgAutorun[dwStep].dwMtPtDriveType & papp->DriveType())
{
if (papp->IsContentTypePresent(_rgAutorun[dwStep].dwMtPtContentType))
{
if (!(_rgAutorun[dwStep].dwNestingLevel & LEVEL_EXECUTE))
{
fConditionResult = ((_rgAutorun[dwStep].fct)(hwndForeground, papp));
s_autorunstatus._rgbAutorunStatus[dwStep] = fConditionResult ? 1 : 0;
fConditionEvaluated = TRUE;
}
else
{
// LEVEL_EXECUTE
#ifdef DEBUG
TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: EXECUTING -> %s", dwStep, _rgAutorun[dwStep].pszDebug);
#endif
_rgAutorun[dwStep].fct(hwndForeground, papp);
// 2 execute
s_autorunstatus._rgbAutorunStatus[dwStep] = 0xEE;
// We're done
fStop = TRUE;
}
}
else
{
#ifdef DEBUG
TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: NO MATCH on CONTENTTYPE, %s ", dwStep, _rgAutorun[dwStep].pszDebug);
#endif
s_autorunstatus._rgbAutorunStatus[dwStep] = 0xCF;
}
}
else
{
#ifdef DEBUG
TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: NO MATCH on DRIVETYPE, %s ", dwStep, _rgAutorun[dwStep].pszDebug);
#endif
s_autorunstatus._rgbAutorunStatus[dwStep] = 0xDF;
}
if (!fStop)
{
if (fConditionResult)
{
#ifdef DEBUG
TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: TRUE -> %s", dwStep, _rgAutorun[dwStep].pszDebug);
#endif
switch (_rgAutorun[dwStep].dwReturnValueHandling)
{
case SKIPDEPENDENTS_ONTRUE:
dwMaxLevelToProcess = _rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK;
break;
case CANCEL_AUTOPLAY_ONTRUE:
if (fConditionEvaluated)
{
fStop = TRUE;
}
break;
default:
dwMaxLevelToProcess = (_rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK) + 1;
break;
case NOTAPPLICABLE_ONANY:
break;
}
}
else
{
#ifdef DEBUG
TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: FALSE -> %s", dwStep, _rgAutorun[dwStep].pszDebug);
#endif
switch (_rgAutorun[dwStep].dwReturnValueHandling)
{
case SKIPDEPENDENTS_ONFALSE:
dwMaxLevelToProcess = _rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK;
break;
case CANCEL_AUTOPLAY_ONFALSE:
if (fConditionEvaluated)
{
fStop = TRUE;
}
break;
default:
dwMaxLevelToProcess = (_rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK) + 1;
break;
case NOTAPPLICABLE_ONANY:
break;
}
}
}
}
else
{
#ifdef DEBUG
TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: SKIPPING , %s ", dwStep, _rgAutorun[dwStep].pszDebug);
#endif
s_autorunstatus._rgbAutorunStatus[dwStep] = 0x5F;
}
}
else
{
#ifdef DEBUG
TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: LVL-SKIP , %s ", dwStep, _rgAutorun[dwStep].pszDebug);
#endif
s_autorunstatus._rgbAutorunStatus[dwStep] = 0x5F;
}
}
s_autorunstatus.dwDriveType = papp->DriveType();
s_autorunstatus.dwContentType = papp->ContentType();
papp->MountPoint()->SetAutorunStatus((BYTE*)&s_autorunstatus, sizeof(s_autorunstatus));
}
DWORD _DoDWORDMapping(DWORD dwLeft, const TWODWORDS* rgtwodword, DWORD ctwodword, BOOL fORed)
{
DWORD dwRight = 0;
for (DWORD dw = 0; dw < ctwodword; ++dw)
{
if (fORed)
{
if (dwLeft & rgtwodword[dw].dwLeft)
{
dwRight |= rgtwodword[dw].dwRight;
}
}
else
{
if (dwLeft == rgtwodword[dw].dwLeft)
{
dwRight = rgtwodword[dw].dwRight;
break;
}
}
}
return dwRight;
}
STDMETHODIMP CSniffDrive::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CSniffDrive, INamespaceWalkCB),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP CSniffDrive::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl)
{
// include everything
HRESULT hr = S_OK;
if (!_pne || !_pne->fStopSniffing)
{
// if we found everything we dont need to worry about sniffing
// now we are just populating the dataobject
if (!_FoundEverything())
{
PERCEIVED gen = GetPerceivedType(psf, pidl);
if (GEN_IMAGE == gen)
{
_dwFound |= CT_AUTOPLAYPIX;
}
else if (GEN_AUDIO == gen)
{
_dwFound |= CT_AUTOPLAYMUSIC;
}
else if (GEN_VIDEO == gen)
{
_dwFound |= CT_AUTOPLAYMOVIE;
}
else
{
_dwFound |= CT_UNKNOWNCONTENT;
}
hr = S_OK;
}
}
else
{
hr = E_FAIL;
}
// we never want the results on the sniff
return hr;
}
STDMETHODIMP CSniffDrive::EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
{
return S_OK;
}
STDMETHODIMP CSniffDrive::LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
{
return S_OK;
}
STDMETHODIMP CSniffDrive::InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel)
{
*ppszCancel = NULL; // use default
TCHAR szMsg[256];
LoadString(g_hinst, IDS_AP_SNIFFPROGRESSDIALOG, szMsg, ARRAYSIZE(szMsg));
return SHStrDup(szMsg, ppszTitle);
}
// static
HRESULT CSniffDrive::Init(HANDLE hThreadSCN)
{
HRESULT hr;
if (DuplicateHandle(GetCurrentProcess(), hThreadSCN, GetCurrentProcess(),
&_hThreadSCN, THREAD_ALL_ACCESS, FALSE, 0))
{
hr = S_OK;
}
else
{
hr = E_FAIL;
}
return S_OK;
}
// static
HRESULT CSniffDrive::CleanUp()
{
if (_dpaNotifs)
{
// We should not need to delete the items, they should all be removed. Even
// if they're, we should leave them there since something will probably try
// to access them.
_dpaNotifs.Destroy();
_dpaNotifs = NULL;
}
if (_hThreadSCN)
{
CloseHandle(_hThreadSCN);
_hThreadSCN = NULL;
}
return S_OK;
}
// static
HRESULT CSniffDrive::InitNotifyWindow(HWND hwnd)
{
_hwndNotify = hwnd;
return S_OK;
}
HRESULT CSniffDrive::RegisterForNotifs(LPCWSTR pszDeviceIDVolume)
{
HRESULT hr;
_pne = new PNPNOTIFENTRY();
if (_pne)
{
HANDLE hDevice = CreateFile(pszDeviceIDVolume, FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE != hDevice)
{
DEV_BROADCAST_HANDLE dbhNotifFilter = {0};
// Assume failure
hr = E_FAIL;
dbhNotifFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
dbhNotifFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
dbhNotifFilter.dbch_handle = hDevice;
_pne->hdevnotify = RegisterDeviceNotification(_hwndNotify, &dbhNotifFilter,
DEVICE_NOTIFY_WINDOW_HANDLE);
if (_pne->hdevnotify)
{
_pne->AddRef();
if (QueueUserAPC(CSniffDrive::_RegisterForNotifsHelper, _hThreadSCN, (ULONG_PTR)_pne))
{
hr = S_OK;
}
else
{
_pne->Release();
}
}
CloseHandle(hDevice);
}
else
{
hr = E_FAIL;
}
if (FAILED(hr))
{
// Something must have gone wrong
_pne->Release();
_pne = NULL;
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT CSniffDrive::UnregisterForNotifs()
{
UnregisterDeviceNotification(_pne->hdevnotify);
QueueUserAPC(CSniffDrive::_UnregisterForNotifsHelper, _hThreadSCN, (ULONG_PTR)_pne);
_pne->Release();
_pne = NULL;
return S_OK;
}
// static
void CALLBACK CSniffDrive::_RegisterForNotifsHelper(ULONG_PTR ul)
{
PNPNOTIFENTRY* pne = (PNPNOTIFENTRY*)ul;
if (!_dpaNotifs)
{
_dpaNotifs.Create(1);
}
if (_dpaNotifs)
{
// We do not check the return value. We cannot free it, since the thread that
// queued this APC to us, expect this chunk of mem to be there until it calls
// UnregisterNotify. We'll leak it. Hopefully, this won't happen often.
_dpaNotifs.AppendPtr(pne);
}
}
// static
void CALLBACK CSniffDrive::_UnregisterForNotifsHelper(ULONG_PTR ul)
{
PNPNOTIFENTRY* pne = (PNPNOTIFENTRY*)ul;
if (_dpaNotifs)
{
int cItem = _dpaNotifs.GetPtrCount();
for (int i = 0; i < cItem; ++i)
{
PNPNOTIFENTRY* pneTmp = _dpaNotifs.GetPtr(i);
if (pneTmp->hdevnotify == pne->hdevnotify)
{
CloseHandle(pne->hThread);
_dpaNotifs.DeletePtr(i);
pne->Release();
break;
}
}
}
}
// static
HRESULT CSniffDrive::HandleNotif(HDEVNOTIFY hdevnotify)
{
int cItem = _dpaNotifs ? _dpaNotifs.GetPtrCount() : 0;
for (int i = 0; i < cItem; ++i)
{
PNPNOTIFENTRY* pneTmp = _dpaNotifs.GetPtr(i);
if (pneTmp->hdevnotify == hdevnotify)
{
pneTmp->fStopSniffing = TRUE;
// We don't check the return value. The worst that will happen is that this
// fails and we'll return too early and PnP will prompt the user to reboot.
// Wait 2 minutes
WaitForSingleObjectEx(pneTmp->hThread, 2 * 60 * 1000, FALSE);
break;
}
}
return S_OK;
}
BOOL CSniffDrive::_FoundEverything()
{
return (_dwFound & DRIVEHAS_EVERYTHING) == DRIVEHAS_EVERYTHING;
}
CSniffDrive::CSniffDrive() : _dwFound(0)
{}
CSniffDrive::~CSniffDrive()
{}
void CMountPoint::SetAutorunStatus(BYTE* rgb, DWORD cbSize)
{
RSSetBinaryValue(NULL, TEXT("_AutorunStatus"), rgb, cbSize);
}
class CAutoPlayVerb : public IDropTarget
{
public:
CAutoPlayVerb() : _cRef(1) {}
// IUnknown refcounting
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void)
{
return ++_cRef;
}
STDMETHODIMP_(ULONG) Release(void)
{
if (--_cRef > 0)
return _cRef;
delete this;
return 0;
}
// IDropTarget ***
STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
STDMETHODIMP DragLeave(void);
STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
protected:
LONG _cRef;
};
HRESULT CAutoPlayVerb::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CAutoPlayVerb, IDropTarget),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
// IDropTarget::DragEnter
HRESULT CAutoPlayVerb::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
*pdwEffect = DROPEFFECT_COPY;
return S_OK;;
}
// IDropTarget::DragOver
HRESULT CAutoPlayVerb::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
*pdwEffect = DROPEFFECT_COPY;
return S_OK;;
}
// IDropTarget::DragLeave
HRESULT CAutoPlayVerb::DragLeave(void)
{
return S_OK;
}
STDAPI CAutoPlayVerb_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
*ppv = NULL;
// aggregation checking is handled in class factory
CAutoPlayVerb* p = new CAutoPlayVerb();
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
STDAPI SHChangeNotifyAutoplayDrive(PCWSTR pszDrive);
// IDropTarget::DragDrop
HRESULT CAutoPlayVerb::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
*pdwEffect = DROPEFFECT_COPY;
// start the AutoPlayDialog
WCHAR szDrive[4];
HRESULT hr = PathFromDataObject(pdtobj, szDrive, ARRAYSIZE(szDrive));
if (SUCCEEDED(hr))
{
hr = SHChangeNotifyAutoplayDrive(szDrive);
}
return hr;
}
DWORD CALLBACK _AutorunPromptProc(void *pv)
{
WCHAR szDrive[4];
CMountPoint::DoAutorun(PathBuildRoot(szDrive, PtrToInt(pv)), AUTORUNFLAG_MENUINVOKED);
return 0;
}
void CMountPoint::DoAutorunPrompt(WPARAM iDrive)
{
SHCreateThread(_AutorunPromptProc, (void *)iDrive, CTF_COINIT | CTF_REF_COUNTED, NULL);
}
STDAPI_(void) Activate_RunDLL(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow)
{
DWORD dwProcessID;
HWND hwnd = GetShellWindow();
GetWindowThreadProcessId(hwnd, &dwProcessID);
AllowSetForegroundWindow(dwProcessID);
}