You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1148 lines
26 KiB
1148 lines
26 KiB
|
|
#include "pch.h"
|
|
|
|
PPCI_TREE
|
|
SoftPCI_BuildTree(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SoftPCI_DisplayTreeMenu(
|
|
IN PPCI_DN Pdn,
|
|
IN POINT Pt
|
|
);
|
|
|
|
VOID
|
|
SoftPCI_DisplayStandardTreeMenu(
|
|
IN PPCI_DN Pdn,
|
|
IN POINT Pt
|
|
);
|
|
|
|
VOID
|
|
SoftPCI_DisplayHotplugTreeMenu(
|
|
IN PPCI_DN Pdn,
|
|
IN POINT Pt
|
|
);
|
|
|
|
VOID
|
|
SoftPCI_FreeBranch(
|
|
IN PPCI_DN Dn
|
|
);
|
|
|
|
VOID
|
|
SoftPCI_InsertTreeItem(
|
|
IN PPCI_DN Pdn,
|
|
IN HTREEITEM HtiParent
|
|
);
|
|
|
|
VOID
|
|
SoftPCI_ExpandItem(
|
|
IN HTREEITEM Hti,
|
|
IN PVOID Arg1,
|
|
IN PVOID Arg2
|
|
);
|
|
|
|
VOID
|
|
SoftPCI_RestoreSelection(
|
|
IN HTREEITEM Hti,
|
|
IN PVOID Data1,
|
|
IN PVOID Data2
|
|
);
|
|
|
|
BOOL g_TreeCreated = FALSE;
|
|
BOOL g_TreeLocked = FALSE;
|
|
BOOL g_PendingRefresh = FALSE;
|
|
PPCI_TREE g_PciTree;
|
|
LONG_PTR g_DefTreeWndProc;
|
|
PWCHAR g_LastSelection = NULL;
|
|
|
|
|
|
VOID
|
|
SoftPCI_CreateTreeView(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
|
|
HTREEITEM htiParent;
|
|
TVITEM tvitem;
|
|
PPCI_DN rootDevNode = NULL;
|
|
HMENU menu = GetMenu(g_SoftPCIMainWnd);
|
|
PPCI_DN pdn = NULL;
|
|
PCI_DN selectedDevNode;
|
|
BOOL selectionFound;
|
|
PWCHAR p;
|
|
//HCURSOR oldCursor;
|
|
|
|
//
|
|
// Empty the tree.
|
|
//
|
|
TreeView_DeleteAllItems(g_TreeViewWnd);
|
|
|
|
if (g_TreeCreated) {
|
|
|
|
SoftPCI_DestroyTree(g_PciTree);
|
|
|
|
}
|
|
|
|
g_PciTree = SoftPCI_BuildTree();
|
|
|
|
if (!g_PciTree) {
|
|
MessageBox(g_SoftPCIMainWnd, L"Failed to create g_PciTree!", L"ERROR", MB_OK);
|
|
return;
|
|
}
|
|
|
|
g_TreeCreated = TRUE;
|
|
|
|
SOFTPCI_ASSERT(g_PciTree->ClassImageListData.ImageList != INVALID_HANDLE_VALUE);
|
|
TreeView_SetImageList(g_TreeViewWnd, g_PciTree->ClassImageListData.ImageList, TVSIL_NORMAL);
|
|
|
|
//
|
|
// Insert the rest of the items.
|
|
//
|
|
SoftPCI_InsertTreeItem(g_PciTree->RootDevNode, TVI_ROOT);
|
|
|
|
//
|
|
// Currently we always expand the entire tree when it is built. Should see
|
|
// if there is a way to avoid this....
|
|
//
|
|
SoftPCI_WalkTree(
|
|
g_PciTree->RootTreeItem,
|
|
SoftPCI_ExpandItem,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Restore last selection if any
|
|
//
|
|
if (g_LastSelection){
|
|
|
|
selectionFound = FALSE;
|
|
SoftPCI_WalkTree(
|
|
g_PciTree->RootTreeItem,
|
|
SoftPCI_RestoreSelection,
|
|
&selectionFound,
|
|
NULL
|
|
);
|
|
|
|
if (!selectionFound) {
|
|
|
|
//
|
|
// If the last selection no longer exists then we back up to the
|
|
// parent and check one more time.
|
|
//
|
|
p = g_LastSelection;
|
|
p += wcslen(g_LastSelection);
|
|
while(*p != '\\'){
|
|
p--;
|
|
}
|
|
*p = 0;
|
|
|
|
//
|
|
// Now run the tree one more time looking for the parent
|
|
//
|
|
SoftPCI_WalkTree(
|
|
g_PciTree->RootTreeItem,
|
|
SoftPCI_RestoreSelection,
|
|
&selectionFound,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
}else{
|
|
|
|
TreeView_Select(g_TreeViewWnd, g_PciTree->RootTreeItem, TVGN_CARET);
|
|
TreeView_EnsureVisible(g_TreeViewWnd, g_PciTree->RootTreeItem);
|
|
}
|
|
|
|
SoftPCI_UpdateTabCtrlWindow(g_CurrentTabSelection);
|
|
|
|
}
|
|
|
|
PPCI_TREE
|
|
SoftPCI_BuildTree(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the entry point for building our PCI_TREE
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
PPCI_TREE we have created
|
|
|
|
--*/
|
|
{
|
|
|
|
DEVNODE dn = 0;
|
|
PPCI_DN pdn;
|
|
PPCI_TREE pcitree;
|
|
|
|
pcitree = (PPCI_TREE) calloc(1, sizeof(PCI_TREE));
|
|
if (!pcitree) return NULL;
|
|
|
|
CM_Locate_DevNode(&dn, NULL, CM_LOCATE_DEVNODE_NORMAL);
|
|
SOFTPCI_ASSERT(dn != 0);
|
|
|
|
pcitree->ClassImageListData.ImageList = INVALID_HANDLE_VALUE ;
|
|
pcitree->ClassImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA) ;
|
|
|
|
if (!SetupDiGetClassImageList(&pcitree->ClassImageListData)){
|
|
pcitree->ClassImageListData.ImageList = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
pcitree->DevInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL) ;
|
|
|
|
SOFTPCI_ASSERT(pcitree->DevInfoSet != INVALID_HANDLE_VALUE);
|
|
|
|
//
|
|
// Now find all things PCI and build a PCI_DN tree
|
|
//
|
|
pdn = NULL;
|
|
SoftPCI_EnumerateDevices(pcitree, &pdn, dn, NULL);
|
|
|
|
pcitree->RootDevNode = pdn;
|
|
|
|
return pcitree;
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_DestroyTree(
|
|
IN PPCI_TREE PciTree
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees all our allocations for the Tree
|
|
|
|
Arguments:
|
|
|
|
PciTree - Tree to distroy
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
PPCI_DN dn = PciTree->RootDevNode;
|
|
|
|
//
|
|
// First set the tree view image list to NULL
|
|
//
|
|
TreeView_SetImageList(g_TreeViewWnd, NULL, TVSIL_NORMAL);
|
|
|
|
//
|
|
// Now free all our allocated PCI_DN structs
|
|
//
|
|
SoftPCI_FreeBranch(dn);
|
|
|
|
//
|
|
// Destroy our image and info lists
|
|
//
|
|
if (PciTree->ClassImageListData.ImageList != INVALID_HANDLE_VALUE){
|
|
SetupDiDestroyClassImageList(&PciTree->ClassImageListData);
|
|
PciTree->ClassImageListData.ImageList = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (PciTree->DevInfoSet != INVALID_HANDLE_VALUE){
|
|
SetupDiDestroyDeviceInfoList(PciTree->DevInfoSet);
|
|
PciTree->DevInfoSet = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// And finally....
|
|
//
|
|
free(PciTree);
|
|
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_DisplayTreeMenu(
|
|
IN PPCI_DN Pdn,
|
|
IN POINT Pt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dispatches the menu request to the appropriate menu function
|
|
|
|
Arguments:
|
|
|
|
Pdn - PCI_DN of the item we are displaying the menu for
|
|
Pt - coordinates for the item
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
if (Pdn->Flags & SOFTPCI_HOTPLUG_SLOT) {
|
|
|
|
SoftPCI_DisplayHotplugTreeMenu(Pdn,Pt);
|
|
|
|
} else if (Pdn->Flags & SOFTPCI_UNENUMERATED_DEVICE) {
|
|
//
|
|
// If it's an unenumerated device (in an unpowered hotplug slot),
|
|
// you can't do anything with it.
|
|
//
|
|
return;
|
|
|
|
} else {
|
|
|
|
SoftPCI_DisplayStandardTreeMenu(Pdn, Pt);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_DisplayStandardTreeMenu(
|
|
IN PPCI_DN Pdn,
|
|
IN POINT Pt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine displays the standard context menu when the user right-clicks a device
|
|
|
|
Arguments:
|
|
|
|
Pdn - PCI_DN of the slot
|
|
Pt - coordinates for the device
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
|
|
HMENU menu, popup;
|
|
ULONG dnProblem;
|
|
BOOL enableDevice = FALSE;
|
|
INT selection = 0;
|
|
|
|
menu = LoadMenu(g_Instance, MAKEINTRESOURCE(IDM_TREEMENU));
|
|
|
|
if (!menu) {
|
|
MessageBox(g_SoftPCIMainWnd, L"failed to display menu!", NULL, MB_OK);
|
|
return;
|
|
}
|
|
|
|
popup = GetSubMenu(menu, 0);
|
|
|
|
//
|
|
// If SoftPCI support is not installed or this isnt a bridge device,
|
|
// disable the option to add devices.
|
|
//
|
|
if ((g_DriverHandle == NULL) ||
|
|
!SoftPCI_IsBridgeDevice(Pdn)) {
|
|
|
|
SoftPCI_DisableMenuItem(menu, ID_INSTALLDEVICE);
|
|
}
|
|
|
|
if (!SoftPCI_IsSoftPCIDevice(Pdn)) {
|
|
|
|
SoftPCI_DisableMenuItem(menu, ID_DELETEDEVICE);
|
|
SoftPCI_DisableMenuItem(menu, ID_STATICDEVICE);
|
|
}
|
|
|
|
if (SoftPCI_GetDeviceNodeProblem(Pdn->DevNode, &dnProblem)) {
|
|
|
|
if (dnProblem == CM_PROB_DISABLED) {
|
|
enableDevice = TRUE;
|
|
SoftPCI_SetMenuItemText(menu, ID_ENABLEDISABLEDEVICE, L"E&nable Device");
|
|
}else{
|
|
//
|
|
// For now we will not allow the option to disable a non-working device
|
|
//
|
|
SoftPCI_DisableMenuItem(menu, ID_ENABLEDISABLEDEVICE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If this device is in a hotplug slot, can't just rip out
|
|
// the hardware. You have to go through the appropriate
|
|
// mechanism.
|
|
//
|
|
if (Pdn->Parent && (Pdn->Parent->Flags & SOFTPCI_HOTPLUG_SLOT)) {
|
|
|
|
SoftPCI_DisableMenuItem(menu, ID_DELETEDEVICE);
|
|
}
|
|
|
|
//
|
|
// Make sure it pops up in the right place....
|
|
//
|
|
ClientToScreen(g_SoftPCIMainWnd, &Pt);
|
|
|
|
//
|
|
// lets see the menu
|
|
//
|
|
selection = TrackPopupMenuEx(
|
|
popup,
|
|
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
|
|
Pt.x, Pt.y,
|
|
g_SoftPCIMainWnd,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Now we will handle our Floating Tree View menu items
|
|
//
|
|
switch (selection) {
|
|
case ID_INSTALLDEVICE:
|
|
DISPLAY_NEWDEV_DLG(Pdn);
|
|
break;
|
|
|
|
case ID_ENABLEDISABLEDEVICE:
|
|
|
|
SoftPCI_EnableDisableDeviceNode(
|
|
Pdn->DevNode,
|
|
enableDevice
|
|
);
|
|
|
|
break;
|
|
|
|
case ID_DELETEDEVICE:
|
|
|
|
if ((MessageBox(g_SoftPCIMainWnd,
|
|
L"This option will delete or surprise remove the device from the system.",
|
|
L"WARNING", MB_OKCANCEL)) == IDOK){
|
|
|
|
|
|
//
|
|
// Here we tell our driver to delete the specified device. This will
|
|
// cause a re-enum of everything that will result in the cleanup
|
|
// of this device in user mode.
|
|
//
|
|
if (!SoftPCI_DeleteDevice(Pdn->SoftDev)) {
|
|
MessageBox(g_SoftPCIMainWnd, L"Failed to delete device!", NULL, MB_OK);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ID_STATICDEVICE:
|
|
if (SoftPCI_SaveDeviceToRegisty(Pdn)){
|
|
MessageBox(g_SoftPCIMainWnd, L"Successfully saved devices to registry!", NULL, MB_OK);
|
|
}else{
|
|
MessageBox(g_SoftPCIMainWnd, L"Failed to save devices to registry!", NULL, MB_OK);
|
|
}
|
|
break;
|
|
|
|
case ID_REFRESHTREE:
|
|
CM_Reenumerate_DevNode(Pdn->DevNode, 0);
|
|
SoftPCI_CreateTreeView();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_DisplayHotplugTreeMenu(
|
|
IN PPCI_DN Pdn,
|
|
IN POINT Pt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine displays the hotplug specific context menu when the user right-clicks a hotplug slot.
|
|
|
|
Arguments:
|
|
|
|
Pdn - PCI_DN of the slot
|
|
Pt - coordinates for the slot
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
|
|
HMENU menu, popup;
|
|
INT selection;
|
|
PPCI_DN parentDn;
|
|
BOOL status;
|
|
SHPC_SLOT_STATUS_REGISTER slotStatus;
|
|
|
|
menu = LoadMenu(g_Instance, MAKEINTRESOURCE(IDM_HOTPLUGSLOTMENU));
|
|
|
|
if (!menu) {
|
|
MessageBox(g_SoftPCIMainWnd, L"failed to display menu!", NULL, MB_OK);
|
|
return;
|
|
}
|
|
|
|
popup = GetSubMenu(menu, 0);
|
|
|
|
//
|
|
// If SoftPCI support is not installed disable the option to add devices.
|
|
//
|
|
if (!g_DriverHandle) {
|
|
|
|
SoftPCI_DisableMenuItem(menu, ID_INSTALLDEVICE);
|
|
}
|
|
|
|
//
|
|
// If our Device Property dialog is open dont allow properties to be
|
|
// selected again.
|
|
//
|
|
if (g_NewDevDlg) {
|
|
|
|
//
|
|
// ISSUE: BrandonA - Figure out why we hang if the first Dialog
|
|
// launched is killed before the second...
|
|
//
|
|
SoftPCI_DisableMenuItem(menu, ID_INSTALLDEVICE);
|
|
}
|
|
//
|
|
// DWALKER
|
|
// Get slot status from driver
|
|
// appropriately grey out open/close MRL menu item.
|
|
// if MRL is closed, disable removing the device.
|
|
//
|
|
parentDn = Pdn->Parent;
|
|
status = SoftPCI_GetSlotStatus(parentDn,
|
|
Pdn->Slot.Function,
|
|
&slotStatus
|
|
);
|
|
if (status == FALSE) {
|
|
MessageBox(g_SoftPCIMainWnd, L"failed to display menu!", NULL, MB_OK);
|
|
return;
|
|
}
|
|
//
|
|
// If the MRL is closed, you can't insert or remove the device.
|
|
// Otherwise, disable the appropriate menu item based on the presence
|
|
// of a device in the slot.
|
|
//
|
|
if (slotStatus.MRLSensorState == SHPC_MRL_CLOSED) {
|
|
|
|
SoftPCI_DisableMenuItem(menu, ID_REMOVEHPDEVICE);
|
|
SoftPCI_DisableMenuItem(menu, ID_INSTALLDEVICE);
|
|
|
|
} else if (Pdn->Child == NULL) {
|
|
|
|
SoftPCI_DisableMenuItem(menu, ID_REMOVEHPDEVICE);
|
|
|
|
} else {
|
|
|
|
SoftPCI_DisableMenuItem(menu, ID_INSTALLDEVICE);
|
|
}
|
|
|
|
if (slotStatus.MRLSensorState == SHPC_MRL_CLOSED) {
|
|
|
|
RemoveMenu(menu, ID_CLOSEMRL, MF_BYCOMMAND);
|
|
|
|
} else {
|
|
|
|
RemoveMenu(menu, ID_OPENMRL, MF_BYCOMMAND);
|
|
}
|
|
|
|
AppendMenu(popup, MF_SEPARATOR, 0, NULL);
|
|
|
|
switch (slotStatus.PowerIndicatorState) {
|
|
case SHPC_INDICATOR_OFF:
|
|
AppendMenu(popup, MF_STRING | MF_GRAYED, ID_POWERINDICATOR, L"Power Indicator: Off");
|
|
break;
|
|
case SHPC_INDICATOR_ON:
|
|
AppendMenu(popup, MF_STRING | MF_GRAYED, ID_POWERINDICATOR, L"Power Indicator: On");
|
|
break;
|
|
case SHPC_INDICATOR_BLINK:
|
|
AppendMenu(popup, MF_STRING | MF_GRAYED, ID_POWERINDICATOR, L"Power Indicator: Blinking");
|
|
break;
|
|
case SHPC_INDICATOR_NOP:
|
|
AppendMenu(popup, MF_STRING | MF_GRAYED, ID_POWERINDICATOR, L"Power Indicator: Unspecified");
|
|
break;
|
|
}
|
|
|
|
switch (slotStatus.AttentionIndicatorState) {
|
|
case SHPC_INDICATOR_OFF:
|
|
AppendMenu(popup, MF_STRING | MF_GRAYED, ID_ATTENINDICATOR, L"Attention Indicator: Off");
|
|
break;
|
|
case SHPC_INDICATOR_ON:
|
|
AppendMenu(popup, MF_STRING | MF_GRAYED, ID_ATTENINDICATOR, L"Attention Indicator: On");
|
|
break;
|
|
case SHPC_INDICATOR_BLINK:
|
|
AppendMenu(popup, MF_STRING | MF_GRAYED, ID_ATTENINDICATOR, L"Attention Indicator: Blinking");
|
|
break;
|
|
case SHPC_INDICATOR_NOP:
|
|
AppendMenu(popup, MF_STRING | MF_GRAYED, ID_POWERINDICATOR, L"Attention Indicator: Unspecified");
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the menu updated after our additions.
|
|
//
|
|
//DrawMenuBar(g_SoftPCIMainWnd);
|
|
|
|
//
|
|
// Make sure it pops up in the right place....
|
|
//
|
|
ClientToScreen(g_SoftPCIMainWnd, &Pt);
|
|
|
|
//
|
|
// lets see the menu
|
|
//
|
|
selection = TrackPopupMenuEx(popup,
|
|
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
|
|
Pt.x, Pt.y,
|
|
g_SoftPCIMainWnd,
|
|
NULL
|
|
);
|
|
|
|
|
|
//
|
|
// Now we will handle our Floating Tree View menu items
|
|
//
|
|
switch (selection) {
|
|
|
|
case ID_INSTALLDEVICE:
|
|
|
|
//
|
|
// For now kill any dialogs we may already have open before starting this one
|
|
//
|
|
//if (g_DevPropDlg) {
|
|
// SendMessage(g_DevPropDlg, WM_CLOSE, 0L, 0L);
|
|
//}
|
|
|
|
DISPLAY_NEWDEV_DLG(Pdn);
|
|
|
|
break;
|
|
|
|
case ID_REMOVEHPDEVICE:
|
|
|
|
SoftPCI_RemoveHotplugDevice(parentDn,
|
|
Pdn->Slot.Function
|
|
);
|
|
SoftPCI_CreateTreeView();
|
|
break;
|
|
|
|
case ID_CLOSEMRL:
|
|
SoftPCI_ExecuteHotplugSlotMethod(parentDn,
|
|
Pdn->Slot.Function,
|
|
MRLClose
|
|
);
|
|
break;
|
|
|
|
case ID_OPENMRL:
|
|
SoftPCI_ExecuteHotplugSlotMethod(parentDn,
|
|
Pdn->Slot.Function,
|
|
MRLOpen
|
|
);
|
|
break;
|
|
|
|
case ID_ATTENBUTTON:
|
|
SoftPCI_ExecuteHotplugSlotMethod(parentDn,
|
|
Pdn->Slot.Function,
|
|
AttentionButton
|
|
);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure we dont lose our focus
|
|
//
|
|
//SetFocus(g_TreeViewWnd);
|
|
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_FreeBranch(
|
|
IN PPCI_DN Dn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will free the specified PCI_DN struct along with all siblings and children.
|
|
|
|
Arguments:
|
|
|
|
Dn - PCI_DN to free
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
|
|
PPCI_DN child, sibling;
|
|
|
|
if (Dn) {
|
|
|
|
child = Dn->Child;
|
|
sibling = Dn->Sibling;
|
|
|
|
if (Dn->SoftDev) {
|
|
free(Dn->SoftDev);
|
|
}
|
|
|
|
SetupDiDeleteDeviceInfo(Dn->PciTree->DevInfoSet, &Dn->DevInfoData) ;
|
|
|
|
free(Dn);
|
|
|
|
SoftPCI_FreeBranch(child);
|
|
|
|
SoftPCI_FreeBranch(sibling);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_OnTreeSelectionChange(
|
|
IN HWND Wnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine informs our properties sheet that the selection has changes so that it can update
|
|
|
|
Arguments:
|
|
|
|
Wnd -
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
|
|
TV_ITEM tviItem;
|
|
PPCI_DN pdn = NULL;
|
|
RECT itemRect;
|
|
ULONG slotCount;
|
|
|
|
//
|
|
// Get the Current Item
|
|
//
|
|
tviItem.mask = TVIF_PARAM;
|
|
tviItem.hItem = TreeView_GetSelection(g_TreeViewWnd);
|
|
tviItem.lParam = 0;
|
|
TreeView_GetItem(g_TreeViewWnd, &tviItem);
|
|
|
|
if (tviItem.lParam) {
|
|
|
|
g_PdnToDisplay = (PPCI_DN)tviItem.lParam;
|
|
|
|
if (g_LastSelection) {
|
|
free(g_LastSelection);
|
|
g_LastSelection = NULL;
|
|
}
|
|
|
|
//
|
|
// Save the last selection so we can restore it if the tree
|
|
// is rebuilt.
|
|
//
|
|
g_LastSelection = SoftPCI_GetPciPathFromDn(g_PdnToDisplay);
|
|
|
|
SoftPCI_UpdateTabCtrlWindow(g_CurrentTabSelection);
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT
|
|
WINAPI
|
|
SoftPCI_TreeWndProc(
|
|
IN HWND Wnd,
|
|
IN UINT Message,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine hooks the Tree Window message proc and is responsible
|
|
for resizing our pane window when it is resized.
|
|
|
|
Arguments:
|
|
|
|
hWnd - Window handle
|
|
Message - Message to process
|
|
wParam - Message param
|
|
lParam - Message param
|
|
|
|
Return Value:
|
|
|
|
return value depends on message handled.
|
|
|
|
--*/
|
|
{
|
|
|
|
RECT rectMain, rectTree;
|
|
TV_ITEM tviItem;
|
|
TVHITTESTINFO hitinfo;
|
|
PPCI_DN pdn;
|
|
PCI_DN dn;
|
|
RECT itemRect;
|
|
POINT pt;
|
|
|
|
//
|
|
// Get the Current Item
|
|
//
|
|
//
|
|
|
|
switch (Message) {
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
switch (wParam){
|
|
|
|
case VK_APPS:
|
|
|
|
//
|
|
// Grab the PCI_DN from the current tree item
|
|
//
|
|
pdn = SoftPCI_GetDnFromTreeItem(NULL);
|
|
|
|
|
|
//
|
|
// We copy this to a new DN because the TREE is constantly being
|
|
// rebuilt and we cannot rely on the TV_ITEM.lParam value to always
|
|
// be accurate later (we may have changed it).
|
|
//
|
|
RtlCopyMemory(&dn, pdn, sizeof(PCI_DN));
|
|
|
|
if (TreeView_GetItemRect(g_TreeViewWnd,
|
|
TreeView_GetSelection(g_TreeViewWnd),
|
|
&itemRect,
|
|
TRUE)) {
|
|
|
|
//
|
|
// Adjust the location for our menu
|
|
//
|
|
pt.x = itemRect.right;
|
|
pt.y = itemRect.top;
|
|
|
|
SoftPCI_DisplayTreeMenu(&dn, pt);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return CallWindowProc((WNDPROC)g_DefTreeWndProc, Wnd, Message, wParam, lParam);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
ZeroMemory(&hitinfo, sizeof(TVHITTESTINFO));
|
|
|
|
hitinfo.pt.x = GET_X_LPARAM(lParam);
|
|
hitinfo.pt.y = GET_Y_LPARAM(lParam);
|
|
|
|
if (TreeView_HitTest(g_TreeViewWnd, &hitinfo)) {
|
|
|
|
g_TreeLocked = TRUE;
|
|
|
|
pdn = SoftPCI_GetDnFromTreeItem(hitinfo.hItem);
|
|
|
|
//
|
|
// See comment above for reason why we copy this here....
|
|
//
|
|
RtlCopyMemory(&dn, pdn, sizeof(PCI_DN));
|
|
|
|
//
|
|
// If an item in the tree is already selected this will cause the selection to change
|
|
// as each item is right clicked.
|
|
//
|
|
TreeView_Select(g_TreeViewWnd, hitinfo.hItem, TVGN_CARET);
|
|
|
|
SoftPCI_DisplayTreeMenu(&dn, hitinfo.pt);
|
|
|
|
g_TreeLocked = FALSE;
|
|
|
|
if (g_PendingRefresh) {
|
|
g_PendingRefresh = FALSE;
|
|
SoftPCI_CreateTreeView();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return CallWindowProc((WNDPROC)g_DefTreeWndProc, Wnd, Message, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
PPCI_DN
|
|
SoftPCI_GetDnFromTreeItem(
|
|
IN HTREEITEM TreeItem
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a PCI_DN for either the currently selected TreeItem
|
|
or the one specified by the caller.
|
|
|
|
Arguments:
|
|
|
|
TreeItem - Handle to TreeItem we want to query. If NULL then we default to current selection.
|
|
|
|
Return Value:
|
|
|
|
return value will be TV_ITEM.lParam value
|
|
|
|
--*/
|
|
{
|
|
|
|
TV_ITEM tviItem;
|
|
|
|
tviItem.mask = TVIF_PARAM;
|
|
tviItem.hItem = (TreeItem ? TreeItem : TreeView_GetSelection(g_TreeViewWnd));
|
|
tviItem.lParam = 0;
|
|
TreeView_GetItem(g_TreeViewWnd, &tviItem);
|
|
|
|
SOFTPCI_ASSERT(((PPCI_DN)tviItem.lParam) != NULL);
|
|
|
|
return (PPCI_DN)tviItem.lParam;
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_InsertTreeItem(
|
|
IN PPCI_DN Pdn,
|
|
IN HTREEITEM HtiParent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes our tree of PCI_DN structs and builds the UI representaion of it.
|
|
|
|
Arguments:
|
|
|
|
Pdn Current Pdn being intserted
|
|
HtiParent The HTREEITEM that is to be the parent of this Pdn
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
PPCI_DN childDevNode;
|
|
PPCI_DN siblingDevNode;
|
|
TV_INSERTSTRUCT tvInsertStruct;
|
|
HTREEITEM htiNewParent;
|
|
TV_ITEM tvi;
|
|
INT index;
|
|
ULONG problem;
|
|
|
|
SOFTPCI_ASSERT(Pdn != NULL);
|
|
|
|
do {
|
|
|
|
childDevNode = Pdn->Child;
|
|
siblingDevNode = Pdn->Sibling;
|
|
|
|
//
|
|
// Get the parent item, and tell it it has children now
|
|
//
|
|
if (HtiParent != TVI_ROOT) {
|
|
|
|
tvi.mask = TVIF_CHILDREN;
|
|
tvi.hItem = HtiParent;
|
|
|
|
TreeView_GetItem(g_TreeViewWnd, &tvi);
|
|
|
|
//
|
|
// Increment the ChildCount;
|
|
//
|
|
++tvi.cChildren;
|
|
TreeView_SetItem(g_TreeViewWnd, &tvi);
|
|
}
|
|
|
|
//
|
|
// Add This Device at the current Level
|
|
//
|
|
tvInsertStruct.hParent = HtiParent;
|
|
tvInsertStruct.hInsertAfter = TVI_LAST;
|
|
tvInsertStruct.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
|
|
tvInsertStruct.item.cChildren = 0;
|
|
tvInsertStruct.item.lParam = (ULONG_PTR) Pdn;
|
|
|
|
tvInsertStruct.item.state = INDEXTOOVERLAYMASK(0);
|
|
|
|
//
|
|
// If the device has a problem make let's reflect so....
|
|
//
|
|
if (SoftPCI_GetDeviceNodeProblem(Pdn->DevNode, &problem)){
|
|
|
|
if (problem == CM_PROB_DISABLED) {
|
|
tvInsertStruct.item.state = INDEXTOOVERLAYMASK(IDI_DISABLED_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
|
|
}else{
|
|
tvInsertStruct.item.state = INDEXTOOVERLAYMASK(IDI_PROBLEM_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
|
|
}
|
|
}
|
|
|
|
tvInsertStruct.item.stateMask = TVIS_OVERLAYMASK | TVIS_CUT;
|
|
|
|
tvInsertStruct.item.pszText = (LPTSTR) Pdn->FriendlyName;
|
|
|
|
//
|
|
// Figure out which icon goes which each device.
|
|
//
|
|
if (SetupDiGetClassImageIndex(&Pdn->PciTree->ClassImageListData, &Pdn->DevInfoData.ClassGuid, &index)){
|
|
tvInsertStruct.item.iImage = tvInsertStruct.item.iSelectedImage = index ;
|
|
}else{
|
|
tvInsertStruct.item.iImage = tvInsertStruct.item.iSelectedImage = -1 ;
|
|
}
|
|
|
|
htiNewParent = TreeView_InsertItem(g_TreeViewWnd, &tvInsertStruct);
|
|
|
|
if (g_PciTree->RootTreeItem == NULL) {
|
|
g_PciTree->RootTreeItem = htiNewParent;
|
|
}
|
|
|
|
//
|
|
// if this device has a child lets walk them next
|
|
//
|
|
if (childDevNode){
|
|
SoftPCI_InsertTreeItem(childDevNode, htiNewParent);
|
|
}
|
|
|
|
}while ((Pdn = siblingDevNode) != NULL);
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_ExpandItem(
|
|
IN HTREEITEM Hti,
|
|
IN PULONG Data1,
|
|
IN PULONG Data2
|
|
)
|
|
{
|
|
//
|
|
// Expand this item.
|
|
//
|
|
TreeView_Expand(g_TreeViewWnd, Hti, TVE_EXPAND);
|
|
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_RestoreSelection(
|
|
IN HTREEITEM Hti,
|
|
IN PVOID Data1,
|
|
IN PVOID Data2
|
|
)
|
|
{
|
|
|
|
PWCHAR slotPath, p;
|
|
PPCI_DN pdn;
|
|
PBOOL selectionFound;
|
|
|
|
selectionFound = (PBOOL)Data1;
|
|
|
|
pdn = SoftPCI_GetDnFromTreeItem(Hti);
|
|
if (pdn == NULL) {
|
|
return;
|
|
}
|
|
|
|
slotPath = SoftPCI_GetPciPathFromDn(pdn);
|
|
|
|
if ((wcscmp(slotPath, g_LastSelection)) == 0) {
|
|
|
|
//
|
|
// Restore the selection to this point.
|
|
//
|
|
TreeView_Select(g_TreeViewWnd, Hti, TVGN_CARET);
|
|
TreeView_EnsureVisible(g_TreeViewWnd, Hti);
|
|
*selectionFound = TRUE;
|
|
}
|
|
|
|
free(slotPath);
|
|
}
|
|
|
|
|
|
VOID
|
|
SoftPCI_WalkTree(
|
|
IN HTREEITEM Hti,
|
|
IN PSOFTPCI_TREECALLBACK TreeCallback,
|
|
IN PVOID Arg1,
|
|
IN PVOID Arg2
|
|
)
|
|
{
|
|
if (Hti) {
|
|
|
|
//
|
|
// Call the CallBack.
|
|
//
|
|
(*TreeCallback)(Hti, Arg1, Arg2);
|
|
|
|
//
|
|
// Call this on my first child.
|
|
//
|
|
SoftPCI_WalkTree(TreeView_GetChild(g_TreeViewWnd, Hti),
|
|
TreeCallback,
|
|
Arg1,
|
|
Arg2
|
|
);
|
|
|
|
//
|
|
// Call this on my first sibling.
|
|
//
|
|
SoftPCI_WalkTree(TreeView_GetNextSibling(g_TreeViewWnd, Hti),
|
|
TreeCallback,
|
|
Arg1,
|
|
Arg2
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
VOID
|
|
SoftPCI_GetDnFromTree(
|
|
IN HTREEITEM Hti,
|
|
IN OUT PVOID Pdn, //PPCI_DN *
|
|
IN PVOID PdnToFind
|
|
)
|
|
{
|
|
|
|
TV_ITEM tvi;
|
|
PPCI_DN pdn = NULL;
|
|
PPCI_DN pdnToFind = (PPCI_DN)PdnToFind;
|
|
|
|
tvi.lParam = 0;
|
|
tvi.hItem = Hti;
|
|
|
|
TreeView_GetItem(g_TreeViewWnd, &tvi);
|
|
|
|
pdn = (PPCI_DN)tvi.lParam;
|
|
|
|
if (pdn) {
|
|
|
|
if ((pdnToFind->Bus == pdn->Bus) &&
|
|
(pdnToFind->Device == pdn->Device) &&
|
|
(pdnToFind->Function == pdn->Function)) {
|
|
|
|
*(PPCI_DN *)Pdn = pdn;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
#endif
|