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.

559 lines
15 KiB

  1. /* Installable drivers for windows. Less common code.
  2. */
  3. #include "user.h"
  4. /*--------------------------------------------------------------------------*\
  5. **
  6. ** NewSignalProc() -
  7. **
  8. \*--------------------------------------------------------------------------*/
  9. #define SG_EXIT 0x0020
  10. #define SG_LOAD_DLL 0x0040
  11. #define SG_EXIT_DLL 0x0080
  12. #define SG_GP_FAULT 0x0666
  13. BOOL
  14. CALLBACK NewSignalProc(
  15. HTASK hTask,
  16. WORD message,
  17. WPARAM wParam,
  18. LPARAM lParam
  19. )
  20. {
  21. BOOL fRet;
  22. // Notify installable drivers this app is going away.
  23. if ( message == SG_EXIT || message == SG_GP_FAULT ) {
  24. InternalBroadcastDriverMessage( NULL, DRV_EXITAPPLICATION,
  25. (message == SG_GP_FAULT
  26. ? DRVEA_ABNORMALEXIT
  27. : DRVEA_NORMALEXIT),
  28. 0L, IBDM_FIRSTINSTANCEONLY );
  29. }
  30. //
  31. // Pass notification on to WOW32 (which passes on to USER32)
  32. //
  33. fRet = SignalProc( hTask, message, wParam, lParam );
  34. //
  35. // After letting WOW32 and User32 cleanup, destroy the shadow
  36. // message queue created by InitApp.
  37. //
  38. if ( message == SG_EXIT || message == SG_GP_FAULT ) {
  39. DeleteQueue();
  40. }
  41. return fRet;
  42. }
  43. HINSTANCE LoadAliasedLibrary(LPCSTR szLibFileName,
  44. LPCSTR szSection,
  45. LPCSTR szIniFile,
  46. LPSTR lpstrTail,
  47. WORD cbTail)
  48. {
  49. char sz[128];
  50. LPSTR pch;
  51. OFSTRUCT os;
  52. HFILE fd;
  53. HINSTANCE h;
  54. WORD errMode;
  55. if (!szLibFileName || !*szLibFileName)
  56. return((HINSTANCE)2); /* File not found */
  57. /* read the filename and additional info. into sz
  58. */
  59. GetPrivateProfileString(szSection, // ini section
  60. szLibFileName, // key name
  61. szLibFileName, // default if no match
  62. sz, // return buffer
  63. sizeof(sz), // return buffer size
  64. szIniFile); // ini. file
  65. sz[sizeof(sz)-1] = 0;
  66. /* strip off the additional info. Remember, DS!=SS so we need to get a lpstr
  67. * to our stack allocated sz.
  68. */
  69. pch = (LPSTR)sz;
  70. while (*pch)
  71. {
  72. if (*pch == ' ')
  73. {
  74. *pch++ = '\0';
  75. break;
  76. }
  77. pch++;
  78. }
  79. // pch pts to ch after first space or null ch
  80. fd = OpenFile(sz, &os, OF_EXIST|OF_SHARE_DENY_NONE);
  81. if (HFILE_ERROR == fd)
  82. return((HINSTANCE)2);
  83. /* copy additional info. to lpstrTail
  84. */
  85. if (lpstrTail && cbTail)
  86. {
  87. while (cbTail-- && (*lpstrTail++ = *pch++))
  88. ;
  89. *(lpstrTail-1) = 0;
  90. }
  91. errMode = SetErrorMode(0x8001);
  92. h = LoadLibrary(sz);
  93. SetErrorMode(errMode);
  94. return (h);
  95. }
  96. int GetDrvrUsage(HMODULE hModule)
  97. /* effects: Runs through the driver list and figures out how many instances of
  98. * this driver module handle we have. We use this instead of GetModuleUsage
  99. * so that we can have drivers loaded as normal DLLs and as installable
  100. * drivers.
  101. */
  102. {
  103. LPDRIVERTABLE lpdt;
  104. int index;
  105. int count;
  106. if (!hInstalledDriverList || !cInstalledDrivers || !hModule)
  107. return(0);
  108. count = 0;
  109. lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
  110. for (index=0;index<cInstalledDrivers;index++)
  111. {
  112. if (lpdt->hModule==hModule)
  113. count++;
  114. lpdt++;
  115. }
  116. return(count);
  117. }
  118. BOOL PASCAL CheckValidDriverProc(LPDRIVERTABLE lpdt, HDRVR hdrv)
  119. /* effects: Some vendors shipped multimedia style installable drivers with
  120. * bogus entry procs. This test checks for these bogus drivers and refuses to
  121. * install them.
  122. */
  123. {
  124. WORD currentSP;
  125. WORD saveSP;
  126. _asm mov saveSP, sp
  127. (void)(lpdt->lpDriverEntryPoint)(0, hdrv, 0, 0L, 0L);
  128. _asm mov currentSP, sp
  129. _asm mov sp, saveSP
  130. if (saveSP != currentSP)
  131. DebugErr(DBF_ERROR, "Invalid driver entry proc address");
  132. return (saveSP == currentSP);
  133. }
  134. LRESULT FAR InternalLoadDriver(LPCSTR szDriverName,
  135. LPCSTR szSectionName,
  136. LPCSTR lpstrTail,
  137. WORD cbTail,
  138. BOOL fSendEnable)
  139. {
  140. int index;
  141. int i;
  142. LPDRIVERTABLE lpdt;
  143. LPDRIVERTABLE lpdtBegin;
  144. LRESULT result;
  145. HGLOBAL h;
  146. HINSTANCE hInstance;
  147. char szDrivers[20];
  148. char szSystemIni[20];
  149. /* Drivers receive the following messages: if the driver was loaded,
  150. * DRV_LOAD. If DRV_LOAD returns non-zero and fSendEnable, DRV_ENABLE.
  151. */
  152. if (!hInstalledDriverList)
  153. h = GlobalAlloc(GHND|GMEM_SHARE, (DWORD)((WORD)sizeof(DRIVERTABLE)));
  154. else
  155. /* Alloc space for the next driver we will install. We may not really
  156. * install the driver in the last slot but rather in an intermediate
  157. * slot which was freed.
  158. */
  159. h = GlobalReAlloc(hInstalledDriverList,
  160. (DWORD)((WORD)sizeof(DRIVERTABLE)*(cInstalledDrivers+1)),
  161. GHND|GMEM_SHARE);
  162. if (!h)
  163. return(0L);
  164. cInstalledDrivers++;
  165. hInstalledDriverList = h;
  166. if (!szSectionName)
  167. LoadString(hInstanceWin, STR_DRIVERS, szDrivers, sizeof(szDrivers));
  168. LoadString(hInstanceWin, STR_SYSTEMINI, szSystemIni, sizeof(szSystemIni));
  169. lpdtBegin = lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList, NULL);
  170. /* Find an empty driver entry */
  171. for (i = 0; i < cInstalledDrivers; i++)
  172. {
  173. if (lpdt->hModule == NULL)
  174. {
  175. index = i;
  176. break;
  177. }
  178. lpdt++;
  179. }
  180. if (index + 1 < cInstalledDrivers)
  181. /* The driver went into an unused slot in the middle somewhere so
  182. * decrement cInstalledDrivers count.
  183. */
  184. cInstalledDrivers--;
  185. /* Temporarly use an hModule to 1 to reserve this entry in case the driver
  186. * loads another driver in its LibMain.
  187. */
  188. lpdt->hModule = (HMODULE)1;
  189. hInstance = LoadAliasedLibrary((LPSTR)szDriverName,
  190. (LPSTR)(szSectionName ? szSectionName : szDrivers),
  191. szSystemIni,
  192. (LPSTR)lpstrTail,
  193. cbTail);
  194. if (hInstance < HINSTANCE_ERROR)
  195. {
  196. lpdt->hModule = NULL;
  197. /* Load failed with an error. Return error code in highword.
  198. */
  199. return(MAKELRESULT(0, hInstance));
  200. }
  201. (FARPROC)lpdt->lpDriverEntryPoint = GetProcAddress(hInstance, "DriverProc");
  202. if (!lpdt->lpDriverEntryPoint)
  203. {
  204. FreeLibrary(hInstance);
  205. lpdt->hModule = 0;
  206. result = 0L;
  207. goto LoadCleanUp;
  208. }
  209. lpdt->hModule = hInstance;
  210. /* Save either the alias or filename of this driver. (depends on what the
  211. * app passed to us to load it)
  212. */
  213. lstrcpy(lpdt->szAliasName, szDriverName);
  214. if (GetDrvrUsage(hInstance) == 1)
  215. {
  216. /* If this is the first instance, send the drv_load message. Don't use
  217. * SendDriverMessage because we haven't initialized the linked list yet
  218. */
  219. if (!CheckValidDriverProc(lpdt, (HDRVR)(index+1)) ||
  220. !(lpdt->lpDriverEntryPoint)(lpdt->dwDriverIdentifier,
  221. (HDRVR)(index+1),
  222. DRV_LOAD,
  223. 0L, 0L))
  224. {
  225. /* Driver failed load call.
  226. */
  227. lpdt->lpDriverEntryPoint = NULL;
  228. lpdt->hModule = NULL;
  229. FreeLibrary(hInstance);
  230. result = 0L;
  231. goto LoadCleanUp;
  232. }
  233. lpdt->fFirstEntry = 1;
  234. }
  235. /* Put driver in the load order linked list
  236. */
  237. if (idFirstDriver == -1)
  238. {
  239. /* Initialize everything when first driver is loaded.
  240. */
  241. idFirstDriver = index;
  242. idLastDriver = index;
  243. lpdt->idNextDriver = -1;
  244. lpdt->idPrevDriver = -1;
  245. }
  246. else
  247. {
  248. /* Insert this driver at the end of the load chain.
  249. */
  250. lpdtBegin[idLastDriver].idNextDriver = index;
  251. lpdt->idPrevDriver = idLastDriver;
  252. lpdt->idNextDriver = -1;
  253. idLastDriver = index;
  254. }
  255. if (fSendEnable && lpdt->fFirstEntry)
  256. SendDriverMessage((HDRVR)(index+1), DRV_ENABLE, 0L, 0L);
  257. result = MAKELRESULT(index+1, hInstance);
  258. LoadCleanUp:
  259. return(result);
  260. }
  261. WORD FAR InternalFreeDriver(HDRVR hDriver, BOOL fSendDisable)
  262. {
  263. LPDRIVERTABLE lpdt;
  264. WORD w;
  265. int id;
  266. /* The driver will receive the following message sequence:
  267. *
  268. * if usage count of driver is 1
  269. * DRV_DISABLE (normally)
  270. * DRV_FREE
  271. */
  272. if ((int)hDriver > cInstalledDrivers || !hDriver)
  273. return(0);
  274. lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
  275. if (!lpdt[(int)hDriver-1].hModule)
  276. return(0);
  277. /* If the driver usage count is 1, then send free and disable messages.
  278. */
  279. /* Clear dwDriverIdentifier so that the sendmessage for DRV_OPEN and
  280. * DRV_ENABLE have dwDriverIdentifier = 0 if an entry gets reused and so
  281. * that the DRV_DISABLE and DRV_FREE messages below also get
  282. * dwDriverIdentifier = 0.
  283. */
  284. lpdt[(int)hDriver-1].dwDriverIdentifier = 0;
  285. w = GetDrvrUsage(lpdt[(int)hDriver-1].hModule);
  286. if (w == 1)
  287. {
  288. if (fSendDisable)
  289. SendDriverMessage(hDriver, DRV_DISABLE, 0L, 0L);
  290. SendDriverMessage(hDriver, DRV_FREE, 0L, 0L);
  291. }
  292. FreeLibrary(lpdt[(int)hDriver-1].hModule);
  293. // Clear the rest of the table entry
  294. lpdt[(int)hDriver-1].hModule = 0; // this indicates free entry
  295. lpdt[(int)hDriver-1].fFirstEntry = 0; // this is also just to be tidy
  296. lpdt[(int)hDriver-1].lpDriverEntryPoint = 0; // this is also just to be tidy
  297. /* Fix up the driver load linked list */
  298. if (idFirstDriver == (int)hDriver-1)
  299. {
  300. idFirstDriver = lpdt[(int)hDriver-1].idNextDriver;
  301. if (idFirstDriver == -1)
  302. {
  303. /* No more drivers in the chain */
  304. idFirstDriver = -1;
  305. idLastDriver = -1;
  306. cInstalledDrivers= 0;
  307. goto Done;
  308. }
  309. else
  310. {
  311. /* Make prev entry of new first driver -1 */
  312. lpdt[idFirstDriver].idPrevDriver = -1;
  313. }
  314. }
  315. else if (idLastDriver == (int)hDriver-1)
  316. {
  317. /* We are freeing the last driver. So find a new last driver. */
  318. idLastDriver = lpdt[(int)hDriver-1].idPrevDriver;
  319. lpdt[idLastDriver].idNextDriver = -1;
  320. }
  321. else
  322. {
  323. /* We are freeing a driver in the middle of the list somewhere. */
  324. id = lpdt[(int)hDriver-1].idPrevDriver;
  325. lpdt[id].idNextDriver = lpdt[(int)hDriver-1].idNextDriver;
  326. id = lpdt[(int)hDriver-1].idNextDriver;
  327. lpdt[id].idPrevDriver = lpdt[(int)hDriver-1].idPrevDriver;
  328. }
  329. Done:
  330. return(w-1);
  331. }
  332. LRESULT InternalOpenDriver(LPCSTR szDriverName,
  333. LPCSTR szSectionName,
  334. LPARAM lParam2,
  335. BOOL fSendEnable)
  336. {
  337. HDRVR hDriver;
  338. LPDRIVERTABLE lpdt;
  339. LRESULT result;
  340. char sz[128];
  341. if (hDriver = (HDRVR)LOWORD(InternalLoadDriver(szDriverName, szSectionName,
  342. sz, sizeof(sz), fSendEnable)))
  343. {
  344. /* Set the driver identifier to the DRV_OPEN call to the driver
  345. * handle. This will let people build helper functions that the driver
  346. * can call with a unique identifier if they want to.
  347. */
  348. lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
  349. lpdt[(int)hDriver-1].dwDriverIdentifier = (DWORD)(WORD)hDriver;
  350. result = SendDriverMessage(hDriver,
  351. DRV_OPEN,
  352. (LPARAM)(LPSTR)sz,
  353. lParam2);
  354. if (!result)
  355. InternalFreeDriver(hDriver, fSendEnable);
  356. else
  357. {
  358. lpdt = (LPDRIVERTABLE)MAKELONG(0,hInstalledDriverList);
  359. lpdt[(int)hDriver-1].dwDriverIdentifier = (DWORD)result;
  360. result = (LRESULT)(DWORD)(WORD)hDriver;
  361. }
  362. }
  363. else
  364. result = 0L;
  365. return(result);
  366. }
  367. LRESULT InternalCloseDriver(HDRVR hDriver, LPARAM lParam1, LPARAM lParam2, BOOL fSendDisable)
  368. {
  369. LPDRIVERTABLE lpdt;
  370. LRESULT result;
  371. int index;
  372. BOOL f;
  373. HMODULE hm;
  374. // check handle in valid range.
  375. if ((int)hDriver > cInstalledDrivers)
  376. return(FALSE);
  377. lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
  378. if (!lpdt[(int)hDriver-1].hModule)
  379. return(FALSE);
  380. result = SendDriverMessage(hDriver, DRV_CLOSE, lParam1, lParam2);
  381. if (result)
  382. {
  383. // Driver didn't abort close
  384. f = lpdt[(int)hDriver-1].fFirstEntry;
  385. hm = lpdt[(int)hDriver-1].hModule;
  386. if (InternalFreeDriver(hDriver, fSendDisable) && f)
  387. {
  388. lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
  389. /* Only one entry for the driver in the driver list has the first
  390. * instance flag set. This is to make it easier to handle system
  391. * messages that only need to be sent to a driver once.
  392. *
  393. * To maintain the flag, we must set the flag in one of the other
  394. * entries if we remove the driver entry with the flag set.
  395. *
  396. * Note that InternalFreeDriver returns the new usage count of
  397. * the driver so if it is zero, we know that there are no other
  398. * entries for the driver in the list and so we don't have to
  399. * do this loop.
  400. */
  401. for (index=0;index<cInstalledDrivers;index++)
  402. if (lpdt[index].hModule == hm && !lpdt[index].fFirstEntry)
  403. {
  404. lpdt[index].fFirstEntry = 1;
  405. break;
  406. }
  407. }
  408. }
  409. return(result);
  410. }
  411. HDRVR API IOpenDriver(LPCSTR szDriverName, LPCSTR szSectionName, LPARAM lParam)
  412. {
  413. LRESULT result;
  414. /* The driver receives the following messages when it is opened. If it isn't
  415. * loaded, the library is loaded and the DRV_LOAD message is sent. If
  416. * DRV_LOAD returns nonzero, the DRV_ENABLE message is sent. Once the
  417. * driver is loaded or if it was previously loaded, the DRV_OPEN message is
  418. * sent.
  419. */
  420. result = InternalOpenDriver(szDriverName, szSectionName, lParam, TRUE);
  421. return((HDRVR)LOWORD(result));
  422. }
  423. LRESULT API ICloseDriver(HDRVR hDriver, LPARAM lParam1, LPARAM lParam2)
  424. {
  425. /* The driver will receive the following message sequence:
  426. *
  427. * DRV_CLOSE
  428. * if DRV_CLOSE returns non-zero
  429. * if driver usage count = 1
  430. * DRV_DISABLE
  431. * DRV_FREE
  432. */
  433. return(InternalCloseDriver(hDriver, lParam1, lParam2, TRUE));
  434. }
  435. HINSTANCE API IGetDriverModuleHandle(HDRVR hDriver)
  436. /* effects: Returns the module handle associated with the given driver ID.
  437. */
  438. {
  439. LPDRIVERTABLE lpdt;
  440. HINSTANCE hModule = NULL;
  441. if (hDriver && ((int)hDriver <= cInstalledDrivers))
  442. {
  443. lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
  444. return lpdt[(int)hDriver-1].hModule;
  445. }
  446. else
  447. return NULL;
  448. }