// this is the internal content-specific stuff related to the // CShellExt object #include "priv.h" #include #include #include //#include #include #include #include #include #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; }