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.

3749 lines
106 KiB

  1. /*----------------------------------------------------------------------------*\
  2. *
  3. * MCIWnd
  4. *
  5. *----------------------------------------------------------------------------*/
  6. #include "mciwndi.h"
  7. LONG FAR PASCAL _loadds MCIWndProc(HWND hwnd, unsigned msg, WORD wParam, LONG lParam);
  8. static LONG OwnerDraw(PMCIWND p, UINT msg, WORD wParam, LONG lParam);
  9. static BOOL NEAR PASCAL mciDialog(HWND hwnd);
  10. static void NEAR PASCAL MCIWndCopy(PMCIWND p);
  11. BOOL FAR _loadds MCIWndRegisterClass(void)
  12. {
  13. WNDCLASS cls;
  14. // !!! We need to register a global class with the hinstance of the DLL
  15. // !!! because it's the DLL that has the code for the window class.
  16. // !!! Otherwise, the class goes away on us and things start to blow!
  17. // !!! HACK HACK HACK The hInstance is the current DS which is the high
  18. // !!! word of the address of all global variables --- sorry NT
  19. #ifndef WIN32
  20. HINSTANCE hInstance = (HINSTANCE)HIWORD((LPVOID)&hInst); // random global
  21. #else
  22. HINSTANCE hInstance = GetModuleHandle(NULL);
  23. #endif
  24. // If we're already registered, we're OK
  25. if (GetClassInfo(hInstance, aszMCIWndClassName, &cls))
  26. return TRUE;
  27. // !!! Save the instance that created the class in a global for cutils.c
  28. // !!! which may need to know this. I know, it's ugly.
  29. hInst = hInstance;
  30. cls.lpszClassName = aszMCIWndClassName;
  31. cls.lpfnWndProc = (WNDPROC)MCIWndProc;
  32. cls.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
  33. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  34. cls.hIcon = NULL;
  35. cls.lpszMenuName = NULL;
  36. cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  37. cls.hInstance = hInstance;
  38. cls.cbClsExtra = 0;
  39. cls.cbWndExtra = sizeof(LPVOID); // big enough for far pointer
  40. if (RegisterClass(&cls)) {
  41. extern BOOL FAR PASCAL InitToolbarClass(HINSTANCE hInstance);
  42. extern BOOL FAR PASCAL InitTrackBar(HINSTANCE hInstance);
  43. if (!InitToolbarClass(hInstance))
  44. return FALSE;
  45. if (!InitTrackBar(hInstance))
  46. return FALSE;
  47. // !!! Other one-time initialization
  48. return TRUE;
  49. }
  50. return FALSE;
  51. }
  52. HWND FAR _loadds MCIWndCreate(HWND hwndParent, HINSTANCE hInstance,
  53. DWORD dwStyle, LPSTR szFile)
  54. {
  55. HWND hwnd;
  56. int x,y,dx,dy;
  57. #ifdef WIN32
  58. #define GetCurrentInstance() GetModuleHandle(NULL);
  59. #else
  60. #define GetCurrentInstance() SELECTOROF(((LPVOID)&hwndParent))
  61. #endif
  62. if (hInstance == NULL)
  63. hInstance = GetCurrentInstance();
  64. if (!MCIWndRegisterClass())
  65. return NULL;
  66. if (HIWORD(dwStyle) == 0)
  67. {
  68. if (hwndParent)
  69. dwStyle |= WS_CHILD | WS_BORDER | WS_VISIBLE;
  70. else
  71. dwStyle |= WS_OVERLAPPEDWINDOW | WS_VISIBLE;
  72. }
  73. // !!! Do we really want to do this?
  74. dwStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  75. x = y = dy = 0;
  76. dx = STANDARD_WIDTH;
  77. // If we're making a top level window, pick some reasonable position
  78. if (hwndParent == NULL && !(dwStyle & WS_POPUP)) {
  79. x = CW_USEDEFAULT;
  80. // Visible overlapped windows treat y as a ShowWindow flag
  81. if (dwStyle & WS_VISIBLE)
  82. y = SW_SHOW;
  83. }
  84. // Our preview open dialog rips if we don't provide a non-zero ID for a
  85. // child window.
  86. hwnd =
  87. #ifdef BIDI
  88. CreateWindowEx(WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON,
  89. #else
  90. CreateWindow (
  91. #endif
  92. aszMCIWndClassName, szNULL, dwStyle,
  93. x, y, dx, dy,
  94. hwndParent,
  95. (HMENU)((dwStyle & WS_CHILD) ? 0x42 : NULL),
  96. hInstance, (LPVOID)szFile);
  97. return hwnd;
  98. }
  99. //
  100. // Give a notification of something interesting to the proper authorites.
  101. //
  102. static LRESULT NotifyOwner(PMCIWND p, unsigned msg, WPARAM wParam, LPARAM lParam)
  103. {
  104. if (p->hwndOwner)
  105. return SendMessage(p->hwndOwner, msg, wParam, lParam);
  106. else
  107. return 0;
  108. }
  109. //
  110. // If an error occured, set our error code and maybe bring up a dialog
  111. // Clears the error code if command was successful.
  112. //
  113. static void MCIWndiHandleError(PMCIWND p, DWORD dw)
  114. {
  115. char ach[128];
  116. // Set/Clear our error code
  117. p->dwError = dw;
  118. if (dw) {
  119. // We want to bring up a dialog on errors, so do so.
  120. // Don't bring up a dialog while we're moving the thumb around because
  121. // that'll REALLY confuse the mouse capture
  122. if (!(p->dwStyle & MCIWNDF_NOERRORDLG) && !p->fScrolling &&
  123. !p->fTracking) {
  124. mciGetErrorString(p->dwError, ach, sizeof(ach));
  125. MessageBox(p->hwnd, ach, LoadSz(IDS_MCIERROR),
  126. #ifdef BIDI
  127. MB_RTL_READING |
  128. #endif
  129. MB_ICONEXCLAMATION | MB_OK);
  130. }
  131. // The "owner" wants to know the error. We tell him after we
  132. // bring up the dialog, because otherwise, our VBX never gets this
  133. // event. (Wierd...)
  134. if (p->dwStyle & MCIWNDF_NOTIFYERROR) {
  135. NotifyOwner(p, MCIWNDM_NOTIFYERROR, p->hwnd, p->dwError);
  136. }
  137. }
  138. }
  139. //
  140. // Send an MCI GetDevCaps command and return whether or not it's supported
  141. // This will not set our error code
  142. //
  143. static BOOL MCIWndDevCaps(PMCIWND p, DWORD item)
  144. {
  145. MCI_GETDEVCAPS_PARMS mciDevCaps;
  146. DWORD dw;
  147. if (p->wDeviceID == NULL)
  148. return FALSE;
  149. mciDevCaps.dwItem = (DWORD)item;
  150. dw = mciSendCommand(p->wDeviceID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM,
  151. (DWORD)(LPVOID)&mciDevCaps);
  152. if (dw == 0)
  153. return (BOOL)mciDevCaps.dwReturn;
  154. else
  155. return FALSE;
  156. }
  157. //
  158. // Send an MCI Status command.
  159. // This will not set our error code
  160. //
  161. static DWORD MCIWndStatus(PMCIWND p, DWORD item, DWORD err)
  162. {
  163. MCI_STATUS_PARMS mciStatus;
  164. DWORD dw;
  165. if (p->wDeviceID == NULL)
  166. return err;
  167. mciStatus.dwItem = (DWORD)item;
  168. dw = mciSendCommand(p->wDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  169. (DWORD)(LPVOID)&mciStatus);
  170. if (dw == 0)
  171. return mciStatus.dwReturn;
  172. else
  173. return err;
  174. }
  175. //
  176. // Send an MCI String command
  177. // Optionally set our error code. Never clears it.
  178. //
  179. static DWORD MCIWndString(PMCIWND p, BOOL fSetErr, LPSTR sz, ...)
  180. {
  181. char ach[256];
  182. int i;
  183. DWORD dw;
  184. if (p->wDeviceID == NULL)
  185. return 0;
  186. for (i=0; *sz && *sz != ' '; )
  187. ach[i++] = *sz++;
  188. i += wsprintf(&ach[i], " %d ", (UINT)p->alias);
  189. i += wvsprintf(&ach[i], sz, &sz + 1); //!!! use varargs
  190. dw = mciSendString(ach, NULL, 0, NULL);
  191. DPF("MCIWndString('%s'): %ld",(LPSTR)ach, dw);
  192. if (fSetErr)
  193. MCIWndiHandleError(p, dw);
  194. return dw;
  195. }
  196. static long atol(LPSTR sz)
  197. {
  198. long l;
  199. //!!! check for (-) sign?
  200. for (l=0; *sz >= '0' && *sz <= '9'; sz++)
  201. l = l*10 + (*sz - '0');
  202. return l;
  203. }
  204. #define SLASH(c) ((c) == '/' || (c) == '\\')
  205. /*--------------------------------------------------------------+
  206. | FileName - return a pointer to the filename part of szPath |
  207. | with no preceding path. |
  208. +--------------------------------------------------------------*/
  209. LPSTR FAR FileName(LPSTR szPath)
  210. {
  211. LPCSTR sz;
  212. sz = &szPath[lstrlen(szPath)];
  213. for (; sz>szPath && !SLASH(*sz) && *sz!=':';)
  214. sz = AnsiPrev(szPath, sz);
  215. return (sz>szPath ? (LPSTR)++sz : (LPSTR)sz);
  216. }
  217. //
  218. // Sends an MCI String command and converts the return string to an integer
  219. // Optionally sets our error code. Never clears it.
  220. //
  221. static DWORD MCIWndGetValue(PMCIWND p, BOOL fSetErr, LPSTR sz, DWORD err, ...)
  222. {
  223. char achRet[20];
  224. char ach[256];
  225. DWORD dw;
  226. int i;
  227. for (i=0; *sz && *sz != ' '; )
  228. ach[i++] = *sz++;
  229. if (p->wDeviceID)
  230. i += wsprintf(&ach[i], " %d ", (UINT)p->alias);
  231. i += wvsprintf(&ach[i], sz, &err + 1); //!!!use varargs
  232. dw = mciSendString(ach, achRet, sizeof(achRet), NULL);
  233. DPF("MCIWndGetValue('%s'): %ld",(LPSTR)ach, dw);
  234. if (fSetErr)
  235. MCIWndiHandleError(p, dw);
  236. if (dw == 0) {
  237. DPF("GetValue('%s'): %ld",(LPSTR)ach, atol(achRet));
  238. return atol(achRet);
  239. } else {
  240. DPF("MCIGetValue('%s'): error=%ld",(LPSTR)ach, dw);
  241. return err;
  242. }
  243. }
  244. //
  245. // Send an MCI command and get the return string back
  246. // This never sets our error code.
  247. //
  248. // Note: szRet can be the same string as sz
  249. //
  250. static DWORD MCIWndGet(PMCIWND p, LPSTR sz, LPSTR szRet, int len, ...)
  251. {
  252. char ach[256];
  253. int i;
  254. DWORD dw;
  255. if (!p->wDeviceID) {
  256. szRet[0] = 0;
  257. return 0L;
  258. }
  259. for (i=0; *sz && *sz != ' '; )
  260. ach[i++] = *sz++;
  261. i += wsprintf(&ach[i], " %d ", (UINT)p->alias);
  262. i += wvsprintf(&ach[i], sz, &len + 1); //!!!use varargs
  263. // initialize to NULL return string
  264. szRet[0] = 0;
  265. dw = mciSendString(ach, szRet, len, p->hwnd);
  266. DPF("MCIWndGet('%s'): '%s'",(LPSTR)ach, (LPSTR)szRet);
  267. return dw;
  268. }
  269. //
  270. // Gets the source or destination rect from the MCI device
  271. // Does NOT set our error code since this is an internal function
  272. //
  273. static void MCIWndRect(PMCIWND p, LPRECT prc, BOOL fSource)
  274. {
  275. MCI_DGV_RECT_PARMS mciRect;
  276. DWORD dw=0;
  277. SetRectEmpty(prc);
  278. if (p->wDeviceID)
  279. dw = mciSendCommand(p->wDeviceID, MCI_WHERE,
  280. (DWORD)fSource ? MCI_DGV_WHERE_SOURCE : MCI_DGV_WHERE_DESTINATION,
  281. (DWORD)(LPVOID)&mciRect);
  282. if (dw == 0)
  283. *prc = mciRect.rc;
  284. prc->right += prc->left;
  285. prc->bottom += prc->top;
  286. }
  287. static VOID MCIWndiSizePlaybar(PMCIWND p)
  288. {
  289. RECT rc;
  290. WORD w, h;
  291. // No playbar!!
  292. if (p->dwStyle & MCIWNDF_NOPLAYBAR)
  293. return;
  294. #define SLOP 7 // Left outdent of toolbar
  295. // How big a window are we putting a toolbar on?
  296. GetClientRect(p->hwnd, &rc);
  297. w = rc.right;
  298. h = rc.bottom;
  299. // Trackbar is a child of Toolbar
  300. SetWindowPos(p->hwndToolbar, NULL,
  301. -SLOP, h - TB_HEIGHT, w + SLOP, TB_HEIGHT,
  302. SWP_NOZORDER);
  303. // Make sure it's visible now
  304. ShowWindow(p->hwndToolbar, SW_SHOW);
  305. // Figure out where the toolbar ends and the trackbar begins
  306. SendMessage(p->hwndToolbar, TB_GETITEMRECT,
  307. (int)SendMessage(p->hwndToolbar, TB_COMMANDTOINDEX,
  308. TOOLBAR_END, 0),
  309. (LPARAM)(LPVOID)&rc);
  310. // Place the trackbar next to the end of the toolbar
  311. SetWindowPos(p->hwndTrackbar, NULL,
  312. rc.right, 3, w - rc.right + 5, TB_HEIGHT, // !!!
  313. SWP_NOZORDER);
  314. //!!! Maybe put menu button on right side of trackbar? So
  315. //!!! make sep the right size (size of the track bar!)
  316. }
  317. // Resize the window by the given percentage
  318. // 0 means use DESTINATION rect and size it automatically
  319. static VOID MCIWndiSize(PMCIWND p, int iSize)
  320. {
  321. RECT rc, rcT;
  322. int dx, dy;
  323. // If we're given a percentage, we take it from the SOURCE size.
  324. // For default, (zero), we use the destination size
  325. if (iSize)
  326. rc = p->rcNormal; /* get the original "normal size" rect */
  327. else {
  328. if (p->wDeviceID)
  329. MCIWndRect(p, &rc, FALSE);/* get the current (destination) size */
  330. else
  331. SetRect(&rc, 0, 0, 0, 0);
  332. iSize = 100;
  333. }
  334. rc.bottom = MulDiv(rc.bottom, iSize, 100);
  335. rc.right = MulDiv(rc.right, iSize, 100);
  336. // Now set the movie to play in the new rect
  337. if (!IsRectEmpty(&rc))
  338. MCIWndString(p, FALSE, szPutDest,
  339. 0, 0, rc.right - rc.left, rc.bottom - rc.top);
  340. // If we're not supposed to resize our window to this new rect, at least
  341. // we'll fix up the toolbar before we leave (the buttons may have changed)
  342. if (p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW) {
  343. MCIWndiSizePlaybar(p);
  344. return;
  345. }
  346. // We're not a windowed device, or we're closed - don't touch our width
  347. if (IsRectEmpty(&rc)) {
  348. GetClientRect(p->hwnd, &rcT);
  349. rc.right = rcT.right;
  350. }
  351. // If we will have a playbar, grow the window by its height
  352. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR))
  353. rc.bottom += TB_HEIGHT;
  354. // Now get the size for our window by growing it by its non-client size
  355. AdjustWindowRect(&rc, GetWindowLong(p->hwnd, GWL_STYLE), FALSE);
  356. // Now we have the new size for our MCIWND. If it's not changing size,
  357. // the SetWindowPos will not generate a WM_SIZE and it won't call our
  358. // SizePlaybar to fix the toolbar. So we better call it ourselves.
  359. // Sometimes we're off by one pixel and it STILL won't generate a WM_SIZE.
  360. GetWindowRect(p->hwnd, &rcT);
  361. dx = ABS((rcT.right - rcT.left) - (rc.right - rc.left));
  362. dy = ABS((rcT.bottom - rcT.top) - (rc.bottom - rc.top));
  363. if (dx < 2 && dy < 2)
  364. MCIWndiSizePlaybar(p);
  365. SetWindowPos(p->hwnd, NULL, 0, 0, rc.right - rc.left,
  366. rc.bottom - rc.top,
  367. SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
  368. // We need to notify the "owner" that our size changed
  369. if (p->dwStyle & MCIWNDF_NOTIFYSIZE)
  370. NotifyOwner(p, MCIWNDM_NOTIFYSIZE, p->hwnd, NULL);
  371. }
  372. //
  373. // Figure out the position in ms of the beginning of the track we're on
  374. //
  375. static DWORD MCIWndiPrevTrack(PMCIWND p)
  376. {
  377. DWORD dw;
  378. int iTrack;
  379. if (!p->fHasTracks)
  380. return 0;
  381. MCIWndString(p, FALSE, szSetFormatTMSF);
  382. dw = MCIWndStatus(p, MCI_STATUS_POSITION, 0); // return value is 0xFFSSMMTT
  383. iTrack = LOWORD(dw) & 0xFF;
  384. // If we're less than 1 second into the track, choose the previous track
  385. if ((iTrack > p->iFirstTrack) && (!(LOWORD(dw) & 0xFF00)) &&
  386. ((HIWORD(dw) & 0xFF) == 0))
  387. iTrack--;
  388. dw = p->pTrackStart[iTrack - p->iFirstTrack];
  389. MCIWndString(p, FALSE, szSetFormatMS);
  390. return dw;
  391. }
  392. //
  393. // Figure out the position in ms of the beginning of the next track
  394. //
  395. static DWORD MCIWndiNextTrack(PMCIWND p)
  396. {
  397. DWORD dw;
  398. int iTrack;
  399. if (!p->fHasTracks)
  400. return 0;
  401. MCIWndString(p, FALSE, szSetFormatTMSF);
  402. dw = MCIWndStatus(p, MCI_STATUS_POSITION, 0); // return value is 0xTTMMSSFF
  403. iTrack = (LOWORD(dw) & 0xFF) + 1;
  404. if (iTrack >= p->iNumTracks + p->iFirstTrack)
  405. iTrack--;
  406. dw = p->pTrackStart[iTrack - p->iFirstTrack];
  407. MCIWndString(p, FALSE, szSetFormatMS);
  408. return dw;
  409. }
  410. //
  411. // Figure out where the tracks begin for making tics
  412. //
  413. static void MCIWndiCalcTracks(PMCIWND p)
  414. {
  415. int i;
  416. if (!p->fHasTracks)
  417. return;
  418. p->iNumTracks = (int)MCIWndGetValue(p, FALSE, szStatusNumTracks, 0);
  419. p->iFirstTrack = MCIWndGetValue(p, FALSE, szStatusPosTrack, 0, 0) == 0
  420. ? 1 : 0;
  421. if (p->pTrackStart)
  422. LocalFree((HANDLE)p->pTrackStart);
  423. if (p->iNumTracks) {
  424. p->pTrackStart = (LONG *)LocalAlloc(LPTR,
  425. p->iNumTracks * sizeof(LONG));
  426. if (p->pTrackStart == NULL) {
  427. p->iNumTracks = 0;
  428. p->fHasTracks = FALSE;
  429. }
  430. for (i = 0; i < p->iNumTracks; i++) {
  431. p->pTrackStart[i] =
  432. MCIWndGetValue(p, FALSE, szStatusPosTrack, 0,
  433. p->iFirstTrack + i);
  434. }
  435. }
  436. }
  437. //
  438. // Mark tics on the trackbar for the beginning of tracks
  439. //
  440. static void MCIWndiMarkTics(PMCIWND p)
  441. {
  442. int i;
  443. if (!p->fHasTracks)
  444. return;
  445. SendMessage(p->hwndTrackbar, TBM_SETTIC, 0, p->dwMediaStart);
  446. for (i = 0; i < p->iNumTracks; i++) {
  447. SendMessage(p->hwndTrackbar, TBM_SETTIC, 0, p->pTrackStart[i]);
  448. }
  449. SendMessage(p->hwndTrackbar, TBM_SETTIC,0, p->dwMediaStart + p->dwMediaLen);
  450. }
  451. static VOID MCIWndiValidateMedia(PMCIWND p)
  452. {
  453. DWORD dw;
  454. if (!p->wDeviceID) {
  455. p->fMediaValid = FALSE;
  456. return;
  457. }
  458. dw = p->dwMediaLen;
  459. p->fMediaValid = TRUE;
  460. p->dwMediaStart = MCIWndGetStart(p->hwnd);
  461. p->dwMediaLen = MCIWndGetLength(p->hwnd);
  462. // !!! do something special if len=0?
  463. // We have a playbar, so set the ranges of the trackbar if we've changed
  464. if (dw != p->dwMediaLen && !(p->dwStyle & MCIWNDF_NOPLAYBAR)) {
  465. // must set position first or zero length range won't move thumb
  466. SendMessage(p->hwndTrackbar, TBM_CLEARTICS, TRUE, 0);
  467. SendMessage(p->hwndTrackbar, TBM_SETPOS, TRUE, p->dwMediaStart);
  468. SendMessage(p->hwndTrackbar, TBM_SETRANGEMIN, 0, p->dwMediaStart);
  469. SendMessage(p->hwndTrackbar, TBM_SETRANGEMAX, 0,
  470. p->dwMediaStart + p->dwMediaLen);
  471. MCIWndiCalcTracks(p);
  472. MCIWndiMarkTics(p);
  473. }
  474. }
  475. //
  476. // Create the filter for the open dialog. Caution: Don't overflow pchD !!!
  477. //
  478. static void MCIWndiBuildMeAFilter(LPSTR pchD)
  479. {
  480. LPSTR pchS;
  481. char ach[128];
  482. // Our filter will look like: "MCI Files\0*.avi;*.wav\0All Files\0*.*\0"
  483. // The actual extensions for the MCI files will come from the list in
  484. // the "mci extensions" section of win.ini
  485. lstrcpy(pchD, LoadSz(IDS_MCIFILES));
  486. // Creates a list like: "avi\0wav\0mid\0"
  487. GetProfileString(szMCIExtensions, NULL, szNULL, ach, sizeof(ach));
  488. for (pchD += lstrlen(pchD)+1, pchS = ach; *pchS;
  489. pchD += lstrlen(pchS)+3, pchS += lstrlen(pchS)+1) {
  490. lstrcpy(pchD, "*.");
  491. lstrcpy(pchD + 2, pchS);
  492. lstrcpy(pchD + 2 + lstrlen(pchS), ";");
  493. }
  494. if (pchS != ach)
  495. --pchD; // erase the last ;
  496. *pchD = '\0';
  497. lstrcpy(++pchD, LoadSz(IDS_ALLFILES));
  498. pchD += lstrlen(pchD) + 1;
  499. lstrcpy(pchD, "*.*\0");
  500. }
  501. //
  502. // Create the playbar windows we'll need later
  503. //
  504. static void MCIWndiMakeMeAPlaybar(PMCIWND p)
  505. {
  506. TBBUTTON tb[7];
  507. extern char aszTrackbarClassName[];
  508. // They don't want a playbar
  509. if (p->dwStyle & MCIWNDF_NOPLAYBAR)
  510. return;
  511. tb[0].iBitmap = 0;
  512. tb[0].idCommand = MCI_PLAY;
  513. tb[0].fsState = TBSTATE_ENABLED | TBSTATE_HIDDEN;
  514. tb[0].fsStyle = TBSTYLE_BUTTON;
  515. tb[0].iString = -1;
  516. tb[1].iBitmap = 2;
  517. tb[1].idCommand = MCI_STOP;
  518. tb[1].fsState = TBSTATE_ENABLED | TBSTATE_HIDDEN;
  519. tb[1].fsStyle = TBSTYLE_BUTTON;
  520. tb[1].iString = -1;
  521. tb[2].iBitmap = 4;
  522. tb[2].idCommand = MCI_RECORD;
  523. tb[2].fsState = TBSTATE_ENABLED | TBSTATE_HIDDEN;
  524. tb[2].fsStyle = TBSTYLE_BUTTON;
  525. tb[2].iString = -1;
  526. tb[3].iBitmap = 5;
  527. tb[3].idCommand = IDM_MCIEJECT;
  528. tb[3].fsState = TBSTATE_ENABLED | TBSTATE_HIDDEN;
  529. tb[3].fsStyle = TBSTYLE_BUTTON;
  530. tb[3].iString = -1;
  531. #define MENUSEP 2
  532. tb[4].iBitmap = MENUSEP;
  533. tb[4].idCommand = -1;
  534. tb[4].fsState = 0;
  535. tb[4].fsStyle = TBSTYLE_SEP;
  536. tb[4].iString = -1;
  537. tb[5].iBitmap = 3;
  538. tb[5].idCommand = IDM_MENU;
  539. tb[5].fsState = TBSTATE_ENABLED;
  540. tb[5].fsStyle = TBSTYLE_BUTTON;
  541. tb[5].iString = -1;
  542. tb[6].iBitmap = 4;
  543. tb[6].idCommand = TOOLBAR_END;
  544. tb[6].fsState = 0;
  545. tb[6].fsStyle = TBSTYLE_SEP;
  546. tb[6].iString = -1;
  547. // Create invisible for now so it doesn't flash
  548. p->hwndToolbar = CreateToolbarEx(p->hwnd,
  549. WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  550. CCS_NOPARENTALIGN | CCS_NORESIZE,
  551. ID_TOOLBAR, 7, GetWindowInstance(p->hwnd),
  552. IDBMP_TOOLBAR, (LPTBBUTTON)&tb[0], 7,
  553. 13, 13, 13, 13, sizeof(TBBUTTON)); // buttons are 13x13
  554. p->hwndTrackbar =
  555. #ifdef BIDI
  556. CreateWindowEx(WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON,
  557. #else
  558. CreateWindow (
  559. #endif
  560. aszTrackbarClassName, NULL,
  561. WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  562. 0, 0, 0, 0, p->hwndToolbar, NULL, GetWindowInstance(p->hwnd), NULL);
  563. // Force ValidateMedia to actually update
  564. p->dwMediaStart = p->dwMediaLen = 0;
  565. // Set the proper range for the scrollbar
  566. MCIWndiValidateMedia(p);
  567. }
  568. //
  569. // Gray/ungray toolbar buttons as necessary
  570. //
  571. static void MCIWndiPlaybarGraying(PMCIWND p)
  572. {
  573. DWORD dwMode;
  574. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR)) {
  575. dwMode = MCIWndGetMode(p->hwnd, NULL, 0);
  576. if (dwMode == MCI_MODE_PLAY) {
  577. // Hide PLAY Show STOP
  578. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  579. MCI_PLAY, TRUE);
  580. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  581. MCI_STOP, FALSE);
  582. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  583. MCI_STOP, TRUE);
  584. if (p->fCanRecord)
  585. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  586. MCI_RECORD, FALSE); // !!! can't record ???
  587. if (p->fCanEject)
  588. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  589. IDM_MCIEJECT, TRUE);
  590. // Treat PAUSE mode like STOP mode
  591. } else if (dwMode == MCI_MODE_PAUSE ||
  592. dwMode == MCI_MODE_STOP) {
  593. // Hide STOP Show PLAY
  594. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  595. MCI_STOP, TRUE);
  596. if (p->fCanPlay) {
  597. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  598. MCI_PLAY, FALSE);
  599. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  600. MCI_PLAY, TRUE);
  601. }
  602. if (p->fCanRecord)
  603. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  604. MCI_RECORD, TRUE);
  605. if (p->fCanEject)
  606. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  607. IDM_MCIEJECT, TRUE);
  608. } else if (dwMode == MCI_MODE_RECORD) {
  609. // Hide PLAY Show STOP
  610. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  611. MCI_PLAY, TRUE);
  612. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  613. MCI_STOP, FALSE);
  614. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  615. MCI_STOP, TRUE);
  616. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  617. MCI_RECORD, FALSE);
  618. if (p->fCanEject)
  619. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  620. IDM_MCIEJECT, TRUE); // !!! safe ???
  621. // recording can change the length
  622. p->fMediaValid = FALSE;
  623. } else if (dwMode == MCI_MODE_SEEK) {
  624. // Hide PLAY Show STOP
  625. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  626. MCI_PLAY, TRUE);
  627. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  628. MCI_STOP, FALSE);
  629. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  630. MCI_STOP, TRUE);
  631. if (p->fCanRecord)
  632. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  633. MCI_RECORD, FALSE);
  634. if (p->fCanEject)
  635. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  636. IDM_MCIEJECT, FALSE);
  637. } else {
  638. // OPEN, NOT_READY, etc. etc.
  639. // Disable everything
  640. if (p->fCanPlay) {
  641. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  642. MCI_PLAY, FALSE);
  643. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  644. MCI_PLAY, FALSE);
  645. }
  646. SendMessage(p->hwndToolbar, TB_HIDEBUTTON,
  647. MCI_STOP, TRUE);
  648. if (p->fCanRecord)
  649. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  650. MCI_RECORD, FALSE);
  651. if (p->fCanEject)
  652. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON,
  653. IDM_MCIEJECT, FALSE);
  654. // Clear all tics
  655. SendMessage(p->hwndTrackbar, TBM_CLEARTICS,1,0);
  656. // Clean out the trackbar
  657. // Make a note to re-query start, length later
  658. SendMessage(p->hwndTrackbar, TBM_SETPOS,
  659. TRUE, 0); // set b4 range
  660. SendMessage(p->hwndTrackbar, TBM_SETRANGE,
  661. 0, 0);
  662. p->fMediaValid = FALSE;
  663. }
  664. }
  665. }
  666. //
  667. // Set up the toolbar to have the right buttons
  668. //
  669. static void MCIWndiFixMyPlaybar(PMCIWND p)
  670. {
  671. if (p->dwStyle & MCIWNDF_NOPLAYBAR)
  672. return;
  673. if (!p->wDeviceID) {
  674. //
  675. // gray the toolbar, go to some default buttons, and set zero len track
  676. //
  677. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR)) {
  678. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, MCI_PLAY, FALSE);
  679. SendMessage(p->hwndToolbar, TB_ENABLEBUTTON, MCI_PLAY, FALSE);
  680. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, MCI_STOP, TRUE );
  681. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, MCI_RECORD, TRUE );
  682. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, IDM_MCIEJECT,TRUE );
  683. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, IDM_MENU,
  684. p->dwStyle & MCIWNDF_NOMENU);
  685. SendMessage(p->hwndTrackbar, TBM_SETPOS, TRUE, 0); // set b4 range
  686. SendMessage(p->hwndTrackbar, TBM_SETRANGE, 0, 0);
  687. }
  688. }
  689. if (p->wDeviceID) {
  690. //
  691. // Use the appropriate buttons
  692. //
  693. if (p->fCanPlay)
  694. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, MCI_PLAY, FALSE);
  695. else
  696. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, MCI_PLAY, TRUE);
  697. if (p->fCanRecord && (p->dwStyle & MCIWNDF_RECORD))
  698. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, MCI_RECORD, FALSE);
  699. else
  700. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, MCI_RECORD, TRUE);
  701. if (p->fCanEject)
  702. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, IDM_MCIEJECT, FALSE);
  703. else
  704. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, IDM_MCIEJECT, TRUE);
  705. SendMessage(p->hwndToolbar, TB_HIDEBUTTON, IDM_MENU,
  706. p->dwStyle & MCIWNDF_NOMENU);
  707. // COMMCTRL toolbar bug ... re-arranging buttons screws up the state
  708. // of the existing buttons, so we better re-gray things
  709. MCIWndiPlaybarGraying(p);
  710. }
  711. }
  712. //
  713. // Make an appropriate menu
  714. //
  715. static void MCIWndiMakeMeAMenu(PMCIWND p)
  716. {
  717. HMENU hmenu, hmenuWindow = NULL, hmenuVolume = NULL, hmenuSpeed = NULL;
  718. int i;
  719. WORD j;
  720. //
  721. // Create the floating popup menu BY HAND since we have no resource file
  722. //
  723. // Destroy the old menu
  724. if (p->hmenu) {
  725. DestroyMenu(p->hmenu);
  726. FreeDitherBrush();
  727. }
  728. p->hmenu = NULL;
  729. // We don't want a menu!
  730. if (p->dwStyle & MCIWNDF_NOMENU)
  731. return;
  732. //
  733. // If we don't want an open command, and nothing's open, don't make
  734. // a menu.
  735. //
  736. if (!p->wDeviceID && (p->dwStyle & MCIWNDF_NOOPEN))
  737. return;
  738. //
  739. // Create the WINDOW sub-popup
  740. // !!! Do we want to have this menu if an AUTOSIZE flag is off?
  741. //
  742. if (p->wDeviceID && p->fCanWindow) {
  743. hmenuWindow = CreatePopupMenu();
  744. if (hmenuWindow) {
  745. AppendMenu(hmenuWindow, MF_ENABLED, IDM_MCIZOOM+50,
  746. LoadSz(IDS_HALFSIZE));
  747. AppendMenu(hmenuWindow, MF_ENABLED, IDM_MCIZOOM+100,
  748. LoadSz(IDS_NORMALSIZE));
  749. AppendMenu(hmenuWindow, MF_ENABLED, IDM_MCIZOOM+200,
  750. LoadSz(IDS_DOUBLESIZE));
  751. }
  752. }
  753. //
  754. // Create the VOLUME sub-popup
  755. //
  756. if (p->wDeviceID && p->fVolume) {
  757. hmenuVolume = CreatePopupMenu();
  758. if (hmenuVolume) {
  759. // !!! Hack from Hell
  760. // Put a bogus menu item at the top. When WINDOWS tries to select
  761. // it after we bring up the menu, we won't let it. We want the
  762. // thumb to stay on the current value.
  763. AppendMenu(hmenuVolume, MF_ENABLED | MF_OWNERDRAW,
  764. IDM_MCIVOLUME + VOLUME_MAX + 1, NULL);
  765. // Create all the Real menu items. Make the menu VOLUME_MAX items
  766. // tall even though the number of unique entries may be less
  767. for (i=IDM_MCIVOLUME + p->wMaxVol; i>=IDM_MCIVOLUME; i-=5)
  768. for (j=0; j < VOLUME_MAX / p->wMaxVol; j++)
  769. AppendMenu(hmenuVolume, MF_ENABLED | MF_OWNERDRAW, i, NULL);
  770. // Now put a filler item at the bottom so every REAL item falls
  771. // inside the channel and there's a unique thumb position for each
  772. // item.
  773. AppendMenu(hmenuVolume, MF_ENABLED | MF_OWNERDRAW,
  774. IDM_MCIVOLUME + VOLUME_MAX + 2, NULL);
  775. // Now CHECK the current volume so the thumb can draw there
  776. // round to nearest 5 so it matches a menu item identifier
  777. i = ((int)MCIWndGetValue(p, FALSE, szStatusVolume, 1000) / 50) * 5;
  778. CheckMenuItem(hmenuVolume, IDM_MCIVOLUME + i, MF_CHECKED);
  779. }
  780. }
  781. //
  782. // Create the SPEED sub-popup
  783. //
  784. if (p->wDeviceID && p->fSpeed) {
  785. hmenuSpeed = CreatePopupMenu();
  786. if (hmenuSpeed) {
  787. // !!! Hack from Hell
  788. // Put a bogus menu item at the top. When WINDOWS tries to select
  789. // it after we bring up the menu, we won't let it. We want the
  790. // thumb to stay on the current value.
  791. AppendMenu(hmenuSpeed, MF_ENABLED | MF_OWNERDRAW,
  792. IDM_MCISPEED + SPEED_MAX + 1, NULL);
  793. // Create all the Real menu items
  794. for (i=IDM_MCISPEED + SPEED_MAX; i>=IDM_MCISPEED; i-=5)
  795. AppendMenu(hmenuSpeed, MF_ENABLED | MF_OWNERDRAW, i, NULL);
  796. // Now put a filler item at the bottom so every REAL item falls
  797. // inside the channel and there's a unique thumb position for each
  798. // item.
  799. AppendMenu(hmenuSpeed, MF_ENABLED | MF_OWNERDRAW,
  800. IDM_MCISPEED + SPEED_MAX + 2, NULL);
  801. // Now CHECK the current speed so the thumb can draw there
  802. // round to nearest 5 so it matches a menu item identifier
  803. i = ((int)MCIWndGetValue(p, FALSE, szStatusSpeed, 1000) / 50) * 5;
  804. CheckMenuItem(hmenuSpeed, IDM_MCISPEED + i, MF_CHECKED);
  805. }
  806. }
  807. hmenu = CreatePopupMenu();
  808. if (hmenu) {
  809. if (p->wDeviceID && p->dwStyle & MCIWNDF_NOPLAYBAR) {
  810. if (p->fCanPlay) {
  811. AppendMenu(hmenu, MF_ENABLED, MCI_PLAY, LoadSz(IDS_PLAY));
  812. AppendMenu(hmenu, MF_ENABLED, MCI_STOP, LoadSz(IDS_STOP));
  813. }
  814. if (p->fCanRecord && (p->dwStyle & MCIWNDF_RECORD))
  815. AppendMenu(hmenu, MF_ENABLED, MCI_RECORD, LoadSz(IDS_RECORD));
  816. if (p->fCanEject)
  817. AppendMenu(hmenu, MF_ENABLED, IDM_MCIEJECT, LoadSz(IDS_EJECT));
  818. if (p->fCanPlay ||
  819. (p->fCanRecord && (p->dwStyle & MCIWNDF_RECORD)) ||
  820. p->fCanEject)
  821. AppendMenu(hmenu, MF_SEPARATOR, NULL, NULL);
  822. }
  823. if (hmenuWindow)
  824. AppendMenu(hmenu, MF_ENABLED|MF_POPUP, (UINT)hmenuWindow,
  825. LoadSz(IDS_VIEW));
  826. if (hmenuVolume)
  827. AppendMenu(hmenu, MF_ENABLED|MF_POPUP, (UINT)hmenuVolume,
  828. LoadSz(IDS_VOLUME));
  829. if (hmenuSpeed)
  830. AppendMenu(hmenu, MF_ENABLED|MF_POPUP, (UINT)hmenuSpeed,
  831. LoadSz(IDS_SPEED));
  832. if (hmenuWindow || hmenuVolume || hmenuSpeed)
  833. AppendMenu(hmenu, MF_SEPARATOR, NULL, NULL);
  834. if (p->wDeviceID && p->fCanRecord && (p->dwStyle & MCIWNDF_RECORD))
  835. AppendMenu(hmenu, MF_ENABLED, IDM_MCINEW, LoadSz(IDS_NEW));
  836. if (!(p->dwStyle & MCIWNDF_NOOPEN))
  837. AppendMenu(hmenu, MF_ENABLED, IDM_MCIOPEN, LoadSz(IDS_OPEN));
  838. if (p->wDeviceID && p->fCanSave && (p->dwStyle & MCIWNDF_RECORD))
  839. AppendMenu(hmenu, MF_ENABLED, MCI_SAVE, LoadSz(IDS_SAVE));
  840. if (p->wDeviceID) {
  841. if (!(p->dwStyle & MCIWNDF_NOOPEN)) {
  842. AppendMenu(hmenu, MF_ENABLED, IDM_MCICLOSE, LoadSz(IDS_CLOSE));
  843. AppendMenu(hmenu, MF_SEPARATOR, NULL, NULL);
  844. }
  845. AppendMenu(hmenu, MF_ENABLED, IDM_COPY, LoadSz(IDS_COPY));
  846. if (p->fCanConfig)
  847. AppendMenu(hmenu, MF_ENABLED, IDM_MCICONFIG,
  848. LoadSz(IDS_CONFIGURE));
  849. // !!! Should we only show this in debug, or if a flag is set?
  850. AppendMenu(hmenu, MF_ENABLED, IDM_MCICOMMAND, LoadSz(IDS_COMMAND));
  851. }
  852. p->hmenu = hmenu;
  853. p->hmenuVolume = hmenuVolume;
  854. p->hmenuSpeed = hmenuSpeed;
  855. CreateDitherBrush(FALSE); // we'll need this to paint OwnerDraw
  856. }
  857. }
  858. //
  859. // Set up everything for an empty window
  860. //
  861. static LONG MCIWndiClose(PMCIWND p, BOOL fRedraw)
  862. {
  863. MCI_GENERIC_PARMS mciGeneric;
  864. // Oh no! The MCI device (probably MMP) has hooked our window proc and if
  865. // we close the device, it will go away, and the hook will DIE! We need to
  866. // do everything BUT the closing of the device. We'll delay that.
  867. if (GetWindowLong(p->hwnd, GWL_WNDPROC) != (LONG)MCIWndProc &&
  868. p->wDeviceID && p->fCanWindow) {
  869. MCIWndString(p, FALSE, szWindowHandle, NULL); // GO AWAY, DEVICE!
  870. PostMessage(p->hwnd, MCI_CLOSE, 0, p->wDeviceID);
  871. } else if (p->wDeviceID)
  872. // buggy drivers crash if we pass a null parms address
  873. mciSendCommand(p->wDeviceID, MCI_CLOSE, 0, (DWORD)(LPVOID)&mciGeneric);
  874. //
  875. // if the device had a palette, we need to send palette changes to
  876. // every window because we just deleted the palette that was realized.
  877. //
  878. if (p->fHasPalette) {
  879. // If we're dying this won't go through unless we SEND
  880. SendMessage(p->hwnd, MCIWNDM_PALETTEKICK, 0, 0);
  881. }
  882. // execute this function even if there's no deviceID since we may want
  883. // to gray things
  884. // The next timer will kill itself since wDeviceID is NULL
  885. p->wDeviceID = 0;
  886. p->achFileName[0] = 0; // kill the filename
  887. p->dwMediaLen = 0; // so next open will invalidate media
  888. // We don't want to redraw cuz we're opening a new file right away
  889. if (!fRedraw)
  890. return 0;
  891. // One of the show bits is on... clear the caption
  892. if (p->dwStyle & MCIWNDF_SHOWALL)
  893. SetWindowText(p->hwnd, LoadSz(IDS_NODEVICE));
  894. // Gray all the stuff on the playbar
  895. MCIWndiFixMyPlaybar(p);
  896. // Make an appropriate menu for our null device
  897. MCIWndiMakeMeAMenu(p);
  898. // Possibly snap ourselves to a small size since there's no device loaded
  899. // Also reposition the toolbar after it's been fixed up
  900. MCIWndiSize(p, 0);
  901. // We need to notify our "owner" that we've closed
  902. if (p->dwStyle & MCIWNDF_NOTIFYMEDIA)
  903. NotifyOwner(p, MCIWNDM_NOTIFYMEDIA, p->hwnd, (LPARAM)(LPVOID)szNULL);
  904. InvalidateRect(p->hwnd, NULL, TRUE);
  905. return 0;
  906. }
  907. //
  908. // This is the WM_CREATE msg of our WndProc
  909. //
  910. static BOOL MCIWndiCreate(HWND hwnd, LONG lParam)
  911. {
  912. PMCIWND p;
  913. DWORD dw;
  914. char ach[20];
  915. HWND hwndP;
  916. p = (PMCIWND)LocalAlloc(LPTR, sizeof(MCIWND));
  917. if (!p)
  918. return FALSE;
  919. SetWindowLong(hwnd, 0, (LONG)(UINT)p);
  920. p->hwnd = hwnd;
  921. p->hwndOwner = GetParent(hwnd); // we'll send notifications here
  922. p->alias = (UINT)hwnd;
  923. p->dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  924. DragAcceptFiles(p->hwnd, (p->dwStyle & (MCIWNDF_NOMENU | MCIWNDF_NOOPEN)) == 0);
  925. if (!(p->dwStyle & WS_CAPTION))
  926. p->dwStyle &= ~MCIWNDF_SHOWALL;
  927. dw = (DWORD)((LPCREATESTRUCT)lParam)->lpCreateParams;
  928. //
  929. // see if we are in a MDIClient
  930. //
  931. if ((p->dwStyle & WS_CHILD) && (hwndP = GetParent(hwnd))) {
  932. GetClassName(hwndP, ach, sizeof(ach));
  933. p->fMdiWindow = lstrcmpi(ach, szMDIClient) == 0;
  934. if (p->fMdiWindow)
  935. dw = ((LPMDICREATESTRUCT)dw)->lParam;
  936. }
  937. MCIWndiMakeMeAPlaybar(p);
  938. // if (szOpenFilter[0] == 0)
  939. // MCIWndiBuildMeAFilter(szOpenFilter);
  940. // Set the default timer frequencies
  941. p->iActiveTimerRate = ACTIVE_TIMER;
  942. p->iInactiveTimerRate = INACTIVE_TIMER;
  943. // initialize the OFN structure we'll use to open files
  944. p->achFileName[0] = '\0';
  945. p->ofn.lStructSize = sizeof(OPENFILENAME);
  946. p->ofn.hwndOwner = hwnd;
  947. p->ofn.hInstance = NULL;
  948. // p->ofn.lpstrFilter = szOpenFilter;
  949. p->ofn.lpstrCustomFilter = NULL;
  950. p->ofn.nMaxCustFilter = 0;
  951. p->ofn.nFilterIndex = 0;
  952. ; p->ofn.lpstrFile = p->achFileName;
  953. ; p->ofn.nMaxFile = sizeof(p->achFileName);
  954. p->ofn.lpstrFileTitle = NULL;
  955. p->ofn.nMaxFileTitle = 0;
  956. p->ofn.lpstrInitialDir = NULL;
  957. p->ofn.lpstrTitle = NULL; // "Open Device";
  958. p->ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  959. p->ofn.nFileOffset = 0;
  960. p->ofn.nFileExtension = 0;
  961. p->ofn.lpstrDefExt = NULL;
  962. p->ofn.lCustData = 0;
  963. p->ofn.lpfnHook = NULL;
  964. p->ofn.lpTemplateName = NULL;
  965. p->hicon = LoadIcon(hInst, MAKEINTRESOURCE(MPLAYERICON));
  966. // Gray stuff; disable things that aren't applicable with no device loaded
  967. MCIWndClose(hwnd);
  968. if (dw && *(LPSTR)dw) // treat extra parm as a filename
  969. MCIWndOpen(hwnd, (LPSTR)dw, 0);
  970. return TRUE;
  971. }
  972. //
  973. // Brings up an OpenDialog or a SaveDialog for the application and returns the
  974. // filename. Returns TRUE if a file name was chosen, FALSE on error or CANCEL.
  975. //
  976. static BOOL MCIWndOpenDlg(PMCIWND p, BOOL fSave, LPSTR szFile, int len)
  977. {
  978. BOOL f;
  979. // !!! Maybe this is a device name and our GetOpenFileName will fail.
  980. // !!! Find someway of bringing up an initial filename anyway?
  981. szFile[0] = 0;
  982. p->ofn.lpstrFile = szFile;
  983. p->ofn.nMaxFile = len;
  984. if (fSave)
  985. p->ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  986. else
  987. p->ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  988. //
  989. // use achReturn to hold the MCI Filter.
  990. //
  991. MCIWndiBuildMeAFilter(p->achReturn);
  992. p->ofn.lpstrFilter = p->achReturn;
  993. /* prompt user for file to open or save */
  994. if (fSave)
  995. f = GetSaveFileNamePreview(&(p->ofn));
  996. else
  997. f = GetOpenFileNamePreview(&(p->ofn));
  998. return f;
  999. }
  1000. // Set our timer, if it's needed
  1001. static void MCIWndiSetTimer(PMCIWND p)
  1002. {
  1003. // We need a TIMER to notify the "owner" when things change
  1004. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR) ||
  1005. (p->dwStyle & MCIWNDF_NOTIFYMODE) ||
  1006. (p->dwStyle & MCIWNDF_SHOWMODE) ||
  1007. (p->dwStyle & MCIWNDF_SHOWPOS) ||
  1008. (p->dwStyle & MCIWNDF_NOTIFYPOS)) {
  1009. p->wTimer = SetTimer(p->hwnd, TIMER1,
  1010. p->fActive? p->iActiveTimerRate : p->iInactiveTimerRate,
  1011. NULL);
  1012. }
  1013. }
  1014. //
  1015. // Save a file. Returns 0 for success
  1016. //
  1017. static LONG MCIWndiSave(PMCIWND p, WORD wFlags, LPSTR szFile)
  1018. {
  1019. char ach[128];
  1020. //
  1021. // If we don't have a filename to save, then get one from a dialog
  1022. //
  1023. if (szFile == (LPVOID)-1L) {
  1024. lstrcpy(ach, p->achFileName);
  1025. if (!MCIWndOpenDlg(p, TRUE, ach, sizeof(ach)))
  1026. return -1;
  1027. szFile = ach;
  1028. }
  1029. // !!! All good little boys should be saving to background... don't wait
  1030. return MCIWndString(p, TRUE, szSave, szFile);
  1031. }
  1032. //
  1033. // Actually open a file and set up the window. Returns 0 for success
  1034. //
  1035. static LONG MCIWndiOpen(PMCIWND p, WORD wFlags, LPSTR szFile)
  1036. {
  1037. DWORD dw = 0;
  1038. HCURSOR hcurPrev;
  1039. char ach[128];
  1040. UINT wDeviceID;
  1041. BOOL fNew = wFlags & MCIWNDOPENF_NEW;
  1042. //
  1043. // We're opening an existing file, szFile is that filename
  1044. // If we don't have a filename to open, then get one from a dialog
  1045. //
  1046. if (!fNew && szFile == (LPVOID)-1L) {
  1047. lstrcpy(ach, p->achFileName);
  1048. if (!MCIWndOpenDlg(p, FALSE, ach, sizeof(ach)))
  1049. return -1;
  1050. szFile = ach;
  1051. }
  1052. //
  1053. // We want to open a new file, szFile is the device to open
  1054. // If it's NULL, we use the current device
  1055. //
  1056. if (fNew && (szFile == NULL || *szFile == 0)) {
  1057. // There is no device, so we can't do anything
  1058. if (!p->wDeviceID)
  1059. return 42; // !!! failure
  1060. MCIWndGetDevice(p->hwnd, ach, sizeof(ach));
  1061. szFile = ach;
  1062. }
  1063. // save the current device ID so we can put it back in case open fails.
  1064. wDeviceID = p->wDeviceID;
  1065. KillTimer(p->hwnd, TIMER1); // setting the deviceID to 0 will mess up timer
  1066. p->wDeviceID = 0; // and if open fails, we don't want that
  1067. p->alias++; // use a new alias
  1068. /*
  1069. * Show the hourglass cursor -- who knows how long this stuff
  1070. * will take
  1071. */
  1072. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1073. // Open a NEW file
  1074. if (fNew) {
  1075. dw = MCIWndGetValue(p, TRUE, szNew, 0,
  1076. szFile, (UINT)p->alias);
  1077. // open an existing file
  1078. } else {
  1079. // first, try to open it shareable
  1080. // don't show or update errors since we try to open it twice
  1081. //
  1082. // dont try shareable for "file" devices
  1083. // hack to check for entension.
  1084. //
  1085. if (lstrlen(szFile) > 4 && szFile[lstrlen(szFile)-4] == '.')
  1086. dw = 0;
  1087. else
  1088. dw = MCIWndGetValue(p, FALSE, szOpenShareable, 0,
  1089. (LPSTR)szFile, (UINT)p->alias);
  1090. // Error! Try again, not shareable.
  1091. if (dw == 0) {
  1092. dw = MCIWndGetValue(p, FALSE, szOpen, 0,
  1093. (LPSTR)szFile, (UINT)p->alias);
  1094. // Last ditch attempt! Try AVI. It'll open anything. This time,
  1095. // show, set errors.
  1096. if (dw == 0) {
  1097. dw = MCIWndGetValue(p, TRUE, szOpenAVI, 0,
  1098. (LPSTR)szFile, (UINT)p->alias);
  1099. }
  1100. }
  1101. }
  1102. if (hcurPrev)
  1103. SetCursor(hcurPrev);
  1104. //
  1105. // Ack! No deviceID... we failed to open
  1106. //
  1107. if (dw == 0)
  1108. {
  1109. p->wDeviceID = wDeviceID;
  1110. MCIWndiSetTimer(p); // Put the timer back now that DeviceID is back
  1111. // p->achFileName[0] = 0; // don't hurt the old filename!
  1112. p->alias--; // back to old alias
  1113. // in case error box or open box wiped us out and we didn't paint
  1114. // because our p->wDeviceID was null because of our open hack
  1115. InvalidateRect(p->hwnd, NULL, TRUE);
  1116. return p->dwError;
  1117. }
  1118. //
  1119. // it worked, now close the old device and open the new.
  1120. //
  1121. if (wDeviceID)
  1122. {
  1123. p->wDeviceID = wDeviceID;
  1124. p->alias--; // back to old alias so the close might actually work
  1125. MCIWndiClose(p, FALSE); // don't redraw
  1126. p->alias++; // new alias again (ACK!)
  1127. }
  1128. p->wDeviceID = (UINT)dw;
  1129. p->dwMode = (DWORD)~0L; // first mode set will be detected as a change
  1130. p->dwPos = (DWORD)~0L; // first pos set will be detected as a change
  1131. // Copy the file or device name into our filename spot
  1132. lstrcpy(p->achFileName, szFile);
  1133. // !!! p->wDeviceType = QueryDeviceTypeMCI(p->wDeviceID);
  1134. // Now set the playback window to be our MCI window
  1135. p->fCanWindow = MCIWndString(p, FALSE, szWindowHandle, (UINT)p->hwnd) == 0;
  1136. if (p->fCanWindow)
  1137. MCIWndGetDest(p->hwnd, &p->rcNormal);
  1138. else
  1139. SetRect(&p->rcNormal, 0, 0, 0, 0);
  1140. // Find out if the device supports palettes.
  1141. p->fHasPalette = MCIWndString(p, FALSE, szStatusPalette) == 0;
  1142. //
  1143. // Now find out the capabilities of this device
  1144. //
  1145. // !!! What about these ???
  1146. // MCI_GETDEVCAPS_DEVICE_TYPE 0x00000004L
  1147. // MCI_GETDEVCAPS_COMPOUND_DEVICE 0x00000006L
  1148. // Find out if the device can record
  1149. p->fCanRecord = MCIWndDevCaps(p, MCI_GETDEVCAPS_CAN_RECORD);
  1150. // Find out if the device can play
  1151. p->fCanPlay = MCIWndDevCaps(p, MCI_GETDEVCAPS_CAN_PLAY);
  1152. // Find out if the device can save
  1153. p->fCanSave = MCIWndDevCaps(p, MCI_GETDEVCAPS_CAN_SAVE);
  1154. // Find out if the device can eject
  1155. p->fCanEject = MCIWndDevCaps(p, MCI_GETDEVCAPS_CAN_EJECT);
  1156. // Find out if the device is file based
  1157. p->fUsesFiles = MCIWndDevCaps(p, MCI_GETDEVCAPS_USES_FILES);
  1158. // Find out if the device has video
  1159. p->fVideo = MCIWndDevCaps(p, MCI_GETDEVCAPS_HAS_VIDEO);
  1160. // Find out if the device has video
  1161. p->fAudio = MCIWndDevCaps(p, MCI_GETDEVCAPS_HAS_AUDIO);
  1162. // Find out if the device can configure
  1163. p->fCanConfig = (MCIWndString(p, FALSE, szConfigureTest) == 0);
  1164. #ifdef DEBUG
  1165. // !!! MCIAVI says no the driver...
  1166. p->fCanConfig = p->fCanWindow;
  1167. #endif
  1168. //
  1169. //
  1170. //
  1171. // Now see if we support speed - try normal, half, and max
  1172. p->fSpeed = MCIWndString(p, FALSE, szSetSpeed1000Test) == 0 &&
  1173. MCIWndString(p, FALSE, szSetSpeed500Test) == 0 &&
  1174. MCIWndString(p, FALSE, szSetSpeedTest, SPEED_MAX * 10) == 0;
  1175. // Now see if we support volume - try normal, mute, and max
  1176. p->fVolume = MCIWndString(p, FALSE, szSetVolumeTest, VOLUME_MAX * 5) ==0 &&
  1177. MCIWndString(p, FALSE, szSetVolume0Test) == 0;
  1178. p->wMaxVol = 100;
  1179. // If someone happens to support double volume, let's give it to them.
  1180. if (MCIWndString(p, FALSE, szSetVolumeTest, VOLUME_MAX * 10) == 0)
  1181. p->wMaxVol = 200;
  1182. // See if the device would support tmsf mode. If so, use milliseconds mode
  1183. // and later on we'll fake knowing where tracks begin and end
  1184. p->fHasTracks = (MCIWndString(p, FALSE, szSetFormatTMSF) == 0);
  1185. if (p->fHasTracks) {
  1186. dw = MCIWndString(p, FALSE, szSetFormatMS);
  1187. if (dw != 0)
  1188. p->fHasTracks = FALSE;
  1189. }
  1190. if (!p->fHasTracks) {
  1191. // Force us into a reasonable time format
  1192. dw = MCIWndString(p, FALSE, szSetFormatFrames);
  1193. if (dw != 0)
  1194. dw = MCIWndString(p, FALSE, szSetFormatMS);
  1195. if (dw != 0)
  1196. ; // !!! What to do? Don't turn playbar off without
  1197. } // !!! destroying it...
  1198. // Set the media length and trackbar range
  1199. MCIWndiValidateMedia(p);
  1200. // set window text
  1201. if (p->dwStyle & MCIWNDF_SHOWNAME)
  1202. SetWindowText(p->hwnd, FileName(szFile));
  1203. // Fix the toolbar buttons for the new device
  1204. MCIWndiFixMyPlaybar(p);
  1205. // Make an appropriate menu for this device
  1206. MCIWndiMakeMeAMenu(p);
  1207. // We need a TIMER to notify the "owner" when things change
  1208. MCIWndiSetTimer(p);
  1209. // Set the size of the movie (and maybe the window) and re-draw new toolbar
  1210. MCIWndiSize(p, p->iZoom);
  1211. #if 0 // We need the focus on our main window to get key accelerators
  1212. // Bring focus to the thumb so caret will flash
  1213. // I know the WM_SETFOCUS msg does this, but it seems to need to happen here
  1214. // too.
  1215. if (p->hwndTrackbar && GetFocus() == p->hwnd)
  1216. SetFocus(p->hwndTrackbar);
  1217. #endif
  1218. // We need to notify our "owner" that we've opened a new file
  1219. if (p->dwStyle & MCIWNDF_NOTIFYMEDIA)
  1220. NotifyOwner(p, MCIWNDM_NOTIFYMEDIA, p->hwnd, (LPARAM)szFile);
  1221. // Make sure the newly opened movie paints in the window now
  1222. InvalidateRect(p->hwnd, NULL, TRUE);
  1223. return 0; // success
  1224. }
  1225. //
  1226. // Set the caption based on what they want to see... Name? Pos? Mode?
  1227. //
  1228. static VOID MCIWndiSetCaption(PMCIWND p)
  1229. {
  1230. char ach[200], achMode[40], achT[40], achPos[40];
  1231. // Don't touch their window text if they don't want us to
  1232. if (!(p->dwStyle & MCIWNDF_SHOWALL))
  1233. return;
  1234. ach[0] = 0;
  1235. if (p->wDeviceID == NULL)
  1236. return;
  1237. if (p->dwStyle & MCIWNDF_SHOWNAME)
  1238. wsprintf(ach, "%s", FileName(p->achFileName));
  1239. if (p->dwStyle & (MCIWNDF_SHOWPOS | MCIWNDF_SHOWMODE))
  1240. lstrcat(ach, " (");
  1241. if (p->dwStyle & MCIWNDF_SHOWPOS) {
  1242. // Get the pretty version of the position as a string
  1243. MCIWndGetPositionString(p->hwnd, achPos, sizeof(achPos));
  1244. if (p->dwStyle & MCIWNDF_SHOWMODE)
  1245. wsprintf(achT, "%s - ", (LPSTR)achPos);
  1246. else
  1247. wsprintf(achT, "%s", (LPSTR)achPos);
  1248. lstrcat(ach, achT);
  1249. }
  1250. if (p->dwStyle & MCIWNDF_SHOWMODE) {
  1251. MCIWndGet(p, szStatusMode, achMode, sizeof(achMode));
  1252. lstrcat(ach, achMode);
  1253. }
  1254. if (p->dwStyle & (MCIWNDF_SHOWPOS | MCIWNDF_SHOWMODE))
  1255. lstrcat(ach, ")");
  1256. SetWindowText(p->hwnd, ach);
  1257. }
  1258. // We never use this any more
  1259. #if 0
  1260. static BOOL MCIWndSeekExact(PMCIWND p, BOOL fExact)
  1261. {
  1262. DWORD dw;
  1263. BOOL fWasExact;
  1264. if (p->wDeviceID == NULL)
  1265. return FALSE;
  1266. // see if the device even has this feature
  1267. dw = MCIWndString(p, FALSE, szStatusSeekExactly);
  1268. if (dw != 0)
  1269. return FALSE;
  1270. // get current value.
  1271. dw = MCIWndStatus(p, MCI_DGV_STATUS_SEEK_EXACTLY, MCI_OFF);
  1272. fWasExact = (dw != MCI_OFF) ? TRUE : FALSE;
  1273. if (fExact)
  1274. dw = MCIWndString(p, FALSE, szSetSeekExactOn);
  1275. else
  1276. dw = MCIWndString(p, FALSE, szSetSeekExactOff);
  1277. return fWasExact;
  1278. }
  1279. #endif
  1280. static LONG MCIWndiChangeStyles(PMCIWND p, UINT mask, UINT value)
  1281. {
  1282. DWORD dwOldStyle = p->dwStyle;
  1283. DWORD dwMaskOff, dwValue, dwChanged;
  1284. //
  1285. // Using the mask, change the appropriate bits in the style
  1286. //
  1287. dwMaskOff = dwOldStyle & (~(DWORD)mask);
  1288. dwValue = (DWORD)mask & (DWORD)value;
  1289. p->dwStyle = dwMaskOff | dwValue;
  1290. //
  1291. // Which bits changed?
  1292. //
  1293. dwChanged = (dwOldStyle & (DWORD)mask) ^ (dwValue & (DWORD)mask);
  1294. //
  1295. // We changed whether or not we want a menu button or a record button
  1296. // on the playbar
  1297. //
  1298. if (dwChanged & (MCIWNDF_NOMENU | MCIWNDF_NOOPEN | MCIWNDF_RECORD)) {
  1299. MCIWndiMakeMeAMenu(p); // add/remove record from the menu
  1300. // We have a playbar, so fix it
  1301. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR)) {
  1302. MCIWndiFixMyPlaybar(p);
  1303. MCIWndiSize(p, 0);
  1304. }
  1305. }
  1306. //
  1307. // We changed the show/don't show playbar flag!
  1308. //
  1309. if (dwChanged & MCIWNDF_NOPLAYBAR) {
  1310. // Remove the playbar
  1311. if (p->dwStyle & MCIWNDF_NOPLAYBAR) {
  1312. DestroyWindow(p->hwndToolbar);
  1313. p->hwndToolbar = NULL;
  1314. p->hwndTrackbar = NULL; // child destroyed automatically
  1315. MCIWndiMakeMeAMenu(p); // since toolbar's gone, menus change
  1316. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW)) {
  1317. // Now resize the window smaller to account for the missing
  1318. // playbar. Don't touch the movie size.
  1319. MCIWndiSize(p, 0);
  1320. // If the window isn't being resized, we may still need to grow
  1321. // the movie size a bit to take up the extra space where the toolbar
  1322. // vanished. (happens automatically in the previous case)
  1323. } else if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE)) {
  1324. PostMessage(p->hwnd, WM_SIZE, 0, 0L);
  1325. }
  1326. // Add a playbar
  1327. } else {
  1328. MCIWndiMakeMeAPlaybar(p);
  1329. MCIWndiFixMyPlaybar(p);
  1330. MCIWndiMakeMeAMenu(p); // since toolbar's used, menus change
  1331. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW)) {
  1332. // Now resize the window a little bigger to account for the new
  1333. // playbar. Don't touch the movie size.
  1334. MCIWndiSize(p, 0);
  1335. // If the window isn't being resized, we may still need to shrink
  1336. // the movie size because the toolbar covers up some extra space.
  1337. // (happens automatically in the previous case)
  1338. } else if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE)) {
  1339. PostMessage(p->hwnd, WM_SIZE, 0, 0L);
  1340. // Irregardless, we need to fix the toolbar
  1341. } else
  1342. // Put the toolbar in a reasonable spot
  1343. MCIWndiSizePlaybar(p);
  1344. }
  1345. }
  1346. //
  1347. // We changed a SHOW flag and need to reset the caption
  1348. //
  1349. if (dwChanged & MCIWNDF_SHOWALL)
  1350. MCIWndiSetCaption(p);
  1351. //
  1352. // We turned the AUTOSIZEMOVIE flag on and need to resize the device.
  1353. // This happens before AUTOSIZEWINDOW so if both flags are turned on
  1354. // the movie will snap to the window not vice versa.
  1355. // !!! Should we even snap it right now?
  1356. //
  1357. if (dwChanged & MCIWNDF_NOAUTOSIZEMOVIE &&
  1358. !(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE))
  1359. PostMessage(p->hwnd, WM_SIZE, 0, 0);
  1360. //
  1361. // We turned the AUTOSIZEWINDOW flag on
  1362. // Snap our window to the current movie size.
  1363. //
  1364. if (dwChanged & MCIWNDF_NOAUTOSIZEWINDOW &&
  1365. !(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
  1366. MCIWndiSize(p, 0);
  1367. DragAcceptFiles(p->hwnd, (p->dwStyle & MCIWNDF_NOMENU | MCIWNDF_NOOPEN) == 0);
  1368. return 0; // !!! success ?
  1369. }
  1370. //
  1371. // We're about to play. We might want to seek to the beginning first if we're
  1372. // at the end, or seek to the end first if we're at the beginning and playing
  1373. // backwards.
  1374. //
  1375. static void MCIWndiPlaySeek(PMCIWND p, BOOL fBackwards)
  1376. {
  1377. // Playing backwards? If we're at the beginning, seek to the end
  1378. if (fBackwards) {
  1379. if (MCIWndGetPosition(p->hwnd) <= MCIWndGetStart(p->hwnd))
  1380. MCIWndSeek(p->hwnd, MCIWND_END);
  1381. return;
  1382. }
  1383. // Playing forwards.
  1384. // If we're near the end, rewind before playing
  1385. // Some devices are broken so we can't just test being at the end
  1386. // Frames mode ... last or second to last frame
  1387. if (MCIWndGetTimeFormat(p->hwnd, NULL, 0) == MCI_FORMAT_FRAMES) {
  1388. if (MCIWndGetPosition(p->hwnd) >= MCIWndGetEnd(p->hwnd) - 1)
  1389. MCIWndSeek(p->hwnd, MCIWND_START);
  1390. // Millisecond mode ... within last 1/4 second
  1391. } else if (MCIWndGetTimeFormat(p->hwnd, NULL, 0) ==
  1392. MCI_FORMAT_MILLISECONDS) {
  1393. if (MCIWndGetEnd(p->hwnd) - MCIWndGetPosition(p->hwnd) < 250)
  1394. MCIWndSeek(p->hwnd, MCIWND_START);
  1395. // something else ... no hack
  1396. } else {
  1397. if (MCIWndGetPosition(p->hwnd) == MCIWndGetEnd(p->hwnd))
  1398. MCIWndSeek(p->hwnd, MCIWND_START);
  1399. }
  1400. }
  1401. //
  1402. // Handle our WM_TIMER
  1403. //
  1404. static void MCIWndiTimerStuff(PMCIWND p)
  1405. {
  1406. DWORD dwMode;
  1407. DWORD dwPos;
  1408. //
  1409. // Someone's interested in knowing the mode of the device
  1410. //
  1411. if ((p->dwStyle & MCIWNDF_NOTIFYMODE) ||
  1412. !(p->dwStyle & MCIWNDF_NOPLAYBAR) ||
  1413. (p->dwStyle & MCIWNDF_SHOWMODE)) {
  1414. dwMode = MCIWndGetMode(p->hwnd, NULL, 0);
  1415. //
  1416. // If we haven't set the trackbar range or media length yet
  1417. // because we weren't ready, maybe we can do it now!
  1418. // Also, don't update media until you're done recording.
  1419. //
  1420. if (dwMode != MCI_MODE_NOT_READY && dwMode != MCI_MODE_OPEN &&
  1421. dwMode != MCI_MODE_RECORD && p->fMediaValid == FALSE)
  1422. MCIWndiValidateMedia(p);
  1423. //
  1424. // No device loaded? Time to kill our timer
  1425. //
  1426. if (p->wDeviceID == NULL)
  1427. KillTimer(p->hwnd, TIMER1);
  1428. //
  1429. // The mode has changed!
  1430. //
  1431. if (dwMode != p->dwMode) {
  1432. p->dwMode = dwMode;
  1433. //
  1434. // Notify the "owner" of the mode change
  1435. //
  1436. if ((p->dwStyle & MCIWNDF_NOTIFYMODE))
  1437. NotifyOwner(p, MCIWNDM_NOTIFYMODE, p->hwnd, dwMode);
  1438. //
  1439. // Set the Window Caption to include the new mode
  1440. //
  1441. if ((p->dwStyle & MCIWNDF_SHOWMODE))
  1442. MCIWndiSetCaption(p);
  1443. //
  1444. // Fix up the toolbar bitmaps if the mode has changed
  1445. //
  1446. MCIWndiPlaybarGraying(p);
  1447. }
  1448. }
  1449. //
  1450. // Someone's interested in knowing the new position
  1451. //
  1452. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR) ||
  1453. (p->dwStyle & MCIWNDF_NOTIFYPOS) ||
  1454. (p->dwStyle & MCIWNDF_SHOWPOS)) {
  1455. dwPos = MCIWndGetPosition(p->hwnd);
  1456. //
  1457. // The position has changed!
  1458. //
  1459. if (dwPos != p->dwPos) {
  1460. //
  1461. // Make sure start and length haven't changed too (format change) ?
  1462. //
  1463. MCIWndiValidateMedia(p);
  1464. p->dwPos = dwPos;
  1465. //
  1466. // Notify the "owner" of the position change
  1467. //
  1468. if ((p->dwStyle & MCIWNDF_NOTIFYPOS))
  1469. NotifyOwner(p, MCIWNDM_NOTIFYPOS, p->hwnd, dwPos);
  1470. //
  1471. // Set the Window Caption to include the new position
  1472. //
  1473. if ((p->dwStyle & MCIWNDF_SHOWPOS))
  1474. MCIWndiSetCaption(p);
  1475. //
  1476. // Update the trackbar to the new position but not while
  1477. // we're dragging the thumb
  1478. //
  1479. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR) && !p->fScrolling)
  1480. SendMessage(p->hwndTrackbar, TBM_SETPOS, TRUE, dwPos);
  1481. }
  1482. }
  1483. }
  1484. static void MCIWndiDrop(HWND hwnd, WPARAM wParam)
  1485. {
  1486. char szPath[256];
  1487. UINT nDropped;
  1488. // Get number of files dropped
  1489. nDropped = DragQueryFile((HANDLE)wParam,0xFFFF,NULL,0);
  1490. if (nDropped) {
  1491. SetActiveWindow(hwnd);
  1492. // Get the file that was dropped....
  1493. DragQueryFile((HANDLE)wParam, 0, szPath, sizeof(szPath));
  1494. MCIWndOpen(hwnd, szPath, 0);
  1495. }
  1496. DragFinish((HANDLE)wParam); /* Delete structure alocated */
  1497. }
  1498. /*--------------------------------------------------------------+
  1499. | MCIWndProc - MCI window's window proc |
  1500. | |
  1501. +--------------------------------------------------------------*/
  1502. LONG FAR PASCAL _loadds MCIWndProc(HWND hwnd, unsigned msg, WORD wParam, LONG lParam)
  1503. {
  1504. PMCIWND p;
  1505. DWORD dw;
  1506. HDC hdc;
  1507. PAINTSTRUCT ps;
  1508. DWORD dwPos;
  1509. POINT pt;
  1510. MINMAXINFO FAR *lpmmi;
  1511. RECT rc;
  1512. BOOL f;
  1513. char ach[80];
  1514. MCI_GENERIC_PARMS mciGeneric;
  1515. LPRECT prc;
  1516. int i;
  1517. HWND hwndD;
  1518. p = (PMCIWND)(UINT)GetWindowLong(hwnd, 0);
  1519. switch(msg){
  1520. case WM_CREATE:
  1521. if (!MCIWndiCreate(hwnd, lParam))
  1522. return -1;
  1523. break;
  1524. // Make the trackbar background LTGRAY like the toolbar
  1525. case WM_CTLCOLOR:
  1526. if ((HWND)LOWORD(lParam) == p->hwndTrackbar)
  1527. return (LRESULT)(UINT)GetStockObject(LTGRAY_BRUSH);
  1528. break;
  1529. case MCI_SAVE:
  1530. // wParam presently unused and not given by the macro
  1531. return MCIWndiSave(p, wParam, (LPSTR)lParam);
  1532. case MCI_OPEN:
  1533. return MCIWndiOpen(p, wParam, (LPSTR)lParam);
  1534. case MCIWNDM_NEW:
  1535. return MCIWndiOpen(p, MCIWNDOPENF_NEW, (LPSTR)lParam);
  1536. case MCI_PLAY:
  1537. if (!p->wDeviceID)
  1538. return 0;
  1539. // Seek to the beginning if we're near the end
  1540. MCIWndiPlaySeek(p, FALSE);
  1541. case MCI_STOP:
  1542. case MCI_PAUSE:
  1543. case MCI_RESUME:
  1544. case MCI_RECORD:
  1545. dw = 0;
  1546. // Report/Show errors for this
  1547. if (p->wDeviceID) {
  1548. // buggy drivers crash if we pass a null parms address
  1549. dw = mciSendCommand(p->wDeviceID, msg, 0,
  1550. (DWORD)(LPVOID)&mciGeneric);
  1551. MCIWndiHandleError(p, dw);
  1552. // kick ourselves to show new Mode
  1553. MCIWndiTimerStuff(p);
  1554. }
  1555. return dw;
  1556. case MCIWNDM_PLAYREVERSE:
  1557. if (!p->wDeviceID)
  1558. return 0;
  1559. // Seek to the end if we're near the beginning
  1560. MCIWndiPlaySeek(p, TRUE);
  1561. dw = MCIWndString(p, TRUE, szPlayReverse, (LPSTR)szNULL);
  1562. // kick ourselves to show new Mode
  1563. MCIWndiTimerStuff(p);
  1564. return dw;
  1565. case MCI_CLOSE:
  1566. if (lParam)
  1567. // We delayed the closing of the MCI device because the MCI
  1568. // device may have hooked our window proc and be on our stack
  1569. // and killing it before would have destroyed the universe.
  1570. // buggy drivers crash if we pass a null parms address
  1571. return mciSendCommand((UINT)lParam, MCI_CLOSE, 0,
  1572. (DWORD)(LPVOID)&mciGeneric);
  1573. else
  1574. // Do all the stuff for closing
  1575. return MCIWndiClose(p, TRUE);
  1576. case MCIWNDM_EJECT:
  1577. return MCIWndString(p, TRUE, szSetDoorOpen);
  1578. case MCIWNDM_PLAYFROM:
  1579. if (lParam == MCIWND_START)
  1580. dw = MCIWndString(p, TRUE, szPlayFrom, MCIWndGetStart(hwnd));
  1581. else
  1582. dw = MCIWndString(p, TRUE, szPlayFrom, (LONG)lParam);
  1583. MCIWndiTimerStuff(p); // kick ourselves to see mode change
  1584. return dw;
  1585. case MCIWNDM_PLAYTO:
  1586. if (lParam == MCIWND_END)
  1587. dw = MCIWndString(p, TRUE, szPlayTo, MCIWndGetEnd(hwnd));
  1588. else if (lParam == MCIWND_START)
  1589. dw = MCIWndString(p, TRUE, szPlayTo, MCIWndGetStart(hwnd));
  1590. else
  1591. dw = MCIWndString(p, TRUE, szPlayTo, (LONG)lParam);
  1592. MCIWndiTimerStuff(p); // kick ourselves to see mode change
  1593. return dw;
  1594. case MCI_STEP:
  1595. return MCIWndString(p, TRUE, szStep, (LONG)lParam);
  1596. case MCI_SEEK:
  1597. if (lParam == MCIWND_START)
  1598. return MCIWndString(p, TRUE, szSeek, MCIWndGetStart(hwnd));
  1599. else if (lParam == MCIWND_END)
  1600. return MCIWndString(p, TRUE, szSeek, MCIWndGetEnd(hwnd));
  1601. else
  1602. return MCIWndString(p, TRUE, szSeek, (LONG)lParam);
  1603. case MCIWNDM_SETREPEAT:
  1604. p->fRepeat = (BOOL)lParam;
  1605. return 0;
  1606. case MCIWNDM_GETREPEAT:
  1607. return p->fRepeat;
  1608. case MCIWNDM_GETDEVICEID:
  1609. return p->wDeviceID;
  1610. case MCIWNDM_GETALIAS:
  1611. return p->alias;
  1612. case MCIWNDM_GETMODE:
  1613. if (lParam)
  1614. MCIWndGet(p, szStatusMode, (LPSTR)lParam, (UINT)wParam);
  1615. return MCIWndStatus(p, MCI_STATUS_MODE, MCI_MODE_NOT_READY);
  1616. // Return the position as a string if they give us a buffer
  1617. case MCIWNDM_GETPOSITION:
  1618. if (lParam) {
  1619. // If we can do tracks, let's give them a pretty string
  1620. if (p->fHasTracks)
  1621. MCIWndString(p, FALSE, szSetFormatTMSF);
  1622. MCIWndGet(p, szStatusPosition, (LPSTR)lParam,(UINT)wParam);
  1623. if (p->fHasTracks)
  1624. MCIWndString(p, FALSE, szSetFormatMS);
  1625. }
  1626. return MCIWndStatus(p, MCI_STATUS_POSITION, 0);
  1627. case MCIWNDM_GETSTART:
  1628. // Start is a command that works differently
  1629. return MCIWndGetValue(p, FALSE, szStatusStart, 0);
  1630. case MCIWNDM_GETLENGTH:
  1631. return MCIWndStatus(p, MCI_STATUS_LENGTH, 0);
  1632. case MCIWNDM_GETEND:
  1633. return MCIWndGetStart(hwnd) + MCIWndGetLength(hwnd);
  1634. case MCIWNDM_SETZOOM:
  1635. p->iZoom = (int)lParam;
  1636. MCIWndiSize(p, (int)lParam);
  1637. return 0;
  1638. case MCIWNDM_GETZOOM:
  1639. return p->iZoom ? p->iZoom : 100;
  1640. case MCIWNDM_GETPALETTE:
  1641. return MCIWndGetValue(p, FALSE, szStatusPalette, NULL);
  1642. case MCIWNDM_SETPALETTE:
  1643. return MCIWndString(p, TRUE, szSetPalette, (HPALETTE)wParam);
  1644. //
  1645. // Returns our error code
  1646. //
  1647. case MCIWNDM_GETERROR:
  1648. if (lParam) {
  1649. mciGetErrorString(p->dwError, (LPSTR)lParam, (UINT)wParam);
  1650. }
  1651. dw = p->dwError;
  1652. // p->dwError = 0L; // we never clear the error
  1653. return dw;
  1654. case MCIWNDM_GETFILENAME:
  1655. if (lParam)
  1656. lstrcpyn((LPSTR)lParam, p->achFileName, (UINT)wParam);
  1657. return (lParam == NULL); // !!!
  1658. case MCIWNDM_GETDEVICE:
  1659. if (lParam)
  1660. return MCIWndGet(p, szSysInfo, (LPSTR)lParam,
  1661. (UINT)wParam);
  1662. return 42; // !!!
  1663. case MCIWNDM_SETVOLUME:
  1664. // Uncheck the current volume, and check the new one.
  1665. // Round to nearest 5 so it matches a menu item identifier
  1666. i = ((int)MCIWndGetValue(p, FALSE, szStatusVolume, 1000) / 50) * 5;
  1667. if (p->hmenuVolume)
  1668. CheckMenuItem(p->hmenuVolume, IDM_MCIVOLUME + i, MF_UNCHECKED);
  1669. dw = MCIWndString(p, TRUE, szSetVolume, (int)lParam);
  1670. i = ((int)lParam / 50) * 5;
  1671. if (p->hmenuVolume)
  1672. CheckMenuItem(p->hmenuVolume, IDM_MCIVOLUME + i, MF_CHECKED);
  1673. return dw;
  1674. case MCIWNDM_GETVOLUME:
  1675. return MCIWndGetValue(p, FALSE, szStatusVolume, 1000);
  1676. case MCIWNDM_SETSPEED:
  1677. // Uncheck the current speed, and check the new one.
  1678. // Round to nearest 5 so it matches a menu item identifier
  1679. i = ((int)MCIWndGetValue(p, FALSE, szStatusSpeed, 1000) / 50) * 5;
  1680. if (p->hmenuSpeed)
  1681. CheckMenuItem(p->hmenuSpeed, IDM_MCISPEED + i, MF_UNCHECKED);
  1682. dw = MCIWndString(p, TRUE, szSetSpeed, (int)lParam);
  1683. i = ((int)lParam / 50) * 5;
  1684. if (p->hmenuSpeed)
  1685. CheckMenuItem(p->hmenuSpeed, IDM_MCISPEED + i, MF_CHECKED);
  1686. return dw;
  1687. case MCIWNDM_GETSPEED:
  1688. return MCIWndGetValue(p, FALSE, szStatusSpeed, 1000);
  1689. case MCIWNDM_SETTIMEFORMAT:
  1690. dw = MCIWndString(p, TRUE, szSetFormat, (LPSTR)lParam);
  1691. MCIWndiValidateMedia(p);
  1692. return dw;
  1693. case MCIWNDM_GETTIMEFORMAT:
  1694. if (lParam)
  1695. MCIWndGet(p, szStatusFormat, (LPSTR)lParam, (UINT)wParam);
  1696. return MCIWndStatus(p, MCI_STATUS_TIME_FORMAT, 0); // !!!
  1697. case MCIWNDM_VALIDATEMEDIA:
  1698. MCIWndiValidateMedia(p);
  1699. break;
  1700. case MCIWNDM_GETSTYLES:
  1701. return (UINT)(p->dwStyle & 0xFFFF);
  1702. case MCIWNDM_CHANGESTYLES:
  1703. return MCIWndiChangeStyles(p, (UINT)wParam, (UINT)lParam);
  1704. case MCIWNDM_SETACTIVETIMER:
  1705. if (wParam)
  1706. p->iActiveTimerRate = (unsigned)wParam;
  1707. if (p->fActive) {
  1708. KillTimer(hwnd, TIMER1);
  1709. MCIWndiSetTimer(p);
  1710. }
  1711. break;
  1712. case MCIWNDM_SETINACTIVETIMER:
  1713. if (wParam)
  1714. p->iInactiveTimerRate = (unsigned)wParam;
  1715. if (!p->fActive) {
  1716. KillTimer(hwnd, TIMER1);
  1717. MCIWndiSetTimer(p);
  1718. }
  1719. break;
  1720. case MCIWNDM_SETTIMERS:
  1721. if (wParam)
  1722. p->iActiveTimerRate = (unsigned)wParam;
  1723. if (lParam)
  1724. p->iInactiveTimerRate = (unsigned)lParam;
  1725. KillTimer(hwnd, TIMER1);
  1726. MCIWndiSetTimer(p);
  1727. break;
  1728. case MCIWNDM_GETACTIVETIMER:
  1729. return p->iActiveTimerRate;
  1730. case MCIWNDM_GETINACTIVETIMER:
  1731. return p->iInactiveTimerRate;
  1732. case MCIWNDM_SENDSTRING:
  1733. //
  1734. // App wants to send a string command.
  1735. // special case the CLOSE command to do our clean up
  1736. if (lstrcmpi((LPSTR)lParam, szClose) == 0)
  1737. return MCIWndClose(hwnd);
  1738. // Always sets/clears our error code
  1739. dw = MCIWndGet(p, (LPSTR)lParam, p->achReturn,sizeof(p->achReturn));
  1740. MCIWndiHandleError(p, dw);
  1741. // kick ourselves in case mode changed from this command
  1742. MCIWndiTimerStuff(p);
  1743. return dw;
  1744. // Gets the return string from the most recent MCIWndSendString()
  1745. case MCIWNDM_RETURNSTRING:
  1746. if (lParam)
  1747. lstrcpyn((LPSTR)lParam, p->achReturn, wParam);
  1748. return (lParam == NULL); // !!!
  1749. case MCIWNDM_REALIZE:
  1750. // buggy drivers crash if we pass a null parms address
  1751. dw = mciSendCommand(p->wDeviceID, MCI_REALIZE,
  1752. (BOOL)wParam ? MCI_ANIM_REALIZE_BKGD : MCI_ANIM_REALIZE_NORM,
  1753. (DWORD)(LPVOID)&mciGeneric);
  1754. break;
  1755. case MCIWNDM_GET_SOURCE:
  1756. MCIWndRect(p, (LPRECT)lParam, TRUE);
  1757. return 0L;
  1758. case MCIWNDM_GET_DEST:
  1759. MCIWndRect(p, (LPRECT)lParam, FALSE);
  1760. return 0L;
  1761. case MCIWNDM_PUT_SOURCE:
  1762. prc = (LPRECT)lParam;
  1763. return MCIWndString(p, FALSE, szPutSource,
  1764. prc->left, prc->top,
  1765. prc->right - prc->left,
  1766. prc->bottom - prc->top);
  1767. case MCIWNDM_PUT_DEST:
  1768. prc = (LPRECT)lParam;
  1769. return MCIWndString(p, FALSE, szPutDest,
  1770. prc->left, prc->top,
  1771. prc->right - prc->left,
  1772. prc->bottom - prc->top);
  1773. case MCIWNDM_CAN_PLAY: return p->fCanPlay;
  1774. case MCIWNDM_CAN_WINDOW: return p->fCanWindow;
  1775. case MCIWNDM_CAN_RECORD: return p->fCanRecord;
  1776. case MCIWNDM_CAN_SAVE: return p->fCanSave;
  1777. case MCIWNDM_CAN_EJECT: return p->fCanEject;
  1778. case MCIWNDM_CAN_CONFIG: return p->fCanConfig;
  1779. case WM_TIMER:
  1780. // This timer means we've moved the mouse off of the menu and need
  1781. // to snap the thumb back to the original value
  1782. if (wParam == TIMER2) {
  1783. KillTimer(hwnd, TIMER2);
  1784. // If only this would cause OwnerDraw to execute, we could see
  1785. // the thumb bounce back to it's default place. Alas, no can do
  1786. //CheckMenuItem(p->hmenuHack, p->uiHack, MF_UNCHECKED);
  1787. //CheckMenuItem(p->hmenuHack, p->uiHack, MF_CHECKED);
  1788. // This code will at least set the parameter back even though
  1789. // the thumb won't physically move.
  1790. if (p->hmenuHack == p->hmenuVolume)
  1791. MCIWndSetVolume(hwnd, (p->uiHack - IDM_MCIVOLUME) * 10);
  1792. else
  1793. MCIWndSetSpeed(hwnd, (p->uiHack - IDM_MCISPEED) * 10);
  1794. }
  1795. //
  1796. // This is not our timer. Bail.
  1797. //
  1798. if (wParam != TIMER1)
  1799. break;
  1800. MCIWndiTimerStuff(p);
  1801. break;
  1802. case WM_GETMINMAXINFO:
  1803. // We don't want anybody messing with the window size
  1804. if (p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW)
  1805. break;
  1806. // do we have a playbar?
  1807. f = !(p->dwStyle & MCIWNDF_NOPLAYBAR);
  1808. lpmmi = (MINMAXINFO FAR *)(lParam);
  1809. SetRect(&rc, 0, 0, SMALLEST_WIDTH, f ? TB_HEIGHT : 0);
  1810. AdjustWindowRect(&rc, GetWindowLong(hwnd, GWL_STYLE), FALSE);
  1811. lpmmi->ptMinTrackSize.y = rc.bottom - rc.top;
  1812. lpmmi->ptMinTrackSize.x = rc.right - rc.left;
  1813. if (!(p->wDeviceID) || !(p->fCanWindow))
  1814. lpmmi->ptMaxTrackSize.y = lpmmi->ptMinTrackSize.y;
  1815. break;
  1816. case WM_SIZE:
  1817. GetClientRect(hwnd, &rc);
  1818. if (!IsIconic(hwnd)) {
  1819. // if we have a playbar, fix it up to the new size
  1820. f = !(p->dwStyle & MCIWNDF_NOPLAYBAR);
  1821. if (f) {
  1822. MCIWndiSizePlaybar(p);
  1823. rc.bottom -= TB_HEIGHT;
  1824. }
  1825. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE))
  1826. MCIWndString(p, FALSE, szPutDest, 0,0, rc.right, rc.bottom);
  1827. } else {
  1828. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE))
  1829. MCIWndString(p, FALSE, szPutDest, 0,0, rc.right, rc.bottom);
  1830. }
  1831. break;
  1832. case WM_RBUTTONDOWN:
  1833. case WM_NCRBUTTONDOWN:
  1834. case WM_PARENTNOTIFY:
  1835. // If we haven't got a menu, or we don't want it, bail
  1836. if (!p->hmenu || p->dwStyle & MCIWNDF_NOMENU)
  1837. break;
  1838. // If this is not a right button down, bail
  1839. if (msg == WM_PARENTNOTIFY && wParam != WM_RBUTTONDOWN)
  1840. break;
  1841. GetCursorPos(&pt);
  1842. // Don't allow error dlgs to come up while we're tracking. That
  1843. // would cause windows to enter the twilight zone.
  1844. p->fTracking = TRUE;
  1845. TrackPopupMenu(p->hmenu,
  1846. TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
  1847. p->fTracking = FALSE;
  1848. return 0;
  1849. case WM_PALETTECHANGED:
  1850. if ((HWND)wParam != hwnd && p->fHasPalette)
  1851. InvalidateRect(hwnd, NULL, FALSE);
  1852. break;
  1853. case WM_QUERYNEWPALETTE:
  1854. if (p->fHasPalette)
  1855. MCIWndRealize(hwnd, FALSE);
  1856. break;
  1857. // Send a WM_PALETTECHANGED to everyone in the system. We need to do
  1858. // this manually sometimes because of GDI.
  1859. case MCIWNDM_PALETTEKICK:
  1860. hwndD = GetDesktopWindow(); // tell everyone DESKTOP changed it
  1861. PostMessage((HWND)-1, WM_PALETTECHANGED, (WPARAM)hwndD, 0);
  1862. // DESKTOP won't repaint if we give it it's own HWND, so pick a
  1863. // random window and PRAY it'll stay valid.
  1864. hwndD = GetActiveWindow();
  1865. hwndD = GetWindow(hwndD, GW_HWNDLAST);
  1866. PostMessage(GetDesktopWindow(), WM_PALETTECHANGED, (WPARAM)hwndD,0);
  1867. return 0;
  1868. case MCIWNDM_OPENINTERFACE:
  1869. wsprintf(ach, szInterface, lParam);
  1870. return MCIWndiOpen(p, 0, (LPSTR)ach);
  1871. case MCIWNDM_SETOWNER:
  1872. p->hwndOwner = (HWND)wParam;
  1873. return 0;
  1874. case WM_ERASEBKGND:
  1875. if (p->fCanWindow) {
  1876. MCIWndRect(p, &rc, FALSE);
  1877. SaveDC((HDC)wParam);
  1878. ExcludeClipRect((HDC)wParam, rc.left, rc.top, rc.right,
  1879. rc.bottom);
  1880. DefWindowProc(hwnd, msg, wParam, lParam);
  1881. RestoreDC((HDC)wParam, -1);
  1882. return 0;
  1883. }
  1884. break;
  1885. case WM_PAINT:
  1886. hdc = BeginPaint(hwnd, &ps);
  1887. if (p->wDeviceID && p->fCanWindow)
  1888. {
  1889. MCI_ANIM_UPDATE_PARMS mciUpdate;
  1890. mciUpdate.hDC = hdc;
  1891. dw = mciSendCommand(p->wDeviceID, MCI_UPDATE,
  1892. MCI_ANIM_UPDATE_HDC | MCI_WAIT |
  1893. MCI_DGV_UPDATE_PAINT,
  1894. (DWORD)(LPVOID)&mciUpdate);
  1895. if (dw != 0) /* if the update fails then erase */
  1896. DefWindowProc(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
  1897. } else if (IsIconic(hwnd)) {
  1898. DefWindowProc(hwnd, WM_ICONERASEBKGND, (WPARAM)hdc, 0);
  1899. DrawIcon(ps.hdc, 0, 0, p->hicon);
  1900. }
  1901. EndPaint(hwnd, &ps);
  1902. break;
  1903. case WM_KEYDOWN:
  1904. switch(wParam) {
  1905. case VK_LEFT:
  1906. SendMessage(hwnd, WM_HSCROLL, TB_LINEUP, 0); break;
  1907. case VK_RIGHT:
  1908. SendMessage(hwnd, WM_HSCROLL, TB_LINEDOWN, 0); break;
  1909. case VK_PRIOR:
  1910. SendMessage(hwnd, WM_HSCROLL, TB_PAGEUP, 0); break;
  1911. case VK_NEXT:
  1912. SendMessage(hwnd, WM_HSCROLL, TB_PAGEDOWN, 0); break;
  1913. case VK_HOME:
  1914. SendMessage(hwnd, WM_HSCROLL, TB_TOP, 0); break;
  1915. case VK_END:
  1916. SendMessage(hwnd, WM_HSCROLL, TB_BOTTOM, 0); break;
  1917. case VK_UP:
  1918. case VK_DOWN:
  1919. dw = MCIWndGetValue(p, FALSE, szStatusVolume, 1000);
  1920. if (wParam == VK_UP)
  1921. i = min((int)p->wMaxVol * 10, (int) dw + 100);
  1922. else
  1923. i = max(0, (int) dw - 100);
  1924. MCIWndSetVolume(p->hwnd, i);
  1925. break;
  1926. default:
  1927. break;
  1928. }
  1929. break;
  1930. case WM_KEYUP:
  1931. switch(wParam) {
  1932. case VK_LEFT:
  1933. case VK_RIGHT:
  1934. case VK_PRIOR:
  1935. case VK_NEXT:
  1936. case VK_HOME:
  1937. case VK_END:
  1938. if (p->fScrolling)
  1939. SendMessage(hwnd, WM_HSCROLL, TB_ENDTRACK, 0);
  1940. break;
  1941. case VK_ESCAPE:
  1942. MCIWndStop(hwnd);
  1943. break;
  1944. default:
  1945. break;
  1946. }
  1947. if (GetKeyState(VK_CONTROL) & 0x8000) {
  1948. switch(wParam) {
  1949. case '1':
  1950. case '2':
  1951. case '3':
  1952. case '4':
  1953. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
  1954. MCIWndSetZoom(hwnd, 100 * (wParam - '0'));
  1955. break;
  1956. case 'P':
  1957. MCIWndPlay(hwnd); break;
  1958. case 'S':
  1959. MCIWndStop(hwnd); break;
  1960. case 'D':
  1961. PostMessage(hwnd, WM_COMMAND, IDM_MCICONFIG, 0); break;
  1962. case 'C':
  1963. PostMessage(hwnd, WM_COMMAND, IDM_COPY, 0); break;
  1964. case VK_F5:
  1965. PostMessage(hwnd, WM_COMMAND, IDM_MCICOMMAND, 0); break;
  1966. case 'F':
  1967. case 'O':
  1968. if (!(p->dwStyle & MCIWNDF_NOOPEN))
  1969. MCIWndOpenDialog(hwnd);
  1970. break;
  1971. case 'M':
  1972. PostMessage(hwnd, WM_COMMAND, ID_TOOLBAR,
  1973. MAKELONG(IDM_MENU, TBN_BEGINDRAG)); break;
  1974. default:
  1975. break;
  1976. }
  1977. }
  1978. break;
  1979. case WM_SYSCHAR:
  1980. switch(wParam) {
  1981. case '1':
  1982. case '2':
  1983. case '3':
  1984. case '4':
  1985. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
  1986. MCIWndSetZoom(hwnd, 100 / ((UINT) wParam - '0'));
  1987. return 0; // break will ding
  1988. default:
  1989. break;
  1990. }
  1991. break;
  1992. case WM_HSCROLL:
  1993. #define FORWARD 1
  1994. #define BACKWARD 2
  1995. dwPos = SendMessage(p->hwndTrackbar, TBM_GETPOS, 0, 0);
  1996. // nothing to do - spurious END without BEGIN
  1997. if (!p->fScrolling && wParam == TB_ENDTRACK)
  1998. break;
  1999. // Turn seek exactly off while scrolling and remember what it was
  2000. // Also, remember if we were playing just before we seeked so we
  2001. // can continue playing after the seek (so moving the thumb doesn't
  2002. // stop the play).
  2003. if (!p->fScrolling) {
  2004. p->fScrolling = TRUE;
  2005. // Wierd artifacts happen if you turn seek exactly off while
  2006. // seeking. You see the key frame and then the actual frame.
  2007. // Nobody can remember why this was ever a good idea.
  2008. //p->fSeekExact = MCIWndSeekExact(p, FALSE);
  2009. // if we're still seeking from last time, don't change this
  2010. if (p->dwMode != MCI_MODE_SEEK)
  2011. p->fPlayAfterSeek = (p->dwMode == MCI_MODE_PLAY);
  2012. // Now which direction was it playing in?
  2013. if (p->fPlayAfterSeek) {
  2014. MCIWndGet(p, szStatusForward, ach, sizeof(ach));
  2015. if (ach[0] == 'F' || ach[0] == 'f')
  2016. p->fPlayAfterSeek = BACKWARD;
  2017. else // by default, choose forward. Some devices
  2018. // don't understand this command and fail.
  2019. p->fPlayAfterSeek = FORWARD;
  2020. }
  2021. }
  2022. switch(wParam)
  2023. {
  2024. case TB_LINEUP:
  2025. dwPos--; break;
  2026. case TB_LINEDOWN:
  2027. dwPos++; break;
  2028. case TB_PAGEUP:
  2029. if (p->fHasTracks) {
  2030. dwPos = MCIWndiPrevTrack(p); break;
  2031. } else {
  2032. dwPos -= p->dwMediaLen / 16; break;
  2033. }
  2034. case TB_PAGEDOWN:
  2035. if (p->fHasTracks) {
  2036. dwPos = MCIWndiNextTrack(p); break;
  2037. } else {
  2038. dwPos += p->dwMediaLen / 16; break;
  2039. }
  2040. case TB_TOP:
  2041. dwPos = p->dwMediaStart; break;
  2042. case TB_BOTTOM:
  2043. dwPos = p->dwMediaStart + p->dwMediaLen; break;
  2044. case TB_THUMBTRACK:
  2045. case TB_THUMBPOSITION:
  2046. break;
  2047. case TB_ENDTRACK:
  2048. // All done. Put seek exact back to what it used to be
  2049. p->fScrolling = FALSE;
  2050. // Don't do this anymore (see above)
  2051. //MCIWndSeekExact(p, p->fSeekExact);
  2052. break;
  2053. default:
  2054. break;
  2055. }
  2056. // If we're windowed, update the position as we scroll. That would
  2057. // be annoying for CD or wave, though. Also, update as soon as we
  2058. // let go of the thumb. Also, never seek around while we're open
  2059. // or not ready.
  2060. if ((p->fCanWindow || !p->fScrolling) && p->dwMode != MCI_MODE_OPEN
  2061. && p->dwMode != MCI_MODE_NOT_READY) {
  2062. MCIWndSeek(hwnd, dwPos);
  2063. MCIWndiTimerStuff(p); // kick ourselves to update mode
  2064. }
  2065. // After we're done, if we were playing before, go back to playing
  2066. if (!p->fScrolling && p->fPlayAfterSeek) {
  2067. if (p->fPlayAfterSeek == FORWARD)
  2068. MCIWndPlay(hwnd);
  2069. else
  2070. MCIWndPlayReverse(hwnd);
  2071. MCIWndiTimerStuff(p); // kick ourselves to update mode
  2072. }
  2073. // Set the trackbar to the (possibly) new position
  2074. SendMessage(p->hwndTrackbar, TBM_SETPOS, TRUE, dwPos);
  2075. break;
  2076. case WM_MENUSELECT:
  2077. break;
  2078. // Sent from a toolbar button being pressed
  2079. case WM_COMMAND:
  2080. // Check for ZOOM commands
  2081. if (wParam >= IDM_MCIZOOM && wParam < IDM_MCIZOOM + 1000)
  2082. MCIWndSetZoom(hwnd, wParam - IDM_MCIZOOM);
  2083. // !!! Hack from Hell
  2084. // If our bogus top menu item is selected, turn it into the REAL
  2085. // menu item closest to it.
  2086. if (wParam == IDM_MCIVOLUME + VOLUME_MAX + 1)
  2087. wParam = IDM_MCIVOLUME + p->wMaxVol;
  2088. if (wParam == IDM_MCIVOLUME + VOLUME_MAX + 2)
  2089. wParam = IDM_MCIVOLUME;
  2090. // VOLUME command? Uncheck old one, reset volume, and check new one
  2091. // Round to the nearest 5 to match a menu identifier
  2092. if (wParam >=IDM_MCIVOLUME && wParam <=IDM_MCIVOLUME + p->wMaxVol) {
  2093. if (MCIWndSetVolume(hwnd, (wParam - IDM_MCIVOLUME) * 10) == 0
  2094. && lParam != 42) {
  2095. CheckMenuItem(p->hmenuVolume, p->uiHack, MF_UNCHECKED);
  2096. // change state only for a real command, not while dragging
  2097. CheckMenuItem(p->hmenuVolume, wParam, MF_CHECKED);
  2098. }
  2099. }
  2100. // !!! Hack from Hell
  2101. // If our bogus top menu item is selected, turn it into the REAL
  2102. // menu item closest to it.
  2103. if (wParam == IDM_MCISPEED + SPEED_MAX + 1)
  2104. wParam = IDM_MCISPEED + SPEED_MAX;
  2105. if (wParam == IDM_MCISPEED + SPEED_MAX + 2)
  2106. wParam = IDM_MCISPEED;
  2107. // SPEED command? Uncheck old one, reset speed, and check new one
  2108. // Round to the nearest 5 to match a menu identifier
  2109. if (wParam >=IDM_MCISPEED && wParam <= IDM_MCISPEED + SPEED_MAX) {
  2110. if (MCIWndSetSpeed(hwnd, (wParam - IDM_MCISPEED) * 10) == 0
  2111. && lParam != 42) {
  2112. // change state only for a real command, not while dragging
  2113. CheckMenuItem(p->hmenuSpeed, p->uiHack, MF_UNCHECKED);
  2114. CheckMenuItem(p->hmenuSpeed, wParam, MF_CHECKED);
  2115. }
  2116. }
  2117. switch(wParam)
  2118. {
  2119. MSG msgT;
  2120. RECT rcT;
  2121. case MCI_RECORD:
  2122. if (GetKeyState(VK_SHIFT) < 0)
  2123. {
  2124. //!!! toggle?
  2125. //MCIWndRecordPreview(hwnd);
  2126. }
  2127. else
  2128. {
  2129. MCIWndRecord(hwnd);
  2130. }
  2131. break;
  2132. // PLAY = normal play
  2133. // SHIFT+PLAY = play backward
  2134. // CTRL+PLAY = play fullscreen
  2135. // SHIFT+CTRL+PLAY = play fullscreen backward
  2136. //
  2137. case MCI_PLAY:
  2138. #define MaybeRepeat (p->fRepeat ? (LPSTR)szRepeat : (LPSTR)szNULL)
  2139. // NOTE: We never set errors for the repeat play, because
  2140. // lots of device don't support it and would fail.
  2141. if (GetKeyState(VK_SHIFT) < 0)
  2142. // If we're at the beginning, seek to the end.
  2143. MCIWndiPlaySeek(p, TRUE);
  2144. else
  2145. // If we're at the end, seek to the beginning.
  2146. MCIWndiPlaySeek(p, FALSE);
  2147. if (GetKeyState(VK_CONTROL) < 0)
  2148. {
  2149. if (GetKeyState(VK_SHIFT) < 0) {
  2150. if (MCIWndString(p, FALSE, szPlayFullscreenReverse,
  2151. MaybeRepeat))
  2152. MCIWndString(p, TRUE, szPlayFullscreenReverse,
  2153. (LPSTR)szNULL);
  2154. } else {
  2155. if (MCIWndString(p, FALSE, szPlayFullscreen,
  2156. MaybeRepeat))
  2157. MCIWndString(p, TRUE, szPlayFullscreen,
  2158. (LPSTR)szNULL);
  2159. }
  2160. } else if (GetKeyState(VK_SHIFT) < 0) {
  2161. if (MCIWndString(p, FALSE, szPlayReverse, MaybeRepeat))
  2162. MCIWndString(p, TRUE, szPlayReverse, (LPSTR)szNULL);
  2163. } else {
  2164. if (MCIWndString(p, FALSE, szPlay, MaybeRepeat))
  2165. MCIWndString(p, TRUE, szPlay, (LPSTR)szNULL);
  2166. }
  2167. // Kick ourselves to fix up toolbar since mode changed
  2168. MCIWndiTimerStuff(p);
  2169. break;
  2170. case MCI_STOP:
  2171. return MCIWndStop(hwnd);
  2172. case MCI_PAUSE:
  2173. return MCIWndPause(hwnd);
  2174. case IDM_MCINEW:
  2175. return MCIWndNew(hwnd, NULL);
  2176. case IDM_MCIOPEN:
  2177. return MCIWndOpenDialog(hwnd);
  2178. case MCI_SAVE:
  2179. return MCIWndSaveDialog(hwnd);
  2180. case IDM_MCICLOSE:
  2181. return MCIWndClose(hwnd);
  2182. case IDM_MCICONFIG:
  2183. MCIWndString(p, TRUE, szConfigure);
  2184. // AVI's configure box might change the size (zoom by 2)
  2185. // so we better call our size routine.
  2186. MCIWndiSize(p, 0);
  2187. // Taking ZOOM X 2 off might leave the outside not painted
  2188. InvalidateRect(hwnd, NULL, TRUE);
  2189. break;
  2190. case IDM_MCICOMMAND:
  2191. mciDialog(hwnd);
  2192. // call mciwndisize?
  2193. break;
  2194. case IDM_COPY:
  2195. MCIWndCopy(p);
  2196. break;
  2197. case IDM_MCIREWIND:
  2198. return MCIWndSeek(hwnd, MCIWND_START);
  2199. case IDM_MCIEJECT:
  2200. return MCIWndEject(hwnd);
  2201. case ID_TOOLBAR:
  2202. if (HIWORD(lParam) != TBN_BEGINDRAG ||
  2203. LOWORD(lParam) != IDM_MENU ||
  2204. !SendMessage(p->hwndToolbar, TB_ISBUTTONENABLED,
  2205. IDM_MENU, 0) ||
  2206. !p->hmenu)
  2207. break;
  2208. SendMessage(p->hwndToolbar, TB_GETITEMRECT,
  2209. (int)SendMessage(p->hwndToolbar, TB_COMMANDTOINDEX,
  2210. IDM_MENU, 0),
  2211. (LPARAM)(LPVOID)&rc);
  2212. rcT = rc;
  2213. ClientToScreen(p->hwndToolbar, (LPPOINT)&rc);
  2214. ClientToScreen(p->hwndToolbar, (LPPOINT)&rc + 1);
  2215. // Push the button down (accelerator won't have done this)
  2216. SendMessage(p->hwndToolbar, TB_PRESSBUTTON, IDM_MENU,
  2217. TRUE);
  2218. // Don't allow error dlgs to come up while we're tracking.
  2219. // That would cause windows to shatter and send shrapnel
  2220. // flying.
  2221. p->fTracking = TRUE;
  2222. TrackPopupMenu(p->hmenu, 0, rc.left, rc.bottom - 1, 0,
  2223. hwnd, &rc); // don't dismiss menu inside button
  2224. p->fTracking = FALSE;
  2225. // Bring the button back up.
  2226. SendMessage(p->hwndToolbar, TB_PRESSBUTTON, IDM_MENU,
  2227. FALSE);
  2228. // What if we press the menu button to make the menu go
  2229. // away? It's just going to bring the menu back up again!
  2230. // So we need to pull the click out of the queue.
  2231. // There are bugs in the toolbar code to prevent me from
  2232. // doing this any other way (like disabling the button)
  2233. if (PeekMessage(&msgT, p->hwndToolbar, WM_LBUTTONDOWN,
  2234. WM_LBUTTONDOWN, PM_NOREMOVE)) {
  2235. if (PtInRect(&rcT, MAKEPOINT(msgT.lParam)))
  2236. PeekMessage(&msgT, p->hwndToolbar, WM_LBUTTONDOWN,
  2237. WM_LBUTTONDOWN, PM_REMOVE);
  2238. }
  2239. break;
  2240. default:
  2241. break;
  2242. }
  2243. break;
  2244. case WM_DESTROY:
  2245. // !!! MMP CLOSE will be deferred till AFTER the DESTROY
  2246. // Don't palette kick when we're going down. Not necessary
  2247. //
  2248. p->fHasPalette = FALSE;
  2249. MCIWndiClose(p, FALSE); //don't leave us playing into a random DC
  2250. if (p->hmenu) {
  2251. DestroyMenu(p->hmenu);
  2252. FreeDitherBrush();
  2253. }
  2254. if (p->pTrackStart)
  2255. LocalFree((HANDLE)p->pTrackStart);
  2256. if (p->hfont) {
  2257. // !!! Someone else may have to go and create it again, but oh
  2258. // !!! well.
  2259. DeleteObject(p->hfont);
  2260. p->hfont = NULL;
  2261. }
  2262. if (p->hicon)
  2263. DestroyIcon(p->hicon);
  2264. // We can't destroy our pointer and then fall through and use it
  2265. f = p->fMdiWindow;
  2266. LocalFree((HLOCAL) p);
  2267. SetWindowLong(hwnd, 0, NULL); // our p
  2268. if (f)
  2269. return DefMDIChildProc(hwnd, msg, wParam, lParam);
  2270. else
  2271. return DefWindowProc(hwnd, msg, wParam, lParam);
  2272. // Use a different rate for the timer depending on if we're active
  2273. // or not.
  2274. case WM_NCACTIVATE:
  2275. // MDI windows need to realize their palette here
  2276. if (p->wDeviceID && p->fMdiWindow && p->fHasPalette)
  2277. MCIWndRealize(hwnd, wParam == FALSE);
  2278. #if 0
  2279. case WM_ACTIVATE:
  2280. p->fActive = wParam;
  2281. KillTimer(hwnd, TIMER1);
  2282. MCIWndiSetTimer(p);
  2283. #endif
  2284. break;
  2285. case WM_SETFOCUS:
  2286. p->fActive = TRUE;
  2287. KillTimer(hwnd, TIMER1);
  2288. MCIWndiSetTimer(p);
  2289. break;
  2290. case WM_KILLFOCUS:
  2291. p->fActive = FALSE;
  2292. KillTimer(hwnd, TIMER1);
  2293. MCIWndiSetTimer(p);
  2294. break;
  2295. // If the user uses MCINOTIFY we pass the notify on to the "owner"
  2296. case MM_MCINOTIFY:
  2297. // Kick ourselves to update toolbar/titles since getting a notify
  2298. // means that stuff might have changed.
  2299. MCIWndiTimerStuff(p);
  2300. return NotifyOwner(p, msg, wParam, lParam);
  2301. case WM_DRAWITEM:
  2302. case WM_MEASUREITEM:
  2303. case WM_DELETEITEM:
  2304. OwnerDraw(p, msg, wParam, lParam);
  2305. return TRUE; // !!!
  2306. case WM_SYSCOMMAND:
  2307. switch (wParam & ~0xF) {
  2308. case SC_MINIMIZE:
  2309. // Minimizing from MAXIMIZED state better do the same thing
  2310. // as restore or windows will always think it's maximized
  2311. // and start wierding out on us (Chico bug 19541).
  2312. if (IsZoomed(hwnd)) {
  2313. wParam = SC_RESTORE | (wParam & 0xF);
  2314. break; // MUST let DefWndProc run
  2315. }
  2316. if (p->wDeviceID && p->fCanWindow) {
  2317. RECT rc;
  2318. MCIWndGetDest(hwnd, &rc);
  2319. if (rc.right > p->rcNormal.right &&
  2320. rc.bottom > p->rcNormal.bottom) {
  2321. // We pressed buttons on the title bar... we really
  2322. // better autosize window.
  2323. dw = p->dwStyle;
  2324. p->dwStyle &= ~MCIWNDF_NOAUTOSIZEWINDOW;
  2325. MCIWndSetZoom(hwnd, 100);
  2326. p->dwStyle = dw;
  2327. return 0;
  2328. }
  2329. }
  2330. break;
  2331. case SC_MAXIMIZE:
  2332. if (p->fCanWindow && !IsIconic(hwnd)) {
  2333. RECT rc;
  2334. MCIWndGetDest(hwnd, &rc);
  2335. if (rc.right < p->rcNormal.right &&
  2336. rc.bottom < p->rcNormal.bottom) {
  2337. // We pressed buttons on the title bar... we really
  2338. // better autosize window.
  2339. dw = p->dwStyle;
  2340. p->dwStyle &= ~MCIWNDF_NOAUTOSIZEWINDOW;
  2341. MCIWndSetZoom(hwnd, 100);
  2342. p->dwStyle = dw;
  2343. return 0;
  2344. }
  2345. if (rc.right >= p->rcNormal.right &&
  2346. rc.right < p->rcNormal.right*2 &&
  2347. rc.bottom >= p->rcNormal.bottom &&
  2348. rc.bottom < p->rcNormal.bottom*2) {
  2349. // We pressed buttons on the title bar... we really
  2350. // better autosize window.
  2351. dw = p->dwStyle;
  2352. p->dwStyle &= ~MCIWNDF_NOAUTOSIZEWINDOW;
  2353. MCIWndSetZoom(hwnd, 200);
  2354. p->dwStyle = dw;
  2355. return 0;
  2356. }
  2357. }
  2358. break;
  2359. }
  2360. break;
  2361. case WM_DROPFILES:
  2362. MCIWndiDrop(hwnd, wParam);
  2363. break;
  2364. case WM_QUERYDRAGICON:
  2365. return (LONG)(UINT)p->hicon;
  2366. }
  2367. if (p && p->fMdiWindow)
  2368. return DefMDIChildProc(hwnd, msg, wParam, lParam);
  2369. else
  2370. return DefWindowProc(hwnd, msg, wParam, lParam);
  2371. }
  2372. static void NEAR PASCAL PatRect(HDC hdc,int x,int y,int dx,int dy)
  2373. {
  2374. RECT rc;
  2375. rc.left = x;
  2376. rc.top = y;
  2377. rc.right = x + dx;
  2378. rc.bottom = y + dy;
  2379. ExtTextOut(hdc,0,0,ETO_OPAQUE,&rc,NULL,0,NULL);
  2380. }
  2381. #define FillRC(hdc, prc) PatRect(hdc, (prc)->left, (prc)->top, (prc)->right - (prc)->left, (prc)->bottom-(prc)->top)
  2382. //
  2383. // Draw the channel for the volume and speed menu controls
  2384. //
  2385. static void NEAR PASCAL DrawChannel(HDC hdc, LPRECT prc)
  2386. {
  2387. HBRUSH hbrTemp;
  2388. int iWidth = prc->right - prc->left;
  2389. // draw the frame around the window
  2390. SetBkColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
  2391. PatRect(hdc, prc->left, prc->top, iWidth, 1);
  2392. PatRect(hdc, prc->left, prc->bottom-2, iWidth, 1);
  2393. PatRect(hdc, prc->left, prc->top, 1, prc->bottom-prc->top-1);
  2394. PatRect(hdc, prc->right-1, prc->top, 1, prc->bottom-prc->top-1);
  2395. SetBkColor(hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
  2396. PatRect(hdc, prc->left, prc->bottom-1, iWidth, 1);
  2397. SetBkColor(hdc, GetSysColor(COLOR_BTNSHADOW));
  2398. PatRect(hdc, prc->left+1, prc->top + 1, iWidth-2,1);
  2399. // draw the background in dither gray
  2400. hbrTemp = SelectObject(hdc, hbrDither);
  2401. if (hbrTemp) {
  2402. PatBlt(hdc, prc->left+1, prc->top + 2,
  2403. iWidth-2, prc->bottom-prc->top-4, PATCOPY);
  2404. SelectObject(hdc, hbrTemp);
  2405. }
  2406. }
  2407. static LONG OwnerDraw(PMCIWND p, UINT msg, WORD wParam, LONG lParam)
  2408. {
  2409. RECT rc, rcMenu, rcChannel, rcThumb;
  2410. HDC hdc;
  2411. int i,dx,dy,len;
  2412. char ach[10];
  2413. DWORD dw;
  2414. HWND hwnd = p->hwnd;
  2415. #define lpMIS ((LPMEASUREITEMSTRUCT)lParam)
  2416. #define lpDIS ((LPDRAWITEMSTRUCT)lParam)
  2417. #define WIDTH_FROM_THIN_AIR 14
  2418. #define CHANNEL_INDENT 6 // for VOLUME and SPEED menu trackbar
  2419. #define MENU_WIDTH 10
  2420. #define THUMB 5
  2421. #define MENU_ITEM_HEIGHT 2
  2422. switch (msg)
  2423. {
  2424. case WM_MEASUREITEM:
  2425. if (p->hfont == NULL)
  2426. p->hfont = CreateFont (8, 0, 0, 0,
  2427. FW_NORMAL,FALSE,FALSE,FALSE,
  2428. ANSI_CHARSET,OUT_DEFAULT_PRECIS,
  2429. CLIP_DEFAULT_PRECIS,PROOF_QUALITY,
  2430. VARIABLE_PITCH | FF_DONTCARE,
  2431. szSmallFonts);
  2432. //
  2433. // The first and last menu items are the spaces above and below
  2434. // the channel, so they need to be taller.
  2435. //
  2436. if (lpMIS->itemID == IDM_MCIVOLUME + VOLUME_MAX + 1
  2437. || lpMIS->itemID == IDM_MCISPEED + SPEED_MAX + 1
  2438. || lpMIS->itemID == IDM_MCIVOLUME + VOLUME_MAX + 2
  2439. || lpMIS->itemID == IDM_MCISPEED + SPEED_MAX + 2) {
  2440. lpMIS->itemHeight = CHANNEL_INDENT;
  2441. lpMIS->itemWidth = MENU_WIDTH;
  2442. } else {
  2443. lpMIS->itemHeight = MENU_ITEM_HEIGHT;
  2444. lpMIS->itemWidth = MENU_WIDTH;
  2445. }
  2446. return TRUE;
  2447. case WM_DRAWITEM:
  2448. rc = lpDIS->rcItem;
  2449. hdc = lpDIS->hDC;
  2450. //
  2451. // Something has been deselected. If we don't see a new selection
  2452. // soon, it means we've dragged the cursor off the menu, and we
  2453. // should pop the thumb back to its original spot.
  2454. //
  2455. if ((lpDIS->itemAction & ODA_SELECT) &&
  2456. !(lpDIS->itemState & ODS_SELECTED))
  2457. SetTimer(p->hwnd, TIMER2, 500, NULL);
  2458. //
  2459. // When asked to draw the selected or checked menu item, we will
  2460. // draw the entire menu. Otherwise, we don't do a thing
  2461. //
  2462. if (lpDIS->itemState & (ODS_SELECTED | ODS_CHECKED)) {
  2463. // This is the item that is checked, or the original spot for
  2464. // the thumb. Remember it so when we drag off the menu, we
  2465. // can bounce the thumb back here.
  2466. if (lpDIS->itemState & ODS_CHECKED) {
  2467. p->uiHack = lpDIS->itemID;
  2468. if (p->uiHack >= IDM_MCISPEED &&
  2469. p->uiHack <= IDM_MCISPEED + SPEED_MAX)
  2470. p->hmenuHack = p->hmenuSpeed;
  2471. else
  2472. p->hmenuHack = p->hmenuVolume;
  2473. }
  2474. // Something is being selected. Obviously the mouse is still
  2475. // on the menu. Scrap our timer that was waiting to see if
  2476. // we've dragged off the menu.
  2477. if (lpDIS->itemState & ODS_SELECTED)
  2478. KillTimer(p->hwnd, TIMER2);
  2479. // !!! Hack !!!
  2480. // If we try to highlight the bogus menu items, bail!
  2481. if (lpDIS->itemID == IDM_MCIVOLUME + VOLUME_MAX + 1)
  2482. break;
  2483. if (lpDIS->itemID == IDM_MCIVOLUME + VOLUME_MAX + 2)
  2484. break;
  2485. if (lpDIS->itemID == IDM_MCISPEED + SPEED_MAX + 1)
  2486. break;
  2487. if (lpDIS->itemID == IDM_MCISPEED + SPEED_MAX + 2)
  2488. break;
  2489. // Actually set the parameter to the value we're dragging so
  2490. // we can hear it change as we move the slider.
  2491. // 42 means DON'T CHECK it (remember which item was originally
  2492. // checked).
  2493. SendMessage(hwnd, WM_COMMAND, lpDIS->itemID, 42);
  2494. //
  2495. // Get the rect of our menu window. GetClipBox is
  2496. // not quite right, so we'll adjust for the border. Our lpDIS
  2497. // contains the proper width of the client area, so we'll use
  2498. // that.
  2499. //
  2500. GetClipBox(hdc, &rc);
  2501. rc.top++; //!!! top border width
  2502. rc.bottom -= 2; //!!! bottom border width
  2503. rc.left = lpDIS->rcItem.left;
  2504. rc.right = lpDIS->rcItem.right;
  2505. rcMenu = rc; // This is the rect of the whole menu
  2506. // !!!
  2507. // Deflate the rect to the area we want the channel to be
  2508. // drawn in. Use HACKY constants.
  2509. // !!!
  2510. i = (rc.right - rc.left - WIDTH_FROM_THIN_AIR) / 2;
  2511. rc.top += CHANNEL_INDENT;
  2512. rc.bottom -= CHANNEL_INDENT;
  2513. rc.left += i;
  2514. rc.right -= i;
  2515. rcChannel = rc; // This is the rect of the channel
  2516. //
  2517. // See where the thumb belongs
  2518. //
  2519. rc = lpDIS->rcItem;
  2520. rc.bottom = rc.top + 2; // Ouch! Make sure size is 2
  2521. //
  2522. // Don't draw the thumb higher than the top of the channel
  2523. //
  2524. if (rc.top < rcChannel.top) {
  2525. rc.top = rcChannel.top;
  2526. rc.bottom = rc.top + 2; // itemHeight
  2527. }
  2528. //
  2529. // Don't draw the thumb below the bottom of the channel
  2530. //
  2531. if (rc.top > rcChannel.bottom - 2) { // where border is
  2532. rc.top = rcChannel.bottom - 2;
  2533. rc.bottom = rc.top + 2;
  2534. }
  2535. //
  2536. // Munge the rect in a bit and draw the thumb there
  2537. //
  2538. rc.left += 2;
  2539. rc.right -= 2;
  2540. rc.bottom+= THUMB;
  2541. rc.top -= THUMB;
  2542. #if 0
  2543. // Make the thumb a little bigger on the checked value
  2544. if (lpDIS->itemState & ODS_CHECKED) {
  2545. rc.top -= 1;
  2546. rc.bottom += 1;
  2547. }
  2548. #endif
  2549. rcThumb = rc; // This is the rect of the thumb
  2550. dx = rc.right - rc.left;
  2551. dy = rc.bottom - rc.top;
  2552. SetBkColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
  2553. PatRect(hdc, rc.left+1, rc.top, dx-2,1 );
  2554. PatRect(hdc, rc.left+1, rc.bottom-1,dx-2,1 );
  2555. PatRect(hdc, rc.left, rc.top+1, 1,dy-2 );
  2556. PatRect(hdc, rc.right-1, rc.top+1, 1,dy-2 );
  2557. InflateRect(&rc,-1,-1);
  2558. dx = rc.right - rc.left;
  2559. dy = rc.bottom - rc.top;
  2560. // SetBkColor(hdc, GetSysColor(COLOR_BTNHILIGHT));
  2561. SetBkColor(hdc, RGB(255,255,255));
  2562. PatRect(hdc, rc.left, rc.top, 1,dy);
  2563. PatRect(hdc, rc.left, rc.top, dx,1);
  2564. SetBkColor(hdc, GetSysColor(COLOR_BTNSHADOW));
  2565. PatRect(hdc, rc.right-1,rc.top+1, 1,dy-1);
  2566. PatRect(hdc, rc.left+1, rc.bottom-1, dx-1,1);
  2567. InflateRect(&rc,-1,-1);
  2568. SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
  2569. SelectObject(hdc, p->hfont);
  2570. len = wsprintf(ach, "%d", lpMIS->itemID % 1000);
  2571. dw = GetTextExtent(hdc, ach, len);
  2572. ExtTextOut(hdc,
  2573. (rc.right + rc.left - LOWORD(dw))/2,
  2574. (rc.bottom + rc.top - HIWORD(dw))/2,
  2575. ETO_OPAQUE,&rc,ach,len,NULL);
  2576. // FillRC(hdc, &rc);
  2577. //
  2578. // Exclude the ClipRect that all that garbage drew into
  2579. //
  2580. ExcludeClipRect(hdc, rcThumb.left, rcThumb.top,
  2581. rcThumb.right, rcThumb.bottom);
  2582. #if 0 // why?
  2583. ExcludeClipRect(hdc, rcThumb.left+1, rcThumb.top,
  2584. rcThumb.right-1, rcThumb.bottom);
  2585. ExcludeClipRect(hdc, rcThumb.left, rcThumb.top+1,
  2586. rcThumb.left+1, rcThumb.bottom-1);
  2587. ExcludeClipRect(hdc, rcThumb.right-1, rcThumb.top+1,
  2588. rcThumb.right, rcThumb.bottom-1);
  2589. #endif
  2590. //
  2591. // Next, draw the channel
  2592. //
  2593. DrawChannel(hdc, &rcChannel);
  2594. ExcludeClipRect(hdc, rcChannel.left, rcChannel.top,
  2595. rcChannel.right, rcChannel.bottom);
  2596. //
  2597. // Lastly, fill the entire menu rect with the menu colour
  2598. //
  2599. SetBkColor(hdc, GetSysColor(COLOR_MENU));
  2600. FillRC(hdc, &rcMenu);
  2601. }
  2602. return TRUE;
  2603. case WM_DELETEITEM:
  2604. return TRUE;
  2605. }
  2606. return TRUE;
  2607. }
  2608. //
  2609. // Code to implement the MCI command dialog box
  2610. //
  2611. void PositionWindowNearParent(HWND hwnd)
  2612. {
  2613. RECT rc;
  2614. RECT rcParent;
  2615. GetWindowRect(hwnd, &rc);
  2616. rc.bottom -= rc.top;
  2617. rc.right -= rc.left;
  2618. GetWindowRect(GetParent(hwnd), &rcParent);
  2619. if (rcParent.bottom + rc.bottom <
  2620. GetSystemMetrics(SM_CYSCREEN)) {
  2621. SetWindowPos(hwnd, NULL,
  2622. min(rc.left, GetSystemMetrics(SM_CXSCREEN) - rc.right),
  2623. rcParent.bottom,
  2624. 0, 0,
  2625. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  2626. } else if (rc.bottom < rcParent.top) {
  2627. SetWindowPos(hwnd, NULL,
  2628. min(rc.left, GetSystemMetrics(SM_CXSCREEN) - rc.right),
  2629. rcParent.top - rc.bottom,
  2630. 0, 0,
  2631. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  2632. }
  2633. }
  2634. /*--------------------------------------------------------------+
  2635. | mciDialog - bring up the dialog for MCI Send Command |
  2636. | |
  2637. +--------------------------------------------------------------*/
  2638. BOOL FAR PASCAL _loadds mciDlgProc(HWND hwnd, unsigned msg, WPARAM wParam, LPARAM lParam)
  2639. {
  2640. char ach[255];
  2641. UINT w;
  2642. DWORD dw;
  2643. PMCIWND p;
  2644. HWND hwndP;
  2645. switch (msg)
  2646. {
  2647. case WM_INITDIALOG:
  2648. // Remember our actually true parent
  2649. SetWindowLong(hwnd, DWL_USER, lParam);
  2650. PositionWindowNearParent(hwnd);
  2651. return TRUE;
  2652. case WM_COMMAND:
  2653. switch (LOWORD(wParam))
  2654. {
  2655. case IDOK:
  2656. #ifdef WIN32
  2657. SendDlgItemMessage(hwnd, IDC_MCICOMMAND, EM_SETSEL, 0, (LPARAM)-1);
  2658. #else
  2659. SendDlgItemMessage(hwnd, IDC_MCICOMMAND, EM_SETSEL, 0, MAKELONG(0, -1));
  2660. #endif
  2661. w = GetDlgItemText(hwnd, IDC_MCICOMMAND, ach, sizeof(ach));
  2662. hwndP = (HWND)GetWindowLong(hwnd, DWL_USER);
  2663. p = (PMCIWND)(UINT)GetWindowLong(hwndP, 0);
  2664. // special case the CLOSE command to do our clean up
  2665. if (lstrcmpi((LPSTR)ach, szClose) == 0) {
  2666. MCIWndClose(hwndP);
  2667. break;
  2668. }
  2669. dw = MCIWndGet(p, ach, ach, sizeof(ach));
  2670. if (dw != 0)
  2671. mciGetErrorString(dw, ach, sizeof(ach));
  2672. SetDlgItemText(hwnd, IDC_RESULT, ach);
  2673. // kick ourselves in case mode changed from this command
  2674. MCIWndiTimerStuff(p);
  2675. break;
  2676. case IDCANCEL:
  2677. EndDialog(hwnd, FALSE);
  2678. break;
  2679. }
  2680. break;
  2681. }
  2682. return FALSE;
  2683. }
  2684. static BOOL NEAR PASCAL mciDialog(HWND hwnd)
  2685. {
  2686. DialogBoxParam(hInst, MAKEINTATOM(DLG_MCICOMMAND), hwnd,
  2687. (DLGPROC)mciDlgProc, hwnd);
  2688. return TRUE;
  2689. }
  2690. //
  2691. // Code to implement the Copy command:
  2692. //
  2693. //
  2694. // MCIWnd tries to copy the same things to the clipboard that VfW MPlayer
  2695. // would have.
  2696. //
  2697. #define SLASH(c) ((c) == '/' || (c) == '\\')
  2698. /**************************************************************************
  2699. convert a file name to a fully qualifed path name, if the file
  2700. exists on a net drive the UNC name is returned.
  2701. ***************************************************************************/
  2702. static BOOL NetParseFile(LPSTR szFile, LPSTR szPath)
  2703. {
  2704. char achDrive[4];
  2705. char achRemote[128];
  2706. int cbRemote = sizeof(achRemote);
  2707. OFSTRUCT of;
  2708. if (szPath == NULL)
  2709. szPath = szFile;
  2710. else
  2711. szPath[0] = 0;
  2712. //
  2713. // Fully qualify the file name
  2714. //
  2715. if (OpenFile(szFile, &of, OF_PARSE) == -1)
  2716. return FALSE;
  2717. lstrcpy(szPath, of.szPathName);
  2718. //
  2719. // if the file is not drive based (probably UNC)
  2720. //
  2721. if (szPath[1] != ':')
  2722. return TRUE;
  2723. achDrive[0] = szPath[0];
  2724. achDrive[1] = ':';
  2725. achDrive[2] = '\0';
  2726. if (WNetGetConnection(achDrive, achRemote, &cbRemote) != WN_SUCCESS)
  2727. return FALSE;
  2728. if (!SLASH(achRemote[0]) || !SLASH(achRemote[1]))
  2729. return TRUE;
  2730. lstrcat(achRemote, szPath+2);
  2731. lstrcpy(szPath, achRemote);
  2732. return TRUE;
  2733. }
  2734. SZCODE aszMPlayerName[] = "MPlayer";
  2735. HANDLE GetMPlayerData(PMCIWND p)
  2736. {
  2737. char szFileName[128];
  2738. char ach[40];
  2739. char szDevice[40];
  2740. HANDLE h;
  2741. LPSTR psz;
  2742. int len;
  2743. LPSTR lpszCaption = szFileName;
  2744. UINT wOptions;
  2745. RECT rc;
  2746. BOOL fCompound, fFile;
  2747. DWORD dw;
  2748. MCI_GETDEVCAPS_PARMS mciDevCaps; /* for the MCI_GETDEVCAPS command */
  2749. //
  2750. // Get the Device Name
  2751. //
  2752. MCIWndGet(p, "sysinfo installname", szDevice, sizeof(szDevice));
  2753. //
  2754. // determine if the device is simple or compound
  2755. //
  2756. mciDevCaps.dwItem = MCI_GETDEVCAPS_COMPOUND_DEVICE;
  2757. dw = mciSendCommand(p->wDeviceID, MCI_GETDEVCAPS,
  2758. MCI_GETDEVCAPS_ITEM, (DWORD)(LPSTR)&mciDevCaps);
  2759. fCompound = (dw == 0 && mciDevCaps.dwReturn != 0);
  2760. //
  2761. // determine if the device handles files
  2762. //
  2763. if (fCompound) {
  2764. mciDevCaps.dwItem = MCI_GETDEVCAPS_USES_FILES;
  2765. dw = mciSendCommand(p->wDeviceID, MCI_GETDEVCAPS,
  2766. MCI_GETDEVCAPS_ITEM, (DWORD)(LPSTR)&mciDevCaps);
  2767. fFile = (dw == 0 && mciDevCaps.dwReturn != 0);
  2768. }
  2769. //
  2770. // Compound devices that support files have an associated filename
  2771. //
  2772. if (fCompound && fFile) {
  2773. lstrcpy(szFileName, p->achFileName);
  2774. //
  2775. // Sometimes the filename is really "device!filename" so we have to peel
  2776. // the real filename out of it
  2777. //
  2778. lstrcpyn(ach, szFileName, lstrlen(szDevice) + 1);
  2779. if ((lstrcmpi(szDevice, ach) == 0) &&
  2780. (szFileName[lstrlen(szDevice)] == '!')) {
  2781. lstrcpy(szFileName, &(p->achFileName[lstrlen(szDevice) + 1]));
  2782. }
  2783. NetParseFile(szFileName, (LPSTR)NULL);
  2784. OemToAnsi(szFileName,szFileName); // Map extended chars.
  2785. } else {
  2786. szFileName[0] = 0;
  2787. }
  2788. #ifdef DEBUG
  2789. DPF(" GetLink: %s|%s!%s\n",
  2790. (LPSTR)aszMPlayerName,
  2791. (LPSTR)szFileName,
  2792. (LPSTR)szDevice);
  2793. #endif
  2794. /* How much data will we be writing? */
  2795. len = 9 + // all the delimeters
  2796. lstrlen(aszMPlayerName) +
  2797. lstrlen(szFileName) +
  2798. lstrlen(szDevice) +
  2799. 5 + 10 + 10 + 10 + // max length of int and long strings
  2800. lstrlen(lpszCaption);
  2801. h = GlobalAlloc(GMEM_DDESHARE|GMEM_ZEROINIT, len);
  2802. if (!h)
  2803. return NULL;
  2804. psz = GlobalLock(h);
  2805. wOptions = 0x0030; // !!!! OPT_PLAY|OPT_BAR
  2806. switch (MCIWndStatus(p, MCI_STATUS_TIME_FORMAT, 0)) {
  2807. case MCI_FORMAT_FRAMES:
  2808. wOptions |= 1; // frame mode
  2809. break;
  2810. case MCI_FORMAT_MILLISECONDS:
  2811. wOptions |= 2; // time mode
  2812. break;
  2813. }
  2814. MCIWndRect(p, &rc, FALSE);
  2815. wsprintf(psz, "%s%c%s%c%s%c%d%c%ld%c%ld%c%ld%c%d%c%s%c",
  2816. (LPSTR)aszMPlayerName, 0,
  2817. (LPSTR)szFileName, 0,
  2818. (LPSTR)szDevice, ',',
  2819. wOptions, ',',
  2820. 0L, ',', // !!! sel start
  2821. 0L, ',', // !!! sel length
  2822. p->dwPos, ',',
  2823. rc.bottom - rc.top, ',',
  2824. lpszCaption, 0);
  2825. return h;
  2826. }
  2827. HBITMAP FAR PASCAL BitmapMCI(PMCIWND p)
  2828. {
  2829. HDC hdc, hdcMem;
  2830. HBITMAP hbm, hbmT;
  2831. HBRUSH hbrOld;
  2832. DWORD dw;
  2833. RECT rc;
  2834. HBRUSH hbrWindowColour;
  2835. /* Minimum size of bitmap is icon size */
  2836. int ICON_MINX = GetSystemMetrics(SM_CXICON);
  2837. int ICON_MINY = GetSystemMetrics(SM_CYICON);
  2838. /* Get size of a frame or an icon that we'll be drawing */
  2839. MCIWndRect(p, &rc, FALSE);
  2840. SetRect(&rc, 0, 0,
  2841. max(ICON_MINX, rc.right - rc.left),
  2842. max(ICON_MINX, rc.bottom - rc.top));
  2843. hdc = GetDC(NULL);
  2844. if (hdc == NULL)
  2845. return NULL;
  2846. hdcMem = CreateCompatibleDC(NULL);
  2847. if (hdcMem == NULL) {
  2848. ReleaseDC(NULL, hdc);
  2849. return NULL;
  2850. }
  2851. /* Big enough to hold text caption too, if necessary */
  2852. hbm = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
  2853. ReleaseDC(NULL, hdc);
  2854. if (hbm == NULL) {
  2855. DeleteDC(hdcMem);
  2856. return NULL;
  2857. }
  2858. hbmT = SelectObject(hdcMem, hbm);
  2859. hbrWindowColour = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  2860. hbrOld = SelectObject(hdcMem, hbrWindowColour);
  2861. PatBlt(hdcMem, 0,0, rc.right, rc.bottom, PATCOPY);
  2862. SelectObject(hdcMem, hbrOld);
  2863. DeleteObject(hbrWindowColour);
  2864. if (p->wDeviceID && p->fCanWindow)
  2865. {
  2866. MCI_ANIM_UPDATE_PARMS mciUpdate;
  2867. mciUpdate.hDC = hdcMem;
  2868. dw = mciSendCommand(p->wDeviceID, MCI_UPDATE,
  2869. MCI_ANIM_UPDATE_HDC | MCI_WAIT,
  2870. (DWORD)(LPVOID)&mciUpdate);
  2871. } else {
  2872. DrawIcon(hdcMem, rc.left, rc.top, p->hicon);
  2873. }
  2874. if (hbmT)
  2875. SelectObject(hdcMem, hbmT);
  2876. DeleteDC(hdcMem);
  2877. return hbm;
  2878. }
  2879. HPALETTE CopyPalette(HPALETTE hpal)
  2880. {
  2881. PLOGPALETTE ppal;
  2882. int nNumEntries;
  2883. int i;
  2884. if (!hpal)
  2885. return NULL;
  2886. GetObject(hpal,sizeof(int),(LPSTR)&nNumEntries);
  2887. if (nNumEntries == 0)
  2888. return NULL;
  2889. ppal = (PLOGPALETTE)LocalAlloc(LPTR,sizeof(LOGPALETTE) +
  2890. nNumEntries * sizeof(PALETTEENTRY));
  2891. if (!ppal)
  2892. return NULL;
  2893. ppal->palVersion = 0x300;
  2894. ppal->palNumEntries = nNumEntries;
  2895. GetPaletteEntries(hpal,0,nNumEntries,ppal->palPalEntry);
  2896. for (i=0; i<nNumEntries; i++)
  2897. ppal->palPalEntry[i].peFlags = 0;
  2898. hpal = CreatePalette(ppal);
  2899. LocalFree((HANDLE)ppal);
  2900. return hpal;
  2901. }
  2902. HANDLE FAR PASCAL PictureFromDib(HANDLE hdib, HPALETTE hpal)
  2903. {
  2904. LPMETAFILEPICT pmfp;
  2905. HANDLE hmfp;
  2906. HANDLE hmf;
  2907. HANDLE hdc;
  2908. LPBITMAPINFOHEADER lpbi;
  2909. if (!hdib)
  2910. return NULL;
  2911. lpbi = (LPVOID)GlobalLock(hdib);
  2912. if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
  2913. lpbi->biClrUsed = 1 << lpbi->biBitCount;
  2914. hdc = CreateMetaFile(NULL);
  2915. if (!hdc)
  2916. return NULL;
  2917. SetWindowOrgEx(hdc, 0, 0, NULL);
  2918. SetWindowExtEx(hdc, (int)lpbi->biWidth, (int)lpbi->biHeight, NULL);
  2919. if (hpal)
  2920. {
  2921. SelectPalette(hdc,hpal,FALSE);
  2922. RealizePalette(hdc);
  2923. }
  2924. SetStretchBltMode(hdc, COLORONCOLOR);
  2925. StretchDIBits(hdc,
  2926. 0,0,(int)lpbi->biWidth, (int)lpbi->biHeight,
  2927. 0,0,(int)lpbi->biWidth, (int)lpbi->biHeight,
  2928. (LPBYTE)lpbi + (int)lpbi->biSize + (int)lpbi->biClrUsed * sizeof(RGBQUAD),
  2929. (LPBITMAPINFO)lpbi,
  2930. DIB_RGB_COLORS,
  2931. SRCCOPY);
  2932. if (hpal)
  2933. SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
  2934. hmf = CloseMetaFile(hdc);
  2935. if (hmfp = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT)))
  2936. {
  2937. pmfp = (LPMETAFILEPICT)GlobalLock(hmfp);
  2938. hdc = GetDC(NULL);
  2939. #if 1
  2940. pmfp->mm = MM_ANISOTROPIC;
  2941. pmfp->hMF = hmf;
  2942. pmfp->xExt = MulDiv((int)lpbi->biWidth ,2540,GetDeviceCaps(hdc, LOGPIXELSX));
  2943. pmfp->yExt = MulDiv((int)lpbi->biHeight,2540,GetDeviceCaps(hdc, LOGPIXELSX));
  2944. #else
  2945. pmfp->mm = MM_TEXT;
  2946. pmfp->hMF = hmf;
  2947. pmfp->xExt = (int)lpbi->biWidth;
  2948. pmfp->yExt = (int)lpbi->biHeight;
  2949. #endif
  2950. ReleaseDC(NULL, hdc);
  2951. }
  2952. else
  2953. {
  2954. DeleteMetaFile(hmf);
  2955. }
  2956. return hmfp;
  2957. }
  2958. #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  2959. /*
  2960. * DibFromBitmap()
  2961. *
  2962. * Will create a global memory block in DIB format that represents the DDB
  2963. * passed in
  2964. *
  2965. */
  2966. HANDLE FAR PASCAL DibFromBitmap(HBITMAP hbm, HPALETTE hpal)
  2967. {
  2968. BITMAP bm;
  2969. BITMAPINFOHEADER bi;
  2970. BITMAPINFOHEADER FAR *lpbi;
  2971. DWORD dw;
  2972. HANDLE hdib;
  2973. HDC hdc;
  2974. HPALETTE hpalT;
  2975. if (!hbm)
  2976. return NULL;
  2977. GetObject(hbm,sizeof(bm),(LPSTR)&bm);
  2978. bi.biSize = sizeof(BITMAPINFOHEADER);
  2979. bi.biWidth = bm.bmWidth;
  2980. bi.biHeight = bm.bmHeight;
  2981. bi.biPlanes = 1;
  2982. bi.biBitCount = (bm.bmPlanes * bm.bmBitsPixel) > 8 ? 24 : 8;
  2983. bi.biCompression = BI_RGB;
  2984. bi.biSizeImage = (DWORD)WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight;
  2985. bi.biXPelsPerMeter = 0;
  2986. bi.biYPelsPerMeter = 0;
  2987. bi.biClrUsed = bi.biBitCount == 8 ? 256 : 0;
  2988. bi.biClrImportant = 0;
  2989. dw = bi.biSize + bi.biClrUsed * sizeof(RGBQUAD) + bi.biSizeImage;
  2990. hdib = GlobalAlloc(GHND | GMEM_DDESHARE, dw);
  2991. if (!hdib)
  2992. return NULL;
  2993. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
  2994. *lpbi = bi;
  2995. hdc = CreateCompatibleDC(NULL);
  2996. if (hpal)
  2997. {
  2998. hpalT = SelectPalette(hdc,hpal,FALSE);
  2999. RealizePalette(hdc);
  3000. }
  3001. GetDIBits(hdc, hbm, 0, (UINT)bi.biHeight,
  3002. (LPSTR)lpbi + (int)lpbi->biSize + (int)lpbi->biClrUsed * sizeof(RGBQUAD),
  3003. (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
  3004. if (hpal)
  3005. SelectPalette(hdc,hpalT,FALSE);
  3006. DeleteDC(hdc);
  3007. return hdib;
  3008. }
  3009. SZCODE aszNative[] = "Native";
  3010. SZCODE aszOwnerLink[] = "OwnerLink";
  3011. // Pretend to be MPlayer copying to the clipboard
  3012. static void NEAR PASCAL MCIWndCopy(PMCIWND p)
  3013. {
  3014. UINT cfNative;
  3015. UINT cfOwnerLink;
  3016. HBITMAP hbm;
  3017. HPALETTE hpal;
  3018. HANDLE hdib;
  3019. HANDLE hmfp;
  3020. cfNative = RegisterClipboardFormat(aszNative);
  3021. cfOwnerLink = RegisterClipboardFormat(aszOwnerLink);
  3022. if (p->wDeviceID) {
  3023. OpenClipboard(p->hwnd);
  3024. EmptyClipboard();
  3025. SetClipboardData(cfNative, GetMPlayerData(p));
  3026. SetClipboardData(cfOwnerLink, GetMPlayerData(p));
  3027. hbm = BitmapMCI(p);
  3028. hpal = MCIWndGetPalette(p->hwnd);
  3029. hpal = CopyPalette(hpal);
  3030. if (hbm) {
  3031. hdib = DibFromBitmap(hbm, hpal);
  3032. hmfp = PictureFromDib(hdib, hpal);
  3033. if (hmfp)
  3034. SetClipboardData(CF_METAFILEPICT, hmfp);
  3035. if (hdib)
  3036. SetClipboardData(CF_DIB, hdib);
  3037. DeleteObject(hbm);
  3038. }
  3039. if (hpal)
  3040. SetClipboardData(CF_PALETTE, hpal);
  3041. CloseClipboard();
  3042. }
  3043. }
  3044. /*****************************************************************************
  3045. ****************************************************************************/
  3046. #ifdef DEBUG
  3047. static void cdecl dprintf(PSTR szFormat, ...)
  3048. {
  3049. char ach[128];
  3050. static BOOL fDebug = -1;
  3051. if (fDebug == -1)
  3052. fDebug = GetProfileInt(szDebug, MODNAME, FALSE);
  3053. if (!fDebug)
  3054. return;
  3055. lstrcpy(ach, MODNAME ": ");
  3056. wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
  3057. lstrcat(ach, "\r\n");
  3058. OutputDebugString(ach);
  3059. }
  3060. #endif