windows-nt/Source/XPSP1/NT/shell/osshell/control/mmsys/drivers.c
2020-09-26 16:20:57 +08:00

5116 lines
150 KiB
C

/* 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[80];
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);
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'))
{
if (LoadDescFromFile(pIDriver, pstrKey, pstrDesc) != DESC_NOFILE)
{
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);
} else {
LocalFree((HANDLE)pIDriver);
goto nextkey;
}
}
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;
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!
//
bInitd = TRUE;
if ( (pstrKey = (LPTSTR)LocalAlloc(LPTR, MAX_SYS_INF_LEN)) != NULL )
infParseField(pinf, 0, pstrKey);
else
break;
/*
* add the installable driver's description to listbox, and filename as data
*/
infParseField(pinf, 3, szDesc);
if ( (iIndex = (int)SendMessage(hWnd, LB_ADDSTRING, 0, (LONG_PTR)(LPTSTR)szDesc)) != LB_ERR )
SendMessage(hWnd, LB_SETITEMDATA, iIndex, (LONG_PTR)pstrKey);
}
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[50];
if (ERROR_SUCCESS ==
RegEnumKey(hKeyCache,
0,
Name,
sizeof(Name)/sizeof(TCHAR))) {
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;
}