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.

395 lines
11 KiB

  1. /*++
  2. Copyright (c) 1991-92 Microsoft Corporation
  3. Module Name:
  4. winproc.c
  5. Abstract:
  6. Spooler window processing code
  7. Author:
  8. Muhunthan Sivapragasam (MuhuntS) 5-Nov-96 port of win95 code
  9. Environment:
  10. User Mode - Win32
  11. Notes:
  12. Revision History:
  13. BabakJ: Jan 1999, Added thread sync code to allow only one thread doing enumeration, and only
  14. one thread waiting. This helps performance specially when Dynamon has many Hydra ports.
  15. --*/
  16. #include "precomp.h"
  17. #include "local.h"
  18. #pragma hdrstop
  19. #include <cfgmgr32.h>
  20. static const GUID USB_PRINTER_GUID =
  21. { 0x28d78fad, 0x5a12, 0x11d1,
  22. { 0xae, 0x5b, 0x0, 0x0, 0xf8, 0x3, 0xa8, 0xc2 } };
  23. static const GUID GUID_DEVCLASS_INFRARED =
  24. { 0x6bdd1fc5L, 0x810f, 0x11d0,
  25. { 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f } };
  26. typedef struct _DEVICE_REGISTER_INFO {
  27. struct _DEVICE_REGISTER_INFO *pNext;
  28. HANDLE hDevice;
  29. LPVOID pData;
  30. PFN_QUERYREMOVE_CALLBACK pfnQueryRemove;
  31. HDEVNOTIFY hNotify;
  32. } DEVICE_REGISTER_INFO, *PDEVICE_REGISTER_INFO;
  33. PDEVICE_REGISTER_INFO gpDevRegnInfo = NULL;
  34. VOID
  35. ConfigChangeThread(
  36. )
  37. {
  38. HINSTANCE hLib;
  39. VOID (*pfnSplConfigChange)();
  40. WaitForSpoolerInitialization();
  41. if ( hLib = LoadLibrary(L"localspl.dll") ) {
  42. if ( pfnSplConfigChange = GetProcAddress(hLib, "SplConfigChange") ) {
  43. pfnSplConfigChange();
  44. }
  45. FreeLibrary(hLib);
  46. }
  47. }
  48. VOID
  49. ReenumeratePortsThreadWorker(
  50. )
  51. {
  52. HINSTANCE hLib;
  53. VOID (*pfnSplReenumeratePorts)();
  54. WaitForSpoolerInitialization();
  55. if ( hLib = LoadLibrary(L"localspl.dll") ) {
  56. if ( pfnSplReenumeratePorts = GetProcAddress(hLib, "SplReenumeratePorts") ) {
  57. pfnSplReenumeratePorts();
  58. }
  59. FreeLibrary(hLib);
  60. }
  61. }
  62. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  63. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  64. /////
  65. ///// To improve performance, and prevent too many unnecessary port enumerations, specially for Hydra/Dynamon:
  66. /////
  67. ///// - We want to allow only one Device Arrival thread to be doing port enumeration.
  68. ///// - If above is happneing, we allow only one more Device Arrival thread be waiting to go in.
  69. ///// - All other threads will be turned away, as there is no need for them to do port enumeration.
  70. /////
  71. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  72. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  73. CRITICAL_SECTION DeviceArrivalCS; // Used to synchronize threads bringing device arrival messages.
  74. HANDLE ThdOutEvent; // Signalled after a thread is done doing the EnumPort work; not signaled when created.
  75. VOID
  76. ReenumeratePortsThread(
  77. )
  78. {
  79. static BOOL fThdIn; // TRUE if a thread is doing enum work at the moment
  80. static BOOL fThdWaiting; // TRUE if a 2nd thread is waiting behind the thread that is inside.
  81. EnterCriticalSection( &DeviceArrivalCS ); // Enter the crit section initialized for this at localspl init code
  82. if( fThdWaiting ) {
  83. LeaveCriticalSection( &DeviceArrivalCS );
  84. return; // A 2nd thread is already waiting to go in. No need for holding more threads.
  85. }
  86. else {
  87. if( fThdIn ) {
  88. fThdWaiting = TRUE; // There is a thread inside doing Enum work. Have the current thread wait for it to finish.
  89. LeaveCriticalSection( &DeviceArrivalCS );
  90. WaitForSingleObject( ThdOutEvent, INFINITE );
  91. EnterCriticalSection( &DeviceArrivalCS );
  92. fThdWaiting = FALSE;
  93. }
  94. fThdIn = TRUE; // The current thread is now going in to do Enum work.
  95. LeaveCriticalSection( &DeviceArrivalCS );
  96. ReenumeratePortsThreadWorker();
  97. EnterCriticalSection( &DeviceArrivalCS );
  98. fThdIn = FALSE;
  99. if( fThdWaiting )
  100. SetEvent( ThdOutEvent );
  101. LeaveCriticalSection( &DeviceArrivalCS );
  102. return;
  103. }
  104. }
  105. DWORD
  106. QueryRemove(
  107. HANDLE hDevice
  108. )
  109. {
  110. LPVOID pData = NULL;
  111. PFN_QUERYREMOVE_CALLBACK pfnQueryRemove = NULL;
  112. PDEVICE_REGISTER_INFO pDevRegnInfo;
  113. EnterRouterSem();
  114. for ( pDevRegnInfo = gpDevRegnInfo ;
  115. pDevRegnInfo ;
  116. pDevRegnInfo = pDevRegnInfo->pNext ) {
  117. if ( pDevRegnInfo->hDevice == hDevice ) {
  118. pfnQueryRemove = pDevRegnInfo->pfnQueryRemove;
  119. pData = pDevRegnInfo->pData;
  120. break;
  121. }
  122. }
  123. LeaveRouterSem();
  124. return pfnQueryRemove ? pfnQueryRemove(pData) : NO_ERROR;
  125. }
  126. DWORD
  127. SplProcessPnPEvent(
  128. DWORD dwEventType,
  129. LPVOID lpEventData,
  130. PVOID pVoid
  131. )
  132. {
  133. HANDLE hThread;
  134. DWORD dwThread, dwReturn = NO_ERROR;
  135. PDEV_BROADCAST_HANDLE pBroadcast;
  136. DBGMSG(DBG_INFO,
  137. ("SplProcessPnPEvent: dwEventType: %d\n", dwEventType));
  138. switch (dwEventType) {
  139. case DBT_CONFIGCHANGED:
  140. hThread = CreateThread(NULL,
  141. 0,
  142. (LPTHREAD_START_ROUTINE)ConfigChangeThread,
  143. NULL,
  144. 0,
  145. &dwThread);
  146. if ( hThread )
  147. CloseHandle(hThread);
  148. break;
  149. case DBT_DEVICEARRIVAL:
  150. case DBT_DEVICEREMOVECOMPLETE:
  151. //
  152. // In case of device arrival we need to see if there are new ports
  153. // and in case of device removal monitors might want to mark ports
  154. // as removed so next reboot they do not have to enumerate them
  155. // ex. USB does this.
  156. //
  157. // We use the default process stack size for this thread. Currently 16KB.
  158. //
  159. hThread = CreateThread(NULL,
  160. 0,
  161. (LPTHREAD_START_ROUTINE)ReenumeratePortsThread,
  162. NULL,
  163. 0,
  164. &dwThread);
  165. if ( hThread )
  166. CloseHandle(hThread);
  167. break;
  168. case DBT_DEVICEQUERYREMOVE:
  169. pBroadcast = (PDEV_BROADCAST_HANDLE)lpEventData;
  170. //
  171. // These checks are to see if we really care about this
  172. //
  173. if ( !pBroadcast ||
  174. pBroadcast->dbch_devicetype != DBT_DEVTYP_HANDLE )
  175. break;
  176. dwReturn = QueryRemove(pBroadcast->dbch_handle);
  177. break;
  178. case DBT_SHELLLOGGEDON:
  179. default:
  180. break;
  181. }
  182. return dwReturn;
  183. }
  184. VOID
  185. RegisterForPnPEvents(
  186. VOID
  187. )
  188. {
  189. DEV_BROADCAST_DEVICEINTERFACE Filter;
  190. // Init the sync objects needed for device arrival thread management
  191. InitializeCriticalSection( &DeviceArrivalCS );
  192. ThdOutEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // Manual reset, non-signaled state
  193. ZeroMemory(&Filter, sizeof(Filter));
  194. Filter.dbcc_size = sizeof(Filter);
  195. Filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  196. CopyMemory(&Filter.dbcc_classguid,
  197. (LPGUID)&USB_PRINTER_GUID,
  198. sizeof(Filter.dbcc_classguid));
  199. if ( !RegisterDeviceNotification(ghSplHandle,
  200. &Filter,
  201. DEVICE_NOTIFY_SERVICE_HANDLE) ) {
  202. DBGMSG(DBG_INFO,
  203. ("RegisterForPnPEvents: RegisterDeviceNotification failed for USB. Error %d\n",
  204. GetLastError()));
  205. } else {
  206. DBGMSG(DBG_WARNING,
  207. ("RegisterForPnPEvents: RegisterDeviceNotification succesful for USB\n"));
  208. }
  209. CopyMemory(&Filter.dbcc_classguid,
  210. (LPGUID)&GUID_DEVCLASS_INFRARED,
  211. sizeof(Filter.dbcc_classguid));
  212. if ( !RegisterDeviceNotification(ghSplHandle,
  213. &Filter,
  214. DEVICE_NOTIFY_SERVICE_HANDLE) ) {
  215. DBGMSG(DBG_INFO,
  216. ("RegisterForPnPEvents: RegisterDeviceNotification failed for IRDA. Error %d\n",
  217. GetLastError()));
  218. } else {
  219. DBGMSG(DBG_WARNING,
  220. ("RegisterForPnPEvents: RegisterDeviceNotification succesful for IRDA\n"));
  221. }
  222. }
  223. BOOL
  224. SplUnregisterForDeviceEvents(
  225. HANDLE hNotify
  226. )
  227. {
  228. PDEVICE_REGISTER_INFO pDevRegnInfo, pPrev;
  229. EnterRouterSem();
  230. //
  231. // Find the registration in our list, remove it and then leave CS to
  232. // call unregister on it
  233. //
  234. for ( pDevRegnInfo = gpDevRegnInfo, pPrev = NULL ;
  235. pDevRegnInfo ;
  236. pPrev = pDevRegnInfo, pDevRegnInfo = pDevRegnInfo->pNext ) {
  237. if ( pDevRegnInfo->hNotify == hNotify ) {
  238. if ( pPrev )
  239. pPrev->pNext = pDevRegnInfo->pNext;
  240. else
  241. gpDevRegnInfo = pDevRegnInfo->pNext;
  242. break;
  243. }
  244. }
  245. LeaveRouterSem();
  246. if ( pDevRegnInfo ) {
  247. UnregisterDeviceNotification(pDevRegnInfo->hNotify);
  248. FreeSplMem(pDevRegnInfo);
  249. return TRUE;
  250. }
  251. return FALSE;
  252. }
  253. HANDLE
  254. SplRegisterForDeviceEvents(
  255. HANDLE hDevice,
  256. LPVOID pData,
  257. PFN_QUERYREMOVE_CALLBACK pfnQueryRemove
  258. )
  259. {
  260. DEV_BROADCAST_HANDLE Filter;
  261. PDEVICE_REGISTER_INFO pDevRegnInfo;
  262. ZeroMemory(&Filter, sizeof(Filter));
  263. Filter.dbch_size = sizeof(Filter);
  264. Filter.dbch_devicetype = DBT_DEVTYP_HANDLE;
  265. Filter.dbch_handle = hDevice;
  266. pDevRegnInfo = (PDEVICE_REGISTER_INFO)
  267. AllocSplMem(sizeof(DEVICE_REGISTER_INFO));
  268. if ( !pDevRegnInfo )
  269. goto Fail;
  270. pDevRegnInfo->hDevice = hDevice;
  271. pDevRegnInfo->pData = pData;
  272. pDevRegnInfo->pfnQueryRemove = pfnQueryRemove;
  273. pDevRegnInfo->hNotify = RegisterDeviceNotification(
  274. ghSplHandle,
  275. &Filter,
  276. DEVICE_NOTIFY_SERVICE_HANDLE);
  277. if ( pDevRegnInfo->hNotify ) {
  278. EnterRouterSem();
  279. pDevRegnInfo->pNext = gpDevRegnInfo;
  280. gpDevRegnInfo = pDevRegnInfo;
  281. LeaveRouterSem();
  282. return pDevRegnInfo->hNotify;
  283. }
  284. FreeSplMem(pDevRegnInfo);
  285. Fail:
  286. return NULL;
  287. }