Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3744 lines
109 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 = 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. // Put a unused menu item at the top. When WINDOWS tries to select
  760. // it after we bring up the menu, we won't let it. We want the
  761. // thumb to stay on the current value.
  762. AppendMenu(hmenuVolume, MF_ENABLED | MF_OWNERDRAW,
  763. IDM_MCIVOLUME + VOLUME_MAX + 1, NULL);
  764. // Create all the Real menu items. Make the menu VOLUME_MAX items
  765. // tall even though the number of unique entries may be less
  766. for (i=IDM_MCIVOLUME + p->wMaxVol; i>=IDM_MCIVOLUME; i-=5)
  767. for (j=0; j < VOLUME_MAX / p->wMaxVol; j++)
  768. AppendMenu(hmenuVolume, MF_ENABLED | MF_OWNERDRAW, i, NULL);
  769. // Now put a filler item at the bottom so every REAL item falls
  770. // inside the channel and there's a unique thumb position for each
  771. // item.
  772. AppendMenu(hmenuVolume, MF_ENABLED | MF_OWNERDRAW,
  773. IDM_MCIVOLUME + VOLUME_MAX + 2, NULL);
  774. // Now CHECK the current volume so the thumb can draw there
  775. // round to nearest 5 so it matches a menu item identifier
  776. i = ((int)MCIWndGetValue(p, FALSE, szStatusVolume, 1000) / 50) * 5;
  777. CheckMenuItem(hmenuVolume, IDM_MCIVOLUME + i, MF_CHECKED);
  778. }
  779. }
  780. //
  781. // Create the SPEED sub-popup
  782. //
  783. if (p->wDeviceID && p->fSpeed) {
  784. hmenuSpeed = CreatePopupMenu();
  785. if (hmenuSpeed) {
  786. // Put a unused menu item at the top. When WINDOWS tries to select
  787. // it after we bring up the menu, we won't let it. We want the
  788. // thumb to stay on the current value.
  789. AppendMenu(hmenuSpeed, MF_ENABLED | MF_OWNERDRAW,
  790. IDM_MCISPEED + SPEED_MAX + 1, NULL);
  791. // Create all the Real menu items
  792. for (i=IDM_MCISPEED + SPEED_MAX; i>=IDM_MCISPEED; i-=5)
  793. AppendMenu(hmenuSpeed, MF_ENABLED | MF_OWNERDRAW, i, NULL);
  794. // Now put a filler item at the bottom so every REAL item falls
  795. // inside the channel and there's a unique thumb position for each
  796. // item.
  797. AppendMenu(hmenuSpeed, MF_ENABLED | MF_OWNERDRAW,
  798. IDM_MCISPEED + SPEED_MAX + 2, NULL);
  799. // Now CHECK the current speed so the thumb can draw there
  800. // round to nearest 5 so it matches a menu item identifier
  801. i = ((int)MCIWndGetValue(p, FALSE, szStatusSpeed, 1000) / 50) * 5;
  802. CheckMenuItem(hmenuSpeed, IDM_MCISPEED + i, MF_CHECKED);
  803. }
  804. }
  805. hmenu = CreatePopupMenu();
  806. if (hmenu) {
  807. if (p->wDeviceID && p->dwStyle & MCIWNDF_NOPLAYBAR) {
  808. if (p->fCanPlay) {
  809. AppendMenu(hmenu, MF_ENABLED, MCI_PLAY, LoadSz(IDS_PLAY));
  810. AppendMenu(hmenu, MF_ENABLED, MCI_STOP, LoadSz(IDS_STOP));
  811. }
  812. if (p->fCanRecord && (p->dwStyle & MCIWNDF_RECORD))
  813. AppendMenu(hmenu, MF_ENABLED, MCI_RECORD, LoadSz(IDS_RECORD));
  814. if (p->fCanEject)
  815. AppendMenu(hmenu, MF_ENABLED, IDM_MCIEJECT, LoadSz(IDS_EJECT));
  816. if (p->fCanPlay ||
  817. (p->fCanRecord && (p->dwStyle & MCIWNDF_RECORD)) ||
  818. p->fCanEject)
  819. AppendMenu(hmenu, MF_SEPARATOR, NULL, NULL);
  820. }
  821. if (hmenuWindow)
  822. AppendMenu(hmenu, MF_ENABLED|MF_POPUP, (UINT)hmenuWindow,
  823. LoadSz(IDS_VIEW));
  824. if (hmenuVolume)
  825. AppendMenu(hmenu, MF_ENABLED|MF_POPUP, (UINT)hmenuVolume,
  826. LoadSz(IDS_VOLUME));
  827. if (hmenuSpeed)
  828. AppendMenu(hmenu, MF_ENABLED|MF_POPUP, (UINT)hmenuSpeed,
  829. LoadSz(IDS_SPEED));
  830. if (hmenuWindow || hmenuVolume || hmenuSpeed)
  831. AppendMenu(hmenu, MF_SEPARATOR, NULL, NULL);
  832. if (p->wDeviceID && p->fCanRecord && (p->dwStyle & MCIWNDF_RECORD))
  833. AppendMenu(hmenu, MF_ENABLED, IDM_MCINEW, LoadSz(IDS_NEW));
  834. if (!(p->dwStyle & MCIWNDF_NOOPEN))
  835. AppendMenu(hmenu, MF_ENABLED, IDM_MCIOPEN, LoadSz(IDS_OPEN));
  836. if (p->wDeviceID && p->fCanSave && (p->dwStyle & MCIWNDF_RECORD))
  837. AppendMenu(hmenu, MF_ENABLED, MCI_SAVE, LoadSz(IDS_SAVE));
  838. if (p->wDeviceID) {
  839. if (!(p->dwStyle & MCIWNDF_NOOPEN)) {
  840. AppendMenu(hmenu, MF_ENABLED, IDM_MCICLOSE, LoadSz(IDS_CLOSE));
  841. AppendMenu(hmenu, MF_SEPARATOR, NULL, NULL);
  842. }
  843. AppendMenu(hmenu, MF_ENABLED, IDM_COPY, LoadSz(IDS_COPY));
  844. if (p->fCanConfig)
  845. AppendMenu(hmenu, MF_ENABLED, IDM_MCICONFIG,
  846. LoadSz(IDS_CONFIGURE));
  847. // !!! Should we only show this in debug, or if a flag is set?
  848. AppendMenu(hmenu, MF_ENABLED, IDM_MCICOMMAND, LoadSz(IDS_COMMAND));
  849. }
  850. p->hmenu = hmenu;
  851. p->hmenuVolume = hmenuVolume;
  852. p->hmenuSpeed = hmenuSpeed;
  853. CreateDitherBrush(FALSE); // we'll need this to paint OwnerDraw
  854. }
  855. }
  856. //
  857. // Set up everything for an empty window
  858. //
  859. static LONG MCIWndiClose(PMCIWND p, BOOL fRedraw)
  860. {
  861. MCI_GENERIC_PARMS mciGeneric;
  862. // Oh no! The MCI device (probably MMP) has hooked our window proc and if
  863. // we close the device, it will go away, and the hook will DIE! We need to
  864. // do everything BUT the closing of the device. We'll delay that.
  865. if (GetWindowLong(p->hwnd, GWL_WNDPROC) != (LONG)MCIWndProc &&
  866. p->wDeviceID && p->fCanWindow) {
  867. MCIWndString(p, FALSE, szWindowHandle, NULL); // GO AWAY, DEVICE!
  868. PostMessage(p->hwnd, MCI_CLOSE, 0, p->wDeviceID);
  869. } else if (p->wDeviceID)
  870. // buggy drivers crash if we pass a null parms address
  871. mciSendCommand(p->wDeviceID, MCI_CLOSE, 0, (DWORD)(LPVOID)&mciGeneric);
  872. //
  873. // if the device had a palette, we need to send palette changes to
  874. // every window because we just deleted the palette that was realized.
  875. //
  876. if (p->fHasPalette) {
  877. // If we're dying this won't go through unless we SEND
  878. SendMessage(p->hwnd, MCIWNDM_PALETTEKICK, 0, 0);
  879. }
  880. // execute this function even if there's no deviceID since we may want
  881. // to gray things
  882. // The next timer will kill itself since wDeviceID is NULL
  883. p->wDeviceID = 0;
  884. p->achFileName[0] = 0; // kill the filename
  885. p->dwMediaLen = 0; // so next open will invalidate media
  886. // We don't want to redraw cuz we're opening a new file right away
  887. if (!fRedraw)
  888. return 0;
  889. // One of the show bits is on... clear the caption
  890. if (p->dwStyle & MCIWNDF_SHOWALL)
  891. SetWindowText(p->hwnd, LoadSz(IDS_NODEVICE));
  892. // Gray all the stuff on the playbar
  893. MCIWndiFixMyPlaybar(p);
  894. // Make an appropriate menu for our null device
  895. MCIWndiMakeMeAMenu(p);
  896. // Possibly snap ourselves to a small size since there's no device loaded
  897. // Also reposition the toolbar after it's been fixed up
  898. MCIWndiSize(p, 0);
  899. // We need to notify our "owner" that we've closed
  900. if (p->dwStyle & MCIWNDF_NOTIFYMEDIA)
  901. NotifyOwner(p, MCIWNDM_NOTIFYMEDIA, p->hwnd, (LPARAM)(LPVOID)szNULL);
  902. InvalidateRect(p->hwnd, NULL, TRUE);
  903. return 0;
  904. }
  905. //
  906. // This is the WM_CREATE msg of our WndProc
  907. //
  908. static BOOL MCIWndiCreate(HWND hwnd, LONG lParam)
  909. {
  910. PMCIWND p;
  911. DWORD dw;
  912. char ach[20];
  913. HWND hwndP;
  914. p = (PMCIWND)LocalAlloc(LPTR, sizeof(MCIWND));
  915. if (!p)
  916. return FALSE;
  917. SetWindowLong(hwnd, 0, (LONG)(UINT)p);
  918. p->hwnd = hwnd;
  919. p->hwndOwner = GetParent(hwnd); // we'll send notifications here
  920. p->alias = (UINT)hwnd;
  921. p->dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  922. DragAcceptFiles(p->hwnd, (p->dwStyle & (MCIWNDF_NOMENU | MCIWNDF_NOOPEN)) == 0);
  923. if (!(p->dwStyle & WS_CAPTION))
  924. p->dwStyle &= ~MCIWNDF_SHOWALL;
  925. dw = (DWORD)((LPCREATESTRUCT)lParam)->lpCreateParams;
  926. //
  927. // see if we are in a MDIClient
  928. //
  929. if ((p->dwStyle & WS_CHILD) && (hwndP = GetParent(hwnd))) {
  930. GetClassName(hwndP, ach, sizeof(ach));
  931. p->fMdiWindow = lstrcmpi(ach, szMDIClient) == 0;
  932. if (p->fMdiWindow)
  933. dw = ((LPMDICREATESTRUCT)dw)->lParam;
  934. }
  935. MCIWndiMakeMeAPlaybar(p);
  936. // if (szOpenFilter[0] == 0)
  937. // MCIWndiBuildMeAFilter(szOpenFilter);
  938. // Set the default timer frequencies
  939. p->iActiveTimerRate = ACTIVE_TIMER;
  940. p->iInactiveTimerRate = INACTIVE_TIMER;
  941. // initialize the OFN structure we'll use to open files
  942. p->achFileName[0] = '\0';
  943. p->ofn.lStructSize = sizeof(OPENFILENAME);
  944. p->ofn.hwndOwner = hwnd;
  945. p->ofn.hInstance = NULL;
  946. // p->ofn.lpstrFilter = szOpenFilter;
  947. p->ofn.lpstrCustomFilter = NULL;
  948. p->ofn.nMaxCustFilter = 0;
  949. p->ofn.nFilterIndex = 0;
  950. ; p->ofn.lpstrFile = p->achFileName;
  951. ; p->ofn.nMaxFile = sizeof(p->achFileName);
  952. p->ofn.lpstrFileTitle = NULL;
  953. p->ofn.nMaxFileTitle = 0;
  954. p->ofn.lpstrInitialDir = NULL;
  955. p->ofn.lpstrTitle = NULL; // "Open Device";
  956. p->ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  957. p->ofn.nFileOffset = 0;
  958. p->ofn.nFileExtension = 0;
  959. p->ofn.lpstrDefExt = NULL;
  960. p->ofn.lCustData = 0;
  961. p->ofn.lpfnHook = NULL;
  962. p->ofn.lpTemplateName = NULL;
  963. p->hicon = LoadIcon(hInst, MAKEINTRESOURCE(MPLAYERICON));
  964. // Gray stuff; disable things that aren't applicable with no device loaded
  965. MCIWndClose(hwnd);
  966. if (dw && *(LPSTR)dw) // treat extra parm as a filename
  967. MCIWndOpen(hwnd, (LPSTR)dw, 0);
  968. return TRUE;
  969. }
  970. //
  971. // Brings up an OpenDialog or a SaveDialog for the application and returns the
  972. // filename. Returns TRUE if a file name was chosen, FALSE on error or CANCEL.
  973. //
  974. static BOOL MCIWndOpenDlg(PMCIWND p, BOOL fSave, LPSTR szFile, int len)
  975. {
  976. BOOL f;
  977. // !!! Maybe this is a device name and our GetOpenFileName will fail.
  978. // !!! Find someway of bringing up an initial filename anyway?
  979. szFile[0] = 0;
  980. p->ofn.lpstrFile = szFile;
  981. p->ofn.nMaxFile = len;
  982. if (fSave)
  983. p->ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  984. else
  985. p->ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  986. //
  987. // use achReturn to hold the MCI Filter.
  988. //
  989. MCIWndiBuildMeAFilter(p->achReturn);
  990. p->ofn.lpstrFilter = p->achReturn;
  991. /* prompt user for file to open or save */
  992. if (fSave)
  993. f = GetSaveFileNamePreview(&(p->ofn));
  994. else
  995. f = GetOpenFileNamePreview(&(p->ofn));
  996. return f;
  997. }
  998. // Set our timer, if it's needed
  999. static void MCIWndiSetTimer(PMCIWND p)
  1000. {
  1001. // We need a TIMER to notify the "owner" when things change
  1002. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR) ||
  1003. (p->dwStyle & MCIWNDF_NOTIFYMODE) ||
  1004. (p->dwStyle & MCIWNDF_SHOWMODE) ||
  1005. (p->dwStyle & MCIWNDF_SHOWPOS) ||
  1006. (p->dwStyle & MCIWNDF_NOTIFYPOS)) {
  1007. p->wTimer = SetTimer(p->hwnd, TIMER1,
  1008. p->fActive? p->iActiveTimerRate : p->iInactiveTimerRate,
  1009. NULL);
  1010. }
  1011. }
  1012. //
  1013. // Save a file. Returns 0 for success
  1014. //
  1015. static LONG MCIWndiSave(PMCIWND p, WORD wFlags, LPSTR szFile)
  1016. {
  1017. char ach[128];
  1018. //
  1019. // If we don't have a filename to save, then get one from a dialog
  1020. //
  1021. if (szFile == (LPVOID)-1L) {
  1022. lstrcpy(ach, p->achFileName);
  1023. if (!MCIWndOpenDlg(p, TRUE, ach, sizeof(ach)))
  1024. return -1;
  1025. szFile = ach;
  1026. }
  1027. // !!! All good little boys should be saving to background... don't wait
  1028. return MCIWndString(p, TRUE, szSave, szFile);
  1029. }
  1030. //
  1031. // Actually open a file and set up the window. Returns 0 for success
  1032. //
  1033. static LONG MCIWndiOpen(PMCIWND p, WORD wFlags, LPSTR szFile)
  1034. {
  1035. DWORD dw = 0;
  1036. HCURSOR hcurPrev;
  1037. char ach[128];
  1038. UINT wDeviceID;
  1039. BOOL fNew = wFlags & MCIWNDOPENF_NEW;
  1040. //
  1041. // We're opening an existing file, szFile is that filename
  1042. // If we don't have a filename to open, then get one from a dialog
  1043. //
  1044. if (!fNew && szFile == (LPVOID)-1L) {
  1045. lstrcpy(ach, p->achFileName);
  1046. if (!MCIWndOpenDlg(p, FALSE, ach, sizeof(ach)))
  1047. return -1;
  1048. szFile = ach;
  1049. }
  1050. //
  1051. // We want to open a new file, szFile is the device to open
  1052. // If it's NULL, we use the current device
  1053. //
  1054. if (fNew && (szFile == NULL || *szFile == 0)) {
  1055. // There is no device, so we can't do anything
  1056. if (!p->wDeviceID)
  1057. return 42; // !!! failure
  1058. MCIWndGetDevice(p->hwnd, ach, sizeof(ach));
  1059. szFile = ach;
  1060. }
  1061. // save the current device ID so we can put it back in case open fails.
  1062. wDeviceID = p->wDeviceID;
  1063. KillTimer(p->hwnd, TIMER1); // setting the deviceID to 0 will mess up timer
  1064. p->wDeviceID = 0; // and if open fails, we don't want that
  1065. p->alias++; // use a new alias
  1066. /*
  1067. * Show the hourglass cursor -- who knows how long this stuff
  1068. * will take
  1069. */
  1070. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1071. // Open a NEW file
  1072. if (fNew) {
  1073. dw = MCIWndGetValue(p, TRUE, szNew, 0,
  1074. szFile, (UINT)p->alias);
  1075. // open an existing file
  1076. } else {
  1077. // first, try to open it shareable
  1078. // don't show or update errors since we try to open it twice
  1079. //
  1080. // dont try shareable for "file" devices
  1081. // hack to check for entension.
  1082. //
  1083. if (lstrlen(szFile) > 4 && szFile[lstrlen(szFile)-4] == '.')
  1084. dw = 0;
  1085. else
  1086. dw = MCIWndGetValue(p, FALSE, szOpenShareable, 0,
  1087. (LPSTR)szFile, (UINT)p->alias);
  1088. // Error! Try again, not shareable.
  1089. if (dw == 0) {
  1090. dw = MCIWndGetValue(p, FALSE, szOpen, 0,
  1091. (LPSTR)szFile, (UINT)p->alias);
  1092. // Last ditch attempt! Try AVI. It'll open anything. This time,
  1093. // show, set errors.
  1094. if (dw == 0) {
  1095. dw = MCIWndGetValue(p, TRUE, szOpenAVI, 0,
  1096. (LPSTR)szFile, (UINT)p->alias);
  1097. }
  1098. }
  1099. }
  1100. if (hcurPrev)
  1101. SetCursor(hcurPrev);
  1102. //
  1103. // Ack! No deviceID... we failed to open
  1104. //
  1105. if (dw == 0)
  1106. {
  1107. p->wDeviceID = wDeviceID;
  1108. MCIWndiSetTimer(p); // Put the timer back now that DeviceID is back
  1109. // p->achFileName[0] = 0; // don't hurt the old filename!
  1110. p->alias--; // back to old alias
  1111. // in case error box or open box wiped us out and we didn't paint
  1112. // because our p->wDeviceID was null because of our open hack
  1113. InvalidateRect(p->hwnd, NULL, TRUE);
  1114. return p->dwError;
  1115. }
  1116. //
  1117. // it worked, now close the old device and open the new.
  1118. //
  1119. if (wDeviceID)
  1120. {
  1121. p->wDeviceID = wDeviceID;
  1122. p->alias--; // back to old alias so the close might actually work
  1123. MCIWndiClose(p, FALSE); // don't redraw
  1124. p->alias++; // new alias again (ACK!)
  1125. }
  1126. p->wDeviceID = (UINT)dw;
  1127. p->dwMode = (DWORD)~0L; // first mode set will be detected as a change
  1128. p->dwPos = (DWORD)~0L; // first pos set will be detected as a change
  1129. // Copy the file or device name into our filename spot
  1130. lstrcpy(p->achFileName, szFile);
  1131. // !!! p->wDeviceType = QueryDeviceTypeMCI(p->wDeviceID);
  1132. // Now set the playback window to be our MCI window
  1133. p->fCanWindow = MCIWndString(p, FALSE, szWindowHandle, (UINT)p->hwnd) == 0;
  1134. if (p->fCanWindow)
  1135. MCIWndGetDest(p->hwnd, &p->rcNormal);
  1136. else
  1137. SetRect(&p->rcNormal, 0, 0, 0, 0);
  1138. // Find out if the device supports palettes.
  1139. p->fHasPalette = MCIWndString(p, FALSE, szStatusPalette) == 0;
  1140. //
  1141. // Now find out the capabilities of this device
  1142. //
  1143. // !!! What about these ???
  1144. // MCI_GETDEVCAPS_DEVICE_TYPE 0x00000004L
  1145. // MCI_GETDEVCAPS_COMPOUND_DEVICE 0x00000006L
  1146. // Find out if the device can record
  1147. p->fCanRecord = MCIWndDevCaps(p, MCI_GETDEVCAPS_CAN_RECORD);
  1148. // Find out if the device can play
  1149. p->fCanPlay = MCIWndDevCaps(p, MCI_GETDEVCAPS_CAN_PLAY);
  1150. // Find out if the device can save
  1151. p->fCanSave = MCIWndDevCaps(p, MCI_GETDEVCAPS_CAN_SAVE);
  1152. // Find out if the device can eject
  1153. p->fCanEject = MCIWndDevCaps(p, MCI_GETDEVCAPS_CAN_EJECT);
  1154. // Find out if the device is file based
  1155. p->fUsesFiles = MCIWndDevCaps(p, MCI_GETDEVCAPS_USES_FILES);
  1156. // Find out if the device has video
  1157. p->fVideo = MCIWndDevCaps(p, MCI_GETDEVCAPS_HAS_VIDEO);
  1158. // Find out if the device has video
  1159. p->fAudio = MCIWndDevCaps(p, MCI_GETDEVCAPS_HAS_AUDIO);
  1160. // Find out if the device can configure
  1161. p->fCanConfig = (MCIWndString(p, FALSE, szConfigureTest) == 0);
  1162. #ifdef DEBUG
  1163. // !!! MCIAVI says no the driver...
  1164. p->fCanConfig = p->fCanWindow;
  1165. #endif
  1166. //
  1167. //
  1168. //
  1169. // Now see if we support speed - try normal, half, and max
  1170. p->fSpeed = MCIWndString(p, FALSE, szSetSpeed1000Test) == 0 &&
  1171. MCIWndString(p, FALSE, szSetSpeed500Test) == 0 &&
  1172. MCIWndString(p, FALSE, szSetSpeedTest, SPEED_MAX * 10) == 0;
  1173. // Now see if we support volume - try normal, mute, and max
  1174. p->fVolume = MCIWndString(p, FALSE, szSetVolumeTest, VOLUME_MAX * 5) ==0 &&
  1175. MCIWndString(p, FALSE, szSetVolume0Test) == 0;
  1176. p->wMaxVol = 100;
  1177. // If someone happens to support double volume, let's give it to them.
  1178. if (MCIWndString(p, FALSE, szSetVolumeTest, VOLUME_MAX * 10) == 0)
  1179. p->wMaxVol = 200;
  1180. // See if the device would support tmsf mode. If so, use milliseconds mode
  1181. // and later on we'll fake knowing where tracks begin and end
  1182. p->fHasTracks = (MCIWndString(p, FALSE, szSetFormatTMSF) == 0);
  1183. if (p->fHasTracks) {
  1184. dw = MCIWndString(p, FALSE, szSetFormatMS);
  1185. if (dw != 0)
  1186. p->fHasTracks = FALSE;
  1187. }
  1188. if (!p->fHasTracks) {
  1189. // Force us into a reasonable time format
  1190. dw = MCIWndString(p, FALSE, szSetFormatFrames);
  1191. if (dw != 0)
  1192. dw = MCIWndString(p, FALSE, szSetFormatMS);
  1193. if (dw != 0)
  1194. ; // !!! What to do? Don't turn playbar off without
  1195. } // !!! destroying it...
  1196. // Set the media length and trackbar range
  1197. MCIWndiValidateMedia(p);
  1198. // set window text
  1199. if (p->dwStyle & MCIWNDF_SHOWNAME)
  1200. SetWindowText(p->hwnd, FileName(szFile));
  1201. // Fix the toolbar buttons for the new device
  1202. MCIWndiFixMyPlaybar(p);
  1203. // Make an appropriate menu for this device
  1204. MCIWndiMakeMeAMenu(p);
  1205. // We need a TIMER to notify the "owner" when things change
  1206. MCIWndiSetTimer(p);
  1207. // Set the size of the movie (and maybe the window) and re-draw new toolbar
  1208. MCIWndiSize(p, p->iZoom);
  1209. #if 0 // We need the focus on our main window to get key accelerators
  1210. // Bring focus to the thumb so caret will flash
  1211. // I know the WM_SETFOCUS msg does this, but it seems to need to happen here
  1212. // too.
  1213. if (p->hwndTrackbar && GetFocus() == p->hwnd)
  1214. SetFocus(p->hwndTrackbar);
  1215. #endif
  1216. // We need to notify our "owner" that we've opened a new file
  1217. if (p->dwStyle & MCIWNDF_NOTIFYMEDIA)
  1218. NotifyOwner(p, MCIWNDM_NOTIFYMEDIA, p->hwnd, (LPARAM)szFile);
  1219. // Make sure the newly opened movie paints in the window now
  1220. InvalidateRect(p->hwnd, NULL, TRUE);
  1221. return 0; // success
  1222. }
  1223. //
  1224. // Set the caption based on what they want to see... Name? Pos? Mode?
  1225. //
  1226. static VOID MCIWndiSetCaption(PMCIWND p)
  1227. {
  1228. char ach[200], achMode[40], achT[40], achPos[40];
  1229. // Don't touch their window text if they don't want us to
  1230. if (!(p->dwStyle & MCIWNDF_SHOWALL))
  1231. return;
  1232. ach[0] = 0;
  1233. if (p->wDeviceID == NULL)
  1234. return;
  1235. if (p->dwStyle & MCIWNDF_SHOWNAME)
  1236. wsprintf(ach, "%s", FileName(p->achFileName));
  1237. if (p->dwStyle & (MCIWNDF_SHOWPOS | MCIWNDF_SHOWMODE))
  1238. lstrcat(ach, " (");
  1239. if (p->dwStyle & MCIWNDF_SHOWPOS) {
  1240. // Get the pretty version of the position as a string
  1241. MCIWndGetPositionString(p->hwnd, achPos, sizeof(achPos));
  1242. if (p->dwStyle & MCIWNDF_SHOWMODE)
  1243. wsprintf(achT, "%s - ", (LPSTR)achPos);
  1244. else
  1245. wsprintf(achT, "%s", (LPSTR)achPos);
  1246. lstrcat(ach, achT);
  1247. }
  1248. if (p->dwStyle & MCIWNDF_SHOWMODE) {
  1249. MCIWndGet(p, szStatusMode, achMode, sizeof(achMode));
  1250. lstrcat(ach, achMode);
  1251. }
  1252. if (p->dwStyle & (MCIWNDF_SHOWPOS | MCIWNDF_SHOWMODE))
  1253. lstrcat(ach, ")");
  1254. SetWindowText(p->hwnd, ach);
  1255. }
  1256. // We never use this any more
  1257. #if 0
  1258. static BOOL MCIWndSeekExact(PMCIWND p, BOOL fExact)
  1259. {
  1260. DWORD dw;
  1261. BOOL fWasExact;
  1262. if (p->wDeviceID == NULL)
  1263. return FALSE;
  1264. // see if the device even has this feature
  1265. dw = MCIWndString(p, FALSE, szStatusSeekExactly);
  1266. if (dw != 0)
  1267. return FALSE;
  1268. // get current value.
  1269. dw = MCIWndStatus(p, MCI_DGV_STATUS_SEEK_EXACTLY, MCI_OFF);
  1270. fWasExact = (dw != MCI_OFF) ? TRUE : FALSE;
  1271. if (fExact)
  1272. dw = MCIWndString(p, FALSE, szSetSeekExactOn);
  1273. else
  1274. dw = MCIWndString(p, FALSE, szSetSeekExactOff);
  1275. return fWasExact;
  1276. }
  1277. #endif
  1278. static LONG MCIWndiChangeStyles(PMCIWND p, UINT mask, UINT value)
  1279. {
  1280. DWORD dwOldStyle = p->dwStyle;
  1281. DWORD dwMaskOff, dwValue, dwChanged;
  1282. //
  1283. // Using the mask, change the appropriate bits in the style
  1284. //
  1285. dwMaskOff = dwOldStyle & (~(DWORD)mask);
  1286. dwValue = (DWORD)mask & (DWORD)value;
  1287. p->dwStyle = dwMaskOff | dwValue;
  1288. //
  1289. // Which bits changed?
  1290. //
  1291. dwChanged = (dwOldStyle & (DWORD)mask) ^ (dwValue & (DWORD)mask);
  1292. //
  1293. // We changed whether or not we want a menu button or a record button
  1294. // on the playbar
  1295. //
  1296. if (dwChanged & (MCIWNDF_NOMENU | MCIWNDF_NOOPEN | MCIWNDF_RECORD)) {
  1297. MCIWndiMakeMeAMenu(p); // add/remove record from the menu
  1298. // We have a playbar, so fix it
  1299. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR)) {
  1300. MCIWndiFixMyPlaybar(p);
  1301. MCIWndiSize(p, 0);
  1302. }
  1303. }
  1304. //
  1305. // We changed the show/don't show playbar flag!
  1306. //
  1307. if (dwChanged & MCIWNDF_NOPLAYBAR) {
  1308. // Remove the playbar
  1309. if (p->dwStyle & MCIWNDF_NOPLAYBAR) {
  1310. DestroyWindow(p->hwndToolbar);
  1311. p->hwndToolbar = NULL;
  1312. p->hwndTrackbar = NULL; // child destroyed automatically
  1313. MCIWndiMakeMeAMenu(p); // since toolbar's gone, menus change
  1314. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW)) {
  1315. // Now resize the window smaller to account for the missing
  1316. // playbar. Don't touch the movie size.
  1317. MCIWndiSize(p, 0);
  1318. // If the window isn't being resized, we may still need to grow
  1319. // the movie size a bit to take up the extra space where the toolbar
  1320. // vanished. (happens automatically in the previous case)
  1321. } else if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE)) {
  1322. PostMessage(p->hwnd, WM_SIZE, 0, 0L);
  1323. }
  1324. // Add a playbar
  1325. } else {
  1326. MCIWndiMakeMeAPlaybar(p);
  1327. MCIWndiFixMyPlaybar(p);
  1328. MCIWndiMakeMeAMenu(p); // since toolbar's used, menus change
  1329. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW)) {
  1330. // Now resize the window a little bigger to account for the new
  1331. // playbar. Don't touch the movie size.
  1332. MCIWndiSize(p, 0);
  1333. // If the window isn't being resized, we may still need to shrink
  1334. // the movie size because the toolbar covers up some extra space.
  1335. // (happens automatically in the previous case)
  1336. } else if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE)) {
  1337. PostMessage(p->hwnd, WM_SIZE, 0, 0L);
  1338. // Irregardless, we need to fix the toolbar
  1339. } else
  1340. // Put the toolbar in a reasonable spot
  1341. MCIWndiSizePlaybar(p);
  1342. }
  1343. }
  1344. //
  1345. // We changed a SHOW flag and need to reset the caption
  1346. //
  1347. if (dwChanged & MCIWNDF_SHOWALL)
  1348. MCIWndiSetCaption(p);
  1349. //
  1350. // We turned the AUTOSIZEMOVIE flag on and need to resize the device.
  1351. // This happens before AUTOSIZEWINDOW so if both flags are turned on
  1352. // the movie will snap to the window not vice versa.
  1353. // !!! Should we even snap it right now?
  1354. //
  1355. if (dwChanged & MCIWNDF_NOAUTOSIZEMOVIE &&
  1356. !(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE))
  1357. PostMessage(p->hwnd, WM_SIZE, 0, 0);
  1358. //
  1359. // We turned the AUTOSIZEWINDOW flag on
  1360. // Snap our window to the current movie size.
  1361. //
  1362. if (dwChanged & MCIWNDF_NOAUTOSIZEWINDOW &&
  1363. !(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
  1364. MCIWndiSize(p, 0);
  1365. DragAcceptFiles(p->hwnd, (p->dwStyle & MCIWNDF_NOMENU | MCIWNDF_NOOPEN) == 0);
  1366. return 0; // !!! success ?
  1367. }
  1368. //
  1369. // We're about to play. We might want to seek to the beginning first if we're
  1370. // at the end, or seek to the end first if we're at the beginning and playing
  1371. // backwards.
  1372. //
  1373. static void MCIWndiPlaySeek(PMCIWND p, BOOL fBackwards)
  1374. {
  1375. // Playing backwards? If we're at the beginning, seek to the end
  1376. if (fBackwards) {
  1377. if (MCIWndGetPosition(p->hwnd) <= MCIWndGetStart(p->hwnd))
  1378. MCIWndSeek(p->hwnd, MCIWND_END);
  1379. return;
  1380. }
  1381. // Playing forwards.
  1382. // If we're near the end, rewind before playing
  1383. // Some devices are broken so we can't just test being at the end
  1384. // Frames mode ... last or second to last frame
  1385. if (MCIWndGetTimeFormat(p->hwnd, NULL, 0) == MCI_FORMAT_FRAMES) {
  1386. if (MCIWndGetPosition(p->hwnd) >= MCIWndGetEnd(p->hwnd) - 1)
  1387. MCIWndSeek(p->hwnd, MCIWND_START);
  1388. // Millisecond mode ... within last 1/4 second
  1389. } else if (MCIWndGetTimeFormat(p->hwnd, NULL, 0) ==
  1390. MCI_FORMAT_MILLISECONDS) {
  1391. if (MCIWndGetEnd(p->hwnd) - MCIWndGetPosition(p->hwnd) < 250)
  1392. MCIWndSeek(p->hwnd, MCIWND_START);
  1393. // something else ... no hack
  1394. } else {
  1395. if (MCIWndGetPosition(p->hwnd) == MCIWndGetEnd(p->hwnd))
  1396. MCIWndSeek(p->hwnd, MCIWND_START);
  1397. }
  1398. }
  1399. //
  1400. // Handle our WM_TIMER
  1401. //
  1402. static void MCIWndiTimerStuff(PMCIWND p)
  1403. {
  1404. DWORD dwMode;
  1405. DWORD dwPos;
  1406. //
  1407. // Someone's interested in knowing the mode of the device
  1408. //
  1409. if ((p->dwStyle & MCIWNDF_NOTIFYMODE) ||
  1410. !(p->dwStyle & MCIWNDF_NOPLAYBAR) ||
  1411. (p->dwStyle & MCIWNDF_SHOWMODE)) {
  1412. dwMode = MCIWndGetMode(p->hwnd, NULL, 0);
  1413. //
  1414. // If we haven't set the trackbar range or media length yet
  1415. // because we weren't ready, maybe we can do it now!
  1416. // Also, don't update media until you're done recording.
  1417. //
  1418. if (dwMode != MCI_MODE_NOT_READY && dwMode != MCI_MODE_OPEN &&
  1419. dwMode != MCI_MODE_RECORD && p->fMediaValid == FALSE)
  1420. MCIWndiValidateMedia(p);
  1421. //
  1422. // No device loaded? Time to kill our timer
  1423. //
  1424. if (p->wDeviceID == NULL)
  1425. KillTimer(p->hwnd, TIMER1);
  1426. //
  1427. // The mode has changed!
  1428. //
  1429. if (dwMode != p->dwMode) {
  1430. p->dwMode = dwMode;
  1431. //
  1432. // Notify the "owner" of the mode change
  1433. //
  1434. if ((p->dwStyle & MCIWNDF_NOTIFYMODE))
  1435. NotifyOwner(p, MCIWNDM_NOTIFYMODE, p->hwnd, dwMode);
  1436. //
  1437. // Set the Window Caption to include the new mode
  1438. //
  1439. if ((p->dwStyle & MCIWNDF_SHOWMODE))
  1440. MCIWndiSetCaption(p);
  1441. //
  1442. // Fix up the toolbar bitmaps if the mode has changed
  1443. //
  1444. MCIWndiPlaybarGraying(p);
  1445. }
  1446. }
  1447. //
  1448. // Someone's interested in knowing the new position
  1449. //
  1450. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR) ||
  1451. (p->dwStyle & MCIWNDF_NOTIFYPOS) ||
  1452. (p->dwStyle & MCIWNDF_SHOWPOS)) {
  1453. dwPos = MCIWndGetPosition(p->hwnd);
  1454. //
  1455. // The position has changed!
  1456. //
  1457. if (dwPos != p->dwPos) {
  1458. //
  1459. // Make sure start and length haven't changed too (format change) ?
  1460. //
  1461. MCIWndiValidateMedia(p);
  1462. p->dwPos = dwPos;
  1463. //
  1464. // Notify the "owner" of the position change
  1465. //
  1466. if ((p->dwStyle & MCIWNDF_NOTIFYPOS))
  1467. NotifyOwner(p, MCIWNDM_NOTIFYPOS, p->hwnd, dwPos);
  1468. //
  1469. // Set the Window Caption to include the new position
  1470. //
  1471. if ((p->dwStyle & MCIWNDF_SHOWPOS))
  1472. MCIWndiSetCaption(p);
  1473. //
  1474. // Update the trackbar to the new position but not while
  1475. // we're dragging the thumb
  1476. //
  1477. if (!(p->dwStyle & MCIWNDF_NOPLAYBAR) && !p->fScrolling)
  1478. SendMessage(p->hwndTrackbar, TBM_SETPOS, TRUE, dwPos);
  1479. }
  1480. }
  1481. }
  1482. static void MCIWndiDrop(HWND hwnd, WPARAM wParam)
  1483. {
  1484. char szPath[256];
  1485. UINT nDropped;
  1486. // Get number of files dropped
  1487. nDropped = DragQueryFile((HANDLE)wParam,0xFFFF,NULL,0);
  1488. if (nDropped) {
  1489. SetActiveWindow(hwnd);
  1490. // Get the file that was dropped....
  1491. DragQueryFile((HANDLE)wParam, 0, szPath, sizeof(szPath));
  1492. MCIWndOpen(hwnd, szPath, 0);
  1493. }
  1494. DragFinish((HANDLE)wParam); /* Delete structure alocated */
  1495. }
  1496. /*--------------------------------------------------------------+
  1497. | MCIWndProc - MCI window's window proc |
  1498. | |
  1499. +--------------------------------------------------------------*/
  1500. LONG FAR PASCAL _loadds MCIWndProc(HWND hwnd, unsigned msg, WORD wParam, LONG lParam)
  1501. {
  1502. PMCIWND p;
  1503. DWORD dw;
  1504. HDC hdc;
  1505. PAINTSTRUCT ps;
  1506. DWORD dwPos;
  1507. POINT pt;
  1508. MINMAXINFO FAR *lpmmi;
  1509. RECT rc;
  1510. BOOL f;
  1511. char ach[80];
  1512. MCI_GENERIC_PARMS mciGeneric;
  1513. LPRECT prc;
  1514. int i;
  1515. HWND hwndD;
  1516. p = (PMCIWND)(UINT)GetWindowLong(hwnd, 0);
  1517. switch(msg){
  1518. case WM_CREATE:
  1519. if (!MCIWndiCreate(hwnd, lParam))
  1520. return -1;
  1521. break;
  1522. // Make the trackbar background LTGRAY like the toolbar
  1523. case WM_CTLCOLOR:
  1524. if ((HWND)LOWORD(lParam) == p->hwndTrackbar)
  1525. return (LRESULT)(UINT)GetStockObject(LTGRAY_BRUSH);
  1526. break;
  1527. case MCI_SAVE:
  1528. // wParam presently unused and not given by the macro
  1529. return MCIWndiSave(p, wParam, (LPSTR)lParam);
  1530. case MCI_OPEN:
  1531. return MCIWndiOpen(p, wParam, (LPSTR)lParam);
  1532. case MCIWNDM_NEW:
  1533. return MCIWndiOpen(p, MCIWNDOPENF_NEW, (LPSTR)lParam);
  1534. case MCI_PLAY:
  1535. if (!p->wDeviceID)
  1536. return 0;
  1537. // Seek to the beginning if we're near the end
  1538. MCIWndiPlaySeek(p, FALSE);
  1539. case MCI_STOP:
  1540. case MCI_PAUSE:
  1541. case MCI_RESUME:
  1542. case MCI_RECORD:
  1543. dw = 0;
  1544. // Report/Show errors for this
  1545. if (p->wDeviceID) {
  1546. // buggy drivers crash if we pass a null parms address
  1547. dw = mciSendCommand(p->wDeviceID, msg, 0,
  1548. (DWORD)(LPVOID)&mciGeneric);
  1549. MCIWndiHandleError(p, dw);
  1550. // kick ourselves to show new Mode
  1551. MCIWndiTimerStuff(p);
  1552. }
  1553. return dw;
  1554. case MCIWNDM_PLAYREVERSE:
  1555. if (!p->wDeviceID)
  1556. return 0;
  1557. // Seek to the end if we're near the beginning
  1558. MCIWndiPlaySeek(p, TRUE);
  1559. dw = MCIWndString(p, TRUE, szPlayReverse, (LPSTR)szNULL);
  1560. // kick ourselves to show new Mode
  1561. MCIWndiTimerStuff(p);
  1562. return dw;
  1563. case MCI_CLOSE:
  1564. if (lParam)
  1565. // We delayed the closing of the MCI device because the MCI
  1566. // device may have hooked our window proc and be on our stack
  1567. // and killing it before would have destroyed the universe.
  1568. // buggy drivers crash if we pass a null parms address
  1569. return mciSendCommand((UINT)lParam, MCI_CLOSE, 0,
  1570. (DWORD)(LPVOID)&mciGeneric);
  1571. else
  1572. // Do all the stuff for closing
  1573. return MCIWndiClose(p, TRUE);
  1574. case MCIWNDM_EJECT:
  1575. return MCIWndString(p, TRUE, szSetDoorOpen);
  1576. case MCIWNDM_PLAYFROM:
  1577. if (lParam == MCIWND_START)
  1578. dw = MCIWndString(p, TRUE, szPlayFrom, MCIWndGetStart(hwnd));
  1579. else
  1580. dw = MCIWndString(p, TRUE, szPlayFrom, (LONG)lParam);
  1581. MCIWndiTimerStuff(p); // kick ourselves to see mode change
  1582. return dw;
  1583. case MCIWNDM_PLAYTO:
  1584. if (lParam == MCIWND_END)
  1585. dw = MCIWndString(p, TRUE, szPlayTo, MCIWndGetEnd(hwnd));
  1586. else if (lParam == MCIWND_START)
  1587. dw = MCIWndString(p, TRUE, szPlayTo, MCIWndGetStart(hwnd));
  1588. else
  1589. dw = MCIWndString(p, TRUE, szPlayTo, (LONG)lParam);
  1590. MCIWndiTimerStuff(p); // kick ourselves to see mode change
  1591. return dw;
  1592. case MCI_STEP:
  1593. return MCIWndString(p, TRUE, szStep, (LONG)lParam);
  1594. case MCI_SEEK:
  1595. if (lParam == MCIWND_START)
  1596. return MCIWndString(p, TRUE, szSeek, MCIWndGetStart(hwnd));
  1597. else if (lParam == MCIWND_END)
  1598. return MCIWndString(p, TRUE, szSeek, MCIWndGetEnd(hwnd));
  1599. else
  1600. return MCIWndString(p, TRUE, szSeek, (LONG)lParam);
  1601. case MCIWNDM_SETREPEAT:
  1602. p->fRepeat = (BOOL)lParam;
  1603. return 0;
  1604. case MCIWNDM_GETREPEAT:
  1605. return p->fRepeat;
  1606. case MCIWNDM_GETDEVICEID:
  1607. return p->wDeviceID;
  1608. case MCIWNDM_GETALIAS:
  1609. return p->alias;
  1610. case MCIWNDM_GETMODE:
  1611. if (lParam)
  1612. MCIWndGet(p, szStatusMode, (LPSTR)lParam, (UINT)wParam);
  1613. return MCIWndStatus(p, MCI_STATUS_MODE, MCI_MODE_NOT_READY);
  1614. // Return the position as a string if they give us a buffer
  1615. case MCIWNDM_GETPOSITION:
  1616. if (lParam) {
  1617. // If we can do tracks, let's give them a pretty string
  1618. if (p->fHasTracks)
  1619. MCIWndString(p, FALSE, szSetFormatTMSF);
  1620. MCIWndGet(p, szStatusPosition, (LPSTR)lParam,(UINT)wParam);
  1621. if (p->fHasTracks)
  1622. MCIWndString(p, FALSE, szSetFormatMS);
  1623. }
  1624. return MCIWndStatus(p, MCI_STATUS_POSITION, 0);
  1625. case MCIWNDM_GETSTART:
  1626. // Start is a command that works differently
  1627. return MCIWndGetValue(p, FALSE, szStatusStart, 0);
  1628. case MCIWNDM_GETLENGTH:
  1629. return MCIWndStatus(p, MCI_STATUS_LENGTH, 0);
  1630. case MCIWNDM_GETEND:
  1631. return MCIWndGetStart(hwnd) + MCIWndGetLength(hwnd);
  1632. case MCIWNDM_SETZOOM:
  1633. p->iZoom = (int)lParam;
  1634. MCIWndiSize(p, (int)lParam);
  1635. return 0;
  1636. case MCIWNDM_GETZOOM:
  1637. return p->iZoom ? p->iZoom : 100;
  1638. case MCIWNDM_GETPALETTE:
  1639. return MCIWndGetValue(p, FALSE, szStatusPalette, NULL);
  1640. case MCIWNDM_SETPALETTE:
  1641. return MCIWndString(p, TRUE, szSetPalette, (HPALETTE)wParam);
  1642. //
  1643. // Returns our error code
  1644. //
  1645. case MCIWNDM_GETERROR:
  1646. if (lParam) {
  1647. mciGetErrorString(p->dwError, (LPSTR)lParam, (UINT)wParam);
  1648. }
  1649. dw = p->dwError;
  1650. // p->dwError = 0L; // we never clear the error
  1651. return dw;
  1652. case MCIWNDM_GETFILENAME:
  1653. if (lParam)
  1654. lstrcpyn((LPSTR)lParam, p->achFileName, (UINT)wParam);
  1655. return (lParam == NULL); // !!!
  1656. case MCIWNDM_GETDEVICE:
  1657. if (lParam)
  1658. return MCIWndGet(p, szSysInfo, (LPSTR)lParam,
  1659. (UINT)wParam);
  1660. return 42; // !!!
  1661. case MCIWNDM_SETVOLUME:
  1662. // Uncheck the current volume, and check the new one.
  1663. // Round to nearest 5 so it matches a menu item identifier
  1664. i = ((int)MCIWndGetValue(p, FALSE, szStatusVolume, 1000) / 50) * 5;
  1665. if (p->hmenuVolume)
  1666. CheckMenuItem(p->hmenuVolume, IDM_MCIVOLUME + i, MF_UNCHECKED);
  1667. dw = MCIWndString(p, TRUE, szSetVolume, (int)lParam);
  1668. i = ((int)lParam / 50) * 5;
  1669. if (p->hmenuVolume)
  1670. CheckMenuItem(p->hmenuVolume, IDM_MCIVOLUME + i, MF_CHECKED);
  1671. return dw;
  1672. case MCIWNDM_GETVOLUME:
  1673. return MCIWndGetValue(p, FALSE, szStatusVolume, 1000);
  1674. case MCIWNDM_SETSPEED:
  1675. // Uncheck the current speed, and check the new one.
  1676. // Round to nearest 5 so it matches a menu item identifier
  1677. i = ((int)MCIWndGetValue(p, FALSE, szStatusSpeed, 1000) / 50) * 5;
  1678. if (p->hmenuSpeed)
  1679. CheckMenuItem(p->hmenuSpeed, IDM_MCISPEED + i, MF_UNCHECKED);
  1680. dw = MCIWndString(p, TRUE, szSetSpeed, (int)lParam);
  1681. i = ((int)lParam / 50) * 5;
  1682. if (p->hmenuSpeed)
  1683. CheckMenuItem(p->hmenuSpeed, IDM_MCISPEED + i, MF_CHECKED);
  1684. return dw;
  1685. case MCIWNDM_GETSPEED:
  1686. return MCIWndGetValue(p, FALSE, szStatusSpeed, 1000);
  1687. case MCIWNDM_SETTIMEFORMAT:
  1688. dw = MCIWndString(p, TRUE, szSetFormat, (LPSTR)lParam);
  1689. MCIWndiValidateMedia(p);
  1690. return dw;
  1691. case MCIWNDM_GETTIMEFORMAT:
  1692. if (lParam)
  1693. MCIWndGet(p, szStatusFormat, (LPSTR)lParam, (UINT)wParam);
  1694. return MCIWndStatus(p, MCI_STATUS_TIME_FORMAT, 0); // !!!
  1695. case MCIWNDM_VALIDATEMEDIA:
  1696. MCIWndiValidateMedia(p);
  1697. break;
  1698. case MCIWNDM_GETSTYLES:
  1699. return (UINT)(p->dwStyle & 0xFFFF);
  1700. case MCIWNDM_CHANGESTYLES:
  1701. return MCIWndiChangeStyles(p, (UINT)wParam, (UINT)lParam);
  1702. case MCIWNDM_SETACTIVETIMER:
  1703. if (wParam)
  1704. p->iActiveTimerRate = (unsigned)wParam;
  1705. if (p->fActive) {
  1706. KillTimer(hwnd, TIMER1);
  1707. MCIWndiSetTimer(p);
  1708. }
  1709. break;
  1710. case MCIWNDM_SETINACTIVETIMER:
  1711. if (wParam)
  1712. p->iInactiveTimerRate = (unsigned)wParam;
  1713. if (!p->fActive) {
  1714. KillTimer(hwnd, TIMER1);
  1715. MCIWndiSetTimer(p);
  1716. }
  1717. break;
  1718. case MCIWNDM_SETTIMERS:
  1719. if (wParam)
  1720. p->iActiveTimerRate = (unsigned)wParam;
  1721. if (lParam)
  1722. p->iInactiveTimerRate = (unsigned)lParam;
  1723. KillTimer(hwnd, TIMER1);
  1724. MCIWndiSetTimer(p);
  1725. break;
  1726. case MCIWNDM_GETACTIVETIMER:
  1727. return p->iActiveTimerRate;
  1728. case MCIWNDM_GETINACTIVETIMER:
  1729. return p->iInactiveTimerRate;
  1730. case MCIWNDM_SENDSTRING:
  1731. //
  1732. // App wants to send a string command.
  1733. // special case the CLOSE command to do our clean up
  1734. if (lstrcmpi((LPSTR)lParam, szClose) == 0)
  1735. return MCIWndClose(hwnd);
  1736. // Always sets/clears our error code
  1737. dw = MCIWndGet(p, (LPSTR)lParam, p->achReturn,sizeof(p->achReturn));
  1738. MCIWndiHandleError(p, dw);
  1739. // kick ourselves in case mode changed from this command
  1740. MCIWndiTimerStuff(p);
  1741. return dw;
  1742. // Gets the return string from the most recent MCIWndSendString()
  1743. case MCIWNDM_RETURNSTRING:
  1744. if (lParam)
  1745. lstrcpyn((LPSTR)lParam, p->achReturn, wParam);
  1746. return (lParam == NULL); // !!!
  1747. case MCIWNDM_REALIZE:
  1748. // buggy drivers crash if we pass a null parms address
  1749. dw = mciSendCommand(p->wDeviceID, MCI_REALIZE,
  1750. (BOOL)wParam ? MCI_ANIM_REALIZE_BKGD : MCI_ANIM_REALIZE_NORM,
  1751. (DWORD)(LPVOID)&mciGeneric);
  1752. break;
  1753. case MCIWNDM_GET_SOURCE:
  1754. MCIWndRect(p, (LPRECT)lParam, TRUE);
  1755. return 0L;
  1756. case MCIWNDM_GET_DEST:
  1757. MCIWndRect(p, (LPRECT)lParam, FALSE);
  1758. return 0L;
  1759. case MCIWNDM_PUT_SOURCE:
  1760. prc = (LPRECT)lParam;
  1761. return MCIWndString(p, FALSE, szPutSource,
  1762. prc->left, prc->top,
  1763. prc->right - prc->left,
  1764. prc->bottom - prc->top);
  1765. case MCIWNDM_PUT_DEST:
  1766. prc = (LPRECT)lParam;
  1767. return MCIWndString(p, FALSE, szPutDest,
  1768. prc->left, prc->top,
  1769. prc->right - prc->left,
  1770. prc->bottom - prc->top);
  1771. case MCIWNDM_CAN_PLAY: return p->fCanPlay;
  1772. case MCIWNDM_CAN_WINDOW: return p->fCanWindow;
  1773. case MCIWNDM_CAN_RECORD: return p->fCanRecord;
  1774. case MCIWNDM_CAN_SAVE: return p->fCanSave;
  1775. case MCIWNDM_CAN_EJECT: return p->fCanEject;
  1776. case MCIWNDM_CAN_CONFIG: return p->fCanConfig;
  1777. case WM_TIMER:
  1778. // This timer means we've moved the mouse off of the menu and need
  1779. // to snap the thumb back to the original value
  1780. if (wParam == TIMER2) {
  1781. KillTimer(hwnd, TIMER2);
  1782. // If only this would cause OwnerDraw to execute, we could see
  1783. // the thumb bounce back to it's default place. Alas, no can do
  1784. //CheckMenuItem(p->hmenuHack, p->uiHack, MF_UNCHECKED);
  1785. //CheckMenuItem(p->hmenuHack, p->uiHack, MF_CHECKED);
  1786. // This code will at least set the parameter back even though
  1787. // the thumb won't physically move.
  1788. if (p->hmenuHack == p->hmenuVolume)
  1789. MCIWndSetVolume(hwnd, (p->uiHack - IDM_MCIVOLUME) * 10);
  1790. else
  1791. MCIWndSetSpeed(hwnd, (p->uiHack - IDM_MCISPEED) * 10);
  1792. }
  1793. //
  1794. // This is not our timer. Bail.
  1795. //
  1796. if (wParam != TIMER1)
  1797. break;
  1798. MCIWndiTimerStuff(p);
  1799. break;
  1800. case WM_GETMINMAXINFO:
  1801. // We don't want anybody messing with the window size
  1802. if (p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW)
  1803. break;
  1804. // do we have a playbar?
  1805. f = !(p->dwStyle & MCIWNDF_NOPLAYBAR);
  1806. lpmmi = (MINMAXINFO FAR *)(lParam);
  1807. SetRect(&rc, 0, 0, SMALLEST_WIDTH, f ? TB_HEIGHT : 0);
  1808. AdjustWindowRect(&rc, GetWindowLong(hwnd, GWL_STYLE), FALSE);
  1809. lpmmi->ptMinTrackSize.y = rc.bottom - rc.top;
  1810. lpmmi->ptMinTrackSize.x = rc.right - rc.left;
  1811. if (!(p->wDeviceID) || !(p->fCanWindow))
  1812. lpmmi->ptMaxTrackSize.y = lpmmi->ptMinTrackSize.y;
  1813. break;
  1814. case WM_SIZE:
  1815. GetClientRect(hwnd, &rc);
  1816. if (!IsIconic(hwnd)) {
  1817. // if we have a playbar, fix it up to the new size
  1818. f = !(p->dwStyle & MCIWNDF_NOPLAYBAR);
  1819. if (f) {
  1820. MCIWndiSizePlaybar(p);
  1821. rc.bottom -= TB_HEIGHT;
  1822. }
  1823. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE))
  1824. MCIWndString(p, FALSE, szPutDest, 0,0, rc.right, rc.bottom);
  1825. } else {
  1826. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE))
  1827. MCIWndString(p, FALSE, szPutDest, 0,0, rc.right, rc.bottom);
  1828. }
  1829. break;
  1830. case WM_RBUTTONDOWN:
  1831. case WM_NCRBUTTONDOWN:
  1832. case WM_PARENTNOTIFY:
  1833. // If we haven't got a menu, or we don't want it, bail
  1834. if (!p->hmenu || p->dwStyle & MCIWNDF_NOMENU)
  1835. break;
  1836. // If this is not a right button down, bail
  1837. if (msg == WM_PARENTNOTIFY && wParam != WM_RBUTTONDOWN)
  1838. break;
  1839. GetCursorPos(&pt);
  1840. // Don't allow error dlgs to come up while we're tracking. That
  1841. // would cause windows to enter the twilight zone.
  1842. p->fTracking = TRUE;
  1843. TrackPopupMenu(p->hmenu,
  1844. TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
  1845. p->fTracking = FALSE;
  1846. return 0;
  1847. case WM_PALETTECHANGED:
  1848. if ((HWND)wParam != hwnd && p->fHasPalette)
  1849. InvalidateRect(hwnd, NULL, FALSE);
  1850. break;
  1851. case WM_QUERYNEWPALETTE:
  1852. if (p->fHasPalette)
  1853. MCIWndRealize(hwnd, FALSE);
  1854. break;
  1855. // Send a WM_PALETTECHANGED to everyone in the system. We need to do
  1856. // this manually sometimes because of GDI.
  1857. case MCIWNDM_PALETTEKICK:
  1858. hwndD = GetDesktopWindow(); // tell everyone DESKTOP changed it
  1859. PostMessage((HWND)-1, WM_PALETTECHANGED, (WPARAM)hwndD, 0);
  1860. // DESKTOP won't repaint if we give it it's own HWND, so pick a
  1861. // random window and PRAY it'll stay valid.
  1862. hwndD = GetActiveWindow();
  1863. hwndD = GetWindow(hwndD, GW_HWNDLAST);
  1864. PostMessage(GetDesktopWindow(), WM_PALETTECHANGED, (WPARAM)hwndD,0);
  1865. return 0;
  1866. case MCIWNDM_OPENINTERFACE:
  1867. wsprintf(ach, szInterface, lParam);
  1868. return MCIWndiOpen(p, 0, (LPSTR)ach);
  1869. case MCIWNDM_SETOWNER:
  1870. p->hwndOwner = (HWND)wParam;
  1871. return 0;
  1872. case WM_ERASEBKGND:
  1873. if (p->fCanWindow) {
  1874. MCIWndRect(p, &rc, FALSE);
  1875. SaveDC((HDC)wParam);
  1876. ExcludeClipRect((HDC)wParam, rc.left, rc.top, rc.right,
  1877. rc.bottom);
  1878. DefWindowProc(hwnd, msg, wParam, lParam);
  1879. RestoreDC((HDC)wParam, -1);
  1880. return 0;
  1881. }
  1882. break;
  1883. case WM_PAINT:
  1884. hdc = BeginPaint(hwnd, &ps);
  1885. if (p->wDeviceID && p->fCanWindow)
  1886. {
  1887. MCI_ANIM_UPDATE_PARMS mciUpdate;
  1888. mciUpdate.hDC = hdc;
  1889. dw = mciSendCommand(p->wDeviceID, MCI_UPDATE,
  1890. MCI_ANIM_UPDATE_HDC | MCI_WAIT |
  1891. MCI_DGV_UPDATE_PAINT,
  1892. (DWORD)(LPVOID)&mciUpdate);
  1893. if (dw != 0) /* if the update fails then erase */
  1894. DefWindowProc(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
  1895. } else if (IsIconic(hwnd)) {
  1896. DefWindowProc(hwnd, WM_ICONERASEBKGND, (WPARAM)hdc, 0);
  1897. DrawIcon(ps.hdc, 0, 0, p->hicon);
  1898. }
  1899. EndPaint(hwnd, &ps);
  1900. break;
  1901. case WM_KEYDOWN:
  1902. switch(wParam) {
  1903. case VK_LEFT:
  1904. SendMessage(hwnd, WM_HSCROLL, TB_LINEUP, 0); break;
  1905. case VK_RIGHT:
  1906. SendMessage(hwnd, WM_HSCROLL, TB_LINEDOWN, 0); break;
  1907. case VK_PRIOR:
  1908. SendMessage(hwnd, WM_HSCROLL, TB_PAGEUP, 0); break;
  1909. case VK_NEXT:
  1910. SendMessage(hwnd, WM_HSCROLL, TB_PAGEDOWN, 0); break;
  1911. case VK_HOME:
  1912. SendMessage(hwnd, WM_HSCROLL, TB_TOP, 0); break;
  1913. case VK_END:
  1914. SendMessage(hwnd, WM_HSCROLL, TB_BOTTOM, 0); break;
  1915. case VK_UP:
  1916. case VK_DOWN:
  1917. dw = MCIWndGetValue(p, FALSE, szStatusVolume, 1000);
  1918. if (wParam == VK_UP)
  1919. i = min((int)p->wMaxVol * 10, (int) dw + 100);
  1920. else
  1921. i = max(0, (int) dw - 100);
  1922. MCIWndSetVolume(p->hwnd, i);
  1923. break;
  1924. default:
  1925. break;
  1926. }
  1927. break;
  1928. case WM_KEYUP:
  1929. switch(wParam) {
  1930. case VK_LEFT:
  1931. case VK_RIGHT:
  1932. case VK_PRIOR:
  1933. case VK_NEXT:
  1934. case VK_HOME:
  1935. case VK_END:
  1936. if (p->fScrolling)
  1937. SendMessage(hwnd, WM_HSCROLL, TB_ENDTRACK, 0);
  1938. break;
  1939. case VK_ESCAPE:
  1940. MCIWndStop(hwnd);
  1941. break;
  1942. default:
  1943. break;
  1944. }
  1945. if (GetKeyState(VK_CONTROL) & 0x8000) {
  1946. switch(wParam) {
  1947. case '1':
  1948. case '2':
  1949. case '3':
  1950. case '4':
  1951. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
  1952. MCIWndSetZoom(hwnd, 100 * (wParam - '0'));
  1953. break;
  1954. case 'P':
  1955. MCIWndPlay(hwnd); break;
  1956. case 'S':
  1957. MCIWndStop(hwnd); break;
  1958. case 'D':
  1959. PostMessage(hwnd, WM_COMMAND, IDM_MCICONFIG, 0); break;
  1960. case 'C':
  1961. PostMessage(hwnd, WM_COMMAND, IDM_COPY, 0); break;
  1962. case VK_F5:
  1963. PostMessage(hwnd, WM_COMMAND, IDM_MCICOMMAND, 0); break;
  1964. case 'F':
  1965. case 'O':
  1966. if (!(p->dwStyle & MCIWNDF_NOOPEN))
  1967. MCIWndOpenDialog(hwnd);
  1968. break;
  1969. case 'M':
  1970. PostMessage(hwnd, WM_COMMAND, ID_TOOLBAR,
  1971. MAKELONG(IDM_MENU, TBN_BEGINDRAG)); break;
  1972. default:
  1973. break;
  1974. }
  1975. }
  1976. break;
  1977. case WM_SYSCHAR:
  1978. switch(wParam) {
  1979. case '1':
  1980. case '2':
  1981. case '3':
  1982. case '4':
  1983. if (!(p->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
  1984. MCIWndSetZoom(hwnd, 100 / ((UINT) wParam - '0'));
  1985. return 0; // break will ding
  1986. default:
  1987. break;
  1988. }
  1989. break;
  1990. case WM_HSCROLL:
  1991. #define FORWARD 1
  1992. #define BACKWARD 2
  1993. dwPos = SendMessage(p->hwndTrackbar, TBM_GETPOS, 0, 0);
  1994. // nothing to do - spurious END without BEGIN
  1995. if (!p->fScrolling && wParam == TB_ENDTRACK)
  1996. break;
  1997. // Turn seek exactly off while scrolling and remember what it was
  1998. // Also, remember if we were playing just before we seeked so we
  1999. // can continue playing after the seek (so moving the thumb doesn't
  2000. // stop the play).
  2001. if (!p->fScrolling) {
  2002. p->fScrolling = TRUE;
  2003. // Wierd artifacts happen if you turn seek exactly off while
  2004. // seeking. You see the key frame and then the actual frame.
  2005. // Nobody can remember why this was ever a good idea.
  2006. //p->fSeekExact = MCIWndSeekExact(p, FALSE);
  2007. // if we're still seeking from last time, don't change this
  2008. if (p->dwMode != MCI_MODE_SEEK)
  2009. p->fPlayAfterSeek = (p->dwMode == MCI_MODE_PLAY);
  2010. // Now which direction was it playing in?
  2011. if (p->fPlayAfterSeek) {
  2012. MCIWndGet(p, szStatusForward, ach, sizeof(ach));
  2013. if (ach[0] == 'F' || ach[0] == 'f')
  2014. p->fPlayAfterSeek = BACKWARD;
  2015. else // by default, choose forward. Some devices
  2016. // don't understand this command and fail.
  2017. p->fPlayAfterSeek = FORWARD;
  2018. }
  2019. }
  2020. switch(wParam)
  2021. {
  2022. case TB_LINEUP:
  2023. dwPos--; break;
  2024. case TB_LINEDOWN:
  2025. dwPos++; break;
  2026. case TB_PAGEUP:
  2027. if (p->fHasTracks) {
  2028. dwPos = MCIWndiPrevTrack(p); break;
  2029. } else {
  2030. dwPos -= p->dwMediaLen / 16; break;
  2031. }
  2032. case TB_PAGEDOWN:
  2033. if (p->fHasTracks) {
  2034. dwPos = MCIWndiNextTrack(p); break;
  2035. } else {
  2036. dwPos += p->dwMediaLen / 16; break;
  2037. }
  2038. case TB_TOP:
  2039. dwPos = p->dwMediaStart; break;
  2040. case TB_BOTTOM:
  2041. dwPos = p->dwMediaStart + p->dwMediaLen; break;
  2042. case TB_THUMBTRACK:
  2043. case TB_THUMBPOSITION:
  2044. break;
  2045. case TB_ENDTRACK:
  2046. // All done. Put seek exact back to what it used to be
  2047. p->fScrolling = FALSE;
  2048. // Don't do this anymore (see above)
  2049. //MCIWndSeekExact(p, p->fSeekExact);
  2050. break;
  2051. default:
  2052. break;
  2053. }
  2054. // If we're windowed, update the position as we scroll. That would
  2055. // be annoying for CD or wave, though. Also, update as soon as we
  2056. // let go of the thumb. Also, never seek around while we're open
  2057. // or not ready.
  2058. if ((p->fCanWindow || !p->fScrolling) && p->dwMode != MCI_MODE_OPEN
  2059. && p->dwMode != MCI_MODE_NOT_READY) {
  2060. MCIWndSeek(hwnd, dwPos);
  2061. MCIWndiTimerStuff(p); // kick ourselves to update mode
  2062. }
  2063. // After we're done, if we were playing before, go back to playing
  2064. if (!p->fScrolling && p->fPlayAfterSeek) {
  2065. if (p->fPlayAfterSeek == FORWARD)
  2066. MCIWndPlay(hwnd);
  2067. else
  2068. MCIWndPlayReverse(hwnd);
  2069. MCIWndiTimerStuff(p); // kick ourselves to update mode
  2070. }
  2071. // Set the trackbar to the (possibly) new position
  2072. SendMessage(p->hwndTrackbar, TBM_SETPOS, TRUE, dwPos);
  2073. break;
  2074. case WM_MENUSELECT:
  2075. break;
  2076. // Sent from a toolbar button being pressed
  2077. case WM_COMMAND:
  2078. // Check for ZOOM commands
  2079. if (wParam >= IDM_MCIZOOM && wParam < IDM_MCIZOOM + 1000)
  2080. MCIWndSetZoom(hwnd, wParam - IDM_MCIZOOM);
  2081. // If our unused top menu item is selected, turn it into the REAL
  2082. // menu item closest to it.
  2083. if (wParam == IDM_MCIVOLUME + VOLUME_MAX + 1)
  2084. wParam = IDM_MCIVOLUME + p->wMaxVol;
  2085. if (wParam == IDM_MCIVOLUME + VOLUME_MAX + 2)
  2086. wParam = IDM_MCIVOLUME;
  2087. // VOLUME command? Uncheck old one, reset volume, and check new one
  2088. // Round to the nearest 5 to match a menu identifier
  2089. if (wParam >=IDM_MCIVOLUME && wParam <=IDM_MCIVOLUME + p->wMaxVol) {
  2090. if (MCIWndSetVolume(hwnd, (wParam - IDM_MCIVOLUME) * 10) == 0
  2091. && lParam != 42) {
  2092. CheckMenuItem(p->hmenuVolume, p->uiHack, MF_UNCHECKED);
  2093. // change state only for a real command, not while dragging
  2094. CheckMenuItem(p->hmenuVolume, wParam, MF_CHECKED);
  2095. }
  2096. }
  2097. // If our unused top menu item is selected, turn it into the REAL
  2098. // menu item closest to it.
  2099. if (wParam == IDM_MCISPEED + SPEED_MAX + 1)
  2100. wParam = IDM_MCISPEED + SPEED_MAX;
  2101. if (wParam == IDM_MCISPEED + SPEED_MAX + 2)
  2102. wParam = IDM_MCISPEED;
  2103. // SPEED command? Uncheck old one, reset speed, and check new one
  2104. // Round to the nearest 5 to match a menu identifier
  2105. if (wParam >=IDM_MCISPEED && wParam <= IDM_MCISPEED + SPEED_MAX) {
  2106. if (MCIWndSetSpeed(hwnd, (wParam - IDM_MCISPEED) * 10) == 0
  2107. && lParam != 42) {
  2108. // change state only for a real command, not while dragging
  2109. CheckMenuItem(p->hmenuSpeed, p->uiHack, MF_UNCHECKED);
  2110. CheckMenuItem(p->hmenuSpeed, wParam, MF_CHECKED);
  2111. }
  2112. }
  2113. switch(wParam)
  2114. {
  2115. MSG msgT;
  2116. RECT rcT;
  2117. case MCI_RECORD:
  2118. if (GetKeyState(VK_SHIFT) < 0)
  2119. {
  2120. //!!! toggle?
  2121. //MCIWndRecordPreview(hwnd);
  2122. }
  2123. else
  2124. {
  2125. MCIWndRecord(hwnd);
  2126. }
  2127. break;
  2128. // PLAY = normal play
  2129. // SHIFT+PLAY = play backward
  2130. // CTRL+PLAY = play fullscreen
  2131. // SHIFT+CTRL+PLAY = play fullscreen backward
  2132. //
  2133. case MCI_PLAY:
  2134. #define MaybeRepeat (p->fRepeat ? (LPSTR)szRepeat : (LPSTR)szNULL)
  2135. // NOTE: We never set errors for the repeat play, because
  2136. // lots of device don't support it and would fail.
  2137. if (GetKeyState(VK_SHIFT) < 0)
  2138. // If we're at the beginning, seek to the end.
  2139. MCIWndiPlaySeek(p, TRUE);
  2140. else
  2141. // If we're at the end, seek to the beginning.
  2142. MCIWndiPlaySeek(p, FALSE);
  2143. if (GetKeyState(VK_CONTROL) < 0)
  2144. {
  2145. if (GetKeyState(VK_SHIFT) < 0) {
  2146. if (MCIWndString(p, FALSE, szPlayFullscreenReverse,
  2147. MaybeRepeat))
  2148. MCIWndString(p, TRUE, szPlayFullscreenReverse,
  2149. (LPSTR)szNULL);
  2150. } else {
  2151. if (MCIWndString(p, FALSE, szPlayFullscreen,
  2152. MaybeRepeat))
  2153. MCIWndString(p, TRUE, szPlayFullscreen,
  2154. (LPSTR)szNULL);
  2155. }
  2156. } else if (GetKeyState(VK_SHIFT) < 0) {
  2157. if (MCIWndString(p, FALSE, szPlayReverse, MaybeRepeat))
  2158. MCIWndString(p, TRUE, szPlayReverse, (LPSTR)szNULL);
  2159. } else {
  2160. if (MCIWndString(p, FALSE, szPlay, MaybeRepeat))
  2161. MCIWndString(p, TRUE, szPlay, (LPSTR)szNULL);
  2162. }
  2163. // Kick ourselves to fix up toolbar since mode changed
  2164. MCIWndiTimerStuff(p);
  2165. break;
  2166. case MCI_STOP:
  2167. return MCIWndStop(hwnd);
  2168. case MCI_PAUSE:
  2169. return MCIWndPause(hwnd);
  2170. case IDM_MCINEW:
  2171. return MCIWndNew(hwnd, NULL);
  2172. case IDM_MCIOPEN:
  2173. return MCIWndOpenDialog(hwnd);
  2174. case MCI_SAVE:
  2175. return MCIWndSaveDialog(hwnd);
  2176. case IDM_MCICLOSE:
  2177. return MCIWndClose(hwnd);
  2178. case IDM_MCICONFIG:
  2179. MCIWndString(p, TRUE, szConfigure);
  2180. // AVI's configure box might change the size (zoom by 2)
  2181. // so we better call our size routine.
  2182. MCIWndiSize(p, 0);
  2183. // Taking ZOOM X 2 off might leave the outside not painted
  2184. InvalidateRect(hwnd, NULL, TRUE);
  2185. break;
  2186. case IDM_MCICOMMAND:
  2187. mciDialog(hwnd);
  2188. // call mciwndisize?
  2189. break;
  2190. case IDM_COPY:
  2191. MCIWndCopy(p);
  2192. break;
  2193. case IDM_MCIREWIND:
  2194. return MCIWndSeek(hwnd, MCIWND_START);
  2195. case IDM_MCIEJECT:
  2196. return MCIWndEject(hwnd);
  2197. case ID_TOOLBAR:
  2198. if (HIWORD(lParam) != TBN_BEGINDRAG ||
  2199. LOWORD(lParam) != IDM_MENU ||
  2200. !SendMessage(p->hwndToolbar, TB_ISBUTTONENABLED,
  2201. IDM_MENU, 0) ||
  2202. !p->hmenu)
  2203. break;
  2204. SendMessage(p->hwndToolbar, TB_GETITEMRECT,
  2205. (int)SendMessage(p->hwndToolbar, TB_COMMANDTOINDEX,
  2206. IDM_MENU, 0),
  2207. (LPARAM)(LPVOID)&rc);
  2208. rcT = rc;
  2209. ClientToScreen(p->hwndToolbar, (LPPOINT)&rc);
  2210. ClientToScreen(p->hwndToolbar, (LPPOINT)&rc + 1);
  2211. // Push the button down (accelerator won't have done this)
  2212. SendMessage(p->hwndToolbar, TB_PRESSBUTTON, IDM_MENU,
  2213. TRUE);
  2214. // Don't allow error dlgs to come up while we're tracking.
  2215. // That would cause windows to shatter and send shrapnel
  2216. // flying.
  2217. p->fTracking = TRUE;
  2218. TrackPopupMenu(p->hmenu, 0, rc.left, rc.bottom - 1, 0,
  2219. hwnd, &rc); // don't dismiss menu inside button
  2220. p->fTracking = FALSE;
  2221. // Bring the button back up.
  2222. SendMessage(p->hwndToolbar, TB_PRESSBUTTON, IDM_MENU,
  2223. FALSE);
  2224. // What if we press the menu button to make the menu go
  2225. // away? It's just going to bring the menu back up again!
  2226. // So we need to pull the click out of the queue.
  2227. // There are bugs in the toolbar code to prevent me from
  2228. // doing this any other way (like disabling the button)
  2229. if (PeekMessage(&msgT, p->hwndToolbar, WM_LBUTTONDOWN,
  2230. WM_LBUTTONDOWN, PM_NOREMOVE)) {
  2231. if (PtInRect(&rcT, MAKEPOINT(msgT.lParam)))
  2232. PeekMessage(&msgT, p->hwndToolbar, WM_LBUTTONDOWN,
  2233. WM_LBUTTONDOWN, PM_REMOVE);
  2234. }
  2235. break;
  2236. default:
  2237. break;
  2238. }
  2239. break;
  2240. case WM_DESTROY:
  2241. // !!! MMP CLOSE will be deferred till AFTER the DESTROY
  2242. // Don't palette kick when we're going down. Not necessary
  2243. //
  2244. p->fHasPalette = FALSE;
  2245. MCIWndiClose(p, FALSE); //don't leave us playing into a random DC
  2246. if (p->hmenu) {
  2247. DestroyMenu(p->hmenu);
  2248. FreeDitherBrush();
  2249. }
  2250. if (p->pTrackStart)
  2251. LocalFree((HANDLE)p->pTrackStart);
  2252. if (p->hfont) {
  2253. // !!! Someone else may have to go and create it again, but oh
  2254. // !!! well.
  2255. DeleteObject(p->hfont);
  2256. p->hfont = NULL;
  2257. }
  2258. if (p->hicon)
  2259. DestroyIcon(p->hicon);
  2260. // We can't destroy our pointer and then fall through and use it
  2261. f = p->fMdiWindow;
  2262. LocalFree((HLOCAL) p);
  2263. SetWindowLong(hwnd, 0, NULL); // our p
  2264. if (f)
  2265. return DefMDIChildProc(hwnd, msg, wParam, lParam);
  2266. else
  2267. return DefWindowProc(hwnd, msg, wParam, lParam);
  2268. // Use a different rate for the timer depending on if we're active
  2269. // or not.
  2270. case WM_NCACTIVATE:
  2271. // MDI windows need to realize their palette here
  2272. if (p->wDeviceID && p->fMdiWindow && p->fHasPalette)
  2273. MCIWndRealize(hwnd, wParam == FALSE);
  2274. #if 0
  2275. case WM_ACTIVATE:
  2276. p->fActive = wParam;
  2277. KillTimer(hwnd, TIMER1);
  2278. MCIWndiSetTimer(p);
  2279. #endif
  2280. break;
  2281. case WM_SETFOCUS:
  2282. p->fActive = TRUE;
  2283. KillTimer(hwnd, TIMER1);
  2284. MCIWndiSetTimer(p);
  2285. break;
  2286. case WM_KILLFOCUS:
  2287. p->fActive = FALSE;
  2288. KillTimer(hwnd, TIMER1);
  2289. MCIWndiSetTimer(p);
  2290. break;
  2291. // If the user uses MCINOTIFY we pass the notify on to the "owner"
  2292. case MM_MCINOTIFY:
  2293. // Kick ourselves to update toolbar/titles since getting a notify
  2294. // means that stuff might have changed.
  2295. MCIWndiTimerStuff(p);
  2296. return NotifyOwner(p, msg, wParam, lParam);
  2297. case WM_DRAWITEM:
  2298. case WM_MEASUREITEM:
  2299. case WM_DELETEITEM:
  2300. OwnerDraw(p, msg, wParam, lParam);
  2301. return TRUE; // !!!
  2302. case WM_SYSCOMMAND:
  2303. switch (wParam & ~0xF) {
  2304. case SC_MINIMIZE:
  2305. // Minimizing from MAXIMIZED state better do the same thing
  2306. // as restore or windows will always think it's maximized
  2307. // and start wierding out on us (Chico bug 19541).
  2308. if (IsZoomed(hwnd)) {
  2309. wParam = SC_RESTORE | (wParam & 0xF);
  2310. break; // MUST let DefWndProc run
  2311. }
  2312. if (p->wDeviceID && p->fCanWindow) {
  2313. RECT rc;
  2314. MCIWndGetDest(hwnd, &rc);
  2315. if (rc.right > p->rcNormal.right &&
  2316. rc.bottom > p->rcNormal.bottom) {
  2317. // We pressed buttons on the title bar... we really
  2318. // better autosize window.
  2319. dw = p->dwStyle;
  2320. p->dwStyle &= ~MCIWNDF_NOAUTOSIZEWINDOW;
  2321. MCIWndSetZoom(hwnd, 100);
  2322. p->dwStyle = dw;
  2323. return 0;
  2324. }
  2325. }
  2326. break;
  2327. case SC_MAXIMIZE:
  2328. if (p->fCanWindow && !IsIconic(hwnd)) {
  2329. RECT rc;
  2330. MCIWndGetDest(hwnd, &rc);
  2331. if (rc.right < p->rcNormal.right &&
  2332. rc.bottom < p->rcNormal.bottom) {
  2333. // We pressed buttons on the title bar... we really
  2334. // better autosize window.
  2335. dw = p->dwStyle;
  2336. p->dwStyle &= ~MCIWNDF_NOAUTOSIZEWINDOW;
  2337. MCIWndSetZoom(hwnd, 100);
  2338. p->dwStyle = dw;
  2339. return 0;
  2340. }
  2341. if (rc.right >= p->rcNormal.right &&
  2342. rc.right < p->rcNormal.right*2 &&
  2343. rc.bottom >= p->rcNormal.bottom &&
  2344. rc.bottom < p->rcNormal.bottom*2) {
  2345. // We pressed buttons on the title bar... we really
  2346. // better autosize window.
  2347. dw = p->dwStyle;
  2348. p->dwStyle &= ~MCIWNDF_NOAUTOSIZEWINDOW;
  2349. MCIWndSetZoom(hwnd, 200);
  2350. p->dwStyle = dw;
  2351. return 0;
  2352. }
  2353. }
  2354. break;
  2355. }
  2356. break;
  2357. case WM_DROPFILES:
  2358. MCIWndiDrop(hwnd, wParam);
  2359. break;
  2360. case WM_QUERYDRAGICON:
  2361. return (LONG)(UINT)p->hicon;
  2362. }
  2363. if (p && p->fMdiWindow)
  2364. return DefMDIChildProc(hwnd, msg, wParam, lParam);
  2365. else
  2366. return DefWindowProc(hwnd, msg, wParam, lParam);
  2367. }
  2368. static void NEAR PASCAL PatRect(HDC hdc,int x,int y,int dx,int dy)
  2369. {
  2370. RECT rc;
  2371. rc.left = x;
  2372. rc.top = y;
  2373. rc.right = x + dx;
  2374. rc.bottom = y + dy;
  2375. ExtTextOut(hdc,0,0,ETO_OPAQUE,&rc,NULL,0,NULL);
  2376. }
  2377. #define FillRC(hdc, prc) PatRect(hdc, (prc)->left, (prc)->top, (prc)->right - (prc)->left, (prc)->bottom-(prc)->top)
  2378. //
  2379. // Draw the channel for the volume and speed menu controls
  2380. //
  2381. static void NEAR PASCAL DrawChannel(HDC hdc, LPRECT prc)
  2382. {
  2383. HBRUSH hbrTemp;
  2384. int iWidth = prc->right - prc->left;
  2385. // draw the frame around the window
  2386. SetBkColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
  2387. PatRect(hdc, prc->left, prc->top, iWidth, 1);
  2388. PatRect(hdc, prc->left, prc->bottom-2, iWidth, 1);
  2389. PatRect(hdc, prc->left, prc->top, 1, prc->bottom-prc->top-1);
  2390. PatRect(hdc, prc->right-1, prc->top, 1, prc->bottom-prc->top-1);
  2391. SetBkColor(hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
  2392. PatRect(hdc, prc->left, prc->bottom-1, iWidth, 1);
  2393. SetBkColor(hdc, GetSysColor(COLOR_BTNSHADOW));
  2394. PatRect(hdc, prc->left+1, prc->top + 1, iWidth-2,1);
  2395. // draw the background in dither gray
  2396. hbrTemp = SelectObject(hdc, hbrDither);
  2397. if (hbrTemp) {
  2398. PatBlt(hdc, prc->left+1, prc->top + 2,
  2399. iWidth-2, prc->bottom-prc->top-4, PATCOPY);
  2400. SelectObject(hdc, hbrTemp);
  2401. }
  2402. }
  2403. static LONG OwnerDraw(PMCIWND p, UINT msg, WORD wParam, LONG lParam)
  2404. {
  2405. RECT rc, rcMenu, rcChannel, rcThumb;
  2406. HDC hdc;
  2407. int i,dx,dy,len;
  2408. char ach[10];
  2409. DWORD dw;
  2410. HWND hwnd = p->hwnd;
  2411. #define lpMIS ((LPMEASUREITEMSTRUCT)lParam)
  2412. #define lpDIS ((LPDRAWITEMSTRUCT)lParam)
  2413. #define WIDTH_FROM_THIN_AIR 14
  2414. #define CHANNEL_INDENT 6 // for VOLUME and SPEED menu trackbar
  2415. #define MENU_WIDTH 10
  2416. #define THUMB 5
  2417. #define MENU_ITEM_HEIGHT 2
  2418. switch (msg)
  2419. {
  2420. case WM_MEASUREITEM:
  2421. if (p->hfont == NULL)
  2422. p->hfont = CreateFont (8, 0, 0, 0,
  2423. FW_NORMAL,FALSE,FALSE,FALSE,
  2424. ANSI_CHARSET,OUT_DEFAULT_PRECIS,
  2425. CLIP_DEFAULT_PRECIS,PROOF_QUALITY,
  2426. VARIABLE_PITCH | FF_DONTCARE,
  2427. szSmallFonts);
  2428. //
  2429. // The first and last menu items are the spaces above and below
  2430. // the channel, so they need to be taller.
  2431. //
  2432. if (lpMIS->itemID == IDM_MCIVOLUME + VOLUME_MAX + 1
  2433. || lpMIS->itemID == IDM_MCISPEED + SPEED_MAX + 1
  2434. || lpMIS->itemID == IDM_MCIVOLUME + VOLUME_MAX + 2
  2435. || lpMIS->itemID == IDM_MCISPEED + SPEED_MAX + 2) {
  2436. lpMIS->itemHeight = CHANNEL_INDENT;
  2437. lpMIS->itemWidth = MENU_WIDTH;
  2438. } else {
  2439. lpMIS->itemHeight = MENU_ITEM_HEIGHT;
  2440. lpMIS->itemWidth = MENU_WIDTH;
  2441. }
  2442. return TRUE;
  2443. case WM_DRAWITEM:
  2444. rc = lpDIS->rcItem;
  2445. hdc = lpDIS->hDC;
  2446. //
  2447. // Something has been deselected. If we don't see a new selection
  2448. // soon, it means we've dragged the cursor off the menu, and we
  2449. // should pop the thumb back to its original spot.
  2450. //
  2451. if ((lpDIS->itemAction & ODA_SELECT) &&
  2452. !(lpDIS->itemState & ODS_SELECTED))
  2453. SetTimer(p->hwnd, TIMER2, 500, NULL);
  2454. //
  2455. // When asked to draw the selected or checked menu item, we will
  2456. // draw the entire menu. Otherwise, we don't do a thing
  2457. //
  2458. if (lpDIS->itemState & (ODS_SELECTED | ODS_CHECKED)) {
  2459. // This is the item that is checked, or the original spot for
  2460. // the thumb. Remember it so when we drag off the menu, we
  2461. // can bounce the thumb back here.
  2462. if (lpDIS->itemState & ODS_CHECKED) {
  2463. p->uiHack = lpDIS->itemID;
  2464. if (p->uiHack >= IDM_MCISPEED &&
  2465. p->uiHack <= IDM_MCISPEED + SPEED_MAX)
  2466. p->hmenuHack = p->hmenuSpeed;
  2467. else
  2468. p->hmenuHack = p->hmenuVolume;
  2469. }
  2470. // Something is being selected. Obviously the mouse is still
  2471. // on the menu. Scrap our timer that was waiting to see if
  2472. // we've dragged off the menu.
  2473. if (lpDIS->itemState & ODS_SELECTED)
  2474. KillTimer(p->hwnd, TIMER2);
  2475. // If we try to highlight the unused menu items, bail
  2476. if (lpDIS->itemID == IDM_MCIVOLUME + VOLUME_MAX + 1)
  2477. break;
  2478. if (lpDIS->itemID == IDM_MCIVOLUME + VOLUME_MAX + 2)
  2479. break;
  2480. if (lpDIS->itemID == IDM_MCISPEED + SPEED_MAX + 1)
  2481. break;
  2482. if (lpDIS->itemID == IDM_MCISPEED + SPEED_MAX + 2)
  2483. break;
  2484. // Actually set the parameter to the value we're dragging so
  2485. // we can hear it change as we move the slider.
  2486. // 42 means DON'T CHECK it (remember which item was originally
  2487. // checked).
  2488. SendMessage(hwnd, WM_COMMAND, lpDIS->itemID, 42);
  2489. //
  2490. // Get the rect of our menu window. GetClipBox is
  2491. // not quite right, so we'll adjust for the border. Our lpDIS
  2492. // contains the proper width of the client area, so we'll use
  2493. // that.
  2494. //
  2495. GetClipBox(hdc, &rc);
  2496. rc.top++; //!!! top border width
  2497. rc.bottom -= 2; //!!! bottom border width
  2498. rc.left = lpDIS->rcItem.left;
  2499. rc.right = lpDIS->rcItem.right;
  2500. rcMenu = rc; // This is the rect of the whole menu
  2501. // !!!
  2502. // Deflate the rect to the area we want the channel to be
  2503. // drawn in. Use HACKY constants.
  2504. // !!!
  2505. i = (rc.right - rc.left - WIDTH_FROM_THIN_AIR) / 2;
  2506. rc.top += CHANNEL_INDENT;
  2507. rc.bottom -= CHANNEL_INDENT;
  2508. rc.left += i;
  2509. rc.right -= i;
  2510. rcChannel = rc; // This is the rect of the channel
  2511. //
  2512. // See where the thumb belongs
  2513. //
  2514. rc = lpDIS->rcItem;
  2515. rc.bottom = rc.top + 2; // Ouch! Make sure size is 2
  2516. //
  2517. // Don't draw the thumb higher than the top of the channel
  2518. //
  2519. if (rc.top < rcChannel.top) {
  2520. rc.top = rcChannel.top;
  2521. rc.bottom = rc.top + 2; // itemHeight
  2522. }
  2523. //
  2524. // Don't draw the thumb below the bottom of the channel
  2525. //
  2526. if (rc.top > rcChannel.bottom - 2) { // where border is
  2527. rc.top = rcChannel.bottom - 2;
  2528. rc.bottom = rc.top + 2;
  2529. }
  2530. //
  2531. // Munge the rect in a bit and draw the thumb there
  2532. //
  2533. rc.left += 2;
  2534. rc.right -= 2;
  2535. rc.bottom+= THUMB;
  2536. rc.top -= THUMB;
  2537. #if 0
  2538. // Make the thumb a little bigger on the checked value
  2539. if (lpDIS->itemState & ODS_CHECKED) {
  2540. rc.top -= 1;
  2541. rc.bottom += 1;
  2542. }
  2543. #endif
  2544. rcThumb = rc; // This is the rect of the thumb
  2545. dx = rc.right - rc.left;
  2546. dy = rc.bottom - rc.top;
  2547. SetBkColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
  2548. PatRect(hdc, rc.left+1, rc.top, dx-2,1 );
  2549. PatRect(hdc, rc.left+1, rc.bottom-1,dx-2,1 );
  2550. PatRect(hdc, rc.left, rc.top+1, 1,dy-2 );
  2551. PatRect(hdc, rc.right-1, rc.top+1, 1,dy-2 );
  2552. InflateRect(&rc,-1,-1);
  2553. dx = rc.right - rc.left;
  2554. dy = rc.bottom - rc.top;
  2555. // SetBkColor(hdc, GetSysColor(COLOR_BTNHILIGHT));
  2556. SetBkColor(hdc, RGB(255,255,255));
  2557. PatRect(hdc, rc.left, rc.top, 1,dy);
  2558. PatRect(hdc, rc.left, rc.top, dx,1);
  2559. SetBkColor(hdc, GetSysColor(COLOR_BTNSHADOW));
  2560. PatRect(hdc, rc.right-1,rc.top+1, 1,dy-1);
  2561. PatRect(hdc, rc.left+1, rc.bottom-1, dx-1,1);
  2562. InflateRect(&rc,-1,-1);
  2563. SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
  2564. SelectObject(hdc, p->hfont);
  2565. len = wsprintf(ach, "%d", lpMIS->itemID % 1000);
  2566. dw = GetTextExtent(hdc, ach, len);
  2567. ExtTextOut(hdc,
  2568. (rc.right + rc.left - LOWORD(dw))/2,
  2569. (rc.bottom + rc.top - HIWORD(dw))/2,
  2570. ETO_OPAQUE,&rc,ach,len,NULL);
  2571. // FillRC(hdc, &rc);
  2572. //
  2573. // Exclude the ClipRect that all that garbage drew into
  2574. //
  2575. ExcludeClipRect(hdc, rcThumb.left, rcThumb.top,
  2576. rcThumb.right, rcThumb.bottom);
  2577. #if 0 // why?
  2578. ExcludeClipRect(hdc, rcThumb.left+1, rcThumb.top,
  2579. rcThumb.right-1, rcThumb.bottom);
  2580. ExcludeClipRect(hdc, rcThumb.left, rcThumb.top+1,
  2581. rcThumb.left+1, rcThumb.bottom-1);
  2582. ExcludeClipRect(hdc, rcThumb.right-1, rcThumb.top+1,
  2583. rcThumb.right, rcThumb.bottom-1);
  2584. #endif
  2585. //
  2586. // Next, draw the channel
  2587. //
  2588. DrawChannel(hdc, &rcChannel);
  2589. ExcludeClipRect(hdc, rcChannel.left, rcChannel.top,
  2590. rcChannel.right, rcChannel.bottom);
  2591. //
  2592. // Lastly, fill the entire menu rect with the menu colour
  2593. //
  2594. SetBkColor(hdc, GetSysColor(COLOR_MENU));
  2595. FillRC(hdc, &rcMenu);
  2596. }
  2597. return TRUE;
  2598. case WM_DELETEITEM:
  2599. return TRUE;
  2600. }
  2601. return TRUE;
  2602. }
  2603. //
  2604. // Code to implement the MCI command dialog box
  2605. //
  2606. void PositionWindowNearParent(HWND hwnd)
  2607. {
  2608. RECT rc;
  2609. RECT rcParent;
  2610. GetWindowRect(hwnd, &rc);
  2611. rc.bottom -= rc.top;
  2612. rc.right -= rc.left;
  2613. GetWindowRect(GetParent(hwnd), &rcParent);
  2614. if (rcParent.bottom + rc.bottom <
  2615. GetSystemMetrics(SM_CYSCREEN)) {
  2616. SetWindowPos(hwnd, NULL,
  2617. min(rc.left, GetSystemMetrics(SM_CXSCREEN) - rc.right),
  2618. rcParent.bottom,
  2619. 0, 0,
  2620. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  2621. } else if (rc.bottom < rcParent.top) {
  2622. SetWindowPos(hwnd, NULL,
  2623. min(rc.left, GetSystemMetrics(SM_CXSCREEN) - rc.right),
  2624. rcParent.top - rc.bottom,
  2625. 0, 0,
  2626. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  2627. }
  2628. }
  2629. /*--------------------------------------------------------------+
  2630. | mciDialog - bring up the dialog for MCI Send Command |
  2631. | |
  2632. +--------------------------------------------------------------*/
  2633. INT_PTR CALLBACK mciDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  2634. {
  2635. char ach[255];
  2636. UINT w;
  2637. DWORD dw;
  2638. PMCIWND p;
  2639. HWND hwndP;
  2640. switch (msg)
  2641. {
  2642. case WM_INITDIALOG:
  2643. // Remember our actually true parent
  2644. SetWindowLong(hwnd, DWL_USER, lParam);
  2645. PositionWindowNearParent(hwnd);
  2646. return TRUE;
  2647. case WM_COMMAND:
  2648. switch (LOWORD(wParam))
  2649. {
  2650. case IDOK:
  2651. #ifdef WIN32
  2652. SendDlgItemMessage(hwnd, IDC_MCICOMMAND, EM_SETSEL, 0, (LPARAM)-1);
  2653. #else
  2654. SendDlgItemMessage(hwnd, IDC_MCICOMMAND, EM_SETSEL, 0, MAKELONG(0, -1));
  2655. #endif
  2656. w = GetDlgItemText(hwnd, IDC_MCICOMMAND, ach, sizeof(ach));
  2657. hwndP = (HWND)GetWindowLong(hwnd, DWL_USER);
  2658. p = (PMCIWND)(UINT)GetWindowLong(hwndP, 0);
  2659. // special case the CLOSE command to do our clean up
  2660. if (lstrcmpi((LPSTR)ach, szClose) == 0) {
  2661. MCIWndClose(hwndP);
  2662. break;
  2663. }
  2664. dw = MCIWndGet(p, ach, ach, sizeof(ach));
  2665. if (dw != 0)
  2666. mciGetErrorString(dw, ach, sizeof(ach));
  2667. SetDlgItemText(hwnd, IDC_RESULT, ach);
  2668. // kick ourselves in case mode changed from this command
  2669. MCIWndiTimerStuff(p);
  2670. break;
  2671. case IDCANCEL:
  2672. EndDialog(hwnd, FALSE);
  2673. break;
  2674. }
  2675. break;
  2676. }
  2677. return FALSE;
  2678. }
  2679. static BOOL NEAR PASCAL mciDialog(HWND hwnd)
  2680. {
  2681. DialogBoxParam(hInst, MAKEINTATOM(DLG_MCICOMMAND), hwnd,
  2682. mciDlgProc, hwnd);
  2683. return TRUE;
  2684. }
  2685. //
  2686. // Code to implement the Copy command:
  2687. //
  2688. //
  2689. // MCIWnd tries to copy the same things to the clipboard that VfW MPlayer
  2690. // would have.
  2691. //
  2692. #define SLASH(c) ((c) == '/' || (c) == '\\')
  2693. /**************************************************************************
  2694. convert a file name to a fully qualifed path name, if the file
  2695. exists on a net drive the UNC name is returned.
  2696. ***************************************************************************/
  2697. static BOOL NetParseFile(LPSTR szFile, LPSTR szPath)
  2698. {
  2699. char achDrive[4];
  2700. char achRemote[128];
  2701. int cbRemote = sizeof(achRemote);
  2702. OFSTRUCT of;
  2703. if (szPath == NULL)
  2704. szPath = szFile;
  2705. else
  2706. szPath[0] = 0;
  2707. //
  2708. // Fully qualify the file name
  2709. //
  2710. if (OpenFile(szFile, &of, OF_PARSE) == -1)
  2711. return FALSE;
  2712. lstrcpy(szPath, of.szPathName);
  2713. //
  2714. // if the file is not drive based (probably UNC)
  2715. //
  2716. if (szPath[1] != ':')
  2717. return TRUE;
  2718. achDrive[0] = szPath[0];
  2719. achDrive[1] = ':';
  2720. achDrive[2] = '\0';
  2721. if (WNetGetConnection(achDrive, achRemote, &cbRemote) != WN_SUCCESS)
  2722. return FALSE;
  2723. if (!SLASH(achRemote[0]) || !SLASH(achRemote[1]))
  2724. return TRUE;
  2725. lstrcat(achRemote, szPath+2);
  2726. lstrcpy(szPath, achRemote);
  2727. return TRUE;
  2728. }
  2729. SZCODE aszMPlayerName[] = "MPlayer";
  2730. HANDLE GetMPlayerData(PMCIWND p)
  2731. {
  2732. char szFileName[128];
  2733. char ach[40];
  2734. char szDevice[40];
  2735. HANDLE h;
  2736. LPSTR psz;
  2737. int len;
  2738. LPSTR lpszCaption = szFileName;
  2739. UINT wOptions;
  2740. RECT rc;
  2741. BOOL fCompound, fFile;
  2742. DWORD dw;
  2743. MCI_GETDEVCAPS_PARMS mciDevCaps; /* for the MCI_GETDEVCAPS command */
  2744. //
  2745. // Get the Device Name
  2746. //
  2747. MCIWndGet(p, "sysinfo installname", szDevice, sizeof(szDevice));
  2748. //
  2749. // determine if the device is simple or compound
  2750. //
  2751. mciDevCaps.dwItem = MCI_GETDEVCAPS_COMPOUND_DEVICE;
  2752. dw = mciSendCommand(p->wDeviceID, MCI_GETDEVCAPS,
  2753. MCI_GETDEVCAPS_ITEM, (DWORD)(LPSTR)&mciDevCaps);
  2754. fCompound = (dw == 0 && mciDevCaps.dwReturn != 0);
  2755. //
  2756. // determine if the device handles files
  2757. //
  2758. if (fCompound) {
  2759. mciDevCaps.dwItem = MCI_GETDEVCAPS_USES_FILES;
  2760. dw = mciSendCommand(p->wDeviceID, MCI_GETDEVCAPS,
  2761. MCI_GETDEVCAPS_ITEM, (DWORD)(LPSTR)&mciDevCaps);
  2762. fFile = (dw == 0 && mciDevCaps.dwReturn != 0);
  2763. }
  2764. //
  2765. // Compound devices that support files have an associated filename
  2766. //
  2767. if (fCompound && fFile) {
  2768. lstrcpy(szFileName, p->achFileName);
  2769. //
  2770. // Sometimes the filename is really "device!filename" so we have to peel
  2771. // the real filename out of it
  2772. //
  2773. lstrcpyn(ach, szFileName, lstrlen(szDevice) + 1);
  2774. if ((lstrcmpi(szDevice, ach) == 0) &&
  2775. (szFileName[lstrlen(szDevice)] == '!')) {
  2776. lstrcpy(szFileName, &(p->achFileName[lstrlen(szDevice) + 1]));
  2777. }
  2778. NetParseFile(szFileName, (LPSTR)NULL);
  2779. OemToAnsi(szFileName,szFileName); // Map extended chars.
  2780. } else {
  2781. szFileName[0] = 0;
  2782. }
  2783. #ifdef DEBUG
  2784. DPF(" GetLink: %s|%s!%s\n",
  2785. (LPSTR)aszMPlayerName,
  2786. (LPSTR)szFileName,
  2787. (LPSTR)szDevice);
  2788. #endif
  2789. /* How much data will we be writing? */
  2790. len = 9 + // all the delimeters
  2791. lstrlen(aszMPlayerName) +
  2792. lstrlen(szFileName) +
  2793. lstrlen(szDevice) +
  2794. 5 + 10 + 10 + 10 + // max length of int and long strings
  2795. lstrlen(lpszCaption);
  2796. h = GlobalAlloc(GMEM_DDESHARE|GMEM_ZEROINIT, len);
  2797. if (!h)
  2798. return NULL;
  2799. psz = GlobalLock(h);
  2800. wOptions = 0x0030; // !!!! OPT_PLAY|OPT_BAR
  2801. switch (MCIWndStatus(p, MCI_STATUS_TIME_FORMAT, 0)) {
  2802. case MCI_FORMAT_FRAMES:
  2803. wOptions |= 1; // frame mode
  2804. break;
  2805. case MCI_FORMAT_MILLISECONDS:
  2806. wOptions |= 2; // time mode
  2807. break;
  2808. }
  2809. MCIWndRect(p, &rc, FALSE);
  2810. wsprintf(psz, "%s%c%s%c%s%c%d%c%ld%c%ld%c%ld%c%d%c%s%c",
  2811. (LPSTR)aszMPlayerName, 0,
  2812. (LPSTR)szFileName, 0,
  2813. (LPSTR)szDevice, ',',
  2814. wOptions, ',',
  2815. 0L, ',', // !!! sel start
  2816. 0L, ',', // !!! sel length
  2817. p->dwPos, ',',
  2818. rc.bottom - rc.top, ',',
  2819. lpszCaption, 0);
  2820. return h;
  2821. }
  2822. HBITMAP FAR PASCAL BitmapMCI(PMCIWND p)
  2823. {
  2824. HDC hdc, hdcMem;
  2825. HBITMAP hbm, hbmT;
  2826. HBRUSH hbrOld;
  2827. DWORD dw;
  2828. RECT rc;
  2829. HBRUSH hbrWindowColour;
  2830. /* Minimum size of bitmap is icon size */
  2831. int ICON_MINX = GetSystemMetrics(SM_CXICON);
  2832. int ICON_MINY = GetSystemMetrics(SM_CYICON);
  2833. /* Get size of a frame or an icon that we'll be drawing */
  2834. MCIWndRect(p, &rc, FALSE);
  2835. SetRect(&rc, 0, 0,
  2836. max(ICON_MINX, rc.right - rc.left),
  2837. max(ICON_MINX, rc.bottom - rc.top));
  2838. hdc = GetDC(NULL);
  2839. if (hdc == NULL)
  2840. return NULL;
  2841. hdcMem = CreateCompatibleDC(NULL);
  2842. if (hdcMem == NULL) {
  2843. ReleaseDC(NULL, hdc);
  2844. return NULL;
  2845. }
  2846. /* Big enough to hold text caption too, if necessary */
  2847. hbm = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
  2848. ReleaseDC(NULL, hdc);
  2849. if (hbm == NULL) {
  2850. DeleteDC(hdcMem);
  2851. return NULL;
  2852. }
  2853. hbmT = SelectObject(hdcMem, hbm);
  2854. hbrWindowColour = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  2855. hbrOld = SelectObject(hdcMem, hbrWindowColour);
  2856. PatBlt(hdcMem, 0,0, rc.right, rc.bottom, PATCOPY);
  2857. SelectObject(hdcMem, hbrOld);
  2858. DeleteObject(hbrWindowColour);
  2859. if (p->wDeviceID && p->fCanWindow)
  2860. {
  2861. MCI_ANIM_UPDATE_PARMS mciUpdate;
  2862. mciUpdate.hDC = hdcMem;
  2863. dw = mciSendCommand(p->wDeviceID, MCI_UPDATE,
  2864. MCI_ANIM_UPDATE_HDC | MCI_WAIT,
  2865. (DWORD)(LPVOID)&mciUpdate);
  2866. } else {
  2867. DrawIcon(hdcMem, rc.left, rc.top, p->hicon);
  2868. }
  2869. if (hbmT)
  2870. SelectObject(hdcMem, hbmT);
  2871. DeleteDC(hdcMem);
  2872. return hbm;
  2873. }
  2874. HPALETTE CopyPalette(HPALETTE hpal)
  2875. {
  2876. PLOGPALETTE ppal;
  2877. int nNumEntries;
  2878. int i;
  2879. if (!hpal)
  2880. return NULL;
  2881. GetObject(hpal,sizeof(int),(LPSTR)&nNumEntries);
  2882. if (nNumEntries == 0)
  2883. return NULL;
  2884. ppal = (PLOGPALETTE)LocalAlloc(LPTR,sizeof(LOGPALETTE) +
  2885. nNumEntries * sizeof(PALETTEENTRY));
  2886. if (!ppal)
  2887. return NULL;
  2888. ppal->palVersion = 0x300;
  2889. ppal->palNumEntries = nNumEntries;
  2890. GetPaletteEntries(hpal,0,nNumEntries,ppal->palPalEntry);
  2891. for (i=0; i<nNumEntries; i++)
  2892. ppal->palPalEntry[i].peFlags = 0;
  2893. hpal = CreatePalette(ppal);
  2894. LocalFree((HANDLE)ppal);
  2895. return hpal;
  2896. }
  2897. HANDLE FAR PASCAL PictureFromDib(HANDLE hdib, HPALETTE hpal)
  2898. {
  2899. LPMETAFILEPICT pmfp;
  2900. HANDLE hmfp;
  2901. HANDLE hmf;
  2902. HANDLE hdc;
  2903. LPBITMAPINFOHEADER lpbi;
  2904. if (!hdib)
  2905. return NULL;
  2906. lpbi = (LPVOID)GlobalLock(hdib);
  2907. if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
  2908. lpbi->biClrUsed = 1 << lpbi->biBitCount;
  2909. hdc = CreateMetaFile(NULL);
  2910. if (!hdc)
  2911. return NULL;
  2912. SetWindowOrgEx(hdc, 0, 0, NULL);
  2913. SetWindowExtEx(hdc, (int)lpbi->biWidth, (int)lpbi->biHeight, NULL);
  2914. if (hpal)
  2915. {
  2916. SelectPalette(hdc,hpal,FALSE);
  2917. RealizePalette(hdc);
  2918. }
  2919. SetStretchBltMode(hdc, COLORONCOLOR);
  2920. StretchDIBits(hdc,
  2921. 0,0,(int)lpbi->biWidth, (int)lpbi->biHeight,
  2922. 0,0,(int)lpbi->biWidth, (int)lpbi->biHeight,
  2923. (LPBYTE)lpbi + (int)lpbi->biSize + (int)lpbi->biClrUsed * sizeof(RGBQUAD),
  2924. (LPBITMAPINFO)lpbi,
  2925. DIB_RGB_COLORS,
  2926. SRCCOPY);
  2927. if (hpal)
  2928. SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
  2929. hmf = CloseMetaFile(hdc);
  2930. if (hmfp = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT)))
  2931. {
  2932. pmfp = (LPMETAFILEPICT)GlobalLock(hmfp);
  2933. hdc = GetDC(NULL);
  2934. #if 1
  2935. pmfp->mm = MM_ANISOTROPIC;
  2936. pmfp->hMF = hmf;
  2937. pmfp->xExt = MulDiv((int)lpbi->biWidth ,2540,GetDeviceCaps(hdc, LOGPIXELSX));
  2938. pmfp->yExt = MulDiv((int)lpbi->biHeight,2540,GetDeviceCaps(hdc, LOGPIXELSX));
  2939. #else
  2940. pmfp->mm = MM_TEXT;
  2941. pmfp->hMF = hmf;
  2942. pmfp->xExt = (int)lpbi->biWidth;
  2943. pmfp->yExt = (int)lpbi->biHeight;
  2944. #endif
  2945. ReleaseDC(NULL, hdc);
  2946. }
  2947. else
  2948. {
  2949. DeleteMetaFile(hmf);
  2950. }
  2951. return hmfp;
  2952. }
  2953. #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  2954. /*
  2955. * DibFromBitmap()
  2956. *
  2957. * Will create a global memory block in DIB format that represents the DDB
  2958. * passed in
  2959. *
  2960. */
  2961. HANDLE FAR PASCAL DibFromBitmap(HBITMAP hbm, HPALETTE hpal)
  2962. {
  2963. BITMAP bm;
  2964. BITMAPINFOHEADER bi;
  2965. BITMAPINFOHEADER FAR *lpbi;
  2966. DWORD dw;
  2967. HANDLE hdib;
  2968. HDC hdc;
  2969. HPALETTE hpalT;
  2970. if (!hbm)
  2971. return NULL;
  2972. GetObject(hbm,sizeof(bm),(LPSTR)&bm);
  2973. bi.biSize = sizeof(BITMAPINFOHEADER);
  2974. bi.biWidth = bm.bmWidth;
  2975. bi.biHeight = bm.bmHeight;
  2976. bi.biPlanes = 1;
  2977. bi.biBitCount = (bm.bmPlanes * bm.bmBitsPixel) > 8 ? 24 : 8;
  2978. bi.biCompression = BI_RGB;
  2979. bi.biSizeImage = (DWORD)WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight;
  2980. bi.biXPelsPerMeter = 0;
  2981. bi.biYPelsPerMeter = 0;
  2982. bi.biClrUsed = bi.biBitCount == 8 ? 256 : 0;
  2983. bi.biClrImportant = 0;
  2984. dw = bi.biSize + bi.biClrUsed * sizeof(RGBQUAD) + bi.biSizeImage;
  2985. hdib = GlobalAlloc(GHND | GMEM_DDESHARE, dw);
  2986. if (!hdib)
  2987. return NULL;
  2988. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
  2989. *lpbi = bi;
  2990. hdc = CreateCompatibleDC(NULL);
  2991. if (hpal)
  2992. {
  2993. hpalT = SelectPalette(hdc,hpal,FALSE);
  2994. RealizePalette(hdc);
  2995. }
  2996. GetDIBits(hdc, hbm, 0, (UINT)bi.biHeight,
  2997. (LPSTR)lpbi + (int)lpbi->biSize + (int)lpbi->biClrUsed * sizeof(RGBQUAD),
  2998. (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
  2999. if (hpal)
  3000. SelectPalette(hdc,hpalT,FALSE);
  3001. DeleteDC(hdc);
  3002. return hdib;
  3003. }
  3004. SZCODE aszNative[] = "Native";
  3005. SZCODE aszOwnerLink[] = "OwnerLink";
  3006. // Pretend to be MPlayer copying to the clipboard
  3007. static void NEAR PASCAL MCIWndCopy(PMCIWND p)
  3008. {
  3009. UINT cfNative;
  3010. UINT cfOwnerLink;
  3011. HBITMAP hbm;
  3012. HPALETTE hpal;
  3013. HANDLE hdib;
  3014. HANDLE hmfp;
  3015. cfNative = RegisterClipboardFormat(aszNative);
  3016. cfOwnerLink = RegisterClipboardFormat(aszOwnerLink);
  3017. if (p->wDeviceID) {
  3018. OpenClipboard(p->hwnd);
  3019. EmptyClipboard();
  3020. SetClipboardData(cfNative, GetMPlayerData(p));
  3021. SetClipboardData(cfOwnerLink, GetMPlayerData(p));
  3022. hbm = BitmapMCI(p);
  3023. hpal = MCIWndGetPalette(p->hwnd);
  3024. hpal = CopyPalette(hpal);
  3025. if (hbm) {
  3026. hdib = DibFromBitmap(hbm, hpal);
  3027. hmfp = PictureFromDib(hdib, hpal);
  3028. if (hmfp)
  3029. SetClipboardData(CF_METAFILEPICT, hmfp);
  3030. if (hdib)
  3031. SetClipboardData(CF_DIB, hdib);
  3032. DeleteObject(hbm);
  3033. }
  3034. if (hpal)
  3035. SetClipboardData(CF_PALETTE, hpal);
  3036. CloseClipboard();
  3037. }
  3038. }
  3039. /*****************************************************************************
  3040. ****************************************************************************/
  3041. #ifdef DEBUG
  3042. static void cdecl dprintf(PSTR szFormat, ...)
  3043. {
  3044. char ach[128];
  3045. static BOOL fDebug = -1;
  3046. if (fDebug == -1)
  3047. fDebug = GetProfileInt(szDebug, MODNAME, FALSE);
  3048. if (!fDebug)
  3049. return;
  3050. lstrcpy(ach, MODNAME ": ");
  3051. wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
  3052. lstrcat(ach, "\r\n");
  3053. OutputDebugString(ach);
  3054. }
  3055. #endif