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

659 lines
15 KiB
C++
Raw Blame History

///////////////////////////////////////////////////////////////////////////////
//
// File: tmscfg.cpp
// Purpose: API Entry points for service ui version 2.0
//
#include "stdafx.h"
#define DLL_BASED __declspec(dllexport)
#include "tmscfg.h"
#include "tmservic.h"
#include "tmsessio.h"
// ===========================================================================
//
// Standard configuration Information
//
// ===========================================================================
//
// Is this server discoverable by INETSLOC?
//
#define INETSLOC_DISCOVERY FALSE
#if (INETSLOC_DISCOVERY) && !defined(_SVCLOC_)
#error You must include svcloc.h.
#endif
//
// If INETSLOC_DISCOVERY == TRUE, define the discovery MASK here.
//
#if (INETSLOC_DISCOVERY)
#define INETSLOC_MASK
#else // (!INETSLOC_DISCOVERY)
#define INETSLOC_MASK (ULONGLONG)(0x00000000)
#endif // (INETSLOC_DISCOVERY)
//
// Do we use the service control manager to control
// the service we administer?
//
#define USE_SC_MANAGER FALSE
//
// Can we change the service state (start/pause/continue)?
//
#define CAN_CHANGE_SERVICE_STATE FALSE
//
// Can we pause this service?
//
#define CAN_PAUSE_SERVICE FALSE
#if (USE_SC_MANAGER)
//
// Name used for this service by the service controller manager.
//
#define SERVICE_SC_NAME _T("TEMPLATE")
#endif // USE_SC_MANAGER
//
// Short descriptive name of the service. This
// is what will show up as the name of the service
// in the internet manager tool.
//
// Issue: I'm assuming here that this name does NOT
// require localisation.
//
#define SERVICE_SHORT_NAME _T("Template v2.0")
//
// Longer name. This is the text that shows up in
// the tooltips text on the internet manager
// tool. This probably should be localised.
//
#define SERVICE_LONG_NAME _T("Template Service")
//
// Use normal colour mapping.
//
#define NORMAL_TB_MAPPING TRUE
//
// Toolbar button background mask. This is
// the colour that gets masked out in
// the bitmap file and replaced with the
// actual button background. This setting
// is automatically assumed to be lt. gray
// if NORMAL_TB_MAPPING (above) is TRUE
//
#define BUTTON_BMP_BACKGROUND RGB(192, 192, 192) // Lt. Gray
//
// Resource ID of the toolbar button bitmap.
//
// The bitmap must be 17x17
//
#define BUTTON_BMP_ID IDB_TEMPLATE
//
// Similar to BUTTON_BMP_BACKGROUND, this is the
// background mask for the service ID
//
#define SERVICE_BMP_BACKGROUND BUTTON_BMP_BACKGROUND
//
// Bitmap id which is used in the service view
// of the service manager.
//
// The bitmap must be 17x17, and can be the
// same as BUTTON_BMP_ID bitmap.
//
#define SERVICE_BMP_ID BUTTON_BMP_ID
// ===========================================================================
//
// End Of Standard configuration Information
//
// ===========================================================================
//
// Helper Macros
//
#define IS_NETBIOS_NAME(lpstr) (*lpstr == _T('\\'))
//
// Return the portion of a computer name without the backslashes
//
#define PURE_COMPUTER_NAME(lpstr) (IS_NETBIOS_NAME(lpstr) ? lpstr + 2 : lpstr)
//
// Global DLL instance
//
HINSTANCE hInstance;
// ============================================================================
//
// ISM API Functions
//
// ============================================================================
///////////////////////////////////////////////////////////////////////////////
//
// Return service-specific information back to
// to the application. This function is called
// by the service manager immediately after
// LoadLibary(); The size element must be
// set prior to calling this API.
//
DLL_BASED DWORD APIENTRY
ISMQueryServiceInfo(
ISMSERVICEINFO * psi // Service information returned.
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState() );
if ( psi == NULL
|| psi->dwSize < ISMSERVICEINFO_SIZE
)
{
TRACE(_T("ISMQueryServiceInfo: ISMSERVICEINFO invalid\n"));
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
#ifdef _DEBUG
if (psi->dwSize != ISMSERVICEINFO_SIZE)
{
TRACE(_T("Warning: internet manager is newer than DLL\n"));
}
#endif // _DEBUG
psi->dwSize = ISMSERVICEINFO_SIZE;
psi->dwVersion = ISM_VERSION;
psi->flServiceInfoFlags = 0
#if (INETSLOC_DISCOVERY)
| ISMI_INETSLOCDISCOVER
#endif
#if (CAN_CHANGE_SERVICE_STATE)
| ISMI_CANCONTROLSERVICE
#endif
#if (CAN_PAUSE_SERVICE)
| ISMI_CANPAUSESERVICE
#endif
#if (NORMAL_TB_MAPPING)
| ISMI_NORMALTBMAPPING
#endif
; /**/
ASSERT(::lstrlen(SERVICE_LONG_NAME) <= MAX_LNLEN);
ASSERT(::lstrlen(SERVICE_SHORT_NAME) <= MAX_SNLEN);
psi->ullDiscoveryMask = INETSLOC_MASK;
psi->rgbButtonBkMask = BUTTON_BMP_BACKGROUND;
psi->nButtonBitmapID = BUTTON_BMP_ID;
psi->rgbServiceBkMask = SERVICE_BMP_BACKGROUND;
psi->nServiceBitmapID = SERVICE_BMP_ID;
::lstrcpy(psi->atchShortName, SERVICE_SHORT_NAME);
::lstrcpy(psi->atchLongName, SERVICE_LONG_NAME);
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// Discover machines running this service. This is
// only necessary for services not discovered with
// inetscloc (which don't give a mask)
//
DLL_BASED DWORD APIENTRY
ISMDiscoverServers(
ISMSERVERINFO * psi, // Server info buffer.
DWORD * pdwBufferSize, // Size required/available.
int * cServers // Number of servers in buffer.
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState() );
#if (INETSLOC_DISCOVERY)
#error You do not need to provide a discovery method.
#else
//
// Dummy example, which discovers 2 servers running our service
//
int cServersFound = 2;
DWORD dwRequiredSize = sizeof(ISMSERVERINFO) * cServersFound;
if (*pdwBufferSize < dwRequiredSize || psi == NULL)
{
*pdwBufferSize = dwRequiredSize;
*cServers = cServersFound;
return ERROR_MORE_DATA;
}
psi[0].dwSize = ISMSERVERINFO_SIZE;
::lstrcpy(psi[0].atchServerName, _T("\\FOO"));
::lstrcpy(psi[0].atchComment, _T("Dummy Entry 1"));
psi[0].nState = INetServiceUnknown;
psi[1].dwSize = ISMSERVERINFO_SIZE;
::lstrcpy(psi[1].atchServerName, _T("\\BAR"));
::lstrcpy(psi[1].atchComment, _T("Dummy Entry 2"));
psi[1].nState = INetServiceUnknown;
return ERROR_SUCCESS;
#endif // (INETSLOC_DISCOVERY)
}
///////////////////////////////////////////////////////////////////////////////
//
// Get information about a specific server with
// regards to this service. Usually this uses
// the service control manager
//
DLL_BASED DWORD APIENTRY
ISMQueryServerInfo(
LPCTSTR lpstrServerName, // Name of server.
ISMSERVERINFO * psi // Server information returned.
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState() );
if ( psi == NULL
|| psi->dwSize < ISMSERVERINFO_SIZE
|| ::lstrlen(lpstrServerName) > MAX_SERVERNAME_LEN
)
{
TRACE(_T("ISMQueryServerInfo: bad parameters\n"));
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
#ifdef _DEBUG
if (psi->dwSize != ISMSERVERINFO_SIZE)
{
TRACE(_T("Warning internet manager is newer than DLL\n"));
}
#endif // _DEBUG
psi->dwSize = ISMSERVERINFO_SIZE;
::lstrcpy(psi->atchServerName, lpstrServerName);
#if (USE_SC_MANAGER)
//
// Provide simple SC management. This is probably
// inadequate for real-world use.
//
SC_HANDLE hScManager;
hScManager = ::OpenSCManager(lpstrServerName, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (hScManager == NULL)
{
return ::GetLastError();
}
DWORD err = ERROR_SUCCESS;
SC_HANDLE hService = ::OpenService(hScManager,
SERVICE_SC_NAME, SERVICE_QUERY_STATUS);
if (hService == NULL)
{
err = ::GetLastError();
}
else
{
SERVICE_STATUS ss;
VERIFY(::QueryServiceStatus(hService, &ss));
switch(ss.dwCurrentState)
{
case SERVICE_STOPPED:
case SERVICE_STOP_PENDING:
psi->nState = INetServiceStopped;
break;
case SERVICE_RUNNING:
case SERVICE_START_PENDING:
case SERVICE_CONTINUE_PENDING:
psi->nState = INetServiceRunning;
break;
case SERVICE_PAUSE_PENDING:
case SERVICE_PAUSED:
psi->nState = INetServicePaused;
break;
default:
psi->nState = INetServiceUnknown;
}
::CloseServiceHandle(hService);
}
::CloseServiceHandle(hScManager);
return err;
#else
::lstrcpy(psi->atchComment, _T("Dummy Entry"));
psi->nState = INetServiceUnknown;
return ERROR_SUCCESS;
#endif // USE_SC_MANAGER
}
///////////////////////////////////////////////////////////////////////////////
//
// Change the service state of the servers (to paused/continue, started,
// stopped, etc)
//
DLL_BASED DWORD APIENTRY
ISMChangeServiceState(
int nNewState, // INetService* definition.
int * pnCurrentState, // Ptr to current state (will be changed
DWORD dwReserved, // Reserved: must be 0
LPCTSTR lpstrServers // Double NULL terminated list of servers.
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState() );
if ( dwReserved != 0L
|| nNewState < INetServiceStopped
|| nNewState > INetServicePaused
)
{
TRACE(_T("ISMChangeServiceState: Invalid information passed\n"));
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
#if (USE_SC_MANAGER)
//
// Provide simple SC management. This is probably
// inadequate for real-world use.
//
SC_HANDLE hService;
SC_HANDLE hScManager;
hScManager = ::OpenSCManager(lpstrServers, NULL, SC_MANAGER_ALL_ACCESS);
if (hScManager == NULL)
{
return ::GetLastError();
}
hService = OpenService(hScManager, SERVICE_SC_NAME, SERVICE_ALL_ACCESS);
if (hService == NULL)
{
return ::GetLastError();
}
SERVICE_STATUS ss;
BOOL fSuccess;
switch(nNewState)
{
case INetServiceStopped:
fSuccess = ::ControlService(hService, SERVICE_CONTROL_STOP, &ss);
break;
case INetServiceRunning:
if (*pnCurrentState == INetServicePaused)
{
fSuccess = ::ControlService(hService, SERVICE_CONTROL_CONTINUE, &ss);
}
else
{
fSuccess = ::StartService(hService, 0, NULL);
}
break;
case INetServicePaused:
fSuccess = ::ControlService(hService, SERVICE_CONTROL_PAUSE, &ss);
break;
}
//
// Update state information
//
VERIFY(::QueryServiceStatus(hService, &ss));
switch(ss.dwCurrentState)
{
case SERVICE_STOPPED:
case SERVICE_STOP_PENDING:
*pnCurrentState = INetServiceStopped;
break;
case SERVICE_RUNNING:
case SERVICE_START_PENDING:
case SERVICE_CONTINUE_PENDING:
*pnCurrentState = INetServiceRunning;
break;
case SERVICE_PAUSE_PENDING:
case SERVICE_PAUSED:
*pnCurrentState = INetServicePaused;
break;
default:
*pnCurrentState = INetServiceUnknown;
}
::CloseServiceHandle(hService);
::CloseServiceHandle(hScManager);
if (!fSuccess)
{
return ::GetLastError();
}
return ERROR_SUCCESS;
#else
return ERROR_INVALID_FUNCTION;
#endif // USE_SC_MANAGER
}
///////////////////////////////////////////////////////////////////////////////
//
// Display configuration property sheet.
//
DLL_BASED DWORD APIENTRY
ISMConfigureServers(
HWND hWnd, // Main app window handle
DWORD dwReserved, // Reserved: must be 0
LPCTSTR lpstrServers // Double NULL terminated list of servers
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState() );
DWORD err;
if (dwReserved != 0L)
{
TRACE(_T("ISMConfigureServers: Invalid information passed\n"));
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
//
// Convert the list of servers to a
// more manageable CStringList.
//
LPCTSTR pBuf = lpstrServers;
CStringList strlServers;
while (*pBuf != TCHAR('\0'))
{
CString strTmp = pBuf;
strlServers.AddTail( strTmp );
pBuf += strTmp.GetLength() + 1;
}
if (strlServers.GetCount() == 0)
{
TRACE(_T("Error: strlServers Count == 0.\n"));
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
CString strCaption;
if (strlServers.GetCount() == 1)
{
CString str;
VERIFY(str.LoadString(IDS_CAPTION));
strCaption.Format(str, PURE_COMPUTER_NAME(lpstrServers));
}
else // Multiple server caption
{
VERIFY(strCaption.LoadString(IDS_CAPTION_MULTIPLE));
}
//
// Show property sheet with some dummy pages on it.
//
CPropertySheet sheet(strCaption, CWnd::FromHandle(hWnd));
CTMServicePage page1;
CTMSessionsPage page2;
sheet.AddPage(&page1);
sheet.AddPage(&page2);
sheet.DoModal();
//
// Didn't do anything, but what we did, we did
// perfectly.
//
err = ERROR_SUCCESS;
return err;
}
// ============================================================================
//
// End of ISM API Functions
//
// ============================================================================
//
// Perform additional initialisation as necessary
//
void
InitializeDLL()
{
#ifdef _DEBUG
afxMemDF |= checkAlwaysMemDF;
#endif // _DEBUG
}
//
// Declare the one and only dll object
//
CConfigDll NEAR theApp;
CConfigDll::CConfigDll(
IN LPCTSTR pszAppName OPTIONAL
)
/*++
Routine Description:
Constructor for USRDLL
Arguments:
LPCTSTR pszAppName : Name of the app or NULL to load from resources
Return Value:
N/A
--*/
: CWinApp(pszAppName)
{
}
BOOL
CConfigDll::InitInstance()
/*++
Routine Description:
Initialise current instance of the DLL
Arguments:
None
Return Value:
TRUE for successful initialisation, FALSE otherwise
--*/
{
BOOL bInit = CWinApp::InitInstance();
hInstance = ::AfxGetInstanceHandle();
ASSERT(hInstance);
InitializeDLL();
return bInit;
}
int
CConfigDll::ExitInstance()
/*++
Routine Description:
Clean up current instance
Arguments:
None
Return Value:
The application<6F>s exit code; 0 indicates no errors, and values greater
than 0 indicate an error.
--*/
{
return CWinApp::ExitInstance();
}
//
// Message Map
//
BEGIN_MESSAGE_MAP(CConfigDll, CWinApp)
//{{AFX_MSG_MAP(CConfigDll)
//}}AFX_MSG_MAP
//
// Global help commands (must be present)
//
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
ON_COMMAND(ID_CONTEXT_HELP, CWinApp::OnContextHelp)
END_MESSAGE_MAP()