Leaked source code of windows server 2003
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.

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