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.

379 lines
11 KiB

  1. /*
  2. drvproc.c
  3. contains MMSYSTEMs DriverProc
  4. Copyright (c) Microsoft Corporation 1990. All rights reserved
  5. */
  6. #include <windows.h>
  7. #include <mmsysver.h>
  8. #include "mmsystem.h"
  9. #include "mmsysi.h"
  10. #include "drvr.h"
  11. #include "mmioi.h"
  12. extern IOProcMapEntry NEAR * gIOProcMapHead; // in MMIO.C
  13. /****************************************************************************
  14. internal prototypes
  15. ****************************************************************************/
  16. static void FAR PASCAL SetPrivateProfileInt(LPSTR szSection, LPSTR szKey, int i, LPSTR szIniFile);
  17. static BYTE fFirstTime=TRUE; // First enable
  18. extern BOOL FAR PASCAL DrvLoad(void); // in init.c
  19. extern BOOL FAR PASCAL DrvFree(void);
  20. extern char far szStartupSound[]; // in mmwnd.c
  21. static SZCODE szExitSound[] = "SystemExit";
  22. #ifdef DEBUG_RETAIL
  23. extern char far szMMSystem[];
  24. extern char far szSystemIni[];
  25. extern char far szDebugOutput[];
  26. extern char far szMci[];
  27. // extern WORD fDebugOutput;
  28. extern int DebugmciSendCommand; // in MCI.C
  29. #ifdef DEBUG
  30. extern char far szDebug[];
  31. extern WORD fDebug;
  32. #endif
  33. #endif
  34. void NEAR PASCAL AppExit(HTASK hTask, BOOL fNormalExit);
  35. /*****************************************************************************
  36. *
  37. * @doc INTERNAL
  38. *
  39. * @api LRESULT | DriverProc | This is the standard DLL entry point. It is
  40. * called from user (3.1) or mmsound.drv (3.0) when MMSYSTEM.DLL is
  41. * loaded, enabled, or disabled.
  42. *
  43. ****************************************************************************/
  44. LRESULT CALLBACK
  45. DriverProc(
  46. DWORD dwDriver,
  47. HDRVR hDriver,
  48. UINT wMessage,
  49. LPARAM lParam1,
  50. LPARAM lParam2
  51. )
  52. {
  53. switch (wMessage)
  54. {
  55. case DRV_LOAD:
  56. //
  57. // first load message, initialize mmsystem.
  58. // sent from USER when loading drivers from drivers= line
  59. //
  60. if (fFirstTime)
  61. return (LRESULT)(LONG)DrvLoad();
  62. //
  63. // a normal load message, a app is trying to open us
  64. // with OpenDriver()
  65. //
  66. break; // return success all other times (1L)
  67. case DRV_FREE:
  68. //
  69. // a free message, this is send just before the DLL is unloaded
  70. // by the driver interface.
  71. //
  72. // sent by user just before system exit, after sending
  73. // the DRV_DISABLE message.
  74. //
  75. DrvFree();
  76. break; // return success (1L)
  77. case DRV_OPEN: // FALL-THROUGH
  78. case DRV_CLOSE:
  79. break; // return success (1L)
  80. case DRV_ENABLE:
  81. DOUT("MMSYSTEM: Enable\r\n");
  82. fFirstTime = FALSE;
  83. break; // return success (1L)
  84. case DRV_DISABLE:
  85. DOUT("MMSYSTEM: Disable\r\n");
  86. break; // return success (1L)
  87. //
  88. // sent when a application is terminating
  89. //
  90. // lParam1:
  91. // DRVEA_ABNORMALEXIT
  92. // DRVEA_NORMALEXIT
  93. //
  94. case DRV_EXITAPPLICATION:
  95. AppExit(GetCurrentTask(), (BOOL)lParam1 == DRVEA_NORMALEXIT);
  96. break;
  97. case DRV_EXITSESSION:
  98. sndPlaySound(szExitSound, SND_SYNC | SND_NODEFAULT);
  99. break;
  100. #ifdef DEBUG_RETAIL
  101. case MM_GET_DEBUG:
  102. break;
  103. case MM_GET_DEBUGOUT:
  104. return (LRESULT)(LONG)fDebugOutput;
  105. case MM_SET_DEBUGOUT:
  106. fDebugOutput = (BYTE)(LONG)lParam1;
  107. SetPrivateProfileInt(szMMSystem,szDebugOutput,fDebugOutput,szSystemIni);
  108. break;
  109. case MM_GET_MCI_DEBUG:
  110. return (LRESULT)(LONG)DebugmciSendCommand;
  111. case MM_SET_MCI_DEBUG:
  112. DebugmciSendCommand = (WORD)(LONG)lParam1;
  113. SetPrivateProfileInt(szMMSystem,szMci,DebugmciSendCommand,szSystemIni);
  114. break;
  115. #ifdef DEBUG
  116. case MM_GET_MM_DEBUG:
  117. return (LRESULT)(LONG)fDebug;
  118. case MM_SET_MM_DEBUG:
  119. fDebug = (BYTE)(LONG)lParam1;
  120. SetPrivateProfileInt(szMMSystem,szDebug,fDebug,szSystemIni);
  121. break;
  122. #ifdef DEBUG
  123. case MM_DRV_RESTART:
  124. break;
  125. #endif
  126. case MM_HINFO_MCI:
  127. if ((HLOCAL)(LONG)lParam2 == (HLOCAL)NULL)
  128. return (LRESULT)(LONG)MCI_wNextDeviceID;
  129. if (MCI_VALID_DEVICE_ID((UINT)(LONG)lParam1))
  130. {
  131. *(LPMCI_DEVICE_NODE)lParam2 = *MCI_lpDeviceList[(UINT)(LONG)lParam1];
  132. break;
  133. }
  134. return (LRESULT)FALSE;
  135. case MM_HINFO_NEXT:
  136. if ((HLOCAL)(LONG)lParam1 == (HLOCAL)NULL)
  137. return (LRESULT)(LONG)(UINT)GetHandleFirst();
  138. else
  139. return (LRESULT)(LONG)(UINT)GetHandleNext((HLOCAL)(LONG)lParam1);
  140. case MM_HINFO_TASK:
  141. return (LRESULT)(LONG)(UINT)GetHandleOwner((HLOCAL)(LONG)lParam1);
  142. case MM_HINFO_TYPE:
  143. return GetHandleType((HLOCAL)(LONG)lParam1);
  144. #endif // ifdef DEBUG
  145. #endif // ifdef DEBUG_RETAIL
  146. default:
  147. return DefDriverProc(dwDriver, hDriver, wMessage, lParam1, lParam2);
  148. }
  149. return (LRESULT)1L;
  150. }
  151. /*****************************************************************************
  152. * @doc INTERNAL
  153. *
  154. * @func void | AppExit |
  155. * a application is exiting, free any MMSYS resources it may own
  156. *
  157. ****************************************************************************/
  158. void NEAR PASCAL AppExit(HTASK hTask, BOOL fNormalExit)
  159. {
  160. HLOCAL h;
  161. HLOCAL hNext;
  162. WORD wDebugFlags;
  163. UINT wDeviceID;
  164. UINT cFree;
  165. UINT cHeap;
  166. UINT err;
  167. if (hdrvDestroy != (HLOCAL)-1)
  168. {
  169. DOUT("MMSYSTEM: Hey! AppExit has been re-entered!\r\n");
  170. }
  171. #ifdef DEBUG
  172. if (!fNormalExit)
  173. ROUT("MMSYSTEM: Abnormal app termination");
  174. #endif
  175. //
  176. // either log a error or a warning depending on wether it was
  177. // a normal exit or not.
  178. //
  179. if (fNormalExit)
  180. wDebugFlags = DBF_MMSYSTEM | DBF_ERROR;
  181. else
  182. wDebugFlags = DBF_MMSYSTEM | DBF_WARNING; // DBF_TRACE?
  183. //
  184. // now free MCI devices.
  185. //
  186. for (wDeviceID=1; wDeviceID<MCI_wNextDeviceID; wDeviceID++)
  187. {
  188. if (MCI_VALID_DEVICE_ID(wDeviceID) && MCI_lpDeviceList[wDeviceID]->hCreatorTask == hTask)
  189. {
  190. DebugErr2(wDebugFlags, "MCI device %ls (%d) not released.", MCI_lpDeviceList[wDeviceID]->lpstrInstallName, wDeviceID);
  191. //
  192. // clear these to force MCI to close the device
  193. //
  194. MCI_lpDeviceList[wDeviceID]->dwMCIFlags &= ~MCINODE_ISCLOSING;
  195. MCI_lpDeviceList[wDeviceID]->dwMCIFlags &= ~MCINODE_ISAUTOCLOSING;
  196. err = (UINT)mciSendCommand(wDeviceID, MCI_CLOSE, NULL, NULL);
  197. #ifdef DEBUG
  198. if (err != 0)
  199. DebugErr1(DBF_WARNING, "Unable to close MCI device (err = %04X).", err);
  200. #endif
  201. }
  202. }
  203. //
  204. // free all WAVE/MIDI/MMIO handles
  205. //
  206. start_over:
  207. for (h=GetHandleFirst(); h; h=hNext)
  208. {
  209. hNext = GetHandleNext(h);
  210. if (GetHandleOwner(h) == hTask)
  211. {
  212. //
  213. // hack for the wave/midi mapper, always free handle's backward.
  214. //
  215. if (hNext && GetHandleOwner(hNext) == hTask)
  216. continue;
  217. //
  218. // do this so even if the close fails we will not
  219. // find it again.
  220. //
  221. SetHandleOwner(h, NULL);
  222. //
  223. // set the hdrvDestroy global so DriverCallback will not
  224. // do anything for this device
  225. //
  226. hdrvDestroy = h;
  227. switch(GetHandleType(h))
  228. {
  229. case TYPE_WAVEOUT:
  230. DebugErr1(wDebugFlags, "WaveOut handle (%04X) was not released.", h);
  231. waveOutReset((HWAVEOUT)h);
  232. err = waveOutClose((HWAVEOUT)h);
  233. break;
  234. case TYPE_WAVEIN:
  235. DebugErr1(wDebugFlags, "WaveIn handle (%04X) was not released.", h);
  236. waveInStop((HWAVEIN)h);
  237. waveInReset((HWAVEIN)h);
  238. err = waveInClose((HWAVEIN)h);
  239. break;
  240. case TYPE_MIDIOUT:
  241. DebugErr1(wDebugFlags, "MidiOut handle (%04X) was not released.", h);
  242. midiOutReset((HMIDIOUT)h);
  243. err = midiOutClose((HMIDIOUT)h);
  244. break;
  245. case TYPE_MIDIIN:
  246. DebugErr1(wDebugFlags, "MidiIn handle (%04X) was not released.", h);
  247. midiInStop((HMIDIIN)h);
  248. midiInReset((HMIDIIN)h);
  249. err = midiInClose((HMIDIIN)h);
  250. break;
  251. case TYPE_MMIO:
  252. DebugErr1(wDebugFlags, "MMIO handle (%04X) was not released.", h);
  253. err = mmioClose((HMMIO)h, 0);
  254. break;
  255. case TYPE_IOPROC:
  256. DebugErr1(wDebugFlags, "MMIO handler '%4.4ls' not removed.", (LPSTR)&((IOProcMapEntry*)h)->fccIOProc);
  257. err = !mmioInstallIOProc(((IOProcMapEntry*)h)->fccIOProc, NULL, MMIO_REMOVEPROC);
  258. break;
  259. }
  260. #ifdef DEBUG
  261. if (err != 0)
  262. DebugErr1(DBF_WARNING, "Unable to close handle (err = %04X).", err);
  263. #endif
  264. //
  265. // unset hdrvDestroy so DriverCallback will work.
  266. // some hosebag drivers (like the TIMER driver)
  267. // may pass NULL as their driver handle.
  268. // so dont set it to NULL.
  269. //
  270. hdrvDestroy = (HLOCAL)-1;
  271. //
  272. // the reason we start over is because a single free may cause
  273. // multiple free's (ie MIDIMAPPER has another HMIDI open, ...)
  274. //
  275. goto start_over;
  276. }
  277. }
  278. //
  279. // what about timeSetEvent()!!!???
  280. //
  281. // any outstanding timer events till be killed by the timer driver
  282. // it self.
  283. //
  284. mciAppExit( hTask );
  285. // shrink our heap, down to minimal size.
  286. if ((cFree = LocalCountFree()) > 1024)
  287. {
  288. cHeap = LocalHeapSize() - (cFree - 512);
  289. LocalShrink(NULL, cHeap);
  290. DPRINTF(("MMSYSTEM: Shrinking the heap (%d)\r\n", cHeap));
  291. }
  292. }
  293. #ifdef DEBUG_RETAIL
  294. /*****************************************************************************
  295. * @doc INTERNAL
  296. *
  297. * @func void | SetPrivateProfileInt | windows should have this function
  298. *
  299. * @comm used by DriverProc to set debug state in SYSTEM.INI
  300. *
  301. ****************************************************************************/
  302. static void FAR PASCAL SetPrivateProfileInt(LPSTR szSection, LPSTR szKey, int i, LPSTR szIniFile)
  303. {
  304. char ach[32] ;
  305. if (i != (int)GetPrivateProfileInt(szSection, szKey, ~i, szIniFile))
  306. {
  307. wsprintf(ach, "%d", i);
  308. WritePrivateProfileString(szSection, szKey, ach, szIniFile);
  309. }
  310. }
  311. #endif //ifdef DEBUG_RETAIL