|
|
/*-----------------------------------------------------------------------------+
| MPLAYER.C | | | | This file contains the code that implements the "MPlayer" (main) dialog box. | | | | (C) Copyright Microsoft Corporation 1991. All rights reserved. | | | | Revision History | | Oct-1992 MikeTri Ported to WIN32 / WIN16 common code | | | +-----------------------------------------------------------------------------*/
/* include files */ #include "nocrap.h"
#include "stdio.h"
#include <windows.h>
#include <mmsystem.h>
#include <shellapi.h>
#include <windowsx.h>
#include <htmlhelp.h>
#include <tchar.h>
#define INCGUID
#include "mpole.h"
#include "mplayer.h"
#include "toolbar.h"
#include "fixreg.h"
#include "helpids.h"
//These include files for WM_DEVICECHANGE messages from the mixer
#include <dbt.h>
#include <cfgmgr32.h>
#include <initguid.h>
#include <mmddk.h>
#include <ks.h>
#include <ksmedia.h>
HDEVNOTIFY MixerEventContext = NULL; //Event Context for WM_DEVICECHANGE messages related to mixer
BOOL DeviceChange_Init(HWND hWnd); void DeviceChange_Cleanup();
//extern int FAR PASCAL ShellAbout(HWND hWnd, LPCTSTR szApp, LPCTSTR szOtherStuff, HICON hIcon);
/* in server.c, but not in a header file like it should be... */ extern PTSTR FAR FileName(LPCTSTR szPath);
/* globals */
// Used in converting units from pixels to Himetric and vice-versa
int giXppli = 0; // pixels per logical inch along width
int giYppli = 0; // pixels per logical inch along height
// Since this is a not an MDI app, there can be only one server and one doc.
CLSID clsid; SRVR srvrMain; DOC docMain; LPMALLOC lpMalloc;
TCHAR szClient[cchFilenameMax]; TCHAR szClientDoc[cchFilenameMax];
// Has the user made changes to the document?
BOOL fDocChanged = FALSE;
/*********************************************************************
** OLE2NOTE: the very last thing an app must be do is properly shut ** down OLE. This call MUST be guarded! it is only allowable to ** call OleUninitialize if OleInitialize has been called. *********************************************************************/
// Has OleInitialize been called? assume not.
BOOL gfOleInitialized = FALSE;
// Clipboard formats
CLIPFORMAT cfNative; CLIPFORMAT cfEmbedSource; CLIPFORMAT cfObjectDescriptor; CLIPFORMAT cfMPlayer;
LPWSTR sz1Ole10Native = L"\1Ole10Native";
/* in server.c, but not in a header file like it should be... */ extern LPTSTR FAR FileName(LPCTSTR szPath); /* in init.c */ extern PTSTR gpchFilter; //extern HMREGNOTIFY ghmrn;
/* globals */
DWORD gwPlatformId; UINT gwPlaybarHeight=TOOLBAR_HEIGHT;/* Taken from server.c */ UINT gwOptions; /* The object options from the dlg box */ BOOL gfEmbeddedObject; // TRUE if editing embedded OLE object
BOOL gfRunWithEmbeddingFlag; // TRUE if we are run with "-Embedding"
BOOL gfPlayingInPlace; // TRUE if playing in place
BOOL gfParentWasEnabled; // TRUE if parent was enabled
BOOL gfShowWhilePlaying; //
BOOL gfDirty; //
int gfErrorBox; // TRUE if we have a message box active
BOOL gfErrorDeath; BOOL gfWinIniChange;
HHOOK hHookMouse; // Mouse hook handle.
HOOKPROC fpMouseHook; // Mouse hook proc address.
HWND ghwndFocusSave; // saved focus window
BOOL gfOpenDialog = FALSE; // If TRUE, put up open dialog
BOOL gfCloseAfterPlaying = FALSE;// TRUE if we are to hide after play
HICON hiconApp; /* app icon */ HMENU ghMenu; /* handle to the dialog's main menu */ HMENU ghDeviceMenu; /* handle to the Device popup menu */ HWND ghwndApp; /* handle to the MPlayer (main) dialog box*/ HWND ghwndMap; /* handle to the track map window */ HWND ghwndStatic; /* handle to the static text window */ HBRUSH ghbrFillPat; /* The selection fill pattern. */ HWND ghwndToolbar; /* handle of the toolbar */ HWND ghwndMark; /* handle of the mark buttons toolbar */ HWND ghwndFSArrows; /* handle of the arrows to the scrollbar */ HWND ghwndTrackbar; /* handle to the trackbar window */ UINT gwStatus = (UINT)(-1); /* device status (if <gwDeviceID> != NULL)*/ DWORD gdwSeekPosition; /* Place to seek to next */ BOOL gfValidMediaInfo; /* are we displaying valid media info? */ BOOL gfValidCaption; /* are we displaying a valid caption? */ BOOL gfScrollTrack; /* is user dragging the scrollbar thumb? */ BOOL gfPlayOnly; /* play only window? */ BOOL gfJustPlayed = FALSE; /* Just sent a PlayMCI() command */ BOOL gfJustPlayedSel = FALSE; /* Just sent a ID_PLAYSEL command. */ BOOL gfUserStopped = FALSE; /* user pressed stop - didn't happen itslf*/ DWORD_PTR dwLastPageUpTime; /* time of last page-left operation */ UINT gwCurScale = ID_NONE; /* current scale style */ LONG glSelStart = -1; /* See if selection changes (dirty object)*/ LONG glSelEnd = -1; /* See if selection changes (dirty object)*/
int gInc; /* how much to inc/dec spin arrows by */
BOOL gfAppActive = FALSE; /* Are we the active application? */ UINT gwHeightAdjust; HWND ghwndFocus = NULL; /* Who had the focus when we went inactive*/ BOOL gfInClose = FALSE; /* ack?*/ BOOL gfCurrentCDChecked = FALSE; /* TRUE if we've checked whether it can play */ BOOL gfCurrentCDNotAudio = FALSE;/* TRUE when we have a CD that we can't play */
extern BOOL gfInPlayMCI;
LPDATAOBJECT gpClipboardDataObject = NULL; /* If non-NULL, call OleFlushClipboard on exit */
HPALETTE ghpalApp;
static sfSeekExact; // last state
UINT gwCurDevice = 0; /* current device */ UINT gwNumDevices = 0; /* number of available media devices */ MCIDEVICE garMciDevices[MAX_MCI_DEVICES]; /* array with info about a device */
/* strings which get loaded in InitMplayerDialog in init.c, English version shown here
All the sizes are much larger than needed, probably. Maybe could save nearly 100 bytes!! :) */ extern TCHAR gszFrames[40]; /* "frames" */ extern TCHAR gszHrs[20]; /* "hrs" */ extern TCHAR gszMin[20]; /* "min" */ extern TCHAR gszSec[20]; /* "sec" */ extern TCHAR gszMsec[20]; /* "msec" */
static SZCODE aszNULL[] = TEXT(""); static BOOL sfInLayout = FALSE; // don't let Layout get re-entered
static SZCODE szSndVol32[] = TEXT("sndvol32.exe");
static SZCODE aszTitleFormat[] = TEXT("%"TS" - %"TS"");
HANDLE ghInst; /* handle to the application instance */ HFONT ghfontMap; /* handle to the font used for drawing
the track map */ LPTSTR gszCmdLine; /* string holding the command line parms */ int giCmdShow; /* command show */ TCHAR gachFileDevice[MAX_PATH]; /* string holding the curr file or device */ TCHAR gachWindowTitle[MAX_PATH]; /* string holding name we will display */ TCHAR gachCaption[MAX_PATH]; /* string holding name we will display */
HACCEL hAccel; int gcAccelEntries;
typedef struct _POS { int x; int y; int cx; /* This field is non-0 if we're currently sizing/moving */ int cy; } POS, *PPOS;
POS posSizeMove = {0,0,0,0}; /* POS we want during size/move operations */
STRING_TO_ID_MAP DevToIconIDMap[] = { { szCDAudio, IDI_DCDA }, { szVideoDisc, IDI_DDEFAULT }, { szSequencer, IDI_DMIDI }, { szVCR, IDI_DDEFAULT }, { szWaveAudio, IDI_DSOUND }, { szAVIVideo, IDI_DVIDEO } };
//CDA file processing///////////////////////////////////////////////////
//The following structure taken from deluxecd. This is used in processing
typedef struct { DWORD dwRIFF; // 'RIFF'
DWORD dwSize; // Chunk size = (file size - 8)
DWORD dwCDDA; // 'CDDA'
DWORD dwFmt; // 'fmt '
DWORD dwCDDASize; // Chunk size of 'fmt ' = 24
WORD wFormat; // Format tag
WORD wTrack; // Track number
DWORD DiscID; // Unique disk id
DWORD lbnTrackStart; // Track starting sector (LBN)
DWORD lbnTrackLength; // Track length (LBN count)
DWORD msfTrackStart; // Track starting sector (MSF)
DWORD msfTrackLength; // Track length (MSF)
} RIFFCDA;
void HandleCDAFile(TCHAR *szFile); BOOL IsTrackFileNameValid(LPTSTR lpstFileName, UINT *pUiTrackIndex); void JumpToCDTrack(UINT trackno);
////////////////////////////////////////////////////////////////////////
/* private function prototypes */
//int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int iCmdShow);
void CleanUpClipboard(); int GetHeightAdjust(HWND hwnd); HANDLE PASCAL GetDib (VOID);
static HHOOK fpfnOldMsgFilter; static HOOKPROC fpfnMsgHook; //Data used for supporting context menu help
BOOL bF1InMenu=FALSE; //If true F1 was pressed on a menu item.
UINT currMenuItem=0; //The current menu item if any.
typedef void (FAR PASCAL *PENWINREGISTERPROC)(UINT, BOOL);
/* Define some constants to make parameters to CreateEvent a tad less obscure:
*/ #define EVENT_DEFAULT_SECURITY NULL
#define EVENT_RESET_MANUAL TRUE
#define EVENT_RESET_AUTOMATIC FALSE
#define EVENT_INITIAL_STATE_SIGNALED TRUE
#define EVENT_INITIAL_STATE_NOT_SIGNALED FALSE
#define EVENT_NO_NAME NULL
HANDLE heventCmdLineScanned; /* Event will be signaled when command line scanned */ HANDLE heventDeviceMenuBuilt; /* Event will be signaled when device menu complete */
#ifdef LATER
SCALE gscaleInitXY[2] = { 0, 0, 0, 0 }; // Initial scale to use for inserting OLE objects
#endif
/*------------------------------------------------------+
| HelpMsgFilter - filter for F1 key in dialogs | | | +------------------------------------------------------*/
DWORD FAR PASCAL HelpMsgFilter(int nCode, DWORD_PTR wParam, DWORD_PTR lParam) { if (nCode >= 0){ LPMSG msg = (LPMSG)lParam;
if ((msg->message == WM_KEYDOWN) && (msg->wParam == VK_F1)) { if(nCode == MSGF_MENU) bF1InMenu = TRUE; SendMessage(ghwndApp, WM_COMMAND, (WPARAM)IDM_HELPTOPICS, 0L); } } // return DefHookProc(nCode, wParam, lParam, (HHOOK FAR *)&fpfnOldMsgFilter);
return 0; }
#ifdef CHICAGO_PRODUCT
BOOL IsBadSegmentedCodePtr(LPARAM lpPtr) { #define DSC_PRESENT 0x80
#define DSC_CODE_BIT 0x08
#define DSC_RW_BIT 0x02
#define DSC_DISCARDABLE 0x10
WORD wSel; WORD wOff; BOOL fRet;
wSel = HIWORD(lpPtr); wOff = LOWORD(lpPtr);
_asm { mov ax, [wSel]; lar bx, ax; jnz ValidDriverCallback_Failure ; //Return TRUE for error
mov ch, DSC_CODE_BIT or DSC_RW_BIT or DSC_PRESENT ; and bh, ch; cmp bh, ch; jne ValidDriverCallback_Failure ; //Not executable segment
test bl, DSC_DISCARDABLE ; jnz ValidDriverCallback_Failure ; //Not fixed segment
lsl cx, ax; ; //Get segment limit
mov bx, [wOff]; cmp bx, cx; jb ValidDriverCallback_Success ; //Valid offset
jne ValidDriverCallback_Failure ; //Not executable segment
ValidDriverCallback_Failure: mov eax, 1; jmp ValidDriverCallback_Return; ValidDriverCallback_Success: xor eax, eax; ValidDriverCallback_Return: mov [fRet], eax; } return fRet; }
#endif
/* RouteKeyPresses
* * Reroutes cursor keys etc to track bar. */ void RouteKeyPresses(PMSG pMsg) { /* Hack for PowerPoint
* * Mail from PaulWa: * * -------- * Here's a problem you might consider fixing. * Launching Media Player with certain keystrokes * doesn't work right (e.g. arrow keys, page up/down, * etc.). * * The problem is due to the fact that Media Player * handles key up events. We use the key down event * to launch the server in slideshow, but then the key * up event is passed to the server. It would probably * be best for Media Player to ignore key up events * unless it had previously received a key down. * If this is very difficult to fix in Media Player, * then we can fix it in PP by launching servers on * key up rather than key down. However, other container * apps will see the same problem. * -------- * * OK, in the spirit of cooperation, let's hack things * so our PowerPoint friends can carry on with their * dubious practices. */ static WPARAM LastVKeyDown;
/* On key down when we're embedded, remember what is was:
*/ if (gfRunWithEmbeddingFlag && (pMsg->message == WM_KEYDOWN)) LastVKeyDown = pMsg->wParam;
/* Don't reroute if it's a key up that doesn't match
* the last key down; this effectively ignores it: */ if (gfRunWithEmbeddingFlag && (pMsg->message == WM_KEYUP) && (pMsg->wParam != LastVKeyDown)) { DPF0("Ignoring WM_KEYUP, since it doesn't match last WM_KEYDOWN.\n"); } else { switch(pMsg->wParam) { case VK_UP: case VK_LEFT: case VK_DOWN: case VK_RIGHT: case VK_NEXT: case VK_PRIOR: case VK_HOME: case VK_END: pMsg->hwnd = ghwndTrackbar; break;
default: break; } }
if (pMsg->message == WM_KEYUP) LastVKeyDown = 0; }
/*
* WinMain(hInst, hPrev, szCmdLine, iCmdShow) * * This is the main procedure for the application. It performs initialization * and then enters a message-processing loop, where it remains until it * receives a WM_QUIT message (meaning the app was closed). This function * always returns TRUE.. * */ int WINAPI WinMain( HINSTANCE hInst /* handle to the current instance of the application */ , HINSTANCE hPrev /* handle to the previous instance of the application */ , LPSTR szCmdLine /* null-terminated string holding the command line params */ , int iCmdShow /* how the window should be initially displayed */ ) { MSG rMsg; /* variable used for holding a message */ HWND hwndFocus; HWND hwndP;
/* call the Pen Windows extensions to allow them to subclass our
edit controls if they so wish */
OSVERSIONINFO OSVersionInfo;
#ifdef UNICODE
LPTSTR szUnicodeCmdLine;
szUnicodeCmdLine = AllocateUnicodeString(szCmdLine); #endif
heventCmdLineScanned = CreateEvent( EVENT_DEFAULT_SECURITY, EVENT_RESET_MANUAL, EVENT_INITIAL_STATE_NOT_SIGNALED, EVENT_NO_NAME );
heventDeviceMenuBuilt = CreateEvent( EVENT_DEFAULT_SECURITY, EVENT_RESET_MANUAL, EVENT_INITIAL_STATE_NOT_SIGNALED, EVENT_NO_NAME );
if (!heventCmdLineScanned || !heventDeviceMenuBuilt) return FALSE;
OSVersionInfo.dwOSVersionInfoSize = sizeof OSVersionInfo;
GetVersionEx(&OSVersionInfo);
gwPlatformId = OSVersionInfo.dwPlatformId;
giCmdShow = iCmdShow;
#ifdef UNICODE
if (!AppInit(hInst,hPrev,szUnicodeCmdLine)) #else
if (!AppInit(hInst,hPrev,szCmdLine)) #endif
return FALSE;
/* Device Menu Initialization:
* * If the user has requested an Open dialog (by supplying the /open * flag with no file name), we've already built the Device menu, * since the list of devices is required up front. * * If we're just playing in tiny mode, we don't need the device list. * It will be built if the user switches to full mode and then accesses * the Device menu or selects File.Open. * * Otherwise go for it. The main window's already up now, so we * can build the list on a background thread. Don't forget to wait * for the event to be signaled when the appropriate menu is accessed. */ if (!gfOpenDialog && !gfPlayOnly) InitDeviceMenu();
#ifdef UNICODE
// ScanCmdLine mangles it, so forget it
// FreeUnicodeString(szUnicodeCmdLine);
#endif
/* setup the message filter to handle grabbing F1 for this task */ fpfnMsgHook = (HOOKPROC)MakeProcInstance((FARPROC)HelpMsgFilter, ghInst); fpfnOldMsgFilter = (HHOOK)SetWindowsHook(WH_MSGFILTER, fpfnMsgHook);
#ifdef DEBUG
GdiSetBatchLimit(1); #endif
for (;;) { /* If we're ever still around after being destroyed, DIE! */ if (!IsWindow(ghwndApp)) break;
/* call the server code and let it unblock the server */ #ifdef OLE1_HACK
ServerUnblock(); #endif /* OLE1_HACK */
/* Polling messages from event queue */
if (!GetMessage(&rMsg, NULL, 0, 0)) break;
if (gfPlayingInPlace) {
// If focus ever gets to the client during play in place,
// be really nasty and force focus to us. (Aldus BUG!!!!)
// Aldus Persuasion won't play in place without this.
hwndFocus = GetFocus(); hwndP = GetParent(ghwndApp);
if (!ghwndIPHatch && hwndFocus && hwndP && GetWindowTask(hwndP) == GetWindowTask(hwndFocus)) PostCloseMessage(); }
/* Hack: post END_SCROLL messages with lParam == -1 */
if ((rMsg.hwnd==ghwndApp) || (rMsg.hwnd && GetParent(rMsg.hwnd)==ghwndApp)) { /* Reroute arrow keys etc to track bar:
*/ if (rMsg.message == WM_KEYDOWN || rMsg.message == WM_KEYUP) RouteKeyPresses(&rMsg); }
if (IsWindow(ghwndApp)) {
if (gfRunWithEmbeddingFlag && docMain.lpIpData && docMain.lpIpData->lpFrame && !IsAccelerator(hAccel, gcAccelEntries, &rMsg, NULL) && OleTranslateAccelerator(docMain.lpIpData->lpFrame, &docMain.lpIpData->frameInfo, &rMsg) == NOERROR) { continue; }
if (hAccel && TranslateAccelerator(ghwndApp, hAccel, &rMsg)) continue;
}
if (rMsg.message == WM_TIMER && rMsg.hwnd == NULL) { #ifdef CHICAGO_PRODUCT
/* The reason for requiring the following test is now lost
* in the mists of time. Now this app is 32-bit, these * bogus timer callbacks (if they really do still occur) * could be 16-bit, so we need to add yet more ugliness * in the form of assembler to an app which is already * hardly a paragon of pulchritude. * * A plea: * * If you add some obscure code such as below, to this or * any other app, even if it has only the teeniest chance * of being less blindingly obvious to someone else than * it is to you at the time of writing, please please please * add a f***ing comment. * * Respectfully, * A Developer */ if (IsBadSegmentedCodePtr(rMsg.lParam)) #else
if (IsBadCodePtr((FARPROC)rMsg.lParam)) #endif /* ~CHICAGO_PRODUCT */
{ DPF0("Bad function pointer (%08lx) in WM_TIMER message\n", rMsg.lParam); rMsg.message = WM_NULL; } } if (rMsg.message == WM_SYSCOMMAND && (((0xFFF0 & rMsg.wParam) == SC_MOVE)|| ((0xFFF0 & rMsg.wParam) == SC_SIZE)) ) { // If ANY window owned by our thread is going into a modal
// size or move loop then we need to force some repainting to
// take place. The cost of not doing so is that garbage can
// be left lying around on the trackbar, e.g. bits of system
// menu, or partially drawn sliders.
UpdateWindow(ghwndApp); } TranslateMessage(&rMsg); DispatchMessage(&rMsg); }
ghwndApp = NULL;
/* Delete the track map font that we created earlier. */
if (ghfontMap != NULL) { DeleteObject(ghfontMap); ghfontMap = NULL; }
if (ghbrFillPat) DeleteObject(ghbrFillPat);
if (ghpalApp) DeleteObject(ghpalApp);
/* if the message hook was installed, remove it and free */ /* up our proc instance for it. */ if (fpfnOldMsgFilter){ UnhookWindowsHook(WH_MSGFILTER, fpfnMsgHook); }
ControlCleanup();
// TermServer();
/*********************************************************************
** OLE2NOTE: the very last thing an app must be do is properly shut ** down OLE. This call MUST be guarded! it is only allowable to ** call OleUninitialize if OleInitialize has been called. *********************************************************************/
// Clean shutdown for OLE
DPFI("*before oleunint"); if (gfOleInitialized) { if (gpClipboardDataObject) CleanUpClipboard(); (void)OleUninitialize(); IMalloc_Release(lpMalloc); lpMalloc = NULL; gfOleInitialized = FALSE; }
if (hOLE32) FreeLibrary(hOLE32);
/* End of program */
return((int)rMsg.wParam); }
void CleanUpClipboard() { /* Check whether the DATAOBJECT we put on the clipboard is still there:
*/ if (OleIsCurrentClipboard(gpClipboardDataObject) == S_OK) { LPDATAOBJECT pIDataObject;
if (OleGetClipboard(&pIDataObject) == S_OK) { OleFlushClipboard(); IDataObject_Release(pIDataObject); } else { DPF0("OleGetClipboard failed\n"); } } else { if(ghClipData) GLOBALFREE(ghClipData); if(ghClipMetafile) GLOBALFREE(ghClipMetafile); if(ghClipDib) GLOBALFREE(ghClipDib); } }
//
// cancel any active menus and close the app.
//
void PostCloseMessage() { HWND hwnd;
hwnd = GetWindowMCI(); if (hwnd != NULL) SendMessage(hwnd, WM_CANCELMODE, 0, 0); SendMessage(ghwndApp, WM_CANCELMODE, 0, 0); PostMessage(ghwndApp, WM_CLOSE, 0, 0); }
//
// If we have a dialog box up (gfErrorBox is set) or we're disabled (we have
// a dialog box up) or the MCI device's default window is disabled (it has a
// dialog box up) then closing us would result in our deaths.
//
BOOL ItsSafeToClose(void) { HWND hwnd;
if (gfErrorBox) return FALSE; if (!IsWindowEnabled(ghwndApp)) return FALSE; hwnd = GetWindowMCI(); if (hwnd && !IsWindowEnabled(hwnd)) return FALSE;
return TRUE; }
/* ResolveLink
* * This routine is called when the user drags and drops a shortcut * onto Media Player. If it succeeds, it returns the full path * of the actual file in szResolved. */ BOOL ResolveLink(LPTSTR szPath, LPTSTR szResolved, LONG cbSize) { IShellLink *psl = NULL; HRESULT hres;
if (!InitOLE(&gfOleInitialized, &lpMalloc)) { DPF0("Initialization of OLE FAILED!! Can't resolve link.\n"); return FALSE; }
hres = (HRESULT)CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC, &IID_IShellLink, &psl);
if (SUCCEEDED(hres)) { IPersistFile *ppf;
psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf);
if (ppf) { WCHAR wszPath[MAX_PATH]; #ifdef UNICODE
lstrcpy (wszPath, szPath); #else
AnsiToUnicodeString(szPath, wszPath, UNKNOWN_LENGTH); #endif
hres = ppf->lpVtbl->Load(ppf, wszPath, 0); ppf->lpVtbl->Release(ppf);
if (FAILED(hres)) { psl->lpVtbl->Release(psl); psl = NULL; } } else { psl->lpVtbl->Release(psl); psl = NULL; } }
if (psl) { psl->lpVtbl->Resolve(psl, NULL, SLR_NO_UI); psl->lpVtbl->GetPath(psl, szResolved, cbSize, NULL, 0); psl->lpVtbl->Release(psl); }
return SUCCEEDED(hres); }
/* ResolveIfLink
* * Called to check whether a given file name is a shortcut * on Windows 95. * * Copies the resolved file name into the buffer provided, * overwriting the original name. * * Returns TRUE if the function succeeded, whether or not the * file name was changed. FALSE indicates that an error occurred. * * Andrew Bell, 16 February 1995 */ BOOL ResolveIfLink(PTCHAR szFileName) { SHFILEINFO sfi; BOOL rc = TRUE;
if ((SHGetFileInfo(szFileName, 0, &sfi, sizeof sfi, SHGFI_ATTRIBUTES) == 1) && ((sfi.dwAttributes & SFGAO_LINK) == SFGAO_LINK)) { TCHAR szResolvedLink[MAX_PATH];
if (ResolveLink(szFileName, szResolvedLink, CHAR_COUNT(szResolvedLink))) lstrcpy(szFileName, szResolvedLink); else rc = FALSE; }
return rc; }
/* JumpToCDTrack()
* * Jumps to the appropriate track on the CD and updates the UI accordingly * */ void JumpToCDTrack(UINT trackno) { //If the track number is invalid just ignore.
//Let the default behaviour take place, There is no need to give a message box
//saying we couldn't jump to track.
if(trackno > gwNumTracks) return;
/* We MUST use PostMessage because the */ /* SETPOS and ENDTRACK must happen one */ /* immediately after the other */ PostMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, gadwTrackStart[trackno]); PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_ENDTRACK, (LPARAM)ghwndTrackbar); }
/*****************************Private*Routine******************************\
* IsTrackFileNameValid * * This routine copied from deluxecd and modified * * This function returns true if the specified filename is a valid CD track.
* On NT track filenames must be of the form: * d:\track(n).cda where d: is the CD-Rom device and \track(n).cda * is the index of the track to be played (starting from 1). * * On Chicago the track filename is actually a riff CDDA file which contains * the track info that we require. * * If the filename is valid the function true and sets * piTrackIndex to the correct value. * * History: * 29-09-94 - StephenE - Created * \**************************************************************************/ BOOL IsTrackFileNameValid( LPTSTR lpstFileName, UINT *puiTrackIndex ) { #define RIFF_RIFF 0x46464952
#define RIFF_CDDA 0x41444443
RIFFCDA cda; HANDLE hFile; int i; DWORD cbRead; BOOL fRead; // Open file and read in CDA info
hFile = CreateFile (lpstFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (INVALID_HANDLE_VALUE == hFile) { return FALSE; } ZeroMemory (&cda, sizeof (cda)); fRead = ReadFile(hFile, &cda, sizeof(cda), &cbRead, NULL); CloseHandle (hFile);
if (!fRead) return FALSE;
//
// Make sure its a RIFF CDDA file
//
if ( (cda.dwRIFF != RIFF_RIFF) || (cda.dwCDDA != RIFF_CDDA) ) { return FALSE; }
*puiTrackIndex = cda.wTrack - 1;
return TRUE; }
/* HandleCDAFile()
* * Checks to see if the opened file is a CDA file and tries to jump to the appropriate track. * */ void HandleCDAFile(TCHAR *szFile) { UINT trackno; if(IsTrackFileNameValid(szFile, &trackno)) { JumpToCDTrack(trackno); } }
/* Process file drop/drag options. */ void PASCAL NEAR doDrop(HWND hwnd, HDROP hDrop) { RECT rc;
if(DragQueryFile(hDrop,(UINT)(~0),NULL,0)){/* # of files dropped */ TCHAR szPath[MAX_PATH];
/* If user dragged/dropped a file regardless of keys pressed
* at the time, open the first selected file from file * manager. */ DragQueryFile(hDrop,0,szPath,sizeof(szPath)/sizeof(TCHAR)); SetActiveWindow(hwnd);
ResolveIfLink(szPath);
if (OpenMciDevice(szPath, NULL)) { SubClassMCIWindow(); PostMessage(hwnd, WM_COMMAND, (WPARAM)ID_PLAY, 0); DirtyObject(FALSE); // we're dirty now!
gfCloseAfterPlaying = FALSE; // stay up from now on
//If the CD Audio device was opened it must have been a *.cda file.
//Try to jump to the track corresponding to the file opened.
if ((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO) { HandleCDAFile(szPath); } } else { gwCurDevice = 0;// force next file open dialog to say
// "all files" because CloseMCI won't.
gwCurScale = ID_NONE; // uncheck all scale types
Layout(); // Make window snap back to smaller size
}
SetMPlayerIcon();
/* Force WM_GETMINMAXINFO to be called so we'll snap to a */ /* proper size. */ GetWindowRect(ghwndApp, &rc); MoveWindow(ghwndApp, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); } DragFinish(hDrop); /* Delete structure alocated for WM_DROPFILES*/ }
/* Change the number in dwPosition to the proper format. szNum contains the */ /* formatted number only "01 45:10" while szBuf contains units such as */ /* "01 45:10 (min:sec)" */ /* If fRound is set, it will not always display millisecond accuracy, but */ /* choose something useful like second accuracy or hundreth sec accuracy. */ void FAR PASCAL FormatTime(DWORD_PTR dwPosition, LPTSTR szNum, LPTSTR szBuf, BOOL fRound) { UINT w; UINT hrs; UINT min; UINT sec; UINT hsec; UINT msec; DWORD dwMaxSize = gdwMediaLength; static TCHAR framestr[40] = TEXT(""); static TCHAR sec_str[40] = TEXT(""); static TCHAR min_str[40] = TEXT(""); static TCHAR hrs_str[40] = TEXT(""); static TCHAR msec_str[40] = TEXT("");
static SZCODE aszLongDecimal[] = TEXT("%ld"); static SZCODE aszFrameFormat[] = TEXT("%"TS" %ld"); static SZCODE asz02Decimal[] = TEXT("%02d "); static SZCODE aszTimeFormat1[] = TEXT("%02d%c%02d%c%02d"); static SZCODE aszTimeFormat2[] = TEXT("%02d%c%02d%c%02d%c%03d"); static SZCODE aszTimeFormat3[] = TEXT("%02d%c%02d%c%02d (%"TS"%c%"TS"%c%"TS")"); static SZCODE aszTimeFormat4[] = TEXT("%02d%c%02d%c%02d%c%03d (%"TS"%c%"TS"%c%"TS"%c%"TS")"); static SZCODE aszTimeFormat5[] = TEXT("%02d%c%02d"); static SZCODE aszTimeFormat6[] = TEXT("%02d%c%02d%c%03d"); static SZCODE aszTimeFormat7[] = TEXT("%02d%c%02d (%"TS"%c%"TS")"); static SZCODE aszTimeFormat8[] = TEXT("%02d%c%02d%c%03d (%"TS"%c%"TS"%c%"TS")"); static SZCODE aszTimeFormat9[] = TEXT("%c%02d"); static SZCODE aszTimeFormat10[] = TEXT("%c%03d"); static SZCODE aszTimeFormat11[] = TEXT("%02d%c%03d"); static SZCODE aszTimeFormat12[] = TEXT("%c%02d (%"TS")"); static SZCODE aszTimeFormat13[] = TEXT("%02d%c%02d (%"TS")"); static SZCODE aszTimeFormat14[] = TEXT("%c%03d (%"TS"%c%"TS")"); static SZCODE aszTimeFormat15[] = TEXT("%02d%c%03d (%"TS"%c%"TS")");
//!!! LoadStrings at init time, dont hardcode...
#define ONE_HOUR (60ul*60ul*1000ul)
#define ONE_MINUTE (60ul*1000ul)
#define ONE_SECOND (1000ul)
if (szBuf) *szBuf = 0; if (szNum) *szNum = 0;
if (gwDeviceID == (UINT)0) return;
if (gwStatus == MCI_MODE_NOT_READY || gwStatus == MCI_MODE_OPEN) return;
switch (gwCurScale) {
case ID_FRAMES: if (!STRLEN(framestr)) LOADSTRING(IDS_FRAME,framestr); if (szNum) wsprintf(szNum, aszLongDecimal, (long)dwPosition); if (szBuf) wsprintf(szBuf, aszFrameFormat, framestr, (long)dwPosition); gInc = 1; // spin arrow inc/dec by one frame
break;
case ID_TRACKS: //
// find the track that contains this position
// also, find the longest track so we know if we should display
// hh:mm:ss or mm:ss or ss.sss or whatever.
//
if (gwNumTracks == 0) return;
dwMaxSize = 0;
for (w=0; w<gwNumTracks-1; w++) {
if (gadwTrackStart[w+1] - gadwTrackStart[w] > dwMaxSize) dwMaxSize = gadwTrackStart[w+1] - gadwTrackStart[w];
/* When a CD is stopped, it's still spinning, and after we */ /* seek to the beginning of a track, it may return a value */ /* slightly less than the track start everyonce in a while.*/ /* So if we're within 200ms of the track start, let's just */ /* pretend we're exactly on the start of the track. */
if (dwPosition < gadwTrackStart[w+1] && gadwTrackStart[w+1] - dwPosition < 200) dwPosition = gadwTrackStart[w+1];
if (gadwTrackStart[w+1] > dwPosition) break; }
if (szNum) { wsprintf(szNum, asz02Decimal, gwFirstTrack + w); szNum += 3; } if (szBuf) { wsprintf(szBuf, asz02Decimal, gwFirstTrack + w); szBuf += 3; }
dwPosition -= gadwTrackStart[w];
for (; w < gwNumTracks - 1; w++) { if (gadwTrackStart[w+1] - gadwTrackStart[w] > dwMaxSize) dwMaxSize = gadwTrackStart[w+1] - gadwTrackStart[w]; }
// fall through
case ID_TIME: if (!STRLEN(sec_str)) { LOADSTRING(IDS_SEC,sec_str); LOADSTRING(IDS_HRS,hrs_str); LOADSTRING(IDS_MIN,min_str); LOADSTRING(IDS_MSEC,msec_str); }
min = (UINT)((dwPosition / ONE_MINUTE) % 60); sec = (UINT)((dwPosition / ONE_SECOND) % 60); msec = (UINT)(dwPosition % 1000);
if (dwMaxSize > ONE_HOUR) {
hrs = (UINT)(dwPosition / ONE_HOUR);
if (szNum && fRound) { wsprintf(szNum, aszTimeFormat1, hrs, chTime, min, chTime, sec); } else if (szNum) { wsprintf(szNum, aszTimeFormat2, hrs, chTime, min, chTime, sec, chDecimal, msec); }
if (szBuf && fRound) { wsprintf(szBuf, aszTimeFormat3, hrs, chTime, min, chTime, sec, hrs_str, chTime, min_str, chTime, sec_str); } else if (szBuf) { wsprintf(szBuf, aszTimeFormat4, hrs, chTime, min, chTime, sec, chDecimal, msec, hrs_str,chTime, min_str,chTime, sec_str, chDecimal, msec_str); }
gInc = 1000; // spin arrow inc/dec by seconds
} else if (dwMaxSize > ONE_MINUTE) {
if (szNum && fRound) { wsprintf(szNum, aszTimeFormat5, min, chTime, sec); } else if (szNum) { wsprintf(szNum, aszTimeFormat6, min, chTime, sec, chDecimal, msec); }
if (szBuf && fRound) { wsprintf(szBuf, aszTimeFormat7, min, chTime, sec, min_str,chTime,sec_str); } else if (szBuf) { wsprintf(szBuf, aszTimeFormat8, min, chTime, sec, chDecimal, msec, min_str,chTime,sec_str, chDecimal, msec_str); }
gInc = 1000; // spin arrow inc/dec by seconds
} else {
hsec = (UINT)((dwPosition % 1000) / 10);
if (szNum && fRound) { if (!sec && chLzero == TEXT('0')) wsprintf(szNum, aszTimeFormat9, chDecimal, hsec); else wsprintf(szNum, aszTimeFormat5, sec, chDecimal, hsec);
} else if (szNum) { if (!sec && chLzero == TEXT('0')) wsprintf(szNum, aszTimeFormat10, chDecimal, msec); else wsprintf(szNum, aszTimeFormat11, sec, chDecimal, msec); }
if (szBuf && fRound) { if (!sec && chLzero == TEXT('0')) wsprintf(szBuf, aszTimeFormat12, chDecimal, hsec, sec_str); else wsprintf(szBuf, aszTimeFormat13, sec, chDecimal, hsec, sec_str);
} else if (szBuf) { if (!sec && chLzero == TEXT('0')) wsprintf(szBuf, aszTimeFormat14, chDecimal, msec, sec_str,chDecimal,msec_str); else wsprintf(szBuf, aszTimeFormat15, sec, chDecimal, msec, sec_str,chDecimal,msec_str); }
gInc = 100; // spin arrow inc/dec by 1/10 second
} } }
BOOL IsCdromDataOnly();
BOOL UpdateWindowText(HWND hwnd, LPTSTR Text) { TCHAR CurrentText[80];
GetWindowText(hwnd, CurrentText, CHAR_COUNT(CurrentText));
if(lstrcmp(Text, CurrentText)) return SetWindowText(hwnd, Text); else return TRUE; }
/*
* UpdateDisplay() * * Update the scrollbar, buttons, etc. If the media information (media * length, no. tracks, etc.) is not currently valid, then update it first. * * The following table shows how the current status (value of <gwStatus>) * affects which windows are enabled: * * Play Pause Stop Eject * MCI_MODE_STOP ENABLE n/a ENABLE * MCI_MODE_PAUSE ENABLE n/a ENABLE ENABLE * MCI_MODE_PLAY n/a ENABLE ENABLE ENABLE * MCI_MODE_OPEN n/a ENABLE * MCI_MODE_RECORD ?????? ?????? ?????? ?????? * MCI_MODE_SEEK ENABLE n/a ENABLE ENABLE * * MCI_MODE_NOT_READY ALL DISABLED * * The eject button is always enabled if the medium can be ejected and * disabled otherwise. * * In open mode, either Play or Eject will cause the media door to close, * but Play will also begin play. In any mode, Eject always does an * implicit Stop first. * * If <gwDeviceID> is NULL, then there is no current device and all four * of these buttons are disabled. * */ void FAR PASCAL UpdateDisplay(void) { DWORD_PTR dwPosition; /* the current position within the medium */ UINT wStatusMCI; /* status of the device according to MCI */ #if 0
TOOLBUTTON tb; #endif
static BOOL sfBlock = FALSE; // keep SeekMCI from causing infinite loop
/* Don't even think about updating the display if the trackbar's scrolling: */ if (gfScrollTrack) return;
/* We've been re-entered */ if (sfBlock) return;
/*
* if for some reason we were closed, close now! */ if (gfErrorDeath) { DPF("*** Trying to close window now!\n"); PostMessage(ghwndApp, gfErrorDeath, 0, 0); return; }
/*
* If the track information is not valid (e.g. a CD was just inserted), * then update it. * */
if (!gfValidMediaInfo) UpdateMCI(); /* update the appropriate global variables*/
/*
* Determine the current position and status ( stopped, playing, etc. ) * as MCI believes them to be. * */
wStatusMCI = StatusMCI(&dwPosition);
/* The deal here is that the user can insert CDs, any of which may not be
* playable because they contain no audio tracks. So, as soon as we detect * that we have a CD we haven't checked, make sure we can play it. * If the current device is CD, and the door isn't open, check it. * */ if (((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO) && (wStatusMCI != MCI_MODE_OPEN)) { if (!gfCurrentCDChecked) { if (IsCdromDataOnly()) { gfCurrentCDNotAudio = TRUE; gwCurScale = ID_NONE; Error(ghwndApp, IDS_INSERTAUDIODISC); } else gfCurrentCDNotAudio = FALSE;
gfCurrentCDChecked = TRUE; } } else { gfCurrentCDChecked = FALSE; // Otherwise, make sure it gets cleared.
gfCurrentCDNotAudio = FALSE; }
/* Here's the problem: If the medium is short, we'll send a Play command */ /* but it'll stop before we notice it was ever playing. So if we know */ /* that we just sent a PlayMCI command, but the status isn't PLAY, then */ /* force the last command to be PLAY. Also, once we notice we are playing*/ /* we can clear gfJustPlayed. */
if (wStatusMCI == MCI_MODE_PLAY && gfJustPlayed) gfJustPlayed = FALSE; if (((wStatusMCI == MCI_MODE_STOP) || (wStatusMCI == MCI_MODE_SEEK)) && gfJustPlayed) { gwStatus = MCI_MODE_PLAY; gfJustPlayed = FALSE; }
if (wStatusMCI == MCI_MODE_SEEK) { // The second major problem is this. During rewind the status
// is SEEK. If we detect MODE_SEEK we will not restart the play,
// and it looks like the auto replay simply ended. Seeking back to
// the beginning can take a significant amount of time. We allow
// ourselves to wait for up to half a second to give the device,
// particularly AVI from a CD or over the network, a chance to
// catch up. Any slower response and the autorepeat will terminate.
dwPosition = gdwLastSeekToPosition; if (!gfUserStopped && (gwOptions&OPT_AUTOREP)) { UINT n=15; for (; n; --n) {
Sleep(32); // If autorepeating and device is seeking, try the status
// again in case it has got back to the beginning
wStatusMCI = StatusMCI(&dwPosition);
if (wStatusMCI != MCI_MODE_SEEK) { wStatusMCI = MCI_MODE_STOP; break; // Exit the FOR loop
} else { dwPosition = gdwLastSeekToPosition; } } } }
/*
* The current device status has * changed from the way MPlayer last perceived it, so update the display * and make MPlayer agree with MCI again. * */
// After we close, our last timer msg must gray stuff and execute this //
if (!gwDeviceID || wStatusMCI != gwStatus) { DWORD dwEndMedia, dwStartSel, dwEndSel, dwEndSelDelta;
/* Auto-repeat and Rewind happen if you stop at the end of the media */ /* (rewind to beginning) or if you stop at the end of the selection */ /* (rewind to beginning of selection). */
dwEndMedia = MULDIV32(gdwMediaLength + gdwMediaStart, 99, 100L); dwStartSel = (DWORD)SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0); dwEndSel = (DWORD)SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0); if (dwEndSel != -1) { dwEndSelDelta = MULDIV32(dwEndSel, 99, 100L); } else { dwEndSelDelta = 0; // force (dwPosition >= dwEndSelDelta) to FALSE
}
if ((wStatusMCI == MCI_MODE_STOP || wStatusMCI == MCI_MODE_PAUSE) && ((dwPosition >= dwEndMedia) || (dwPosition==0) || (dwPosition >= dwEndSelDelta && gfJustPlayedSel)) && dwPosition >= gdwMediaStart // dwPosition may == the beginning
&& !gfScrollTrack && (gwStatus == MCI_MODE_PLAY || gwStatus == MCI_MODE_SEEK)) {
DPF("End of medium\n");
/* We're at the end of the entire media or at the end of */ /* our selection now, and stopped automatically (not */ /* by the user). We were playing or seeking. So */ /* we can check the Auto Repeat and Auto Rewind flags. */ /* CD players seem to return a length that's too big, so */ /* we check for > 99% done. Use semaphore to keep from */ /* causing an infinite loop. */
if (!gfUserStopped && (gwOptions & OPT_AUTOREP)) { DPF("Auto-Repeat\n"); sfBlock = TRUE; // calls UpdateDisplay which will
// re-enter this code just before mode
/* Repeat either the selection or whole thing. */ /* NOTE: Must send message while gwStatus is STOPPED.*/
gwStatus = wStatusMCI; // old status no longer valid
if (gfJustPlayedSel && dwPosition >= dwEndSelDelta) { SeekMCI(dwStartSel); // MCICDA doen't go to start w/out this.
SendMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAYSEL, 0); } else { SeekToStartMCI(); SendMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAY, 0); }
sfBlock = FALSE; // switches to SEEK.
gwStatus = (UINT)(-1); // old status no longer valid
return; // because we are switching modes
} else if (!gfCloseAfterPlaying && !gfUserStopped && (gwOptions & OPT_AUTORWD)) { DPF("Auto-Rewind to media start\n"); //
// set gwStatus so SeekMCI will just seek!
sfBlock = TRUE; // calls UpdateDisplay which will
// re-enter this code just before mode
// switches to SEEK.
/* Rewind either the selection or whole thing. */ gwStatus = wStatusMCI; // or SeekMCI will play, too.
if (gfJustPlayedSel && dwPosition >= dwEndSelDelta) { SeekMCI(dwStartSel); } else { SeekToStartMCI(); } sfBlock = FALSE; gwStatus = (UINT)(-1); // old status no longer valid
return; // because we are switching modes
} else if (gfCloseAfterPlaying) PostCloseMessage(); }
/*
* Enable or disable the various controls according to the new status, * following the rules given in the header to this function. * */
EnableWindow(ghwndTrackbar, TRUE); // Good to always have something enabled
/* Show status bar if full mplayer and if device loaded */ if (ghwndStatic && !gfPlayOnly) { if (IsWindowVisible(ghwndStatic) != (gwDeviceID ? TRUE : FALSE)) { ShowWindow(ghwndStatic, gwDeviceID ? SW_SHOW : SW_HIDE); InvalidateRect(ghwndApp, NULL, TRUE); } }
if (gwDeviceID != (UINT)0 ) {
switch (wStatusMCI) { case MCI_MODE_PLAY: toolbarSetFocus(ghwndToolbar,BTN_PAUSE); break;
case MCI_MODE_PAUSE: case MCI_MODE_STOP: toolbarSetFocus(ghwndToolbar,BTN_PLAY); break; } }
if (wStatusMCI == MCI_MODE_OPEN || wStatusMCI == MCI_MODE_NOT_READY || gwDeviceID == (UINT)0 || ((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO) && gfCurrentCDNotAudio) { /* Try to modify both -- one of them should work */
toolbarModifyState(ghwndToolbar, BTN_PLAY, TBINDEX_MAIN, BTNST_GRAYED); toolbarModifyState(ghwndToolbar, BTN_PAUSE, TBINDEX_MAIN, BTNST_GRAYED);
toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, BTNST_GRAYED); toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, BTNST_GRAYED); toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, BTNST_GRAYED); toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, BTNST_GRAYED);
SendMessage(ghwndTrackbar, TBM_SETRANGEMIN, (WPARAM)FALSE, 0); SendMessage(ghwndTrackbar, TBM_SETRANGEMAX, (WPARAM)FALSE, 0); SendMessage(ghwndTrackbar, TBM_CLEARTICS, (WPARAM)FALSE, 0); SendMessage(ghwndTrackbar, TBM_CLEARSEL, (WPARAM)TRUE, 0);
if (ghwndMark) { toolbarModifyState(ghwndMark, BTN_MARKIN, TBINDEX_MARK, BTNST_GRAYED); toolbarModifyState(ghwndMark, BTN_MARKOUT, TBINDEX_MARK, BTNST_GRAYED); }
if (ghwndFSArrows) { toolbarModifyState(ghwndFSArrows, ARROW_NEXT, TBINDEX_ARROWS, BTNST_GRAYED); toolbarModifyState(ghwndFSArrows, ARROW_PREV, TBINDEX_ARROWS, BTNST_GRAYED); }
/* Enable transport and Mark buttons if we come from a state where */ /* they were gray. Layout will then re-gray the ones that */ /* shouldn't have been enabled because they don't fit. */ } else if (gwStatus == MCI_MODE_OPEN || gwStatus == MCI_MODE_NOT_READY || gwStatus == -1 ) {
/* Only one of these buttons exists */ toolbarModifyState(ghwndToolbar, BTN_PLAY, TBINDEX_MAIN, BTNST_UP); toolbarModifyState(ghwndToolbar, BTN_PAUSE, TBINDEX_MAIN, BTNST_UP);
if (!gfPlayOnly || gfOle2IPEditing) { toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, BTNST_UP); toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, BTNST_UP); toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, BTNST_UP); toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, BTNST_UP);
if (ghwndMark) { toolbarModifyState(ghwndMark, BTN_MARKIN, TBINDEX_MARK, BTNST_UP); toolbarModifyState(ghwndMark, BTN_MARKOUT, TBINDEX_MARK, BTNST_UP); } if (ghwndFSArrows) { toolbarModifyState(ghwndFSArrows, ARROW_PREV, TBINDEX_ARROWS, BTNST_UP); toolbarModifyState(ghwndFSArrows, ARROW_NEXT, TBINDEX_ARROWS, BTNST_UP); } } /* AND we need to call layout to gray the buttons that are too
* short to fit in this window right now. */ Layout(); }
//
// always have the stop button if we are playing in place
//
if ((gwDeviceID != (UINT)0) && (wStatusMCI == MCI_MODE_PAUSE || wStatusMCI == MCI_MODE_PLAY || wStatusMCI == MCI_MODE_SEEK || gfPlayingInPlace)) {
if (toolbarStateFromButton(ghwndToolbar, BTN_STOP, TBINDEX_MAIN) == BTNST_GRAYED) toolbarModifyState(ghwndToolbar, BTN_STOP, TBINDEX_MAIN, BTNST_UP);
} else { toolbarModifyState(ghwndToolbar, BTN_STOP, TBINDEX_MAIN, BTNST_GRAYED); }
if (!gfPlayOnly || gfOle2IPEditing) { if ((gwDeviceID != (UINT)0) && (gwDeviceType & DTMCI_CANEJECT)) toolbarModifyState(ghwndToolbar, BTN_EJECT, TBINDEX_MAIN, BTNST_UP); else toolbarModifyState(ghwndToolbar, BTN_EJECT, TBINDEX_MAIN, BTNST_GRAYED);
EnableWindow(ghwndMap, (gwDeviceID != (UINT)0)); }
// WHO had the idea that setting focus back to play every
// time the status changes was a good idea ??
/* Only set focus if we won't take activation by doing so */ //VIJRif (gfAppActive) {
if (wStatusMCI == MCI_MODE_NOT_READY) { //if (gfAppActive)
//SetFocus(ghwndToolbar); //Setting focus messes up menu access
//using the ALT key
} else if (wStatusMCI != MCI_MODE_SEEK && gwStatus != MCI_MODE_SEEK) { if (wStatusMCI == MCI_MODE_PLAY) { //VIJR SetFocus(ghwndToolbar); // give focus to PAUSE button
toolbarSetFocus(ghwndToolbar, BTN_PAUSE); } else { //VIJR SetFocus(ghwndToolbar); // give focus to PLAY button
toolbarSetFocus(ghwndToolbar, BTN_PLAY); if (wStatusMCI == MCI_MODE_OPEN || wStatusMCI == MCI_MODE_NOT_READY || gwDeviceID == (UINT)0) { /* Try to modify both -- one of them should work */ toolbarModifyState(ghwndToolbar, BTN_PLAY, TBINDEX_MAIN, BTNST_GRAYED); } } } //VIJR}
if (wStatusMCI == MCI_MODE_OPEN || gwStatus == MCI_MODE_OPEN || gwStatus == MCI_MODE_NOT_READY || wStatusMCI == MCI_MODE_NOT_READY) {
/* Either the medium was just ejected, or it was just
* re-inserted -- in either case, the media information (length, * # of tracks, etc.) is currently invalid and needs to be updated. */
gfValidMediaInfo = FALSE; }
/*
* Set <gwStatus> to agree with what MCI tells us, and update the * display accordingly. * */
gwStatus = wStatusMCI; gfValidCaption = FALSE; }
/*
* The previous code may have invalidated the Media again, so we'll update * now instead of waiting for the next UpdateDisplay call. * */
if (!gfValidMediaInfo) UpdateMCI(); /* update the appropriate global variables*/
/* If the caption is not valid, then update it */
if (!gfValidCaption) {
TCHAR ach[_MAX_PATH * 2 + 60]; // string used for the window caption
TCHAR achWhatToPrint[_MAX_PATH * 2 + 40]; // room for doc title too
if (gfPlayOnly) { if (gwDeviceID == (UINT)0) lstrcpy(ach, gachAppName); /* just use the app name */ else lstrcpy(ach, gachWindowTitle); /* just use device */ } else { /* Latest style guide says title bars should have
* <object> - <appname>, so do that for anything * other than NT: */ if (gwPlatformId == VER_PLATFORM_WIN32_NT) wsprintf(achWhatToPrint, aszTitleFormat, gachAppName, gachWindowTitle); else wsprintf(achWhatToPrint, aszTitleFormat, gachWindowTitle, gachAppName);
if (gwDeviceID == (UINT)0) { lstrcpy(ach, gachAppName); /* just display the app name */ } else if (gwStatus == MCI_MODE_NOT_READY) { wsprintf(ach, aszNotReadyFormat, achWhatToPrint); /* the current file / device */ } else { wsprintf(ach, aszReadyFormat, achWhatToPrint, /* the current file / device */ MapModeToStatusString((WORD)wStatusMCI)); } }
if (gfEmbeddedObject) { if (!SetTitle((LPDOC)&docMain, szClientDoc)) UpdateWindowText(ghwndApp, ach);
SetMPlayerIcon();
} else { UpdateWindowText(ghwndApp, ach); }
gfValidCaption = TRUE;
}
/* Update the scrollbar thumb position unless the user is dragging it */ /* or the media is current seeking to a previously requested position. */
if (!gfScrollTrack && gfValidMediaInfo && wStatusMCI != MCI_MODE_SEEK) { TCHAR ach[40]; if (ghwndStatic) { FormatTime(dwPosition, NULL, ach, TRUE); WriteStatusMessage(ghwndStatic, ach); } SendMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, dwPosition); }
/* Finish any required window painting immediately */
if (gfOle2IPEditing && wStatusMCI == MCI_MODE_STOP && ((gwDeviceType & DTMCI_DEVICE) == DTMCI_AVIVIDEO)) { RedrawWindow(ghwndTrackbar, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } UpdateWindow(ghwndApp); }
/*
* EnableTimer(fEnable) * * Enable the display-update timer if <fEnable> is TRUE. * Disable the timer if <fEnable> is FALSE. * */
void FAR PASCAL EnableTimer(BOOL fEnable) { DPF("EnableTimer(%d) %dms\n", fEnable, gfAppActive ? UPDATE_MSEC : UPDATE_INACTIVE_MSEC);
if (fEnable) SetTimer(ghwndApp, UPDATE_TIMER, gfAppActive ? UPDATE_MSEC : UPDATE_INACTIVE_MSEC, NULL); else KillTimer(ghwndApp, UPDATE_TIMER); }
void FAR PASCAL Layout(void) { RECT rcClient, rc; int iYOffset; UINT wWidth; UINT wFSArrowsWidth = 2 * FSARROW_WIDTH - 1; // 2 arrow buttons wide
UINT wFSArrowsHeight = FSARROW_HEIGHT; UINT wFSTrackHeight = FSTRACK_HEIGHT; UINT wFSTrackWidth; UINT wToolbarWidth; UINT wMinStatusWidth = 0; int iYPosition; BOOL fShowMark; BOOL fShowTrackbar; BOOL fShowStatus; HDWP hdwp; int nState; // The status of the transport buttons (when visible)
DWORD_PTR dw; // the current position within the medium
UINT wStatusMCI; // status of the device according to MCI
UINT wBaseUnits; BOOL fRedrawFrame; SIZE StatusTextExtent; BOOL fRepaintToolbar; // TRUE if we remove or add something to toolbar area
/* OK to execute if we're hidden to set ourselves up for being shown */
if (sfInLayout || IsIconic(ghwndApp)) return;
if (gfInPlayMCI) { DPF("Layout() called when in PlayMCI(). Posting message to Layout() later.\n"); /* Don't allow this to happen, because Layout() may cause a call to
* MCI_PUT (via SetWindowPos(ghwndMCI)), which will result in a * device-not-ready error, as the MCI_PLAY hasn't completed. */ PostMessage(ghwndApp, WM_DOLAYOUT, 0, 0); return; }
sfInLayout = TRUE;
#ifdef DEBUG
GetWindowRect(ghwndApp, &rc); DPF("***** Layout Window Rect ***** %d %d\n", rc.right - rc.left, rc.bottom - rc.top); #endif
if (gfPlayOnly) {
extern UINT gwPlaybarHeight; // in server.c
#define XSLOP 0
#define XOFF 2
if (gfOle2IPEditing || gfOle2IPPlaying) { /* Don't call GetClientrect, because the window may have a border,
* and this will cause us to shrink the window. * Note this is a hack to get around the problem of the window * changing size when it is in place, making some displays dither * the video in a disgusting manner. */ GetWindowRect(ghwndApp, &rc); rc.right -= rc.left; rc.bottom -= rc.top; rc.left = rc.top = 0; } else GetClientRect(ghwndApp, &rc);
rc.bottom -= gwPlaybarHeight;
#if 0
/* If we set WS_MAXIMIZE, user doesn't allow the window to be
* sized on NT. What's the idea behind this code anyway? */
if (ghwndMCI && !EqualRect(&rc, &grcSize)) fRedrawFrame = SetWS(ghwndApp, WS_MAXIMIZE /* |WS_MAXIMIZEBOX */); else if (ghwndMCI) fRedrawFrame = //SetWS(ghwndApp, WS_MAXIMIZEBOX) ||
ClrWS(ghwndApp, WS_MAXIMIZE); else fRedrawFrame = ClrWS(ghwndApp, WS_MAXIMIZEBOX); #endif
fRedrawFrame = FALSE;
/* Here's another horrible hack.
* When you try to Play an in-place video after an Open (OLE), * the toolbar and trackbar don't get drawn correctly. * I haven't figured out why this is, but forcing a redraw * seems to fix it. This code gets executed only when the window * position changes, so it isn't too much of a hit. */ if (gfOle2IPEditing || gfOle2IPPlaying) fRedrawFrame = TRUE;
if (fRedrawFrame) SetWindowPos(ghwndApp, NULL, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
if (ghwndMCI) SetWindowPos(ghwndMCI, NULL, 0, 0, rc.right, rc.bottom, SWP_NOZORDER|SWP_NOACTIVATE);
// If we are inplace editing place controls on the ghwndIPToolWindow
// and the static window at the bottom of ghwndApp.
if(gfOle2IPEditing) {
SendMessage(ghwndTrackbar, TBM_SHOWTICS, TRUE, FALSE);
SetWindowPos(ghwndStatic, NULL, 3, rc.bottom + 2 + (gwPlaybarHeight - TOOLBAR_HEIGHT)/2, rc.right - rc.left - 8, TOOLBAR_HEIGHT-7, SWP_NOZORDER|SWP_NOACTIVATE);
// Why are we getting the Status here when we have a global that
// contains it? Because gwStatus is set in UpdateDisplay, but
// Layout() is called by UpdateDisplay, so the global is not always
// set properly when this code runs. BUT! We must NOT pass a string
// to StatusMCI() or it will think UpdateDisplay() called it, and
// not tell UpdateDisplay() the proper mode next time it asks for it,
// because it will think that it already knows it.
wStatusMCI = StatusMCI(NULL); nState = (wStatusMCI == MCI_MODE_OPEN || wStatusMCI == MCI_MODE_NOT_READY || gwDeviceID == (UINT) 0) ? BTNST_GRAYED : BTNST_UP;
toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, nState); toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, nState); toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, nState); toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, nState);
ShowWindow(ghwndTrackbar, SW_SHOW); ShowWindow(ghwndToolbar, SW_SHOW); ShowWindow(ghwndStatic, SW_SHOW); ShowWindow(ghwndFSArrows, SW_SHOW); ShowWindow(ghwndMark, SW_SHOW); ShowWindow(ghwndMap, SW_SHOW);
if (ghwndIPToolWindow && (ghwndIPToolWindow != GetParent(ghwndTrackbar)) && (ghwndIPScrollWindow != GetParent(ghwndTrackbar))) { SetParent(ghwndTrackbar,ghwndIPToolWindow); SetWindowPos(ghwndTrackbar, NULL,4,TOOL_WIDTH+2, 11*BUTTONWIDTH+3,FSTRACK_HEIGHT,SWP_NOZORDER | SWP_NOACTIVATE); SetParent(ghwndMap,ghwndIPToolWindow); SetWindowPos(ghwndMap, NULL,4,TOOL_WIDTH+FSTRACK_HEIGHT+2+2, 11*BUTTONWIDTH+50,MAP_HEIGHT,SWP_NOZORDER | SWP_NOACTIVATE); } CalcTicsOfDoom();
} else {
#define LEFT_MARGIN 1
SendMessage(ghwndTrackbar, TBM_SHOWTICS, FALSE, FALSE);
SetWindowPos(ghwndToolbar, NULL, LEFT_MARGIN, rc.bottom + 2 + (gwPlaybarHeight - TOOLBAR_HEIGHT)/2, XSLOP + 2 * (BUTTONWIDTH - XOFF), TOOLBAR_HEIGHT, SWP_NOZORDER|SWP_NOACTIVATE);
SetWindowPos(ghwndTrackbar, NULL, XSLOP + 2 * (BUTTONWIDTH - XOFF) + LEFT_MARGIN, rc.bottom + (gwPlaybarHeight - TOOLBAR_HEIGHT)/2 + 1, rc.right-rc.left-(2 * XSLOP + 2 *(BUTTONWIDTH - XOFF) - LEFT_MARGIN), TOOLBAR_HEIGHT - 1, SWP_NOZORDER | SWP_NOACTIVATE);
// HACK!!!
// If we aren't visible, officially disable ourselves so that the
// trackbar shift code won't try and set selection
ShowWindow(ghwndTrackbar, gwPlaybarHeight > 0 ? SW_SHOW : SW_HIDE); ShowWindow(ghwndToolbar, gwPlaybarHeight > 0 ? SW_SHOW : SW_HIDE); ShowWindow(ghwndStatic, SW_HIDE); ShowWindow(ghwndFSArrows, SW_HIDE); ShowWindow(ghwndMark, SW_HIDE); ShowWindow(ghwndMap, SW_HIDE); }
goto Exit_Layout; }
fRedrawFrame = ClrWS(ghwndApp, WS_MAXIMIZEBOX);
if (fRedrawFrame) SetWindowPos(ghwndApp, NULL, 0, 0, 0, 0, SWP_DRAWFRAME| SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
if (GetMenu(ghwndApp) != ghMenu) SetMenu(ghwndApp, ghMenu);
wBaseUnits = LOWORD(GetDialogBaseUnits()); // prop. to size of system font
/* If we're bigger than we're allowed to be then shrink us right now */ GetWindowRect(ghwndApp, &rc);
gwHeightAdjust = GetHeightAdjust(ghwndApp);
DPF1("Layout: WindowRect = %x, %x, %x, %x\n", rc);
if (rc.bottom - rc.top != (int)(MAX_NORMAL_HEIGHT + gwHeightAdjust)) { MoveWindow(ghwndApp, rc.left, rc.top, rc.right - rc.left, (int)(MAX_NORMAL_HEIGHT + gwHeightAdjust), TRUE); }
hdwp = BeginDeferWindowPos(6);
if (!hdwp) goto Exit_Layout;
GetClientRect(ghwndApp, &rcClient); // get new size
wWidth = rcClient.right;
iYOffset = rcClient.bottom - MAX_NORMAL_HEIGHT + 2; // start here
/* ??? Hide the trackbar if it can't fit on completely ??? */ iYPosition = iYOffset >= 0 ? iYOffset : ((iYOffset >= - 9) ? iYOffset + 9 : 1000);
fShowTrackbar = (iYOffset >= - 9);
/* Focus in on trackbar which is about to go away */ if (!fShowTrackbar && GetFocus() == ghwndTrackbar) SetFocus(ghwndToolbar);
ShowWindow(ghwndToolbar, SW_SHOW);
/* The space that COMMCTRL puts to the left of the first toolbar button:
*/ #define SLOPLFT 0
#define XOFF1 8
// how long did it end up being?
wFSTrackWidth = wWidth - SB_XPOS - 1 - wFSArrowsWidth - SLOPLFT;
DeferWindowPos(hdwp, ghwndTrackbar, HWND_TOP, SB_XPOS, iYPosition, wFSTrackWidth, wFSTrackHeight, SWP_NOZORDER | SWP_NOREDRAW | (fShowTrackbar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
/* Toolbar positioning:
* * If the window is not wide enough to accommodate all the buttons * and status bar, here's what we do: * * If the status bar is invisible, first remove the mark buttons, * then use the small control width (with only three buttons). * * If the status bar is visible, give it priority over the mark * buttons and the extra controls, but remove it if there isn't * room for it and the small control width. */
if (gwDeviceID) { fShowStatus = TRUE;
if (GetStatusTextExtent(ghwndStatic, &StatusTextExtent)) { RECT rc; LONG StatusWidth; /* Total width of status window */ LONG TextAreaWidth; /* Width minus border and size grip */
/* Allow for the border around the status window:
*/ GetWindowRect(ghwndStatic, &rc); StatusWidth = rc.right - rc.left;
SendMessage(ghwndStatic, SB_GETRECT, 0, (LPARAM)&rc); TextAreaWidth = rc.right - rc.left;
wMinStatusWidth = StatusTextExtent.cx + (StatusWidth - TextAreaWidth) + 16; } } else { fShowStatus = FALSE; }
wToolbarWidth = LARGE_CONTROL_WIDTH + SLOPLFT; fShowMark = TRUE;
if (wWidth < LARGE_CONTROL_WIDTH + SLOPLFT + MARK_WIDTH + XOFF1 + wMinStatusWidth) { fShowMark = FALSE;
if (wWidth < LARGE_CONTROL_WIDTH + SLOPLFT + wMinStatusWidth) wToolbarWidth = SMALL_CONTROL_WIDTH + SLOPLFT;
if (wWidth < SMALL_CONTROL_WIDTH + SLOPLFT + wMinStatusWidth) fShowStatus = FALSE; }
fRepaintToolbar = FALSE;
/* If we're adding or removing the mark buttons or the status window,
* make sure we repaint things so that the separator bar corresponds. * (It should separate the status window from the buttons, but should * go away when the status window does.) */ if (IsWindowVisible(ghwndStatic) != fShowStatus) fRepaintToolbar = TRUE; else if (IsWindowVisible(ghwndMark) != fShowMark) fRepaintToolbar = TRUE;
ShowWindow(ghwndStatic, fShowStatus);
/* Turn off the toolbar (for tabbing) if it's not going to be there */ /* and if we're disabled, we better not keep the focus. */ if (!fShowMark) { if (GetFocus() == ghwndMark) SetFocus(ghwndToolbar); // can't give it to SB, might be gone too
EnableWindow(ghwndMark, FALSE); } else EnableWindow(ghwndMark, TRUE);
DeferWindowPos(hdwp, ghwndFSArrows, HWND_TOP, SB_XPOS + wFSTrackWidth, // wWidth - 1 - wFSArrowsWidth,
iYPosition + 2, wFSArrowsWidth + SLOPLFT, wFSArrowsHeight + 4, /* Er, 4 because it works */ SWP_NOZORDER);
iYOffset += wFSTrackHeight;
DeferWindowPos(hdwp, ghwndMap, HWND_TOP, SB_XPOS, iYOffset, wWidth - SB_XPOS, MAP_HEIGHT, SWP_NOZORDER | SWP_NOREDRAW | (fShowTrackbar ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); iYOffset += MAP_HEIGHT;
/* Do we show the last four buttons on the main toolbar? */ /* If not, then disable them for tabs and such. */ if (wToolbarWidth == LARGE_CONTROL_WIDTH + SLOPLFT) {
// Why are we getting the Status here when we have a global that
// contains it? Because gwStatus is set in UpdateDisplay, but
// Layout() is called by UpdateDisplay, so the global is not always
// set properly when this code runs. BUT! We must NOT pass a string
// to StatusMCI() or it will think UpdateDisplay() called it, and
// not tell UpdateDisplay() the proper mode next time it asks for it,
// because it will think that it already knows it.
wStatusMCI = StatusMCI(&dw); nState = (wStatusMCI == MCI_MODE_OPEN || wStatusMCI == MCI_MODE_NOT_READY || gwDeviceID == (UINT)0) ? BTNST_GRAYED : BTNST_UP;
toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, nState); toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, nState); toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, nState); toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, nState); toolbarModifyState(ghwndToolbar, BTN_PLAY, TBINDEX_MAIN, nState); } else { toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, BTNST_GRAYED); toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, BTNST_GRAYED); toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, BTNST_GRAYED); toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, BTNST_GRAYED); }
DeferWindowPos(hdwp, ghwndToolbar, HWND_TOP, 2, iYOffset + 2, wToolbarWidth, TOOLBAR_HEIGHT, SWP_NOZORDER);
DeferWindowPos(hdwp, ghwndMark, HWND_TOP, wToolbarWidth + XOFF1, iYOffset + 2, MARK_WIDTH, TOOLBAR_HEIGHT, SWP_NOZORDER | (fShowMark ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
#define ARBITRARY_Y_OFFSET 4
DeferWindowPos(hdwp, ghwndStatic, HWND_TOP, wToolbarWidth + (fShowMark ? MARK_WIDTH + XOFF1 : 0) + XOFF1, iYOffset + ARBITRARY_Y_OFFSET, wWidth - (wToolbarWidth + 3) - (fShowMark ? MARK_WIDTH + XOFF1 : 0) - XOFF1, TOOLBAR_HEIGHT - 6, SWP_NOZORDER);
EndDeferWindowPos(hdwp);
if (fRepaintToolbar) { InvalidateRect(ghwndApp, NULL, TRUE); }
CalcTicsOfDoom();
/* These little gems have just cost me about ten hours worth of debugging -
* note the useful and descriptive comments... * * The Win32 problem caused by this only arises with CD Audio, when the disk is * ejected and then another one is inserted into the drive. At that point * the redrawing misses out the Trackmap FSArrows, the borders on the * Mark buttons, and various bits of the toolbar. * * I will leave this here on the assumption that whichever bout * on Win16 they are intended to fix still exists - it certainly doesn't on * Win32. */
Exit_Layout: sfInLayout = FALSE; return; }
/* What is the previous mark from our current spot? */ LONG_PTR CalcPrevMark(void) { LONG_PTR lStart, lEnd, lPos, lTol, lTrack = -1, lTarget; LONG_PTR l;
lStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0); lEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0); lPos = SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0);
/* Find the next track we should go to (ignore selection markers) */ if (gwCurScale == ID_TRACKS) { lTol = (LONG)gdwMediaLength / 2000; for (l = (LONG)gwNumTracks - 1; l >= 0; l--) { if (gadwTrackStart[l] < (DWORD)lPos - lTol) { lTrack = gadwTrackStart[l]; break; } } }
/* For msec mode: */ /* Our current position fluctuates randomly and even if we're dead on */ /* a selection mark, it might say we're a little before or after it. */ /* So we'll allow a margin for error so that you don't forever stay */ /* still while you hit PrevMark because it happens to be saying you're*/ /* always past the mark you're at. The margin of error will be */ /* half the width of the thumb. */
if (gwCurScale == ID_FRAMES) lTol = 0L; else lTol = 0L;//VIJR-TBTrackGetLogThumbWidth(ghwndTrackbar) / 2;
if (lEnd != -1 && lPos > lEnd + lTol) lTarget = lEnd; else if (lStart != -1 && lPos > lStart + lTol) lTarget = lStart; else lTarget = 0;
/* go to the either the selection mark or the next track (the closest) */ if (lTrack != -1 && lTrack > lTarget) lTarget = lTrack;
return lTarget; }
/* What is the next mark from our current spot? */ LONG_PTR CalcNextMark(void) { LONG_PTR lStart, lEnd, lPos, lTol, lTrack = -1, lTarget; UINT_PTR w;
lStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0); lEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0); lPos = SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0);
/* Find the next track we should go to (ignore selection markers) */ if (gwCurScale == ID_TRACKS) { lTol = (LONG)gdwMediaLength / 2000; for (w = 0; w < gwNumTracks; w++) { if (gadwTrackStart[w] > (DWORD)lPos + lTol) { lTrack = gadwTrackStart[w]; break; } } }
/* For msec mode: */ /* Our current position fluctuates randomly and even if we're dead on */ /* a selection mark, it might say we're a little before or after it. */ /* So we'll allow a margin for error so that you don't forever stay */ /* still while you hit NextMark because it happens to be saying you're*/ /* always before the mark you're at. The margin of error will be */ /* half the width of the thumb. */
if (gwCurScale == ID_FRAMES) lTol = 0L; else lTol = 0L;//VIJR-TBTrackGetLogThumbWidth(ghwndTrackbar) / 2;
/* Find the selection mark we should go to */ if (lStart != -1 && lPos < lStart - lTol) lTarget = lStart; else if (lEnd != -1 && lPos < lEnd - lTol) lTarget = lEnd; else lTarget = gdwMediaStart + gdwMediaLength;
/* go to the either the selection mark or the next track (the closest) */ if (lTrack != -1 && lTrack < lTarget) lTarget = lTrack;
return lTarget; }
HICON GetIconFromProgID(LPTSTR szProgID) { DWORD Status; HKEY hkeyDefaultIcon; BOOL rc = FALSE; DWORD Type; DWORD Size; TCHAR szProgIDDefaultIcon[128]; TCHAR szDefaultIcon[MAX_PATH+4]; /* <path>,N */ HICON hicon = NULL; LPTSTR pIconIndex; UINT IconIndex;
wsprintf(szProgIDDefaultIcon, TEXT("%s\\DefaultIcon"), szProgID);
Status = RegOpenKeyEx( HKEY_CLASSES_ROOT, szProgIDDefaultIcon, 0, KEY_READ, &hkeyDefaultIcon );
if (Status == NO_ERROR) { Size = CHAR_COUNT(szDefaultIcon);
Status = RegQueryValueEx( hkeyDefaultIcon, aszNULL, 0, &Type, (LPBYTE)szDefaultIcon, &Size );
if (Status == NO_ERROR) { /* Find a comma in the string. After it comes the icon index:
*/ pIconIndex = STRCHR(szDefaultIcon, TEXT(','));
if (pIconIndex) { /* Null terminate the file name:
*/ *pIconIndex = TEXT('\0');
/* Get the index that comes after the comma:
*/ IconIndex = ATOI(pIconIndex+1);
DPF1("Extracting icon #%d from %"DTS"\n", IconIndex, szDefaultIcon);
hicon = ExtractIcon(ghInst, szDefaultIcon, IconIndex); }
} else { DPF0("Couldn't find Default Icon for %"DTS"\n", szProgID); }
RegCloseKey(hkeyDefaultIcon); }
return hicon; }
/* GetIconForCurrentDevice
* * Checks what device is currently selected, and returns a handle to the * appropriate icon of the specified size. If there is no current device, * returns either the application's icon or the default icon for media * documents. * * Parameters: * * Size - GI_SMALL (for title bar) or GI_LARGE (for in-place icon). * * DefaultID - Default to use if no current device. APPICON or IDI_DDEFAULT. * * Return: * * Icon handle * * * Andrew Bell (andrewbe), 31 March 1995 */ HICON GetIconForCurrentDevice(UINT Size, UINT DefaultID) { TCHAR DeviceName[256]; DWORD i; LPTSTR ImageID = NULL; int cx; int cy; HICON hIcon;
GetDeviceNameMCI(DeviceName, BYTE_COUNT(DeviceName));
if (DeviceName[0]) { for (i = 0; i < sizeof DevToIconIDMap / sizeof *DevToIconIDMap; i++) { if (!lstrcmpi(DeviceName, DevToIconIDMap[i].pString)) { ImageID = MAKEINTRESOURCE(DevToIconIDMap[i].ID); break; } } }
else { if (Size == GI_LARGE) {
hIcon = GetIconFromProgID(gachProgID);
if (hIcon) { return hIcon; } } }
if (ImageID == NULL) ImageID = MAKEINTRESOURCE(DefaultID);
cx = (Size == GI_SMALL ? GetSystemMetrics(SM_CXSMICON) : 0); cy = (Size == GI_SMALL ? GetSystemMetrics(SM_CYSMICON) : 0);
hIcon = (HICON)LoadImage(ghInst, ImageID, IMAGE_ICON, cx, cy, LR_DEFAULTSIZE);
return hIcon; }
/* SetMPlayerIcon
* * Sets the icon based upon the current device. Uses default document * icon if embedded, otherwise the application icon. * * Andrew Bell (andrewbe), 31 March 1995 */ void SetMPlayerIcon() { UINT DefaultID;
DefaultID = gfEmbeddedObject ? IDI_DDEFAULT : APPICON;
SendMessage(ghwndApp, WM_SETICON, FALSE, (LPARAM)GetIconForCurrentDevice(GI_SMALL, DefaultID)); }
/*--------------------------------------------------------------+
| AskUpdate - ask the user if they want to update the | | object (if we're dirty). | | IDYES means yes, go ahead and update please. | | IDNO means don't update, but continue. | | IDCANCEL means don't update, and cancel what | | you were doing. | +--------------------------------------------------------------*/ int NEAR PASCAL AskUpdate(void) { UINT w;
/* Don't update object if no device is loaded into mplayer! */ if (IsObjectDirty() && gfDirty != -1 && gfEmbeddedObject && gwDeviceID) {
if((glCurrentVerb == OLEIVERB_PRIMARY) && !gfOle2IPEditing) return IDNO; //
// if we are a hidden MPlayer (most likely doing a Play verb) then
// update without asking?
//
if (!IsWindowVisible(ghwndApp) || gfOle2IPEditing) return IDYES;
w = ErrorResBox(ghwndApp, ghInst, MB_YESNOCANCEL | MB_ICONQUESTION, IDS_APPNAME, IDS_UPDATEOBJECT, szClientDoc);
} else w = IDNO;
return w; }
void SizePlaybackWindow(int dx, int dy) { RECT rc; HWND hwndPlay;
if (gfPlayOnly) { SetRect(&rc, 0, 0, dx, dy); SetMPlayerSize(&rc); } else { if (dx == 0 && dy == 0) { SetMPlayerSize(NULL); // size MPlayer to default size
dx = grcSize.right; // then size the playback window too.
dy = grcSize.bottom; } hwndPlay = GetWindowMCI();
if (hwndPlay != NULL) {
/* make sure that the play window isn't iconized */
if (IsIconic(hwndPlay)) return;
GetClientRect(hwndPlay, &rc); ClientToScreen(hwndPlay, (LPPOINT)&rc); SetRect(&rc, rc.left, rc.top, rc.left+dx, rc.top+dy); PutWindowMCI(&rc); SetRect(&rc, 0, 0, dx, dy); SetDestRectMCI(&rc); } } }
/* StartSndVol
* * Kicks off the Sound Volume app asynchronously so we don't hang the UI. */ VOID StartSndVol( ) { STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation;
memset( &StartupInfo, 0, sizeof StartupInfo ); StartupInfo.cb = sizeof(StartupInfo); StartupInfo.wShowWindow = SW_SHOW;
CreateProcess( NULL, szSndVol32, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInformation );
ExitThread( 0 ); }
/* GetHeightAdjust
* * Finds the real height adjustment needed, by subtracting the client * height from the main window height. This allows for menus that * have wrapped. */ int GetHeightAdjust(HWND hwnd) { RECT rcWindow; RECT rcClient; int WindowHeight; int ClientHeight;
GetWindowRect(hwnd, &rcWindow); GetClientRect(hwnd, &rcClient); WindowHeight = rcWindow.bottom - rcWindow.top; ClientHeight = rcClient.bottom - rcClient.top;
return WindowHeight - ClientHeight; }
/* Message-cracking routines for MPlayerWndProc:
*/
BOOL MPlayer_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) { InitMPlayerDialog(hwnd);
/* set off a thread to check that the OLE registry stuff is not corrupted */
#ifdef CHICAGO_PRODUCT
/* If this is the Chicago Media Player, only mess with the registry
* if we're actually running on that platform. * The guy may be running it on NT. */ if (gwPlatformId != VER_PLATFORM_WIN32_WINDOWS) return TRUE; #endif
if (!IgnoreRegCheck()) BackgroundRegCheck(hwnd);
//Register for WM_DEVICECHANGE notification.
DeviceChange_Init(hwnd);
return TRUE; }
void MPlayer_OnShowWindow(HWND hwnd, BOOL fShow, UINT status) { if (fShow) Layout(); // we're about to be shown and want to set
}
void MPlayer_OnSize(HWND hwnd, UINT state, int cx, int cy) { /* Don't waste time Layout()ing if we're not visible */ if (state != SIZE_RESTORED || IsWindowVisible(hwnd)) {
Layout();
// If we are inplace editing, our size change must be informed
// to the container, unless the size change was a result of a
// OnPosRectChange sent to us by the container.
if ((gfOle2IPEditing || gfOle2IPPlaying) && ghwndMCI) {
RECT rc; RECT rcPrev;
rcPrev = gInPlacePosRect; GetWindowRect(ghwndApp, &gInPlacePosRect); gfInPlaceResize = TRUE; rc = gInPlacePosRect;
/* Check that the previous rect wasn't empty, otherwise we send
* a bogus OLE_CHANGED on startup. */ if (!gfPosRectChange /*&& !IsRectEmpty(&rcPrev)*/) {
MapWindowPoints(NULL,ghwndCntr,(POINT FAR *)&rc,(UINT)2);
DPF("IOleInPlaceSite::OnPosRectChange %d, %d, %d, %d\n", rc); if (!gfInPPViewer) IOleInPlaceSite_OnPosRectChange(docMain.lpIpData->lpSite, &rc); fDocChanged = TRUE; SendDocMsg((LPDOC)&docMain, OLE_CHANGED); }
gfPosRectChange = FALSE; } } }
BOOL MPlayer_OnWindowPosChanging(HWND hwnd, LPWINDOWPOS lpwpos) { #define SNAPTOGOODSIZE
#ifdef SNAPTOGOODSIZE
BOOL wHeight; #endif
DPF2("ENTER OnWindowPosChanging: lpwpos = %x, %x, %x, %x\n", *((PPOS)&lpwpos->x));
if (IsIconic(hwnd) || gfPlayOnly) return TRUE;
/* posSizeMove contains the height we want to be when sizing.
* Don't let the system tell us otherwise. */ if (posSizeMove.cx != 0) { lpwpos->cy = posSizeMove.cy; posSizeMove = *(PPOS)&lpwpos->x; }
else if (!(lpwpos->flags & SWP_NOSIZE)) {
#ifdef SNAPTOGOODSIZE
/* We should also do things here to make the window
** snap to good sizes */ wHeight = lpwpos->cy - gwHeightAdjust; // if (lpwpos->cy >= (int) gwHeightAdjust + MAX_NORMAL_HEIGHT) {
// } else if (lpwpos->cy < (int) gwHeightAdjust +
// ((MIN_NORMAL_HEIGHT + MAX_NORMAL_HEIGHT) / 2)) {
// lpwpos->cy = (int) gwHeightAdjust + MIN_NORMAL_HEIGHT;
// } else {
lpwpos->cy = (int) gwHeightAdjust + MAX_NORMAL_HEIGHT; // }
#endif
}
DPF2("EXIT OnWindowPosChanging: lpwpos = %x, %x, %x, %x\n", *((PPOS)&lpwpos->x));
return FALSE; }
BOOL MPlayer_OnWindowPosChanged(HWND hwnd, LPWINDOWPOS lpwpos) { if (!IsIconic(hwnd) && !gfPlayOnly && !gfOle2IPEditing && !gfOle2IPPlaying) { /* The problem here is that we want to modify the height of the
* window while tracking to take account of the menu height. * In its wisdom, the system keeps trying to resize us back to the * original height. So, during tracking, we keep hold of the * dimensions we want to be and ignore the height that we get * passed on WM_WINDOWPOSCHANGING. */ if (posSizeMove.cx != 0) { int NewHeightAdjust = GetHeightAdjust(hwnd);
if ((int)gwHeightAdjust != NewHeightAdjust) { /* The total non-client height has changed, so it must
* be the menu that's wrapped or unwrapped. * Modify our height adjustment accordingly and resize * the window. */ DPF("Menu appears to have wrapped. Changing window height.\n");
posSizeMove.cy += ( NewHeightAdjust - gwHeightAdjust ); gwHeightAdjust = NewHeightAdjust; MoveWindow(ghwndApp, posSizeMove.x, posSizeMove.y, posSizeMove.cx, posSizeMove.cy, TRUE); return FALSE; } }
if (ghwndStatic && IsWindowVisible(ghwndStatic)) { InvalidateRect(ghwndStatic, NULL, FALSE); } }
FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, DefWindowProc);
return TRUE; }
void MPlayer_OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange) { if (ghwndMCI && !IsIconic(hwnd)) FORWARD_WM_PALETTECHANGED(ghwndMCI, hwndPaletteChange, SendMessage); }
BOOL MPlayer_OnQueryNewPalette(HWND hwnd) { HWND hwndT; HPALETTE hpal, hpalT; HDC hdc; UINT PaletteEntries;
if (IsIconic(hwnd)) return FALSE;
if (ghwndMCI) return FORWARD_WM_QUERYNEWPALETTE(ghwndMCI, SendMessage);
hwndT = GetWindowMCI(); hpal = PaletteMCI();
if ((hwndT != NULL) && (hpal != NULL)) { hdc = GetDC(hwnd); hpalT = SelectPalette(hdc, hpal, FALSE); PaletteEntries = RealizePalette(hdc); SelectPalette(hdc, hpalT, FALSE); ReleaseDC(hwnd, hdc);
if (PaletteEntries != GDI_ERROR) { InvalidateRect(hwndT, NULL, TRUE); return TRUE; } }
return FALSE; }
HBRUSH MPlayer_OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild, int type) { /* Only interested in the CTLCOLOR_STATIC messages.
* On Win32, type should always equal CTLCOLOR_STATIC: */ switch( type ) { case CTLCOLOR_STATIC: SetBkColor(hdc, rgbButtonFace); SetTextColor(hdc, rgbButtonText); }
return hbrButtonFace; }
void MPlayer_OnWinIniChange(HWND hwnd, LPCTSTR lpszSectionName) { if (!lpszSectionName || !lstrcmpi(lpszSectionName, (LPCTSTR)aszIntl)) if (GetIntlSpecs()) InvalidateRect(ghwndMap, NULL, TRUE);
if (!gfPlayOnly) {
if (gwHeightAdjust != (WORD)(2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENU))) {
RECT rc;
gwHeightAdjust = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENU); GetClientRect(hwnd, &rc); gfWinIniChange = TRUE; SetMPlayerSize(&rc); gfWinIniChange = FALSE; } } }
void MPlayer_OnMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags) { // Make sure that the container is still not displaying info. about
// its own menu.
if (gfOle2IPEditing && docMain.lpIpData->lpFrame) {
//Should have some useful text later.
IOleInPlaceFrame_SetStatusText(docMain.lpIpData->lpFrame, L""); } else { //Keep track of which menu bar item is currently popped up.
//This will be used for displaying the appropriate help from the mplayer.hlp file
//when the user presses the F1 key.
currMenuItem = item; } }
#define MVSIZEFIRST 1
#define MVMOVE 9
void MPlayer_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) { RECT rc;
if (gfPlayOnly && !IsIconic(hwnd) && IsZoomed(hwnd)) {
if (codeHitTest >= HTSIZEFIRST && codeHitTest <= HTSIZELAST) {
SendMessage(hwnd, WM_SYSCOMMAND, // (WPARAM)(SC_SIZE + (codeHitTest - HTSIZEFIRST + MVSIZEFIRST) ),
(WPARAM)SC_SIZE, MAKELPARAM(x, y)); return; }
GetWindowRect(hwnd, &rc);
if (codeHitTest == HTCAPTION && (rc.left > 0 || rc.top > 0 || rc.right < GetSystemMetrics(SM_CXSCREEN) || rc.bottom < GetSystemMetrics(SM_CYSCREEN))) {
SendMessage(hwnd, WM_SYSCOMMAND, // (WPARAM)(SC_MOVE | MVMOVE),
(WPARAM)SC_MOVE, MAKELPARAM(x, y)); return; } }
FORWARD_WM_NCLBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, DefWindowProc); }
void MPlayer_OnNCLButtonDblClk(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) { //
// when the user dbl-clicks on the caption, toggle the play mode.
//
if (codeHitTest == HTCAPTION && !IsIconic(hwnd)) SendMessage(hwnd, WM_COMMAND, (WPARAM)IDM_WINDOW, 0); }
void MPlayer_OnInitMenu(HWND hwnd, HMENU hMenu) {
EnableMenuItem(hMenu, IDM_CLOSE, gwDeviceID ? MF_ENABLED : MF_GRAYED); // EnableMenuItem(hMenu, IDM_UPDATE, gwDeviceID && gfEmbeddedObject ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hMenu, IDM_COPY_OBJECT, (gwDeviceID && (gwStatus != MCI_MODE_OPEN) && (gwStatus != MCI_MODE_NOT_READY)) ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_CONFIG, gwDeviceID && (gwDeviceType & DTMCI_CANCONFIG) ? MF_ENABLED : MF_GRAYED);
CheckMenuItem(hMenu, IDM_SCALE + ID_TIME, gwCurScale == ID_TIME ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SCALE + ID_TRACKS, gwCurScale == ID_TRACKS ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SCALE + ID_FRAMES, gwCurScale == ID_FRAMES ? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem(hMenu, IDM_SCALE + ID_TIME, gwDeviceID && !gfCurrentCDNotAudio && (gwDeviceType & DTMCI_TIMEMS) ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_SCALE + ID_FRAMES, gwDeviceID && !gfCurrentCDNotAudio && (gwDeviceType & DTMCI_TIMEFRAMES) ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_SCALE + ID_TRACKS, gwDeviceID && !gfCurrentCDNotAudio && (gwNumTracks > 1) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hMenu, IDM_OPTIONS, gwDeviceID ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_SELECTION, gwDeviceID && gdwMediaLength ? MF_ENABLED : MF_GRAYED);
#ifdef DEBUG
EnableMenuItem(hMenu, IDM_MCISTRING, gwDeviceID ? MF_ENABLED : MF_GRAYED); #endif
/*
EnableMenuItem(hMenu, IDM_PASTE_PICTURE , gwDeviceID && (IsClipboardFormatAvailable(CF_METAFILEPICT) || IsClipboardFormatAvailable(CF_BITMAP) || IsClipboardFormatAvailable(CF_DIB)) ? MF_ENABLED : MF_GRAYED);
//
// what is paste frame!
//
EnableMenuItem(hMenu, IDM_PASTE_FRAME, gwDeviceID && (gwDeviceType & DTMCI_CANCONFIG) ? MF_ENABLED : MF_GRAYED); */ }
void MPlayer_OnInitMenuPopup(HWND hwnd, HMENU hMenu, UINT item, BOOL fSystemMenu) { static BOOL VolumeControlChecked = FALSE;
/* Here we look to see whether the menu selected is the Device popup,
* and, if it is the first time, search for the Sound Volume applet. * If we can't find it, grey out the menu item. */
/* Caution: When we're in place, there seems to be a discrepancy
* in the value of parameter UINT item depending on which app is our * container. If you use Spy to look at the parameters sent on * WM_INITMENUPOPUP, some apps seem to have zero-based menus (e.g. * ProgMan, PowerPoint, FileMan), which is what I would expect, * but others seem to have one-based menus (e.g. Word, Excel). * Why is this? I don't know. But it means that, when the * Insert Clip menu item is selected, the item parameter may be * either 2 or 3. That's why I'm calling GetSubMenu, since hMenu * is always what I would expect. * * I sent some mail to the User and OLE guys to point this out, * but haven't heard anything yet. * * andrewbe, 28 February 1995 */
if (hMenu == GetSubMenu(ghMenu, menuposDevice)) { HCURSOR hcurPrev;
if(!VolumeControlChecked) { /*
** Check to see if the volume controller piglet can be found on ** the path. */ { TCHAR chBuffer[8]; LPTSTR lptstr;
if( SearchPath( NULL, szSndVol32, NULL, 8, chBuffer, &lptstr ) == 0L ) EnableMenuItem( hMenu, IDM_VOLUME, MF_GRAYED );
VolumeControlChecked = TRUE; } }
/* On Device (or Insert Clip) menu start menu building if necessary
* (e.g. if we came up in tiny mode then switched to full size), * and wait for the separate thread to complete. */ InitDeviceMenu(); hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT)); WaitForDeviceMenu(); SetCursor(hcurPrev); }
/////////////////////////////////////////////////////////////////////////////
// This code allows a window to by sized even when in the maximized state
/////////////////////////////////////////////////////////////////////////////
if (gfPlayOnly && !IsIconic(hwnd) && fSystemMenu && IsZoomed(hwnd)) EnableMenuItem(hMenu, SC_SIZE, !IsIconic(hwnd) ? MF_ENABLED : MF_GRAYED); }
void MPlayer_OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo) { RECT rc;
if (gfPlayOnly) { SetRect(&rc, 0, 0, 0, TOOLBAR_HEIGHT); AdjustWindowRect(&rc, (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE), FALSE); lpMinMaxInfo->ptMinTrackSize.y = rc.bottom - rc.top - 1;
if (!gfPlayingInPlace && (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW))) lpMinMaxInfo->ptMaxTrackSize.y = lpMinMaxInfo->ptMinTrackSize.y; } else { lpMinMaxInfo->ptMinTrackSize.y = MAX_NORMAL_HEIGHT + gwHeightAdjust; lpMinMaxInfo->ptMaxTrackSize.y = MAX_NORMAL_HEIGHT + gwHeightAdjust; } }
void MPlayer_OnPaint(HWND hwnd) { PAINTSTRUCT ps; RECT rc; int x1, x2, y, y2; UINT wParent; HBRUSH hbrOld;
BeginPaint(hwnd, &ps);
if (gfPlayOnly) {
extern UINT gwPlaybarHeight; // in server.c
/* Separate mci playback window from controls */ if (gwDeviceType & DTMCI_CANWINDOW) { SelectObject(ps.hdc, hbrButtonText); GetClientRect(ghwndApp, &rc); PatBlt(ps.hdc, 0, rc.bottom - gwPlaybarHeight, rc.right, 1, PATCOPY); } } else { hbrOld = SelectObject(ps.hdc, hbrButtonText); GetClientRect(ghwndApp, &rc); wParent = rc.right;
y = rc.bottom - 27; // where to paint borders around toolbar
/* Line above trackbar */ #ifdef CHICAGO_PRODUCT
y2 = rc.bottom - 74; /* This looks bad on NT */ PatBlt(ps.hdc, 0, y2, wParent, 1, PATCOPY); #else
y2 = rc.bottom - 75; #endif
/* Lines around toolbars */ PatBlt(ps.hdc, 0, y, wParent, 1, PATCOPY); GetClientRect(ghwndToolbar, &rc); x1 = rc.right; PatBlt(ps.hdc, x1, y, 1, TOOLBAR_HEIGHT + 3, PATCOPY); GetWindowRect(ghwndApp, &rc); x2 = rc.left;
if (IsWindowVisible(ghwndStatic)) { GetWindowRect(ghwndStatic, &rc); MapWindowPoints(NULL, ghwndApp, (LPPOINT)&rc, 1); x2 = rc.left - 2 - GetSystemMetrics(SM_CXFRAME);
PatBlt(ps.hdc, x2, y, 1, TOOLBAR_HEIGHT + 3, PATCOPY); }
SelectObject(ps.hdc, hbrButtonHighLight); /* Line above trackbar */ PatBlt(ps.hdc, 0, y2 + 1, wParent, 1, PATCOPY); /* Lines around toolbar */ PatBlt(ps.hdc, 0, y + 1, wParent, 1, PATCOPY); PatBlt(ps.hdc, x1 + 1, y + 1, 1, TOOLBAR_HEIGHT + 2, PATCOPY); if (IsWindowVisible(ghwndStatic)) { PatBlt(ps.hdc, x2 + 1, y + 1, 1,TOOLBAR_HEIGHT +2, PATCOPY); } SelectObject(ps.hdc, hbrOld); }
EndPaint(hwnd, &ps);
}
void MPlayer_OnCommand_Toolbar_Play() { /* This checks to see whether the ALT key is held down.
* If so, the current selection (if it exists) is played, * otherwise the whole shooting match. * Note, this does not appear to be documented at present. */ if (GetKeyState(VK_MENU) < 0) PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAYSEL, 0);
/* On WFW, pressing the play button when in place plays the
* current selection, if there is one. Do the same if we're * playing or editing in place. */ else if (gfOle2IPPlaying || gfOle2IPEditing) PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAYSEL, 0); else PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAY, 0); }
void MPlayer_OnCommand_Toolbar_Pause() { PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PAUSE, 0L); }
void MPlayer_OnCommand_Toolbar_Stop() { PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_STOP, 0L); }
void MPlayer_OnCommand_Toolbar_Eject() { PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_EJECT, 0L); }
void MPlayer_OnCommand_Toolbar_Home() { LONG_PTR lPos = CalcPrevMark();
/* We MUST use PostMessage because the */ /* SETPOS and ENDTRACK must happen one */ /* immediately after the other */
PostMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, lPos);
PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_ENDTRACK, (LPARAM)ghwndTrackbar); }
void MPlayer_OnCommand_Toolbar_End() { LONG_PTR lPos = CalcNextMark();
/* We MUST use PostMessage because the */ /* SETPOS and ENDTRACK must happen one */ /* immediately after the other */
PostMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, lPos);
PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_ENDTRACK, (LPARAM)ghwndTrackbar); }
void MPlayer_OnCommand_Toolbar_Rwd(HWND hwndCtl) { if (hwndCtl == (HWND)REPEAT_ID) { if (gwCurScale != ID_TRACKS) PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_PAGEUP, 0L); else PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_LINEUP, 0L); } }
void MPlayer_OnCommand_Toolbar_Fwd(HWND hwndCtl) { if (hwndCtl == (HWND)REPEAT_ID) { if (gwCurScale != ID_TRACKS) PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_PAGEDOWN, 0L); else PostMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_LINEDOWN, 0L); } }
void MPlayer_OnCommand_Toolbar_MarkIn() { SendMessage(ghwndTrackbar, TBM_SETSELSTART, (WPARAM)TRUE, SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0));
DirtyObject(TRUE); }
void MPlayer_OnCommand_Toolbar_MarkOut() { SendMessage(ghwndTrackbar, TBM_SETSELEND, (WPARAM)TRUE, SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0));
DirtyObject(TRUE); }
void MPlayer_OnCommand_Toolbar_ArrowPrev(HWND hwndCtl) { if (hwndCtl == (HWND)REPEAT_ID) SendMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_LINEUP, 0L); }
void MPlayer_OnCommand_Toolbar_ArrowNext(HWND hwndCtl) { if (hwndCtl == (HWND)REPEAT_ID) SendMessage(ghwndApp, WM_HSCROLL, (WPARAM)TB_LINEDOWN, 0L); }
void MPlayer_OnCommand_Menu_CopyObject(HWND hwnd) { if (gfPlayingInPlace) { DPF0("Mplayer WndProc: Can't cutorcopy\n"); return; }
DPF("Mplayer WndProc: Calling cutorcopy\n");
if (!InitOLE(&gfOleInitialized, &lpMalloc)) { /* How likely is this? Do we need a dialog box?
*/ DPF0("Initialization of OLE FAILED!! Can't do copy.\n"); }
#ifdef OLE1_HACK
CopyObject(hwnd); #endif /* OLE1_HACK */
CutOrCopyObj(&docMain); }
void MPlayer_OnCommand_Menu_Config(HWND hwnd) { RECT rcBefore; RECT rcAfter;
if (gfPlayingInPlace) return;
GetDestRectMCI (&rcBefore);
ConfigMCI(hwnd);
/* If the MCI window size changed, we need to resize */ /* our reduced mplayer. */ if (gfPlayOnly) { GetDestRectMCI (&rcAfter);
if (!EqualRect(&rcBefore, &rcAfter) && (!IsRectEmpty(&rcAfter))) SetMPlayerSize(&rcAfter); } }
void MPlayer_OnCommand_Menu_Volume(HWND hwnd) { HANDLE hThread; DWORD dwThreadId;
hThread = CreateThread( NULL, 0L, (LPTHREAD_START_ROUTINE)StartSndVol, NULL, 0L, &dwThreadId );
if ( hThread != NULL ) { CloseHandle( hThread ); } }
void MPlayer_OnCommand_PlayToggle(HWND hwnd) { /* This is for the accelerator to toggle play and pause. */ /* Ordinary play commands better not toggle. */
DPF2("MPlayer_OnCommand_PlayToggle: gwStatus == %x\n", gwStatus);
switch(gwStatus) {
case MCI_MODE_STOP: case MCI_MODE_PAUSE: case MCI_MODE_SEEK: PostMessage(hwnd, WM_COMMAND, (WPARAM)ID_PLAY, 0); break;
case MCI_MODE_PLAY: PostMessage(hwnd, WM_COMMAND, (WPARAM)ID_PAUSE, 0); break; } }
void MPlayer_OnCommand_PlaySel(HWND hwnd, HWND hwndCtl) { DWORD_PTR dwPos, dwStart, dwEnd; BOOL f; dwPos = 0; // Make Prefix Happy..
DPF2("MPlayer_OnCommand_PlaySel: gwStatus == %x\n", gwStatus);
switch(gwStatus) {
case MCI_MODE_OPEN: case MCI_MODE_NOT_READY:
Error(ghwndApp, IDS_CANTPLAY); if (gfCloseAfterPlaying) // get us out now!!
PostCloseMessage();
break;
default:
/* If the shift key's being held down, make this the start
* of a selection: */
if((GetKeyState(VK_SHIFT) < 0) &&(toolbarStateFromButton(ghwndMark, BTN_MARKIN, TBINDEX_MARK) != BTNST_GRAYED)) SendMessage(hwnd, WM_COMMAND, IDT_MARKIN, 0);
/* Start playing the medium */
StatusMCI(&dwPos); // get the REAL position
dwStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0); dwEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
/* If there is no valid selection, act like PLAY */ if (dwStart == -1 || dwEnd == -1 || dwStart == dwEnd) hwndCtl = (HWND)ID_PLAY;
// Be nice and rewind automatically if we're at the end of the media.
// Depending on the device, though, the end could be "start + len"
// or "start + len - 1"
if (hwndCtl == (HWND)ID_PLAY && dwPos >= gdwMediaStart + gdwMediaLength - 1) { if (!SeekMCI(gdwMediaStart)) break; }
if (hwndCtl == (HWND)ID_PLAYSEL) { f = PlayMCI(dwStart, dwEnd); gfJustPlayedSel = TRUE; } else { f = PlayMCI(0, 0); gfJustPlayedSel = FALSE; }
// get us out NOW!! or focus goes to client
if (!f && gfCloseAfterPlaying) PostCloseMessage();
/* No longer needed - reset for next time */ gfUserStopped = FALSE;
gwStatus = (UINT)(-1); // force rewind if needed
break; } }
void MPlayer_OnCommand_Pause() { /* Pause the medium, unless we are already paused */
DPF2("MPlayer_OnCommand_Pause: gwStatus == %x\n", gwStatus);
switch(gwStatus) {
case MCI_MODE_PAUSE: PlayMCI(0, 0); break;
case MCI_MODE_PLAY: case MCI_MODE_SEEK: PauseMCI(); break;
case MCI_MODE_STOP: case MCI_MODE_OPEN: break; } }
void MPlayer_OnCommand_Stop() { /* Stop the medium */
DPF2("MPlayer_OnCommand_Stop: gwStatus == %x\n", gwStatus);
switch(gwStatus) {
case MCI_MODE_PAUSE: case MCI_MODE_PLAY: case MCI_MODE_STOP: case MCI_MODE_SEEK:
StopMCI(); SeekToStartMCI(); gfUserStopped = TRUE; // we did this
gfCloseAfterPlaying = FALSE; //stay up from now on
UpdateDisplay();
// Focus should go to PLAY button now
toolbarSetFocus(ghwndToolbar, BTN_PLAY); break;
case MCI_MODE_OPEN: break; }
if (gfPlayingInPlace) PostCloseMessage(); }
void MPlayer_OnCommand_Eject() { /*
* Eject the medium if it currently isn't ejected. If it * is currently ejected, then load the new medium into * the device. * */
switch(gwStatus) {
case MCI_MODE_PLAY: case MCI_MODE_PAUSE:
StopMCI(); EjectMCI(TRUE);
break;
case MCI_MODE_STOP: case MCI_MODE_SEEK: case MCI_MODE_NOT_READY:
EjectMCI(TRUE);
break;
case MCI_MODE_OPEN:
EjectMCI(FALSE);
break; } }
void MPlayer_OnCommand_Escape() { MPlayer_OnCommand_Stop();
if( gfOle2IPEditing || gfOle2IPPlaying) PostCloseMessage(); }
void MPlayer_OnCommand_Menu_Open() { UINT wLastScale; UINT wLastDeviceID; TCHAR szFile[256]; RECT rc;
wLastScale = gwCurScale; // save old scale
wLastDeviceID = gwDeviceID; if (gfPlayingInPlace || gfOle2IPEditing || gfOle2IPPlaying) return;
InitDeviceMenu(); WaitForDeviceMenu();
if (OpenDoc(gwCurDevice,szFile)) { DirtyObject(FALSE); /* Force WM_GETMINMAXINFO to be called so we'll snap */ /* to a proper size. */ GetWindowRect(ghwndApp, &rc); MoveWindow(ghwndApp, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
if (gfOpenDialog) CompleteOpenDialog(TRUE); else gfCloseAfterPlaying = FALSE; // stay up from now on
//If the CD Audio device was opened it must have been a *.cda file.
//Try to jump to the track corresponding to the file opened.
if ((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO) { HandleCDAFile(szFile); } } else { if (gfOpenDialog) CompleteOpenDialog(FALSE);
/* The previous device may or may not still be open.
* If it is, make sure we have the right scale. */ if (gwDeviceID == wLastDeviceID) gwCurScale = wLastScale; // restore to last scale
InvalidateRect(ghwndMap, NULL, TRUE); //erase map area
}
// put the focus on the Play button
SetFocus(ghwndToolbar); // give focus to PLAY button
toolbarSetFocus(ghwndToolbar, BTN_PLAY);
SetMPlayerIcon(); }
void MPlayer_OnCommand_Menu_Close(HWND hwnd) { if (gfEmbeddedObject && !gfSeenPBCloseMsg) { // this is File.Update
#ifdef OLE1_HACK
if( gDocVersion == DOC_VERSION_OLE1 ) Ole1UpdateObject(); else #endif /* OLE1_HACK */
UpdateObject(); } else { // this is File.Close
gfSeenPBCloseMsg = TRUE;
WriteOutOptions(); InitDoc(TRUE); SetMPlayerIcon(); gwCurDevice = 0;// force next file open dialog to say
// "all files" because CloseMCI won't.
gwCurScale = ID_NONE; // uncheck all scale types
Layout(); // Make window snap back to smaller size
// if it should.
// Don't leave us closed in play only mode
if (gfPlayOnly) SendMessage(hwnd, WM_COMMAND, (WPARAM)IDM_WINDOW, 0); } }
void MPlayer_OnCommand_Menu_Exit() { PostCloseMessage(); }
void MPlayer_OnCommand_Menu_Scale(UINT id) { /*
* Invalidate the track map window so it will be * redrawn with the correct positions, etc. */ if (gwCurScale != id - IDM_SCALE) {
// Restoring the selection doesn't work yet,
// because UpdateMCI clears the selection,
// plus we need to do some conversion.
// int SelStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0);
// int SelEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
SendMessage(ghwndTrackbar, TBM_CLEARTICS, (WPARAM)FALSE, 0L); if (gwCurScale == ID_FRAMES || id - IDM_SCALE == ID_FRAMES) gfValidMediaInfo = FALSE;
gwCurScale = id - IDM_SCALE; DirtyObject(TRUE); // change scale changes PAGE UP/DOWN
CalcTicsOfDoom();
// SendMessage(ghwndTrackbar, TBM_SETSELSTART, TRUE, SelStart);
// SendMessage(ghwndTrackbar, TBM_SETSELEND, TRUE, SelEnd);
} }
void MPlayer_OnCommand_Menu_Selection(HWND hwnd) { if (!gfPlayingInPlace) setselDialog(hwnd); }
void MPlayer_OnCommand_Menu_Options(HWND hwnd) { if (!gfPlayingInPlace) optionsDialog(hwnd); }
void MPlayer_OnCommand_Menu_MCIString(HWND hwnd) { if (!gfPlayingInPlace && gwDeviceID) mciDialog(hwnd); }
void MPlayer_OnCommand_Menu_Window(HWND hwnd) { //
// make MPlayer small/big
//
//!! dont do this if inside client document !!
//!! or if we're not visible !!
if (!IsWindowVisible(ghwndApp) || gfPlayingInPlace || IsIconic(hwnd) || gfOle2IPEditing) return;
// allowed to get out of teeny mode when no file is open
if (gwDeviceID != (UINT)0 || gfPlayOnly) { gfPlayOnly = !gfPlayOnly; SizeMPlayer(); } }
void MPlayer_OnCommand_Menu_Zoom(HWND hwnd, int id) { int dx, dy;
if (IsIconic(hwnd) ||gfPlayingInPlace || gfOle2IPPlaying || gfOle2IPEditing || !(gwDeviceType & DTMCI_CANWINDOW)) return;
dx = grcSize.right * (id-IDM_ZOOM); dy = grcSize.bottom * (id-IDM_ZOOM);
//
// if the playback windows is now larger than the screen
// maximize MPlayer, this only makes sence for Tiny mode.
//
if (gfPlayOnly && (dx >= GetSystemMetrics(SM_CXSCREEN) || dy >= GetSystemMetrics(SM_CYSCREEN))) { ClrWS(hwnd, WS_MAXIMIZE); DefWindowProc(hwnd, WM_SYSCOMMAND, (WPARAM)SC_MAXIMIZE, 0); } else { SizePlaybackWindow(dx, dy); } }
void DoHtmlHelp() { //note, using ANSI version of function because UNICODE is foobar in NT5 builds
char chDst[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, gszHtmlHelpFileName, -1, chDst, MAX_PATH, NULL, NULL); HtmlHelpA(GetDesktopWindow(), chDst, HH_DISPLAY_TOPIC, 0); }
void MPlayer_OnCommand_Menu_HelpTopics(HWND hwnd) { static TCHAR HelpFile[] = TEXT("MPLAYER.HLP"); //Handle context menu help
if(bF1InMenu) { switch(currMenuItem) { case IDM_OPEN: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_FILE_OPEN); break; case IDM_CLOSE: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_FILE_CLOSE); break; case IDM_EXIT: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_FILE_EXIT); break; case IDM_COPY_OBJECT: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_EDIT_COPY_OBJECT); break; case IDM_OPTIONS: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_EDIT_OPTIONS); break; case IDM_SELECTION: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_EDIT_SELECTION); break; case IDM_CONFIG: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_DEVICE_PROPERTIES); break; case IDM_VOLUME: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_DEVICE_VOLUME_CONTROL); break; case IDM_SCALE + ID_TIME: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_SCALE_TIME); break; case IDM_SCALE + ID_TRACKS: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_SCALE_TRACKS); break; case IDM_SCALE + ID_FRAMES: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_SCALE_FRAMES); break; case IDM_HELPTOPICS: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_HELP_HELP_TOPICS); break; case IDM_ABOUT: WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_MPLYR_CS_MEDIA_PLAYER_HELP_ABOUT); break; default://In the default case just display the HTML Help.
DoHtmlHelp(); } bF1InMenu = FALSE; //This flag will be set again if F1 is pressed in a menu.
} else DoHtmlHelp(); }
void MPlayer_OnCommand_Menu_About(HWND hwnd) { ShellAbout(hwnd, gachAppName, aszNULL, hiconApp); }
void MPlayer_OnCommand_Default(HWND hwnd, int id) { /*
* Determine if the user selected one of the entries in * the Device menu. * */
if (id > IDM_DEVICE0 && (id <= (WORD)(IDM_DEVICE0 + gwNumDevices)) ) {
BOOL fHasWindow, fHadWindow, fHadDevice;
fHadWindow = (gwDeviceID != (UINT)0) && (gwDeviceType & DTMCI_CANWINDOW); fHadDevice = (gwDeviceID != (UINT)0);
//Choose and open a new device. If we are active inplace we have
//to consider the effect of the change in device on the visual appearence.
//For this we have to take into account whether the current and previous
//device had a playback window or not. We also have to consider
//whether this is the first device are opening.
//After all the crazy munging send a messages to the container about
//the changes.
if (DoChooseDevice(id-IDM_DEVICE0)) { if (gfOpenDialog) CompleteOpenDialog(TRUE);
fHasWindow = (gwDeviceID != (UINT)0) && (gwDeviceType & DTMCI_CANWINDOW); if(gfOle2IPEditing) { if (fHasWindow && fHadWindow) { GetWindowRect(ghwndApp, (LPRECT)&gInPlacePosRect); gfInPlaceResize = TRUE; SendDocMsg((LPDOC)&docMain, OLE_SIZECHG); SendDocMsg((LPDOC)&docMain, OLE_CHANGED); }
else { RECT rc; RECT rctmp;
ClrWS(ghwndApp, WS_THICKFRAME|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_BORDER);
if (gwOptions & OPT_BORDER) SetWS(ghwndApp, WS_BORDER);
GetWindowRect(ghwndApp, &rc);
if (!(gwDeviceType & DTMCI_CANWINDOW)) { HBITMAP hbm; BITMAP bm;
if (!fHadDevice) GetWindowRect(ghwndIPHatch, &rc); hbm = BitmapMCI(); GetObject(hbm,sizeof(bm),&bm); rc.bottom = rc.top + bm.bmHeight; rc.right = rc.left + bm.bmWidth; DeleteObject(hbm); } else { if(!fHadDevice) { rc.bottom -= (GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYBORDER)); gwOptions |= OPT_BAR | OPT_TITLE; } rc.bottom += gInPlacePosRect.top - rc.top - 4*GetSystemMetrics(SM_CYBORDER) - 4 ; rc.right += gInPlacePosRect.left - rc.left- 4*GetSystemMetrics(SM_CXBORDER) - 4 ; rc.top = gInPlacePosRect.top; rc.left = gInPlacePosRect.left; } rctmp = gPrevPosRect; MapWindowPoints( ghwndCntr, NULL, (LPPOINT)&rctmp,2); OffsetRect((LPRECT)&rc, rctmp.left - rc.left, rctmp.top -rc.top); gInPlacePosRect = rc; gfInPlaceResize = TRUE; if(!(gwDeviceType & DTMCI_CANWINDOW) && (gwOptions & OPT_BAR)) { rc.top = rc.bottom - gwPlaybarHeight; } EditInPlace(ghwndApp,ghwndIPHatch,&rc); SendDocMsg((LPDOC)&docMain, OLE_SIZECHG); SendDocMsg((LPDOC)&docMain, OLE_CHANGED); if (!(gwDeviceType & DTMCI_CANWINDOW) && !(gwOptions &OPT_BAR)) ShowWindow(ghwndApp, SW_HIDE); else ShowWindow(ghwndApp, SW_SHOW); } }
DirtyObject(FALSE);
if (!gfOpenDialog) gfCloseAfterPlaying = FALSE; // stay up from now on
SetMPlayerIcon(); } else if (gfOpenDialog) CompleteOpenDialog(FALSE); } }
#define HANDLE_COMMAND(id, call) case (id): (call); break
void MPlayer_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { switch (id) {
HANDLE_COMMAND(IDT_PLAY, MPlayer_OnCommand_Toolbar_Play()); HANDLE_COMMAND(IDT_PAUSE, MPlayer_OnCommand_Toolbar_Pause()); HANDLE_COMMAND(IDT_STOP, MPlayer_OnCommand_Toolbar_Stop()); HANDLE_COMMAND(IDT_EJECT, MPlayer_OnCommand_Toolbar_Eject()); HANDLE_COMMAND(IDT_HOME, MPlayer_OnCommand_Toolbar_Home()); HANDLE_COMMAND(IDT_END, MPlayer_OnCommand_Toolbar_End()); HANDLE_COMMAND(IDT_RWD, MPlayer_OnCommand_Toolbar_Rwd(hwndCtl)); HANDLE_COMMAND(IDT_FWD, MPlayer_OnCommand_Toolbar_Fwd(hwndCtl)); HANDLE_COMMAND(IDT_MARKIN, MPlayer_OnCommand_Toolbar_MarkIn()); HANDLE_COMMAND(IDT_MARKOUT, MPlayer_OnCommand_Toolbar_MarkOut()); HANDLE_COMMAND(IDT_ARROWPREV, MPlayer_OnCommand_Toolbar_ArrowPrev(hwndCtl)); HANDLE_COMMAND(IDT_ARROWNEXT, MPlayer_OnCommand_Toolbar_ArrowNext(hwndCtl)); HANDLE_COMMAND(IDM_COPY_OBJECT, MPlayer_OnCommand_Menu_CopyObject(hwnd)); HANDLE_COMMAND(IDM_CONFIG, MPlayer_OnCommand_Menu_Config(hwnd)); HANDLE_COMMAND(IDM_VOLUME, MPlayer_OnCommand_Menu_Volume(hwnd)); HANDLE_COMMAND(ID_PLAYTOGGLE, MPlayer_OnCommand_PlayToggle(hwnd)); HANDLE_COMMAND(ID_PLAY, MPlayer_OnCommand_PlaySel(hwnd, (HWND)IntToPtr(id))); HANDLE_COMMAND(ID_PLAYSEL, MPlayer_OnCommand_PlaySel(hwnd, (HWND)IntToPtr(id))); HANDLE_COMMAND(ID_PAUSE, MPlayer_OnCommand_Pause()); HANDLE_COMMAND(ID_STOP, MPlayer_OnCommand_Stop()); HANDLE_COMMAND(ID_EJECT, MPlayer_OnCommand_Eject()); HANDLE_COMMAND(ID_ESCAPE, MPlayer_OnCommand_Escape()); HANDLE_COMMAND(IDM_OPEN, MPlayer_OnCommand_Menu_Open()); HANDLE_COMMAND(IDM_CLOSE, MPlayer_OnCommand_Menu_Close(hwnd)); HANDLE_COMMAND(IDM_EXIT, MPlayer_OnCommand_Menu_Exit()); HANDLE_COMMAND(IDM_SCALE + ID_TIME, MPlayer_OnCommand_Menu_Scale(id)); HANDLE_COMMAND(IDM_SCALE + ID_TRACKS, MPlayer_OnCommand_Menu_Scale(id)); HANDLE_COMMAND(IDM_SCALE + ID_FRAMES, MPlayer_OnCommand_Menu_Scale(id)); HANDLE_COMMAND(IDM_SELECTION, MPlayer_OnCommand_Menu_Selection(hwnd)); HANDLE_COMMAND(IDM_OPTIONS, MPlayer_OnCommand_Menu_Options(hwnd)); HANDLE_COMMAND(IDM_MCISTRING, MPlayer_OnCommand_Menu_MCIString(hwnd)); HANDLE_COMMAND(IDM_WINDOW, MPlayer_OnCommand_Menu_Window(hwnd)); HANDLE_COMMAND(IDM_ZOOM1, MPlayer_OnCommand_Menu_Zoom(hwnd, id)); HANDLE_COMMAND(IDM_ZOOM2, MPlayer_OnCommand_Menu_Zoom(hwnd, id)); HANDLE_COMMAND(IDM_ZOOM3, MPlayer_OnCommand_Menu_Zoom(hwnd, id)); HANDLE_COMMAND(IDM_ZOOM4, MPlayer_OnCommand_Menu_Zoom(hwnd, id)); HANDLE_COMMAND(IDM_HELPTOPICS, MPlayer_OnCommand_Menu_HelpTopics(hwnd)); HANDLE_COMMAND(IDM_ABOUT, MPlayer_OnCommand_Menu_About(hwnd));
default: MPlayer_OnCommand_Default(hwnd, id); }
UpdateDisplay(); }
void MPlayer_OnClose(HWND hwnd) { int f;
DPF("WM_CLOSE received\n");
if (gfInClose) { DPF("*** \n"); DPF("*** Trying to re-enter WM_CLOSE\n"); DPF("*** \n"); return; }
// Ask if we want to update before we set gfInClose to TRUE or
// we won't let the dialog box up.
f = AskUpdate(); if (f == IDYES) UpdateObject(); if (f == IDCANCEL) { gfInClose = FALSE; return; }
gfInClose = TRUE;
ExitApplication(); if (gfPlayingInPlace) EndPlayInPlace(hwnd); if (gfOle2IPEditing) EndEditInPlace(hwnd);
if (docMain.lpoleclient) IOleClientSite_OnShowWindow(docMain.lpoleclient, FALSE);
SendDocMsg(&docMain,OLE_CLOSED); DestroyDoc(&docMain); ExitApplication();
if (hMciOle) { FreeLibrary(hMciOle); hMciOle = NULL; }
//
// set either the owner or the WS_CHILD bit so it will
// not act up because we have the palette bit set and cause the
// desktop to steal the palette.
//
// because we are being run from client apps that dont deal
// with palettes we dont want the desktop to hose the palette.
//
if (gfPlayOnly && gfCloseAfterPlaying && gfRunWithEmbeddingFlag) SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LPARAM)GetDesktopWindow() );
if (!ItsSafeToClose()) { DPF("*** \n"); DPF("*** Trying to close MPLAYER with a ErrorBox up\n"); DPF("*** \n"); gfErrorDeath = WM_CLOSE; gfInClose = FALSE; return; }
f = AskUpdate(); if (f == IDYES) UpdateObject(); if (f == IDCANCEL) { gfInClose = FALSE; return; }
PostMessage(ghwndApp, WM_USER_DESTROY, 0, 0); DPF("WM_DESTROY message sent\n"); }
void MPlayer_OnEndSession(HWND hwnd, BOOL fEnding) { if (fEnding) { WriteOutPosition(); WriteOutOptions(); CloseMCI(FALSE); } }
void MPlayer_OnDestroy(HWND hwnd) { /*
* Relinquish control of whatever MCI device we were using (if any). If * this device is not shareable, then performing this action allows * someone else to gain access to the device. * */
/* Client might close us if he dies while we're Playing in Place */ if (gfPlayingInPlace) { DPF("****\n"); DPF("**** Window destroyed while in place!\n"); DPF("****\n"); }
//Unregister the WM_DEVICECHANGE notification
DeviceChange_Cleanup();
WriteOutOptions(); CloseMCI(FALSE);
SetMenu(hwnd, NULL);
if (ghMenu) DestroyMenu(ghMenu);
ghMenu = NULL;
WinHelp(hwnd, gszHelpFileName, HELP_QUIT, 0L);
PostQuitMessage(0);
if (IsWindow(ghwndFrame)) SetFocus(ghwndFrame); else if (IsWindow(ghwndFocusSave)) SetFocus(ghwndFocusSave);
//Inform OLE that we are not taking any more calls.
if (gfOleInitialized) { #ifdef OLE1_HACK
if( gDocVersion == DOC_VERSION_OLE1 ) TerminateServer(); else #endif /* OLE1_HACK */
/* Verify that the server was initialised by checking that one
* of the fields in docMain is non-null: */ if( docMain.hwnd ) CoDisconnectObject((LPUNKNOWN)&docMain, 0); else DPF0("An instance of the server was never created.\n"); } }
void MPlayer_OnTimer(HWND hwnd, UINT id) { MSG msg;
UpdateDisplay(); PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE); }
#define MARK_START -1
#define MARK_NONE 0
#define MARK_END 1
void UpdateSelection(HWND hwnd, INT_PTR pos, int *pPrevMark) { INT_PTR SelStart; INT_PTR SelEnd;
SelStart = SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0); SelEnd = SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0);
if (pos < SelStart) { SendMessage(hwnd, WM_COMMAND, IDT_MARKIN, 0); *pPrevMark = MARK_START; } else if (pos > SelEnd) { SendMessage(hwnd, WM_COMMAND, IDT_MARKOUT, 0); *pPrevMark = MARK_END; } else { if (*pPrevMark == MARK_START) SendMessage(hwnd, WM_COMMAND, IDT_MARKIN, 0); else SendMessage(hwnd, WM_COMMAND, IDT_MARKOUT, 0); } }
void MPlayer_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) { DWORD_PTR dwPosition; /* player's current position in the medium*/ DWORD_PTR dwCurTime; /* Time a page up/down is last made */ TCHAR ach[60]; static int PrevMark;
/* If the media has no size, we can't seek. */ if (gdwMediaLength == 0L) return;
dwPosition = SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0);
if (!gfScrollTrack) { gfScrollTrack = TRUE;
/* If the shift key's being held down, make this the start
* of a selection: */
if((GetKeyState(VK_SHIFT) < 0) &&(toolbarStateFromButton(ghwndMark, BTN_MARKIN, TBINDEX_MARK) != BTNST_GRAYED)) { SendMessage(ghwndTrackbar, TBM_CLEARSEL, (WPARAM)TRUE, 0); SendMessage(hwnd, WM_COMMAND, IDT_MARKIN, 0); SetFocus(ghwndTrackbar); /* So that escape will go to
the trackbar's subclassed winproc. */ }
sfSeekExact = SeekExactMCI(FALSE); }
switch (code) { /*
* Set the new position within the medium to be * slightly before/after the current position if the * left/right scroll arrow was clicked on. */ case TB_LINEUP: /* left scroll arrow */ dwPosition -= (gwCurScale == ID_FRAMES) ? 1L : SCROLL_GRANULARITY; break;
case TB_LINEDOWN: /* right scroll arrow */ dwPosition += (gwCurScale == ID_FRAMES) ? 1L : SCROLL_GRANULARITY; break;
case TB_PAGEUP: /* page-left */
/*
* If the user just did a page-left a short time ago, * then seek to the start of the previous track. * Otherwise, seek to the start of this track. * */ if (gwCurScale != ID_TRACKS) { dwPosition -= SCROLL_BIGGRAN; } else { dwCurTime = GetCurrentTime(); if (dwCurTime - dwLastPageUpTime < SKIPTRACKDELAY_MSEC) SkipTrackMCI(-1); else SkipTrackMCI(0);
dwLastPageUpTime = dwCurTime; goto BreakOut; // avoid SETPOS
}
break;
case TB_PAGEDOWN: /* page-right */
if (gwCurScale != ID_TRACKS) { dwPosition += SCROLL_BIGGRAN; } else { /* Seek to the start of the next track */ SkipTrackMCI(1); // Ensure next PageUp can't possibly do SkipTrackMCI(-1)
// which will skip back too far if you page
// left, right, left really quickly.
dwLastPageUpTime = 0; goto BreakOut; // avoid SETPOS
}
break;
case TB_THUMBTRACK: /* track thumb movement */ //!!! we should do a "set seek exactly off"
/* Only seek while tracking for windowed devices that */ /* aren't currently playing */ if ((gwDeviceType & DTMCI_CANWINDOW) && !(gwStatus == MCI_MODE_PLAY)) { SeekMCI(dwPosition); }
break;
case TB_TOP: dwPosition = gdwMediaStart; break;
case TB_BOTTOM: dwPosition = gdwMediaStart + gdwMediaLength; break;
case TB_THUMBPOSITION: /* thumb has been positioned */ break;
case TB_ENDTRACK: /* user let go of scroll */ DPF2("TB_ENDTRACK\n");
gfScrollTrack = FALSE;
/* New as of 2/7/91: Only seek on ENDTRACK */
/*
* Calculate the new position in the medium * corresponding to the scrollbar position, and seek * to this new position. * */
/* We really want to update our position */ if (hwndCtl) { if (gdwSeekPosition) { dwPosition = gdwSeekPosition; gdwSeekPosition = 0; }
/* Go back to the seek mode we were in before */ /* we started scrolling. */ SeekExactMCI(sfSeekExact); SeekMCI(dwPosition); }
PrevMark = MARK_NONE;
return;
default: return; } SendMessage(ghwndTrackbar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)dwPosition); /* Clamp to a valid range */ dwPosition = SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0);
BreakOut:
if (GetKeyState(VK_SHIFT) < 0) UpdateSelection(hwnd, dwPosition, &PrevMark);
if (ghwndStatic) { FormatTime(dwPosition, NULL, ach, TRUE); //VIJR-SBSetWindowText(ghwndStatic, ach);
WriteStatusMessage(ghwndStatic, ach); }
// Dirty if you just move the thumb???
// if (!IsObjectDirty() && !gfCloseAfterPlaying) // don't want playing to dirty
// DirtyObject();
}
void MPlayer_OnSysCommand(HWND hwnd, UINT cmd, int x, int y) { RECT rc;
// The bottom four bits of wParam contain system information. They
// must be masked off in order to work out the actual command.
// See the comments section in the online help for WM_SYSCOMMAND.
switch (cmd & 0xFFF0) {
case SC_MINIMIZE: DPF("minimized -- turn off timer\n"); ClrWS(hwnd, WS_MAXIMIZE); EnableTimer(FALSE); break;
case SC_MAXIMIZE: if (gfPlayOnly && !IsIconic(hwnd)) { (void)PostMessage(hwnd, WM_COMMAND, (WPARAM)IDM_ZOOM2, 0); return; }
break;
case SC_RESTORE: if (gfPlayOnly && !IsIconic(hwnd)) { GetWindowRect(hwnd, &rc); if (rc.left > 0 || rc.top > 0) (void)PostMessage(hwnd, WM_COMMAND, (WPARAM)IDM_ZOOM1, 0); return; }
if (gwDeviceID != (UINT)0) { DPF("un-minimized -- turn timer back on\n"); EnableTimer(TRUE); }
break; }
FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, DefWindowProc); }
int MPlayer_OnMouseActivate(HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT msg) { if (gfPlayingInPlace && !gfOle2IPPlaying) return MA_NOACTIVATE; else /* !!! Is this the right thing to do in this case? */ return FORWARD_WM_MOUSEACTIVATE(hwnd, hwndTopLevel, codeHitTest, msg, DefWindowProc); }
UINT MPlayer_OnNCHitTest(HWND hwnd, int x, int y) { UINT Pos;
Pos = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc);
if (gfPlayingInPlace && (Pos == HTCLIENT)) Pos = HTNOWHERE;
return Pos; }
void MPlayer_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized) { HWND hwndT;
gfAppActive = (state != WA_INACTIVE);
// Put the playback window BEHIND us so it's kinda
// visible, but not on top of us (annoying).
if (gfAppActive && !ghwndMCI && !IsIconic(hwnd) && ((hwndT = GetWindowMCI()) != NULL)) { SetWindowPos(hwndT, hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); }
if (gwDeviceID != (UINT)0) EnableTimer(TRUE);
/* Remember who had focus if we're being de-activated. */ /* Give focus back to him once we're re-activated. */ /* Don't remember a window that doesn't belong to us, */ /* or when we give focus back to it, we'll never be */ /* able to activate! */
#if 0
/* Commenting this out for now. This code looks dubious.
* wParam (as was) contains state and fMinimized, so, if we're minimized, * it will always be non-null. */
if (wParam && ghwndFocus) { SetFocus(ghwndFocus); } else if (!wParam) { ghwndFocus = GetFocus(); } #endif
FORWARD_WM_ACTIVATE(hwnd, state, hwndActDeact, fMinimized, DefWindowProc); }
void MPlayer_OnSysColorChange(HWND hwnd) { ControlCleanup(); ControlInit(ghInst);
FORWARD_WM_SYSCOLORCHANGE(ghwndToolbar, SendMessage); FORWARD_WM_SYSCOLORCHANGE(ghwndFSArrows, SendMessage); FORWARD_WM_SYSCOLORCHANGE(ghwndMark, SendMessage); FORWARD_WM_SYSCOLORCHANGE(ghwndTrackbar, SendMessage); }
void MPlayer_OnDropFiles(HWND hwnd, HDROP hdrop) { doDrop(hwnd, hdrop); }
LRESULT MPlayer_OnNotify(HWND hwnd, int idFrom, NMHDR FAR* pnmhdr) { LPTOOLTIPTEXT pTtt; LPTBNOTIFY pTbn; TCHAR ach[40];
switch(pnmhdr->code) {
case TTN_NEEDTEXT:
pTtt = (LPTOOLTIPTEXT)pnmhdr;
if (gfPlayOnly && (pTtt->hdr.idFrom != IDT_PLAY) && (pTtt->hdr.idFrom != IDT_PAUSE) && (pTtt->hdr.idFrom != IDT_STOP) && !gfOle2IPEditing) break; switch (pTtt->hdr.idFrom) { case IDT_PLAY: case IDT_PAUSE: case IDT_STOP: case IDT_EJECT: case IDT_HOME: case IDT_END: case IDT_FWD: case IDT_RWD: case IDT_MARKIN: case IDT_MARKOUT: case IDT_ARROWPREV: case IDT_ARROWNEXT: LOADSTRING(pTtt->hdr.idFrom, ach); lstrcpy(pTtt->szText, ach); break; default: *pTtt->szText = TEXT('\0'); break; }
break;
case TBN_BEGINDRAG: pTbn = (LPTBNOTIFY)pnmhdr; if(pTbn->iItem == IDT_ARROWPREV || pTbn->iItem == IDT_ARROWNEXT) SendMessage(ghwndFSArrows, WM_STARTTRACK, (WPARAM)pTbn->iItem, 0L); else SendMessage(ghwndToolbar, WM_STARTTRACK, (WPARAM)pTbn->iItem, 0L); break;
case TBN_ENDDRAG: pTbn = (LPTBNOTIFY)pnmhdr; if(pTbn->iItem == IDT_ARROWPREV || pTbn->iItem == IDT_ARROWNEXT) SendMessage(ghwndFSArrows, WM_ENDTRACK, (WPARAM)pTbn->iItem, 0L); else SendMessage(ghwndToolbar, WM_ENDTRACK, (WPARAM)pTbn->iItem, 0L); break; }
return 0; }
////////////////////////////////////////////////////////////////////////////////////////////
// * DeviceChange_Init
// First time initialization for WM_DEVICECHANGE messages
// This is specific to NT5
////////////////////////////////////////////////////////////////////////////////////////////
BOOL DeviceChange_Init(HWND hWnd) { DEV_BROADCAST_DEVICEINTERFACE dbi;
dbi.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; dbi.dbcc_reserved = 0; dbi.dbcc_classguid = KSCATEGORY_AUDIO; dbi.dbcc_name[0] = TEXT('\0');
MixerEventContext = RegisterDeviceNotification(hWnd, (PVOID)&dbi, DEVICE_NOTIFY_WINDOW_HANDLE); if(!MixerEventContext) return FALSE; return TRUE; }
////////////////////////////////////////////////////////////////////////////////////////////
// * DeviceChange_Cleanup
// Unregister the device notification.
////////////////////////////////////////////////////////////////////////////////////////////
void DeviceChange_Cleanup() { if (MixerEventContext) { UnregisterDeviceNotification(MixerEventContext); MixerEventContext = NULL; }
return; }
void DisplayNoMciDeviceError() { DWORD ErrorID;
if (!lstrcmpi(gachOpenExtension, aszKeyMID)) ErrorID = IDS_CANTPLAYMIDI;
else if (!lstrcmpi(gachOpenExtension, aszKeyAVI)) ErrorID = IDS_CANTPLAYVIDEO;
else if (!lstrcmpi(gachOpenExtension, aszKeyWAV)) ErrorID = IDS_CANTPLAYSOUND;
else ErrorID = IDS_NOMCIDEVICES;
Error(ghwndApp, ErrorID); }
/*
* MPlayerWndProc(hwnd, wMsg, wParam, lParam) * * This is the message processing routine for the MPLAYERBOX (main) dialog. * */ //Harmless message-cracker because the user guys will not fix their
//windowsx.h macro which cause the irritating rip.
//This is also a wee bit faster because the message
//is forwarded only on select and not on deselects. Also we do not care
//about the params
#define HANDLE_MPLAYER_WM_MENUSELECT(hwnd, message, fn) \
case (message): if(lParam) ((fn)((hwnd), (HMENU)(lParam), (UINT)LOWORD(wParam), 0L, 0L )); break;
LRESULT FAR PASCAL MPlayerWndProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { switch (wMsg) {
HANDLE_MSG(hwnd, WM_CREATE, MPlayer_OnCreate); HANDLE_MSG(hwnd, WM_SHOWWINDOW, MPlayer_OnShowWindow); HANDLE_MSG(hwnd, WM_SIZE, MPlayer_OnSize); HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, MPlayer_OnWindowPosChanging); HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, MPlayer_OnWindowPosChanged); HANDLE_MSG(hwnd, WM_PALETTECHANGED, MPlayer_OnPaletteChanged); HANDLE_MSG(hwnd, WM_QUERYNEWPALETTE, MPlayer_OnQueryNewPalette); HANDLE_MSG(hwnd, WM_CTLCOLORSTATIC, MPlayer_OnCtlColor); HANDLE_MSG(hwnd, WM_WININICHANGE, MPlayer_OnWinIniChange); HANDLE_MPLAYER_WM_MENUSELECT(hwnd, WM_MENUSELECT, MPlayer_OnMenuSelect); HANDLE_MSG(hwnd, WM_NCLBUTTONDOWN, MPlayer_OnNCLButtonDown); HANDLE_MSG(hwnd, WM_NCLBUTTONDBLCLK, MPlayer_OnNCLButtonDblClk); HANDLE_MSG(hwnd, WM_INITMENU, MPlayer_OnInitMenu); HANDLE_MSG(hwnd, WM_INITMENUPOPUP, MPlayer_OnInitMenuPopup); HANDLE_MSG(hwnd, WM_GETMINMAXINFO, MPlayer_OnGetMinMaxInfo); HANDLE_MSG(hwnd, WM_PAINT, MPlayer_OnPaint); HANDLE_MSG(hwnd, WM_COMMAND, MPlayer_OnCommand); HANDLE_MSG(hwnd, WM_CLOSE, MPlayer_OnClose); HANDLE_MSG(hwnd, WM_ENDSESSION, MPlayer_OnEndSession); HANDLE_MSG(hwnd, WM_DESTROY, MPlayer_OnDestroy); HANDLE_MSG(hwnd, WM_TIMER, MPlayer_OnTimer); HANDLE_MSG(hwnd, WM_HSCROLL, MPlayer_OnHScroll); HANDLE_MSG(hwnd, WM_SYSCOMMAND, MPlayer_OnSysCommand); HANDLE_MSG(hwnd, WM_MOUSEACTIVATE, MPlayer_OnMouseActivate); HANDLE_MSG(hwnd, WM_NCHITTEST, MPlayer_OnNCHitTest); HANDLE_MSG(hwnd, WM_ACTIVATE, MPlayer_OnActivate); HANDLE_MSG(hwnd, WM_SYSCOLORCHANGE, MPlayer_OnSysColorChange); HANDLE_MSG(hwnd, WM_DROPFILES, MPlayer_OnDropFiles); HANDLE_MSG(hwnd, WM_NOTIFY, MPlayer_OnNotify);
/* Other bits of stuff that need tidying up sometime:
*/
case WM_NOMCIDEVICES: /* This was posted by the thread building the Device
* menu to tell us it couldn't find any MCI devices. */ DisplayNoMciDeviceError(); PostMessage(ghwndApp, WM_CLOSE, 0, 0); break;
case WM_GETDIB: return (LRESULT)GetDib();
case WM_DEVICECHANGE : { //if plug-and-play sends this, pass it along to the component
PDEV_BROADCAST_DEVICEINTERFACE bid = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
//Check to see if this is a audio message
if (!MixerEventContext || !bid || bid->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE || !IsEqualGUID(&KSCATEGORY_AUDIO, &bid->dbcc_classguid) || !(*bid->dbcc_name)) { break; } else { switch(wParam) { case DBT_DEVICEQUERYREMOVE: CloseMCI(TRUE); //Close the MCI device
break; case DBT_DEVICEREMOVECOMPLETE: CloseMCI(TRUE); //Close the MCI device
break;
default: break; } } }
case WM_ENTERSIZEMOVE: if (!IsIconic(hwnd) && !gfPlayOnly && !gfOle2IPEditing && !gfOle2IPPlaying) { /* Save the current window position in x, y, dx, dy format:
*/ GetWindowRect(hwnd, (PRECT)&posSizeMove); posSizeMove.cx -= posSizeMove.x; posSizeMove.cy -= posSizeMove.y; } break;
case WM_EXITSIZEMOVE: SetRectEmpty((PRECT)&posSizeMove); break;
case WM_DOLAYOUT: Layout(); break;
case WM_BADREG: if ( IDYES == ErrorResBox(hwnd, NULL, MB_YESNO | MB_ICONEXCLAMATION, IDS_APPNAME, IDS_BADREG) ) if (!SetRegValues()) Error(ghwndApp, IDS_FIXREGERROR); break;
case WM_SEND_OLE_CHANGE: fDocChanged = TRUE; SendDocMsg((LPDOC)&docMain,OLE_CHANGED); break;
case MM_MCINOTIFY: #if 0
//
// don't do this because, some devices send notify failures
// where there really is not a error.
//
if ((WORD)wParam == MCI_NOTIFY_FAILURE) { Error(ghwndApp, IDS_NOTIFYFAILURE); } #endif
UpdateDisplay(); break;
#ifdef OLE1_HACK
/* Actually do the FixLink, SetData and DoVerb we've been putting off */ /* for so long. */ case WM_DO_VERB: /* This message comes from server.c (and goes back there too) */ DelayedFixLink(wParam, LOWORD(lParam), HIWORD(lParam)); //OK on NT. LKG
break; #endif /* OLE1_HACK */
#ifdef LATER
// We'll need to call RegisterWindowMessage and provide a message hook proc
// for this on Win32.
case WM_HELP: WinHelp(hwnd, TEXT("MPLAYER.HLP"), HELP_PARTIALKEY, (DWORD)aszNULL); return TRUE; #endif /* LATER */
case WM_USER_DESTROY: DPF("WM_USER_DESTROY received\n");
if (gfPlayingInPlace) { DPF("****\n"); DPF("**** Window destroyed while in place!\n"); DPF("****\n"); EndPlayInPlace(hwnd); }
if (gfOle2IPEditing) { EndEditInPlace(hwnd); }
if (!ItsSafeToClose()) { DPF("*** \n"); DPF("*** Trying to destroy MPLAYER with an ErrorBox up\n"); DPF("*** \n"); gfErrorDeath = WM_USER_DESTROY; return TRUE; }
if (!gfRunWithEmbeddingFlag) WriteOutPosition();
DestroyWindow(hwnd); DestroyIcon(hiconApp); return TRUE;
case WM_USER+500: /*
** This message is sent by the HookProc inside mciole32.dll when ** it detects that it should stop playing in place of a WOW client ** application. ** ** Because the OleActivate originated in mciole16.dll, ** mciole32.dll does not know the OLE Object that is being ** played and therefore dose not know how to close that object. ** Only mplay32.exe has the necessary information, hence ** mciole32.dll sends this message to mplay32.exe. */ if (gfPlayingInPlace) { EndPlayInPlace(hwnd); } PostMessage( hwnd, WM_CLOSE, 0L, 0L ); break; }
return DefWindowProc(hwnd, wMsg, wParam, lParam); }
/* InitInstance
* ------------ * * Create brushes used by the program, the main window, and * do any other per-instance initialization. * * HANDLE hInstance * * RETURNS: TRUE if successful * FALSE otherwise. * * CUSTOMIZATION: Re-implement * */ BOOL InitInstance (HANDLE hInstance) { HDC hDC;
static SZCODE aszNative[] = TEXT("Native"); static SZCODE aszEmbedSrc[] = TEXT("Embed Source"); static SZCODE aszObjDesc[] = TEXT("Object Descriptor"); static SZCODE aszMplayer[] = TEXT("mplayer"); static SZCODE aszClientDoc[] = TEXT("Client Document");
/* Why doesn't RegisterClipboardFormat return a value of type CLIPFORMAT (WORD)
* instead of UINT? */ cfNative = (CLIPFORMAT)RegisterClipboardFormat (aszNative); cfEmbedSource = (CLIPFORMAT)RegisterClipboardFormat (aszEmbedSrc); cfObjectDescriptor = (CLIPFORMAT)RegisterClipboardFormat (aszObjDesc); cfMPlayer = (CLIPFORMAT)RegisterClipboardFormat (aszMplayer);
szClient[0] = TEXT('\0');
lstrcpy (szClientDoc, aszClientDoc);
// Initialize global variables with LOGPIXELSX and LOGPIXELSY
hDC = GetDC (NULL); // Get the hDC of the desktop window
giXppli = GetDeviceCaps (hDC, LOGPIXELSX); giYppli = GetDeviceCaps (hDC, LOGPIXELSY); ReleaseDC (NULL, hDC);
return TRUE; }
#define COINIT_APARTMENTTHREADED 2
/* InitOLE
* * This should be called only when we're certain that OLE is needed, * to avoid loading loads of unnecessary stuff. * */ BOOL InitOLE (PBOOL pfInit, LPMALLOC *ppMalloc) { HRESULT hr;
if (*pfInit) return TRUE;
hr = (HRESULT)OleInitialize(NULL);
if (!SUCCEEDED (hr)) { DPF0("OleInitialize failed with error 0x%08x\n", hr); Error(NULL, IDS_OLEINIT); return FALSE; }
if (ppMalloc && (CoGetMalloc(MEMCTX_TASK, ppMalloc) != S_OK)) { Error(NULL, IDS_OLENOMEM); OleUninitialize(); return FALSE; } /*****************************************************************
** OLE2NOTE: we must remember the fact that OleInitialize has ** been called successfully. the very last thing an app must ** do is properly shut down OLE by calling ** OleUninitialize. This call MUST be guarded! it is only ** allowable to call OleUninitialize if OleInitialize has ** been called SUCCESSFULLY. *****************************************************************/
*pfInit = TRUE;
return TRUE; }
// This function cleans up all the OLE2 stuff. It lets the container
// save the object and informs that it is closing.
BOOL ExitApplication () {
DPFI("\n*******Exitapp\n"); // if we registered class factory, we must revoke it
if(gfOle2IPEditing || gfOle2IPPlaying) DoInPlaceDeactivate((LPDOC)&docMain);
SendDocMsg((LPDOC)&docMain,OLE_CLOSED); if (srvrMain.fEmbedding) { HRESULT status; srvrMain.fEmbedding = FALSE; // HACK--guard against revoking twice
status = (HRESULT)CoRevokeClassObject (srvrMain.dwRegCF); }
return TRUE; }
#ifdef DEBUG
/* DbgGlobalLock
* * Debug wrapper for GlobalLock * * Checks that the memory handle to be locked isn't already locked, * and checks the return code from GlobalLock. * * andrewbe, 1 March 1995 */ LPVOID DbgGlobalLock(HGLOBAL hglbMem) { LPVOID lpReturn;
if (GlobalFlags(hglbMem) & GMEM_LOCKCOUNT) DPF0("Calling GlobalLock on already locked memory object %08x\n", hglbMem);
lpReturn = GlobalLock(hglbMem);
if (lpReturn == NULL) DPF0("GlobalLock(%08x) failed: Error %d\n", hglbMem, GetLastError());
return lpReturn; }
/* DbgGlobalUnlock
* * Debug wrapper for GlobalUnlock * * Checks the return code from GlobalUnlock, and outputs appropriate * error messages * * andrewbe, 1 March 1995 */ BOOL DbgGlobalUnlock(HGLOBAL hglbMem) { BOOL boolReturn;
boolReturn = GlobalUnlock(hglbMem);
if ((boolReturn) && (GlobalFlags(hglbMem) & GMEM_LOCKCOUNT)) { DPF0("Locks still outstanding on memory object %08x\n", hglbMem); } else { DWORD Error = GetLastError();
if (Error == ERROR_NOT_LOCKED) { DPF0("Attempt to unlock already unlocked memory object %08x\n", hglbMem); } else if (Error != NO_ERROR) { DPF0("Error %d attempting to unlock memory object %08x\n", Error, hglbMem); } }
return boolReturn; }
/* DbgGlobalFree
* * Debug wrapper for GlobalFree. * * Checks that the global handle has no locks before freeing, * then checks that the call succeeded. Error messages output * as appropriate. * * andrewbe, 1 March 1995 * */ HGLOBAL DbgGlobalFree(HGLOBAL hglbMem) { HGLOBAL hglbReturn;
if (GlobalFlags(hglbMem) & GMEM_LOCKCOUNT) DPF0("Freeing global memory object %08x still locked\n", hglbMem);
hglbReturn = GlobalFree(hglbMem);
if (hglbReturn != NULL) DPF0("GlobalFree(%08x) failed: Error %d\n", hglbMem, GetLastError());
return hglbReturn; }
#ifdef UNICODE
/* Note: This function assumes that szFormat strings are NOT unicode.
* Unicode var params may, however, be passed, as long as %ws is specified * in the format string. */ #endif
void FAR cdecl dprintf(LPSTR szFormat, ...) { CHAR ach[_MAX_PATH * 3]; // longest I think we need
int s,d; va_list va;
va_start(va, szFormat); s = wvsprintfA(ach,szFormat, va); va_end(va);
#if 0
strcat(ach,"\n"); s++; #endif
for (d=sizeof(ach)-1; s>=0; s--) { if ((ach[d--] = ach[s]) == TEXT('\n')) ach[d--] = TEXT('\r'); }
/* Not unicode */ if (*(ach+d+1) != ' ') OutputDebugStringA("MPLAYER: "); OutputDebugStringA(ach+d+1); }
#endif
|