|
|
#pragma warning( disable: 4103)
#include "mmcpl.h"
#include <cpl.h>
#define NOSTATUSBAR
#include <commctrl.h>
#include <prsht.h>
#include <regstr.h>
#include <infstr.h>
#include <devguid.h>
#include "draw.h"
#include "utils.h"
#include "drivers.h"
#include "sulib.h"
#include "medhelp.h"
#include <tchar.h>
#define GetString(_psz,_id) LoadString(myInstance,(_id),(_psz),sizeof((_psz))/sizeof(TCHAR))
// Global info struct. One instance for the whole dialog
typedef struct _OUR_PROP_PARAMS { HDEVINFO DeviceInfoSet; PSP_DEVINFO_DATA DeviceInfoData; HKEY hkDrv; // Key to classguid\0000
HKEY hkDrivers; // Key to classguid\0000\Drivers
BOOL bClosing; // Set to TRUE while dialog is closing
TCHAR szSubClasses[256]; // Subclasses to process
} OUR_PROP_PARAMS, *POUR_PROP_PARAMS;
typedef enum { NodeTypeRoot, NodeTypeClass, NodeTypeDriver } NODETYPE;
// Tree node. One per node on tree.
typedef struct _DMTREE_NODE; typedef BOOL (*PFNCONFIG) (HWND ParentHwnd, struct _DMTREE_NODE *pTreeNode); typedef BOOL (*PFNQUERYCONFIG)(HWND ParentHwnd, struct _DMTREE_NODE *pTreeNode); typedef struct _DMTREE_NODE { NODETYPE NodeType; // Type of node
PFNCONFIG pfnConfig; // Ptr to config function
PFNQUERYCONFIG pfnQueryConfig; // Ptr to query config function
int QueryConfigInfo; // Data for config function
TCHAR szDescription[MAXSTR]; // Node description
TCHAR szDriver[MAXSTR]; // Driver name of this node
WCHAR wszDriver[MAXSTR]; // Wide char driver name
TCHAR szAlias[MAXSTR]; // Alias
WCHAR wszAlias[MAXSTR]; // Wide char alias
DriverClass dc; // Legacy-style driver class, if available
HTREEITEM hti; // For use with MIDI prop sheet callback
} DMTREE_NODE, *PDMTREE_NODE;
INT_PTR APIENTRY DmAdvPropPageDlgProc(IN HWND hDlg, IN UINT uMessage, IN WPARAM wParam, IN LPARAM lParam );
UINT CALLBACK DmAdvPropPageDlgCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp );
BOOL DmAdvPropPage_OnCommand( HWND ParentHwnd, int ControlId, HWND ControlHwnd, UINT NotifyCode );
BOOL DmAdvPropPage_OnContextMenu( HWND HwndControl, WORD Xpos, WORD Ypos );
BOOL DmAdvPropPage_OnHelp( HWND ParentHwnd, LPHELPINFO HelpInfo );
BOOL DmAdvPropPage_OnInitDialog( HWND ParentHwnd, HWND FocusHwnd, LPARAM Lparam );
BOOL DmAdvPropPage_OnNotify( HWND ParentHwnd, LPNMHDR NmHdr );
void DmAdvPropPage_OnPropertiesClicked( HWND ParentHwnd, POUR_PROP_PARAMS Params );
BOOL DmOverrideResourcesPage(LPVOID Info, LPFNADDPROPSHEETPAGE AddFunc, LPARAM Lparam, POUR_PROP_PARAMS Params );
BOOL AddCDROMPropertyPage( HDEVINFO hDeviceInfoSet, PSP_DEVINFO_DATA pDeviceInfoData, LPFNADDPROPSHEETPAGE AddFunc, LPARAM Lparam );
BOOL AddSpecialPropertyPage( DWORD SpecialDriverType, LPFNADDPROPSHEETPAGE AddFunc, LPARAM Lparam );
BOOL DmInitDeviceTree(HWND hwndTree, POUR_PROP_PARAMS Params);
BOOL DmAdvPropPage_OnDestroy( HWND ParentHwnd, LPNMHDR NmHdr );
void DoProperties(HWND ParentHwnd, HWND hWndI, HTREEITEM htiCur);
BOOL QueryConfigDriver(HWND ParentHwnd, PDMTREE_NODE pTreeNode) { HANDLE hDriver;
if (pTreeNode->NodeType!=NodeTypeDriver) { return FALSE; }
if (pTreeNode->QueryConfigInfo==0) // if 0, the we haven't checked yet
{ INT_PTR IsConfigurable;
// open the driver
hDriver = OpenDriver(pTreeNode->wszDriver, NULL, 0L); if (!hDriver) { return FALSE; }
// Send the DRV_CONFIGURE message to the driver
IsConfigurable = SendDriverMessage(hDriver, DRV_QUERYCONFIGURE, 0L, 0L);
CloseDriver(hDriver, 0L, 0L);
// 1->Is configurable, -1->Not configurable
pTreeNode->QueryConfigInfo = IsConfigurable ? 1 : -1; }
return (pTreeNode->QueryConfigInfo>0); }
BOOL PNPDriverToIResource(PDMTREE_NODE pTreeNode, IRESOURCE* pir) { IDRIVER tempIDriver;
if ((pir->pcn = (PCLASSNODE)LocalAlloc (LPTR, sizeof(CLASSNODE))) == NULL) { return FALSE; }
if (!DriverClassToClassNode(pir->pcn, pTreeNode->dc)) { LocalFree ((HANDLE)pir->pcn); return FALSE; }
pir->iNode = 2; // 1=class, 2=device, 3=acm, 4=instmt
lstrcpy (pir->szFriendlyName, pTreeNode->szDescription); lstrcpy (pir->szDesc, pTreeNode->szDescription); lstrcpy (pir->szFile, pTreeNode->szDriver); lstrcpy (pir->szDrvEntry, pTreeNode->szAlias); lstrcpy (pir->szClass, pir->pcn->szClass);
pir->fQueryable = (short)QueryConfigDriver(NULL, pTreeNode); pir->iClassID = (short)DriverClassToOldClassID(pTreeNode->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:
//
ZeroMemory(&tempIDriver,sizeof(IDRIVER));
lstrcpy(tempIDriver.wszAlias,pTreeNode->wszAlias); lstrcpy(tempIDriver.szAlias,pTreeNode->szAlias); lstrcpy(tempIDriver.wszFile,pTreeNode->wszDriver); lstrcpy(tempIDriver.szFile,pTreeNode->szDriver); lstrcpy(tempIDriver.szDesc,pTreeNode->szDescription); lstrcpy(tempIDriver.szSection,wcsstr(pTreeNode->szDescription, TEXT("MCI")) ? szMCI : szDrivers); lstrcpy(tempIDriver.wszSection,wcsstr(pTreeNode->szDescription, TEXT("MCI")) ? szMCI : szDrivers);
pir->fStatus = (int)GetDriverStatus (&tempIDriver);
return TRUE; }
BOOL ConfigDriver(HWND ParentHwnd, PDMTREE_NODE pTreeNode) { //need to pop up the legacy properties dialog
IRESOURCE ir; DEVTREENODE dtn; TCHAR szTab[ cchRESOURCE ];
if ((pTreeNode->NodeType == NodeTypeDriver) && (pTreeNode->dc != dcINVALID)) { if (PNPDriverToIResource(pTreeNode, &ir)) { GetString (szTab, IDS_GENERAL);
dtn.lParam = (LPARAM)&ir; dtn.hwndTree = ParentHwnd;
//must call this function twice to fill in the array of PIDRIVERs in drivers.c
//otherwise, many of the "settings" calls won't work
InitInstalled (GetParent (ParentHwnd), szDrivers); InitInstalled (GetParent (ParentHwnd), szMCI);
switch (pTreeNode->dc) { case dcMIDI : ShowWithMidiDevPropSheet (szTab, DevPropDlg, DLG_DEV_PROP, ParentHwnd, pTreeNode->szDescription, pTreeNode->hti, (LPARAM)&dtn, (LPARAM)&ir, (LPARAM)ParentHwnd); break;
case dcWAVE : ShowPropSheet (szTab, DevPropDlg, DLG_WAVDEV_PROP, ParentHwnd, pTreeNode->szDescription, (LPARAM)&dtn); break;
default: ShowPropSheet (szTab, DevPropDlg, DLG_DEV_PROP, ParentHwnd, pTreeNode->szDescription, (LPARAM)&dtn); break; } //end switch
FreeIResource (&ir); } }
return (FALSE); }
const static DWORD aDMPropHelpIds[] = { // Context Help IDs
IDC_ADV_TREE, IDH_GENERIC_DEVICES, ID_ADV_PROP, IDH_ADV_PROPERTIES, 0, 0 };
//******************************************************************************
//* Subtype code
//******************************************************************************
//
// Subtype info. Array of one per device class subtype
typedef struct _SUBTYPE_INFO { TCHAR *szClass; DWORD DescId; DWORD IconId; PFNCONFIG pfnConfig; PFNQUERYCONFIG pfnQueryConfig; DriverClass dc; TCHAR szDescription[64]; DWORD IconIndex; } SUBTYPE_INFO;
static SUBTYPE_INFO SubtypeInfo[] = { { TEXT(""), IDS_MM_HEADER, IDI_MMICON, ConfigDriver, QueryConfigDriver, dcOTHER}, { TEXT("waveaudio"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI}, { TEXT("wavemap"), IDS_WAVE_HEADER, IDI_WAVE, ConfigDriver, QueryConfigDriver, dcWAVE}, { TEXT("wave"), IDS_WAVE_HEADER, IDI_WAVE, ConfigDriver, QueryConfigDriver, dcWAVE}, { TEXT("vids"), IDS_ICM_HEADER, IDI_ICM, ConfigDriver, QueryConfigDriver, dcVCODEC}, { TEXT("vidc"), IDS_ICM_HEADER, IDI_ICM, ConfigDriver, QueryConfigDriver, dcVCODEC}, { TEXT("sequencer"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI}, { TEXT("msvideo"), IDS_VIDCAP_HEADER, IDI_VIDEO, ConfigDriver, QueryConfigDriver, dcVIDCAP}, { TEXT("msacm"), IDS_ACM_HEADER, IDI_ACM, ConfigDriver, QueryConfigDriver, dcACODEC}, { TEXT("mpegvideo"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI}, { TEXT("mixer"), IDS_MIXER_HEADER, IDI_MIXER, ConfigDriver, QueryConfigDriver, dcMIXER}, { TEXT("midimapper"), IDS_MIDI_HEADER, IDI_MIDI, ConfigDriver, QueryConfigDriver, dcMIDI}, { TEXT("midi"), IDS_MIDI_HEADER, IDI_MIDI, ConfigDriver, QueryConfigDriver, dcMIDI}, { TEXT("mci"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI}, { TEXT("icm"), IDS_ICM_HEADER, IDI_ICM, ConfigDriver, QueryConfigDriver, dcVCODEC}, { TEXT("cdaudio"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI}, { TEXT("avivideo"), IDS_MCI_HEADER, IDI_MCI, ConfigDriver, QueryConfigDriver, dcMCI}, { TEXT("aux"), IDS_AUX_HEADER, IDI_AUX, ConfigDriver, QueryConfigDriver, dcAUX}, { TEXT("acm"), IDS_ACM_HEADER, IDI_ACM, ConfigDriver, QueryConfigDriver, dcACODEC}, { TEXT("joy"), IDS_JOYSTICK_HEADER, IDI_JOYSTICK, ConfigDriver, QueryConfigDriver, dcJOY} };
#define SUBTYPE_INFO_SIZE (sizeof(SubtypeInfo)/sizeof(SUBTYPE_INFO))
BOOL LoadSubtypeInfo(HWND hwndTree) { UINT i; UINT uFlags; int cxMiniIcon; int cyMiniIcon; DWORD dwLayout;
HIMAGELIST hImagelist;
// Create the image list
cxMiniIcon = (int)GetSystemMetrics(SM_CXSMICON); cyMiniIcon = (int)GetSystemMetrics(SM_CYSMICON); uFlags = ILC_MASK | ILC_COLOR32; if (GetProcessDefaultLayout(&dwLayout) && (dwLayout & LAYOUT_RTL)) { uFlags |= ILC_MIRROR; }
hImagelist = ImageList_Create(cxMiniIcon, cyMiniIcon, uFlags, SUBTYPE_INFO_SIZE, 4); if (!hImagelist) return FALSE;
for (i=0;i<SUBTYPE_INFO_SIZE;i++) { HICON hIcon;
// Load the description
LoadString(ghInstance, SubtypeInfo[i].DescId, SubtypeInfo[i].szDescription, 64);
// Load the image into the image list
hIcon = LoadImage (ghInstance, MAKEINTRESOURCE( SubtypeInfo[i].IconId ), IMAGE_ICON, cxMiniIcon, cyMiniIcon, LR_DEFAULTCOLOR);
if (hIcon) // PREFIX 160723
{ SubtypeInfo[i].IconIndex = ImageList_AddIcon(hImagelist, hIcon); DestroyIcon(hIcon); } else { SubtypeInfo[i].IconIndex = -1; } }
// Clean out and initialize tree control
TreeView_SetImageList(hwndTree, hImagelist, TVSIL_NORMAL);
return TRUE; }
SUBTYPE_INFO *GetSubtypeInfo(TCHAR *pszClass) { UINT iClass; if (pszClass) { for (iClass=0;iClass<SUBTYPE_INFO_SIZE;iClass++) { if (!lstrcmpi(pszClass,SubtypeInfo[iClass].szClass)) return &SubtypeInfo[iClass]; } }
return &SubtypeInfo[0]; }
//******************************************************************************
/*
Routine Description: MediaPropPageProvider
Entry-point for adding additional device manager property sheet pages. Registry specifies this routine under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96C-E325-11CE-BFC1-08002BE10318} EnumPropPage32="mmsys.cpl,thisproc"
This entry-point gets called only when the DeviceManager asks for additional property pages.
Arguments:
Info - points to PROPSHEETPAGE_REQUEST, see setupapi.h AddFunc - function ptr to call to add sheet. Lparam - add sheet functions private data handle.
Return Value:
BOOL: FALSE if pages could not be added, TRUE on success
*/ BOOL APIENTRY MediaPropPageProvider(LPVOID Info, LPFNADDPROPSHEETPAGE AddFunc, LPARAM Lparam ) { PSP_PROPSHEETPAGE_REQUEST pprPropPageRequest; PROPSHEETPAGE psp; HPROPSHEETPAGE hpsp; POUR_PROP_PARAMS Params; HDEVINFO DeviceInfoSet; PSP_DEVINFO_DATA DeviceInfoData; DWORD SpecialDriverType;
HKEY hkDrv; HKEY hkDrivers; DWORD cbLen;
pprPropPageRequest = (PSP_PROPSHEETPAGE_REQUEST) Info;
if (pprPropPageRequest->PageRequested != SPPSR_ENUM_ADV_DEVICE_PROPERTIES) { return TRUE; }
DeviceInfoSet = pprPropPageRequest->DeviceInfoSet; DeviceInfoData = pprPropPageRequest->DeviceInfoData;
// This API is called for both devices and the class as a whole
// (when someone right-clicks on the class and chooses properties).
// In the class case the DeviceInfoData field of the propPageRequest structure is NULL.
// We don't do anything in that case, so just return.
if (!DeviceInfoData) { return TRUE; }
SpecialDriverType = IsSpecialDriver(DeviceInfoSet, DeviceInfoData); if (SpecialDriverType) { SP_DEVINSTALL_PARAMS DeviceInstallParams;
DeviceInstallParams.cbSize = sizeof(DeviceInstallParams); SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams); DeviceInstallParams.Flags |= DI_RESOURCEPAGE_ADDED | DI_DRIVERPAGE_ADDED; // | DI_GENERALPAGE_ADDED;
SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams); AddSpecialPropertyPage(SpecialDriverType, AddFunc, Lparam); return TRUE; }
if (AddCDROMPropertyPage(DeviceInfoSet,DeviceInfoData, AddFunc, Lparam)) { return TRUE; }
// Open device reg key to see if this is a WDM driver
hkDrv = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS); if (!hkDrv) return FALSE;
// Allocate and zero out memory for the struct that will contain page specific data
Params = (POUR_PROP_PARAMS)LocalAlloc(LPTR, sizeof(OUR_PROP_PARAMS)); if (!Params) { RegCloseKey(hkDrv); return FALSE; }
// Initialize Params structure
Params->DeviceInfoSet = DeviceInfoSet; Params->DeviceInfoData = DeviceInfoData; Params->hkDrv = hkDrv;
// Override Resource page if this is not a WDM (PNP) driver
DmOverrideResourcesPage(Info, AddFunc, Lparam, Params);
// Try a couple of things to see if there are actually any drivers under this key
// and cache the results
// Try to open up the Drivers subkey
if (RegOpenKey(Params->hkDrv, TEXT("Drivers"), &hkDrivers)) { RegCloseKey(hkDrv); LocalFree(Params); return TRUE; }
// Try to read the SubClasses key to determine which subclasses to process
cbLen=sizeof(Params->szSubClasses); if (RegQueryValueEx(hkDrivers, TEXT("Subclasses"), NULL, NULL, (LPBYTE)Params->szSubClasses, &cbLen)) { RegCloseKey(hkDrv); RegCloseKey(hkDrivers); LocalFree(Params); return TRUE; }
Params->hkDrivers = hkDrivers;
// Initialize the property sheet page
psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = PSP_USECALLBACK; // | PSP_HASHELP;
psp.hInstance = ghInstance; psp.pszTemplate = MAKEINTRESOURCE(DLG_DM_ADVDLG); psp.pfnDlgProc = DmAdvPropPageDlgProc; // dlg window proc
psp.lParam = (LPARAM) Params; psp.pfnCallback = DmAdvPropPageDlgCallback; // control callback of the dlg window proc
// Create the page & get back a handle
hpsp = CreatePropertySheetPage(&psp); if (!hpsp) { RegCloseKey(hkDrv); LocalFree(Params); return FALSE; }
// Add the property page
if (!(*AddFunc)(hpsp, Lparam)) { DestroyPropertySheetPage(hpsp); return FALSE; }
return TRUE; } /* DmAdvPropPageProvider */
UINT CALLBACK DmAdvPropPageDlgCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { POUR_PROP_PARAMS Params;
switch (uMsg) { case PSPCB_CREATE: // This gets called when the page is created
return TRUE; // return TRUE to continue with creation of page
case PSPCB_RELEASE: // This gets called when the page is destroyed
Params = (POUR_PROP_PARAMS) ppsp->lParam; RegCloseKey(Params->hkDrv); RegCloseKey(Params->hkDrivers); LocalFree(Params); // Free our local params
return 0; // return value ignored
default: break; }
return TRUE; }
/*++
Routine Description: DmAdvPropPageDlgProc
The windows control function for the Port Settings properties window
Arguments:
hDlg, uMessage, wParam, lParam: standard windows DlgProc parameters
Return Value:
BOOL: FALSE if function fails, TRUE if function passes
--*/ INT_PTR APIENTRY DmAdvPropPageDlgProc(IN HWND hDlg, IN UINT uMessage, IN WPARAM wParam, IN LPARAM lParam) { switch (uMessage) { case WM_COMMAND: return DmAdvPropPage_OnCommand(hDlg, (int) LOWORD(wParam), (HWND)lParam, (UINT)HIWORD(wParam));
case WM_CONTEXTMENU: return DmAdvPropPage_OnContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
case WM_HELP: return DmAdvPropPage_OnHelp(hDlg, (LPHELPINFO) lParam);
case WM_INITDIALOG: return DmAdvPropPage_OnInitDialog(hDlg, (HWND)wParam, lParam);
case WM_NOTIFY: return DmAdvPropPage_OnNotify(hDlg, (NMHDR *)lParam);
case WM_DESTROY: return DmAdvPropPage_OnDestroy(hDlg, (NMHDR *)lParam); }
return FALSE; } /* DmAdvPropPageDlgProc */
BOOL DmAdvPropPage_OnCommand( HWND ParentHwnd, int ControlId, HWND ControlHwnd, UINT NotifyCode ) { POUR_PROP_PARAMS params = (POUR_PROP_PARAMS) GetWindowLongPtr(ParentHwnd, DWLP_USER);
switch (ControlId) { case ID_ADV_PROP: DmAdvPropPage_OnPropertiesClicked(ParentHwnd, params); break; }
return FALSE; }
BOOL DmAdvPropPage_OnContextMenu( HWND HwndControl, WORD Xpos, WORD Ypos ) { WinHelp(HwndControl, gszWindowsHlp, HELP_CONTEXTMENU, (ULONG_PTR) aDMPropHelpIds); return FALSE; }
BOOL DmAdvPropPage_OnHelp( HWND ParentHwnd, LPHELPINFO HelpInfo ) { if (HelpInfo->iContextType == HELPINFO_WINDOW) { WinHelp((HWND) HelpInfo->hItemHandle, gszWindowsHlp, HELP_WM_HELP, (ULONG_PTR) aDMPropHelpIds); } return FALSE; }
BOOL DmAdvPropPage_OnInitDialog( HWND ParentHwnd, HWND FocusHwnd, LPARAM Lparam ) { HWND hwndTree; POUR_PROP_PARAMS Params; HCURSOR hCursor; BOOL bSuccess;
// on WM_INITDIALOG call, lParam points to the property sheet page.
//
// The lParam field in the property sheet page struct is set by the
// caller. When I created the property sheet, I passed in a pointer
// to a struct containing information about the device. Save this in
// the user window long so I can access it on later messages.
Params = (POUR_PROP_PARAMS) ((LPPROPSHEETPAGE)Lparam)->lParam; SetWindowLongPtr(ParentHwnd, DWLP_USER, (ULONG_PTR) Params);
// Put up the wait cursor
hCursor = SetCursor(LoadCursor(NULL,IDC_WAIT));
//create the device tree.
hwndTree = GetDlgItem(ParentHwnd, IDC_ADV_TREE);
// Initialize the tree
bSuccess = DmInitDeviceTree(hwndTree, Params);
// Enable the adv properties button
EnableWindow(GetDlgItem(ParentHwnd, ID_ADV_PROP), TRUE);
// Tear down the wait cursor
SetCursor(hCursor);
return bSuccess; }
BOOL DmAdvPropPage_OnNotify( HWND ParentHwnd, LPNMHDR NmHdr ) { POUR_PROP_PARAMS Params = (POUR_PROP_PARAMS) GetWindowLongPtr(ParentHwnd, DWLP_USER);
switch (NmHdr->code) { case PSN_APPLY: // Sent when the user clicks on Apply OR OK !!
SetWindowLongPtr(ParentHwnd, DWLP_MSGRESULT, (LONG_PTR)PSNRET_NOERROR); return TRUE;
case TVN_SELCHANGED: //Don't bother if we are closing. This helps avoid irritating
//redraw problems as destroy causes several of these messages to be sent.
if (!Params->bClosing) { LPNM_TREEVIEW lpnmtv; TV_ITEM tvi; PDMTREE_NODE pTreeNode; BOOL fEnablePropButton; HWND hwndProp;
lpnmtv = (LPNM_TREEVIEW)NmHdr; tvi = lpnmtv->itemNew; pTreeNode = (PDMTREE_NODE)tvi.lParam; fEnablePropButton = pTreeNode->pfnQueryConfig(ParentHwnd, pTreeNode);
//override the enabling for driver entries
if ((pTreeNode->NodeType == NodeTypeDriver) && (pTreeNode->dc != dcINVALID)) { fEnablePropButton = TRUE; }
// Enable or disable the Properties button depending upon
// whether this driver can be configured
hwndProp = GetDlgItem(ParentHwnd, ID_ADV_PROP); EnableWindow(hwndProp, fEnablePropButton); } break;
case NM_DBLCLK: //show properties on a double-click
if (NmHdr->idFrom == (DWORD)IDC_ADV_TREE) { HWND hwndTree; TV_HITTESTINFO tvht;
hwndTree = GetDlgItem(ParentHwnd, IDC_ADV_TREE);
// Find out which tree item the cursor is on and call properties on it
GetCursorPos(&tvht.pt); ScreenToClient(hwndTree, &tvht.pt); TreeView_HitTest(hwndTree, &tvht); if (tvht.flags & TVHT_ONITEM) { DoProperties(ParentHwnd, hwndTree, tvht.hItem); } } break;
#if 0 // stolen from Win98, not integrated yet
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 TVN_ITEMEXPANDING: { TV_ITEM tvi; HWND hwndTree = GetDlgItem(hDlg,IDC_ADV_TREE);
tvi = lpnmtv->itemNew; tvi.mask = TVIF_PARAM; if (!TreeView_GetItem(hwndTree, &tvi)) break;
if (!tvi.lParam || IsBadReadPtr((LPVOID)tvi.lParam, 2)) { DPF("****TVN_ITEMEXPANDING: lParam = 0 || BadReadPtr***\r\n"); break; } if (*((short *)(tvi.lParam)) == 1) { //re-enum ACM codecs on expand because their states could have been programmatically changed.
PCLASSNODE pcn = (PCLASSNODE)(tvi.lParam);
if (lpnmtv->action == TVE_EXPAND && !lstrcmpi(pcn->szClass, ACM)) { if (gfLoadedACM) ACMNodeChange(hDlg); } } else if (!tvi.lParam && lpnmtv->action == TVE_COLLAPSE) { //dont let the root collapse.
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)TRUE); return TRUE; } break; }
case TVN_BEGINLABELEDIT: //we don't want to allow editing of label unless the user explicitly wants it by
//clicking context menu item
if (!gfEditLabel) SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)TRUE); return TRUE;
case TVN_ENDLABELEDIT: { HWND hwndTree; LPSTR pszFriendlyName = ((TV_DISPINFO *) lpnm)->item.pszText; TV_ITEM item; HTREEITEM hti; PIRESOURCE pIResource; char szWarn[128]; char ach[MAXSTR];
//user has chosen a new friendly name. COnfirm with the user and put it in the
//registry. ALso unhook KB hook which was used to track Esc and Return
if (gfnKBHook) { UnhookWindowsHookEx(gfnKBHook); gfnKBHook = NULL; } if (!pszFriendlyName) return FALSE; hwndTree = GetDlgItem(hDlg, IDC_ADV_TREE); hti = TreeView_GetSelection(hwndTree); item.hItem = hti; item.mask = TVIF_PARAM; TreeView_GetItem(hwndTree, &item);
LoadString(ghInstance, IDS_FRIENDLYWARNING, szWarn, sizeof(szWarn)); wsprintf(ach, szWarn, pszFriendlyName); LoadString(ghInstance, IDS_FRIENDLYNAME, szWarn, sizeof(szWarn)); if (mmse_MessageBox(hDlg, ach, szWarn, MMSE_YESNO) == MMSE_NO) { SetFocus(hwndTree); return FALSE; } if (*((short *)(item.lParam)) == 2) { pIResource = (PIRESOURCE)item.lParam; lstrcpy(pIResource->szFriendlyName, pszFriendlyName); SaveDevFriendlyName(pIResource); } else { PINSTRUMENT pInstr = (PINSTRUMENT)item.lParam; lstrcpy(pInstr->szFriendlyName, pszFriendlyName); SaveInstrFriendlyName(pInstr); } SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LPARAM)(LRESULT)TRUE); return TRUE; } case NM_RCLICK: //popup context menu.
TreeContextMenu(hDlg, GetDlgItem(hDlg, IDC_ADV_TREE)); return TRUE;
#endif
default: return FALSE; }
return FALSE; }
void DoProperties(HWND ParentHwnd, HWND hWndI, HTREEITEM htiCur) { TV_ITEM tvi; PDMTREE_NODE pTreeNode; BOOL bRestart;
// Get item struct attached to selected node
tvi.mask = TVIF_PARAM; tvi.hItem = htiCur; if (TreeView_GetItem (hWndI, &tvi)) { // Get my private data structure from item struct
pTreeNode = (PDMTREE_NODE)tvi.lParam;
if (pTreeNode->NodeType != NodeTypeDriver) { if (!pTreeNode->pfnQueryConfig(ParentHwnd, pTreeNode)) { return; } }
// Call config and get back whether restart needed
pTreeNode->hti = htiCur; //this allows us to work with the legacy MIDI setup code
bRestart = pTreeNode->pfnConfig(ParentHwnd, pTreeNode);
if (bRestart) { PropSheet_Changed(GetParent(ParentHwnd), ParentHwnd); } }
return; }
void DmAdvPropPage_OnPropertiesClicked( HWND ParentHwnd, POUR_PROP_PARAMS Params ) { HWND hWndI; HTREEITEM htiCur;
// Get handle to treeview control
hWndI = GetDlgItem(ParentHwnd, IDC_ADV_TREE);
// Get handle to currently selected node
htiCur = TreeView_GetSelection (hWndI);
if (htiCur != NULL) { DoProperties(ParentHwnd, hWndI, htiCur); }
return; }
INT_PTR APIENTRY DmResourcesPageDlgProc(IN HWND hDlg, IN UINT uMessage, IN WPARAM wParam, IN LPARAM lParam) { return FALSE; } /* DmAdvPropPageDlgProc */
INT_PTR CALLBACK CDDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL AddCDROMPropertyPage( HDEVINFO hDeviceInfoSet, PSP_DEVINFO_DATA pDeviceInfoData, LPFNADDPROPSHEETPAGE AddFunc, LPARAM Lparam ) { BOOL fHandled = FALSE;
if (IsEqualGUID(&pDeviceInfoData->ClassGuid,&GUID_DEVCLASS_CDROM)) { PROPSHEETPAGE psp; HPROPSHEETPAGE hpsp; PALLDEVINFO padi;
padi = GlobalAllocPtr(GHND, sizeof(ALLDEVINFO));
if (!padi) return FALSE;
padi->hDevInfo = hDeviceInfoSet; padi->pDevInfoData = pDeviceInfoData;
// Add our own page for DLG_DM_LEGACY_RESOURCES
// Initialize the property sheet page
psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = 0; psp.hInstance = ghInstance; psp.pszTemplate = MAKEINTRESOURCE(DM_CDDLG); psp.pfnDlgProc = CDDlg; // dlg window proc
psp.lParam = (LPARAM) padi; psp.pfnCallback = 0; // control callback of the dlg window proc
// Create the page & get back a handle
hpsp = CreatePropertySheetPage(&psp); if (!hpsp) { fHandled = TRUE; } else if (!(*AddFunc)(hpsp, Lparam)) { GlobalFreePtr(padi); DestroyPropertySheetPage(hpsp); fHandled = FALSE; } }
return(fHandled); }
INT_PTR CALLBACK AdvDlg(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL AddSpecialPropertyPage( DWORD SpecialDriverType, LPFNADDPROPSHEETPAGE AddFunc, LPARAM Lparam ) { PROPSHEETPAGE psp; HPROPSHEETPAGE hpsp;
// Add our own page for DLG_DM_LEGACY_RESOURCES
// Initialize the property sheet page
psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = 0; psp.hInstance = ghInstance; psp.pszTemplate = MAKEINTRESOURCE(DM_ADVDLG); psp.pfnDlgProc = AdvDlg; // dlg window proc
psp.lParam = (LPARAM)SpecialDriverType; psp.pfnCallback = 0; // control callback of the dlg window proc
// Create the page & get back a handle
hpsp = CreatePropertySheetPage(&psp); if (!hpsp) { return FALSE; }
// Add the property page
if (!(*AddFunc)(hpsp, Lparam)) { DestroyPropertySheetPage(hpsp); return FALSE; }
return TRUE; }
BOOL DmOverrideResourcesPage(LPVOID Info, LPFNADDPROPSHEETPAGE AddFunc, LPARAM Lparam, POUR_PROP_PARAMS Params ) { HKEY hkDrv; HDEVINFO DeviceInfoSet; PSP_DEVINFO_DATA DeviceInfoData; SP_DEVINSTALL_PARAMS DeviceInstallParams; PROPSHEETPAGE psp; HPROPSHEETPAGE hpsp;
TCHAR szDriverType[16]; DWORD cbLen;
hkDrv = Params->hkDrv; DeviceInfoSet = Params->DeviceInfoSet; DeviceInfoData = Params->DeviceInfoData;
// Query value of DriverType field to decide if this is a WDM driver
cbLen = sizeof(szDriverType); if (!RegQueryValueEx(hkDrv, TEXT("DriverType"), NULL, NULL, (LPBYTE)szDriverType, &cbLen)) { if ( lstrcmpi(szDriverType,TEXT("Legacy")) || lstrcmpi(szDriverType,TEXT("PNPISA")) ) { // This is a PNPISA or Legacy device. Override resource page.
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS); SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams); DeviceInstallParams.Flags |= DI_RESOURCEPAGE_ADDED; SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
// Add our own page for DLG_DM_LEGACY_RESOURCES
// Initialize the property sheet page
psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = 0; psp.hInstance = ghInstance; psp.pszTemplate = MAKEINTRESOURCE(DLG_DM_LEGACY_RESOURCES); psp.pfnDlgProc = DmResourcesPageDlgProc; // dlg window proc
psp.lParam = (LPARAM)0; psp.pfnCallback = 0; // control callback of the dlg window proc
// Create the page & get back a handle
hpsp = CreatePropertySheetPage(&psp); if (!hpsp) { return FALSE; }
// Add the property page
if (!(*AddFunc)(hpsp, Lparam)) { DestroyPropertySheetPage(hpsp); return FALSE; }
} }
return TRUE; }
/*
*************************************************************** * BOOL DmInitDeviceTree * * This function calls commctrl to create the image list and tree and * the opens the registry, reads each class and loads all devices under * the class by calling ReadNodes. For ACM however it uses ACM * APIs (this enumeration code is in msacmcpl.c) *************************************************************** */ BOOL DmInitDeviceTree(HWND hwndTree, POUR_PROP_PARAMS Params) { TV_INSERTSTRUCT ti;
HDEVINFO DeviceInfoSet; PSP_DEVINFO_DATA DeviceInfoData;
TCHAR *strtok_State; // strtok state
TCHAR *pszClass; // Information about e.g. classguid\0000\Drivers\wave
HKEY hkClass;
DWORD idxR3DriverName; // Information about e.g. classguid\0000\Drivers\wave\foo.drv
HKEY hkR3DriverName; TCHAR szR3DriverName[64];
DWORD cbLen;
PDMTREE_NODE pTreeNode;
SUBTYPE_INFO *pSubtypeInfo;
HTREEITEM htiRoot; HTREEITEM htiClass; HTREEITEM htiDriver;
// Load up all the class descriptions and icons
LoadSubtypeInfo(hwndTree);
// Clear out the tree
SendMessage(hwndTree, WM_SETREDRAW, FALSE, 0L);
// Allocate my private data structure for this class
pTreeNode = (PDMTREE_NODE)LocalAlloc(LPTR, sizeof(DMTREE_NODE)); if (!pTreeNode) { return FALSE; }
pSubtypeInfo = GetSubtypeInfo(NULL);
pTreeNode->NodeType = NodeTypeRoot; pTreeNode->pfnConfig = pSubtypeInfo->pfnConfig; pTreeNode->pfnQueryConfig = pSubtypeInfo->pfnQueryConfig;
// Insert root entry
ti.hParent = TVI_ROOT; ti.hInsertAfter = TVI_LAST; ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; ti.item.iImage = ti.item.iSelectedImage = pSubtypeInfo->IconIndex; ti.item.pszText = pSubtypeInfo->szDescription; ti.item.lParam = (LPARAM)pTreeNode; htiRoot = NULL; //TreeView_InsertItem(hwndTree, &ti);
// Enumerate all the subclasses
for ( pszClass = mystrtok(Params->szSubClasses,NULL,&strtok_State); pszClass; pszClass = mystrtok(NULL,NULL,&strtok_State) ) {
// Get an ID for this class
pSubtypeInfo = GetSubtypeInfo(pszClass);
// Open up each subclass
if (RegOpenKey(Params->hkDrivers, pszClass, &hkClass)) { continue; }
// Allocate my private data structure for this class
pTreeNode = (PDMTREE_NODE)LocalAlloc(LPTR, sizeof(DMTREE_NODE)); if (!pTreeNode) { RegCloseKey(hkClass); continue; }
pTreeNode->NodeType = NodeTypeClass; pTreeNode->pfnConfig = pSubtypeInfo->pfnConfig; pTreeNode->pfnQueryConfig = pSubtypeInfo->pfnQueryConfig;
// Initialize tree insert struct
ti.hParent = htiRoot; ti.hInsertAfter = TVI_LAST; ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; ti.item.iImage = ti.item.iSelectedImage = pSubtypeInfo->IconIndex; ti.item.pszText = pSubtypeInfo->szDescription; ti.item.lParam = (LPARAM)pTreeNode;
// Insert Class entry into tree
htiClass = TreeView_InsertItem(hwndTree, &ti);
// Under each class is a set of driver name subkeys.
// For each driver (e.g. foo1.drv, foo2.drv, etc.)
for (idxR3DriverName = 0; !RegEnumKey(hkClass, idxR3DriverName, szR3DriverName, sizeof(szR3DriverName)/sizeof(TCHAR)); idxR3DriverName++) {
// Open the key to the driver name
if (RegOpenKey(hkClass, szR3DriverName, &hkR3DriverName)) { continue; }
// Create the branch for this subclass
pTreeNode = (PDMTREE_NODE)LocalAlloc(LPTR, sizeof(DMTREE_NODE)); pTreeNode->NodeType = NodeTypeDriver; pTreeNode->pfnConfig = pSubtypeInfo->pfnConfig; pTreeNode->pfnQueryConfig = pSubtypeInfo->pfnQueryConfig; pTreeNode->dc = pSubtypeInfo->dc;
// Get driver name
cbLen = sizeof(pTreeNode->szDriver); RegQueryValueEx(hkR3DriverName, TEXT("Driver"), NULL, NULL, (LPBYTE)pTreeNode->szDriver, &cbLen); wcscpy(pTreeNode->wszDriver, pTreeNode->szDriver);
// Get driver description
cbLen = sizeof(pTreeNode->szDescription); RegQueryValueEx(hkR3DriverName, TEXT("Description"), NULL, NULL, (LPBYTE)pTreeNode->szDescription, &cbLen);
// Get driver alias
cbLen = sizeof(pTreeNode->szAlias); RegQueryValueEx(hkR3DriverName, TEXT("Alias"), NULL, NULL, (LPBYTE)pTreeNode->szAlias, &cbLen); wcscpy(pTreeNode->wszAlias, pTreeNode->szAlias);
// Insert Class entry
ti.hParent = htiClass; ti.hInsertAfter = TVI_LAST; ti.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; ti.item.iImage = ti.item.iSelectedImage = pSubtypeInfo->IconIndex; ti.item.pszText = pTreeNode->szDescription; ti.item.lParam = (LPARAM)pTreeNode;
htiDriver = TreeView_InsertItem(hwndTree, &ti);
// Close the Driver Name key
RegCloseKey(hkR3DriverName); } // Close the class key
RegCloseKey(hkClass); }
// Open up the tree and display
TreeView_Expand(hwndTree, htiRoot, TVE_EXPAND); SendMessage(hwndTree, WM_SETREDRAW, TRUE, 0L);
return TRUE; }
// Free up the tree
void DmFreeAdvDlgTree (HWND hTree, HTREEITEM hti) { HTREEITEM htiChild; TV_ITEM tvi;
// Delete all children by calling myself recursively
while ((htiChild = TreeView_GetChild(hTree, hti)) != NULL) { DmFreeAdvDlgTree(hTree, htiChild); }
if (hti!=TVI_ROOT) { // Delete my attached data structures
tvi.mask = TVIF_PARAM; tvi.hItem = hti; tvi.lParam = 0; TreeView_GetItem(hTree, &tvi); if (tvi.lParam != 0) LocalFree ((HANDLE)tvi.lParam);
// Delete myself
TreeView_DeleteItem (hTree, hti); }
return; }
BOOL DmAdvPropPage_OnDestroy( HWND ParentHwnd, LPNMHDR NmHdr ) { HWND hTree; HIMAGELIST hImageList; POUR_PROP_PARAMS Params = (POUR_PROP_PARAMS) GetWindowLongPtr(ParentHwnd, DWLP_USER);
if (Params) { Params->bClosing = TRUE; // Remember that we're now closing
}
// Get handle to treeview control
hTree = GetDlgItem(ParentHwnd, IDC_ADV_TREE);
// Free all the entries on the control
DmFreeAdvDlgTree(hTree,TVI_ROOT);
// Free up the image list attached to the control
hImageList = TreeView_GetImageList(hTree, TVSIL_NORMAL); if (hImageList) { TreeView_SetImageList(hTree, NULL, TVSIL_NORMAL); ImageList_Destroy (hImageList); }
return FALSE; }
|