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.

2175 lines
50 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. wndproc.CPP
  5. Abstract:
  6. This is the window procedure for STI server process
  7. Author:
  8. Vlad Sadovsky (vlads) 12-20-96
  9. Revision History:
  10. 20-Dec-1996 Vlads Created
  11. 28-Sep-1997 VladS Added code for SCM glue
  12. 20-May-2000 ByronC Replaced windows messaging
  13. --*/
  14. //
  15. // Headers
  16. //
  17. #include "precomp.h"
  18. #include "stiexe.h"
  19. #include <windowsx.h>
  20. #include "device.h"
  21. #include "monui.h"
  22. #include <validate.h>
  23. #include <apiutil.h>
  24. #include <shellapi.h>
  25. #include <devguid.h>
  26. #include "wiamindr.h"
  27. //
  28. // Definitions
  29. //
  30. #define REFRESH_ASYNC 1 // Do refresh asyncronously
  31. #define USE_WORKER_THREAD 1 // Run configuration changes on separate worker thread
  32. #define USE_BROADCASTSYSTEM 1 // Rebroadcast device arrivals/removal
  33. #define DEVICE_REFRESH_WAIT_TIME 30000 // Wait time in milliseconds
  34. //
  35. // Interval to delay refreshing device list after add new device notification received
  36. //
  37. #define REFRESH_DELAY 3000
  38. #define BOOT_REFRESH_DELAY 5000
  39. #define STI_MSG_WAIT_TIME 1
  40. //
  41. // External references
  42. //
  43. extern BOOL g_fUIPermitted;
  44. extern DWORD g_dwCurrentState;
  45. extern LONG g_lTotalActiveDevices;
  46. extern LONG g_lGlobalDeviceId;
  47. extern UINT g_uiDefaultPollTimeout;
  48. extern HDEVNOTIFY g_hStiServiceNotificationSink ;
  49. extern HWND g_hStiServiceWindow;
  50. extern BOOL g_fUseServiceCtrlSink;
  51. extern BOOL g_fFirstDevNodeChangeMsg;
  52. //
  53. // Global Data
  54. //
  55. //
  56. // Static data
  57. //
  58. //
  59. // Prototypes
  60. //
  61. LRESULT CALLBACK
  62. StiExeWinProc(
  63. HWND hwnd,
  64. UINT uMsg,
  65. WPARAM wParam,
  66. LPARAM lParam
  67. );
  68. DWORD
  69. StiWnd_OnServiceControlMessage(
  70. HWND hwnd,
  71. WPARAM wParam,
  72. LPARAM lParam
  73. );
  74. BOOL
  75. OnSetParameters(
  76. WPARAM wParam,
  77. LPARAM lParam
  78. );
  79. BOOL
  80. OnDoRefreshActiveDeviceList(
  81. WPARAM wParam,
  82. LPARAM lParam
  83. );
  84. BOOL
  85. OnAddNewDevice(
  86. DEVICE_BROADCAST_INFO *psDevBroadcast
  87. );
  88. BOOL
  89. OnRemoveActiveDevice(
  90. DEVICE_BROADCAST_INFO *psDevBroadcast,
  91. BOOL fRebroadcastRemoval
  92. );
  93. VOID
  94. ConfigChangeThread(
  95. LPVOID lpParameter
  96. );
  97. VOID
  98. DebugDumpDeviceList(
  99. VOID
  100. );
  101. VOID
  102. DebugPurgeDeviceList(
  103. VOID *pContext
  104. );
  105. VOID
  106. RefreshDeviceCallback(
  107. VOID * pContext
  108. );
  109. DWORD
  110. ResetSavedWindowPos(
  111. HWND hWnd
  112. );
  113. DWORD
  114. SaveWindowPos(
  115. HWND hWnd
  116. );
  117. VOID
  118. DumpDeviceChangeData(
  119. HWND hWnd,
  120. WPARAM wParam,
  121. LPARAM lParam
  122. );
  123. VOID
  124. StiServiceStop(
  125. VOID
  126. );
  127. VOID
  128. StiServicePause(
  129. VOID
  130. );
  131. VOID
  132. StiServiceResume(
  133. VOID
  134. );
  135. VOID
  136. BroadcastSTIChange(
  137. DEVICE_BROADCAST_INFO *psDevBroadcastInfo,
  138. LPTSTR lpszStiAction
  139. );
  140. VOID
  141. BroadcastSysMessageThreadProc(
  142. VOID *pContext
  143. );
  144. //
  145. // Message handlers prototypes
  146. //
  147. BOOL StiWnd_OnQueryEndSession(HWND hwnd);
  148. VOID StiWnd_OnEndSession(HWND hwnd, BOOL fEnding);
  149. int StiWnd_OnCreate(HWND hwnd,LPCREATESTRUCT lpCreateStruct);
  150. VOID StiWnd_OnDoRefreshActiveDeviceList(WPARAM wParam,LPARAM lParam);
  151. BOOL StiWnd_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);
  152. VOID StiWnd_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  153. VOID StiWnd_OnSize(HWND hwnd, UINT state, int cx, int cy);
  154. VOID StiWnd_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
  155. VOID StiWnd_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
  156. VOID StiWnd_OnDestroy(HWND hwnd);
  157. VOID StiWnd_OnMenuRefresh(VOID);
  158. VOID StiWnd_OnMenuDeviceList(VOID);
  159. VOID StiWnd_OnMenuSetTimeout(VOID);
  160. VOID StiWnd_OnMenuRemoveAll(VOID);
  161. //
  162. // Utilities
  163. //
  164. BOOL
  165. ParseGUID(
  166. LPGUID pguid,
  167. LPCTSTR ptsz
  168. );
  169. BOOL
  170. IsStillImagePnPMessage(
  171. PDEV_BROADCAST_HDR pDev
  172. );
  173. BOOL
  174. GetDeviceNameFromDevNode(
  175. DEVNODE dnDevNode,
  176. StiCString& strDeviceName
  177. );
  178. //
  179. // Code
  180. //
  181. VOID
  182. WINAPI
  183. StiMessageCallback(
  184. VOID *pArg
  185. )
  186. /*++
  187. Routine Description:
  188. This routine simply calls the Sti message dispatcher (aka winproc). It
  189. is used in conjunction with StiPostMessage to replace ::PostMessage.
  190. Arguments:
  191. pArg - Must be of type STI_MESSAGE
  192. Return Value:
  193. None.
  194. --*/
  195. {
  196. STI_MESSAGE *pMessage = (STI_MESSAGE*)pArg;
  197. LRESULT lRes = 0;
  198. //
  199. // Validate params
  200. //
  201. if (!pMessage) {
  202. DBG_WRN(("::StiMessageCallback, NULL message"));
  203. return;
  204. }
  205. if (IsBadReadPtr(pMessage, sizeof(STI_MESSAGE))) {
  206. DBG_WRN(("::StiMessageCallback, Bad message"));
  207. return;
  208. }
  209. //
  210. // Call StiSvcWinProc to process the message
  211. //
  212. _try {
  213. lRes = StiSvcWinProc(NULL,
  214. pMessage->m_uMsg,
  215. pMessage->m_wParam,
  216. pMessage->m_lParam);
  217. }
  218. _finally {
  219. pMessage = NULL;
  220. }
  221. return;
  222. }
  223. VOID
  224. WINAPI
  225. StiRefreshCallback(
  226. VOID *pArg
  227. )
  228. /*++
  229. Routine Description:
  230. This routine simply calls RefreshDeviceList.
  231. Arguments:
  232. pArg - Must be of type STI_MESSAGE
  233. Return Value:
  234. None.
  235. --*/
  236. {
  237. STI_MESSAGE *pMessage = (STI_MESSAGE*)pArg;
  238. LRESULT lRes = 0;
  239. //
  240. // Validate params
  241. //
  242. if (!pMessage) {
  243. DBG_WRN(("::StiRefreshCallback, NULL message"));
  244. return;
  245. }
  246. if (IsBadReadPtr(pMessage, sizeof(STI_MESSAGE))) {
  247. DBG_WRN(("::StiRefreshCallback, Bad message"));
  248. return;
  249. }
  250. //
  251. // Call RefreshDeviceList
  252. //
  253. _try {
  254. RefreshDeviceList((WORD)pMessage->m_wParam,
  255. (WORD)pMessage->m_lParam);
  256. }
  257. _finally {
  258. pMessage = NULL;
  259. }
  260. return;
  261. }
  262. LRESULT
  263. StiSendMessage(
  264. HWND hWnd,
  265. UINT Msg,
  266. WPARAM wParam,
  267. LPARAM lParam
  268. )
  269. /*++
  270. Routine Description:
  271. This routine replaces the normal windows messaging SendMessage by calling
  272. the message dispatcher (StiSvcWinProc) directly. It replaces ::SendMessage.
  273. Arguments:
  274. hWnd - handle to destination window. This is not used.
  275. Msg - message
  276. wParam - first message parameter
  277. lParam - second message parameterReturn Value:
  278. Return Value:
  279. --*/
  280. {
  281. return StiSvcWinProc(NULL, Msg, wParam, lParam);
  282. }
  283. BOOL
  284. StiPostMessage(
  285. HWND hWnd,
  286. UINT Msg,
  287. WPARAM wParam,
  288. LPARAM lParam
  289. )
  290. /*++
  291. Routine Description:
  292. This routine simulates PostMessage by putting StiMessageCallback on the
  293. Scheduler's queue.
  294. Arguments:
  295. hWnd - handle to destination window. This is not used.
  296. Msg - message
  297. wParam - first message parameter
  298. lParam - second message parameterReturn Value:
  299. Return Value:
  300. TRUE - success
  301. FALSE - message could not be posted
  302. --*/
  303. {
  304. BOOL bRet = FALSE;
  305. STI_MESSAGE *pMsg = new STI_MESSAGE(Msg, wParam, lParam);
  306. if (pMsg) {
  307. if (ScheduleWorkItem((PFN_SCHED_CALLBACK) StiMessageCallback,
  308. pMsg,
  309. STI_MSG_WAIT_TIME,
  310. NULL)) {
  311. bRet = TRUE;
  312. } else {
  313. delete pMsg;
  314. }
  315. }
  316. if (!bRet) {
  317. DBG_WRN(("::StiPostMessage, could not post message"));
  318. }
  319. return bRet;
  320. }
  321. BOOL
  322. StiRefreshWithDelay(
  323. ULONG ulDelay,
  324. WPARAM wParam,
  325. LPARAM lParam
  326. )
  327. /*++
  328. Routine Description:
  329. This routine simulates PostMessage by putting StiMessageCallback on the
  330. Scheduler's queue with a delay of ulDelay.
  331. Arguments:
  332. ulDelay - delay in milliseconds
  333. Msg - message
  334. wParam - first message parameter
  335. lParam - second message parameter
  336. Return Value:
  337. TRUE - success
  338. FALSE - message could not be posted
  339. --*/
  340. {
  341. BOOL bRet = FALSE;
  342. STI_MESSAGE *pMsg = new STI_MESSAGE(0, wParam, lParam);
  343. if (pMsg) {
  344. if (ScheduleWorkItem((PFN_SCHED_CALLBACK) StiRefreshCallback,
  345. pMsg,
  346. ulDelay,
  347. NULL)) {
  348. bRet = TRUE;
  349. } else {
  350. delete pMsg;
  351. }
  352. }
  353. if (!bRet) {
  354. DBG_WRN(("::StiRefreshWithDelay, could not post message"));
  355. }
  356. return bRet;
  357. }
  358. HWND
  359. WINAPI
  360. CreateMasterWindow(
  361. VOID
  362. )
  363. /*++
  364. Routine Description:
  365. Arguments:
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. #ifndef WINNT
  371. //Don't use windows messaging on NT
  372. DBG_FN(CreateMasterWindow);
  373. WNDCLASSEX wc;
  374. HWND hwnd = FindWindow(g_szClass,NULL);
  375. if (hwnd) {
  376. //
  377. // Notify master window that we started.
  378. //
  379. if (g_fUIPermitted) {
  380. ::ShowWindow(hwnd,g_fUIPermitted ? SW_SHOWNORMAL : SW_HIDE);
  381. }
  382. return NULL;
  383. }
  384. //
  385. // Create class
  386. //
  387. memset(&wc,0,sizeof(wc));
  388. wc.cbSize = sizeof(WNDCLASSEX);
  389. wc.style = 0;
  390. wc.lpfnWndProc = StiExeWinProc;
  391. wc.cbClsExtra = 0;
  392. wc.cbWndExtra = 0;
  393. wc.hInstance = g_hInst;
  394. wc.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(1));
  395. wc.hCursor = LoadCursor(NULL,IDC_ARROW);
  396. wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
  397. wc.lpszClassName = g_szClass;
  398. wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
  399. if (!RegisterClassEx(&wc))
  400. return NULL;
  401. #ifndef WINNT
  402. #ifdef FE_IME
  403. // Disable IME processing on Millenium
  404. ImmDisableIME(::GetCurrentThreadId());
  405. #endif
  406. #endif
  407. g_hMainWindow = CreateWindowEx(0, // Style bits
  408. g_szClass, // Class name
  409. g_szTitle, // Title
  410. WS_OVERLAPPEDWINDOW , // Window style bits
  411. CW_USEDEFAULT, // x
  412. CW_USEDEFAULT, // y
  413. CW_USEDEFAULT, // h
  414. CW_USEDEFAULT, // w
  415. NULL, // Parent
  416. NULL, // Menu
  417. g_hInst, // Module instance
  418. NULL); // Options
  419. if(g_hMainWindow) {
  420. // Register custom message
  421. g_StiFileLog->SetLogWindowHandle(g_hMainWindow);
  422. }
  423. DBG_ERR(("WIASERVC :: CreateMasterWindow. Handle = %X ",g_hMainWindow);
  424. #endif
  425. return g_hMainWindow;
  426. }
  427. LRESULT
  428. CALLBACK
  429. StiExeWinProc(
  430. HWND hwnd,
  431. UINT uMsg,
  432. WPARAM wParam,
  433. LPARAM lParam
  434. )
  435. /*++
  436. Routine Description:
  437. Master window callback procedure
  438. Arguments:
  439. Return Value:
  440. None.
  441. --*/
  442. {
  443. switch(uMsg) {
  444. case WM_COMMAND:
  445. HANDLE_WM_COMMAND(hwnd, wParam, lParam, StiWnd_OnCommand);
  446. break;
  447. case WM_CREATE:
  448. return HANDLE_WM_CREATE(hwnd, wParam, lParam, StiWnd_OnCreate);
  449. break;
  450. case STIMON_MSG_SET_PARAMETERS:
  451. OnSetParameters(wParam,lParam);
  452. break;
  453. case STIMON_MSG_VISUALIZE:
  454. {
  455. //
  456. // Make ourselves visible or hidden
  457. //
  458. BOOL fShow = (BOOL)wParam;
  459. g_fUIPermitted = fShow;
  460. ShowWindow(hwnd,fShow ? SW_SHOWNORMAL : SW_HIDE);
  461. g_StiFileLog->SetReportMode(g_StiFileLog->QueryReportMode() | STI_TRACE_LOG_TOUI);
  462. }
  463. break;
  464. case WM_DESTROY:
  465. HANDLE_WM_DESTROY(hwnd, wParam, lParam, StiWnd_OnDestroy);
  466. break;
  467. case WM_ENDSESSION:
  468. return HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, StiWnd_OnEndSession);
  469. case WM_QUERYENDSESSION:
  470. return HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, StiWnd_OnQueryEndSession);
  471. case WM_CLOSE:
  472. DBG_TRC(("Service instance received WM_CLOSE"));
  473. default:
  474. return DefWindowProc(hwnd,uMsg,wParam,lParam);
  475. }
  476. return 0L;
  477. } /* endproc WinProc */
  478. BOOL
  479. WINAPI
  480. OnSetParameters(
  481. WPARAM wParam,
  482. LPARAM lParam
  483. )
  484. /*++
  485. Routine Description:
  486. Arguments:
  487. None.
  488. Return Value:
  489. None.
  490. --*/
  491. {
  492. switch(wParam) {
  493. case STIMON_MSG_SET_TIMEOUT:
  494. return lParam ? ResetAllPollIntervals((UINT)lParam) : 0;
  495. default:
  496. ;
  497. }
  498. return 0;
  499. }
  500. BOOL
  501. WINAPI
  502. StiWnd_OnQueryEndSession(
  503. HWND hwnd
  504. )
  505. /*++
  506. Routine Description:
  507. Arguments:
  508. None.
  509. Return Value:
  510. None.
  511. --*/
  512. {
  513. return TRUE;
  514. }
  515. VOID
  516. WINAPI
  517. StiWnd_OnEndSession(
  518. HWND hwnd,
  519. BOOL fEnding
  520. )
  521. /*++
  522. Routine Description:
  523. Arguments:
  524. None.
  525. Return Value:
  526. None.
  527. --*/
  528. {
  529. return;
  530. }
  531. BOOL
  532. WINAPI
  533. StiWnd_OnCreate(
  534. HWND hwnd,
  535. LPCREATESTRUCT lpCreateStruct
  536. )
  537. /*++
  538. Routine Description:
  539. Arguments:
  540. None.
  541. Return Value:
  542. None.
  543. --*/
  544. {
  545. // Restore window charateristics
  546. ResetSavedWindowPos(hwnd);
  547. return TRUE;
  548. }
  549. VOID
  550. WINAPI
  551. StiWnd_OnCommand(
  552. HWND hwnd,
  553. int id,
  554. HWND hwndCtl,
  555. UINT codeNotify
  556. )
  557. /*++
  558. Routine Description:
  559. Arguments:
  560. None.
  561. Return Value:
  562. None.
  563. --*/
  564. {
  565. switch (id) {
  566. case IDM_TOOLS_DEVLIST:
  567. StiWnd_OnMenuDeviceList();
  568. break;
  569. case IDM_TOOLS_REFRESH:
  570. StiWnd_OnMenuRefresh();
  571. break;
  572. case IDM_TOOLS_TIMEOUT:
  573. StiWnd_OnMenuSetTimeout();
  574. break;
  575. case IDM_TOOLS_REMOVEALL:
  576. StiWnd_OnMenuRemoveAll();
  577. break;
  578. }
  579. }
  580. VOID
  581. WINAPI
  582. StiWnd_OnDestroy(
  583. HWND hwnd
  584. )
  585. /*++
  586. Routine Description:
  587. Arguments:
  588. None.
  589. Return Value:
  590. None.
  591. --*/
  592. {
  593. DBG_TRC(("Service instance received WM_DESTROY"));
  594. // Save current window position
  595. SaveWindowPos(hwnd);
  596. // Main window is going away.
  597. PostQuitMessage(0);
  598. return;
  599. }
  600. //
  601. // Menu verb handlers
  602. //
  603. VOID
  604. WINAPI
  605. StiWnd_OnMenuRefresh(
  606. VOID
  607. )
  608. /*++
  609. Routine Description:
  610. Arguments:
  611. None.
  612. Return Value:
  613. None.
  614. --*/
  615. {
  616. STIMONWPRINTF(TEXT("Menu: Refreshing device list "));
  617. OnDoRefreshActiveDeviceList(STIMON_MSG_REFRESH_REREAD,
  618. STIMON_MSG_REFRESH_NEW | STIMON_MSG_REFRESH_EXISTING
  619. );
  620. STIMONWPRINTF(TEXT("Done refreshing device list. Active device count:%d Current device id:%d "),
  621. g_lTotalActiveDevices,g_lGlobalDeviceId);
  622. }
  623. VOID
  624. WINAPI
  625. StiWnd_OnMenuDeviceList(
  626. VOID
  627. )
  628. /*++
  629. Routine Description:
  630. Arguments:
  631. None.
  632. Return Value:
  633. None.
  634. --*/
  635. {
  636. STIMONWPRINTF(TEXT("Menu: Displaying device list "));
  637. DebugDumpDeviceList();
  638. STIMONWPRINTF(TEXT("Active device count:%d Current device id:%d "),
  639. g_lTotalActiveDevices,g_lGlobalDeviceId);
  640. }
  641. VOID
  642. StiWnd_OnMenuRemoveAll(
  643. VOID
  644. )
  645. /*++
  646. Routine Description:
  647. Arguments:
  648. None.
  649. Return Value:
  650. None.
  651. --*/
  652. {
  653. STIMONWPRINTF(TEXT("Menu: removing all devices "));
  654. #ifdef USE_WORKER_THREAD
  655. HANDLE hThread;
  656. DWORD dwThread;
  657. hThread = ::CreateThread(NULL,
  658. 0,
  659. (LPTHREAD_START_ROUTINE)DebugPurgeDeviceList,
  660. (LPVOID)0,
  661. 0,
  662. &dwThread);
  663. if ( hThread )
  664. CloseHandle(hThread);
  665. #else
  666. //
  667. // Try to schedule refresh work item
  668. //
  669. DWORD dwSchedulerCookie = ::ScheduleWorkItem(
  670. (PFN_SCHED_CALLBACK) DebugPurgeDeviceList,
  671. (LPVOID)0,
  672. 10);
  673. if ( !dwSchedulerCookie ){
  674. ASSERT(("Refresh routine could not schedule work item", 0));
  675. STIMONWPRINTF(TEXT("Could not schedule asyncronous removal"));
  676. }
  677. #endif
  678. }
  679. VOID
  680. WINAPI
  681. StiWnd_OnMenuSetTimeout(
  682. VOID
  683. )
  684. /*++
  685. Routine Description:
  686. Arguments:
  687. None.
  688. Return Value:
  689. None.
  690. --*/
  691. {
  692. CSetTimeout cdlg(IDD_SETTIMEOUT,::GetActiveWindow(),NULL,g_uiDefaultPollTimeout);
  693. if ( (cdlg.CreateModal() == IDOK) && (cdlg.m_fValidChange) ) {
  694. g_uiDefaultPollTimeout = cdlg.GetNewTimeout();
  695. if (cdlg.IsAllChange()) {
  696. // Update all devices
  697. ResetAllPollIntervals(g_uiDefaultPollTimeout);
  698. }
  699. }
  700. }
  701. DWORD
  702. WINAPI
  703. ResetSavedWindowPos(
  704. HWND hwnd
  705. )
  706. /*++
  707. Loads the window position structure from registry and resets
  708. Returns:
  709. Win32 error code. NO_ERROR on success
  710. --*/
  711. {
  712. DWORD dwError = NO_ERROR;
  713. BUFFER buf;
  714. RegEntry re(REGSTR_PATH_STICONTROL,HKEY_LOCAL_MACHINE);
  715. re.GetValue(REGSTR_VAL_DEBUG_STIMONUIWIN,&buf);
  716. if (buf.QuerySize() >= sizeof(WINDOWPLACEMENT) ) {
  717. WINDOWPLACEMENT *pWinPos = (WINDOWPLACEMENT *)buf.QueryPtr();
  718. //
  719. // Command line and registry settings override last saved parameters
  720. //
  721. pWinPos->showCmd = g_fUIPermitted ? SW_SHOWNORMAL : SW_HIDE;
  722. dwError = ::SetWindowPlacement(hwnd,(WINDOWPLACEMENT *)buf.QueryPtr());
  723. }
  724. else {
  725. ::ShowWindow(hwnd,g_fUIPermitted ? SW_SHOWNORMAL : SW_HIDE);
  726. }
  727. return dwError;
  728. } //
  729. DWORD
  730. WINAPI
  731. SaveWindowPos(
  732. HWND hwnd
  733. )
  734. /*++
  735. Loads the window position structure from registry and resets
  736. Returns:
  737. Win32 error code. NO_ERROR on success
  738. --*/
  739. {
  740. DWORD dwError = NO_ERROR;
  741. BUFFER buf(sizeof(WINDOWPLACEMENT));
  742. if (buf.QuerySize() >= sizeof(WINDOWPLACEMENT) ) {
  743. WINDOWPLACEMENT *pWinPos = (WINDOWPLACEMENT *)buf.QueryPtr();
  744. pWinPos->length = sizeof(WINDOWPLACEMENT);
  745. dwError = ::GetWindowPlacement(hwnd,(WINDOWPLACEMENT *)buf.QueryPtr());
  746. RegEntry re(REGSTR_PATH_STICONTROL,HKEY_LOCAL_MACHINE);
  747. dwError = re.SetValue(REGSTR_VAL_DEBUG_STIMONUIWIN,(unsigned char *)buf.QueryPtr(),buf.QuerySize());
  748. }
  749. else {
  750. dwError = ::GetLastError();
  751. }
  752. return dwError;
  753. } //
  754. //
  755. // Window procedure and handlers for service hidden window
  756. //
  757. LRESULT
  758. WINAPI
  759. CALLBACK
  760. StiSvcWinProc(
  761. HWND hwnd,
  762. UINT uMsg,
  763. WPARAM wParam,
  764. LPARAM lParam
  765. )
  766. /*++
  767. Routine Description:
  768. STI service hidden window. Used for queuing actions and receiving
  769. PnP notifications and Power broadcasts
  770. Arguments:
  771. Return Value:
  772. None.
  773. --*/
  774. {
  775. DBG_FN(StiSvcWinProc);
  776. PDEVICE_BROADCAST_INFO pBufDevice;
  777. LRESULT lRet = NOERROR;
  778. DBG_TRC(("Came to Service Window proc .uMsg=%X wParam=%X lParam=%X",uMsg,wParam,lParam));
  779. //
  780. // Give WIA a chance at processing messages. Note that
  781. // WIA hooks both message dispatch and the window proc. so that
  782. // both posted and sent messages can be detected.
  783. //
  784. if (ProcessWiaMsg(hwnd, uMsg, wParam, lParam) == S_OK) {
  785. return 0;
  786. }
  787. switch(uMsg) {
  788. case WM_CREATE:
  789. {
  790. #ifdef WINNT
  791. /*
  792. //*
  793. //* REMOVE all instances where we register for PnP events using window Handle on NT
  794. //*
  795. if (!g_fUseServiceCtrlSink || !g_hStiServiceNotificationSink) {
  796. DEV_BROADCAST_HDR *psh;
  797. DEV_BROADCAST_DEVICEINTERFACE sNotificationFilter;
  798. DWORD dwError;
  799. //
  800. // Register to receive device notifications from PnP
  801. //
  802. psh = (DEV_BROADCAST_HDR *)&sNotificationFilter;
  803. psh->dbch_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  804. psh->dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  805. psh->dbch_reserved = 0;
  806. sNotificationFilter.dbcc_classguid = *g_pguidDeviceNotificationsGuid;
  807. CopyMemory(&sNotificationFilter.dbcc_classguid,g_pguidDeviceNotificationsGuid,sizeof(GUID));
  808. sNotificationFilter.dbcc_name[0] = 0x0;
  809. DPRINTF(DM_TRACE, TEXT("Attempting to register with PnP"));
  810. g_hStiServiceNotificationSink =
  811. RegisterDeviceNotification(hwnd,
  812. (LPVOID)&sNotificationFilter,
  813. DEVICE_NOTIFY_WINDOW_HANDLE);
  814. dwError = GetLastError();
  815. if( !g_hStiServiceNotificationSink && (NOERROR != dwError)) {
  816. //
  817. // Failed to create notification sink with PnP subsystem
  818. //
  819. // ASSERT
  820. StiLogTrace(STI_TRACE_ERROR,TEXT("Failed to register with PnP ErrorCode =%d"),dwError);
  821. }
  822. DPRINTF(DM_WARNING ,TEXT("Done register with PnP"));
  823. }
  824. */
  825. #endif
  826. }
  827. break;
  828. case STIMON_MSG_REFRESH:
  829. OnDoRefreshActiveDeviceList(wParam,lParam);
  830. break;
  831. case STIMON_MSG_REMOVE_DEVICE:
  832. pBufDevice = (PDEVICE_BROADCAST_INFO )lParam;
  833. //
  834. // wParam value indicates whether device removal should be rebroadcasted
  835. //
  836. if (pBufDevice) {
  837. lRet = OnRemoveActiveDevice(pBufDevice,(BOOL)wParam) ? NOERROR : (LRESULT) ::GetLastError();
  838. delete pBufDevice;
  839. }
  840. break;
  841. case STIMON_MSG_ADD_DEVICE:
  842. pBufDevice = (PDEVICE_BROADCAST_INFO )lParam;
  843. //
  844. // New device arrived
  845. //
  846. if (pBufDevice) {
  847. lRet = OnAddNewDevice(pBufDevice)? NOERROR : (LRESULT) ::GetLastError();
  848. delete pBufDevice;
  849. }
  850. break;
  851. case WM_DEVICECHANGE:
  852. DumpDeviceChangeData(hwnd,wParam,lParam);
  853. return (StiWnd_OnDeviceChangeMessage(hwnd,(UINT)wParam,lParam));
  854. break;
  855. case WM_POWERBROADCAST:
  856. return (StiWnd_OnPowerControlMessage(hwnd,(DWORD)wParam,lParam));
  857. default:
  858. return DefWindowProc(hwnd,uMsg,wParam,lParam);
  859. }
  860. return lRet;
  861. } // endproc WinProc
  862. DWORD
  863. WINAPI
  864. StiWnd_OnPowerControlMessage(
  865. HWND hwnd,
  866. DWORD dwPowerEvent,
  867. LPARAM lParam
  868. )
  869. /*++
  870. Routine Description:
  871. Process power management broadcast messages .
  872. Arguments:
  873. None.
  874. Return Value:
  875. None.
  876. --*/
  877. {
  878. DBG_FN(StiWnd_OnPowerControlMessage);
  879. DWORD dwRet = NO_ERROR;
  880. UINT uiTraceMessage = 0;
  881. #ifdef DEBUG
  882. static LPCTSTR pszPwrEventNames[] = {
  883. TEXT("PBT_APMQUERYSUSPEND"), // 0x0000
  884. TEXT("PBT_APMQUERYSTANDBY"), // 0x0001
  885. TEXT("PBT_APMQUERYSUSPENDFAILED"), // 0x0002
  886. TEXT("PBT_APMQUERYSTANDBYFAILED"), // 0x0003
  887. TEXT("PBT_APMSUSPEND"), // 0x0004
  888. TEXT("PBT_APMSTANDBY"), // 0x0005
  889. TEXT("PBT_APMRESUMECRITICAL"), // 0x0006
  890. TEXT("PBT_APMRESUMESUSPEND"), // 0x0007
  891. TEXT("PBT_APMRESUMESTANDBY"), // 0x0008
  892. // TEXT(" PBTF_APMRESUMEFROMFAILURE"), // 0x00000001
  893. TEXT("PBT_APMBATTERYLOW"), // 0x0009
  894. TEXT("PBT_APMPOWERSTATUSCHANGE"), // 0x000A
  895. TEXT("PBT_APMOEMEVENT"), // 0x000B
  896. TEXT("PBT_UNKNOWN"), // 0x000C
  897. TEXT("PBT_UNKNOWN"), // 0x000D
  898. TEXT("PBT_UNKNOWN"), // 0x000E
  899. TEXT("PBT_UNKNOWN"), // 0x000F
  900. TEXT("PBT_UNKNOWN"), // 0x0010
  901. TEXT("PBT_UNKNOWN"), // 0x0011
  902. TEXT("PBT_APMRESUMEAUTOMATIC"), // 0x0012
  903. };
  904. // UINT uiMsgIndex;
  905. //
  906. // uiMsgIndex = (dwPowerEvent < (sizeof(pszPwrEventNames) / sizeof(CHAR *) )) ?
  907. // (UINT) dwPowerEvent : 0x0010;
  908. DBG_TRC(("Still image APM Broadcast Message:%S Code:%x ",
  909. pszPwrEventNames[dwPowerEvent],dwPowerEvent));
  910. #endif
  911. switch(dwPowerEvent)
  912. {
  913. case PBT_APMQUERYSUSPEND:
  914. //
  915. // Request for permission to suspend
  916. //
  917. if(g_NumberOfActiveTransfers > 0) {
  918. //
  919. // Veto suspend while any transfers are in progress
  920. //
  921. return BROADCAST_QUERY_DENY;
  922. }
  923. SchedulerSetPauseState(TRUE);
  924. dwRet = TRUE;
  925. break;
  926. case PBT_APMQUERYSUSPENDFAILED:
  927. //
  928. // Suspension request denied - do nothing
  929. //
  930. SchedulerSetPauseState(FALSE);
  931. break;
  932. case PBT_APMSUSPEND:
  933. StiServicePause();
  934. uiTraceMessage = MSG_TRACE_PWR_SUSPEND;
  935. break;
  936. case PBT_APMRESUMECRITICAL:
  937. // Operation resuming after critical suspension
  938. // Fall through
  939. case PBT_APMRESUMESUSPEND:
  940. //
  941. // Operation resuming after suspension
  942. // Restart all services which were active at the moment of suspend
  943. //
  944. StiServiceResume();
  945. uiTraceMessage = MSG_TRACE_PWR_RESUME;
  946. g_fFirstDevNodeChangeMsg = TRUE;
  947. break;
  948. default:
  949. dwRet = ERROR_INVALID_PARAMETER;
  950. }
  951. return (dwRet == NOERROR) ? TRUE : FALSE;
  952. }
  953. LRESULT
  954. WINAPI
  955. StiWnd_OnDeviceChangeMessage(
  956. HWND hwnd,
  957. UINT DeviceEvent,
  958. LPARAM lParam
  959. )
  960. /*++
  961. Routine Description:
  962. Arguments:
  963. None.
  964. Return Value:
  965. None.
  966. --*/
  967. {
  968. DBG_FN(StiWnd_OnDeviceChangeMessage);
  969. //DWORD dwRet = NO_ERROR;
  970. LRESULT lRet = NOERROR;
  971. PDEV_BROADCAST_HDR pDev = (PDEV_BROADCAST_HDR)lParam;
  972. DEVICE_BROADCAST_INFO *pBufDevice;
  973. static LPCTSTR pszDBTEventNames[] = {
  974. TEXT("DBT_DEVICEARRIVAL"), // 0x8000
  975. TEXT("DBT_DEVICEQUERYREMOVE"), // 0x8001
  976. TEXT("DBT_DEVICEQUERYREMOVEFAILED"), // 0x8002
  977. TEXT("DBT_DEVICEREMOVEPENDING"), // 0x8003
  978. TEXT("DBT_DEVICEREMOVECOMPLETE"), // 0x8004
  979. TEXT("DBT_DEVICETYPESPECIFIC"), // 0x8005
  980. };
  981. BOOL fLocatedDeviceInstance = FALSE;
  982. BOOL fNeedReenumerateDeviceList = FALSE;
  983. //
  984. // If the DeviceEvent is DBT_DEVNODES_CHANGED, then lParam will be NULL,
  985. // so skip devnode processing.
  986. //
  987. if ((DeviceEvent != DBT_DEVNODES_CHANGED) &&
  988. (DeviceEvent != DBT_DEVICEARRIVAL)) {
  989. //
  990. // Determine if message is for us
  991. //
  992. if (IsBadReadPtr(pDev,sizeof(PDEV_BROADCAST_HDR))) {
  993. return FALSE;
  994. }
  995. //
  996. // Trace that we are here. For all messages, not intended for StillImage devices , we should refresh
  997. // device list if we are running on WIndows NT and registered for device interfaces other than StillImage
  998. //
  999. PDEV_BROADCAST_DEVNODE pDevNode = (PDEV_BROADCAST_DEVNODE)lParam;
  1000. PDEV_BROADCAST_DEVICEINTERFACE pDevInterface = (PDEV_BROADCAST_DEVICEINTERFACE)pDev;
  1001. if (IsStillImagePnPMessage(pDev)) {
  1002. DBG_TRC(("Still image Device/DevNode PnP Message:%S Type:%x DevNode:%x ",
  1003. ((DeviceEvent>=0x8000) && (DeviceEvent<=0x8005) ?
  1004. pszDBTEventNames[DeviceEvent-0x8000] : TEXT("Unknown DBT message"),
  1005. pDev->dbch_devicetype,
  1006. pDevNode->dbcd_devnode)));
  1007. //
  1008. // Update device info set if necessary
  1009. //
  1010. if (g_pDeviceInfoSet) {
  1011. if (DeviceEvent == DBT_DEVICEARRIVAL) {
  1012. g_pDeviceInfoSet->ProcessNewDeviceChangeMessage(lParam);
  1013. }
  1014. }
  1015. //
  1016. // Get device name and store along with the broadacast structure
  1017. //
  1018. pBufDevice = new DEVICE_BROADCAST_INFO;
  1019. if (!pBufDevice) {
  1020. ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1021. return FALSE;
  1022. }
  1023. //
  1024. // Fill in information we have
  1025. //
  1026. pBufDevice->m_uiDeviceChangeMessage = DeviceEvent;
  1027. pBufDevice->m_strBroadcastedName.CopyString(pDevInterface->dbcc_name) ;
  1028. pBufDevice->m_dwDevNode = pDevNode->dbcd_devnode;
  1029. fLocatedDeviceInstance = FALSE;
  1030. fLocatedDeviceInstance = GetDeviceNameFromDevBroadcast((DEV_BROADCAST_HEADER *)pDev,pBufDevice);
  1031. if (fLocatedDeviceInstance) {
  1032. DBG_TRC(("DEVICECHANGE: Device (%S) ",(LPCTSTR)pBufDevice->m_strDeviceName));
  1033. }
  1034. else {
  1035. DBG_TRC(("DEVICECHANGE: Device - failed to get device name from broadcast"));
  1036. }
  1037. //
  1038. // We don't need broadcast information if device instance had not been found
  1039. //
  1040. if (!fLocatedDeviceInstance) {
  1041. delete pBufDevice;
  1042. pBufDevice = NULL;
  1043. }
  1044. }
  1045. else {
  1046. //
  1047. // Not ours , but we are watching it - send refresh message to reread device list.
  1048. //
  1049. if (IsPlatformNT() ) {
  1050. fNeedReenumerateDeviceList = TRUE;
  1051. }
  1052. } // endif IsStillImageDevNode
  1053. }
  1054. //
  1055. // Process device event
  1056. //
  1057. lRet = NOERROR;
  1058. switch(DeviceEvent)
  1059. {
  1060. case DBT_DEVICEARRIVAL:
  1061. /*
  1062. if (fLocatedDeviceInstance && pBufDevice) {
  1063. PostMessage(hwnd,STIMON_MSG_ADD_DEVICE,1,(LPARAM)pBufDevice);
  1064. }
  1065. else {
  1066. //
  1067. // Just refresh active list
  1068. //
  1069. fNeedReenumerateDeviceList = TRUE;
  1070. //
  1071. //::PostMessage(g_hStiServiceWindow,
  1072. // STIMON_MSG_REFRESH,
  1073. // STIMON_MSG_REFRESH_REREAD,
  1074. // STIMON_MSG_REFRESH_NEW
  1075. // );
  1076. }
  1077. */
  1078. g_pDevMan->ProcessDeviceArrival();
  1079. break;
  1080. case DBT_DEVICEQUERYREMOVE:
  1081. if ( fLocatedDeviceInstance && (pDev->dbch_devicetype == DBT_DEVTYP_HANDLE )) {
  1082. //
  1083. // This is targeted query - remove. We should disable PnP and device notifications and
  1084. // close interface handle immediately and then wait for remove - complete.
  1085. //
  1086. // NOTE: We always close and remove the device here, since it's the safest. If
  1087. // we wait till REMOVECOMPLETE, it may be too late.
  1088. //
  1089. #ifdef USE_POST_FORPNP
  1090. PostMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,1,(LPARAM)pBufDevice);
  1091. #else
  1092. lRet = ::SendMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,1,(LPARAM)pBufDevice);
  1093. #endif
  1094. }
  1095. break;
  1096. case DBT_DEVICEQUERYREMOVEFAILED:
  1097. if ( fLocatedDeviceInstance && (pDev->dbch_devicetype == DBT_DEVTYP_HANDLE )) {
  1098. //
  1099. // This is targeted query - remove - failed. We should reenable PnP notifications
  1100. //
  1101. // BUGBUG For now nothing to do as device is gone .
  1102. }
  1103. break;
  1104. case DBT_DEVICEREMOVEPENDING:
  1105. if (fLocatedDeviceInstance) {
  1106. //
  1107. // Added here for NT, as REMOVECOMPLETE comes too late
  1108. //
  1109. #ifdef USE_POST_FORPNP
  1110. PostMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,1,(LPARAM)pBufDevice);
  1111. #else
  1112. lRet = ::SendMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,1,(LPARAM)pBufDevice);
  1113. #endif
  1114. }
  1115. break;
  1116. case DBT_DEVICEREMOVECOMPLETE:
  1117. //
  1118. // For Windows 9x we can immediately remove device , as we don't have handle based
  1119. // notifications.
  1120. // On NT we should do that for handle based notifications only
  1121. //
  1122. fNeedReenumerateDeviceList = TRUE;
  1123. if ( fLocatedDeviceInstance &&
  1124. ( (pDev->dbch_devicetype == DBT_DEVTYP_HANDLE ) ||
  1125. (pDev->dbch_devicetype == DBT_DEVTYP_DEVNODE )
  1126. )
  1127. ) {
  1128. //
  1129. // We 've got targeted remove complete - get rid of device structures
  1130. //
  1131. if ( fLocatedDeviceInstance ) {
  1132. //
  1133. // Immediately remove device, as PnP counts handles and expects everyting
  1134. // to be cleaned up when this message handler returns.
  1135. //
  1136. lRet = ::SendMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,FALSE,(LPARAM)pBufDevice);
  1137. fNeedReenumerateDeviceList = FALSE;
  1138. }
  1139. else {
  1140. //
  1141. // Bad thing happened - we really need to have active device when receiving notifications for it
  1142. //
  1143. ASSERT(("WM_DEVICECHANGE/REMOVE_COMPLETE/HANDLE No device found", 0));
  1144. }
  1145. }
  1146. else {
  1147. //
  1148. // Update info set as device is really destroyed now .
  1149. //
  1150. if (g_pDeviceInfoSet) {
  1151. g_pDeviceInfoSet->ProcessDeleteDeviceChangeMessage(lParam);
  1152. }
  1153. fNeedReenumerateDeviceList = TRUE;
  1154. }
  1155. break;
  1156. case DBT_DEVICETYPESPECIFIC:
  1157. break;
  1158. case DBT_DEVNODES_CHANGED:
  1159. if (g_fFirstDevNodeChangeMsg) {
  1160. //
  1161. // DevNodes have been modified in some way, so safest thing
  1162. // is to refresh the device list
  1163. //
  1164. fNeedReenumerateDeviceList = TRUE;
  1165. //
  1166. // Set flag to indicate that the first devnode change message
  1167. // after returning from standby has been handled
  1168. //
  1169. g_fFirstDevNodeChangeMsg = FALSE;
  1170. }
  1171. break;
  1172. default:
  1173. lRet = ERROR_INVALID_PARAMETER;
  1174. }
  1175. if ( fNeedReenumerateDeviceList ) {
  1176. //
  1177. // Purge the whole list , as this is the most reliable way to eliminate inactive devices
  1178. // Broadcast device removal here, as only now we know for sure device is gone.
  1179. //
  1180. // Nb: when we get this message, PnP on NT won't give us device name , thus reenumeration
  1181. // is required to clean up
  1182. //
  1183. ::PostMessage(g_hStiServiceWindow,
  1184. STIMON_MSG_REFRESH,
  1185. STIMON_MSG_REFRESH_REREAD,
  1186. STIMON_MSG_PURGE_REMOVED | STIMON_MSG_REFRESH_NEW );
  1187. }
  1188. return (lRet == NOERROR) ? TRUE : FALSE;
  1189. }
  1190. //
  1191. // Guard to avoid reentrance in refresh routine
  1192. //
  1193. static LONG lInRefresh = 0L;
  1194. BOOL
  1195. OnDoRefreshActiveDeviceList(
  1196. WPARAM wParam,
  1197. LPARAM lParam
  1198. )
  1199. /*++
  1200. Routine Description:
  1201. Arguments:
  1202. None.
  1203. Return Value:
  1204. None.
  1205. --*/
  1206. {
  1207. DBG_FN(OnDoRefreshActiveDeviceList);
  1208. DWORD dwParameter = MAKELONG(wParam,lParam);
  1209. #ifdef REFRESH_ASYNC
  1210. #ifdef USE_WORKER_THREAD
  1211. HANDLE hThread;
  1212. DWORD dwThread;
  1213. hThread = ::CreateThread(NULL,
  1214. 0,
  1215. (LPTHREAD_START_ROUTINE)ConfigChangeThread,
  1216. (LPVOID)ULongToPtr(dwParameter),
  1217. 0,
  1218. &dwThread);
  1219. if ( hThread )
  1220. CloseHandle(hThread);
  1221. #else
  1222. //
  1223. // Try to schedule refresh work item.
  1224. // This code will not work in case of suspending, because processing work items is stopped
  1225. //
  1226. ASSERT(("Suspending should not call schedule work item routine",
  1227. (wParam == STIMON_MSG_REFRESH_SUSPEND)));
  1228. DWORD dwSchedulerCookie = ::ScheduleWorkItem(
  1229. (PFN_SCHED_CALLBACK) ConfigChangeThread,
  1230. (LPVOID)dwParameter,
  1231. REFRESH_DELAY );
  1232. if ( dwSchedulerCookie ){
  1233. }
  1234. else {
  1235. ASSERT(("Refresh routine could not schedule work item", 0));
  1236. ::WaitAndYield(::GetCurrentProcess(), REFRESH_DELAY);
  1237. RefreshDeviceList(wParam,(WORD)lParam);
  1238. }
  1239. #endif
  1240. #else
  1241. if (InterlockedExchange(&lInRefresh,1L)) {
  1242. return 0;
  1243. }
  1244. ConfigChangeThread((LPVOID)dwParameter);
  1245. InterlockedExchange(&lInRefresh,0L);
  1246. #endif
  1247. return TRUE;
  1248. }
  1249. VOID
  1250. ConfigChangeThread(
  1251. LPVOID lpParameter
  1252. )
  1253. /*++
  1254. Routine Description:
  1255. Arguments:
  1256. None.
  1257. Return Value:
  1258. None.
  1259. --*/
  1260. {
  1261. ULONG ulParam = PtrToUlong(lpParameter);
  1262. WORD wCommand = LOWORD(ulParam);
  1263. WORD wFlags = HIWORD(ulParam);
  1264. DWORD dwWait = 0;
  1265. DBG_FN(ConfigChangeThread);
  1266. #ifdef DELAY_ON_BOOT
  1267. STIMONWPRINTF(TEXT("Refreshing device list. Command:%d Flags :%x"),wCommand,wFlags);
  1268. //
  1269. // On boot refresh - delay updating device list , to keep some devices happy
  1270. //
  1271. if (wFlags & STIMON_MSG_BOOT ) {
  1272. DBG_TRC(("Delaying refresh on boot "));
  1273. ::Sleep(BOOT_REFRESH_DELAY);
  1274. }
  1275. #endif
  1276. //
  1277. // Wait for any pending refreshes to happen first. Only do the refresh once the other
  1278. // has completed.
  1279. // NOTE: For now, we always do the refresh - maybe we should skip if we timeout?
  1280. // One exception is if this is the first device enumeration (indicated by STIMON_MSG_BOOT)
  1281. // In this case, set the event so we don't timeout (the event is created unsignalled
  1282. // so WIA clients will wait on it).
  1283. //
  1284. if (!(wFlags & STIMON_MSG_BOOT)) {
  1285. dwWait = WaitForSingleObject(g_hDevListCompleteEvent, DEVICE_REFRESH_WAIT_TIME);
  1286. if (dwWait == WAIT_TIMEOUT) {
  1287. DBG_WRN(("::ConfigChangeThread, timed out while waiting for device list enumeration..."));
  1288. }
  1289. }
  1290. RefreshDeviceList(wCommand,wFlags);
  1291. //
  1292. // Update service status when necessary. If we are going to suspend - now it's time
  1293. // to let SCM know we are paused. Note, that it might be not only result of power management
  1294. // operation, but service pausing for any other reason.
  1295. //
  1296. if ( wCommand == STIMON_MSG_REFRESH_SUSPEND) {
  1297. // BUGBUG Service status should be updated only after everything paused
  1298. UpdateServiceStatus(SERVICE_PAUSED,NOERROR,0);
  1299. }
  1300. }
  1301. BOOL
  1302. OnAddNewDevice(
  1303. DEVICE_BROADCAST_INFO *psDevBroadcastInfo
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. Arguments:
  1308. None.
  1309. Return Value:
  1310. None.
  1311. --*/
  1312. {
  1313. USES_CONVERSION;
  1314. BOOL fRet;
  1315. fRet = (psDevBroadcastInfo != NULL) && (psDevBroadcastInfo->m_strDeviceName.GetLength() > 0);
  1316. if (fRet) {
  1317. //
  1318. // Create new device and add to the monitored list
  1319. //
  1320. DBG_TRC(("New device (%S) is being added to the list after PnP event",(LPCTSTR)psDevBroadcastInfo->m_strDeviceName));
  1321. fRet = AddDeviceByName((LPCTSTR)psDevBroadcastInfo->m_strDeviceName,TRUE);
  1322. // If device successfully recognized - broadcast it's appearance
  1323. if (fRet) {
  1324. BroadcastSTIChange(psDevBroadcastInfo,TEXT("STI\\Arrival\\"));
  1325. }
  1326. //
  1327. // Send delayed refresh message to pick up registry changes, happening in parallel
  1328. //
  1329. //
  1330. ::PostMessage(g_hStiServiceWindow,
  1331. STIMON_MSG_REFRESH,
  1332. STIMON_MSG_REFRESH_REREAD,
  1333. STIMON_MSG_REFRESH_EXISTING | STIMON_MSG_REFRESH_NEW
  1334. );
  1335. //
  1336. // Fire the WIA device arrival event
  1337. //
  1338. if (psDevBroadcastInfo) {
  1339. // DBG_TRC(("WIA FIRE OnAddNewDevice : for device "));
  1340. //
  1341. // NotifyWiaDeviceEvent(T2W((LPTSTR)(LPCTSTR)psDevBroadcastInfo->m_strDeviceName),
  1342. // &WIA_EVENT_DEVICE_CONNECTED,
  1343. // NULL,
  1344. // 0,
  1345. // g_dwMessagePumpThreadId);
  1346. }
  1347. }
  1348. else {
  1349. DBG_ERR(("DevNode appears to be invalid, could not locate name"));
  1350. #ifdef WINNT
  1351. //
  1352. // Temporarily for NT make refresh , looking for new devices
  1353. //
  1354. ::PostMessage(g_hStiServiceWindow,
  1355. STIMON_MSG_REFRESH,
  1356. STIMON_MSG_REFRESH_REREAD,
  1357. STIMON_MSG_REFRESH_NEW
  1358. );
  1359. #endif
  1360. }
  1361. return fRet;
  1362. }
  1363. BOOL
  1364. OnRemoveActiveDevice(
  1365. DEVICE_BROADCAST_INFO *psDevBroadcastInfo,
  1366. BOOL fRebroadcastRemoval
  1367. )
  1368. /*++
  1369. Routine Description:
  1370. Arguments:
  1371. None.
  1372. Return Value:
  1373. None.
  1374. --*/
  1375. {
  1376. DBG_FN(OnRemoveActiveDevice);
  1377. USES_CONVERSION;
  1378. BOOL fRet;
  1379. fRet = (psDevBroadcastInfo != NULL) && (psDevBroadcastInfo->m_strDeviceName.GetLength() > 0);
  1380. DBG_TRC(("OnRemoveActiveDevice : Entering for device (%S) ",
  1381. fRet ? (LPCTSTR)psDevBroadcastInfo->m_strDeviceName : TEXT("<Invalid>")));
  1382. if (fRet) {
  1383. if (fRebroadcastRemoval) {
  1384. BroadcastSTIChange(psDevBroadcastInfo,TEXT("STI\\Removal\\"));
  1385. }
  1386. DBG_TRC(("Device (%S) is being removed after PnP event",(LPCTSTR)psDevBroadcastInfo->m_strDeviceName));
  1387. //
  1388. // Mark the device as being removed
  1389. //
  1390. MarkDeviceForRemoval((LPTSTR)(LPCTSTR)psDevBroadcastInfo->m_strDeviceName);
  1391. //
  1392. // Fire the WIA device removal event
  1393. //
  1394. if (psDevBroadcastInfo) {
  1395. DBG_TRC(("WIA FIRE OnRemoveActiveDevice : for device %S", psDevBroadcastInfo->m_strDeviceName));
  1396. NotifyWiaDeviceEvent((LPWSTR)T2W((LPTSTR)(LPCTSTR)psDevBroadcastInfo->m_strDeviceName),
  1397. &WIA_EVENT_DEVICE_DISCONNECTED,
  1398. NULL,
  1399. 0,
  1400. g_dwMessagePumpThreadId);
  1401. }
  1402. fRet = RemoveDeviceByName((LPTSTR)(LPCTSTR)psDevBroadcastInfo->m_strDeviceName);
  1403. }
  1404. else {
  1405. DBG_ERR(("DevNode appears to be invalid, could not locate name"));
  1406. #ifdef WINNT
  1407. //
  1408. // Temporarily for NT make refresh , looking for new devices
  1409. //
  1410. ::PostMessage(g_hStiServiceWindow,
  1411. STIMON_MSG_REFRESH,
  1412. STIMON_MSG_REFRESH_REREAD,
  1413. STIMON_MSG_REFRESH_EXISTING | STIMON_MSG_REFRESH_NEW
  1414. );
  1415. #endif
  1416. }
  1417. return fRet;
  1418. }
  1419. VOID
  1420. BroadcastSTIChange(
  1421. DEVICE_BROADCAST_INFO *psDevBroadcastInfo,
  1422. LPTSTR lpszStiAction
  1423. )
  1424. /*++
  1425. Routine Description:
  1426. Rebroadcasts STI specific device change message.
  1427. This is done so that STI client applications have a way to update their
  1428. device information without resorting to complicated PnP mechanism .
  1429. Device name and action is broadcasted
  1430. Arguments:
  1431. psDevBroadcastInfo - structure describing broadcast
  1432. lpszStiAction - string , encoding action, performed on a device
  1433. Return Value:
  1434. None.
  1435. --*/
  1436. {
  1437. USES_CONVERSION;
  1438. #ifdef USE_BROADCASTSYSTEM
  1439. DBG_FN(BroadcastSTIChange);
  1440. struct _DEV_BROADCAST_USERDEFINED *pBroadcastHeader;
  1441. StiCString strDeviceAnnouncement;
  1442. PBYTE pBroadcastString = NULL;
  1443. UINT uiBroadcastBufSize;
  1444. HANDLE hThread;
  1445. DWORD dwThread;
  1446. strDeviceAnnouncement.CopyString(lpszStiAction);
  1447. strDeviceAnnouncement+=psDevBroadcastInfo->m_strDeviceName;
  1448. uiBroadcastBufSize = sizeof(*pBroadcastHeader) + strDeviceAnnouncement.GetAllocLength();
  1449. pBroadcastString = new BYTE[uiBroadcastBufSize];
  1450. pBroadcastHeader =(struct _DEV_BROADCAST_USERDEFINED *)pBroadcastString;
  1451. if (pBroadcastHeader) {
  1452. pBroadcastHeader->dbud_dbh.dbch_reserved = 0;
  1453. pBroadcastHeader->dbud_dbh.dbch_devicetype = DBT_DEVTYP_OEM;
  1454. lstrcpyA(pBroadcastHeader->dbud_szName,T2A((LPTSTR)(LPCTSTR)strDeviceAnnouncement));
  1455. pBroadcastHeader->dbud_dbh.dbch_size = uiBroadcastBufSize;
  1456. DBG_TRC(("Broadcasting STI device (%S) action (%S)",
  1457. pBroadcastHeader->dbud_szName,
  1458. lpszStiAction));
  1459. hThread = ::CreateThread(NULL,
  1460. 0,
  1461. (LPTHREAD_START_ROUTINE)BroadcastSysMessageThreadProc,
  1462. (LPVOID)pBroadcastString,
  1463. 0,
  1464. &dwThread);
  1465. if ( hThread )
  1466. CloseHandle(hThread);
  1467. }
  1468. #endif // USE_BROADCASTSYSTEM
  1469. } // endproc
  1470. VOID
  1471. BroadcastSysMessageThreadProc(
  1472. VOID *pContext
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. Arguments:
  1477. --*/
  1478. {
  1479. DWORD dwStartTime = ::GetTickCount();
  1480. DWORD dwRecepients = BSM_APPLICATIONS
  1481. // | BSM_ALLDESKTOPS
  1482. // | BSM_ALLCOMPONENTS
  1483. ;
  1484. struct _DEV_BROADCAST_USERDEFINED *pBroadcastHeader =
  1485. (_DEV_BROADCAST_USERDEFINED *) pContext;
  1486. ::BroadcastSystemMessage(BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG |
  1487. BSF_POSTMESSAGE | BSF_IGNORECURRENTTASK,
  1488. &dwRecepients, // Broadcast to all
  1489. WM_DEVICECHANGE,
  1490. DBT_USERDEFINED, // wParam
  1491. (LPARAM)pBroadcastHeader // lParam
  1492. );
  1493. DBG_TRC((" Broadcasted system message for (%S). Taken time (ms): %d ",
  1494. pBroadcastHeader->dbud_szName,
  1495. (::GetTickCount() - dwStartTime)
  1496. ));
  1497. delete[] (BYTE *) pContext;
  1498. return;
  1499. }
  1500. VOID
  1501. DumpDeviceChangeData(
  1502. HWND hWnd,
  1503. WPARAM wParam,
  1504. LPARAM lParam
  1505. )
  1506. /*++
  1507. Loads the window position structure from registry and resets
  1508. Returns:
  1509. Win32 error code. NO_ERROR on success
  1510. --*/
  1511. {
  1512. #ifdef MAXDEBUG
  1513. TCHAR szDbg[MAX_PATH];
  1514. OutputDebugString(TEXT("STISvc: WM_DEVICECHANGE message received\n"));
  1515. switch (wParam) {
  1516. case DBT_DEVICEARRIVAL:
  1517. OutputDebugString(TEXT(" DBT_DEVICEARRIVAL event\n"));
  1518. break;
  1519. case DBT_DEVICEREMOVECOMPLETE:
  1520. OutputDebugString(TEXT(" DBT_DEVICEREMOVECOMPLETE event\n"));
  1521. break;
  1522. case DBT_DEVICEQUERYREMOVE:
  1523. OutputDebugString(TEXT(" DBT_DEVICEQUERYREMOVE event\n"));
  1524. break;
  1525. case DBT_DEVICEQUERYREMOVEFAILED:
  1526. OutputDebugString(TEXT(" DBT_DEVICEQUERYREMOVEFAILED event\n"));
  1527. break;
  1528. case DBT_DEVICEREMOVEPENDING:
  1529. OutputDebugString(TEXT(" DBT_DEVICEREMOVEPENDING event\n"));
  1530. break;
  1531. case DBT_DEVICETYPESPECIFIC:
  1532. OutputDebugString(TEXT(" DBT_DEVICETYPESPECIFIC event\n"));
  1533. break;
  1534. case DBT_CUSTOMEVENT:
  1535. OutputDebugString(TEXT(" DBT_CUSTOMEVENT event\n"));
  1536. break;
  1537. case DBT_CONFIGCHANGECANCELED:
  1538. OutputDebugString(TEXT(" DBT_CONFIGCHANGECANCELED event\n"));
  1539. break;
  1540. case DBT_CONFIGCHANGED:
  1541. OutputDebugString(TEXT(" DBT_CONFIGCHANGED event\n"));
  1542. break;
  1543. case DBT_QUERYCHANGECONFIG:
  1544. OutputDebugString(TEXT(" DBT_QUERYCHANGECONFIG event\n"));
  1545. break;
  1546. case DBT_USERDEFINED:
  1547. OutputDebugString(TEXT(" DBT_USERDEFINED event\n"));
  1548. break;
  1549. default:
  1550. CHAR szOutput[MAX_PATH];
  1551. sprintf(szOutput, " DBT_unknown event, value (%d)\n", wParam);
  1552. OutputDebugStringA(szOutput);
  1553. break;
  1554. }
  1555. if (!lParam || IsBadReadPtr((PDEV_BROADCAST_HDR)lParam,sizeof(DEV_BROADCAST_HDR))) {
  1556. return ;
  1557. }
  1558. switch (((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype) {
  1559. case DBT_DEVTYP_DEVICEINTERFACE: {
  1560. PDEV_BROADCAST_DEVICEINTERFACE p = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
  1561. TCHAR * pString;
  1562. OutputDebugString(TEXT(" DBT_DEVTYP_DEVICEINTERFACE\n"));
  1563. wsprintf(szDbg, TEXT(" %s\n"), p->dbcc_name);
  1564. OutputDebugString(szDbg);
  1565. if (UuidToString(&p->dbcc_classguid, (RPC_STRING* )&pString) == RPC_S_OK)
  1566. {
  1567. wsprintf(szDbg, TEXT(" %s\n"), pString);
  1568. OutputDebugString(szDbg);
  1569. RpcStringFree((RPC_STRING* )&pString);
  1570. }
  1571. break;
  1572. }
  1573. case DBT_DEVTYP_HANDLE:
  1574. OutputDebugString(TEXT(" DBT_DEVTYP_HANDLE\n"));
  1575. break;
  1576. default:
  1577. break;
  1578. }
  1579. wsprintf(szDbg, TEXT(" wParam = %X lParam=%X\n"),wParam,lParam);
  1580. OutputDebugString(szDbg);
  1581. #endif
  1582. } // DumpDeviceChangeData