|
|
/*==========================================================================*/ //
// mmcpl.c
//
// Copyright (C) 1993-1994 Microsoft Corporation. All Rights Reserved.
//
// 06/94 -Created- VijR
//
/*==========================================================================*/
#pragma warning( disable: 4103)
#include "mmcpl.h"
#include <cpl.h>
#define NOSTATUSBAR
#include <commctrl.h>
#include <prsht.h>
#include <regstr.h>
#include <infstr.h>
#include <devguid.h>
#include "draw.h"
#include "utils.h"
#include "drivers.h"
#include "sulib.h"
#include <tchar.h>
#include <hwtab.h>
#include "debug.h"
#ifndef cchRESOURCE
#define cchRESOURCE 256
#endif
/*
*************************************************************** * Globals *************************************************************** */ HINSTANCE ghInstance = NULL; BOOL gfNukeExt = -1; HWND ghwndMsgBox = NULL; HWND ghwndAdvProp = NULL; BOOL gfVoiceTab = FALSE;
#ifdef FIX_BUG_15451
static TCHAR cszFORKLINE[] = TEXT("RUNDLL32.EXE MMSYS.CPL,ShowDriverSettingsAfterFork %s"); #endif // FIX_BUG_15451
SZCODE cszAUDIO[] = AUDIO; SZCODE cszVIDEO[] = VIDEO; SZCODE cszCDAUDIO[] = CDAUDIO; SZCODE cszMIDI[] = MIDI; SZCODE cszVOICE[] = VOICE; SZCODE cszVOLUME[] = VOLUME;
/*
*************************************************************** * Typedefs *************************************************************** */
typedef struct _ExtPropSheetCBParam //Callback Parameter
{ HTREEITEM hti; LPPROPSHEETHEADER ppsh; LPARAM lParam1; //PIRESOURCE/PINSTRUMENT etc. depending on node. (OR) Simple propsheet class
LPARAM lParam2; //hwndTree (OR) Simple propsheet name
} EXTPROPSHEETCBPARAM, *PEXTPROPSHEETCBPARAM;
typedef struct _MBInfo { LPTSTR szTitle; LPTSTR szMsg; UINT uStyle; } MBINFO, *PMBINFO;
/*
*************************************************************** * Defines *************************************************************** */
#define MAXPAGES 8 // MAX number of sheets allowed
#define MAXMODULES 32 // MAX number of external modules allowed
#define MAXCLASSSIZE 64
#define cComma TEXT(',')
#define PROPTABSIZE 13
#define GetString(_str,_id,_hi) LoadString (_hi, _id, _str, sizeof(_str)/sizeof(TCHAR))
/*
*************************************************************** * File Globals *************************************************************** */ static SZCODE aszSimpleProperties[] = REGSTR_PATH_MEDIARESOURCES TEXT("\\MediaExtensions\\shellx\\SimpleProperties\\"); static SZCODE aszShellName[] = TEXT("ShellName");
static UINT g_cRefCnt; // keeps track of the ref count
static int g_cProcesses = 0; static int g_nStartPage = 0;
/*
*************************************************************** * Prototypes *************************************************************** */ INT_PTR CALLBACK AudioDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK VideoDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK CDDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK ACMDlg(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); INT_PTR CALLBACK SoundDlg(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK VolumeDlg(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK AddDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK AdvDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK HardwareDlgProc(HWND hdlg, UINT uMsg, WPARAM wp, LPARAM lp); INT_PTR CALLBACK VoiceDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); //INT_PTR CALLBACK EffectDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
//
// This is the dialog procedure for the "Hardware" page.
//
INT_PTR CALLBACK HardwareDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) { static HWND s_hwndHW = NULL;
switch (uMessage) { case WM_NOTIFY: { NMHDR * pnmhdr = (NMHDR *) lParam; int code = pnmhdr->code;
switch (code) { case HWN_FILTERITEM: { NMHWTAB *pnmht = (NMHWTAB *) lParam; BOOL fFilter = FALSE;
if (!pnmht->fHidden) // Let's not bother looking at devices already hidden
{ fFilter = FALSE; }
return(TRUE); } break;
case HWN_SELECTIONCHANGED: { NMHWTAB *pnmht = (NMHWTAB *) lParam;
if (pnmht) { if (pnmht->pdinf) { if (IsEqualGUID(&(pnmht->pdinf->ClassGuid),&GUID_DEVCLASS_CDROM)) { SetWindowText(s_hwndHW, TEXT("hh.exe ms-its:tshoot.chm::/hdw_drives.htm")); } else { SetWindowText(s_hwndHW, TEXT("hh.exe ms-its:tshoot.chm::/tssound.htm")); } } } } break; } } break;
case WM_INITDIALOG: { GUID guidClass[2];
guidClass[0] = GUID_DEVCLASS_CDROM; guidClass[1] = GUID_DEVCLASS_MEDIA;
s_hwndHW = DeviceCreateHardwarePageEx(hDlg, (const GUID *) &guidClass, 2, HWTAB_LARGELIST );
if (s_hwndHW) { SetWindowText(s_hwndHW, TEXT("hh.exe ms-its:tshoot.chm::/tssound.htm")); } else { DestroyWindow(hDlg); // catastrophic failure
} } return FALSE; }
return FALSE; }
INT_PTR CALLBACK CD_HardwareDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) { switch (uMessage) { case WM_INITDIALOG: { HWND hwndHW;
hwndHW = DeviceCreateHardwarePageEx(hDlg, &GUID_DEVCLASS_CDROM, 1, HWTAB_SMALLLIST);
if (hwndHW) { SetWindowText(hwndHW, TEXT("hh.exe ms-its:tshoot.chm::/hdw_multi.htm")); } else { DestroyWindow(hDlg); // catastrophic failure
} } return FALSE; }
return FALSE; }
/*
*************************************************************** *************************************************************** */
INT_PTR FAR PASCAL mmse_MessageBoxProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { switch (wMsg) { case WM_INITDIALOG: { PMBINFO pmbInfo = (PMBINFO)lParam; UINT uStyle = pmbInfo->uStyle;
SetWindowText(hDlg, pmbInfo->szTitle); SetWindowText(GetDlgItem(hDlg, MMSE_TEXT), pmbInfo->szMsg); if (IsFlagClear(uStyle, MMSE_OK)) DestroyWindow(GetDlgItem(hDlg, MMSE_OK)); if (IsFlagClear(uStyle, MMSE_YES)) DestroyWindow(GetDlgItem(hDlg, MMSE_YES)); if (IsFlagClear(uStyle, MMSE_NO)) DestroyWindow(GetDlgItem(hDlg, MMSE_NO)); ghwndMsgBox = hDlg; break; } case WM_DESTROY: ghwndMsgBox = NULL; break; case WM_COMMAND: { switch (GET_WM_COMMAND_ID(wParam, lParam)) { case MMSE_YES: EndDialog(hDlg, MMSE_YES); break; case MMSE_NO: EndDialog(hDlg, MMSE_NO); break; case MMSE_OK: EndDialog(hDlg, MMSE_OK); break; } break; } default: return FALSE; } return TRUE; }
INT_PTR mmse_MessageBox(HWND hwndP, LPTSTR szMsg, LPTSTR szTitle, UINT uStyle) { MBINFO mbInfo;
mbInfo.szMsg = szMsg; mbInfo.szTitle = szTitle; mbInfo.uStyle = uStyle;
return DialogBoxParam(ghInstance, MAKEINTRESOURCE(DLG_MESSAGE_BOX), hwndP, mmse_MessageBoxProc, (LPARAM)&mbInfo); }
/*==========================================================================*/ int FAR PASCAL lstrncmpi( LPCTSTR lszKey, LPCTSTR lszClass, int iSize) { TCHAR aszKey[64];
lstrcpyn(aszKey, lszKey, iSize); return lstrcmpi(aszKey, lszClass); }
int StrByteLen(LPTSTR sz) { LPTSTR psz;
if (!sz) return 0; for (psz = sz; *psz; psz = CharNext(psz)) ; return (int)(psz - sz); }
static void NukeExt(LPTSTR sz) { int len;
len = StrByteLen(sz);
if (len > 4 && sz[len-4] == TEXT('.')) sz[len-4] = 0; }
static LPTSTR NukePath(LPTSTR sz) { LPTSTR pTmp, pSlash;
for (pSlash = pTmp = sz; *pTmp; pTmp = CharNext(pTmp)) { if (*pTmp == TEXT('\\')) pSlash = pTmp; } return (pSlash == sz ? pSlash : pSlash+1); }
void CheckNukeExtOption(LPTSTR sz) { SHFILEINFO sfi;
SHGetFileInfo(sz, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME); if (lstrcmpi((LPTSTR)(sfi.szDisplayName+lstrlen(sfi.szDisplayName)-4), cszWavExt)) gfNukeExt = TRUE; else gfNukeExt = FALSE; }
LPTSTR PASCAL NiceName(LPTSTR sz, BOOL fNukePath) { SHFILEINFO sfi;
if (gfNukeExt == -1) CheckNukeExtOption(sz);
if (!SHGetFileInfo(sz, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME)) return sz;
if (fNukePath) { lstrcpy(sz, sfi.szDisplayName); } else { LPTSTR lpszFileName;
lpszFileName = NukePath(sz); lstrcpy(lpszFileName, sfi.szDisplayName); if (lpszFileName != sz) CharUpperBuff(sz, 1); } return sz; }
/*
*************************************************************** * ErrorBox * * Description: * Brings up error Dialog displaying error * * Parameters: * HWND hDlg - Window handle * int iResource - id of the resource to be loaded * LPTSTR lpszDesc - The string to be inserted in the resource string * * Returns: BOOL * *************************************************************** */ BOOL PASCAL ErrorBox(HWND hDlg, int iResource, LPTSTR lpszDesc) { TCHAR szBuf[MAXMSGLEN]; TCHAR szTitle[MAXSTR]; TCHAR szResource[MAXMSGLEN];
LoadString(ghInstance, iResource, szResource, MAXSTR); LoadString(ghInstance, IDS_ERROR, szTitle, MAXSTR); wsprintf(szBuf, szResource, lpszDesc); MessageBox(hDlg, szBuf, szTitle, MB_APPLMODAL | MB_OK |MB_ICONSTOP); return TRUE; }
int PASCAL DisplayMessage(HWND hDlg, int iResTitle, int iResMsg, UINT uStyle) { TCHAR szBuf[MAXMSGLEN]; TCHAR szTitle[MAXSTR]; UINT uAddStyle = MB_APPLMODAL;
if (!LoadString(ghInstance, iResTitle, szTitle, MAXSTR)) return FALSE; if (!LoadString(ghInstance, iResMsg, szBuf, MAXSTR)) return FALSE; if (uStyle & MB_OK) uAddStyle |= MB_ICONASTERISK; else uAddStyle |= MB_ICONQUESTION; return MessageBox(hDlg, szBuf, szTitle, uStyle | uAddStyle); }
//Adds spaces around Tab Names to make them all approx. same size.
STATIC void PadWithSpaces(LPTSTR szName, LPTSTR szPaddedName) { static SZCODE cszFmt[] = TEXT("%s%s%s"); TCHAR szPad[8]; int i;
i = PROPTABSIZE - lstrlen(szName);
i = (i <= 0) ? 0 : i/2; for (szPad[i] = TEXT('\0');i; i--) szPad[i-1] = TEXT(' '); wsprintf(szPaddedName, cszFmt, szPad, szName, szPad); }
/*==========================================================================*/ UINT CALLBACK CallbackPage( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { if (uMsg == PSPCB_RELEASE) { DPF_T("* RelasePage %s *", (LPTSTR)ppsp->pszTitle); } return 1; }
/*==========================================================================*/ static BOOL PASCAL NEAR AddPage( LPPROPSHEETHEADER ppsh, LPCTSTR pszTitle, DLGPROC pfnDialog, UINT idTemplate, LPARAM lParam) { if (ppsh->nPages < MAXPAGES) {
if (pfnDialog) { PROPSHEETPAGE psp; psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = PSP_DEFAULT | PSP_USETITLE | PSP_USECALLBACK; psp.hInstance = ghInstance; psp.pszTemplate = MAKEINTRESOURCE(idTemplate); psp.pszIcon = NULL; psp.pszTitle = pszTitle; psp.pfnDlgProc = pfnDialog; psp.lParam = (LPARAM)lParam; psp.pfnCallback = CallbackPage; psp.pcRefParent = NULL; if (ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp)) { ppsh->nPages++; return TRUE; } } } return FALSE; }
/*==========================================================================*/ BOOL CALLBACK MMExtPropSheetCallback(DWORD dwFunc, DWORD_PTR dwParam1, DWORD_PTR dwParam2, DWORD_PTR dwInstance) { PEXTPROPSHEETCBPARAM pcbp = (PEXTPROPSHEETCBPARAM)dwInstance;
if (!pcbp && dwFunc != MM_EPS_BLIND_TREECHANGE) return FALSE; switch (dwFunc) { case MM_EPS_GETNODEDESC: { if (!dwParam1) return FALSE; if (pcbp->hti == NULL) lstrcpy((LPTSTR)dwParam1, (LPTSTR)pcbp->lParam2); else { GetTreeItemNodeDesc ((LPTSTR)dwParam1, (PIRESOURCE)pcbp->lParam1); } break; } case MM_EPS_GETNODEID: { if (!dwParam1) return FALSE; if (pcbp->hti == NULL) lstrcpy((LPTSTR)dwParam1, (LPTSTR)pcbp->lParam2); else { GetTreeItemNodeID ((LPTSTR)dwParam1, (PIRESOURCE)pcbp->lParam1); } break; } case MM_EPS_ADDSHEET: { HPROPSHEETPAGE hpsp = (HPROPSHEETPAGE)dwParam1;
if (hpsp && (pcbp->ppsh->nPages < MAXPAGES)) { pcbp->ppsh->phpage[pcbp->ppsh->nPages++] = hpsp; return TRUE; } return FALSE; } case MM_EPS_TREECHANGE: { RefreshAdvDlgTree (); break; } case MM_EPS_BLIND_TREECHANGE: { RefreshAdvDlgTree (); break; } default: return FALSE; } return TRUE; }
INT_PTR CALLBACK SpeechDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
/*==========================================================================*/ static BOOL PASCAL NEAR AddSpeechPage(LPPROPSHEETHEADER ppsh) { TCHAR aszTitleRes[128]; TCHAR szTmp[32];
LoadString(ghInstance, IDS_SPEECH_NAME, aszTitleRes, sizeof(aszTitleRes)/sizeof(TCHAR)); PadWithSpaces((LPTSTR)aszTitleRes, (LPTSTR)szTmp); return AddPage(ppsh, szTmp, SpeechDlgProc, IDD_SPEECH, (LPARAM)NULL); }
/*==========================================================================*/ static BOOL PASCAL NEAR AddAdvancedPage( LPPROPSHEETHEADER ppsh) { TCHAR aszTitleRes[128]; TCHAR szTmp[32];
LoadString(ghInstance, IDS_ADVANCED, aszTitleRes, sizeof(aszTitleRes)/sizeof(TCHAR)); PadWithSpaces((LPTSTR)aszTitleRes, (LPTSTR)szTmp); return AddPage(ppsh, szTmp, AdvDlg, ADVDLG, (LPARAM)NULL); }
/*==========================================================================*/ static BOOL PASCAL NEAR AddHardwarePage( LPPROPSHEETHEADER ppsh) { TCHAR aszTitleRes[128]; TCHAR szTmp[32];
// Don't add a hardware tab if the admin restricted it
if (SHRestricted(REST_NOHARDWARETAB)) return FALSE;
LoadString(ghInstance, IDS_HARDWARE, aszTitleRes, sizeof(aszTitleRes)/sizeof(TCHAR)); PadWithSpaces((LPTSTR)aszTitleRes, (LPTSTR)szTmp); return AddPage(ppsh, szTmp, HardwareDlgProc, HWDLG, (LPARAM)NULL); }
/*==========================================================================*/ static BOOL PASCAL NEAR AddSchemesPage( LPPROPSHEETHEADER ppsh) { TCHAR aszTitleRes[128];
LoadString(ghInstance, IDS_EVENTSNAME, aszTitleRes, sizeof(aszTitleRes)/sizeof(TCHAR)); return AddPage(ppsh, aszTitleRes, SoundDlg, SOUNDDIALOG, (LPARAM)NULL); }
/*==========================================================================*/
static void PASCAL NEAR AddInternalPages (LPPROPSHEETHEADER ppsh) { static EXTPROPSHEETCBPARAM cbp; TCHAR szText[ cchRESOURCE ]; TCHAR szPadded[ cchRESOURCE ];
// Add the Volume page
//
GetString (szText, IDS_VOLUMENAME, ghInstance); PadWithSpaces (szText, szPadded); AddPage (ppsh, szPadded, VolumeDlg, IDD_VOLUME, (LPARAM)NULL);
// Add the Sound Scheme page
//
GetString (szText, IDS_EVENTSNAME, ghInstance); PadWithSpaces (szText, szPadded); AddPage (ppsh, szPadded, SoundDlg, SOUNDDIALOG, (LPARAM)NULL);
// Add the Audio page
//
GetString (szText, IDS_AUDIO_TAB, ghInstance); PadWithSpaces (szText, szPadded); AddPage (ppsh, szPadded, AudioDlg, AUDIODLG, (LPARAM)NULL);
// Add the Voice page
//
GetString (szText, IDS_VOICE, ghInstance); PadWithSpaces (szText, szPadded); AddPage (ppsh, szPadded, VoiceDlg, VOICEDLG, (LPARAM)NULL);
// Add the Video page
//
/* GetString (szText, IDS_VIDEO_TAB, ghInstance);
PadWithSpaces (szText, szPadded); AddPage (ppsh, szPadded, VideoDlg, VIDEODLG, (LPARAM)NULL); */
// Add the MIDI page
//
/* GetString (szText, IDS_MIDI_TAB, ghInstance);
PadWithSpaces (szText, szPadded); cbp.ppsh = ppsh; cbp.hti = NULL; cbp.lParam1 = (LPARAM)cszMIDI; cbp.lParam2 = (LPARAM)szPadded; AddSimpleMidiPages ((LPVOID)szPadded, MMExtPropSheetCallback, (LPARAM)&cbp); */
// Add the CD Audio page
//
/* GetString (szText, IDS_CDAUDIO_TAB, ghInstance);
PadWithSpaces (szText, szPadded); AddPage (ppsh, szPadded, CDDlg, CDDLG, (LPARAM)NULL); */ }
static void InitPSH(LPPROPSHEETHEADER ppsh, HWND hwndParent, LPTSTR pszCaption, HPROPSHEETPAGE FAR * phpsp) { ppsh->dwSize = sizeof(PROPSHEETHEADER); ppsh->dwFlags = PSH_PROPTITLE; ppsh->hwndParent = hwndParent; ppsh->hInstance = ghInstance; ppsh->pszCaption = pszCaption; ppsh->nPages = 0; ppsh->nStartPage = 0; ppsh->phpage = phpsp; }
/*==========================================================================*/ #ifdef FIX_BUG_15451
static void PASCAL cplMMDoubleClick (HWND hCPlWnd, int nStartPage) #else // FIX_BUG_15451
static void PASCAL cplMMDoubleClick (HWND hCPlWnd) #endif // FIX_BUG_15451
{ PROPSHEETHEADER psh; HPROPSHEETPAGE hpsp[MAXPAGES]; TCHAR strOldDir[MAX_PATH], strSysDir[MAX_PATH];
strOldDir[0] = TEXT('\0'); strSysDir[0] = TEXT('\0');
GetSystemDirectory(strSysDir, MAX_PATH); GetCurrentDirectory(MAX_PATH, strOldDir); SetCurrentDirectory(strSysDir); wsInfParseInit();
InitCommonControls(); OleInitialize(NULL);
RegSndCntrlClass((LPCTSTR)DISPFRAMCLASS); InitPSH(&psh,hCPlWnd,(LPTSTR)MAKEINTRESOURCE(IDS_MMNAME),hpsp);
#ifdef FIX_BUG_15451
psh.nStartPage = nStartPage; #else // FIX_BUG_15451
psh.nStartPage = g_nStartPage; #endif // FIX_BUG_15451
g_nStartPage = 0; AddInternalPages(&psh); //AddSpeechPage(&psh);
//AddAdvancedPage(&psh);
AddHardwarePage(&psh); PropertySheet(&psh);
OleUninitialize();
infClose(NULL); SetCurrentDirectory(strOldDir); }
/*==========================================================================*/ static void PASCAL cplEventsDoubleClick (HWND hCPlWnd) { PROPSHEETHEADER psh; HPROPSHEETPAGE hpsp[MAXPAGES];
InitCommonControls(); RegSndCntrlClass((LPCTSTR)DISPFRAMCLASS); InitPSH(&psh,hCPlWnd,(LPTSTR)MAKEINTRESOURCE(IDS_EVENTSNAME),hpsp); AddSchemesPage(&psh); PropertySheet(&psh); }
#ifdef FIX_BUG_15451
/*==========================================================================*/ /*
* ShowDriverSettings * ShowDriverSettingsAfterFork * * When the user selects DevicesTab.<anydevice>.Properties.Settings, a * DRV_CONFIGURE message is sent to the selected user-mode driver, to cause * it to display its configuration dialog. The sound drivers shipped with * NT (SNDBLST,MVAUDIO,SNDSYS) exhibit a bug in this condition: when the * configuration dialog is complete (regardless of whether OK or CANCEL was * selected), these drivers attempt to unload-and-reload their kernel-mode * component in order to begin using the new (or restore the original) * driver settings. The unload request fails, because both the Audio tab * and SNDVOL.EXE have open mixer handles and pending IRPs within the kernel * driver (the latter are used to provide notifications of volume changes). * Worse, when the unload fails, it leaves the driver useless: its state * remains STOP_PENDING, and it cannot be resurrected without logging off * and back on. * * These routines have been provided as a temporary workaround for bug 15451, * which describes the problem mentioned above. The theory behind this * solution is two-fold: * 1- close SNDVOL.EXE as soon as a driver's configuration dialog is * to be displayed, and restart it directly thereafter. This prevents * it from maintaining any open handles to and/or pending IRPs within the * kernel driver. * 2- if the Audio tab has ever been displayed, it will have open mixers * which must be closed. Because a bug/design flaw within these sound * drivers prevents the mixers from being closed without killing this * process (the sound drivers each cache open mixer handles), the * routine ShowDriverSettings forks a new MMSYS.CPL process, which is * then used to display the driver's settings dialog. * * The flow of this solution follows: * * 1- MMSYS.CPL starts on Audio tab, setting fHaveStartedAudioDialog to TRUE. * 2- User selects Devices tab. * 3- User selects a device driver. * 4- User selects Properties+Settings; control reaches ShowDriverSettings(). * 5- ShowDriverSettings() determines if there is a need to fork a new process: * this will be the case if the Audio tab has been displayed, and the * device for which it is to display settings contains mixers. If either * of these conditions is false, ShowDriverSettings displays the driver's * settings dialog directly (via ConfigureDriver()). * 6- ShowDriverSettings() uses WinExec() to fork a new process, using * the routine ShowDriverSettingsAfterFork() as an entry point. If the * exec fails, ShowDriverSettings() displays the driver's settings dialog * directly (via ConfigureDriver()). * PROCESS 1: PROCESS 2: * 7- Enters WaitForNewCPLWindow(), 1- ShowDriverSettingsAfterFork() will * which will wait up to 5 seconds receive on its command-line the * for the new MMSYS.CPL process name of the driver for which * to open a driver Properties settings have been requested. It * dialog which matches its own: opens the primary dialog, using the * if it finds such a dialog, Devices tab as the initial tab-- * WaitForNewCPLWindow() will post so that the Advanced tab is never * IDCANCEL messages to both the displayed, and because the Devices * current driver Properties dialog, tab is the active tab on the other * and to this process's main process. * dialog, terminating this process. 2- During WM_INITDIALOG of the Devices * dialog, this process searches for * the previous process' MMSYS.CPL dialog. * If successful, it moves this MMSYS.CPL * dialog directly behind the previous dialog. * 3- During ID_INIT of the Devices dialog, this * process searches the TreeView for the driver * which was named on the comand-line: if found, * it highlights the TreeItem and simulates a press * of the Properties button * 4- During WM_INITDIALOG of the device's Properties dialog, * this process searches for the previous process' device's * properties dialog. If successful, it moves this dialog * directly behind its counterpart. * 5- During ID_INIT of the device's Properties dialog, this process * simulates a press of the Settings button * 6- When the Settings button is pressed, this process recognizes that * it has been forked and skips the call to ShowDriverSettings(), * instead simply displaying the driver's settings dialog (via * ConfigureDriver()). * * Let it be known that this is a hack, and should be removed post-beta. * */
extern BOOL fHaveStartedAudioDialog; // in MSACMCPL.C
void ShowDriverSettings (HWND hDlg, LPTSTR pszName) { if (fHaveStartedAudioDialog && fDeviceHasMixers (pszName)) { TCHAR szForkLine[ cchRESOURCE *2 ];
STARTUPINFO si; PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.wShowWindow = SW_SHOW; si.dwFlags = STARTF_USESHOWWINDOW;
wsprintf (szForkLine, cszFORKLINE, pszName);
if (CreateProcess(NULL,szForkLine,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) { (void)WaitForNewCPLWindow (hDlg); } else { ConfigureDriver (hDlg, pszName); } } else { ConfigureDriver (hDlg, pszName); } }
void WINAPI ShowDriverSettingsAfterFork ( HWND hwndStub, HINSTANCE hAppInstance, LPTSTR lpszCmdLine, int nCmdShow) { #ifdef UNICODE
WCHAR szCmdLine[ cchRESOURCE ]; #else
#define szCmdLine lpszCmdLine
#endif
lstrcpy (szDriverWhichNeedsSettings, szCmdLine); cplMMDoubleClick (NULL, 4); // 4==Start on Advanced ("Devices") tab
}
void WINAPI ShowDriverSettingsAfterForkW ( HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow) { #ifdef UNICODE
#define szCmdLine lpwszCmdLine
#else
CHAR szCmdLine[ cchRESOURCE ]; wcstombs(szCmdLine, lpwszCmdLine, cchRESOURCE); #endif
lstrcpy (szDriverWhichNeedsSettings, szCmdLine); cplMMDoubleClick (NULL, 4); // 4==Start on Advanced ("Devices") tab
}
#endif // FIX_BUG_15451
// Globals to support sound event command line parameters.
#define MAX_SND_EVNT_CMD_LINE 32
TCHAR gszCmdLineApp[MAX_SND_EVNT_CMD_LINE]; TCHAR gszCmdLineEvent[MAX_SND_EVNT_CMD_LINE];
/*==========================================================================*/ LONG CPlApplet( HWND hCPlWnd, UINT Msg, LPARAM lParam1, LPARAM lParam2) { switch (Msg) { case CPL_INIT: wHelpMessage = RegisterWindowMessage(TEXT("ShellHelp")); DPF_T("*CPL_INIT*"); g_cRefCnt++; return (LRESULT)TRUE;
case CPL_GETCOUNT: return (LRESULT)1;
case CPL_INQUIRE: DPF_T("*CPL_INQUIRE*"); switch (lParam1) { case 0: ((LPCPLINFO)lParam2)->idIcon = IDI_MMICON; ((LPCPLINFO)lParam2)->idName = IDS_MMNAME; ((LPCPLINFO)lParam2)->idInfo = IDS_MMINFO; break; default: return FALSE; } ((LPCPLINFO)lParam2)->lData = 0L; return TRUE;
case CPL_NEWINQUIRE: switch (lParam1) { case 0: ((LPNEWCPLINFO)lParam2)->hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_MMICON)); LoadString(ghInstance, IDS_MMNAME, ((LPNEWCPLINFO)lParam2)->szName, sizeof(((LPNEWCPLINFO)lParam2)->szName)/sizeof(TCHAR)); LoadString(ghInstance, IDS_MMINFO, ((LPNEWCPLINFO)lParam2)->szInfo, sizeof(((LPNEWCPLINFO)lParam2)->szInfo)/sizeof(TCHAR)); break; default: return FALSE; } ((LPNEWCPLINFO)lParam2)->dwHelpContext = 0; ((LPNEWCPLINFO)lParam2)->dwSize = sizeof(NEWCPLINFO); ((LPNEWCPLINFO)lParam2)->lData = 0L; ((LPNEWCPLINFO)lParam2)->szHelpFile[0] = 0; return TRUE;
case CPL_DBLCLK: DPF_T("* CPL_DBLCLICK*"); // Do the applet thing.
switch (lParam1) { case 0: // Check for obsolete command line (see comments
// under CPL_STARTWPARAMS)
if ((-1) == g_nStartPage) break;
#ifdef FIX_BUG_15451
lstrcpy (szDriverWhichNeedsSettings, TEXT("")); cplMMDoubleClick(hCPlWnd, g_nStartPage); #else // FIX_BUG_15451
cplMMDoubleClick(hCPlWnd); #endif // FIX_BUG_15451
break; } break;
case CPL_STARTWPARMS: switch (lParam1) { case 0: if (lParam2 && *((LPTSTR)lParam2)) { TCHAR c;
c = *((LPTSTR)lParam2); if (c > TEXT('0') && c < TEXT('5')) { g_nStartPage = c - TEXT('0'); break; }
// The "S" command line was used on Windows 98 and Windows 98
// SE. The command line was written to the Active Setup
// registry to run logic to setup preferred devices on a
// specific PnP device instance. It is obsolete and handled in
// winmm.dll itself. This cpl should do nothing for this
// command line.
if ((c == TEXT('S')) || (c == TEXT('s'))) { g_nStartPage = (-1); break; } } g_nStartPage = 0; break;
// For sound events, the passed in parameter indicates a module
// name and event. If a name is passed only show it's sound events.
// If a name and event are passed only show the event.
/* case 1:
if (lParam2 && *((LPTSTR)lParam2)) { TCHAR *psz;
if ((psz = wcschr((LPTSTR)lParam2, TEXT(','))) != NULL) { *psz++ = TEXT('\0'); wcsncpy(gszCmdLineEvent, psz, MAX_SND_EVNT_CMD_LINE/sizeof(TCHAR)); gszCmdLineEvent[MAX_SND_EVNT_CMD_LINE-sizeof(TCHAR)] = TEXT('\0'); } wcsncpy(gszCmdLineApp, (LPTSTR)lParam2, MAX_SND_EVNT_CMD_LINE/sizeof(TCHAR)); gszCmdLineApp[MAX_SND_EVNT_CMD_LINE-sizeof(TCHAR)] = TEXT('\0'); } break; */ }
break;
case CPL_EXIT: DPF_T("* CPL_EXIT*"); g_cRefCnt--; break; } return 0; }
void PASCAL ShowPropSheet(LPCTSTR pszTitle, DLGPROC pfnDialog, UINT idTemplate, HWND hWndParent, LPTSTR pszCaption, LPARAM lParam) { PROPSHEETHEADER psh; HPROPSHEETPAGE hpsp[MAXPAGES];
InitPSH(&psh,hWndParent,pszCaption,hpsp); AddPage(&psh, pszTitle, pfnDialog, idTemplate, lParam); PropertySheet(&psh);
}
void PASCAL ShowMidiPropSheet(LPPROPSHEETHEADER ppshExt, LPCTSTR pszTitle, HWND hWndParent, short iMidiPropType, LPTSTR pszCaption, HTREEITEM hti, LPARAM lParam1, LPARAM lParam2) { PROPSHEETHEADER psh; LPPROPSHEETHEADER ppsh; HPROPSHEETPAGE hpsp[MAXPAGES]; static EXTPROPSHEETCBPARAM cbp;
if (!ppshExt) { ppsh = &psh; InitPSH(ppsh,hWndParent,pszCaption,hpsp); } else ppsh = ppshExt;
cbp.lParam1 = lParam1; cbp.lParam2 = lParam2; cbp.hti = hti; cbp.ppsh = ppsh;
if (iMidiPropType == MIDI_CLASS_PROP) { if (AddMidiPages((LPVOID)pszTitle, MMExtPropSheetCallback, (LPARAM)&cbp)) { PropertySheet(ppsh); } } else if (iMidiPropType == MIDI_INSTRUMENT_PROP) { if (AddInstrumentPages((LPVOID)pszTitle, MMExtPropSheetCallback, (LPARAM)&cbp)) { PropertySheet(ppsh); } } else { if (AddDevicePages((LPVOID)pszTitle, MMExtPropSheetCallback, (LPARAM)&cbp)) { PropertySheet(ppsh); } } }
void PASCAL ShowWithMidiDevPropSheet(LPCTSTR pszTitle, DLGPROC pfnDialog, UINT idTemplate, HWND hWndParent, LPTSTR pszCaption, HTREEITEM hti, LPARAM lParam, LPARAM lParamExt1, LPARAM lParamExt2) { PROPSHEETHEADER psh; HPROPSHEETPAGE hpsp[MAXPAGES];
InitPSH(&psh,hWndParent,pszCaption,hpsp); AddPage(&psh, pszTitle, pfnDialog, idTemplate, lParam); PropertySheet(&psh); // Disabling the details sheet - obsolete 01/10/2001
//ShowMidiPropSheet(&psh, pszCaption, hWndParent,MIDI_DEVICE_PROP,pszCaption,hti,lParamExt1,lParamExt2);
}
BOOL WINAPI ShowMMCPLPropertySheetW(HWND hwndParent, LPCTSTR pszPropSheetID, LPTSTR pszTabName, LPTSTR pszCaption) { DLGPROC pfnDlgProc; UINT idTemplate; HWND hwndP; PROPSHEETHEADER psh; HPROPSHEETPAGE hpsp[MAXPAGES];
if (GetWindowLongPtr(hwndParent, GWL_EXSTYLE) & WS_EX_TOPMOST) hwndP = NULL; else hwndP = hwndParent;
InitPSH(&psh,hwndP,pszCaption,hpsp); psh.dwFlags = 0;
if (!lstrcmpi(pszPropSheetID, cszAUDIO)) { pfnDlgProc = AudioDlg; idTemplate = AUDIODLG; goto ShowSheet; } if (!lstrcmpi(pszPropSheetID, cszVOICE)) { pfnDlgProc = VoiceDlg; idTemplate = VOICEDLG; goto ShowSheet; } if (!lstrcmpi(pszPropSheetID, cszVOLUME)) { pfnDlgProc = VolumeDlg; idTemplate = IDD_VOLUME; goto ShowSheet; } if (!lstrcmpi(pszPropSheetID, cszVIDEO)) { pfnDlgProc = VideoDlg; idTemplate = VIDEODLG; goto ShowSheet; } if (!lstrcmpi(pszPropSheetID, cszCDAUDIO)) { pfnDlgProc = CD_HardwareDlgProc; idTemplate = HWDLG; goto ShowSheet; } if (!lstrcmpi(pszPropSheetID, cszMIDI)) { /*
static EXTPROPSHEETCBPARAM cbpMIDI;
cbpMIDI.ppsh = &psh; cbpMIDI.hti = NULL; cbpMIDI.lParam1 = (LPARAM)pszPropSheetID; cbpMIDI.lParam2 = (LPARAM)pszTabName; AddSimpleMidiPages((LPVOID)pszTabName, MMExtPropSheetCallback, (LPARAM)&cbpMIDI); PropertySheet(&psh); return TRUE; */
pfnDlgProc = AudioDlg; idTemplate = AUDIODLG; goto ShowSheet;
}
return FALSE; ShowSheet: AddPage(&psh, pszTabName, pfnDlgProc, idTemplate, (LPARAM)NULL); PropertySheet(&psh); return TRUE; }
BOOL WINAPI ShowMMCPLPropertySheet(HWND hwndParent, LPCSTR pszPropSheetID, LPSTR pszTabName, LPSTR pszCaption) { DLGPROC pfnDlgProc; UINT idTemplate; HWND hwndP; PROPSHEETHEADER psh; HPROPSHEETPAGE hpsp[MAXPAGES]; TCHAR szPropSheetID[MAX_PATH]; TCHAR szTabName[MAX_PATH]; TCHAR szCaption[MAX_PATH];
//convert three params into UNICODE strings
MultiByteToWideChar( GetACP(), 0, pszPropSheetID, -1, szPropSheetID, sizeof(szPropSheetID) / sizeof(TCHAR) ); MultiByteToWideChar( GetACP(), 0, pszTabName, -1, szTabName, sizeof(szTabName) / sizeof(TCHAR) ); MultiByteToWideChar( GetACP(), 0, pszCaption, -1, szCaption, sizeof(szCaption) / sizeof(TCHAR) );
return (ShowMMCPLPropertySheetW(hwndParent,szPropSheetID,szTabName,szCaption)); }
//allows you to show control panel from RUNDLL32
DWORD WINAPI ShowFullControlPanel(HWND hwndP, HINSTANCE hInst, LPTSTR szCmd, int nShow) { cplMMDoubleClick(hwndP, 0); return 0; }
DWORD WINAPI ShowAudioPropertySheet(HWND hwndP, HINSTANCE hInst, LPTSTR szCmd, int nShow) { TCHAR szAudio[MAXLNAME]; TCHAR szAudioProperties[MAXLNAME]; char mbcszAUDIO[MAXLNAME]; char mbszAudio[MAXLNAME]; char mbszAudioProperties[MAXLNAME]; HWND hwndPrev;
LoadString(ghInstance, IDS_AUDIOPROPERTIES, szAudioProperties, sizeof(szAudioProperties)/sizeof(TCHAR)); hwndPrev = FindWindow(NULL,szAudioProperties); if (hwndPrev) { SetForegroundWindow(hwndPrev); } else { LoadString(ghInstance, IDS_WAVE_HEADER, szAudio, sizeof(szAudio)/sizeof(TCHAR)); ShowMMCPLPropertySheetW(hwndP, cszAUDIO, szAudio, szAudioProperties); } return 0; }
DWORD WINAPI mmseRunOnce(HWND hwnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nShow) { // This is an obsolete function formerly used to migrate
// registry and driver information. We leave the export
// in place in case an old installation has left a RunOnce
// command in place to execute this function.
return 0; }
DWORD WINAPI mmseRunOnceW(HWND hwnd, HINSTANCE hInst, LPWSTR lpwszCmdLine, int nShow) { // This is an obsolete function formerly used to migrate
// registry and driver information. We leave the export
// in place in case an old installation has left a RunOnce
// command in place to execute this function.
return 0; }
extern BOOL DriversDllInitialize (IN PVOID, IN DWORD, IN PCONTEXT OPTIONAL);
BOOL DllInitialize (IN PVOID hInstance, IN DWORD ulReason, IN PCONTEXT pctx OPTIONAL) { // patch in the old DRIVERS.DLL code (see DRIVERS.C)
//
DriversDllInitialize (hInstance, ulReason, pctx);
if (ulReason == DLL_PROCESS_ATTACH) { ++g_cProcesses; ghInstance = hInstance; DisableThreadLibraryCalls(hInstance); return TRUE; }
if (ulReason == DLL_PROCESS_DETACH) { --g_cProcesses; return TRUE; }
return TRUE; }
DWORD WINAPI MediaClassInstaller( IN DI_FUNCTION InstallFunction, IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ) /*++
Routine Description:
This routine acts as the class installer for Media devices.
Arguments:
InstallFunction - Specifies the device installer function code indicating the action being performed.
DeviceInfoSet - Supplies a handle to the device information set being acted upon by this install action.
DeviceInfoData - Optionally, supplies the address of a device information element being acted upon by this install action.
Return Value:
If this function successfully completed the requested action, the return value is NO_ERROR.
If the default behavior is to be performed for the requested action, the return value is ERROR_DI_DO_DEFAULT.
If an error occurred while attempting to perform the requested action, a Win32 error code is returned.
--*/ { DWORD dwRet=ERROR_DI_DO_DEFAULT;
switch (InstallFunction) {
case DIF_SELECTBESTCOMPATDRV: dwRet = Media_SelectBestCompatDrv(DeviceInfoSet,DeviceInfoData); break;
case DIF_ALLOW_INSTALL: dwRet = Media_AllowInstall(DeviceInfoSet,DeviceInfoData); break;
case DIF_INSTALLDEVICE : dwRet = Media_InstallDevice(DeviceInfoSet, DeviceInfoData); break;
case DIF_REMOVE: dwRet = Media_RemoveDevice(DeviceInfoSet,DeviceInfoData); break;
case DIF_SELECTDEVICE: dwRet = Media_SelectDevice(DeviceInfoSet,DeviceInfoData); break;
case DIF_FIRSTTIMESETUP: // Fall through
case DIF_DETECT: dwRet = Media_MigrateLegacy(DeviceInfoSet,DeviceInfoData); break;
}
return dwRet;
}
DWORD WINAPI mmWOW64MediaInstallDevice(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData) { SP_DEVINSTALL_PARAMS DeviceInstallParams; HWND hWnd;
//
// Get the device install parameters, so we'll know what parent window to use for any
// UI that occurs during configuration of this device.
//
DeviceInstallParams.cbSize = sizeof(DeviceInstallParams); if (SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) { hWnd = DeviceInstallParams.hwndParent; } else { hWnd = NULL; }
//
// The INF will have created a "Drivers" subkey under the device's software key.
// This tree, in turn, contains subtrees for each type of driver (aux, midi, etc.)
// applicable for this device. We must now traverse this tree, and create entries
// in Drivers32 for each function alias.
//
return InstallDriversForPnPDevice(hWnd, DeviceInfoSet, DeviceInfoData); }
DWORD WINAPI mmWOW64MediaRemoveDevice(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData) { if( RemoveDriver(DeviceInfoSet, DeviceInfoData) ) { return NO_ERROR; } else { return ERROR_BAD_DRIVER; } }
DWORD WINAPI mmWOW64MediaClassInstallerA(HWND hwnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nShow) /*++
Routine Description:
This routine acts as a thunking layer for calling the 32-bit installation functions from the 64-bit setup via RunDLL32.exe.
Arguments:
hwnd - not used
hInst - not used
lpwszCmdLine - command line arguments: "Instance ID (string)" DI_FUNCTION (as an integer)
nShow - not used
Return Value:
If this function successfully completed the requested action, the return value is NO_ERROR.
If an error occurred while attempting to perform the requested action, a Win32 error code is returned.
--*/ { LPSTR strInstanceID = NULL; LPSTR strInstallIndex = NULL; DWORD dwInstallIndex = 0; LPSTR strTemp = NULL; HDEVINFO DeviceInfoSet = NULL; SP_DEVINFO_DATA DeviceInfoData; DWORD dwResult = NO_ERROR;
// Find first quote
strTemp = strchr( lpszCmdLine, '\"' ); if( !strTemp ) { return ERROR_INVALID_PARAMETER; }
// Instance ID
// Skip first quote
strInstanceID = ++strTemp;
// Find second quote
strTemp = strchr( strTemp, '\"' ); if( !strTemp ) { return ERROR_INVALID_PARAMETER; }
// NULL-terminate the InstanceID
*strTemp = 0;
// Install Index
// Skip the NULL
strInstallIndex = ++strTemp;
// Convert the installation index
dwInstallIndex = atoi( strInstallIndex );
// Create a device handle
DeviceInfoSet = SetupDiCreateDeviceInfoList( NULL, NULL ); if( INVALID_HANDLE_VALUE == DeviceInfoSet ) { return ERROR_NOT_ENOUGH_MEMORY; }
// Create the device info structure
ZeroMemory( &DeviceInfoData, sizeof(SP_DEVINFO_DATA) ); DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if( 0 == SetupDiOpenDeviceInfoA( DeviceInfoSet, strInstanceID, NULL, 0, &DeviceInfoData ) ) { dwResult = GetLastError(); }
// Do the installation task
if( NO_ERROR == dwResult ) { switch( dwInstallIndex ) { case DIF_INSTALLDEVICE: dwResult = mmWOW64MediaInstallDevice(DeviceInfoSet, &DeviceInfoData); break; case DIF_REMOVE: dwResult = mmWOW64MediaRemoveDevice(DeviceInfoSet, &DeviceInfoData); break; default: dwResult = ERROR_INVALID_PARAMETER; break; } }
SetupDiDestroyDeviceInfoList( DeviceInfoSet );
return dwResult; }
|