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

2540 lines
77 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "ids.h"
  4. #include "mtptl.h"
  5. #include "hwcmmn.h"
  6. #include "datautil.h"
  7. // for now
  8. #include "mixctnt.h"
  9. #include "filetbl.h"
  10. #include "apprmdlg.h"
  11. #include "views.h"
  12. #include <ddraw.h>
  13. CDPA<PNPNOTIFENTRY> CSniffDrive::_dpaNotifs = NULL;
  14. HANDLE CSniffDrive::_hThreadSCN = NULL;
  15. HWND CSniffDrive::_hwndNotify = NULL;
  16. //
  17. // if a drive has a AutoRun.inf file and AutoRun is not restricted in
  18. // the registry. copy the AutoRun info into a key in the registry.
  19. //
  20. // HKEY_CLASSES_ROOT\AutoRun\0 (0=A,1=B,...)
  21. //
  22. // the key is a standard ProgID key, has DefaultIcon, shell, shellex, ...
  23. //
  24. // the autorun file looks like this....
  25. //
  26. // [AutoRun]
  27. // key = value
  28. // key = value
  29. // key = value
  30. //
  31. // examples:
  32. //
  33. // [AutoRun]
  34. // DefaultIcon = foo.exe,1
  35. // shell=myverb
  36. // shell\myverb = &MyVerb
  37. // shell\myverb\command = myexe.exe
  38. //
  39. // will give the drive a icon from 'foo.exe'
  40. // add a verb called myverb (with name "&My Verb")
  41. // and make myverb default.
  42. //
  43. // [AutoRun]
  44. // shell\myverb = &MyVerb
  45. // shell\myverb\command = myexe.exe
  46. //
  47. // add a verb called myverb (with name "&My Verb")
  48. // verb will not be default.
  49. //
  50. // any thing they add will be copied over, they can add wacky things
  51. // like CLSID's or shellx\ContextMenuHandlers and it will work.
  52. //
  53. // or they can just copy over data the app will look at later.
  54. //
  55. // the following special cases will be supported....
  56. //
  57. // [AutoRun]
  58. // Open = command.exe /params
  59. // Icon = iconfile, iconnumber
  60. //
  61. // will be treated like:
  62. //
  63. // [AutoRun]
  64. // DefaultIcon = iconfile, iconnumber
  65. // shell = AutoRun
  66. // shell\AutoRun = Auto&Play
  67. // shell\AutoRun\command = command.exe /params
  68. //
  69. //
  70. // This function tries to take care of the case that a command was registered
  71. // in the autrun file of a cdrom. If the command is relative than see if the
  72. // command exists on the CDROM
  73. void CMountPoint::_QualifyCommandToDrive(LPTSTR pszCommand)
  74. {
  75. // for now we assume that we'll call this only for CD mounted on a drive letter
  76. // (by oppoition to a folder)
  77. if (_IsMountedOnDriveLetter())
  78. {
  79. TCHAR szImage[MAX_PATH];
  80. lstrcpy(szImage, pszCommand);
  81. PathRemoveArgs(szImage);
  82. PathUnquoteSpaces(szImage);
  83. if (PathIsRelative(szImage))
  84. {
  85. TCHAR szFinal[MAX_PATH];
  86. LPTSTR pszTmp = szImage;
  87. lstrcpy(szFinal, _GetName());
  88. // do simple check for command, check for "..\abc" or "../abc"
  89. while ((TEXT('.') == *pszTmp) && (TEXT('.') == *(pszTmp + 1)) &&
  90. ((TEXT('\\') == *(pszTmp + 2)) || (TEXT('/') == *(pszTmp + 2))))
  91. {
  92. pszTmp += 3;
  93. }
  94. lstrcatn(szFinal, pszTmp, ARRAYSIZE(szFinal));
  95. // we first check if it exists on the CD
  96. DWORD dwAttrib = GetFileAttributes(szFinal);
  97. if (0xFFFFFFFF == dwAttrib)
  98. {
  99. // It's not on the CD, try appending ".exe"
  100. lstrcatn(szFinal, TEXT(".exe"), ARRAYSIZE(szFinal));
  101. dwAttrib = GetFileAttributes(szFinal);
  102. }
  103. if (0xFFFFFFFF != dwAttrib)
  104. {
  105. // Yes, it's on the CD
  106. PathQuoteSpaces(szFinal);
  107. LPTSTR pszArgs = PathGetArgs(pszCommand);
  108. if (pszArgs && *pszArgs)
  109. lstrcatn(szFinal, pszArgs - 1, ARRAYSIZE(szFinal));
  110. // MAX_PATH: educated guess
  111. lstrcpyn(pszCommand, szFinal, MAX_PATH);
  112. }
  113. else
  114. {
  115. // No, not on the CD
  116. }
  117. }
  118. }
  119. }
  120. // This one does not hit the drive
  121. BOOL CMountPoint::_IsAutoRunDrive()
  122. {
  123. BOOL fRet = TRUE;
  124. // Add support for now drive letter
  125. if (_IsMountedOnDriveLetter())
  126. {
  127. int iDrive = DRIVEID(_GetName());
  128. // Restrict auto-run's to particular drives.
  129. if (SHRestricted(REST_NODRIVEAUTORUN) & (1 << iDrive))
  130. {
  131. fRet = FALSE;
  132. }
  133. }
  134. if (fRet)
  135. {
  136. UINT uDriveType = _GetDriveType();
  137. // Restrict auto-run's to particular types of drives.
  138. if (SHRestricted(REST_NODRIVETYPEAUTORUN) & (1 << (uDriveType & DRIVE_TYPE)))
  139. {
  140. fRet = FALSE;
  141. }
  142. else
  143. {
  144. if (DRIVE_UNKNOWN == (uDriveType & DRIVE_TYPE))
  145. {
  146. fRet = FALSE;
  147. }
  148. }
  149. if (fRet && _IsFloppy())
  150. {
  151. fRet = FALSE;
  152. }
  153. }
  154. return fRet;
  155. }
  156. HRESULT CMountPoint::_AddAutoplayVerb()
  157. {
  158. HRESULT hr = E_FAIL;
  159. if (RSSetTextValue(TEXT("shell\\Autoplay\\DropTarget"), TEXT("CLSID"),
  160. TEXT("{f26a669a-bcbb-4e37-abf9-7325da15f931}"), REG_OPTION_NON_VOLATILE))
  161. {
  162. // IDS_MENUAUTORUN -> 8504
  163. if (RSSetTextValue(TEXT("shell\\Autoplay"), TEXT("MUIVerb"),
  164. TEXT("@shell32.dll,-8504"), REG_OPTION_NON_VOLATILE))
  165. {
  166. if (RSSetTextValue(TEXT("shell"), NULL, TEXT("None"), REG_OPTION_NON_VOLATILE))
  167. {
  168. hr = S_OK;
  169. }
  170. }
  171. }
  172. return hr;
  173. }
  174. HRESULT CMountPoint::_CopyInvokeVerbKey(LPCWSTR pszProgID, LPCWSTR pszVerb)
  175. {
  176. ASSERT(pszProgID);
  177. ASSERT(pszVerb);
  178. WCHAR szKey[MAX_PATH];
  179. HRESULT hr = E_FAIL;
  180. wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("shell\\%s"), pszVerb);
  181. HKEY hkeyNew = RSDuplicateSubKey(szKey, TRUE, FALSE);
  182. if (hkeyNew)
  183. {
  184. wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("%s\\shell\\%s"), pszProgID, pszVerb);
  185. if (ERROR_SUCCESS == SHCopyKey(HKEY_CLASSES_ROOT, szKey, hkeyNew, 0))
  186. {
  187. if (RSSetTextValue(TEXT("shell"), NULL, pszVerb, REG_OPTION_NON_VOLATILE))
  188. {
  189. hr = S_OK;
  190. }
  191. }
  192. RegCloseKey(hkeyNew);
  193. }
  194. return hr;
  195. }
  196. BOOL CMountPoint::_ProcessAutoRunFile()
  197. {
  198. BOOL fRet = TRUE;
  199. if (!_fAutorunFileProcessed)
  200. {
  201. BOOL fProcessFile = FALSE;
  202. if (_IsCDROM())
  203. {
  204. CMtPtLocal* pmtptlocal = (CMtPtLocal*)this;
  205. // not CDs with no media, or no autorun.inf files
  206. if (pmtptlocal->_IsMediaPresent())
  207. {
  208. if (!pmtptlocal->_CanUseVolume())
  209. {
  210. fProcessFile = TRUE;
  211. }
  212. else
  213. {
  214. if ((HWDMC_HASAUTORUNINF & pmtptlocal->_pvol->dwMediaCap) &&
  215. !(HWDMC_HASUSEAUTOPLAY & pmtptlocal->_pvol->dwMediaCap))
  216. {
  217. fProcessFile = TRUE;
  218. }
  219. }
  220. }
  221. }
  222. else
  223. {
  224. if (_IsRemote())
  225. {
  226. fProcessFile = TRUE;
  227. }
  228. else
  229. {
  230. if (_IsFixedDisk())
  231. {
  232. fProcessFile = TRUE;
  233. }
  234. }
  235. }
  236. if (fProcessFile)
  237. {
  238. LPCTSTR pszSection;
  239. TCHAR szInfFile[MAX_PATH];
  240. TCHAR szKeys[512];
  241. TCHAR szValue[MAX_PATH];
  242. TCHAR szIcon[MAX_PATH + 12]; // MAX_PATH + room for ",1000000000" (for icon index part)
  243. LPTSTR pszKey;
  244. int iDrive = 0;
  245. RSDeleteSubKey(TEXT("Shell"));
  246. if (_IsMountedOnDriveLetter())
  247. {
  248. iDrive = DRIVEID(_GetName());
  249. }
  250. // build abs path to AutoRun.inf
  251. lstrcpyn(szInfFile, _GetName(), ARRAYSIZE(szInfFile));
  252. lstrcat(szInfFile, TEXT("AutoRun.inf"));
  253. #if defined(_X86_)
  254. pszSection = TEXT("AutoRun.x86");
  255. #elif defined(_IA64_)
  256. pszSection = TEXT("AutoRun.Ia64");
  257. #elif defined(_AMD64_)
  258. pszSection = TEXT("AutoRun.Amd64");
  259. #endif
  260. //
  261. // make sure a file exists before calling GetPrivateProfileString
  262. // because for some media this check might take a long long time
  263. // and we dont want to have kernel wait wiht the Win16Lock
  264. //
  265. UINT err = SetErrorMode(SEM_FAILCRITICALERRORS);
  266. if (!PathFileExistsAndAttributes(szInfFile, NULL))
  267. {
  268. SetErrorMode(err);
  269. _fAutorunFileProcessed = TRUE;
  270. return FALSE;
  271. }
  272. //
  273. // get all the keys in the [AutoRun] section
  274. //
  275. // Flush the INI cache, or this may fail during a Device broadcast
  276. WritePrivateProfileString(NULL, NULL, NULL, szInfFile);
  277. #if defined(_X86_)
  278. pszSection = TEXT("AutoRun.x86");
  279. #elif defined(_IA64_)
  280. pszSection = TEXT("AutoRun.Ia64");
  281. #endif
  282. int i = GetPrivateProfileString(pszSection, NULL, c_szNULL, szKeys, ARRAYSIZE(szKeys), szInfFile);
  283. // if we fail to find a platform-specific AutoRun section, fall
  284. // back to looking for the naked "AutoRun" section.
  285. if (0 == i)
  286. {
  287. pszSection = TEXT("AutoRun");
  288. i = GetPrivateProfileString(pszSection, NULL, c_szNULL, szKeys, ARRAYSIZE(szKeys), szInfFile);
  289. }
  290. SetErrorMode(err);
  291. if (i >= 4)
  292. {
  293. //
  294. // make sure the external strings are what we think.
  295. //
  296. ASSERT(lstrcmpi(c_szOpen,TEXT("open")) == 0);
  297. ASSERT(lstrcmpi(c_szShell, TEXT("shell")) == 0);
  298. // now walk all the keys in the .inf file and copy them to the registry.
  299. for (pszKey = szKeys; *pszKey; pszKey += lstrlen(pszKey) + 1)
  300. {
  301. GetPrivateProfileString(pszSection, pszKey,
  302. c_szNULL, szValue, ARRAYSIZE(szValue), szInfFile);
  303. //
  304. // special case open =
  305. //
  306. if (lstrcmpi(pszKey, c_szOpen) == 0)
  307. {
  308. if (_IsMountedOnDriveLetter())
  309. {
  310. RSSetTextValue(c_szShell, NULL, TEXT("AutoRun"));
  311. _QualifyCommandToDrive(szValue);
  312. RSSetTextValue(TEXT("shell\\AutoRun\\command"), NULL, szValue);
  313. LoadString(HINST_THISDLL, IDS_MENUAUTORUN, szValue, ARRAYSIZE(szValue));
  314. RSSetTextValue(TEXT("shell\\AutoRun"), NULL, szValue);
  315. }
  316. }
  317. //
  318. // special case ShellExecute
  319. //
  320. else if (lstrcmpi(pszKey, TEXT("ShellExecute")) == 0)
  321. {
  322. if (_IsMountedOnDriveLetter())
  323. {
  324. TCHAR szPath[MAX_PATH];
  325. StrCpyN(szPath, TEXT("RunDLL32.EXE Shell32.DLL,ShellExec_RunDLL "), ARRAYSIZE(szPath));
  326. StrCatBuff(szPath, szValue, ARRAYSIZE(szPath));
  327. RSSetTextValue(c_szShell, NULL, TEXT("AutoRun"));
  328. RSSetTextValue(TEXT("shell\\AutoRun\\command"), NULL, szPath);
  329. LoadString(HINST_THISDLL, IDS_MENUAUTORUN, szValue, ARRAYSIZE(szValue));
  330. RSSetTextValue(TEXT("shell\\AutoRun"), NULL, szValue);
  331. }
  332. }
  333. //
  334. // special case icon =
  335. // make sure the icon file has a full path...
  336. //
  337. else if (lstrcmpi(pszKey, TEXT("Icon")) == 0)
  338. {
  339. lstrcpyn(szIcon, _GetName(), ARRAYSIZE(szIcon));
  340. lstrcatn(szIcon, szValue, ARRAYSIZE(szIcon));
  341. RSSetTextValue(TEXT("_Autorun\\DefaultIcon"), NULL, szIcon);
  342. }
  343. //
  344. // special case label =
  345. // make sure the label file has a full path...
  346. //
  347. else if (lstrcmpi(pszKey, TEXT("Label")) == 0)
  348. {
  349. RSSetTextValue(TEXT("_Autorun\\DefaultLabel"), NULL, szValue);
  350. }
  351. //
  352. // special case shell = open
  353. // We have an autorun file but this puts open as the default verb
  354. // so we force it to be Autorun
  355. //
  356. else if (!lstrcmpi(pszKey, TEXT("shell")) && !lstrcmpi(szValue, TEXT("open")))
  357. {
  358. if (_IsMountedOnDriveLetter())
  359. {
  360. RSSetTextValue(pszKey, NULL, TEXT("Autorun"));
  361. }
  362. }
  363. //
  364. // it is just a key/value pair copy it over.
  365. //
  366. else
  367. {
  368. if (_IsMountedOnDriveLetter())
  369. {
  370. if (lstrcmpi(PathFindFileName(pszKey), c_szCommand) == 0)
  371. _QualifyCommandToDrive(szValue);
  372. RSSetTextValue(pszKey, NULL, szValue);
  373. }
  374. }
  375. }
  376. }
  377. else
  378. {
  379. fRet = FALSE;
  380. }
  381. }
  382. _fAutorunFileProcessed = TRUE;
  383. }
  384. return fRet;
  385. }
  386. // sends the "QueryCancelAutoPlay" msg to the window to see if it wants
  387. // to cancel the autoplay. useful for dialogs that are prompting for disk
  388. // inserts or cases where the app wants to capture the event and not let
  389. // other apps be run
  390. // static
  391. BOOL CMountPoint::_AppAllowsAutoRun(HWND hwndApp, CMountPoint* pmtpt)
  392. {
  393. ULONG_PTR dwCancel = 0;
  394. DWORD dwType = pmtpt->_GetAutorunContentType();
  395. WCHAR cDrive = pmtpt->_GetNameFirstCharUCase();
  396. int iDrive = cDrive - TEXT('A');
  397. SendMessageTimeout(hwndApp, QueryCancelAutoPlayMsg(), iDrive, dwType, SMTO_NORMAL | SMTO_ABORTIFHUNG,
  398. 1000, &dwCancel);
  399. return (dwCancel == 0);
  400. }
  401. STDAPI SHCreateQueryCancelAutoPlayMoniker(IMoniker** ppmoniker)
  402. {
  403. return CreateClassMoniker(CLSID_QueryCancelAutoPlay, ppmoniker);
  404. }
  405. struct QUERRYRUNNINGOBJECTSTRUCT
  406. {
  407. WCHAR szMountPoint[MAX_PATH];
  408. DWORD dwContentType;
  409. WCHAR szLabel[MAX_LABEL];
  410. DWORD dwSerialNumber;
  411. };
  412. BOOL _RegValueExist(HKEY hkey, LPCWSTR pszKey, LPCWSTR pszValue)
  413. {
  414. BOOL fRet = FALSE;
  415. HKEY hkeySub;
  416. if (ERROR_SUCCESS == RegOpenKeyEx(hkey, pszKey, 0, MAXIMUM_ALLOWED, &hkeySub))
  417. {
  418. fRet = (RegQueryValueEx(hkeySub, pszValue, 0, NULL, NULL, NULL) ==
  419. ERROR_SUCCESS);
  420. RegCloseKey(hkeySub);
  421. }
  422. return fRet;
  423. }
  424. BOOL _ShouldQueryMoniker(IMoniker* pmoniker, IBindCtx* pbindctx)
  425. {
  426. BOOL fRet = FALSE;
  427. DWORD dwMkSys;
  428. HRESULT hr = pmoniker->IsSystemMoniker(&dwMkSys);
  429. if (S_OK == hr)
  430. {
  431. // Is it a class moniker?
  432. if (MKSYS_CLASSMONIKER == dwMkSys)
  433. {
  434. // Yes
  435. LPWSTR pszDisplayName;
  436. hr = pmoniker->GetDisplayName(pbindctx, NULL, &pszDisplayName);
  437. if (SUCCEEDED(hr))
  438. {
  439. // We should get a "clsid:331F1768-05A9-4ddd-B86E-DAE34DDC998A:"
  440. // 37, because we do not have brackets and to explicitly truncate the trailing ":"
  441. WCHAR szCLSID[37];
  442. // The "+ 6" skips the "clsid:" part
  443. StrCpyN(szCLSID, pszDisplayName + 6, ARRAYSIZE(szCLSID));
  444. fRet = _RegValueExist(HKEY_LOCAL_MACHINE,
  445. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\CancelAutoplay\\CLSID"),
  446. szCLSID);
  447. CoTaskMemFree(pszDisplayName);
  448. }
  449. }
  450. }
  451. return fRet;
  452. }
  453. DWORD WINAPI _QueryRunningObjectThreadProc(void* pv)
  454. {
  455. QUERRYRUNNINGOBJECTSTRUCT* pqro = (QUERRYRUNNINGOBJECTSTRUCT*)pv;
  456. HRESULT hrRet = S_OK;
  457. HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
  458. if (SUCCEEDED(hr))
  459. {
  460. IRunningObjectTable* prot;
  461. hr = GetRunningObjectTable(0, &prot);
  462. if (SUCCEEDED(hr))
  463. {
  464. IMoniker* pmoniker;
  465. IBindCtx* pbindctx;
  466. hr = CreateBindCtx(0, &pbindctx);
  467. if (SUCCEEDED(hr))
  468. {
  469. BIND_OPTS2 bindopts;
  470. ZeroMemory(&bindopts, sizeof(bindopts));
  471. bindopts.cbStruct = sizeof(bindopts);
  472. bindopts.dwClassContext = CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD;
  473. hr = pbindctx->SetBindOptions(&bindopts);
  474. if (SUCCEEDED(hr))
  475. {
  476. HKEY hkey;
  477. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  478. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\CancelAutoplay\\CLSID"),
  479. 0, MAXIMUM_ALLOWED, &hkey))
  480. {
  481. DWORD dwIndex = 0;
  482. WCHAR szCLSID[39] = TEXT("{");
  483. DWORD cchCLSID = ARRAYSIZE(szCLSID) - 1;
  484. while ((S_FALSE != hrRet) &&
  485. (ERROR_SUCCESS == RegEnumValue(hkey, dwIndex, &(szCLSID[1]),
  486. &cchCLSID, 0, 0, 0, 0)))
  487. {
  488. CLSID clsid;
  489. szCLSID[37] = TEXT('}');
  490. szCLSID[38] = 0;
  491. hr = CLSIDFromString(szCLSID, &clsid);
  492. if (SUCCEEDED(hr))
  493. {
  494. IMoniker* pmoniker;
  495. // Create the moniker that we'll put in the ROT
  496. hr = CreateClassMoniker(clsid, &pmoniker);
  497. if (SUCCEEDED(hr))
  498. {
  499. IUnknown* punk;
  500. hr = prot->GetObject(pmoniker, &punk);
  501. if (SUCCEEDED(hr) && (S_FALSE != hr))
  502. {
  503. IQueryCancelAutoPlay* pqca;
  504. hr = punk->QueryInterface(IID_PPV_ARG(IQueryCancelAutoPlay, &pqca));
  505. if (SUCCEEDED(hr))
  506. {
  507. hrRet = pqca->AllowAutoPlay(pqro->szMountPoint, pqro->dwContentType,
  508. pqro->szLabel, pqro->dwSerialNumber);
  509. pqca->Release();
  510. }
  511. punk->Release();
  512. }
  513. pmoniker->Release();
  514. }
  515. }
  516. ++dwIndex;
  517. cchCLSID = ARRAYSIZE(szCLSID) - 1;
  518. }
  519. RegCloseKey(hkey);
  520. }
  521. }
  522. pbindctx->Release();
  523. }
  524. if (S_FALSE != hrRet)
  525. {
  526. // This case is to support WMP and CD burning. We did not get to replace
  527. // their cancel logic before shipping.
  528. hr = SHCreateQueryCancelAutoPlayMoniker(&pmoniker);
  529. if (SUCCEEDED(hr))
  530. {
  531. IUnknown* punk;
  532. hr = prot->GetObject(pmoniker, &punk);
  533. if (SUCCEEDED(hr) && (S_FALSE != hr))
  534. {
  535. IQueryCancelAutoPlay* pqca;
  536. hr = punk->QueryInterface(IID_PPV_ARG(IQueryCancelAutoPlay, &pqca));
  537. if (SUCCEEDED(hr))
  538. {
  539. hrRet = pqca->AllowAutoPlay(pqro->szMountPoint, pqro->dwContentType,
  540. pqro->szLabel, pqro->dwSerialNumber);
  541. pqca->Release();
  542. }
  543. punk->Release();
  544. }
  545. pmoniker->Release();
  546. }
  547. }
  548. prot->Release();
  549. }
  550. CoUninitialize();
  551. }
  552. LocalFree((HLOCAL)pqro);
  553. return (DWORD)hrRet;
  554. }
  555. // static
  556. HRESULT CMountPoint::_QueryRunningObject(CMountPoint* pmtpt, DWORD dwAutorunContentType, BOOL* pfAllow)
  557. {
  558. *pfAllow = TRUE;
  559. QUERRYRUNNINGOBJECTSTRUCT *pqro;
  560. HRESULT hr = SHLocalAlloc(sizeof(*pqro), &pqro);
  561. if (SUCCEEDED(hr))
  562. {
  563. WCHAR szLabel[MAX_LABEL];
  564. if (!(ARCONTENT_BLANKCD & dwAutorunContentType) &&
  565. !(ARCONTENT_BLANKDVD & dwAutorunContentType))
  566. {
  567. if (pmtpt->_GetGVILabel(szLabel, ARRAYSIZE(szLabel)))
  568. {
  569. lstrcpyn(pqro->szLabel, szLabel, ARRAYSIZE(pqro->szLabel));
  570. pmtpt->_GetSerialNumber(&(pqro->dwSerialNumber));
  571. }
  572. }
  573. lstrcpyn(pqro->szMountPoint, pmtpt->_GetName(), ARRAYSIZE(pqro->szMountPoint));
  574. pqro->dwContentType = dwAutorunContentType;
  575. HANDLE hThread = CreateThread(NULL, 0, _QueryRunningObjectThreadProc,
  576. pqro, 0, NULL);
  577. if (hThread)
  578. {
  579. // thread now owns these guys, NULL them out to avoid dbl free
  580. pqro = NULL; // don't free this below
  581. hr = S_FALSE;
  582. // Wait 3 sec to see if wants to process it. If not, it's
  583. // fair play for us.
  584. DWORD dwWait = WaitForSingleObject(hThread, 3000);
  585. if (WAIT_OBJECT_0 == dwWait)
  586. {
  587. // Return within time and did not failed
  588. DWORD dwExitCode;
  589. if (GetExitCodeThread(hThread, &dwExitCode))
  590. {
  591. HRESULT hrHandlesEvent = (HRESULT)dwExitCode;
  592. // Will return S_FALSE if they do NOT allow AutoRun
  593. if (SUCCEEDED(hrHandlesEvent) && (S_FALSE == hrHandlesEvent))
  594. {
  595. *pfAllow = FALSE;
  596. }
  597. hr = S_OK;
  598. }
  599. }
  600. CloseHandle(hThread);
  601. }
  602. else
  603. {
  604. hr = E_OUTOFMEMORY;
  605. }
  606. LocalFree((HLOCAL)pqro); // may be NULL
  607. }
  608. return hr;
  609. }
  610. CAutoPlayParams::CAutoPlayParams(LPCWSTR pszDrive, CMountPoint* pMtPt, DWORD dwAutorunFlags)
  611. : _pszDrive(pszDrive),
  612. _pmtpt(pMtPt),
  613. _dwAutorunFlags(dwAutorunFlags),
  614. _state(APS_RESET),
  615. _pdo(NULL),
  616. _fCheckAlwaysDoThisCheckBox(FALSE)
  617. {
  618. _dwDriveType = pMtPt->_GetMTPTDriveType();
  619. _dwContentType = pMtPt->_GetMTPTContentType();
  620. if (DT_ANYLOCALDRIVES & _dwDriveType)
  621. _pmtptl = (CMtPtLocal*)pMtPt;
  622. else
  623. _pmtptl = NULL;
  624. // maybe assert on these?
  625. }
  626. BOOL CAutoPlayParams::_ShouldSniffDrive(BOOL fCheckHandlerDefaults)
  627. {
  628. BOOL fSniff = FALSE;
  629. if (_pmtptl)
  630. {
  631. if (CT_AUTORUNINF & _dwContentType)
  632. {
  633. if (_pmtptl->_CanUseVolume())
  634. {
  635. if (_pmtptl->_pvol->dwMediaCap & HWDMC_HASUSEAUTOPLAY)
  636. {
  637. fSniff = TRUE;
  638. }
  639. }
  640. }
  641. else
  642. {
  643. fSniff = TRUE;
  644. }
  645. if (fSniff)
  646. {
  647. fSniff = FALSE;
  648. if (!((CT_CDAUDIO | CT_DVDMOVIE) & _dwContentType))
  649. {
  650. if (_pmtptl->_CanUseVolume())
  651. {
  652. if (!(HWDVF_STATE_HASAUTOPLAYHANDLER & _pmtptl->_pvol->dwVolumeFlags) &&
  653. !(HWDVF_STATE_DONOTSNIFFCONTENT & _pmtptl->_pvol->dwVolumeFlags))
  654. {
  655. if (AUTORUNFLAG_MENUINVOKED & _dwAutorunFlags)
  656. {
  657. fSniff = TRUE;
  658. }
  659. else if (DT_FIXEDDISK & _dwDriveType)
  660. {
  661. if (HWDDC_REMOVABLEDEVICE & _pmtptl->_pvol->dwDriveCapability)
  662. {
  663. fSniff = TRUE;
  664. }
  665. }
  666. else
  667. {
  668. if (AUTORUNFLAG_MEDIAARRIVAL & _dwAutorunFlags)
  669. {
  670. fSniff = TRUE;
  671. }
  672. else
  673. {
  674. if (AUTORUNFLAG_MTPTARRIVAL & _dwAutorunFlags)
  675. {
  676. if (HWDDC_REMOVABLEDEVICE & _pmtptl->_pvol->dwDriveCapability)
  677. {
  678. fSniff = TRUE;
  679. }
  680. }
  681. }
  682. }
  683. }
  684. }
  685. }
  686. }
  687. }
  688. if (fSniff && fCheckHandlerDefaults)
  689. {
  690. // Let's make sure the user did not pick "Take no action" for all Autoplay
  691. // content types, it would be useless to sniff.
  692. BOOL fAllTakeNoAction = TRUE;
  693. DWORD rgdwContentType[] =
  694. {
  695. CT_AUTOPLAYMUSIC,
  696. CT_AUTOPLAYPIX,
  697. CT_AUTOPLAYMOVIE,
  698. CT_AUTOPLAYMUSIC | CT_AUTOPLAYPIX | CT_AUTOPLAYMOVIE, // Mix content
  699. };
  700. for (DWORD dw = 0; fAllTakeNoAction && (dw < ARRAYSIZE(rgdwContentType)); ++dw)
  701. {
  702. WCHAR szContentTypeHandler[MAX_CONTENTTYPEHANDLER];
  703. DWORD dwMtPtContentType = rgdwContentType[dw];
  704. HRESULT hr = _GetContentTypeHandler(dwMtPtContentType, szContentTypeHandler, ARRAYSIZE(szContentTypeHandler));
  705. if (SUCCEEDED(hr))
  706. {
  707. IAutoplayHandler* piah;
  708. hr = _GetAutoplayHandler(Drive(), TEXT("ContentArrival"), szContentTypeHandler, &piah);
  709. if (SUCCEEDED(hr))
  710. {
  711. LPWSTR pszHandlerDefault;
  712. hr = piah->GetDefaultHandler(&pszHandlerDefault);
  713. if (SUCCEEDED(hr))
  714. {
  715. if (HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED &
  716. HANDLERDEFAULT_GETFLAGS(hr))
  717. {
  718. fAllTakeNoAction = FALSE;
  719. }
  720. else
  721. {
  722. if (lstrcmpi(pszHandlerDefault, TEXT("MSTakeNoAction")))
  723. {
  724. fAllTakeNoAction = FALSE;
  725. }
  726. }
  727. CoTaskMemFree(pszHandlerDefault);
  728. }
  729. piah->Release();
  730. }
  731. }
  732. }
  733. if (fAllTakeNoAction)
  734. {
  735. fSniff = FALSE;
  736. }
  737. }
  738. return fSniff;
  739. }
  740. DWORD CAutoPlayParams::ContentType()
  741. {
  742. return _dwContentType;
  743. }
  744. HRESULT CAutoPlayParams::_InitObjects(IShellFolder **ppsf)
  745. {
  746. HRESULT hr;
  747. if (!_pdo || ppsf)
  748. {
  749. LPITEMIDLIST pidlFolder;
  750. hr = SHParseDisplayName(_pszDrive, NULL, &pidlFolder, 0, NULL);
  751. if (SUCCEEDED(hr))
  752. {
  753. hr = SHGetUIObjectOf(pidlFolder, NULL, IID_PPV_ARG(IDataObject, &_pdo));
  754. ILFree(pidlFolder);
  755. }
  756. }
  757. else
  758. {
  759. hr = S_OK;
  760. }
  761. if (SUCCEEDED(hr) && ppsf)
  762. {
  763. // we need to avoid hitting the burn folder
  764. // so we skip junctions for the sniff
  765. IBindCtx * pbc;
  766. hr = SHCreateSkipBindCtx(NULL, &pbc);
  767. if (SUCCEEDED(hr))
  768. {
  769. LPITEMIDLIST pidlFolder;
  770. hr = SHParseDisplayName(_pszDrive, pbc, &pidlFolder, 0, NULL);
  771. if (SUCCEEDED(hr))
  772. {
  773. hr = SHBindToObjectEx(NULL, pidlFolder, pbc, IID_PPV_ARG(IShellFolder, ppsf));
  774. ILFree(pidlFolder);
  775. }
  776. pbc->Release();
  777. }
  778. }
  779. return hr;
  780. }
  781. HRESULT CAutoPlayParams::_AddWalkToDataObject(INamespaceWalk* pnsw)
  782. {
  783. UINT cidl;
  784. LPITEMIDLIST *apidl;
  785. HRESULT hr = pnsw->GetIDArrayResult(&cidl, &apidl);
  786. if (SUCCEEDED(hr))
  787. {
  788. // we need to add this back in
  789. if (cidl)
  790. {
  791. // ragged array
  792. HIDA hida = HIDA_Create(&c_idlDesktop, cidl, (LPCITEMIDLIST *)apidl);
  793. if (hida)
  794. {
  795. IDLData_InitializeClipboardFormats(); // init our registerd formats
  796. // should we free hida on FAILED?
  797. DataObj_SetGlobal(_pdo, g_cfAutoPlayHIDA, hida);
  798. }
  799. }
  800. FreeIDListArray(apidl, cidl);
  801. }
  802. return hr;
  803. }
  804. HRESULT CAutoPlayParams::_Sniff(DWORD *pdwFound)
  805. {
  806. // we found nothing
  807. HRESULT hr = S_FALSE;
  808. *pdwFound = 0;
  809. if (_pmtptl->_CanUseVolume())
  810. {
  811. // setup the IDataObject and IShellFolder for the walk
  812. IShellFolder *psf;
  813. HRESULT hr = _InitObjects(&psf);
  814. if (SUCCEEDED(hr))
  815. {
  816. INamespaceWalk* pnsw;
  817. hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC, IID_PPV_ARG(INamespaceWalk, &pnsw));
  818. if (SUCCEEDED(hr))
  819. {
  820. CSniffDrive sniff;
  821. hr = sniff.RegisterForNotifs(_pmtptl->_pvol->pszDeviceIDVolume);
  822. if (SUCCEEDED(hr))
  823. {
  824. // We don't care about the return value. WE don't want to stop Autorun for as much.
  825. // If sniffing fail we go on with what we have.
  826. if (SUCCEEDED(pnsw->Walk(psf, NSWF_IGNORE_AUTOPLAY_HIDA | NSWF_DONT_TRAVERSE_LINKS | NSWF_SHOW_PROGRESS, 4, &sniff)))
  827. {
  828. // we keep everything we found
  829. _AddWalkToDataObject(pnsw);
  830. }
  831. sniff.UnregisterForNotifs();
  832. *pdwFound = sniff.Found();
  833. }
  834. pnsw->Release();
  835. }
  836. psf->Release();
  837. }
  838. }
  839. return hr;
  840. }
  841. // BEGIN: Fcts for matrix below
  842. //
  843. BOOL CMountPoint::_acShiftKeyDown(HWND , CAutoPlayParams *)
  844. {
  845. return (GetAsyncKeyState(VK_SHIFT) < 0);
  846. }
  847. BOOL _IsDirectXExclusiveMode()
  848. {
  849. BOOL fRet = FALSE;
  850. // This code determines whether a DirectDraw 7 process (game) is running and
  851. // whether it's exclusively holding the video to the machine in full screen mode.
  852. // The code is probably to be considered untrusted and hence is wrapped in a
  853. // __try / __except block. It could AV and therefore bring down shell
  854. // with it. Not very good. If the code does raise an exception the release
  855. // call is skipped. Tough. Don't trust the release method either.
  856. IDirectDraw7 *pIDirectDraw7 = NULL;
  857. HRESULT hr = CoCreateInstance(CLSID_DirectDraw7, NULL, CLSCTX_INPROC_SERVER,
  858. IID_IDirectDraw7, (void**)&pIDirectDraw7);
  859. if (SUCCEEDED(hr))
  860. {
  861. ASSERT(pIDirectDraw7);
  862. __try
  863. {
  864. hr = IDirectDraw7_Initialize(pIDirectDraw7, NULL);
  865. if (DD_OK == hr)
  866. {
  867. fRet = (IDirectDraw7_TestCooperativeLevel(pIDirectDraw7) ==
  868. DDERR_EXCLUSIVEMODEALREADYSET);
  869. }
  870. IDirectDraw7_Release(pIDirectDraw7);
  871. }
  872. __except (EXCEPTION_EXECUTE_HANDLER)
  873. {
  874. }
  875. }
  876. return fRet;
  877. }
  878. // From a mail regarding the DirectX fct below:
  879. //
  880. // You can definitely count on the following:
  881. //
  882. // (1) If shadow cursors are on, there is definitely not an exclusive mode app running.
  883. // (2) If hot tracking is on, there is definitely not an exclusive mode app running.
  884. // (3) If message boxes for SEM_NOGPFAULTERRORBOX, SEM_FAILCRITICALERRORS, or
  885. // SEM_NOOPENFILEERRORBOX have not been disabled via SetErrorMode, then there
  886. // is definitely not an exclusive mode app running.
  887. //
  888. // Note: we cannot use (3) since this is per-process.
  889. BOOL CMountPoint::_acDirectXAppRunningFullScreen(HWND hwndForeground, CAutoPlayParams *)
  890. {
  891. BOOL fRet = FALSE;
  892. BOOL fSPI;
  893. if (SystemParametersInfo(SPI_GETCURSORSHADOW, 0, &fSPI, 0) && !fSPI)
  894. {
  895. if (SystemParametersInfo(SPI_GETHOTTRACKING, 0, &fSPI, 0) && !fSPI)
  896. {
  897. // There's a chance that a DirectX app is running full screen. Let's do the
  898. // expensive DirectX calls that will tell us for sure.
  899. fRet = _IsDirectXExclusiveMode();
  900. }
  901. }
  902. return fRet;
  903. }
  904. BOOL CMountPoint::_acCurrentDesktopIsActiveConsole(HWND , CAutoPlayParams *)
  905. {
  906. BOOL fRetValue = FALSE; // block auto-run/auto-play if we can't determine our state.
  907. if (0 == GetSystemMetrics(SM_REMOTESESSION))
  908. {
  909. //
  910. // We are not remoted. See if we are the active console session.
  911. //
  912. BOOL b;
  913. DWORD dwProcessSession;
  914. b = ProcessIdToSessionId(GetCurrentProcessId(), &dwProcessSession);
  915. if (b)
  916. {
  917. DWORD dwConsoleSession = WTSGetActiveConsoleSessionId( );
  918. if ( dwProcessSession == dwConsoleSession )
  919. {
  920. //
  921. // See if the screen saver is running.
  922. //
  923. BOOL b;
  924. BOOL fScreenSaver;
  925. b = SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0, &fScreenSaver, 0 );
  926. if (b)
  927. {
  928. if (!fScreenSaver)
  929. {
  930. //
  931. // We made it here, we must be the active console session without a
  932. // screen saver.
  933. //
  934. HDESK hDesk = OpenInputDesktop( 0, FALSE, DESKTOP_CREATEWINDOW );
  935. if ( NULL != hDesk )
  936. {
  937. //
  938. // We have access to the current desktop which should indicate that
  939. // WinLogon isn't.
  940. //
  941. CloseDesktop( hDesk );
  942. fRetValue = TRUE;
  943. }
  944. // else "WinLogon" has the "desktop"... don't allow auto-run/auto-play.
  945. }
  946. // else a screen saver is running... don't allow auto-run/auto-play.
  947. }
  948. // else we are in an undeterminate state... don't allow auto-run/auto-play.
  949. }
  950. // else we aren't the console... don't allow auto-run/auto-play
  951. }
  952. // else we are in an undeterminate state... don't allow auto-run/auto-play.
  953. }
  954. // else we are remoted... don't allow auto-run/auto-play.
  955. return fRetValue;
  956. }
  957. BOOL CMountPoint::_acDriveIsMountedOnDriveLetter(HWND , CAutoPlayParams *papp)
  958. {
  959. return _IsDriveLetter(papp->Drive());
  960. }
  961. BOOL CMountPoint::_acDriveIsRestricted(HWND , CAutoPlayParams *papp)
  962. {
  963. BOOL fIsRestricted = (SHRestricted(REST_NODRIVES) & (1 << DRIVEID(papp->Drive())));
  964. if (!fIsRestricted)
  965. {
  966. fIsRestricted = !(papp->MountPoint()->_IsAutoRunDrive());
  967. }
  968. return fIsRestricted;
  969. }
  970. BOOL CMountPoint::_acHasAutorunCommand(HWND , CAutoPlayParams *papp)
  971. {
  972. BOOL fRet = FALSE;
  973. if ((papp->IsContentTypePresent(CT_AUTORUNINF)) &&
  974. (DT_ANYLOCALDRIVES & papp->DriveType()))
  975. {
  976. CMtPtLocal* pmtptl = (CMtPtLocal*)papp->MountPoint();
  977. if (pmtptl->_CanUseVolume())
  978. {
  979. if (pmtptl->_pvol->dwMediaCap & HWDMC_HASAUTORUNCOMMAND)
  980. {
  981. fRet = TRUE;
  982. }
  983. }
  984. else
  985. {
  986. fRet = papp->MountPoint()->_IsAutorun();
  987. }
  988. }
  989. else
  990. {
  991. fRet = papp->IsContentTypePresent(CT_AUTORUNINF);
  992. }
  993. return fRet;
  994. }
  995. BOOL CMountPoint::_acHasUseAutoPLAY(HWND , CAutoPlayParams *papp)
  996. {
  997. BOOL fRet = FALSE;
  998. if (papp->IsContentTypePresent(CT_AUTORUNINF) &&
  999. (DT_ANYLOCALDRIVES & papp->DriveType()))
  1000. {
  1001. CMtPtLocal* pmtptl = (CMtPtLocal*)papp->MountPoint();
  1002. if (pmtptl->_CanUseVolume())
  1003. {
  1004. if (pmtptl->_pvol->dwMediaCap & HWDMC_HASUSEAUTOPLAY)
  1005. {
  1006. fRet = TRUE;
  1007. }
  1008. }
  1009. else
  1010. {
  1011. // If we're here, most likely the ShellService is not running, so we won't be able to
  1012. // Autoplay anyway.
  1013. fRet = FALSE;
  1014. }
  1015. }
  1016. else
  1017. {
  1018. // not supported for remote drives
  1019. }
  1020. return fRet;
  1021. }
  1022. BOOL CMountPoint::_acForegroundAppAllowsAutorun(HWND hwndForeground, CAutoPlayParams *papp)
  1023. {
  1024. return _AppAllowsAutoRun(hwndForeground, papp->MountPoint());
  1025. }
  1026. static const TWODWORDS allcontentsVSarcontenttypemappings[] =
  1027. {
  1028. { CT_AUTORUNINF , ARCONTENT_AUTORUNINF },
  1029. { CT_CDAUDIO , ARCONTENT_AUDIOCD },
  1030. { CT_DVDMOVIE , ARCONTENT_DVDMOVIE },
  1031. { CT_UNKNOWNCONTENT , ARCONTENT_UNKNOWNCONTENT },
  1032. { CT_BLANKCDR , ARCONTENT_BLANKCD },
  1033. { CT_BLANKCDRW , ARCONTENT_BLANKCD },
  1034. { CT_BLANKDVDR , ARCONTENT_BLANKDVD },
  1035. { CT_BLANKDVDRW , ARCONTENT_BLANKDVD },
  1036. { CT_AUTOPLAYMUSIC , ARCONTENT_AUTOPLAYMUSIC },
  1037. { CT_AUTOPLAYPIX , ARCONTENT_AUTOPLAYPIX },
  1038. { CT_AUTOPLAYMOVIE , ARCONTENT_AUTOPLAYVIDEO },
  1039. };
  1040. BOOL CMountPoint::_acQueryCancelAutoplayAllowsAutorun(HWND , CAutoPlayParams *papp)
  1041. {
  1042. BOOL fAllow = TRUE;
  1043. DWORD dwAutorunContentType = _DoDWORDMapping(papp->ContentType(),
  1044. allcontentsVSarcontenttypemappings, ARRAYSIZE(allcontentsVSarcontenttypemappings),
  1045. TRUE);
  1046. _QueryRunningObject(papp->MountPoint(), dwAutorunContentType, &fAllow);
  1047. return fAllow;
  1048. }
  1049. BOOL CMountPoint::_acUserHasSelectedApplication(HWND hwndForeground, CAutoPlayParams *papp)
  1050. {
  1051. BOOL fRet = FALSE;
  1052. WCHAR szContentTypeHandler[MAX_CONTENTTYPEHANDLER];
  1053. DWORD dwMtPtContentType = papp->ContentType() & ~CT_UNKNOWNCONTENT;
  1054. HRESULT hr = _GetContentTypeHandler(dwMtPtContentType, szContentTypeHandler, ARRAYSIZE(szContentTypeHandler));
  1055. if (SUCCEEDED(hr))
  1056. {
  1057. IAutoplayHandler* piah;
  1058. hr = _GetAutoplayHandler(papp->Drive(), TEXT("ContentArrival"), szContentTypeHandler, &piah);
  1059. if (SUCCEEDED(hr))
  1060. {
  1061. LPWSTR pszHandlerDefault;
  1062. hr = piah->GetDefaultHandler(&pszHandlerDefault);
  1063. if (SUCCEEDED(hr))
  1064. {
  1065. if (HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED &
  1066. HANDLERDEFAULT_GETFLAGS(hr))
  1067. {
  1068. fRet = FALSE;
  1069. }
  1070. else
  1071. {
  1072. if (HANDLERDEFAULT_USERCHOSENDEFAULT &
  1073. HANDLERDEFAULT_GETFLAGS(hr))
  1074. {
  1075. fRet = lstrcmpi(pszHandlerDefault, TEXT("MSPromptEachTime"));
  1076. }
  1077. else
  1078. {
  1079. fRet = FALSE;
  1080. }
  1081. }
  1082. if (!fRet)
  1083. {
  1084. if (((HANDLERDEFAULT_USERCHOSENDEFAULT &
  1085. HANDLERDEFAULT_GETFLAGS(hr)) ||
  1086. (HANDLERDEFAULT_EVENTHANDLERDEFAULT &
  1087. HANDLERDEFAULT_GETFLAGS(hr))) &&
  1088. !(HANDLERDEFAULT_DEFAULTSAREDIFFERENT &
  1089. HANDLERDEFAULT_GETFLAGS(hr)))
  1090. {
  1091. papp->_fCheckAlwaysDoThisCheckBox = TRUE;
  1092. }
  1093. }
  1094. CoTaskMemFree(pszHandlerDefault);
  1095. }
  1096. piah->Release();
  1097. }
  1098. }
  1099. return fRet;
  1100. }
  1101. BOOL CMountPoint::_acShellIsForegroundApp(HWND hwndForeground, CAutoPlayParams *papp)
  1102. {
  1103. BOOL fRet = FALSE;
  1104. WCHAR szModule[MAX_PATH];
  1105. if (GetWindowModuleFileName(hwndForeground, szModule, ARRAYSIZE(szModule)))
  1106. {
  1107. if (!lstrcmpi(PathFindFileName(szModule), TEXT("explorer.exe")))
  1108. {
  1109. fRet = TRUE;
  1110. }
  1111. }
  1112. return fRet;
  1113. }
  1114. BOOL CMountPoint::_acOSIsServer(HWND , CAutoPlayParams *papp)
  1115. {
  1116. return IsOS(OS_ANYSERVER);
  1117. }
  1118. BOOL CMountPoint::_acIsDockedLaptop(HWND hwndForeground, CAutoPlayParams *papp)
  1119. {
  1120. return (GMID_DOCKED & SHGetMachineInfo(GMI_DOCKSTATE));
  1121. }
  1122. BOOL CMountPoint::_acDriveIsFormatted(HWND hwndForeground, CAutoPlayParams *papp)
  1123. {
  1124. return papp->MountPoint()->IsFormatted();
  1125. }
  1126. BOOL CMountPoint::_acShellExecuteDriveAutorunINF(HWND hwndForeground, CAutoPlayParams *papp)
  1127. {
  1128. SHELLEXECUTEINFO ei = {
  1129. sizeof(ei), // size
  1130. SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI, // flags
  1131. NULL,
  1132. NULL, // verb
  1133. papp->Drive(), // file
  1134. papp->Drive(), // params
  1135. papp->Drive(), // directory
  1136. SW_NORMAL, // show.
  1137. NULL, // hinstance
  1138. NULL, // IDLIST
  1139. NULL, // class name
  1140. NULL, // class key
  1141. 0, // hot key
  1142. NULL, // icon
  1143. NULL, // hProcess
  1144. };
  1145. return ShellExecuteEx(&ei);
  1146. }
  1147. HRESULT _InvokeAutoRunProgid(HKEY hkProgid, LPCWSTR pszVerb, IDataObject *pdo)
  1148. {
  1149. IShellExtInit *psei;
  1150. HRESULT hr = CoCreateInstance(CLSID_ShellFileDefExt, NULL, CLSCTX_INPROC, IID_PPV_ARG(IShellExtInit, &psei));
  1151. if (SUCCEEDED(hr))
  1152. {
  1153. hr = psei->Initialize(NULL, pdo, hkProgid);
  1154. if (SUCCEEDED(hr))
  1155. {
  1156. IContextMenu *pcm;
  1157. hr = psei->QueryInterface(IID_PPV_ARG(IContextMenu, &pcm));
  1158. if (SUCCEEDED(hr))
  1159. {
  1160. CHAR szVerb[64];
  1161. // maybe hwnd
  1162. // maybe punkSite
  1163. // maybe ICI flags
  1164. SHUnicodeToAnsi(pszVerb, szVerb, ARRAYSIZE(szVerb));
  1165. hr = SHInvokeCommandOnContextMenu(NULL, NULL, pcm, 0, szVerb);
  1166. pcm->Release();
  1167. }
  1168. }
  1169. psei->Release();
  1170. }
  1171. return hr;
  1172. }
  1173. HRESULT _GetProgidAndVerb(DWORD dwContentType, PCWSTR pszHandler, PWSTR pszInvokeProgID,
  1174. DWORD cchInvokeProgID, PWSTR pszInvokeVerb, DWORD cchInvokeVerb)
  1175. {
  1176. HRESULT hr;
  1177. if (0 == StrCmpI(pszHandler, TEXT("AutoplayLegacyHandler")) && (dwContentType & (CT_CDAUDIO | CT_DVDMOVIE)))
  1178. {
  1179. HKEY hkey;
  1180. BOOL fGotDefault = FALSE;
  1181. if (dwContentType & CT_CDAUDIO)
  1182. {
  1183. StrCpyN(pszInvokeProgID, TEXT("AudioCD"), cchInvokeProgID);
  1184. }
  1185. else
  1186. {
  1187. ASSERT(dwContentType & CT_DVDMOVIE);
  1188. StrCpyN(pszInvokeProgID, TEXT("DVD"), cchInvokeProgID);
  1189. }
  1190. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, pszInvokeProgID, 0, MAXIMUM_ALLOWED,
  1191. &hkey))
  1192. {
  1193. HKEY hkey2;
  1194. if (ERROR_SUCCESS == RegOpenKeyEx(hkey, TEXT("shell"), 0, MAXIMUM_ALLOWED,
  1195. &hkey2))
  1196. {
  1197. DWORD cbInvokeVerb = cchInvokeVerb * sizeof(WCHAR);
  1198. if (ERROR_SUCCESS == RegQueryValueEx(hkey2, NULL, NULL, NULL, (PBYTE)pszInvokeVerb,
  1199. &cbInvokeVerb))
  1200. {
  1201. if (cbInvokeVerb && *pszInvokeVerb)
  1202. {
  1203. if (cbInvokeVerb != (cchInvokeVerb * sizeof(WCHAR)))
  1204. {
  1205. fGotDefault = TRUE;
  1206. }
  1207. }
  1208. }
  1209. RegCloseKey(hkey2);
  1210. }
  1211. RegCloseKey(hkey);
  1212. }
  1213. if (!fGotDefault)
  1214. {
  1215. StrCpyN(pszInvokeVerb, TEXT("play"), cchInvokeVerb);
  1216. }
  1217. hr = S_OK;
  1218. }
  1219. else
  1220. {
  1221. hr = _GetHandlerInvokeProgIDAndVerb(pszHandler, pszInvokeProgID,
  1222. cchInvokeProgID, pszInvokeVerb, cchInvokeVerb);
  1223. }
  1224. return hr;
  1225. }
  1226. BOOL CMountPoint::_ExecuteHelper(LPCWSTR pszHandler, LPCWSTR pszContentTypeHandler,
  1227. CAutoPlayParams *papp, DWORD dwMtPtContentType)
  1228. {
  1229. HRESULT hr;
  1230. if (lstrcmpi(pszHandler, TEXT("MSTakeNoAction")))
  1231. {
  1232. WCHAR szInvokeProgID[260];
  1233. WCHAR szInvokeVerb[CCH_KEYMAX];
  1234. hr = _GetProgidAndVerb(dwMtPtContentType, pszHandler, szInvokeProgID,
  1235. ARRAYSIZE(szInvokeProgID), szInvokeVerb, ARRAYSIZE(szInvokeVerb));
  1236. if (SUCCEEDED(hr))
  1237. {
  1238. HKEY hkey;
  1239. if (dwMtPtContentType & (CT_CDAUDIO | CT_DVDMOVIE))
  1240. {
  1241. hr = papp->MountPoint()->_CopyInvokeVerbKey(szInvokeProgID, szInvokeVerb);
  1242. hkey = papp->MountPoint()->RSDuplicateRootKey();
  1243. papp->MountPoint()->RSSetTextValue(TEXT("shell"), NULL, szInvokeVerb, REG_OPTION_NON_VOLATILE);
  1244. }
  1245. else
  1246. {
  1247. hr = ResultFromWin32(RegOpenKeyExW(HKEY_CLASSES_ROOT, szInvokeProgID, 0, MAXIMUM_ALLOWED, &hkey));
  1248. }
  1249. if (SUCCEEDED(hr))
  1250. {
  1251. IDataObject* pdo;
  1252. hr = papp->DataObject(&pdo);
  1253. if (SUCCEEDED(hr))
  1254. {
  1255. hr = _InvokeAutoRunProgid(hkey, szInvokeVerb, pdo);
  1256. pdo->Release();
  1257. }
  1258. RegCloseKey(hkey);
  1259. }
  1260. }
  1261. }
  1262. else
  1263. {
  1264. hr = S_FALSE;
  1265. }
  1266. return SUCCEEDED(hr);
  1267. }
  1268. BOOL CMountPoint::_acExecuteAutoplayDefault(HWND hwndForeground, CAutoPlayParams *papp)
  1269. {
  1270. BOOL fRet = FALSE;
  1271. if (DT_ANYLOCALDRIVES & papp->DriveType())
  1272. {
  1273. WCHAR szContentTypeHandler[MAX_CONTENTTYPEHANDLER];
  1274. DWORD dwMtPtContentType = papp->ContentType() & ~CT_UNKNOWNCONTENT;
  1275. HRESULT hr = _GetContentTypeHandler(dwMtPtContentType, szContentTypeHandler, ARRAYSIZE(szContentTypeHandler));
  1276. if (SUCCEEDED(hr))
  1277. {
  1278. IAutoplayHandler* piah;
  1279. hr = _GetAutoplayHandler(papp->Drive(), TEXT("ContentArrival"), szContentTypeHandler, &piah);
  1280. if (SUCCEEDED(hr))
  1281. {
  1282. LPWSTR pszHandlerDefault;
  1283. hr = piah->GetDefaultHandler(&pszHandlerDefault);
  1284. if (SUCCEEDED(hr))
  1285. {
  1286. // No need to check for (S_HANDLERS_MORE_RECENT_THAN_USER_SELECTION == hr) here
  1287. // It should have been caught by _acUserHasSelectedApplication
  1288. fRet = _ExecuteHelper(pszHandlerDefault, szContentTypeHandler, papp, dwMtPtContentType);
  1289. }
  1290. CoTaskMemFree(pszHandlerDefault);
  1291. }
  1292. piah->Release();
  1293. }
  1294. }
  1295. return fRet;
  1296. }
  1297. BOOL CMountPoint::_acWasjustDocked(HWND hwndForeground, CAutoPlayParams *papp)
  1298. {
  1299. BOOL fRet = FALSE;
  1300. if (DT_ANYLOCALDRIVES & papp->DriveType())
  1301. {
  1302. CMtPtLocal* pmtptl = (CMtPtLocal*)papp->MountPoint();
  1303. if (pmtptl->_CanUseVolume())
  1304. {
  1305. if (pmtptl->_pvol->dwVolumeFlags & HWDVF_STATE_JUSTDOCKED)
  1306. {
  1307. fRet = TRUE;
  1308. }
  1309. }
  1310. }
  1311. return fRet;
  1312. }
  1313. CRITICAL_SECTION g_csAutoplayPrompt = {0};
  1314. HDPA g_hdpaAutoplayPrompt = NULL;
  1315. BOOL CMountPoint::_acPromptUser(HWND hwndForeground, CAutoPlayParams *papp)
  1316. {
  1317. BOOL fRet = FALSE;
  1318. BOOL fShowDlg = TRUE;
  1319. if (papp->Drive())
  1320. {
  1321. fShowDlg = _AddAutoplayPrompt(papp->Drive());
  1322. }
  1323. if (fShowDlg)
  1324. {
  1325. CBaseContentDlg* pdlg;
  1326. papp->ForceSniff();
  1327. DWORD dwMtPtContentType = papp->ContentType() & ~CT_UNKNOWNCONTENT;
  1328. if (dwMtPtContentType)
  1329. {
  1330. if (_acIsMixedContent(hwndForeground, papp))
  1331. {
  1332. pdlg = new CMixedContentDlg();
  1333. dwMtPtContentType &= CT_ANYAUTOPLAYCONTENT;
  1334. if (pdlg)
  1335. {
  1336. pdlg->_iResource = DLG_APMIXEDCONTENT;
  1337. }
  1338. }
  1339. else
  1340. {
  1341. pdlg = new CHWContentPromptDlg();
  1342. if (pdlg)
  1343. {
  1344. pdlg->_iResource = DLG_APPROMPTUSER;
  1345. }
  1346. }
  1347. }
  1348. if (pdlg)
  1349. {
  1350. // Better be a local drive
  1351. if (DT_ANYLOCALDRIVES & papp->DriveType())
  1352. {
  1353. CMtPtLocal* pmtptl = (CMtPtLocal*)papp->MountPoint();
  1354. if (pmtptl->_CanUseVolume())
  1355. {
  1356. HRESULT hr = pdlg->Init(pmtptl->_pvol->pszDeviceIDVolume, papp->Drive(), dwMtPtContentType,
  1357. papp->_fCheckAlwaysDoThisCheckBox);
  1358. pdlg->_hinst = g_hinst;
  1359. pdlg->_hwndParent = NULL;
  1360. if (SUCCEEDED(hr))
  1361. {
  1362. INT_PTR iRet = pdlg->DoModal(pdlg->_hinst, MAKEINTRESOURCE(pdlg->_iResource),
  1363. pdlg->_hwndParent);
  1364. if (IDOK == iRet)
  1365. {
  1366. fRet = _ExecuteHelper(pdlg->_szHandler, pdlg->_szContentTypeHandler,
  1367. papp, dwMtPtContentType);
  1368. }
  1369. }
  1370. }
  1371. }
  1372. pdlg->Release();
  1373. }
  1374. if (papp->Drive())
  1375. {
  1376. _RemoveFromAutoplayPromptHDPA(papp->Drive());
  1377. }
  1378. }
  1379. return fRet;
  1380. }
  1381. BOOL CMountPoint::_acIsMixedContent(HWND hwndForeground, CAutoPlayParams *papp)
  1382. {
  1383. BOOL fRet;
  1384. if (papp->IsContentTypePresent(CT_ANYAUTOPLAYCONTENT))
  1385. {
  1386. fRet = IsMixedContent(papp->ContentType());
  1387. }
  1388. else
  1389. {
  1390. fRet = FALSE;
  1391. }
  1392. return fRet;
  1393. }
  1394. BOOL CMountPoint::_acAlwaysReturnsTRUE(HWND hwndForeground, CAutoPlayParams *papp)
  1395. {
  1396. return TRUE;
  1397. }
  1398. BOOL CMountPoint::_acShouldSniff(HWND hwndForeground, CAutoPlayParams *papp)
  1399. {
  1400. BOOL fRet = TRUE;
  1401. CMtPtLocal* pmtptl = papp->MountPointLocal();
  1402. if (pmtptl)
  1403. {
  1404. if (pmtptl->_CanUseVolume())
  1405. {
  1406. fRet = !(HWDVF_STATE_DONOTSNIFFCONTENT & pmtptl->_pvol->dwVolumeFlags);
  1407. }
  1408. }
  1409. return fRet;
  1410. }
  1411. BOOL CMountPoint::_acAddAutoplayVerb(HWND hwndForeground, CAutoPlayParams *papp)
  1412. {
  1413. CMtPtLocal* pmtptl = papp->MountPointLocal();
  1414. if (pmtptl)
  1415. {
  1416. if (pmtptl->_CanUseVolume())
  1417. {
  1418. // We don't care about the return value
  1419. pmtptl->_AddAutoplayVerb();
  1420. }
  1421. }
  1422. return TRUE;
  1423. }
  1424. //
  1425. // END: Fcts for matrix below
  1426. #define SKIPDEPENDENTS_ONFALSE 0x00000001 // Skips dependents
  1427. #define SKIPDEPENDENTS_ONTRUE 0x00000002 // Skips dependents
  1428. #define CANCEL_AUTOPLAY_ONFALSE 0x00000004
  1429. #define CANCEL_AUTOPLAY_ONTRUE 0x00000008
  1430. #define NOTAPPLICABLE_ONANY 0x00000010
  1431. #define LEVEL_EXECUTE 0x10000000
  1432. #define LEVEL_SKIP 0x20000000
  1433. #define LEVEL_SPECIALMASK 0x30000000
  1434. #define LEVEL_REALLEVELMASK 0x0FFFFFFF
  1435. typedef BOOL (AUTORUNFCT)(HWND hwndForeground, CAutoPlayParams *papp);
  1436. // fct is called with pszDrive, papp->MountPoint(), hwndForeground, drive type and content type
  1437. struct AUTORUNCONDITION
  1438. {
  1439. DWORD dwNestingLevel;
  1440. DWORD dwMtPtDriveType;
  1441. DWORD dwMtPtContentType;
  1442. DWORD dwReturnValueHandling;
  1443. AUTORUNFCT* fct;
  1444. #ifdef DEBUG
  1445. LPCWSTR pszDebug;
  1446. #endif
  1447. };
  1448. // For this table to be more readable, add the content of \\stephstm\public\usertype.dat to
  1449. // %ProgramFiles%\Microsoft Visual Studio\Common\MSDev98\Bin\usertype.dat
  1450. // then restart MSDev
  1451. // AR_ENTRY -> AUTORUN_ENTRY
  1452. #ifdef DEBUG
  1453. #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) }
  1454. #else
  1455. #define AR_ENTRY(a, b, c, d, e) { (a), (b), (c), (d), CMountPoint::e }
  1456. #endif
  1457. // DT_* -> DriveType
  1458. // CT_* -> ContentType
  1459. static const AUTORUNCONDITION _rgAutorun[] =
  1460. {
  1461. // We don't autorun if the drive is not mounted on a drive letter
  1462. AR_ENTRY(0, DT_ANYTYPE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acDriveIsMountedOnDriveLetter),
  1463. // We don't autorun if this is a restricted drive
  1464. AR_ENTRY(0, DT_ANYTYPE & ~DT_REMOTE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acDriveIsRestricted),
  1465. // Add the Autoplay Verb
  1466. AR_ENTRY(1, DT_ANYTYPE & ~DT_REMOTE, CT_ANYCONTENT & ~CT_AUTORUNINF, SKIPDEPENDENTS_ONFALSE, _acAddAutoplayVerb),
  1467. // We don't autorun if the Shift key is down
  1468. AR_ENTRY(0, DT_ANYTYPE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acShiftKeyDown),
  1469. // We don't autorun if a laptop was just docked. All devices in the craddle come as nhew devices.
  1470. AR_ENTRY(0, DT_ANYTYPE & ~DT_REMOTE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acWasjustDocked),
  1471. // We don't autorun if the Current Desktop is not the active console desktop
  1472. AR_ENTRY(0, DT_ANYTYPE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acCurrentDesktopIsActiveConsole),
  1473. // We don't autorun if the Current Desktop is not the active console desktop
  1474. AR_ENTRY(0, DT_ANYTYPE, CT_ANYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acDirectXAppRunningFullScreen),
  1475. // Remote drive always Autorun (mostly opening folder)
  1476. AR_ENTRY(1, DT_REMOTE, CT_ANYCONTENT, SKIPDEPENDENTS_ONFALSE, _acForegroundAppAllowsAutorun),
  1477. AR_ENTRY(1, DT_REMOTE, CT_ANYCONTENT, SKIPDEPENDENTS_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1478. AR_ENTRY(2 | LEVEL_EXECUTE, DT_REMOTE, CT_ANYCONTENT, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
  1479. // Autorun.inf
  1480. AR_ENTRY(1, DT_ANYTYPE & ~DT_REMOVABLEDISK, CT_AUTORUNINF, SKIPDEPENDENTS_ONFALSE, _acHasAutorunCommand),
  1481. AR_ENTRY(2, DT_ANYTYPE & ~DT_REMOVABLEDISK, CT_AUTORUNINF, SKIPDEPENDENTS_ONTRUE, _acHasUseAutoPLAY),
  1482. AR_ENTRY(3, DT_ANYTYPE & ~DT_REMOVABLEDISK, CT_AUTORUNINF, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
  1483. AR_ENTRY(3, DT_ANYTYPE & ~DT_REMOVABLEDISK, CT_AUTORUNINF, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1484. AR_ENTRY(4 | LEVEL_EXECUTE, DT_ANYCDDRIVES, CT_AUTORUNINF, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
  1485. // CD Audio
  1486. AR_ENTRY(1, DT_ANYCDDRIVES, CT_CDAUDIO, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
  1487. AR_ENTRY(1, DT_ANYCDDRIVES, CT_CDAUDIO, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1488. AR_ENTRY(2, DT_ANYCDDRIVES, CT_CDAUDIO, SKIPDEPENDENTS_ONFALSE, _acUserHasSelectedApplication),
  1489. AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYCDDRIVES, CT_CDAUDIO, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
  1490. AR_ENTRY(LEVEL_EXECUTE | 1, DT_ANYCDDRIVES, CT_CDAUDIO, NOTAPPLICABLE_ONANY, _acPromptUser),
  1491. // DVD Movie
  1492. AR_ENTRY(1, DT_ANYCDDRIVES, CT_DVDMOVIE, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
  1493. AR_ENTRY(1, DT_ANYCDDRIVES, CT_DVDMOVIE, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1494. AR_ENTRY(2, DT_ANYCDDRIVES, CT_DVDMOVIE, SKIPDEPENDENTS_ONFALSE, _acUserHasSelectedApplication),
  1495. AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYCDDRIVES, CT_DVDMOVIE, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
  1496. AR_ENTRY(LEVEL_EXECUTE | 1, DT_ANYCDDRIVES, CT_DVDMOVIE, NOTAPPLICABLE_ONANY, _acPromptUser),
  1497. // Writable CDs
  1498. AR_ENTRY(1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
  1499. AR_ENTRY(1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1500. AR_ENTRY(2, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, SKIPDEPENDENTS_ONFALSE, _acUserHasSelectedApplication),
  1501. AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
  1502. AR_ENTRY(LEVEL_EXECUTE | 1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, NOTAPPLICABLE_ONANY, _acPromptUser),
  1503. // Writable DVDs
  1504. AR_ENTRY(LEVEL_SKIP | 1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
  1505. AR_ENTRY(LEVEL_SKIP | 1, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1506. AR_ENTRY(LEVEL_SKIP | 2, DT_ANYCDDRIVES, CT_BLANKCDWRITABLE, SKIPDEPENDENTS_ONFALSE, _acUserHasSelectedApplication),
  1507. AR_ENTRY(LEVEL_SKIP | 3 | LEVEL_EXECUTE, DT_ANYDVDDRIVES, CT_BLANKDVDWRITABLE, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
  1508. AR_ENTRY(LEVEL_SKIP | LEVEL_EXECUTE | 1, DT_ANYDVDDRIVES, CT_BLANKDVDWRITABLE, NOTAPPLICABLE_ONANY, _acPromptUser),
  1509. // Mixed content
  1510. AR_ENTRY(1, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, SKIPDEPENDENTS_ONFALSE, _acIsMixedContent),
  1511. AR_ENTRY(2, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, SKIPDEPENDENTS_ONTRUE, _acUserHasSelectedApplication),
  1512. AR_ENTRY(3, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1513. AR_ENTRY(4 | LEVEL_EXECUTE, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acPromptUser),
  1514. AR_ENTRY(LEVEL_EXECUTE | 2, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
  1515. // Single Autoplay content
  1516. AR_ENTRY(1, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1517. AR_ENTRY(2, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, SKIPDEPENDENTS_ONTRUE, _acUserHasSelectedApplication),
  1518. AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acPromptUser),
  1519. AR_ENTRY(LEVEL_EXECUTE | 2, DT_ANYTYPE & ~DT_REMOTE, CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acExecuteAutoplayDefault),
  1520. // Unknown content
  1521. AR_ENTRY(1, DT_ANYREMOVABLEMEDIADRIVES, CT_UNKNOWNCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
  1522. AR_ENTRY(1, DT_ANYREMOVABLEMEDIADRIVES, CT_UNKNOWNCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1523. // If we should not sniff, we should not open a folder either
  1524. AR_ENTRY(2, DT_ANYREMOVABLEMEDIADRIVES, CT_UNKNOWNCONTENT, SKIPDEPENDENTS_ONFALSE, _acShouldSniff),
  1525. AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYREMOVABLEMEDIADRIVES, CT_UNKNOWNCONTENT, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
  1526. // Weird CDs have autorun.inf but no autorun command
  1527. AR_ENTRY(2, DT_ANYREMOVABLEMEDIADRIVES, CT_AUTORUNINF, SKIPDEPENDENTS_ONTRUE, _acHasAutorunCommand),
  1528. AR_ENTRY(3 | LEVEL_EXECUTE, DT_ANYREMOVABLEMEDIADRIVES, CT_AUTORUNINF, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
  1529. // Former ShellOpen, basically we ShellExecute whatever drives except CD drives if the shell is in the foreground
  1530. AR_ENTRY(1, ~DT_ANYCDDRIVES, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, SKIPDEPENDENTS_ONFALSE, _acShellIsForegroundApp),
  1531. AR_ENTRY(2, ~DT_ANYCDDRIVES, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acAlwaysReturnsTRUE),
  1532. // Additonnal restrictions on Fixed disk drive
  1533. AR_ENTRY(3, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acDriveIsFormatted),
  1534. AR_ENTRY(4, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acOSIsServer),
  1535. AR_ENTRY(5, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONTRUE, _acIsDockedLaptop),
  1536. AR_ENTRY(6, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
  1537. AR_ENTRY(6, DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1538. AR_ENTRY(7 | LEVEL_EXECUTE, DT_ANYTYPE, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
  1539. // Non Fixed Disk drives
  1540. AR_ENTRY(3, ~DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acForegroundAppAllowsAutorun),
  1541. AR_ENTRY(3, ~DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, CANCEL_AUTOPLAY_ONFALSE, _acQueryCancelAutoplayAllowsAutorun),
  1542. AR_ENTRY(4 | LEVEL_EXECUTE, ~DT_FIXEDDISK, CT_ANYCONTENT & ~CT_ANYAUTOPLAYCONTENT, NOTAPPLICABLE_ONANY, _acShellExecuteDriveAutorunINF),
  1543. };
  1544. // This array will be dumped in the registry under the Volume GUID of the
  1545. // drive in a value named _AutorunStatus
  1546. //
  1547. // Each byte represents an entry in the above table. Following is the
  1548. // meaning of each byte:
  1549. //
  1550. // 01: Condition was TRUE
  1551. // 00: Condition was FALSE
  1552. // CF: ContentType condition was failed
  1553. // DF: DriveType condition was failed
  1554. // 5F: Condition was skipped (5 looks like an 'S' :)
  1555. // EE: Condition was executed
  1556. // FF: Never got there
  1557. // Use a struct to avoid alignement issues
  1558. #pragma pack(push, 4)
  1559. struct AUTORUNSTATUS
  1560. {
  1561. BYTE _rgbAutorunStatus[ARRAYSIZE(_rgAutorun)];
  1562. DWORD dwDriveType;
  1563. DWORD dwContentType;
  1564. };
  1565. #pragma pack(pop)
  1566. static AUTORUNSTATUS s_autorunstatus;
  1567. // static
  1568. void CMountPoint::DoAutorun(LPCWSTR pszDrive, DWORD dwAutorunFlags)
  1569. {
  1570. CMountPoint* pmtpt = GetMountPoint(pszDrive);
  1571. FillMemory(s_autorunstatus._rgbAutorunStatus, sizeof(s_autorunstatus._rgbAutorunStatus), -1);
  1572. if (pmtpt)
  1573. {
  1574. CAutoPlayParams app(pszDrive, pmtpt, dwAutorunFlags);
  1575. if (AUTORUNFLAG_MENUINVOKED & dwAutorunFlags)
  1576. {
  1577. _acPromptUser(GetForegroundWindow(), &app);
  1578. }
  1579. else
  1580. {
  1581. _DoAutorunHelper(&app);
  1582. }
  1583. pmtpt->Release();
  1584. }
  1585. }
  1586. void CAutoPlayParams::_TrySniff()
  1587. {
  1588. if (!(APS_DID_SNIFF & _state))
  1589. {
  1590. if (_ShouldSniffDrive(TRUE))
  1591. {
  1592. DWORD dwFound;
  1593. if (SUCCEEDED(_Sniff(&dwFound)))
  1594. {
  1595. _dwContentType |= dwFound;
  1596. }
  1597. }
  1598. _state |= APS_DID_SNIFF;
  1599. }
  1600. }
  1601. BOOL CAutoPlayParams::IsContentTypePresent(DWORD dwContentType)
  1602. {
  1603. BOOL fRet;
  1604. if (CT_ANYCONTENT == dwContentType)
  1605. {
  1606. fRet = TRUE;
  1607. }
  1608. else
  1609. {
  1610. // We special case this because we do not want to sniff at this point
  1611. if ((CT_ANYCONTENT & ~CT_AUTORUNINF) == dwContentType)
  1612. {
  1613. if (CT_AUTORUNINF == _dwContentType)
  1614. {
  1615. fRet = FALSE;
  1616. }
  1617. else
  1618. {
  1619. // Anything else is good
  1620. fRet = TRUE;
  1621. }
  1622. }
  1623. else
  1624. {
  1625. if (CT_ANYAUTOPLAYCONTENT & dwContentType)
  1626. {
  1627. _TrySniff();
  1628. }
  1629. fRet = !!(dwContentType & _dwContentType);
  1630. }
  1631. }
  1632. return fRet;
  1633. }
  1634. void CAutoPlayParams::ForceSniff()
  1635. {
  1636. if (AUTORUNFLAG_MENUINVOKED & _dwAutorunFlags)
  1637. {
  1638. _TrySniff();
  1639. }
  1640. }
  1641. // static
  1642. void CMountPoint::_DoAutorunHelper(CAutoPlayParams *papp)
  1643. {
  1644. DWORD dwMaxLevelToProcess = 0;
  1645. BOOL fStop = FALSE;
  1646. HWND hwndForeground = GetForegroundWindow();
  1647. for (DWORD dwStep = 0; !fStop && (dwStep < ARRAYSIZE(_rgAutorun)); ++dwStep)
  1648. {
  1649. if (!(_rgAutorun[dwStep].dwNestingLevel & LEVEL_SKIP))
  1650. {
  1651. if ((_rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK) <= dwMaxLevelToProcess)
  1652. {
  1653. BOOL fConditionResult = FALSE;
  1654. // We do not want to Cancel the whole Autoplay operation if we do not get a
  1655. // match for a drive type or content type. We do the Cancel Autoplay only
  1656. // if the condition was evaluated.
  1657. BOOL fConditionEvaluated = FALSE;
  1658. if (_rgAutorun[dwStep].dwMtPtDriveType & papp->DriveType())
  1659. {
  1660. if (papp->IsContentTypePresent(_rgAutorun[dwStep].dwMtPtContentType))
  1661. {
  1662. if (!(_rgAutorun[dwStep].dwNestingLevel & LEVEL_EXECUTE))
  1663. {
  1664. fConditionResult = ((_rgAutorun[dwStep].fct)(hwndForeground, papp));
  1665. s_autorunstatus._rgbAutorunStatus[dwStep] = fConditionResult ? 1 : 0;
  1666. fConditionEvaluated = TRUE;
  1667. }
  1668. else
  1669. {
  1670. // LEVEL_EXECUTE
  1671. #ifdef DEBUG
  1672. TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: EXECUTING -> %s", dwStep, _rgAutorun[dwStep].pszDebug);
  1673. #endif
  1674. _rgAutorun[dwStep].fct(hwndForeground, papp);
  1675. // 2 execute
  1676. s_autorunstatus._rgbAutorunStatus[dwStep] = 0xEE;
  1677. // We're done
  1678. fStop = TRUE;
  1679. }
  1680. }
  1681. else
  1682. {
  1683. #ifdef DEBUG
  1684. TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: NO MATCH on CONTENTTYPE, %s ", dwStep, _rgAutorun[dwStep].pszDebug);
  1685. #endif
  1686. s_autorunstatus._rgbAutorunStatus[dwStep] = 0xCF;
  1687. }
  1688. }
  1689. else
  1690. {
  1691. #ifdef DEBUG
  1692. TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: NO MATCH on DRIVETYPE, %s ", dwStep, _rgAutorun[dwStep].pszDebug);
  1693. #endif
  1694. s_autorunstatus._rgbAutorunStatus[dwStep] = 0xDF;
  1695. }
  1696. if (!fStop)
  1697. {
  1698. if (fConditionResult)
  1699. {
  1700. #ifdef DEBUG
  1701. TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: TRUE -> %s", dwStep, _rgAutorun[dwStep].pszDebug);
  1702. #endif
  1703. switch (_rgAutorun[dwStep].dwReturnValueHandling)
  1704. {
  1705. case SKIPDEPENDENTS_ONTRUE:
  1706. dwMaxLevelToProcess = _rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK;
  1707. break;
  1708. case CANCEL_AUTOPLAY_ONTRUE:
  1709. if (fConditionEvaluated)
  1710. {
  1711. fStop = TRUE;
  1712. }
  1713. break;
  1714. default:
  1715. dwMaxLevelToProcess = (_rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK) + 1;
  1716. break;
  1717. case NOTAPPLICABLE_ONANY:
  1718. break;
  1719. }
  1720. }
  1721. else
  1722. {
  1723. #ifdef DEBUG
  1724. TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: FALSE -> %s", dwStep, _rgAutorun[dwStep].pszDebug);
  1725. #endif
  1726. switch (_rgAutorun[dwStep].dwReturnValueHandling)
  1727. {
  1728. case SKIPDEPENDENTS_ONFALSE:
  1729. dwMaxLevelToProcess = _rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK;
  1730. break;
  1731. case CANCEL_AUTOPLAY_ONFALSE:
  1732. if (fConditionEvaluated)
  1733. {
  1734. fStop = TRUE;
  1735. }
  1736. break;
  1737. default:
  1738. dwMaxLevelToProcess = (_rgAutorun[dwStep].dwNestingLevel & LEVEL_REALLEVELMASK) + 1;
  1739. break;
  1740. case NOTAPPLICABLE_ONANY:
  1741. break;
  1742. }
  1743. }
  1744. }
  1745. }
  1746. else
  1747. {
  1748. #ifdef DEBUG
  1749. TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: SKIPPING , %s ", dwStep, _rgAutorun[dwStep].pszDebug);
  1750. #endif
  1751. s_autorunstatus._rgbAutorunStatus[dwStep] = 0x5F;
  1752. }
  1753. }
  1754. else
  1755. {
  1756. #ifdef DEBUG
  1757. TraceMsg(TF_MOUNTPOINT, "AUTORUN[%d]: LVL-SKIP , %s ", dwStep, _rgAutorun[dwStep].pszDebug);
  1758. #endif
  1759. s_autorunstatus._rgbAutorunStatus[dwStep] = 0x5F;
  1760. }
  1761. }
  1762. s_autorunstatus.dwDriveType = papp->DriveType();
  1763. s_autorunstatus.dwContentType = papp->ContentType();
  1764. papp->MountPoint()->SetAutorunStatus((BYTE*)&s_autorunstatus, sizeof(s_autorunstatus));
  1765. }
  1766. DWORD _DoDWORDMapping(DWORD dwLeft, const TWODWORDS* rgtwodword, DWORD ctwodword, BOOL fORed)
  1767. {
  1768. DWORD dwRight = 0;
  1769. for (DWORD dw = 0; dw < ctwodword; ++dw)
  1770. {
  1771. if (fORed)
  1772. {
  1773. if (dwLeft & rgtwodword[dw].dwLeft)
  1774. {
  1775. dwRight |= rgtwodword[dw].dwRight;
  1776. }
  1777. }
  1778. else
  1779. {
  1780. if (dwLeft == rgtwodword[dw].dwLeft)
  1781. {
  1782. dwRight = rgtwodword[dw].dwRight;
  1783. break;
  1784. }
  1785. }
  1786. }
  1787. return dwRight;
  1788. }
  1789. STDMETHODIMP CSniffDrive::QueryInterface(REFIID riid, void **ppv)
  1790. {
  1791. static const QITAB qit[] =
  1792. {
  1793. QITABENT(CSniffDrive, INamespaceWalkCB),
  1794. { 0 },
  1795. };
  1796. return QISearch(this, qit, riid, ppv);
  1797. }
  1798. STDMETHODIMP CSniffDrive::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl)
  1799. {
  1800. // include everything
  1801. HRESULT hr = S_OK;
  1802. if (!_pne || !_pne->fStopSniffing)
  1803. {
  1804. // if we found everything we dont need to worry about sniffing
  1805. // now we are just populating the dataobject
  1806. if (!_FoundEverything())
  1807. {
  1808. PERCEIVED gen = GetPerceivedType(psf, pidl);
  1809. if (GEN_IMAGE == gen)
  1810. {
  1811. _dwFound |= CT_AUTOPLAYPIX;
  1812. }
  1813. else if (GEN_AUDIO == gen)
  1814. {
  1815. _dwFound |= CT_AUTOPLAYMUSIC;
  1816. }
  1817. else if (GEN_VIDEO == gen)
  1818. {
  1819. _dwFound |= CT_AUTOPLAYMOVIE;
  1820. }
  1821. else
  1822. {
  1823. _dwFound |= CT_UNKNOWNCONTENT;
  1824. }
  1825. hr = S_OK;
  1826. }
  1827. }
  1828. else
  1829. {
  1830. hr = E_FAIL;
  1831. }
  1832. // we never want the results on the sniff
  1833. return hr;
  1834. }
  1835. STDMETHODIMP CSniffDrive::EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  1836. {
  1837. return S_OK;
  1838. }
  1839. STDMETHODIMP CSniffDrive::LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  1840. {
  1841. return S_OK;
  1842. }
  1843. STDMETHODIMP CSniffDrive::InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel)
  1844. {
  1845. *ppszCancel = NULL; // use default
  1846. TCHAR szMsg[256];
  1847. LoadString(g_hinst, IDS_AP_SNIFFPROGRESSDIALOG, szMsg, ARRAYSIZE(szMsg));
  1848. return SHStrDup(szMsg, ppszTitle);
  1849. }
  1850. // static
  1851. HRESULT CSniffDrive::Init(HANDLE hThreadSCN)
  1852. {
  1853. HRESULT hr;
  1854. if (DuplicateHandle(GetCurrentProcess(), hThreadSCN, GetCurrentProcess(),
  1855. &_hThreadSCN, THREAD_ALL_ACCESS, FALSE, 0))
  1856. {
  1857. hr = S_OK;
  1858. }
  1859. else
  1860. {
  1861. hr = E_FAIL;
  1862. }
  1863. return S_OK;
  1864. }
  1865. // static
  1866. HRESULT CSniffDrive::CleanUp()
  1867. {
  1868. if (_dpaNotifs)
  1869. {
  1870. // We should not need to delete the items, they should all be removed. Even
  1871. // if they're, we should leave them there since something will probably try
  1872. // to access them.
  1873. _dpaNotifs.Destroy();
  1874. _dpaNotifs = NULL;
  1875. }
  1876. if (_hThreadSCN)
  1877. {
  1878. CloseHandle(_hThreadSCN);
  1879. _hThreadSCN = NULL;
  1880. }
  1881. return S_OK;
  1882. }
  1883. // static
  1884. HRESULT CSniffDrive::InitNotifyWindow(HWND hwnd)
  1885. {
  1886. _hwndNotify = hwnd;
  1887. return S_OK;
  1888. }
  1889. HRESULT CSniffDrive::RegisterForNotifs(LPCWSTR pszDeviceIDVolume)
  1890. {
  1891. HRESULT hr;
  1892. _pne = new PNPNOTIFENTRY();
  1893. if (_pne)
  1894. {
  1895. HANDLE hDevice = CreateFile(pszDeviceIDVolume, FILE_READ_ATTRIBUTES,
  1896. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  1897. if (INVALID_HANDLE_VALUE != hDevice)
  1898. {
  1899. DEV_BROADCAST_HANDLE dbhNotifFilter = {0};
  1900. // Assume failure
  1901. hr = E_FAIL;
  1902. dbhNotifFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  1903. dbhNotifFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
  1904. dbhNotifFilter.dbch_handle = hDevice;
  1905. _pne->hdevnotify = RegisterDeviceNotification(_hwndNotify, &dbhNotifFilter,
  1906. DEVICE_NOTIFY_WINDOW_HANDLE);
  1907. if (_pne->hdevnotify)
  1908. {
  1909. _pne->AddRef();
  1910. if (QueueUserAPC(CSniffDrive::_RegisterForNotifsHelper, _hThreadSCN, (ULONG_PTR)_pne))
  1911. {
  1912. hr = S_OK;
  1913. }
  1914. else
  1915. {
  1916. _pne->Release();
  1917. }
  1918. }
  1919. CloseHandle(hDevice);
  1920. }
  1921. else
  1922. {
  1923. hr = E_FAIL;
  1924. }
  1925. if (FAILED(hr))
  1926. {
  1927. // Something must have gone wrong
  1928. _pne->Release();
  1929. _pne = NULL;
  1930. }
  1931. }
  1932. else
  1933. {
  1934. hr = E_OUTOFMEMORY;
  1935. }
  1936. return hr;
  1937. }
  1938. HRESULT CSniffDrive::UnregisterForNotifs()
  1939. {
  1940. UnregisterDeviceNotification(_pne->hdevnotify);
  1941. QueueUserAPC(CSniffDrive::_UnregisterForNotifsHelper, _hThreadSCN, (ULONG_PTR)_pne);
  1942. _pne->Release();
  1943. _pne = NULL;
  1944. return S_OK;
  1945. }
  1946. // static
  1947. void CALLBACK CSniffDrive::_RegisterForNotifsHelper(ULONG_PTR ul)
  1948. {
  1949. PNPNOTIFENTRY* pne = (PNPNOTIFENTRY*)ul;
  1950. if (!_dpaNotifs)
  1951. {
  1952. _dpaNotifs.Create(1);
  1953. }
  1954. if (_dpaNotifs)
  1955. {
  1956. // We do not check the return value. We cannot free it, since the thread that
  1957. // queued this APC to us, expect this chunk of mem to be there until it calls
  1958. // UnregisterNotify. We'll leak it. Hopefully, this won't happen often.
  1959. _dpaNotifs.AppendPtr(pne);
  1960. }
  1961. }
  1962. // static
  1963. void CALLBACK CSniffDrive::_UnregisterForNotifsHelper(ULONG_PTR ul)
  1964. {
  1965. PNPNOTIFENTRY* pne = (PNPNOTIFENTRY*)ul;
  1966. if (_dpaNotifs)
  1967. {
  1968. int cItem = _dpaNotifs.GetPtrCount();
  1969. for (int i = 0; i < cItem; ++i)
  1970. {
  1971. PNPNOTIFENTRY* pneTmp = _dpaNotifs.GetPtr(i);
  1972. if (pneTmp->hdevnotify == pne->hdevnotify)
  1973. {
  1974. CloseHandle(pne->hThread);
  1975. _dpaNotifs.DeletePtr(i);
  1976. pne->Release();
  1977. break;
  1978. }
  1979. }
  1980. }
  1981. }
  1982. // static
  1983. HRESULT CSniffDrive::HandleNotif(HDEVNOTIFY hdevnotify)
  1984. {
  1985. int cItem = _dpaNotifs ? _dpaNotifs.GetPtrCount() : 0;
  1986. for (int i = 0; i < cItem; ++i)
  1987. {
  1988. PNPNOTIFENTRY* pneTmp = _dpaNotifs.GetPtr(i);
  1989. if (pneTmp->hdevnotify == hdevnotify)
  1990. {
  1991. pneTmp->fStopSniffing = TRUE;
  1992. // We don't check the return value. The worst that will happen is that this
  1993. // fails and we'll return too early and PnP will prompt the user to reboot.
  1994. // Wait 2 minutes
  1995. WaitForSingleObjectEx(pneTmp->hThread, 2 * 60 * 1000, FALSE);
  1996. break;
  1997. }
  1998. }
  1999. return S_OK;
  2000. }
  2001. BOOL CSniffDrive::_FoundEverything()
  2002. {
  2003. return (_dwFound & DRIVEHAS_EVERYTHING) == DRIVEHAS_EVERYTHING;
  2004. }
  2005. CSniffDrive::CSniffDrive() : _dwFound(0)
  2006. {}
  2007. CSniffDrive::~CSniffDrive()
  2008. {}
  2009. void CMountPoint::SetAutorunStatus(BYTE* rgb, DWORD cbSize)
  2010. {
  2011. RSSetBinaryValue(NULL, TEXT("_AutorunStatus"), rgb, cbSize);
  2012. }
  2013. class CAutoPlayVerb : public IDropTarget
  2014. {
  2015. public:
  2016. CAutoPlayVerb() : _cRef(1) {}
  2017. // IUnknown refcounting
  2018. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  2019. STDMETHODIMP_(ULONG) AddRef(void)
  2020. {
  2021. return ++_cRef;
  2022. }
  2023. STDMETHODIMP_(ULONG) Release(void)
  2024. {
  2025. if (--_cRef > 0)
  2026. return _cRef;
  2027. delete this;
  2028. return 0;
  2029. }
  2030. // IDropTarget ***
  2031. STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  2032. STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  2033. STDMETHODIMP DragLeave(void);
  2034. STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  2035. protected:
  2036. LONG _cRef;
  2037. };
  2038. HRESULT CAutoPlayVerb::QueryInterface(REFIID riid, void **ppv)
  2039. {
  2040. static const QITAB qit[] =
  2041. {
  2042. QITABENT(CAutoPlayVerb, IDropTarget),
  2043. { 0 },
  2044. };
  2045. return QISearch(this, qit, riid, ppv);
  2046. }
  2047. // IDropTarget::DragEnter
  2048. HRESULT CAutoPlayVerb::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  2049. {
  2050. *pdwEffect = DROPEFFECT_COPY;
  2051. return S_OK;;
  2052. }
  2053. // IDropTarget::DragOver
  2054. HRESULT CAutoPlayVerb::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  2055. {
  2056. *pdwEffect = DROPEFFECT_COPY;
  2057. return S_OK;;
  2058. }
  2059. // IDropTarget::DragLeave
  2060. HRESULT CAutoPlayVerb::DragLeave(void)
  2061. {
  2062. return S_OK;
  2063. }
  2064. STDAPI CAutoPlayVerb_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppv)
  2065. {
  2066. HRESULT hr = E_OUTOFMEMORY;
  2067. *ppv = NULL;
  2068. // aggregation checking is handled in class factory
  2069. CAutoPlayVerb* p = new CAutoPlayVerb();
  2070. if (p)
  2071. {
  2072. hr = p->QueryInterface(riid, ppv);
  2073. p->Release();
  2074. }
  2075. return hr;
  2076. }
  2077. STDAPI SHChangeNotifyAutoplayDrive(PCWSTR pszDrive);
  2078. // IDropTarget::DragDrop
  2079. HRESULT CAutoPlayVerb::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  2080. {
  2081. *pdwEffect = DROPEFFECT_COPY;
  2082. // start the AutoPlayDialog
  2083. WCHAR szDrive[4];
  2084. HRESULT hr = PathFromDataObject(pdtobj, szDrive, ARRAYSIZE(szDrive));
  2085. if (SUCCEEDED(hr))
  2086. {
  2087. hr = SHChangeNotifyAutoplayDrive(szDrive);
  2088. }
  2089. return hr;
  2090. }
  2091. DWORD CALLBACK _AutorunPromptProc(void *pv)
  2092. {
  2093. WCHAR szDrive[4];
  2094. CMountPoint::DoAutorun(PathBuildRoot(szDrive, PtrToInt(pv)), AUTORUNFLAG_MENUINVOKED);
  2095. return 0;
  2096. }
  2097. void CMountPoint::DoAutorunPrompt(WPARAM iDrive)
  2098. {
  2099. SHCreateThread(_AutorunPromptProc, (void *)iDrive, CTF_COINIT | CTF_REF_COUNTED, NULL);
  2100. }
  2101. STDAPI_(void) Activate_RunDLL(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow)
  2102. {
  2103. DWORD dwProcessID;
  2104. HWND hwnd = GetShellWindow();
  2105. GetWindowThreadProcessId(hwnd, &dwProcessID);
  2106. AllowSetForegroundWindow(dwProcessID);
  2107. }