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

1321 lines
39 KiB
C++

// this is the internal content-specific stuff related to the
// CShellExt object
#include "priv.h"
#include <stdio.h>
#include <tchar.h>
#include <iiscnfgp.h>
//#include <inetinfo.h>
#include <winsvc.h>
#include <pwsdata.hxx>
#include <iwamreg.h>
#include <shlwapi.h>
#include "wrapmb.h"
#include "Sink.h"
#include "eddir.h"
#include "shellext.h"
#include "wrapmb.h"
extern HINSTANCE g_hmodThisDll; // Handle to this DLL itself.
#define SZ_MB_SERVICE _T("/LM/W3SVC/")
#define SZ_ROOT _T("/ROOT")
#define SZ_SERVER_KEYTYPE _T("IIsWebServer")
#define IIS_CAP1_10_CONNECTION_LIMIT 0x00000040
BOOL MakeWAMApplication( IN LPCTSTR pszPath, IN BOOL fCreate );
BOOL MyFormatString1( IN LPTSTR pszSource, IN DWORD cchMax, LPTSTR pszReplace );
//--------------------------------------------------------------------
// test if we have proper access to the metabase
BOOL CShellExt::FIsAdmin()
{
BOOL fAnswer = FALSE;
CWrapMetaBase mb;
FInitMetabase();
// first things first. get the state of the server
// init the mb object. If it fails then the server app is probably not running
if ( mb.FInit(m_pMBCom) )
{
BOOL fOpen = mb.Open(_T("/LM/W3SVC"), METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
if ( fOpen )
{
// Write some nonsense
DWORD dwDummy = 0x1234;
fAnswer = mb.SetDword( _T(""), MD_ISM_ACCESS_CHECK, IIS_MD_UT_FILE, dwDummy, 0 );
// close the metabase object
mb.Close();
}
}
// Grrrrr!! Boyd, you should clean up after youself
FCloseMetabase();
// return the answer
return fAnswer;
}
//---------------------------------------------------------------
// return FALSE if we do NOT handle the message
BOOL CShellExt::OnCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
switch (LOWORD(wParam))
{
case IDC_LIST:
return OnListBoxNotify(hDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
case IDC_ADD:
OnAdd();
return TRUE;
case IDC_EDIT:
OnEdit();
return TRUE;
case IDC_REMOVE:
OnRemove();
return TRUE;
case IDC_RDO_NOT:
OnRdoNot();
break;
case IDC_RDO_SHARE:
OnRdoShare();
break;
case IDC_COMBO_SERVER:
if ( HIWORD(wParam) == CBN_SELCHANGE )
{
OnSelchangeComboServer();
}
break;
}
// we did not handle it
return FALSE;
}
//---------------------------------------------------------------
// return FALSE if we do NOT handle the message
BOOL CShellExt::OnListBoxNotify(HWND hDlg, int idCtrl, WORD code, HWND hwndControl)
{
switch (code)
{
case LBN_DBLCLK:
{
OnEdit();
return TRUE;
}
case LBN_SELCHANGE:
{
EnableItems();
return TRUE;
}
}
return FALSE;
}
//---------------------------------------------------------------
// return FALSE if we do NOT handle the message
BOOL CShellExt::OnMessage(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BOOL fHandledMessage = FALSE;
// the BIG dialog switch statement....
switch( uMsg )
{
case WM_INITDIALOG:
m_hwnd = hDlg;
// init the controls
if ( !InitControls() )
return FALSE;
// the big init
if ( FInitMetabase() )
{
Init();
m_fInitialized = TRUE;
}
else
return FALSE;
// return success
fHandledMessage = TRUE;
break;
case WM_DESTROY:
ResetListContent();
break;
case WM_COMMAND:
fHandledMessage = OnCommand(hDlg, wParam, lParam);
break;
case WM_UPDATE_SERVER_STATE:
UpdateState();
EnableItems();
return TRUE;
case WM_UPDATE_ALIAS_LIST:
EmptyList();
BuildAliasList();
EnableItems();
return TRUE;
case WM_SHUTDOWN_NOTIFY:
EnterShutdownMode();
return TRUE;
case WM_INSPECT_SERVER_LIST:
InspectServerList();
return TRUE;
case WM_TIMER:
if ( wParam == PWS_TIMER_CHECKFORSERVERRESTART )
{
OnTimer( (UINT)wParam );
fHandledMessage = TRUE;
}
break;
};
// return whether or not we handled the message
return fHandledMessage;
}
//---------------------------------------------------------------
// obtain all the control handles that we will need as the dialog goes along
BOOL CShellExt::InitControls()
{
m_icon_pws = GetDlgItem( m_hwnd, IDC_STATIC_ICON_PWS );
m_icon_iis = GetDlgItem( m_hwnd, IDC_STATIC_ICON_IIS );
m_static_share_on_title = GetDlgItem( m_hwnd, IDC_STATIC_SHARE_ON );
m_ccombo_server = GetDlgItem( m_hwnd, IDC_COMBO_SERVER );
m_cbtn_share = GetDlgItem( m_hwnd, IDC_RDO_SHARE );
m_cbtn_not = GetDlgItem( m_hwnd, IDC_RDO_NOT );
m_cstatic_alias_title = GetDlgItem( m_hwnd, IDC_STATIC_ALIAS_TITLE );
m_cbtn_add = GetDlgItem( m_hwnd, IDC_ADD );
m_cbtn_remove = GetDlgItem( m_hwnd, IDC_REMOVE );
m_cbtn_edit = GetDlgItem( m_hwnd, IDC_EDIT );
m_clist_list = GetDlgItem( m_hwnd, IDC_LIST );
m_static_status = GetDlgItem( m_hwnd, IDC_STATIC_STATUS );
return TRUE;
}
//--------------------------------------------------------------------
// remove all the alias items in the list
void CShellExt::EmptyList()
{
ListBox_ResetContent( m_clist_list );
}
//---------------------------------------------------------------
// CDialog simulation routines
void CShellExt::UpdateData( BOOL fDialogToData )
{
// get the data
if ( fDialogToData )
{
// set the data
m_int_share = (SendMessage( m_cbtn_share, BM_GETCHECK, 0, 0 ) == BST_CHECKED);
m_int_server = (int)SendMessage( m_ccombo_server, CB_GETCURSEL, 0, 0 );
if ( m_int_server < 0 )
m_int_server = 0;
}
else
{
// set the data
SendMessage( m_ccombo_server, CB_SETCURSEL, m_int_server, 0 );
if ( m_int_share )
{
SendMessage( m_cbtn_not, BM_SETCHECK, BST_UNCHECKED, 0 );
SendMessage( m_cbtn_share, BM_SETCHECK, BST_CHECKED, 0 );
}
else
{
SendMessage( m_cbtn_share, BM_SETCHECK, BST_UNCHECKED, 0 );
SendMessage( m_cbtn_not, BM_SETCHECK, BST_CHECKED, 0 );
}
}
}
//--------------------------------------------------------------------
// This method gets called when an object in the metabase has been
// deleted. The purpose is to see if the current virtual directory in
// the metabase has been deleted or not. If it has been deleted, then
// we go to the default sever. Or the first one. Or whatever is there.
void CShellExt::InspectServerList()
{
BOOL fItsGone = FALSE;
TCHAR szRoot[200];
CWrapMetaBase mb;
if ( !mb.FInit(m_pMBCom) )
return;
// Attempt to open the root. If that fails, its otta here
GetRootString( szRoot, 100 );
if (!mb.Open(szRoot))
return;
mb.Close();
// it is gone. Default to the first one
SendMessage( m_ccombo_server, CB_SETCURSEL, 0, 0 );
}
//------------------------------------------------------------------
// This routine builds the correct metabase path up to /LM/W3SVC/*/ROOT
// where the * is the current virtual server selected in the drop down.
// There are two versions of this routine. One where the string is passed
// in as a variable, and the other returns it
void CShellExt::GetRootString( LPTSTR sz, DWORD cchMax )
{
// get the service part
GetVirtServerString(sz, cchMax);
// add on the ROOT part
StrCatBuff(sz, SZ_ROOT, cchMax);
}
//------------------------------------------------------------------
// This routine builds the correct metabase path up to /LM/W3SVC/*
// where the * is the current virtual server selected in the drop down.
// There are two versions of this routine. One where the string is passed
// in as a variable, and the other returns it
void CShellExt::GetVirtServerString(LPTSTR sz, DWORD cchMax)
{
*sz = 0;
StrCatBuff(sz, SZ_MB_SERVICE, cchMax);
UpdateData( TRUE );
// the private string data on the item
PTCHAR pch = (PTCHAR)SendMessage( m_ccombo_server, CB_GETITEMDATA, m_int_server, 0 );
// do something if it fails
if ( !pch || (pch == (PTCHAR)CB_ERR) )
return;
// the virtual server is indicated by the current selection in the
// server combo box. We get its index and retrieve the path from the
// private data attached to the item in the list
StrCat(sz, pch);
}
//--------------------------------------------------------------------
void CShellExt::ResetListContent()
{
PTCHAR psz;
// first, get the number of strings
DWORD nNumStrings = (DWORD)SendMessage( m_ccombo_server, CB_GETCOUNT, 0, 0 );
if ( nNumStrings == CB_ERR ) return;
// delete all the hidden server path strings
for ( DWORD i = 0; i < nNumStrings; i++ )
{
// get the string pointer
psz = (PTCHAR)SendMessage( m_ccombo_server, CB_GETITEMDATA, i, 0 );
// if it is there, delete it
if (psz != NULL)
LocalFree(psz);
}
// wipe out any items currently in the box before re-adding
SendMessage( m_ccombo_server, CB_RESETCONTENT, 0, 0 );
}
//--------------------------------------------------------------------
// initialize the combo box so the user can select which virtual server
// to administer from the shell extension.
void CShellExt::InitSeverInfo()
{
DWORD err;
CWrapMetaBase mb;
INT i;
if ( !mb.FInit(m_pMBCom) )
return;
TCHAR szKey[MAX_PATH];
TCHAR szDescription[MAX_PATH];
ZeroMemory( szKey, MAX_PATH );
ZeroMemory( szDescription, MAX_PATH );
// wipe out any items currently in the box before re-adding
ResetListContent();
// first open the metabase and get the server capabilities
if ( mb.Open(_T("/LM/W3SVC/")) )
{
DWORD dw;
// test if there is a 10 connection limit and use
// that flag as a test for IIS vs. PWS
if ( mb.GetDword( _T("Info"), MD_SERVER_CAPABILITIES, IIS_MD_UT_SERVER, &dw ) )
m_fIsPWS = (dw & IIS_CAP1_10_CONNECTION_LIMIT) != 0;
#ifdef DEBUG_ALWAYS_IIS
m_fIsPWS = FALSE;
#endif
// now enumerate the children to build the drop down list. Since there could
// be gaps in the list 1,2,4,5,6,8 etc (some may have been deleted) we need
// to keep an additional list of path names that correspond to the positions
// in the combo box. The list of names is stored in m_rgbszServerPaths
TCHAR szServer[MAX_PATH];
DWORD index = 0;
while (mb.EnumObjects( _T(""), szServer, MAX_PATH, index))
{
// before we can add this key we need to inspect its keytype to
// make sure that it is a virtual server
// get the type
BOOL f = mb.GetString( szServer, MD_KEY_TYPE, IIS_MD_UT_SERVER,
szDescription, MAX_PATH, 0 );
// check the type
if ( !f || (StrCmp(szDescription, SZ_SERVER_KEYTYPE) != 0) )
{
// increment to the next key
index++;
continue;
}
// now get the description of the virtual server
f = mb.GetString( szServer, MD_SERVER_COMMENT, IIS_MD_UT_SERVER,
szDescription, MAX_PATH, 0 );
// if the description isn't there, load the default description
if ( !f )
{
LoadString(g_hmodThisDll, IDS_DEFAULT_SERVER_DESCRIPTION, szDescription, MAX_PATH);
StrCatBuff(szDescription, szServer, MAX_PATH);
}
// add the description to the combo box
i = (INT)SendMessage( m_ccombo_server, CB_ADDSTRING, 0, (LPARAM)szDescription );
// hide the server path as private data
LRESULT err = SendMessage( m_ccombo_server, CB_SETITEMDATA, i, (LPARAM)StrDup(szServer));
// increment to the next key
index++;
}
// close the metabase
mb.Close();
// default to selecting the first item in the combo box
SendMessage( m_ccombo_server, CB_SETCURSEL, 0, 0 );
}
else
{
err = GetLastError();
}
// show the correct icon
if ( m_fIsPWS )
ShowWindow( m_icon_iis, SW_HIDE );
else
ShowWindow( m_icon_pws, SW_HIDE );
// if it is pws, then hide the server drop-down
if ( m_fIsPWS )
{
ShowWindow( m_static_share_on_title, SW_HIDE );
ShowWindow( m_ccombo_server, SW_HIDE );
}
}
//--------------------------------------------------------------------
// initialize the page's data - read in any existing info from the metabase
// - or determine that it is not in the metabase
void CShellExt::Init()
{
// attempt to set up the sink
m_fInitializedSink = InitializeSink();
// prepare to set up the data
UpdateData( TRUE );
// initialize the server information and combo box
InitSeverInfo();
// fill in the list of aliases
BuildAliasList();
// set the data into place
UpdateData( FALSE );
// update the state of the server
UpdateState();
EnableItems();
}
//--------------------------------------------------------------------
// update the state of the server
void CShellExt::UpdateState()
{
BOOL fUpdate = FALSE;
CWrapMetaBase mb;
TCHAR sz[MAX_PATH];
TCHAR szVirtServer[MAX_PATH];
TCHAR szStatus[MAX_PATH];
m_state = MD_SERVER_STATE_STOPPED;
// first things first. get the state of the server
// init the mb object. If it fails then the server app is probably not running
if ( mb.FInit(m_pMBCom) )
{
GetVirtServerString( szVirtServer, MAX_PATH );
if ( mb.Open(szVirtServer) )
{
if ( !mb.GetDword( _T(""), MD_SERVER_STATE, IIS_MD_UT_SERVER, &m_state ) )
{
DWORD err = GetLastError( );
if ( err == RPC_E_SERVERCALL_RETRYLATER )
{
// try again later....
mb.Close();
PostMessage( m_hwnd, WM_UPDATE_SERVER_STATE, 0, 0 );
return;
}
}
// close the metabase object
mb.Close();
}
}
// show the appropriate items
switch( m_state )
{
case MD_SERVER_STATE_STARTING:
if ( m_fIsPWS )
LoadString( g_hmodThisDll, IDS_STATUS_STARTING, szStatus, MAX_PATH );
else
LoadString( g_hmodThisDll, IDS_STATUS_IIS_STARTING, szStatus, MAX_PATH );
break;
case MD_SERVER_STATE_STARTED:
if ( m_fIsPWS )
LoadString( g_hmodThisDll, IDS_STATUS_STARTED, szStatus, MAX_PATH );
else
LoadString( g_hmodThisDll, IDS_STATUS_IIS_STARTED, szStatus, MAX_PATH );
break;
case MD_SERVER_STATE_STOPPED:
case MD_SERVER_STATE_STOPPING:
if ( m_fIsPWS )
LoadString( g_hmodThisDll, IDS_STATUS_STOPPED, szStatus, MAX_PATH );
else
LoadString( g_hmodThisDll, IDS_STATUS_IIS_STOPPED, szStatus, MAX_PATH );
break;
case MD_SERVER_STATE_PAUSED:
if ( m_fIsPWS )
LoadString( g_hmodThisDll, IDS_STATUS_PAUSED, szStatus, MAX_PATH );
else
LoadString( g_hmodThisDll, IDS_STATUS_IIS_PAUSED, szStatus, MAX_PATH );
break;
};
// set the string into the dialog
SetWindowText( m_static_status, szStatus );
}
//--------------------------------------------------------------------
// enable items as appropriate
void CShellExt::EnableItems()
{
UpdateData( TRUE );
// if the virtual server is not running, disable most of the items
if ( m_state != MD_SERVER_STATE_STARTED )
{
EnableWindow( m_cbtn_share, FALSE );
EnableWindow( m_cbtn_not, FALSE );
EnableWindow( m_cstatic_alias_title, FALSE );
EnableWindow( m_cbtn_add, FALSE );
EnableWindow( m_cbtn_remove, FALSE );
EnableWindow( m_cbtn_edit, FALSE );
EnableWindow( m_clist_list, FALSE );
}
else
{
EnableWindow( m_cbtn_share, TRUE );
EnableWindow( m_cbtn_not, TRUE );
EnableWindow( m_ccombo_server, TRUE );
EnableWindow( m_static_share_on_title, TRUE );
EnableWindow( m_clist_list, TRUE);
EnableWindow( m_cbtn_add, FALSE);
EnableWindow( m_cbtn_remove, FALSE);
EnableWindow( m_cbtn_edit, FALSE);
m_int_share = 0;
// the virtual server is running. Do the normal thing.
// first, check the overall count of the items in the list
if ( ListBox_GetCount(m_clist_list) > 0 )
{
m_int_share = 1;
// there is stuff in the list - sharing is on
EnableWindow( m_cstatic_alias_title, TRUE );
EnableWindow( m_cbtn_add, TRUE );
// we shouldn't enable Remove for the root directory
TCHAR buffer[MAX_PATH];
int idx = ListBox_GetCurSel(m_clist_list);
if (idx != LB_ERR)
{
EnableWindow( m_cbtn_edit, TRUE );
ListBox_GetText(m_clist_list, idx, buffer);
if (StrCmp(_T("/"), buffer) != 0)
EnableWindow(m_cbtn_remove, TRUE );
}
}
}
UpdateData( FALSE );
}
//------------------------------------------------------------------
BOOL CShellExt::InitializeSink()
{
IConnectionPointContainer * pConnPointContainer = NULL;
HRESULT hRes;
BOOL fSinkConnected = FALSE;
// m_pMBCom is defined in webshrpg.h
IUnknown * pmb = (IUnknown*)m_pMBCom;
m_pEventSink = new CImpIMSAdminBaseSink();
if ( !m_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,
&m_pConnPoint);
if (SUCCEEDED(hRes))
{
hRes = m_pConnPoint->Advise( (IUnknown *)m_pEventSink,
&m_dwSinkCookie);
if (SUCCEEDED(hRes))
{
fSinkConnected = TRUE;
}
}
if ( pConnPointContainer )
{
pConnPointContainer->Release();
pConnPointContainer = NULL;
}
}
if ( !fSinkConnected )
{
delete m_pEventSink;
m_pEventSink = NULL;
}
else
{
// we are connected. Tell it where to send the udpates
m_pEventSink->SetPage( this );
}
return fSinkConnected;
}
//------------------------------------------------------------------
void CShellExt::TerminateSink()
{
if (m_dwSinkCookie)
{
m_pConnPoint->Unadvise( m_dwSinkCookie );
}
if (m_pEventSink)
{
delete m_pEventSink;
m_pEventSink = NULL;
}
}
//------------------------------------------------------------------------
// recursively add all the items to the tree
void CShellExt::RecurseAddVDItems(CWrapMetaBase * pmb, LPCTSTR szMB)
{
DWORD index = 0;
BOOL fAddAlias;
TCHAR sz[MAX_PATH];
TCHAR szMBPath[MAX_PATH];
// now we need to see if this is already points to us
fAddAlias = FALSE;
if ( pmb->GetString(szMB, MD_VR_PATH, IIS_MD_UT_FILE, sz, MAX_PATH, 0) )
{
// do the comparison - without regard to case
if (StrCmpI(m_szPropSheetFileUserClickedOn, sz) == 0)
{
ListBox_AddString(m_clist_list, *szMB == 0 ? _T("/") : (LPTSTR)szMB);
}
}
// enumerate the sub-directories of the open directory and add them
// to the tree. Recurse each to add its children as well
// enumerate the directories, adding each to the list
while (pmb->EnumObjects(szMB, sz, MAX_PATH, index))
{
// build the display name for this item
StrCpy(szMBPath, szMB);
PathAppend(szMBPath, sz);
// recurse the item
RecurseAddVDItems(pmb, szMBPath);
// advance the index
index++;
}
}
//--------------------------------------------------------------------
// rebuild all the alias items in the list
// NOTE: The only way (for now) to edit the Home directory is in the pws application
void CShellExt::BuildAliasList()
{
DWORD err;
TCHAR szRoot[200];
// create the metabase wrapper
CWrapMetaBase mb;
if ( !mb.FInit(m_pMBCom) )
return;
// go for the root directory first
GetRootString(szRoot, 100);
if ( mb.Open(szRoot) )
{
// do the recursive adding thing
RecurseAddVDItems( &mb, _T("") );
// close the metabase object
mb.Close();
}
else
err = GetLastError();
}
//--------------------------------------------------------------------
void CShellExt::OnRemove()
{
int nItem;
CWrapMetaBase mb;
TCHAR szItem[MAX_PATH];
TCHAR szWAMPath[MAX_PATH];
ZeroMemory( szItem, MAX_PATH );
ZeroMemory( szWAMPath, MAX_PATH );
// get the root string once
TCHAR szRoot[200];
GetRootString( szRoot, 100 );
// get the string of the selected item
nItem = ListBox_GetCurSel(m_clist_list);
ListBox_GetText(m_clist_list, nItem, szItem);
// create the metabase wrapper
if ( !mb.FInit(m_pMBCom) )
return;
// munge the name into the confirm string - reuse the existing wampath string
LoadString( g_hmodThisDll, IDS_CONFIRM_REMOVE, szWAMPath, MAX_PATH );
TCHAR szCaption[80];
LoadString(g_hmodThisDll, IDS_PAGE_TITLE, szCaption, 80);
MyFormatString1( szWAMPath, MAX_PATH, szItem );
// ask the user if the really want to do this
if ( MessageBox( m_hwnd, szWAMPath, szCaption, MB_YESNO ) == IDYES )
{
// the WAM stuff can take some time, so put up the wait cursor
SetCursor( LoadCursor(NULL, IDC_WAIT) );
// remove the WAM application first
StrCpy( szWAMPath, szRoot );
StrCat( szWAMPath, szItem );
MakeWAMApplication( szWAMPath, FALSE );
// open the metabase at the root
if ( mb.Open(szRoot, METADATA_PERMISSION_WRITE) )
{
// remove the item from the metabase
mb.DeleteObject( szItem );
// close the metabase object
mb.Close();
}
// remove the item from the tree
PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
SetCursor( LoadCursor(NULL, IDC_ARROW) );
}
}
//--------------------------------------------------------------------
void CShellExt::OnRdoNot()
{
DWORD nItems;
CWrapMetaBase mb;
TCHAR szItem[MAX_PATH];
TCHAR szWAMPath[MAX_PATH];
ZeroMemory( szItem, WIDE_MAX_PATH );
ZeroMemory( szWAMPath, WIDE_MAX_PATH );
// if there already are no aliases - don't bother
nItems = ListBox_GetCount(m_clist_list);
if ( nItems <= 0 )
return;
// create the metabase wrapper
if ( !mb.FInit(m_pMBCom) )
return;
TCHAR szCaption[80];
LoadString(g_hmodThisDll, IDS_PAGE_TITLE, szCaption, 80);
// reuse the szWAMPath
LoadString( g_hmodThisDll, IDS_CONFIRM_SHARENOT, szWAMPath, MAX_PATH );
// make sure the user wants to do this
if ( MessageBox( m_hwnd, szWAMPath, szCaption, MB_YESNO ) == IDYES )
{
// the WAM stuff can take some time, so put up the wait cursor
SetCursor( LoadCursor(NULL, IDC_WAIT) );
// open the metabase at the root
TCHAR szRoot[200];
GetRootString(szRoot, 100);
if ( mb.Open(szRoot, METADATA_PERMISSION_WRITE) )
{
// loop through the list, deleting each item
for ( DWORD iItem = 0; iItem < nItems; iItem++ )
{
// get the relative path
ListBox_GetText(m_clist_list, iItem, szItem);
// remove the WAM application first
StrCpy( szWAMPath, szRoot );
StrCat( szWAMPath, szItem );
MakeWAMApplication( szWAMPath, FALSE );
// blast it out of existence
mb.DeleteObject( szItem );
}
// close the metabase
mb.Close();
}
// update the display
PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
SetCursor( LoadCursor(NULL, IDC_ARROW) );
}
else
EnableItems();
}
//--------------------------------------------------------------------
void CShellExt::OnAdd()
{
CEditDirectory dlgEdit(m_hwnd);
CWrapMetaBase mb;
DWORD i;
PTCHAR psz, psz2 = NULL;
TCHAR szRoot[MAX_PATH];
TCHAR szFolder[MAX_PATH];
TCHAR szTestName[MAX_PATH];
ZeroMemory(szRoot, MAX_PATH);
ZeroMemory(szFolder, MAX_PATH);
ZeroMemory(szTestName, MAX_PATH);
// get the root string once
GetRootString(dlgEdit.m_szRoot, MAX_PATH);
// get ready //m_sz_alias
dlgEdit.m_fNewItem = TRUE;
dlgEdit.m_pMBCom = m_pMBCom;
StrCpy(dlgEdit.m_sz_path, m_szPropSheetFileUserClickedOn);
// the initial name for the new alias should be the name of the directory itself.
// if there already is a virtual directory with that name, then we append a 2 to
// it. if that exists, increment until we get a valid name.
// find the part after the last '\\' character in the path
psz = PathFindFileName(m_szPropSheetFileUserClickedOn);
// put the short file name into place temporarily
StrCpy(szFolder, psz);
PathMakePretty(szFolder);
// prepare the metabase - as that is where we have to check to see if it is there
// create the metabase wrapper
if ( !mb.FInit(m_pMBCom) )
return;
// prep the test name
StrCpy(dlgEdit.m_sz_alias, szFolder);
wsprintf(szTestName, _T("%s/%s"), dlgEdit.m_szRoot, dlgEdit.m_sz_alias);
// increment the name of the directory until it is valid
i = 1;
while ( mb.Open(szTestName) )
{
// close it right away
mb.Close();
// increment the counter
i++;
// prep the test name
wsprintf(dlgEdit.m_sz_alias, _T("%s%d"), szFolder, i);
wsprintf(szTestName, _T("%s/%s"), dlgEdit.m_szRoot, dlgEdit.m_sz_alias);
}
// record the pointer to alias dlg in case a shutdown event happens
m_pEditAliasDlg = &dlgEdit;
// run it - the dialog handles writing to the metabase
if ( dlgEdit.DoModal() == IDOK )
PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
m_pEditAliasDlg = NULL;
SetCursor( LoadCursor(NULL, IDC_ARROW) );
}
//--------------------------------------------------------------------
void CShellExt::OnEdit()
{
CEditDirectory dlg( m_hwnd );
TCHAR szItem[MAX_PATH];
ZeroMemory( szItem, MAX_PATH );
int nItem;
// get the string of the selected item
nItem = ListBox_GetCurSel(m_clist_list);
ListBox_GetText(m_clist_list, nItem, szItem);
// get ready
dlg.m_pMBCom = m_pMBCom;
StrCpy( dlg.m_sz_alias, szItem );
StrCpy( dlg.m_sz_path, m_szPropSheetFileUserClickedOn );
GetRootString( dlg.m_szRoot, 100 );
// record the pointer to alias dlg in case a shutdown event happens
m_pEditAliasDlg = &dlg;
// run it - the dialog handles writing to the metabase
if ( dlg.DoModal() == IDOK )
PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
m_pEditAliasDlg = NULL;
}
//--------------------------------------------------------------------
// to share an item - all we really have to do is add an alias
void CShellExt::OnRdoShare()
{
if ( ListBox_GetCount(m_clist_list) <= 0 )
OnAdd();
EnableItems();
}
//--------------------------------------------------------------------
// the selection in the server combo box has just changed. This means
// we need to rebuild the alias lsit based on this new server
void CShellExt::OnSelchangeComboServer()
{
PostMessage( m_hwnd, WM_UPDATE_SERVER_STATE, 0, 0 );
PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
}
//------------------------------------------------------------------------
void CShellExt::SinkNotify(
/* [in] */ DWORD dwMDNumElements,
/* [size_is][in] */ MD_CHANGE_OBJECT __RPC_FAR pcoChangeList[ ])
{
BOOL fPostedState = FALSE;
// if a key has been deleted, make sure it wasn't our virtual server
if ( pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_DELETE_OBJECT )
{
PostMessage( m_hwnd, WM_INSPECT_SERVER_LIST, 0, 0 );
}
// do the appropriate action based on the type of change
if ( (pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_DELETE_OBJECT) ||
(pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_ADD_OBJECT) ||
(pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_RENAME_OBJECT) )
{
PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
}
else if ( pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_SET_DATA )
{
for ( DWORD iElement = 0; iElement < dwMDNumElements; iElement++ )
{
// each change has a list of IDs...
for ( DWORD iID = 0; iID < pcoChangeList[iElement].dwMDNumDataIDs; iID++ )
{
// look for the ids that we are interested in
switch( pcoChangeList[iElement].pdwMDDataIDs[iID] )
{
case MD_SERVER_STATE:
if ( !fPostedState )
PostMessage( m_hwnd, WM_UPDATE_SERVER_STATE, 0, 0 );
fPostedState = TRUE;
break;
default:
// do nothing
break;
};
}
}
}
}
//--------------------------------------------------------------------
// only arrives if shutdown notify has happened
void CShellExt::OnTimer( UINT nIDEvent )
{
CheckIfServerIsRunningAgain();
}
//--------------------------------------------------------------------
// This routine is called called when we process the shutdown notify
// windows message that we posted to our queue when we got the shutdown
// notification event from the metabase. We cant just do this when we
// get the shutdown notify because that could leave the metabse in
// a funky state, and that would be bad.
void CShellExt::EnterShutdownMode()
{
TCHAR szStatus[400];
// if the edit alias dialog is open, start by closing it
if ( m_pEditAliasDlg )
{
m_pEditAliasDlg->EndDialog(IDCANCEL);
m_pEditAliasDlg = NULL;
}
// shutdown the sink attached to the document
TerminateSink();
m_fInitializedSink = FALSE;
// close the link to the metabase - it is going away after all
FCloseMetabase();
// record that we are in shutdown mode
m_fShutdownMode = TRUE;
// start up the timer mechanism
SetTimer( m_hwnd, PWS_TIMER_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
// empty all the items in the list
EmptyList();
// set the current status string
if ( m_fIsPWS )
LoadString( g_hmodThisDll, IDS_STATUS_SHUTDOWN, szStatus, 200 );
else
LoadString( g_hmodThisDll, IDS_STATUS_IIS_SHUTDOWN, szStatus, 200 );
// disable everything
EnableWindow( m_cbtn_share, FALSE );
EnableWindow( m_cbtn_not, FALSE );
EnableWindow( m_cstatic_alias_title, FALSE );
EnableWindow( m_cbtn_add, FALSE );
EnableWindow( m_cbtn_remove, FALSE );
EnableWindow( m_cbtn_edit, FALSE );
EnableWindow( m_clist_list, FALSE );
EnableWindow( m_static_share_on_title, FALSE );
EnableWindow( m_ccombo_server, 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 CShellExt::CheckIfServerIsRunningAgain()
{
// see if the server is running. If it is, show the icon and stop the timer.
if ( FIsW3Running() )
{
// if we can't use the metabase, there is no point in this
if ( !FInitMetabase() )
return;
// attempt to set up the sink
m_fInitializedSink = InitializeSink();
// clear the shutdown mode flag
m_fShutdownMode = FALSE;
// stop the timer mechanism
KillTimer( m_hwnd, PWS_TIMER_CHECKFORSERVERRESTART );
// enable any items that need it
EnableWindow( m_cbtn_share, TRUE );
EnableWindow( m_cbtn_not, TRUE );
EnableWindow( m_static_share_on_title, TRUE );
EnableWindow( m_ccombo_server, TRUE );
// tell the main page to update itself
PostMessage( m_hwnd, WM_UPDATE_SERVER_STATE, 0, 0 );
PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
}
}
// 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 CShellExt::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;
}
//--------------------------------------------------------------------
void CShellExt::OnFinalRelease()
{
CleanUpConnections();
}
//--------------------------------------------------------------------
void CShellExt::CleanUpConnections()
{
// if we have the metabase, release it
if ( m_fInitializedSink )
{
TerminateSink();
m_fInitializedSink = FALSE;
}
if ( m_fInitialized )
{
FCloseMetabase();
m_fInitialized = FALSE;
}
}
//--------------------------------------------------------------------
BOOL CShellExt::FInitMetabase()
{
BOOL f = TRUE;
HRESULT hres;
if ( !m_pMBCom )
{
hres = CoInitialize(NULL);
if ( SUCCEEDED(hres) )
{
f = FInitMetabaseWrapperEx( NULL, &m_pMBCom );
}
}
return f;
}
//--------------------------------------------------------------------
BOOL CShellExt::FCloseMetabase()
{
BOOL f = TRUE;
if ( m_pMBCom )
{
f = FCloseMetabaseWrapperEx( &m_pMBCom );
m_pMBCom = NULL;
CoUninitialize();
}
return f;
}
//------------------------------------------------------------------------
// This routine takes a path to a virutal directory in the metabase and creates
// a WAM application there. Most of the code is actually obtaining and maintaining
// the interface to the WAM ole object
// szPath The path to the metabase
// fCreate True if creating an application, FALSE if deleting an existing app
BOOL MakeWAMApplication( IN LPCTSTR pszPath, IN BOOL fCreate )
{
IClassFactory* pcsfFactory = NULL;
IWamAdmin2* pWAM;
HRESULT hresError;
BOOL fAnswer = FALSE;
hresError = CoGetClassObject( CLSID_WamAdmin, CLSCTX_SERVER, NULL,
IID_IClassFactory, (void**) &pcsfFactory);
if (FAILED(hresError))
return FALSE;
// create the instance of the interface
hresError = pcsfFactory->CreateInstance(NULL, IID_IWamAdmin2, (void **)&pWAM);
if (FAILED(hresError))
return FALSE;
// release the factory
pcsfFactory->Release();
// calc the string length just once
DWORD szLen = _tcslen(pszPath);
// this part will be nicer after it is converted to unicode
WCHAR* pwch;
// allocate the name buffer
pwch = new WCHAR[szLen + 2];
if ( !pwch )
{
pWAM->Release();
return FALSE;
}
ZeroMemory( pwch, (szLen + 2)*sizeof(WCHAR) );
// unicodize the name into the buffer
if ( pwch )
{
#ifdef _UNICODE
//
// UNICODE conversion by RonaldM
//
// This is actually probably not needed.
//
lstrcpy(pwch, pszPath);
#else
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszPath, -1,
pwch, szLen );
#endif // _UNICODE
// create the in-proc application, if requested
if ( fCreate )
{
hresError = pWAM->AppCreate2( pwch, eAppRunOutProcInDefaultPool );
}
else
{
// delete the application. Because the whole virtual dir is going away,
// delete any applications lower down in the tree as well
hresError = pWAM->AppDelete( pwch, TRUE );
}
// check the error code
fAnswer = SUCCEEDED( hresError );
// clean up
delete pwch;
}
// release the logging ui
pWAM->Release();
// return the answer
return fAnswer;
}
//------------------------------------------------------------------------
BOOL MyFormatString1( IN LPTSTR pszSource, IN DWORD cchMax, LPTSTR pszReplace )
{
return FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszSource,
NULL,
NULL,
pszSource,
cchMax,
(va_list*)&pszReplace
) > 0;
}