762 lines
23 KiB
C++
762 lines
23 KiB
C++
|
#define INITGUID
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <tchar.h>
|
||
|
#include <shellapi.h>
|
||
|
|
||
|
#include <ole2.h>
|
||
|
#include <coguid.h>
|
||
|
#include <iadmw.h>
|
||
|
|
||
|
#include <iiscnfg.h>
|
||
|
|
||
|
#include "pwstray.h"
|
||
|
#include "resource.h"
|
||
|
#include "sink.h"
|
||
|
|
||
|
#include <pwsdata.hxx>
|
||
|
|
||
|
|
||
|
#define MB_TIMEOUT 5000
|
||
|
|
||
|
// not a string!
|
||
|
#define DW_TRAY_ICON_ID 'PWSt'
|
||
|
|
||
|
#define REGKEY_STP _T("SOFTWARE\\Microsoft\\INetStp")
|
||
|
#define REGKEY_INSTALLKEY _T("InstallPath")
|
||
|
|
||
|
//USE_MFC=1
|
||
|
|
||
|
|
||
|
//========================================================= globals
|
||
|
HINSTANCE g_hInstance = NULL;
|
||
|
HWND g_hwnd = NULL;
|
||
|
HMENU g_hMenuMain = NULL;
|
||
|
|
||
|
UINT g_dwNewTaskbarMessage = 0;
|
||
|
|
||
|
DWORD g_dwSinkCookie = 0;
|
||
|
CImpIMSAdminBaseSink* g_pEventSink = NULL;
|
||
|
IConnectionPoint* g_pConnPoint = NULL;
|
||
|
|
||
|
IMSAdminBase* g_pMBCom = NULL;
|
||
|
|
||
|
DWORD g_dwServerState = 0;
|
||
|
|
||
|
//========================================================= forwards
|
||
|
DWORD DWGetServerState();
|
||
|
BOOL FUpdateTrayIcon( DWORD dwMessage );
|
||
|
|
||
|
BOOL InitializeMetabase( OLECHAR* pocMachineName );
|
||
|
void TerminateMetabase();
|
||
|
BOOL InitializeSink();
|
||
|
void TerminateSink();
|
||
|
|
||
|
BOOL GetAdminPath( TCHAR* pch, WORD cch );
|
||
|
BOOL SetServerState( DWORD dwControlCode );
|
||
|
BOOL LaunchAdminUI();
|
||
|
void RunContextMenu();
|
||
|
|
||
|
BOOL FIsW3Running();
|
||
|
void CheckIfServerIsRunningAgain();
|
||
|
void CheckIfServerUpAndDied();
|
||
|
|
||
|
|
||
|
// routine to see if w3svc is running
|
||
|
//--------------------------------------------------------------------
|
||
|
// the method we use to see if the service is running is different on
|
||
|
// windows NT from win95
|
||
|
BOOL FIsW3Running()
|
||
|
{
|
||
|
OSVERSIONINFO info_os;
|
||
|
info_os.dwOSVersionInfoSize = sizeof(info_os);
|
||
|
|
||
|
if ( !GetVersionEx( &info_os ) )
|
||
|
return FALSE;
|
||
|
|
||
|
// if the platform is NT, query the service control manager
|
||
|
if ( info_os.dwPlatformId == VER_PLATFORM_WIN32_NT )
|
||
|
{
|
||
|
BOOL fRunning = FALSE;
|
||
|
|
||
|
// open the service manager
|
||
|
SC_HANDLE sch = OpenSCManager(NULL, NULL, GENERIC_READ );
|
||
|
if ( sch == NULL ) return FALSE;
|
||
|
|
||
|
// get the service
|
||
|
SC_HANDLE schW3 = OpenService(sch, _T("W3SVC"), SERVICE_QUERY_STATUS );
|
||
|
if ( sch == NULL )
|
||
|
{
|
||
|
CloseServiceHandle( sch );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// query the service status
|
||
|
SERVICE_STATUS status;
|
||
|
ZeroMemory( &status, sizeof(status) );
|
||
|
if ( QueryServiceStatus(schW3, &status) )
|
||
|
{
|
||
|
fRunning = (status.dwCurrentState == SERVICE_RUNNING);
|
||
|
}
|
||
|
|
||
|
CloseServiceHandle( schW3 );
|
||
|
CloseServiceHandle( sch );
|
||
|
|
||
|
// return the answer
|
||
|
return fRunning;
|
||
|
}
|
||
|
|
||
|
// if the platform is Windows95, see if the object exists
|
||
|
if ( info_os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
|
||
|
{
|
||
|
HANDLE hEvent;
|
||
|
BOOL fFound = FALSE;
|
||
|
hEvent = CreateEvent(NULL, TRUE, FALSE, _T(PWS_SHUTDOWN_EVENT));
|
||
|
if ( hEvent != NULL )
|
||
|
{
|
||
|
fFound = (GetLastError() == ERROR_ALREADY_EXISTS);
|
||
|
CloseHandle(hEvent);
|
||
|
}
|
||
|
return(fFound);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// This routine is called on a timer event. The timer events only come if we
|
||
|
// have received a shutdown notify callback from the metabase. So the server
|
||
|
// is down. We need to wait around until it comes back up, then show ourselves.
|
||
|
void CheckIfServerIsRunningAgain()
|
||
|
{
|
||
|
// see if the server is running. If it is, show the icon and stop the timer.
|
||
|
if ( FIsW3Running() && g_hwnd )
|
||
|
{
|
||
|
// if we can't use the metabase, there is no point in this
|
||
|
if ( !g_pMBCom && !InitializeMetabase(NULL) )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// if we can't use the sink, there is no point in this
|
||
|
if ( !g_pEventSink && !InitializeSink() )
|
||
|
{
|
||
|
TerminateMetabase();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// stop the life timer mechanism
|
||
|
KillTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART );
|
||
|
|
||
|
// start the unexpected server death test timer
|
||
|
SetTimer( g_hwnd, PWS_TRAY_CHECKTOSEEIFINETINFODIED, TIMER_SERVERDIED, NULL );
|
||
|
|
||
|
// show the tray icon
|
||
|
g_dwServerState = DWGetServerState();
|
||
|
FUpdateTrayIcon( NIM_ADD );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// This routine is called on a timer event. The timer events only come if we know
|
||
|
// the server is running. To avoid wasting too many extra cycles it is called rather
|
||
|
// infrequently. What we are doing here is attempting to see if the server died
|
||
|
// without sending us proper notification. If it did, we should clean up the
|
||
|
// icon and start waiting for it to come back.
|
||
|
void CheckIfServerUpAndDied()
|
||
|
{
|
||
|
if ( !FIsW3Running() )
|
||
|
{
|
||
|
// hide the tray icon
|
||
|
FUpdateTrayIcon( NIM_DELETE );
|
||
|
// disconnect the sink mechanism
|
||
|
TerminateSink();
|
||
|
// disconnect from the metabase
|
||
|
TerminateMetabase();
|
||
|
// stop the death timer
|
||
|
KillTimer( g_hwnd, PWS_TRAY_CHECKTOSEEIFINETINFODIED );
|
||
|
// start the life timer
|
||
|
SetTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
BOOL FUpdateTrayIcon( DWORD dwMessage )
|
||
|
{
|
||
|
NOTIFYICONDATA dataIcon;
|
||
|
|
||
|
// prepare the common parts of the icon data structure
|
||
|
dataIcon.cbSize = sizeof( dataIcon );
|
||
|
dataIcon.hWnd = g_hwnd;
|
||
|
dataIcon.uID = DW_TRAY_ICON_ID;
|
||
|
dataIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
||
|
dataIcon.uCallbackMessage = WM_PWS_TRAY_SHELL_NOTIFY;
|
||
|
|
||
|
// prepare the state-dependant icon handle
|
||
|
switch( g_dwServerState )
|
||
|
{
|
||
|
case MD_SERVER_STATE_PAUSED:
|
||
|
case MD_SERVER_STATE_PAUSING:
|
||
|
dataIcon.hIcon = LoadIcon( g_hInstance, MAKEINTRESOURCE(IDI_PAUSED) );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_STARTED:
|
||
|
case MD_SERVER_STATE_STARTING:
|
||
|
dataIcon.hIcon = LoadIcon( g_hInstance, MAKEINTRESOURCE(IDI_RUNNING) );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_STOPPED:
|
||
|
case MD_SERVER_STATE_STOPPING:
|
||
|
dataIcon.hIcon = LoadIcon( g_hInstance, MAKEINTRESOURCE(IDI_STOPPED) );
|
||
|
break;
|
||
|
};
|
||
|
|
||
|
// prepare the state-dependant tip strings
|
||
|
switch( g_dwServerState )
|
||
|
{
|
||
|
case MD_SERVER_STATE_PAUSED:
|
||
|
LoadString( g_hInstance, IDS_PAUSED, dataIcon.szTip, 63 );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_PAUSING:
|
||
|
LoadString( g_hInstance, IDS_PAUSING, dataIcon.szTip, 63 );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_STARTED:
|
||
|
LoadString( g_hInstance, IDS_STARTED, dataIcon.szTip, 63 );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_STARTING:
|
||
|
LoadString( g_hInstance, IDS_STARTING, dataIcon.szTip, 63 );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_STOPPED:
|
||
|
LoadString( g_hInstance, IDS_STOPPED, dataIcon.szTip, 63 );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_STOPPING:
|
||
|
LoadString( g_hInstance, IDS_STOPPING, dataIcon.szTip, 63 );
|
||
|
break;
|
||
|
};
|
||
|
DWORD err = GetLastError();
|
||
|
|
||
|
// make the shell call
|
||
|
return Shell_NotifyIcon( dwMessage, &dataIcon );
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
DWORD DWGetServerState()
|
||
|
{
|
||
|
HRESULT hErr;
|
||
|
METADATA_HANDLE hMeta;
|
||
|
METADATA_RECORD mdRecord;
|
||
|
DWORD state = 1000;
|
||
|
DWORD dwRequiredLen;
|
||
|
|
||
|
// open the w3svc key so we can get its state
|
||
|
// since this is a pws thing, we only care about the first
|
||
|
// server instance
|
||
|
hErr = g_pMBCom->OpenKey(
|
||
|
METADATA_MASTER_ROOT_HANDLE,
|
||
|
L"/LM/W3SVC/1/",
|
||
|
METADATA_PERMISSION_READ,
|
||
|
MB_TIMEOUT,
|
||
|
&hMeta);
|
||
|
if ( FAILED(hErr) )
|
||
|
return state;
|
||
|
|
||
|
// prepare the metadata record
|
||
|
mdRecord.dwMDIdentifier = MD_SERVER_STATE;
|
||
|
mdRecord.dwMDAttributes = METADATA_INHERIT;
|
||
|
mdRecord.dwMDUserType = IIS_MD_UT_SERVER;
|
||
|
mdRecord.dwMDDataType = DWORD_METADATA;
|
||
|
mdRecord.dwMDDataLen = sizeof(DWORD);
|
||
|
mdRecord.pbMDData = (PBYTE)&state;
|
||
|
|
||
|
// get the data
|
||
|
hErr = g_pMBCom->GetData(
|
||
|
hMeta,
|
||
|
L"",
|
||
|
&mdRecord,
|
||
|
&dwRequiredLen );
|
||
|
|
||
|
// close the key
|
||
|
hErr = g_pMBCom->CloseKey( hMeta );
|
||
|
|
||
|
// return the answer
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// deal with mouse messages that occur on the tray icon
|
||
|
void On_WM_PWS_TRAY_SHELL_NOTIFY(UINT uID, UINT uMouseMsg)
|
||
|
{
|
||
|
if ( uID != DW_TRAY_ICON_ID )
|
||
|
return;
|
||
|
|
||
|
// act on the mouse message
|
||
|
switch( uMouseMsg )
|
||
|
{
|
||
|
case WM_LBUTTONDBLCLK:
|
||
|
LaunchAdminUI();
|
||
|
break;
|
||
|
case WM_RBUTTONDOWN:
|
||
|
RunContextMenu();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// the window proc callback procedure
|
||
|
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch( message )
|
||
|
{
|
||
|
case WM_CREATE:
|
||
|
// get the registered windows message signifying that there is a new
|
||
|
// taskbar. When this message is triggered, we need to re-insert the icon
|
||
|
// into the taskbar. This is usually done when the shell restarts.
|
||
|
// see http://www.microsoft.com/msdn/sdk/inetsdk/help/itt/shell/taskbar.htm
|
||
|
// also see the default case for processing of the message
|
||
|
g_dwNewTaskbarMessage = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
||
|
break;
|
||
|
|
||
|
case WM_PWS_TRAY_SHUTDOWN_NOTIFY:
|
||
|
// hide the tray icon
|
||
|
FUpdateTrayIcon( NIM_DELETE );
|
||
|
// disconnect the sink mechanism
|
||
|
TerminateSink();
|
||
|
// disconnect from the metabase
|
||
|
TerminateMetabase();
|
||
|
// start the time mechanism
|
||
|
SetTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
|
||
|
break;
|
||
|
|
||
|
case WM_TIMER:
|
||
|
switch ( wParam )
|
||
|
{
|
||
|
case PWS_TRAY_CHECKFORSERVERRESTART:
|
||
|
CheckIfServerIsRunningAgain();
|
||
|
break;
|
||
|
case PWS_TRAY_CHECKTOSEEIFINETINFODIED:
|
||
|
CheckIfServerUpAndDied();
|
||
|
break;
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case WM_PWS_TRAY_SHELL_NOTIFY:
|
||
|
On_WM_PWS_TRAY_SHELL_NOTIFY( (UINT)wParam, (UINT)lParam );
|
||
|
break;
|
||
|
case WM_PWS_TRAY_UPDATE_STATE:
|
||
|
g_dwServerState = DWGetServerState();
|
||
|
FUpdateTrayIcon( NIM_MODIFY );
|
||
|
break;
|
||
|
case WM_DESTROY:
|
||
|
FUpdateTrayIcon( NIM_DELETE );
|
||
|
PostQuitMessage(0);
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
switch( LOWORD(wParam) )
|
||
|
{
|
||
|
case ID_START:
|
||
|
SetServerState( MD_SERVER_COMMAND_START );
|
||
|
break;
|
||
|
case ID_STOP:
|
||
|
SetServerState( MD_SERVER_COMMAND_STOP );
|
||
|
break;
|
||
|
case ID_PAUSE:
|
||
|
SetServerState( MD_SERVER_COMMAND_PAUSE );
|
||
|
break;
|
||
|
case ID_CONTINUE:
|
||
|
SetServerState( MD_SERVER_COMMAND_CONTINUE );
|
||
|
break;
|
||
|
case ID_PROPERTIES:
|
||
|
LaunchAdminUI();
|
||
|
break;
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// cannot case directly on g_dwNewTaskbarMessage because it is not a constant
|
||
|
if ( message == g_dwNewTaskbarMessage )
|
||
|
{
|
||
|
// Just go straight into waitin' for the server mode. If the server is
|
||
|
// running it will catch the first time throught the timer. If it is not,
|
||
|
// then we just sit around and wait for it
|
||
|
// start the time mechanism
|
||
|
SetTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
return(DefWindowProc(hWnd, message, wParam, lParam ));
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// main routine
|
||
|
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow )
|
||
|
{
|
||
|
WNDCLASS wndclass;
|
||
|
MSG msg;
|
||
|
|
||
|
// record the instance handle
|
||
|
g_hInstance = hInstance;
|
||
|
|
||
|
// do nothing if this app is already running
|
||
|
if ( hPrevInstance )
|
||
|
return 0;
|
||
|
|
||
|
// one more test of previous instances
|
||
|
if ( FindWindow(PWS_TRAY_WINDOW_CLASS,NULL) )
|
||
|
return 0;
|
||
|
|
||
|
// start ole
|
||
|
if ( FAILED(CoInitialize( NULL )) )
|
||
|
return 0;
|
||
|
|
||
|
// get the menu handle
|
||
|
g_hMenuMain = LoadMenu( g_hInstance, MAKEINTRESOURCE(IDR_POPUP) );
|
||
|
|
||
|
// prepare and register the window class
|
||
|
wndclass.style = 0;
|
||
|
wndclass.lpfnWndProc = WndProc;
|
||
|
wndclass.cbClsExtra = 0;
|
||
|
wndclass.cbWndExtra = 0;
|
||
|
wndclass.hInstance = hInstance;
|
||
|
wndclass.hIcon = NULL;
|
||
|
wndclass.hCursor = NULL;
|
||
|
wndclass.hbrBackground = NULL;
|
||
|
wndclass.lpszMenuName = NULL;
|
||
|
wndclass.lpszClassName = PWS_TRAY_WINDOW_CLASS;
|
||
|
RegisterClass( &wndclass );
|
||
|
|
||
|
// create the window
|
||
|
g_hwnd = CreateWindow(
|
||
|
PWS_TRAY_WINDOW_CLASS, // pointer to registered class name
|
||
|
_T(""), // pointer to window name
|
||
|
0, // window style
|
||
|
0, // horizontal position of window
|
||
|
0, // vertical position of window
|
||
|
0, // window width
|
||
|
0, // window height
|
||
|
NULL, // handle to parent or owner window
|
||
|
NULL, // handle to menu or child-window identifier
|
||
|
hInstance, // handle to application instance
|
||
|
NULL // pointer to window-creation data
|
||
|
);
|
||
|
|
||
|
// Just go straight into waitin' for the server mode. If the server is
|
||
|
// running it will catch the first time throught the timer. If it is not,
|
||
|
// then we just sit around and wait for it
|
||
|
// start the time mechanism
|
||
|
SetTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
|
||
|
|
||
|
// run the message loop
|
||
|
while (GetMessage(&msg, NULL, 0, 0))
|
||
|
{
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage( &msg);
|
||
|
}
|
||
|
|
||
|
// clean up the sink and the metabase
|
||
|
DestroyMenu( g_hMenuMain );
|
||
|
TerminateSink();
|
||
|
TerminateMetabase();
|
||
|
CoUninitialize();
|
||
|
|
||
|
return((int)msg.wParam);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------
|
||
|
BOOL InitializeSink()
|
||
|
{
|
||
|
IConnectionPointContainer * pConnPointContainer = NULL;
|
||
|
HRESULT hRes;
|
||
|
BOOL fSinkConnected = FALSE;
|
||
|
|
||
|
// g_pMBCom is defined in wrapmb
|
||
|
IUnknown* pmb = (IUnknown*)g_pMBCom;
|
||
|
|
||
|
g_pEventSink = new CImpIMSAdminBaseSink();
|
||
|
|
||
|
if ( !g_pEventSink )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// First query the object for its Connection Point Container. This
|
||
|
// essentially asks the object in the server if it is connectable.
|
||
|
//
|
||
|
hRes = pmb->QueryInterface( IID_IConnectionPointContainer,
|
||
|
(PVOID *)&pConnPointContainer);
|
||
|
if SUCCEEDED(hRes)
|
||
|
{
|
||
|
// Find the requested Connection Point. This AddRef's the
|
||
|
// returned pointer.
|
||
|
|
||
|
hRes = pConnPointContainer->FindConnectionPoint( IID_IMSAdminBaseSink,
|
||
|
&g_pConnPoint);
|
||
|
|
||
|
if (SUCCEEDED(hRes))
|
||
|
{
|
||
|
hRes = g_pConnPoint->Advise( (IUnknown *)g_pEventSink,
|
||
|
&g_dwSinkCookie);
|
||
|
|
||
|
if (SUCCEEDED(hRes))
|
||
|
{
|
||
|
fSinkConnected = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( pConnPointContainer )
|
||
|
{
|
||
|
pConnPointContainer->Release();
|
||
|
pConnPointContainer = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !fSinkConnected )
|
||
|
{
|
||
|
delete g_pEventSink;
|
||
|
g_pEventSink = NULL;
|
||
|
}
|
||
|
|
||
|
return fSinkConnected;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------
|
||
|
void TerminateSink()
|
||
|
{
|
||
|
HRESULT hRes;
|
||
|
if ( g_dwSinkCookie && g_pConnPoint )
|
||
|
hRes = g_pConnPoint->Unadvise( g_dwSinkCookie );
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------
|
||
|
BOOL InitializeMetabase( OLECHAR* pocMachineName )
|
||
|
{
|
||
|
IClassFactory* pcsfFactory = NULL;
|
||
|
COSERVERINFO csiMachineName;
|
||
|
COSERVERINFO* pcsiParam = NULL;
|
||
|
|
||
|
HRESULT hresError;
|
||
|
|
||
|
//release previous interface if needed
|
||
|
if( g_pMBCom != NULL )
|
||
|
{
|
||
|
g_pMBCom->Release();
|
||
|
g_pMBCom = NULL;
|
||
|
}
|
||
|
|
||
|
//fill the structure for CoGetClassObject
|
||
|
ZeroMemory( &csiMachineName, sizeof(csiMachineName) );
|
||
|
// csiMachineName.pAuthInfo = NULL;
|
||
|
// csiMachineName.dwFlags = 0;
|
||
|
// csiMachineName.pServerInfoExt = NULL;
|
||
|
csiMachineName.pwszName = pocMachineName;
|
||
|
pcsiParam = &csiMachineName;
|
||
|
|
||
|
hresError = CoGetClassObject(GETAdminBaseCLSID(TRUE), CLSCTX_SERVER, pcsiParam,
|
||
|
IID_IClassFactory, (void**) &pcsfFactory);
|
||
|
if (FAILED(hresError))
|
||
|
return FALSE;
|
||
|
|
||
|
// create the instance of the interface
|
||
|
hresError = pcsfFactory->CreateInstance(NULL, IID_IMSAdminBase, (void **)&g_pMBCom);
|
||
|
if (FAILED(hresError))
|
||
|
{
|
||
|
g_pMBCom = FALSE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// release the factory
|
||
|
pcsfFactory->Release();
|
||
|
|
||
|
// success
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------
|
||
|
void TerminateMetabase()
|
||
|
{
|
||
|
if ( g_pMBCom )
|
||
|
{
|
||
|
g_pMBCom->Release();
|
||
|
g_pMBCom = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//======================================== control actions
|
||
|
//------------------------------------------------------------------------
|
||
|
// get the inetinfo path
|
||
|
BOOL LaunchAdminUI()
|
||
|
{
|
||
|
TCHAR chPath[MAX_PATH+1];
|
||
|
|
||
|
// get the path to the admin UI
|
||
|
if ( !GetAdminPath( chPath, MAX_PATH ) )
|
||
|
{
|
||
|
LoadString( g_hInstance, IDS_ADMINUI_ERR, chPath, MAX_PATH );
|
||
|
MessageBox( g_hwnd, chPath, NULL, MB_OK|MB_ICONERROR );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// do it
|
||
|
ShellExecute(
|
||
|
NULL, // handle to parent window
|
||
|
NULL, // pointer to string that specifies operation to perform
|
||
|
chPath, // pointer to filename or folder name string
|
||
|
NULL, // pointer to string that specifies executable-file parameters
|
||
|
NULL, // pointer to string that specifies default directory
|
||
|
SW_SHOW // whether file is shown when opened
|
||
|
);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
// get the inetinfo path
|
||
|
BOOL GetAdminPath( TCHAR* pch, WORD cch )
|
||
|
{
|
||
|
HKEY hKey;
|
||
|
DWORD err, type;
|
||
|
DWORD cbBuff = cch * sizeof(TCHAR);
|
||
|
|
||
|
// get the server install path from the registry
|
||
|
// open the registry key, if it exists
|
||
|
err = RegOpenKeyEx(
|
||
|
HKEY_LOCAL_MACHINE, // handle of open key
|
||
|
REGKEY_STP, // address of name of subkey to open
|
||
|
0, // reserved
|
||
|
KEY_READ, // security access mask
|
||
|
&hKey // address of handle of open key
|
||
|
);
|
||
|
|
||
|
// if we did not open the key for any reason (say... it doesn't exist)
|
||
|
// then leave right away
|
||
|
if ( err != ERROR_SUCCESS )
|
||
|
return FALSE;
|
||
|
|
||
|
type = REG_SZ;
|
||
|
err = RegQueryValueEx(
|
||
|
hKey, // handle of key to query
|
||
|
REGKEY_INSTALLKEY, // address of name of value to query
|
||
|
NULL, // reserved
|
||
|
&type, // address of buffer for value type
|
||
|
(PUCHAR)pch, // address of data buffer
|
||
|
&cbBuff // address of data buffer size
|
||
|
);
|
||
|
|
||
|
// close the key
|
||
|
RegCloseKey( hKey );
|
||
|
|
||
|
// if we did get the key for any reason (say... it doesn't exist)
|
||
|
// then leave right away
|
||
|
if ( err != ERROR_SUCCESS )
|
||
|
return FALSE;
|
||
|
|
||
|
// tack on the file name itself
|
||
|
TCHAR chFile[64];
|
||
|
|
||
|
if ( LoadString( g_hInstance, IDS_ADMIN_UI, chFile, 63 ) == 0 )
|
||
|
return FALSE;
|
||
|
|
||
|
_tcscat( pch, chFile );
|
||
|
|
||
|
// success
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
BOOL SetServerState( DWORD dwControlCode )
|
||
|
{
|
||
|
HRESULT hErr;
|
||
|
METADATA_HANDLE hMeta;
|
||
|
METADATA_RECORD mdRecord;
|
||
|
|
||
|
// open the w3svc key so we can get its state
|
||
|
// since this is a pws thing, we only care about the first
|
||
|
// server instance
|
||
|
hErr = g_pMBCom->OpenKey(
|
||
|
METADATA_MASTER_ROOT_HANDLE,
|
||
|
L"/LM/W3SVC/1/",
|
||
|
METADATA_PERMISSION_WRITE,
|
||
|
MB_TIMEOUT,
|
||
|
&hMeta);
|
||
|
if ( FAILED(hErr) )
|
||
|
return FALSE;
|
||
|
|
||
|
// prepare the metadata record
|
||
|
mdRecord.dwMDIdentifier = MD_SERVER_COMMAND;
|
||
|
mdRecord.dwMDAttributes = 0;
|
||
|
mdRecord.dwMDUserType = IIS_MD_UT_SERVER;
|
||
|
mdRecord.dwMDDataType = DWORD_METADATA;
|
||
|
mdRecord.dwMDDataLen = sizeof(DWORD);
|
||
|
mdRecord.pbMDData = (PBYTE)&dwControlCode;
|
||
|
|
||
|
// get the data
|
||
|
hErr = g_pMBCom->SetData(
|
||
|
hMeta,
|
||
|
L"",
|
||
|
&mdRecord );
|
||
|
|
||
|
// close the key
|
||
|
hErr = g_pMBCom->CloseKey( hMeta );
|
||
|
|
||
|
// return the answer
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void RunContextMenu()
|
||
|
{
|
||
|
POINT pos;
|
||
|
HMENU hMenuSub;
|
||
|
RECT rect = {0,0,1,1};
|
||
|
BOOL f;
|
||
|
|
||
|
static BOOL fTracking = FALSE;
|
||
|
|
||
|
if ( fTracking ) return;
|
||
|
fTracking = TRUE;
|
||
|
|
||
|
// where is the mouse? This tells us where to put the menu
|
||
|
if ( !g_hMenuMain || !GetCursorPos(&pos) )
|
||
|
return;
|
||
|
|
||
|
// get the menu handle
|
||
|
hMenuSub = GetSubMenu( g_hMenuMain, 0 );
|
||
|
|
||
|
// easiest to start by disabling all the state based items
|
||
|
f = EnableMenuItem( hMenuSub, ID_START, MF_BYCOMMAND|MF_GRAYED );
|
||
|
f = EnableMenuItem( hMenuSub, ID_STOP, MF_BYCOMMAND|MF_GRAYED );
|
||
|
f = EnableMenuItem( hMenuSub, ID_PAUSE, MF_BYCOMMAND|MF_GRAYED );
|
||
|
f = EnableMenuItem( hMenuSub, ID_CONTINUE, MF_BYCOMMAND|MF_GRAYED );
|
||
|
|
||
|
// prepare the state based menu items
|
||
|
switch( g_dwServerState )
|
||
|
{
|
||
|
case MD_SERVER_STATE_PAUSED:
|
||
|
case MD_SERVER_STATE_PAUSING:
|
||
|
EnableMenuItem( hMenuSub, ID_STOP, MF_BYCOMMAND|MF_ENABLED );
|
||
|
EnableMenuItem( hMenuSub, ID_CONTINUE, MF_BYCOMMAND|MF_ENABLED );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_STARTED:
|
||
|
case MD_SERVER_STATE_STARTING:
|
||
|
EnableMenuItem( hMenuSub, ID_STOP, MF_BYCOMMAND|MF_ENABLED );
|
||
|
EnableMenuItem( hMenuSub, ID_PAUSE, MF_BYCOMMAND|MF_ENABLED );
|
||
|
break;
|
||
|
case MD_SERVER_STATE_STOPPED:
|
||
|
case MD_SERVER_STATE_STOPPING:
|
||
|
EnableMenuItem( hMenuSub, ID_START, MF_BYCOMMAND|MF_ENABLED );
|
||
|
break;
|
||
|
};
|
||
|
|
||
|
// this is necessary, because we need to get a lose focus message for the menu
|
||
|
// to go down when the user click on some other process outside the up menu
|
||
|
SetForegroundWindow(g_hwnd);
|
||
|
|
||
|
// run the menu
|
||
|
TrackPopupMenu(hMenuSub, TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x, pos.y, 0, g_hwnd, NULL);
|
||
|
|
||
|
fTracking = FALSE;
|
||
|
}
|