2541 lines
77 KiB
C++
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);
|
|
}
|