1344 lines
28 KiB
C++
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;
|
|
}
|