windows-nt/Source/XPSP1/NT/net/ias/mmc/proxy/proxynode.cpp
2020-09-26 16:20:57 +08:00

309 lines
7.6 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000, Microsoft Corp. All rights reserved.
//
// FILE
//
// proxynode.cpp
//
// SYNOPSIS
//
// Defines the class ProxyNode.
//
// MODIFICATION HISTORY
//
// 02/19/2000 Original version.
//
///////////////////////////////////////////////////////////////////////////////
#include <proxypch.h>
#include <proxynode.h>
#include <proxypolicies.h>
#include <servergroups.h>
//////////
// From mmcutility.cpp
//////////
HRESULT IfServiceInstalled(
LPCWSTR lpszMachine,
LPCWSTR lpszService,
BOOL* pBool
);
//////////
// Helper function to get the NT build number of a machine.
//////////
LONG GetBuildNumber(LPCWSTR machineName, PLONG buildNum) throw ()
{
const WCHAR KEY[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion";
const WCHAR VALUE[] = L"CurrentBuildNumber";
LONG error;
HKEY hklm = HKEY_LOCAL_MACHINE;
// Only do a remote connect when machineName is specified.
CRegKey remote;
if (machineName && machineName[0])
{
error = RegConnectRegistryW(
machineName,
HKEY_LOCAL_MACHINE,
&remote.m_hKey
);
if (error) { return error; }
hklm = remote;
}
CRegKey currentVersion;
error = currentVersion.Open(hklm, KEY, KEY_READ);
if (error) { return error; }
WCHAR data[16];
DWORD dataLen = sizeof(data);
error = currentVersion.QueryValue(data, VALUE, &dataLen);
if (error) { return error; }
*buildNum = _wtol(data);
return NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// ConnectInfo
//
// DESCRIPTION
//
// Encapsulates the info that needs to be passed to the connect thread.
//
///////////////////////////////////////////////////////////////////////////////
class ConnectInfo
{
public:
ProxyNode* node;
CComPtr<IConsoleNameSpace2> nameSpace;
CComPtr<IDataObject> dataObject;
HSCOPEITEM relativeID;
};
ProxyNode::ProxyNode(
SnapInView& view,
IDataObject* parentData,
HSCOPEITEM parentId
)
: SnapInPreNamedItem(IDS_PROXY_NODE),
state(CONNECTING),
title(IDS_PROXY_VIEW_TITLE),
body(IDS_PROXY_VIEW_BODY),
worker(NULL)
{
// Save the connect info.
ConnectInfo* info = new (AfxThrow) ConnectInfo;
info->node = this;
info->nameSpace = view.getNameSpace();
info->dataObject = parentData;
info->relativeID = parentId;
// Create the connect thread.
worker = CreateThread(NULL, 0, connectRoutine, info, 0, NULL);
if (!worker)
{
delete info;
AfxThrowLastError();
}
}
HRESULT ProxyNode::getResultViewType(
LPOLESTR* ppViewType,
long* pViewOptions
) throw ()
{
// Set our result view to the MessageView control.
*pViewOptions = MMC_VIEW_OPTIONS_NOLISTVIEWS;
return StringFromCLSID(CLSID_MessageView, ppViewType);
}
HRESULT ProxyNode::onExpand(
SnapInView& view,
HSCOPEITEM itemId,
BOOL expanded
)
{
if (!expanded || state != CONNECTED) { return S_FALSE; }
SCOPEDATAITEM sdi;
memset(&sdi, 0, sizeof(sdi));
sdi.mask = SDI_STR |
SDI_PARAM |
SDI_IMAGE |
SDI_OPENIMAGE |
SDI_CHILDREN |
SDI_PARENT;
sdi.displayname = MMC_CALLBACK;
sdi.cChildren = 0;
sdi.relativeID = itemId;
// Create the ProxyPolicies node ...
policies = new (AfxThrow) ProxyPolicies(connection);
// ... and insert.
sdi.nImage = IMAGE_CLOSED_PROXY_POLICY_NODE;
sdi.nOpenImage = IMAGE_OPEN_PROXY_POLICY_NODE;
sdi.lParam = (LPARAM)(SnapInDataItem*)policies;
CheckError(view.getNameSpace()->InsertItem(&sdi));
policies->setScopeId(sdi.ID);
// Create the ServerGroups node ...
groups = new (AfxThrow) ServerGroups(connection);
// ... and insert.
sdi.nImage = IMAGE_CLOSED_SERVER_GROUP_NODE;
sdi.nOpenImage = IMAGE_OPEN_SERVER_GROUPS_NODE;
sdi.lParam = (LPARAM)(SnapInDataItem*)groups;
CheckError(view.getNameSpace()->InsertItem(&sdi));
groups->setScopeId(sdi.ID);
// All went well.
state = EXPANDED;
return S_OK;
}
HRESULT ProxyNode::onShow(
SnapInView& view,
HSCOPEITEM itemId,
BOOL selected
)
{
if (!selected) { return S_FALSE; }
// Get the IMessageView interface ...
CComPtr<IUnknown> unk;
CheckError(view.getConsole()->QueryResultView(&unk));
CComPtr<IMessageView> msgView;
CheckError(unk->QueryInterface(
__uuidof(IMessageView),
(PVOID*)&msgView
));
// ... and set our information. We don't care if this fails.
msgView->SetIcon(Icon_Information);
msgView->SetTitleText(title);
msgView->SetBodyText(body);
return S_OK;
}
HRESULT ProxyNode::onContextHelp(SnapInView& view) throw ()
{
return view.displayHelp(L"ias_ops.chm::/sag_ias_crp_node.htm");
}
ProxyNode::~ProxyNode() throw ()
{
if (worker)
{
WaitForSingleObject(worker, INFINITE);
CloseHandle(worker);
}
}
void ProxyNode::connect(ConnectInfo& info) throw ()
{
HGLOBAL global = NULL;
// We'll assume that the node is suppressed until we've verified that the
// target machine (1) has IAS installed and (2) supports proxy policies.
State newState = SUPPRESSED;
try
{
// Extract the machine name from the parentData.
UINT cf = RegisterClipboardFormatW(L"MMC_SNAPIN_MACHINE_NAME");
ExtractData(
info.dataObject,
(CLIPFORMAT)cf,
4096,
&global
);
PCWSTR machine = (PCWSTR)global;
// Get the build number of the machine.
LONG error, buildNum;
error = GetBuildNumber(machine, &buildNum);
if (error) { AfxThrowOleException(HRESULT_FROM_WIN32(error)); }
// If the machine supports proxy policies, ...
if (buildNum >= 2220)
{
// ... ensure that IAS is actually installed.
BOOL installed;
CheckError(IfServiceInstalled(machine, L"IAS", &installed));
if (installed)
{
connection.connect(machine);
newState = CONNECTED;
}
}
}
catch (...)
{
// Something went wrong.
newState = FAILED;
}
GlobalFree(global);
// Don't add the node if we're suppressed.
if (newState != SUPPRESSED)
{
SCOPEDATAITEM sdi;
ZeroMemory(&sdi, sizeof(SCOPEDATAITEM));
sdi.mask = SDI_STR |
SDI_IMAGE |
SDI_OPENIMAGE |
SDI_CHILDREN |
SDI_PARENT |
SDI_PARAM;
sdi.displayname = MMC_CALLBACK;
sdi.lParam = (LPARAM)this;
sdi.relativeID = info.relativeID;
if (newState == CONNECTED)
{
sdi.nImage = IMAGE_CLOSED_PROXY_NODE;
sdi.nOpenImage = IMAGE_OPEN_PROXY_NODE;
sdi.cChildren = 2;
}
else
{
sdi.nImage = IMAGE_CLOSED_BAD_PROXY_NODE;
sdi.nOpenImage = IMAGE_OPEN_BAD_PROXY_NODE;
}
info.nameSpace->InsertItem(&sdi);
}
// We don't update the state until everything is finished.
state = newState;
}
DWORD ProxyNode::connectRoutine(LPVOID param) throw ()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
ConnectInfo* info = (ConnectInfo*)param;
info->node->connect(*info);
delete info;
CoUninitialize();
return 0;
}