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.

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