2025-04-27 07:49:33 -04:00

556 lines
12 KiB
C++

// ***************************************************************************
//
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
//
// File: classsearch.h
//
// Description:
// This file implements the CClassSearch class which is a subclass
// of the MFC CDialog class. It is a part of the Class Explorer OCX,
// and it performs the following functions:
// a. Allows the user to type in the name of a class to search
// for. The actual search is performed by the CClassNavCtl
// class.
//
// Part of:
// ClassNav.ocx
//
// Used by:
// CClassNavCtrl
//
// History:
// Judith Ann Powell 10-08-96 Created.
//
//
//**************************************************************************
#include "precomp.h"
#include "resource.h"
#include "classnav.h"
#include "wbemidl.h"
#include "CClassTree.h"
#include "CContainedToolBar.h"
#include "Banner.h"
#include "ClassNavCtl.h"
#include "AddDialog.h"
#include "ClassSearch.h"
#include "olemsclient.h"
#include "comdef.h"
#include "logindlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define CHUNK_SIZE 500
// ***************************************************************************
//
// CClassSearch::CClassSearch
//
// Description:
// This member function is the public constructor. It initializes the state
// of member variables.
//
// Parameters:
// CClassNavCtrl* pParent Parent
//
// Returns:
// NONE
//
// Globals accessed:
// NONE
//
// Globals modified:
// NONE
//
// ***************************************************************************
CClassSearch::CClassSearch(CClassNavCtrl* pParent)
: CDialog(CClassSearch::IDD, NULL)
{
//{{AFX_DATA_INIT(CClassSearch)
m_csSearchClass = _T("");
m_bSearchProperties = FALSE;
m_bSearchDescriptions = FALSE;
m_bSearchClassNames = TRUE;
//}}AFX_DATA_INIT
m_pParent = pParent;
}
// ***************************************************************************
//
// CClassSearch::DoDataExchange
//
// Description:
// Called by the framework to exchange and validate dialog data.
//
// Parameters:
// pDX A pointer to a CDataExchange object.
//
// Returns:
// VOID
//
// Globals accessed:
// NONE
//
// Globals modified:
// NONE
//
// ***************************************************************************
void CClassSearch::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CClassSearch)
DDX_Control(pDX, IDC_CHECK_SEARCH_CLASS, m_ctrlCheckClassNames);
DDX_Control(pDX, IDC_LIST_SEARCH_RESULTS, m_lbSearchResults);
DDX_Text(pDX, IDC_EDIT1, m_csSearchClass);
DDX_Check(pDX, IDC_CHECK_SEARCH_PROPERTIES, m_bSearchProperties);
DDX_Check(pDX, IDC_CHECK_SEARCH_DESCRIPTIONS, m_bSearchDescriptions);
DDX_Check(pDX, IDC_CHECK_SEARCH_CLASS, m_bSearchClassNames);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CClassSearch, CDialog)
//{{AFX_MSG_MAP(CClassSearch)
ON_BN_CLICKED(IDC_BUTTON_SEARCH, OnButtonSearch)
ON_LBN_DBLCLK(IDC_LIST_SEARCH_RESULTS, OnDblclkListSearchResults)
ON_LBN_SELCHANGE(IDC_LIST_SEARCH_RESULTS, OnSelchangeListSearchResults)
ON_EN_SETFOCUS(IDC_EDIT1, OnSetfocusEdit1)
ON_BN_CLICKED(IDC_CHECK_SEARCH_CLASS, OnCheckSearchClass)
ON_BN_CLICKED(IDC_CHECK_SEARCH_DESCRIPTIONS, OnCheckSearchDescriptions)
ON_BN_CLICKED(IDC_CHECK_SEARCH_PROPERTIES, OnCheckSearchProperties)
ON_EN_UPDATE(IDC_EDIT1, OnUpdateEdit1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/* EOF: CClassSearch.cpp */
///////////////////////////////////////////////////////////////////////////////////////
void CClassSearch::OnButtonSearch()
{
CleanupMap();
m_lbSearchResults.ResetContent();
UpdateData();
m_csSearchClass.TrimLeft();
m_csSearchClass.TrimRight();
if (m_csSearchClass.IsEmpty()) {
return;
}
BeginWaitCursor();
HRESULT hr = DoSearch();
if (FAILED (hr)) {
m_lbSearchResults.AddString(_T("Search failed"));
return;
}
//if no objects were found
if (m_mapNamesToObjects.IsEmpty()) {
m_lbSearchResults.AddString(_T("No matches"));
}
POSITION pos;
IWbemClassObject * pObj;
CString key;
for( pos = m_mapNamesToObjects.GetStartPosition(); pos != NULL; ) {
m_mapNamesToObjects.GetNextAssoc( pos, key, (void*&)pObj );
m_lbSearchResults.AddString(key);
}
UpdateOKButtonState();
EndWaitCursor();
DWORD time1 = GetTickCount();
//clean up all messages from the message queue: in case user was clicking
//with the hourglass on...
MSG msg;
while (PeekMessage(&msg, m_hWnd, 0, WM_USER - 1, PM_NOREMOVE)) {
if (time1 < msg.time) {
break;
}
else {
//remove the message
PeekMessage(&msg, m_hWnd, 0, WM_USER - 1, PM_REMOVE);
}
}
}
//*************************************************************************************
// Set selected object and close the dialog
//*************************************************************************************
void CClassSearch::OnDblclkListSearchResults()
{
OnOK();
}
IWbemClassObject * CClassSearch::GetSelectedObject()
{
return m_pSelectedObject;
}
BOOL CClassSearch::OnInitDialog()
{
CDialog::OnInitDialog();
//make "Search" button the default
SetDefID(IDC_BUTTON_SEARCH);
//disable "Search" button until text is entered into edit box
GetDlgItem(IDC_BUTTON_SEARCH)->EnableWindow(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CClassSearch::CleanupMap()
{
POSITION pos;
IWbemClassObject * pObj;
CString key;
for( pos = m_mapNamesToObjects.GetStartPosition(); pos != NULL; ) {
m_mapNamesToObjects.GetNextAssoc( pos, key, (void*&)pObj );
pObj->Release();
}
m_mapNamesToObjects.RemoveAll();
}
void CClassSearch::OnOK()
{
int index = m_lbSearchResults.GetCurSel();
if (index == LB_ERR) {
//nothing is selected
m_pSelectedObject = NULL;
m_csSelectedClass.Empty();
CleanupMap();
CDialog::OnOK();
return;
}
CString name;
m_lbSearchResults.GetText(index, name);
IWbemClassObject * pObj = NULL;
BOOL res = m_mapNamesToObjects.Lookup(name, (void*&)pObj );
if (!res) {
//this executes when "No matches" is selected
m_pSelectedObject = NULL;
m_csSelectedClass.Empty();
CleanupMap();
//Dialog stays up
return;
}
ASSERT(pObj);
m_pSelectedObject = pObj;
m_csSelectedClass = name;
//do another AddRef() on selected object, because subsequent call to
//CleanupMap will release
m_pSelectedObject->AddRef();
CleanupMap();
CDialog::OnOK();
}
CString CClassSearch::GetSelectedClassName()
{
return m_csSelectedClass;
}
void CClassSearch::OnSelchangeListSearchResults()
{
if (m_lbSearchResults.GetCurSel() != LB_ERR) { //an item is selected
SetDefID(IDOK);
}
else {
SetDefID(IDC_BUTTON_SEARCH);
}
}
void CClassSearch::OnSetfocusEdit1()
{
//if edit box receives input focus, "Search" button should become the default
SetDefID(IDC_BUTTON_SEARCH);
}
void CClassSearch::OnCheckSearchClass()
{
UpdateSearchButtonState();
}
void CClassSearch::OnCheckSearchDescriptions()
{
UpdateSearchButtonState();
}
void CClassSearch::OnCheckSearchProperties()
{
UpdateSearchButtonState();
}
void CClassSearch::UpdateSearchButtonState()
{
//the button should be enabled if at least one of the search checkboxes is checked
UpdateData();
if ((m_bSearchClassNames || m_bSearchProperties || m_bSearchDescriptions) &&
(!m_csSearchClass.IsEmpty())) {
GetDlgItem(IDC_BUTTON_SEARCH)->EnableWindow(TRUE);
}
else {
GetDlgItem(IDC_BUTTON_SEARCH)->EnableWindow(FALSE);
}
}
void CClassSearch::OnUpdateEdit1()
{
UpdateSearchButtonState();
}
/******************************************************************************
// This method disables OK button when search result list is empty("No matches")
// and ensbles it when there are valid items in the result list.
*******************************************************************************/
void CClassSearch::UpdateOKButtonState()
{
GetDlgItem(IDOK)->EnableWindow(!m_mapNamesToObjects.IsEmpty());
}
HRESULT CClassSearch::DoSearch()
{
ASSERT(m_pParent->GetServices());
IEnumWbemClassObject * pEnum = NULL;
//GET ALL CLASSES IN THE NAMESPACE
HRESULT hr = m_pParent->GetServices()->CreateClassEnum(NULL,
WBEM_FLAG_DEEP | WBEM_FLAG_USE_AMENDED_QUALIFIERS,
NULL, &pEnum);
if (FAILED(hr)) {
return hr;
}
hr = SetEnumInterfaceSecurity(m_pParent->GetCurrentNamespace(),
pEnum,
m_pParent->GetServices());
if (FAILED(hr)) {
// Oh well, just keep going, just in case it works without the security set correctly
// return hr;
}
IWbemClassObject * pObj[CHUNK_SIZE];
ULONG uRet = 0;
while (1) {
for (UINT i = 0; i < CHUNK_SIZE; i++) {
pObj[i] = NULL;
}
hr = pEnum->Next(WBEM_INFINITE, CHUNK_SIZE, (IWbemClassObject **)&pObj, &uRet);
TRACE(_T("hresult from Next is %x\n"), hr);
TRACE(_T("Next returned %d items\n"), uRet);
if (hr == WBEM_S_FALSE && uRet== 0) {
break;
}
if (FAILED(hr) && uRet == 0) {
break;
}
for (i = 0; i < uRet; i++) {
TRACE(_T("object %d\n"), i);
if (m_bSearchClassNames) {
hr = CheckClassNameForPattern(pObj[i], m_csSearchClass);
if (SUCCEEDED (hr)) {
//add this object, inspect the next one
m_mapNamesToObjects.SetAt(GetIWbemClass(pObj[i]), pObj[i]);
continue;
}
}
//pattern is not found in class name. Check in property names:
if (m_bSearchProperties) {
hr = CheckPropertyNamesForPattern(pObj[i], m_csSearchClass);
if (SUCCEEDED (hr)) {
//add this object, inspect the next one
m_mapNamesToObjects.SetAt(GetIWbemClass(pObj[i]), pObj[i]);
continue;
}
}
//pattern is not found in property names. Check in description:
if (m_bSearchDescriptions) {
hr = CheckDescriptionForPattern(pObj[i], m_csSearchClass);
if (SUCCEEDED (hr)) {
m_mapNamesToObjects.SetAt(GetIWbemClass(pObj[i]), pObj[i]);
continue;
}
}
//if we got here, pattern is not found
pObj[i]->Release();
}
}
pEnum->Release();
return S_OK;
}
HRESULT CClassSearch::CheckPropertyNamesForPattern(IWbemClassObject *pObj, CString &pattern)
{
ASSERT (pObj);
bstr_t bstrClass("__CLASS");
VARIANT var;
VariantInit(&var);
HRESULT hr = pObj->BeginEnumeration(WBEM_FLAG_LOCAL_ONLY);
if (FAILED(hr)) {
return hr;
}
while (1) {
BSTR bstrOut;
hr = pObj->Next(0L, &bstrOut, NULL, NULL, NULL);
if (hr == WBEM_S_NO_MORE_DATA ) {
break;
}
if (FAILED(hr)) {
continue;
}
CString csPropName;
csPropName = (char *)bstr_t(bstrOut);
SysFreeString(bstrOut);
csPropName.MakeUpper();
pattern.MakeUpper();
if (csPropName.Find((LPCTSTR)pattern) == -1) {
continue;
}
else {
return S_OK;
}
}
return E_FAIL;
}
HRESULT CClassSearch::CheckDescriptionForPattern(IWbemClassObject *pObj, CString &pattern)
{
ASSERT (pObj);
IWbemQualifierSet * pQualSet = NULL;
HRESULT hr = pObj->GetQualifierSet(&pQualSet);
if (FAILED(hr)) {
return hr;
}
CString descr ("Description");
VARIANT varOut;
VariantInit(&varOut);
hr = pQualSet->Get(descr.AllocSysString(), 0L, &varOut, NULL);
if (FAILED(hr)) {
pQualSet->Release();
return hr;
}
ASSERT (varOut.vt == VT_BSTR);
CString csDescr((char *)bstr_t(varOut.bstrVal));
csDescr.MakeUpper();
pattern.MakeUpper();
if (csDescr.Find((LPCTSTR)pattern) == -1) {
pQualSet->Release();
return E_FAIL;
}
pQualSet->Release();
return S_OK;
}
HRESULT CClassSearch::CheckClassNameForPattern(IWbemClassObject *pObj, CString &pattern)
{
ASSERT (pObj);
bstr_t bstrClass("__CLASS");
VARIANT var;
VariantInit(&var);
HRESULT hr = pObj->Get(bstrClass, 0L, &var, NULL, NULL);
if (FAILED(hr)) {
return hr;
}
ASSERT (var.vt == VT_BSTR);
CString csClassName((char *)bstr_t(var.bstrVal));
csClassName.MakeUpper();
pattern.MakeUpper();
if (csClassName.Find(pattern) == -1) {
return E_FAIL;
}
return S_OK;
}