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.

645 lines
16 KiB

  1. #include "shellprv.h"
  2. #include "mixctnt.h"
  3. #include "clsobj.h"
  4. #include "apprmdlg.h"
  5. #include "hwcmmn.h"
  6. #include "ids.h"
  7. #include "shpriv.h"
  8. #include "mtptl.h"
  9. #include "filetbl.h"
  10. class CDeviceEventHandler : public IHWEventHandler
  11. {
  12. public:
  13. CDeviceEventHandler();
  14. // IUnknown
  15. STDMETHODIMP QueryInterface(REFIID, void **);
  16. STDMETHODIMP_(ULONG) AddRef(void);
  17. STDMETHODIMP_(ULONG) Release(void);
  18. // IHWEventHandler
  19. STDMETHODIMP Initialize(LPCWSTR pszParams);
  20. STDMETHODIMP HandleEvent(LPCWSTR pszDeviceID, LPCWSTR pszAltDeviceID, LPCWSTR pszEventType);
  21. STDMETHODIMP HandleEventWithContent(LPCWSTR pszDeviceID,
  22. LPCWSTR pszAltDeviceID, LPCWSTR pszEventType,
  23. LPCWSTR pszContentTypeHandler, IDataObject* pdtobj);
  24. private:
  25. ~CDeviceEventHandler();
  26. LONG _cRef;
  27. LPWSTR _pszParams;
  28. };
  29. CDeviceEventHandler::CDeviceEventHandler() : _cRef(1)
  30. {
  31. DllAddRef();
  32. }
  33. CDeviceEventHandler::~CDeviceEventHandler()
  34. {
  35. CoTaskMemFree(_pszParams)
  36. DllRelease();
  37. }
  38. STDAPI CDeviceEventHandler_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppv)
  39. {
  40. HRESULT hr = E_OUTOFMEMORY;
  41. *ppv = NULL;
  42. // aggregation checking is handled in class factory
  43. CDeviceEventHandler* pHWMixedContent = new CDeviceEventHandler();
  44. if (pHWMixedContent)
  45. {
  46. hr = pHWMixedContent->QueryInterface(riid, ppv);
  47. pHWMixedContent->Release();
  48. }
  49. return hr;
  50. }
  51. // IUnknown
  52. STDMETHODIMP CDeviceEventHandler::QueryInterface(REFIID riid, void **ppv)
  53. {
  54. static const QITAB qit[] =
  55. {
  56. QITABENT(CDeviceEventHandler, IHWEventHandler),
  57. { 0 },
  58. };
  59. return QISearch(this, qit, riid, ppv);
  60. }
  61. STDMETHODIMP_(ULONG) CDeviceEventHandler::AddRef()
  62. {
  63. return InterlockedIncrement(&_cRef);
  64. }
  65. STDMETHODIMP_(ULONG) CDeviceEventHandler::Release()
  66. {
  67. if (InterlockedDecrement(&_cRef))
  68. return _cRef;
  69. delete this;
  70. return 0;
  71. }
  72. // IHWEventHandler
  73. STDMETHODIMP CDeviceEventHandler::Initialize(LPCWSTR pszParams)
  74. {
  75. return SHStrDup(pszParams, &_pszParams);
  76. }
  77. DWORD WINAPI _PromptThreadProc(void* pv)
  78. {
  79. CBaseContentDlg* pdlg = (CBaseContentDlg*)pv;
  80. if (IDOK == pdlg->DoModal(pdlg->_hinst, MAKEINTRESOURCE(pdlg->_iResource), pdlg->_hwndParent))
  81. {
  82. // Try to Autoplay this type handler
  83. IHWDevice* phwd;
  84. if (SUCCEEDED(_GetHWDevice(pdlg->_pszDeviceID, &phwd)))
  85. {
  86. phwd->AutoplayHandler(TEXT("DeviceArrival"), pdlg->_szHandler);
  87. phwd->Release();
  88. }
  89. }
  90. _RemoveFromAutoplayPromptHDPA(pdlg->_pszDeviceID);
  91. pdlg->Release();
  92. return 0;
  93. }
  94. HRESULT _Prompt(LPCWSTR pszDeviceID, LPCWSTR pszEventType, BOOL fCheckAlwaysDoThis)
  95. {
  96. HRESULT hr;
  97. BOOL fShowDlg = _AddAutoplayPrompt(pszDeviceID);
  98. if (fShowDlg)
  99. {
  100. BOOL fDialogShown = FALSE;
  101. CBaseContentDlg* pdlg = new CNoContentDlg();
  102. if (pdlg)
  103. {
  104. pdlg->_szContentTypeHandler[0] = 0;
  105. pdlg->_hinst = g_hinst;
  106. pdlg->_iResource = DLG_APNOCONTENT;
  107. pdlg->_hwndParent = NULL;
  108. hr = pdlg->Init(pszDeviceID, NULL, 0, fCheckAlwaysDoThis);
  109. if (SUCCEEDED(hr))
  110. {
  111. if (SHCreateThread(_PromptThreadProc, pdlg, CTF_COINIT, NULL))
  112. {
  113. fDialogShown = TRUE;
  114. }
  115. else
  116. {
  117. pdlg->Release();
  118. }
  119. }
  120. else
  121. {
  122. pdlg->Release();
  123. }
  124. }
  125. else
  126. {
  127. hr = E_OUTOFMEMORY;
  128. }
  129. if (!fDialogShown)
  130. {
  131. _RemoveFromAutoplayPromptHDPA(pszDeviceID);
  132. }
  133. }
  134. else
  135. {
  136. hr = S_FALSE;
  137. }
  138. return hr;
  139. }
  140. STDMETHODIMP CDeviceEventHandler::HandleEvent(LPCWSTR pszDeviceID, LPCWSTR pszAltDeviceID, LPCWSTR pszEventType)
  141. {
  142. HRESULT hr = E_NOTIMPL;
  143. if (!lstrcmp(_pszParams, TEXT("PromptEachTimeNoContent")))
  144. {
  145. hr = _Prompt(pszDeviceID, pszEventType, FALSE);
  146. }
  147. else
  148. {
  149. // The '*' means to check the AlwaysDoThis checkbox!
  150. if (!lstrcmp(_pszParams, TEXT("PromptEachTimeNoContent*")))
  151. {
  152. hr = _Prompt(pszDeviceID, pszEventType, TRUE);
  153. }
  154. }
  155. return hr;
  156. }
  157. STDMETHODIMP CDeviceEventHandler::HandleEventWithContent(LPCWSTR pszDeviceID,
  158. LPCWSTR pszAltDeviceID, LPCWSTR pszEventType,
  159. LPCWSTR pszContentTypeHandler, IDataObject* pdtobj)
  160. {
  161. return E_FAIL;
  162. }
  163. class CDeviceAutoPlayNotification : IQueryContinue
  164. {
  165. public:
  166. CDeviceAutoPlayNotification();
  167. void CreateNotificationThread();
  168. // IUnknown
  169. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  170. STDMETHODIMP_(ULONG) AddRef();
  171. STDMETHODIMP_(ULONG) Release();
  172. // IQueryContinue
  173. STDMETHODIMP QueryContinue(); // S_OK -> Continue, other
  174. HRESULT Init(LPCTSTR pszDevice, LPCWSTR pszEventType, CCrossThreadFlag* pDeviceGoneFlag);
  175. private:
  176. ~CDeviceAutoPlayNotification();
  177. void _DoNotificationUI();
  178. static DWORD CALLBACK s_ThreadProc(void *pv);
  179. LONG _cRef;
  180. LPTSTR _pszDevice;
  181. LPTSTR _pszEventType;
  182. CCrossThreadFlag* _pDeviceGoneFlag;
  183. BOOL _fPoppedUpDlg;
  184. };
  185. CDeviceAutoPlayNotification::CDeviceAutoPlayNotification() : _cRef(1)
  186. {}
  187. HRESULT CDeviceAutoPlayNotification::Init(LPCTSTR pszDevice, LPCWSTR pszEventType,
  188. CCrossThreadFlag* pDeviceGoneFlag)
  189. {
  190. HRESULT hr = S_OK;
  191. _pszDevice = StrDup(pszDevice);
  192. _pszEventType = StrDup(pszEventType);
  193. pDeviceGoneFlag->AddRef();
  194. _pDeviceGoneFlag = pDeviceGoneFlag;
  195. if (!_pszDevice || !_pszEventType)
  196. {
  197. hr = E_OUTOFMEMORY;
  198. }
  199. return hr;
  200. }
  201. CDeviceAutoPlayNotification::~CDeviceAutoPlayNotification()
  202. {
  203. LocalFree(_pszDevice);
  204. LocalFree(_pszEventType);
  205. if (_pDeviceGoneFlag)
  206. {
  207. _pDeviceGoneFlag->Release();
  208. }
  209. }
  210. HRESULT CDeviceAutoPlayNotification::QueryInterface(REFIID riid, void **ppv)
  211. {
  212. static const QITAB qit[] =
  213. {
  214. QITABENT(CDeviceAutoPlayNotification, IQueryContinue),
  215. { 0 },
  216. };
  217. return QISearch(this, qit, riid, ppv);
  218. }
  219. STDMETHODIMP_(ULONG) CDeviceAutoPlayNotification::AddRef()
  220. {
  221. return InterlockedIncrement(&_cRef);
  222. }
  223. STDMETHODIMP_(ULONG) CDeviceAutoPlayNotification::Release()
  224. {
  225. if (InterlockedDecrement(&_cRef))
  226. return _cRef;
  227. delete this;
  228. return 0;
  229. }
  230. HRESULT CDeviceAutoPlayNotification::QueryContinue()
  231. {
  232. HRESULT hr;
  233. if (_fPoppedUpDlg || _pDeviceGoneFlag->IsSignaled())
  234. {
  235. hr = S_FALSE;
  236. }
  237. else
  238. {
  239. hr = S_OK;
  240. }
  241. return hr;
  242. }
  243. void CDeviceAutoPlayNotification::_DoNotificationUI()
  244. {
  245. DWORD dwTimeOut = 30;
  246. #ifdef DEBUG
  247. dwTimeOut = 60;
  248. #endif
  249. IUserNotification *pun;
  250. HRESULT hr = CoCreateInstance(CLSID_UserNotification, NULL, CLSCTX_ALL, IID_PPV_ARG(IUserNotification, &pun));
  251. if (SUCCEEDED(hr))
  252. {
  253. IHWDeviceCustomProperties* pdcp;
  254. if (SUCCEEDED(GetDeviceProperties(_pszDevice, &pdcp)))
  255. {
  256. HICON hicon = NULL;
  257. WORD_BLOB* pblob;
  258. if (SUCCEEDED(pdcp->GetMultiStringProperty(TEXT("Icons"), TRUE, &pblob)))
  259. {
  260. TCHAR szLocation[MAX_PATH + 10];
  261. lstrcpyn(szLocation, pblob->asData, ARRAYSIZE(szLocation));
  262. int iIcon = PathParseIconLocation(szLocation);
  263. ExtractIconEx(szLocation, iIcon, NULL, &hicon, 1);
  264. CoTaskMemFree(pblob);
  265. }
  266. LPWSTR psz;
  267. if (SUCCEEDED(pdcp->GetStringProperty(TEXT("Label"), &psz)))
  268. {
  269. TCHAR szName[128];
  270. SHLoadIndirectString(psz, szName, ARRAYSIZE(szName), NULL);
  271. pun->SetIconInfo(hicon, szName);
  272. CoTaskMemFree(psz);
  273. }
  274. pdcp->Release();
  275. if (hicon)
  276. DestroyIcon(hicon);
  277. }
  278. pun->SetBalloonRetry(dwTimeOut * 1000, 0, 0); // show for 30 sec, then go away
  279. hr = pun->Show(SAFECAST(this, IQueryContinue *), 1 * 1000); // 1 sec poll for callback
  280. pun->Release();
  281. if (S_OK == hr)
  282. {
  283. _Prompt(_pszDevice, _pszEventType, FALSE);
  284. _fPoppedUpDlg = TRUE;
  285. }
  286. }
  287. }
  288. DWORD CALLBACK CDeviceAutoPlayNotification::s_ThreadProc(void *pv)
  289. {
  290. CDeviceAutoPlayNotification *pldsui = (CDeviceAutoPlayNotification *)pv;
  291. pldsui->_DoNotificationUI();
  292. pldsui->Release();
  293. return 0;
  294. }
  295. void CDeviceAutoPlayNotification::CreateNotificationThread()
  296. {
  297. AddRef();
  298. if (!SHCreateThread(s_ThreadProc, this, CTF_COINIT, NULL))
  299. {
  300. Release();
  301. }
  302. }
  303. HRESULT DoDeviceNotification(LPCTSTR pszDevice, LPCTSTR pszEventType, CCrossThreadFlag* pDeviceGoneFlag)
  304. {
  305. HRESULT hr;
  306. CDeviceAutoPlayNotification *pldsui = new CDeviceAutoPlayNotification();
  307. if (pldsui)
  308. {
  309. hr = pldsui->Init(pszDevice, pszEventType, pDeviceGoneFlag);
  310. if (SUCCEEDED(hr))
  311. {
  312. pldsui->CreateNotificationThread();
  313. }
  314. pldsui->Release();
  315. }
  316. else
  317. {
  318. hr = E_OUTOFMEMORY;
  319. }
  320. return hr;
  321. }
  322. template <typename TCALLBACKFCT, typename TCALLBACKARG, typename TCALLBACKRET>
  323. BOOL _FindAutoplayStructAndExecuteCB(LPCWSTR pszDriveOrDeviceID, TCALLBACKFCT fct, TCALLBACKARG arg, TCALLBACKRET* pRet)
  324. {
  325. BOOL fRet = FALSE;
  326. EnterCriticalSection(&g_csAutoplayPrompt);
  327. if (g_hdpaAutoplayPrompt)
  328. {
  329. int n = DPA_GetPtrCount(g_hdpaAutoplayPrompt);
  330. for (int i = 0; i < n; ++i)
  331. {
  332. AUTOPLAYPROMPT* pap = (AUTOPLAYPROMPT*)DPA_GetPtr(g_hdpaAutoplayPrompt, i);
  333. if (!lstrcmpi(pap->szDriveOrDeviceID, pszDriveOrDeviceID))
  334. {
  335. fRet = TRUE;
  336. *pRet = fct(pap, arg);
  337. break;
  338. }
  339. }
  340. }
  341. LeaveCriticalSection(&g_csAutoplayPrompt);
  342. return fRet;
  343. }
  344. BOOL _AddAutoplayPromptEntry(LPCWSTR pszDriveOrDeviceID, BOOL fDlgWillBeShown)
  345. {
  346. BOOL fFoundEntry = FALSE;
  347. BOOL fWasRunning = FALSE;
  348. EnterCriticalSection(&g_csAutoplayPrompt);
  349. if (g_hdpaAutoplayPrompt)
  350. {
  351. int n = DPA_GetPtrCount(g_hdpaAutoplayPrompt);
  352. for (int i = 0; i < n; ++i)
  353. {
  354. AUTOPLAYPROMPT* pap = (AUTOPLAYPROMPT*)DPA_GetPtr(g_hdpaAutoplayPrompt, i);
  355. if (!lstrcmpi(pap->szDriveOrDeviceID, pszDriveOrDeviceID))
  356. {
  357. fWasRunning = pap->fDlgWillBeShown;
  358. fFoundEntry = TRUE;
  359. if (!pap->fDlgWillBeShown)
  360. {
  361. pap->fDlgWillBeShown = fDlgWillBeShown;
  362. }
  363. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: Found entry for %s - (dlg = %d -> %d)",
  364. pszDriveOrDeviceID, fWasRunning, pap->fDlgWillBeShown);
  365. break;
  366. }
  367. }
  368. }
  369. if (!fFoundEntry)
  370. {
  371. if (!g_hdpaAutoplayPrompt)
  372. {
  373. g_hdpaAutoplayPrompt = DPA_Create(3);
  374. }
  375. if (g_hdpaAutoplayPrompt)
  376. {
  377. AUTOPLAYPROMPT* pap;
  378. if (SUCCEEDED(SHLocalAlloc(sizeof(AUTOPLAYPROMPT), &pap)))
  379. {
  380. lstrcpyn(pap->szDriveOrDeviceID, pszDriveOrDeviceID, ARRAYSIZE(pap->szDriveOrDeviceID));
  381. pap->fDlgWillBeShown = fDlgWillBeShown;
  382. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: Adding entry for %s - (dlg = %d)",
  383. pszDriveOrDeviceID, fDlgWillBeShown);
  384. if (-1 == DPA_AppendPtr(g_hdpaAutoplayPrompt, (void*)pap))
  385. {
  386. LocalFree((HLOCAL)pap);
  387. }
  388. else
  389. {
  390. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: Total # of entry: %d",
  391. DPA_GetPtrCount(g_hdpaAutoplayPrompt));
  392. }
  393. }
  394. }
  395. }
  396. LeaveCriticalSection(&g_csAutoplayPrompt);
  397. return !fWasRunning;
  398. }
  399. BOOL _AddAutoplayPrompt(LPCWSTR pszDriveOrDeviceID)
  400. {
  401. return _AddAutoplayPromptEntry(pszDriveOrDeviceID, TRUE);
  402. }
  403. void _RemoveFromAutoplayPromptHDPA(LPCWSTR pszAltDeviceID)
  404. {
  405. EnterCriticalSection(&g_csAutoplayPrompt);
  406. if (g_hdpaAutoplayPrompt)
  407. {
  408. int n = DPA_GetPtrCount(g_hdpaAutoplayPrompt);
  409. for (int i = 0; i < n; ++i)
  410. {
  411. AUTOPLAYPROMPT* pap = (AUTOPLAYPROMPT*)DPA_GetPtr(g_hdpaAutoplayPrompt, i);
  412. if (!lstrcmpi(pap->szDriveOrDeviceID, pszAltDeviceID))
  413. {
  414. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: Removing %s",
  415. pap->szDriveOrDeviceID);
  416. if (pap->pDeviceGoneFlag)
  417. {
  418. pap->pDeviceGoneFlag->Release();
  419. }
  420. LocalFree((HLOCAL)pap);
  421. DPA_DeletePtr(g_hdpaAutoplayPrompt, i);
  422. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: Total # of entry: %d",
  423. DPA_GetPtrCount(g_hdpaAutoplayPrompt));
  424. break;
  425. }
  426. }
  427. }
  428. LeaveCriticalSection(&g_csAutoplayPrompt);
  429. }
  430. // Set/Get HWND
  431. typedef BOOL (*PFNSETAAUTOPLAYPROMPTHWNDCB)(AUTOPLAYPROMPT* pap, HWND hwnd);
  432. BOOL _SetAutoplayPromptHWNDCB(AUTOPLAYPROMPT* pap, HWND hwnd)
  433. {
  434. pap->hwndDlg = hwnd;
  435. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: SetHWND for %s - (dlg = %d)",
  436. pap->szDriveOrDeviceID, pap->fDlgWillBeShown);
  437. return TRUE;
  438. }
  439. void _SetAutoplayPromptHWND(LPCWSTR pszAltDeviceID, HWND hwnd)
  440. {
  441. BOOL fRet;
  442. _FindAutoplayStructAndExecuteCB<PFNSETAAUTOPLAYPROMPTHWNDCB, HWND, BOOL>
  443. (pszAltDeviceID, _SetAutoplayPromptHWNDCB, hwnd, &fRet);
  444. }
  445. typedef BOOL (*PFNGETAAUTOPLAYPROMPTHWNDCB)(AUTOPLAYPROMPT* pap, HWND* phwnd);
  446. BOOL _GetAutoplayPromptHWNDCB(AUTOPLAYPROMPT* pap, HWND* phwnd)
  447. {
  448. *phwnd = pap->hwndDlg;
  449. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: GetHWND for %s - (dlg = %d)",
  450. pap->szDriveOrDeviceID, pap->fDlgWillBeShown);
  451. return TRUE;
  452. }
  453. BOOL _GetAutoplayPromptHWND(LPCWSTR pszAltDeviceID, HWND* phwnd)
  454. {
  455. BOOL fRet;
  456. return _FindAutoplayStructAndExecuteCB<PFNGETAAUTOPLAYPROMPTHWNDCB, HWND*, BOOL>
  457. (pszAltDeviceID, _GetAutoplayPromptHWNDCB, phwnd, &fRet);
  458. }
  459. // Set/Get DeviceGoneFlag
  460. typedef BOOL (*PFNSETDEVICEGONEFLAGCB)(AUTOPLAYPROMPT* pap, CCrossThreadFlag* pDeviceGoneFlag);
  461. BOOL _SetDeviceGoneFlagCB(AUTOPLAYPROMPT* pap, CCrossThreadFlag* pDeviceGoneFlag)
  462. {
  463. pap->pDeviceGoneFlag = pDeviceGoneFlag;
  464. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: SetDeviceGoneFlag for %s - (dlg = %d)",
  465. pap->szDriveOrDeviceID, pap->fDlgWillBeShown);
  466. return TRUE;
  467. }
  468. void AttachGoneFlagForDevice(LPCWSTR pszAltDeviceID, CCrossThreadFlag* pDeviceGoneFlag)
  469. {
  470. BOOL fRet;
  471. if (!_FindAutoplayStructAndExecuteCB<PFNSETDEVICEGONEFLAGCB, CCrossThreadFlag*, BOOL>
  472. (pszAltDeviceID, _SetDeviceGoneFlagCB, pDeviceGoneFlag, &fRet))
  473. {
  474. _AddAutoplayPromptEntry(pszAltDeviceID, FALSE);
  475. if (_FindAutoplayStructAndExecuteCB<PFNSETDEVICEGONEFLAGCB, CCrossThreadFlag*, BOOL>
  476. (pszAltDeviceID, _SetDeviceGoneFlagCB, pDeviceGoneFlag, &fRet))
  477. {
  478. if (fRet)
  479. {
  480. pDeviceGoneFlag->AddRef();
  481. }
  482. }
  483. }
  484. }
  485. typedef BOOL (*PFNGETDEVICEGONEFLAGCB)(AUTOPLAYPROMPT* pap, CCrossThreadFlag** ppDeviceGoneFlag);
  486. BOOL _GetDeviceGoneFlagCB(AUTOPLAYPROMPT* pap, CCrossThreadFlag** ppDeviceGoneFlag)
  487. {
  488. *ppDeviceGoneFlag = pap->pDeviceGoneFlag;
  489. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: GetDeviceGoneFlag for %s - (dlg = %d)",
  490. pap->szDriveOrDeviceID, pap->fDlgWillBeShown);
  491. return !!(*ppDeviceGoneFlag);
  492. }
  493. BOOL GetGoneFlagForDevice(LPCWSTR pszAltDeviceID, CCrossThreadFlag** ppDeviceGoneFlag)
  494. {
  495. BOOL fRet;
  496. if (_FindAutoplayStructAndExecuteCB<PFNGETDEVICEGONEFLAGCB, CCrossThreadFlag**, BOOL>
  497. (pszAltDeviceID, _GetDeviceGoneFlagCB, ppDeviceGoneFlag, &fRet))
  498. {
  499. (*ppDeviceGoneFlag)->AddRef();
  500. }
  501. else
  502. {
  503. TraceMsg(TF_MOUNTPOINT, "AUTOPLAY: GetDeviceGoneFlag for %s -> Did not find!",
  504. pszAltDeviceID);
  505. fRet = FALSE;
  506. }
  507. return fRet;
  508. }