/////////////////////////////////////////////////////////////////////////////////////////////////////////// // // MAIN.CPP // // Main window of multimedia framework // // Copyright (c) Microsoft Corporation 1997 // // 12/14/97 David Stewart / dstewart // /////////////////////////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #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 #include "..\cdopt\cdopt.h" #include "..\cdnet\cdnet.h" #include "mmenu.h" #include #include "shellico.h" #include #include "..\cdplay\playres.h" #include "wininet.h" //Support for new WM_DEVICECHANGE behaviour in NT5 ///////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include 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 == -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 { //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 //////////////////////////////////////////////////////////////////////////////////////////// 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//////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////