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.

4855 lines
139 KiB

  1. /*-----------------------------------------------------------------------------+
  2. | MPLAYER.C |
  3. | |
  4. | This file contains the code that implements the "MPlayer" (main) dialog box. |
  5. | |
  6. | (C) Copyright Microsoft Corporation 1991. All rights reserved. |
  7. | |
  8. | Revision History |
  9. | Oct-1992 MikeTri Ported to WIN32 / WIN16 common code |
  10. | |
  11. +-----------------------------------------------------------------------------*/
  12. /* include files */
  13. #include "nocrap.h"
  14. #include "stdio.h"
  15. #include <windows.h>
  16. #include <mmsystem.h>
  17. #include <shellapi.h>
  18. #include <windowsx.h>
  19. #include <htmlhelp.h>
  20. #include <tchar.h>
  21. #define INCGUID
  22. #include "mpole.h"
  23. #include "mplayer.h"
  24. #include "toolbar.h"
  25. #include "fixreg.h"
  26. #include "helpids.h"
  27. //These include files for WM_DEVICECHANGE messages from the mixer
  28. #include <dbt.h>
  29. #include <cfgmgr32.h>
  30. #include <initguid.h>
  31. #include <mmddk.h>
  32. #include <ks.h>
  33. #include <ksmedia.h>
  34. HDEVNOTIFY MixerEventContext = NULL; //Event Context for WM_DEVICECHANGE messages related to mixer
  35. BOOL DeviceChange_Init(HWND hWnd);
  36. void DeviceChange_Cleanup();
  37. //extern int FAR PASCAL ShellAbout(HWND hWnd, LPCTSTR szApp, LPCTSTR szOtherStuff, HICON hIcon);
  38. /* in server.c, but not in a header file like it should be... */
  39. extern PTSTR FAR FileName(LPCTSTR szPath);
  40. /* globals */
  41. // Used in converting units from pixels to Himetric and vice-versa
  42. int giXppli = 0; // pixels per logical inch along width
  43. int giYppli = 0; // pixels per logical inch along height
  44. // Since this is a not an MDI app, there can be only one server and one doc.
  45. CLSID clsid;
  46. SRVR srvrMain;
  47. DOC docMain;
  48. LPMALLOC lpMalloc;
  49. TCHAR szClient[cchFilenameMax];
  50. TCHAR szClientDoc[cchFilenameMax];
  51. // Has the user made changes to the document?
  52. BOOL fDocChanged = FALSE;
  53. /*********************************************************************
  54. ** OLE2NOTE: the very last thing an app must be do is properly shut
  55. ** down OLE. This call MUST be guarded! it is only allowable to
  56. ** call OleUninitialize if OleInitialize has been called.
  57. *********************************************************************/
  58. // Has OleInitialize been called? assume not.
  59. BOOL gfOleInitialized = FALSE;
  60. // Clipboard formats
  61. CLIPFORMAT cfNative;
  62. CLIPFORMAT cfEmbedSource;
  63. CLIPFORMAT cfObjectDescriptor;
  64. CLIPFORMAT cfMPlayer;
  65. LPWSTR sz1Ole10Native = L"\1Ole10Native";
  66. /* in server.c, but not in a header file like it should be... */
  67. extern LPTSTR FAR FileName(LPCTSTR szPath);
  68. /* in init.c */
  69. extern PTSTR gpchFilter;
  70. //extern HMREGNOTIFY ghmrn;
  71. /* globals */
  72. DWORD gwPlatformId;
  73. UINT gwPlaybarHeight=TOOLBAR_HEIGHT;/* Taken from server.c */
  74. UINT gwOptions; /* The object options from the dlg box */
  75. BOOL gfEmbeddedObject; // TRUE if editing embedded OLE object
  76. BOOL gfRunWithEmbeddingFlag; // TRUE if we are run with "-Embedding"
  77. BOOL gfPlayingInPlace; // TRUE if playing in place
  78. BOOL gfParentWasEnabled; // TRUE if parent was enabled
  79. BOOL gfShowWhilePlaying; //
  80. BOOL gfDirty; //
  81. int gfErrorBox; // TRUE if we have a message box active
  82. BOOL gfErrorDeath;
  83. BOOL gfWinIniChange;
  84. HHOOK hHookMouse; // Mouse hook handle.
  85. HOOKPROC fpMouseHook; // Mouse hook proc address.
  86. HWND ghwndFocusSave; // saved focus window
  87. BOOL gfOpenDialog = FALSE; // If TRUE, put up open dialog
  88. BOOL gfCloseAfterPlaying = FALSE;// TRUE if we are to hide after play
  89. HICON hiconApp; /* app icon */
  90. HMENU ghMenu; /* handle to the dialog's main menu */
  91. HMENU ghDeviceMenu; /* handle to the Device popup menu */
  92. HWND ghwndApp; /* handle to the MPlayer (main) dialog box*/
  93. HWND ghwndMap; /* handle to the track map window */
  94. HWND ghwndStatic; /* handle to the static text window */
  95. HBRUSH ghbrFillPat; /* The selection fill pattern. */
  96. HWND ghwndToolbar; /* handle of the toolbar */
  97. HWND ghwndMark; /* handle of the mark buttons toolbar */
  98. HWND ghwndFSArrows; /* handle of the arrows to the scrollbar */
  99. HWND ghwndTrackbar; /* handle to the trackbar window */
  100. UINT gwStatus = (UINT)(-1); /* device status (if <gwDeviceID> != NULL)*/
  101. DWORD gdwSeekPosition; /* Place to seek to next */
  102. BOOL gfValidMediaInfo; /* are we displaying valid media info? */
  103. BOOL gfValidCaption; /* are we displaying a valid caption? */
  104. BOOL gfScrollTrack; /* is user dragging the scrollbar thumb? */
  105. BOOL gfPlayOnly; /* play only window? */
  106. BOOL gfJustPlayed = FALSE; /* Just sent a PlayMCI() command */
  107. BOOL gfJustPlayedSel = FALSE; /* Just sent a ID_PLAYSEL command. */
  108. BOOL gfUserStopped = FALSE; /* user pressed stop - didn't happen itslf*/
  109. DWORD_PTR dwLastPageUpTime; /* time of last page-left operation */
  110. UINT gwCurScale = ID_NONE; /* current scale style */
  111. LONG glSelStart = -1; /* See if selection changes (dirty object)*/
  112. LONG glSelEnd = -1; /* See if selection changes (dirty object)*/
  113. int gInc; /* how much to inc/dec spin arrows by */
  114. BOOL gfAppActive = FALSE; /* Are we the active application? */
  115. UINT gwHeightAdjust;
  116. HWND ghwndFocus = NULL; /* Who had the focus when we went inactive*/
  117. BOOL gfInClose = FALSE; /* ack?*/
  118. BOOL gfCurrentCDChecked = FALSE; /* TRUE if we've checked whether it can play */
  119. BOOL gfCurrentCDNotAudio = FALSE;/* TRUE when we have a CD that we can't play */
  120. extern BOOL gfInPlayMCI;
  121. LPDATAOBJECT gpClipboardDataObject = NULL; /* If non-NULL, call OleFlushClipboard on exit */
  122. HPALETTE ghpalApp;
  123. static sfSeekExact; // last state
  124. UINT gwCurDevice = 0; /* current device */
  125. UINT gwNumDevices = 0; /* number of available media devices */
  126. MCIDEVICE garMciDevices[MAX_MCI_DEVICES]; /* array with info about a device */
  127. /* strings which get loaded in InitMplayerDialog in init.c, English version shown here
  128. All the sizes are much larger than needed, probably. Maybe could save nearly 100 bytes!! :)
  129. */
  130. extern TCHAR gszFrames[40]; /* "frames" */
  131. extern TCHAR gszHrs[20]; /* "hrs" */
  132. extern TCHAR gszMin[20]; /* "min" */
  133. extern TCHAR gszSec[20]; /* "sec" */
  134. extern TCHAR gszMsec[20]; /* "msec" */
  135. static SZCODE aszNULL[] = TEXT("");
  136. static BOOL sfInLayout = FALSE; // don't let Layout get re-entered
  137. static SZCODE szSndVol32[] = TEXT("sndvol32.exe");
  138. static SZCODE aszTitleFormat[] = TEXT("%"TS" - %"TS"");
  139. HANDLE ghInst; /* handle to the application instance */
  140. HFONT ghfontMap; /* handle to the font used for drawing
  141. the track map */
  142. LPTSTR gszCmdLine; /* string holding the command line parms */
  143. int giCmdShow; /* command show */
  144. TCHAR gachFileDevice[MAX_PATH]; /* string holding the curr file or device */
  145. TCHAR gachWindowTitle[MAX_PATH]; /* string holding name we will display */
  146. TCHAR gachCaption[MAX_PATH]; /* string holding name we will display */
  147. HACCEL hAccel;
  148. int gcAccelEntries;
  149. typedef struct _POS
  150. {
  151. int x;
  152. int y;
  153. int cx; /* This field is non-0 if we're currently sizing/moving */
  154. int cy;
  155. }
  156. POS, *PPOS;
  157. POS posSizeMove = {0,0,0,0}; /* POS we want during size/move operations */
  158. STRING_TO_ID_MAP DevToIconIDMap[] =
  159. {
  160. { szCDAudio, IDI_DCDA },
  161. { szVideoDisc, IDI_DDEFAULT },
  162. { szSequencer, IDI_DMIDI },
  163. { szVCR, IDI_DDEFAULT },
  164. { szWaveAudio, IDI_DSOUND },
  165. { szAVIVideo, IDI_DVIDEO }
  166. };
  167. //CDA file processing///////////////////////////////////////////////////
  168. //The following structure taken from deluxecd. This is used in processing
  169. typedef struct {
  170. DWORD dwRIFF; // 'RIFF'
  171. DWORD dwSize; // Chunk size = (file size - 8)
  172. DWORD dwCDDA; // 'CDDA'
  173. DWORD dwFmt; // 'fmt '
  174. DWORD dwCDDASize; // Chunk size of 'fmt ' = 24
  175. WORD wFormat; // Format tag
  176. WORD wTrack; // Track number
  177. DWORD DiscID; // Unique disk id
  178. DWORD lbnTrackStart; // Track starting sector (LBN)
  179. DWORD lbnTrackLength; // Track length (LBN count)
  180. DWORD msfTrackStart; // Track starting sector (MSF)
  181. DWORD msfTrackLength; // Track length (MSF)
  182. } RIFFCDA;
  183. void HandleCDAFile(TCHAR *szFile);
  184. BOOL IsTrackFileNameValid(LPTSTR lpstFileName, UINT *pUiTrackIndex);
  185. void JumpToCDTrack(UINT trackno);
  186. ////////////////////////////////////////////////////////////////////////
  187. /* private function prototypes */
  188. //int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int iCmdShow);
  189. void CleanUpClipboard();
  190. int GetHeightAdjust(HWND hwnd);
  191. HANDLE PASCAL GetDib (VOID);
  192. static HHOOK fpfnOldMsgFilter;
  193. static HOOKPROC fpfnMsgHook;
  194. //Data used for supporting context menu help
  195. BOOL bF1InMenu=FALSE; //If true F1 was pressed on a menu item.
  196. UINT currMenuItem=0; //The current menu item if any.
  197. typedef void (FAR PASCAL *PENWINREGISTERPROC)(UINT, BOOL);
  198. /* Define some constants to make parameters to CreateEvent a tad less obscure:
  199. */
  200. #define EVENT_DEFAULT_SECURITY NULL
  201. #define EVENT_RESET_MANUAL TRUE
  202. #define EVENT_RESET_AUTOMATIC FALSE
  203. #define EVENT_INITIAL_STATE_SIGNALED TRUE
  204. #define EVENT_INITIAL_STATE_NOT_SIGNALED FALSE
  205. #define EVENT_NO_NAME NULL
  206. HANDLE heventCmdLineScanned; /* Event will be signaled when command line scanned */
  207. HANDLE heventDeviceMenuBuilt; /* Event will be signaled when device menu complete */
  208. #ifdef LATER
  209. SCALE gscaleInitXY[2] = { 0, 0, 0, 0 }; // Initial scale to use for inserting OLE objects
  210. #endif
  211. /*------------------------------------------------------+
  212. | HelpMsgFilter - filter for F1 key in dialogs |
  213. | |
  214. +------------------------------------------------------*/
  215. DWORD FAR PASCAL HelpMsgFilter(int nCode, DWORD_PTR wParam, DWORD_PTR lParam)
  216. {
  217. if (nCode >= 0){
  218. LPMSG msg = (LPMSG)lParam;
  219. if ((msg->message == WM_KEYDOWN) && (msg->wParam == VK_F1))
  220. {
  221. if(nCode == MSGF_MENU)
  222. bF1InMenu = TRUE;
  223. SendMessage(ghwndApp, WM_COMMAND, (WPARAM)IDM_HELPTOPICS, 0L);
  224. }
  225. }
  226. // return DefHookProc(nCode, wParam, lParam, (HHOOK FAR *)&fpfnOldMsgFilter);
  227. return 0;
  228. }
  229. #ifdef CHICAGO_PRODUCT
  230. BOOL IsBadSegmentedCodePtr(LPARAM lpPtr)
  231. {
  232. #define DSC_PRESENT 0x80
  233. #define DSC_CODE_BIT 0x08
  234. #define DSC_RW_BIT 0x02
  235. #define DSC_DISCARDABLE 0x10
  236. WORD wSel;
  237. WORD wOff;
  238. BOOL fRet;
  239. wSel = HIWORD(lpPtr);
  240. wOff = LOWORD(lpPtr);
  241. _asm {
  242. mov ax, [wSel];
  243. lar bx, ax;
  244. jnz ValidDriverCallback_Failure ; //Return TRUE for error
  245. mov ch, DSC_CODE_BIT or DSC_RW_BIT or DSC_PRESENT ;
  246. and bh, ch;
  247. cmp bh, ch;
  248. jne ValidDriverCallback_Failure ; //Not executable segment
  249. test bl, DSC_DISCARDABLE ;
  250. jnz ValidDriverCallback_Failure ; //Not fixed segment
  251. lsl cx, ax; ; //Get segment limit
  252. mov bx, [wOff];
  253. cmp bx, cx;
  254. jb ValidDriverCallback_Success ; //Valid offset
  255. jne ValidDriverCallback_Failure ; //Not executable segment
  256. ValidDriverCallback_Failure:
  257. mov eax, 1;
  258. jmp ValidDriverCallback_Return;
  259. ValidDriverCallback_Success:
  260. xor eax, eax;
  261. ValidDriverCallback_Return:
  262. mov [fRet], eax;
  263. }
  264. return fRet;
  265. }
  266. #endif
  267. /* RouteKeyPresses
  268. *
  269. * Reroutes cursor keys etc to track bar.
  270. */
  271. void RouteKeyPresses(PMSG pMsg)
  272. {
  273. /* Hack for PowerPoint
  274. *
  275. * Mail from PaulWa:
  276. *
  277. * --------
  278. * Here's a problem you might consider fixing.
  279. * Launching Media Player with certain keystrokes
  280. * doesn't work right (e.g. arrow keys, page up/down,
  281. * etc.).
  282. *
  283. * The problem is due to the fact that Media Player
  284. * handles key up events. We use the key down event
  285. * to launch the server in slideshow, but then the key
  286. * up event is passed to the server. It would probably
  287. * be best for Media Player to ignore key up events
  288. * unless it had previously received a key down.
  289. * If this is very difficult to fix in Media Player,
  290. * then we can fix it in PP by launching servers on
  291. * key up rather than key down. However, other container
  292. * apps will see the same problem.
  293. * --------
  294. *
  295. * OK, in the spirit of cooperation, let's hack things
  296. * so our PowerPoint friends can carry on with their
  297. * dubious practices.
  298. */
  299. static WPARAM LastVKeyDown;
  300. /* On key down when we're embedded, remember what is was:
  301. */
  302. if (gfRunWithEmbeddingFlag && (pMsg->message == WM_KEYDOWN))
  303. LastVKeyDown = pMsg->wParam;
  304. /* Don't reroute if it's a key up that doesn't match
  305. * the last key down; this effectively ignores it:
  306. */
  307. if (gfRunWithEmbeddingFlag &&
  308. (pMsg->message == WM_KEYUP) && (pMsg->wParam != LastVKeyDown))
  309. {
  310. DPF0("Ignoring WM_KEYUP, since it doesn't match last WM_KEYDOWN.\n");
  311. }
  312. else
  313. {
  314. switch(pMsg->wParam)
  315. {
  316. case VK_UP:
  317. case VK_LEFT:
  318. case VK_DOWN:
  319. case VK_RIGHT:
  320. case VK_NEXT:
  321. case VK_PRIOR:
  322. case VK_HOME:
  323. case VK_END:
  324. pMsg->hwnd = ghwndTrackbar;
  325. break;
  326. default:
  327. break;
  328. }
  329. }
  330. if (pMsg->message == WM_KEYUP)
  331. LastVKeyDown = 0;
  332. }
  333. /*
  334. * WinMain(hInst, hPrev, szCmdLine, iCmdShow)
  335. *
  336. * This is the main procedure for the application. It performs initialization
  337. * and then enters a message-processing loop, where it remains until it
  338. * receives a WM_QUIT message (meaning the app was closed). This function
  339. * always returns TRUE..
  340. *
  341. */
  342. int WINAPI WinMain( HINSTANCE hInst /* handle to the current instance of the application */
  343. , HINSTANCE hPrev /* handle to the previous instance of the application */
  344. , LPSTR szCmdLine /* null-terminated string holding the command line params */
  345. , int iCmdShow /* how the window should be initially displayed */
  346. )
  347. {
  348. MSG rMsg; /* variable used for holding a message */
  349. HWND hwndFocus;
  350. HWND hwndP;
  351. /* call the Pen Windows extensions to allow them to subclass our
  352. edit controls if they so wish
  353. */
  354. OSVERSIONINFO OSVersionInfo;
  355. #ifdef UNICODE
  356. LPTSTR szUnicodeCmdLine;
  357. szUnicodeCmdLine = AllocateUnicodeString(szCmdLine);
  358. #endif
  359. heventCmdLineScanned = CreateEvent( EVENT_DEFAULT_SECURITY,
  360. EVENT_RESET_MANUAL,
  361. EVENT_INITIAL_STATE_NOT_SIGNALED,
  362. EVENT_NO_NAME );
  363. heventDeviceMenuBuilt = CreateEvent( EVENT_DEFAULT_SECURITY,
  364. EVENT_RESET_MANUAL,
  365. EVENT_INITIAL_STATE_NOT_SIGNALED,
  366. EVENT_NO_NAME );
  367. if (!heventCmdLineScanned || !heventDeviceMenuBuilt)
  368. return FALSE;
  369. OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo;
  370. GetVersionEx(&OSVersionInfo);
  371. gwPlatformId = OSVersionInfo.dwPlatformId;
  372. giCmdShow = iCmdShow;
  373. #ifdef UNICODE
  374. if (!AppInit(hInst,hPrev,szUnicodeCmdLine))
  375. #else
  376. if (!AppInit(hInst,hPrev,szCmdLine))
  377. #endif
  378. return FALSE;
  379. /* Device Menu Initialization:
  380. *
  381. * If the user has requested an Open dialog (by supplying the /open
  382. * flag with no file name), we've already built the Device menu,
  383. * since the list of devices is required up front.
  384. *
  385. * If we're just playing in tiny mode, we don't need the device list.
  386. * It will be built if the user switches to full mode and then accesses
  387. * the Device menu or selects File.Open.
  388. *
  389. * Otherwise go for it. The main window's already up now, so we
  390. * can build the list on a background thread. Don't forget to wait
  391. * for the event to be signaled when the appropriate menu is accessed.
  392. */
  393. if (!gfOpenDialog && !gfPlayOnly)
  394. InitDeviceMenu();
  395. #ifdef UNICODE
  396. // ScanCmdLine mangles it, so forget it
  397. // FreeUnicodeString(szUnicodeCmdLine);
  398. #endif
  399. /* setup the message filter to handle grabbing F1 for this task */
  400. fpfnMsgHook = (HOOKPROC)MakeProcInstance((FARPROC)HelpMsgFilter, ghInst);
  401. fpfnOldMsgFilter = (HHOOK)SetWindowsHook(WH_MSGFILTER, fpfnMsgHook);
  402. #ifdef DEBUG
  403. GdiSetBatchLimit(1);
  404. #endif
  405. for (;;)
  406. {
  407. /* If we're ever still around after being destroyed, DIE! */
  408. if (!IsWindow(ghwndApp))
  409. break;
  410. /* call the server code and let it unblock the server */
  411. #ifdef OLE1_HACK
  412. ServerUnblock();
  413. #endif /* OLE1_HACK */
  414. /* Polling messages from event queue */
  415. if (!GetMessage(&rMsg, NULL, 0, 0))
  416. break;
  417. if (gfPlayingInPlace) {
  418. // If focus ever gets to the client during play in place,
  419. // be really nasty and force focus to us. (Aldus BUG!!!!)
  420. // Aldus Persuasion won't play in place without this.
  421. hwndFocus = GetFocus();
  422. hwndP = GetParent(ghwndApp);
  423. if (!ghwndIPHatch && hwndFocus && hwndP &&
  424. GetWindowTask(hwndP) == GetWindowTask(hwndFocus))
  425. PostCloseMessage();
  426. }
  427. /* Hack: post END_SCROLL messages with lParam == -1 */
  428. if ((rMsg.hwnd==ghwndApp)
  429. || (rMsg.hwnd && GetParent(rMsg.hwnd)==ghwndApp))
  430. {
  431. /* Reroute arrow keys etc to track bar:
  432. */
  433. if (rMsg.message == WM_KEYDOWN || rMsg.message == WM_KEYUP)
  434. RouteKeyPresses(&rMsg);
  435. }
  436. if (IsWindow(ghwndApp)) {
  437. if (gfRunWithEmbeddingFlag
  438. && docMain.lpIpData
  439. && docMain.lpIpData->lpFrame
  440. && !IsAccelerator(hAccel, gcAccelEntries, &rMsg, NULL)
  441. && OleTranslateAccelerator(docMain.lpIpData->lpFrame,
  442. &docMain.lpIpData->frameInfo, &rMsg) == NOERROR) {
  443. continue;
  444. }
  445. if (hAccel && TranslateAccelerator(ghwndApp, hAccel, &rMsg))
  446. continue;
  447. }
  448. if (rMsg.message == WM_TIMER && rMsg.hwnd == NULL) {
  449. #ifdef CHICAGO_PRODUCT
  450. /* The reason for requiring the following test is now lost
  451. * in the mists of time. Now this app is 32-bit, these
  452. * bogus timer callbacks (if they really do still occur)
  453. * could be 16-bit, so we need to add yet more ugliness
  454. * in the form of assembler to an app which is already
  455. * hardly a paragon of pulchritude.
  456. *
  457. * A plea:
  458. *
  459. * If you add some obscure code such as below, to this or
  460. * any other app, even if it has only the teeniest chance
  461. * of being less blindingly obvious to someone else than
  462. * it is to you at the time of writing, please please please
  463. * add a f***ing comment.
  464. *
  465. * Respectfully,
  466. * A Developer
  467. */
  468. if (IsBadSegmentedCodePtr(rMsg.lParam))
  469. #else
  470. if (IsBadCodePtr((FARPROC)rMsg.lParam))
  471. #endif /* ~CHICAGO_PRODUCT */
  472. {
  473. DPF0("Bad function pointer (%08lx) in WM_TIMER message\n", rMsg.lParam);
  474. rMsg.message = WM_NULL;
  475. }
  476. }
  477. if (rMsg.message == WM_SYSCOMMAND
  478. && (((0xFFF0 & rMsg.wParam) == SC_MOVE)|| ((0xFFF0 & rMsg.wParam) == SC_SIZE)) ) {
  479. // If ANY window owned by our thread is going into a modal
  480. // size or move loop then we need to force some repainting to
  481. // take place. The cost of not doing so is that garbage can
  482. // be left lying around on the trackbar, e.g. bits of system
  483. // menu, or partially drawn sliders.
  484. UpdateWindow(ghwndApp);
  485. }
  486. TranslateMessage(&rMsg);
  487. DispatchMessage(&rMsg);
  488. }
  489. ghwndApp = NULL;
  490. /* Delete the track map font that we created earlier. */
  491. if (ghfontMap != NULL) {
  492. DeleteObject(ghfontMap);
  493. ghfontMap = NULL;
  494. }
  495. if (ghbrFillPat)
  496. DeleteObject(ghbrFillPat);
  497. if (ghpalApp)
  498. DeleteObject(ghpalApp);
  499. /* if the message hook was installed, remove it and free */
  500. /* up our proc instance for it. */
  501. if (fpfnOldMsgFilter){
  502. UnhookWindowsHook(WH_MSGFILTER, fpfnMsgHook);
  503. }
  504. ControlCleanup();
  505. // TermServer();
  506. /*********************************************************************
  507. ** OLE2NOTE: the very last thing an app must be do is properly shut
  508. ** down OLE. This call MUST be guarded! it is only allowable to
  509. ** call OleUninitialize if OleInitialize has been called.
  510. *********************************************************************/
  511. // Clean shutdown for OLE
  512. DPFI("*before oleunint");
  513. if (gfOleInitialized) {
  514. if (gpClipboardDataObject)
  515. CleanUpClipboard();
  516. (void)OleUninitialize();
  517. IMalloc_Release(lpMalloc);
  518. lpMalloc = NULL;
  519. gfOleInitialized = FALSE;
  520. }
  521. if (hOLE32)
  522. FreeLibrary(hOLE32);
  523. /* End of program */
  524. return((int)rMsg.wParam);
  525. }
  526. void CleanUpClipboard()
  527. {
  528. /* Check whether the DATAOBJECT we put on the clipboard is still there:
  529. */
  530. if (OleIsCurrentClipboard(gpClipboardDataObject) == S_OK)
  531. {
  532. LPDATAOBJECT pIDataObject;
  533. if (OleGetClipboard(&pIDataObject) == S_OK)
  534. {
  535. OleFlushClipboard();
  536. IDataObject_Release(pIDataObject);
  537. }
  538. else
  539. {
  540. DPF0("OleGetClipboard failed\n");
  541. }
  542. }
  543. else
  544. {
  545. if(ghClipData)
  546. GLOBALFREE(ghClipData);
  547. if(ghClipMetafile)
  548. GLOBALFREE(ghClipMetafile);
  549. if(ghClipDib)
  550. GLOBALFREE(ghClipDib);
  551. }
  552. }
  553. //
  554. // cancel any active menus and close the app.
  555. //
  556. void PostCloseMessage()
  557. {
  558. HWND hwnd;
  559. hwnd = GetWindowMCI();
  560. if (hwnd != NULL)
  561. SendMessage(hwnd, WM_CANCELMODE, 0, 0);
  562. SendMessage(ghwndApp, WM_CANCELMODE, 0, 0);
  563. PostMessage(ghwndApp, WM_CLOSE, 0, 0);
  564. }
  565. //
  566. // If we have a dialog box up (gfErrorBox is set) or we're disabled (we have
  567. // a dialog box up) or the MCI device's default window is disabled (it has a
  568. // dialog box up) then closing us would result in our deaths.
  569. //
  570. BOOL ItsSafeToClose(void)
  571. {
  572. HWND hwnd;
  573. if (gfErrorBox)
  574. return FALSE;
  575. if (!IsWindowEnabled(ghwndApp))
  576. return FALSE;
  577. hwnd = GetWindowMCI();
  578. if (hwnd && !IsWindowEnabled(hwnd))
  579. return FALSE;
  580. return TRUE;
  581. }
  582. /* ResolveLink
  583. *
  584. * This routine is called when the user drags and drops a shortcut
  585. * onto Media Player. If it succeeds, it returns the full path
  586. * of the actual file in szResolved.
  587. */
  588. BOOL ResolveLink(LPTSTR szPath, LPTSTR szResolved, LONG cbSize)
  589. {
  590. IShellLink *psl = NULL;
  591. HRESULT hres;
  592. if (!InitOLE(&gfOleInitialized, &lpMalloc))
  593. {
  594. DPF0("Initialization of OLE FAILED!! Can't resolve link.\n");
  595. return FALSE;
  596. }
  597. hres = (HRESULT)CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC,
  598. &IID_IShellLink, &psl);
  599. if (SUCCEEDED(hres))
  600. {
  601. IPersistFile *ppf;
  602. psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf);
  603. if (ppf)
  604. {
  605. WCHAR wszPath[MAX_PATH];
  606. #ifdef UNICODE
  607. lstrcpy (wszPath, szPath);
  608. #else
  609. AnsiToUnicodeString(szPath, wszPath, UNKNOWN_LENGTH);
  610. #endif
  611. hres = ppf->lpVtbl->Load(ppf, wszPath, 0);
  612. ppf->lpVtbl->Release(ppf);
  613. if (FAILED(hres))
  614. {
  615. psl->lpVtbl->Release(psl);
  616. psl = NULL;
  617. }
  618. }
  619. else
  620. {
  621. psl->lpVtbl->Release(psl);
  622. psl = NULL;
  623. }
  624. }
  625. if (psl)
  626. {
  627. psl->lpVtbl->Resolve(psl, NULL, SLR_NO_UI);
  628. psl->lpVtbl->GetPath(psl, szResolved, cbSize, NULL, 0);
  629. psl->lpVtbl->Release(psl);
  630. }
  631. return SUCCEEDED(hres);
  632. }
  633. /* ResolveIfLink
  634. *
  635. * Called to check whether a given file name is a shortcut
  636. * on Windows 95.
  637. *
  638. * Copies the resolved file name into the buffer provided,
  639. * overwriting the original name.
  640. *
  641. * Returns TRUE if the function succeeded, whether or not the
  642. * file name was changed. FALSE indicates that an error occurred.
  643. *
  644. * Andrew Bell, 16 February 1995
  645. */
  646. BOOL ResolveIfLink(PTCHAR szFileName)
  647. {
  648. SHFILEINFO sfi;
  649. BOOL rc = TRUE;
  650. if ((SHGetFileInfo(szFileName, 0, &sfi, sizeof sfi, SHGFI_ATTRIBUTES) == 1)
  651. && ((sfi.dwAttributes & SFGAO_LINK) == SFGAO_LINK))
  652. {
  653. TCHAR szResolvedLink[MAX_PATH];
  654. if (ResolveLink(szFileName, szResolvedLink, CHAR_COUNT(szResolvedLink)))
  655. lstrcpy(szFileName, szResolvedLink);
  656. else
  657. rc = FALSE;
  658. }
  659. return rc;
  660. }
  661. /* JumpToCDTrack()
  662. *
  663. * Jumps to the appropriate track on the CD and updates the UI accordingly
  664. *
  665. */
  666. void JumpToCDTrack(UINT trackno)
  667. {
  668. //If the track number is invalid just ignore.
  669. //Let the default behaviour take place, There is no need to give a message box
  670. //saying we couldn't jump to track.
  671. if(trackno > gwNumTracks)
  672. return;
  673. /* We MUST use PostMessage because the */
  674. /* SETPOS and ENDTRACK must happen one */
  675. /* immediately after the other */
  676. PostMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, gadwTrackStart[trackno]);
  677. PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_ENDTRACK, (LPARAM)ghwndTrackbar);
  678. }
  679. /*****************************Private*Routine******************************\
  680. * IsTrackFileNameValid
  681. *
  682. * This routine copied from deluxecd and modified
  683. *
  684. * This function returns true if the specified filename is a valid CD track.
  685. * On NT track filenames must be of the form:
  686. * d:\track(n).cda where d: is the CD-Rom device and \track(n).cda
  687. * is the index of the track to be played (starting from 1).
  688. *
  689. * On Chicago the track filename is actually a riff CDDA file which contains
  690. * the track info that we require.
  691. *
  692. * If the filename is valid the function true and sets
  693. * piTrackIndex to the correct value.
  694. *
  695. * History:
  696. * 29-09-94 - StephenE - Created
  697. *
  698. \**************************************************************************/
  699. BOOL
  700. IsTrackFileNameValid(
  701. LPTSTR lpstFileName,
  702. UINT *puiTrackIndex
  703. )
  704. {
  705. #define RIFF_RIFF 0x46464952
  706. #define RIFF_CDDA 0x41444443
  707. RIFFCDA cda;
  708. HANDLE hFile;
  709. int i;
  710. DWORD cbRead;
  711. BOOL fRead;
  712. // Open file and read in CDA info
  713. hFile = CreateFile (lpstFileName, GENERIC_READ,
  714. FILE_SHARE_READ, NULL,
  715. OPEN_EXISTING, 0, NULL);
  716. if (INVALID_HANDLE_VALUE == hFile) {
  717. return FALSE;
  718. }
  719. ZeroMemory (&cda, sizeof (cda));
  720. fRead = ReadFile(hFile, &cda, sizeof(cda), &cbRead, NULL);
  721. CloseHandle (hFile);
  722. if (!fRead)
  723. return FALSE;
  724. //
  725. // Make sure its a RIFF CDDA file
  726. //
  727. if ( (cda.dwRIFF != RIFF_RIFF) || (cda.dwCDDA != RIFF_CDDA) ) {
  728. return FALSE;
  729. }
  730. *puiTrackIndex = cda.wTrack - 1;
  731. return TRUE;
  732. }
  733. /* HandleCDAFile()
  734. *
  735. * Checks to see if the opened file is a CDA file and tries to jump to the appropriate track.
  736. *
  737. */
  738. void HandleCDAFile(TCHAR *szFile)
  739. {
  740. UINT trackno;
  741. if(IsTrackFileNameValid(szFile, &trackno))
  742. {
  743. JumpToCDTrack(trackno);
  744. }
  745. }
  746. /* Process file drop/drag options. */
  747. void PASCAL NEAR doDrop(HWND hwnd, HDROP hDrop)
  748. {
  749. RECT rc;
  750. if(DragQueryFile(hDrop,(UINT)(~0),NULL,0)){/* # of files dropped */
  751. TCHAR szPath[MAX_PATH];
  752. /* If user dragged/dropped a file regardless of keys pressed
  753. * at the time, open the first selected file from file
  754. * manager.
  755. */
  756. DragQueryFile(hDrop,0,szPath,sizeof(szPath)/sizeof(TCHAR));
  757. SetActiveWindow(hwnd);
  758. ResolveIfLink(szPath);
  759. if (OpenMciDevice(szPath, NULL)) {
  760. SubClassMCIWindow();
  761. PostMessage(hwnd, WM_COMMAND, (WPARAM)ID_PLAY, 0);
  762. DirtyObject(FALSE); // we're dirty now!
  763. gfCloseAfterPlaying = FALSE; // stay up from now on
  764. //If the CD Audio device was opened it must have been a *.cda file.
  765. //Try to jump to the track corresponding to the file opened.
  766. if ((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO)
  767. {
  768. HandleCDAFile(szPath);
  769. }
  770. }
  771. else
  772. {
  773. gwCurDevice = 0;// force next file open dialog to say
  774. // "all files" because CloseMCI won't.
  775. gwCurScale = ID_NONE; // uncheck all scale types
  776. Layout(); // Make window snap back to smaller size
  777. }
  778. SetMPlayerIcon();
  779. /* Force WM_GETMINMAXINFO to be called so we'll snap to a */
  780. /* proper size. */
  781. GetWindowRect(ghwndApp, &rc);
  782. MoveWindow(ghwndApp, rc.left, rc.top, rc.right - rc.left,
  783. rc.bottom - rc.top, TRUE);
  784. }
  785. DragFinish(hDrop); /* Delete structure alocated for WM_DROPFILES*/
  786. }
  787. /* Change the number in dwPosition to the proper format. szNum contains the */
  788. /* formatted number only "01 45:10" while szBuf contains units such as */
  789. /* "01 45:10 (min:sec)" */
  790. /* If fRound is set, it will not always display millisecond accuracy, but */
  791. /* choose something useful like second accuracy or hundreth sec accuracy. */
  792. void FAR PASCAL FormatTime(DWORD_PTR dwPosition, LPTSTR szNum, LPTSTR szBuf, BOOL fRound)
  793. {
  794. UINT w;
  795. UINT hrs;
  796. UINT min;
  797. UINT sec;
  798. UINT hsec;
  799. UINT msec;
  800. DWORD dwMaxSize = gdwMediaLength;
  801. static TCHAR framestr[40] = TEXT("");
  802. static TCHAR sec_str[40] = TEXT("");
  803. static TCHAR min_str[40] = TEXT("");
  804. static TCHAR hrs_str[40] = TEXT("");
  805. static TCHAR msec_str[40] = TEXT("");
  806. static SZCODE aszLongDecimal[] = TEXT("%ld");
  807. static SZCODE aszFrameFormat[] = TEXT("%"TS" %ld");
  808. static SZCODE asz02Decimal[] = TEXT("%02d ");
  809. static SZCODE aszTimeFormat1[] = TEXT("%02d%c%02d%c%02d");
  810. static SZCODE aszTimeFormat2[] = TEXT("%02d%c%02d%c%02d%c%03d");
  811. static SZCODE aszTimeFormat3[] = TEXT("%02d%c%02d%c%02d (%"TS"%c%"TS"%c%"TS")");
  812. static SZCODE aszTimeFormat4[] = TEXT("%02d%c%02d%c%02d%c%03d (%"TS"%c%"TS"%c%"TS"%c%"TS")");
  813. static SZCODE aszTimeFormat5[] = TEXT("%02d%c%02d");
  814. static SZCODE aszTimeFormat6[] = TEXT("%02d%c%02d%c%03d");
  815. static SZCODE aszTimeFormat7[] = TEXT("%02d%c%02d (%"TS"%c%"TS")");
  816. static SZCODE aszTimeFormat8[] = TEXT("%02d%c%02d%c%03d (%"TS"%c%"TS"%c%"TS")");
  817. static SZCODE aszTimeFormat9[] = TEXT("%c%02d");
  818. static SZCODE aszTimeFormat10[] = TEXT("%c%03d");
  819. static SZCODE aszTimeFormat11[] = TEXT("%02d%c%03d");
  820. static SZCODE aszTimeFormat12[] = TEXT("%c%02d (%"TS")");
  821. static SZCODE aszTimeFormat13[] = TEXT("%02d%c%02d (%"TS")");
  822. static SZCODE aszTimeFormat14[] = TEXT("%c%03d (%"TS"%c%"TS")");
  823. static SZCODE aszTimeFormat15[] = TEXT("%02d%c%03d (%"TS"%c%"TS")");
  824. //!!! LoadStrings at init time, dont hardcode...
  825. #define ONE_HOUR (60ul*60ul*1000ul)
  826. #define ONE_MINUTE (60ul*1000ul)
  827. #define ONE_SECOND (1000ul)
  828. if (szBuf)
  829. *szBuf = 0;
  830. if (szNum)
  831. *szNum = 0;
  832. if (gwDeviceID == (UINT)0)
  833. return;
  834. if (gwStatus == MCI_MODE_NOT_READY || gwStatus == MCI_MODE_OPEN)
  835. return;
  836. switch (gwCurScale) {
  837. case ID_FRAMES:
  838. if (!STRLEN(framestr))
  839. LOADSTRING(IDS_FRAME,framestr);
  840. if (szNum)
  841. wsprintf(szNum, aszLongDecimal, (long)dwPosition);
  842. if (szBuf)
  843. wsprintf(szBuf, aszFrameFormat, framestr, (long)dwPosition);
  844. gInc = 1; // spin arrow inc/dec by one frame
  845. break;
  846. case ID_TRACKS:
  847. //
  848. // find the track that contains this position
  849. // also, find the longest track so we know if we should display
  850. // hh:mm:ss or mm:ss or ss.sss or whatever.
  851. //
  852. if (gwNumTracks == 0)
  853. return;
  854. dwMaxSize = 0;
  855. for (w=0; w<gwNumTracks-1; w++) {
  856. if (gadwTrackStart[w+1] - gadwTrackStart[w] > dwMaxSize)
  857. dwMaxSize = gadwTrackStart[w+1] - gadwTrackStart[w];
  858. /* When a CD is stopped, it's still spinning, and after we */
  859. /* seek to the beginning of a track, it may return a value */
  860. /* slightly less than the track start everyonce in a while.*/
  861. /* So if we're within 200ms of the track start, let's just */
  862. /* pretend we're exactly on the start of the track. */
  863. if (dwPosition < gadwTrackStart[w+1] &&
  864. gadwTrackStart[w+1] - dwPosition < 200)
  865. dwPosition = gadwTrackStart[w+1];
  866. if (gadwTrackStart[w+1] > dwPosition)
  867. break;
  868. }
  869. if (szNum) {
  870. wsprintf(szNum, asz02Decimal, gwFirstTrack + w);
  871. szNum += 3;
  872. }
  873. if (szBuf) {
  874. wsprintf(szBuf, asz02Decimal, gwFirstTrack + w);
  875. szBuf += 3;
  876. }
  877. dwPosition -= gadwTrackStart[w];
  878. for (; w < gwNumTracks - 1; w++) {
  879. if (gadwTrackStart[w+1] - gadwTrackStart[w] > dwMaxSize)
  880. dwMaxSize = gadwTrackStart[w+1] - gadwTrackStart[w];
  881. }
  882. // fall through
  883. case ID_TIME:
  884. if (!STRLEN(sec_str))
  885. {
  886. LOADSTRING(IDS_SEC,sec_str);
  887. LOADSTRING(IDS_HRS,hrs_str);
  888. LOADSTRING(IDS_MIN,min_str);
  889. LOADSTRING(IDS_MSEC,msec_str);
  890. }
  891. min = (UINT)((dwPosition / ONE_MINUTE) % 60);
  892. sec = (UINT)((dwPosition / ONE_SECOND) % 60);
  893. msec = (UINT)(dwPosition % 1000);
  894. if (dwMaxSize > ONE_HOUR) {
  895. hrs = (UINT)(dwPosition / ONE_HOUR);
  896. if (szNum && fRound) {
  897. wsprintf(szNum, aszTimeFormat1,
  898. hrs, chTime, min, chTime, sec);
  899. } else if (szNum) {
  900. wsprintf(szNum, aszTimeFormat2,
  901. hrs, chTime, min, chTime, sec, chDecimal, msec);
  902. }
  903. if (szBuf && fRound) {
  904. wsprintf(szBuf, aszTimeFormat3,
  905. hrs, chTime, min, chTime, sec, hrs_str,
  906. chTime, min_str, chTime, sec_str);
  907. } else if (szBuf) {
  908. wsprintf(szBuf,
  909. aszTimeFormat4,
  910. hrs, chTime, min, chTime, sec, chDecimal, msec,
  911. hrs_str,chTime, min_str,chTime,
  912. sec_str, chDecimal, msec_str);
  913. }
  914. gInc = 1000; // spin arrow inc/dec by seconds
  915. } else if (dwMaxSize > ONE_MINUTE) {
  916. if (szNum && fRound) {
  917. wsprintf(szNum, aszTimeFormat5, min, chTime, sec);
  918. } else if (szNum) {
  919. wsprintf(szNum, aszTimeFormat6, min, chTime, sec,
  920. chDecimal, msec);
  921. }
  922. if (szBuf && fRound) {
  923. wsprintf(szBuf, aszTimeFormat7, min, chTime, sec,
  924. min_str,chTime,sec_str);
  925. } else if (szBuf) {
  926. wsprintf(szBuf, aszTimeFormat8,
  927. min, chTime, sec, chDecimal, msec,
  928. min_str,chTime,sec_str, chDecimal,
  929. msec_str);
  930. }
  931. gInc = 1000; // spin arrow inc/dec by seconds
  932. } else {
  933. hsec = (UINT)((dwPosition % 1000) / 10);
  934. if (szNum && fRound) {
  935. if (!sec && chLzero == TEXT('0'))
  936. wsprintf(szNum, aszTimeFormat9, chDecimal, hsec);
  937. else
  938. wsprintf(szNum, aszTimeFormat5, sec, chDecimal, hsec);
  939. } else if (szNum) {
  940. if (!sec && chLzero == TEXT('0'))
  941. wsprintf(szNum, aszTimeFormat10, chDecimal, msec);
  942. else
  943. wsprintf(szNum, aszTimeFormat11, sec, chDecimal, msec);
  944. }
  945. if (szBuf && fRound) {
  946. if (!sec && chLzero == TEXT('0'))
  947. wsprintf(szBuf, aszTimeFormat12, chDecimal, hsec, sec_str);
  948. else
  949. wsprintf(szBuf, aszTimeFormat13, sec, chDecimal, hsec, sec_str);
  950. } else if (szBuf) {
  951. if (!sec && chLzero == TEXT('0'))
  952. wsprintf(szBuf, aszTimeFormat14, chDecimal,
  953. msec, sec_str,chDecimal,msec_str);
  954. else
  955. wsprintf(szBuf, aszTimeFormat15, sec, chDecimal,
  956. msec, sec_str,chDecimal,msec_str);
  957. }
  958. gInc = 100; // spin arrow inc/dec by 1/10 second
  959. }
  960. }
  961. }
  962. BOOL IsCdromDataOnly();
  963. BOOL UpdateWindowText(HWND hwnd, LPTSTR Text)
  964. {
  965. TCHAR CurrentText[80];
  966. GetWindowText(hwnd, CurrentText, CHAR_COUNT(CurrentText));
  967. if(lstrcmp(Text, CurrentText))
  968. return SetWindowText(hwnd, Text);
  969. else
  970. return TRUE;
  971. }
  972. /*
  973. * UpdateDisplay()
  974. *
  975. * Update the scrollbar, buttons, etc. If the media information (media
  976. * length, no. tracks, etc.) is not currently valid, then update it first.
  977. *
  978. * The following table shows how the current status (value of <gwStatus>)
  979. * affects which windows are enabled:
  980. *
  981. * Play Pause Stop Eject
  982. * MCI_MODE_STOP ENABLE n/a ENABLE
  983. * MCI_MODE_PAUSE ENABLE n/a ENABLE ENABLE
  984. * MCI_MODE_PLAY n/a ENABLE ENABLE ENABLE
  985. * MCI_MODE_OPEN n/a ENABLE
  986. * MCI_MODE_RECORD ?????? ?????? ?????? ??????
  987. * MCI_MODE_SEEK ENABLE n/a ENABLE ENABLE
  988. *
  989. * MCI_MODE_NOT_READY ALL DISABLED
  990. *
  991. * The eject button is always enabled if the medium can be ejected and
  992. * disabled otherwise.
  993. *
  994. * In open mode, either Play or Eject will cause the media door to close,
  995. * but Play will also begin play. In any mode, Eject always does an
  996. * implicit Stop first.
  997. *
  998. * If <gwDeviceID> is NULL, then there is no current device and all four
  999. * of these buttons are disabled.
  1000. *
  1001. */
  1002. void FAR PASCAL UpdateDisplay(void)
  1003. {
  1004. DWORD_PTR dwPosition; /* the current position within the medium */
  1005. UINT wStatusMCI; /* status of the device according to MCI */
  1006. #if 0
  1007. TOOLBUTTON tb;
  1008. #endif
  1009. static BOOL sfBlock = FALSE; // keep SeekMCI from causing infinite loop
  1010. /* Don't even think about updating the display if the trackbar's scrolling: */
  1011. if (gfScrollTrack)
  1012. return;
  1013. /* We've been re-entered */
  1014. if (sfBlock)
  1015. return;
  1016. /*
  1017. * if for some reason we were closed, close now!
  1018. */
  1019. if (gfErrorDeath) {
  1020. DPF("*** Trying to close window now!\n");
  1021. PostMessage(ghwndApp, gfErrorDeath, 0, 0);
  1022. return;
  1023. }
  1024. /*
  1025. * If the track information is not valid (e.g. a CD was just inserted),
  1026. * then update it.
  1027. *
  1028. */
  1029. if (!gfValidMediaInfo)
  1030. UpdateMCI(); /* update the appropriate global variables*/
  1031. /*
  1032. * Determine the current position and status ( stopped, playing, etc. )
  1033. * as MCI believes them to be.
  1034. *
  1035. */
  1036. wStatusMCI = StatusMCI(&dwPosition);
  1037. /* The deal here is that the user can insert CDs, any of which may not be
  1038. * playable because they contain no audio tracks. So, as soon as we detect
  1039. * that we have a CD we haven't checked, make sure we can play it.
  1040. * If the current device is CD, and the door isn't open, check it.
  1041. *
  1042. */
  1043. if (((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO) &&
  1044. (wStatusMCI != MCI_MODE_OPEN))
  1045. {
  1046. if (!gfCurrentCDChecked)
  1047. {
  1048. if (IsCdromDataOnly())
  1049. {
  1050. gfCurrentCDNotAudio = TRUE;
  1051. gwCurScale = ID_NONE;
  1052. Error(ghwndApp, IDS_INSERTAUDIODISC);
  1053. }
  1054. else
  1055. gfCurrentCDNotAudio = FALSE;
  1056. gfCurrentCDChecked = TRUE;
  1057. }
  1058. }
  1059. else
  1060. {
  1061. gfCurrentCDChecked = FALSE; // Otherwise, make sure it gets cleared.
  1062. gfCurrentCDNotAudio = FALSE;
  1063. }
  1064. /* Here's the problem: If the medium is short, we'll send a Play command */
  1065. /* but it'll stop before we notice it was ever playing. So if we know */
  1066. /* that we just sent a PlayMCI command, but the status isn't PLAY, then */
  1067. /* force the last command to be PLAY. Also, once we notice we are playing*/
  1068. /* we can clear gfJustPlayed. */
  1069. if (wStatusMCI == MCI_MODE_PLAY && gfJustPlayed)
  1070. gfJustPlayed = FALSE;
  1071. if (((wStatusMCI == MCI_MODE_STOP) || (wStatusMCI == MCI_MODE_SEEK)) && gfJustPlayed) {
  1072. gwStatus = MCI_MODE_PLAY;
  1073. gfJustPlayed = FALSE;
  1074. }
  1075. if (wStatusMCI == MCI_MODE_SEEK) {
  1076. // The second major problem is this. During rewind the status
  1077. // is SEEK. If we detect MODE_SEEK we will not restart the play,
  1078. // and it looks like the auto replay simply ended. Seeking back to
  1079. // the beginning can take a significant amount of time. We allow
  1080. // ourselves to wait for up to half a second to give the device,
  1081. // particularly AVI from a CD or over the network, a chance to
  1082. // catch up. Any slower response and the autorepeat will terminate.
  1083. dwPosition = gdwLastSeekToPosition;
  1084. if (!gfUserStopped && (gwOptions&OPT_AUTOREP)) {
  1085. UINT n=15;
  1086. for (; n; --n) {
  1087. Sleep(32);
  1088. // If autorepeating and device is seeking, try the status
  1089. // again in case it has got back to the beginning
  1090. wStatusMCI = StatusMCI(&dwPosition);
  1091. if (wStatusMCI != MCI_MODE_SEEK) {
  1092. wStatusMCI = MCI_MODE_STOP;
  1093. break; // Exit the FOR loop
  1094. } else {
  1095. dwPosition = gdwLastSeekToPosition;
  1096. }
  1097. }
  1098. }
  1099. }
  1100. /*
  1101. * The current device status has
  1102. * changed from the way MPlayer last perceived it, so update the display
  1103. * and make MPlayer agree with MCI again.
  1104. *
  1105. */
  1106. // After we close, our last timer msg must gray stuff and execute this //
  1107. if (!gwDeviceID || wStatusMCI != gwStatus) {
  1108. DWORD dwEndMedia, dwStartSel, dwEndSel, dwEndSelDelta;
  1109. /* Auto-repeat and Rewind happen if you stop at the end of the media */
  1110. /* (rewind to beginning) or if you stop at the end of the selection */
  1111. /* (rewind to beginning of selection). */
  1112. dwEndMedia = MULDIV32(gdwMediaLength + gdwMediaStart, 99, 100L);
  1113. dwStartSel = (DWORD)SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0);
  1114. dwEndSel = (DWORD)SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
  1115. if (dwEndSel != -1) {
  1116. dwEndSelDelta = MULDIV32(dwEndSel, 99, 100L);
  1117. } else {
  1118. dwEndSelDelta = 0; // force (dwPosition >= dwEndSelDelta) to FALSE
  1119. }
  1120. if ((wStatusMCI == MCI_MODE_STOP || wStatusMCI == MCI_MODE_PAUSE)
  1121. && ((dwPosition >= dwEndMedia) || (dwPosition==0) ||
  1122. (dwPosition >= dwEndSelDelta && gfJustPlayedSel))
  1123. && dwPosition >= gdwMediaStart // dwPosition may == the beginning
  1124. && !gfScrollTrack
  1125. && (gwStatus == MCI_MODE_PLAY || gwStatus == MCI_MODE_SEEK)) {
  1126. DPF("End of medium\n");
  1127. /* We're at the end of the entire media or at the end of */
  1128. /* our selection now, and stopped automatically (not */
  1129. /* by the user). We were playing or seeking. So */
  1130. /* we can check the Auto Repeat and Auto Rewind flags. */
  1131. /* CD players seem to return a length that's too big, so */
  1132. /* we check for > 99% done. Use semaphore to keep from */
  1133. /* causing an infinite loop. */
  1134. if (!gfUserStopped && (gwOptions & OPT_AUTOREP)) {
  1135. DPF("Auto-Repeat\n");
  1136. sfBlock = TRUE; // calls UpdateDisplay which will
  1137. // re-enter this code just before mode
  1138. /* Repeat either the selection or whole thing. */
  1139. /* NOTE: Must send message while gwStatus is STOPPED.*/
  1140. gwStatus = wStatusMCI; // old status no longer valid
  1141. if (gfJustPlayedSel && dwPosition >= dwEndSelDelta)
  1142. {
  1143. SeekMCI(dwStartSel); // MCICDA doen't go to start w/out this.
  1144. SendMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAYSEL, 0);
  1145. }
  1146. else
  1147. {
  1148. SeekToStartMCI();
  1149. SendMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAY, 0);
  1150. }
  1151. sfBlock = FALSE; // switches to SEEK.
  1152. gwStatus = (UINT)(-1); // old status no longer valid
  1153. return; // because we are switching modes
  1154. } else if (!gfCloseAfterPlaying && !gfUserStopped &&
  1155. (gwOptions & OPT_AUTORWD)) {
  1156. DPF("Auto-Rewind to media start\n");
  1157. //
  1158. // set gwStatus so SeekMCI will just seek!
  1159. sfBlock = TRUE; // calls UpdateDisplay which will
  1160. // re-enter this code just before mode
  1161. // switches to SEEK.
  1162. /* Rewind either the selection or whole thing. */
  1163. gwStatus = wStatusMCI; // or SeekMCI will play, too.
  1164. if (gfJustPlayedSel && dwPosition >= dwEndSelDelta)
  1165. {
  1166. SeekMCI(dwStartSel);
  1167. }
  1168. else
  1169. {
  1170. SeekToStartMCI();
  1171. }
  1172. sfBlock = FALSE;
  1173. gwStatus = (UINT)(-1); // old status no longer valid
  1174. return; // because we are switching modes
  1175. }
  1176. else if (gfCloseAfterPlaying)
  1177. PostCloseMessage();
  1178. }
  1179. /*
  1180. * Enable or disable the various controls according to the new status,
  1181. * following the rules given in the header to this function.
  1182. *
  1183. */
  1184. EnableWindow(ghwndTrackbar, TRUE); // Good to always have something enabled
  1185. /* Show status bar if full mplayer and if device loaded */
  1186. if (ghwndStatic && !gfPlayOnly)
  1187. {
  1188. if (IsWindowVisible(ghwndStatic) != (gwDeviceID ? TRUE : FALSE))
  1189. {
  1190. ShowWindow(ghwndStatic, gwDeviceID ? SW_SHOW : SW_HIDE);
  1191. InvalidateRect(ghwndApp, NULL, TRUE);
  1192. }
  1193. }
  1194. if (gwDeviceID != (UINT)0 ) {
  1195. switch (wStatusMCI)
  1196. {
  1197. case MCI_MODE_PLAY:
  1198. toolbarSetFocus(ghwndToolbar,BTN_PAUSE);
  1199. break;
  1200. case MCI_MODE_PAUSE:
  1201. case MCI_MODE_STOP:
  1202. toolbarSetFocus(ghwndToolbar,BTN_PLAY);
  1203. break;
  1204. }
  1205. }
  1206. if (wStatusMCI == MCI_MODE_OPEN || wStatusMCI == MCI_MODE_NOT_READY ||
  1207. gwDeviceID == (UINT)0 ||
  1208. ((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO) && gfCurrentCDNotAudio) {
  1209. /* Try to modify both -- one of them should work */
  1210. toolbarModifyState(ghwndToolbar, BTN_PLAY, TBINDEX_MAIN, BTNST_GRAYED);
  1211. toolbarModifyState(ghwndToolbar, BTN_PAUSE, TBINDEX_MAIN, BTNST_GRAYED);
  1212. toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, BTNST_GRAYED);
  1213. toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, BTNST_GRAYED);
  1214. toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, BTNST_GRAYED);
  1215. toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, BTNST_GRAYED);
  1216. SendMessage(ghwndTrackbar, TBM_SETRANGEMIN, (WPARAM)FALSE, 0);
  1217. SendMessage(ghwndTrackbar, TBM_SETRANGEMAX, (WPARAM)FALSE, 0);
  1218. SendMessage(ghwndTrackbar, TBM_CLEARTICS, (WPARAM)FALSE, 0);
  1219. SendMessage(ghwndTrackbar, TBM_CLEARSEL, (WPARAM)TRUE, 0);
  1220. if (ghwndMark) {
  1221. toolbarModifyState(ghwndMark, BTN_MARKIN, TBINDEX_MARK, BTNST_GRAYED);
  1222. toolbarModifyState(ghwndMark, BTN_MARKOUT, TBINDEX_MARK, BTNST_GRAYED);
  1223. }
  1224. if (ghwndFSArrows) {
  1225. toolbarModifyState(ghwndFSArrows, ARROW_NEXT, TBINDEX_ARROWS, BTNST_GRAYED);
  1226. toolbarModifyState(ghwndFSArrows, ARROW_PREV, TBINDEX_ARROWS, BTNST_GRAYED);
  1227. }
  1228. /* Enable transport and Mark buttons if we come from a state where */
  1229. /* they were gray. Layout will then re-gray the ones that */
  1230. /* shouldn't have been enabled because they don't fit. */
  1231. } else if (gwStatus == MCI_MODE_OPEN || gwStatus == MCI_MODE_NOT_READY
  1232. || gwStatus == -1 ) {
  1233. /* Only one of these buttons exists */
  1234. toolbarModifyState(ghwndToolbar, BTN_PLAY, TBINDEX_MAIN, BTNST_UP);
  1235. toolbarModifyState(ghwndToolbar, BTN_PAUSE, TBINDEX_MAIN, BTNST_UP);
  1236. if (!gfPlayOnly || gfOle2IPEditing) {
  1237. toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, BTNST_UP);
  1238. toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, BTNST_UP);
  1239. toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, BTNST_UP);
  1240. toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, BTNST_UP);
  1241. if (ghwndMark) {
  1242. toolbarModifyState(ghwndMark, BTN_MARKIN, TBINDEX_MARK, BTNST_UP);
  1243. toolbarModifyState(ghwndMark, BTN_MARKOUT, TBINDEX_MARK, BTNST_UP);
  1244. }
  1245. if (ghwndFSArrows) {
  1246. toolbarModifyState(ghwndFSArrows, ARROW_PREV, TBINDEX_ARROWS, BTNST_UP);
  1247. toolbarModifyState(ghwndFSArrows, ARROW_NEXT, TBINDEX_ARROWS, BTNST_UP);
  1248. }
  1249. }
  1250. /* AND we need to call layout to gray the buttons that are too
  1251. * short to fit in this window right now.
  1252. */
  1253. Layout();
  1254. }
  1255. //
  1256. // always have the stop button if we are playing in place
  1257. //
  1258. if ((gwDeviceID != (UINT)0) &&
  1259. (wStatusMCI == MCI_MODE_PAUSE ||
  1260. wStatusMCI == MCI_MODE_PLAY ||
  1261. wStatusMCI == MCI_MODE_SEEK || gfPlayingInPlace)) {
  1262. if (toolbarStateFromButton(ghwndToolbar, BTN_STOP, TBINDEX_MAIN) == BTNST_GRAYED)
  1263. toolbarModifyState(ghwndToolbar, BTN_STOP, TBINDEX_MAIN, BTNST_UP);
  1264. } else {
  1265. toolbarModifyState(ghwndToolbar, BTN_STOP, TBINDEX_MAIN, BTNST_GRAYED);
  1266. }
  1267. if (!gfPlayOnly || gfOle2IPEditing) {
  1268. if ((gwDeviceID != (UINT)0) && (gwDeviceType & DTMCI_CANEJECT))
  1269. toolbarModifyState(ghwndToolbar, BTN_EJECT, TBINDEX_MAIN, BTNST_UP);
  1270. else
  1271. toolbarModifyState(ghwndToolbar, BTN_EJECT, TBINDEX_MAIN, BTNST_GRAYED);
  1272. EnableWindow(ghwndMap, (gwDeviceID != (UINT)0));
  1273. }
  1274. // WHO had the idea that setting focus back to play every
  1275. // time the status changes was a good idea ??
  1276. /* Only set focus if we won't take activation by doing so */
  1277. //VIJRif (gfAppActive) {
  1278. if (wStatusMCI == MCI_MODE_NOT_READY) {
  1279. //if (gfAppActive)
  1280. //SetFocus(ghwndToolbar); //Setting focus messes up menu access
  1281. //using the ALT key
  1282. } else if (wStatusMCI != MCI_MODE_SEEK &&
  1283. gwStatus != MCI_MODE_SEEK) {
  1284. if (wStatusMCI == MCI_MODE_PLAY) {
  1285. //VIJR SetFocus(ghwndToolbar); // give focus to PAUSE button
  1286. toolbarSetFocus(ghwndToolbar, BTN_PAUSE);
  1287. } else {
  1288. //VIJR SetFocus(ghwndToolbar); // give focus to PLAY button
  1289. toolbarSetFocus(ghwndToolbar, BTN_PLAY);
  1290. if (wStatusMCI == MCI_MODE_OPEN || wStatusMCI == MCI_MODE_NOT_READY ||
  1291. gwDeviceID == (UINT)0) {
  1292. /* Try to modify both -- one of them should work */
  1293. toolbarModifyState(ghwndToolbar, BTN_PLAY, TBINDEX_MAIN, BTNST_GRAYED);
  1294. }
  1295. }
  1296. }
  1297. //VIJR}
  1298. if (wStatusMCI == MCI_MODE_OPEN || gwStatus == MCI_MODE_OPEN
  1299. || gwStatus == MCI_MODE_NOT_READY
  1300. || wStatusMCI == MCI_MODE_NOT_READY) {
  1301. /* Either the medium was just ejected, or it was just
  1302. * re-inserted -- in either case, the media information (length,
  1303. * # of tracks, etc.) is currently invalid and needs to be updated.
  1304. */
  1305. gfValidMediaInfo = FALSE;
  1306. }
  1307. /*
  1308. * Set <gwStatus> to agree with what MCI tells us, and update the
  1309. * display accordingly.
  1310. *
  1311. */
  1312. gwStatus = wStatusMCI;
  1313. gfValidCaption = FALSE;
  1314. }
  1315. /*
  1316. * The previous code may have invalidated the Media again, so we'll update
  1317. * now instead of waiting for the next UpdateDisplay call.
  1318. *
  1319. */
  1320. if (!gfValidMediaInfo)
  1321. UpdateMCI(); /* update the appropriate global variables*/
  1322. /* If the caption is not valid, then update it */
  1323. if (!gfValidCaption) {
  1324. TCHAR ach[_MAX_PATH * 2 + 60]; // string used for the window caption
  1325. TCHAR achWhatToPrint[_MAX_PATH * 2 + 40]; // room for doc title too
  1326. if (gfPlayOnly) {
  1327. if (gwDeviceID == (UINT)0)
  1328. lstrcpy(ach, gachAppName); /* just use the app name */
  1329. else
  1330. lstrcpy(ach, gachWindowTitle); /* just use device */
  1331. } else {
  1332. /* Latest style guide says title bars should have
  1333. * <object> - <appname>, so do that for anything
  1334. * other than NT:
  1335. */
  1336. if (gwPlatformId == VER_PLATFORM_WIN32_NT)
  1337. wsprintf(achWhatToPrint, aszTitleFormat, gachAppName,
  1338. gachWindowTitle);
  1339. else
  1340. wsprintf(achWhatToPrint, aszTitleFormat, gachWindowTitle,
  1341. gachAppName);
  1342. if (gwDeviceID == (UINT)0) {
  1343. lstrcpy(ach, gachAppName); /* just display the app name */
  1344. } else if (gwStatus == MCI_MODE_NOT_READY) {
  1345. wsprintf(ach, aszNotReadyFormat,
  1346. achWhatToPrint); /* the current file / device */
  1347. } else {
  1348. wsprintf(ach, aszReadyFormat,
  1349. achWhatToPrint, /* the current file / device */
  1350. MapModeToStatusString((WORD)wStatusMCI));
  1351. }
  1352. }
  1353. if (gfEmbeddedObject) {
  1354. if (!SetTitle((LPDOC)&docMain, szClientDoc))
  1355. UpdateWindowText(ghwndApp, ach);
  1356. SetMPlayerIcon();
  1357. } else {
  1358. UpdateWindowText(ghwndApp, ach);
  1359. }
  1360. gfValidCaption = TRUE;
  1361. }
  1362. /* Update the scrollbar thumb position unless the user is dragging it */
  1363. /* or the media is current seeking to a previously requested position. */
  1364. if (!gfScrollTrack && gfValidMediaInfo && wStatusMCI != MCI_MODE_SEEK) {
  1365. TCHAR ach[40];
  1366. if (ghwndStatic) {
  1367. FormatTime(dwPosition, NULL, ach, TRUE);
  1368. WriteStatusMessage(ghwndStatic, ach);
  1369. }
  1370. SendMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, dwPosition);
  1371. }
  1372. /* Finish any required window painting immediately */
  1373. if (gfOle2IPEditing && wStatusMCI == MCI_MODE_STOP &&
  1374. ((gwDeviceType & DTMCI_DEVICE) == DTMCI_AVIVIDEO))
  1375. {
  1376. RedrawWindow(ghwndTrackbar, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  1377. }
  1378. UpdateWindow(ghwndApp);
  1379. }
  1380. /*
  1381. * EnableTimer(fEnable)
  1382. *
  1383. * Enable the display-update timer if <fEnable> is TRUE.
  1384. * Disable the timer if <fEnable> is FALSE.
  1385. *
  1386. */
  1387. void FAR PASCAL EnableTimer(BOOL fEnable)
  1388. {
  1389. DPF("EnableTimer(%d) %dms\n", fEnable, gfAppActive ? UPDATE_MSEC : UPDATE_INACTIVE_MSEC);
  1390. if (fEnable)
  1391. SetTimer(ghwndApp, UPDATE_TIMER,
  1392. gfAppActive ? UPDATE_MSEC : UPDATE_INACTIVE_MSEC, NULL);
  1393. else
  1394. KillTimer(ghwndApp, UPDATE_TIMER);
  1395. }
  1396. void FAR PASCAL Layout(void)
  1397. {
  1398. RECT rcClient, rc;
  1399. int iYOffset;
  1400. UINT wWidth;
  1401. UINT wFSArrowsWidth = 2 * FSARROW_WIDTH - 1; // 2 arrow buttons wide
  1402. UINT wFSArrowsHeight = FSARROW_HEIGHT;
  1403. UINT wFSTrackHeight = FSTRACK_HEIGHT;
  1404. UINT wFSTrackWidth;
  1405. UINT wToolbarWidth;
  1406. UINT wMinStatusWidth = 0;
  1407. int iYPosition;
  1408. BOOL fShowMark;
  1409. BOOL fShowTrackbar;
  1410. BOOL fShowStatus;
  1411. HDWP hdwp;
  1412. int nState; // The status of the transport buttons (when visible)
  1413. DWORD_PTR dw; // the current position within the medium
  1414. UINT wStatusMCI; // status of the device according to MCI
  1415. UINT wBaseUnits;
  1416. BOOL fRedrawFrame;
  1417. SIZE StatusTextExtent;
  1418. BOOL fRepaintToolbar; // TRUE if we remove or add something to toolbar area
  1419. /* OK to execute if we're hidden to set ourselves up for being shown */
  1420. if (sfInLayout || IsIconic(ghwndApp))
  1421. return;
  1422. if (gfInPlayMCI) {
  1423. DPF("Layout() called when in PlayMCI(). Posting message to Layout() later.\n");
  1424. /* Don't allow this to happen, because Layout() may cause a call to
  1425. * MCI_PUT (via SetWindowPos(ghwndMCI)), which will result in a
  1426. * device-not-ready error, as the MCI_PLAY hasn't completed.
  1427. */
  1428. PostMessage(ghwndApp, WM_DOLAYOUT, 0, 0);
  1429. return;
  1430. }
  1431. sfInLayout = TRUE;
  1432. #ifdef DEBUG
  1433. GetWindowRect(ghwndApp, &rc);
  1434. DPF("***** Layout Window Rect ***** %d %d\n", rc.right - rc.left, rc.bottom - rc.top);
  1435. #endif
  1436. if (gfPlayOnly) {
  1437. extern UINT gwPlaybarHeight; // in server.c
  1438. #define XSLOP 0
  1439. #define XOFF 2
  1440. if (gfOle2IPEditing || gfOle2IPPlaying)
  1441. {
  1442. /* Don't call GetClientrect, because the window may have a border,
  1443. * and this will cause us to shrink the window.
  1444. * Note this is a hack to get around the problem of the window
  1445. * changing size when it is in place, making some displays dither
  1446. * the video in a disgusting manner.
  1447. */
  1448. GetWindowRect(ghwndApp, &rc);
  1449. rc.right -= rc.left;
  1450. rc.bottom -= rc.top;
  1451. rc.left = rc.top = 0;
  1452. }
  1453. else
  1454. GetClientRect(ghwndApp, &rc);
  1455. rc.bottom -= gwPlaybarHeight;
  1456. #if 0
  1457. /* If we set WS_MAXIMIZE, user doesn't allow the window to be
  1458. * sized on NT. What's the idea behind this code anyway?
  1459. */
  1460. if (ghwndMCI && !EqualRect(&rc, &grcSize))
  1461. fRedrawFrame = SetWS(ghwndApp, WS_MAXIMIZE /* |WS_MAXIMIZEBOX */);
  1462. else if (ghwndMCI)
  1463. fRedrawFrame = //SetWS(ghwndApp, WS_MAXIMIZEBOX) ||
  1464. ClrWS(ghwndApp, WS_MAXIMIZE);
  1465. else
  1466. fRedrawFrame = ClrWS(ghwndApp, WS_MAXIMIZEBOX);
  1467. #endif
  1468. fRedrawFrame = FALSE;
  1469. /* Here's another horrible hack.
  1470. * When you try to Play an in-place video after an Open (OLE),
  1471. * the toolbar and trackbar don't get drawn correctly.
  1472. * I haven't figured out why this is, but forcing a redraw
  1473. * seems to fix it. This code gets executed only when the window
  1474. * position changes, so it isn't too much of a hit.
  1475. */
  1476. if (gfOle2IPEditing || gfOle2IPPlaying)
  1477. fRedrawFrame = TRUE;
  1478. if (fRedrawFrame)
  1479. SetWindowPos(ghwndApp,
  1480. NULL,
  1481. 0,
  1482. 0,
  1483. 0,
  1484. 0,
  1485. SWP_DRAWFRAME|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  1486. if (ghwndMCI)
  1487. SetWindowPos(ghwndMCI,
  1488. NULL,
  1489. 0,
  1490. 0,
  1491. rc.right,
  1492. rc.bottom,
  1493. SWP_NOZORDER|SWP_NOACTIVATE);
  1494. // If we are inplace editing place controls on the ghwndIPToolWindow
  1495. // and the static window at the bottom of ghwndApp.
  1496. if(gfOle2IPEditing) {
  1497. SendMessage(ghwndTrackbar, TBM_SHOWTICS, TRUE, FALSE);
  1498. SetWindowPos(ghwndStatic,
  1499. NULL,
  1500. 3,
  1501. rc.bottom + 2 + (gwPlaybarHeight - TOOLBAR_HEIGHT)/2,
  1502. rc.right - rc.left - 8,
  1503. TOOLBAR_HEIGHT-7,
  1504. SWP_NOZORDER|SWP_NOACTIVATE);
  1505. // Why are we getting the Status here when we have a global that
  1506. // contains it? Because gwStatus is set in UpdateDisplay, but
  1507. // Layout() is called by UpdateDisplay, so the global is not always
  1508. // set properly when this code runs. BUT! We must NOT pass a string
  1509. // to StatusMCI() or it will think UpdateDisplay() called it, and
  1510. // not tell UpdateDisplay() the proper mode next time it asks for it,
  1511. // because it will think that it already knows it.
  1512. wStatusMCI = StatusMCI(NULL);
  1513. nState = (wStatusMCI == MCI_MODE_OPEN
  1514. || wStatusMCI == MCI_MODE_NOT_READY
  1515. || gwDeviceID == (UINT) 0)
  1516. ? BTNST_GRAYED
  1517. : BTNST_UP;
  1518. toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, nState);
  1519. toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, nState);
  1520. toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, nState);
  1521. toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, nState);
  1522. ShowWindow(ghwndTrackbar, SW_SHOW);
  1523. ShowWindow(ghwndToolbar, SW_SHOW);
  1524. ShowWindow(ghwndStatic, SW_SHOW);
  1525. ShowWindow(ghwndFSArrows, SW_SHOW);
  1526. ShowWindow(ghwndMark, SW_SHOW);
  1527. ShowWindow(ghwndMap, SW_SHOW);
  1528. if (ghwndIPToolWindow && (ghwndIPToolWindow != GetParent(ghwndTrackbar))
  1529. && (ghwndIPScrollWindow != GetParent(ghwndTrackbar)))
  1530. {
  1531. SetParent(ghwndTrackbar,ghwndIPToolWindow);
  1532. SetWindowPos(ghwndTrackbar, NULL,4,TOOL_WIDTH+2,
  1533. 11*BUTTONWIDTH+3,FSTRACK_HEIGHT,SWP_NOZORDER | SWP_NOACTIVATE);
  1534. SetParent(ghwndMap,ghwndIPToolWindow);
  1535. SetWindowPos(ghwndMap, NULL,4,TOOL_WIDTH+FSTRACK_HEIGHT+2+2,
  1536. 11*BUTTONWIDTH+50,MAP_HEIGHT,SWP_NOZORDER | SWP_NOACTIVATE);
  1537. }
  1538. CalcTicsOfDoom();
  1539. } else {
  1540. #define LEFT_MARGIN 1
  1541. SendMessage(ghwndTrackbar, TBM_SHOWTICS, FALSE, FALSE);
  1542. SetWindowPos(ghwndToolbar,
  1543. NULL,
  1544. LEFT_MARGIN,
  1545. rc.bottom + 2 + (gwPlaybarHeight - TOOLBAR_HEIGHT)/2,
  1546. XSLOP + 2 * (BUTTONWIDTH - XOFF),
  1547. TOOLBAR_HEIGHT,
  1548. SWP_NOZORDER|SWP_NOACTIVATE);
  1549. SetWindowPos(ghwndTrackbar,
  1550. NULL,
  1551. XSLOP + 2 * (BUTTONWIDTH - XOFF) + LEFT_MARGIN,
  1552. rc.bottom + (gwPlaybarHeight - TOOLBAR_HEIGHT)/2 + 1,
  1553. rc.right-rc.left-(2 * XSLOP + 2 *(BUTTONWIDTH - XOFF) - LEFT_MARGIN),
  1554. TOOLBAR_HEIGHT - 1,
  1555. SWP_NOZORDER | SWP_NOACTIVATE);
  1556. // HACK!!!
  1557. // If we aren't visible, officially disable ourselves so that the
  1558. // trackbar shift code won't try and set selection
  1559. ShowWindow(ghwndTrackbar, gwPlaybarHeight > 0 ? SW_SHOW : SW_HIDE);
  1560. ShowWindow(ghwndToolbar, gwPlaybarHeight > 0 ? SW_SHOW : SW_HIDE);
  1561. ShowWindow(ghwndStatic, SW_HIDE);
  1562. ShowWindow(ghwndFSArrows, SW_HIDE);
  1563. ShowWindow(ghwndMark, SW_HIDE);
  1564. ShowWindow(ghwndMap, SW_HIDE);
  1565. }
  1566. goto Exit_Layout;
  1567. }
  1568. fRedrawFrame = ClrWS(ghwndApp, WS_MAXIMIZEBOX);
  1569. if (fRedrawFrame)
  1570. SetWindowPos(ghwndApp, NULL, 0, 0, 0, 0, SWP_DRAWFRAME|
  1571. SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  1572. if (GetMenu(ghwndApp) != ghMenu)
  1573. SetMenu(ghwndApp, ghMenu);
  1574. wBaseUnits = LOWORD(GetDialogBaseUnits()); // prop. to size of system font
  1575. /* If we're bigger than we're allowed to be then shrink us right now */
  1576. GetWindowRect(ghwndApp, &rc);
  1577. gwHeightAdjust = GetHeightAdjust(ghwndApp);
  1578. DPF1("Layout: WindowRect = %x, %x, %x, %x\n", rc);
  1579. if (rc.bottom - rc.top != (int)(MAX_NORMAL_HEIGHT + gwHeightAdjust)) {
  1580. MoveWindow(ghwndApp,
  1581. rc.left,
  1582. rc.top,
  1583. rc.right - rc.left,
  1584. (int)(MAX_NORMAL_HEIGHT + gwHeightAdjust),
  1585. TRUE);
  1586. }
  1587. hdwp = BeginDeferWindowPos(6);
  1588. if (!hdwp)
  1589. goto Exit_Layout;
  1590. GetClientRect(ghwndApp, &rcClient); // get new size
  1591. wWidth = rcClient.right;
  1592. iYOffset = rcClient.bottom - MAX_NORMAL_HEIGHT + 2; // start here
  1593. /* ??? Hide the trackbar if it can't fit on completely ??? */
  1594. iYPosition = iYOffset >= 0 ? iYOffset :
  1595. ((iYOffset >= - 9) ? iYOffset + 9 : 1000);
  1596. fShowTrackbar = (iYOffset >= - 9);
  1597. /* Focus in on trackbar which is about to go away */
  1598. if (!fShowTrackbar && GetFocus() == ghwndTrackbar)
  1599. SetFocus(ghwndToolbar);
  1600. ShowWindow(ghwndToolbar, SW_SHOW);
  1601. /* The space that COMMCTRL puts to the left of the first toolbar button:
  1602. */
  1603. #define SLOPLFT 0
  1604. #define XOFF1 8
  1605. // how long did it end up being?
  1606. wFSTrackWidth = wWidth - SB_XPOS - 1 - wFSArrowsWidth - SLOPLFT;
  1607. DeferWindowPos(hdwp,
  1608. ghwndTrackbar,
  1609. HWND_TOP,
  1610. SB_XPOS,
  1611. iYPosition,
  1612. wFSTrackWidth,
  1613. wFSTrackHeight,
  1614. SWP_NOZORDER | SWP_NOREDRAW |
  1615. (fShowTrackbar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
  1616. /* Toolbar positioning:
  1617. *
  1618. * If the window is not wide enough to accommodate all the buttons
  1619. * and status bar, here's what we do:
  1620. *
  1621. * If the status bar is invisible, first remove the mark buttons,
  1622. * then use the small control width (with only three buttons).
  1623. *
  1624. * If the status bar is visible, give it priority over the mark
  1625. * buttons and the extra controls, but remove it if there isn't
  1626. * room for it and the small control width.
  1627. */
  1628. if (gwDeviceID)
  1629. {
  1630. fShowStatus = TRUE;
  1631. if (GetStatusTextExtent(ghwndStatic, &StatusTextExtent))
  1632. {
  1633. RECT rc;
  1634. LONG StatusWidth; /* Total width of status window */
  1635. LONG TextAreaWidth; /* Width minus border and size grip */
  1636. /* Allow for the border around the status window:
  1637. */
  1638. GetWindowRect(ghwndStatic, &rc);
  1639. StatusWidth = rc.right - rc.left;
  1640. SendMessage(ghwndStatic, SB_GETRECT, 0, (LPARAM)&rc);
  1641. TextAreaWidth = rc.right - rc.left;
  1642. wMinStatusWidth = StatusTextExtent.cx + (StatusWidth - TextAreaWidth) + 16;
  1643. }
  1644. }
  1645. else
  1646. {
  1647. fShowStatus = FALSE;
  1648. }
  1649. wToolbarWidth = LARGE_CONTROL_WIDTH + SLOPLFT;
  1650. fShowMark = TRUE;
  1651. if (wWidth < LARGE_CONTROL_WIDTH + SLOPLFT + MARK_WIDTH + XOFF1 + wMinStatusWidth)
  1652. {
  1653. fShowMark = FALSE;
  1654. if (wWidth < LARGE_CONTROL_WIDTH + SLOPLFT + wMinStatusWidth)
  1655. wToolbarWidth = SMALL_CONTROL_WIDTH + SLOPLFT;
  1656. if (wWidth < SMALL_CONTROL_WIDTH + SLOPLFT + wMinStatusWidth)
  1657. fShowStatus = FALSE;
  1658. }
  1659. fRepaintToolbar = FALSE;
  1660. /* If we're adding or removing the mark buttons or the status window,
  1661. * make sure we repaint things so that the separator bar corresponds.
  1662. * (It should separate the status window from the buttons, but should
  1663. * go away when the status window does.)
  1664. */
  1665. if (IsWindowVisible(ghwndStatic) != fShowStatus)
  1666. fRepaintToolbar = TRUE;
  1667. else if (IsWindowVisible(ghwndMark) != fShowMark)
  1668. fRepaintToolbar = TRUE;
  1669. ShowWindow(ghwndStatic, fShowStatus);
  1670. /* Turn off the toolbar (for tabbing) if it's not going to be there */
  1671. /* and if we're disabled, we better not keep the focus. */
  1672. if (!fShowMark) {
  1673. if (GetFocus() == ghwndMark)
  1674. SetFocus(ghwndToolbar); // can't give it to SB, might be gone too
  1675. EnableWindow(ghwndMark, FALSE);
  1676. } else
  1677. EnableWindow(ghwndMark, TRUE);
  1678. DeferWindowPos(hdwp,
  1679. ghwndFSArrows,
  1680. HWND_TOP,
  1681. SB_XPOS + wFSTrackWidth,
  1682. // wWidth - 1 - wFSArrowsWidth,
  1683. iYPosition + 2,
  1684. wFSArrowsWidth + SLOPLFT,
  1685. wFSArrowsHeight + 4, /* Er, 4 because it works */
  1686. SWP_NOZORDER);
  1687. iYOffset += wFSTrackHeight;
  1688. DeferWindowPos(hdwp,
  1689. ghwndMap,
  1690. HWND_TOP,
  1691. SB_XPOS,
  1692. iYOffset,
  1693. wWidth - SB_XPOS,
  1694. MAP_HEIGHT,
  1695. SWP_NOZORDER | SWP_NOREDRAW |
  1696. (fShowTrackbar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
  1697. iYOffset += MAP_HEIGHT;
  1698. /* Do we show the last four buttons on the main toolbar? */
  1699. /* If not, then disable them for tabs and such. */
  1700. if (wToolbarWidth == LARGE_CONTROL_WIDTH + SLOPLFT)
  1701. {
  1702. // Why are we getting the Status here when we have a global that
  1703. // contains it? Because gwStatus is set in UpdateDisplay, but
  1704. // Layout() is called by UpdateDisplay, so the global is not always
  1705. // set properly when this code runs. BUT! We must NOT pass a string
  1706. // to StatusMCI() or it will think UpdateDisplay() called it, and
  1707. // not tell UpdateDisplay() the proper mode next time it asks for it,
  1708. // because it will think that it already knows it.
  1709. wStatusMCI = StatusMCI(&dw);
  1710. nState = (wStatusMCI == MCI_MODE_OPEN
  1711. || wStatusMCI == MCI_MODE_NOT_READY
  1712. || gwDeviceID == (UINT)0) ? BTNST_GRAYED : BTNST_UP;
  1713. toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, nState);
  1714. toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, nState);
  1715. toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, nState);
  1716. toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, nState);
  1717. toolbarModifyState(ghwndToolbar, BTN_PLAY, TBINDEX_MAIN, nState);
  1718. }
  1719. else
  1720. {
  1721. toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, BTNST_GRAYED);
  1722. toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, BTNST_GRAYED);
  1723. toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, BTNST_GRAYED);
  1724. toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, BTNST_GRAYED);
  1725. }
  1726. DeferWindowPos(hdwp,
  1727. ghwndToolbar,
  1728. HWND_TOP,
  1729. 2,
  1730. iYOffset + 2,
  1731. wToolbarWidth,
  1732. TOOLBAR_HEIGHT,
  1733. SWP_NOZORDER);
  1734. DeferWindowPos(hdwp,
  1735. ghwndMark,
  1736. HWND_TOP,
  1737. wToolbarWidth + XOFF1,
  1738. iYOffset + 2,
  1739. MARK_WIDTH,
  1740. TOOLBAR_HEIGHT,
  1741. SWP_NOZORDER | (fShowMark ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
  1742. #define ARBITRARY_Y_OFFSET 4
  1743. DeferWindowPos(hdwp,
  1744. ghwndStatic,
  1745. HWND_TOP,
  1746. wToolbarWidth + (fShowMark ? MARK_WIDTH + XOFF1 : 0) + XOFF1,
  1747. iYOffset + ARBITRARY_Y_OFFSET,
  1748. wWidth - (wToolbarWidth + 3) -
  1749. (fShowMark ? MARK_WIDTH + XOFF1 : 0) - XOFF1,
  1750. TOOLBAR_HEIGHT - 6,
  1751. SWP_NOZORDER);
  1752. EndDeferWindowPos(hdwp);
  1753. if (fRepaintToolbar)
  1754. {
  1755. InvalidateRect(ghwndApp, NULL, TRUE);
  1756. }
  1757. CalcTicsOfDoom();
  1758. /* These little gems have just cost me about ten hours worth of debugging -
  1759. * note the useful and descriptive comments...
  1760. *
  1761. * The Win32 problem caused by this only arises with CD Audio, when the disk is
  1762. * ejected and then another one is inserted into the drive. At that point
  1763. * the redrawing misses out the Trackmap FSArrows, the borders on the
  1764. * Mark buttons, and various bits of the toolbar.
  1765. *
  1766. * I will leave this here on the assumption that whichever bout
  1767. * on Win16 they are intended to fix still exists - it certainly doesn't on
  1768. * Win32.
  1769. */
  1770. Exit_Layout:
  1771. sfInLayout = FALSE;
  1772. return;
  1773. }
  1774. /* What is the previous mark from our current spot? */
  1775. LONG_PTR CalcPrevMark(void)
  1776. {
  1777. LONG_PTR lStart, lEnd, lPos, lTol, lTrack = -1, lTarget;
  1778. LONG_PTR l;
  1779. lStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0);
  1780. lEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
  1781. lPos = SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0);
  1782. /* Find the next track we should go to (ignore selection markers) */
  1783. if (gwCurScale == ID_TRACKS) {
  1784. lTol = (LONG)gdwMediaLength / 2000;
  1785. for (l = (LONG)gwNumTracks - 1; l >= 0; l--) {
  1786. if (gadwTrackStart[l] < (DWORD)lPos - lTol) {
  1787. lTrack = gadwTrackStart[l];
  1788. break;
  1789. }
  1790. }
  1791. }
  1792. /* For msec mode: */
  1793. /* Our current position fluctuates randomly and even if we're dead on */
  1794. /* a selection mark, it might say we're a little before or after it. */
  1795. /* So we'll allow a margin for error so that you don't forever stay */
  1796. /* still while you hit PrevMark because it happens to be saying you're*/
  1797. /* always past the mark you're at. The margin of error will be */
  1798. /* half the width of the thumb. */
  1799. if (gwCurScale == ID_FRAMES)
  1800. lTol = 0L;
  1801. else
  1802. lTol = 0L;//VIJR-TBTrackGetLogThumbWidth(ghwndTrackbar) / 2;
  1803. if (lEnd != -1 && lPos > lEnd + lTol)
  1804. lTarget = lEnd;
  1805. else if (lStart != -1 && lPos > lStart + lTol)
  1806. lTarget = lStart;
  1807. else
  1808. lTarget = 0;
  1809. /* go to the either the selection mark or the next track (the closest) */
  1810. if (lTrack != -1 && lTrack > lTarget)
  1811. lTarget = lTrack;
  1812. return lTarget;
  1813. }
  1814. /* What is the next mark from our current spot? */
  1815. LONG_PTR CalcNextMark(void)
  1816. {
  1817. LONG_PTR lStart, lEnd, lPos, lTol, lTrack = -1, lTarget;
  1818. UINT_PTR w;
  1819. lStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0);
  1820. lEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
  1821. lPos = SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0);
  1822. /* Find the next track we should go to (ignore selection markers) */
  1823. if (gwCurScale == ID_TRACKS) {
  1824. lTol = (LONG)gdwMediaLength / 2000;
  1825. for (w = 0; w < gwNumTracks; w++) {
  1826. if (gadwTrackStart[w] > (DWORD)lPos + lTol) {
  1827. lTrack = gadwTrackStart[w];
  1828. break;
  1829. }
  1830. }
  1831. }
  1832. /* For msec mode: */
  1833. /* Our current position fluctuates randomly and even if we're dead on */
  1834. /* a selection mark, it might say we're a little before or after it. */
  1835. /* So we'll allow a margin for error so that you don't forever stay */
  1836. /* still while you hit NextMark because it happens to be saying you're*/
  1837. /* always before the mark you're at. The margin of error will be */
  1838. /* half the width of the thumb. */
  1839. if (gwCurScale == ID_FRAMES)
  1840. lTol = 0L;
  1841. else
  1842. lTol = 0L;//VIJR-TBTrackGetLogThumbWidth(ghwndTrackbar) / 2;
  1843. /* Find the selection mark we should go to */
  1844. if (lStart != -1 && lPos < lStart - lTol)
  1845. lTarget = lStart;
  1846. else if (lEnd != -1 && lPos < lEnd - lTol)
  1847. lTarget = lEnd;
  1848. else
  1849. lTarget = gdwMediaStart + gdwMediaLength;
  1850. /* go to the either the selection mark or the next track (the closest) */
  1851. if (lTrack != -1 && lTrack < lTarget)
  1852. lTarget = lTrack;
  1853. return lTarget;
  1854. }
  1855. HICON GetIconFromProgID(LPTSTR szProgID)
  1856. {
  1857. DWORD Status;
  1858. HKEY hkeyDefaultIcon;
  1859. BOOL rc = FALSE;
  1860. DWORD Type;
  1861. DWORD Size;
  1862. TCHAR szProgIDDefaultIcon[128];
  1863. TCHAR szDefaultIcon[MAX_PATH+4]; /* <path>,N */
  1864. HICON hicon = NULL;
  1865. LPTSTR pIconIndex;
  1866. UINT IconIndex;
  1867. wsprintf(szProgIDDefaultIcon, TEXT("%s\\DefaultIcon"), szProgID);
  1868. Status = RegOpenKeyEx( HKEY_CLASSES_ROOT, szProgIDDefaultIcon, 0,
  1869. KEY_READ, &hkeyDefaultIcon );
  1870. if (Status == NO_ERROR)
  1871. {
  1872. Size = CHAR_COUNT(szDefaultIcon);
  1873. Status = RegQueryValueEx( hkeyDefaultIcon,
  1874. aszNULL,
  1875. 0,
  1876. &Type,
  1877. (LPBYTE)szDefaultIcon,
  1878. &Size );
  1879. if (Status == NO_ERROR)
  1880. {
  1881. /* Find a comma in the string. After it comes the icon index:
  1882. */
  1883. pIconIndex = STRCHR(szDefaultIcon, TEXT(','));
  1884. if (pIconIndex)
  1885. {
  1886. /* Null terminate the file name:
  1887. */
  1888. *pIconIndex = TEXT('\0');
  1889. /* Get the index that comes after the comma:
  1890. */
  1891. IconIndex = ATOI(pIconIndex+1);
  1892. DPF1("Extracting icon #%d from %"DTS"\n", IconIndex, szDefaultIcon);
  1893. hicon = ExtractIcon(ghInst, szDefaultIcon, IconIndex);
  1894. }
  1895. }
  1896. else
  1897. {
  1898. DPF0("Couldn't find Default Icon for %"DTS"\n", szProgID);
  1899. }
  1900. RegCloseKey(hkeyDefaultIcon);
  1901. }
  1902. return hicon;
  1903. }
  1904. /* GetIconForCurrentDevice
  1905. *
  1906. * Checks what device is currently selected, and returns a handle to the
  1907. * appropriate icon of the specified size. If there is no current device,
  1908. * returns either the application's icon or the default icon for media
  1909. * documents.
  1910. *
  1911. * Parameters:
  1912. *
  1913. * Size - GI_SMALL (for title bar) or GI_LARGE (for in-place icon).
  1914. *
  1915. * DefaultID - Default to use if no current device. APPICON or IDI_DDEFAULT.
  1916. *
  1917. * Return:
  1918. *
  1919. * Icon handle
  1920. *
  1921. *
  1922. * Andrew Bell (andrewbe), 31 March 1995
  1923. */
  1924. HICON GetIconForCurrentDevice(UINT Size, UINT DefaultID)
  1925. {
  1926. TCHAR DeviceName[256];
  1927. DWORD i;
  1928. LPTSTR ImageID = NULL;
  1929. int cx;
  1930. int cy;
  1931. HICON hIcon;
  1932. GetDeviceNameMCI(DeviceName, BYTE_COUNT(DeviceName));
  1933. if (DeviceName[0])
  1934. {
  1935. for (i = 0; i < sizeof DevToIconIDMap / sizeof *DevToIconIDMap; i++)
  1936. {
  1937. if (!lstrcmpi(DeviceName, DevToIconIDMap[i].pString))
  1938. {
  1939. ImageID = MAKEINTRESOURCE(DevToIconIDMap[i].ID);
  1940. break;
  1941. }
  1942. }
  1943. }
  1944. else
  1945. {
  1946. if (Size == GI_LARGE)
  1947. {
  1948. hIcon = GetIconFromProgID(gachProgID);
  1949. if (hIcon)
  1950. {
  1951. return hIcon;
  1952. }
  1953. }
  1954. }
  1955. if (ImageID == NULL)
  1956. ImageID = MAKEINTRESOURCE(DefaultID);
  1957. cx = (Size == GI_SMALL ? GetSystemMetrics(SM_CXSMICON) : 0);
  1958. cy = (Size == GI_SMALL ? GetSystemMetrics(SM_CYSMICON) : 0);
  1959. hIcon = (HICON)LoadImage(ghInst, ImageID, IMAGE_ICON,
  1960. cx, cy, LR_DEFAULTSIZE);
  1961. return hIcon;
  1962. }
  1963. /* SetMPlayerIcon
  1964. *
  1965. * Sets the icon based upon the current device. Uses default document
  1966. * icon if embedded, otherwise the application icon.
  1967. *
  1968. * Andrew Bell (andrewbe), 31 March 1995
  1969. */
  1970. void SetMPlayerIcon()
  1971. {
  1972. UINT DefaultID;
  1973. DefaultID = gfEmbeddedObject ? IDI_DDEFAULT : APPICON;
  1974. SendMessage(ghwndApp, WM_SETICON, FALSE,
  1975. (LPARAM)GetIconForCurrentDevice(GI_SMALL, DefaultID));
  1976. }
  1977. /*--------------------------------------------------------------+
  1978. | AskUpdate - ask the user if they want to update the |
  1979. | object (if we're dirty). |
  1980. | IDYES means yes, go ahead and update please. |
  1981. | IDNO means don't update, but continue. |
  1982. | IDCANCEL means don't update, and cancel what |
  1983. | you were doing. |
  1984. +--------------------------------------------------------------*/
  1985. int NEAR PASCAL AskUpdate(void)
  1986. {
  1987. UINT w;
  1988. /* Don't update object if no device is loaded into mplayer! */
  1989. if (IsObjectDirty() && gfDirty != -1 && gfEmbeddedObject && gwDeviceID) {
  1990. if((glCurrentVerb == OLEIVERB_PRIMARY) && !gfOle2IPEditing)
  1991. return IDNO;
  1992. //
  1993. // if we are a hidden MPlayer (most likely doing a Play verb) then
  1994. // update without asking?
  1995. //
  1996. if (!IsWindowVisible(ghwndApp) || gfOle2IPEditing)
  1997. return IDYES;
  1998. w = ErrorResBox(ghwndApp, ghInst,
  1999. MB_YESNOCANCEL | MB_ICONQUESTION,
  2000. IDS_APPNAME, IDS_UPDATEOBJECT, szClientDoc);
  2001. } else
  2002. w = IDNO;
  2003. return w;
  2004. }
  2005. void SizePlaybackWindow(int dx, int dy)
  2006. {
  2007. RECT rc;
  2008. HWND hwndPlay;
  2009. if (gfPlayOnly) {
  2010. SetRect(&rc, 0, 0, dx, dy);
  2011. SetMPlayerSize(&rc);
  2012. }
  2013. else {
  2014. if (dx == 0 && dy == 0) {
  2015. SetMPlayerSize(NULL); // size MPlayer to default size
  2016. dx = grcSize.right; // then size the playback window too.
  2017. dy = grcSize.bottom;
  2018. }
  2019. hwndPlay = GetWindowMCI();
  2020. if (hwndPlay != NULL) {
  2021. /* make sure that the play window isn't iconized */
  2022. if (IsIconic(hwndPlay))
  2023. return;
  2024. GetClientRect(hwndPlay, &rc);
  2025. ClientToScreen(hwndPlay, (LPPOINT)&rc);
  2026. SetRect(&rc, rc.left, rc.top, rc.left+dx, rc.top+dy);
  2027. PutWindowMCI(&rc);
  2028. SetRect(&rc, 0, 0, dx, dy);
  2029. SetDestRectMCI(&rc);
  2030. }
  2031. }
  2032. }
  2033. /* StartSndVol
  2034. *
  2035. * Kicks off the Sound Volume app asynchronously so we don't hang the UI.
  2036. */
  2037. VOID StartSndVol( )
  2038. {
  2039. STARTUPINFO StartupInfo;
  2040. PROCESS_INFORMATION ProcessInformation;
  2041. memset( &StartupInfo, 0, sizeof StartupInfo );
  2042. StartupInfo.cb = sizeof(StartupInfo);
  2043. StartupInfo.wShowWindow = SW_SHOW;
  2044. CreateProcess( NULL, szSndVol32, NULL, NULL, FALSE, 0,
  2045. NULL, NULL, &StartupInfo, &ProcessInformation );
  2046. ExitThread( 0 );
  2047. }
  2048. /* GetHeightAdjust
  2049. *
  2050. * Finds the real height adjustment needed, by subtracting the client
  2051. * height from the main window height. This allows for menus that
  2052. * have wrapped.
  2053. */
  2054. int GetHeightAdjust(HWND hwnd)
  2055. {
  2056. RECT rcWindow;
  2057. RECT rcClient;
  2058. int WindowHeight;
  2059. int ClientHeight;
  2060. GetWindowRect(hwnd, &rcWindow);
  2061. GetClientRect(hwnd, &rcClient);
  2062. WindowHeight = rcWindow.bottom - rcWindow.top;
  2063. ClientHeight = rcClient.bottom - rcClient.top;
  2064. return WindowHeight - ClientHeight;
  2065. }
  2066. /* Message-cracking routines for MPlayerWndProc:
  2067. */
  2068. BOOL MPlayer_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
  2069. {
  2070. InitMPlayerDialog(hwnd);
  2071. /* set off a thread to check that the OLE registry stuff is not corrupted */
  2072. #ifdef CHICAGO_PRODUCT
  2073. /* If this is the Chicago Media Player, only mess with the registry
  2074. * if we're actually running on that platform.
  2075. * The guy may be running it on NT.
  2076. */
  2077. if (gwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
  2078. return TRUE;
  2079. #endif
  2080. if (!IgnoreRegCheck())
  2081. BackgroundRegCheck(hwnd);
  2082. //Register for WM_DEVICECHANGE notification.
  2083. DeviceChange_Init(hwnd);
  2084. return TRUE;
  2085. }
  2086. void MPlayer_OnShowWindow(HWND hwnd, BOOL fShow, UINT status)
  2087. {
  2088. if (fShow)
  2089. Layout(); // we're about to be shown and want to set
  2090. }
  2091. void MPlayer_OnSize(HWND hwnd, UINT state, int cx, int cy)
  2092. {
  2093. /* Don't waste time Layout()ing if we're not visible */
  2094. if (state != SIZE_RESTORED || IsWindowVisible(hwnd)) {
  2095. Layout();
  2096. // If we are inplace editing, our size change must be informed
  2097. // to the container, unless the size change was a result of a
  2098. // OnPosRectChange sent to us by the container.
  2099. if ((gfOle2IPEditing || gfOle2IPPlaying) && ghwndMCI) {
  2100. RECT rc;
  2101. RECT rcPrev;
  2102. rcPrev = gInPlacePosRect;
  2103. GetWindowRect(ghwndApp, &gInPlacePosRect);
  2104. gfInPlaceResize = TRUE;
  2105. rc = gInPlacePosRect;
  2106. /* Check that the previous rect wasn't empty, otherwise we send
  2107. * a bogus OLE_CHANGED on startup.
  2108. */
  2109. if (!gfPosRectChange /*&& !IsRectEmpty(&rcPrev)*/) {
  2110. MapWindowPoints(NULL,ghwndCntr,(POINT FAR *)&rc,(UINT)2);
  2111. DPF("IOleInPlaceSite::OnPosRectChange %d, %d, %d, %d\n", rc);
  2112. if (!gfInPPViewer)
  2113. IOleInPlaceSite_OnPosRectChange(docMain.lpIpData->lpSite, &rc);
  2114. fDocChanged = TRUE;
  2115. SendDocMsg((LPDOC)&docMain, OLE_CHANGED);
  2116. }
  2117. gfPosRectChange = FALSE;
  2118. }
  2119. }
  2120. }
  2121. BOOL MPlayer_OnWindowPosChanging(HWND hwnd, LPWINDOWPOS lpwpos)
  2122. {
  2123. #define SNAPTOGOODSIZE
  2124. #ifdef SNAPTOGOODSIZE
  2125. BOOL wHeight;
  2126. #endif
  2127. DPF2("ENTER OnWindowPosChanging: lpwpos = %x, %x, %x, %x\n", *((PPOS)&lpwpos->x));
  2128. if (IsIconic(hwnd) || gfPlayOnly)
  2129. return TRUE;
  2130. /* posSizeMove contains the height we want to be when sizing.
  2131. * Don't let the system tell us otherwise.
  2132. */
  2133. if (posSizeMove.cx != 0)
  2134. {
  2135. lpwpos->cy = posSizeMove.cy;
  2136. posSizeMove = *(PPOS)&lpwpos->x;
  2137. }
  2138. else if (!(lpwpos->flags & SWP_NOSIZE)) {
  2139. #ifdef SNAPTOGOODSIZE
  2140. /* We should also do things here to make the window
  2141. ** snap to good sizes */
  2142. wHeight = lpwpos->cy - gwHeightAdjust;
  2143. // if (lpwpos->cy >= (int) gwHeightAdjust + MAX_NORMAL_HEIGHT) {
  2144. // } else if (lpwpos->cy < (int) gwHeightAdjust +
  2145. // ((MIN_NORMAL_HEIGHT + MAX_NORMAL_HEIGHT) / 2)) {
  2146. // lpwpos->cy = (int) gwHeightAdjust + MIN_NORMAL_HEIGHT;
  2147. // } else {
  2148. lpwpos->cy = (int) gwHeightAdjust + MAX_NORMAL_HEIGHT;
  2149. // }
  2150. #endif
  2151. }
  2152. DPF2("EXIT OnWindowPosChanging: lpwpos = %x, %x, %x, %x\n", *((PPOS)&lpwpos->x));
  2153. return FALSE;
  2154. }
  2155. BOOL MPlayer_OnWindowPosChanged(HWND hwnd, LPWINDOWPOS lpwpos)
  2156. {
  2157. if (!IsIconic(hwnd) && !gfPlayOnly && !gfOle2IPEditing && !gfOle2IPPlaying)
  2158. {
  2159. /* The problem here is that we want to modify the height of the
  2160. * window while tracking to take account of the menu height.
  2161. * In its wisdom, the system keeps trying to resize us back to the
  2162. * original height. So, during tracking, we keep hold of the
  2163. * dimensions we want to be and ignore the height that we get
  2164. * passed on WM_WINDOWPOSCHANGING.
  2165. */
  2166. if (posSizeMove.cx != 0)
  2167. {
  2168. int NewHeightAdjust = GetHeightAdjust(hwnd);
  2169. if ((int)gwHeightAdjust != NewHeightAdjust)
  2170. {
  2171. /* The total non-client height has changed, so it must
  2172. * be the menu that's wrapped or unwrapped.
  2173. * Modify our height adjustment accordingly and resize
  2174. * the window.
  2175. */
  2176. DPF("Menu appears to have wrapped. Changing window height.\n");
  2177. posSizeMove.cy += ( NewHeightAdjust - gwHeightAdjust );
  2178. gwHeightAdjust = NewHeightAdjust;
  2179. MoveWindow(ghwndApp,
  2180. posSizeMove.x, posSizeMove.y,
  2181. posSizeMove.cx, posSizeMove.cy, TRUE);
  2182. return FALSE;
  2183. }
  2184. }
  2185. if (ghwndStatic && IsWindowVisible(ghwndStatic))
  2186. {
  2187. InvalidateRect(ghwndStatic, NULL, FALSE);
  2188. }
  2189. }
  2190. FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, DefWindowProc);
  2191. return TRUE;
  2192. }
  2193. void MPlayer_OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange)
  2194. {
  2195. if (ghwndMCI && !IsIconic(hwnd))
  2196. FORWARD_WM_PALETTECHANGED(ghwndMCI, hwndPaletteChange, SendMessage);
  2197. }
  2198. BOOL MPlayer_OnQueryNewPalette(HWND hwnd)
  2199. {
  2200. HWND hwndT;
  2201. HPALETTE hpal, hpalT;
  2202. HDC hdc;
  2203. UINT PaletteEntries;
  2204. if (IsIconic(hwnd))
  2205. return FALSE;
  2206. if (ghwndMCI)
  2207. return FORWARD_WM_QUERYNEWPALETTE(ghwndMCI, SendMessage);
  2208. hwndT = GetWindowMCI();
  2209. hpal = PaletteMCI();
  2210. if ((hwndT != NULL) && (hpal != NULL)) {
  2211. hdc = GetDC(hwnd);
  2212. hpalT = SelectPalette(hdc, hpal, FALSE);
  2213. PaletteEntries = RealizePalette(hdc);
  2214. SelectPalette(hdc, hpalT, FALSE);
  2215. ReleaseDC(hwnd, hdc);
  2216. if (PaletteEntries != GDI_ERROR) {
  2217. InvalidateRect(hwndT, NULL, TRUE);
  2218. return TRUE;
  2219. }
  2220. }
  2221. return FALSE;
  2222. }
  2223. HBRUSH MPlayer_OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild, int type)
  2224. {
  2225. /* Only interested in the CTLCOLOR_STATIC messages.
  2226. * On Win32, type should always equal CTLCOLOR_STATIC:
  2227. */
  2228. switch( type )
  2229. {
  2230. case CTLCOLOR_STATIC:
  2231. SetBkColor(hdc, rgbButtonFace);
  2232. SetTextColor(hdc, rgbButtonText);
  2233. }
  2234. return hbrButtonFace;
  2235. }
  2236. void MPlayer_OnWinIniChange(HWND hwnd, LPCTSTR lpszSectionName)
  2237. {
  2238. if (!lpszSectionName || !lstrcmpi(lpszSectionName, (LPCTSTR)aszIntl))
  2239. if (GetIntlSpecs())
  2240. InvalidateRect(ghwndMap, NULL, TRUE);
  2241. if (!gfPlayOnly) {
  2242. if (gwHeightAdjust != (WORD)(2 * GetSystemMetrics(SM_CYFRAME) +
  2243. GetSystemMetrics(SM_CYCAPTION) +
  2244. GetSystemMetrics(SM_CYBORDER) +
  2245. GetSystemMetrics(SM_CYMENU))) {
  2246. RECT rc;
  2247. gwHeightAdjust = 2 * GetSystemMetrics(SM_CYFRAME) +
  2248. GetSystemMetrics(SM_CYCAPTION) +
  2249. GetSystemMetrics(SM_CYBORDER) +
  2250. GetSystemMetrics(SM_CYMENU);
  2251. GetClientRect(hwnd, &rc);
  2252. gfWinIniChange = TRUE;
  2253. SetMPlayerSize(&rc);
  2254. gfWinIniChange = FALSE;
  2255. }
  2256. }
  2257. }
  2258. void MPlayer_OnMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags)
  2259. {
  2260. // Make sure that the container is still not displaying info. about
  2261. // its own menu.
  2262. if (gfOle2IPEditing && docMain.lpIpData->lpFrame) {
  2263. //Should have some useful text later.
  2264. IOleInPlaceFrame_SetStatusText(docMain.lpIpData->lpFrame, L"");
  2265. }
  2266. else
  2267. {
  2268. //Keep track of which menu bar item is currently popped up.
  2269. //This will be used for displaying the appropriate help from the mplayer.hlp file
  2270. //when the user presses the F1 key.
  2271. currMenuItem = item;
  2272. }
  2273. }
  2274. #define MVSIZEFIRST 1
  2275. #define MVMOVE 9
  2276. void MPlayer_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest)
  2277. {
  2278. RECT rc;
  2279. if (gfPlayOnly && !IsIconic(hwnd) && IsZoomed(hwnd)) {
  2280. if (codeHitTest >= HTSIZEFIRST && codeHitTest <= HTSIZELAST) {
  2281. SendMessage(hwnd, WM_SYSCOMMAND,
  2282. // (WPARAM)(SC_SIZE + (codeHitTest - HTSIZEFIRST + MVSIZEFIRST) ),
  2283. (WPARAM)SC_SIZE,
  2284. MAKELPARAM(x, y));
  2285. return;
  2286. }
  2287. GetWindowRect(hwnd, &rc);
  2288. if (codeHitTest == HTCAPTION && (rc.left > 0 || rc.top > 0 ||
  2289. rc.right < GetSystemMetrics(SM_CXSCREEN) ||
  2290. rc.bottom < GetSystemMetrics(SM_CYSCREEN))) {
  2291. SendMessage(hwnd, WM_SYSCOMMAND,
  2292. // (WPARAM)(SC_MOVE | MVMOVE),
  2293. (WPARAM)SC_MOVE,
  2294. MAKELPARAM(x, y));
  2295. return;
  2296. }
  2297. }
  2298. FORWARD_WM_NCLBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, DefWindowProc);
  2299. }
  2300. void MPlayer_OnNCLButtonDblClk(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest)
  2301. {
  2302. //
  2303. // when the user dbl-clicks on the caption, toggle the play mode.
  2304. //
  2305. if (codeHitTest == HTCAPTION && !IsIconic(hwnd))
  2306. SendMessage(hwnd, WM_COMMAND, (WPARAM)IDM_WINDOW, 0);
  2307. }
  2308. void MPlayer_OnInitMenu(HWND hwnd, HMENU hMenu)
  2309. {
  2310. EnableMenuItem(hMenu, IDM_CLOSE, gwDeviceID ? MF_ENABLED : MF_GRAYED);
  2311. // EnableMenuItem(hMenu, IDM_UPDATE, gwDeviceID && gfEmbeddedObject ? MF_ENABLED : MF_GRAYED);
  2312. EnableMenuItem(hMenu, IDM_COPY_OBJECT, (gwDeviceID && (gwStatus != MCI_MODE_OPEN) && (gwStatus != MCI_MODE_NOT_READY)) ? MF_ENABLED : MF_GRAYED);
  2313. EnableMenuItem(hMenu, IDM_CONFIG, gwDeviceID && (gwDeviceType & DTMCI_CANCONFIG) ? MF_ENABLED : MF_GRAYED);
  2314. CheckMenuItem(hMenu, IDM_SCALE + ID_TIME, gwCurScale == ID_TIME ? MF_CHECKED : MF_UNCHECKED);
  2315. CheckMenuItem(hMenu, IDM_SCALE + ID_TRACKS, gwCurScale == ID_TRACKS ? MF_CHECKED : MF_UNCHECKED);
  2316. CheckMenuItem(hMenu, IDM_SCALE + ID_FRAMES, gwCurScale == ID_FRAMES ? MF_CHECKED : MF_UNCHECKED);
  2317. EnableMenuItem(hMenu, IDM_SCALE + ID_TIME, gwDeviceID && !gfCurrentCDNotAudio && (gwDeviceType & DTMCI_TIMEMS) ? MF_ENABLED : MF_GRAYED);
  2318. EnableMenuItem(hMenu, IDM_SCALE + ID_FRAMES, gwDeviceID && !gfCurrentCDNotAudio && (gwDeviceType & DTMCI_TIMEFRAMES) ? MF_ENABLED : MF_GRAYED);
  2319. EnableMenuItem(hMenu, IDM_SCALE + ID_TRACKS, gwDeviceID && !gfCurrentCDNotAudio && (gwNumTracks > 1) ? MF_ENABLED : MF_GRAYED);
  2320. EnableMenuItem(hMenu, IDM_OPTIONS, gwDeviceID ? MF_ENABLED : MF_GRAYED);
  2321. EnableMenuItem(hMenu, IDM_SELECTION, gwDeviceID && gdwMediaLength ? MF_ENABLED : MF_GRAYED);
  2322. #ifdef DEBUG
  2323. EnableMenuItem(hMenu, IDM_MCISTRING, gwDeviceID ? MF_ENABLED : MF_GRAYED);
  2324. #endif
  2325. /*
  2326. EnableMenuItem(hMenu, IDM_PASTE_PICTURE , gwDeviceID &&
  2327. (IsClipboardFormatAvailable(CF_METAFILEPICT) ||
  2328. IsClipboardFormatAvailable(CF_BITMAP) ||
  2329. IsClipboardFormatAvailable(CF_DIB))
  2330. ? MF_ENABLED : MF_GRAYED);
  2331. //
  2332. // what is paste frame!
  2333. //
  2334. EnableMenuItem(hMenu, IDM_PASTE_FRAME, gwDeviceID &&
  2335. (gwDeviceType & DTMCI_CANCONFIG) ? MF_ENABLED : MF_GRAYED);
  2336. */
  2337. }
  2338. void MPlayer_OnInitMenuPopup(HWND hwnd, HMENU hMenu, UINT item, BOOL fSystemMenu)
  2339. {
  2340. static BOOL VolumeControlChecked = FALSE;
  2341. /* Here we look to see whether the menu selected is the Device popup,
  2342. * and, if it is the first time, search for the Sound Volume applet.
  2343. * If we can't find it, grey out the menu item.
  2344. */
  2345. /* Caution: When we're in place, there seems to be a discrepancy
  2346. * in the value of parameter UINT item depending on which app is our
  2347. * container. If you use Spy to look at the parameters sent on
  2348. * WM_INITMENUPOPUP, some apps seem to have zero-based menus (e.g.
  2349. * ProgMan, PowerPoint, FileMan), which is what I would expect,
  2350. * but others seem to have one-based menus (e.g. Word, Excel).
  2351. * Why is this? I don't know. But it means that, when the
  2352. * Insert Clip menu item is selected, the item parameter may be
  2353. * either 2 or 3. That's why I'm calling GetSubMenu, since hMenu
  2354. * is always what I would expect.
  2355. *
  2356. * I sent some mail to the User and OLE guys to point this out,
  2357. * but haven't heard anything yet.
  2358. *
  2359. * andrewbe, 28 February 1995
  2360. */
  2361. if (hMenu == GetSubMenu(ghMenu, menuposDevice))
  2362. {
  2363. HCURSOR hcurPrev;
  2364. if(!VolumeControlChecked)
  2365. {
  2366. /*
  2367. ** Check to see if the volume controller piglet can be found on
  2368. ** the path.
  2369. */
  2370. {
  2371. TCHAR chBuffer[8];
  2372. LPTSTR lptstr;
  2373. if( SearchPath( NULL, szSndVol32, NULL, 8, chBuffer, &lptstr ) == 0L )
  2374. EnableMenuItem( hMenu, IDM_VOLUME, MF_GRAYED );
  2375. VolumeControlChecked = TRUE;
  2376. }
  2377. }
  2378. /* On Device (or Insert Clip) menu start menu building if necessary
  2379. * (e.g. if we came up in tiny mode then switched to full size),
  2380. * and wait for the separate thread to complete.
  2381. */
  2382. InitDeviceMenu();
  2383. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2384. WaitForDeviceMenu();
  2385. SetCursor(hcurPrev);
  2386. }
  2387. /////////////////////////////////////////////////////////////////////////////
  2388. // This code allows a window to by sized even when in the maximized state
  2389. /////////////////////////////////////////////////////////////////////////////
  2390. if (gfPlayOnly && !IsIconic(hwnd) && fSystemMenu && IsZoomed(hwnd))
  2391. EnableMenuItem(hMenu, SC_SIZE,
  2392. !IsIconic(hwnd) ? MF_ENABLED : MF_GRAYED);
  2393. }
  2394. void MPlayer_OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo)
  2395. {
  2396. RECT rc;
  2397. if (gfPlayOnly) {
  2398. SetRect(&rc, 0, 0, 0, TOOLBAR_HEIGHT);
  2399. AdjustWindowRect(&rc, (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE), FALSE);
  2400. lpMinMaxInfo->ptMinTrackSize.y = rc.bottom - rc.top - 1;
  2401. if (!gfPlayingInPlace &&
  2402. (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW)))
  2403. lpMinMaxInfo->ptMaxTrackSize.y = lpMinMaxInfo->ptMinTrackSize.y;
  2404. }
  2405. else {
  2406. lpMinMaxInfo->ptMinTrackSize.y = MAX_NORMAL_HEIGHT + gwHeightAdjust;
  2407. lpMinMaxInfo->ptMaxTrackSize.y = MAX_NORMAL_HEIGHT + gwHeightAdjust;
  2408. }
  2409. }
  2410. void MPlayer_OnPaint(HWND hwnd)
  2411. {
  2412. PAINTSTRUCT ps;
  2413. RECT rc;
  2414. int x1, x2, y, y2;
  2415. UINT wParent;
  2416. HBRUSH hbrOld;
  2417. BeginPaint(hwnd, &ps);
  2418. if (gfPlayOnly) {
  2419. extern UINT gwPlaybarHeight; // in server.c
  2420. /* Separate mci playback window from controls */
  2421. if (gwDeviceType & DTMCI_CANWINDOW) {
  2422. SelectObject(ps.hdc, hbrButtonText);
  2423. GetClientRect(ghwndApp, &rc);
  2424. PatBlt(ps.hdc, 0, rc.bottom - gwPlaybarHeight, rc.right, 1, PATCOPY);
  2425. }
  2426. }
  2427. else {
  2428. hbrOld = SelectObject(ps.hdc, hbrButtonText);
  2429. GetClientRect(ghwndApp, &rc);
  2430. wParent = rc.right;
  2431. y = rc.bottom - 27; // where to paint borders around toolbar
  2432. /* Line above trackbar */
  2433. #ifdef CHICAGO_PRODUCT
  2434. y2 = rc.bottom - 74;
  2435. /* This looks bad on NT */
  2436. PatBlt(ps.hdc, 0, y2, wParent, 1, PATCOPY);
  2437. #else
  2438. y2 = rc.bottom - 75;
  2439. #endif
  2440. /* Lines around toolbars */
  2441. PatBlt(ps.hdc, 0, y, wParent, 1, PATCOPY);
  2442. GetClientRect(ghwndToolbar, &rc);
  2443. x1 = rc.right;
  2444. PatBlt(ps.hdc, x1, y, 1, TOOLBAR_HEIGHT + 3, PATCOPY);
  2445. GetWindowRect(ghwndApp, &rc);
  2446. x2 = rc.left;
  2447. if (IsWindowVisible(ghwndStatic)) {
  2448. GetWindowRect(ghwndStatic, &rc);
  2449. MapWindowPoints(NULL, ghwndApp, (LPPOINT)&rc, 1);
  2450. x2 = rc.left - 2 - GetSystemMetrics(SM_CXFRAME);
  2451. PatBlt(ps.hdc, x2, y, 1, TOOLBAR_HEIGHT + 3, PATCOPY);
  2452. }
  2453. SelectObject(ps.hdc, hbrButtonHighLight);
  2454. /* Line above trackbar */
  2455. PatBlt(ps.hdc, 0, y2 + 1, wParent, 1, PATCOPY);
  2456. /* Lines around toolbar */
  2457. PatBlt(ps.hdc, 0, y + 1, wParent, 1, PATCOPY);
  2458. PatBlt(ps.hdc, x1 + 1, y + 1, 1, TOOLBAR_HEIGHT + 2, PATCOPY);
  2459. if (IsWindowVisible(ghwndStatic)) {
  2460. PatBlt(ps.hdc, x2 + 1, y + 1, 1,TOOLBAR_HEIGHT +2, PATCOPY);
  2461. }
  2462. SelectObject(ps.hdc, hbrOld);
  2463. }
  2464. EndPaint(hwnd, &ps);
  2465. }
  2466. void MPlayer_OnCommand_Toolbar_Play()
  2467. {
  2468. /* This checks to see whether the ALT key is held down.
  2469. * If so, the current selection (if it exists) is played,
  2470. * otherwise the whole shooting match.
  2471. * Note, this does not appear to be documented at present.
  2472. */
  2473. if (GetKeyState(VK_MENU) < 0)
  2474. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAYSEL, 0);
  2475. /* On WFW, pressing the play button when in place plays the
  2476. * current selection, if there is one. Do the same if we're
  2477. * playing or editing in place.
  2478. */
  2479. else if (gfOle2IPPlaying || gfOle2IPEditing)
  2480. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAYSEL, 0);
  2481. else
  2482. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAY, 0);
  2483. }
  2484. void MPlayer_OnCommand_Toolbar_Pause()
  2485. {
  2486. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PAUSE, 0L);
  2487. }
  2488. void MPlayer_OnCommand_Toolbar_Stop()
  2489. {
  2490. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_STOP, 0L);
  2491. }
  2492. void MPlayer_OnCommand_Toolbar_Eject()
  2493. {
  2494. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_EJECT, 0L);
  2495. }
  2496. void MPlayer_OnCommand_Toolbar_Home()
  2497. {
  2498. LONG_PTR lPos = CalcPrevMark();
  2499. /* We MUST use PostMessage because the */
  2500. /* SETPOS and ENDTRACK must happen one */
  2501. /* immediately after the other */
  2502. PostMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, lPos);
  2503. PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_ENDTRACK, (LPARAM)ghwndTrackbar);
  2504. }
  2505. void MPlayer_OnCommand_Toolbar_End()
  2506. {
  2507. LONG_PTR lPos = CalcNextMark();
  2508. /* We MUST use PostMessage because the */
  2509. /* SETPOS and ENDTRACK must happen one */
  2510. /* immediately after the other */
  2511. PostMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, lPos);
  2512. PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_ENDTRACK, (LPARAM)ghwndTrackbar);
  2513. }
  2514. void MPlayer_OnCommand_Toolbar_Rwd(HWND hwndCtl)
  2515. {
  2516. if (hwndCtl == (HWND)REPEAT_ID)
  2517. {
  2518. if (gwCurScale != ID_TRACKS)
  2519. PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_PAGEUP, 0L);
  2520. else
  2521. PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_LINEUP, 0L);
  2522. }
  2523. }
  2524. void MPlayer_OnCommand_Toolbar_Fwd(HWND hwndCtl)
  2525. {
  2526. if (hwndCtl == (HWND)REPEAT_ID)
  2527. {
  2528. if (gwCurScale != ID_TRACKS)
  2529. PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_PAGEDOWN, 0L);
  2530. else
  2531. PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_LINEDOWN, 0L);
  2532. }
  2533. }
  2534. void MPlayer_OnCommand_Toolbar_MarkIn()
  2535. {
  2536. SendMessage(ghwndTrackbar, TBM_SETSELSTART, (WPARAM)TRUE,
  2537. SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0));
  2538. DirtyObject(TRUE);
  2539. }
  2540. void MPlayer_OnCommand_Toolbar_MarkOut()
  2541. {
  2542. SendMessage(ghwndTrackbar, TBM_SETSELEND, (WPARAM)TRUE,
  2543. SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0));
  2544. DirtyObject(TRUE);
  2545. }
  2546. void MPlayer_OnCommand_Toolbar_ArrowPrev(HWND hwndCtl)
  2547. {
  2548. if (hwndCtl == (HWND)REPEAT_ID)
  2549. SendMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_LINEUP, 0L);
  2550. }
  2551. void MPlayer_OnCommand_Toolbar_ArrowNext(HWND hwndCtl)
  2552. {
  2553. if (hwndCtl == (HWND)REPEAT_ID)
  2554. SendMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_LINEDOWN, 0L);
  2555. }
  2556. void MPlayer_OnCommand_Menu_CopyObject(HWND hwnd)
  2557. {
  2558. if (gfPlayingInPlace)
  2559. {
  2560. DPF0("Mplayer WndProc: Can't cutorcopy\n");
  2561. return;
  2562. }
  2563. DPF("Mplayer WndProc: Calling cutorcopy\n");
  2564. if (!InitOLE(&gfOleInitialized, &lpMalloc))
  2565. {
  2566. /* How likely is this? Do we need a dialog box?
  2567. */
  2568. DPF0("Initialization of OLE FAILED!! Can't do copy.\n");
  2569. }
  2570. #ifdef OLE1_HACK
  2571. CopyObject(hwnd);
  2572. #endif /* OLE1_HACK */
  2573. CutOrCopyObj(&docMain);
  2574. }
  2575. void MPlayer_OnCommand_Menu_Config(HWND hwnd)
  2576. {
  2577. RECT rcBefore;
  2578. RECT rcAfter;
  2579. if (gfPlayingInPlace)
  2580. return;
  2581. GetDestRectMCI (&rcBefore);
  2582. ConfigMCI(hwnd);
  2583. /* If the MCI window size changed, we need to resize */
  2584. /* our reduced mplayer. */
  2585. if (gfPlayOnly)
  2586. {
  2587. GetDestRectMCI (&rcAfter);
  2588. if (!EqualRect(&rcBefore, &rcAfter) && (!IsRectEmpty(&rcAfter)))
  2589. SetMPlayerSize(&rcAfter);
  2590. }
  2591. }
  2592. void MPlayer_OnCommand_Menu_Volume(HWND hwnd)
  2593. {
  2594. HANDLE hThread;
  2595. DWORD dwThreadId;
  2596. hThread = CreateThread( NULL, 0L,
  2597. (LPTHREAD_START_ROUTINE)StartSndVol,
  2598. NULL, 0L, &dwThreadId );
  2599. if ( hThread != NULL ) {
  2600. CloseHandle( hThread );
  2601. }
  2602. }
  2603. void MPlayer_OnCommand_PlayToggle(HWND hwnd)
  2604. {
  2605. /* This is for the accelerator to toggle play and pause. */
  2606. /* Ordinary play commands better not toggle. */
  2607. DPF2("MPlayer_OnCommand_PlayToggle: gwStatus == %x\n", gwStatus);
  2608. switch(gwStatus) {
  2609. case MCI_MODE_STOP:
  2610. case MCI_MODE_PAUSE:
  2611. case MCI_MODE_SEEK:
  2612. PostMessage(hwnd, WM_COMMAND, (WPARAM)ID_PLAY, 0);
  2613. break;
  2614. case MCI_MODE_PLAY:
  2615. PostMessage(hwnd, WM_COMMAND, (WPARAM)ID_PAUSE, 0);
  2616. break;
  2617. }
  2618. }
  2619. void MPlayer_OnCommand_PlaySel(HWND hwnd, HWND hwndCtl)
  2620. {
  2621. DWORD_PTR dwPos, dwStart, dwEnd;
  2622. BOOL f;
  2623. dwPos = 0; // Make Prefix Happy..
  2624. DPF2("MPlayer_OnCommand_PlaySel: gwStatus == %x\n", gwStatus);
  2625. switch(gwStatus) {
  2626. case MCI_MODE_OPEN:
  2627. case MCI_MODE_NOT_READY:
  2628. Error(ghwndApp, IDS_CANTPLAY);
  2629. if (gfCloseAfterPlaying) // get us out now!!
  2630. PostCloseMessage();
  2631. break;
  2632. default:
  2633. /* If the shift key's being held down, make this the start
  2634. * of a selection:
  2635. */
  2636. if((GetKeyState(VK_SHIFT) < 0)
  2637. &&(toolbarStateFromButton(ghwndMark, BTN_MARKIN, TBINDEX_MARK)
  2638. != BTNST_GRAYED))
  2639. SendMessage(hwnd, WM_COMMAND, IDT_MARKIN, 0);
  2640. /* Start playing the medium */
  2641. StatusMCI(&dwPos); // get the REAL position
  2642. dwStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0);
  2643. dwEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
  2644. /* If there is no valid selection, act like PLAY */
  2645. if (dwStart == -1 || dwEnd == -1 || dwStart == dwEnd)
  2646. hwndCtl = (HWND)ID_PLAY;
  2647. // Be nice and rewind automatically if we're at the end of the media.
  2648. // Depending on the device, though, the end could be "start + len"
  2649. // or "start + len - 1"
  2650. if (hwndCtl == (HWND)ID_PLAY &&
  2651. dwPos >= gdwMediaStart + gdwMediaLength - 1) {
  2652. if (!SeekMCI(gdwMediaStart))
  2653. break;
  2654. }
  2655. if (hwndCtl == (HWND)ID_PLAYSEL) {
  2656. f = PlayMCI(dwStart, dwEnd);
  2657. gfJustPlayedSel = TRUE;
  2658. } else {
  2659. f = PlayMCI(0, 0);
  2660. gfJustPlayedSel = FALSE;
  2661. }
  2662. // get us out NOW!! or focus goes to client
  2663. if (!f && gfCloseAfterPlaying)
  2664. PostCloseMessage();
  2665. /* No longer needed - reset for next time */
  2666. gfUserStopped = FALSE;
  2667. gwStatus = (UINT)(-1); // force rewind if needed
  2668. break;
  2669. }
  2670. }
  2671. void MPlayer_OnCommand_Pause()
  2672. {
  2673. /* Pause the medium, unless we are already paused */
  2674. DPF2("MPlayer_OnCommand_Pause: gwStatus == %x\n", gwStatus);
  2675. switch(gwStatus) {
  2676. case MCI_MODE_PAUSE:
  2677. PlayMCI(0, 0);
  2678. break;
  2679. case MCI_MODE_PLAY:
  2680. case MCI_MODE_SEEK:
  2681. PauseMCI();
  2682. break;
  2683. case MCI_MODE_STOP:
  2684. case MCI_MODE_OPEN:
  2685. break;
  2686. }
  2687. }
  2688. void MPlayer_OnCommand_Stop()
  2689. {
  2690. /* Stop the medium */
  2691. DPF2("MPlayer_OnCommand_Stop: gwStatus == %x\n", gwStatus);
  2692. switch(gwStatus) {
  2693. case MCI_MODE_PAUSE:
  2694. case MCI_MODE_PLAY:
  2695. case MCI_MODE_STOP:
  2696. case MCI_MODE_SEEK:
  2697. StopMCI();
  2698. SeekToStartMCI();
  2699. gfUserStopped = TRUE; // we did this
  2700. gfCloseAfterPlaying = FALSE; //stay up from now on
  2701. UpdateDisplay();
  2702. // Focus should go to PLAY button now
  2703. toolbarSetFocus(ghwndToolbar, BTN_PLAY);
  2704. break;
  2705. case MCI_MODE_OPEN:
  2706. break;
  2707. }
  2708. if (gfPlayingInPlace)
  2709. PostCloseMessage();
  2710. }
  2711. void MPlayer_OnCommand_Eject()
  2712. {
  2713. /*
  2714. * Eject the medium if it currently isn't ejected. If it
  2715. * is currently ejected, then load the new medium into
  2716. * the device.
  2717. *
  2718. */
  2719. switch(gwStatus) {
  2720. case MCI_MODE_PLAY:
  2721. case MCI_MODE_PAUSE:
  2722. StopMCI();
  2723. EjectMCI(TRUE);
  2724. break;
  2725. case MCI_MODE_STOP:
  2726. case MCI_MODE_SEEK:
  2727. case MCI_MODE_NOT_READY:
  2728. EjectMCI(TRUE);
  2729. break;
  2730. case MCI_MODE_OPEN:
  2731. EjectMCI(FALSE);
  2732. break;
  2733. }
  2734. }
  2735. void MPlayer_OnCommand_Escape()
  2736. {
  2737. MPlayer_OnCommand_Stop();
  2738. if( gfOle2IPEditing || gfOle2IPPlaying)
  2739. PostCloseMessage();
  2740. }
  2741. void MPlayer_OnCommand_Menu_Open()
  2742. {
  2743. UINT wLastScale;
  2744. UINT wLastDeviceID;
  2745. TCHAR szFile[256];
  2746. RECT rc;
  2747. wLastScale = gwCurScale; // save old scale
  2748. wLastDeviceID = gwDeviceID;
  2749. if (gfPlayingInPlace || gfOle2IPEditing || gfOle2IPPlaying)
  2750. return;
  2751. InitDeviceMenu();
  2752. WaitForDeviceMenu();
  2753. if (OpenDoc(gwCurDevice,szFile))
  2754. {
  2755. DirtyObject(FALSE);
  2756. /* Force WM_GETMINMAXINFO to be called so we'll snap */
  2757. /* to a proper size. */
  2758. GetWindowRect(ghwndApp, &rc);
  2759. MoveWindow(ghwndApp,
  2760. rc.left,
  2761. rc.top,
  2762. rc.right - rc.left,
  2763. rc.bottom - rc.top,
  2764. TRUE);
  2765. if (gfOpenDialog)
  2766. CompleteOpenDialog(TRUE);
  2767. else
  2768. gfCloseAfterPlaying = FALSE; // stay up from now on
  2769. //If the CD Audio device was opened it must have been a *.cda file.
  2770. //Try to jump to the track corresponding to the file opened.
  2771. if ((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO)
  2772. {
  2773. HandleCDAFile(szFile);
  2774. }
  2775. }
  2776. else
  2777. {
  2778. if (gfOpenDialog)
  2779. CompleteOpenDialog(FALSE);
  2780. /* The previous device may or may not still be open.
  2781. * If it is, make sure we have the right scale.
  2782. */
  2783. if (gwDeviceID == wLastDeviceID)
  2784. gwCurScale = wLastScale; // restore to last scale
  2785. InvalidateRect(ghwndMap, NULL, TRUE); //erase map area
  2786. }
  2787. // put the focus on the Play button
  2788. SetFocus(ghwndToolbar); // give focus to PLAY button
  2789. toolbarSetFocus(ghwndToolbar, BTN_PLAY);
  2790. SetMPlayerIcon();
  2791. }
  2792. void MPlayer_OnCommand_Menu_Close(HWND hwnd)
  2793. {
  2794. if (gfEmbeddedObject && !gfSeenPBCloseMsg) {
  2795. // this is File.Update
  2796. #ifdef OLE1_HACK
  2797. if( gDocVersion == DOC_VERSION_OLE1 )
  2798. Ole1UpdateObject();
  2799. else
  2800. #endif /* OLE1_HACK */
  2801. UpdateObject();
  2802. }
  2803. else
  2804. {
  2805. // this is File.Close
  2806. gfSeenPBCloseMsg = TRUE;
  2807. WriteOutOptions();
  2808. InitDoc(TRUE);
  2809. SetMPlayerIcon();
  2810. gwCurDevice = 0;// force next file open dialog to say
  2811. // "all files" because CloseMCI won't.
  2812. gwCurScale = ID_NONE; // uncheck all scale types
  2813. Layout(); // Make window snap back to smaller size
  2814. // if it should.
  2815. // Don't leave us closed in play only mode
  2816. if (gfPlayOnly)
  2817. SendMessage(hwnd, WM_COMMAND, (WPARAM)IDM_WINDOW, 0);
  2818. }
  2819. }
  2820. void MPlayer_OnCommand_Menu_Exit()
  2821. {
  2822. PostCloseMessage();
  2823. }
  2824. void MPlayer_OnCommand_Menu_Scale(UINT id)
  2825. {
  2826. /*
  2827. * Invalidate the track map window so it will be
  2828. * redrawn with the correct positions, etc.
  2829. */
  2830. if (gwCurScale != id - IDM_SCALE) {
  2831. // Restoring the selection doesn't work yet,
  2832. // because UpdateMCI clears the selection,
  2833. // plus we need to do some conversion.
  2834. // int SelStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0);
  2835. // int SelEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
  2836. SendMessage(ghwndTrackbar, TBM_CLEARTICS, (WPARAM)FALSE, 0L);
  2837. if (gwCurScale == ID_FRAMES || id - IDM_SCALE == ID_FRAMES)
  2838. gfValidMediaInfo = FALSE;
  2839. gwCurScale = id - IDM_SCALE;
  2840. DirtyObject(TRUE); // change scale changes PAGE UP/DOWN
  2841. CalcTicsOfDoom();
  2842. // SendMessage(ghwndTrackbar, TBM_SETSELSTART, TRUE, SelStart);
  2843. // SendMessage(ghwndTrackbar, TBM_SETSELEND, TRUE, SelEnd);
  2844. }
  2845. }
  2846. void MPlayer_OnCommand_Menu_Selection(HWND hwnd)
  2847. {
  2848. if (!gfPlayingInPlace)
  2849. setselDialog(hwnd);
  2850. }
  2851. void MPlayer_OnCommand_Menu_Options(HWND hwnd)
  2852. {
  2853. if (!gfPlayingInPlace)
  2854. optionsDialog(hwnd);
  2855. }
  2856. void MPlayer_OnCommand_Menu_MCIString(HWND hwnd)
  2857. {
  2858. if (!gfPlayingInPlace && gwDeviceID)
  2859. mciDialog(hwnd);
  2860. }
  2861. void MPlayer_OnCommand_Menu_Window(HWND hwnd)
  2862. {
  2863. //
  2864. // make MPlayer small/big
  2865. //
  2866. //!! dont do this if inside client document !!
  2867. //!! or if we're not visible !!
  2868. if (!IsWindowVisible(ghwndApp) || gfPlayingInPlace || IsIconic(hwnd)
  2869. || gfOle2IPEditing)
  2870. return;
  2871. // allowed to get out of teeny mode when no file is open
  2872. if (gwDeviceID != (UINT)0 || gfPlayOnly) {
  2873. gfPlayOnly = !gfPlayOnly;
  2874. SizeMPlayer();
  2875. }
  2876. }
  2877. void MPlayer_OnCommand_Menu_Zoom(HWND hwnd, int id)
  2878. {
  2879. int dx, dy;
  2880. if (IsIconic(hwnd) ||gfPlayingInPlace || gfOle2IPPlaying || gfOle2IPEditing ||
  2881. !(gwDeviceType & DTMCI_CANWINDOW))
  2882. return;
  2883. dx = grcSize.right * (id-IDM_ZOOM);
  2884. dy = grcSize.bottom * (id-IDM_ZOOM);
  2885. //
  2886. // if the playback windows is now larger than the screen
  2887. // maximize MPlayer, this only makes sence for Tiny mode.
  2888. //
  2889. if (gfPlayOnly &&
  2890. (dx >= GetSystemMetrics(SM_CXSCREEN) ||
  2891. dy >= GetSystemMetrics(SM_CYSCREEN))) {
  2892. ClrWS(hwnd, WS_MAXIMIZE);
  2893. DefWindowProc(hwnd, WM_SYSCOMMAND, (WPARAM)SC_MAXIMIZE, 0);
  2894. }
  2895. else {
  2896. SizePlaybackWindow(dx, dy);
  2897. }
  2898. }
  2899. void DoHtmlHelp()
  2900. {
  2901. //note, using ANSI version of function because UNICODE is foobar in NT5 builds
  2902. char chDst[MAX_PATH];
  2903. WideCharToMultiByte(CP_ACP, 0, gszHtmlHelpFileName,
  2904. -1, chDst, MAX_PATH, NULL, NULL);
  2905. HtmlHelpA(GetDesktopWindow(), chDst, HH_DISPLAY_TOPIC, 0);
  2906. }
  2907. void MPlayer_OnCommand_Menu_HelpTopics(HWND hwnd)
  2908. {
  2909. static TCHAR HelpFile[] = TEXT("MPLAYER.HLP");
  2910. //Handle context menu help
  2911. if(bF1InMenu)
  2912. {
  2913. switch(currMenuItem)
  2914. {
  2915. case IDM_OPEN:
  2916. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_FILE_OPEN);
  2917. break;
  2918. case IDM_CLOSE:
  2919. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_FILE_CLOSE);
  2920. break;
  2921. case IDM_EXIT:
  2922. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_FILE_EXIT);
  2923. break;
  2924. case IDM_COPY_OBJECT:
  2925. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_EDIT_COPY_OBJECT);
  2926. break;
  2927. case IDM_OPTIONS:
  2928. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_EDIT_OPTIONS);
  2929. break;
  2930. case IDM_SELECTION:
  2931. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_EDIT_SELECTION);
  2932. break;
  2933. case IDM_CONFIG:
  2934. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_DEVICE_PROPERTIES);
  2935. break;
  2936. case IDM_VOLUME:
  2937. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_DEVICE_VOLUME_CONTROL);
  2938. break;
  2939. case IDM_SCALE + ID_TIME:
  2940. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_SCALE_TIME);
  2941. break;
  2942. case IDM_SCALE + ID_TRACKS:
  2943. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_SCALE_TRACKS);
  2944. break;
  2945. case IDM_SCALE + ID_FRAMES:
  2946. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_SCALE_FRAMES);
  2947. break;
  2948. case IDM_HELPTOPICS:
  2949. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_HELP_HELP_TOPICS);
  2950. break;
  2951. case IDM_ABOUT:
  2952. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_HELP_ABOUT);
  2953. break;
  2954. default://In the default case just display the HTML Help.
  2955. DoHtmlHelp();
  2956. }
  2957. bF1InMenu = FALSE; //This flag will be set again if F1 is pressed in a menu.
  2958. }
  2959. else
  2960. DoHtmlHelp();
  2961. }
  2962. void MPlayer_OnCommand_Menu_About(HWND hwnd)
  2963. {
  2964. ShellAbout(hwnd, gachAppName, aszNULL, hiconApp);
  2965. }
  2966. void MPlayer_OnCommand_Default(HWND hwnd, int id)
  2967. {
  2968. /*
  2969. * Determine if the user selected one of the entries in
  2970. * the Device menu.
  2971. *
  2972. */
  2973. if (id > IDM_DEVICE0 &&
  2974. (id <= (WORD)(IDM_DEVICE0 + gwNumDevices))
  2975. ) {
  2976. BOOL fHasWindow, fHadWindow, fHadDevice;
  2977. fHadWindow = (gwDeviceID != (UINT)0) && (gwDeviceType & DTMCI_CANWINDOW);
  2978. fHadDevice = (gwDeviceID != (UINT)0);
  2979. //Choose and open a new device. If we are active inplace we have
  2980. //to consider the effect of the change in device on the visual appearence.
  2981. //For this we have to take into account whether the current and previous
  2982. //device had a playback window or not. We also have to consider
  2983. //whether this is the first device are opening.
  2984. //After all the crazy munging send a messages to the container about
  2985. //the changes.
  2986. if (DoChooseDevice(id-IDM_DEVICE0))
  2987. {
  2988. if (gfOpenDialog)
  2989. CompleteOpenDialog(TRUE);
  2990. fHasWindow = (gwDeviceID != (UINT)0) && (gwDeviceType & DTMCI_CANWINDOW);
  2991. if(gfOle2IPEditing)
  2992. {
  2993. if (fHasWindow && fHadWindow)
  2994. {
  2995. GetWindowRect(ghwndApp, (LPRECT)&gInPlacePosRect);
  2996. gfInPlaceResize = TRUE;
  2997. SendDocMsg((LPDOC)&docMain, OLE_SIZECHG);
  2998. SendDocMsg((LPDOC)&docMain, OLE_CHANGED);
  2999. }
  3000. else
  3001. {
  3002. RECT rc;
  3003. RECT rctmp;
  3004. ClrWS(ghwndApp,
  3005. WS_THICKFRAME|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_BORDER);
  3006. if (gwOptions & OPT_BORDER)
  3007. SetWS(ghwndApp, WS_BORDER);
  3008. GetWindowRect(ghwndApp, &rc);
  3009. if (!(gwDeviceType & DTMCI_CANWINDOW))
  3010. {
  3011. HBITMAP hbm;
  3012. BITMAP bm;
  3013. if (!fHadDevice)
  3014. GetWindowRect(ghwndIPHatch, &rc);
  3015. hbm = BitmapMCI();
  3016. GetObject(hbm,sizeof(bm),&bm);
  3017. rc.bottom = rc.top + bm.bmHeight;
  3018. rc.right = rc.left + bm.bmWidth;
  3019. DeleteObject(hbm);
  3020. }
  3021. else
  3022. {
  3023. if(!fHadDevice)
  3024. {
  3025. rc.bottom -= (GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYBORDER));
  3026. gwOptions |= OPT_BAR | OPT_TITLE;
  3027. }
  3028. rc.bottom += gInPlacePosRect.top - rc.top - 4*GetSystemMetrics(SM_CYBORDER) - 4 ;
  3029. rc.right += gInPlacePosRect.left - rc.left- 4*GetSystemMetrics(SM_CXBORDER) - 4 ;
  3030. rc.top = gInPlacePosRect.top;
  3031. rc.left = gInPlacePosRect.left;
  3032. }
  3033. rctmp = gPrevPosRect;
  3034. MapWindowPoints( ghwndCntr, NULL, (LPPOINT)&rctmp,2);
  3035. OffsetRect((LPRECT)&rc, rctmp.left - rc.left, rctmp.top -rc.top);
  3036. gInPlacePosRect = rc;
  3037. gfInPlaceResize = TRUE;
  3038. if(!(gwDeviceType & DTMCI_CANWINDOW) && (gwOptions & OPT_BAR))
  3039. {
  3040. rc.top = rc.bottom - gwPlaybarHeight;
  3041. }
  3042. EditInPlace(ghwndApp,ghwndIPHatch,&rc);
  3043. SendDocMsg((LPDOC)&docMain, OLE_SIZECHG);
  3044. SendDocMsg((LPDOC)&docMain, OLE_CHANGED);
  3045. if (!(gwDeviceType & DTMCI_CANWINDOW) && !(gwOptions &OPT_BAR))
  3046. ShowWindow(ghwndApp, SW_HIDE);
  3047. else
  3048. ShowWindow(ghwndApp, SW_SHOW);
  3049. }
  3050. }
  3051. DirtyObject(FALSE);
  3052. if (!gfOpenDialog)
  3053. gfCloseAfterPlaying = FALSE; // stay up from now on
  3054. SetMPlayerIcon();
  3055. }
  3056. else
  3057. if (gfOpenDialog)
  3058. CompleteOpenDialog(FALSE);
  3059. }
  3060. }
  3061. #define HANDLE_COMMAND(id, call) case (id): (call); break
  3062. void MPlayer_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  3063. {
  3064. switch (id) {
  3065. HANDLE_COMMAND(IDT_PLAY, MPlayer_OnCommand_Toolbar_Play());
  3066. HANDLE_COMMAND(IDT_PAUSE, MPlayer_OnCommand_Toolbar_Pause());
  3067. HANDLE_COMMAND(IDT_STOP, MPlayer_OnCommand_Toolbar_Stop());
  3068. HANDLE_COMMAND(IDT_EJECT, MPlayer_OnCommand_Toolbar_Eject());
  3069. HANDLE_COMMAND(IDT_HOME, MPlayer_OnCommand_Toolbar_Home());
  3070. HANDLE_COMMAND(IDT_END, MPlayer_OnCommand_Toolbar_End());
  3071. HANDLE_COMMAND(IDT_RWD, MPlayer_OnCommand_Toolbar_Rwd(hwndCtl));
  3072. HANDLE_COMMAND(IDT_FWD, MPlayer_OnCommand_Toolbar_Fwd(hwndCtl));
  3073. HANDLE_COMMAND(IDT_MARKIN, MPlayer_OnCommand_Toolbar_MarkIn());
  3074. HANDLE_COMMAND(IDT_MARKOUT, MPlayer_OnCommand_Toolbar_MarkOut());
  3075. HANDLE_COMMAND(IDT_ARROWPREV, MPlayer_OnCommand_Toolbar_ArrowPrev(hwndCtl));
  3076. HANDLE_COMMAND(IDT_ARROWNEXT, MPlayer_OnCommand_Toolbar_ArrowNext(hwndCtl));
  3077. HANDLE_COMMAND(IDM_COPY_OBJECT, MPlayer_OnCommand_Menu_CopyObject(hwnd));
  3078. HANDLE_COMMAND(IDM_CONFIG, MPlayer_OnCommand_Menu_Config(hwnd));
  3079. HANDLE_COMMAND(IDM_VOLUME, MPlayer_OnCommand_Menu_Volume(hwnd));
  3080. HANDLE_COMMAND(ID_PLAYTOGGLE, MPlayer_OnCommand_PlayToggle(hwnd));
  3081. HANDLE_COMMAND(ID_PLAY, MPlayer_OnCommand_PlaySel(hwnd, (HWND)IntToPtr(id)));
  3082. HANDLE_COMMAND(ID_PLAYSEL, MPlayer_OnCommand_PlaySel(hwnd, (HWND)IntToPtr(id)));
  3083. HANDLE_COMMAND(ID_PAUSE, MPlayer_OnCommand_Pause());
  3084. HANDLE_COMMAND(ID_STOP, MPlayer_OnCommand_Stop());
  3085. HANDLE_COMMAND(ID_EJECT, MPlayer_OnCommand_Eject());
  3086. HANDLE_COMMAND(ID_ESCAPE, MPlayer_OnCommand_Escape());
  3087. HANDLE_COMMAND(IDM_OPEN, MPlayer_OnCommand_Menu_Open());
  3088. HANDLE_COMMAND(IDM_CLOSE, MPlayer_OnCommand_Menu_Close(hwnd));
  3089. HANDLE_COMMAND(IDM_EXIT, MPlayer_OnCommand_Menu_Exit());
  3090. HANDLE_COMMAND(IDM_SCALE + ID_TIME, MPlayer_OnCommand_Menu_Scale(id));
  3091. HANDLE_COMMAND(IDM_SCALE + ID_TRACKS, MPlayer_OnCommand_Menu_Scale(id));
  3092. HANDLE_COMMAND(IDM_SCALE + ID_FRAMES, MPlayer_OnCommand_Menu_Scale(id));
  3093. HANDLE_COMMAND(IDM_SELECTION, MPlayer_OnCommand_Menu_Selection(hwnd));
  3094. HANDLE_COMMAND(IDM_OPTIONS, MPlayer_OnCommand_Menu_Options(hwnd));
  3095. HANDLE_COMMAND(IDM_MCISTRING, MPlayer_OnCommand_Menu_MCIString(hwnd));
  3096. HANDLE_COMMAND(IDM_WINDOW, MPlayer_OnCommand_Menu_Window(hwnd));
  3097. HANDLE_COMMAND(IDM_ZOOM1, MPlayer_OnCommand_Menu_Zoom(hwnd, id));
  3098. HANDLE_COMMAND(IDM_ZOOM2, MPlayer_OnCommand_Menu_Zoom(hwnd, id));
  3099. HANDLE_COMMAND(IDM_ZOOM3, MPlayer_OnCommand_Menu_Zoom(hwnd, id));
  3100. HANDLE_COMMAND(IDM_ZOOM4, MPlayer_OnCommand_Menu_Zoom(hwnd, id));
  3101. HANDLE_COMMAND(IDM_HELPTOPICS, MPlayer_OnCommand_Menu_HelpTopics(hwnd));
  3102. HANDLE_COMMAND(IDM_ABOUT, MPlayer_OnCommand_Menu_About(hwnd));
  3103. default: MPlayer_OnCommand_Default(hwnd, id);
  3104. }
  3105. UpdateDisplay();
  3106. }
  3107. void MPlayer_OnClose(HWND hwnd)
  3108. {
  3109. int f;
  3110. DPF("WM_CLOSE received\n");
  3111. if (gfInClose) {
  3112. DPF("*** \n");
  3113. DPF("*** Trying to re-enter WM_CLOSE\n");
  3114. DPF("*** \n");
  3115. return;
  3116. }
  3117. // Ask if we want to update before we set gfInClose to TRUE or
  3118. // we won't let the dialog box up.
  3119. f = AskUpdate();
  3120. if (f == IDYES)
  3121. UpdateObject();
  3122. if (f == IDCANCEL) {
  3123. gfInClose = FALSE;
  3124. return;
  3125. }
  3126. gfInClose = TRUE;
  3127. ExitApplication();
  3128. if (gfPlayingInPlace)
  3129. EndPlayInPlace(hwnd);
  3130. if (gfOle2IPEditing)
  3131. EndEditInPlace(hwnd);
  3132. if (docMain.lpoleclient)
  3133. IOleClientSite_OnShowWindow(docMain.lpoleclient, FALSE);
  3134. SendDocMsg(&docMain,OLE_CLOSED);
  3135. DestroyDoc(&docMain);
  3136. ExitApplication();
  3137. if (hMciOle)
  3138. {
  3139. FreeLibrary(hMciOle);
  3140. hMciOle = NULL;
  3141. }
  3142. //
  3143. // set either the owner or the WS_CHILD bit so it will
  3144. // not act up because we have the palette bit set and cause the
  3145. // desktop to steal the palette.
  3146. //
  3147. // because we are being run from client apps that dont deal
  3148. // with palettes we dont want the desktop to hose the palette.
  3149. //
  3150. if (gfPlayOnly && gfCloseAfterPlaying && gfRunWithEmbeddingFlag)
  3151. SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LPARAM)GetDesktopWindow() );
  3152. if (!ItsSafeToClose()) {
  3153. DPF("*** \n");
  3154. DPF("*** Trying to close MPLAYER with a ErrorBox up\n");
  3155. DPF("*** \n");
  3156. gfErrorDeath = WM_CLOSE;
  3157. gfInClose = FALSE;
  3158. return;
  3159. }
  3160. f = AskUpdate();
  3161. if (f == IDYES)
  3162. UpdateObject();
  3163. if (f == IDCANCEL) {
  3164. gfInClose = FALSE;
  3165. return;
  3166. }
  3167. PostMessage(ghwndApp, WM_USER_DESTROY, 0, 0);
  3168. DPF("WM_DESTROY message sent\n");
  3169. }
  3170. void MPlayer_OnEndSession(HWND hwnd, BOOL fEnding)
  3171. {
  3172. if (fEnding) {
  3173. WriteOutPosition();
  3174. WriteOutOptions();
  3175. CloseMCI(FALSE);
  3176. }
  3177. }
  3178. void MPlayer_OnDestroy(HWND hwnd)
  3179. {
  3180. /*
  3181. * Relinquish control of whatever MCI device we were using (if any). If
  3182. * this device is not shareable, then performing this action allows
  3183. * someone else to gain access to the device.
  3184. *
  3185. */
  3186. /* Client might close us if he dies while we're Playing in Place */
  3187. if (gfPlayingInPlace) {
  3188. DPF("****\n");
  3189. DPF("**** Window destroyed while in place!\n");
  3190. DPF("****\n");
  3191. }
  3192. //Unregister the WM_DEVICECHANGE notification
  3193. DeviceChange_Cleanup();
  3194. WriteOutOptions();
  3195. CloseMCI(FALSE);
  3196. SetMenu(hwnd, NULL);
  3197. if (ghMenu)
  3198. DestroyMenu(ghMenu);
  3199. ghMenu = NULL;
  3200. WinHelp(hwnd, gszHelpFileName, HELP_QUIT, 0L);
  3201. PostQuitMessage(0);
  3202. if (IsWindow(ghwndFrame))
  3203. SetFocus(ghwndFrame);
  3204. else if (IsWindow(ghwndFocusSave))
  3205. SetFocus(ghwndFocusSave);
  3206. //Inform OLE that we are not taking any more calls.
  3207. if (gfOleInitialized)
  3208. {
  3209. #ifdef OLE1_HACK
  3210. if( gDocVersion == DOC_VERSION_OLE1 )
  3211. TerminateServer();
  3212. else
  3213. #endif /* OLE1_HACK */
  3214. /* Verify that the server was initialised by checking that one
  3215. * of the fields in docMain is non-null:
  3216. */
  3217. if( docMain.hwnd )
  3218. CoDisconnectObject((LPUNKNOWN)&docMain, 0);
  3219. else
  3220. DPF0("An instance of the server was never created.\n");
  3221. }
  3222. }
  3223. void MPlayer_OnTimer(HWND hwnd, UINT id)
  3224. {
  3225. MSG msg;
  3226. UpdateDisplay();
  3227. PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE);
  3228. }
  3229. #define MARK_START -1
  3230. #define MARK_NONE 0
  3231. #define MARK_END 1
  3232. void UpdateSelection(HWND hwnd, INT_PTR pos, int *pPrevMark)
  3233. {
  3234. INT_PTR SelStart;
  3235. INT_PTR SelEnd;
  3236. SelStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0);
  3237. SelEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
  3238. if (pos < SelStart)
  3239. {
  3240. SendMessage(hwnd, WM_COMMAND, IDT_MARKIN, 0);
  3241. *pPrevMark = MARK_START;
  3242. }
  3243. else if (pos > SelEnd)
  3244. {
  3245. SendMessage(hwnd, WM_COMMAND, IDT_MARKOUT, 0);
  3246. *pPrevMark = MARK_END;
  3247. }
  3248. else
  3249. {
  3250. if (*pPrevMark == MARK_START)
  3251. SendMessage(hwnd, WM_COMMAND, IDT_MARKIN, 0);
  3252. else
  3253. SendMessage(hwnd, WM_COMMAND, IDT_MARKOUT, 0);
  3254. }
  3255. }
  3256. void MPlayer_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)
  3257. {
  3258. DWORD_PTR dwPosition; /* player's current position in the medium*/
  3259. DWORD_PTR dwCurTime; /* Time a page up/down is last made */
  3260. TCHAR ach[60];
  3261. static int PrevMark;
  3262. /* If the media has no size, we can't seek. */
  3263. if (gdwMediaLength == 0L)
  3264. return;
  3265. dwPosition = SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0);
  3266. if (!gfScrollTrack) {
  3267. gfScrollTrack = TRUE;
  3268. /* If the shift key's being held down, make this the start
  3269. * of a selection:
  3270. */
  3271. if((GetKeyState(VK_SHIFT) < 0)
  3272. &&(toolbarStateFromButton(ghwndMark, BTN_MARKIN, TBINDEX_MARK)
  3273. != BTNST_GRAYED))
  3274. {
  3275. SendMessage(ghwndTrackbar, TBM_CLEARSEL, (WPARAM)TRUE, 0);
  3276. SendMessage(hwnd, WM_COMMAND, IDT_MARKIN, 0);
  3277. SetFocus(ghwndTrackbar); /* So that escape will go to
  3278. the trackbar's subclassed
  3279. winproc. */
  3280. }
  3281. sfSeekExact = SeekExactMCI(FALSE);
  3282. }
  3283. switch (code) {
  3284. /*
  3285. * Set the new position within the medium to be
  3286. * slightly before/after the current position if the
  3287. * left/right scroll arrow was clicked on.
  3288. */
  3289. case TB_LINEUP: /* left scroll arrow */
  3290. dwPosition -= (gwCurScale == ID_FRAMES) ? 1L : SCROLL_GRANULARITY;
  3291. break;
  3292. case TB_LINEDOWN: /* right scroll arrow */
  3293. dwPosition += (gwCurScale == ID_FRAMES) ? 1L : SCROLL_GRANULARITY;
  3294. break;
  3295. case TB_PAGEUP: /* page-left */
  3296. /*
  3297. * If the user just did a page-left a short time ago,
  3298. * then seek to the start of the previous track.
  3299. * Otherwise, seek to the start of this track.
  3300. *
  3301. */
  3302. if (gwCurScale != ID_TRACKS) {
  3303. dwPosition -= SCROLL_BIGGRAN;
  3304. } else {
  3305. dwCurTime = GetCurrentTime();
  3306. if (dwCurTime - dwLastPageUpTime < SKIPTRACKDELAY_MSEC)
  3307. SkipTrackMCI(-1);
  3308. else
  3309. SkipTrackMCI(0);
  3310. dwLastPageUpTime = dwCurTime;
  3311. goto BreakOut; // avoid SETPOS
  3312. }
  3313. break;
  3314. case TB_PAGEDOWN: /* page-right */
  3315. if (gwCurScale != ID_TRACKS) {
  3316. dwPosition += SCROLL_BIGGRAN;
  3317. } else {
  3318. /* Seek to the start of the next track */
  3319. SkipTrackMCI(1);
  3320. // Ensure next PageUp can't possibly do SkipTrackMCI(-1)
  3321. // which will skip back too far if you page
  3322. // left, right, left really quickly.
  3323. dwLastPageUpTime = 0;
  3324. goto BreakOut; // avoid SETPOS
  3325. }
  3326. break;
  3327. case TB_THUMBTRACK: /* track thumb movement */
  3328. //!!! we should do a "set seek exactly off"
  3329. /* Only seek while tracking for windowed devices that */
  3330. /* aren't currently playing */
  3331. if ((gwDeviceType & DTMCI_CANWINDOW) &&
  3332. !(gwStatus == MCI_MODE_PLAY)) {
  3333. SeekMCI(dwPosition);
  3334. }
  3335. break;
  3336. case TB_TOP:
  3337. dwPosition = gdwMediaStart;
  3338. break;
  3339. case TB_BOTTOM:
  3340. dwPosition = gdwMediaStart + gdwMediaLength;
  3341. break;
  3342. case TB_THUMBPOSITION: /* thumb has been positioned */
  3343. break;
  3344. case TB_ENDTRACK: /* user let go of scroll */
  3345. DPF2("TB_ENDTRACK\n");
  3346. gfScrollTrack = FALSE;
  3347. /* New as of 2/7/91: Only seek on ENDTRACK */
  3348. /*
  3349. * Calculate the new position in the medium
  3350. * corresponding to the scrollbar position, and seek
  3351. * to this new position.
  3352. *
  3353. */
  3354. /* We really want to update our position */
  3355. if (hwndCtl) {
  3356. if (gdwSeekPosition) {
  3357. dwPosition = gdwSeekPosition;
  3358. gdwSeekPosition = 0;
  3359. }
  3360. /* Go back to the seek mode we were in before */
  3361. /* we started scrolling. */
  3362. SeekExactMCI(sfSeekExact);
  3363. SeekMCI(dwPosition);
  3364. }
  3365. PrevMark = MARK_NONE;
  3366. return;
  3367. default:
  3368. return;
  3369. }
  3370. SendMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)dwPosition);
  3371. /* Clamp to a valid range */
  3372. dwPosition = SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0);
  3373. BreakOut:
  3374. if (GetKeyState(VK_SHIFT) < 0)
  3375. UpdateSelection(hwnd, dwPosition, &PrevMark);
  3376. if (ghwndStatic) {
  3377. FormatTime(dwPosition, NULL, ach, TRUE);
  3378. //VIJR-SBSetWindowText(ghwndStatic, ach);
  3379. WriteStatusMessage(ghwndStatic, ach);
  3380. }
  3381. // Dirty if you just move the thumb???
  3382. // if (!IsObjectDirty() && !gfCloseAfterPlaying) // don't want playing to dirty
  3383. // DirtyObject();
  3384. }
  3385. void MPlayer_OnSysCommand(HWND hwnd, UINT cmd, int x, int y)
  3386. {
  3387. RECT rc;
  3388. // The bottom four bits of wParam contain system information. They
  3389. // must be masked off in order to work out the actual command.
  3390. // See the comments section in the online help for WM_SYSCOMMAND.
  3391. switch (cmd & 0xFFF0) {
  3392. case SC_MINIMIZE:
  3393. DPF("minimized -- turn off timer\n");
  3394. ClrWS(hwnd, WS_MAXIMIZE);
  3395. EnableTimer(FALSE);
  3396. break;
  3397. case SC_MAXIMIZE:
  3398. if (gfPlayOnly && !IsIconic(hwnd)) {
  3399. (void)PostMessage(hwnd, WM_COMMAND, (WPARAM)IDM_ZOOM2, 0);
  3400. return;
  3401. }
  3402. break;
  3403. case SC_RESTORE:
  3404. if (gfPlayOnly && !IsIconic(hwnd)) {
  3405. GetWindowRect(hwnd, &rc);
  3406. if (rc.left > 0 || rc.top > 0)
  3407. (void)PostMessage(hwnd, WM_COMMAND, (WPARAM)IDM_ZOOM1, 0);
  3408. return;
  3409. }
  3410. if (gwDeviceID != (UINT)0) {
  3411. DPF("un-minimized -- turn timer back on\n");
  3412. EnableTimer(TRUE);
  3413. }
  3414. break;
  3415. }
  3416. FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, DefWindowProc);
  3417. }
  3418. int MPlayer_OnMouseActivate(HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT msg)
  3419. {
  3420. if (gfPlayingInPlace && !gfOle2IPPlaying)
  3421. return MA_NOACTIVATE;
  3422. else
  3423. /* !!! Is this the right thing to do in this case? */
  3424. return FORWARD_WM_MOUSEACTIVATE(hwnd, hwndTopLevel, codeHitTest, msg,
  3425. DefWindowProc);
  3426. }
  3427. UINT MPlayer_OnNCHitTest(HWND hwnd, int x, int y)
  3428. {
  3429. UINT Pos;
  3430. Pos = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc);
  3431. if (gfPlayingInPlace && (Pos == HTCLIENT))
  3432. Pos = HTNOWHERE;
  3433. return Pos;
  3434. }
  3435. void MPlayer_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized)
  3436. {
  3437. HWND hwndT;
  3438. gfAppActive = (state != WA_INACTIVE);
  3439. // Put the playback window BEHIND us so it's kinda
  3440. // visible, but not on top of us (annoying).
  3441. if (gfAppActive && !ghwndMCI && !IsIconic(hwnd) &&
  3442. ((hwndT = GetWindowMCI()) != NULL))
  3443. {
  3444. SetWindowPos(hwndT, hwnd, 0, 0, 0, 0,
  3445. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  3446. }
  3447. if (gwDeviceID != (UINT)0)
  3448. EnableTimer(TRUE);
  3449. /* Remember who had focus if we're being de-activated. */
  3450. /* Give focus back to him once we're re-activated. */
  3451. /* Don't remember a window that doesn't belong to us, */
  3452. /* or when we give focus back to it, we'll never be */
  3453. /* able to activate! */
  3454. #if 0
  3455. /* Commenting this out for now. This code looks dubious.
  3456. * wParam (as was) contains state and fMinimized, so, if we're minimized,
  3457. * it will always be non-null.
  3458. */
  3459. if (wParam && ghwndFocus) {
  3460. SetFocus(ghwndFocus);
  3461. } else if (!wParam) {
  3462. ghwndFocus = GetFocus();
  3463. }
  3464. #endif
  3465. FORWARD_WM_ACTIVATE(hwnd, state, hwndActDeact, fMinimized, DefWindowProc);
  3466. }
  3467. void MPlayer_OnSysColorChange(HWND hwnd)
  3468. {
  3469. ControlCleanup();
  3470. ControlInit(ghInst);
  3471. FORWARD_WM_SYSCOLORCHANGE(ghwndToolbar, SendMessage);
  3472. FORWARD_WM_SYSCOLORCHANGE(ghwndFSArrows, SendMessage);
  3473. FORWARD_WM_SYSCOLORCHANGE(ghwndMark, SendMessage);
  3474. FORWARD_WM_SYSCOLORCHANGE(ghwndTrackbar, SendMessage);
  3475. }
  3476. void MPlayer_OnDropFiles(HWND hwnd, HDROP hdrop)
  3477. {
  3478. doDrop(hwnd, hdrop);
  3479. }
  3480. LRESULT MPlayer_OnNotify(HWND hwnd, int idFrom, NMHDR FAR* pnmhdr)
  3481. {
  3482. LPTOOLTIPTEXT pTtt;
  3483. LPTBNOTIFY pTbn;
  3484. TCHAR ach[40];
  3485. switch(pnmhdr->code) {
  3486. case TTN_NEEDTEXT:
  3487. pTtt = (LPTOOLTIPTEXT)pnmhdr;
  3488. if (gfPlayOnly && (pTtt->hdr.idFrom != IDT_PLAY)
  3489. && (pTtt->hdr.idFrom != IDT_PAUSE)
  3490. && (pTtt->hdr.idFrom != IDT_STOP)
  3491. && !gfOle2IPEditing)
  3492. break;
  3493. switch (pTtt->hdr.idFrom) {
  3494. case IDT_PLAY:
  3495. case IDT_PAUSE:
  3496. case IDT_STOP:
  3497. case IDT_EJECT:
  3498. case IDT_HOME:
  3499. case IDT_END:
  3500. case IDT_FWD:
  3501. case IDT_RWD:
  3502. case IDT_MARKIN:
  3503. case IDT_MARKOUT:
  3504. case IDT_ARROWPREV:
  3505. case IDT_ARROWNEXT:
  3506. LOADSTRING(pTtt->hdr.idFrom, ach);
  3507. lstrcpy(pTtt->szText, ach);
  3508. break;
  3509. default:
  3510. *pTtt->szText = TEXT('\0');
  3511. break;
  3512. }
  3513. break;
  3514. case TBN_BEGINDRAG:
  3515. pTbn = (LPTBNOTIFY)pnmhdr;
  3516. if(pTbn->iItem == IDT_ARROWPREV || pTbn->iItem == IDT_ARROWNEXT)
  3517. SendMessage(ghwndFSArrows, WM_STARTTRACK, (WPARAM)pTbn->iItem, 0L);
  3518. else
  3519. SendMessage(ghwndToolbar, WM_STARTTRACK, (WPARAM)pTbn->iItem, 0L);
  3520. break;
  3521. case TBN_ENDDRAG:
  3522. pTbn = (LPTBNOTIFY)pnmhdr;
  3523. if(pTbn->iItem == IDT_ARROWPREV || pTbn->iItem == IDT_ARROWNEXT)
  3524. SendMessage(ghwndFSArrows, WM_ENDTRACK, (WPARAM)pTbn->iItem, 0L);
  3525. else
  3526. SendMessage(ghwndToolbar, WM_ENDTRACK, (WPARAM)pTbn->iItem, 0L);
  3527. break;
  3528. }
  3529. return 0;
  3530. }
  3531. ////////////////////////////////////////////////////////////////////////////////////////////
  3532. // * DeviceChange_Init
  3533. // First time initialization for WM_DEVICECHANGE messages
  3534. // This is specific to NT5
  3535. ////////////////////////////////////////////////////////////////////////////////////////////
  3536. BOOL DeviceChange_Init(HWND hWnd)
  3537. {
  3538. DEV_BROADCAST_DEVICEINTERFACE dbi;
  3539. dbi.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  3540. dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  3541. dbi.dbcc_reserved = 0;
  3542. dbi.dbcc_classguid = KSCATEGORY_AUDIO;
  3543. dbi.dbcc_name[0] = TEXT('\0');
  3544. MixerEventContext = RegisterDeviceNotification(hWnd,
  3545. (PVOID)&dbi,
  3546. DEVICE_NOTIFY_WINDOW_HANDLE);
  3547. if(!MixerEventContext)
  3548. return FALSE;
  3549. return TRUE;
  3550. }
  3551. ////////////////////////////////////////////////////////////////////////////////////////////
  3552. // * DeviceChange_Cleanup
  3553. // Unregister the device notification.
  3554. ////////////////////////////////////////////////////////////////////////////////////////////
  3555. void DeviceChange_Cleanup()
  3556. {
  3557. if (MixerEventContext) {
  3558. UnregisterDeviceNotification(MixerEventContext);
  3559. MixerEventContext = NULL;
  3560. }
  3561. return;
  3562. }
  3563. void DisplayNoMciDeviceError()
  3564. {
  3565. DWORD ErrorID;
  3566. if (!lstrcmpi(gachOpenExtension, aszKeyMID))
  3567. ErrorID = IDS_CANTPLAYMIDI;
  3568. else if (!lstrcmpi(gachOpenExtension, aszKeyAVI))
  3569. ErrorID = IDS_CANTPLAYVIDEO;
  3570. else if (!lstrcmpi(gachOpenExtension, aszKeyWAV))
  3571. ErrorID = IDS_CANTPLAYSOUND;
  3572. else
  3573. ErrorID = IDS_NOMCIDEVICES;
  3574. Error(ghwndApp, ErrorID);
  3575. }
  3576. /*
  3577. * MPlayerWndProc(hwnd, wMsg, wParam, lParam)
  3578. *
  3579. * This is the message processing routine for the MPLAYERBOX (main) dialog.
  3580. *
  3581. */
  3582. //Harmless message-cracker because the user guys will not fix their
  3583. //windowsx.h macro which cause the irritating rip.
  3584. //This is also a wee bit faster because the message
  3585. //is forwarded only on select and not on deselects. Also we do not care
  3586. //about the params
  3587. #define HANDLE_MPLAYER_WM_MENUSELECT(hwnd, message, fn) \
  3588. case (message): if(lParam) ((fn)((hwnd), (HMENU)(lParam), (UINT)LOWORD(wParam), 0L, 0L )); break;
  3589. LRESULT FAR PASCAL MPlayerWndProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  3590. {
  3591. switch (wMsg) {
  3592. HANDLE_MSG(hwnd, WM_CREATE, MPlayer_OnCreate);
  3593. HANDLE_MSG(hwnd, WM_SHOWWINDOW, MPlayer_OnShowWindow);
  3594. HANDLE_MSG(hwnd, WM_SIZE, MPlayer_OnSize);
  3595. HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, MPlayer_OnWindowPosChanging);
  3596. HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, MPlayer_OnWindowPosChanged);
  3597. HANDLE_MSG(hwnd, WM_PALETTECHANGED, MPlayer_OnPaletteChanged);
  3598. HANDLE_MSG(hwnd, WM_QUERYNEWPALETTE, MPlayer_OnQueryNewPalette);
  3599. HANDLE_MSG(hwnd, WM_CTLCOLORSTATIC, MPlayer_OnCtlColor);
  3600. HANDLE_MSG(hwnd, WM_WININICHANGE, MPlayer_OnWinIniChange);
  3601. HANDLE_MPLAYER_WM_MENUSELECT(hwnd, WM_MENUSELECT, MPlayer_OnMenuSelect);
  3602. HANDLE_MSG(hwnd, WM_NCLBUTTONDOWN, MPlayer_OnNCLButtonDown);
  3603. HANDLE_MSG(hwnd, WM_NCLBUTTONDBLCLK, MPlayer_OnNCLButtonDblClk);
  3604. HANDLE_MSG(hwnd, WM_INITMENU, MPlayer_OnInitMenu);
  3605. HANDLE_MSG(hwnd, WM_INITMENUPOPUP, MPlayer_OnInitMenuPopup);
  3606. HANDLE_MSG(hwnd, WM_GETMINMAXINFO, MPlayer_OnGetMinMaxInfo);
  3607. HANDLE_MSG(hwnd, WM_PAINT, MPlayer_OnPaint);
  3608. HANDLE_MSG(hwnd, WM_COMMAND, MPlayer_OnCommand);
  3609. HANDLE_MSG(hwnd, WM_CLOSE, MPlayer_OnClose);
  3610. HANDLE_MSG(hwnd, WM_ENDSESSION, MPlayer_OnEndSession);
  3611. HANDLE_MSG(hwnd, WM_DESTROY, MPlayer_OnDestroy);
  3612. HANDLE_MSG(hwnd, WM_TIMER, MPlayer_OnTimer);
  3613. HANDLE_MSG(hwnd, WM_HSCROLL, MPlayer_OnHScroll);
  3614. HANDLE_MSG(hwnd, WM_SYSCOMMAND, MPlayer_OnSysCommand);
  3615. HANDLE_MSG(hwnd, WM_MOUSEACTIVATE, MPlayer_OnMouseActivate);
  3616. HANDLE_MSG(hwnd, WM_NCHITTEST, MPlayer_OnNCHitTest);
  3617. HANDLE_MSG(hwnd, WM_ACTIVATE, MPlayer_OnActivate);
  3618. HANDLE_MSG(hwnd, WM_SYSCOLORCHANGE, MPlayer_OnSysColorChange);
  3619. HANDLE_MSG(hwnd, WM_DROPFILES, MPlayer_OnDropFiles);
  3620. HANDLE_MSG(hwnd, WM_NOTIFY, MPlayer_OnNotify);
  3621. /* Other bits of stuff that need tidying up sometime:
  3622. */
  3623. case WM_NOMCIDEVICES:
  3624. /* This was posted by the thread building the Device
  3625. * menu to tell us it couldn't find any MCI devices.
  3626. */
  3627. DisplayNoMciDeviceError();
  3628. PostMessage(ghwndApp, WM_CLOSE, 0, 0);
  3629. break;
  3630. case WM_GETDIB:
  3631. return (LRESULT)GetDib();
  3632. case WM_DEVICECHANGE :
  3633. {
  3634. //if plug-and-play sends this, pass it along to the component
  3635. PDEV_BROADCAST_DEVICEINTERFACE bid = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
  3636. //Check to see if this is a audio message
  3637. if (!MixerEventContext || !bid ||
  3638. bid->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE ||
  3639. !IsEqualGUID(&KSCATEGORY_AUDIO, &bid->dbcc_classguid) ||
  3640. !(*bid->dbcc_name))
  3641. {
  3642. break;
  3643. }
  3644. else
  3645. {
  3646. switch(wParam)
  3647. {
  3648. case DBT_DEVICEQUERYREMOVE:
  3649. CloseMCI(TRUE); //Close the MCI device
  3650. break;
  3651. case DBT_DEVICEREMOVECOMPLETE:
  3652. CloseMCI(TRUE); //Close the MCI device
  3653. break;
  3654. default:
  3655. break;
  3656. }
  3657. }
  3658. }
  3659. case WM_ENTERSIZEMOVE:
  3660. if (!IsIconic(hwnd) && !gfPlayOnly && !gfOle2IPEditing && !gfOle2IPPlaying)
  3661. {
  3662. /* Save the current window position in x, y, dx, dy format:
  3663. */
  3664. GetWindowRect(hwnd, (PRECT)&posSizeMove);
  3665. posSizeMove.cx -= posSizeMove.x;
  3666. posSizeMove.cy -= posSizeMove.y;
  3667. }
  3668. break;
  3669. case WM_EXITSIZEMOVE:
  3670. SetRectEmpty((PRECT)&posSizeMove);
  3671. break;
  3672. case WM_DOLAYOUT:
  3673. Layout();
  3674. break;
  3675. case WM_BADREG:
  3676. if ( IDYES == ErrorResBox(hwnd, NULL,
  3677. MB_YESNO | MB_ICONEXCLAMATION, IDS_APPNAME, IDS_BADREG) )
  3678. if (!SetRegValues())
  3679. Error(ghwndApp, IDS_FIXREGERROR);
  3680. break;
  3681. case WM_SEND_OLE_CHANGE:
  3682. fDocChanged = TRUE;
  3683. SendDocMsg((LPDOC)&docMain,OLE_CHANGED);
  3684. break;
  3685. case MM_MCINOTIFY:
  3686. #if 0
  3687. //
  3688. // don't do this because, some devices send notify failures
  3689. // where there really is not a error.
  3690. //
  3691. if ((WORD)wParam == MCI_NOTIFY_FAILURE) {
  3692. Error(ghwndApp, IDS_NOTIFYFAILURE);
  3693. }
  3694. #endif
  3695. UpdateDisplay();
  3696. break;
  3697. #ifdef OLE1_HACK
  3698. /* Actually do the FixLink, SetData and DoVerb we've been putting off */
  3699. /* for so long. */
  3700. case WM_DO_VERB:
  3701. /* This message comes from server.c (and goes back there too) */
  3702. DelayedFixLink(wParam, LOWORD(lParam), HIWORD(lParam)); //OK on NT. LKG
  3703. break;
  3704. #endif /* OLE1_HACK */
  3705. #ifdef LATER
  3706. // We'll need to call RegisterWindowMessage and provide a message hook proc
  3707. // for this on Win32.
  3708. case WM_HELP:
  3709. WinHelp(hwnd, TEXT("MPLAYER.HLP"), HELP_PARTIALKEY,
  3710. (DWORD)aszNULL);
  3711. return TRUE;
  3712. #endif /* LATER */
  3713. case WM_USER_DESTROY:
  3714. DPF("WM_USER_DESTROY received\n");
  3715. if (gfPlayingInPlace) {
  3716. DPF("****\n");
  3717. DPF("**** Window destroyed while in place!\n");
  3718. DPF("****\n");
  3719. EndPlayInPlace(hwnd);
  3720. }
  3721. if (gfOle2IPEditing) {
  3722. EndEditInPlace(hwnd);
  3723. }
  3724. if (!ItsSafeToClose()) {
  3725. DPF("*** \n");
  3726. DPF("*** Trying to destroy MPLAYER with an ErrorBox up\n");
  3727. DPF("*** \n");
  3728. gfErrorDeath = WM_USER_DESTROY;
  3729. return TRUE;
  3730. }
  3731. if (!gfRunWithEmbeddingFlag)
  3732. WriteOutPosition();
  3733. DestroyWindow(hwnd);
  3734. DestroyIcon(hiconApp);
  3735. return TRUE;
  3736. case WM_USER+500:
  3737. /*
  3738. ** This message is sent by the HookProc inside mciole32.dll when
  3739. ** it detects that it should stop playing in place of a WOW client
  3740. ** application.
  3741. **
  3742. ** Because the OleActivate originated in mciole16.dll,
  3743. ** mciole32.dll does not know the OLE Object that is being
  3744. ** played and therefore dose not know how to close that object.
  3745. ** Only mplay32.exe has the necessary information, hence
  3746. ** mciole32.dll sends this message to mplay32.exe.
  3747. */
  3748. if (gfPlayingInPlace) {
  3749. EndPlayInPlace(hwnd);
  3750. }
  3751. PostMessage( hwnd, WM_CLOSE, 0L, 0L );
  3752. break;
  3753. }
  3754. return DefWindowProc(hwnd, wMsg, wParam, lParam);
  3755. }
  3756. /* InitInstance
  3757. * ------------
  3758. *
  3759. * Create brushes used by the program, the main window, and
  3760. * do any other per-instance initialization.
  3761. *
  3762. * HANDLE hInstance
  3763. *
  3764. * RETURNS: TRUE if successful
  3765. * FALSE otherwise.
  3766. *
  3767. * CUSTOMIZATION: Re-implement
  3768. *
  3769. */
  3770. BOOL InitInstance (HANDLE hInstance)
  3771. {
  3772. HDC hDC;
  3773. static SZCODE aszNative[] = TEXT("Native");
  3774. static SZCODE aszEmbedSrc[] = TEXT("Embed Source");
  3775. static SZCODE aszObjDesc[] = TEXT("Object Descriptor");
  3776. static SZCODE aszMplayer[] = TEXT("mplayer");
  3777. static SZCODE aszClientDoc[] = TEXT("Client Document");
  3778. /* Why doesn't RegisterClipboardFormat return a value of type CLIPFORMAT (WORD)
  3779. * instead of UINT?
  3780. */
  3781. cfNative = (CLIPFORMAT)RegisterClipboardFormat (aszNative);
  3782. cfEmbedSource = (CLIPFORMAT)RegisterClipboardFormat (aszEmbedSrc);
  3783. cfObjectDescriptor = (CLIPFORMAT)RegisterClipboardFormat (aszObjDesc);
  3784. cfMPlayer = (CLIPFORMAT)RegisterClipboardFormat (aszMplayer);
  3785. szClient[0] = TEXT('\0');
  3786. lstrcpy (szClientDoc, aszClientDoc);
  3787. // Initialize global variables with LOGPIXELSX and LOGPIXELSY
  3788. hDC = GetDC (NULL); // Get the hDC of the desktop window
  3789. giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  3790. giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  3791. ReleaseDC (NULL, hDC);
  3792. return TRUE;
  3793. }
  3794. #define COINIT_APARTMENTTHREADED 2
  3795. /* InitOLE
  3796. *
  3797. * This should be called only when we're certain that OLE is needed,
  3798. * to avoid loading loads of unnecessary stuff.
  3799. *
  3800. */
  3801. BOOL InitOLE (PBOOL pfInit, LPMALLOC *ppMalloc)
  3802. {
  3803. HRESULT hr;
  3804. if (*pfInit)
  3805. return TRUE;
  3806. hr = (HRESULT)OleInitialize(NULL);
  3807. if (!SUCCEEDED (hr))
  3808. {
  3809. DPF0("OleInitialize failed with error 0x%08x\n", hr);
  3810. Error(NULL, IDS_OLEINIT);
  3811. return FALSE;
  3812. }
  3813. if (ppMalloc && (CoGetMalloc(MEMCTX_TASK, ppMalloc) != S_OK))
  3814. {
  3815. Error(NULL, IDS_OLENOMEM);
  3816. OleUninitialize();
  3817. return FALSE;
  3818. }
  3819. /*****************************************************************
  3820. ** OLE2NOTE: we must remember the fact that OleInitialize has
  3821. ** been called successfully. the very last thing an app must
  3822. ** do is properly shut down OLE by calling
  3823. ** OleUninitialize. This call MUST be guarded! it is only
  3824. ** allowable to call OleUninitialize if OleInitialize has
  3825. ** been called SUCCESSFULLY.
  3826. *****************************************************************/
  3827. *pfInit = TRUE;
  3828. return TRUE;
  3829. }
  3830. // This function cleans up all the OLE2 stuff. It lets the container
  3831. // save the object and informs that it is closing.
  3832. BOOL ExitApplication ()
  3833. {
  3834. DPFI("\n*******Exitapp\n");
  3835. // if we registered class factory, we must revoke it
  3836. if(gfOle2IPEditing || gfOle2IPPlaying)
  3837. DoInPlaceDeactivate((LPDOC)&docMain);
  3838. SendDocMsg((LPDOC)&docMain,OLE_CLOSED);
  3839. if (srvrMain.fEmbedding) {
  3840. HRESULT status;
  3841. srvrMain.fEmbedding = FALSE; // HACK--guard against revoking twice
  3842. status = (HRESULT)CoRevokeClassObject (srvrMain.dwRegCF);
  3843. }
  3844. return TRUE;
  3845. }
  3846. #ifdef DEBUG
  3847. /* DbgGlobalLock
  3848. *
  3849. * Debug wrapper for GlobalLock
  3850. *
  3851. * Checks that the memory handle to be locked isn't already locked,
  3852. * and checks the return code from GlobalLock.
  3853. *
  3854. * andrewbe, 1 March 1995
  3855. */
  3856. LPVOID DbgGlobalLock(HGLOBAL hglbMem)
  3857. {
  3858. LPVOID lpReturn;
  3859. if (GlobalFlags(hglbMem) & GMEM_LOCKCOUNT)
  3860. DPF0("Calling GlobalLock on already locked memory object %08x\n", hglbMem);
  3861. lpReturn = GlobalLock(hglbMem);
  3862. if (lpReturn == NULL)
  3863. DPF0("GlobalLock(%08x) failed: Error %d\n", hglbMem, GetLastError());
  3864. return lpReturn;
  3865. }
  3866. /* DbgGlobalUnlock
  3867. *
  3868. * Debug wrapper for GlobalUnlock
  3869. *
  3870. * Checks the return code from GlobalUnlock, and outputs appropriate
  3871. * error messages
  3872. *
  3873. * andrewbe, 1 March 1995
  3874. */
  3875. BOOL DbgGlobalUnlock(HGLOBAL hglbMem)
  3876. {
  3877. BOOL boolReturn;
  3878. boolReturn = GlobalUnlock(hglbMem);
  3879. if ((boolReturn) && (GlobalFlags(hglbMem) & GMEM_LOCKCOUNT))
  3880. {
  3881. DPF0("Locks still outstanding on memory object %08x\n", hglbMem);
  3882. }
  3883. else
  3884. {
  3885. DWORD Error = GetLastError();
  3886. if (Error == ERROR_NOT_LOCKED)
  3887. {
  3888. DPF0("Attempt to unlock already unlocked memory object %08x\n", hglbMem);
  3889. }
  3890. else if (Error != NO_ERROR)
  3891. {
  3892. DPF0("Error %d attempting to unlock memory object %08x\n", Error, hglbMem);
  3893. }
  3894. }
  3895. return boolReturn;
  3896. }
  3897. /* DbgGlobalFree
  3898. *
  3899. * Debug wrapper for GlobalFree.
  3900. *
  3901. * Checks that the global handle has no locks before freeing,
  3902. * then checks that the call succeeded. Error messages output
  3903. * as appropriate.
  3904. *
  3905. * andrewbe, 1 March 1995
  3906. *
  3907. */
  3908. HGLOBAL DbgGlobalFree(HGLOBAL hglbMem)
  3909. {
  3910. HGLOBAL hglbReturn;
  3911. if (GlobalFlags(hglbMem) & GMEM_LOCKCOUNT)
  3912. DPF0("Freeing global memory object %08x still locked\n", hglbMem);
  3913. hglbReturn = GlobalFree(hglbMem);
  3914. if (hglbReturn != NULL)
  3915. DPF0("GlobalFree(%08x) failed: Error %d\n", hglbMem, GetLastError());
  3916. return hglbReturn;
  3917. }
  3918. #ifdef UNICODE
  3919. /* Note: This function assumes that szFormat strings are NOT unicode.
  3920. * Unicode var params may, however, be passed, as long as %ws is specified
  3921. * in the format string.
  3922. */
  3923. #endif
  3924. void FAR cdecl dprintf(LPSTR szFormat, ...)
  3925. {
  3926. CHAR ach[_MAX_PATH * 3]; // longest I think we need
  3927. int s,d;
  3928. va_list va;
  3929. va_start(va, szFormat);
  3930. s = wvsprintfA(ach,szFormat, va);
  3931. va_end(va);
  3932. #if 0
  3933. strcat(ach,"\n");
  3934. s++;
  3935. #endif
  3936. for (d=sizeof(ach)-1; s>=0; s--)
  3937. {
  3938. if ((ach[d--] = ach[s]) == TEXT('\n'))
  3939. ach[d--] = TEXT('\r');
  3940. }
  3941. /* Not unicode */
  3942. if (*(ach+d+1) != ' ')
  3943. OutputDebugStringA("MPLAYER: ");
  3944. OutputDebugStringA(ach+d+1);
  3945. }
  3946. #endif