|
|
/* DRIVERS.C
** ** Copyright (C) Microsoft, 1990, All Rights Reserved. ** ** Multimedia Control Panel Applet for installing/configuring installable ** device drivers. See the ispec doc DRIVERS.DOC for more information. ** ** History: ** ** Tue Jul 31 1990 -by- MichaelE ** Created. ** ** Thu Oct 25 1990 -by- MichaelE ** Added restart, horz. scroll, added SKIPDESC reading desc. strings. ** ** Sat Oct 27 1990 -by- MichaelE ** Added FileCopy. Uses SULIB.LIB and LZCOPY.LIB. Finished stuff ** for case of installing a driver with more than one type. ** ** May 1991 -by- JohnYG ** Added and replaced too many things to list. Better management ** of removed drivers, correct usage of DRV_INSTALL/DRV_REMOVE, ** installing VxD's, replaced "Unknown" dialog with an OEMSETUP.INF ** method, proper "Cancel" method, fixed many potential UAE's. */
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntseapi.h>
#include <windows.h>
#include <mmsystem.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <cpl.h>
#include <cphelp.h>
#include <commctrl.h>
#include <mmcpl.h>
#include <mmddkp.h>
#include <mmreg.h>
#include <msacm.h>
#include <msacmdrv.h>
#include <regstr.h>
#include "drivers.h"
#include "sulib.h"
#include "utils.h"
#include "medhelp.h"
#include "midi.h"
#ifdef FIX_BUG_15451
#include "trayvol.h"
#endif // FIX_BUG_15451
#ifndef cchLENGTH
#define cchLENGTH(_sz) (sizeof(_sz) / sizeof((_sz)[0]))
#endif
#ifndef TreeView_GetGrandParent
#define TreeView_GetGrandParent(_htree,_hti) \
TreeView_GetParent(_htree,TreeView_GetParent(_htree,_hti)) #endif
/*
* Enable the definition below to cause MCI devices to be listed by their * internal descriptions in the tree, rather than their descriptions as * read from Drivers.Desc. * */ // #define GET_MCI_DEVICE_DESCRIPTIONS_FROM_THEIR_DEVICES
typedef struct { int idIcon; int idName; int idInfo; BOOL bEnabled; DWORD dwContext; LPTSTR pszHelp; } APPLET_INFO;
#define NUM_APPLETS 1
#define OBJECT_SIZE 1024
BOOL bBadOemSetup; BOOL bRestart = FALSE; int iRestartMessage = 0; BOOL bInstallBootLine = FALSE; BOOL bCopyVxD; BOOL bFindOEM = FALSE; BOOL bRelated = FALSE; BOOL bCopyEvenIfOlder = FALSE; BOOL bDriversAppInUse; BOOL bCopyingRelated; BOOL bDescFileValid; HANDLE myInstance; HWND hAdvDlgTree; UINT wHelpMessage; DWORD dwContext; PINF pinfOldDefault = NULL; TCHAR szDriversHlp[24]; TCHAR szLastQuery[20]; TCHAR szSetupInf[18]; TCHAR szKnown[250]; TCHAR szRestartDrv[MAXDRVSTR]; // Warning - Making this string longer could cause a buffer overflow
TCHAR szUnlisted[150]; TCHAR szRelatedDesc[30]; TCHAR szAppName[26]; TCHAR szDrivers[12]; TCHAR szRemove[12]; TCHAR szControlIni[20]; TCHAR szSysIni[20]; TCHAR szMCI[6]; TCHAR szOutOfRemoveSpace[54]; TCHAR szDriversDesc[38]; TCHAR szUserDrivers[38];
// Where the source of files to copy is - user updates
TCHAR szDirOfSrc[MAX_PATH]; TCHAR szAddDriver[36]; TCHAR szNoDesc[36]; TCHAR szError[20]; TCHAR szRemoveOrNot[250]; TCHAR szRemoveOrNotStrict[250]; TCHAR szStringBuf[128]; TCHAR szMDrivers[38]; TCHAR szMDrivers32[38]; TCHAR szFullPath[MAXFILESPECLEN]; TCHAR szSystem[MAX_PATH]; TCHAR szOemInf[MAX_PATH]; TCHAR aszClose[16]; TCHAR szFileError[50];
#ifdef FIX_BUG_15451
TCHAR szDriverWhichNeedsSettings[MAX_PATH]; // See MMCPL.C
#endif // FIX_BUG_15451
static HANDLE hIList; static HANDLE hWndMain;
/*
* Global flag telling us if we're allowed to write to ini files */
BOOL IniFileReadAllowed; BOOL IniFileWriteAllowed;
/*
*** Stuff for keeping track of the TreeView window * */
#define GetString(_psz,_id) LoadString(myInstance,(_id),(_psz),sizeof((_psz))/sizeof(TCHAR))
static struct // aDriverKeyword
{ LPTSTR psz; // text found as alias for driver
DriverClass dc; // DriverClass inferred from keyword
} aDriverKeyword[] = // (used by GuessDriverClass())
{ { TEXT("waveaudio"), dcMCI }, // (sort in inverse alphabetical;
{ TEXT("wavemap"), dcWAVE }, // in particular, longer names first)
{ TEXT("wave"), dcWAVE }, { TEXT("vids"), dcVCODEC }, { TEXT("vidc"), dcVCODEC }, { TEXT("sequencer"), dcMCI }, { TEXT("msvideo"), dcVIDCAP }, { TEXT("msacm"), dcACODEC }, { TEXT("mpegvideo"), dcMCI }, { TEXT("mixer"), dcMIXER }, { TEXT("midimapper"), dcMIDI }, { TEXT("midi"), dcMIDI }, { TEXT("mci"), dcMCI }, { TEXT("icm"), dcVCODEC }, { TEXT("cdaudio"), dcMCI }, { TEXT("avivideo"), dcMCI }, { TEXT("aux"), dcAUX }, { TEXT("acm"), dcACODEC }, { TEXT("joy"), dcJOY } };
#define nDriverKEYWORDS ((int)(sizeof(aDriverKeyword) / \
sizeof(aDriverKeyword[0])))
static struct // aKeywordDesc
{ DriverClass dc; // DriverClass
LPTSTR psz; // alias which best describes class
} aKeywordDesc[] = // (used by DriverClassToClassNode())
{ { dcWAVE, TEXT("wave") }, { dcMIXER, TEXT("mixer") }, { dcVIDCAP, TEXT("msvideo") }, { dcVCODEC, TEXT("icm") }, { dcAUX, TEXT("aux") }, { dcACODEC, TEXT("acm") }, { dcMIDI, TEXT("midi") }, { dcJOY, TEXT("joystick") } };
#define nKeywordDESCS ((int)(sizeof(aKeywordDesc) / \
sizeof(aKeywordDesc[0])))
static struct // aDriverRoot
{ DriverClass dc; // corresponding driver classification
BOOL fAlwaysMake; // TRUE if should exist even w/o child
int idIcon; // icon for items under this tree
int idDesc; // description string for parent
int idEnable; // string to describe enabling action
int idDisable; // string to describe disabling action
HTREEITEM hti; // item within tree
DWORD dwBit; // bit mask representing this node
} aDriverRoot[] = // (order will define order in display)
{ { dcINVALID, TRUE, IDI_MMICON, IDS_MM_HEADER, 0, 0 }, { dcWAVE, TRUE, IDI_WAVE, IDS_WAVE_HEADER, IDS_ENABLEAUDIO, IDS_DISABLEAUDIO }, { dcMIDI, TRUE, IDI_MIDI, IDS_MIDI_HEADER, IDS_ENABLEMIDI, IDS_DISABLEMIDI }, { dcMIXER, TRUE, IDI_MIXER, IDS_MIXER_HEADER, IDS_ENABLEMIXER, IDS_DISABLEMIXER }, { dcAUX, TRUE, IDI_AUX, IDS_AUX_HEADER, IDS_ENABLEAUX, IDS_DISABLEAUX }, { dcMCI, TRUE, IDI_MCI, IDS_MCI_HEADER, IDS_ENABLEMCI, IDS_DISABLEMCI }, { dcVCODEC, TRUE, IDI_ICM, IDS_ICM_HEADER, IDS_ENABLEICM, IDS_DISABLEICM }, { dcACODEC, TRUE, IDI_ACM, IDS_ACM_HEADER, IDS_ENABLEACM, IDS_DISABLEACM }, { dcVIDCAP, TRUE, IDI_VIDEO, IDS_VIDCAP_HEADER, IDS_ENABLECAP, IDS_DISABLECAP }, { dcJOY, TRUE, IDI_JOYSTICK,IDS_JOYSTICK_HEADER, IDS_ENABLEJOY, IDS_DISABLEJOY }, { dcOTHER, FALSE, IDI_MMICON, IDS_OTHER_HEADER, IDS_ENABLEJOY, IDS_DISABLEJOY }, };
#define nDriverROOTS ((int)(sizeof(aDriverRoot) / sizeof(aDriverRoot[0])))
static LPCTSTR aDriversToSKIP[] = { TEXT( "MMDRV.DLL" ), TEXT( "MIDIMAP.DLL" ), TEXT( "MSACM32.DRV" ) };
static TCHAR cszMMDRVDLL[] = TEXT("MMDRV.DLL"); static TCHAR cszAliasKERNEL[] = TEXT("KERNEL"); static TCHAR cszRegValueLOADTYPE[] = TEXT("Load Type");
#define nDriversToSKIP ((int)( sizeof(aDriversToSKIP) \
/ sizeof(aDriversToSKIP[0]) ))
static HIMAGELIST hImageList = NULL; // image list for treeview in advdlg
DriverClass g_dcFilterClass = dcINVALID;
short DriverClassToRootIndex (DriverClass); DriverClass GuessDriverClass (PIDRIVER); #ifdef FIX_BUG_15451
DriverClass GuessDriverClassFromAlias (LPTSTR); #endif // FIX_BUG_15451
DriverClass GuessDriverClassFromTreeItem (HTREEITEM hti); BOOL EnsureRootIndexExists (HWND, short); HTREEITEM AdvDlgFindTopLevel (void); BOOL InitAdvDlgTree (HWND); void FreeAdvDlgTree (HWND); void TreeContextMenu (HWND, HWND);
int lstrnicmp (LPTSTR, LPTSTR, size_t); LPTSTR lstrchr (LPTSTR, TCHAR); void lstrncpy (LPTSTR, LPTSTR, size_t);
void ShowDeviceProperties (HWND, HTREEITEM);
PIDRIVER FindIDriverByTreeItem (HTREEITEM);
#ifdef FIX_BUG_15451
HTREEITEM FindTreeItemByDriverName (LPTSTR); #endif // FIX_BUG_15451
// We want to run "control joy.cpl" when the joystick devices
// are highlight and the user clicks Add/Remove/Properties buttons.
BOOL RunJoyControlPanel(void); //qzheng
/*
*** * */
DWORD GetFileDateTime (LPTSTR); LPTSTR GetProfile (LPTSTR,LPTSTR, LPTSTR, LPTSTR, int); void AddIDrivers (HWND, LPTSTR, LPTSTR); HTREEITEM AddIDriver (HWND, PIDRIVER, DriverClass); BOOL AddIDriverByName (HWND, LPCWSTR, DriverClass); PIDRIVER GetSelectedIDriver (HWND); BOOL FillTreeFromWinMM (HWND); BOOL FillTreeFromMSACM (HWND); BOOL FillTreeFromMCI (HWND); BOOL FillTreeFromMIDI (HWND); BOOL FillTreeFromRemaining (HWND); void FillTreeFromRemainingBySection (HWND, long ii, LPCTSTR, DriverClass); BOOL CALLBACK FillTreeFromMSACMQueryCallback (HACMDRIVERID, DWORD_PTR, DWORD); int __cdecl FillTreeFromMSACMSortCallback (const void *p1, const void *p2); BOOL InitAvailable (HWND, int); void RemoveAvailable (HWND); BOOL UserInstalled (LPTSTR); INT_PTR RestartDlg (HWND, unsigned, WPARAM, LPARAM); INT_PTR AddUnlistedDlg (HWND, unsigned, WPARAM, LPARAM); INT_PTR AvailableDriversDlg (HWND, unsigned, WPARAM, LPARAM); INT_PTR AdvDlg (HWND, unsigned, WPARAM, LPARAM); void ReBoot (HWND); BOOL GetMappable (PIDRIVER); BOOL SetMappable (PIRESOURCE, BOOL);
#define REGSTR_PATH_WAVEMAPPER TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Wave Mapper")
#define REGSTR_VALUE_MAPPABLE TEXT("Mappable")
#define REGSTR_PATH_MCI TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\MCI")
#define REGSTR_PATH_MCI32 TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\MCI32")
#define REGSTR_PATH_DRIVERS TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers")
#define REGSTR_PATH_DRIVERS32 TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32")
/*
* REALLOC - Allows expansion of GlobalAlloc()'d block while retaining contents * * Newly-allocated portions of memory are initialized to zero, while * the contents of reallocated portions of memory are retained. * * Parameters: * LPVOID _pData....allocated array * mysize_t _cOld.....current count of elements in allocated array * mysize_t _cNew.....minimum number of elements requested * mysize_t _cDelta...granularity of increase * * Example: * { * mysize_t cElements = 0; // Number of elements allocated so far
* DataType *aElements = NULL; // Allocated array of DataType
* * // At this point, cElements == 0 (obviously)
* * REALLOC (aElements, cElements, 10, 16) * * // The line above requested 10 elements, and indicated that elements
* // should be allocated in increments of 16. So cElements is 16 at this
* // point (thus, sizeof(aElements) == sizeof(DataType)*16).
* * REALLOC (aElements, cElements, 12, 16) * * // The line above requested 12 elements. Since cElements is already 16,
* // REALLOC knows that 12 elements are already available--and does nothing.
* * REALLOC (aElements, cElements, 17, 16) * * // The line above requested 17 elements, in increments of 16. aElements
* // has been reallocated to contain 32 elements, and cElements is
* // therefore 32.
* * GlobalFree ((HGLOBAL)aElements); // All done!
* aElements = NULL; * cElements = 0; * } * * */
typedef signed long mysize_t;
#ifdef REALLOC
#undef REALLOC
#endif
#define REALLOC(_pData,_cOld,_cNew,_cDelta) \
ReallocFn (sizeof(*_pData), (void **)&_pData, &_cOld, _cNew, _cDelta)
#ifdef DivRoundUp
#undef DivRoundUp
#endif
#define DivRoundUp(_a,_b) ( (LONG)(((_a) + (_b) -1) / (_b)) )
#ifdef RoundUp
#undef RoundUp
#endif
#define RoundUp(_a,_b) ( DivRoundUp(_a,_b) * (LONG)_b )
BOOL ReallocFn (mysize_t cbElement, LPVOID *ppOld, mysize_t *pcOld, mysize_t cNew, mysize_t cDelta) { LPVOID pNew; mysize_t cbOld, cbNew;
// First check if we actually need to reallocate or not.
// It's possible that {ppOld} was already allocated with
// enough space.
//
if ( ((*ppOld) != NULL) && (cNew <= (*pcOld)) ) return TRUE;
// Oh well. Determine how much space we need, and how much
// is allocated now.
//
cNew = RoundUp (cNew, cDelta); cbNew = cbElement * cNew; cbOld = (ppOld == NULL) ? 0 : (cbElement * (*pcOld));
// Allocate the space and copy over the original contents.
// Zero-fill the remaining space.
//
if ((pNew = (LPVOID)GlobalAlloc (GMEM_FIXED, cbNew)) == NULL) return FALSE;
if (cbOld != 0) { memcpy (pNew, *ppOld, cbOld); GlobalFree ((HGLOBAL)(*ppOld)); }
memset (&((char*)pNew)[ cbOld ], 0x00, cbNew -cbOld);
// Finally, update the passed-in pointers and we're done.
//
*pcOld = cNew; *ppOld = pNew;
return TRUE; }
/*
* PIDRIVER ARRAY * * The AddIDrivers() routine LocalAlloc()'s a single IDRIVER structure * for each installed device driver. Pointers to these structures are * retained in the InstalledDriver array, and indices into this array * are stored as the LPARAM values for each tree item. Each element * in the array stores not only a pointer to the driver's IDRIVER structure, * but also a DWORD which, as a combination of aDriverRoot[].dwBit values, * reflects the tree root items under which the driver has tree items. * */
typedef struct // InstalledDriver
{ PIDRIVER pIDriver; // Pointer to AddIDrivers()'s PIDRIVER structure
DWORD dwBits; // Combination of aDriverRoot[].dwBit flags
} InstalledDriver;
InstalledDriver *aInstalledDrivers = NULL; mysize_t cInstalledDrivers = 0;
#define NOPIDRIVER ((LPARAM)-1)
/*
* CheckSectionAccess() * * See if we can read/write to a given section */
BOOL CheckSectionAccess(TCHAR *szIniFile, TCHAR *SectionName) { static TCHAR TestKey[] = TEXT("TestKey!!!"); static TCHAR TestData[] = TEXT("TestData"); static TCHAR ReturnData[50];
/*
* Check we can write, read back and delete our key */
return WritePrivateProfileString(SectionName, TestKey, TestData, szIniFile) &&
GetPrivateProfileString(SectionName, TestKey, TEXT(""), ReturnData, sizeof(ReturnData) / sizeof(TCHAR), szIniFile) == (DWORD)wcslen(TestData) &&
WritePrivateProfileString(SectionName, TestKey, NULL, szIniFile); }
/*
* CheckIniAccess() * * Checks access to our 2 .ini file sections - DRIVERS_SECTION and * MCI_SECTION by just writing and reading some junk * * Basically if we don't have access to these sections we're not * going to allow Add and Remove. The individual MCI drivers must * take care not to put their data into non-writeable storage although * this completely messes up the default parameters thing so we're going * to put these into a well-known key in the win.ini file (ie per user). * */
BOOL CheckIniAccess(void) { return CheckSectionAccess(szSysIni, szDrivers) && CheckSectionAccess(szSysIni, szMCI) && CheckSectionAccess(szControlIni, szUserDrivers) && CheckSectionAccess(szControlIni, szDriversDesc) && CheckSectionAccess(szControlIni, szRelatedDesc); }
/*
* QueryRemoveDrivers() * * Ask the user if they're sure. If the Driver is one required by the * system (ie not listed in [Userinstallable.drivers] in control.ini) * warn the user of that too. */
BOOL QueryRemoveDrivers(HWND hDlg, LPTSTR szKey, LPTSTR szDesc) { TCHAR bufout[MAXSTR];
if (UserInstalled(szKey)) wsprintf(bufout, szRemoveOrNot, (LPTSTR)szDesc); else wsprintf(bufout, szRemoveOrNotStrict, (LPTSTR)szDesc);
return (MessageBox(hDlg, bufout, szRemove, MB_ICONEXCLAMATION | MB_TASKMODAL | MB_YESNO) == IDYES ); }
/*
* GetProfile() * * Get private profile strings. */
LPTSTR GetProfile(LPTSTR pstrAppName, LPTSTR pstrKeyName, LPTSTR pstrIniFile, LPTSTR pstrRet, int cbSize) { TCHAR szNULL[2];
szNULL[0] = TEXT('\0'); GetPrivateProfileString(pstrAppName, (pstrKeyName==NULL) ? NULL : (LPTSTR)pstrKeyName, szNULL, pstrRet, cbSize/sizeof(TCHAR), pstrIniFile); return(pstrRet); }
/*********************************************************************
* * AddIDrivers() * * Add drivers in the passed key strings list to the InstalledDrivers array * *********************************************************************/
void AddIDrivers(HWND hWnd, LPTSTR pstrKeys, LPTSTR pstrSection) { PIDRIVER pIDriver; LPTSTR pstrKey; LPTSTR pstrDesc;
pstrKey = pstrKeys; pstrDesc = (LPTSTR)LocalAlloc(LPTR, (MAXSTR * sizeof(TCHAR)));
if (!pstrDesc) return;
/*
* parse key strings for profile, and make IDRIVER structs */
while ( *pstrKey ) { pIDriver = (PIDRIVER)LocalAlloc(LPTR, sizeof(IDRIVER)); if ( pIDriver ) { LPTSTR pstr;
if (*GetProfile(pstrSection, pstrKey, szSysIni, pIDriver->szFile, sizeof(pIDriver->szFile)) == TEXT('\0')) { LocalFree((HANDLE)pIDriver); goto nextkey; }
for ( pstr=pIDriver->szFile; *pstr && (*pstr!=COMMA) && (*pstr!=SPACE); pstr++ ) ; *pstr = TEXT('\0');
#ifdef TRASHDRIVERDESC
if (bDescFileValid) #endif
/*
* try to load the cached description */
GetProfile(szDriversDesc, pIDriver->szFile, szControlIni, pIDriver->szDesc, sizeof(pIDriver->szDesc));
/*
* if we failed, then try to get the information from * mmdriver.inf or the exehdr */
if (pIDriver->szDesc[0] == TEXT('\0')) { int nResult = LoadDescFromFile(pIDriver, pstrKey, pstrDesc, MAXSTR); if( nResult == DESC_ERROR || nResult == DESC_NOFILE ) { LocalFree((HANDLE)pIDriver); goto nextkey; } else { if (!*pstrDesc) { /*
* failed to load a description. * The file isn't in setup.inf * and doesn't have exehdr information */
lstrcpy(pIDriver->szDesc, pIDriver->szFile); lstrcat(pIDriver->szDesc, szNoDesc); } else lstrcpy(pIDriver->szDesc, pstrDesc);
WritePrivateProfileString(szDriversDesc, pIDriver->szFile, pIDriver->szDesc, szControlIni); } }
wcsncpy(pIDriver->szAlias, pstrKey, sizeof(pIDriver->szAlias)/sizeof(TCHAR)); pIDriver->szAlias[sizeof(pIDriver->szAlias)/sizeof(TCHAR) - 1] = TEXT('\0'); wcscpy(pIDriver->wszAlias, pIDriver->szAlias);
wcsncpy(pIDriver->szSection, pstrSection,sizeof(pIDriver->szSection)/sizeof(TCHAR)); pIDriver->szSection[sizeof(pIDriver->szSection)/sizeof(TCHAR) - 1] = TEXT('\0'); wcscpy(pIDriver->wszSection, pIDriver->szSection);
pIDriver->KernelDriver = IsFileKernelDriver(pIDriver->szFile); pIDriver->fQueryable = pIDriver->KernelDriver ? 0 : -1;
pIDriver->lp = 0L;
if (!AddIDriverToArray (pIDriver)) LocalFree((HANDLE)pIDriver); } else break; //ERROR Low Memory
nextkey: while (*pstrKey++); } LocalFree((HANDLE)pstrDesc); }
/*
* AddIDriverToArray - Adds the given PIDRIVER to the InstalledDrivers array * */
BOOL AddIDriverToArray (PIDRIVER pIDriver) { mysize_t ii;
if (pIDriver == NULL) { return FALSE; }
// Don't create duplicate entries in this array; one PIDRIVER
// per driver-file is sufficient.
//
for (ii = 0; ii < cInstalledDrivers; ++ii) { if (aInstalledDrivers[ ii ].pIDriver != NULL) { if (!lstrcmpi (aInstalledDrivers[ ii ].pIDriver->szFile, pIDriver->szFile)) { return FALSE; } } }
// To reduce repetitive calls to GlobalAlloc(), we'll allocate
// space for an additional 50 InstalledDriver entries within
// the aInstalledDrivers array each time we run out of space.
//
#define nDriverEntriesToAllocAtONCE 50
for (ii = 0; ii < cInstalledDrivers; ++ii) { if (aInstalledDrivers[ ii ].pIDriver == NULL) break; }
if (ii >= cInstalledDrivers) { if (!REALLOC (aInstalledDrivers, // Array
cInstalledDrivers, // Current size of array
1+ii, // Requested size of array
nDriverEntriesToAllocAtONCE)) { return FALSE; } }
aInstalledDrivers[ ii ].pIDriver = pIDriver; aInstalledDrivers[ ii ].dwBits = 0L;
return TRUE; }
/*********************************************************************
* * FindInstallableDriversSection() * *********************************************************************/
PINF FindInstallableDriversSection(PINF pinf) { PINF pinfFound;
pinfFound = infFindSection(pinf, szMDrivers32);
if (pinfFound == NULL) { pinfFound = infFindSection(pinf, szMDrivers); }
return pinfFound; }
//NOTE: Returns nSize as a count of bytes, not characters (later calls expect this)
int GetINISectionSize(LPCTSTR pstrSection, LPCTSTR pstrFile) { int ncbSize = 0; int ncbMaxSize = 0;
while (ncbSize >= ncbMaxSize) { TCHAR szNULL[2]; LPTSTR pStr = NULL;
szNULL[0] = TEXT('\0');
ncbMaxSize += SECTION; //allocate another 512 bytes
pStr = (LPTSTR)LocalAlloc(LPTR, ncbMaxSize);
if (!pStr) { //we're trying to allocate too much memory ...
//drop out and use the last smaller size that worked
break; }
ncbSize = GetPrivateProfileString(pstrSection, NULL, szNULL, pStr, ncbMaxSize/sizeof(TCHAR), pstrFile); ncbSize = (ncbSize+2) * sizeof(TCHAR); //convert to byte count, adding two chars
//to account for terminating null and API's truncation
LocalFree(pStr); }
return (ncbSize); }
/*********************************************************************
* * InitInstalled() * * Add the drivers installed in [DRIVERS] and [MCI] to the Installed * Drivers list box. * *********************************************************************/
BOOL InitInstalled(HWND hWnd, LPTSTR pstrSection) { BOOL bSuccess=FALSE; LPTSTR pstr; int nSize = SECTION;
#ifdef TRASHDRIVERDESC
UINT wTime; BOOL fForce; TCHAR szOut[10];
wTime = LOWORD(GetFileDateTime(szControlIni)) >> 1; if (fForce = (GetPrivateProfileInt((LPTSTR)szUserDrivers, (LPTSTR)szLastQuery, 0, (LPTSTR)szControlIni) != wTime)) { wsprintf(szOut, TEXT("%d"), wTime); WritePrivateProfileString((LPTSTR)szUserDrivers, (LPTSTR)szLastQuery, szOut, (LPTSTR)szControlIni); WritePrivateProfileString((LPTSTR)szDriversDesc, NULL, NULL, (LPTSTR)szControlIni); bDescFileValid = FALSE; } else bDescFileValid = TRUE; #endif
nSize = GetINISectionSize(pstrSection, szSysIni);
pstr = (LPTSTR)LocalAlloc(LPTR, nSize); if ( pstr ) { if (*GetProfile(pstrSection, NULL, szSysIni, pstr, nSize )) { AddIDrivers(hWnd,pstr,pstrSection); bSuccess = TRUE; }
LocalFree((HANDLE)pstr); }
return(bSuccess); }
/*
* RefreshAdvDlgTree - Clears the Devices tree, and fills it back in * */
void RefreshAdvDlgTree (void) { if (hAdvDlgTree != NULL) { SendMessage (hAdvDlgTree, WM_SETREDRAW, FALSE, 0L);
FreeAdvDlgTree (hAdvDlgTree); InitAdvDlgTree (hAdvDlgTree); InitInstalled (GetParent (hAdvDlgTree), szDrivers); InitInstalled (GetParent (hAdvDlgTree), szMCI); FillTreeInAdvDlg (hAdvDlgTree, NULL);
SendMessage (hAdvDlgTree, WM_SETREDRAW, TRUE, 0L); } }
/*
* FillTreeInAdvDlg - Adds TreeItems for each entry in aInstalledDrivers * * If pIDriver is specified, the first treeitem to mention that driver * will be highlighted. * */
BOOL FillTreeInAdvDlg (HWND hTree, PIDRIVER pIDriver) { if (!FillTreeFromWinMM (hTree)) return FALSE;
if (!FillTreeFromMSACM (hTree)) return FALSE;
if (!FillTreeFromMCI (hTree)) return FALSE;
if (!FillTreeFromMIDI (hTree)) return FALSE;
if (!FillTreeFromRemaining (hTree)) return FALSE;
if (pIDriver != NULL) // Do we have to highlight a pIDriver?
{ short idr;
for (idr = 0; idr < nDriverROOTS; idr++) { HTREEITEM hti;
if ((hti = aDriverRoot[ idr ].hti) == NULL) continue;
for (hti = TreeView_GetChild (hTree, hti); hti != NULL; hti = TreeView_GetNextSibling (hTree, hti)) { if (pIDriver == FindIDriverByTreeItem (hti)) { TreeView_SelectItem (hTree, hti); break; } }
if (hti != NULL) // Found and selected a TreeItem?
break; // Then we're done!
} }
return TRUE; }
/*
* FillTreeFromWinMM - Adds tree items for all WinMM-controlled MM devices * * This routine adds tree items under the following DriverClasses: * dcWAVE - waveOut* * dcMIXER - mixer* * dcAUX - aux* * */
BOOL FillTreeFromWinMM (HWND hTree) { UINT iDevice; UINT cDevices; WCHAR szDriver[ cchRESOURCE ];
// Add entries for each waveOut device
//
cDevices = waveOutGetNumDevs (); for (iDevice = 0; iDevice < cDevices; ++iDevice) { if (waveOutMessage (HWAVEOUT_INDEX(iDevice), DRV_QUERYFILENAME, (DWORD_PTR)szDriver, (DWORD_PTR)cchRESOURCE) == MMSYSERR_NOERROR) { AddIDriverByName (hTree, szDriver, dcWAVE); } }
// Add entries for each mixer device
//
cDevices = mixerGetNumDevs (); for (iDevice = 0; iDevice < cDevices; ++iDevice) { if (mixerMessage (HMIXER_INDEX(iDevice), DRV_QUERYFILENAME, (DWORD_PTR)szDriver, (DWORD_PTR)cchRESOURCE) == MMSYSERR_NOERROR) { AddIDriverByName (hTree, szDriver, dcMIXER); } }
// Add entries for each aux device
//
cDevices = auxGetNumDevs (); for (iDevice = 0; iDevice < cDevices; ++iDevice) { if (auxOutMessage (iDevice, DRV_QUERYFILENAME, (DWORD_PTR)szDriver, (DWORD_PTR)cchRESOURCE) == MMSYSERR_NOERROR) { AddIDriverByName (hTree, szDriver, dcAUX); } }
return TRUE; }
/*
* FillTreeFromMSACM - Adds tree items for all MSACM-controlled MM devices * * This routine adds tree items under the following DriverClasses: * dcACODEC - acmDriverEnum() * * Note that, since audio codecs are supposed to be sorted in the tree, * all audio codec treeitems are first deleted from the tree (if there * are any at this point) then all audio codecs are added in their * sorted order. * */
typedef struct { DWORD dwPriority; // priority of this audio codec
PIDRIVER pIDriver; // matching driver file (or NULL)
WORD wMid; // manufacturer ID
WORD wPid; // product ID
TCHAR szDesc[ ACMDRIVERDETAILS_LONGNAME_CHARS ]; } AudioCodec;
AudioCodec *pCodecs; mysize_t cCodecs;
extern BOOL gfLoadedACM; // From MSACMCPL.C
BOOL FillTreeFromMSACM (HWND hTree) { MMRESULT mmr; short idr; mysize_t ii;
if (!gfLoadedACM) { if (LoadACM()) gfLoadedACM = TRUE; } if (!gfLoadedACM) return FALSE;
// Step one: get rid of any audio codecs listed in the tree
//
if ((idr = DriverClassToRootIndex (dcACODEC)) != -1) { if (aDriverRoot[ idr ].hti != NULL) { HTREEITEM hti;
while ((hti = TreeView_GetChild (hTree, aDriverRoot[ idr ].hti)) != 0) { TreeView_DeleteItem (hTree, hti);
if (hti == TreeView_GetChild (hTree, aDriverRoot[ idr ].hti)) break; // if it didn't delete, make sure we don't loop forever!
} }
for (ii = 0; ii < cInstalledDrivers; ++ii) { aInstalledDrivers[ ii ].dwBits &= ~aDriverRoot[ idr ].dwBit; } }
// Step two: query ACM to obtain the list of codecs
//
pCodecs = NULL; cCodecs = 0;
mmr = (MMRESULT)acmDriverEnum (FillTreeFromMSACMQueryCallback, 0, ACM_DRIVERENUMF_NOLOCAL | ACM_DRIVERENUMF_DISABLED);
// Step three: sort the list of codecs and add each to the tree
//
if ((mmr == MMSYSERR_NOERROR) && (pCodecs != NULL)) { mysize_t iiDr;
qsort (pCodecs, (size_t)cCodecs, sizeof(AudioCodec), FillTreeFromMSACMSortCallback);
// Assign lp=wMid+wPid for each audio codec we find
//
for (iiDr = 0; iiDr < cInstalledDrivers; ++iiDr) { if (aInstalledDrivers[ iiDr ].pIDriver == NULL) continue; if (aInstalledDrivers[ iiDr ].pIDriver->lp != 0L) // already did this
continue;
if (GuessDriverClass (aInstalledDrivers[ iiDr ].pIDriver) == dcACODEC) { HANDLE hDriver;
hDriver = OpenDriver (aInstalledDrivers[iiDr].pIDriver->wszAlias, aInstalledDrivers[iiDr].pIDriver->wszSection, 0L); if (hDriver != NULL) { ACMDRIVERDETAILSW add; memset ((TCHAR *)&add, 0x00, sizeof(add)); add.cbStruct = sizeof(add); SendDriverMessage (hDriver, ACMDM_DRIVER_DETAILS, (LONG_PTR)&add, 0); CloseDriver (hDriver, 0L, 0L);
aInstalledDrivers[ iiDr ].pIDriver->lp = MAKELONG( add.wMid, add.wPid ); } } }
// Search for installed drivers with matching lp=wMid+wPid's
//
for (iiDr = 0; iiDr < cInstalledDrivers; ++iiDr) { if (aInstalledDrivers[ iiDr ].pIDriver == NULL) continue;
if ((aInstalledDrivers[ iiDr ].pIDriver->szAlias[0] == TEXT('\0')) || (GuessDriverClass (aInstalledDrivers[iiDr].pIDriver) == dcACODEC)) { for (ii = 0; ii < cCodecs; ++ii) { if (pCodecs[ ii ].dwPriority == 0) continue;
if ( (pCodecs[ ii ].wMid == LOWORD( aInstalledDrivers[ iiDr ].pIDriver->lp )) && (pCodecs[ ii ].wPid == HIWORD( aInstalledDrivers[ iiDr ].pIDriver->lp )) ) { pCodecs[ ii ].pIDriver = aInstalledDrivers[ iiDr ].pIDriver; break; } } } }
// Add each in-use entry in pCodecs to the treeview
//
for (ii = 0; ii < cCodecs; ++ii) { if (pCodecs[ ii ].dwPriority == 0) continue;
// The PCM converter, for instance, won't have a matching
// PID. So create a bogus one--the lack of an szAlias
// will let us know it's bogus--and insert it into the
// aInstalledDrivers array.
//
if (pCodecs[ ii ].pIDriver == NULL) { PIDRIVER pid = (PIDRIVER)LocalAlloc(LPTR, sizeof(IDRIVER));
if (pid != NULL) { memset (pid, 0x00, sizeof(IDRIVER)); pid->lp = MAKELONG( pCodecs[ ii ].wMid, pCodecs[ ii ].wPid ); lstrcpy (pid->szDesc, pCodecs[ ii ].szDesc);
if (!AddIDriverToArray (pid)) LocalFree ((HLOCAL)pid); else { pCodecs[ ii ].pIDriver = pid; } } }
if (pCodecs[ ii ].pIDriver != NULL) { AddIDriver (hTree, pCodecs[ ii ].pIDriver, dcACODEC); } } }
// Cleanup
//
if (pCodecs != NULL) { GlobalFree ((HGLOBAL)pCodecs); pCodecs = NULL; cCodecs = 0; }
return (mmr == MMSYSERR_NOERROR) ? TRUE : FALSE; }
/*
* FillTreeFromMCI - Adds tree items for all MCI devices * * This routine adds tree items under the following DriverClasses: * dcMCI - mciSendCommand * */
BOOL FillTreeFromMCI (HWND hTree) { MCI_SYSINFO_PARMS mciSysInfo; TCHAR szAlias[ cchRESOURCE ];
// How many MCI devices does WinMM know about?
//
memset ((TCHAR *)&mciSysInfo, 0x00, sizeof(mciSysInfo)); mciSysInfo.lpstrReturn = szAlias; mciSysInfo.dwRetSize = cchLENGTH(szAlias); mciSysInfo.wDeviceType = MCI_ALL_DEVICE_ID;
if (mciSendCommand (MCI_ALL_DEVICE_ID, MCI_SYSINFO, MCI_SYSINFO_QUANTITY, (DWORD_PTR)&mciSysInfo) == 0) { DWORD iDevice; DWORD cDevices;
cDevices = *((DWORD *)(mciSysInfo.lpstrReturn));
// Get the name of each MCI device in turn.
//
for (iDevice = 0; iDevice < cDevices; ++iDevice) { mysize_t ii;
memset ((TCHAR *)&mciSysInfo, 0x00, sizeof(mciSysInfo)); mciSysInfo.lpstrReturn = szAlias; mciSysInfo.dwRetSize = cchLENGTH(szAlias); mciSysInfo.wDeviceType = MCI_ALL_DEVICE_ID; mciSysInfo.dwNumber = 1+iDevice; // note: 1-based, not 0-based!
if (mciSendCommand (MCI_ALL_DEVICE_ID, MCI_SYSINFO, MCI_SYSINFO_NAME, (DWORD_PTR)&mciSysInfo) != 0) { continue; }
// Got an alias--search the InstalledDrivers array
// and try to find a matching PIDRIVER.
//
for (ii = 0; ii < cInstalledDrivers; ++ii) { if (aInstalledDrivers[ ii ].pIDriver == NULL) continue; if (!lstrcmpi (aInstalledDrivers[ ii ].pIDriver->szAlias, szAlias)) { #ifdef GET_MCI_DEVICE_DESCRIPTIONS_FROM_THEIR_DEVICES
MCI_OPEN_PARMS mciOpen; MCI_INFO_PARMS mciInfo; MCIERROR rc;
// It's an installed, functioning, happy MCI device.
// Open it up and see what it calls itself; update the
// description in the PIDRIVER (what's in there was
// obtained from the registry, thus from MMDRIVER.INF,
// and we instead want what Media Player lists in its
// Device menu).
//
memset ((TCHAR *)&mciOpen, 0x00, sizeof(mciOpen)); mciOpen.lpstrDeviceType = szAlias;
rc = mciSendCommand (0,MCI_OPEN,MCI_OPEN_TYPE,(DWORD)&mciOpen); if (rc == MCIERR_MUST_USE_SHAREABLE) { rc = mciSendCommand (0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD)&mciOpen); } if (rc == 0) { TCHAR szDesc[ cchRESOURCE ]; szDesc[0] = 0;
mciInfo.lpstrReturn = szDesc; mciInfo.dwRetSize = cchLENGTH(szDesc);
if (mciSendCommand (mciOpen.wDeviceID, MCI_INFO, MCI_INFO_PRODUCT, (DWORD)&mciInfo) == 0) { lstrcpy (aInstalledDrivers[ ii ].pIDriver->szDesc, szDesc); }
mciSendCommand (mciOpen.wDeviceID, MCI_CLOSE, 0L, 0); } #endif // GET_MCI_DEVICE_DESCRIPTIONS_FROM_THEIR_DEVICES
AddIDriver (hTree, aInstalledDrivers[ ii ].pIDriver, dcMCI); break; } } } }
return TRUE; }
/*
* FillTreeFromMIDI - Adds tree items for all MIDI devices and instruments * * This routine adds tree items under the following DriverClasses: * dcMIDI - LoadInstruments() provides necessary data * */
BOOL FillTreeFromMIDI (HWND hTree) { MCMIDI mcm; UINT iiRoot; int idrMIDI;
if ((idrMIDI = DriverClassToRootIndex (dcMIDI)) == -1) return FALSE;
// First load in all relevant information regarding MIDI
// instruments. Fortunately, all that work is encapsulated
// nicely within one routine.
//
memset (&mcm, 0x00, sizeof(mcm)); LoadInstruments (&mcm, FALSE);
// Each entry in mcm's api array is one of three things:
// - a parent (say, a sound card)
// - a child (say, an external instrument)
// - the "(none)" thing that we want to skip
//
// Add each parent to the tree, and when we find a parent,
// add all its children.
//
for (iiRoot = 0; iiRoot < mcm.nInstr; ++iiRoot) { TCHAR szName[ MAXSTR ]; LPTSTR pch; PIDRIVER pid;
if (mcm.api[ iiRoot ] == NULL) continue; if (mcm.api[ iiRoot ]->piParent != NULL) continue; if (mcm.api[ iiRoot ]->szKey[0] == TEXT('\0')) continue;
// Found a parent! If we can match it to an installed driver,
// add it to the tree. Note that mcm.api[]->szKey will
// be of the form "MMDRV.DLL<0000>"--we need to strip off
// the "<0000>" before we can match this thing to a PIDRIVER.
//
lstrcpy (szName, mcm.api[ iiRoot ]->szKey); if ((pch = lstrchr (szName, TEXT('<'))) != NULL) *pch = TEXT('\0');
if ((pid = FindIDriverByName (szName)) != NULL) { HTREEITEM hti; UINT ii; TV_ITEM tvi;
if ((hti = AddIDriver (hTree, pid, dcMIDI)) == NULL) continue;
#if 0
tvi.mask = TVIF_TEXT; tvi.hItem = hti; tvi.pszText = mcm.api[ iiRoot ]->szFriendly; TreeView_SetItem(hTree, &tvi); #endif
// We've added this parent. See if it has any children,
// and if so, stick 'em in the tree.
//
for (ii = 0; ii < mcm.nInstr; ++ii) { PINSTRUM lp; TV_INSERTSTRUCT ti;
if (mcm.api[ ii ] == NULL) continue; if (mcm.api[ ii ]->piParent != mcm.api[ iiRoot ]) continue;
// Yep--it's got a parent. Allocate a second copy
// of this PINSTRUM; that copy will be our LPARAM value.
//
if ((lp = (PINSTRUM)LocalAlloc(LPTR,sizeof (INSTRUM))) == NULL) continue; memcpy ((TCHAR *)lp, (TCHAR *)mcm.api[ ii ], sizeof (INSTRUM));
// Now add a treeitem for this instrument.
//
ti.hParent = hti; ti.hInsertAfter = TVI_LAST; ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; ti.item.iImage = (int)idrMIDI; ti.item.iSelectedImage = (int)idrMIDI; ti.item.pszText = mcm.api[ ii ]->szFriendly; ti.item.lParam = (LPARAM)lp;
if (!TreeView_InsertItem (hTree, &ti)) break; } } }
// Done--cleanup and we're out of here.
//
FreeInstruments (&mcm);
if (mcm.hkMidi) RegCloseKey (mcm.hkMidi);
return TRUE; }
// To reduce repetitive calls to GlobalAlloc(), we'll allocate
// space for an additional 10 AudioCodec entries within
// the pCodecs array each time we run out of space.
//
#define nAudioCodecEntriesToAllocAtONCE 10
BOOL CALLBACK FillTreeFromMSACMQueryCallback (HACMDRIVERID hadid, DWORD_PTR dwUser, DWORD fdwSupport) { short ii; AudioCodec *pac; ACMDRIVERDETAILS add;
// Find or create a place in which to store information
// about this codec
//
for (ii = 0; ii < cCodecs; ++ii) { if (pCodecs[ ii ].dwPriority == 0) break; } if (ii >= cCodecs) { if (!REALLOC (pCodecs, cCodecs, 1+ii, nAudioCodecEntriesToAllocAtONCE)) return FALSE; } pac = &pCodecs[ ii ]; // for shorthand
// Find out about this codec
//
memset ((TCHAR *)&add, 0x00, sizeof(add)); add.cbStruct = sizeof(add); if (acmDriverDetails (hadid, &add, 0) == MMSYSERR_NOERROR) { acmMetrics ((HACMOBJ)hadid,ACM_METRIC_DRIVER_PRIORITY,&pac->dwPriority);
lstrcpy (pac->szDesc, add.szLongName);
pac->wMid = add.wMid; pac->wPid = add.wPid;
pac->pIDriver = NULL; }
return TRUE; // keep counting
}
int __cdecl FillTreeFromMSACMSortCallback (const void *p1, const void *p2) { if (((AudioCodec *)p1)->dwPriority == 0) return 1; if (((AudioCodec *)p2)->dwPriority == 0) return -1; return ((AudioCodec *)p1)->dwPriority - ((AudioCodec *)p2)->dwPriority; }
/*
* FillTreeFromRemaining - Adds tree items for all remaining MM devices * * This routine adds a single tree item for each entry in the aInstalledDrivers * array which is not already represented somewhere in the tree. The * classification is based on the driver's alias--if that fails, it is lumped * under dcOTHER. * */
BOOL FillTreeFromRemaining (HWND hTree) { mysize_t ii;
for (ii = 0; ii < cInstalledDrivers; ++ii) { UINT iiSkipCheck;
if (aInstalledDrivers[ ii ].pIDriver == NULL) continue; if (aInstalledDrivers[ ii ].pIDriver->szAlias[0] == TEXT('\0')) continue;
// (don't do this for any not-to-be-displayed drivers)
//
for (iiSkipCheck = 0; iiSkipCheck < nDriversToSKIP; iiSkipCheck++) { if (!FileNameCmp ((LPTSTR)aDriversToSKIP[ iiSkipCheck ], (LPTSTR)aInstalledDrivers[ ii ].pIDriver->szFile)) break; } if (iiSkipCheck < nDriversToSKIP) continue;
// Zip through the {drivers,drivers32,mci,mci32} sections, to
// try to classify this driver. If we find a classification
// for which we haven't already added an entry in the tree,
// add another.
//
FillTreeFromRemainingBySection (hTree, ii, REGSTR_PATH_DRIVERS, dcINVALID);
FillTreeFromRemainingBySection (hTree, ii, REGSTR_PATH_DRIVERS32, dcINVALID);
FillTreeFromRemainingBySection (hTree, ii, REGSTR_PATH_MCI, dcMCI);
FillTreeFromRemainingBySection (hTree, ii, REGSTR_PATH_MCI32, dcMCI);
// If the dwBits element is zero, then this driver hasn't
// already been assigned a treeitem elsewhere. In that event,
// call AddIDriver() with dcOTHER--to tell it to lump this
// driver under "Other Drivers".
//
if (aInstalledDrivers[ ii ].dwBits == 0) { AddIDriver (hTree, aInstalledDrivers[ ii ].pIDriver, dcOTHER); } }
return TRUE; }
void FillTreeFromRemainingBySection (HWND hTree, long iiDriver, LPCTSTR pszSection, DriverClass dcSection) { HKEY hk; UINT ii;
if (RegOpenKey (HKEY_LOCAL_MACHINE, pszSection, &hk)) return;
for (ii = 0; ; ++ii) { TCHAR szLHS[ cchRESOURCE ]; TCHAR szRHS[ cchRESOURCE ]; DWORD dw1; DWORD dw2; DWORD dw3;
dw1 = cchRESOURCE; dw3 = cchRESOURCE; if (RegEnumValue (hk, ii, szLHS, &dw1, 0, &dw2, (LPBYTE)szRHS, &dw3) != ERROR_SUCCESS) { break; }
if (!FileNameCmp (szRHS, aInstalledDrivers[ iiDriver ].pIDriver->szFile)) { DriverClass dc;
if ((dc = dcSection) == dcINVALID) dc = GuessDriverClassFromAlias (szLHS);
if ((dc == dcINVALID) || (dc == dcOTHER)) continue;
(void)AddIDriver (hTree, aInstalledDrivers[ iiDriver ].pIDriver, dc); } }
RegCloseKey (hk); }
#ifdef FIX_BUG_15451
HWND MakeThisCPLLookLikeTheOldCPL (HWND hWndCPL) { TCHAR szTitle[ cchRESOURCE ]; HWND hWndOldCPL = NULL;
GetWindowText (hWndCPL, szTitle, cchRESOURCE);
for (hWndOldCPL = GetWindow (hWndCPL, GW_HWNDFIRST); hWndOldCPL != NULL; hWndOldCPL = GetWindow (hWndOldCPL, GW_HWNDNEXT)) { TCHAR szTitleTest[ cchRESOURCE ]; GetWindowText (hWndOldCPL, szTitleTest, cchRESOURCE); if ( (!lstrcmpi (szTitle, szTitleTest)) && (hWndCPL != hWndOldCPL) ) { RECT rOld; GetWindowRect (hWndOldCPL, &rOld); SetWindowPos (hWndCPL, hWndOldCPL, rOld.left, rOld.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); SetWindowPos (hWndOldCPL, hWndCPL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } }
return hWndOldCPL; }
HWND MakeThisDialogLookLikeTheOldDialog (HWND hDlg) { TCHAR szTitle[ cchRESOURCE ]; RECT rOld; POINT pt; HWND hWndOldDlg;
GetWindowText (hDlg, szTitle, cchRESOURCE);
for (hWndOldDlg = GetWindow (hDlg, GW_HWNDFIRST); hWndOldDlg != NULL; hWndOldDlg = GetWindow (hWndOldDlg, GW_HWNDNEXT)) { TCHAR szTitleTest[ cchRESOURCE ]; GetWindowText (hWndOldDlg, szTitleTest, cchRESOURCE); if ( (!lstrcmpi (szTitle, szTitleTest)) && (hDlg != hWndOldDlg) ) { GetWindowRect (hWndOldDlg, &rOld);
SetWindowPos (hDlg, NULL, rOld.left, rOld.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
return hWndOldDlg; } }
return NULL; }
BOOL WaitForNewCPLWindow (HWND hWndMyDlg) { TCHAR szTitle[ cchRESOURCE ]; HWND hWnd; DWORD tickStart;
#define msecMAXWAIT 5000
hWndMyDlg = GetParent (hWndMyDlg); // (hWndMyDlg was a property sheet)
GetWindowText (hWndMyDlg, szTitle, cchRESOURCE);
for (tickStart = GetTickCount(); GetTickCount() - tickStart < msecMAXWAIT;) { MSG msg;
for (hWnd = GetWindow (hWndMyDlg, GW_HWNDFIRST); hWnd != NULL; hWnd = GetWindow (hWnd, GW_HWNDNEXT)) { TCHAR szTitleTest[ cchRESOURCE ]; if (!IsWindowVisible (hWnd)) continue; GetWindowText (hWnd, szTitleTest, cchRESOURCE); if ( (!lstrcmpi (szTitle, szTitleTest)) && (hWnd != hWndMyDlg) ) { PropSheet_PressButton (hWndMyDlg, PSBTN_CANCEL); hWnd = GetParent (GetParent (hAdvDlgTree)); PropSheet_PressButton (hWnd, PSBTN_CANCEL); return TRUE; } }
if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { if (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } } }
return FALSE; } #endif // FIX_BUG_15451
// Prevent any more REMOVE button presses
// Otherwise one can get stacked up and cause trouble,
// particularly if it is assocated with a driver that
// is automatically removed. We have to use a static
// as any focus changes cause the button to change state.
//
static long fWorking = 0;
/********************************************************************
* * AdvDlg () * * Display list of installed installable drivers. Return TRUE/FALSE * indicating if should restart windows. * ********************************************************************/
const static DWORD aAdvDlgHelpIds[] = { // Context Help IDs
IDC_ADV_TREE, IDH_GENERIC_DEVICES, ID_ADV_PROP, IDH_ADV_PROPERTIES, ID_ADV_REMOVE, IDH_MMCPL_DEVPROP_REMOVE, 0, 0 };
void MapDriverClass(DWORD_PTR dwSetupClass) { g_dcFilterClass = dcINVALID;
switch (dwSetupClass) { case IS_MS_MMMCI : { g_dcFilterClass = dcMCI; } break;
case IS_MS_MMVID : { g_dcFilterClass = dcVCODEC; } break;
case IS_MS_MMACM : { g_dcFilterClass = dcACODEC; } break;
case IS_MS_MMVCD : { g_dcFilterClass = dcVIDCAP; } break;
case IS_MS_MMDRV : { g_dcFilterClass = dcLEGACY; } break; } }
INT_PTR AdvDlg (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { HANDLE hWndI, hWnd; PIDRIVER pIDriver; DWORD_PTR dwType = 0;
switch ( uMsg ) { case WM_INITDIALOG: #ifdef FIX_BUG_15451
if (szDriverWhichNeedsSettings[0] != TEXT('\0')) { MakeThisCPLLookLikeTheOldCPL (GetParent(hDlg)); } #endif // FIX_BUG_15451
wsStartWait();
if (lParam) { dwType = ((LPPROPSHEETPAGE) lParam)->lParam; }
MapDriverClass(dwType);
hWndI = GetDlgItem(hDlg, IDC_ADV_TREE); SendMessage(hWndI,WM_SETREDRAW, FALSE, 0L);
InitAdvDlgTree (hWndI); // initialize the treeview display
/*
* Handle the fact that we may not be able to update our .ini * sections * */
IniFileWriteAllowed = CheckIniAccess();
// Note nasty sneaky hack: using (A|B) instead of (A&&B)
// makes both functions evaluate in either success or
// failure cases.
//
IniFileReadAllowed = ( InitInstalled (hDlg, szDrivers) | InitInstalled (hDlg, szMCI) );
FillTreeInAdvDlg (GetDlgItem (hDlg, IDC_ADV_TREE), NULL);
wsEndWait();
if ((!IniFileReadAllowed) || (!IniFileWriteAllowed)) { TCHAR szCantAdd[120]; EnableWindow(GetDlgItem(hDlg, ID_ADV_ADD),FALSE); EnableWindow(GetDlgItem(hDlg, ID_ADV_REMOVE),FALSE); LoadString(myInstance,IDS_CANTADD,szCantAdd,sizeof(szCantAdd)/sizeof(TCHAR)); MessageBox(hDlg, szCantAdd, szError, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); }
SendMessage (hWndI, WM_SETREDRAW, TRUE, 0L);
break;
case WM_COMMAND: hWndI = GetDlgItem(hDlg, IDC_ADV_TREE); hWndMain = hDlg;
pIDriver = GetSelectedIDriver (hWndI);
switch ( LOWORD(wParam )) { case ID_ADV_PROP: { HTREEITEM htiCur = TreeView_GetSelection (hWndI); DriverClass dc = GuessDriverClassFromTreeItem (htiCur);
if (fWorking) break;
++fWorking; // Just starting an operation
if( dc == dcJOY ) // We want to run "control joy.cpl" when the joystick devices
// are highlight and the user clicks Properties buttons.
RunJoyControlPanel(); else ShowDeviceProperties (hDlg, TreeView_GetSelection(hWndI));
--fWorking; // Finished with this operation
} break;
case ID_WHATSTHIS: { WinHelp((HWND)GetDlgItem (hDlg, IDC_ADV_TREE), gszWindowsHlp, HELP_WM_HELP, (UINT_PTR)(LPTSTR)aAdvDlgHelpIds); } break;
case ID_ADV_REMOVE: { HWND hTree = GetDlgItem (hDlg, IDC_ADV_TREE); HTREEITEM htiCur = TreeView_GetSelection (hTree); DriverClass dc = GuessDriverClassFromTreeItem (htiCur); PIDRIVER pid; LONG_PTR Status;
if ((!IniFileReadAllowed) || (!IniFileWriteAllowed)) break; // (button should be disabled)
if( dc == dcJOY ) { RunJoyControlPanel(); break; }
if (TreeView_GetParent (hAdvDlgTree, htiCur) && TreeView_GetGrandParent (hAdvDlgTree, htiCur) && (GuessDriverClassFromTreeItem ( TreeView_GetGrandParent (hAdvDlgTree, htiCur) ) == dcMIDI)) { TV_ITEM tvi; PINSTRUM pin;
tvi.mask = TVIF_PARAM; tvi.hItem = htiCur; tvi.lParam = 0; TreeView_GetItem(hAdvDlgTree, &tvi);
if ((pin = (PINSTRUM)tvi.lParam) != NULL) { RemoveInstrumentByKeyName (pin->szKey); RefreshAdvDlgTree (); KickMapper (hDlg); }
break; }
if ((pid = FindIDriverByTreeItem (htiCur)) == NULL) break;
if (dc == dcLEGACY) { dc = GuessDriverClass(pid); }
if (pid->szAlias[0] == TEXT('\0')) { TCHAR szCantRemove[ cchRESOURCE ]; GetString(szCantRemove, IDS_ACMREMOVEFAIL); MessageBox(hDlg, szCantRemove, szError, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); break; }
if (fWorking) break; ++fWorking; // Just starting an operation
if (QueryRemoveDrivers (hDlg, pid->szAlias, pid->szDesc)) { if ((Status = PostRemove (pid, TRUE)) != DRVCNF_CANCEL) { switch (dc) { case dcMIDI: break; case dcACODEC: acmDeleteCodec (LOWORD(pid->lp), HIWORD(pid->lp)); break; default: break; }
iRestartMessage = IDS_RESTART_REM;
if (Status == DRVCNF_RESTART) { DialogBox (myInstance, MAKEINTRESOURCE(DLG_RESTART), hDlg, RestartDlg); } } }
--fWorking; // Finished with this operation
} break;
case ID_ADV_ADD: { HTREEITEM htiCur = TreeView_GetSelection (hWndI); DriverClass dc = GuessDriverClassFromTreeItem (htiCur);
if ((!IniFileReadAllowed) || (!IniFileWriteAllowed)) break; // (button should be disabled)
if( dc == dcJOY ) { RunJoyControlPanel(); break; }
if (fWorking) break; ++fWorking; // Just starting an operation
bCopyEvenIfOlder = FALSE;
DialogBox(myInstance, MAKEINTRESOURCE(DLG_KNOWN), hDlg, AvailableDriversDlg);
bCopyEvenIfOlder = FALSE;
--fWorking; // Finished with this operation
} break;
case ID_ADV_TSHOOT: { TCHAR szCommand[ MAX_PATH ]; STARTUPINFO si; PROCESS_INFORMATION pi; LoadString(myInstance,IDS_TSHOOT, szCommand, sizeof(szCommand)/sizeof(TCHAR)); ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_NORMAL; if (CreateProcess(NULL, szCommand, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi)) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } } break;
#ifdef FIX_BUG_15451
case ID_INIT: if (szDriverWhichNeedsSettings[0] != TEXT('\0')) { HTREEITEM hti;
if ((hti = FindTreeItemByDriverName ( szDriverWhichNeedsSettings)) != 0) { TreeView_Expand (hAdvDlgTree, TreeView_GetParent(hAdvDlgTree,hti), TVE_EXPAND); TreeView_SelectItem(hAdvDlgTree,hti); FORWARD_WM_COMMAND(hDlg,ID_ADV_PROP,0,0,PostMessage); } else { szDriverWhichNeedsSettings[0] = 0; } } break; #endif // FIX_BUG_15451
default: return(FALSE); } break;
case WM_NOTIFY: { NMHDR *lpnm = (NMHDR *)lParam; LPNM_TREEVIEW lpnmtv = (LPNM_TREEVIEW)lParam;
switch (lpnm->code) { case PSN_KILLACTIVE: FORWARD_WM_COMMAND (hDlg, IDOK, 0, 0, SendMessage); break;
case PSN_APPLY: FORWARD_WM_COMMAND (hDlg, ID_APPLY, 0, 0, SendMessage); break;
case PSN_SETACTIVE: FORWARD_WM_COMMAND (hDlg, ID_INIT, 0, 0, SendMessage); break;
case PSN_RESET: FORWARD_WM_COMMAND (hDlg, IDCANCEL, 0, 0, SendMessage); break;
case NM_DBLCLK: // show properties or expand/collapse tree node.
//
if (lpnm->idFrom == (UINT)IDC_ADV_TREE) { HWND hTree = GetDlgItem (hDlg, IDC_ADV_TREE); HTREEITEM htiCur = TreeView_GetSelection (hTree); TV_HITTESTINFO tvht;
if (!htiCur) break;
GetCursorPos (&tvht.pt); ScreenToClient (hTree, &tvht.pt); TreeView_HitTest (hTree, &tvht);
if ( (tvht.flags & TVHT_ONITEM) && (TreeView_GetChild (hTree, htiCur) == NULL) && (IsWindowEnabled (GetDlgItem(hDlg,ID_ADV_PROP))) ) { FORWARD_WM_COMMAND(hDlg,ID_ADV_PROP,0,0,PostMessage); } } break;
case NM_RCLICK: TreeContextMenu (hDlg, GetDlgItem (hDlg, IDC_ADV_TREE)); return TRUE; break; } } break;
// The TreeView has its own right-click handling, and presents a
// "What's This?" automatically--so don't handle WM_CONTEXTMENU
// for that control.
//
case WM_CONTEXTMENU: if (wParam != (WPARAM)GetDlgItem (hDlg, IDC_ADV_TREE)) { WinHelp((HWND)wParam, gszWindowsHlp, HELP_CONTEXTMENU, (UINT_PTR)(LPTSTR)aAdvDlgHelpIds); } break;
case WM_HELP: WinHelp(((LPHELPINFO)lParam)->hItemHandle, gszWindowsHlp, HELP_WM_HELP, (UINT_PTR)(LPTSTR)aAdvDlgHelpIds); break;
case WM_DESTROY: FreeAdvDlgTree (GetDlgItem (hDlg, IDC_ADV_TREE)); return FALSE; break;
default: return FALSE; break; } return(TRUE); }
/*
*** TreeContextMenu * * This function displays the context menu that pops up when the * user right clicks on any of the tree view items. * */ void TreeContextMenu (HWND hWnd, HWND hKeyTreeWnd) { DWORD MessagePos; POINT MessagePoint; TV_HITTESTINFO TVHitTestInfo; HMENU hContextMenu; HMENU hContextPopupMenu; TV_ITEM TVItem; int MenuCommand; TCHAR szCollapse[32];
// dont bring up a menu unless click is on the item.
//
MessagePos = GetMessagePos(); MessagePoint.x = GET_X_LPARAM(MessagePos); MessagePoint.y = GET_Y_LPARAM(MessagePos);
TVHitTestInfo.pt = MessagePoint; ScreenToClient(hKeyTreeWnd, &TVHitTestInfo.pt); TVItem.hItem = TreeView_HitTest(hKeyTreeWnd, &TVHitTestInfo);
if (TVItem.hItem == NULL) return;
hContextMenu = LoadMenu(ghInstance, MAKEINTRESOURCE(POPUP_TREE_CONTEXT)); if (hContextMenu == NULL) return;
hContextPopupMenu = GetSubMenu (hContextMenu, 0);
TVItem.mask = TVIF_STATE | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM; TreeView_GetItem(hKeyTreeWnd, &TVItem);
// show collapse item because we are expanded?
//
if (TVItem.state & TVIS_EXPANDED) { LoadString(ghInstance, IDS_COLLAPSE, szCollapse, sizeof(szCollapse)/sizeof(TCHAR)); ModifyMenu(hContextPopupMenu, ID_TOGGLE, MF_BYCOMMAND | MF_STRING, ID_TOGGLE, szCollapse); } SetMenuDefaultItem (hContextPopupMenu, ID_TOGGLE, MF_BYCOMMAND);
if (TVItem.cChildren == 0) //gray expand/collaps if no children
{ SetMenuDefaultItem(hContextPopupMenu, ID_ADV_PROP, MF_BYCOMMAND); EnableMenuItem(hContextPopupMenu, ID_TOGGLE, MF_GRAYED |MF_BYCOMMAND); }
TreeView_SelectItem (hKeyTreeWnd, TVItem.hItem); MenuCommand = TrackPopupMenuEx (hContextPopupMenu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN | TPM_TOPALIGN, MessagePoint.x, MessagePoint.y, hWnd, NULL);
DestroyMenu (hContextMenu); FORWARD_WM_COMMAND(hWnd, MenuCommand, 0, 0, SendMessage); }
/*--------------------------------------------------------------------------*
* * * * * LB_AVAILABLE Dialog Routines * * * * * *--------------------------------------------------------------------------*/
/*
* DLG: LB_AVAILABLE * * InitAvailable() * * Add the available drivers from mmdriver.inf to the passed list box. * The format of [Installable.drivers] in setup.inf is: * profile=disk#:driverfile,"type1,type2","Installable driver Description","vxd1.386,vxd2.386","opt1,2,3" * * for example: * * driver1=6:sndblst.drv,"midi,wave","SoundBlaster MIDI and Waveform drivers","vdmad.386,vadmad.386","3,260" */
BOOL InitAvailable(HWND hWnd, int iLine) { PINF pinf; BOOL bInitd=FALSE; LPTSTR pstrKey; int iIndex; LONG lResult; TCHAR szDesc[MAX_INF_LINE_LEN];
SendMessage(hWnd,WM_SETREDRAW, FALSE, 0L);
/*
* Parse the list of keywords and load their strings */
for (pinf = FindInstallableDriversSection(NULL); pinf; pinf = infNextLine(pinf)) { //
// found at least one keyname!
//
pstrKey = (LPTSTR)LocalAlloc(LPTR, (MAX_SYS_INF_LEN * sizeof(TCHAR))); if( pstrKey == NULL ) break;
if( ERROR_SUCCESS == infParseField(pinf, 0, pstrKey, MAX_SYS_INF_LEN) && ERROR_SUCCESS == infParseField(pinf, 3, szDesc, SIZEOF(szDesc)) ) { /*
* add the installable driver's description to listbox, and filename as data */ if ( (iIndex = (int)SendMessage(hWnd, LB_ADDSTRING, 0, (LONG_PTR)(LPTSTR)szDesc)) != LB_ERR ) { SendMessage(hWnd, LB_SETITEMDATA, iIndex, (LONG_PTR)pstrKey); bInitd = TRUE; } } else { LocalFree( pstrKey ); pstrKey = NULL; } }
if (iLine == UNLIST_LINE) { //
// Add the "Install unlisted..." choice to the top of the list
// box.
LoadString(myInstance, IDS_UPDATED, szDesc, sizeof(szDesc)/sizeof(TCHAR)); if ((iIndex = (int)(LONG)SendMessage(hWnd, LB_INSERTSTRING, 0, (LPARAM)(LPTSTR)szDesc)) != LB_ERR) SendMessage(hWnd, LB_SETITEMDATA, (WPARAM)iIndex, (LPARAM)0); } if (bInitd)
SendMessage(hWnd, LB_SETCURSEL, 0, 0L );
SendMessage(hWnd,WM_SETREDRAW, TRUE, 0L); return(bInitd); }
/*
* DLG: LB_AVAILABLE * * RemoveAvailable() * * Remove all drivers from the listbox and free all storage associated with * the keyname */
void RemoveAvailable(HWND hWnd) { int iIndex; HWND hWndA; LPTSTR pstrKey;
hWndA = GetDlgItem(hWnd, LB_AVAILABLE); iIndex = (int)SendMessage(hWndA, LB_GETCOUNT, 0, 0L); while ( iIndex-- > 0) { if (( (pstrKey = (LPTSTR)SendMessage(hWndA, LB_GETITEMDATA, iIndex, 0L)) != (LPTSTR)LB_ERR ) && pstrKey) LocalFree((HLOCAL)pstrKey); } }
/*
* DLG: LB_AVAILABLE * * AvailableDriversDlg() * * List the available installable drivers or return FALSE if there are none. */
const static DWORD aAvailDlgHelpIds[] = { // Context Help IDs
LB_AVAILABLE, IDH_ADD_DRIVER_LIST, ID_DRVSTRING, IDH_ADD_DRIVER_LIST,
0, 0 };
INT_PTR AvailableDriversDlg(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPTSTR pstrKey; //-jyg- added
HWND hWndA; int iIndex;
switch ( uMsg ) { case WM_INITDIALOG: ShowWindow(hWnd, TRUE); wsStartWait(); if (pinfOldDefault) { infSetDefault(pinfOldDefault); pinfOldDefault = NULL; }
if ( !InitAvailable(hWndA = GetDlgItem(hWnd, LB_AVAILABLE), UNLIST_LINE)) { /*
* We weren't able to find the [installable.drivers] section * of the * mmdriver.inf OR it was corrupt. Go ahead and query the * user to find an oemsetup.inf to make our default. This * is a bad state. */ EndDialog(hWnd, FALSE); bFindOEM = TRUE; wcscpy(szDrv, szOemInf); if (DialogBox(myInstance, MAKEINTRESOURCE(DLG_INSERTDISK), hWnd, AddDriversDlg) == TRUE) PostMessage(hWnd, WM_INITDIALOG, 0, 0L); else pinfOldDefault = infSetDefault(pinfOldDefault);
bFindOEM = FALSE; } wsEndWait(); break;
case WM_COMMAND:
switch ( LOWORD(wParam )) { case LB_AVAILABLE:
// Hm... We've picked it.
if ( HIWORD(wParam) == LBN_DBLCLK ) SendMessage(hWnd, WM_COMMAND, IDOK, 0L); break;
case IDOK:
/*
* We've made our selection */
hWndA = GetDlgItem(hWnd, LB_AVAILABLE);
if ( (iIndex = (int)SendMessage(hWndA, LB_GETCURSEL, 0, 0L)) != LB_ERR) { if (!iIndex) { /*
* The first entry is for OEMs */
INT_PTR iFound; bBadOemSetup = FALSE;
bCopyEvenIfOlder = TRUE; bFindOEM = TRUE; hMesgBoxParent = hWnd; while ((iFound = DialogBox(myInstance, MAKEINTRESOURCE(DLG_INSERTDISK), hWnd, AddDriversDlg)) == 2); if (iFound == 1) { RemoveAvailable(hWnd); SendDlgItemMessage(hWnd, LB_AVAILABLE, LB_RESETCONTENT, 0, 0L); PostMessage(hWnd, WM_INITDIALOG, 0, 0L); } bFindOEM = FALSE; } else { /*
* The user selected an entry from our .inf */
wsStartWait();
/*
* The data associated with the list item is * the driver key name (field 0 in the inf file). */
pstrKey = (LPTSTR)SendMessage(hWndA, LB_GETITEMDATA, iIndex, 0L); bCopyingRelated = FALSE; bQueryExist = TRUE;
if (InstallDrivers(hWndMain, hWnd, pstrKey)) { RefreshAdvDlgTree (); wsEndWait();
/*
* If bRestart is true then the system must * be restarted to activate these changes */
if (bRestart) { iRestartMessage= IDS_RESTART_ADD; DialogBox(myInstance, MAKEINTRESOURCE(DLG_RESTART), hWnd, RestartDlg); } } else wsEndWait();
bRestart = FALSE; bRelated = FALSE; } } EndDialog(hWnd, FALSE); break;
case IDCANCEL: EndDialog(hWnd, FALSE); break;
default: return(FALSE); } break;
case WM_CONTEXTMENU: WinHelp((HWND)wParam, gszWindowsHlp, HELP_CONTEXTMENU, (UINT_PTR)(LPTSTR)aAvailDlgHelpIds); break;
case WM_HELP: WinHelp(((LPHELPINFO)lParam)->hItemHandle, gszWindowsHlp, HELP_WM_HELP, (UINT_PTR)(LPTSTR)aAvailDlgHelpIds); break;
case WM_DESTROY: //
// free the strings added as DATAITEM to the avail list
RemoveAvailable(hWnd); return(FALSE);
default: return FALSE; break; } return(TRUE); }
BOOL DriversDllInitialize( IN PVOID hInstance , IN DWORD ulReason , IN PCONTEXT pctx OPTIONAL ) { if (ulReason != DLL_PROCESS_ATTACH) return TRUE;
myInstance = hInstance; LoadString(myInstance, IDS_CLOSE, aszClose, sizeof(aszClose)/sizeof(TCHAR)); LoadString(myInstance, IDS_DRIVERDESC, szDriversDesc, sizeof(szDriversDesc)/sizeof(TCHAR)); LoadString(myInstance, IDS_FILE_ERROR, szFileError, sizeof(szFileError)/sizeof(TCHAR)); LoadString(myInstance, IDS_INSTALLDRIVERS, szMDrivers, sizeof(szMDrivers)/sizeof(TCHAR)); LoadString(myInstance, IDS_INSTALLDRIVERS32, szMDrivers32, sizeof(szMDrivers)/sizeof(TCHAR)); LoadString(myInstance, IDS_RELATEDDESC, szRelatedDesc, sizeof(szRelatedDesc)/sizeof(TCHAR)); LoadString(myInstance, IDS_USERINSTALLDRIVERS, szUserDrivers, sizeof(szUserDrivers)/sizeof(TCHAR)); LoadString(myInstance, IDS_UNLISTED, (LPTSTR)szUnlisted, sizeof(szUnlisted)/sizeof(TCHAR)); LoadString(myInstance, IDS_KNOWN, szKnown, sizeof(szKnown)/sizeof(TCHAR)); LoadString(myInstance, IDS_OEMSETUP, szOemInf, sizeof(szOemInf)/sizeof(TCHAR)); LoadString(myInstance, IDS_SYSTEM, szSystem, sizeof(szSystem)/sizeof(TCHAR)); LoadString(myInstance, IDS_OUT_OF_REMOVE_SPACE, szOutOfRemoveSpace, sizeof(szOutOfRemoveSpace)/sizeof(TCHAR)); LoadString(myInstance, IDS_NO_DESCRIPTION, szNoDesc, sizeof(szNoDesc)/sizeof(TCHAR)); LoadString(myInstance, IDS_ERRORBOX, szError, sizeof(szError)/sizeof(TCHAR)); LoadString(myInstance, IDS_REMOVEORNOT, szRemoveOrNot, sizeof(szRemoveOrNot)/sizeof(TCHAR)); LoadString(myInstance, IDS_REMOVEORNOTSTRICT, szRemoveOrNotStrict, sizeof(szRemoveOrNotStrict)/sizeof(TCHAR)); LoadString(myInstance, IDS_SETUPINF, szSetupInf, sizeof(szSetupInf)/sizeof(TCHAR)); LoadString(myInstance, IDS_APPNAME, szAppName, sizeof(szAppName)/sizeof(TCHAR));
LoadString(myInstance, IDS_DRIVERS, szDrivers, sizeof(szDrivers)/sizeof(TCHAR)); LoadString(myInstance, IDS_REMOVE, szRemove, sizeof(szRemove)/sizeof(TCHAR)); LoadString(myInstance, IDS_CONTROLINI, szControlIni, sizeof(szControlIni)/sizeof(TCHAR)); LoadString(myInstance, IDS_SYSINI, szSysIni, sizeof(szSysIni)/sizeof(TCHAR)); LoadString(myInstance, IDS_MCI, szMCI, sizeof(szMCI)/sizeof(TCHAR)); LoadString(myInstance, IDS_DEFDRIVE, szDirOfSrc, sizeof(szDirOfSrc)/sizeof(TCHAR)); LoadString(myInstance, IDS_CONTROL_HLP_FILE, szDriversHlp, sizeof(szDriversHlp)/sizeof(TCHAR)); LoadString(myInstance, IDS_LASTQUERY, szLastQuery, sizeof(szLastQuery)/sizeof(TCHAR));
return TRUE; }
void DeleteCPLCache(void) { HKEY hKeyCache;
if (ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, TEXT("Control Panel\\Cache\\multimed.cpl"), &hKeyCache)) { for ( ; ; ) { TCHAR Name[MAX_PATH+1]; // This is the max size that RegEnumKey()+NULL can return
if (ERROR_SUCCESS == RegEnumKey(hKeyCache, 0, Name, ARRAYSIZE(Name))) { HKEY hSubKey;
RegDeleteKey(hKeyCache, Name); } else { break; // leave loop
} }
RegDeleteKey(hKeyCache, NULL); RegCloseKey(hKeyCache); } }
/*
** RestartDlg() ** ** Offer user the choice to (not) restart windows. */ INT_PTR RestartDlg(HWND hDlg, unsigned uiMessage, WPARAM wParam, LPARAM lParam) { switch (uiMessage) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: //
// don't restart windows
//
EndDialog(hDlg, FALSE); break;
case IDOK: //
// do restart windows, *dont* dismiss dialog incase
// the user canceled it.
//
ReBoot(hDlg); SetActiveWindow(hDlg); //EndDialog(hDlg, TRUE);
break;
default: return FALSE; } return TRUE;
case WM_INITDIALOG: /*
** Delete the control panel's cache so it will get it ** right! */
DeleteCPLCache();
if (iRestartMessage) { TCHAR szMesg1[300]; TCHAR szMesg2[300];
LoadString(myInstance, iRestartMessage, szMesg1, sizeof(szMesg1)/sizeof(TCHAR)); wsprintf(szMesg2, szMesg1, (LPTSTR)szRestartDrv); SetDlgItemText(hDlg, IDS_RESTARTTEXT, (LPTSTR)szMesg2);
if (iRestartMessage == IDS_RESTART_NOSOUND) { PostMessage (hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg,IDOK), (LPARAM)TRUE); } } return TRUE;
case WM_KEYUP: if (wParam == VK_F3) //
// don't restart windows
//
EndDialog(hDlg, FALSE); break;
default: break; } return FALSE; }
/*
* UserInstalled() * * */
BOOL UserInstalled(LPTSTR szKey) { TCHAR buf[MAXSTR]; LPTSTR lpstr = NULL; ZeroMemory (buf, sizeof (buf)); // make prefix happy.
lpstr = GetProfile (szUserDrivers, (LPTSTR)szKey, szControlIni, buf, sizeof(buf)); if (lpstr && *lpstr != TEXT('\0')) return(TRUE); else return(FALSE); }
/*
* AddUnlistedDlg() * * The following function processes requests by the user to install unlisted * or updated drivers. * * PARAMETERS: The normal Dialog box parameters * RETURN VALUE: The usual Dialog box return value */
INT_PTR AddUnlistedDlg(HWND hDlg, unsigned nMsg, WPARAM wParam, LPARAM lParam) { switch (nMsg) { case WM_INITDIALOG: { HWND hListDrivers; BOOL bFoundDrivers;
wsStartWait(); hListDrivers = GetDlgItem(hDlg, LB_UNLISTED);
/* Search for drivers */ bFoundDrivers = InitAvailable(hListDrivers, NO_UNLIST_LINE); if (!bFoundDrivers) { //
// We weren't able to find the MMDRIVERS section of the
// setup.inf OR it was corrupt. Go ahead and query the
// user to find an oemsetup.inf to make our default. This
// is a bad state.
//
INT_PTR iFound;
bFindOEM = TRUE; bBadOemSetup = TRUE; while ((iFound = DialogBox(myInstance, MAKEINTRESOURCE(DLG_INSERTDISK), hMesgBoxParent, AddDriversDlg)) == 2); bFindOEM = FALSE; if (iFound == 1) { SendDlgItemMessage(hDlg, LB_AVAILABLE, LB_RESETCONTENT, 0, 0L); PostMessage(hDlg, WM_INITDIALOG, 0, 0L); } EndDialog(hDlg, FALSE); } SendMessage(hListDrivers, LB_SETCURSEL, 0, 0L); wsEndWait();
break; }
case WM_COMMAND: switch (LOWORD(wParam)) { case IDH_DLG_ADD_UNKNOWN: goto DoHelp;
case LB_UNLISTED: if (HIWORD(wParam) != LBN_DBLCLK) break;
// else Fall through here
case IDOK: { HWND hWndA; int iIndex; LPTSTR pstrKey;
hWndA = GetDlgItem(hDlg, LB_UNLISTED); if ( (iIndex = (int)SendMessage(hWndA, LB_GETCURSEL, 0, 0L)) != LB_ERR) { wsStartWait(); pstrKey = (LPTSTR)SendMessage(hWndA, LB_GETITEMDATA, iIndex, 0L); bCopyingRelated = FALSE; bQueryExist = TRUE; if (InstallDrivers(hWndMain, hDlg, pstrKey)) { RefreshAdvDlgTree (); wsEndWait();
if (bRestart) { iRestartMessage= IDS_RESTART_ADD; DialogBox(myInstance, MAKEINTRESOURCE(DLG_RESTART), hDlg, RestartDlg); } } else wsEndWait(); bRelated = FALSE; bRestart = FALSE; } EndDialog(hDlg, FALSE); } break;
case IDCANCEL: EndDialog(hDlg, wParam); break;
default: return FALSE; } break;
case WM_HELP: DoHelp: WinHelp (hDlg, gszWindowsHlp, HELP_CONTEXT, IDH_MMCPL_DEVPROP_ENABLE); break;
default: return FALSE; } return TRUE; } /*
* ReBoot() * * Restart the system. If this fails we put up a message box */
void ReBoot(HWND hDlg) { DWORD Error; BOOLEAN WasEnabled;
/*
* We must adjust our privilege level to be allowed to restart the * system */
RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &WasEnabled ); /*
* Try to reboot the system */
if (!ExitWindowsEx(EWX_REBOOT, 0xFFFFFFFF)) {
Error = GetLastError();
/*
* Put up a message box if we failed */
if (Error != NO_ERROR) { TCHAR szCantRestart[80]; LoadString(myInstance, Error == ERROR_PRIVILEGE_NOT_HELD || Error == ERROR_NOT_ALL_ASSIGNED || Error == ERROR_ACCESS_DENIED ? IDS_CANNOT_RESTART_PRIVILEGE : IDS_CANNOT_RESTART_UNKNOWN, szCantRestart, sizeof(szCantRestart)/sizeof(TCHAR));
MessageBox(hDlg, szCantRestart, szError, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); } } }
void OpenDriverError(HWND hDlg, LPTSTR szDriver, LPTSTR szFile) { TCHAR szMesg[MAXSTR]; TCHAR szMesg2[MAXSTR];
LoadString(myInstance, IDS_INSTALLING_DRIVERS, szMesg, sizeof(szMesg)/sizeof(TCHAR)); wsprintf(szMesg2, szMesg, szDriver, szFile); MessageBox(hDlg, szMesg2, szError, MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
}
/*
*** AddIDriver - Adds a treeitem referencing the given PIDRIVER * * Note that the listed PIDRIVER should already have been added to the * aInstalledDrivers array (via AddIDriverToArray()) before calling this * routine. * */
HTREEITEM AddIDriver (HWND hTree, PIDRIVER pIDriver, DriverClass dc) { short idr; TV_INSERTSTRUCT ti; HTREEITEM hti; short ii; TCHAR szFile[ _MAX_FNAME +1 +_MAX_EXT +1 ]; TCHAR szExt[ _MAX_EXT +1 ]; TCHAR szDesc[ cchRESOURCE ];
// don't add an entry for one of the to-be-skipped drivers
//
lsplitpath (pIDriver->szFile, NULL, NULL, szFile, szExt);
if (szExt[0] != TEXT('\0')) lstrcat (szFile, szExt);
//check to see if we're trying to put a PNP driver into the legacy tree
if (g_dcFilterClass == dcLEGACY) { if ((dc == dcWAVE) || (dc == dcMIDI) || (dc == dcMIXER) || (dc == dcAUX)) { if (IsPnPDriver(szFile)) { return FALSE; } } }
if (dc != dcMIDI) { for (ii = 0; ii < nDriversToSKIP; ii++) { if (!lstrcmpi (szFile, aDriversToSKIP[ ii ])) return FALSE; } }
// If we were given a DriverClass, then the caller has
// specified where we should create an entry--add the "Audio for"
// (etc) tag before the description, and add it.
//
// Otherwise, determine where this driver belongs in the tree
//
if (dc != dcINVALID) { TCHAR szTag[ cchRESOURCE ];
switch (dc) { case dcWAVE: GetString (szTag, IDS_AUDIOFOR); break; case dcMIDI: GetString (szTag, IDS_MIDIFOR); break; case dcMIXER: GetString (szTag, IDS_MIXERFOR); break; case dcAUX: GetString (szTag, IDS_AUXFOR); break; default: lstrcpy (szTag, TEXT("%s")); break; }
wsprintf (szDesc, szTag, pIDriver->szDesc); } else { if ((dc = GuessDriverClass (pIDriver)) == dcINVALID) return FALSE;
lstrcpy (szDesc, pIDriver->szDesc); }
// map that classification into an index within the
// root entries of the tree (aDriverRoot[])
//
if ((idr = DriverClassToRootIndex (dc)) == -1) return FALSE;
// if this driver already has an entry under this DriverClass,
// then don't add another.
//
for (ii =0; ii < cInstalledDrivers; ++ii) { if (aInstalledDrivers[ ii ].pIDriver == pIDriver) break; } if (ii >= cInstalledDrivers) { ii = (short)NOPIDRIVER; } else if (aInstalledDrivers[ ii ].dwBits & aDriverRoot[ idr ].dwBit) { return FALSE; // Already have an entry here!
}
// since not all roots need exist all the time, make sure
// this classification HAS a root in the tree
//
if (!EnsureRootIndexExists (hTree, idr)) return FALSE;
// finally, insert an item into the tree for this driver
// note that for audio codecs to be sorted properly, they must
// be added via this routine in their appropriate order--ie,
// call this routine for the highest-priority codec first.
//
ti.hParent = aDriverRoot[ idr ].hti; ti.hInsertAfter = (dc == dcACODEC) ? TVI_LAST : TVI_SORT; ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; ti.item.iImage = (int)idr; ti.item.iSelectedImage = (int)idr; ti.item.pszText = szDesc; ti.item.lParam = ii;
if ((hti = TreeView_InsertItem (hTree, &ti)) == NULL) return FALSE;
if (ii != NOPIDRIVER) aInstalledDrivers[ ii ].dwBits |= aDriverRoot[ idr ].dwBit;
return hti; }
BOOL AddIDriverByName (HWND hTree, LPCWSTR wszFile, DriverClass dc) { LPTSTR pch; TCHAR tszFile[ max(cchRESOURCE, MAX_PATH) ]; PIDRIVER pid;
#ifdef UNICODE
lstrcpy (tszFile, wszFile); #else
wcstombs (tszFile, wszFile, cchRESOURCE); #endif
// Strip off any trailing whitespace
//
if (tszFile[0] == TEXT('\0')) return FALSE;
for (pch = &tszFile[ lstrlen(tszFile)-1 ]; pch >= tszFile && (*pch == TEXT('\t') || *pch == TEXT(' ')); --pch) ; *(1+pch) = TEXT('\0');
// If this is MMDRV.DLL, then it's possibly providing the
// user-mode component for kernel-mode drivers. Since it's
// apparently impossible to determine the name of the .SYS
// file which is providing a "\\.\WaveIn0" device (etc),
// we'll use a hack: Check around for anyone registered
// under the alias "Kernel", and use that.
//
if (!lstrcmpi (tszFile, cszMMDRVDLL)) { mysize_t ii; for (ii = 0; ii < cInstalledDrivers; ++ii) { if (aInstalledDrivers[ ii ].pIDriver == NULL) continue; if (!lstrnicmp (aInstalledDrivers[ ii ].pIDriver->szAlias, cszAliasKERNEL, lstrlen(cszAliasKERNEL))) { lstrcpy (tszFile, aInstalledDrivers[ ii ].pIDriver->szFile); break; } } if (ii >= cInstalledDrivers) return FALSE; }
// Find the driver in the aInstalledDriver array, and add
// an entry for it in the tree.
//
if ((pid = FindIDriverByName (tszFile)) == NULL) return FALSE;
if (AddIDriver (hTree, pid, dc) == NULL) return FALSE;
return TRUE; }
/*
*** RemoveIDriver - Removes (and optionally frees) an IDRIVER from hAdvDlgTree * */
void RemoveIDriver (HWND hTree, PIDRIVER pIDriver, BOOL fFreeToo) { mysize_t ii; short idr; HTREEITEM hti;
// Find each TreeItem which references this entry.
//
for (idr = 0; idr < nDriverROOTS; idr++) { if ((hti = aDriverRoot[ idr ].hti) == NULL) continue;
hti = TreeView_GetChild (hTree, hti); while (hti != NULL) { if (pIDriver != FindIDriverByTreeItem (hti)) { hti = TreeView_GetNextSibling (hTree, hti); continue; }
// We found a tree item which uses this driver, so delete the
// item. Also note that this may cause the driver's parent
// node to no longer be necessary.
//
TreeView_DeleteItem (hTree, hti); hti = TreeView_GetChild (hTree, aDriverRoot[ idr ].hti);
if (!aDriverRoot[ idr ].fAlwaysMake) // may no longer need parent?
{ if (hti == NULL) // parent now has no children?
{ TreeView_DeleteItem (hTree, aDriverRoot[ idr ].hti); aDriverRoot[ idr ].hti = NULL; } } } }
// See if we can find the given pIDriver within the
// aInstalledDriver array.
//
for (ii = 0; ii < cInstalledDrivers; ++ii) { if (aInstalledDrivers[ ii ].pIDriver == pIDriver) { aInstalledDrivers[ ii ].dwBits = 0L; // no longer in tree at all
if (fFreeToo) { LocalFree ((HANDLE)aInstalledDrivers[ ii ].pIDriver); aInstalledDrivers[ ii ].pIDriver = NULL; }
break; // There's only one entry in this array for each pIDriver
} } }
#ifdef FIX_BUG_15451
HTREEITEM FindTreeItemByDriverName (LPTSTR pszName) { PIDRIVER pid; short idr; HTREEITEM hti;
if ((pid = FindIDriverByName (pszName)) == NULL) return (HTREEITEM)0;
for (idr = 0; idr < nDriverROOTS; idr++) { if ((hti = aDriverRoot[ idr ].hti) == NULL) continue;
for (hti = TreeView_GetChild (hAdvDlgTree, hti); hti != NULL; hti = TreeView_GetNextSibling (hAdvDlgTree, hti)) { if (pid == FindIDriverByTreeItem (hti)) { return hti; } } }
return (HTREEITEM)0; } #endif // FIX_BUG_15451
PIDRIVER FindIDriverByTreeItem (HTREEITEM hti) { TV_ITEM tvi;
tvi.mask = TVIF_PARAM; tvi.hItem = hti; TreeView_GetItem (hAdvDlgTree, &tvi);
if ( (tvi.lParam < 0) || (tvi.lParam >= cInstalledDrivers) ) { return NULL; }
return aInstalledDrivers[ tvi.lParam ].pIDriver; }
/*
*** FindIDriverByName - Returns the first found IDRIVER structure with a name * */
PIDRIVER FindIDriverByName (LPTSTR szFile) { mysize_t ii;
for (ii = 0; ii < cInstalledDrivers; ++ii) { if (aInstalledDrivers[ ii ].pIDriver == NULL) continue; if (aInstalledDrivers[ ii ].pIDriver->szAlias[0] == TEXT('\0')) continue;
if (!FileNameCmp (aInstalledDrivers[ ii ].pIDriver->szFile, szFile)) return aInstalledDrivers[ ii ].pIDriver; }
return NULL; }
PIDRIVER FindIDriverByResource (PIRESOURCE pir) { return FindIDriverByName (FileName( pir->szFile )); }
/*
*** GetSelectedIDriver - Returns the IDRIVER structure the user has selected * */
PIDRIVER GetSelectedIDriver (HWND hTree) { HTREEITEM htiCur = TreeView_GetSelection (hTree);
if (htiCur == NULL) return NULL;
return FindIDriverByTreeItem (htiCur); }
/*
*** DriverClassToRootIndex - obtain idr for which {aDriverRoot[idr].dc == dc} * * The array index for aDriverRoot[] is NOT a DriverClass--that is, * aDriverRoot[ PickAnyDC ].dc is not necessarily equal to PickAnyDC. * Given a DC, this routine finds the index into aDriverRoot which references * that DC. * */
short DriverClassToRootIndex (DriverClass dc) { short idr;
for (idr = 0; idr < nDriverROOTS; idr++) { if (aDriverRoot[ idr ].dc == dc) return idr; }
return -1; }
/*
*** GetDriverClass - guess a DriverClass based on an IDRIVER structure * * The registry has several different aliases which it uses in the LHS * of HKLM\software\microsoft\windowsnt\drivers,drivers32,etc to indicate * the classification of a particular driver. These include: * * AUX, MIDI, MIDIMAPPER, MIXER, MSACM.*, VIDC.* WAVE, WAVEMAPPER * * as well as others--the full array of known entries is tracked within * aDriverKeywords[]. In addition, any of these may be followed by a * string of digits by which they are distinguished. This routine parses * these keywords and returns a corresponding DriverClass enum. * */
DriverClass GuessDriverClass (PIDRIVER pid) { #ifdef FIX_BUG_15451
return GuessDriverClassFromAlias (pid->szAlias); }
DriverClass GuessDriverClassFromAlias (LPTSTR pszAlias) { #endif // FIX_BUG_15451
TCHAR szAlias[ cchRESOURCE ]; TCHAR *pch; short ii;
#ifdef FIX_BUG_15451
lstrcpy (szAlias, pszAlias); // Make a local copy so we can munge it
#else // FIX_BUG_15451
lstrcpy (szAlias, pid->szAlias); // Make a local copy so we can munge it
#endif // FIX_BUG_15451
if ((pch = lstrchr (szAlias, TEXT('.'))) != NULL) *pch = TEXT('0');
for (ii = 0; ii < nDriverKEYWORDS; ii++) { if (!lstrnicmp (szAlias, aDriverKeyword[ii].psz, lstrlen (aDriverKeyword[ii].psz))) { return aDriverKeyword[ii].dc; } }
return dcOTHER; }
DriverClass GuessDriverClassFromTreeItem (HTREEITEM hti) { short idr;
for (idr = 0; idr < nDriverROOTS; idr++) { if (hti == aDriverRoot[idr].hti) return aDriverRoot[idr].dc; }
return (g_dcFilterClass); }
/*
*** EnsureRootIndexExists - makes sure a given parent exists in hAdvDlgTree * */
BOOL EnsureRootIndexExists (HWND hTree, short idr) { TV_INSERTSTRUCT ti; TCHAR szDesc[ cchRESOURCE ]; HWND hwndParent = NULL; HWND hwndName = NULL;
// If we already HAVE a root in the tree, we're done.
//
if (aDriverRoot[ idr ].hti != NULL) return TRUE;
if (g_dcFilterClass != dcINVALID) { if (g_dcFilterClass == dcLEGACY) { if ((aDriverRoot[ idr ].dc != dcWAVE) && (aDriverRoot[ idr ].dc != dcMIDI) && (aDriverRoot[ idr ].dc != dcMIXER) && (aDriverRoot[ idr ].dc != dcAUX)) { return FALSE; } } else if (aDriverRoot[ idr ].dc != g_dcFilterClass) { return FALSE; } }
aDriverRoot[idr].hti = TVI_ROOT;
LoadString (myInstance, aDriverRoot[idr].idDesc, szDesc, cchRESOURCE);
if ((g_dcFilterClass == dcINVALID) || (g_dcFilterClass == dcLEGACY)) { ti.hInsertAfter = TVI_LAST; ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; ti.item.iImage = idr; ti.item.iSelectedImage = idr; ti.item.pszText = szDesc; ti.item.lParam = NOPIDRIVER;
if (aDriverRoot[idr].dc == dcINVALID) ti.hParent = TVI_ROOT; else ti.hParent = AdvDlgFindTopLevel ();
if ((aDriverRoot[idr].hti = TreeView_InsertItem (hTree, &ti)) == NULL) return FALSE; }
if (g_dcFilterClass != dcINVALID) { hwndParent = GetParent(hTree); if (hwndParent) { hwndName = GetDlgItem(hwndParent,IDC_DEVICECLASS); if (hwndName) { if (g_dcFilterClass == dcLEGACY) { LoadString (myInstance, IDS_WAVE_HEADER, szDesc, cchRESOURCE); }
SetWindowText(hwndName,szDesc); } } }
return TRUE; }
/*
**** AdvDlgFindTopLevel - Finds the HTREEITEM associated with the tree root * * If there's a "Multimedia Devices" tree item under which the other roots * are collected, this will return that item. Otherwise, it returns TVI_ROOT. * */
HTREEITEM AdvDlgFindTopLevel (void) { short idr;
for (idr = 0; idr < nDriverROOTS; idr++) { if (aDriverRoot[idr].dc == dcINVALID) return aDriverRoot[idr].hti; }
return TVI_ROOT; }
/*
**** InitAdvDlgTree - Prepares the AdvDlg's treeview to display devices * */
BOOL InitAdvDlgTree (HWND hTree) { int cxIcon, cyIcon; short idr; UINT uFlags; DWORD dwLayout;
#ifdef UNICODE
TreeView_SetUnicodeFormat(hTree,TRUE); #endif
// Make sure we start with a clean slate
//
hAdvDlgTree = hTree; SendMessage (hTree, WM_SETREDRAW, FALSE, 0L);
for (idr = 0; idr < nDriverROOTS; idr++) { aDriverRoot[ idr ].hti = NULL; aDriverRoot[ idr ].dwBit = ((DWORD)1) << idr; }
// Create an imagelist for the icons in the treeview
//
cxIcon = (int)GetSystemMetrics (SM_CXSMICON); cyIcon = (int)GetSystemMetrics (SM_CYSMICON); uFlags = ILC_MASK | ILC_COLOR32;
if (GetProcessDefaultLayout(&dwLayout) && (dwLayout & LAYOUT_RTL)) { uFlags |= ILC_MIRROR; }
if ((hImageList = ImageList_Create (cxIcon, cyIcon, uFlags, nDriverROOTS, 1)) == NULL) return FALSE;
for (idr = 0; idr < nDriverROOTS; idr++) { HICON hi = LoadImage (myInstance, MAKEINTRESOURCE( aDriverRoot[idr].idIcon ), IMAGE_ICON, cxIcon, cyIcon, LR_DEFAULTCOLOR); ImageList_AddIcon (hImageList, hi); }
TreeView_SetImageList (hTree, hImageList, TVSIL_NORMAL);
if (g_dcFilterClass == dcINVALID) { // Create the root nodes that are supposed to exist
// even without children (note that not all are)
//
for (idr = 0; idr < nDriverROOTS; idr++) { if (aDriverRoot[ idr ].dc == dcINVALID) { if (!EnsureRootIndexExists (hTree, idr)) return FALSE; } } for (idr = 0; idr < nDriverROOTS; idr++) { if (aDriverRoot[ idr ].dc != dcINVALID && aDriverRoot[ idr ].fAlwaysMake) { if (!EnsureRootIndexExists (hTree, idr)) return FALSE; } } } // Expand the tree somewhat, so the user doesn't get
// greeted by a blank page
//
TreeView_Expand (hTree, AdvDlgFindTopLevel(), TVE_EXPAND);
SendMessage (hTree, WM_SETREDRAW, TRUE, 0L); return TRUE; }
/*
**** FreeAdvDlgTree - Removes and frees all items within the AdvDlg treeview * */
void FreeAdvDlgTree (HWND hTree) { short idr;
// Delete all leaf nodes
//
for (idr = 0; idr < nDriverROOTS; idr++) { HTREEITEM hti;
if (aDriverRoot[idr].dc == dcINVALID) continue; if (aDriverRoot[idr].hti == NULL) continue;
while ((hti = TreeView_GetChild (hTree, aDriverRoot[idr].hti)) != NULL) { if (aDriverRoot[ idr ].dc == dcMIDI) { HTREEITEM htiInstrument;
while ((htiInstrument = TreeView_GetChild (hTree, hti)) != NULL) { TV_ITEM tvi; tvi.mask = TVIF_PARAM; tvi.hItem = htiInstrument; tvi.lParam = 0;
TreeView_GetItem(hTree, &tvi);
if (tvi.lParam != 0) LocalFree ((HANDLE)tvi.lParam);
TreeView_DeleteItem (hTree, htiInstrument); } }
TreeView_DeleteItem (hTree, hti); } }
// Delete everything else
//
TreeView_DeleteAllItems (hTree);
// Delete the tree's image list
//
if (hImageList) { TreeView_SetImageList (hTree, NULL, TVSIL_NORMAL); ImageList_Destroy (hImageList); hImageList = NULL; }
// Delete the InstalledDrivers array
//
if (aInstalledDrivers != NULL) { mysize_t ii; for (ii = 0; ii < cInstalledDrivers; ++ii) { if (aInstalledDrivers[ ii ].pIDriver != NULL) { LocalFree ((HANDLE)aInstalledDrivers[ ii ].pIDriver); aInstalledDrivers[ ii ].pIDriver = NULL; } }
GlobalFree ((HGLOBAL)aInstalledDrivers); aInstalledDrivers = NULL; cInstalledDrivers = 0; } }
int lstrnicmp (LPTSTR pszA, LPTSTR pszB, size_t cch) { #ifdef UNICODE
size_t cchA, cchB; TCHAR *pch;
for (cchA = 1, pch = pszA; cchA < cch; cchA++, pch++) { if (*pch == TEXT('\0')) break; } for (cchB = 1, pch = pszB; cchB < cch; cchB++, pch++) { if (*pch == TEXT('\0')) break; }
return (CompareStringW (GetThreadLocale(), NORM_IGNORECASE, pszA, cchA, pszB, cchB) )-2; // CompareStringW returns {1,2,3} instead of {-1,0,1}.
#else
return _strnicmp (pszA, pszB, cch); #endif
}
LPTSTR lstrchr (LPTSTR pszTarget, TCHAR ch) { size_t ich; if (pszTarget == NULL) return NULL; for (ich = 0; pszTarget[ich] != TEXT('\0'); ich++) { if (pszTarget[ich] == ch) return &pszTarget[ ich ]; }
return NULL; }
void lsplitpath (LPTSTR pszSource, LPTSTR pszDrive, LPTSTR pszPath, LPTSTR pszName, LPTSTR pszExt) { LPTSTR pszLastSlash = NULL; LPTSTR pszLastDot = NULL; LPTSTR pch; size_t cchCopy;
/*
* NOTE: This routine was snitched out of USERPRI.LIB 'cause the * one in there doesn't split the extension off the name properly. * * We assume that the path argument has the following form, where any * or all of the components may be missing. * * <drive><dir><fname><ext> * * and each of the components has the following expected form(s) * * drive: * 0 to _MAX_DRIVE-1 characters, the last of which, if any, is a * ':' * dir: * 0 to _MAX_DIR-1 characters in the form of an absolute path * (leading '/' or '\') or relative path, the last of which, if * any, must be a '/' or '\'. E.g - * absolute path: * \top\next\last\ ; or * /top/next/last/ * relative path: * top\next\last\ ; or * top/next/last/ * Mixed use of '/' and '\' within a path is also tolerated * fname: * 0 to _MAX_FNAME-1 characters not including the '.' character * ext: * 0 to _MAX_EXT-1 characters where, if any, the first must be a * '.' * */
// extract drive letter and :, if any
//
if (*(pszSource + _MAX_DRIVE - 2) == TEXT(':')) { if (pszDrive) { lstrncpy (pszDrive, pszSource, _MAX_DRIVE-1); pszDrive[ _MAX_DRIVE-1 ] = TEXT('\0'); } pszSource += _MAX_DRIVE-1; } else if (pszDrive) { *pszDrive = TEXT('\0'); }
// extract path string, if any. pszSource now points to the first
// character of the path, if any, or the filename or extension, if
// no path was specified. Scan ahead for the last occurence, if
// any, of a '/' or '\' path separator character. If none is found,
// there is no path. We will also note the last '.' character found,
// if any, to aid in handling the extension.
//
for (pch = pszSource; *pch != TEXT('\0'); pch++) { if (*pch == TEXT('/') || *pch == TEXT('\\')) pszLastSlash = pch; else if (*pch == TEXT('.')) pszLastDot = pch; }
// if we found a '\\' or '/', fill in pszPath
//
if (pszLastSlash) { if (pszPath) { cchCopy = (size_t)min((UINT)_MAX_DIR-1, (pszLastSlash-pszSource) + 1); lstrncpy (pszPath, pszSource, cchCopy); pszPath[ cchCopy ] = 0; } pszSource = pszLastSlash +1; } else if (pszPath) { *pszPath = TEXT('\0'); }
// extract file name and extension, if any. Path now points to
// the first character of the file name, if any, or the extension
// if no file name was given. Dot points to the '.' beginning the
// extension, if any.
//
if (pszLastDot && (pszLastDot >= pszSource)) { // found the marker for an extension -
// copy the file name up to the '.'.
//
if (pszName) { cchCopy = (size_t)min( (UINT)_MAX_DIR-1, (pszLastDot-pszSource) ); lstrncpy (pszName, pszSource, cchCopy); pszName[ cchCopy ] = 0; }
// now we can get the extension
//
if (pszExt) { lstrncpy (pszExt, pszLastDot, _MAX_EXT -1); pszExt[ _MAX_EXT-1 ] = TEXT('\0'); } } else { // found no extension, give empty extension and copy rest of
// string into fname.
//
if (pszName) { lstrncpy (pszName, pszSource, _MAX_FNAME -1); pszName[ _MAX_FNAME -1 ] = TEXT('\0'); }
if (pszExt) { *pszExt = TEXT('\0'); } }
}
void lstrncpy (LPTSTR pszTarget, LPTSTR pszSource, size_t cch) { size_t ich; for (ich = 0; ich < cch; ich++) { if ((pszTarget[ich] = pszSource[ich]) == TEXT('\0')) break; } }
/*
* DEVICE PROPERTY SHEETS _____________________________________________________ * */
// General flag macros
//
#define SetFlag(obj, f) do {obj |= (f);} while (0)
#define ToggleFlag(obj, f) do {obj ^= (f);} while (0)
#define ClearFlag(obj, f) do {obj &= ~(f);} while (0)
#define IsFlagSet(obj, f) (BOOL)(((obj) & (f)) == (f))
#define IsFlagClear(obj, f) (BOOL)(((obj) & (f)) != (f))
BOOL InstrumentToResource (PIRESOURCE, HTREEITEM); BOOL DriverToResource (HWND,PIRESOURCE,PIDRIVER,DriverClass); DriverClass OldClassIDToDriverClass (int); void FreeClassNode (PCLASSNODE); PIDRIVER FindIDriverByResource (PIRESOURCE); void EnableDriverService (PIRESOURCE, BOOL);
BOOL PASCAL DoDevPropCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify); STATIC void SetDevStatus(int iStatus, HWND hDlg); INT_PTR CALLBACK ACMDlg(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
/*
*** DriverToResource - create a PIRESOURCE structure from a PIDRIVER structure * * The Win95 code uses PIRESOURCEs (among other structures) to keep track of * the item in the Advanced tab's treeview; the old WinNT code used PIDRIVER * structures to keep track of the items in its listbox. The tree now uses * PIDRIVER structures, but we create PIRESOURCE structures out of 'em before * passing control off to the Win95 properties dialogs, which came through * largely unmodified. * * BTW, I retained the PIDRIVER structures as the main treeview structure * because it prevented difficulty in porting over the Install/Remove Driver * code from the old NT code. * */
BOOL DriverToResource (HWND hPar, PIRESOURCE pir, PIDRIVER pid, DriverClass dc) { if (dc == dcINVALID) { if ((dc = GuessDriverClass (pid)) == dcINVALID) return FALSE; }
if ((pir->pcn = (PCLASSNODE)LocalAlloc (LPTR, sizeof(CLASSNODE))) == NULL) return FALSE;
if (!DriverClassToClassNode (pir->pcn, dc)) { LocalFree ((HANDLE)pir->pcn); return FALSE; }
if (dc == dcACODEC) pir->iNode = 3; // 1=class, 2=device, 3=acm, 4=instmt
// else if (dc == dcINSTRUMENT)
// pir->iNode = 4; // 1=class, 2=device, 3=acm, 4=instmt
else pir->iNode = 2; // 1=class, 2=device, 3=acm, 4=instmt
lstrcpy (pir->szFriendlyName, pid->szDesc); lstrcpy (pir->szDesc, pid->szDesc); lstrcpy (pir->szFile, pid->szFile); lstrcpy (pir->szDrvEntry, pid->szAlias); lstrcpy (pir->szClass, pir->pcn->szClass);
pid->fQueryable = IsConfigurable (pid, hPar); pir->fQueryable = (short)pid->fQueryable; pir->iClassID = (short)DriverClassToOldClassID (dc); pir->szParam[0] = 0; pir->dnDevNode = 0; pir->hDriver = NULL;
// Find fStatus, which despite its name is really a series of
// flags--in Win95 it's composed of DEV_* flags (from the old
// mmcpl.h), but those are tied with PNP. Here, we use the
// dwStatus* flags:
//
pir->fStatus = (int)GetDriverStatus (pid);
return TRUE; }
BOOL InstrumentToResource (PIRESOURCE pir, HTREEITEM hti) { TV_ITEM tvi; PINSTRUM pin;
tvi.mask = TVIF_PARAM; tvi.hItem = hti; tvi.lParam = 0; TreeView_GetItem(hAdvDlgTree, &tvi);
if ((pin = (PINSTRUM)tvi.lParam) == NULL) return FALSE;
if ((pir->pcn = (PCLASSNODE)LocalAlloc (LPTR, sizeof(CLASSNODE))) == NULL) return FALSE;
if (!DriverClassToClassNode (pir->pcn, dcMIDI)) { LocalFree ((HANDLE)pir->pcn); return FALSE; }
pir->iNode = 4; // 1=class, 2=device, 3=acm, 4=instmt
lstrcpy (pir->szFriendlyName, pin->szFriendly); lstrcpy (pir->szDesc, pin->szKey); // lstrcpy (pir->szFile, TEXT("unused"));
// lstrcpy (pir->szDrvEntry, TEXT("unused"));
lstrcpy (pir->szClass, pir->pcn->szClass);
pir->fQueryable = FALSE; pir->iClassID = MIDI_ID; pir->szParam[0] = 0; pir->dnDevNode = 0; pir->hDriver = NULL; pir->fStatus = 0;
return TRUE; }
BOOL DriverClassToClassNode (PCLASSNODE pcn, DriverClass dc) { short idr; short ii; int cxIcon, cyIcon;
if ((idr = DriverClassToRootIndex (dc)) == -1) return FALSE;
pcn->iNode = 1; // 1=class, 2=device, 3=acm, 4=instmt
GetString (pcn->szClassName, aDriverRoot[idr].idDesc); pcn->szClass[0] = TEXT('\0');
for (ii = 0; ii < nKeywordDESCS; ii++) { if (aKeywordDesc[ii].dc == dc) { lstrcpy (pcn->szClass, aKeywordDesc[ii].psz); break; } }
cxIcon = (int)GetSystemMetrics (SM_CXICON); cyIcon = (int)GetSystemMetrics (SM_CYICON);
pcn->hIcon = LoadImage (myInstance, MAKEINTRESOURCE( aDriverRoot[ idr ].idIcon ), IMAGE_ICON, cxIcon, cyIcon, LR_DEFAULTCOLOR);
return TRUE; }
int DriverClassToOldClassID (DriverClass dc) { switch (dc) { case dcWAVE: return WAVE_ID; break; case dcMIDI: return MIDI_ID; break; case dcMIXER: return MIXER_ID; break; case dcAUX: return AUX_ID; break; case dcMCI: return MCI_ID; break; case dcACODEC: return ACM_ID; break; case dcVCODEC: return ICM_ID; break; case dcVIDCAP: return VIDCAP_ID; break; case dcJOY: return JOYSTICK_ID; break; default: return JOYSTICK_ID; break; } }
DriverClass OldClassIDToDriverClass (int ii) { switch (ii) { case WAVE_ID: return dcWAVE; break; case MIDI_ID: return dcMIDI; break; case MIXER_ID: return dcMIXER; break; case AUX_ID: return dcAUX; break; case MCI_ID: return dcMCI; break; case ACM_ID: return dcACODEC; break; case ICM_ID: return dcVCODEC; break; case VIDCAP_ID: return dcVIDCAP; break; case JOYSTICK_ID: return dcJOY; break; default: return dcOTHER; } }
void FreeIResource (PIRESOURCE pir) { if (pir->pcn != NULL) { FreeClassNode (pir->pcn); LocalFree ((HANDLE)pir->pcn); pir->pcn = NULL; } }
void FreeClassNode (PCLASSNODE pcn) { if (pcn->hIcon != NULL) { DestroyIcon (pcn->hIcon); pcn->hIcon = NULL; } }
DWORD GetDriverStatus (PIDRIVER pid) { DWORD dwStatus; SC_HANDLE scManager; SC_HANDLE scDriver; TCHAR szName[ cchRESOURCE ];
dwStatus = 0;
lsplitpath (pid->szFile, NULL, NULL, szName, NULL);
// First step: determine if the driver has a service
//
if ((scManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL) { if ((scDriver = OpenService (scManager, szName, GENERIC_READ)) != NULL) { QUERY_SERVICE_CONFIG qsc; SERVICE_STATUS ss; DWORD cbReq; void *pqsc;
SetFlag (dwStatus, dwStatusHASSERVICE);
// Great! It has a service. Find out if the service
// is actively running, and whether it is disabled.
//
if (QueryServiceConfig (scDriver, &qsc, sizeof(qsc), &cbReq)) { if (qsc.dwStartType != SERVICE_DISABLED) { SetFlag (dwStatus, dwStatusSvcENABLED); } } else if ((pqsc = (void *)LocalAlloc (LPTR, cbReq)) != NULL) { if (QueryServiceConfig (scDriver, (QUERY_SERVICE_CONFIG *)pqsc, cbReq, &cbReq)) { if ( ((QUERY_SERVICE_CONFIG *)pqsc)->dwStartType != SERVICE_DISABLED) { SetFlag (dwStatus, dwStatusSvcENABLED); } }
LocalFree ((HANDLE)pqsc); }
if (QueryServiceStatus (scDriver, &ss)) { if ((ss.dwCurrentState != SERVICE_STOPPED) && (ss.dwCurrentState != SERVICE_STOP_PENDING)) { SetFlag (dwStatus, dwStatusSvcSTARTED); } }
CloseServiceHandle (scDriver); }
CloseServiceHandle (scManager); }
// If no service, see if we can talk to the driver itself
//
if (!IsFlagSet (dwStatus, dwStatusHASSERVICE)) { HANDLE hDriver;
if ((hDriver = OpenDriver (pid->wszAlias, pid->wszSection, 0L)) != NULL) { SetFlag (dwStatus, dwStatusDRIVEROK);
CloseDriver (hDriver, 0L, 0L); } }
// If it's a wave device, can we map through it?
//
if (GetMappable (pid)) { SetFlag (dwStatus, dwStatusMAPPABLE); }
return dwStatus; }
void GetTreeItemNodeDesc (LPTSTR pszTarget, PIRESOURCE pir) { lstrcpy (pszTarget, pir->szFriendlyName); }
void GetTreeItemNodeID (LPTSTR pszTarget, PIRESOURCE pir) { DriverClass dc; CLASSNODE cn;
*pszTarget = 0; // In case we fail later
dc = OldClassIDToDriverClass (pir->iClassID); if (!DriverClassToClassNode (&cn, dc)) return;
switch (pir->iNode) // 1=class, 2=device, 3=acm, 4=instmt
{ case 1: // class
lstrcpy (pszTarget, cn.szClass); break;
case 2: // instrument
wsprintf (pszTarget, TEXT("%s\\%s"), cn.szClass, pir->szDrvEntry); break;
case 4: // instrument
lstrcpy (pszTarget, pir->szDesc); break;
default: lstrcpy (pszTarget, pir->szDesc); break; }
FreeClassNode (&cn); }
void ShowDeviceProperties (HWND hPar, HTREEITEM hti) { IRESOURCE ir; CLASSNODE cn; DEVTREENODE dtn; short idr; TCHAR szTitle[ cchRESOURCE ]; TCHAR szTab[ cchRESOURCE ]; DriverClass dc; PIDRIVER pid;
if (hti == NULL) return;
if (TreeView_GetParent (hAdvDlgTree, hti) && TreeView_GetGrandParent (hAdvDlgTree, hti) && (GuessDriverClassFromTreeItem ( TreeView_GetGrandParent (hAdvDlgTree, hti) ) == dcMIDI)) { if (InstrumentToResource (&ir, hti)) { ShowMidiPropSheet (NULL, ir.szFriendlyName, hPar, MIDI_INSTRUMENT_PROP, ir.szFriendlyName, hti, (LPARAM)&ir, (LPARAM)hAdvDlgTree);
FreeIResource (&ir); } return; } else if ((pid = FindIDriverByTreeItem (hti)) != NULL) { dc = GuessDriverClassFromTreeItem (TreeView_GetParent(hAdvDlgTree,hti)); if (dc == dcINVALID) { if ((dc = GuessDriverClass (pid)) == dcINVALID) return; } } else { if ((dc = GuessDriverClassFromTreeItem (hti)) == dcINVALID) return; }
if (g_dcFilterClass != dcINVALID) { if ((dc == dcOTHER) || (dc == dcINVALID)) { dc = g_dcFilterClass; } }
if ((idr = DriverClassToRootIndex (dc)) == -1) return;
if (pid == NULL) // Just want class properties?
{ if (!DriverClassToClassNode (&cn, dc)) return;
if (dc == dcMIDI) // MIDI class properties?
{ GetString (szTitle, aDriverRoot[idr].idDesc);
ShowMidiPropSheet (NULL, szTitle, hPar, MIDI_CLASS_PROP, szTitle, hti, (LPARAM)&cn, (LPARAM)hAdvDlgTree); } else // Generic class properties? (nothing to do, really)
{ GetString (szTab, IDS_GENERAL); GetString (szTitle, aDriverRoot[idr].idDesc);
dtn.lParam = (LPARAM)&cn; dtn.hwndTree = hAdvDlgTree;
ShowPropSheet (szTab, DevPropDlg, DLG_DEV_PROP, hPar, szTitle, (LPARAM)&dtn); }
FreeClassNode (&cn); } else { switch (dc) { case dcACODEC: GetString (szTab, IDS_GENERAL);
ShowPropSheet (szTab, ACMDlg, DLG_ACMDEV_PROP, hPar, pid->szDesc, pid->lp);
// Re-sort the Audio Codec entries, in case their priorities
// have changed. Then find treeview item for this codec,
// and select it.
//
{ HTREEITEM hti; short idr;
SendMessage (hAdvDlgTree, WM_SETREDRAW, FALSE, 0L); FillTreeFromMSACM (hAdvDlgTree); SendMessage (hAdvDlgTree, WM_SETREDRAW, TRUE, 0L);
if ((idr = DriverClassToRootIndex (dcACODEC)) != -1) { if ((hti = aDriverRoot[ idr ].hti) != NULL) { for (hti = TreeView_GetChild (hAdvDlgTree, hti); hti != NULL; hti = TreeView_GetNextSibling (hAdvDlgTree, hti)) { if (pid == FindIDriverByTreeItem (hti)) { TreeView_SelectItem (hAdvDlgTree, hti); break; } } } } } break;
case dcMIDI: if (!DriverToResource (hPar, &ir, pid, dc)) break;
GetString (szTab, IDS_GENERAL);
dtn.lParam = (LPARAM)&ir; dtn.hwndTree = hAdvDlgTree;
ShowWithMidiDevPropSheet (szTab, DevPropDlg, DLG_DEV_PROP, hPar, pid->szDesc, hti, (LPARAM)&dtn, (LPARAM)&ir, (LPARAM)hAdvDlgTree);
FreeIResource (&ir); break;
case dcWAVE: if (!DriverToResource (hPar, &ir, pid, dc)) break;
GetString (szTab, IDS_GENERAL);
dtn.lParam = (LPARAM)&ir; dtn.hwndTree = hAdvDlgTree;
ShowPropSheet (szTab, DevPropDlg, DLG_WAVDEV_PROP, hPar, pid->szDesc, (LPARAM)&dtn);
FreeIResource (&ir); break;
default: if (!DriverToResource (hPar, &ir, pid, dc)) break;
GetString (szTab, IDS_GENERAL);
dtn.lParam = (LPARAM)&ir; dtn.hwndTree = hAdvDlgTree;
ShowPropSheet (szTab, DevPropDlg, DLG_DEV_PROP, hPar, pid->szDesc, (LPARAM)&dtn);
FreeIResource (&ir); break; } } }
#include "medhelp.h"
const static DWORD aDevPropHelpIds[] = { // Context Help IDs
ID_DEV_SETTINGS, IDH_MMCPL_DEVPROP_SETTINGS, IDC_DEV_ICON, NO_HELP, IDC_DEV_DESC, NO_HELP, IDC_DEV_STATUS, NO_HELP, IDC_ENABLE, IDH_MMCPL_DEVPROP_ENABLE, IDC_DISABLE, IDH_MMCPL_DEVPROP_DISABLE, IDC_DONOTMAP, IDH_MMCPL_DEVPROP_DONT_MAP, 0, 0 };
/*
*************************************************************** * DlgProc for device Property sheet. *************************************************************** */ INT_PTR CALLBACK DevPropDlg (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm;
switch (uMsg) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_KILLACTIVE: FORWARD_WM_COMMAND(hDlg, IDOK, 0, 0, SendMessage); break;
case PSN_APPLY: FORWARD_WM_COMMAND(hDlg, ID_APPLY, 0, 0, SendMessage); break;
case PSN_SETACTIVE: FORWARD_WM_COMMAND(hDlg, ID_INIT, 0, 0, SendMessage); break;
case PSN_RESET: FORWARD_WM_COMMAND(hDlg, IDCANCEL, 0, 0, SendMessage); break; } break;
case WM_INITDIALOG: { PIRESOURCE pIResource; PCLASSNODE pcn; PDEVTREENODE pdtn = (PDEVTREENODE)(((LPPROPSHEETPAGE)lParam)->lParam);
SetWindowLongPtr(hDlg, DWLP_USER, ((LPPROPSHEETPAGE)lParam)->lParam);
if (*((short *)(pdtn->lParam)) == 1) { HWND hwndTree = pdtn->hwndTree; HTREEITEM htiCur = TreeView_GetSelection(hwndTree); TCHAR sz[cchRESOURCE]; TV_ITEM tvi;
tvi.mask = TVIF_CHILDREN; tvi.hItem = htiCur; TreeView_GetItem(hwndTree, &tvi);
pcn = (PCLASSNODE)(pdtn->lParam); //set class icon.
SendDlgItemMessage(hDlg, IDC_DEV_ICON, STM_SETICON, (WPARAM)pcn->hIcon , 0L); SetWindowText(GetDlgItem(hDlg, IDC_DEV_DESC), pcn->szClassName); DestroyWindow(GetDlgItem(hDlg, IDC_ENABLE)); DestroyWindow(GetDlgItem(hDlg, IDC_DISABLE)); DestroyWindow(GetDlgItem(hDlg, ID_DEV_SETTINGS));
GetString (sz, (tvi.cChildren) ? IDS_NOPROP : IDS_NODEVS); SetWindowText(GetDlgItem(hDlg, IDC_DEV_STATUS), sz); } else { pIResource = (PIRESOURCE)(pdtn->lParam); SendDlgItemMessage(hDlg, IDC_DEV_ICON, STM_SETICON, (WPARAM)pIResource->pcn->hIcon , 0L); SetWindowText(GetDlgItem(hDlg, IDC_DEV_DESC), pIResource->szDesc); if (!IsFlagSet(pIResource->fStatus, dwStatusHASSERVICE) && !IsFlagSet(pIResource->fStatus, dwStatusDRIVEROK)) { SetDevStatus(pIResource->fStatus, hDlg); } else { if (pIResource->iClassID == WAVE_ID) { CheckDlgButton (hDlg, IDC_DONOTMAP, IsFlagClear(pIResource->fStatus, dwStatusMAPPABLE)); }
if (!pIResource->fQueryable || pIResource->fQueryable == -1) EnableWindow(GetDlgItem(hDlg, ID_DEV_SETTINGS), FALSE); if (!IsFlagSet (pIResource->fStatus, dwStatusHASSERVICE)) { DestroyWindow(GetDlgItem(hDlg, IDC_ENABLE)); DestroyWindow(GetDlgItem(hDlg, IDC_DISABLE)); } else { TCHAR szStatusStr[MAXSTR]; DriverClass dc; short idr;
dc = OldClassIDToDriverClass (pIResource->iClassID); idr = DriverClassToRootIndex (dc);
if (idr == -1) { DestroyWindow (GetDlgItem(hDlg, IDC_ENABLE)); DestroyWindow (GetDlgItem(hDlg, IDC_DISABLE)); } else { GetString (szStatusStr, aDriverRoot[idr].idEnable); SetDlgItemText(hDlg, IDC_ENABLE, szStatusStr); GetString (szStatusStr, aDriverRoot[idr].idDisable); SetDlgItemText(hDlg, IDC_DISABLE, szStatusStr); } } } SetDevStatus(pIResource->fStatus, hDlg); }
#ifdef FIX_BUG_15451
if (szDriverWhichNeedsSettings[0] != TEXT('\0')) { MakeThisDialogLookLikeTheOldDialog (GetParent(hDlg)); } #endif // FIX_BUG_15451
break; }
case WM_DESTROY: break;
case WM_DROPFILES: break;
case WM_CONTEXTMENU: WinHelp ((HWND) wParam, NULL, HELP_CONTEXTMENU, (UINT_PTR) (LPTSTR) aDevPropHelpIds); return TRUE;
case WM_HELP: { LPHELPINFO lphi = (LPVOID) lParam; WinHelp (lphi->hItemHandle, NULL, HELP_WM_HELP, (UINT_PTR) (LPTSTR) aDevPropHelpIds); return TRUE; }
case WM_COMMAND: HANDLE_WM_COMMAND(hDlg, wParam, lParam, DoDevPropCommand); break; } return FALSE; }
/*
*************************************************************** * *************************************************************** */ BOOL PASCAL DoDevPropCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify) { PDEVTREENODE pdtn = (PDEVTREENODE)GetWindowLongPtr(hDlg, DWLP_USER); PIRESOURCE pIResource; static int fDevStatus;
if (!pdtn) return FALSE; pIResource = (PIRESOURCE)(pdtn->lParam);
switch (id) {
case ID_APPLY: if ((pIResource->iNode == 2) && (fDevStatus != pIResource->fStatus)) { if ( (IsFlagSet (fDevStatus, dwStatusMAPPABLE)) != (IsFlagSet (pIResource->fStatus, dwStatusMAPPABLE)) ) { SetMappable (pIResource, (BOOL)IsFlagSet (fDevStatus, dwStatusMAPPABLE)); }
if ( (IsFlagSet (fDevStatus, dwStatusHASSERVICE)) && (IsFlagSet (fDevStatus, dwStatusSvcENABLED) != IsFlagSet (pIResource->fStatus, dwStatusSvcENABLED)) ) { #if 0 // TODO: Multiportmidi
if ( (pIResource->iClassID == MIDI_ID) && (IsFlagSet(fDevStatus, DEV_MULTIPORTMIDI)) ) { EnableMultiPortMIDI (pIResource, IsFlagSet (fDevStatus, dwStatusSvcENABLED)); } else #endif
{ EnableDriverService (pIResource, IsFlagSet (fDevStatus, dwStatusSvcENABLED)); } } DisplayMessage(hDlg, IDS_CHANGESAVED, IDS_RESTART, MB_OK); } return TRUE;
case IDOK: return TRUE; case IDCANCEL: break;
case ID_INIT: if (pIResource->iNode == 2) fDevStatus = pIResource->fStatus; #ifdef FIX_BUG_15451
if (szDriverWhichNeedsSettings[0] != TEXT('\0')) { FORWARD_WM_COMMAND(hDlg,ID_DEV_SETTINGS,0,0,PostMessage); } #endif // FIX_BUG_15451
break;
case IDC_DONOTMAP: if(Button_GetCheck(GetDlgItem(hDlg, IDC_DONOTMAP))) ClearFlag(fDevStatus, dwStatusMAPPABLE); else SetFlag(fDevStatus, dwStatusMAPPABLE); PropSheet_Changed(GetParent(hDlg),hDlg); break;
case IDC_ENABLE: if (IsFlagSet (fDevStatus, dwStatusHASSERVICE)) { SetFlag(fDevStatus, dwStatusSvcENABLED); SetDevStatus(fDevStatus, hDlg); PropSheet_Changed(GetParent(hDlg),hDlg); #if 0 // TODO: Multiportmidi
if (IsFlagSet(fDevStatus, DEV_MULTIPORTMIDI)) { DisplayMessage(hDlg, IDS_ENABLE, IDS_ENABLEMULTIPORTMIDI, MB_OK); } #endif
} break;
case IDC_DISABLE: if (IsFlagSet (fDevStatus, dwStatusHASSERVICE)) { ClearFlag(fDevStatus, dwStatusSvcENABLED); SetDevStatus(fDevStatus, hDlg); PropSheet_Changed(GetParent(hDlg),hDlg); #if 0 // TODO: Multiportmidi
if (IsFlagSet(fDevStatus, DEV_MULTIPORTMIDI)) { DisplayMessage(hDlg, IDS_DISABLE, IDS_DISABLEMULTIPORTMIDI, MB_OK); } #endif
} break;
case ID_DEV_SETTINGS: #ifdef FIX_BUG_15451
if (szDriverWhichNeedsSettings[0] != TEXT('\0')) { ConfigureDriver (hDlg, szDriverWhichNeedsSettings); szDriverWhichNeedsSettings[0] = 0; } else { PIDRIVER pid;
if ((pid = FindIDriverByResource (pIResource)) == NULL) break;
ShowDriverSettings (hDlg, pid->szFile); } #else // FIX_BUG_15451
{ PIDRIVER pid; HANDLE hDriver;
if ((pid = FindIDriverByResource (pIResource)) == NULL) break;
if ((hDriver = OpenDriver (pid->wszAlias, pid->wszSection, 0L)) == 0) { OpenDriverError(hDlg, pid->szDesc, pid->szFile); } else { DRVCONFIGINFO DrvConfigInfo; InitDrvConfigInfo(&DrvConfigInfo, pid); if ((SendDriverMessage( hDriver, DRV_CONFIGURE, (LONG)hDlg, (LONG)(LPDRVCONFIGINFO)&DrvConfigInfo) == DRVCNF_RESTART)) { iRestartMessage= 0; DialogBox(myInstance, MAKEINTRESOURCE(DLG_RESTART), hDlg, RestartDlg); } CloseDriver(hDriver, 0L, 0L); } } #endif // FIX_BUG_15451
break; } return FALSE; }
/*
*************************************************************** * Check the status flag for the device and display the appropriate text the * the device properties prop sheet. *************************************************************** */ STATIC void SetDevStatus(int iStatus, HWND hDlg) { HWND hwndS = GetDlgItem(hDlg, IDC_DEV_STATUS); TCHAR szStatus[cchRESOURCE];
if (IsFlagSet (iStatus, dwStatusHASSERVICE)) { if (IsFlagSet (iStatus, dwStatusSvcENABLED)) { if (IsFlagSet (iStatus, dwStatusSvcSTARTED)) GetString (szStatus, IDS_DEVENABLEDOK); else GetString (szStatus, IDS_DEVENABLEDNOTOK);
CheckRadioButton (hDlg, IDC_ENABLE, IDC_DISABLE, IDC_ENABLE); } else // service has been disabled
{ if (IsFlagSet (iStatus, dwStatusSvcSTARTED)) GetString (szStatus, IDS_DEVDISABLEDOK); else GetString (szStatus, IDS_DEVDISABLED);
CheckRadioButton(hDlg, IDC_ENABLE, IDC_DISABLE, IDC_DISABLE); }
SetWindowText(hwndS, szStatus); } else // driver does not have a service, and thus can't be disabled
{ if (IsFlagSet (iStatus, dwStatusDRIVEROK)) GetString (szStatus, IDS_DEVENABLEDOK); else GetString (szStatus, IDS_DEVENABLEDNODRIVER);
CheckRadioButton(hDlg, IDC_ENABLE, IDC_DISABLE, IDC_ENABLE); SetWindowText(hwndS, szStatus); } }
/*
*** EnableDriverService - enable or disable a service-based driver * * If Enable, the service will be set to start==system_start. * If !Enable, the service will be set to start==disabled. * */
void EnableDriverService (PIRESOURCE pir, BOOL fEnable) { SC_HANDLE scManager; SC_HANDLE scDriver; TCHAR szName[ cchRESOURCE ];
lsplitpath (pir->szFile, NULL, NULL, szName, NULL);
// First step: determine if the driver has a service
//
if ((scManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL) { if ((scDriver = OpenService (scManager, szName, SERVICE_ALL_ACCESS)) != 0) { QUERY_SERVICE_CONFIG qsc; SERVICE_STATUS ss; DWORD cbReq; void *pqsc;
ChangeServiceConfig (scDriver, SERVICE_NO_CHANGE, (fEnable) ? SERVICE_SYSTEM_START : SERVICE_DISABLED, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
CloseServiceHandle (scDriver); }
CloseServiceHandle (scManager); } }
/*
*************************************************************** * SetMappable * * Sets the "Mappable" value for wave devices in the registry. * The registry key is created if necessary * *************************************************************** */
BOOL SetMappable (PIRESOURCE pIResource, BOOL fMappable) { TCHAR szFile[ _MAX_FNAME +1 +_MAX_EXT +1 ]; TCHAR szExt[ _MAX_EXT +1 ]; TCHAR szRegKey[MAX_PATH+1]; DWORD dwMappable; HKEY hKey;
dwMappable = (fMappable) ? 1 : 0;
lsplitpath (pIResource->szFile, NULL, NULL, szFile, szExt); if (szExt[0] != TEXT('\0')) lstrcat (szFile, szExt);
wsprintf (szRegKey, TEXT("%s\\%s"), REGSTR_PATH_WAVEMAPPER, szFile);
if (RegCreateKey (HKEY_LOCAL_MACHINE, szRegKey, &hKey) != ERROR_SUCCESS) { return FALSE; }
if (RegSetValueEx (hKey, REGSTR_VALUE_MAPPABLE, (DWORD)0, REG_DWORD, (void *)&dwMappable, sizeof(dwMappable)) != ERROR_SUCCESS) { RegCloseKey (hKey); return FALSE; }
RegCloseKey (hKey);
if (fMappable) { SetFlag(pIResource->fStatus, dwStatusMAPPABLE); } else { ClearFlag(pIResource->fStatus, dwStatusMAPPABLE); }
return TRUE; }
BOOL GetMappable (PIDRIVER pIDriver) { TCHAR szFile[ _MAX_FNAME +1 +_MAX_EXT +1 ]; TCHAR szExt[ _MAX_EXT +1 ]; TCHAR szRegKey[MAX_PATH+1]; DWORD dwMappable; DWORD dwSize; DWORD dwType; HKEY hKey;
lsplitpath (pIDriver->szFile, NULL, NULL, szFile, szExt); if (szExt[0] != TEXT('\0')) lstrcat (szFile, szExt);
wsprintf (szRegKey, TEXT("%s\\%s"), REGSTR_PATH_WAVEMAPPER, szFile);
if (RegOpenKey (HKEY_LOCAL_MACHINE, szRegKey, &hKey) != ERROR_SUCCESS) { return TRUE; }
dwSize = sizeof(dwMappable); if (RegQueryValueEx (hKey, REGSTR_VALUE_MAPPABLE, NULL, &dwType, (void *)&dwMappable, &dwSize) != ERROR_SUCCESS) { RegCloseKey (hKey); return TRUE; }
RegCloseKey (hKey);
return (dwMappable) ? TRUE : FALSE; }
#ifdef FIX_BUG_15451
// FixDriverService - work around known problems with sound drivers
//
// If there was a functioning kernel-mode service in place before the
// config dialog was presented, then there should still be one
// afterwards. However, there are two known problems with the
// currently-release drivers:
//
// 1) The service may not have shut down properly, and is stuck
// in a STOP_PENDING state(*). If this is the case, we need to
// ensure that the service is set to load on SYSTEM_START, and
// tell the user that the machine has to be rebooted before sound
// will work again.
//
// 2) The service may have failed to restart properly, and is
// stopped(**). If this is the case, and LoadType!=0, try setting
// LoadType=1 and starting the service.
//
// (*) -- bug #15451 in NT/SUR, where pending IRPs and open mixer
// handles prevent the service from shutting down
//
// (**) -- bug #XXXXX in NT/SUR, where some RISC machines stop the
// service, set LoadType=1, and fail to restart the service
// after you cancel their config dialog
//
BOOL FixDriverService (PIDRIVER pid) { SC_HANDLE scManager; SC_HANDLE scDriver; SERVICE_STATUS ss; BOOL rc = FALSE; TCHAR szName[ cchRESOURCE ];
lsplitpath (pid->szFile, NULL, NULL, szName, NULL);
// First step: open the service...even if it's hosed, we should
// still be able to do this.
//
if ((scManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS)) == 0) { return FALSE; } if ((scDriver = OpenService (scManager, szName, SERVICE_ALL_ACCESS)) == 0) { CloseServiceHandle (scManager); return FALSE; }
// Now check its status. Look for STOP_PENDING and STOPPED states.
//
if (QueryServiceStatus (scDriver, &ss)) { if (ss.dwCurrentState == SERVICE_STOP_PENDING) { // The service didn't stop properly--we'll have to reboot.
// Make sure the service is configured such that it will start
// properly when we restart.
//
ChangeServiceConfig (scDriver, SERVICE_NO_CHANGE, SERVICE_SYSTEM_START, // Enable this puppy!
SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
// Tell the caller that a reboot is mandatory
rc = TRUE; } else if (ss.dwCurrentState == SERVICE_STOPPED) { TCHAR szKey[ cchRESOURCE ]; HKEY hkParams;
// The service stopped, but didn't restart properly--it could
// just be the LoadType problem. To fix this, we'll need
// to enumerate all the keys underneath the key
// HKLM\System\CurrentControlSet\Services\(thisdriver)\Parameters,
// and look for ...\Parameters\*\LoadType==(DWORD)1.
//
// First step is to open HKLM\System\CCS\Services\(driver)\Parms.
//
wsprintf (szKey, TEXT("%s\\%s\\Parameters"), REGSTR_PATH_SERVICES, szName);
if (RegOpenKey (HKEY_LOCAL_MACHINE, szKey, &hkParams) == 0) { DWORD cSubKeys; DWORD iSubKey; BOOL fFixedLoadType = FALSE;
// Find out how many subkeys there are under here--the
// keys we want are named "Device0" through "Device(n-1)"
//
RegQueryInfoKey (hkParams, NULL, // lpClass
NULL, // lpcbClass
NULL, // lpReserved
&cSubKeys, // Whoops! We want this.
NULL, // lpcbMaxSubKeyLen
NULL, // lpcbMaxClassLen
NULL, // lpcValues
NULL, // lpcbMaxValueNameLen
NULL, // lpcbMaxValueLen
NULL, // lpcbSecurityDescriptor
NULL); // lpftLastWriteTime
// Open each subkey in turn, and look for a LoadType=
// which is bogus.
//
for (iSubKey = 0; iSubKey < cSubKeys; ++iSubKey) { HKEY hk; TCHAR szSubKey[ cchRESOURCE ]; wsprintf (szSubKey, TEXT("Device%lu"), (LONG)iSubKey);
if (RegOpenKey (hkParams, szSubKey, &hk) == ERROR_SUCCESS) { DWORD dwLoadType; DWORD dwType; DWORD dwSize = sizeof(dwType);
if (RegQueryValueEx (hk, cszRegValueLOADTYPE, NULL, &dwType, (void *)&dwLoadType, &dwSize) == 0) { if (dwLoadType == 1) { dwLoadType = 0; fFixedLoadType = TRUE;
RegSetValueEx (hk, cszRegValueLOADTYPE, 0, REG_DWORD, (void *)&dwLoadType, sizeof(dwLoadType)); } }
RegCloseKey (hk); } }
// If we fixed a LoadType value, try to restart the service.
//
if (fFixedLoadType) { if (StartService (scDriver, 0, NULL)) { ChangeServiceConfig (scDriver, SERVICE_NO_CHANGE, SERVICE_SYSTEM_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } } } } }
// Clean up. We'll return TRUE if a reboot is necessary, and FALSE
// otherwise.
//
CloseServiceHandle (scDriver); CloseServiceHandle (scManager); return rc; }
void ConfigureDriver (HWND hDlg, LPTSTR pszName) { PIDRIVER pid; HANDLE hDriver; BOOL fShowTrayVol; BOOL fRestartDialog = FALSE;
if ((pid = FindIDriverByName (pszName)) == NULL) return;
fShowTrayVol = GetTrayVolumeEnabled(); if (fShowTrayVol) SetTrayVolumeEnabled(FALSE);
if ((hDriver = OpenDriver (pid->wszAlias, pid->wszSection, 0L)) == 0) { OpenDriverError(hDlg, pid->szDesc, pid->szFile); } else { DWORD dwStatus = GetDriverStatus (pid); BOOL fHadService = IsFlagSet (dwStatus, dwStatusSvcSTARTED) && IsFlagSet (dwStatus, dwStatusHASSERVICE);
DRVCONFIGINFO DrvConfigInfo; InitDrvConfigInfo(&DrvConfigInfo, pid); if ((SendDriverMessage( hDriver, DRV_CONFIGURE, (LONG_PTR)hDlg, (LONG_PTR)(LPDRVCONFIGINFO)&DrvConfigInfo) == DRVCNF_RESTART)) { iRestartMessage = 0; fRestartDialog = TRUE; } CloseDriver(hDriver, 0L, 0L);
// If there was a functioning kernel-mode service in place before the
// config dialog was presented, then we should verify that there is
// still one in place now. See FixDriverService() for details.
//
if (fHadService) { dwStatus = GetDriverStatus (pid);
if (!IsFlagSet (dwStatus, dwStatusSvcSTARTED) || !IsFlagSet (dwStatus, dwStatusHASSERVICE)) { if (FixDriverService (pid)) { iRestartMessage = IDS_RESTART_NOSOUND; fRestartDialog = TRUE; } } } }
if (fShowTrayVol) SetTrayVolumeEnabled(TRUE);
if (fRestartDialog) { DialogBox(myInstance,MAKEINTRESOURCE(DLG_RESTART),hDlg,RestartDlg); } }
BOOL fDeviceHasMixers (LPTSTR pszName) { HKEY hk; UINT ii; BOOL rc = FALSE;
if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_DRIVERS32, &hk)) { return FALSE; }
for (ii = 0; ; ++ii) { TCHAR szLHS[ cchRESOURCE ]; TCHAR szRHS[ cchRESOURCE ]; DWORD dw1; DWORD dw2; DWORD dw3;
dw1 = cchRESOURCE; dw3 = cchRESOURCE; if (RegEnumValue (hk, ii, szLHS, &dw1, 0, &dw2, (LPBYTE)szRHS, &dw3) != ERROR_SUCCESS) { break; }
if ( (GuessDriverClassFromAlias (szLHS) == dcMIXER) && (!FileNameCmp (pszName, szRHS)) ) { rc = TRUE; break; } }
RegCloseKey (hk); return rc; } #endif // FIX_BUG_15451
TCHAR c_tszControlExeS[] = TEXT("control.exe %s");
BOOL RunJoyControlPanel(void) { STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR tsz[MAX_PATH]; BOOL fRtn;
memset(&si, 0, sizeof(si)); si.cb = sizeof(si); wsprintf(tsz, c_tszControlExeS, TEXT("joy.cpl")); if (CreateProcess(0, tsz, 0, 0, 0, 0, 0, 0, &si, &pi)) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); fRtn = TRUE; } else { fRtn = FALSE; }
return fRtn; }
|