|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// MAIN.CPP
//
// Main window of multimedia framework
//
// Copyright (c) Microsoft Corporation 1997
//
// 12/14/97 David Stewart / dstewart
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <TCHAR.H>
#include "resource.h"
#include "objbase.h"
#include "initguid.h"
#include "sink.h"
#include "dib.h"
#include "resource.h"
#include "mbutton.h"
#include "knob.h"
#include "winuser.h"
#include "img.h"
#include "frame.h"
#include <htmlhelp.h>
#include "..\cdopt\cdopt.h"
#include "..\cdnet\cdnet.h"
#include "mmenu.h"
#include <stdio.h>
#include "shellico.h"
#include <shellapi.h>
#include "..\cdplay\playres.h"
#include "wininet.h"
//Support for new WM_DEVICECHANGE behaviour in NT5
/////////////////////////////////////////////////
#include <objbase.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <initguid.h>
#include <dbt.h>
#include <devguid.h>
#include <mmddkp.h>
#include <ks.h>
#include <ksmedia.h>
HDEVNOTIFY DeviceEventContext = NULL; BOOL bUseHandle = FALSE; //Indicates whether a handle is being used for device notification,
//instead of the general KSCATEGORY_AUDIO
BOOL Volume_DeviceChange_Init(HWND hWnd, DWORD dwMixerID); void Volume_DeviceChange_Cleanup(); //////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// Next 2 lines added to add multimon support
#define COMPILE_MULTIMON_STUBS
#include "multimon.h"
////////////////////////////////////////////////////////////////////////////////////////////
// #defines for main ui and call-downs to cd player unit
#define IDC_LEDWINDOW IDC_LED
#define WM_LED_INFO_PAINT (WM_USER+2000) //wparam = bool (allow self-draw), lparam = vol info
#define WM_LED_MUTE (WM_USER+2001) //wparam = unused, lparam = bool (mute)
#define WM_LED_DOWNLOAD (WM_USER+2002) //wparam = unused, lparam = download flag
//command ids from cdplayer
#define ID_CDUPDATE IDM_NET_CD
//battery power limit, stated as a percentage
#define BATTERY_PERCENTAGE_LIMIT 10
//helpers for detecting where the mouse is hitting
#define TITLEBAR_HEIGHT 15
#define TITLEBAR_YOFFSET_LARGE 7
#define TITLEBAR_YOFFSET_SMALL 4
#define SYSMENU_XOFFSET 7
#define SYSMENU_WIDTH 12
//volume bar timer stuff
#define VOLUME_PERSIST_TIMER_RATE 2000
#define VOLUME_PERSIST_TIMER_EVENT 1000
#define SYSTIMERID 1001
//don't remove the parens on these, or My Dear Aunt Sally will getcha
#define IDM_HOMEMENU_BASE (LAST_SEARCH_MENU_ID + 1)
#define IDM_NETMENU_BASE (LAST_SEARCH_MENU_ID + 100)
#define IDM_TRACKLIST_BASE 10000
#define IDM_DISCLIST_BASE 20000
#define TYPICAL_DISPLAY_AREA 48 //this value is the offset for large fonts
#define EDGE_CURVE_WIDTH 24
#define EDGE_CURVE_HEIGHT 26
#define VENDORLOGO_WIDTH 44
#define VENDORLOGO_HEIGHT 22
#define LOGO_Y_OFFSET 10
//if button is re-hit within the time limit, don't allow it to trigger
#define MENU_TIMER_RATE 400
//ie autosearch url
#define REG_KEY_SEARCHURL TEXT("Software\\Microsoft\\Internet Explorer\\SearchUrl")
#define REG_KEY_SHELLSETTINGS REG_KEY_NEW_FRAMEWORK TEXT("\\Settings")
#define REG_KEY_SHELLENABLE TEXT("Tray")
#define PLAYCOMMAND1 TEXT("/play")
#define PLAYCOMMAND2 TEXT("-play")
#define TRAYCOMMAND1 TEXT("/tray")
#define TRAYCOMMAND2 TEXT("-tray")
//////////////////////////////////////////////////////////////////////////////////////
// Gradient stuff
#ifndef SPI_GETGRADIENTCAPTIONS
//from nt50 version of winuser.h
#define SPI_GETGRADIENTCAPTIONS 0x1008
#define COLOR_GRADIENTACTIVECAPTION 27
#define COLOR_GRADIENTINACTIVECAPTION 28
#endif
typedef BOOL (WINAPI *GRADIENTPROC)(HDC,PTRIVERTEX,ULONG,PUSHORT,ULONG,ULONG);
////////////////////////////////////////////////////////////////////////////////////////////
// Main functions in this file, forward-declared
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); BOOL LoadComponents(void); void AddComponent(IMMComponent*); void CleanUp(void); void InitComponents(HWND); BOOL CreateToolTips(HWND);
////////////////////////////////////////////////////////////////////////////////////////////
// Globals to this file
//Component information ... we only have one component now ...
//this is in here to handle eventual move to multi-component design
PCOMPNODE pCompList = NULL; //head of component list
PCOMPNODE pCompListTail = NULL; //tail of component list
PCOMPNODE pNodeCurrent = NULL; //currently selected component
int nNumComps = 0; //number of components
HWND hwndCurrentComp = NULL; //window handle of current component
HINSTANCE hInst = NULL; //global instance of exe
int g_nColorMode = COLOR_VERYHI; //global containing color mode (hi contract, 16 color, etc)
HWND hwndMain = NULL; //main window handle
HWND g_hwndTT = NULL; //tooltips
HHOOK g_hhk = NULL; //tooltips message hook
TCHAR g_tooltext[MAX_PATH]; //tooltip text holder
HANDLE hbmpMain = NULL; //main window bitmap, normal size
HANDLE hbmpMainRestore = NULL; //main window bitmap, restored size
HANDLE hbmpMainSmall = NULL; //main window bitmap, small size
HANDLE hbmpMainNoBar = NULL; //main window bitmap, normal with no title bar
BITMAP bmMain; //bitmap metrics for normal size
BITMAP bmMainRestore; //bitmap metrics for restored size
BITMAP bmMainSmall; //bitmap metrics for small size
BITMAP bmMainNoBar; //bitmap metrics for no bar size
HPALETTE hpalMain = NULL; //Palette of application
BOOL fPlaying = FALSE; //Play state of CD for play/pause
BOOL fIntro = FALSE; //Intro mode state
BOOL fShellMode = FALSE; //are we in shell icon mode?
int nCDMode = IDM_MODE_NORMAL; //Current mode of CD (starts on normal mode)
int nDispAreaOffset = 0; //Display area offset for large font mode
CustomMenu* g_pMenu = NULL; //Pointer to current custom menu
UINT nLastMenu = 0; //ID of last button to display a menu
BOOL fBlockMenu = 0; //Flag to block menu re-entry
BOOL fOptionsDlgUp = FALSE; //is options dialog active?
LPCDTITLE pSingleTitle = NULL; //Disc ID for a direct download from tree control
LPCDOPT g_pOptions = NULL; //for download callbacks when dialog is up
LPCDDATA g_pData = NULL; //for callbacks to cd when dialog is up
TCHAR szAppName[MAX_PATH/2]; //IDS_APPNAME "Deluxe CD Player"
DWORD dwLastMixID = (DWORD)-1; //Last mixer ID
HMIXEROBJ hmix = NULL; //current open mixer handle
TCHAR szLineName[MIXER_LONG_NAME_CHARS];//current volume line name
MIXERCONTROLDETAILS mixerlinedetails; //current volume details
MIXERCONTROLDETAILS mutelinedetails; //current mute details
DWORD mixervalue[2]; //current volume level
LONG lCachedBalance = 0; //last balance level
BOOL fmutevalue; //current mute value
HANDLE hMutex = NULL; //hMutex to prevent multiple instances of EXE
int g_nViewMode = VIEW_MODE_NORMAL; //view mode setting (default to normal)
WORD wDefButtonID = IDB_OPTIONS; //default button
HCURSOR hCursorMute = NULL; //mute button cursor
HMODULE hmImage = NULL; //module handle of dll with gradient function
GRADIENTPROC fnGradient = NULL; //gradient function
UINT g_uTaskbarRestart = 0; //registered message for taskbar re-creation
UINT giVolDevChange = 0; //registered message for mmsystem device change
#ifdef UNICODE
#define CANONFUNCTION "InternetCanonicalizeUrlW"
#else
#define CANONFUNCTION "InternetCanonicalizeUrlA"
#endif
////////////////////////////////////////////////////////////////////////////////////////////
// Structures and defines for custom button controls
#define NUM_BUTTONS 16
typedef struct BUTTONINFO { int id; //id of control
POINT uixy; //x, y location on screen
POINT uixy2; //x, y location when restored or small
int width; //width of control in bitmap and on screen
int height; //height of control in bitmap and on screen
int width2; //width of control on screen when restored
int nIconID; //id of icon, if any
int nToolTipID; //id of tooltip string
BOOL fBlockTab; //true = don't tab stop here
DWORD dwStyle; //style for toolkit, see mbutton.h
} BUTTONINFO, *LPBUTTONINFO; BUTTONINFO biButtons[NUM_BUTTONS];
////////////////////////////////////////////////////////////////////////////////////////////
// * GetSettings
// Reads the x and y positions of app for startup
// Also gets the view mode
////////////////////////////////////////////////////////////////////////////////////////////
void GetSettings(int& x, int& y) { x = CW_USEDEFAULT; y = CW_USEDEFAULT; g_nViewMode = VIEW_MODE_NORMAL;
LPCDOPT pOpt = GetCDOpt();
if( pOpt ) { LPCDOPTIONS pOptions = pOpt->GetCDOpts(); LPCDOPTDATA pOptionData = pOptions->pCDData;
x = pOptionData->dwWindowX; y = pOptionData->dwWindowY; g_nViewMode = pOptionData->dwViewMode; nCDMode = pOptionData->dwPlayMode; if (nCDMode < IDM_MODE_NORMAL) { nCDMode = IDM_MODE_NORMAL; } } }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetSettings
// Sets X, Y and view mode of app on shutdown
////////////////////////////////////////////////////////////////////////////////////////////
void SetSettings(int x, int y) { LPCDOPT pOpt = GetCDOpt();
if(pOpt) { LPCDOPTIONS pOptions = pOpt->GetCDOpts(); LPCDOPTDATA pOptionData = pOptions->pCDData;
pOptionData->dwWindowX = x; pOptionData->dwWindowY = y; pOptionData->dwViewMode = g_nViewMode; pOptionData->dwPlayMode = nCDMode;
pOpt->UpdateRegistry(); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * GetXOffset
// Returns 0 normally, or size of a single border if captions are turned on
////////////////////////////////////////////////////////////////////////////////////////////
int GetXOffset() { #ifndef MMFW_USE_CAPTION
return 0; #else
return GetSystemMetrics(SM_CXFIXEDFRAME); #endif
}
////////////////////////////////////////////////////////////////////////////////////////////
// * GetYOffset
// Returns 0 normally, or size of a single border if captions are turned on
////////////////////////////////////////////////////////////////////////////////////////////
int GetYOffset() { #ifndef MMFW_USE_CAPTION
return 0; #else
return GetSystemMetrics(SM_CYFIXEDFRAME); #endif
}
////////////////////////////////////////////////////////////////////////////////////////////
// * GetYOffsetCaption
// Returns 0 normally, or size of a caption if captions are turned on
////////////////////////////////////////////////////////////////////////////////////////////
int GetYOffsetCaption() { #ifndef MMFW_USE_CAPTION
return 0; #else
return GetSystemMetrics(SM_CYCAPTION); #endif
}
////////////////////////////////////////////////////////////////////////////////////////////
// * DetermineColorMode
// Sets the g_nColorMode variable for use in creating the bumps for the app
////////////////////////////////////////////////////////////////////////////////////////////
void DetermineColorMode() { g_nColorMode = COLOR_VERYHI;
HDC hdcScreen = GetDC(NULL); UINT uBPP = GetDeviceCaps(hdcScreen, PLANES) * GetDeviceCaps(hdcScreen, BITSPIXEL); ReleaseDC(NULL, hdcScreen);
switch (uBPP) { case 8 : { g_nColorMode = COLOR_256; } break;
case 4 : { g_nColorMode = COLOR_16; } break;
case 2 : { g_nColorMode = COLOR_HICONTRAST; } break; }
//check directly for accessibility mode
HIGHCONTRAST hi_con; ZeroMemory(&hi_con,sizeof(hi_con)); hi_con.cbSize = sizeof(hi_con);
SystemParametersInfo(SPI_GETHIGHCONTRAST,sizeof(hi_con),&hi_con,0);
if (hi_con.dwFlags & HCF_HIGHCONTRASTON) { g_nColorMode = COLOR_HICONTRAST; } }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetPalette
// Sets the palette for the app, generated from all bitmaps in the application and DLLs
////////////////////////////////////////////////////////////////////////////////////////////
HPALETTE SetPalette() { #define NUMPALCOLORS 94
BYTE byVals[NUMPALCOLORS][3] = { 6, 6, 6, 18, 19, 45, 25, 40, 1, 17, 46, 46, 49, 7, 7, 45, 52, 3, 49, 49, 49, 24, 24, 91, 0, 90, 8, 1, 108, 5, 55, 67, 2, 33, 76, 76, 94, 29, 24, 102, 18, 102, 93, 94, 23, 78, 78, 78, 84, 84, 108, 78, 111, 111, 109, 80, 80, 108, 107, 79, 120, 120, 120, 15, 9, 157, 17, 8, 246, 55, 93, 175, 20, 91, 231, 83, 39, 167, 92, 16, 223, 96, 94, 150, 88, 87, 217, 0, 157, 15, 0, 153, 51, 0, 190, 18, 10, 155, 120, 6, 252, 17, 9, 236, 92, 127, 135, 35, 83, 142, 117, 92, 241, 21, 87, 223, 81, 14, 171, 171, 39, 147, 223, 18, 252, 157, 15, 244, 236, 87, 137, 136, 80, 184, 184, 112, 141, 141, 106, 170, 153, 119, 171, 168, 87, 155, 213, 101, 218, 170, 90, 233, 226, 154, 19, 24, 155, 26, 109, 138, 116, 8, 170, 98, 101, 243, 18, 6, 245, 10, 96, 233, 89, 17, 229, 103, 101, 154, 39, 161, 163, 26, 249, 158, 77, 159, 149, 94, 254, 234, 20, 160, 234, 29, 242, 233, 76, 163, 218, 81, 244, 163, 151, 10, 157, 156, 102, 164, 214, 45, 165, 242, 87, 223, 174, 17, 228, 160, 77, 242, 232, 15, 233, 218, 102, 138, 138, 138, 142, 141, 176, 148, 180, 180, 174, 141, 140, 169, 130, 168, 181, 179, 136, 176, 176, 177, 172, 170, 220, 133, 207, 177, 171, 236, 233, 231, 169, 157, 252, 170, 253, 247, 243, 168, 202, 204, 204, 201, 201, 243, 208, 238, 238, 246, 212, 212, 248, 244, 198, 250, 250, 250 };
struct { LOGPALETTE lp; PALETTEENTRY ape[NUMPALCOLORS-1]; } pal;
LOGPALETTE* pLP = (LOGPALETTE*)&pal; pLP->palVersion = 0x300; pLP->palNumEntries = NUMPALCOLORS;
for (int i = 0; i < pLP->palNumEntries; i++) { pLP->palPalEntry[i].peRed = byVals[i][0]; pLP->palPalEntry[i].peGreen = byVals[i][1]; pLP->palPalEntry[i].peBlue = byVals[i][2]; pLP->palPalEntry[i].peFlags = 0; }
return (CreatePalette(pLP)); }
////////////////////////////////////////////////////////////////////////////////////////////
// * GetCurrentCDDrive
// returns the drive number of the cd that is currently selected in the cdplayer ui
////////////////////////////////////////////////////////////////////////////////////////////
int GetCurrentCDDrive() { IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { MMMEDIAID mmMedia; mmMedia.nDrive = -1; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); pAuto->Release(); return (mmMedia.nDrive); }
return -1; }
////////////////////////////////////////////////////////////////////////////////////////////
// * InitCDVol
// Sets up the mixer structures for the current cd drive
////////////////////////////////////////////////////////////////////////////////////////////
BOOL InitCDVol(HWND hwndCallback, LPCDOPTIONS pCDOpts) { //figure out which drive we're on
int nDrive = GetCurrentCDDrive();
//return if the drive is bogus
if (nDrive < 0) { return FALSE; }
//get the cdunit info from the options
CDUNIT* pCDUnit = pCDOpts->pCDUnitList; //scan the list to find the one we want
for (int index = 0; index < nDrive; index++) { pCDUnit = pCDUnit->pNext; } //check to see if we already have an open mixer
if (hmix!=NULL) { //we've been here before ... may not need to be here now,
//if both the mixer id and the control id are the same
if ((dwLastMixID == pCDUnit->dwMixID) && (mixerlinedetails.dwControlID == pCDUnit->dwVolID)) { return FALSE; }
//a change is coming, go ahead and close this mixer
mixerClose((HMIXER)hmix); }
//remember our last mixer id
dwLastMixID = pCDUnit->dwMixID;
//open the mixer
mixerOpen((HMIXER*)(&hmix),pCDUnit->dwMixID,(DWORD_PTR)hwndCallback,0,CALLBACK_WINDOW|MIXER_OBJECTF_MIXER); Volume_DeviceChange_Init(hwndCallback, pCDUnit->dwMixID); MIXERLINE mlDst; MMRESULT mmr; int newDest; ZeroMemory(&mlDst, sizeof(mlDst)); mlDst.cbStruct = sizeof(mlDst); mlDst.dwDestination = pCDUnit->dwMixID; mmr = mixerGetLineInfo((HMIXEROBJ)hmix , &mlDst , MIXER_GETLINEINFOF_DESTINATION);
//save the details of the volume line
mixerlinedetails.cbStruct = sizeof(mixerlinedetails); mixerlinedetails.dwControlID = pCDUnit->dwVolID; mixerlinedetails.cChannels = mlDst.cChannels; mixerlinedetails.hwndOwner = 0; mixerlinedetails.cMultipleItems = 0; mixerlinedetails.cbDetails = sizeof(mixervalue); mixerlinedetails.paDetails = &mixervalue[0]; //save the details of the mute line
mutelinedetails.cbStruct = sizeof(mutelinedetails); mutelinedetails.dwControlID = pCDUnit->dwMuteID; mutelinedetails.cChannels = 1; mutelinedetails.hwndOwner = 0; mutelinedetails.cMultipleItems = 0; mutelinedetails.cbDetails = sizeof(fmutevalue); mutelinedetails.paDetails = &fmutevalue;
//save the name of the volume line
_tcscpy(szLineName,pCDUnit->szVolName);
return TRUE; }
////////////////////////////////////////////////////////////////////////////////////////////
// * GetVolume
////////////////////////////////////////////////////////////////////////////////////////////
DWORD GetVolume() { //get the value of this mixer control line
ZeroMemory(mixervalue,sizeof(DWORD)*2); mixerGetControlDetails(hmix,&mixerlinedetails,MIXER_GETCONTROLDETAILSF_VALUE); return ((mixervalue[0] > mixervalue[1]) ? mixervalue[0] : mixervalue[1]); }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetVolume
////////////////////////////////////////////////////////////////////////////////////////////
void SetVolume(DWORD dwVol) { LONG lBalance = 0;
//if this is a stereo device, we need to check the balance
if (mixerlinedetails.cChannels > 1) { ZeroMemory(mixervalue,sizeof(DWORD)*2); mixerGetControlDetails(hmix,&mixerlinedetails,MIXER_GETCONTROLDETAILSF_VALUE);
LONG lDiv = (LONG)(max(mixervalue[0], mixervalue[1]) - 0);
//
// if we're pegged, don't try to calculate the balance.
//
if (mixervalue[0] == 0 && mixervalue[1] == 0) lBalance = lCachedBalance; else if (mixervalue[0] == 0) lBalance = 32; else if (mixervalue[1] == 0) lBalance = -32; else if (lDiv > 0) { lBalance = (32 * ((LONG)mixervalue[1]-(LONG)mixervalue[0])) / lDiv; //
// we always lose precision doing this.
//
if (lBalance > 0) lBalance++; if (lBalance < 0) lBalance--;
//if we lost precision above, we can get it back by checking
//the previous value of our balance. We're usually only off by
//one if this is the result of a rounding error. Otherwise,
//we probably have a different balance because the user set it.
if (((lCachedBalance - lBalance) == 1) || ((lCachedBalance - lBalance) == -1)) { lBalance = lCachedBalance; } } else lBalance = 0; }
//save this balance setting so we can use it if we're pegged later
lCachedBalance = lBalance;
//
// Recalc channels based on Balance vs. Volume
//
mixervalue[0] = dwVol; mixervalue[1] = dwVol; if (lBalance > 0) mixervalue[0] -= (lBalance * (LONG)(mixervalue[1]-0)) / 32; else if (lBalance < 0) mixervalue[1] -= (-lBalance * (LONG)(mixervalue[0]-0)) / 32;
mixerSetControlDetails(hmix,&mixerlinedetails,MIXER_SETCONTROLDETAILSF_VALUE); }
////////////////////////////////////////////////////////////////////////////////////////////
// * GetMute
////////////////////////////////////////////////////////////////////////////////////////////
BOOL GetMute() { if (mutelinedetails.dwControlID != DWORD(-1)) { mixerGetControlDetails(hmix,&mutelinedetails,MIXER_GETCONTROLDETAILSF_VALUE); } else { //mixer line doesn't exist, assume not muted
fmutevalue = FALSE; }
return (fmutevalue); }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetMute
// Implemented as a toggle from current state
////////////////////////////////////////////////////////////////////////////////////////////
void SetMute() { if (mutelinedetails.dwControlID != DWORD(-1)) { if (GetMute()) { //muted, so unmute
fmutevalue = FALSE; mixerSetControlDetails(hmix,&mutelinedetails,MIXER_SETCONTROLDETAILSF_VALUE); } else { //not muted, so mute
fmutevalue = TRUE; MMRESULT mmr = mixerSetControlDetails(hmix,&mutelinedetails,MIXER_SETCONTROLDETAILSF_VALUE); } } }
////////////////////////////////////////////////////////////////////////////////////////////
// * CanStartShell()
// Checks to see if we can launch if wanting to do so in shell mode
// Returns FALSE only if asking for "tray mode" and if reg setting is FALSE (or not present)
////////////////////////////////////////////////////////////////////////////////////////////
BOOL CanStartShell() { BOOL retval = TRUE; //default to allowing launch
fShellMode = FALSE;
//if asking for permission to launch try, see if the registry setting is there
HKEY hKeySettings; long lResult = ::RegOpenKeyEx( HKEY_CURRENT_USER, REG_KEY_SHELLSETTINGS, 0, KEY_READ, &hKeySettings );
if (lResult == ERROR_SUCCESS) { DWORD fEnable = FALSE; DWORD dwType = REG_DWORD; DWORD dwCbData = sizeof(fEnable); lResult = ::RegQueryValueEx( hKeySettings, REG_KEY_SHELLENABLE, NULL, &dwType, (LPBYTE)&fEnable, &dwCbData );
if (fEnable) { fShellMode = TRUE; }
RegCloseKey(hKeySettings);
//check for the query on the command line
TCHAR szCommand[MAX_PATH]; _tcscpy(szCommand,GetCommandLine()); _tcslwr(szCommand); if ((_tcsstr(szCommand,TRAYCOMMAND1) != NULL) || (_tcsstr(szCommand,TRAYCOMMAND2) != NULL)) { //user wants to check try status ... base on fenable
retval = (BOOL)fEnable; } } //end if regkey
return (retval); }
////////////////////////////////////////////////////////////////////////////////////////////
// * ShellOnly()
// Returns TRUE if we should not make the main UI visible.
////////////////////////////////////////////////////////////////////////////////////////////
BOOL ShellOnly() { BOOL retval = FALSE;
if (fShellMode) { //check for the query on the command line
TCHAR szCommand[MAX_PATH]; _tcscpy(szCommand,GetCommandLine()); _tcslwr(szCommand); if ((_tcsstr(szCommand,TRAYCOMMAND1) != NULL) || (_tcsstr(szCommand,TRAYCOMMAND2) != NULL)) { retval = TRUE; } }
return (retval); }
////////////////////////////////////////////////////////////////////////////////////////////
// * IsOnlyInstance
// Check to see if this is the only instance, based on the webcd mutex
////////////////////////////////////////////////////////////////////////////////////////////
BOOL IsOnlyInstance() { hMutex = CreateMutex(NULL,TRUE,WEBCD_MUTEX); if (GetLastError()==ERROR_ALREADY_EXISTS) { if (hMutex!=NULL) { ReleaseMutex(hMutex); CloseHandle(hMutex); hMutex = NULL; }
//send the command line to the app that is already running
HWND hwndFind = FindWindow(FRAMEWORK_CLASS, NULL);
if (hwndFind) { //we only want to do this if NOT "autoplayed" ... that is, if /play is on the
//command line, don't refocus us ... see bug 1244
//(the old cdplayer implements it this way, too!)
TCHAR szCommand[MAX_PATH]; _tcscpy(szCommand,GetCommandLine()); _tcslwr(szCommand); if ((_tcsstr(szCommand,PLAYCOMMAND1) == NULL) && (_tcsstr(szCommand,PLAYCOMMAND2) == NULL)) { //get the most recent "child" window
hwndFind = GetLastActivePopup(hwndFind);
//bring the window up if it is iconic
if (IsIconic(hwndFind)) { ShowWindow(hwndFind,SW_RESTORE); }
//display the window
ShowWindow(hwndFind,SW_SHOW); //this "wakes up" if in shell mode in other inst.
BringWindowToTop(hwndFind); SetForegroundWindow(hwndFind); }
//forward the command line found to the second instance,
//only if it is NOT an "autoplay" message -- we'll scan that instead
TCHAR tempCmdLine[MAX_PATH]; _tcscpy(tempCmdLine,GetCommandLine()); if (_tcslen(tempCmdLine) > 0) { if (tempCmdLine[_tcslen(tempCmdLine)-1] != TEXT('\\')) { COPYDATASTRUCT cpds; cpds.dwData = 0L; cpds.cbData = (_tcslen(GetCommandLine()) + 1) * sizeof(TCHAR); cpds.lpData = LocalAlloc(LPTR,cpds.cbData); if (cpds.lpData == NULL) { // Error - not enough memory to continue
return (FALSE); }
_tcscpy((LPTSTR)cpds.lpData, GetCommandLine());
SendMessage(hwndFind, WM_COPYDATA, 0, (LPARAM)(LPVOID)&cpds); LocalFree((HLOCAL)cpds.lpData); } //end if not autoplay command line
} //end if non-0 command line
} //end if found other window
return (FALSE); }
return (TRUE); }
////////////////////////////////////////////////////////////////////////////////////////////
// * CalculateDispAreaOffset
// Figures out how big the display area should be if we're not in standard font mode
////////////////////////////////////////////////////////////////////////////////////////////
void CalculateDispAreaOffset(IMMComponent* pComp) { if (!pComp) { return; } MMCOMPDATA mmComp; mmComp.dwSize = sizeof(mmComp); pComp->GetInfo(&mmComp);
//mmComp.rect (height) contains the min height of the display area on this monitor
//for the largest view ... other views seem to be OK with different font settings
//calculate how big the view must be compared to its normal min size
nDispAreaOffset = (mmComp.rect.bottom - mmComp.rect.top) - TYPICAL_DISPLAY_AREA;
//don't let the display area shrink, only grow
if (nDispAreaOffset < 0) { nDispAreaOffset = 0; } }
////////////////////////////////////////////////////////////////////////////////////////////
// * BuildFrameworkBitmaps
// Creates the bitmaps for normal, restored, and small sizes
////////////////////////////////////////////////////////////////////////////////////////////
BOOL BuildFrameworkBitmaps() { POINT ptSys = {SYSMENU_XOFFSET,TITLEBAR_YOFFSET_LARGE}; RECT rectMain = {0,0,480,150}; RECT rectView = {10,25,472,98}; RECT rectSeps[2] = {93,97,95,146,302,97,304,146}; rectView.bottom += nDispAreaOffset; rectMain.bottom += nDispAreaOffset;
for (UINT i = 0; i < sizeof(rectSeps) / sizeof(RECT); i++) { rectSeps[i].top += nDispAreaOffset; rectSeps[i].bottom += nDispAreaOffset; }
HDC hdcMain = GetDC(hwndMain); hbmpMain = BuildFrameBitmap(hdcMain,&rectMain,&rectView,VIEW_MODE_NORMAL,&ptSys,rectSeps,2,&bmMain);
//"no title bar" mode
ptSys.x = SYSMENU_XOFFSET; ptSys.y = TITLEBAR_YOFFSET_LARGE; SetRect(&rectMain,0,0,480,134); SetRect(&rectView,10,9,472,82); SetRect(&rectSeps[0],93,81,95,130); SetRect(&rectSeps[1],302,81,304,130); hbmpMainNoBar = BuildFrameBitmap(hdcMain,&rectMain,&rectView,VIEW_MODE_NOBAR,&ptSys,rectSeps,2,&bmMainNoBar);
//"restored" mode
ptSys.x = SYSMENU_XOFFSET; ptSys.y = TITLEBAR_YOFFSET_SMALL; SetRect(&rectMain,0,0,393,50); SetRect(&rectView,301,21,386,43); SetRect(&rectSeps[0],92,25,101,38); SetRect(&rectSeps[1],211,25,220,38); hbmpMainRestore = BuildFrameBitmap(hdcMain,&rectMain,&rectView,VIEW_MODE_RESTORE,&ptSys,rectSeps,2,&bmMainRestore);
//"very small" mode, no title bar
SetRect(&rectMain,0,0,393,38); SetRect(&rectView,301,9,386,30); SetRect(&rectSeps[0],92,13,101,26); SetRect(&rectSeps[1],211,13,220,26); hbmpMainSmall = BuildFrameBitmap(hdcMain,&rectMain,&rectView,VIEW_MODE_SMALL,&ptSys,rectSeps,2,&bmMainSmall);
ReleaseDC(hwndMain,hdcMain);
return TRUE; }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetCurvedEdges
// Changes clipping region of an HWND to have curved corners
////////////////////////////////////////////////////////////////////////////////////////////
void SetCurvedEdges(HWND hwnd) { RECT rect; GetWindowRect(hwnd,&rect);
//set the rect to "client" coordinates
rect.bottom = rect.bottom - rect.top; rect.right = rect.right - rect.left; rect.top = 0; rect.left = 0; HRGN region = CreateRoundRectRgn(GetXOffset(), GetYOffsetCaption() + GetYOffset(), (rect.right - GetXOffset())+1, (rect.bottom - GetYOffset())+1, EDGE_CURVE_WIDTH, EDGE_CURVE_HEIGHT);
SetWindowRgn(hwnd,region,TRUE); }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetNoBarMode(HWND hwnd)
// Changes the view mode to have no title bar
////////////////////////////////////////////////////////////////////////////////////////////
void SetNoBarMode(HWND hwnd) { g_nViewMode = VIEW_MODE_NOBAR;
HDWP hdwp = BeginDeferWindowPos(NUM_BUTTONS+3);
//move/size/hide buttons
for (int i = 0; i < NUM_BUTTONS; i++) { hdwp = DeferWindowPos(hdwp,GetDlgItem(hwnd,biButtons[i].id),hwnd, biButtons[i].uixy.x, biButtons[i].uixy.y - (bmMain.bmHeight - bmMainNoBar.bmHeight), biButtons[i].width, biButtons[i].height, SWP_NOACTIVATE|SWP_NOZORDER);
if (biButtons[i].dwStyle == MBS_SYSTEMTYPE) { ShowWindow(GetDlgItem(hwnd,biButtons[i].id),SW_HIDE); } }
//move volume and mute
hdwp = DeferWindowPos(hdwp,GetDlgItem(hwnd,IDB_VOLUME),hwnd, 403, (93+nDispAreaOffset) - (bmMain.bmHeight - bmMainNoBar.bmHeight), 45, 45, SWP_NOACTIVATE|SWP_NOZORDER);
hdwp = DeferWindowPos(hdwp,GetDlgItem(hwnd,IDB_MUTE),hwnd, 450, (122+nDispAreaOffset) - (bmMain.bmHeight - bmMainNoBar.bmHeight), 13, 13, SWP_NOACTIVATE|SWP_NOZORDER);
//move display screen
hdwp = DeferWindowPos(hdwp,hwndCurrentComp,hwnd,24,32-(bmMain.bmHeight - bmMainNoBar.bmHeight),431,56+nDispAreaOffset,SWP_NOACTIVATE|SWP_NOZORDER); InvalidateRect(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),NULL,TRUE);
//size main window
int sx = GetXOffset()*2; int sy = (GetYOffset()*2) + GetYOffsetCaption(); SetWindowPos(hwnd,NULL,0,0, bmMainNoBar.bmWidth+sx, bmMainNoBar.bmHeight+sy, SWP_NOMOVE|SWP_NOZORDER);
SetCurvedEdges(hwnd);
InvalidateRect(hwnd,NULL,TRUE); EndDeferWindowPos(hdwp); }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetRestoredMode
// Changes the view mode to restored
////////////////////////////////////////////////////////////////////////////////////////////
void SetRestoredMode(HWND hwnd) { if (g_nViewMode == VIEW_MODE_NORMAL) { //pre-blit the new button sizes
CMButton* pButton; pButton = GetMButtonFromID(hwnd,IDB_PLAY); pButton->PreDrawUpstate(biButtons[2].width2,biButtons[2].height); pButton = GetMButtonFromID(hwnd,IDB_STOP); pButton->PreDrawUpstate(biButtons[3].width2,biButtons[3].height); pButton = GetMButtonFromID(hwnd,IDB_EJECT); pButton->PreDrawUpstate(biButtons[4].width2,biButtons[4].height); pButton = GetMButtonFromID(hwnd,IDB_TRACK); pButton->PreDrawUpstate(biButtons[10].width2,biButtons[10].height); }
g_nViewMode = VIEW_MODE_RESTORE;
HDWP hdwp = BeginDeferWindowPos(NUM_BUTTONS+2);
//move/size/hide buttons
for (int i = 0; i < NUM_BUTTONS; i++) { if (biButtons[i].uixy2.x != 0) { hdwp = DeferWindowPos(hdwp,GetDlgItem(hwnd,biButtons[i].id),hwnd, biButtons[i].uixy2.x, biButtons[i].uixy2.y, biButtons[i].width2, biButtons[i].height, SWP_NOACTIVATE|SWP_NOZORDER); } else { ShowWindow(GetDlgItem(hwnd,biButtons[i].id),SW_HIDE); //prevents tabbing
}
if (biButtons[i].dwStyle == MBS_SYSTEMTYPE) { ShowWindow(GetDlgItem(hwnd,biButtons[i].id),SW_SHOW); } }
//move display screen
hdwp = DeferWindowPos(hdwp,hwndCurrentComp,hwnd,303,24,81,17,SWP_NOACTIVATE|SWP_NOZORDER); InvalidateRect(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),NULL,TRUE);
//size main window
int sx = GetXOffset()*2; int sy = (GetYOffset()*2) + GetYOffsetCaption(); SetWindowPos(hwnd,NULL,0,0, bmMainRestore.bmWidth+sx, bmMainRestore.bmHeight+sy, SWP_NOMOVE|SWP_NOZORDER);
ShowWindow(GetDlgItem(hwnd,IDB_VOLUME),SW_HIDE); ShowWindow(GetDlgItem(hwnd,IDB_MUTE),SW_HIDE); ShowWindow(GetDlgItem(hwnd,IDB_SET_NORMAL_MODE),SW_SHOW); ShowWindow(GetDlgItem(hwnd,IDB_SET_TINY_MODE),SW_HIDE);
SetCurvedEdges(hwnd);
InvalidateRect(hwnd,NULL,TRUE); EndDeferWindowPos(hdwp); }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetNormalMode
// Changes the view mode to normal
////////////////////////////////////////////////////////////////////////////////////////////
void SetNormalMode(HWND hwnd) { //going from restore to max
g_nViewMode = VIEW_MODE_NORMAL;
//pre-blit the new button sizes
CMButton* pButton; pButton = GetMButtonFromID(hwnd,IDB_PLAY); pButton->PreDrawUpstate(biButtons[2].width,biButtons[2].height); pButton = GetMButtonFromID(hwnd,IDB_STOP); pButton->PreDrawUpstate(biButtons[3].width,biButtons[3].height); pButton = GetMButtonFromID(hwnd,IDB_EJECT); pButton->PreDrawUpstate(biButtons[4].width,biButtons[4].height); pButton = GetMButtonFromID(hwnd,IDB_TRACK); pButton->PreDrawUpstate(biButtons[10].width,biButtons[10].height);
HDWP hdwp = BeginDeferWindowPos(NUM_BUTTONS+3);
//move/size/show buttons
for (int i = 0; i < NUM_BUTTONS; i++) { ShowWindow(GetDlgItem(hwnd,biButtons[i].id),SW_SHOW); hdwp = DeferWindowPos(hdwp,GetDlgItem(hwnd,biButtons[i].id),hwnd, biButtons[i].uixy.x, biButtons[i].uixy.y, biButtons[i].width, biButtons[i].height, SWP_NOACTIVATE|SWP_NOZORDER); }
//move volume and mute
hdwp = DeferWindowPos(hdwp,GetDlgItem(hwnd,IDB_VOLUME),hwnd, 403, 93+nDispAreaOffset, 45, 45, SWP_NOACTIVATE|SWP_NOZORDER);
hdwp = DeferWindowPos(hdwp,GetDlgItem(hwnd,IDB_MUTE),hwnd, 450, 122+nDispAreaOffset, 13, 13, SWP_NOACTIVATE|SWP_NOZORDER);
//move display screen
hdwp = DeferWindowPos(hdwp,hwndCurrentComp,hwnd,24,32,431,56+nDispAreaOffset,SWP_NOACTIVATE|SWP_NOZORDER); InvalidateRect(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),NULL,TRUE);
ShowWindow(GetDlgItem(hwnd,IDB_VOLUME),SW_SHOW); ShowWindow(GetDlgItem(hwnd,IDB_MUTE),SW_SHOW); ShowWindow(GetDlgItem(hwnd,IDB_SET_NORMAL_MODE),SW_HIDE); ShowWindow(GetDlgItem(hwnd,IDB_SET_TINY_MODE),SW_SHOW);
//Resize window
int sx = GetXOffset()*2; int sy = (GetYOffset()*2) + GetYOffsetCaption(); SetWindowPos(hwnd,NULL,0,0, bmMain.bmWidth+sx, bmMain.bmHeight+sy, SWP_NOMOVE|SWP_NOZORDER);
SetCurvedEdges(hwnd);
InvalidateRect(hwnd,NULL,TRUE); EndDeferWindowPos(hdwp); }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetSmallMode
// Changes the view mode to small
////////////////////////////////////////////////////////////////////////////////////////////
void SetSmallMode(HWND hwnd) { g_nViewMode = VIEW_MODE_SMALL;
HDWP hdwp = BeginDeferWindowPos(NUM_BUTTONS+2);
//move/size/hide buttons
for (int i = 0; i < NUM_BUTTONS; i++) { if (biButtons[i].uixy2.x != 0) { hdwp = DeferWindowPos(hdwp,GetDlgItem(hwnd,biButtons[i].id),hwnd, biButtons[i].uixy2.x, biButtons[i].uixy2.y - (bmMainRestore.bmHeight - bmMainSmall.bmHeight), biButtons[i].width2, biButtons[i].height, SWP_NOACTIVATE|SWP_NOZORDER); }
if (biButtons[i].dwStyle == MBS_SYSTEMTYPE) { ShowWindow(GetDlgItem(hwnd,biButtons[i].id),SW_HIDE); } }
//move display screen
hdwp = DeferWindowPos(hdwp,hwndCurrentComp,hwnd,303,24-(bmMainRestore.bmHeight - bmMainSmall.bmHeight),81,17,SWP_NOACTIVATE|SWP_NOZORDER); InvalidateRect(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),NULL,TRUE);
//size main window
int sx = GetXOffset()*2; int sy = (GetYOffset()*2) + GetYOffsetCaption(); SetWindowPos(hwnd,NULL,0,0, bmMainSmall.bmWidth+sx, bmMainSmall.bmHeight+sy, SWP_NOMOVE|SWP_NOZORDER);
SetCurvedEdges(hwnd);
InvalidateRect(hwnd,NULL,TRUE); EndDeferWindowPos(hdwp); }
////////////////////////////////////////////////////////////////////////////////////////////
// * AdjustForMultimon
// Will move the app onto the primary display if its x,y settings are not on a monitor
////////////////////////////////////////////////////////////////////////////////////////////
void AdjustForMultimon(HWND hwnd) { RECT rect; GetWindowRect(hwnd,&rect);
int cxWnd = rect.right - rect.left; int cyWnd = rect.bottom - rect.top;
// Check if the app's rect is visible is any of the monitors
if( NULL == MonitorFromRect( &rect, 0L ) ) { //The window is not visible. Let's center it in the primary monitor.
//Note: the window could be in this state if (1) the display mode was changed from
//a high-resolution to a lower resolution, with the cdplayer in the corner. Or,
//(2) the multi-mon configuration was rearranged.
RECT rcDesktop;
GetWindowRect( GetDesktopWindow(), &rcDesktop ); int cxDesktop = (rcDesktop.right - rcDesktop.left); int cyDesktop = (rcDesktop.bottom - rcDesktop.top);
int x = (cxDesktop - cxWnd) / 2; //center in x
int y = (cyDesktop - cyWnd) / 3; //and a little towards the top
SetWindowPos(hwnd,NULL,x,y,0,0,SWP_NOSIZE|SWP_NOZORDER); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * WinMain
// Entry point for application
////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstEXE, HINSTANCE hInstEXEPrev, PSTR lpszCmdLine, int nCmdShow) { //first thing, must check tray icon state
if (!CanStartShell()) { return (0); } if (!IsOnlyInstance()) { //can't have more than one of these
return (0); } //save the global hinstance
hInst = hInstEXE;
DetermineColorMode(); //start our linked list of components
pCompList = new COMPNODE; ZeroMemory(pCompList,sizeof(COMPNODE)); pCompListTail = pCompList;
//load the app name
LoadString(hInstEXE,IDS_APPNAME,szAppName,sizeof(szAppName)/sizeof(TCHAR));
//init the networking component (this just inits some crit sections)
CDNET_Init(hInstEXE);
//load components from registry
if (!LoadComponents()) { CleanUp(); return (0); } //register our main window class
WNDCLASSEX wc; ATOM atomClassName; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.lpszClassName = FRAMEWORK_CLASS; wc.lpfnWndProc = MainWndProc; wc.hInstance = hInstEXE; wc.style = CS_DBLCLKS; wc.hIcon = LoadIcon(hInstEXE, MAKEINTRESOURCE(IDI_MMFW)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.hIconSm = (HICON)LoadImage(hInstEXE, MAKEINTRESOURCE(IDI_MMFW), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); atomClassName = RegisterClassEx(&wc);
int x = CW_USEDEFAULT; int y = CW_USEDEFAULT; GetSettings(x,y);
hpalMain = SetPalette();
#ifndef MMFW_USE_CAPTION
DWORD dwStyle = WS_POPUP|WS_SYSMENU|WS_MINIMIZEBOX|WS_CLIPCHILDREN; #else
DWORD dwStyle = WS_POPUP|WS_SYSMENU|WS_MINIMIZEBOX|WS_CAPTION|WS_CLIPCHILDREN; #endif
//create our main window
HWND hwnd = CreateWindowEx(WS_EX_APPWINDOW, MAKEINTATOM(atomClassName), szAppName, dwStyle, x, y, 0, 0, NULL, NULL, hInstEXE, NULL);
if (hwnd == NULL) { //major failure here!
CleanUp(); return 0; }
hwndMain = hwnd;
//tell our sink what our main window is
CFrameworkNotifySink::m_hwndTitle = hwnd;
//create the bitmaps of the main ui
if (!BuildFrameworkBitmaps()) { //failure -- can't create bitmaps for framework
CleanUp(); return 0; }
int bmWidth = bmMain.bmWidth; int bmHeight = bmMain.bmHeight;
//set window size to match the width and height of the correct mode's bitmap
switch (g_nViewMode) { case VIEW_MODE_RESTORE : { bmWidth = bmMainRestore.bmWidth; bmHeight = bmMainRestore.bmHeight; } break;
case VIEW_MODE_SMALL : { bmWidth = bmMainSmall.bmWidth; bmHeight = bmMainSmall.bmHeight; } break;
case VIEW_MODE_NOBAR : { bmWidth = bmMainNoBar.bmWidth; bmHeight = bmMainNoBar.bmHeight; } break; }
int sx = GetXOffset()*2; int sy = (GetYOffset()*2) + GetYOffsetCaption(); SetWindowPos(hwnd,NULL,0,0,bmWidth+sx,bmHeight+sy,SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
//check the window pos against multimon
AdjustForMultimon(hwnd);
SetCurvedEdges(hwnd);
//Send us a message to set the initial mode of the player
SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(nCDMode,0),0);
//show us!
if (!ShellOnly()) { ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd);
LPCDDATA pCDData = GetCDData();
if (pCDData) { pCDData->Initialize(hwnd); pCDData->CheckDatabase(hwnd); } }
if (fShellMode) { CreateShellIcon(hInst,hwnd,pNodeCurrent,szAppName); }
//main message loop
MSG msg;
for (;;) { if (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)) { if (msg.message == WM_QUIT) break;
/*
if (hAccelApp && TranslateAccelerator(hwndApp, hAccelApp, &msg)) continue; */
if (!IsDialogMessage(hwnd,&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } //end if dialg msg
} else { WaitMessage(); } } //end for
//get outta here!
CleanUp();
return ((int)msg.wParam); }
////////////////////////////////////////////////////////////////////////////////////////////
// * ShowNewComponentWindow
// Displays the chosen component
// (Sort of a holdover from the old multi-component days, but it also serves to
// initialize the first component loaded)
////////////////////////////////////////////////////////////////////////////////////////////
void ShowNewComponentWindow(PCOMPNODE pNode, HWND hwnd) { if (pNode == NULL) { return; }
//don't bother if we're already there
if (pNode->hwndComp == hwndCurrentComp) { return; } if (hwndCurrentComp != NULL) { ShowWindow(hwndCurrentComp,SW_HIDE); }
hwndCurrentComp = pNode->hwndComp; ShowWindow(hwndCurrentComp,SW_SHOW);
pNodeCurrent = pNode;
MMCOMPDATA mmComp; mmComp.dwSize = sizeof(mmComp); pNode->pComp->GetInfo(&mmComp);
if (_tcslen(pNode->szTitle)==0) { _tcscpy(pNode->szTitle,mmComp.szName); }
SetWindowText(hwnd,szAppName);
//also set icons
if (mmComp.hiconLarge != NULL) { SendMessage(hwnd, WM_SETICON, TRUE, (LPARAM)mmComp.hiconLarge); }
if (mmComp.hiconSmall != NULL) { SendMessage(hwnd, WM_SETICON, FALSE, (LPARAM)mmComp.hiconSmall); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * InitButtonProperties
// Set up the button info structure for all the transport buttons
//
// Should Fix: this is pretty ugly and hard-coded. Implement to read from some kind of
// easily-editable resource for when layout changes come?
////////////////////////////////////////////////////////////////////////////////////////////
void InitButtonProperties() { //set up each button's properties
ZeroMemory(biButtons,sizeof(BUTTONINFO)*NUM_BUTTONS);
//order of buttons in this array affects the tab order
biButtons[0].id = IDB_OPTIONS; biButtons[0].nToolTipID = IDB_TT_OPTIONS; biButtons[0].uixy.x = 11; biButtons[0].uixy.y = 102 + nDispAreaOffset; biButtons[0].width = 76; biButtons[0].height = 19; biButtons[0].uixy2.x = 9; biButtons[0].uixy2.y = 23; biButtons[0].width2 = 76; biButtons[0].dwStyle = MBS_STANDARDLEFT | MBS_DROPRIGHT;
biButtons[1].id = IDB_NET; biButtons[1].nToolTipID = IDB_TT_NET; biButtons[1].uixy.x = 11; biButtons[1].uixy.y = 125 + nDispAreaOffset; biButtons[1].width = 76; biButtons[1].height = 19; biButtons[1].dwStyle = MBS_STANDARDLEFT | MBS_DROPRIGHT;
biButtons[2].id = IDB_PLAY; biButtons[2].nToolTipID = IDB_TT_PLAY; biButtons[2].uixy.x = 103; biButtons[2].uixy.y = 102 + nDispAreaOffset; biButtons[2].width = 64; biButtons[2].height = 19; biButtons[2].uixy2.x = 102; biButtons[2].uixy2.y = 23; biButtons[2].width2 = 34; biButtons[2].dwStyle = MBS_STANDARDLEFT | MBS_STANDARDRIGHT; biButtons[2].nIconID = IDI_ICON_PLAY;
biButtons[3].id = IDB_STOP; biButtons[3].nToolTipID = IDB_TT_STOP; biButtons[3].uixy.x = 174; biButtons[3].uixy.y = 102 + nDispAreaOffset; biButtons[3].width = 64; biButtons[3].height = 19; biButtons[3].uixy2.x = 136; biButtons[3].uixy2.y = 23; biButtons[3].width2 = 34; biButtons[3].dwStyle = MBS_STANDARDLEFT | MBS_STANDARDRIGHT; biButtons[3].nIconID = IDI_ICON_STOP;
biButtons[4].id = IDB_EJECT; biButtons[4].nToolTipID = IDB_TT_EJECT; biButtons[4].uixy.x = 245; biButtons[4].uixy.y = 102 + nDispAreaOffset; biButtons[4].width = 51; biButtons[4].height = 19; biButtons[4].uixy2.x = 170; biButtons[4].uixy2.y = 23; biButtons[4].width2 = 34; biButtons[4].dwStyle = MBS_STANDARDLEFT | MBS_STANDARDRIGHT; biButtons[4].nIconID = IDI_ICON_EJECT;
biButtons[5].id = IDB_REW; biButtons[5].nToolTipID = IDB_TT_REW; biButtons[5].uixy.x = 103; biButtons[5].uixy.y = 125 + nDispAreaOffset; biButtons[5].width = 33; biButtons[5].height = 19; biButtons[5].dwStyle = MBS_STANDARDLEFT | MBS_TOGGLERIGHT; biButtons[5].nIconID = IDI_ICON_REW;
biButtons[6].id = IDB_FFWD; biButtons[6].nToolTipID = IDB_TT_FFWD; biButtons[6].uixy.x = 136; biButtons[6].uixy.y = 125 + nDispAreaOffset; biButtons[6].width = 31; biButtons[6].height = 19; biButtons[6].dwStyle = MBS_TOGGLELEFT | MBS_STANDARDRIGHT; biButtons[6].nIconID = IDI_ICON_FFWD;
biButtons[7].id = IDB_PREVTRACK; biButtons[7].nToolTipID = IDB_TT_PREVTRACK; biButtons[7].uixy.x = 174; biButtons[7].uixy.y = 125 + nDispAreaOffset; biButtons[7].width = 33; biButtons[7].height = 19; biButtons[7].dwStyle = MBS_STANDARDLEFT | MBS_TOGGLERIGHT; biButtons[7].nIconID = IDI_ICON_PREV;
biButtons[8].id = IDB_NEXTTRACK; biButtons[8].nToolTipID = IDB_TT_NEXTTRACK; biButtons[8].uixy.x = 207; biButtons[8].uixy.y = 125 + nDispAreaOffset; biButtons[8].width = 31; biButtons[8].height = 19; biButtons[8].dwStyle = MBS_TOGGLELEFT | MBS_STANDARDRIGHT; biButtons[8].nIconID = IDI_ICON_NEXT;
biButtons[9].id = IDB_MODE; biButtons[9].nToolTipID = IDB_TT_MODE; biButtons[9].uixy.x = 245; biButtons[9].uixy.y = 125 + nDispAreaOffset; biButtons[9].width = 51; biButtons[9].height = 19; biButtons[9].dwStyle = MBS_STANDARDLEFT | MBS_DROPRIGHT; biButtons[9].nIconID = IDI_MODE_NORMAL;
biButtons[10].id = IDB_TRACK; biButtons[10].nToolTipID = IDB_TT_TRACK; biButtons[10].uixy.x = 312; biButtons[10].uixy.y = 102 + nDispAreaOffset; biButtons[10].width = 76; biButtons[10].height = 19; biButtons[10].uixy2.x = 221; biButtons[10].uixy2.y = 23; biButtons[10].width2 = 72; biButtons[10].dwStyle = MBS_STANDARDLEFT | MBS_DROPRIGHT;
biButtons[11].id = IDB_DISC; biButtons[11].nToolTipID = IDB_TT_DISC; biButtons[11].uixy.x = 312; biButtons[11].uixy.y = 125 + nDispAreaOffset; biButtons[11].width = 76; biButtons[11].height = 19; biButtons[11].dwStyle = MBS_STANDARDLEFT | MBS_DROPRIGHT;
biButtons[12].id = IDB_CLOSE; biButtons[12].nToolTipID = IDB_TT_CLOSE; biButtons[12].uixy.x = 456; biButtons[12].uixy.y = 7; biButtons[12].width = 15; biButtons[12].height = 14; biButtons[12].fBlockTab = TRUE; biButtons[12].uixy2.x = 371; biButtons[12].uixy2.y = 4; biButtons[12].width2 = 15; biButtons[12].dwStyle = MBS_SYSTEMTYPE; biButtons[12].nIconID = IDB_CLOSE;
biButtons[13].id = IDB_MINIMIZE; biButtons[13].nToolTipID = IDB_TT_MINIMIZE; biButtons[13].uixy.x = 427; biButtons[13].uixy.y = 7; biButtons[13].width = 14; biButtons[13].height = 14; biButtons[13].fBlockTab = TRUE; biButtons[13].uixy2.x = 343; biButtons[13].uixy2.y = 4; biButtons[13].width2 = 14; biButtons[13].dwStyle = MBS_SYSTEMTYPE; biButtons[13].nIconID = IDB_MINIMIZE;
biButtons[14].id = IDB_SET_TINY_MODE; biButtons[14].nToolTipID = IDB_TT_RESTORE; biButtons[14].uixy.x = 442; biButtons[14].uixy.y = 7; biButtons[14].width = 14; biButtons[14].height = 14; biButtons[14].fBlockTab = TRUE; biButtons[14].uixy2.x = 357; biButtons[14].uixy2.y = 4; biButtons[14].width2 = 14; biButtons[14].dwStyle = MBS_SYSTEMTYPE; biButtons[14].nIconID = IDB_SET_TINY_MODE;
biButtons[15].id = IDB_SET_NORMAL_MODE; biButtons[15].nToolTipID = IDB_TT_MAXIMIZE; biButtons[15].uixy.x = 442; biButtons[15].uixy.y = 7; biButtons[15].width = 14; biButtons[15].height = 14; biButtons[15].fBlockTab = TRUE; biButtons[15].uixy2.x = 357; biButtons[15].uixy2.y = 4; biButtons[15].width2 = 14; biButtons[15].dwStyle = MBS_SYSTEMTYPE; biButtons[15].nIconID = IDB_SET_NORMAL_MODE; }
////////////////////////////////////////////////////////////////////////////////////////////
// * CreateMuteButton
// Make the little mute button guy
////////////////////////////////////////////////////////////////////////////////////////////
void CreateMuteButton(HWND hwndOwner) { //first load mute button's cursor
hCursorMute = LoadCursor(hInst,MAKEINTRESOURCE(IDC_MUTE)); CMButton* pButton = NULL;
TCHAR szCaption[MAX_PATH]; LoadString(hInst,IDB_MUTE,szCaption,sizeof(szCaption)/sizeof(TCHAR)); int yOffset = 122+nDispAreaOffset; if (g_nViewMode == VIEW_MODE_NOBAR) { yOffset -= 16; }
pButton = CreateMButton(szCaption,IDB_MUTE,WS_VISIBLE|WS_TABSTOP, MBS_SYSTEMTYPE, 450, yOffset, 13, 13, hwndOwner, FALSE, //create original, not subclass
IDB_MUTE, IDB_TT_MUTE, hInst);
//hide this button in small mode
if ((g_nViewMode==VIEW_MODE_RESTORE)||((g_nViewMode==VIEW_MODE_SMALL))) { ShowWindow(pButton->GetHWND(),SW_HIDE); }
//set up tool tip
TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_IDISHWND; ti.hwnd = hwndOwner; ti.uId = (UINT_PTR)(pButton->GetHWND()); ti.hinst = hInst; ti.lpszText = LPSTR_TEXTCALLBACK; SendMessage(g_hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
//make sure button is in correct state if muted on start up
SendMessage(pButton->GetHWND(),BM_SETSTATE,(WPARAM)GetMute(),0); SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_MUTE,0,GetMute()); }
////////////////////////////////////////////////////////////////////////////////////////////
// * CreateVolumeKnob
// Put up the volume knob that EVERYONE LOVES
////////////////////////////////////////////////////////////////////////////////////////////
void CreateVolumeKnob(HWND hwndOwner) { LPCDOPT pOpt = GetCDOpt(); if( pOpt ) { LPCDOPTIONS pCDOpts = pOpt->GetCDOpts(); InitCDVol(hwndOwner,pCDOpts);
//ok, this is bad, but I have the options here and the only other thing
//I need from them is the "topmost" setting for the main window ...
//so I'll go ahead and take care of that here rather than recreating
//this struct somewhere or making it global.
SetWindowPos(hwndOwner, pCDOpts->pCDData->fTopMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); DWORD dwVol = GetVolume(); int yOffset = 93+nDispAreaOffset; if (g_nViewMode == VIEW_MODE_NOBAR) { yOffset -= 16; }
CKnob* pKnob = CreateKnob(WS_VISIBLE | WS_TABSTOP, 0xFFFF, dwVol, 403, yOffset, 45, 45, hwndOwner, IDB_VOLUME, hInst);
TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_IDISHWND; ti.hwnd = hwndOwner; ti.uId = (UINT_PTR)(pKnob->GetHWND()); ti.hinst = hInst; ti.lpszText = LPSTR_TEXTCALLBACK; SendMessage(g_hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
if ((g_nViewMode==VIEW_MODE_RESTORE)||((g_nViewMode==VIEW_MODE_SMALL))) { ShowWindow(pKnob->GetHWND(),SW_HIDE); } CreateMuteButton(hwndOwner); } else { //fix for bug 886 ... turns off mute line in case of cdopt.dll failure
SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_MUTE,0,FALSE); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * CreateButtonWindows
// Put the transport control buttons onto the screen
////////////////////////////////////////////////////////////////////////////////////////////
void CreateButtonWindows(HWND hwndOwner) { InitMButtons(hInst,hwndOwner);
InitButtonProperties();
for (int i = 0; i < NUM_BUTTONS; i++) { DWORD wsTab = biButtons[i].fBlockTab ? 0 : WS_TABSTOP;
CMButton* pButton = NULL; TCHAR szCaption[MAX_PATH]; LoadString(hInst,biButtons[i].id,szCaption,sizeof(szCaption)/sizeof(TCHAR)); int x, y, width; int nView = SW_SHOW;
switch (g_nViewMode) { case VIEW_MODE_NORMAL : { x = biButtons[i].uixy.x; y = biButtons[i].uixy.y; width = biButtons[i].width; if (biButtons[i].id == IDB_SET_NORMAL_MODE) { nView = SW_HIDE; } } break;
case VIEW_MODE_NOBAR : { x = biButtons[i].uixy.x; y = biButtons[i].uixy.y - 16; width = biButtons[i].width; if (biButtons[i].dwStyle == MBS_SYSTEMTYPE) { nView = SW_HIDE; } } break;
case VIEW_MODE_RESTORE : { x = biButtons[i].uixy2.x; y = biButtons[i].uixy2.y; width = biButtons[i].width2; if (biButtons[i].id == IDB_SET_TINY_MODE) { nView = SW_HIDE; } } break;
case VIEW_MODE_SMALL : { x = biButtons[i].uixy2.x; y = biButtons[i].uixy2.y - 12; width = biButtons[i].width2; } break; }
//for buttons that aren't going to blit in smaller modes
if (width == 0) { //set to normal width
width = biButtons[i].width; nView = SW_HIDE; }
pButton = CreateMButton(szCaption,biButtons[i].nIconID,WS_VISIBLE|wsTab, biButtons[i].dwStyle, x, y, width, biButtons[i].height, hwndOwner, FALSE, //create original, not subclass
biButtons[i].id, biButtons[i].nToolTipID, hInst);
//hide system buttons in small mode
if (g_nViewMode == VIEW_MODE_SMALL) { if (biButtons[i].dwStyle == MBS_SYSTEMTYPE) { ShowWindow(pButton->GetHWND(),SW_HIDE); } }
if (nView == SW_HIDE) { ShowWindow(pButton->GetHWND(),SW_HIDE); }
TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_IDISHWND; ti.hwnd = hwndOwner; ti.uId = (UINT_PTR)(pButton->GetHWND()); ti.hinst = hInst; ti.lpszText = LPSTR_TEXTCALLBACK; SendMessage(g_hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
//set focus and default to first control
if (i == 0) { SetFocus(pButton->GetHWND()); } } //end for buttons
SendMessage(hwndOwner, DM_SETDEFID, biButtons[0].id, 0); }
////////////////////////////////////////////////////////////////////////////////////////////
// * VolPersistTimerProc
// When we're done displaying the volume, tell CD player to repaint normally
////////////////////////////////////////////////////////////////////////////////////////////
void CALLBACK VolPersistTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) { //turn on painting in the led window
SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_INFO_PAINT,1,0); InvalidateRect(hwndCurrentComp,NULL,FALSE); KillTimer(hwnd,idEvent); }
////////////////////////////////////////////////////////////////////////////////////////////
// * IsNetOK
// Returns TRUE if it is OK to do networking-related stuff (i.e. the database is all right)
////////////////////////////////////////////////////////////////////////////////////////////
BOOL IsNetOK(HWND hwnd) { DWORD dwRet = FALSE; LPCDDATA pData = GetCDData(); if (pData) { if (SUCCEEDED(pData->CheckDatabase(hwnd))) { dwRet = TRUE; } }
return (dwRet); }
////////////////////////////////////////////////////////////////////////////////////////////
// * IsDownloading
// Check on the networking thread to see if it is active
////////////////////////////////////////////////////////////////////////////////////////////
BOOL IsDownloading() { BOOL retcode = FALSE; ICDNet* pICDNet = NULL; if (SUCCEEDED(CDNET_CreateInstance(NULL, IID_ICDNet, (void**)&pICDNet))) { retcode = pICDNet->IsDownloading(); pICDNet->Release(); }
return (retcode); }
////////////////////////////////////////////////////////////////////////////////////////////
// * CancelDownload
// Tell the networking thread to quit as soon as it can
////////////////////////////////////////////////////////////////////////////////////////////
void CancelDownload() { ICDNet* pICDNet = NULL; if (SUCCEEDED(CDNET_CreateInstance(NULL, IID_ICDNet, (void**)&pICDNet))) { pICDNet->CancelDownload(); pICDNet->Release(); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * EndDownloadThreads
// Kills the download threads on shutdown
////////////////////////////////////////////////////////////////////////////////////////////
void EndDownloadThreads() { //optimization: don't bother if CDNET.DLL is not loaded
if (GetModuleHandle(TEXT("CDNET.DLL"))) { if (IsDownloading()) { CancelDownload(); } } }
////////////////////////////////////////////////////////////////////////////////////////////
// * MenuButtonTimerProc
// Big ol' hack to make the menus that drop down from button seem like real menus ...
// if the user hits the button before the timeout time, we don't redisplay the menu
////////////////////////////////////////////////////////////////////////////////////////////
void CALLBACK MenuButtonTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) { //single-shot timer turns off the "block menu" flag
fBlockMenu = FALSE; nLastMenu = 0; KillTimer(hwnd,idEvent); }
////////////////////////////////////////////////////////////////////////////////////////////
// * BlockMenu
// Turns on the button/menu hack
////////////////////////////////////////////////////////////////////////////////////////////
void BlockMenu(HWND hwnd) { fBlockMenu = TRUE; SetTimer(hwnd,nLastMenu,MENU_TIMER_RATE,(TIMERPROC)MenuButtonTimerProc); }
////////////////////////////////////////////////////////////////////////////////////////////
// * NormalizeNameForMenuDisplay
// This function turns a string like "Twist & Shout" into
// "Twist && Shout" because otherwise it will look like
// "Twist _Shout" in the menu due to the accelerator char
//
// Defined in cdplayer.lib
//
////////////////////////////////////////////////////////////////////////////////////////////
extern "C" void NormalizeNameForMenuDisplay(TCHAR* szInput, TCHAR* szOutput, DWORD cbLen);
////////////////////////////////////////////////////////////////////////////////////////////
// * DrawButton
// Response to WM_DRAWITEM on buttons
////////////////////////////////////////////////////////////////////////////////////////////
void DrawButton(UINT idCtl, LPDRAWITEMSTRUCT lpdis) { CMButton* pButton = GetMButtonFromID(hwndMain,idCtl);
if (pButton!=NULL) { pButton->Draw(lpdis); }
//special case ... if the button is one of the scanner buttons,
//forward this message to the component
if ((idCtl==IDB_REW) || (idCtl==IDB_FFWD)) { switch (idCtl) { case IDB_REW : idCtl = IDM_PLAYBAR_SKIPBACK; break; case IDB_FFWD : idCtl = IDM_PLAYBAR_SKIPFORE; break; } lpdis->CtlID = idCtl; SendMessage(hwndCurrentComp,WM_DRAWITEM,idCtl,(LPARAM)lpdis); }
if ( (idCtl == IDB_OPTIONS) || (idCtl == IDB_MODE) || (idCtl == IDB_TRACK) || (idCtl == IDB_NET) || (idCtl == IDB_DISC) ) { if (lpdis->itemState & ODS_SELECTED) { if ((fBlockMenu) && (nLastMenu == idCtl)) { return; }
HWND hwnd = hwndMain; RECT rect; AllocCustomMenu(&g_pMenu); CustomMenu* pSearchSubMenu = NULL; CustomMenu* pProviderSubMenu = NULL;
if (!g_pMenu) { return; }
if (idCtl == IDB_OPTIONS) { g_pMenu->AppendMenu(IDM_OPTIONS,hInst,IDM_OPTIONS); g_pMenu->AppendMenu(IDM_PLAYLIST,hInst,IDM_PLAYLIST); g_pMenu->AppendSeparator();
if (!IsNetOK(hwnd)) { EnableMenuItem(g_pMenu->GetMenuHandle(), IDM_PLAYLIST, MF_BYCOMMAND | MF_GRAYED); }
if (g_nViewMode == VIEW_MODE_NORMAL) { g_pMenu->AppendMenu(IDM_TINY,hInst,IDM_TINY); } else { g_pMenu->AppendMenu(IDM_NORMAL,hInst,IDM_NORMAL); }
g_pMenu->AppendSeparator();
g_pMenu->AppendMenu(IDM_HELP,hInst,IDM_HELP); g_pMenu->AppendMenu(IDM_ABOUT,hInst,IDM_ABOUT);
g_pMenu->AppendSeparator();
g_pMenu->AppendMenu(IDM_EXIT,hInst,IDM_EXIT); } //end if options
if (idCtl == IDB_NET) { AllocCustomMenu(&pSearchSubMenu); AllocCustomMenu(&pProviderSubMenu);
MMMEDIAID mmMedia; mmMedia.nDrive = -1; IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); pAuto->Release();
BOOL fContinue = TRUE;
//append static menu choices
if (IsDownloading()) { g_pMenu->AppendMenu(IDM_NET_CANCEL,hInst,IDM_NET_CANCEL); } else { g_pMenu->AppendMenu(IDM_NET_UPDATE,hInst,IDM_NET_UPDATE); if (mmMedia.dwMediaID == 0) { //need to gray out menu
MENUITEMINFO mmi; mmi.cbSize = sizeof(mmi); mmi.fMask = MIIM_STATE; mmi.fState = MFS_GRAYED; HMENU hMenu = g_pMenu->GetMenuHandle(); SetMenuItemInfo(hMenu,IDM_NET_UPDATE,FALSE,&mmi); } } //if networking is not allowed, gray it out ...
//don't worry about cancel case, it won't be there
if (!IsNetOK(hwnd)) { EnableMenuItem(g_pMenu->GetMenuHandle(), IDM_NET_UPDATE, MF_BYCOMMAND | MF_GRAYED); }
//don't allow searching if title isn't available
LPCDDATA pData = GetCDData(); if (pData) { if (pData->QueryTitle(mmMedia.dwMediaID)) { pSearchSubMenu->AppendMenu(IDM_NET_BAND,hInst,IDM_NET_BAND); pSearchSubMenu->AppendMenu(IDM_NET_CD,hInst,IDM_NET_CD); pSearchSubMenu->AppendMenu(IDM_NET_ROLLINGSTONE_ARTIST,hInst,IDM_NET_ROLLINGSTONE_ARTIST); pSearchSubMenu->AppendMenu(IDM_NET_BILLBOARD_ARTIST,hInst,IDM_NET_BILLBOARD_ARTIST); pSearchSubMenu->AppendMenu(IDM_NET_BILLBOARD_ALBUM,hInst,IDM_NET_BILLBOARD_ALBUM); g_pMenu->AppendMenu(hInst,IDM_NET_SEARCH_HEADING,pSearchSubMenu); } } //end if pdata
//display any provider home pages
DWORD i = 0; LPCDOPT pOpt = GetCDOpt(); if( pOpt ) { LPCDOPTIONS pCDOpts = pOpt->GetCDOpts();
LPCDPROVIDER pProviderList = pCDOpts->pProviderList;
while (pProviderList!=NULL) { TCHAR szProviderMenu[MAX_PATH]; TCHAR szHomePageFormat[MAX_PATH/2]; LoadString(hInst,IDS_HOMEPAGEFORMAT,szHomePageFormat,sizeof(szHomePageFormat)/sizeof(TCHAR)); wsprintf(szProviderMenu,szHomePageFormat,pProviderList->szProviderName); pProviderSubMenu->AppendMenu(IDM_HOMEMENU_BASE+i,szProviderMenu);
pProviderList = pProviderList->pNext; i++; } //end while
g_pMenu->AppendMenu(hInst,IDM_NET_PROVIDER_HEADING,pProviderSubMenu); } //end home pages
//display internet-loaded disc menus
if (pData) { if (pData->QueryTitle(mmMedia.dwMediaID)) { LPCDTITLE pCDTitle = NULL; hr = pData->LockTitle(&pCDTitle,mmMedia.dwMediaID);
if (SUCCEEDED(hr)) { for (i = 0; i < pCDTitle->dwNumMenus; i++) { if (i==0) { g_pMenu->AppendSeparator(); }
TCHAR szDisplayNet[MAX_PATH]; NormalizeNameForMenuDisplay(pCDTitle->pMenuTable[i].szMenuText,szDisplayNet,sizeof(szDisplayNet)); g_pMenu->AppendMenu(i + IDM_NETMENU_BASE,szDisplayNet); }
pData->UnlockTitle(pCDTitle,FALSE); } } //end if query title
} } //end if net
if (idCtl == IDB_MODE) { g_pMenu->AppendMenu(IDM_MODE_NORMAL,hInst,IDI_MODE_NORMAL,IDM_MODE_NORMAL); g_pMenu->AppendMenu(IDM_MODE_RANDOM,hInst,IDI_MODE_RANDOM,IDM_MODE_RANDOM); g_pMenu->AppendMenu(IDM_MODE_REPEATONE,hInst,IDI_MODE_REPEATONE,IDM_MODE_REPEATONE); g_pMenu->AppendMenu(IDM_MODE_REPEATALL,hInst,IDI_MODE_REPEATALL,IDM_MODE_REPEATALL); g_pMenu->AppendMenu(IDM_MODE_INTRO,hInst,IDI_MODE_INTRO,IDM_MODE_INTRO); g_pMenu->SetMenuDefaultItem(nCDMode,FALSE); } //end if mode
if (idCtl==IDB_TRACK) { IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { int i = 0; while (SUCCEEDED(hr)) { MMTRACKORDISC mmTrack; mmTrack.nNumber = i++; hr = pAuto->OnAction(MMACTION_GETTRACKINFO,&mmTrack); if (SUCCEEDED(hr)) { g_pMenu->AppendMenu(mmTrack.nID + IDM_TRACKLIST_BASE, mmTrack.szName); if (mmTrack.fCurrent) { g_pMenu->SetMenuDefaultItem(mmTrack.nID + IDM_TRACKLIST_BASE,FALSE); } //end if current
} //end if ok
} //end while
pAuto->Release(); } } //end if track
if (idCtl == IDB_DISC) { IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); int i = 0;
if ((SUCCEEDED(hr)) && (pAuto != NULL)) { while (SUCCEEDED(hr)) { MMTRACKORDISC mmDisc; mmDisc.nNumber = i++; hr = pAuto->OnAction(MMACTION_GETDISCINFO,&mmDisc); if (SUCCEEDED(hr)) { g_pMenu->AppendMenu(mmDisc.nID + IDM_DISCLIST_BASE, mmDisc.szName); if (mmDisc.fCurrent) { g_pMenu->SetMenuDefaultItem(mmDisc.nID + IDM_DISCLIST_BASE,FALSE); } //end if current
} } pAuto->Release(); } if (i > 0) { g_pMenu->AppendSeparator(); }
g_pMenu->AppendMenu(IDM_OPENVIRTUALCD,hInst,IDM_OPENVIRTUALCD); } //end if disc
//push down to under button
HWND hwndButton = pButton->GetHWND(); GetClientRect(hwndButton,&rect);
//convert whole rect to screen coordinates
ClientToScreen(hwndButton,(LPPOINT)&rect); ClientToScreen(hwndButton,((LPPOINT)&rect)+1);
KillTimer(hwnd,nLastMenu); nLastMenu = idCtl; fBlockMenu = TRUE; pButton->SetMenuingState(TRUE); if (g_pMenu) { g_pMenu->TrackPopupMenu(0,rect.left,rect.bottom,hwnd,&rect); } else { BlockMenu(hwnd); } pButton->SetMenuingState(FALSE); if (g_pMenu) { g_pMenu->Destroy(); g_pMenu = NULL; } if (pProviderSubMenu) { pProviderSubMenu->Destroy(); pProviderSubMenu = NULL; } if (pSearchSubMenu) { pSearchSubMenu->Destroy(); pSearchSubMenu = NULL; } } //end if selected
} //end if right button
return; }
////////////////////////////////////////////////////////////////////////////////////////////
// * OnNCHitTest
// How we pretend that we have a real caption
////////////////////////////////////////////////////////////////////////////////////////////
UINT OnNCHitTest(HWND hwnd, short x, short y, BOOL fButtonDown) { UINT ht = HTCLIENT;
if (!fButtonDown) { ht = FORWARD_WM_NCHITTEST(hwnd, x, y, DefWindowProc ); }
RECT rect; GetClientRect(hwnd,&rect); rect.bottom = rect.top + TITLEBAR_HEIGHT + (g_nViewMode == VIEW_MODE_NORMAL ? TITLEBAR_YOFFSET_LARGE : TITLEBAR_YOFFSET_SMALL);
POINT pt; pt.x = (LONG)x; pt.y = (LONG)y;
ScreenToClient(hwnd,&pt);
if (PtInRect(&rect,pt)) { ht = HTCAPTION; }
rect.left = SYSMENU_XOFFSET; rect.right = SYSMENU_XOFFSET + SYSMENU_WIDTH; //check for a system-menu hit.
if (PtInRect(&rect,pt)) { ht = HTSYSMENU; }
//always a caption hit in small mode or nobar mode
if (g_nViewMode >= VIEW_MODE_SMALL) { ht = HTCAPTION; }
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, ht);
return (ht); }
////////////////////////////////////////////////////////////////////////////////////////////
// * FillGradient
// from kernel's caption.c
// Allows us to have the cool gradient caption bar that you get for free otherwise
////////////////////////////////////////////////////////////////////////////////////////////
void FillGradient(HDC hdc, LPCRECT prc, COLORREF rgbLeft, COLORREF rgbRight) { TRIVERTEX avert[2]; static GRADIENT_RECT auRect[1] = {0,1}; #define GetCOLOR16(RGB, clr) ((COLOR16)(Get ## RGB ## Value(clr) << 8))
avert[0].Red = GetCOLOR16(R, rgbLeft); avert[0].Green = GetCOLOR16(G, rgbLeft); avert[0].Blue = GetCOLOR16(B, rgbLeft);
avert[1].Red = GetCOLOR16(R, rgbRight); avert[1].Green = GetCOLOR16(G, rgbRight); avert[1].Blue = GetCOLOR16(B, rgbRight);
avert[0].x = prc->left; avert[0].y = prc->top; avert[1].x = prc->right; avert[1].y = prc->bottom;
//only load once, when needed. Freed in "CleanUp" call
if (hmImage == NULL) { hmImage = LoadLibrary(TEXT("MSIMG32.DLL")); if (hmImage!=NULL) { fnGradient = (GRADIENTPROC)GetProcAddress(hmImage,"GradientFill"); } }
if (fnGradient!=NULL) { fnGradient(hdc, avert, 2, (PUSHORT)auRect, 1, 0x00000000); return; }
BOOL fActiveWindow = FALSE;
if (hwndMain == GetForegroundWindow()) { fActiveWindow = TRUE; }
HBRUSH hbrush = CreateSolidBrush(GetSysColor(fActiveWindow ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION)); FillRect(hdc,prc,hbrush); DeleteObject(hbrush); }
////////////////////////////////////////////////////////////////////////////////////////////
// * DrawTitleBar
// Blits the title bar to the screen
////////////////////////////////////////////////////////////////////////////////////////////
void DrawTitleBar(HDC hdc, HWND hwnd, BOOL fActiveWindow, BOOL fExludeRect) { if (g_nViewMode >= VIEW_MODE_SMALL) { return; //no title bar in these views
}
RECT rect; HBRUSH hbrush;
//convert the client rect of the minimize button into the rect within the
//main display area
RECT minButtonRect; RECT mainWndRect; GetWindowRect(hwnd,&mainWndRect); HWND hwndButton = GetDlgItem(hwnd,IDB_MINIMIZE);
if (!hwndButton) { return; //must have been called before button was created
}
GetWindowRect(hwndButton,&minButtonRect); HDC memDC = CreateCompatibleDC(hdc); HBITMAP hbmp = CreateCompatibleBitmap(hdc, (g_nViewMode == VIEW_MODE_NORMAL ? bmMain.bmWidth : bmMainRestore.bmWidth), (g_nViewMode == VIEW_MODE_NORMAL ? bmMain.bmHeight : bmMainRestore.bmHeight)); HBITMAP holdbmp = (HBITMAP)SelectObject(memDC, hbmp);
BOOL fGradient = FALSE; SystemParametersInfo(SPI_GETGRADIENTCAPTIONS,0,&fGradient,0);
//we just need the left-hand side.
//to get it, we take the width of the window and subtract the offset
//from the right of the window
minButtonRect.left = (mainWndRect.right - mainWndRect.left) - (mainWndRect.right - minButtonRect.left);
rect.left = SYSMENU_XOFFSET + SYSMENU_WIDTH + 1; rect.right = minButtonRect.left - (GetXOffset()*2) - 1;
rect.top = (g_nViewMode == VIEW_MODE_NORMAL ? TITLEBAR_YOFFSET_LARGE : TITLEBAR_YOFFSET_SMALL);
rect.bottom = rect.top + TITLEBAR_HEIGHT;
if (fGradient) { DWORD dwStartColor = GetSysColor(fActiveWindow ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION); DWORD dwFinishColor = GetSysColor(fActiveWindow ? COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION); FillGradient(memDC,&rect,dwStartColor,dwFinishColor); } else { hbrush = CreateSolidBrush(GetSysColor(fActiveWindow ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION)); FillRect(memDC,&rect,hbrush); DeleteObject(hbrush); }
TCHAR s[MAX_PATH]; GetWindowText(hwnd,s,MAX_PATH-1);
SetBkMode(memDC,TRANSPARENT); SetTextColor(memDC, GetSysColor(fActiveWindow ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
//create title bar font
NONCLIENTMETRICS metrics; metrics.cbSize = sizeof(metrics); SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(metrics),&metrics,0);
if (IS_DBCS_CHARSET(metrics.lfCaptionFont.lfCharSet)) { metrics.lfCaptionFont.lfHeight = (-9 * STANDARD_PIXELS_PER_INCH) / 72; } else { metrics.lfCaptionFont.lfHeight = (-8 * STANDARD_PIXELS_PER_INCH) / 72; }
HFONT hTitleFont = CreateFontIndirect(&metrics.lfCaptionFont);
HFONT hOrgFont = (HFONT)SelectObject(memDC, hTitleFont);
ExtTextOut( memDC, rect.left + 3, rect.top, 0, NULL, s, _tcslen(s), NULL );
SelectObject(memDC,hOrgFont);
BitBlt(hdc,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top-1,memDC,rect.left,rect.top,SRCCOPY);
if (fExludeRect) { ExcludeClipRect(hdc,rect.left,rect.top,rect.right,rect.bottom-1); }
SelectObject(memDC, holdbmp); DeleteObject(hbmp); SelectObject(memDC, hOrgFont); DeleteDC(memDC); DeleteObject(hTitleFont); } ////////////////////////////////////////////////////////////////////////////////////////////
// * DrawVolume
// Tells the cdplayer to start showing the volume setting
////////////////////////////////////////////////////////////////////////////////////////////
void DrawVolume(DWORD level) { //we just have the led window draw it
HWND ledWnd = GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW);
MMONVOLCHANGED mmVolChange; mmVolChange.dwNewVolume = level; mmVolChange.fMuted = FALSE; mmVolChange.szLineName = szLineName;
SendMessage(ledWnd,WM_LED_INFO_PAINT,0,(LPARAM)&mmVolChange); }
////////////////////////////////////////////////////////////////////////////////////////////
// * OnToolTipNotify
// Called from tool tips to get the text they need to display
////////////////////////////////////////////////////////////////////////////////////////////
VOID OnToolTipNotify(LPARAM lParam) { LPTOOLTIPTEXT lpttt; HWND hwndCtrl;
if ((((LPNMHDR) lParam)->code) == TTN_NEEDTEXT) { hwndCtrl = (HWND)((LPNMHDR)lParam)->idFrom; lpttt = (LPTOOLTIPTEXT) lParam;
if (hwndCtrl == GetDlgItem(hwndMain,IDB_VOLUME)) { GetWindowText(hwndCtrl,g_tooltext,sizeof(g_tooltext)/sizeof(TCHAR)); } else { CMButton* pButton = GetMButtonFromHWND(hwndCtrl); if (pButton) { LoadString(hInst,pButton->GetToolTipID(),g_tooltext,sizeof(g_tooltext)/sizeof(TCHAR)); } } lpttt->lpszText = g_tooltext; } return; }
////////////////////////////////////////////////////////////////////////////////////////////
// * GetNumBatchedTitles
// Get the number of titles currently in the batch queue
////////////////////////////////////////////////////////////////////////////////////////////
DWORD GetNumBatchedTitles() { LPCDDATA pData = GetCDData(); DWORD dwReturn = 0;
if (pData) { dwReturn = pData->GetNumBatched(); }
return (dwReturn); }
////////////////////////////////////////////////////////////////////////////////////////////
// * HandleBadServiceProvider
// Put up message box if the provider did not pass validation
////////////////////////////////////////////////////////////////////////////////////////////
void HandleBadServiceProvider(HWND hwndParent) { TCHAR szError[MAX_PATH]; LoadString(hInst,IDS_BADPROVIDER,szError,sizeof(szError)/sizeof(TCHAR)); MessageBox(hwndParent,szError,szAppName,MB_ICONEXCLAMATION|MB_OK); }
////////////////////////////////////////////////////////////////////////////////////////////
// * NormalizeNameForURL
// Changes a name to a "normalized" name for URL
////////////////////////////////////////////////////////////////////////////////////////////
void NormalizeNameForURL(LPCTSTR szName, LPTSTR szOutput, DWORD cbOutputLen) { typedef BOOL (PASCAL *CANPROC)(LPCTSTR, LPTSTR, LPDWORD, DWORD); CANPROC canProc = NULL; _tcscpy(szOutput,szName); //init URL with passed-in value
//if possible, canonicalize the URL
HMODULE hNet = LoadLibrary(TEXT("WININET.DLL")); if (hNet!=NULL) { canProc = (CANPROC)GetProcAddress(hNet,CANONFUNCTION); if (canProc!=NULL) { BOOL f = canProc(szName,szOutput,&cbOutputLen,0); } FreeLibrary(hNet); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * OpenBrowserURL
// Opens a URL in the default browser
////////////////////////////////////////////////////////////////////////////////////////////
void OpenBrowserURL(TCHAR* szURL) { ShellExecute(NULL,_TEXT("open"),szURL,NULL,_TEXT(""),SW_NORMAL); }
////////////////////////////////////////////////////////////////////////////////////////////
// * ProgressDlgProc
// Main proc for download progress dialog
// Should Fix: Put in own file
////////////////////////////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK ProgressDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL fReturnVal = TRUE; static HWND hwndAnimate = NULL; static HANDLE hLogo = NULL; static LPCDOPT pOpts = NULL; static fOneDownloaded = FALSE; static LPCDPROVIDER pCurrent = NULL; switch (msg) { default: fReturnVal = FALSE; break; case WM_INITDIALOG: { fOneDownloaded = FALSE; BOOL fSingle = FALSE; DWORD dwDiscID = (DWORD)-1; //use batch
if (lParam == 0) { if (!pSingleTitle) { EndDialog(hDlg,-1); return FALSE; }
fSingle = TRUE; dwDiscID = pSingleTitle->dwTitleID; lParam = 1; }
if (IsDownloading()) { //if we're downloading on the Main UI, put up a "waiting" message for now
TCHAR szWaiting[MAX_PATH]; LoadString(hInst,IDS_WAITINGFORDOWNLOAD,szWaiting,sizeof(szWaiting)/sizeof(TCHAR)); SendDlgItemMessage(hDlg,IDC_STATIC_INFO,WM_SETTEXT,0,(LPARAM)szWaiting); }
//set the range
SendDlgItemMessage(hDlg, IDC_METER, PBM_SETRANGE, 0, MAKELPARAM(0, lParam)); SendDlgItemMessage(hDlg, IDC_METER, PBM_SETPOS, 0, 0);
//proceed with the download
MMNET mmNet; mmNet.discid = dwDiscID; mmNet.hwndCallback = hDlg; //call back to this guy
mmNet.fForceNet = fSingle; mmNet.pData = (void*)GetCDData(); if (fSingle) { mmNet.pData2 = (void*)pSingleTitle; } else { mmNet.pData2 = NULL; } SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(ID_CDUPDATE,0),(LPARAM)&mmNet);
pOpts = GetCDOpt(); if (!hLogo) { //get the path to the vendor logo file
if (pOpts) { LPCDOPTIONS pOptions = NULL; pOptions = pOpts->GetCDOpts();
if (pOptions) { if (pOptions->pCurrentProvider!=NULL) { hLogo = OpenDIB(pOptions->pCurrentProvider->szProviderLogo,(HFILE)-1); pCurrent = pOptions->pCurrentProvider; } //end if current provider ok
} //end if poptions ok
} //end if popts created
}
fReturnVal = TRUE; } break;
case WM_PAINT : { HDC hdc; PAINTSTRUCT ps;
hdc = BeginPaint( hDlg, &ps ); RECT progressrect, mainrect; GetWindowRect(GetDlgItem(hDlg,IDC_METER),&progressrect); GetWindowRect(hDlg,&mainrect); mainrect.top = mainrect.top + GetSystemMetrics(SM_CYCAPTION);
//turn on animation if it is not visible
if (!hwndAnimate) { hwndAnimate = Animate_Create(hDlg, IDI_ICON_ANI_DOWN, WS_CHILD|ACS_TRANSPARENT, hInst);
//headers don't have Animate_OpenEx yet,
//so just do the straight call
SendMessage(hwndAnimate,ACM_OPEN,(WPARAM)hInst, (LPARAM)MAKEINTRESOURCE(IDI_ICON_ANI_DOWN));
//move to the top/left of the window, equidistant from top and progress indicator
RECT anirect; GetWindowRect(hwndAnimate,&anirect); MoveWindow(hwndAnimate, progressrect.left - mainrect.left - 3, ((progressrect.top - mainrect.top) - (anirect.bottom - anirect.top)) - LOGO_Y_OFFSET, anirect.right - anirect.left, anirect.bottom - anirect.top, FALSE);
Animate_Play(hwndAnimate,0,-1,-1); ShowWindow(hwndAnimate,SW_SHOW);
//move "info" window
MoveWindow(GetDlgItem(hDlg,IDC_STATIC_INFO), (progressrect.left - mainrect.left) + (anirect.right - anirect.left) + 3, ((progressrect.top - mainrect.top) - (anirect.bottom - anirect.top)) - LOGO_Y_OFFSET, ((progressrect.right - mainrect.left) - VENDORLOGO_WIDTH - 3) - ((progressrect.left - mainrect.left) + (anirect.right - anirect.left) + 3), anirect.bottom - anirect.top, FALSE); }
if (hLogo) { DibBlt(hdc, (progressrect.right - mainrect.left) - (VENDORLOGO_WIDTH + 5), ((progressrect.top - mainrect.top) - VENDORLOGO_HEIGHT) - LOGO_Y_OFFSET, -1, -1, hLogo, 0,0, SRCCOPY,0); }
EndPaint(hDlg,&ps); return 0; } break;
//try to launch provider home page
case WM_LBUTTONUP : { if ((hLogo) && (pCurrent)) { RECT progressrect, mainrect; GetWindowRect(GetDlgItem(hDlg,IDC_METER),&progressrect); GetWindowRect(hDlg,&mainrect); mainrect.top = mainrect.top + GetSystemMetrics(SM_CYCAPTION);
RECT logoRect; SetRect(&logoRect, (progressrect.right - mainrect.left) - VENDORLOGO_WIDTH, ((progressrect.top - mainrect.top) - VENDORLOGO_HEIGHT) - LOGO_Y_OFFSET, (progressrect.right - mainrect.left), (progressrect.top - mainrect.top) - LOGO_Y_OFFSET);
POINT pt; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); if (PtInRect(&logoRect,pt)) { OpenBrowserURL(pCurrent->szProviderHome); } } } break;
case WM_DESTROY : { if (hwndAnimate) { DestroyWindow(hwndAnimate); hwndAnimate = NULL; }
if (hLogo) { GlobalFree(hLogo); hLogo = NULL; } } break;
case WM_NET_DB_UPDATE_BATCH : { LPCDOPT pOpts = GetCDOpt(); if (pOpts) { pOpts->DownLoadCompletion(0,NULL); } } break;
case WM_NET_DB_UPDATE_DISC : { LPCDOPT pOpts = GetCDOpt(); if (pOpts) { pOpts->DiscChanged((LPCDUNIT)lParam); } } break;
case WM_NET_CHANGEPROVIDER : { LPCDPROVIDER pProv = (LPCDPROVIDER)lParam; if (pProv!=NULL) { pCurrent = pProv;
if (hLogo) { GlobalFree(hLogo); hLogo = NULL; }
hLogo = OpenDIB(pCurrent->szProviderLogo,(HFILE)-1); InvalidateRect(hDlg,NULL,FALSE); UpdateWindow(hDlg); } //end if provider ok
} break;
case WM_NET_STATUS : { //until at least one title is downloaded, we need to do
//something to entertain the user, so go ahead and show the
//downloading text
if (!fOneDownloaded) { TCHAR progstr[MAX_PATH]; LoadString((HINSTANCE)wParam,(UINT)lParam,progstr,sizeof(progstr)/sizeof(TCHAR)); SendDlgItemMessage(hDlg,IDC_STATIC_INFO,WM_SETTEXT,0,(LPARAM)progstr); } } break;
case WM_NET_DONE : { fOneDownloaded = TRUE;
if (lParam == (LPARAM)-1) { HandleBadServiceProvider(hDlg); EndDialog(hDlg,0); break; }
if (lParam == 0) { EndDialog(hDlg,0); break; } else { MMNET mmNet; mmNet.discid = (DWORD)lParam; mmNet.hwndCallback = hDlg; mmNet.pData = (void*)GetCDData(); mmNet.pData2 = NULL; mmNet.fForceNet = FALSE; SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(ID_CDUPDATE,0),(LPARAM)&mmNet);
LPCDDATA pData = GetCDData(); //try to display that we found a title
if (!pData) { break; } //
// Try to read in title from the options database
//
if (!pData->QueryTitle((DWORD)(lParam))) { break; }
//
// We found an entry for this disc, so copy all the information
// from the title database
LPCDTITLE pCDTitle = NULL;
if (FAILED(pData->LockTitle(&pCDTitle,(DWORD)(lParam)))) { break; }
TCHAR foundstr[MAX_PATH]; TCHAR formatstr[MAX_PATH]; LoadString(hInst,IDS_FOUND,formatstr,sizeof(formatstr)/sizeof(TCHAR)); wsprintf(foundstr,formatstr,pCDTitle->szTitle,pCDTitle->szArtist); SendDlgItemMessage(hDlg,IDC_STATIC_INFO,WM_SETTEXT,0,(LPARAM)foundstr); } } break;
case WM_NET_INCMETER : { LRESULT dwPos = SendDlgItemMessage(hDlg,IDC_METER,PBM_GETPOS,0,0); SendDlgItemMessage(hDlg, IDC_METER, PBM_SETPOS, (WPARAM)++dwPos, 0); } break;
case WM_NET_DB_FAILURE : { TCHAR szDBError[MAX_PATH]; LoadString(hInst,IDS_DB_FAILURE,szDBError,sizeof(szDBError)/sizeof(TCHAR)); MessageBox(hDlg,szDBError,szAppName,MB_ICONERROR|MB_OK); } break;
case WM_NET_NET_FAILURE : { TCHAR szNetError[MAX_PATH]; LoadString(hInst,IDS_NET_FAILURE,szNetError,sizeof(szNetError)/sizeof(TCHAR)); MessageBox(hDlg,szNetError,szAppName,MB_ICONERROR|MB_OK); } break;
case WM_COMMAND : { if (LOWORD(wParam) == IDCANCEL) { CancelDownload(); EndDialog(hDlg,-1); } } }
return fReturnVal; }
////////////////////////////////////////////////////////////////////////////////////////////
// * HandleDiscsNotFound
// Ask the user if they want to nuke unfound batched titles, or save them for another time
////////////////////////////////////////////////////////////////////////////////////////////
void HandleDiscsNotFound(HWND hwndParent) { DWORD dwNumNotFound = GetNumBatchedTitles();
if (dwNumNotFound == 0) { return; }
TCHAR szNotFound[MAX_PATH];
if (dwNumNotFound > 1) { TCHAR szFormat[MAX_PATH]; LoadString(hInst,IDS_NOTFOUND,szFormat,sizeof(szFormat)/sizeof(TCHAR));
wsprintf(szNotFound,szFormat,dwNumNotFound); } else { LoadString(hInst,IDS_NOTFOUND1,szNotFound,sizeof(szNotFound)/sizeof(TCHAR)); }
int nAnswer = MessageBox(hwndParent,szNotFound,szAppName,MB_YESNO|MB_ICONQUESTION);
if (nAnswer == IDNO) { LPCDDATA pData = GetCDData(); if (pData) { pData->DumpBatch(); } } //if said "no" to keeping batch
}
////////////////////////////////////////////////////////////////////////////////////////////
// * OptionsDownloadCallback
// Called from the options dialog to do batches or single downloads
////////////////////////////////////////////////////////////////////////////////////////////
DWORD CALLBACK OptionsDownloadCallback(LPCDTITLE pTitle, LPARAM lParam, HWND hwndParent) { if (pTitle == NULL) { DWORD dwNumBatched = GetNumBatchedTitles();
if (dwNumBatched > 0) { DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_DOWNLOADPROGRESS), hwndParent,ProgressDlgProc,dwNumBatched); }
HandleDiscsNotFound(hwndParent);
//refresh the number of batched titles
return GetNumBatchedTitles(); } else { pSingleTitle = pTitle; INT_PTR status = DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_DOWNLOADPROGRESS), hwndParent,ProgressDlgProc,0);
//update the UI
LPCDOPT pOpts = GetCDOpt(); if (pOpts) { LPCDUNIT pUnit = pOpts->GetCDOpts()->pCDUnitList;
while (pUnit!=NULL) { if (pUnit->dwTitleID == pSingleTitle->dwTitleID) { pUnit->fDownLoading = FALSE; pOpts->DiscChanged(pUnit); break; } pUnit = pUnit->pNext; } }
//if download wasn't canceled, check for disc id in database
if (status != -1) { LPCDDATA pData = GetCDData(); if (!pData->QueryTitle(pSingleTitle->dwTitleID)) { TCHAR szNotFound[MAX_PATH]; LoadString(hInst,IDS_TITLE_NOT_FOUND,szNotFound,sizeof(szNotFound)/sizeof(TCHAR)); MessageBox(hwndParent,szNotFound,szAppName,MB_ICONINFORMATION|MB_OK); } else { if (pOpts) { LPCDOPTIONS pCDOpts = pOpts->GetCDOpts(); pCDOpts->dwBatchedTitles = GetNumBatchedTitles(); pOpts->DownLoadCompletion(1,&(pSingleTitle->dwTitleID)); } //end if OK to update batch number
} }
return 0; } return 0; }
////////////////////////////////////////////////////////////////////////////////////////////
// * OptionsApply
// Called from the options dialog when appy is hit, or by main UI when OK is hit
////////////////////////////////////////////////////////////////////////////////////////////
void CALLBACK OptionsApply(LPCDOPTIONS pCDOpts) { if (!pCDOpts) { return; } //tell the CD player to rescan its settings ...
//most of the settings are for it
IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { pAuto->OnAction(MMACTION_READSETTINGS,pCDOpts->pCDData); pAuto->Release(); }
LPCDUNIT pUnit = pCDOpts->pCDUnitList; LPCDDATA pData = GetCDData();
while (pUnit!=NULL) { BOOL fRemove = FALSE; if (pData) { fRemove = !(pData->QueryTitle(pUnit->dwTitleID)); }
if ((pUnit->fChanged) || (fRemove)) { if ((pUnit->dwTitleID != 0) && (pUnit->dwTitleID != (DWORD)-1)) { //tell the cd player that a title was updated, perhaps the ones in the drive
MMNET mmNet; mmNet.discid = pUnit->dwTitleID; mmNet.hwndCallback = hwndMain; mmNet.pData = (void*)GetCDData(); mmNet.pData2 = NULL; mmNet.fForceNet = FALSE; SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(ID_CDUPDATE,0),(LPARAM)&mmNet); } } pUnit = pUnit->pNext; }
SetWindowPos(hwndMain, pCDOpts->pCDData->fTopMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
//may have changed cd volume line
if (InitCDVol(hwndMain, pCDOpts)) { //when the volume line changes, we need to update the knob
DWORD dwVol = GetVolume(); CKnob* pKnob = GetKnobFromID(hwndMain,IDB_VOLUME); if (pKnob!=NULL) { pKnob->SetPosition(dwVol,TRUE); }
SendMessage(GetDlgItem(hwndMain,IDB_MUTE),BM_SETSTATE,(WPARAM)GetMute(),0); SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_MUTE,0,GetMute()); } //if vol line changed
//may have turned on/off shell mode
//we only care if the main UI is visible (i.e. not in shell-only mode)
if (IsWindowVisible(hwndMain)) { if (fShellMode != pCDOpts->pCDData->fTrayEnabled) { fShellMode = pCDOpts->pCDData->fTrayEnabled; if (fShellMode) { CreateShellIcon(hInst,hwndMain,pNodeCurrent,szAppName); } else { DestroyShellIcon(); } //end shellmode
} //end if shellmode changed in options
} //end main ui visible
}
////////////////////////////////////////////////////////////////////////////////////////////
// * HandleMixerControlChange
// Updates UI when sndvol32 or other apps change our mixerline
////////////////////////////////////////////////////////////////////////////////////////////
void HandleMixerControlChange(DWORD dwLineID) { if (dwLineID == mixerlinedetails.dwControlID) { DWORD dwVol = GetVolume(); CKnob* pKnob = GetKnobFromID(hwndMain,IDB_VOLUME); //possible to get this change before knob is up
if (pKnob!=NULL) { pKnob->SetPosition(dwVol,TRUE); } }
if (dwLineID == mutelinedetails.dwControlID) { SendMessage(GetDlgItem(hwndMain,IDB_MUTE),BM_SETSTATE,(WPARAM)GetMute(),0); SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_MUTE,0,GetMute()); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * ChildPaletteProc
// Updates child windows when palette changes
////////////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK ChildPaletteProc(HWND hwnd, LPARAM lParam) { InvalidateRect(hwnd,NULL,FALSE); UpdateWindow(hwnd); return TRUE; }
////////////////////////////////////////////////////////////////////////////////////////////
// * HandlePaletteChange
// Updates window when palette changes
////////////////////////////////////////////////////////////////////////////////////////////
int HandlePaletteChange() { HDC hdc = GetDC(hwndMain); HPALETTE hOldPal = SelectPalette(hdc,hpalMain,FALSE); UINT i = RealizePalette(hdc); if (i) { //update child windows "by hand", since they are clipped
EnumChildWindows(hwndMain,ChildPaletteProc,0);
//update main window
InvalidateRect(hwndMain,NULL,FALSE); UpdateWindow(hwndMain); } SelectPalette(hdc,hOldPal,TRUE); RealizePalette(hdc); ReleaseDC(hwndMain,hdc); return i; }
////////////////////////////////////////////////////////////////////////////////////////////
// * HandleDisplayChange
// Figures out if we need to recalc all bitmaps and does so ...
////////////////////////////////////////////////////////////////////////////////////////////
void HandleDisplayChange() { int nOrgColorMode = g_nColorMode;
DetermineColorMode();
//only do anythhing if they changed modes
if (g_nColorMode != nOrgColorMode) { //nuke all child windows
for (int i = 0; i < NUM_BUTTONS; i++) { DestroyWindow(GetDlgItem(hwndMain,biButtons[i].id)); }
DestroyWindow(GetDlgItem(hwndMain,IDB_MUTE)); DestroyWindow(GetDlgItem(hwndMain,IDB_VOLUME)); UninitMButtons();
//nuke the bitmaps
GlobalFree(hbmpMain); GlobalFree(hbmpMainRestore); GlobalFree(hbmpMainSmall); GlobalFree(hbmpMainNoBar); DeleteObject(hpalMain);
hpalMain = SetPalette();
//rebuild the bitmaps
BuildFrameworkBitmaps();
//recreate the windows
CreateButtonWindows(hwndMain); CreateVolumeKnob(hwndMain); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * DoPaint
// Handles the WM_PAINT for the main UI, actually a multimon paint callback
////////////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK DoPaint(HMONITOR hmonitor, HDC hdc, LPRECT lprcMonitor, LPARAM lData) { HWND hwnd = (HWND)lData;
HPALETTE hpalOld = SelectPalette(hdc, hpalMain, FALSE); RealizePalette(hdc);
BOOL fActiveWindow = FALSE; if (hwnd == GetForegroundWindow()) { fActiveWindow = TRUE; }
DrawTitleBar(hdc, hwnd, fActiveWindow, TRUE);
HANDLE hbmpView; BITMAP* pBM = &bmMain; switch (g_nViewMode) { case VIEW_MODE_NORMAL : { hbmpView = hbmpMain; } break; case VIEW_MODE_RESTORE : { hbmpView = hbmpMainRestore; pBM = &bmMainRestore; } break;
case VIEW_MODE_SMALL : { hbmpView = hbmpMainSmall; pBM = &bmMainSmall; } break;
case VIEW_MODE_NOBAR : { hbmpView = hbmpMainNoBar; pBM = &bmMainNoBar; } break; }
DibBlt(hdc, 0, 0, -1, -1, hbmpView, 0,0, SRCCOPY,0);
//reset the clipping region that was set in DrawTitleBar for reverse paint
RECT rcParent; GetClientRect( hwnd, &rcParent ); HRGN region = CreateRectRgn(rcParent.left,rcParent.top,rcParent.right,rcParent.bottom);
SelectClipRgn(hdc, region); DeleteObject(region);
SelectPalette(hdc, hpalOld, TRUE); RealizePalette(hdc);
return TRUE; }
////////////////////////////////////////////////////////////////////////////////////////////
// * SetPlayButtonState
// Handles the play button's icon
////////////////////////////////////////////////////////////////////////////////////////////
void SetPlayButtonState(BOOL fIntroMode) { CMButton* pButton = GetMButtonFromID(hwndMain,IDB_PLAY);
if (pButton) { if ((fPlaying) && (fIntroMode)) { pButton->SetIcon(IDI_MODE_INTRO); pButton->SetToolTipID(IDB_TT_INTRO); SetWindowText(pButton->GetHWND(),TEXT("2")); }
if ((fPlaying) && (fIntro) && (!fIntroMode)) { pButton->SetIcon(IDI_ICON_PAUSE); pButton->SetToolTipID(IDB_TT_PAUSE); SetWindowText(pButton->GetHWND(),TEXT("1")); } }
fIntro = fIntroMode;
//need to save playback mode at this point
LPCDOPT pOpt = GetCDOpt();
if(pOpt) { LPCDOPTIONS pOptions = pOpt->GetCDOpts(); LPCDOPTDATA pOptionData = pOptions->pCDData; pOptionData->dwPlayMode = nCDMode; pOpt->UpdateRegistry(); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * GetSearchURL
// Returns the standard IE "autosearch" URL
////////////////////////////////////////////////////////////////////////////////////////////
BOOL GetSearchURL(TCHAR* szSearchURL) { BOOL fRet = FALSE; HKEY hKeySearch = NULL;
long lResult = ::RegOpenKeyEx( HKEY_CURRENT_USER, REG_KEY_SEARCHURL, 0, KEY_READ, &hKeySearch );
if (lResult == ERROR_SUCCESS) { DWORD dwCbData = MAX_PATH; DWORD dwType = REG_SZ; lResult = ::RegQueryValueEx( hKeySearch, TEXT(""), NULL, &dwType, (LPBYTE)szSearchURL, &dwCbData );
if (lResult == ERROR_SUCCESS) { fRet = TRUE; }
RegCloseKey(hKeySearch); }
return (fRet); }
////////////////////////////////////////////////////////////////////////////////////////////
// * OpenVirtualCD
// Switches over to "Virtual CD mode" --
// basically a mode where we are playing back an ASX playlist of cached audio files
////////////////////////////////////////////////////////////////////////////////////////////
void OpenVirtualCD() { //display dialog
//if dialog successful, switch UI to msdxm.ocx mode
}
////////////////////////////////////////////////////////////////////////////////////////////
// * HandleCommand
// Handles all WM_COMMAND message for the main app
////////////////////////////////////////////////////////////////////////////////////////////
void HandleCommand(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { //handle system commands
if ((LOWORD(wParam) >= SC_SIZE) && (LOWORD(wParam) <= SC_CONTEXTHELP)) { SendMessage(hwnd,WM_SYSCOMMAND,(WPARAM)LOWORD(wParam),0); return; }
switch (LOWORD(wParam)) { case IDM_EXIT : { //if the shell icon is showing, then closing the app means hiding it
if (fShellMode) { ShowWindow(hwnd,SW_HIDE); } else { SendMessage(hwnd, WM_CLOSE, 0, 0); } return; } //end exit
break;
case IDM_EXIT_SHELL : { //if the shell icon wanted us to shut down, but the main ui is visible, just
//nuke shell mode
if (IsWindowVisible(hwnd)) { DestroyShellIcon(); fShellMode = FALSE; } else { SendMessage(hwnd, WM_CLOSE, 0, 0); } return; } break; }
IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { if ((LOWORD(wParam) >= IDM_TRACKLIST_BASE) && (LOWORD(wParam) < IDM_TRACKLIST_SHELL_BASE)) { MMCHANGETRACK mmTrack; mmTrack.nNewTrack = LOWORD(wParam) - IDM_TRACKLIST_BASE; pAuto->OnAction(MMACTION_SETTRACK,&mmTrack); }
if ((LOWORD(wParam) >= IDM_TRACKLIST_SHELL_BASE) && (LOWORD(wParam) < IDM_DISCLIST_BASE)) { MMCHANGETRACK mmTrack; mmTrack.nNewTrack = LOWORD(wParam) - IDM_TRACKLIST_SHELL_BASE; pAuto->OnAction(MMACTION_SETTRACK,&mmTrack);
//play it if we're not playing
if (!fPlaying) { pAuto->OnAction(MMACTION_PLAY,NULL); } }
if ((LOWORD(wParam) >= IDM_DISCLIST_BASE) && (LOWORD(wParam) < IDM_NET_UPDATE)) { MMCHANGEDISC mmDisc; mmDisc.nNewDisc = LOWORD(wParam) - IDM_DISCLIST_BASE; pAuto->OnAction(MMACTION_SETDISC,&mmDisc); }
if ((LOWORD(wParam) >= IDM_HOMEMENU_BASE) && (LOWORD(wParam) < IDM_NETMENU_BASE)) { int i = LOWORD(wParam) - IDM_HOMEMENU_BASE;
LPCDOPT pOpt = GetCDOpt(); if( pOpt ) { LPCDOPTIONS pCDOpts = pOpt->GetCDOpts();
LPCDPROVIDER pProviderList = pCDOpts->pProviderList;
for (int x = 0; x < i; x++) { pProviderList = pProviderList->pNext; }
OpenBrowserURL(pProviderList->szProviderHome); } }
if ((LOWORD(wParam) >= IDM_NETMENU_BASE) && (LOWORD(wParam) < IDM_OPTIONS)) { MMMEDIAID mmMedia; mmMedia.nDrive = -1; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); LPCDDATA pData = GetCDData();
if (!pData) { return; }
if (!pData->QueryTitle(mmMedia.dwMediaID)) { return; }
LPCDTITLE pCDTitle = NULL; hr = pData->LockTitle(&pCDTitle,mmMedia.dwMediaID);
if (FAILED(hr)) { return; }
LPCDMENU pCDMenu = &(pCDTitle->pMenuTable[LOWORD(wParam)-IDM_NETMENU_BASE]);
if (pCDMenu->szMenuQuery) { OpenBrowserURL(pCDMenu->szMenuQuery); }
pData->UnlockTitle(pCDTitle,FALSE); }
switch (LOWORD(wParam)) { case IDM_NET_UPDATE : { MMNET mmNet; mmNet.discid = 0; //use current disc
mmNet.hwndCallback = hwnd; mmNet.pData = (void*)GetCDData(); mmNet.pData2 = NULL; mmNet.fForceNet = FALSE; SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(ID_CDUPDATE,0),(LPARAM)&mmNet); } break;
case IDM_NET_CANCEL : { CancelDownload(); } break;
case IDM_NET_ROLLINGSTONE_ARTIST : case IDM_NET_BILLBOARD_ALBUM : case IDM_NET_BILLBOARD_ARTIST : { MMMEDIAID mmMedia; mmMedia.nDrive = -1; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); TCHAR szQuery[MAX_PATH*4];
LPCDDATA pData = GetCDData();
if (!pData) { break; }
if (!pData->QueryTitle(mmMedia.dwMediaID)) { return; }
LPCDTITLE pCDTitle = NULL; hr = pData->LockTitle(&pCDTitle,mmMedia.dwMediaID);
if (FAILED(hr)) { break; }
//normalize (canonize) the title and artist names
TCHAR szArtist[CDSTR*3]; TCHAR szTitle[CDSTR*3]; NormalizeNameForURL(pCDTitle->szArtist,szArtist,sizeof(szArtist)); NormalizeNameForURL(pCDTitle->szTitle,szTitle,sizeof(szTitle));
pData->UnlockTitle(pCDTitle,FALSE);
if ((LOWORD(wParam) == IDM_NET_BILLBOARD_ARTIST)) { TCHAR szFormat[MAX_PATH]; LoadString(hInst,IDS_BILLBOARD_FORMAT_ARTIST,szFormat,sizeof(szFormat)/sizeof(TCHAR)); wsprintf(szQuery,szFormat,szArtist); } else if ((LOWORD(wParam) == IDM_NET_ROLLINGSTONE_ARTIST)) { TCHAR szFormat[MAX_PATH]; LoadString(hInst,IDS_ROLLINGSTONE_FORMAT_ARTIST,szFormat,sizeof(szFormat)/sizeof(TCHAR)); wsprintf(szQuery,szFormat,szArtist); } else { TCHAR szFormat[MAX_PATH]; LoadString(hInst,IDS_BILLBOARD_FORMAT_ALBUM,szFormat,sizeof(szFormat)/sizeof(TCHAR)); wsprintf(szQuery,szFormat,szArtist,szTitle); }
OpenBrowserURL(szQuery); } break;
case IDM_NET_CD : { MMMEDIAID mmMedia; mmMedia.nDrive = -1; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); TCHAR szQuery[MAX_PATH*4];
LPCDDATA pData = GetCDData();
if (!pData) { break; }
if (!pData->QueryTitle(mmMedia.dwMediaID)) { return; }
LPCDTITLE pCDTitle = NULL; hr = pData->LockTitle(&pCDTitle,mmMedia.dwMediaID);
if (FAILED(hr)) { break; }
TCHAR szSearchURL[MAX_PATH]; if (!GetSearchURL(szSearchURL)) { break; }
TCHAR szTemp[MAX_PATH*2]; TCHAR szTemp2[MAX_PATH*2];
wsprintf(szTemp,TEXT("%s %s"),pCDTitle->szArtist,pCDTitle->szTitle); NormalizeNameForURL(szTemp,szTemp2,sizeof(szTemp2)); wsprintf(szQuery,szSearchURL,szTemp2);
pData->UnlockTitle(pCDTitle,FALSE);
OpenBrowserURL(szQuery); } break;
case IDM_NET_BAND : { MMMEDIAID mmMedia; mmMedia.nDrive = -1; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); TCHAR szQuery[MAX_PATH*3];
LPCDDATA pData = GetCDData();
if (!pData) { break; }
if (!pData->QueryTitle(mmMedia.dwMediaID)) { return; }
LPCDTITLE pCDTitle = NULL; hr = pData->LockTitle(&pCDTitle,mmMedia.dwMediaID);
if (FAILED(hr)) { break; }
TCHAR szSearchURL[MAX_PATH]; if (!GetSearchURL(szSearchURL)) { break; }
TCHAR szArtist[CDSTR*3]; NormalizeNameForURL(pCDTitle->szArtist,szArtist,sizeof(szArtist));
wsprintf(szQuery,szSearchURL,szArtist);
pData->UnlockTitle(pCDTitle,FALSE);
OpenBrowserURL(szQuery); } break;
case IDM_MODE_NORMAL : { nCDMode = LOWORD(wParam); SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(IDM_OPTIONS_NORMAL,0),(LPARAM)0); InvalidateRect(hwndCurrentComp,NULL,FALSE); UpdateWindow(hwndCurrentComp); CMButton* pButton = GetMButtonFromID(hwnd,IDB_MODE); if (pButton) { pButton->SetIcon(IDI_MODE_NORMAL); } SetPlayButtonState(FALSE); } break;
case IDM_MODE_REPEATONE : { nCDMode = LOWORD(wParam); SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(IDM_OPTIONS_REPEAT_SINGLE,0),(LPARAM)0); InvalidateRect(hwndCurrentComp,NULL,FALSE); UpdateWindow(hwndCurrentComp); CMButton* pButton = GetMButtonFromID(hwnd,IDB_MODE); if (pButton) { pButton->SetIcon(IDI_MODE_REPEATONE); } SetPlayButtonState(FALSE); } break;
case IDM_MODE_REPEATALL : { nCDMode = LOWORD(wParam); SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(IDM_OPTIONS_CONTINUOUS,0),(LPARAM)0); InvalidateRect(hwndCurrentComp,NULL,FALSE); UpdateWindow(hwndCurrentComp); CMButton* pButton = GetMButtonFromID(hwnd,IDB_MODE); if (pButton) { pButton->SetIcon(IDI_MODE_REPEATALL); } SetPlayButtonState(FALSE); } break;
case IDM_MODE_RANDOM : { nCDMode = LOWORD(wParam); SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(IDM_OPTIONS_RANDOM,0),(LPARAM)0); InvalidateRect(hwndCurrentComp,NULL,FALSE); UpdateWindow(hwndCurrentComp); CMButton* pButton = GetMButtonFromID(hwnd,IDB_MODE); if (pButton) { pButton->SetIcon(IDI_MODE_RANDOM); } SetPlayButtonState(FALSE); } break;
case IDM_MODE_INTRO : { nCDMode = LOWORD(wParam); SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(IDM_OPTIONS_INTRO,0),(LPARAM)0); InvalidateRect(hwndCurrentComp,NULL,FALSE); UpdateWindow(hwndCurrentComp); CMButton* pButton = GetMButtonFromID(hwnd,IDB_MODE); if (pButton) { pButton->SetIcon(IDI_MODE_INTRO); } SetPlayButtonState(TRUE); } break;
case IDM_HELP : { char chDst[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, HELPFILENAME, -1, chDst, MAX_PATH, NULL, NULL); HtmlHelpA(GetDesktopWindow(), chDst, HH_DISPLAY_TOPIC, 0); } break;
case IDM_ABOUT : { ShellAbout( hwnd, szAppName, TEXT(""), LoadIcon(hInst, MAKEINTRESOURCE(IDI_MMFW))); } break;
case IDM_NORMAL : { SetNormalMode(hwnd); } break;
case IDM_TINY : { SetRestoredMode(hwnd); } break;
case IDB_MUTE : { //fix for bug 220 ... if mute button is set from "SetMute" during a button
//click, it will get ANOTHER button click when it's focus is killed, so we
//need to make sure it stays in the right state at the right time
if (GetFocus()==GetDlgItem(hwndMain,IDB_MUTE)) { SetMute(); } else { SendMessage(GetDlgItem(hwndMain,IDB_MUTE),BM_SETSTATE,(WPARAM)GetMute(),0); } } break;
case IDM_OPENVIRTUALCD : { OpenVirtualCD(); } break;
case IDM_PLAYLIST : case IDM_OPTIONS : { CDOPT_PAGE nStartSheet = CDOPT_PAGE_PLAY;
if (LOWORD(wParam) == IDM_PLAYLIST) { nStartSheet = CDOPT_PAGE_PLAYLIST; }
LPCDOPT pOpt = GetCDOpt(); if( pOpt ) { LPCDOPTIONS pCDOpts = pOpt->GetCDOpts();
LPCDDATA pData = GetCDData();
if( pData ) { //go through and set media ids for each drive
LPCDUNIT pUnit = pCDOpts->pCDUnitList; int nCurrDrive = 0; while (pUnit!=NULL) { MMMEDIAID mmMedia; mmMedia.nDrive = nCurrDrive; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia);
MMNETQUERY mmNetQuery; mmNetQuery.nDrive = nCurrDrive++; mmNetQuery.szNetQuery = pUnit->szNetQuery; pAuto->OnAction(MMACTION_GETNETQUERY,&mmNetQuery);
pUnit->dwTitleID = mmMedia.dwMediaID; pUnit->dwNumTracks = mmMedia.dwNumTracks; if (IsDownloading()) { pUnit->fDownLoading = TRUE; } else { pUnit->fDownLoading = FALSE; } pUnit = pUnit->pNext; }
//set the number of batched titles and the callback functions
pCDOpts->dwBatchedTitles = GetNumBatchedTitles(); pCDOpts->pfnDownloadTitle = OptionsDownloadCallback; pCDOpts->pfnOptionsCallback = OptionsApply;
fOptionsDlgUp = TRUE; HRESULT hr = pOpt->OptionsDialog(hwnd, pData, nStartSheet); fOptionsDlgUp = FALSE;
if (hr == S_OK) //don't use succeeded macro here, S_FALSE is also valid
{ OptionsApply(pCDOpts); } } //if pdata
} } break;
case IDB_PLAY : { if (fPlaying) { if (fIntro) { //set to normal mode
SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(IDM_MODE_NORMAL,0),0); //set button back to regular icon
CMButton* pButton = GetMButtonFromID(hwnd,IDB_PLAY); if (pButton) { pButton->SetIcon(IDI_ICON_PAUSE); pButton->SetToolTipID(IDB_TT_PAUSE); SetWindowText(pButton->GetHWND(),TEXT("1")); } } else { pAuto->OnAction(MMACTION_PAUSE,NULL); } } else { pAuto->OnAction(MMACTION_PLAY,NULL); } } break;
case IDB_EJECT : { pAuto->OnAction(MMACTION_UNLOADMEDIA,NULL); } break;
case IDB_FFWD : { pAuto->OnAction(MMACTION_FFWD,NULL); } break;
case IDB_NEXTTRACK : { pAuto->OnAction(MMACTION_NEXTTRACK,NULL); } break;
case IDB_PREVTRACK : { pAuto->OnAction(MMACTION_PREVTRACK,NULL); } break;
case IDB_REW : { pAuto->OnAction(MMACTION_REWIND,NULL); } break;
case IDB_STOP : { pAuto->OnAction(MMACTION_STOP,NULL); } break;
case IDB_MINIMIZE : { ShowWindow(hwnd,SW_MINIMIZE); //see \\redrum\slmro\proj\win\src\CORE\user\mssyscmd.c
PlaySound(TEXT("Minimize"),NULL,SND_ALIAS|SND_NODEFAULT|SND_ASYNC|SND_NOWAIT|SND_NOSTOP); } break;
case IDB_SET_NORMAL_MODE : { SetNormalMode(hwnd); } break;
case IDB_SET_TINY_MODE : { SetRestoredMode(hwnd); } break;
case IDB_CLOSE : { //if the shell icon is showing, then closing the app means hiding it
if (fShellMode) { ShowWindow(hwnd,SW_HIDE); } else { SendMessage(hwnd, WM_CLOSE, 0, 0); } } break; }
if (pAuto) { pAuto->Release(); pAuto = NULL; } } }
////////////////////////
// Handles device change message from WinMM, All we need to do here is close any open
// Mixer Handles, re-compute mixer ID and control ID's and re-Open appropriately
//
void WinMMDeviceChangeHandler(HWND hWnd) { LPCDOPT pOpt = GetCDOpt();
if (hmix) // Close open mixer handle
{ mixerClose((HMIXER)hmix); hmix = NULL; }
if(pOpt) { LPCDOPTIONS pCDOpts = pOpt->GetCDOpts();
pOpt->MMDeviceChanged();
InitCDVol(hwndMain,pCDOpts); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * HandlePowerBroadcast
// On VxD drivers, you can't "suspend" with an open mixer device. Bug 1132.
//
// If lParam == 1, this is a device remove
//
////////////////////////////////////////////////////////////////////////////////////////////
BOOL HandlePowerBroadcast(HWND hWnd, WPARAM wParam, LPARAM lParam) { BOOL fRet = TRUE; switch (wParam) { case PBT_APMQUERYSTANDBY: case PBT_APMQUERYSUSPEND: { if (hmix) { mixerClose((HMIXER)hmix); hmix = NULL; } } //end case power off
break;
case PBT_APMSTANDBY : case PBT_APMSUSPEND : { //actually suspending, go ahead and stop the cd
if (fPlaying) { IMMComponentAutomation* pAuto = NULL; if (pNodeCurrent) { HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { //at this point, we can actually stop the CD
pAuto->OnAction(MMACTION_STOP,NULL); //release the automation object
pAuto->Release(); } } //end if pnodecurrent
} //end if playing
} break;
case PBT_APMQUERYSTANDBYFAILED: case PBT_APMRESUMESTANDBY: case PBT_APMQUERYSUSPENDFAILED: case PBT_APMRESUMESUSPEND: { WinMMDeviceChangeHandler(hWnd); } //end case power on
break; } //end switch
return fRet; }
////////////////////////////////////////////////////////////////////////////////////////////
// * HandleSysMenuInit
// Make sure the system menu only shows the correct choices
////////////////////////////////////////////////////////////////////////////////////////////
void HandleSysMenuInit(HWND hwnd, HMENU hmenu) { //always gray out
EnableMenuItem(hmenu,SC_SIZE, MF_BYCOMMAND|MF_GRAYED); EnableMenuItem(hmenu,SC_MAXIMIZE,MF_BYCOMMAND|MF_GRAYED);
//always enable
EnableMenuItem(hmenu,SC_CLOSE,MF_BYCOMMAND|MF_ENABLED);
//enable or gray based on minimize state
if (IsIconic(hwnd)) { EnableMenuItem(hmenu,SC_RESTORE, MF_BYCOMMAND|MF_ENABLED); EnableMenuItem(hmenu,SC_MOVE, MF_BYCOMMAND|MF_GRAYED); EnableMenuItem(hmenu,SC_MINIMIZE,MF_BYCOMMAND|MF_GRAYED); } else { EnableMenuItem(hmenu,SC_RESTORE, MF_BYCOMMAND|MF_GRAYED); EnableMenuItem(hmenu,SC_MOVE, MF_BYCOMMAND|MF_ENABLED); EnableMenuItem(hmenu,SC_MINIMIZE,MF_BYCOMMAND|MF_ENABLED); } }
////////////////////////////////////////////////////////////////////////////////////////////
// * SysMenuTimerProc
// Make sure the system menu only shows on a single click
////////////////////////////////////////////////////////////////////////////////////////////
void CALLBACK SysMenuTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) { KillTimer(hwnd,idEvent);
POINTS pts; RECT rect;
//make sure the menu shows up in a good-looking place
GetClientRect(hwnd,&rect); rect.left = SYSMENU_XOFFSET; rect.right = SYSMENU_XOFFSET + SYSMENU_WIDTH; rect.bottom = rect.top + TITLEBAR_HEIGHT + (g_nViewMode == VIEW_MODE_NORMAL ? TITLEBAR_YOFFSET_LARGE : TITLEBAR_YOFFSET_SMALL);
ClientToScreen(hwnd,(LPPOINT)&rect); ClientToScreen(hwnd,((LPPOINT)&rect)+1); pts.x = (short)rect.left; pts.y = (short)rect.bottom;
HMENU hSysMenu = GetSystemMenu(hwnd,FALSE);
TPMPARAMS tpm; tpm.cbSize = sizeof(tpm); memcpy(&(tpm.rcExclude),&rect,sizeof(RECT)); TrackPopupMenuEx(hSysMenu,0,pts.x,pts.y,hwnd,&tpm); }
BOOL HandleKeyboardAppCommand(HWND hwnd, short cmd) { BOOL fHandled = FALSE;
switch (cmd) { case APPCOMMAND_VOLUME_MUTE : { SetMute(); fHandled = TRUE; } break;
case APPCOMMAND_VOLUME_DOWN : { SendMessage(GetDlgItem(hwnd,IDB_VOLUME),WM_KEYDOWN,VK_DOWN,0); fHandled = TRUE; } break;
case APPCOMMAND_VOLUME_UP : { SendMessage(GetDlgItem(hwnd,IDB_VOLUME),WM_KEYDOWN,VK_UP,0); fHandled = TRUE; } break;
case APPCOMMAND_MEDIA_NEXTTRACK : { SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(IDB_NEXTTRACK,0),(LPARAM)0); fHandled = TRUE; } break;
case APPCOMMAND_MEDIA_PREVIOUSTRACK : { SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(IDB_PREVTRACK,0),(LPARAM)0); fHandled = TRUE; } break;
case APPCOMMAND_MEDIA_STOP : { SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(IDB_STOP,0),(LPARAM)0); fHandled = TRUE; } break;
case APPCOMMAND_MEDIA_PLAY_PAUSE : { SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(IDB_PLAY,0),(LPARAM)0); fHandled = TRUE; } break;
default: { fHandled = FALSE; } break; } //end switch
return fHandled; }
////////////////////////////////////////////////////////////////////////////////////////////
// * MainWndProc
// Main window's message switcher
////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { //we're being created, start up
case WM_CREATE : { hwndMain = hwnd;
g_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); giVolDevChange = RegisterWindowMessage(TEXT("winmm_devicechange"));
CreateToolTips(hwnd); InitComponents(hwnd); CreateButtonWindows(hwnd); CreateVolumeKnob(hwnd);
//if no disc in player, gray out the track button
IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { MMMEDIAID mmMedia; mmMedia.nDrive = -1; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); pAuto->Release(); if (mmMedia.dwMediaID == 0) { EnableWindow(GetDlgItem(hwnd,IDB_TRACK),FALSE); } } } break;
case SHELLMESSAGE_CDICON : { return (ShellIconHandeMessage(lParam)); } break;
//called from sndvol32 or other apps that change mixer
case MM_MIXM_CONTROL_CHANGE : { HandleMixerControlChange((DWORD)lParam); } break;
//palette changed
case WM_PALETTECHANGED : case WM_QUERYNEWPALETTE : { return (HandlePaletteChange()); } break;
//autoplay copied command line when second instance running
case WM_COPYDATA : { SendMessage(hwndCurrentComp,WM_COPYDATA,wParam,lParam); } break;
//new keyboard interface
case WM_APPCOMMAND : { return HandleKeyboardAppCommand(hwnd,GET_APPCOMMAND_LPARAM(lParam)); } break; //activation/deactivation -- need to repaint title
case WM_ACTIVATE : { HDC hdc = GetDC(hwnd); DrawTitleBar(hdc,hwnd,LOWORD(wParam),FALSE); ReleaseDC(hwnd,hdc); } break;
//check for switch to tiny mode
case WM_NCLBUTTONDBLCLK : case WM_LBUTTONDBLCLK : { KillTimer(hwnd,SYSTIMERID);
if (((int)wParam == HTSYSMENU) && (iMsg == WM_NCLBUTTONDBLCLK)) { break; //don't allow this on a sys menu double-click
} switch (g_nViewMode) { case VIEW_MODE_NORMAL : SetNoBarMode(hwnd); break; case VIEW_MODE_NOBAR : SetNormalMode(hwnd); break; case VIEW_MODE_RESTORE : SetSmallMode(hwnd); break; case VIEW_MODE_SMALL : SetRestoredMode(hwnd); break; } //end switch on view mode
} break;
//handle left click on system menu
//need to set timer to handle double-click
case WM_NCLBUTTONDOWN : { if ((int)wParam == HTSYSMENU) { SetTimer(hwnd,SYSTIMERID,GetDoubleClickTime()+100,(TIMERPROC)SysMenuTimerProc); } } break;
//handle right click on system menu or caption
//no need for timer on double-click
case WM_NCRBUTTONDOWN : { if (((int)wParam == HTCAPTION) || ((int)wParam == HTSYSMENU)) { POINTS pts = MAKEPOINTS(lParam); HMENU hSysMenu = GetSystemMenu(hwnd,FALSE); TrackPopupMenu(hSysMenu,0,pts.x,pts.y,0,hwnd,NULL); } } break;
case WM_INITMENU : { HandleSysMenuInit(hwnd,(HMENU)wParam); } break;
case WM_POWERBROADCAST: { return (HandlePowerBroadcast(hwnd,wParam,0)); } break;
//check for mouse in title bar
case WM_NCHITTEST : { return (OnNCHitTest(hwnd, LOWORD(lParam), HIWORD(lParam),FALSE)); } break;
case WM_NET_DB_UPDATE_BATCH : { LPCDOPT pOpts = GetCDOpt(); if (pOpts) { pOpts->DownLoadCompletion(0,NULL); } } break;
case WM_NET_DB_UPDATE_DISC : { LPCDOPT pOpts = GetCDOpt(); if (pOpts) { pOpts->DiscChanged((LPCDUNIT)lParam); } } break;
//download finished on a disc
case WM_NET_INCMETER : //download finished on discid <lparam>
{ //lparam == -1 means the provider failed the validation check
if (lParam == (LPARAM)-1) { SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_DOWNLOAD,0,(LPARAM)FALSE); HandleBadServiceProvider(hwnd); break; }
if (lParam != 0) { MMNET mmNet; mmNet.discid = (DWORD)(lParam); mmNet.hwndCallback = hwnd; mmNet.pData = (void*)GetCDData(); mmNet.pData2 = NULL; mmNet.fForceNet = FALSE; SendMessage(hwndCurrentComp,WM_COMMAND,MAKEWPARAM(ID_CDUPDATE,0),(LPARAM)&mmNet);
LPCDOPT pOpt = GetCDOpt(); if (pOpt) { LPCDUNIT pUnit = pOpt->GetCDOpts()->pCDUnitList; int nCurrDrive = 0; while (pUnit!=NULL) { if (pUnit->dwTitleID == mmNet.discid) { pUnit->fDownLoading = FALSE; break; } pUnit = pUnit->pNext; } LPCDOPTIONS pCDOpts = pOpt->GetCDOpts(); pCDOpts->dwBatchedTitles = GetNumBatchedTitles();
pOpt->DownLoadCompletion(1,&(mmNet.discid)); }
//put up a message box if the title still isn't available
IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { MMMEDIAID mmMedia; mmMedia.nDrive = -1; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); pAuto->Release();
if (mmNet.discid == mmMedia.dwMediaID) { LPCDDATA pData = GetCDData(); if (!pData->QueryTitle(mmNet.discid)) { TCHAR szNotFound[MAX_PATH]; LoadString(hInst,IDS_TITLE_NOT_FOUND,szNotFound,sizeof(szNotFound)/sizeof(TCHAR)); MessageBox(hwnd,szNotFound,szAppName,MB_ICONINFORMATION|MB_OK); } } //end if disc is same as what is showing in player
} //end if pauto ok
} } break;
case WM_NET_DB_FAILURE : { TCHAR szDBError[MAX_PATH]; LoadString(hInst,IDS_DB_FAILURE,szDBError,sizeof(szDBError)/sizeof(TCHAR)); MessageBox(hwnd,szDBError,szAppName,MB_ICONERROR|MB_OK); } break;
case WM_NET_NET_FAILURE : { TCHAR szNetError[MAX_PATH]; LoadString(hInst,IDS_NET_FAILURE,szNetError,sizeof(szNetError)/sizeof(TCHAR)); MessageBox(hwnd,szNetError,szAppName,MB_ICONERROR|MB_OK); } break;
case WM_NET_DONE : { if (lParam == 0) { //if lparam is 0, download is done ... nuke the animation
SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_DOWNLOAD,0,(LPARAM)FALSE); } } break;
//Network status callback
case WM_NET_STATUS : //download information string in <lparam>
{ //we basically just ignore the string messages and start
//the animation if one isn't going already
SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_DOWNLOAD,0,(LPARAM)TRUE); } break;
case WM_NET_CHANGEPROVIDER : { SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_NET_CHANGEPROVIDER,wParam,lParam); } break;
//change the title bar contents
case WM_SIZE : { if (wParam != SIZE_MINIMIZED) { TCHAR szText[MAX_PATH]; _tcscpy(szText,szAppName); if (pNodeCurrent) { if (_tcslen(pNodeCurrent->szTitle) > 0) { wsprintf(szText,TEXT("%s - %s"),pNodeCurrent->szTitle,szAppName); } } SetWindowText(hwnd,szText); } } break;
//notification that the current disc drive is different
case WM_DISCCHANGED : { LPCDOPT pOpt = GetCDOpt(); if( pOpt ) { LPCDOPTIONS pCDOpts = pOpt->GetCDOpts(); if (InitCDVol(hwnd,pCDOpts)) { DWORD dwVol = GetVolume(); CKnob* pKnob = GetKnobFromID(hwndMain,IDB_VOLUME); if (pKnob!=NULL) { pKnob->SetPosition(dwVol,(BOOL)lParam); }
SendMessage(GetDlgItem(hwnd,IDB_MUTE),BM_SETSTATE,(WPARAM)GetMute(),0); SendMessage(GetDlgItem(hwndCurrentComp,IDC_LEDWINDOW),WM_LED_MUTE,0,GetMute()); } } //end if popt
//if no disc in player, gray out the track button
IMMComponentAutomation* pAuto = NULL; HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { MMMEDIAID mmMedia; mmMedia.nDrive = -1; pAuto->OnAction(MMACTION_GETMEDIAID,&mmMedia); pAuto->Release(); if (mmMedia.dwMediaID == 0) { EnableWindow(GetDlgItem(hwnd,IDB_TRACK),FALSE); } } } break; case WM_SYSCOLORCHANGE : case WM_DISPLAYCHANGE : { //user may have turned on high-contrast mode,
//or changed the display depth. Either way,
//it may be time to change bitmaps
HandleDisplayChange(); } break; case WM_ERASEBKGND : { EnumDisplayMonitors((HDC)wParam, NULL, DoPaint, (LPARAM)hwnd); return TRUE; } break;
case WM_SETCURSOR : { if ((HWND)wParam == GetDlgItem(hwnd,IDB_MUTE)) { if (hCursorMute) { SetCursor(hCursorMute); return TRUE; } } } break;
case WM_HELP : { char chDst[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, HELPFILENAME, -1, chDst, MAX_PATH, NULL, NULL); HtmlHelpA(GetDesktopWindow(), chDst, HH_DISPLAY_TOPIC, 0); } break;
case WM_CLOSE : { if ((fShellMode) && IsWindowVisible(hwnd)) { ShowWindow(hwnd,SW_HIDE); return 0; } } break;
case WM_PAINT : { //multi-mon paint
HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint( hwnd, &ps ); EnumDisplayMonitors(hdc, NULL, DoPaint, (LPARAM)hwnd); EndPaint(hwnd, &ps); return 0; } break;
//default push putton handler
case DM_SETDEFID : { wDefButtonID = (WORD)wParam; } break;
case DM_GETDEFID : { return (MAKELRESULT(wDefButtonID,DC_HASDEFID)); } break;
//custom menu accel handler
case WM_MENUCHAR : { if (g_pMenu) { return (g_pMenu->MenuChar((TCHAR)LOWORD(wParam),(UINT)HIWORD(wParam),(HMENU)lParam)); } } break; //custom menu handler
case WM_MEASUREITEM : { if (lParam == 0) return (0);
if (g_pMenu) { g_pMenu->MeasureItem(hwnd,(LPMEASUREITEMSTRUCT)lParam); } } break;
//custom menu/button handler
case WM_DRAWITEM : { if (lParam == 0) return (0);
if (wParam == 0) { if (g_pMenu) { g_pMenu->DrawItem(hwnd,(LPDRAWITEMSTRUCT)lParam); return (1); } } else { DrawButton((UINT)wParam,(LPDRAWITEMSTRUCT)lParam); return (1); }
return (0); }
//notify is either from tool tip or volume knob
case WM_NOTIFY : { if ((((LPNMHDR)lParam)->code) == TTN_NEEDTEXT) { OnToolTipNotify(lParam); } else { if ((int)wParam == IDB_VOLUME) { CKnob* pKnob = GetKnobFromID(hwnd,IDB_VOLUME);
DWORD dwNewVol = pKnob->GetPosition();
DrawVolume(pKnob->GetPosition());
if ((((LPNMHDR)lParam)->code) == TRUE) { SetVolume(dwNewVol); }
//reset timer to repaint client area
KillTimer(hwnd,VOLUME_PERSIST_TIMER_EVENT); SetTimer(hwnd,VOLUME_PERSIST_TIMER_EVENT,VOLUME_PERSIST_TIMER_RATE,(TIMERPROC)VolPersistTimerProc); } //end if knob
} //end else
} break; //menu going away
case WM_EXITMENULOOP : { BlockMenu(hwnd); } break; //command message
case WM_COMMAND : { HandleCommand(hwnd, iMsg, wParam, lParam); } break;
case WM_DEVICECHANGE : { //if plug-and-play sends this, pass it along to the component
PDEV_BROADCAST_DEVICEINTERFACE bdi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam; PDEV_BROADCAST_HANDLE bh = (PDEV_BROADCAST_HANDLE)lParam; //If we have an handle on the device then we get a DEV_BROADCAST_HDR structure as the lParam.
//Or else it means that we have registered for the general audio category KSCATEGORY_AUDIO.
if(bUseHandle) { if(!DeviceEventContext || !bh || bh->dbch_devicetype != DBT_DEVTYP_HANDLE) { return (SendMessage(hwndCurrentComp,WM_DEVICECHANGE,wParam,lParam)); } } else if (!DeviceEventContext || !bdi || bdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE || !IsEqualGUID(KSCATEGORY_AUDIO, bdi->dbcc_classguid) || !(*bdi->dbcc_name) ) { return (SendMessage(hwndCurrentComp,WM_DEVICECHANGE,wParam,lParam)); } //Handle device changes to the mixer device.
switch(wParam) { //send "1" in lparam to indicate that this is a device remove and not a power request
case DBT_DEVICEQUERYREMOVE: HandlePowerBroadcast(hwndMain, PBT_APMQUERYSUSPEND, (LPARAM)1); break; case DBT_DEVICEQUERYREMOVEFAILED: HandlePowerBroadcast(hwndMain, PBT_APMQUERYSUSPENDFAILED, (LPARAM)1); break; default: break; } }
case WM_WININICHANGE : { return (SendMessage(hwndCurrentComp,WM_WININICHANGE,wParam,lParam)); }
//we're done
case WM_ENDSESSION : case WM_DESTROY : { if ((iMsg == WM_ENDSESSION) && (!wParam)) { return 0; }
if (hMutex) { ReleaseMutex(hMutex); CloseHandle(hMutex); hMutex = NULL; }
//if playing and we don't want to be, stop it
//BE VERY PARANOID and check all variables, this is an RTMCRIT bug fix
LPCDOPT pOpt = GetCDOpt(); if (pOpt) { LPCDOPTIONS pOptions = pOpt->GetCDOpts(); if (pOptions) { LPCDOPTDATA pOptionData = pOptions->pCDData; if (pOptionData) { if (pOptionData->fExitStop) { IMMComponentAutomation* pAuto = NULL; if (pNodeCurrent) { HRESULT hr = pNodeCurrent->pComp->QueryInterface(IID_IMMComponentAutomation,(void**)&pAuto); if ((SUCCEEDED(hr)) && (pAuto != NULL)) { //at this point, we can actually stop the CD
pAuto->OnAction(MMACTION_STOP,NULL); //release the automation object
pAuto->Release(); } } //end if pnodecurrent
} //end if "stop on exit"
} //end if option data ok
} //end if options OK
} //end if opt OK
//make sure we're not downloading
EndDownloadThreads();
//Unregister the WM_DEVICECHANGE notification
Volume_DeviceChange_Cleanup(); //close the volume mixer
mixerClose((HMIXER)hmix);
//delete any GDI objects
GlobalFree(hbmpMain); GlobalFree(hbmpMainRestore); GlobalFree(hbmpMainSmall); GlobalFree(hbmpMainNoBar); DeleteObject(hpalMain);
//shut down the button class
UninitMButtons();
//save window state
if (!IsIconic(hwnd)) { RECT rect; GetWindowRect(hwnd,&rect); SetSettings(rect.left,rect.top); } PostQuitMessage(0); return (0); } }
if (iMsg == g_uTaskbarRestart) { if (fShellMode) { CreateShellIcon(hInst,hwndMain,pNodeCurrent,szAppName); } }
if (iMsg == giVolDevChange) { WinMMDeviceChangeHandler(hwnd); }
return (DefWindowProc(hwnd, iMsg, wParam, lParam)); }
////////////////////////////////////////////////////////////////////////////////////////////
// * LoadComponents
// Load registered componets from registry
// This code modified from the original MFC-based "Jazz" implementation, with blessings
// from todorfay <g>
////////////////////////////////////////////////////////////////////////////////////////////
BOOL LoadComponents( void ) { BOOL fSuccess = FALSE; IMMComponent* pIComponent = NULL; TCHAR szError[MAX_PATH];
if( SUCCEEDED(CDPLAY_CreateInstance(NULL, IID_IMMComponent, (void**)&pIComponent)) ) { fSuccess = TRUE; AddComponent(pIComponent); } else { TCHAR strMsg[MAX_PATH]; LoadString(hInst,IDS_ERRORLOADINGCOMP,szError,sizeof(szError)/sizeof(TCHAR)); TCHAR strReinstall[MAX_PATH]; LoadString(hInst,IDS_REINSTALL,strReinstall,sizeof(strReinstall)/sizeof(TCHAR)); wsprintf(strMsg,TEXT("%s\n\n%s"), szError, strReinstall); MessageBox(NULL, strMsg, szAppName, MB_OK|MB_ICONERROR ); }
return fSuccess; }
////////////////////////////////////////////////////////////////////////////////////////////
// * AddComponent
// Add a component to the list of comps
////////////////////////////////////////////////////////////////////////////////////////////
void AddComponent(IMMComponent* pComponent) { pCompListTail->pComp = pComponent; pCompListTail->pSink = new CFrameworkNotifySink(pCompListTail); pCompListTail->pSink->AddRef();
PCOMPNODE pNew = new COMPNODE; pNew->pComp = NULL; pNew->pNext = NULL; pNew->hwndComp = NULL; pNew->pSink = NULL; pNew->szTitle[0] = '\0';
pCompListTail->pNext = pNew; pCompListTail = pNew; }
////////////////////////////////////////////////////////////////////////////////////////////
// * CleanUp
// Get rid of anything that might have been around, like linked list, mutex, bitmaps, etc.
////////////////////////////////////////////////////////////////////////////////////////////
void CleanUp(void) { if (pCompList) { while (pCompList->pNext != NULL) { PCOMPNODE pTemp = pCompList; pCompList = pTemp->pNext; if (pTemp->pComp) { pTemp->pComp->Release(); pTemp->pSink->Release(); } delete pTemp; } delete pCompList; pCompList = NULL; }
if (g_pOptions) { g_pOptions->Release(); }
if (g_pData) { g_pData->Release(); }
if (g_hhk) { UnhookWindowsHookEx(g_hhk); g_hhk = NULL; }
if (hmImage) { FreeLibrary(hmImage); }
if (fShellMode) { DestroyShellIcon(); }
CDNET_Uninit(); }
////////////////////////////////////////////////////////////////////////////////////////////
// * InitComponents
// Initialize components by calling their INIT functions and setting their window sizes
////////////////////////////////////////////////////////////////////////////////////////////
void InitComponents(HWND hwnd) { PCOMPNODE pList = pCompList;
RECT rect; while (pList->pNext!=NULL) { IMMComponent* pComp = pList->pComp; if (pComp) { nNumComps++; pComp->Init(pList->pSink,hwnd,&rect,&(pList->hwndComp),&(pList->hmenuComp));
CalculateDispAreaOffset(pComp);
switch (g_nViewMode) { case VIEW_MODE_NORMAL : { SetRect(&rect,24,32,455,88+nDispAreaOffset); } break;
case VIEW_MODE_RESTORE : { SetRect(&rect,303,24,384,41); } break;
case VIEW_MODE_SMALL : { SetRect(&rect,303,12,384,29); } break;
case VIEW_MODE_NOBAR : { SetRect(&rect,24,16,455,72+nDispAreaOffset); } break; }
SetWindowPos(pList->hwndComp, hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER|SWP_NOACTIVATE);
//size ledwindow to maximum size
HWND hwndLED = GetDlgItem(pList->hwndComp,IDC_LEDWINDOW); if (hwndLED) { SetRect(&rect,24,32,455,88+nDispAreaOffset); SetWindowPos(hwndLED, pList->hwndComp, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER|SWP_NOACTIVATE);
InvalidateRect(hwndLED,NULL,FALSE); UpdateWindow(hwndLED); }
if (!hwndCurrentComp) { ShowNewComponentWindow(pList, hwnd); } } //end if comp ok
pList = pList->pNext; } //end while
}
////////////////////////////////////////////////////////////////////////////////////////////
// * GetToolTipMsgProc
// Msg hook for tool tips so they know when to pop up
////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK GetToolTipMsgProc(int nCode, WPARAM wParam, LPARAM lParam) { MSG *lpmsg; lpmsg = (MSG *) lParam; if (nCode < 0 || !(IsChild(hwndMain, lpmsg->hwnd))) { return (CallNextHookEx(g_hhk, nCode, wParam, lParam)); }
switch (lpmsg->message) { case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: if (g_hwndTT != NULL) { MSG msg; msg.lParam = lpmsg->lParam; msg.wParam = lpmsg->wParam; msg.message = lpmsg->message; msg.hwnd = lpmsg->hwnd; SendMessage(g_hwndTT, TTM_RELAYEVENT, 0, (LPARAM) (LPMSG) &msg); } break; default: break; }
return (CallNextHookEx(g_hhk, nCode, wParam, lParam)); } ////////////////////////////////////////////////////////////////////////////////////////////
// * CreateToolTips
// Common control setup code to init tool tips
////////////////////////////////////////////////////////////////////////////////////////////
BOOL CreateToolTips(HWND hwnd) { InitCommonControls();
g_hwndTT = CreateWindowEx(0, TOOLTIPS_CLASS, (LPTSTR) NULL, TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwnd, (HMENU) NULL, hInst, NULL); if (g_hwndTT == NULL) return FALSE;
// Install a hook procedure to monitor the message stream for mouse
// messages intended for the controls in main window
g_hhk = SetWindowsHookEx(WH_GETMESSAGE, GetToolTipMsgProc, (HINSTANCE) NULL, GetCurrentThreadId());
if (g_hhk == NULL) return FALSE; return TRUE; }
//WM_DEVICECHANGE support/////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
void Volume_DeviceChange_Cleanup() { if (DeviceEventContext) { UnregisterDeviceNotification(DeviceEventContext); DeviceEventContext = 0; }
bUseHandle = FALSE;
return; }
/*
************************************************************************************************** Volume_GetDeviceHandle()
given a mixerID this functions opens its corresponding device handle. This handle can be used to register for DeviceNotifications.
dwMixerID -- The mixer ID phDevice -- a pointer to a handle. This pointer will hold the handle value if the function is successful return values -- If the handle could be obtained successfully the return vlaue is TRUE.
************************************************************************************************** */ BOOL Volume_GetDeviceHandle(DWORD dwMixerID, HANDLE *phDevice) { MMRESULT mmr; ULONG cbSize=0; TCHAR *szInterfaceName=NULL;
//Query for the Device interface name
mmr = mixerMessage((HMIXER)dwMixerID, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&cbSize, 0L); if(MMSYSERR_NOERROR == mmr) { szInterfaceName = (TCHAR *)GlobalAllocPtr(GHND, (cbSize+1)*sizeof(TCHAR)); if(!szInterfaceName) { return FALSE; }
mmr = mixerMessage((HMIXER)dwMixerID, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)szInterfaceName, cbSize); if(MMSYSERR_NOERROR != mmr) { GlobalFreePtr(szInterfaceName); return FALSE; } } else { return FALSE; }
//Get an handle on the device interface name.
*phDevice = CreateFile(szInterfaceName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
GlobalFreePtr(szInterfaceName); if(INVALID_HANDLE_VALUE == *phDevice) { return FALSE; }
return TRUE; }
/* Volume_DeviceChange_Init()
* First time initialization for WM_DEVICECHANGE messages * * On NT 5.0, you have to register for device notification */ BOOL Volume_DeviceChange_Init(HWND hWnd, DWORD dwMixerID) {
DEV_BROADCAST_HANDLE DevBrodHandle; DEV_BROADCAST_DEVICEINTERFACE dbi; HANDLE hMixerDevice=NULL; MMRESULT mmr;
//If we had registered already for device notifications, unregister ourselves.
Volume_DeviceChange_Cleanup();
//If we get the device handle register for device notifications on it.
if(Volume_GetDeviceHandle(dwMixerID, &hMixerDevice)) { memset(&DevBrodHandle, 0, sizeof(DEV_BROADCAST_HANDLE));
DevBrodHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE); DevBrodHandle.dbch_devicetype = DBT_DEVTYP_HANDLE; DevBrodHandle.dbch_handle = hMixerDevice;
DeviceEventContext = RegisterDeviceNotification(hWnd, &DevBrodHandle, DEVICE_NOTIFY_WINDOW_HANDLE);
if(hMixerDevice) { CloseHandle(hMixerDevice); hMixerDevice = NULL; } if(DeviceEventContext) { bUseHandle = TRUE; return TRUE; } }
if(!DeviceEventContext) { //Register for notifications from all audio devices. KSCATEGORY_AUDIO gives notifications
//on device arrival and removal. We cannot identify which device the notification has arrived for
//but we can take some precautionary measures on these messages so that we do not crash.
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');
DeviceEventContext = RegisterDeviceNotification(hWnd, (PVOID)&dbi, DEVICE_NOTIFY_WINDOW_HANDLE); if(!DeviceEventContext) return FALSE; }
return TRUE; }
//WM_DEVICECHANGE support ends////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
|