windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/dimapcfg/dmtcfg.cpp
2020-09-26 16:20:57 +08:00

3159 lines
92 KiB
C++

//===========================================================================
// dmtcfg.cpp
//
// File / code creation functionality
//
// Functions:
// dmtcfgCreatePropertySheet
// dmtcfgDlgProc
// dmtcfgOnInitDialog
// dmtcfgOnClose
// dmtcfgOnCommand
// dmtcfgOnNotify
// dmtcfgCreateGenreList
// dmtcfgFreeGenreList
// dmtcfgCreateSubGenreList
// dmtcfgFreeSubGenreList
// dmtcfgCreateActionList
// dmtcfgFreeActionList
//
// History:
// 08/20/1999 - davidkl - created
//===========================================================================
#include "dimaptst.h"
#include "dmtinput.h"
//#include "dmtwrite.h"
#include "dmtcfg.h"
//---------------------------------------------------------------------------
//===========================================================================
// dmtcfgCreatePropertySheet
//
// Create property sheet dialog for device action map configuration
//
// Parameters:
// HINSTANCE hinst - app instance handle
// HWND hwndParent - parent window handle
// LPSTR szSelectedGenre
// DMTGENRE_NODE* pGenreList
// DMTGENRE_NODE* pDeviceNode
// BOOL fStartWithDefaults
//
// Returns: HRESULT
//
// History:
// 08/23/1999 - davidkl - created
// 09/08/1999 - davidkl - changed param list
//===========================================================================
HRESULT dmtcfgCreatePropertySheet(HINSTANCE hinst,
HWND hwndParent,
LPSTR szSelectedGenre,
DMTGENRE_NODE *pGenreList,
DMTDEVICE_NODE *pDeviceNode,
BOOL fStartWithDefaults)
{
HRESULT hRes = S_OK;
UINT u = 0;
UINT uSel = 0;
DMTGENRE_NODE *pNode = NULL;
PROPSHEETPAGEA *pPages = NULL;
PROPSHEETHEADERA psh;
char szCaption[MAX_PATH];
DMT_APPINFO *pdmtai = NULL;
DMTDEVICE_NODE dmtd;
// validate pGenreList
if(IsBadReadPtr((void*)pGenreList, sizeof(DMTGENRE_NODE)))
{
DPF(0, "dmtcfgCreatePropertySheet - invalid pGenreList (%016Xh)",
pGenreList);
return E_POINTER;
}
// validate pDeviceNode
if(IsBadReadPtr((void*)pDeviceNode, sizeof(DMTDEVICE_NODE)))
{
DPF(0, "dmtcfgCreatePropertySheet - invalid pDeviceNode (%016Xh)",
pDeviceNode);
return E_POINTER;
}
__try
{
// count the genres
//
// find the node we care about
u = 0;
pNode = pGenreList;
while(pNode)
{
// if we find our genre, start on that page
if(!lstrcmpiA(szSelectedGenre, pNode->szName))
{
uSel = u;
}
// increment the number of genres
u++;
pNode = pNode->pNext;
}
// allocate the page array (dw pages)
pPages = (PROPSHEETPAGEA*)LocalAlloc(LMEM_FIXED,
sizeof(PROPSHEETPAGEA) * u);
if(!pPages)
{
DPF(0, "dmtcfgCreatePropertySheet - insufficient mempory to "
"allocate pPages array");
hRes = E_OUTOFMEMORY;
__leave;
}
// add device name to caption
wsprintfA(szCaption,
"Configure Device Action Map - %s",
pDeviceNode->szName);
// strip the next ptr from the selected device node
CopyMemory((void*)&dmtd, (void*)pDeviceNode, sizeof(DMTDEVICE_NODE));
dmtd.pNext = NULL;
// allocate app info data struct for pages
pdmtai = (DMT_APPINFO*)LocalAlloc(LMEM_FIXED,
u * sizeof(DMT_APPINFO));
if(!pdmtai)
{
hRes = E_OUTOFMEMORY;
__leave;
}
ZeroMemory((void*)pdmtai, u * sizeof(DMT_APPINFO));
// prepare property sheet header
psh.dwSize = sizeof(PROPSHEETHEADERA);
psh.dwFlags = PSH_PROPSHEETPAGE |
PSP_USETITLE | PSH_NOAPPLYNOW;
psh.hwndParent = hwndParent;
psh.hInstance = hinst;
psh.pszCaption = szCaption;
psh.nPages = u;
psh.nStartPage = uSel;
psh.ppsp = pPages;
// describe sheets
pNode = pGenreList;
for(u = 0; u < (DWORD)(psh.nPages); u++)
{
if(!pNode)
{
DPF(0, "dmtcfgCreatePropertySheet - we messed up! "
"we allocated less than %d pages",
psh.nPages);
DPF(0, "PLEASE find someone to look at this NOW");
hRes = E_UNEXPECTED;
DebugBreak();
__leave;
}
// populate the app info for the page
(pdmtai + u)->pGenreList = pNode;
(pdmtai + u)->pDeviceList = &dmtd;
(pdmtai + u)->fStartWithDefaults = fStartWithDefaults;
(pdmtai + u)->fLaunchCplEditMode = FALSE;
// populate the page array entry
ZeroMemory((void*)(pPages + u), sizeof(PROPSHEETPAGEA));
(pPages + u)->dwSize = sizeof(PROPSHEETPAGEA);
(pPages + u)->dwFlags = PSP_USETITLE;
(pPages + u)->hInstance = hinst;
(pPages + u)->pszTemplate = MAKEINTRESOURCEA(IDD_CONFIGURE_MAPPING_PAGE);
(pPages + u)->pfnDlgProc = (DLGPROC)dmtcfgDlgProc;
(pPages + u)->pszTitle = pNode->szName;
(pPages + u)->lParam = (LPARAM)(pdmtai + u);
// next node
pNode = pNode->pNext;
}
// create this thing
if(0 > PropertySheetA(&psh))
{
DPF(0, "dmtcfgCreatePropertySheet - dialog creation failed (%08Xh)",
GetLastError());
hRes = E_UNEXPECTED;
__leave;
}
}
__finally
{
// free the app info array
if(pdmtai)
{
if(LocalFree((HLOCAL)pdmtai))
{
DPF(0, "dmtcfgCreaatePropertySheet - !!!MEMORY LEAK!!! "
"LocalFree(pdmtai) failed (%08X)",
GetLastError());
hRes = S_FALSE;
}
pdmtai = NULL;
}
// free the page array
if(pPages)
{
if(LocalFree((HLOCAL)pPages))
{
DPF(0, "dmtcfgCreaatePropertySheet - !!!MEMORY LEAK!!! "
"LocalFree(pPages) failed (%08X)",
GetLastError());
hRes = S_FALSE;
}
pPages = NULL;
}
}
// done
return hRes;
} //*** end dmtcfgCreatePropertySheet()
//===========================================================================
// dmtcfgDlgProc
//
// Configure Device Action Map dialog processing function
//
// Parameters: (see SDK help for parameter details)
// HWND hwnd
// UINT uMsg
// WPARAM wparam
// LPARAM lparam
//
// Returns: (see SDK help for return value details)
// BOOL
//
// History:
// 08/20/1999 - davidkl - created
//===========================================================================
BOOL CALLBACK dmtcfgDlgProc(HWND hwnd,
UINT uMsg,
WPARAM wparam,
LPARAM lparam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return dmtcfgOnInitDialog(hwnd,
(HWND)wparam,
lparam);
case WM_COMMAND:
return dmtcfgOnCommand(hwnd,
LOWORD(wparam),
(HWND)lparam,
HIWORD(wparam));
case WM_NOTIFY:
return dmtcfgOnNotify(hwnd,
(PSHNOTIFY *)lparam);
case WM_DMT_UPDATE_LISTS:
return dmtcfgOnUpdateLists(hwnd);
}
return FALSE;
} //*** end dmtcfgDlgProc()
//===========================================================================
// dmtcfgOnInitDialog
//
// Handle WM_INITDIALOG processing for the config device box
//
// Parameters:
// HWND hwnd - handle to property page
// HWND hwndFocus - handle of ctrl with focus
// LPARAM lparam - user data (in this case, PROPSHEETPAGE*)
//
// Returns: BOOL
//
// History:
// 08/20/1999 - davidkl - created
//===========================================================================
BOOL dmtcfgOnInitDialog(HWND hwnd,
HWND hwndFocus,
LPARAM lparam)
{
HRESULT hRes = S_OK;
PROPSHEETPAGEA *ppsp = (PROPSHEETPAGEA*)lparam;
DMTGENRE_NODE *pGenre = NULL;
DMTSUBGENRE_NODE *pSubNode = NULL;
DMTMAPPING_NODE *pMapNode = NULL;
//LONG lPrev = 0L;
//JJ 64Bit Compat
LONG_PTR lPrev = 0;
// int nIdx = 0;
LONG_PTR nIdx = 0;
DMTDEVICE_NODE *pDevice = NULL;
DMT_APPINFO *pdmtai = NULL;
UINT u = 0;
WORD wTypeCtrl = 0;
DIACTIONFORMATA diaf;
DPF(5, "dmtcfgOnInitDialog");
// validate ppsp (lparam)
if(IsBadWritePtr((void*)ppsp, sizeof(PROPSHEETPAGEA)))
{
DPF(0, "dmtcfgOnInitDialog - invalid lParam (%016Xh)",
ppsp);
return FALSE;
}
// pdmtai == ppsp->lParam
pdmtai = (DMT_APPINFO*)(ppsp->lParam);
// validate pdmtai
if(IsBadWritePtr((void*)pdmtai, sizeof(DMT_APPINFO)))
{
DPF(0, "dmtcfgOnInitDialog - invalid ppsp.ptp (%016Xh)",
pdmtai);
return FALSE;
}
// pGenre == pdmtai->pGenreList
pGenre = pdmtai->pGenreList;
// valdiate pGenre
if(IsBadWritePtr((void*)pGenre, sizeof(DMTGENRE_NODE)))
{
DPF(0, "dmtcfgOnInitDialog - invalid pGenre (%016Xh)",
pGenre);
return FALSE;
}
// pDevice == pdmtai->pDeviceList
pDevice = pdmtai->pDeviceList;
// valdiate pGenre
if(IsBadWritePtr((void*)pDevice, sizeof(DMTDEVICE_NODE)))
{
DPF(0, "dmtcfgOnInitDialog - invalid pDevice (%016Xh)",
pDevice);
return FALSE;
}
// change the property sheet dialog button text
// Ok -> Save
SetWindowTextA(GetDlgItem(GetParent(hwnd), IDOK),
"&Save");
// Apply -> Load
//SetWindowTextA(GetDlgItem(GetParent(hwnd), IDC_PS_APPLY),
// "Load");
// Cancel -> Close
SetWindowTextA(GetDlgItem(GetParent(hwnd), IDCANCEL),
"&Close");
__try
{
// store the app info in the property page's user data
SetLastError(0);
//lPrev = SetWindowLong(hwnd,
// GWL_USERDATA,
// (LONG)pdmtai);
//JJ 64Bit Compat
lPrev = SetWindowLongPtr(hwnd,
GWLP_USERDATA,
(LONG_PTR)pdmtai);
if(!lPrev && GetLastError())
{
// serious app problem.
// we need to stop things right here and now
DPF(0, "dmtcfgOnInitDialog - This is bad... "
"We failed to store pdmtai");
DPF(0, "dmtcfgOnInitDialog - Please find someone "
"to look at this right away");
DebugBreak();
hRes = E_FAIL;
__leave;
}
// walk the list and populate the subgenre list box
//
// store the ptr to the subgenre node in the listbox
// entry user data
pSubNode = pGenre->pSubGenreList;
while(pSubNode)
{
// add the subgenre name to the list
nIdx = SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRE),
CB_ADDSTRING,
0,
(LPARAM)(pSubNode->szName));
// store the subgenre node in the list entry
SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRE),
CB_SETITEMDATA,
nIdx,
(LPARAM)pSubNode);
// if the user has requested default mappings
// get them for the specified device
if(pdmtai->fStartWithDefaults)
{
// walk the mappings list until the selected
// device is found
pMapNode = pSubNode->pMappingList;
while(pMapNode)
{
// try to match on guidInstance
if(IsEqualGUID(pDevice->guidInstance,
pMapNode->guidInstance))
{
// match found
break;
}
// next mapping
pMapNode = pMapNode->pNext;
}
if(pMapNode)
{
ZeroMemory((void*)&diaf, sizeof(DIACTIONFORMATA));
diaf.dwSize = sizeof(DIACTIONFORMATA);
diaf.dwActionSize = sizeof(DIACTIONA);
diaf.dwNumActions = (DWORD)(pMapNode->uActions);
diaf.rgoAction = pMapNode->pdia;
diaf.dwDataSize = 4 * diaf.dwNumActions;
diaf.guidActionMap = GUID_DIMapTst;
diaf.dwGenre = pSubNode->dwGenreId;
diaf.dwBufferSize = DMTINPUT_BUFFERSIZE;
lstrcpyA(diaf.tszActionMap, DMT_APP_CAPTION);
// get the default mappings
hRes = (pDevice->pdid)->BuildActionMap(&diaf,
(LPCSTR)NULL,
DIDBAM_HWDEFAULTS);
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
}
else
{
// ISSUE-2001/03/29-timgill needs error handling
}
}
// next subgenre
pSubNode = pSubNode->pNext;
}
// set the subgenre list selection
SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRE),
CB_SETCURSEL,
0,
0);
// selectively disable axis/button/pov radio buttons
//
// this is done if the selected device does not
// actually have one of these objects
//
// since axes are our "prefered" initial display
// option, check them last
if(dmtinputDeviceHasObject(pDevice->pObjectList,
DMTA_TYPE_POV))
{
EnableWindow(GetDlgItem(hwnd, IDC_TYPE_POV), TRUE);
wTypeCtrl = IDC_TYPE_POV;
}
if(dmtinputDeviceHasObject(pDevice->pObjectList,
DMTA_TYPE_BUTTON))
{
EnableWindow(GetDlgItem(hwnd, IDC_TYPE_BUTTON), TRUE);
wTypeCtrl = IDC_TYPE_BUTTON;
}
if(dmtinputDeviceHasObject(pDevice->pObjectList,
DMTA_TYPE_AXIS))
{
EnableWindow(GetDlgItem(hwnd, IDC_TYPE_AXIS), TRUE);
wTypeCtrl = IDC_TYPE_AXIS;
}
// select the axes radio button
if(0 == wTypeCtrl)
{
// we have a "device" that has no objects...
//
// this is very bad
DebugBreak();
return TRUE;
}
CheckRadioButton(hwnd,
IDC_TYPE_POV,
IDC_TYPE_AXIS,
wTypeCtrl);
// for the default subgenre, walk the list and populate
// the actions list box
//
// store the ptr to the actions node in the listbox
// entry user data
pSubNode = (DMTSUBGENRE_NODE*)SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRE),
CB_GETITEMDATA,
0,
0L);
// update the lists
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
// select the first entry in each list
SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_SETCURSEL,
0,
0L);
SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_SETCURSEL,
0,
0L);
// display the subgenre description
SetDlgItemTextA(hwnd,
IDC_DESCRIPTION,
pSubNode->szDescription);
// make sure the map/unmap buttons are enabled correctly
SendMessageA(hwnd,
WM_COMMAND,
IDC_CONTROLS,
0L);
}
__finally
{
// if failure case, clean house
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
}
// done
return TRUE;
} //*** end dmtcfgOnInitDialog()
//===========================================================================
// dmtcfgOnCommand
//
// Handle WM_COMMAND processing for the config device box
//
// Parameters:
// HWND hwnd - handle to property page
// WORD wId - control identifier (LOWORD(wparam))
// HWND hwndCtrl - handle to control ((HWND)lparam)
// WORD wNotifyCode - notification code (HIWORD(wparam))
//
// Returns: BOOL
//
// History:
// 08/20/1999 - davidkl - created
//===========================================================================
BOOL dmtcfgOnCommand(HWND hwnd,
WORD wId,
HWND hwndCtrl,
WORD wNotifyCode)
{
HRESULT hRes = S_OK;
// UINT uSel = 0;
//JJ 64Bit Compat
UINT_PTR uSel = 0;
UINT uActions = 0;
BOOL fEnable = FALSE;
DMT_APPINFO *pdmtai = NULL;
DMTSUBGENRE_NODE *pSubGenre = NULL;
DMTMAPPING_NODE *pMapping = NULL;
DIACTIONA *pdia = NULL;
DPF(5, "dmtcfgOnCommand");
// get the window data
//pdmtai = (DMT_APPINFO*)GetWindowLong(hwnd, GWL_USERDATA);
//JJ 64Bit Compat
pdmtai = (DMT_APPINFO*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(!pdmtai)
{
// big problem
//
// this should NEVER happen
// ISSUE-2001/03/29-timgill Needs error case handling
}
// what is the currently selected subgenre?
uSel = SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRE),
CB_GETCURSEL,
0,
0L);
pSubGenre = (DMTSUBGENRE_NODE*)SendMessageA(GetDlgItem(hwnd,
IDC_SUBGENRE),
CB_GETITEMDATA,
uSel,
0L);
if(!pSubGenre)
{
// big problem
//
// this should NEVER happen
// ISSUE-2001/03/29-timgill Needs error case handling
}
// get the active DIACTION array
pMapping = pSubGenre->pMappingList;
while(pMapping)
{
// match pdmtai->pDeviceList->guidInstance with
// pMapping->guidInstance
if(IsEqualGUID(pdmtai->pDeviceList->guidInstance,
pMapping->guidInstance))
{
break;
}
// next mapping
pMapping = pMapping->pNext;
}
if(pMapping)
{
pdia = pMapping->pdia;
uActions = pMapping->uActions;
}
// update genre description
SetDlgItemTextA(hwnd,
IDC_DESCRIPTION,
pSubGenre->szDescription);
switch(wId)
{
case IDC_SUBGENRE:
// based on the selected subgenre
//
// display the objects/actions for the selected type
// (see type IDs below)
if(CBN_SELCHANGE == wNotifyCode)
{
// update the lists
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
}
break;
case IDC_TYPE_AXIS:
case IDC_TYPE_BUTTON:
case IDC_TYPE_POV:
// update the lists
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
// make sure the unmap button is selected as appropriate
SendMessageA(hwnd,
WM_COMMAND,
IDC_CONTROLS,
0L);
break;
case IDC_CONTROLS:
// if a mapped action is selected
// enable the "Unmap action" button
fEnable = dmtcfgIsControlMapped(hwnd,
pdia,
uActions);
EnableWindow(GetDlgItem(hwnd, IDC_UNMAP),
fEnable);
// do NOT enable the map button if there are no
// more actions
if(!SendMessage(GetDlgItem(hwnd, IDC_ACTIONS),
LB_GETCOUNT,
0, 0L))
{
EnableWindow(GetDlgItem(hwnd, IDC_STORE_MAPPING),
FALSE);
}
else
{
EnableWindow(GetDlgItem(hwnd, IDC_STORE_MAPPING),
!fEnable);
}
// if >any< controls are mapped
// enable the "Unmap all" button
fEnable = dmtcfgAreAnyControlsMapped(hwnd,
pdia,
uActions);
EnableWindow(GetDlgItem(hwnd, IDC_UNMAP_ALL),
fEnable);
break;
case IDC_STORE_MAPPING: // "Map action"
// map it
hRes = dmtcfgMapAction(hwnd,
pdmtai->pDeviceList->guidInstance,
pdia,
uActions);
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
// set the changed flag
pMapping->fChanged = TRUE;
break;
case IDC_UNMAP: // "Unmap action"
// unmap it
hRes = dmtcfgUnmapAction(hwnd,
pdia,
uActions);
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
// set the changed flag
pMapping->fChanged = TRUE;
break;
case IDC_UNMAP_ALL: // "Unmap all"
hRes = dmtcfgUnmapAllActions(hwnd,
pdia,
uActions);
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
// set the changed flag
pMapping->fChanged = TRUE;
break;
}
// done
return FALSE;
} //*** end dmtcfgOnCommand()
//===========================================================================
// dmtcfgOnNotify
//
// Handle WM_NOTIFY processing for the config device box
//
// Parameters:
// HWND hwnd - handle to property page
// PSHNOTIFY *ppsh - PSHNOTIFY ptr
//
// Returns: BOOL
//
// History:
// 08/20/1999 - davidkl - created
// 10/14/1999 - davidkl - implemented save calls
//===========================================================================
BOOL dmtcfgOnNotify(HWND hwnd,
PSHNOTIFY *pNotify)
{
//int n = 0;
//JJ 64Bit Compat
INT_PTR n = 0;
BOOL fSave = FALSE;
DMT_APPINFO *pdmtai = NULL;
// 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
DPF(5, "dmtcfgOnNotify: hwnd == %Ph", hwnd);
// get the window data
//pdmtai = (DMT_APPINFO*)GetWindowLong(hwnd, GWL_USERDATA);
//JJ 64Bit Compat
pdmtai = (DMT_APPINFO*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(!pdmtai)
{
// bad news
// ISSUE-2001/03/29-timgill Needs error case handling
}
switch(pNotify->hdr.code)
{
case PSN_SETACTIVE:
DPF(5, "PSN_SETACTIVE");
// force the apply button to be enabled
SendMessageA(GetParent(hwnd),
PSM_CHANGED,
(WPARAM)hwnd,
0L);
break;
case PSN_KILLACTIVE:
DPF(5, "PSN_KILLACTIVE");
// make sure we get a PSN_APPLY message
//SetWindowLong(hwnd, DWL_MSGRESULT, (LONG)FALSE);
SetWindowLong(hwnd, DWLP_MSGRESULT, (LONG)FALSE);
break;
case PSN_APPLY:
DPF(5, "PSN_APPLY - %s",
(pNotify->lParam) ? "Ok" : "Apply");
// save/load mapping data
//
// OK == Save
// Apply == Load
// which button was clicked?
if(pNotify->lParam)
{
// save mapping data
SendMessage(hwnd,
WM_DMT_FILE_SAVE,
0,0L);
}
else
{
// load mapping data
// ISSUE-2001/03/29-timgill Load Mapping Data not yet implemented
MessageBoxA(hwnd, "Load - Not Yet Implemented",
pdmtai->pDeviceList->szName,
MB_OK);
}
// DO NOT allow the dialog to close
//SetWindowLong(hwnd,
// DWL_MSGRESULT,
// (LONG)PSNRET_INVALID_NOCHANGEPAGE);
//JJ 64Bit Compat
SetWindowLongPtr(hwnd,
DWLP_MSGRESULT,
(LONG_PTR)PSNRET_INVALID_NOCHANGEPAGE);
break;
}
// done
return TRUE;
} //*** end dmtcfgOnNotify()
//===========================================================================
// dmtcfgOnUpdateLists
//
// Handle WM_DMT_UPDATE_LISTS message
//
// Parameters:
//
// Returns: BOOL
//
// History:
// 08/25/1999 - davidkl - created
// 11/12/1999 - dvaidkl - fixed problem with control selection setting
//===========================================================================
BOOL dmtcfgOnUpdateLists(HWND hwnd)
{
//int nIdx = -1;
//int nSelCtrl = -1;
//JJ 64Bit Compat
INT_PTR nSelCtrl = -1;
INT_PTR nIdx = -1;
int n = 0;
INT_PTR nControls = 0;
INT_PTR nActions = 0;
//int nControls = 0;
//int nActions = 0;
DWORD dwType = DMTA_TYPE_UNKNOWN;
DWORD dwObjType = DMTA_TYPE_UNKNOWN;
DMTSUBGENRE_NODE *pSubGenre = NULL;
DMTACTION_NODE *pAction = NULL;
DMTMAPPING_NODE *pMapping = NULL;
DMTDEVICEOBJECT_NODE *pObjectList = NULL;
DMTDEVICEOBJECT_NODE *pObjectNode = NULL;
DMT_APPINFO *pdmtai = NULL;
DIACTION *pdia = NULL;
BOOL fFound = FALSE;
char szBuf[MAX_PATH];
DPF(5, "dmtcfgOnUpdateLists");
// get the window data
//pdmtai = (DMT_APPINFO*)GetWindowLong(hwnd, GWL_USERDATA);
//JJ 64Bit Compat
pdmtai = (DMT_APPINFO*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(!pdmtai)
{
// bad news
// ISSUE-2001/03/29-timgill Needs error case handling
}
// device object list
pObjectList = pdmtai->pDeviceList->pObjectList;
// get the currently selected control
nSelCtrl = SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_GETCURSEL,
0,
0L);
// clear the list box contents
// actions
SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_RESETCONTENT,
0,
0L);
// controls
SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_RESETCONTENT,
0,
0L);
// get the current selection
nIdx = SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRE),
CB_GETCURSEL,
0,
0L);
// get the item data
pSubGenre = (DMTSUBGENRE_NODE*)SendMessageA(GetDlgItem(hwnd,
IDC_SUBGENRE),
CB_GETITEMDATA,
nIdx,
0L);
// get the DIACTION array specific to the current device
pMapping = pSubGenre->pMappingList;
while(pMapping)
{
// match pdmtai->pDeviceList->guidInstance
// with pMapping->guidInstance
if(IsEqualGUID(pdmtai->pDeviceList->guidInstance,
pMapping->guidInstance))
{
break;
}
// next mapping
pMapping = pMapping->pNext;
}
if(!pMapping)
{
// this is very bad and should NEVER happen
// ISSUE-2001/03/29-timgill Needs error case handling
DebugBreak();
}
pdia = pMapping->pdia;
nActions = (int)pMapping->uActions;
// what control type is selected?
dwType = IDC_TYPE_AXIS - (dmtGetCheckedRadioButton(hwnd,
IDC_TYPE_POV,
IDC_TYPE_AXIS));
// populate the action list
nIdx = 0;
pAction = pSubGenre->pActionList;
while(pAction)
{
// filter to the selected control type
if(dwType == pAction->dwType)
{
// filter actions that are already assigned
// first, find a matching action in the array
fFound = FALSE;
for(n = 0; n < nActions; n++)
{
// match based on the semantic / action id
if((pdia+n)->dwSemantic == pAction->dwActionId)
{
DPF(2, "dmtcfgOnUpdateLists- found matching action "
"pAction->dwActionId (%08Xh) == "
"(pdia+u)->dwSemantic (%08Xh)",
pAction->dwActionId,
(pdia+n)->dwSemantic);
fFound = TRUE;
break;
}
}
// next, read the action array entry,
// if GUID_NULL == guidInstance, add the entry
if(!fFound ||
IsEqualGUID(GUID_NULL, (pdia+n)->guidInstance))
{
// prepend the action priority
wsprintfA(szBuf, "(Pri%d) %s",
pAction->dwPriority,
pAction->szName);
// add the action name
nIdx = SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_ADDSTRING,
0,
(LPARAM)szBuf);
// add the item data (action node)
SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_SETITEMDATA,
nIdx,
(LPARAM)pAction);
} //* assigned action filter
} //* control type filter
// next action
pAction = pAction->pNext;
}
// populate the control list
nIdx = 0;
pObjectNode = pObjectList;
while(pObjectNode)
{
// convert dinput's DIDFT to our
// internal control type
if(FAILED(dmtinputXlatDIDFTtoInternalType(pObjectNode->dwObjectType,
&dwObjType)))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
DPF(3, "dmtcfgOnUpdateLists - %s : DIDFT type %08Xh, internal type %d",
pObjectNode->szName,
pObjectNode->dwObjectType,
dwObjType);
// filter on control type
//
// dwType populated above
if(dwType == dwObjType)
{
// check to if mapped
//
// we do this by scanning the DIACTION array, looking
// for actions that contain our device's guidInstance
// and our object's offset
// if so, put the mapping info in ()
wsprintfA(szBuf, "%s",
pObjectNode->szName);
for(n = 0; n < nActions; n++)
{
if(IsEqualGUID((pdia+n)->guidInstance,
pdmtai->pDeviceList->guidInstance) &&
((pdia+n)->dwObjID ==
pObjectNode->dwObjectType))
{
wsprintfA(szBuf, "%s (%s)",
pObjectNode->szName,
(pdia+n)->lptszActionName);
break;
}
}
// add the control name
nIdx = SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_ADDSTRING,
0,
(LPARAM)szBuf);
// add the item data (object node)
SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_SETITEMDATA,
nIdx,
(LPARAM)pObjectNode);
} //* control type filter
// next control
pObjectNode = pObjectNode->pNext;
}
// count the number of entries in each list
nControls = SendMessage(GetDlgItem(hwnd, IDC_CONTROLS),
LB_GETCOUNT,
0,
0L);
nActions = SendMessage(GetDlgItem(hwnd, IDC_ACTIONS),
LB_GETCOUNT,
0,
0L);
// set the selected entry in each list
//
// only do this if there are entries in the lists
if(nControls)
{
if(nSelCtrl > nControls)
{
nSelCtrl = 0;
}
SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_SETCURSEL,
nSelCtrl,
0L);
}
if(nActions)
{
SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_SETCURSEL,
0,
0L);
}
// if there are no controls or no actions
//
// disable the map button
if(!nControls || !nActions)
{
EnableWindow(GetDlgItem(hwnd, IDC_STORE_MAPPING), FALSE);
}
// done
return FALSE;
} //*** end dmtcfgOnUpdateLists()
//===========================================================================
// dmtcfgSourceDlgProc
//
// Configure Device Mapping Source Code dialog processing function
//
// Parameters: (see SDK help for parameter details)
// HWND hwnd
// UINT uMsg
// WPARAM wparam
// LPARAM lparam
//
// Returns: (see SDK help for return value details)
// BOOL
//
// History:
// 08/31/1999 - davidkl - created
//===========================================================================
BOOL CALLBACK dmtcfgSourceDlgProc(HWND hwnd,
UINT uMsg,
WPARAM wparam,
LPARAM lparam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return dmtcfgSourceOnInitDialog(hwnd,
(HWND)wparam,
lparam);
case WM_COMMAND:
return dmtcfgSourceOnCommand(hwnd,
LOWORD(wparam),
(HWND)lparam,
HIWORD(wparam));
case WM_DMT_UPDATE_LISTS:
return dmtcfgSourceOnUpdateLists(hwnd);
}
return FALSE;
} //*** end dmtcfgSourceDlgProc()
//===========================================================================
// dmtcfgSourceOnInitDialog
//
// Handle WM_INITDIALOG processing for the config source box
//
// Parameters:
// HWND hwnd - handle to property page
// HWND hwndFocus - handle of ctrl with focus
// LPARAM lparam - user data (in this case, PROPSHEETPAGE*)
//
// Returns: BOOL
//
// History:
// 08/31/1999 - davidkl - created
// 10/07/1999 - davidkl - reworked code to match UI change
//===========================================================================
BOOL dmtcfgSourceOnInitDialog(HWND hwnd,
HWND hwndFocus,
LPARAM lparam)
{
DMTSUBGENRE_NODE *pSubGenre = (DMTSUBGENRE_NODE*)lparam;
//LONG lPrev = 0L;
//JJ 64Bit Compat
LONG_PTR lPrev = 0;
int nIdx = 0;
char szBuf[MAX_PATH];
DPF(5, "dmtcfgSourceOnInitDialog");
// validate pSubGenre (lparam)
if(IsBadWritePtr((void*)pSubGenre, sizeof(DMTSUBGENRE_NODE)))
{
DPF(0, "dmtcfgOnInitDialog - invalid ppsp.ptp (%016Xh)",
pSubGenre);
return FALSE;
}
// set the window caption to include the subgenre name
wsprintfA(szBuf, "Configure Device Mapping Source Code - %s",
pSubGenre->szName);
SetWindowTextA(hwnd, szBuf);
// store the subgenre node in the window's user data
SetLastError(0);
//lPrev = SetWindowLong(hwnd,
// GWL_USERDATA,
// (LONG)pSubGenre);
//JJ 64Bit Compat
lPrev = SetWindowLongPtr(hwnd,
GWLP_USERDATA,
(LONG_PTR)pSubGenre);
if(!lPrev && GetLastError())
{
// serious app problem.
// we need to stop things right here and now
DPF(0, "dmtcfgSourceOnInitDialog - This is bad... "
"We failed to store pSubGenre");
DPF(0, "dmtcfgSourceOnInitDialog - Please find someone "
"to look at this right away");
DebugBreak();
return FALSE;
}
// populate the subgenre edit box
SetWindowTextA(GetDlgItem(hwnd, IDC_SUBGENRE),
pSubGenre->szName);
// display the subgenre description
SetWindowTextA(GetDlgItem(hwnd, IDC_DESCRIPTION),
pSubGenre->szDescription);
// select the axes radio button
CheckRadioButton(hwnd,
IDC_TYPE_POV,
IDC_TYPE_AXIS,
IDC_TYPE_AXIS);
// populate the actions list box
//
// store the ptr to the actions node in the listbox
// entry user data
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
// done
return TRUE;
} //*** end dmtcfgSourceOnInitDialog()
//===========================================================================
// dmtcfgSourceOnCommand
//
// Handle WM_COMMAND processing for the config source box
//
// Parameters:
// HWND hwnd - handle to property page
// WORD wId - control identifier (LOWORD(wparam))
// HWND hwndCtrl - handle to control ((HWND)lparam)
// WORD wNotifyCode - notification code (HIWORD(wparam))
//
// Returns: BOOL
//
// History:
// 08/31/1999 - davidkl - created
//===========================================================================
BOOL dmtcfgSourceOnCommand(HWND hwnd,
WORD wId,
HWND hwndCtrl,
WORD wNotifyCode)
{
DMTGENRE_NODE *pGenre = NULL;
DPF(5, "dmtcfgOnCommand");
// get the genre from the window's user data
// ISSUE-2001/03/29-timgill config source box fails to handle many UI messages
// IDC_ADD_ACTION, IDC_REMOVE_ACTION, IDC_RENAME_ACTION, IDC_CUSTOM_ACTION all do nothing
// IDOK/IDCANCEL merely do default processing
switch(wId)
{
case IDOK:
EndDialog(hwnd, 0);
break;
case IDCANCEL:
EndDialog(hwnd, -1);
break;
case IDC_SUBGENRE:
// based on the selected subgenre
//
// display the objects/actions for the selected type
// (see type IDs below)
if(CBN_SELCHANGE == wNotifyCode)
{
// update the lists
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
}
break;
case IDC_TYPE_AXIS:
case IDC_TYPE_BUTTON:
case IDC_TYPE_POV:
// update the lists
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
break;
case IDC_ADD_ACTION:
break;
case IDC_REMOVE_ACTION:
break;
case IDC_RENAME_ACTION:
break;
case IDC_CUSTOM_ACTION:
break;
}
// done
return FALSE;
} //*** end dmtcfgSourceOnCommand()
//===========================================================================
// dmtcfgSourceOnUpdateLists
//
// Handle WM_DMT_UPDATE_LISTS message
//
// Parameters:
//
// Returns: BOOL
//
// History:
// 08/31/1999 - davidkl - created
// 10/07/1999 - davidkl - modified to match UI change
//===========================================================================
BOOL dmtcfgSourceOnUpdateLists(HWND hwnd)
{
//int nIdx = -1;
//JJ 64Bit Compat
INT_PTR nIdx = -1;
DWORD dwType = 0x0badbad0;
DMTSUBGENRE_NODE *pSubGenre = NULL;
DMTACTION_NODE *pAction = NULL;
char szBuf[MAX_PATH];
// get the subgenre node from the window's user data
//pSubGenre = (DMTSUBGENRE_NODE*)GetWindowLong(hwnd,
// GWL_USERDATA);
//JJ 64Bit Compat
pSubGenre = (DMTSUBGENRE_NODE*)GetWindowLongPtr(hwnd,
GWLP_USERDATA);
if(!pSubGenre)
{
// this is very bad
// ISSUE-2001/03/29-timgill Needs error case handling
DebugBreak();
return TRUE;
}
// clear the list box contents
SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_RESETCONTENT,
0,
0L);
// what control type is selected?
dwType = IDC_TYPE_AXIS - (dmtGetCheckedRadioButton(hwnd,
IDC_TYPE_POV,
IDC_TYPE_AXIS));
// populate the action list
pAction = pSubGenre->pActionList;
while(pAction)
{
// filter to the selected control type
if(dwType == pAction->dwType)
{
// filter actions that are already selected
/*
if(DMT_ACTION_NOTASSIGNED == pAction->dwDevObj)
{
*/
// if the priority is NOT 1, append that info to the name string
//
// ISSUE-2001/03/29-timgill Should the priority 1 mapping display colour be different (eg. red)?
// Do game developers CARE about action priorities?
/*
if(1 < pAction->dwPriority)
{
wsprintfA(szBuf, "(Pri%d) %s",
pAction->dwPriority,
pAction->szName);
}
else
{
*/
lstrcpyA(szBuf, pAction->szName);
// }
// add the action name
nIdx = SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_ADDSTRING,
0,
(LPARAM)szBuf);
// add the extra data (action node)
SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_SETITEMDATA,
nIdx,
(LPARAM)&(pAction));
/*
} //* assigned action filter
*/
} // control type filter
// next action
pAction = pAction->pNext;
}
// done
return FALSE;
} //*** end dmtcfgSourceOnUpdateLists()
//===========================================================================
// dmtcfgCreateGenreList
//
// Reads genres.ini and creates the genre list used to populate the
// Configure Device Action Map property sheet dialog. Returns the number of
// parent genres (NOT subgenres) found
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 08/23/1999 - davidkl - created
// 09/28/1999 - davidkl - modified to match new ini format
//===========================================================================
HRESULT dmtcfgCreateGenreList(DMTGENRE_NODE **ppdmtgList)
{
HRESULT hRes = S_OK;
UINT u = 0;
BOOL fFound = FALSE;
DMTGENRE_NODE *pCurrent = NULL;
DMTGENRE_NODE *pNew = NULL;
DMTGENRE_NODE *pHold = NULL;
char szItem[64];
char szBuf[MAX_PATH];
char szGroup[MAX_PATH];
// validate ppmdtgList
if(IsBadWritePtr((void*)ppdmtgList, sizeof(DMTGENRE_NODE*)))
{
DPF(0, "dmtcfgCreateGenreList - invalid ppdmtgList (%016Xh)",
ppdmtgList);
return E_POINTER;
}
// check to make sure we are not being asked
// to append to an existing list
//
// callers MUST pass a NULL list
if(*ppdmtgList)
{
DPF(0, "dmtcfgCreateGenreList - ppdmtgList points to "
"existing list! (%016Xh)", *ppdmtgList);
return E_INVALIDARG;
}
__try
{
// get the genre names from genres.ini
pCurrent = *ppdmtgList;
lstrcpyA(szBuf, "");
u = 0;
while(lstrcmpA("<<>>", szBuf))
{
// get the name of the genre
wsprintfA(szItem, "%d", u);
GetPrivateProfileStringA(szItem,
"N",
"<<>>",
szBuf,
MAX_PATH,
GENRES_INI);
if(!lstrcmpA("<<>>", szBuf))
{
DPF(3, "end of genre list");
continue;
}
DPF(3, "Genre name == %s", szBuf);
// extract the group name
hRes = dmtcfgGetGenreGroupName(szBuf,
szGroup);
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
// walk the list
//
// make sure we did not get a duplicate name
fFound = FALSE;
pHold = pCurrent;
pCurrent = *ppdmtgList;
while(pCurrent)
{
if(!lstrcmpiA(pCurrent->szName,
szGroup))
{
// match found
fFound = TRUE;
break;
}
// next node
pCurrent = pCurrent->pNext;
}
if(!fFound)
{
// no match, allocate a new node
// allocate the genre node
pNew = (DMTGENRE_NODE*)LocalAlloc(LMEM_FIXED,
sizeof(DMTGENRE_NODE));
if(!pNew)
{
DPF(0, "dmtcfgCreateGenreList - insufficient memory to "
"allocate genre list node");
hRes = E_OUTOFMEMORY;
__leave;
}
// initialize the new node
ZeroMemory((void*)pNew, sizeof(DMTGENRE_NODE));
// set the name field
lstrcpyA(pNew->szName, szGroup);
// get the list of subgenres
hRes = dmtcfgCreateSubGenreList(pNew->szName,
&(pNew->pSubGenreList));
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
// add it to the end of the list
pCurrent = pHold;
if(pCurrent)
{
// append the list
pCurrent->pNext = pNew;
// go to the next node
pCurrent = pCurrent->pNext;
}
else
{
// new list head
pCurrent = pNew;
*ppdmtgList = pCurrent;
}
}
// next genre
u++;
}
}
__finally
{
if(FAILED(hRes))
{
// cleanup allocations
DPF(1, "dmtcfgCreateGenreList - Failure occurred, "
"freeing genre list");
dmtcfgFreeGenreList(ppdmtgList);
*ppdmtgList = NULL;
}
}
// done
return hRes;
} //*** end dmtcfgCreateGenreList()
//===========================================================================
// dmtcfgFreeGenreList
//
// Frees the linked list (and sub-lists) created by dmtcfgCreateGenreList
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 08/23/1999 - davidkl - created
//===========================================================================
HRESULT dmtcfgFreeGenreList(DMTGENRE_NODE **ppdmtgList)
{
HRESULT hRes = S_OK;
DMTGENRE_NODE *pNode = NULL;
// validate ppdmtgList
if(IsBadWritePtr((void*)ppdmtgList, sizeof(PDMTGENRE_NODE)))
{
DPF(0, "dmtcfgFreeGenreList - Invalid ppdmtgList (%016Xh)",
ppdmtgList);
return E_POINTER;
}
// validate *ppdmtgList
if(IsBadReadPtr((void*)*ppdmtgList, sizeof(DMTGENRE_NODE)))
{
if(NULL != *ppdmtgList)
{
DPF(0, "dmtcfgFreeGenreList - Invalid *ppdmtgList (%016Xh)",
*ppdmtgList);
return E_POINTER;
}
else
{
// if NULL, then return "did nothing"
DPF(3, "dmtcfgFreeGenreList - Nothing to do....");
return S_FALSE;
}
}
// walk the list and free each object
while(*ppdmtgList)
{
pNode = *ppdmtgList;
*ppdmtgList = (*ppdmtgList)->pNext;
// first, free the action list
DPF(5, "dmtcfgFreeGenreList - "
"freeing subgenre list (%016Xh)",
pNode->pSubGenreList);
hRes = dmtcfgFreeSubGenreList(&(pNode->pSubGenreList));
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
DPF(5, "dmtcfgFreeGenreList - Deleting Node (%016Xh)", pNode);
if(LocalFree((HLOCAL)pNode))
{
DPF(0, "dmtcfgFreeSubGenreList - MEMORY LEAK - "
"LocalFree() failed (%d)...",
GetLastError());
hRes = DMT_S_MEMORYLEAK;
}
DPF(5, "dmtcfgFreeGenreList - Node deleted");
}
// make sure that we set *ppdmtgList to NULL
*ppdmtgList = NULL;
// done
return hRes;
} //*** end dmtcfgFreeGenreList()
//===========================================================================
// dmtcfgCreateSubGenreList
//
// Reads genres.ini and creates the subgenre list used to populate the
// Configure Device Action Map property sheet dialog.
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 08/24/1999 - davidkl - created
// 09/29/1999 - davidkl - modified to match new ini format
//===========================================================================
HRESULT dmtcfgCreateSubGenreList(LPSTR szGenre,
DMTSUBGENRE_NODE **ppdmtsgList)
{
HRESULT hRes = S_OK;
UINT u = 0;
DMTSUBGENRE_NODE *pCurrent = NULL;
DMTSUBGENRE_NODE *pNew = NULL;
char szItem[64];
char szGroup[MAX_PATH];
char szBuf[MAX_PATH];
// validate ppmdtsgList
if(IsBadWritePtr((void*)ppdmtsgList, sizeof(DMTSUBGENRE_NODE*)))
{
return E_POINTER;
}
// check to make sure we are not being asked
// to append to an existing list
//
// callers MUST pass a NULL list
if(*ppdmtsgList)
{
return E_INVALIDARG;
}
__try
{
// get the subgenre names from genres.ini
pCurrent = *ppdmtsgList;
lstrcpyA(szBuf, "");
u = 0;
while(lstrcmpA("<<>>", szBuf))
{
// look for subgenres belonging to szGenre
wsprintfA(szItem, "%d", u);
GetPrivateProfileStringA(szItem,
"N",
"<<>>",
szBuf,
MAX_PATH,
GENRES_INI);
if(!lstrcmpA("<<>>", szBuf))
{
DPF(3, "end of subgenre list");
continue;
}
hRes = dmtcfgGetGenreGroupName(szBuf,
szGroup);
if(FAILED(hRes))
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
// if we do not belong to the genre group
//
// make believe we found nothing
if(lstrcmpiA(szGenre, szGroup))
{
u++;
DPF(4, "bucket mismatch... skipping");
continue;
}
// we fit in the szGenre bucket
//
// allocate the genre node
pNew = (DMTSUBGENRE_NODE*)LocalAlloc(LMEM_FIXED,
sizeof(DMTSUBGENRE_NODE));
if(!pNew)
{
hRes = E_OUTOFMEMORY;
__leave;
}
// initialize the new node
ZeroMemory((void*)pNew, sizeof(DMTSUBGENRE_NODE));
// get the genreid
pNew->dwGenreId = GetPrivateProfileInt(szItem,
"AI0",
0,
GENRES_INI);
pNew->dwGenreId &= DMT_GENRE_MASK;
DPF(4, "SubGenre ID == %08Xh", pNew->dwGenreId);
// get the "name" (Txt1)
GetPrivateProfileStringA(szItem,
"T1",
"<<>>",
pNew->szName,
MAX_PATH,
GENRES_INI);
DPF(3, "SubGenre name == %s", pNew->szName);
// get the description (Txt2)
GetPrivateProfileStringA(szItem,
"T2",
"<<>>",
pNew->szDescription,
MAX_PATH,
GENRES_INI);
DPF(4, "SubGenre description == %s", pNew->szDescription);
// get the list of actions
hRes = dmtcfgCreateActionList(szItem,
&(pNew->pActionList));
if(FAILED(hRes) || DMT_S_MEMORYLEAK == hRes)
{
// ISSUE-2001/03/29-timgill Needs error case handling
}
// add it to the end of the list
if(pCurrent)
{
// append the list
pCurrent->pNext = pNew;
// go to the next node
pCurrent = pCurrent->pNext;
}
else
{
// new list head
pCurrent = pNew;
*ppdmtsgList = pCurrent;
}
// next subgenre
u++;
}
}
__finally
{
// cleanup in failure case
if(FAILED(hRes))
{
DPF(1, "dmtcfgCreateSubGenreList - Failure occurred, "
"freeing subgenre list");
dmtcfgFreeSubGenreList(ppdmtsgList);
*ppdmtsgList = NULL;
}
}
//JJ_FIX
g_NumSubGenres = u;
// done
return S_OK;
} //*** end dmtcfgCreateSubGenreList()
//===========================================================================
// dmtcfgFreeSubGenreList
//
// Frees the linked list created by dmtcfgCreateSubGenreList
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 08/24/1999 - davidkl - created
// 08/25/1999 - davidkl - implemented
//===========================================================================
HRESULT dmtcfgFreeSubGenreList(DMTSUBGENRE_NODE **ppdmtsgList)
{
HRESULT hRes = S_OK;
DMTSUBGENRE_NODE *pNode = NULL;
// validate ppdmtaList
if(IsBadWritePtr((void*)ppdmtsgList, sizeof(PDMTSUBGENRE_NODE)))
{
DPF(0, "dmtcfgFreeSubGenreList - Invalid ppdmtsgList (%016Xh)",
ppdmtsgList);
return E_POINTER;
}
// validate *ppPortList
if(IsBadReadPtr((void*)*ppdmtsgList, sizeof(DMTSUBGENRE_NODE)))
{
if(NULL != *ppdmtsgList)
{
DPF(0, "dmtcfgFreeSubGenreList - Invalid *ppdmtsgList (%016Xh)",
*ppdmtsgList);
return E_POINTER;
}
else
{
// if NULL, then return "did nothing"
DPF(3, "dmtcfgFreeSubGenreList - Nothing to do....");
return S_FALSE;
}
}
// walk the list and free each object
while(*ppdmtsgList)
{
pNode = *ppdmtsgList;
*ppdmtsgList = (*ppdmtsgList)->pNext;
// first, free the action list
DPF(5, "dmtcfgFreeSubGenreList - "
"freeing action list (%016Xh)",
pNode->pActionList);
hRes = dmtcfgFreeActionList(&(pNode->pActionList));
if(FAILED(hRes))
{
hRes = DMT_S_MEMORYLEAK;
}
// then free the mapping list array
if(pNode->pMappingList)
{
hRes = dmtcfgFreeMappingList(&(pNode->pMappingList));
if(FAILED(hRes) || DMT_S_MEMORYLEAK == hRes)
{
hRes = DMT_S_MEMORYLEAK;
}
pNode->pMappingList = NULL;
}
// finally, free the node
DPF(5, "dmtcfgFreeSubGenreList - Deleting Node (%016Xh)", pNode);
if(LocalFree((HLOCAL)pNode))
{
DPF(0, "dmtcfgFreeSubGenreList - MEMORY LEAK - "
"LocalFree(Node) failed (%d)...",
GetLastError());
hRes = DMT_S_MEMORYLEAK;
}
DPF(5, "dmtcfgFreeSubGenreList - Node deleted");
}
// make sure that we set *ppdmtsgList to NULL
*ppdmtsgList = NULL;
// done
return hRes;
} //*** end dmtcfgFreeSubGenreList()
//===========================================================================
// dmtcfgCreateActionList
//
// Reads genres.ini and creates the action list used to populate the
// Configure Device Action Map property sheet dialog.
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 08/24/1999 - davidkl - created
// 09/07/1999 - davidkl - added DIACTION**
// 09/28/1999 - davidkl - updated to use info extraction macros
// 02/14/2000 - davidkl - started conversion to GetPrivateProfileSectionA
//===========================================================================
HRESULT dmtcfgCreateActionList(LPSTR szGenreSubgenre,
DMTACTION_NODE **ppdmtaList)
{
HRESULT hRes = S_OK;
UINT u = 0;
BYTE bTypeMask = 0x03;
DMTACTION_NODE *pCurrent = NULL;
DMTACTION_NODE *pNew = NULL;
char szItem[MAX_PATH];
char szBuf[MAX_PATH];
// validate ppmdtsgList
if(IsBadWritePtr((void*)ppdmtaList, sizeof(DMTACTION_NODE*)))
{
DPF(0, "dmtcfgCreateActionList - invalid ppdmtaList (%016Xh)",
ppdmtaList);
return E_POINTER;
}
// check to make sure we are not being asked
// to append to an existing list
//
// callers MUST pass a NULL list
if(*ppdmtaList)
{
DPF(0, "dmtcfgCreateActionList - ppdmtaList points to "
"existing list! (%016Xh)", *ppdmtaList);
return E_INVALIDARG;
}
__try
{
// get the action info from genres.ini
pCurrent = *ppdmtaList;
#ifdef BNW
char *pszSection = NULL;
char *pCurrent = NULL;
int nAlloc = 0;
// allocate space for the (Win9x) max size of an ini section
nAlloc = 32727;
pszSection = (char*)LocalAlloc(LMEM_FIXED,
sizeof(char) * nAlloc);
if(!pszSection)
{
// alloc failed,
// try ~1/2 of the max (that should still cover the
// fill size of the section)
nAlloc = 16386;
pszSection = (char*)LocalAlloc(LMEM_FIXED,
sizeof(char) * nAlloc);
if(!pszSection)
{
// alloc failed,
// try ~1/4 of the max (that should still cover the
// fill size of the section)
nAlloc = 8192;
pszSection = (char*)LocalAlloc(LMEM_FIXED,
sizeof(char) * nAlloc);
if(!pszSection)
{
// alloc failed,
// try ~1/8 of the max (that should still cover the
// fill size of the section)
nAlloc = 4096;
pszSection = (char*)LocalAlloc(LMEM_FIXED,
sizeof(char) * nAlloc);
if(!pszSection)
{
// alloc failed,
// try ~1/16 of the max (that should still cover the
// fill size of the section) - this is our last attempt
nAlloc = 2048;
pszSection = (char*)LocalAlloc(LMEM_FIXED,
sizeof(char) * nAlloc);
if(!pszSection)
{
// alloc failed, we give up
__leave;
}
}
}
}
}
DPF(2, "dmtcfgCreateActionList - section allocation: %d bytes", nAlloc);
// read the section specified by szGenreSubgenre
GetPrivateProfileSectionA(szGenreSubgenre,
pszSection,
nAlloc,
GENRES_INI);
/* the following code fragment does nothing - u is incremented and then never used again
// parse the action information from the section
for(u = 0; ; u++)
{
break;
}
*/
#else
lstrcpyA(szBuf, "");
u = 0;
while(lstrcmpA("<<>>", szBuf))
{
// add the name of the action to the node
wsprintfA(szItem, "AN%d", u);
GetPrivateProfileStringA(szGenreSubgenre,
szItem,
"<<>>",
szBuf,
MAX_PATH,
GENRES_INI);
if(!lstrcmpA("<<>>", szBuf))
{
DPF(3, "end of action list");
continue;
}
DPF(3, "Action name == %s", szBuf);
// allocate the genre node
pNew = (DMTACTION_NODE*)LocalAlloc(LMEM_FIXED,
sizeof(DMTACTION_NODE));
if(!pNew)
{
hRes = E_OUTOFMEMORY;
__leave;
}
// initialize the new node
ZeroMemory((void*)pNew, sizeof(DMTACTION_NODE));
lstrcpyA(pNew->szName, szBuf);
// get the action id
wsprintfA(szItem, "AI%d", u);
pNew->dwActionId = GetPrivateProfileIntA(szGenreSubgenre,
szItem,
0x0badbad0,
GENRES_INI);
DPF(4, "Action ID == %08Xh", pNew->dwActionId);
// get the action priority
pNew->dwPriority = dmtinputGetActionPri(pNew->dwActionId);
DPF(4, "Action priority == %d", pNew->dwPriority);
// get action type
pNew->dwType = dmtinputGetActionObjectType(pNew->dwActionId);
DPF(4, "Action type == %d", pNew->dwType);
// get the action type name
wsprintfA(szItem, "AIN%d", u);
GetPrivateProfileStringA(szGenreSubgenre,
szItem,
"<<>>",
pNew->szActionId,
MAX_ACTION_ID_STRING,
GENRES_INI);
DPF(4, "Action ID name == %s", pNew->szActionId);
// add it to the end of the list
if(pCurrent)
{
// append the list
pCurrent->pNext = pNew;
// go to the next node
pCurrent = pCurrent->pNext;
}
else
{
// new list head
pCurrent = pNew;
*ppdmtaList = pCurrent;
}
// net action
u++;
}
#endif // BNW
}
__finally
{
#ifdef BNW
// free the section memory we allocated
if(LocalFree((HLOCAL)pszSection))
{
// memory leak
DPF(0, "dmtcfgCreateActionList - !! MEMORY LEAK !! - LocalFree(section) failed");
}
#endif // BNW
// cleanup in failure case
if(FAILED(hRes))
{
// free action list
DPF(1, "dmtcfgCreateActionList - Failure occurred, "
"freeing action list");
dmtcfgFreeActionList(ppdmtaList);
*ppdmtaList = NULL;
}
}
// done
return S_OK;
} //*** end dmtCreateActionList()
//===========================================================================
// dmtcfgFreeActionList
//
// Frees the linked list created by dmtcfgCreateActionList
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 08/24/1999 - davidkl - created
// 08/25/1999 - davidkl - implemented
//===========================================================================
HRESULT dmtcfgFreeActionList(DMTACTION_NODE **ppdmtaList)
{
HRESULT hRes = S_OK;
DMTACTION_NODE *pNode = NULL;
// validate ppdmtaList
if(IsBadWritePtr((void*)ppdmtaList, sizeof(PDMTACTION_NODE)))
{
DPF(0, "dmtcfgFreeActionList - Invalid ppdmtaList (%016Xh)",
ppdmtaList);
return E_POINTER;
}
// validate *ppdmtaList
if(IsBadReadPtr((void*)*ppdmtaList, sizeof(DMTACTION_NODE)))
{
if(NULL != *ppdmtaList)
{
DPF(0, "dmtcfgFreeActionList - Invalid *ppdmtaList (%016Xh)",
*ppdmtaList);
return E_POINTER;
}
else
{
// if NULL, then return "did nothing"
DPF(3, "dmtcfgFreeActionList - Nothing to do....");
return S_FALSE;
}
}
// walk the list and free each object
while(*ppdmtaList)
{
pNode = *ppdmtaList;
*ppdmtaList = (*ppdmtaList)->pNext;
// free the node
DPF(5, "dmtcfgFreeActionList - deleting Node (%016Xh)", pNode);
if(LocalFree((HLOCAL)pNode))
{
DPF(0, "dmtcfgFreeActionList - MEMORY LEAK - "
"LocalFree(Node) failed (%d)...",
GetLastError());
hRes = DMT_S_MEMORYLEAK;
}
DPF(5, "dmtcfgFreeActionList - Node deleted");
}
// make sure that we set *ppObjList to NULL
*ppdmtaList = NULL;
// done
return hRes;
} //*** end dmtcfgFreeActionList()
//===========================================================================
// dmtcfgCreateMappingList
//
// Creates a device mapping list
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 09/23/1999 - davidkl - created
//===========================================================================
HRESULT dmtcfgCreateMappingList(DMTDEVICE_NODE *pDeviceList,
DMTACTION_NODE *pActions,
DMTMAPPING_NODE **ppdmtmList)
{
HRESULT hRes = S_OK;
UINT uActions = NULL;
DMTACTION_NODE *pActionNode = NULL;
DMTMAPPING_NODE *pNew = NULL;
DMTMAPPING_NODE *pCurrent = NULL;
DMTDEVICE_NODE *pDeviceNode = NULL;
// validate pDeviceList
if(IsBadReadPtr((void*)pDeviceList, sizeof(DMTDEVICE_NODE)))
{
DPF(0, "dmtcfgCreateMappingList - invalid pDeviceList (%016Xh)",
pDeviceList);
return E_POINTER;
}
// validate pActions
if(IsBadReadPtr((void*)pActions, sizeof(DMTACTION_NODE)))
{
if(NULL != pActions)
{
DPF(0, "dmtcfgCreateMappingList - invalid pActions (%016Xh)",
pActions);
return E_POINTER;
}
else
{
// no actions for this subgenre
DPF(3, "dmtcfgCreateMappingList - No actions for this subgenre, "
"nothing to do...");
return S_FALSE;
}
}
// validate ppdmtmList
if(IsBadWritePtr((void*)ppdmtmList, sizeof(DMTMAPPING_NODE)))
{
DPF(0, "dmtcfgCreateMappingList - invalid ppdmtmList (%016Xh)",
ppdmtmList);
return E_POINTER;
}
// check to make sure we are not being asked
// to append to an existing list
//
// callers MUST pass a NULL list
if(*ppdmtmList)
{
DPF(0, "dmtcfgCreateMappingList - ppdmtmList points to "
"existing list! (%016Xh)", *ppdmtmList);
return E_INVALIDARG;
}
__try
{
// count the actions
//
// this lets us know how much space to allocate for the
uActions = 0;
pActionNode = pActions;
while(pActionNode)
{
uActions++;
// next node
pActionNode = pActionNode->pNext;
}
// for each device
pDeviceNode = pDeviceList;
while(pDeviceNode)
{
// allocate the mapping node
pNew = (DMTMAPPING_NODE*)LocalAlloc(LMEM_FIXED,
sizeof(DMTMAPPING_NODE));
if(!pNew)
{
DPF(3, "dmtcfgCreateMappingList - Insufficient memory to "
"allocate mapping list node");
hRes = E_OUTOFMEMORY;
__leave;
}
// initialize the new node
ZeroMemory((void*)pNew, sizeof(DMTMAPPING_NODE));
// allocate the action array
pNew->pdia = (DIACTIONA*)LocalAlloc(LMEM_FIXED,
uActions * sizeof(DIACTIONA));
if(!(pNew->pdia))
{
hRes = E_OUTOFMEMORY;
__leave;
}
// initial population of the action array
hRes = dmtinputPopulateActionArray(pNew->pdia,
uActions,
pActions);
if(FAILED(hRes))
{
__leave;
}
// add the number of actions
pNew->uActions = uActions;
// add the device instance guid
pNew->guidInstance = pDeviceNode->guidInstance;
// add the new node to the list
if(pCurrent)
{
// append the list
pCurrent->pNext = pNew;
// go to the next node
pCurrent = pCurrent->pNext;
}
else
{
// new list head
pCurrent = pNew;
*ppdmtmList = pCurrent;
}
// next device
pDeviceNode = pDeviceNode->pNext;
}
}
__finally
{
// in case of error...
if(FAILED(hRes))
{
// free list
dmtcfgFreeMappingList(ppdmtmList);
*ppdmtmList = NULL;
}
}
// done
return hRes;
} //*** end dmtcfgCreateMappingList()
//===========================================================================
// dmtcfgFreeMappingList
//
// Completely frees a mapping list
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 09/23/1999 - davidkl - created
//===========================================================================
HRESULT dmtcfgFreeMappingList(DMTMAPPING_NODE **ppdmtmList)
{
HRESULT hRes = S_OK;
DMTMAPPING_NODE *pNode = NULL;
// validate ppdmtmList
if(IsBadWritePtr((void*)ppdmtmList, sizeof(DMTMAPPING_NODE*)))
{
return E_POINTER;
}
// validate *ppdmtmList
if(IsBadWritePtr((void*)*ppdmtmList, sizeof(DMTMAPPING_NODE)))
{
if(NULL != *ppdmtmList)
{
return E_POINTER;
}
else
{
// nothing to do
return S_FALSE;
}
}
// walk the list and free each object
while(*ppdmtmList)
{
pNode = *ppdmtmList;
*ppdmtmList = (*ppdmtmList)->pNext;
// first free the action array
if(LocalFree((HLOCAL)(pNode->pdia)))
{
DPF(0, "dmtcfgFreeMappingList - MEMORY LEAK - "
"LocalFree(pdia) failed (%d)...",
GetLastError());
hRes = DMT_S_MEMORYLEAK;
}
// lastly, free the node
DPF(5, "dmtcfgFreeMappingList - deleting Node (%016Xh)", pNode);
if(LocalFree((HLOCAL)pNode))
{
DPF(0, "dmtcfgFreeMappingList - MEMORY LEAK - "
"LocalFree(Node) failed (%d)...",
GetLastError());
hRes = DMT_S_MEMORYLEAK;
}
DPF(5, "dmtcfgFreeMappingList - Node deleted");
}
// make sure that we set *ppObjList to NULL
*ppdmtmList = NULL;
// done
return hRes;
} //*** end dmtcfgFreeMappingList
//===========================================================================
// dmtcfgCreateAllMappingLists
//
// Uses dmtcfgCreateMappingList to create mapping lists for each subgenre
// referenced by pdmtai->pGenreList for each device refereced by
// pdmtai->pDeviceList
//
// Parameters:
//
// Returns: HRESULT
//
// History:
// 09/23/1999 - davidkl - created
//===========================================================================
HRESULT dmtcfgCreateAllMappingLists(DMT_APPINFO *pdmtai)
{
HRESULT hRes = S_OK;
HRESULT hr = S_OK;
DMTGENRE_NODE *pGenreNode = NULL;
DMTSUBGENRE_NODE *pSubGenreNode = NULL;
// validate pdmtai
if(IsBadReadPtr((void*)pdmtai, sizeof(DMT_APPINFO)))
{
return E_POINTER;
}
// validate pdmtai->pGenreList
if(IsBadReadPtr((void*)(pdmtai->pGenreList), sizeof(DMTGENRE_NODE)))
{
return E_POINTER;
}
// validate pdmtai->pDeviceList
if(IsBadReadPtr((void*)(pdmtai->pDeviceList), sizeof(DMTDEVICE_NODE)))
{
return E_POINTER;
}
// for each genre
pGenreNode = pdmtai->pGenreList;
while(pGenreNode)
{
// for each subgenre of the genre
pSubGenreNode = pGenreNode->pSubGenreList;
while(pSubGenreNode)
{
// create the mapping list
hr = dmtcfgCreateMappingList(pdmtai->pDeviceList,
pSubGenreNode->pActionList,
&(pSubGenreNode->pMappingList));
if(FAILED(hr))
{
hRes = S_FALSE;
}
// next subgenre
pSubGenreNode = pSubGenreNode->pNext;
}
// next genre
pGenreNode = pGenreNode->pNext;
}
// done
return hRes;
} //*** end dmtcfgCreateAllMappingLists()
//===========================================================================
// dmtcfgFreeAllMappingLists
//
// Walks the provided genre list and frees the mapping list found in each
// subgenre node
//
// Parameters:
// DMTGENRE_NODE *pdmtgList - list of genres
//
// Returns: HRESULT
//
// History:
// 10/05/1999 - davidkl - created
//===========================================================================
HRESULT dmtcfgFreeAllMappingLists(DMTGENRE_NODE *pdmtgList)
{
HRESULT hRes = S_OK;
HRESULT hr = S_OK;
DMTGENRE_NODE *pGenre = NULL;
DMTSUBGENRE_NODE *pSubGenre = NULL;
// validate pdmtgList
if(IsBadReadPtr((void*)pdmtgList, sizeof(DMTGENRE_NODE)))
{
return E_POINTER;
}
// walk the genre list
pGenre = pdmtgList;
while(pGenre)
{
// walk each subgenre list
pSubGenre = pGenre->pSubGenreList;
while(pSubGenre)
{
// free the mapping list
hr = dmtcfgFreeMappingList(&(pSubGenre->pMappingList));
if(S_OK != hr)
{
hRes = hr;
}
// next subgenre
pSubGenre = pSubGenre->pNext;
}
// next genre
pGenre = pGenre->pNext;
}
// done
return hRes;
} //*** end dmtcfgFreeAllMappingLists()
//===========================================================================
// dmtcfgMapAction
//
// Connects the dots between an action (in the map config dialog) to a device
// object
//
// Parameters:
// HWND hwnd - handle to property page window
// REFGUID guidInstance - instance GUID of DirectInputDevice object
// DIACTIONA *pdia - ptr to array of DIACTIONA structuresfs
// UINT uActions - number of actions in pdia
//
// Returns: HRESULT
//
// History:
// 09/14/1999 - davidkl - created
//===========================================================================
HRESULT dmtcfgMapAction(HWND hwnd,
REFGUID guidInstance,
DIACTIONA *pdia,
UINT uActions)
{
HRESULT hRes = S_OK;
// UINT uObjectSel = 0;
//JJ 64Bit Compat
UINT_PTR uObjectSel = 0;
UINT_PTR uActionSel = 0;
// UINT uActionSel = 0;
UINT u = 0;
BOOL fFound = FALSE;
DMTDEVICEOBJECT_NODE *pObject = NULL;
DMTACTION_NODE *pAction = NULL;
// valudate pdia
if(IsBadWritePtr((void*)pdia, sizeof(DIACTION)))
{
DPF(0, "dmtinputMapAction - invalid pdia (%016Xh)",
pdia);
return E_POINTER;
}
__try
{
// get the object & it's data
uObjectSel = SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_GETCURSEL,
0,
0L);
pObject = (DMTDEVICEOBJECT_NODE*)SendMessageA(GetDlgItem(hwnd,
IDC_CONTROLS),
LB_GETITEMDATA,
(WPARAM)uObjectSel,
0L);
if(!pObject)
{
hRes = E_UNEXPECTED;
__leave;
}
// get the action's data
uActionSel = SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_GETCURSEL,
0,
0L);
pAction = (DMTACTION_NODE*)SendMessageA(GetDlgItem(hwnd, IDC_ACTIONS),
LB_GETITEMDATA,
(WPARAM)uActionSel,
0L);
if(!pAction)
{
hRes = E_UNEXPECTED;
__leave;
}
// find the appropriate action in the array
fFound = FALSE;
for(u = 0; u < uActions; u++)
{
// match based on the semantic / action id
if((pdia + u)->dwSemantic == pAction->dwActionId)
{
DPF(2, "dmtcfgMapAction - found matching action "
"pAction->dwActionId (%08Xh) == "
"(pdia+u)->dwSemantic (%08Xh)",
pAction->dwActionId,
(pdia + u)->dwSemantic);
fFound = TRUE;
break;
}
}
// did we find the action in the array?
if(!fFound)
{
// no. this is very bad!
//
// if this EVER happens,
// we have a serious bug in this app
hRes = E_FAIL;
// since this should NEVER happen,
// break into the debugger and alert the tester
DPF(0, "dmtcfgMapAction - action not found in pdia!");
DPF(0, "dmtcfgMapAction - we were looking for "
"%08Xh (%s)",
pAction->dwActionId,
pAction->szActionId);
DPF(0, "dmtcfgMapAction - CRITICAL failure. "
"This should have never happened!");
DPF(0, "dmtcfgMapAction - Please find someone "
"to look at this right away. ");
DebugBreak();
__leave;
}
// update the action array
(pdia + u)->dwObjID = pObject->dwObjectType;
(pdia + u)->guidInstance = guidInstance;
// HIWORD((DWORD)uAppData) == object type
// LOWORD((DWORD)uAppData) == pObject->wCtrlId
(pdia + u)->uAppData = (DIDFT_GETTYPE(pObject->dwObjectType) << 16) |
(pObject->wCtrlId);
// update the list boxes
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
// enable the unmap & unmap all buttons
EnableWindow(GetDlgItem(hwnd, IDC_UNMAP_ALL), TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_UNMAP), TRUE);
// disable the map button
EnableWindow(GetDlgItem(hwnd, IDC_STORE_MAPPING), FALSE);
}
__finally
{
// cleanup
// nothing to do... yet
}
// done
return hRes;
} //*** end dmtcfgMapAction()
//===========================================================================
// dmtcfgUnmapAction
//
// Disconnects the dots between an action (in the map config dialog) and a
// device object
//
// Parameters:
// HWND hwnd - handle to property page window
// DIACTIONA *pdia - ptr to DIACTIONA array
// UINNT uActions - number of elements in pdia
//
// Returns: HRESULT
//
// History:
// 09/15/1999 - davidkl - created
//===========================================================================
HRESULT dmtcfgUnmapAction(HWND hwnd,
DIACTIONA *pdia,
UINT uActions)
{
HRESULT hRes = S_OK;
UINT u = 0;
// UINT uSel = 0;
//JJ 64Bit Compat
UINT_PTR uSel = 0;
BOOL fFound = FALSE;
DMTSUBGENRE_NODE *pSubGenre = NULL;
DMTDEVICEOBJECT_NODE *pObject = NULL;
// validate pdia
if(IsBadWritePtr((void*)pdia, uActions * sizeof(DIACTIONA)))
{
return E_POINTER;
}
__try
{
// get the current control selection
uSel = SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_GETCURSEL,
0,
0L);
pObject = (DMTDEVICEOBJECT_NODE*)SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_GETITEMDATA,
(WPARAM)uSel,
0L);
if(!pObject)
{
// this is bad
hRes = E_UNEXPECTED;
__leave;
}
// spin through pdia
// look for an action with our object's offset
fFound = FALSE;
for(u = 0; u < uActions; u++)
{
// first check the guid
if(IsEqualGUID(pObject->guidDeviceInstance, (pdia+u)->guidInstance))
{
// then compare the offset
if((pdia+u)->dwObjID == pObject->dwObjectType)
{
fFound = TRUE;
break;
}
}
}
// if nothing is found,
// the selected object is not mapped
//
// (non-critical internal error condition)
if(!fFound)
{
hRes = S_FALSE;
__leave;
}
// reset the guidInstance and dwSemantic fields
(pdia + u)->guidInstance = GUID_NULL;
(pdia + u)->dwObjID = 0;
(pdia + u)->uAppData = 0;
// update the lists
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
// enable the map button
EnableWindow(GetDlgItem(hwnd, IDC_STORE_MAPPING), TRUE);
// disable the unmap button
EnableWindow(GetDlgItem(hwnd, IDC_UNMAP), FALSE);
// if no other actions are mapped,
// disable the unmap all button
fFound = FALSE;
for(u = 0; u < uActions; u++)
{
if(!IsEqualGUID(GUID_NULL, (pdia+u)->guidInstance))
{
fFound = TRUE;
}
}
if(!fFound)
{
EnableWindow(GetDlgItem(hwnd, IDC_UNMAP_ALL), FALSE);
}
}
__finally
{
// cleanup
// nothing to do... yet
}
// done
return hRes;
} //*** end dmtcfgUnmapAction()
//===========================================================================
// dmtcfgUnmapAllActions
//
// Disconnects the all connections between an action (in the map config
// dialog) and a device object
//
// Parameters:
// HWND hwnd - handle to property page window
// DIACTIONA *pdia - ptr to DIACTIONA array
// UINNT uActions - number of elements in pdia
//
// Returns: HRESULT
//
// History:
// 09/15/1999 - davidkl - created
//===========================================================================
HRESULT dmtcfgUnmapAllActions(HWND hwnd,
DIACTIONA *pdia,
UINT uActions)
{
UINT u = 0;
// validate pdia
if(IsBadWritePtr((void*)pdia, uActions * sizeof(DIACTIONA)))
{
return E_POINTER;
}
// spin through pdia
// reset the guidInstance and dwSemantic fields
for(u = 0; u < uActions; u++)
{
(pdia + u)->guidInstance = GUID_NULL;
(pdia + u)->dwObjID = 0;
(pdia + u)->uAppData = 0;
}
// update the lists
SendMessageA(hwnd,
WM_DMT_UPDATE_LISTS,
0,
0L);
// disable the unmap & unmap all buttons
EnableWindow(GetDlgItem(hwnd, IDC_UNMAP), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_UNMAP_ALL), FALSE);
// enable the map button
EnableWindow(GetDlgItem(hwnd, IDC_STORE_MAPPING), TRUE);
// done
return S_OK;
} //*** end dmtcfgUnmapAllActions()
//===========================================================================
// dmtcfgIsControlMapped
//
// Checks to see if a control is mapped to an action
//
// Parameters:
//
// Returns:
//
// History:
// 09/15/1999 - davidkl - created
//===========================================================================
BOOL dmtcfgIsControlMapped(HWND hwnd,
DIACTIONA *pdia,
UINT uActions)
{
BOOL fMapped = FALSE;
UINT u = 0;
// UINT uSel = 0;
//JJ 64Bit Compat
UINT_PTR uSel = 0;
DMTDEVICEOBJECT_NODE *pObject = NULL;
// validate pdia
if(IsBadReadPtr((void*)pdia, uActions * sizeof(pdia)))
{
DPF(0, "dmtcfgIsControlMapped - invalid pdia (%016Xh)",
pdia);
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
// get the currently selected control
uSel = SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_GETCURSEL,
0,
0L);
pObject = (DMTDEVICEOBJECT_NODE*)SendMessageA(GetDlgItem(hwnd, IDC_CONTROLS),
LB_GETITEMDATA,
(WPARAM)uSel,
0L);
if(!pObject)
{
// this is bad
//
// (serious internal app error)
SetLastError(ERROR_GEN_FAILURE);
DebugBreak();
return FALSE;
}
// check the array,
// see if this control is mapped to anything
fMapped = FALSE;
for(u = 0; u < uActions; u++)
{
// first check the guid
if(IsEqualGUID(pObject->guidDeviceInstance, (pdia+u)->guidInstance))
{
// then compare the offset
if((pdia+u)->dwObjID == pObject->dwObjectType)
// if((pdia+u)->dwObjID == pObject->dwObjectOffset)
{
fMapped = TRUE;
break;
}
}
}
// done
SetLastError(ERROR_SUCCESS);
return fMapped;
} //*** end dmtcfgIsControlMapped()
//===========================================================================
// dmtcfgAreAnyControlsMapped
//
// Checks to see if any controls are mapped to an action.
//
// Parameters:
//
// Returns:
//
// History:
// 11/01/1999 - davidkl - created
//===========================================================================
BOOL dmtcfgAreAnyControlsMapped(HWND hwnd,
DIACTIONA *pdia,
UINT uActions)
{
BOOL fMapped = FALSE;
UINT u = 0;
// validate pdia
if(IsBadReadPtr((void*)pdia, uActions * sizeof(pdia)))
{
DPF(0, "dmtcfgAreAnyControlsMapped - invalid pdia (%016Xh)",
pdia);
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
// check the array,
// see if this control is mapped to anything
fMapped = FALSE;
for(u = 0; u < uActions; u++)
{
// check guid
//
// if not GUID_NULL, this action is mapped
if(!IsEqualGUID(GUID_NULL, (pdia+u)->guidInstance))
{
fMapped = TRUE;
break;
}
}
// done
SetLastError(ERROR_SUCCESS);
return fMapped;
} //*** end dmtcfgAreAnyControlsMapped()
//===========================================================================
// dmtcfgGetGenreGroupName
//
// Extracts the genre group name from the genres.ini entry
//
// Paramters:
//
// Returns: HRESULT
//
// History:
// 09/28/1999 - davidkl - created
// 09/29/1999 - davidkl - modified "buckets"
//===========================================================================
HRESULT dmtcfgGetGenreGroupName(PSTR szGenreName,
PSTR szGenreGroupName)
{
HRESULT hRes = S_OK;
char *pcFirst = NULL;
char *pcCurrent = NULL;
// find the first '_'
pcFirst = strchr(szGenreName, '_');
// copy the characters between pcFirst and pcLast
pcCurrent = pcFirst+1; // skip past the first '_'
while((*pcCurrent != '_') && (*pcCurrent != '\0'))
{
*szGenreGroupName = *pcCurrent;
// next character
pcCurrent++;
szGenreGroupName++;
}
*szGenreGroupName = '\0';
// done
return hRes;
} //*** end dmtcfgGetGenreGroupName()
//===========================================================================
//===========================================================================