589 lines
19 KiB
C++
589 lines
19 KiB
C++
/****************************************************************************
|
|
*
|
|
* File: ghost.cpp
|
|
* Project: DxDiag (DirectX Diagnostic Tool)
|
|
* Author: Mike Anderson (manders@microsoft.com)
|
|
* Purpose: Allow user to remove/restore "ghost" display devices
|
|
*
|
|
* (C) Copyright 1998-1999 Microsoft Corp. All rights reserved.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <tchar.h>
|
|
#include <Windows.h>
|
|
#include <multimon.h>
|
|
#include "reginfo.h"
|
|
#include "sysinfo.h"
|
|
#include "dispinfo.h"
|
|
#include "resource.h"
|
|
|
|
// Structure for ghost display devices
|
|
struct Ghost
|
|
{
|
|
TCHAR m_szKey[100];
|
|
TCHAR m_szDesc[100];
|
|
Ghost* m_pGhostPrev;
|
|
Ghost* m_pGhostNext;
|
|
};
|
|
|
|
static VOID BuildGhostList(BOOL bBackedUp, DisplayInfo* pDisplayInfoFirst, Ghost** ppGhostFirst);
|
|
static INT_PTR CALLBACK GhostDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
static VOID UpdateStuff(HWND hwnd);
|
|
static VOID MoveSelectedItems(HWND hwnd, BOOL bBackup);
|
|
static BOOL MoveGhost(HWND hwnd, Ghost* pGhost, BOOL bBackup);
|
|
static DWORD RegCreateTree(HKEY hTree, HKEY hReplacement);
|
|
static DWORD RegCreateValues(HKEY hReplacement, LPCTSTR lpSubKey, HKEY hNewKey);
|
|
static VOID RemoveFromListBox(Ghost* pGhost, HWND hwndList);
|
|
static VOID FreeGhostList(Ghost** ppGhostFirst);
|
|
|
|
static Ghost* s_pGhostBackedUpFirst = NULL;
|
|
static Ghost* s_pGhostRestoredFirst = NULL;
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* AdjustGhostDevices
|
|
*
|
|
****************************************************************************/
|
|
VOID AdjustGhostDevices(HWND hwndMain, DisplayInfo* pDisplayInfoFirst)
|
|
{
|
|
HINSTANCE hinst = (HINSTANCE)GetWindowLongPtr(hwndMain, GWLP_HINSTANCE);
|
|
|
|
BuildGhostList(TRUE, NULL, &s_pGhostBackedUpFirst);
|
|
BuildGhostList(FALSE, pDisplayInfoFirst, &s_pGhostRestoredFirst);
|
|
DialogBox(hinst, MAKEINTRESOURCE(IDD_GHOST), hwndMain, GhostDialogProc);
|
|
FreeGhostList(&s_pGhostBackedUpFirst);
|
|
FreeGhostList(&s_pGhostRestoredFirst);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* BuildGhostList
|
|
*
|
|
****************************************************************************/
|
|
VOID BuildGhostList(BOOL bBackedUp, DisplayInfo* pDisplayInfoFirst, Ghost** ppGhostFirst)
|
|
{
|
|
HKEY hkey;
|
|
HKEY hkey2;
|
|
DisplayInfo* pDisplayInfo;
|
|
TCHAR* pszCompare;
|
|
TCHAR szName[100];
|
|
LONG iKey;
|
|
Ghost* pGhostNew;
|
|
DWORD cbData = 100;
|
|
DWORD dwType;
|
|
BOOL bActive;
|
|
|
|
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, bBackedUp ?
|
|
TEXT("System\\CurrentControlSet\\Services\\Class\\DisplayBackup") :
|
|
TEXT("System\\CurrentControlSet\\Services\\Class\\Display"), KEY_READ, NULL, &hkey))
|
|
{
|
|
return;
|
|
}
|
|
|
|
iKey = 0;
|
|
while (ERROR_SUCCESS == RegEnumKey(hkey, iKey, szName, 100))
|
|
{
|
|
bActive = FALSE; // unless found TRUE below
|
|
for (pDisplayInfo = pDisplayInfoFirst; pDisplayInfo != NULL; pDisplayInfo = pDisplayInfo->m_pDisplayInfoNext)
|
|
{
|
|
pszCompare = pDisplayInfo->m_szKeyDeviceKey;
|
|
if (lstrlen(pszCompare) > 4)
|
|
{
|
|
pszCompare += (lstrlen(pszCompare) - 4);
|
|
if (lstrcmp(szName, pszCompare) == 0)
|
|
{
|
|
bActive = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!bActive &&
|
|
ERROR_SUCCESS == RegOpenKeyEx(hkey, szName, KEY_READ, NULL, &hkey2))
|
|
{
|
|
pGhostNew = new Ghost;
|
|
if (pGhostNew != NULL)
|
|
{
|
|
ZeroMemory(pGhostNew, sizeof(Ghost));
|
|
cbData = 100;
|
|
RegQueryValueEx(hkey2, TEXT("DriverDesc"), 0, &dwType, (LPBYTE)pGhostNew->m_szDesc, &cbData);
|
|
lstrcpy(pGhostNew->m_szKey, szName);
|
|
pGhostNew->m_pGhostNext = *ppGhostFirst;
|
|
if (pGhostNew->m_pGhostNext != NULL)
|
|
pGhostNew->m_pGhostNext->m_pGhostPrev = pGhostNew;
|
|
*ppGhostFirst = pGhostNew;
|
|
}
|
|
RegCloseKey(hkey2);
|
|
}
|
|
iKey++;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GhostDialogProc
|
|
*
|
|
****************************************************************************/
|
|
INT_PTR CALLBACK GhostDialogProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
HWND hwndRList = GetDlgItem(hwnd, IDC_RESTOREDLIST);
|
|
HWND hwndBList = GetDlgItem(hwnd, IDC_BACKEDUPLIST);
|
|
Ghost* pGhost;
|
|
TCHAR sz[300];
|
|
LRESULT iItem;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
for (pGhost = s_pGhostRestoredFirst; pGhost != NULL; pGhost = pGhost->m_pGhostNext)
|
|
{
|
|
wsprintf(sz, TEXT("%s: %s"), pGhost->m_szKey, pGhost->m_szDesc);
|
|
iItem = SendMessage(hwndRList, LB_ADDSTRING, 0, (LPARAM)sz);
|
|
SendMessage(hwndRList, LB_SETITEMDATA, iItem, (LPARAM)pGhost);
|
|
}
|
|
|
|
for (pGhost = s_pGhostBackedUpFirst; pGhost != NULL; pGhost = pGhost->m_pGhostNext)
|
|
{
|
|
wsprintf(sz, TEXT("%s: %s"), pGhost->m_szKey, pGhost->m_szDesc);
|
|
iItem = SendMessage(hwndBList, LB_ADDSTRING, 0, (LPARAM)sz);
|
|
SendMessage(hwndBList, LB_SETITEMDATA, iItem, (LPARAM)pGhost);
|
|
}
|
|
UpdateStuff(hwnd);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
WORD wID = LOWORD(wparam);
|
|
switch(wID)
|
|
{
|
|
case IDCANCEL:
|
|
EndDialog(hwnd, IDCANCEL);
|
|
break;
|
|
case IDOK:
|
|
EndDialog(hwnd, IDOK);
|
|
break;
|
|
case IDC_RESTOREDLIST:
|
|
if (HIWORD(wparam) == LBN_SELCHANGE)
|
|
{
|
|
if (SendMessage(hwndRList, LB_GETSELCOUNT, 0, 0) > 0)
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BACKUP), TRUE);
|
|
else
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BACKUP), FALSE);
|
|
}
|
|
break;
|
|
case IDC_BACKEDUPLIST:
|
|
if (HIWORD(wparam) == LBN_SELCHANGE)
|
|
{
|
|
if (SendMessage(hwndBList, LB_GETSELCOUNT, 0, 0) > 0)
|
|
EnableWindow(GetDlgItem(hwnd, IDC_RESTORE), TRUE);
|
|
else
|
|
EnableWindow(GetDlgItem(hwnd, IDC_RESTORE), FALSE);
|
|
}
|
|
break;
|
|
case IDC_BACKUP:
|
|
MoveSelectedItems(hwnd, TRUE);
|
|
UpdateStuff(hwnd);
|
|
break;
|
|
case IDC_RESTORE:
|
|
MoveSelectedItems(hwnd, FALSE);
|
|
UpdateStuff(hwnd);
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* UpdateStuff - Update some UI details based on lists.
|
|
*
|
|
****************************************************************************/
|
|
VOID UpdateStuff(HWND hwnd)
|
|
{
|
|
HWND hwndRList = GetDlgItem(hwnd, IDC_RESTOREDLIST);
|
|
HWND hwndBList = GetDlgItem(hwnd, IDC_BACKEDUPLIST);
|
|
|
|
if (SendMessage(hwndRList, LB_GETCOUNT, 0, 0) > 0)
|
|
{
|
|
if (SendMessage(hwndRList, LB_GETSELCOUNT, 0, 0) == 0)
|
|
SendMessage(hwndRList, LB_SETSEL, TRUE, 0); // Select first item
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BACKUP), TRUE);
|
|
}
|
|
else
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BACKUP), FALSE);
|
|
}
|
|
|
|
if (SendMessage(hwndBList, LB_GETCOUNT, 0, 0) > 0)
|
|
{
|
|
if (SendMessage(hwndBList, LB_GETSELCOUNT, 0, 0) == 0)
|
|
SendMessage(hwndBList, LB_SETSEL, TRUE, 0); // Select first item
|
|
EnableWindow(GetDlgItem(hwnd, IDC_RESTORE), TRUE);
|
|
}
|
|
else
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, IDC_RESTORE), FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* MoveSelectedItems
|
|
*
|
|
****************************************************************************/
|
|
VOID MoveSelectedItems(HWND hwnd, BOOL bBackup)
|
|
{
|
|
HWND hwndFromList;
|
|
HWND hwndToList;
|
|
Ghost** ppGhostFromFirst;
|
|
Ghost** ppGhostToFirst;
|
|
LONG iItemArray[100];
|
|
LONG iItem;
|
|
Ghost* pGhost;
|
|
Ghost* pGhost2;
|
|
TCHAR sz[200];
|
|
|
|
if (bBackup)
|
|
{
|
|
hwndFromList = GetDlgItem(hwnd, IDC_RESTOREDLIST);
|
|
hwndToList = GetDlgItem(hwnd, IDC_BACKEDUPLIST);
|
|
ppGhostFromFirst = &s_pGhostRestoredFirst;
|
|
ppGhostToFirst = &s_pGhostBackedUpFirst;
|
|
}
|
|
else
|
|
{
|
|
hwndFromList = GetDlgItem(hwnd, IDC_BACKEDUPLIST);
|
|
hwndToList = GetDlgItem(hwnd, IDC_RESTOREDLIST);
|
|
ppGhostFromFirst = &s_pGhostBackedUpFirst;
|
|
ppGhostToFirst = &s_pGhostRestoredFirst;
|
|
}
|
|
|
|
SendMessage(hwndFromList, LB_GETSELITEMS, 100, (LPARAM)iItemArray);
|
|
for (iItem = (LONG) SendMessage(hwndFromList, LB_GETSELCOUNT, 0, 0) - 1; iItem >= 0; iItem--)
|
|
{
|
|
pGhost = (Ghost*)SendMessage(hwndFromList, LB_GETITEMDATA, iItemArray[iItem], 0);
|
|
if (MoveGhost(hwnd, pGhost, bBackup))
|
|
{
|
|
// Remove from old list
|
|
if (pGhost->m_pGhostNext != NULL)
|
|
pGhost->m_pGhostNext->m_pGhostPrev = pGhost->m_pGhostPrev;
|
|
if (pGhost->m_pGhostPrev == NULL)
|
|
*ppGhostFromFirst = pGhost->m_pGhostNext;
|
|
else
|
|
pGhost->m_pGhostPrev->m_pGhostNext = pGhost->m_pGhostNext;
|
|
|
|
// Add to new list
|
|
pGhost->m_pGhostPrev = NULL;
|
|
pGhost->m_pGhostNext = *ppGhostToFirst;
|
|
if (pGhost->m_pGhostNext != NULL)
|
|
pGhost->m_pGhostNext->m_pGhostPrev = pGhost;
|
|
*ppGhostToFirst = pGhost;
|
|
|
|
// Update list boxes:
|
|
SendMessage(hwndFromList, LB_GETTEXT, iItemArray[iItem], (LPARAM)sz);
|
|
SendMessage(hwndFromList, LB_DELETESTRING, iItemArray[iItem], 0);
|
|
SendMessage(hwndToList, LB_SETITEMDATA, SendMessage(hwndToList, LB_ADDSTRING, 0, (LPARAM)sz), (LPARAM)pGhost);
|
|
|
|
// If we overwrote another Ghost with the same key, remove it from dest list:
|
|
for (pGhost2 = *ppGhostToFirst; pGhost2 != NULL; pGhost2 = pGhost2->m_pGhostNext)
|
|
{
|
|
if (pGhost2 != pGhost && lstrcmp(pGhost2->m_szKey, pGhost->m_szKey) == 0)
|
|
{
|
|
if (pGhost2->m_pGhostNext != NULL)
|
|
pGhost2->m_pGhostNext->m_pGhostPrev = pGhost2->m_pGhostPrev;
|
|
if (pGhost2->m_pGhostPrev == NULL)
|
|
*ppGhostToFirst = pGhost2->m_pGhostNext;
|
|
else
|
|
pGhost2->m_pGhostPrev->m_pGhostNext = pGhost2->m_pGhostNext;
|
|
RemoveFromListBox(pGhost2, hwndToList);
|
|
delete pGhost2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* MoveGhost
|
|
*
|
|
****************************************************************************/
|
|
BOOL MoveGhost(HWND hwnd, Ghost* pGhost, BOOL bBackup)
|
|
{
|
|
HKEY hkeySrcParent = NULL;
|
|
HKEY hkeySrc = NULL;
|
|
HKEY hkeyDestParent = NULL;
|
|
HKEY hkeyDest = NULL;
|
|
DWORD dwDisposition;
|
|
BOOL bRet = FALSE;
|
|
|
|
// Open source key:
|
|
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, bBackup ?
|
|
TEXT("System\\CurrentControlSet\\Services\\Class\\Display") :
|
|
TEXT("System\\CurrentControlSet\\Services\\Class\\DisplayBackup"),
|
|
KEY_ALL_ACCESS, NULL, &hkeySrcParent))
|
|
{
|
|
goto LEnd;
|
|
}
|
|
if (ERROR_SUCCESS != RegOpenKeyEx(hkeySrcParent, pGhost->m_szKey,
|
|
KEY_ALL_ACCESS, NULL, &hkeySrc))
|
|
{
|
|
goto LEnd;
|
|
}
|
|
|
|
// Create destination key:
|
|
if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_LOCAL_MACHINE, bBackup ?
|
|
TEXT("System\\CurrentControlSet\\Services\\Class\\DisplayBackup") :
|
|
TEXT("System\\CurrentControlSet\\Services\\Class\\Display"),
|
|
0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyDestParent, &dwDisposition))
|
|
{
|
|
goto LEnd;
|
|
}
|
|
// Ensure key isn't already there:
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyDestParent, pGhost->m_szKey, KEY_ALL_ACCESS, NULL, &hkeyDest))
|
|
{
|
|
RegCloseKey(hkeyDest);
|
|
hkeyDest = NULL;
|
|
|
|
TCHAR szMessage[300];
|
|
TCHAR szTitle[100];
|
|
|
|
LoadString(NULL, IDS_APPFULLNAME, szTitle, 100);
|
|
LoadString(NULL, IDS_REPLACEGHOST, szMessage, 300);
|
|
|
|
if (IDYES == MessageBox(hwnd, szMessage, szTitle, MB_YESNO))
|
|
{
|
|
RegDeleteKey(hkeyDestParent, pGhost->m_szKey);
|
|
}
|
|
else
|
|
{
|
|
goto LEnd;
|
|
}
|
|
}
|
|
if (ERROR_SUCCESS != RegCreateKeyEx(hkeyDestParent, pGhost->m_szKey, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyDest, &dwDisposition))
|
|
{
|
|
goto LEnd;
|
|
}
|
|
|
|
// Copy tree:
|
|
if (ERROR_SUCCESS != RegCreateValues(hkeySrc, NULL, hkeyDest))
|
|
goto LEnd;
|
|
if (ERROR_SUCCESS != RegCreateTree(hkeyDest, hkeySrc))
|
|
goto LEnd;
|
|
|
|
// Delete old tree
|
|
RegDeleteKey(hkeySrcParent, pGhost->m_szKey);
|
|
|
|
bRet = TRUE; // Everything succeeded
|
|
|
|
LEnd:
|
|
if (hkeySrcParent != NULL)
|
|
RegCloseKey(hkeySrcParent);
|
|
if (hkeySrc != NULL)
|
|
RegCloseKey(hkeySrc);
|
|
if (hkeyDestParent != NULL)
|
|
RegCloseKey(hkeyDestParent);
|
|
if (hkeyDest != NULL)
|
|
RegCloseKey(hkeyDest);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* RegCreateTree
|
|
*
|
|
****************************************************************************/
|
|
DWORD RegCreateTree(HKEY hTree, HKEY hReplacement)
|
|
{
|
|
#define REGSTR_MAX_VALUE_LENGTH 300
|
|
DWORD cdwClass, dwSubKeyLength, dwDisposition, dwKeyIndex = 0;
|
|
LPTSTR pSubKey = NULL;
|
|
TCHAR szSubKey[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
|
|
TCHAR szClass[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
|
|
HKEY hNewKey, hKey;
|
|
DWORD lRet;
|
|
|
|
for(;;)
|
|
{
|
|
dwSubKeyLength = REGSTR_MAX_VALUE_LENGTH;
|
|
cdwClass = REGSTR_MAX_VALUE_LENGTH;
|
|
lRet=RegEnumKeyEx(
|
|
hReplacement,
|
|
dwKeyIndex,
|
|
szSubKey,
|
|
&dwSubKeyLength,
|
|
NULL,
|
|
szClass,
|
|
&cdwClass,
|
|
NULL
|
|
);
|
|
if(lRet == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
lRet = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
else if(lRet == ERROR_SUCCESS)
|
|
{
|
|
if ((lRet=RegCreateKeyEx(hTree, szSubKey,0, szClass,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
|
|
&hNewKey, &dwDisposition)) != ERROR_SUCCESS )
|
|
break;
|
|
else // add key values and recurse
|
|
{
|
|
if ((lRet=RegCreateValues( hReplacement, szSubKey, hNewKey))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
CloseHandle(hNewKey);
|
|
break;
|
|
}
|
|
if ( (lRet=RegOpenKeyEx(hReplacement, szSubKey, 0,
|
|
KEY_ALL_ACCESS, &hKey )) == ERROR_SUCCESS )
|
|
{
|
|
lRet=RegCreateTree(hNewKey, hKey);
|
|
CloseHandle(hKey);
|
|
CloseHandle(hNewKey);
|
|
if ( lRet != ERROR_SUCCESS )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(hNewKey);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
++dwKeyIndex;
|
|
} // end for loop
|
|
return lRet;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* RegCreateValues
|
|
*
|
|
****************************************************************************/
|
|
DWORD RegCreateValues(HKEY hReplacement, LPCTSTR lpSubKey, HKEY hNewKey)
|
|
{
|
|
DWORD cbValue, dwSubKeyIndex=0, dwType, cdwBuf;
|
|
DWORD dwValues, cbMaxValueData, i;
|
|
LPTSTR pSubKey = NULL;
|
|
TCHAR szValue[REGSTR_MAX_VALUE_LENGTH]; // this should be dynamic.
|
|
HKEY hKey;
|
|
DWORD lRet = ERROR_SUCCESS;
|
|
LPBYTE pBuf;
|
|
|
|
if (lstrlen(lpSubKey) == 0)
|
|
{
|
|
hKey = hReplacement;
|
|
}
|
|
else
|
|
{
|
|
if ((lRet = RegOpenKeyEx(hReplacement, lpSubKey, 0,
|
|
KEY_ALL_ACCESS, &hKey )) != ERROR_SUCCESS)
|
|
{
|
|
return lRet;
|
|
}
|
|
}
|
|
if ((lRet = RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL,
|
|
NULL, &dwValues,NULL, &cbMaxValueData,
|
|
NULL, NULL)) == ERROR_SUCCESS)
|
|
{
|
|
if ( dwValues )
|
|
{
|
|
if ((pBuf = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
cbMaxValueData )))
|
|
{
|
|
for (i = 0; i < dwValues ; i++)
|
|
{
|
|
// get values to create
|
|
cbValue = REGSTR_MAX_VALUE_LENGTH;
|
|
cdwBuf = cbMaxValueData;
|
|
lRet = RegEnumValue(
|
|
hKey, // handle of key to query
|
|
i, // index of value to query
|
|
szValue, // buffer for value string
|
|
&cbValue, // address for size of buffer
|
|
NULL, // reserved
|
|
&dwType, // buffer address for type code
|
|
pBuf, // address of buffer for value data
|
|
&cdwBuf // address for size of buffer
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == lRet )
|
|
{
|
|
if( (lRet = RegSetValueEx(hNewKey, szValue, 0,
|
|
dwType, (CONST BYTE *)pBuf,
|
|
cdwBuf))!= ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
|
|
} // for loop
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, pBuf);
|
|
}
|
|
}
|
|
if (lstrlen(lpSubKey) != 0)
|
|
{
|
|
CloseHandle(hKey);
|
|
}
|
|
return lRet;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* RemoveFromListBox
|
|
*
|
|
****************************************************************************/
|
|
VOID RemoveFromListBox(Ghost* pGhostRemove, HWND hwndList)
|
|
{
|
|
LONG iItem;
|
|
Ghost* pGhost;
|
|
|
|
for (iItem = (LONG) SendMessage(hwndList, LB_GETCOUNT, 0, 0) - 1; iItem >= 0; iItem--)
|
|
{
|
|
pGhost = (Ghost*)SendMessage(hwndList, LB_GETITEMDATA, iItem, 0);
|
|
if (pGhost == pGhostRemove)
|
|
{
|
|
SendMessage(hwndList, LB_DELETESTRING, iItem, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FreeGhostList
|
|
*
|
|
****************************************************************************/
|
|
VOID FreeGhostList(Ghost** ppGhostFirst)
|
|
{
|
|
Ghost* pGhostNext;
|
|
while (*ppGhostFirst != NULL)
|
|
{
|
|
pGhostNext = (*ppGhostFirst)->m_pGhostNext;
|
|
delete *ppGhostFirst;
|
|
*ppGhostFirst = pGhostNext;
|
|
}
|
|
}
|