Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2088 lines
53 KiB

/*++
Copyright (c) 1989-2001 Microsoft Corporation
Module Name:
CSearch.cpp
Abstract:
This module contains code that handles the searching of the disk for
fixed entries.
Author:
kinshu created July 2, 2001
Notes:
The search window is implemented as a modeless window that has NULL as its parent.
We had to do this because we want the users to tab between the main window and the
search window
--*/
#include "precomp.h"
/////////////////////// Extern variables //////////////////////////////////////
extern BOOL g_bMainAppExpanded;
extern BOOL g_bSomeWizardActive;
extern HINSTANCE g_hInstance;
extern HWND g_hDlg;
extern HIMAGELIST g_hImageList;
///////////////////////////////////////////////////////////////////////////////
//////////////////////// Defines //////////////////////////////////////////////
// We're using the high 4 bits of the TAGID to say what PDB the TAGID is from.
#define PDB_MAIN 0x00000000
#define PDB_TEST 0x10000000
#define PDB_LOCAL 0x20000000
// Used to get the tag ref from the tagid, the low 28 bits
#define TAGREF_STRIP_TAGID 0x0FFFFFFF
// Used to get the PDB from the tagid, the high 4 bits
#define TAGREF_STRIP_PDB 0xF0000000
// Subitems for the columns of the list view
#define SEARCH_COL_AFFECTEDFILE 0
#define SEARCH_COL_PATH 1
#define SEARCH_COL_APP 2
#define SEARCH_COL_ACTION 3
#define SEARCH_COL_DBTYPE 4
// Total number of columns in the search dialog list view
#define TOT_COLS 5
///////////////////////////////////////////////////////////////////////////////
//////////////////////// Global variables /////////////////////////////////////
// Index where the next element will be inserted in the list view
UINT g_nIndex = 0;
// The search object
CSearch* g_pSearch;
// width and height of the dialog box. These are required in the WM_SIZE handler
int g_cWidthSrch;
int g_cHeightSrch;
//
// This will hold the path that we want to search. e.g c:\*.exe or c:\
// This will be the content of the text box
static TCHAR s_szPath[MAX_PATH + 5]; // just so that we can have *.exe at the end, if needed. This will be an invalid path.
// The path that the user last searched on.
static TCHAR s_szPrevPath[MAX_PATH + 5]; // just so that we can have *.exe at the end, if needed. This will be an invalid path.
//
// What type of entries are we looking for. The values of these will be set depending
// upon if the corresponding check boxes are set
BOOL s_bAppHelp; // We want to see entries with Apphelp
BOOL s_bShims; // We want to see entries with shims/flags or patches
BOOL s_bLayers; // We want to see entries with layers
HSDB g_hSDB;
// The handle to the search dialog
HWND g_hSearchDlg;
// The thread which does all the job
HANDLE g_hSearchThread = NULL;
// The handle to the search results list
HWND g_hwndSearchList;
// If this is TRUE, we must abort the search. Typically set when the user presses STOP button
BOOL g_bAbort;
// The critical section that guards g_bAbort and access to the list view
CRITICAL_SECTION g_CritSect;
// The handle to the main dialog
HWND g_hdlgSearchDB;
// This is a bit array that describes which cols are sorted in which fashion
static LONG s_lColumnSort;
//
// This will contain the cur dir before we started search
TCHAR g_szPresentDir[MAX_PATH];
// This will be the path that we want to show in the status bar
TCHAR g_szNewPathFound[MAX_PATH];
//////////////////////////////////////////////////////////////////////////////
//////////////////////// Function Declarations //////////////////////////////
void
ShowContextMenu(
WPARAM wParam,
LPARAM lParam
);
void
OnBrowse(
HWND hdlg
);
BOOL
AddNewResult(
LPARAM lParam
);
void
DoSearch(
HWND hDlg
);
void
OnSearchInitDialog(
HWND hDlg,
LPARAM lParam
);
void
SaveResults(
HWND hdlg
);
void
SearchDirectory(
LPTSTR szDir,
LPTSTR szExt
);
//////////////////////////////////////////////////////////////////////////////
void
GetCheckStatus(
IN HWND hDlg
)
/*++
GetCheckStatus
Desc: Ses static variables by looking which check boxes have been selected
Params:
IN HWND hDlg: The search dialog box
Return:
void
Notes: The check boxes work in OR manner. So if we select all of them it means select fixes
that have either of them
--*/
{
//
// Do we want to search for entries with Apphelp?
//
s_bAppHelp = (IsDlgButtonChecked(hDlg, IDC_CHKAPP) == BST_CHECKED) ? TRUE : FALSE;
//
// Do we want to search for entries with shims, flags or patches?
//
s_bShims = (IsDlgButtonChecked(hDlg, IDC_CHKSHI) == BST_CHECKED) ? TRUE : FALSE;
//
// Do we want to search for entries with layers?
//
s_bLayers = (IsDlgButtonChecked(hDlg, IDC_CHKLAY) == BST_CHECKED) ? TRUE : FALSE;
}
void
StopSearch(
void
)
/*++
StopSearch
Desc: Enables/Disables the various buttons and does other stuff that has to
be done after the search has stopped because it was complete or the user
pressed Stop button
Notes: Does not actually stop the search, but performs the necessary actions after
search has been stopped
--*/
{
HWND hwndList = NULL;
if (g_hSearchThread) {
CloseHandle(g_hSearchThread);
g_hSearchThread = NULL;
}
KillTimer(g_hSearchDlg, 0);
Animate_Stop(GetDlgItem(g_hSearchDlg, IDC_ANIMATE));
SetCurrentDirectory(g_szPresentDir);
EnableWindow(GetDlgItem(g_hSearchDlg, IDC_STOP), FALSE);
EnableWindow(GetDlgItem(g_hSearchDlg, IDC_SEARCH), TRUE);
EnableWindow(GetDlgItem(g_hSearchDlg, IDC_NEWSEARCH), TRUE);
EnableWindow(GetDlgItem(g_hSearchDlg, IDC_SAVE), TRUE);
EnableWindow(GetDlgItem(g_hSearchDlg, IDC_CHKAPP), TRUE);
EnableWindow(GetDlgItem(g_hSearchDlg, IDC_CHKLAY), TRUE);
EnableWindow(GetDlgItem(g_hSearchDlg, IDC_CHKSHI), TRUE);
hwndList = GetDlgItem(g_hSearchDlg, IDC_LIST);
//
// We need to enable the static control if we have found some results in search
//
EnableWindow(GetDlgItem(g_hSearchDlg, IDC_STATIC_CAPTION),
ListView_GetItemCount(hwndList) > 0);
SetActiveWindow(g_hdlgSearchDB);
SetFocus(g_hdlgSearchDB);
}
void
HandleSearchSizing(
IN HWND hDlg
)
/*++
HandleSearchSizing
Desc: Handles WM_SIZE for the search dialog
Paras:
IN HWND hDlg: The search dialog
Return:
void
--*/
{
int nWidth;
int nHeight;
int nStatusbarTop;
RECT rDlg;
if (g_cWidthSrch == 0 || g_cHeightSrch == 0) {
return;
}
GetWindowRect(hDlg, &rDlg);
nWidth = rDlg.right - rDlg.left;
nHeight = rDlg.bottom - rDlg.top;
int deltaW = nWidth - g_cWidthSrch;
int deltaH = nHeight - g_cHeightSrch;
HWND hwnd;
RECT r;
HDWP hdwp = BeginDeferWindowPos(10);
if (hdwp == NULL) {
//
// NULL indicates that insufficient system resources are available to
// allocate the structure. To get extended error information, call GetLastError.
//
assert(FALSE);
goto End;
}
//
// The status bar
//
hwnd = GetDlgItem(hDlg, IDC_STATUSBAR);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left,
nStatusbarTop = r.top + deltaH,
r.right - r.left + deltaW,
r.bottom - r.top + deltaH,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The result list view
//
hwnd = GetDlgItem(hDlg, IDC_LIST);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left,
r.top,
r.right - r.left + deltaW,
nStatusbarTop - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The browse button
//
hwnd = GetDlgItem(hDlg, IDC_BROWSE);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left + deltaW,
r.top,
r.right - r.left,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The search button
//
hwnd = GetDlgItem(hDlg, IDC_SEARCH);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left + deltaW,
r.top,
r.right - r.left,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The save button. Used to export results to a tab separated text file
//
hwnd = GetDlgItem(hDlg, IDC_SAVE);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left + deltaW,
r.top,
r.right - r.left,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The stop button
//
hwnd = GetDlgItem(hDlg, IDC_STOP);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left + deltaW,
r.top,
r.right - r.left,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The new search button
//
hwnd = GetDlgItem(hDlg, IDC_NEWSEARCH);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left + deltaW,
r.top,
r.right - r.left,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The help button
//
hwnd = GetDlgItem(hDlg, IDC_SEARCH_HELP);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left + deltaW,
r.top,
r.right - r.left,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The animate control
//
hwnd = GetDlgItem(hDlg, IDC_ANIMATE);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left + deltaW,
r.top,
r.right - r.left,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The text box
//
hwnd = GetDlgItem(hDlg, IDC_PATH);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left,
r.top,
r.right - r.left + deltaW,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
//
// The group control
//
hwnd = GetDlgItem(hDlg, IDC_GROUP);
GetWindowRect(hwnd, &r);
MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
DeferWindowPos(hdwp,
hwnd,
NULL,
r.left,
r.top,
r.right - r.left + deltaW,
r.bottom - r.top,
SWP_NOZORDER | SWP_NOACTIVATE);
EndDeferWindowPos(hdwp);
ListView_SetColumnWidth(g_hwndSearchList, TOT_COLS - 1, LVSCW_AUTOSIZE_USEHEADER);
g_cWidthSrch = nWidth;
g_cHeightSrch = nHeight;
End:
return;
}
INT_PTR
HandleTextChange(
IN HWND hdlg,
IN WPARAM wParam
)
/*++
HandleTextChange
Desc: Handles the WM_COMMAND messages for the text box
Params:
IN HWND hdlg: The handle to the query dilaog box
IN WPARAM wParam: The wParam that comes with WM_COMMAND
Return:
TRUE: If we process this message
FALSE: Otherwise
--*/
{
TCHAR szText[MAX_PATH];
DWORD dwFlags;
BOOL bEnable;
INT_PTR ipReturn = FALSE;
switch (HIWORD(wParam)) {
case EN_CHANGE:
//
// We disable the search button if there is no path that we can search on//
//
*szText = 0;
GetDlgItemText(hdlg, IDC_PATH, szText, ARRAYSIZE(szText));
bEnable = ValidInput(szText);
//
// If we have some text in the text field, enable the search button, otherwise
// disable it
//
EnableWindow(GetDlgItem(hdlg, IDC_SEARCH), bEnable);
ipReturn = TRUE;
break;
default: ipReturn = FALSE;
}
return ipReturn;
}
INT_PTR CALLBACK
SearchDialog(
IN HWND hDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
SearchDialog
Desc: Dialog proc for the search dialog
Paras: Standard dialog handler parameters
IN HWND hDlg
IN UINT uMsg
IN WPARAM wParam
IN LPARAM lParam
Return: Standard dialog handler return
--*/
{
switch (uMsg) {
case WM_SIZE:
if (wParam != SIZE_MINIMIZED) {
HandleSearchSizing(hDlg);
}
break;
case WM_GETMINMAXINFO:
{
MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
pmmi->ptMinTrackSize.x = 400;
pmmi->ptMinTrackSize.y = 365;
return 0;
break;
}
case WM_INITDIALOG:
OnSearchInitDialog(hDlg, lParam);
break;
case WM_DESTROY:
{
HIMAGELIST hImageList = ListView_GetImageList(g_hwndSearchList, LVSIL_SMALL);
if (hImageList) {
ImageList_Destroy(hImageList);
}
hImageList = ListView_GetImageList(g_hwndSearchList, LVSIL_NORMAL);
if (hImageList) {
ImageList_Destroy(hImageList);
}
g_hdlgSearchDB = NULL;
if (g_pSearch) {
delete g_pSearch;
g_pSearch = NULL;
}
DeleteCriticalSection(&g_CritSect);
//
// Remove the list view contents and the items that are tied with it.
//
ClearResults(hDlg, TRUE);
return 0;
}
case WM_USER_NEWMATCH:
AddNewResult(lParam);
break;
case WM_USER_NEWFILE:
{
EnterCriticalSection(&g_CritSect);
if (g_pSearch) {
SetWindowText(g_pSearch->m_hStatusBar , (LPTSTR)lParam);
}
if (lParam) {
delete[] ((TCHAR*)lParam);
}
LeaveCriticalSection(&g_CritSect);
break;
}
case WM_CONTEXTMENU:
ShowContextMenu(wParam, lParam);
break;
case WM_NOTIFY:
{
LPNMHDR lpnmhdr = (LPNMHDR)lParam;
if (lpnmhdr && lpnmhdr->idFrom == IDC_LIST) {
return HandleSearchListNotification(hDlg, lParam);
}
return FALSE;
}
case WM_TIMER:
if (g_hSearchThread) {
if (WAIT_OBJECT_0 == WaitForSingleObject(g_hSearchThread, 0)) {
StopSearch();
K_SIZE k_size = 260;
TCHAR* pszString = new TCHAR[k_size];
if (pszString == NULL) {
MEM_ERR;
break;
}
SafeCpyN(pszString, CSTRING(IDS_SEARCHCOMPLETE), k_size);
SendNotifyMessage(g_hSearchDlg, WM_USER_NEWFILE, 0,(LPARAM)pszString);
}
}
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_STOP:
g_bAbort = TRUE;
break;
case IDC_BROWSE:
OnBrowse(hDlg);
break;
case IDC_SEARCH:
DoSearch(hDlg);
break;
case IDC_NEWSEARCH:
ClearResults(hDlg, TRUE);
break;
case IDC_SAVE:
SaveResults(hDlg);
break;
case IDC_PATH:
HandleTextChange(hDlg, wParam);
break;
case IDC_SEARCH_HELP:
ShowInlineHelp(TEXT("searching_for_fixes.htm"));
break;
case IDCANCEL:
{
Animate_Close(GetDlgItem(hDlg, IDC_ANIMATE));
g_bAbort = TRUE;
if (g_hSearchThread) {
WaitForSingleObject(g_hSearchThread, INFINITE);
}
DestroyWindow(hDlg);
break;
}
case ID_VIEWCONTENTS:
{
LVITEM lvi;
PMATCHEDENTRY pmMatched;
INT iSelection;
iSelection = ListView_GetSelectionMark(g_hwndSearchList);
if (iSelection == -1) {
break;
}
ZeroMemory(&lvi, sizeof(lvi));
lvi.iItem = iSelection;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
if (ListView_GetItem(g_hwndSearchList, &lvi)) {
pmMatched = (PMATCHEDENTRY)lvi.lParam;
GotoEntry(pmMatched);
}
break;
}
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
DWORD WINAPI
SearchThread(
IN LPVOID pVoid
)
/*++
SearchThread
Desc: The thread routine that does the actual search
Params:
IN LPVOID pVoid: Pointer to the search string. We get it trimmed
Return:
0
--*/
{
LPTSTR szSearch = (LPTSTR)pVoid;
PTCHAR pchFirstSlash = NULL;
DWORD dwReturn;
//
// Separate the extension and the directory
//
TCHAR szDrive[_MAX_DRIVE], szDir[MAX_PATH], szFile[MAX_PATH * 2] , szExt[MAX_PATH], szDirWithDrive[MAX_PATH * 2];
*szDirWithDrive = *szDrive = *szDir = *szFile = *szExt = 0;
_tsplitpath(szSearch, szDrive, szDir, szFile, szExt);
SafeCpyN(szDirWithDrive, szDrive, ARRAYSIZE(szDirWithDrive));
StringCchCat(szDirWithDrive, ARRAYSIZE(szDirWithDrive), szDir);
if (lstrlen(szDirWithDrive) == 0) {
//
// Only the file name is there, check in the current drive
//
*szDirWithDrive = 0;
dwReturn = GetCurrentDirectory(MAX_PATH, szDirWithDrive);
if (dwReturn > 0 && dwReturn < ARRAYSIZE(szDirWithDrive)) {
pchFirstSlash = _tcschr(szDirWithDrive, TEXT('\\'));
if (pchFirstSlash) {
//
// We will now get only the present drive in szDirWithDrive
//
*(++pchFirstSlash) = 0;
}
} else {
//
// Error condition.
//
Dbg(dlError, "[SearchThread]: Could not execute GetCurrentDirectory properly");
goto End;
}
}
StringCchCat(szFile, ARRAYSIZE(szFile), szExt);
if (lstrlen(szFile) == 0) {
SafeCpyN(szFile, TEXT("*.EXE"), ARRAYSIZE(szFile));
}
if (!SetCurrentDirectory(szDirWithDrive)) {
MSGF(g_hdlgSearchDB,
g_szAppName,
MB_ICONINFORMATION,
TEXT("\'%s\'-%s"),
szDirWithDrive,
GetString(IDS_PATHERROR));
return 0;
}
SearchDirectory(szDirWithDrive, szFile);
End:
return 0;
}
void
Search(
IN HWND hDlg,
IN LPCTSTR szSearch
)
/*++
Search
Desc: Creates the thread that will do the actual search
Params:
IN HWND hDlg: The search dialog
IN LPCTSTR szSearch: The files to search
Return:
void
--*/
{
DWORD dwID;
Animate_Play(GetDlgItem(hDlg, IDC_ANIMATE), 0, -1, -1);
g_hSearchThread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START)SearchThread, (PVOID)szSearch, 0, (unsigned int*)&dwID);
}
BOOL
PopulateFromExes(
IN LPTSTR szPath,
IN TAGREF tagref
)
/*++
PopulateFromExes
Desc: For the file with path szPath, checks if it needs to be added to the results
list view and if yes, then calls SendNotifyMessage() to add this to the results
list view
Params:
IN LPTSTR szPath: The path of the file found
IN TAGREF tagref: TAGREF for the entry. The TAGREF incorporates the TAGID and a
constant that tells us which PDB the TAGID is from.
Return:
--*/
{
BOOL bEntryHasAppHelp = FALSE;
BOOL bEntryHasShims = FALSE;
BOOL bEntryHasPatches = FALSE;
BOOL bEntryHasFlags = FALSE;
BOOL bEntryHasLayers = FALSE;
TAGID ID; //TAGID for the entry
PDB pDB; //The database pdb
BOOL bOk = TRUE;
PMATCHEDENTRY pmEntry = new MATCHEDENTRY;
if (pmEntry == NULL) {
MEM_ERR;
return FALSE;
}
//
// Get the database pdb and the tag id for this tagref of the entry. We need
// these so that we can get the properties of this entry from the database in which
// it resides
//
if (!SdbTagRefToTagID(g_hSDB, tagref, &pDB, &ID)) {
bOk = FALSE;
assert(FALSE);
goto End;
}
//
// Find out how this entry has been fixed. Get its app-name as well
//
if (pDB == NULL || !LookUpEntryProperties(pDB,
ID,
&bEntryHasLayers,
&bEntryHasShims,
&bEntryHasPatches,
&bEntryHasFlags,
&bEntryHasAppHelp,
pmEntry->strAppName)) {
assert(FALSE);
bOk = FALSE;
goto End;
}
pmEntry->tiExe = ID;
pmEntry->strPath = szPath;
switch (tagref & TAGREF_STRIP_PDB) {
case PDB_MAIN:
pmEntry->strDatabase = CSTRING(IDS_GLOBAL);
break;
case PDB_TEST:
pmEntry->strDatabase = CSTRING(IDS_TEST);
break;
case PDB_LOCAL:
pmEntry->strDatabase = CSTRING(IDS_LOCAL);
break;
default:
pmEntry->strDatabase = CSTRING(IDS_LOCAL);
break;
}
if (!GetDbGuid(pmEntry->szGuid, ARRAYSIZE(pmEntry->szGuid), pDB)) {
assert(FALSE);
bOk = FALSE;
goto End;
}
BOOL bShow = FALSE;
if (bEntryHasAppHelp && s_bAppHelp) {
pmEntry->strAction.Strcat(CSTRING(IDS_APPHELPS));
bShow = TRUE;
}
if ((bEntryHasShims || bEntryHasFlags || bEntryHasPatches) && s_bShims) {
pmEntry->strAction.Strcat(CSTRING(IDS_FIXES));
bShow = TRUE;
}
if (bEntryHasLayers && s_bLayers) {
pmEntry->strAction.Strcat(CSTRING(IDS_MODES));
bShow = TRUE;
}
int nLength = pmEntry->strAction.Length();
if (nLength) {
pmEntry->strAction.SetChar(nLength - 1, TEXT('\0'));
}
if (bShow) {
SendNotifyMessage(g_hSearchDlg, WM_USER_NEWMATCH, 0, (LPARAM)pmEntry);
}
//
// NOTE: the strings of pmEntry that are not used later are freed by the handler
// of WM_USER_NEWMATCH, only the szGuid is retained
// after the handler of WM_USER_NEWMATCH ends.
// This is required so that we can double click on the list item.
//
// The pmEntry data-structure is deleted when the window gets destroyed
//
End:
if (bOk == FALSE && pmEntry) {
delete pmEntry;
}
return bOk;
}
void
SearchDirectory(
IN LPTSTR pszDir,
IN LPTSTR szExtension
)
/*++
SearchDirectory
Desc: Searches a directory recursively for fixed files with a specified extension.
Wild cards are allowed
Params:
IN LPTSTR pszDir: The directory to search in. This may or may not have a ending \
IN LPTSTR szExtension: The extensions to look for
Return:
void
Note: If pszDir is a drive should have a \ at the end
--*/
{
HANDLE hFile;
WIN32_FIND_DATA Data;
TCHAR szCurrentDir[MAX_PATH_BUFFSIZE];
BOOL bAbort = FALSE;
TCHAR* pszString = NULL;
INT iLength = 0;
DWORD dwReturn = 0;
*szCurrentDir = 0;
dwReturn = GetCurrentDirectory(ARRAYSIZE(szCurrentDir), szCurrentDir);
if (dwReturn == 0 || dwReturn >= ARRAYSIZE(szCurrentDir)) {
assert(FALSE);
Dbg(dlError, "SearchDirectory GetCurrentDirectory Failed");
return;
}
if (!SetCurrentDirectory(pszDir)) {
//
// We do not prompt here, because we might have encountered a directory that we
// do not have rights to access. Typically, network paths.
//
return;
}
iLength = lstrlen(pszDir) + 1;
pszString = new TCHAR[iLength];
if (pszString == NULL) {
MEM_ERR;
return;
}
SafeCpyN(pszString, pszDir, iLength);
SendNotifyMessage(g_hSearchDlg, WM_USER_NEWFILE, 0, (LPARAM)pszString);
hFile = FindFirstFile(szExtension, &Data);
if (hFile != INVALID_HANDLE_VALUE) {
do {
CSTRING szStr;
szStr.Sprintf(TEXT("%s"), pszDir);
if (*pszDir && TEXT('\\') != pszDir[lstrlen(pszDir) - 1]) {
szStr.Strcat(TEXT("\\"));
}
szStr.Strcat(Data.cFileName);
SDBQUERYRESULT Res;
ZeroMemory(&Res, sizeof(SDBQUERYRESULT));
//
// Determine if this file is affected in any way.
//
if ((Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
if (SdbGetMatchingExe(g_hSDB,
(LPCTSTR)szStr,
NULL,
NULL,
SDBGMEF_IGNORE_ENVIRONMENT,
&Res)) {
//
// At the moment we only look for exe entires. i.e. to say, we
// do not catch programs fixed using the compat UI or the tab
// we only show programs that have been fixed by installing some
// custom database
//
for (int nExeLoop = 0; nExeLoop < SDB_MAX_EXES; ++nExeLoop) {
if (Res.atrExes[nExeLoop]) {
PopulateFromExes(szStr, Res.atrExes[nExeLoop]);
}
}
}
//
// Close any local databases that might have been opened by SdbGetMatchingExe(...)
//
SdbReleaseMatchingExe(g_hSDB, Res.atrExes[0]);
}
bAbort = g_bAbort;
} while (FindNextFile(hFile, &Data) && !bAbort);
FindClose(hFile);
}
//
// Now go through the sub-directories.
//
hFile = FindFirstFile(TEXT("*.*"), &Data);
if (hFile != INVALID_HANDLE_VALUE) {
do {
if (Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
BOOL bForbidden = FALSE;
if (TEXT('.') == Data.cFileName[0]) {
bForbidden = TRUE;
}
if (!bForbidden) {
TCHAR szPath[MAX_PATH * 2];
SafeCpyN(szPath, pszDir, MAX_PATH);
ADD_PATH_SEPARATOR(szPath, ARRAYSIZE(szPath));
StringCchCat(szPath, ARRAYSIZE(szPath), Data.cFileName);
SearchDirectory(szPath, szExtension);
}
}
bAbort = g_bAbort;
} while (FindNextFile(hFile, &Data) && !bAbort);
FindClose(hFile);
}
SetCurrentDirectory(szCurrentDir);
}
void
CSearch::Begin(
void
)
/*++
CSearch::Begin
Desc: Begins the search
--*/
{
if (g_hSDB == NULL) {
g_hSDB = SdbInitDatabase(0, NULL);
}
g_pSearch = this;
InitializeCriticalSection(&g_CritSect);
HWND hwnd = CreateDialog(g_hInstance,
MAKEINTRESOURCE(IDD_SEARCH),
GetDesktopWindow(),
SearchDialog);
ShowWindow(hwnd, SW_NORMAL);
return;
}
void
GotoEntry(
IN PMATCHEDENTRY pmMatched
)
/*++
GotoEntry
Desc: Selects the entry with tagid of pmMatched->tiExe in the entry tree.
Params:
IN PMATCHEDENTRY pmMatched: Contains information about the entry that we want to
show in the contents pane(RHS) and the database pane(LHS) in the main window
Return:
void
--*/
{
if (g_bSomeWizardActive) {
//
// We do not want that the focus should go to some other database, because
// some wizard is active, which believes that he is modal.
//
MessageBox(g_hdlgSearchDB, GetString(IDS_SOMEWIZARDACTIVE), g_szAppName, MB_ICONINFORMATION);
return;
}
if (pmMatched == NULL) {
assert(FALSE);
return;
}
BOOL bMainSDB = FALSE;
WCHAR wszShimDB[MAX_PATH];
*wszShimDB = 0;
if (pmMatched == NULL) {
return;
}
PDATABASE pDatabase = NULL;
if (lstrcmp(GlobalDataBase.szGUID, pmMatched->szGuid) == 0) {
//
// This is the global database
//
pDatabase = &GlobalDataBase;
bMainSDB = TRUE;
if (!g_bMainAppExpanded) {
SetStatus(GetDlgItem(g_hSearchDlg, IDC_STATUSBAR), IDS_LOADINGMAIN);
SetCursor(LoadCursor(NULL, IDC_WAIT));
INT iResult = ShowMainEntries(g_hdlgSearchDB);
if (iResult == -1) {
SetStatus(GetDlgItem(g_hdlgSearchDB, IDC_STATUSBAR), CSTRING(IDS_LOADINGMAIN));
SetCursor(LoadCursor(NULL, IDC_WAIT));
return;
} else {
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
SetStatus(GetDlgItem(g_hSearchDlg, IDC_STATUSBAR), TEXT(""));
}
} else {
//
// We have to now search for the database in the installed databases list
//
PDATABASE pDatabaseInstalled = InstalledDataBaseList.pDataBaseHead;
while (pDatabaseInstalled) {
if (lstrcmpi(pmMatched->szGuid, pDatabaseInstalled->szGUID) == 0) {
pDatabase = pDatabaseInstalled;
break;
}
pDatabaseInstalled = pDatabaseInstalled->pNext;
}
if (pDatabaseInstalled == NULL) {
//
// We might come here if the database was uninstalled after we populated
// the search results
//
MessageBox(g_hSearchDlg, GetString(IDS_NOLONGEREXISTS), g_szAppName, MB_ICONWARNING);
return;
}
}
//
// Now for this database, search the particular entry
//
PDBENTRY pApp = pDatabase->pEntries, pEntry;
pEntry = pApp;
while (pApp) {
pEntry = pApp;
while (pEntry) {
if (pEntry->tiExe == pmMatched->tiExe) {
goto EndLoop;
}
pEntry = pEntry->pSameAppExe;
}
pApp = pApp->pNext;
}
if (pApp == NULL) {
MessageBox(g_hSearchDlg, GetString(IDS_NOLONGEREXISTS), g_szAppName, MB_ICONWARNING);
return;
}
EndLoop:
//
// Select the app in the DB tree
//
HTREEITEM hItemEntry = DBTree.FindChild(pDatabase->hItemAllApps, (LPARAM)pApp);
assert(hItemEntry);
TreeView_SelectItem(DBTree.m_hLibraryTree, hItemEntry);
//
// Now select the entry within the app in the entry tree
//
hItemEntry = CTree::FindChild(g_hwndEntryTree, TVI_ROOT, (LPARAM)pEntry);
assert(hItemEntry);
if (hItemEntry) {
TreeView_SelectItem(g_hwndEntryTree, hItemEntry);
SetFocus(g_hwndEntryTree);
}
}
BOOL
HandleSearchListNotification(
IN HWND hdlg,
IN LPARAM lParam
)
/*++
HandleSearchListNotification
Desc: Handles the notification messages for the Search List
Params:
IN HWND hdlg: The search dialog
IN LPARAM lParam: The LPARAM of WM_NOTIFY
Return:
TRUE: If the message was handled by this routine.
FALSE: Otherwise
--*/
{
LPNMHDR pnm = (LPNMHDR)lParam;
HWND hwndList = GetDlgItem(hdlg, IDC_LIST);
switch (pnm->code) {
case NM_DBLCLK:
SendMessage(hdlg, WM_COMMAND, (WPARAM)ID_VIEWCONTENTS, 0);
break;
case LVN_COLUMNCLICK:
{
LPNMLISTVIEW pnmlv = (LPNMLISTVIEW)lParam;
COLSORT colSort;
colSort.hwndList = hwndList;
colSort.iCol = pnmlv->iSubItem;
colSort.lSortColMask = s_lColumnSort;
ListView_SortItemsEx(hwndList, CompareItemsEx, &colSort);
if ((s_lColumnSort & 1L << colSort.iCol) == 0) {
//
// Was in ascending order
//
s_lColumnSort |= (1L << colSort.iCol);
} else {
s_lColumnSort &= (~(1L << colSort.iCol));
}
break;
}
default: return FALSE;
}
return TRUE;
}
void
ClearResults(
IN HWND hdlg,
IN BOOL bClearSearchPath
)
/*++
ClearResults
Desc: Clears the contents of the list view and the text box
Params:
IN HWND hdlg: The search dialog
IN BOOL bClearSearchPath: Do we wish to clear the contents of the text field also
--*/
{
HWND hwndList = GetDlgItem(hdlg, IDC_LIST);
INT iCount = ListView_GetItemCount(hwndList);
LVITEM lvi;
ZeroMemory(&lvi, sizeof(lvi));
//
// Free the lParam for the list view.
//
CleanUpListView(hdlg);
SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
ListView_DeleteAllItems(hwndList);
SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
InvalidateRect(hwndList, NULL, TRUE);
UpdateWindow(hwndList);
if (bClearSearchPath) {
SetDlgItemText(hdlg, IDC_PATH, TEXT(""));
}
}
void
SaveResults(
IN HWND hdlg
)
/*++
SaveResults
Desc: Saves the search results in a tab separated file
Params:
IN HWND hdlg: The search dialog
--*/
{
CSTRING strFileName;
TCHAR szTitle[256], szFilter[128], szExt[8];
*szTitle = *szFilter = *szExt = 0;
BOOL bResult = GetFileName(hdlg,
GetString(IDS_SAVE_RESULTS_TITLE, szTitle, ARRAYSIZE(szTitle)),
GetString(IDS_SAVE_RESULTS_FILTER, szFilter, ARRAYSIZE(szFilter)),
TEXT(""),
GetString(IDS_SAVE_RESULTS_EXT, szExt, ARRAYSIZE(szExt)),
OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT,
FALSE,
strFileName,
TRUE);
if (bResult) {
SetCursor(LoadCursor(NULL, IDC_WAIT));
SaveListViewToFile(GetDlgItem(hdlg, IDC_LIST), TOT_COLS, strFileName.pszString, NULL);
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
}
void
CleanUpListView(
IN HWND hdlg
)
/*++
CleanUpListView
Desc: Frees the structures associated with the lParam of the list view
Params:
IN HWND hdlg: The search dialog
******************************************************************************
Warn: This method should not be directky called. Call ClearResults instead
******************************************************************************
--*/
{
HWND hwndList = GetDlgItem(hdlg, IDC_LIST);
INT iCount = ListView_GetItemCount(hwndList);
LVITEM lvi;
ZeroMemory(&lvi, sizeof(lvi));
//
// Free the lParam for the list view.
//
for (INT iIndex = 0; iIndex < iCount; ++iIndex) {
lvi.mask = LVIF_PARAM;
lvi.iItem = iIndex;
lvi.iSubItem = 0;
if (ListView_GetItem(hwndList, &lvi) && lvi.lParam) {
delete (PMATCHEDENTRY)lvi.lParam;
} else {
assert(FALSE);
}
}
}
void
OnSearchInitDialog(
IN HWND hDlg,
IN LPARAM lParam
)
/*++
OnSearchInitDialog
Desc: Handles WM_INITDIALOG for the search dialog box
Params:
IN HWND hDlg: The search dialog box
IN LPARAM lParam: The lParam for WM_INITDIALOG
Return:
void
--*/
{
//
// Limit the length of the path text field
//
SendMessage(GetDlgItem(hDlg, IDC_PATH),
EM_LIMITTEXT,
(WPARAM)MAX_PATH - 1,
(LPARAM)0);
g_hdlgSearchDB = hDlg;
s_lColumnSort = 0;
Animate_OpenEx(GetDlgItem(hDlg, IDC_ANIMATE),
g_hInstance,
MAKEINTRESOURCE(IDA_SEARCH));
//
// Set all the buttons
//
CheckDlgButton(hDlg, IDC_CHKLAY, BST_CHECKED);
CheckDlgButton(hDlg, IDC_CHKSHI, BST_CHECKED);
CheckDlgButton(hDlg, IDC_CHKAPP, BST_CHECKED);
EnableWindow(GetDlgItem(hDlg, IDC_STOP), FALSE);
g_pSearch->m_hStatusBar = GetDlgItem(hDlg, IDC_STATUSBAR);
CSearch* pPresentSearch = (CSearch*)lParam;
g_hSearchDlg = hDlg;
g_hwndSearchList = GetDlgItem(hDlg, IDC_LIST);
ListView_SetExtendedListViewStyleEx(g_hwndSearchList,
0,
LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT);
//
// Add the columns that we are going to show in the list view
//
//
// Name of the fixed program file
//
InsertColumnIntoListView(g_hwndSearchList,
GetString(IDS_AFFECTED_FILE),
SEARCH_COL_AFFECTEDFILE,
20);
//
// Path of the fixed program file
//
InsertColumnIntoListView(g_hwndSearchList,
GetString(IDS_PATH),
SEARCH_COL_PATH,
30);
//
// App-Name of the fixed program file
//
InsertColumnIntoListView(g_hwndSearchList,
GetString(IDS_APP),
SEARCH_COL_APP,
20);
//
// Action type. This column will show a concatenated string specifying
// whether fixes, layers and/or apphelp is used for this entry
//
InsertColumnIntoListView(g_hwndSearchList,
GetString(IDS_ACTION),
SEARCH_COL_ACTION,
15);
//
// The database type of the database where the entry resides. One of Global or Local
//
InsertColumnIntoListView(g_hwndSearchList,
GetString(IDS_DATABASE),
SEARCH_COL_DBTYPE,
15);
ListView_SetColumnWidth(g_hwndSearchList, TOT_COLS - 1, LVSCW_AUTOSIZE_USEHEADER);
RECT r;
GetWindowRect(hDlg, &r);
g_cWidthSrch = r.right - r.left;
g_cHeightSrch = r.bottom - r.top;
SHAutoComplete(GetDlgItem(hDlg, IDC_PATH), AUTOCOMPLETE);
if (*s_szPrevPath) {
//
// The user has invoked the search dialog previously, let us
// now show the directory/path that he searched for previously
//
SetDlgItemText(hDlg, IDC_PATH, s_szPrevPath);
} else {
//
// This is the first time that the user is using this search option.
// Default to the programs folder
//
LPITEMIDLIST lpIDL = NULL;
if (SUCCEEDED(SHGetFolderLocation(NULL,
CSIDL_PROGRAM_FILES,
NULL,
0,
&lpIDL))) {
if (lpIDL == NULL) {
return;
}
if (SHGetPathFromIDList(lpIDL, s_szPath)) {
ADD_PATH_SEPARATOR(s_szPath, ARRAYSIZE(s_szPath));
StringCchCat(s_szPath, ARRAYSIZE(s_szPath), TEXT("*.exe"));
SetDlgItemText(hDlg, IDC_PATH, s_szPath);
//
// Free the pidl
//
LPMALLOC lpMalloc = NULL;
if (SUCCEEDED(SHGetMalloc(&lpMalloc)) && lpMalloc) {
lpMalloc->Free(lpIDL);
} else {
assert(FALSE);
}
}
}
}
return;
}
void
DoSearch(
IN HWND hDlg
)
/*++
DoSearch
Desc: Handle the pressing of the search button.
Params:
IN HWND hDlg: The search dialog box
Return:
void
--*/
{
if (hDlg == NULL) {
ASSERT(FALSE);
return;
}
DWORD dwReturn = 0;
HWND hwndList = GetDlgItem(hDlg, IDC_LIST);
if (GetFocus() == hwndList
&& ListView_GetNextItem(hwndList, -1, LVNI_SELECTED) != -1) {
//
// We will get this message when we press enter in the list box,
// as IDC_SEARCH is the default button.
// So in this case we have to pretend as the user double clicked in the list
// view
//
SendNotifyMessage(hDlg, WM_COMMAND, (WPARAM)ID_VIEWCONTENTS , 0);
return;
}
//
// We need to get rid of the drop down list for the AUTOCOMPLETE text field.
//
SetFocus(GetDlgItem(hDlg, IDC_SEARCH));
SendMessage(GetDlgItem(hDlg, IDC_SEARCH),
WM_NEXTDLGCTL,
(WPARAM)TRUE,
(LPARAM)GetDlgItem(hDlg, IDC_SEARCH));
FlushCache();
GetCheckStatus(hDlg);
*s_szPath = 0;
*s_szPrevPath = 0;
GetDlgItemText(hDlg, IDC_PATH, s_szPath, ARRAYSIZE(s_szPath));
CSTRING::Trim(s_szPath);
SafeCpyN(s_szPrevPath, s_szPath, ARRAYSIZE(s_szPrevPath));
g_nIndex = 0;
//
// Clear the list view but do not remove the contents of the text field
//
ClearResults(hDlg, FALSE);
SetTimer(hDlg, 0, 100, NULL);
EnableWindow(GetDlgItem(hDlg, IDC_STOP), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_SEARCH), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_NEWSEARCH), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_SAVE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CAPTION), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_CHKAPP), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_CHKLAY), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_CHKSHI), FALSE);
g_bAbort = FALSE;
*g_szPresentDir = 0;
dwReturn = GetCurrentDirectory(ARRAYSIZE(g_szPresentDir), g_szPresentDir);
if (dwReturn == 0 || dwReturn >= ARRAYSIZE(g_szPresentDir)) {
assert(FALSE);
Dbg(dlError, "DoSearch GetCurrentDirectory failed");
}
Search(hDlg, s_szPath);
}
BOOL
AddNewResult(
IN LPARAM lParam
)
/*++
AddNewResult
Desc: We found a new file that matches out search criteria, lets now add this
to the list view. This is the handler for WM_USER_NEWMATCH
Params:
IN LPARAM lParam: The lParam that comes with WM_USER_NEWMATCH. This is
a pointer to a MATCHEDENTRY
Notes: Please note that this routine will also free some members of MATCHEDENTRY that
we do not need except to populate the list view
Return:
TRUE: If we added the result fields in the list view
FALSE: Otherwise
--*/
{
PMATCHEDENTRY pmEntry = (PMATCHEDENTRY)lParam;
CSTRING strExeName;
int iImage;
HICON hIcon;
HIMAGELIST himl;
HIMAGELIST himlSm;
LVITEM lvi;
if (pmEntry == NULL) {
assert(FALSE);
return FALSE;
}
EnterCriticalSection(&g_CritSect);
strExeName = pmEntry->strPath;
strExeName.ShortFilename();
himl = ListView_GetImageList(g_hwndSearchList, LVSIL_NORMAL);
if (!himl) {
himl = ImageList_Create(16, 15, ILC_COLOR32 | ILC_MASK, 10, 1);
if (!himl) {
return FALSE;
}
hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));
ImageList_AddIcon(himl, hIcon);
ListView_SetImageList(g_hwndSearchList, himl, LVSIL_NORMAL);
}
himlSm = ListView_GetImageList(g_hwndSearchList, LVSIL_SMALL);
if (!himlSm) {
himlSm = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON), ILC_COLOR | ILC_MASK, 0, 0);
if (!himlSm) {
return FALSE;
}
hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));
ImageList_AddIcon(himlSm, hIcon);
ListView_SetImageList(g_hwndSearchList, himlSm, LVSIL_SMALL);
}
//
// Get the icon for the file
//
hIcon = ExtractIcon(g_hInstance, pmEntry->strPath, 0);
if (!hIcon) {
iImage = 0;
} else {
iImage = ImageList_AddIcon(himl, hIcon);
if (iImage == -1) {
iImage = 0;
}
int iImageSm = ImageList_AddIcon(himlSm, hIcon);
assert(iImage == iImageSm);
DestroyIcon(hIcon);
}
ZeroMemory(&lvi, sizeof(lvi));
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvi.pszText = strExeName;
lvi.iItem = g_nIndex;
lvi.iSubItem = SEARCH_COL_AFFECTEDFILE;
lvi.iImage = iImage;
lvi.lParam = (LPARAM)pmEntry;
INT iIndex = ListView_InsertItem(g_hwndSearchList, &lvi);
//
// Set the various result fields in the list view
//
ListView_SetItemText(g_hwndSearchList, iIndex, SEARCH_COL_PATH, pmEntry->strPath);
ListView_SetItemText(g_hwndSearchList, iIndex, SEARCH_COL_APP, pmEntry->strAppName);
ListView_SetItemText(g_hwndSearchList, iIndex, SEARCH_COL_ACTION, pmEntry->strAction);
ListView_SetItemText(g_hwndSearchList, iIndex, SEARCH_COL_DBTYPE, pmEntry->strDatabase);
//
// Remove the strings that are no longer going to be used.
// Keep the dbguid, this will be used for matching when we double click.
//
pmEntry->strAction.Release();
pmEntry->strDatabase.Release();
pmEntry->strPath.Release();
//
// Increment the index where we want to put in the next result
//
g_nIndex++;
LeaveCriticalSection(&g_CritSect);
return TRUE;
}
void
OnBrowse(
IN HWND hDlg
)
/*++
OnBrowse
Desc: Handles the pressing of the browse button
Params:
IN HWND hdlg: The handle to the search dialog
Return:
void
--*/
{
BROWSEINFO brInfo;
TCHAR szDir[MAX_PATH * 2] = TEXT("");
brInfo.hwndOwner = g_hwndSearchList;
brInfo.pidlRoot = NULL;
brInfo.pszDisplayName = szDir;
brInfo.lpszTitle = GetString(IDS_SELECTDIR);
brInfo.ulFlags = BIF_STATUSTEXT | BIF_RETURNONLYFSDIRS;
brInfo.lpfn = NULL;
brInfo.lParam = NULL;
LPITEMIDLIST lpIDL = SHBrowseForFolder(&brInfo);
*szDir = 0;
if (lpIDL == NULL) {
//
// The user pressed cancel
//
return;
}
//
// Get the actual path from the pidl and free it
//
if (SHGetPathFromIDList(lpIDL, szDir)) {
ADD_PATH_SEPARATOR(szDir, ARRAYSIZE(szDir));
StringCchCat(szDir, ARRAYSIZE(szDir), TEXT("*.exe"));
SetDlgItemText(hDlg, IDC_PATH, szDir);
//
// Free the pidl
//
LPMALLOC lpMalloc;
if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
lpMalloc->Free(lpIDL);
} else {
assert(FALSE);
}
} else {
assert(FALSE);
}
}
void
ShowContextMenu(
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
ShowContextMenu
Desc: Shows the context menu. Handles WM_CONTEXTMENU
Params:
IN WPARAM wParam: The wParam that comes with WM_CONTEXTMENU.
Return:
--*/
{
HWND hWnd = (HWND)wParam;
if (hWnd == g_hwndSearchList) {
int iSelection = ListView_GetSelectionMark(g_hwndSearchList);
if (iSelection == -1) {
return;
}
LVITEM lvi = {0};
PMATCHEDENTRY pmMatched = NULL;
lvi.iItem = iSelection;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
if (!ListView_GetItem(g_hwndSearchList, &lvi)) {
return;
}
pmMatched = (PMATCHEDENTRY)lvi.lParam;
if (pmMatched == NULL) {
assert(FALSE);
return;
}
UINT uX = LOWORD(lParam);
UINT uY = HIWORD(lParam);
HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_CONTEXT));
HMENU hContext;
//
// Get the context menu for search
//
hContext = GetSubMenu(hMenu, 3);
if (hContext == NULL) {
goto End;
}
TrackPopupMenuEx(hContext,
TPM_LEFTALIGN | TPM_TOPALIGN,
uX,
uY,
g_hSearchDlg,
NULL);
End:
if (hMenu) {
DestroyMenu(hMenu);
hMenu = NULL;
}
}
}