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.

362 lines
9.7 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1985-1991. All rights reserved.
  3. Title: avitask.c - Background task that actually manipulates AVI files.
  4. *****************************************************************************/
  5. #include "graphic.h"
  6. void FAR PASCAL DebugBreak(void);
  7. BOOL FAR PASCAL mciaviCloseFile(NPMCIGRAPHIC npMCI);
  8. BOOL FAR PASCAL mciaviOpenFile(NPMCIGRAPHIC npMCI);
  9. #if defined(WIN32) || !defined(DEBUG)
  10. #define StackTop() (void *)0
  11. #define StackMin() (void *)0
  12. #define StackBot() (void *)0
  13. #define StackMark()
  14. #define StackTest() TRUE
  15. #else
  16. #define STACK _based(_segname("_STACK"))
  17. #define StackTop() *((UINT STACK *)10)
  18. #define StackMin() *((UINT STACK *)12)
  19. #define StackBot() *((UINT STACK *)14)
  20. #define StackMark() *((UINT STACK*)StackBot()) = 42
  21. #define StackTest() *((UINT STACK*)StackBot()) == 42
  22. #endif
  23. /***************************************************************************
  24. ***************************************************************************/
  25. #ifndef WIN32
  26. #pragma optimize("", off)
  27. void FAR SetPSP(UINT psp)
  28. {
  29. _asm {
  30. mov bx,psp
  31. mov ah,50h
  32. int 21h
  33. }
  34. }
  35. #pragma optimize("", on)
  36. #endif
  37. /***************************************************************************
  38. *
  39. * @doc INTERNAL MCIAVI
  40. *
  41. * @api void | mciaviTask | This function is the background task which plays
  42. * AVI files. It is called as a result of the call to mmTaskCreate()
  43. * in DeviceOpen(). When this function returns, the task is destroyed.
  44. *
  45. * @parm DWORD | dwInst | instance data passed to mmCreateTask - contains
  46. * a pointer to an instance data block.
  47. *
  48. ***************************************************************************/
  49. void FAR PASCAL _LOADDS mciaviTask(DWORD dwInst)
  50. {
  51. NPMCIGRAPHIC npMCI;
  52. npMCI = (NPMCIGRAPHIC) dwInst;
  53. // Set this task's error mode to the same as the parent's.
  54. SetErrorMode(npMCI->uErrorMode);
  55. DPF2(("MCIAVI: Bkgd Task hTask=%04X\n", GetCurrentTask()));
  56. DPF2(("MCIAVI: Stack: %04X %04X %04X\n", StackTop(), StackMin(), StackBot()));
  57. /* Task state is TASKBEINGCREATED at fn. entry, then goes to TASKINIT. */
  58. Assert(npMCI && npMCI->wTaskState == TASKBEINGCREATED);
  59. npMCI->wTaskState = TASKINIT;
  60. #ifndef WIN32
  61. //
  62. // in order to make this task, more like a "thread" we want to use the
  63. // same PSP as our parent, so we can share file handles and things.
  64. //
  65. // when we get created hTask is a PSP
  66. //
  67. npMCI->pspTask = GetCurrentPDB(); // save our PSP
  68. #endif
  69. npMCI->hTask = GetCurrentTask();
  70. npMCI->dwTaskError = 0;
  71. /* Open the file */
  72. if (!mciaviOpenFile(npMCI)) {
  73. // NOTE: IsTask() returns FALSE when hTask==0
  74. // Set hTask to 0 BEFORE setting wTaskState. Our creator is polling
  75. // the state of wTaskState...
  76. // npMCI->wTaskState = TASKABORT;
  77. // npMCI->hTask = 0; // This stops others using this task thread.
  78. DPF1(("Failed to open AVI file\n"));
  79. goto exit;
  80. }
  81. while (IsTask(npMCI->hTask)) {
  82. npMCI->wTaskState = TASKIDLE;
  83. DPF2(("MCIAVI: Idle\n"));
  84. DPF2(("MCIAVI: Stack: %04X %04X %04X\n", StackTop(), StackMin(), StackBot()));
  85. StackMark();
  86. /* Block until task is needed. The task count could */
  87. /* be anything at the exit of playfile or recordfile */
  88. /* so continue to block until the state really changes. */
  89. while (npMCI->wTaskState == TASKIDLE)
  90. {
  91. mmTaskBlock(npMCI->hTask);
  92. }
  93. mciaviMessage(npMCI, npMCI->wTaskState);
  94. AssertSz(StackTest(), "Stack overflow");
  95. if (npMCI->wTaskState == TASKCLOSE) {
  96. break;
  97. }
  98. }
  99. exit:
  100. mciaviTaskCleanup(npMCI);
  101. }
  102. /***************************************************************************
  103. *
  104. * @doc INTERNAL MCIAVI
  105. *
  106. * @api WORD | mciaviTaskCleanup | called when the background task
  107. * is being destroyed. This is where critical cleanup goes.
  108. *
  109. ***************************************************************************/
  110. void FAR PASCAL mciaviTaskCleanup(NPMCIGRAPHIC npMCI)
  111. {
  112. #ifndef WIN32
  113. //
  114. // restore our PSP back to normal before exit.
  115. //
  116. if (npMCI->pspTask)
  117. {
  118. SetPSP(npMCI->pspTask);
  119. }
  120. #endif
  121. #ifdef USEAVIFILE
  122. //
  123. // we must do this so COMPOBJ will shut down right.
  124. //
  125. FreeAVIFile(npMCI);
  126. #endif
  127. //
  128. // call a MSVideo shutdown routine.
  129. //
  130. //
  131. // Signal the foreground task that we're all done.
  132. // This must be absolutely the last thing we do.
  133. //
  134. npMCI->hTask = 0;
  135. npMCI->wTaskState = TASKCLOSED;
  136. }
  137. /***************************************************************************
  138. *
  139. * @doc INTERNAL MCIAVI
  140. *
  141. * @api void | mciaviMessage | this function handles a message from the
  142. * background task.
  143. *
  144. ***************************************************************************/
  145. void NEAR PASCAL mciaviMessage(NPMCIGRAPHIC npMCI, UINT msg)
  146. {
  147. UINT wNotification;
  148. switch (msg) {
  149. case TASKREADINDEX:
  150. Assert(0);
  151. break;
  152. /* Check to see if we just got closed */
  153. case TASKCLOSE:
  154. DPF1(("MCIAVI: Closing\n"));
  155. // hold critsec during close in case someone comes in to
  156. // eg DeviceRealize during the close when things are half-deleted.
  157. EnterCrit(npMCI);
  158. mciaviCloseFile(npMCI);
  159. LeaveCrit(npMCI);
  160. /* The htask must be set to NULL, otherwise CloseDevice() will */
  161. /* get stuck. */
  162. // NOTE: IsTask() returns FALSE when hTask==0
  163. // npMCI->hTask = 0;
  164. // npMCI->wTaskState = TASKABORT;
  165. return;
  166. case TASKRELOAD:
  167. DPF(("MCIAVI: Loading new file....\n"));
  168. mciaviCloseFile(npMCI);
  169. npMCI->dwTaskError = 0;
  170. npMCI->wTaskState = TASKINIT;
  171. if (!mciaviOpenFile(npMCI)) {
  172. // !!! mciaviOpenNew() !!!!!!!!!!!!!!!!!!!!!
  173. npMCI->wTaskState = TASKCLOSE;
  174. // npMCI->hTask = 0;
  175. return;
  176. }
  177. break;
  178. // We've been woken up to play....
  179. case TASKSTARTING:
  180. DPF2(("MCIAVI: Now busy\n"));
  181. /* Reset to no error */
  182. npMCI->dwTaskError = 0;
  183. wNotification = mciaviPlayFile(npMCI);
  184. if ((wNotification != MCI_NOTIFY_FAILURE) ||
  185. ((npMCI->dwFlags & MCIAVI_WAITING) == 0))
  186. GraphicDelayedNotify(npMCI, wNotification);
  187. break;
  188. default:
  189. DPF(("MCIAVI: Unknown task state!!!! (%d)\n", msg));
  190. break;
  191. }
  192. }
  193. #ifdef WIN32
  194. /***************************************************************************
  195. *
  196. * @doc INTERNAL MCIAVI
  197. *
  198. * @api int | GetPrioritySeparation | Find the foreground process priority
  199. * boost
  200. *
  201. * @rdesc Returns 0, 1 or 2
  202. *
  203. ***************************************************************************/
  204. DWORD GetPrioritySeparation(void)
  205. {
  206. static DWORD Win32PrioritySeparation = 0xFFFFFFFF;
  207. /* If we're not initialized get the current separation */
  208. if (Win32PrioritySeparation == 0xFFFFFFFF) {
  209. HKEY hKey;
  210. Win32PrioritySeparation = 2; // This is the default
  211. /* Code copied from shell\control\main\prictl.c */
  212. if (RegOpenKeyEx(
  213. HKEY_LOCAL_MACHINE,
  214. TEXT("SYSTEM\\CurrentControlSet\\Control\\PriorityControl"),
  215. 0,
  216. KEY_QUERY_VALUE,
  217. &hKey) == ERROR_SUCCESS) {
  218. DWORD Type;
  219. DWORD Length;
  220. Length = sizeof(Win32PrioritySeparation);
  221. /* Read the value which is the priority boost given to
  222. forground processes */
  223. if (RegQueryValueEx(
  224. hKey,
  225. TEXT("Win32PrioritySeparation"),
  226. NULL,
  227. &Type,
  228. (LPBYTE)&Win32PrioritySeparation,
  229. &Length
  230. ) != ERROR_SUCCESS) {
  231. Win32PrioritySeparation = 2;
  232. }
  233. RegCloseKey(hKey);
  234. }
  235. }
  236. return Win32PrioritySeparation;
  237. }
  238. #endif // WIN32
  239. /***************************************************************************
  240. *
  241. * @doc INTERNAL MCIAVI
  242. *
  243. * @api void| aviTaskYield | This function yields in the picky way windows
  244. * wants us to.
  245. *
  246. * basicly we Dispatch any messages in our que that belong to a window.
  247. *
  248. * NOTE we should not remove
  249. *
  250. ***************************************************************************/
  251. void NEAR PASCAL aviTaskYield(void)
  252. {
  253. MSG msg;
  254. #ifdef WIN32
  255. DWORD PrioritySeparation;
  256. //
  257. // Do our own kind of 'yield'. The reason for doing the
  258. // Peekmessage on Windows 3.1 was that if you didn't call
  259. // it Windows would think you were spinning out of control.
  260. // For Windows NT if you call PeekMessage 100 times without
  261. // getting anything your priority is lowered which would mess
  262. // up our tinkering with the priority here.
  263. //
  264. PrioritySeparation = GetPrioritySeparation();
  265. if (PrioritySeparation != 0) {
  266. SetThreadPriority(GetCurrentThread(),
  267. PrioritySeparation == 1 ?
  268. THREAD_PRIORITY_BELOW_NORMAL : // minus 1
  269. THREAD_PRIORITY_LOWEST); // minus 2
  270. Sleep(0); // Causes reschedule decision
  271. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  272. } else {
  273. Sleep(0); // Let other threads in
  274. }
  275. #else
  276. //
  277. // if we were MCIWAVE we would do this....
  278. //
  279. //if (PeekMessage(&msg, NULL, 0, WM_MM_RESERVED_FIRST-1, PM_REMOVE))
  280. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  281. DPF(("aviTaskYield: got message %04X to window %04X\n", msg.message, msg.hwnd));
  282. DispatchMessage(&msg);
  283. }
  284. #endif // WIN32
  285. }
  286.