windows-nt/Source/XPSP1/NT/inetsrv/iis/ui/admin/mmc/inetmgr.cpp
2020-09-26 16:20:57 +08:00

1344 lines
28 KiB
C++

/*++
Copyright (c) 1994-1998 Microsoft Corporation
Module Name :
inetmgr.cpp
Abstract:
Main program object
Author:
Ronald Meijer (ronaldm)
Project:
Internet Services Manager
Functions Exported:
Revision History:
--*/
//
// Include files
//
#include "stdafx.h"
#include "inetmgr.h"
#include "constr.h"
#include <dos.h>
#include <direct.h>
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
//
// Default HTML help topics file name
//
#define DEFAULT_HTML _T("htmldocs\\inetdocs.htm")
LPOLESTR
CoTaskDupString(
IN LPCOLESTR szString
)
/*++
Routine Description:
Helper function to duplicate a OLESTR
Arguments:
LPOLESTR szString : Source string
Return Value:
Pointer to the new string or NULL
--*/
{
OLECHAR * lpString = (OLECHAR *)CoTaskMemAlloc(
sizeof(OLECHAR)*(lstrlen(szString) + 1)
);
if (lpString != NULL)
{
lstrcpy(lpString, szString);
}
return lpString;
}
HRESULT
BuildResURL(
OUT CString & str,
IN HINSTANCE hSourceInstance
)
/*++
Routine Description:
Helper function to generate "res://" type string
Arguments:
CString & str : Returns res:// string
HINSTANCE hSourceInstance : Source instance,
: or -1 for current module
: or NULL for calling app (MMC)
Return Value:
HRESULT
--*/
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CError err;
TCHAR atchModuleFileName[MAX_PATH + 1];
int cch = ::GetModuleFileName(
(hSourceInstance == (HINSTANCE) - 1)
? ::AfxGetInstanceHandle()
: hSourceInstance,
atchModuleFileName,
sizeof(atchModuleFileName) / sizeof(OLECHAR)
);
if (!cch)
{
err.GetLastWinError();
ASSERT(FALSE);
return err;
}
str = _T("res://");
str += atchModuleFileName;
return err;
}
//
// Static Initialization
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
LPCTSTR CServiceInfo::s_cszSupcfg = _T("::SUPCFG:");
//
// ISM Method VTable Definition
//
CServiceInfo::ISM_METHOD_DEF CServiceInfo::s_imdMethods[ISM_NUM_METHODS] =
{
//-----------ID----------------Must Have?--------------Method Name------------
ISM_QUERY_SERVICE_INFO, TRUE, SZ_SERVICEINFO_PROC,
ISM_DISCOVER_SERVERS, FALSE, SZ_DISCOVERY_PROC,
ISM_QUERY_SERVER_INFO, TRUE, SZ_SERVERINFO_PROC,
ISM_CHANGE_SERVICE_STATE, FALSE, SZ_CHANGESTATE_PROC,
ISM_CONFIGURE, TRUE, SZ_CONFIGURE_PROC,
ISM_BIND, FALSE, SZ_BIND_PROC,
ISM_UNBIND, FALSE, SZ_UNBIND_PROC,
ISM_CONFIGURE_CHILD, FALSE, SZ_CONFIGURE_CHILD_PROC,
ISM_ENUMERATE_INSTANCES, FALSE, SZ_ENUMERATE_INSTANCES_PROC,
ISM_ENUMERATE_CHILDREN, FALSE, SZ_ENUMERATE_CHILDREN_PROC,
ISM_ADD_INSTANCE, FALSE, SZ_ADD_INSTANCE_PROC,
ISM_DELETE_INSTANCE, FALSE, SZ_DELETE_INSTANCE_PROC,
ISM_ADD_CHILD, FALSE, SZ_ADD_CHILD_PROC,
ISM_DELETE_CHILD, FALSE, SZ_DELETE_CHILD_PROC,
ISM_RENAME_CHILD, FALSE, SZ_RENAME_CHILD_PROC,
ISM_QUERY_INSTANCE_INFO, FALSE, SZ_QUERY_INSTANCE_INFO_PROC,
ISM_QUERY_CHILD_INFO, FALSE, SZ_QUERY_CHILD_INFO_PROC,
ISM_MMC_CONFIGURE, FALSE, SZ_MMC_CONFIGURE_PROC,
ISM_MMC_CONFIGURE_CHILD, FALSE, SZ_MMC_CONFIGURE_CHILD_PROC,
ISM_SECURITY_WIZARD, FALSE, SZ_SECURITY_WIZARD_PROC
};
CServiceInfo::CServiceInfo(
IN int nID,
IN LPCTSTR lpDLLName
)
/*++
Routine Description:
Constructor for service info object. Load the specified config DLL,
and initialise the entry points.
Arguments:
int nID : The guaranteed unique ID assigned to this service
LPCTSTR lpDLLName : The config DLL name to be loaded
Return Value:
N/A
--*/
: CObjectPlus(),
m_hModule(NULL),
m_psiMaster(NULL),
m_strDLLName(lpDLLName),
m_strSupDLLName(),
#ifndef USE_VTABLE
m_pfnQueryServiceInfo(NULL),
m_pfnDiscoverServers(NULL),
m_pfnQueryServerInfo(NULL),
m_pfnChangeServiceState(NULL),
m_pfnConfigure(NULL),
m_pfnConfigureChild(NULL),
m_pfnEnumerateInstances(NULL),
m_pfnEnumerateChildren(NULL),
m_pfnAddInstance(NULL),
m_pfnDeleteInstance(NULL),
m_pfnAddChild(NULL),
m_pfnDeleteChild(NULL),
m_pfnRenameChild(NULL),
m_pfnQueryInstanceInfo(NULL),
m_pfnQueryChildInfo(NULL),
m_pfnISMMMCConfigureServers(NULL),
m_pfnISMMMCConfigureChild(NULL),
m_pfnISMSecurityWizard(NULL),
#endif // USE_VTABLE
m_nID(nID),
m_iBmpID(-1),
m_iBmpChildID(-1)
{
#ifdef USE_VTABLE
//
// Initialize VTable
//
ZeroMemory(&m_rgpfnISMMethods, sizeof(m_rgpfnISMMethods));
#endif // USE_VTABLE
//
// Check for parameter options.
//
TRACEEOLID("Raw DLL name: " << m_strDLLName);
//
// Load super DLL
//
int nOpt = m_strDLLName.Find(s_cszSupcfg);
if (nOpt >= 0)
{
m_strSupDLLName = m_strDLLName.Mid(nOpt + lstrlen(s_cszSupcfg));
m_strDLLName.ReleaseBuffer(nOpt);
TRACEEOLID("Superceed DLL: " << m_strSupDLLName);
}
TRACEEOLID("Attempting to load " << m_strDLLName);
CError err;
BOOL fMissingMethod = FALSE;
m_hModule = ::AfxLoadLibrary(m_strDLLName);
if (m_hModule == NULL)
{
err.GetLastWinError();
if (err.Succeeded())
{
//
// This shouldn't happen, but it sometimes does.
// AfxLoadLibrary resets the last error somewhere???
//
TRACEEOLID("Error!!! Library not loaded, but last error returned 0");
err = ERROR_DLL_NOT_FOUND;
}
TRACEEOLID("Failed to load "
<< m_strDLLName
<< " GetLastError() returns "
<< err
);
}
else
{
TRACEEOLID(m_strDLLName << " LoadLibrary succeeded");
#ifdef USE_VTABLE
//
// Initialize VTable
//
for (int i = 0; i < ISM_NUM_METHODS; ++i)
{
m_rgpfnISMMethods[CServiceInfo::s_imdMethods[i].iID] =
(pfnISMMethod)GetProcAddress(
m_hModule,
CServiceInfo::s_imdMethods[i].lpszMethodName
);
if (CServiceInfo::s_imdMethods[i].fMustHave
&& !m_rgpfnISMMethods[CServiceInfo::s_imdMethods[i].iID])
{
fMissingMethod = TRUE;
}
}
#else
//
// Initialise function pointers (not all need be
// present)
//
m_pfnQueryServiceInfo = (pfnQueryServiceInfo)
::GetProcAddress(m_hModule, SZ_SERVICEINFO_PROC);
m_pfnDiscoverServers = (pfnDiscoverServers)
::GetProcAddress(m_hModule, SZ_DISCOVERY_PROC);
m_pfnQueryServerInfo = (pfnQueryServerInfo)
::GetProcAddress(m_hModule, SZ_SERVERINFO_PROC);
m_pfnChangeServiceState = (pfnChangeServiceState)
::GetProcAddress(m_hModule, SZ_CHANGESTATE_PROC);
m_pfnConfigure = (pfnConfigure)
::GetProcAddress(m_hModule, SZ_CONFIGURE_PROC);
m_pfnBind = (pfnBind)
::GetProcAddress(m_hModule, SZ_BIND_PROC);
m_pfnUnbind = (pfnUnbind)
::GetProcAddress(m_hModule, SZ_UNBIND_PROC);
m_pfnConfigureChild = (pfnConfigureChild)
::GetProcAddress(m_hModule, SZ_CONFIGURE_CHILD_PROC);
m_pfnEnumerateInstances = (pfnEnumerateInstances)
::GetProcAddress(m_hModule, SZ_ENUMERATE_INSTANCES_PROC);
m_pfnEnumerateChildren = (pfnEnumerateChildren)
::GetProcAddress(m_hModule, SZ_ENUMERATE_CHILDREN_PROC);
m_pfnAddInstance = (pfnAddInstance)
::GetProcAddress(m_hModule, SZ_ADD_INSTANCE_PROC);
m_pfnDeleteInstance = (pfnDeleteInstance)
::GetProcAddress(m_hModule, SZ_DELETE_INSTANCE_PROC);
m_pfnAddChild = (pfnAddChild)
::GetProcAddress(m_hModule, SZ_ADD_CHILD_PROC);
m_pfnDeleteChild = (pfnDeleteChild)
::GetProcAddress(m_hModule, SZ_DELETE_CHILD_PROC);
m_pfnRenameChild = (pfnRenameChild)
::GetProcAddress(m_hModule, SZ_RENAME_CHILD_PROC);
m_pfnQueryInstanceInfo = (pfnQueryInstanceInfo)
::GetProcAddress(m_hModule, SZ_QUERY_INSTANCE_INFO_PROC);
m_pfnQueryChildInfo = (pfnQueryChildInfo)
::GetProcAddress(m_hModule, SZ_QUERY_CHILD_INFO_PROC);
m_pfnISMMMCConfigureServers = (pfnISMMMCConfigureServers)
::GetProcAddress(m_hModule, SZ_MMC_CONFIGURE_PROC);
m_pfnISMMMCConfigureChild = (pfnISMMMCConfigureChild)
::GetProcAddress(m_hModule, SZ_MMC_CONFIGURE_CHILD_PROC);
m_pfnISMSecurityWizard = (pfnISMSecurityWizard)
::GetProcAddress(m_hModule, SZ_SECURITY_WIZARD_PROC);
fMissingMethod = m_pfnQueryServiceInfo == NULL
|| m_pfnQueryServerInfo == NULL
|| m_pfnChangeServiceState == NULL
|| m_pfnConfigure == NULL;
#endif // USE_VTABLE
::ZeroMemory(&m_si, sizeof(m_si));
m_si.dwSize = sizeof(m_si);
err = ISMQueryServiceInfo(&m_si);
}
if (err.Failed())
{
//
// Fill in the short and long names
// with default values.
//
CString strMenu, strToolTips, str;
VERIFY(strMenu.LoadString(IDS_DEFAULT_SHORTNAME));
VERIFY(strToolTips.LoadString(IDS_DEFAULT_LONGNAME));
//
// Since the structure was zero-filled to
// begin with, lstrcpyn is ok, because
// we will always have the terminating NULL
//
str.Format(strMenu, (LPCTSTR)lpDLLName);
::lstrcpyn(
m_si.atchShortName,
(LPCTSTR)str,
sizeof((m_si.atchShortName) - 1) / sizeof(m_si.atchShortName[0])
);
str.Format(strToolTips, (LPCTSTR)lpDLLName);
::lstrcpyn(
m_si.atchLongName,
(LPCTSTR)str,
sizeof((m_si.atchLongName) - 1) / sizeof(m_si.atchLongName[0])
);
}
BOOL fInitOK = m_hModule != NULL
&& !fMissingMethod
&& err.Succeeded();
//
// The service is selected at startup
// time if it loaded succesfully
//
m_fIsSelected = fInitOK;
TRACEEOLID("Success = " << fInitOK);
m_hrReturnCode = err;
}
CServiceInfo::~CServiceInfo()
/*++
Routine Description:
Destruct the object by unloading the config DLL
Arguments:
N/A
Return Value:
N/A
--*/
{
TRACEEOLID("Cleaning up service info");
if (m_hModule != NULL)
{
TRACEEOLID("Unloading library");
VERIFY(::AfxFreeLibrary(m_hModule));
}
}
//
// ISM Api Functions
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#ifdef USE_VTABLE
DWORD
CServiceInfo::ISMQueryServiceInfo(
OUT ISMSERVICEINFO * psi
)
/*++
Routine Description:
Return service-specific information back to
to the application. This function is called
by the service manager immediately after
LoadLibary();
Arguments:
ISMSERVICEINFO * psi : Service information returned.
Return Value:
Error return code
--*/
{
if (ISM_NO_VTABLE_ENTRY(ISM_QUERY_SERVICE_INFO))
{
return ERROR_CAN_NOT_COMPLETE;
}
DWORD err = ISM_VTABLE(ISM_QUERY_SERVICE_INFO)(psi);
if (RequiresSuperDll() && err == ERROR_SUCCESS)
{
//
// This service is superceded. Add "downlevel" to
// service name, if there's room.
//
CString strDL;
VERIFY(strDL.LoadString(IDS_DOWNLEVEL));
if (lstrlen(psi->atchShortName) + strDL.GetLength() < MAX_SNLEN)
{
lstrcat(psi->atchShortName, (LPCTSTR)strDL);
}
}
return err;
}
DWORD
CServiceInfo::ISMQueryServerInfo(
IN LPCTSTR lpszServerName,
OUT ISMSERVERINFO * psi
)
/*++
Routine Description:
Get information on a single server with regards to
this service.
Arguments:
LPCTSTR lpszServerName : Name of server.
ISMSERVERINFO * psi : Server information returned.
Return Value:
Error return code
--*/
{
DWORD err;
if (HasSuperDll())
{
//
// This config DLL is superceded by another one. If _that_ service
// is installed, then assume this one is not.
//
err = GetSuperDll()->ISMQueryServerInfo(lpszServerName, psi);
if (err == ERROR_SUCCESS)
{
//
// The superceding service is installed. That means this
// service is not.
//
return ERROR_SERVICE_DOES_NOT_EXIST;
}
}
if (ISM_NO_VTABLE_ENTRY(ISM_QUERY_SERVER_INFO))
{
return ERROR_CAN_NOT_COMPLETE;
}
return ISM_VTABLE(ISM_QUERY_SERVER_INFO)(
lpszServerName,
psi
);
}
#else !USE_VTABLE
//
// CODEWORK: Most of these method below could be inlined
//
DWORD
CServiceInfo::ISMQueryServiceInfo(
OUT ISMSERVICEINFO * psi
)
/*++
Routine Description:
Return service-specific information back to
to the application. This function is called
by the service manager immediately after
LoadLibary();
Arguments:
ISMSERVICEINFO * psi : Service information returned.
Return Value:
Error return code
--*/
{
if (m_pfnQueryServiceInfo == NULL)
{
return ERROR_CAN_NOT_COMPLETE;
}
DWORD err = (*m_pfnQueryServiceInfo)(psi);
if (RequiresSuperDll() && err == ERROR_SUCCESS)
{
//
// This service is superceded. Add "downlevel" to
// service name, if there's room.
//
CString strDL;
VERIFY(strDL.LoadString(IDS_DOWNLEVEL));
if (lstrlen(psi->atchShortName) + strDL.GetLength() < MAX_SNLEN)
{
lstrcat(psi->atchShortName, (LPCTSTR)strDL);
}
}
return err;
}
DWORD
CServiceInfo::ISMQueryServerInfo(
IN LPCTSTR lpszServerName, // Name of server.
OUT ISMSERVERINFO * psi // Server information returned.
)
/*++
Routine Description:
Get information on a single server with regards to
this service.
Arguments:
LPCTSTR lpszServerName : Name of server.
ISMSERVERINFO * psi : Server information returned.
Return Value:
Error return code
--*/
{
DWORD err;
if (HasSuperDll())
{
//
// This config DLL is superceded by another one. If _that_ service
// is installed, then assume this one is not.
//
err = GetSuperDll()->ISMQueryServerInfo(lpszServerName, psi);
if (err == ERROR_SUCCESS)
{
//
// The superceding service is installed. That means this
// service is not.
//
return ERROR_SERVICE_DOES_NOT_EXIST;
}
}
if (m_pfnQueryServerInfo != NULL)
{
return (*m_pfnQueryServerInfo)(lpszServerName, psi);
}
return ERROR_CAN_NOT_COMPLETE;
}
#endif // USE_VTABLE
//
// New Instance Command Class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CNewInstanceCmd::CNewInstanceCmd(
IN CServiceInfo * pServiceInfo
)
/*++
Routine Description:
New instance command constructor. Build a menu command
for the create new submenu.
Arguments:
CServiceInfo * pServiceInfo : Service info object
Return Value:
N/A
--*/
: m_pServiceInfo(pServiceInfo)
{
ASSERT(m_pServiceInfo != NULL);
try
{
CString str;
VERIFY(str.LoadString(IDS_MENU_EX_NEWINSTANCE));
m_strMenuCommand.Format(str, m_pServiceInfo->GetShortName());
VERIFY(str.LoadString(IDS_MENU_TT_EX_NEWINSTANCE));
m_strTTText.Format(str, m_pServiceInfo->GetShortName());
}
catch(CMemoryException * e)
{
e->ReportError();
e->Delete();
}
}
/* static */
CServiceInfo *
CServerInfo::FindServiceByMask(
IN ULONGLONG ullTarget,
IN CObListPlus & oblServices
)
/*++
Routine Description:
Given the inetsloc mask, return the service this
fits. Return NULL if the service was not found.
Arguments:
ULONGLONG ullTarget : The mask to look for
CObListPlus & oblServices : List of service objects in which to look
Return Value:
Pointer to service object that uses this mask, or NULL if the
service isn't found
--*/
{
CObListIter obli(oblServices);
CServiceInfo * psi;
//
// Straight sequential search
//
TRACEEOLID("Looking for service with mask " << (DWORD)ullTarget);
while (psi = (CServiceInfo *)obli.Next())
{
if (psi->InitializedOK()
&& psi->UseInetSlocDiscover()
&& psi->QueryDiscoveryMask() == ullTarget
)
{
TRACEEOLID("Found it: " << psi->GetShortName());
return psi;
}
}
//
// Didn't find it..
//
TRACEEOLID("Error: mask not matched up with any known service");
return NULL;
}
/* static */
LPCTSTR
CServerInfo::CleanServerName(
IN OUT CString & str
)
/*++
Routine Description:
Utility function to clean up a computer/hostname
Arguments:
CString & str : Server name to be cleaned up
Return Value:
Pointer to the string
--*/
{
#ifdef ENFORCE_NETBIOS
//
// Clean up name, and enforce leading slashes
//
str.MakeUpper();
try
{
if (!IS_NETBIOS_NAME(str))
{
str = _T("\\\\") + str;
}
}
catch(CMemoryException * e)
{
TRACEEOLID("!!!exception cleaning up server name");
e->ReportError();
e->Delete();
}
#else
//
// If the name is NETBIOS, convert to upper case. Otherwise
// the name is assumed to be a hostname, and should be
// converted to lower case.
//
if (IS_NETBIOS_NAME(str))
{
str.MakeUpper();
}
else
{
str.MakeLower();
}
#endif // ENFORCE_NETBIOS
return str;
}
CServerInfo::CServerInfo(
IN LPCTSTR lpszServerName,
IN ISMSERVERINFO * psi,
IN CServiceInfo * pServiceInfo
)
/*++
Routine Description:
Construct with a server name. This is typically
in response to a single connection attempt
Arguments:
LPCTSTR lpszServerName : Name of this server
ISMSERVERINFO * psi : Server info
CServiceInfo * pServiceInfo : service that found it.
Return Value:
N/A
--*/
: m_strServerName(lpszServerName),
m_strComment( psi->atchComment),
m_nServiceState(psi->nState),
m_hServer(NULL),
m_pService(pServiceInfo)
{
CServerInfo::CleanServerName(m_strServerName);
if (m_pService != NULL)
{
//
// Bind here
//
if (m_pService->IsK2Service())
{
ASSERT(m_hServer == NULL);
HRESULT hr = m_pService->ISMBind(
m_strServerName,
&m_hServer
);
}
}
else
{
TRACEEOLID("Did not match up server with installed service");
}
}
CServerInfo::CServerInfo(
IN LPCSTR lpszServerName,
IN LPINET_SERVICE_INFO lpisi,
IN CObListPlus & oblServices
)
/*++
Routine Description:
Construct with information from the inetsloc discover
process. Construction of the CString will automatically
perform the ANSI/Unicode conversion,
Arguments:
LPCSTR lpszServerName : Name of this server (no "\\")
LPINET_SERVICE_INFO lpisi : Discovery information
CObListPlus & oblServices : List of installed services
Return Value:
N/A
--*/
: m_strServerName(lpszServerName),
m_strComment(lpisi->ServiceComment),
m_nServiceState(lpisi->ServiceState),
m_hServer(NULL),
m_pService(NULL)
{
CServerInfo::CleanServerName(m_strServerName);
m_pService = FindServiceByMask(lpisi->ServiceMask, oblServices);
if (m_pService != NULL)
{
if (m_pService->IsK2Service())
{
ASSERT(m_hServer == NULL);
HRESULT hr = m_pService->ISMBind(
m_strServerName,
&m_hServer
);
}
}
else
{
TRACEEOLID("Did not match up server with installed service");
}
}
HRESULT
CServerInfo::ISMRebind()
/*++
Routine Description:
Handle lost connection. Attempt to rebind.
Arguments:
None
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
if (m_pService != NULL)
{
if (m_pService->IsK2Service())
{
//
// Must be previously bound
//
ASSERT(m_hServer != NULL);
//
// This may cause a first chance exception, because
// the handle could be invalid at this stage
//
hr = m_pService->ISMUnbind(m_hServer);
hr = m_pService->ISMBind(
m_strServerName,
&m_hServer
);
}
}
return hr;
}
CServerInfo::CServerInfo(
IN const CServerInfo & si
)
/*++
Routine Description:
Copy Constructor
Arguments:
const CServerInfo & si : Source server info object
Return Value:
N/A
--*/
: m_strServerName(si.m_strServerName),
m_strComment(si.m_strComment),
m_nServiceState(si.m_nServiceState),
m_hServer(NULL),
m_pService(si.m_pService)
{
//
// Bind again here
//
if (m_pService->IsK2Service())
{
ASSERT(m_hServer == NULL);
HRESULT hr = m_pService->ISMBind(
m_strServerName,
&m_hServer
);
}
}
CServerInfo::~CServerInfo()
/*++
Routine Description:
Destruct the object. Do not free in the pointer
to the service, because we don't own it.
Arguments:
N/A
Return Value:
N/A
--*/
{
//
// Unbind here
//
if (m_pService->IsK2Service())
{
m_pService->ISMUnbind(m_hServer);
}
}
const CServerInfo &
CServerInfo::operator=(
IN const CServerInfo & si
)
/*++
Routine Description:
Assignment operator
Arguments:
const CServerInfo & si : Source server info object
Return Value:
Reference to this object
--*/
{
m_strServerName = si.m_strServerName;
m_nServiceState = si.m_nServiceState;
m_strComment = si.m_strComment;
m_pService = si.m_pService;
//
// Need to rebind
//
if (m_pService->IsK2Service())
{
ASSERT(m_hServer == NULL);
HRESULT hr = m_pService->ISMBind(
m_strServerName,
&m_hServer
);
}
return *this;
}
BOOL
CServerInfo::operator==(
IN CServerInfo & si
)
/*++
Routine Description:
Comparision Operator
Arguments:
const CServerInfo & si : Server info object to be compared against
Return Value:
TRUE if the objects are the same, FALSE otherwise
--*/
{
//
// Must be the same service type
//
if (m_pService != si.m_pService)
{
return FALSE;
}
//
// And computer name
//
return ::lstrcmpi(
QueryServerDisplayName(),
si.QueryServerDisplayName()
) == 0;
}
DWORD
CServerInfo::ChangeServiceState(
IN int nNewState,
OUT int * pnCurrentState,
IN DWORD dwInstance
)
/*++
Routine Description:
Change Service State on this computer (running,
stopped, paused)
Arguments:
int nNewState : New service state INetServiceRunning, etc
int * pnCurrentState : Pointer to current state
DWORD dwInstance : Instance ID whose state is to be changed
Return Value:
Error return code
--*/
{
ASSERT(m_pService != NULL);
//
// Allocate string with 2 terminating NULLS,
// as required by the apis.
//
int nLen = m_strServerName.GetLength();
LPTSTR lpServers = AllocTString(nLen + 2);
if (lpServers == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
::lstrcpy(lpServers, m_strServerName);
lpServers[nLen+1] = _T('\0');
//
// Call the actual api (0 -- means service)
//
DWORD err = m_pService->ISMChangeServiceState(
nNewState,
pnCurrentState,
dwInstance,
lpServers
);
FreeMem(lpServers);
return err;
}
DWORD
CServerInfo::ConfigureServer(
IN HWND hWnd,
IN DWORD dwInstance
)
/*++
Routine Description:
Perform configuration on this server
Arguments:
HWND hWnd : Parent window handle
DWORD dwInstance : Instance ID to be configured
Return Value:
Error return code
--*/
{
ASSERT(m_pService != NULL);
//
// Allocate string with 2 terminating NULLS
//
// CODEWORK: Make this a helper function
//
int nLen = m_strServerName.GetLength();
LPTSTR lpServers = AllocTString(nLen + 2);
if (lpServers == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
::lstrcpy(lpServers, (LPCTSTR)m_strServerName);
lpServers[nLen + 1] = _T('\0');
DWORD err = m_pService->ISMConfigureServers(hWnd, dwInstance, lpServers);
FreeMem(lpServers);
return err;
}
HRESULT
CServerInfo::MMMCConfigureServer(
IN PVOID lpfnProvider,
IN LPARAM param,
IN LONG_PTR handle,
IN DWORD dwInstance
)
/*++
Routine Description:
Bring up the service configuration property sheets, using the MMC
property mechanism.
Arguments:
PVOID lpfnProvider : Provider callback
LPARAM param : lparam to be passed to the sheet
LONG_PTR handle : console handle
DWORD dwInstance : Instance number
Return Value:
Error return code
--*/
{
ASSERT(m_pService != NULL);
/*
//
// Allocate string with 2 terminating NULLS
//
int nLen = m_strServerName.GetLength();
LPTSTR lpServers = AllocTString(nLen + 2);
if (lpServers == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
::lstrcpy(lpServers, (LPCTSTR)m_strServerName);
lpServers[nLen + 1] = _T('\0');
*/
CError err(m_pService->ISMMMCConfigureServers(
m_hServer,
lpfnProvider,
param,
handle,
dwInstance
));
// FreeMem(lpServers);
return err;
}
DWORD
CServerInfo::Refresh()
/*++
Routine Description:
Attempt to refresh the comment and server state of
the server object
Arguments:
None
Return Value:
Error return code
--*/
{
ISMSERVERINFO si;
si.dwSize = sizeof(si);
CError err(m_pService->ISMQueryServerInfo(
(LPCTSTR)m_strServerName,
&si
));
if (err.Succeeded())
{
ASSERT(si.nState == INetServiceStopped ||
si.nState == INetServicePaused ||
si.nState == INetServiceRunning ||
si.nState == INetServiceUnknown);
m_nServiceState = si.nState;
m_strComment = si.atchComment;
}
return err;
}