Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1320 lines
39 KiB

  1. // this is the internal content-specific stuff related to the
  2. // CShellExt object
  3. #include "priv.h"
  4. #include <stdio.h>
  5. #include <tchar.h>
  6. #include <iiscnfgp.h>
  7. //#include <inetinfo.h>
  8. #include <winsvc.h>
  9. #include <pwsdata.hxx>
  10. #include <iwamreg.h>
  11. #include <shlwapi.h>
  12. #include "wrapmb.h"
  13. #include "Sink.h"
  14. #include "eddir.h"
  15. #include "shellext.h"
  16. #include "wrapmb.h"
  17. extern HINSTANCE g_hmodThisDll; // Handle to this DLL itself.
  18. #define SZ_MB_SERVICE _T("/LM/W3SVC/")
  19. #define SZ_ROOT _T("/ROOT")
  20. #define SZ_SERVER_KEYTYPE _T("IIsWebServer")
  21. #define IIS_CAP1_10_CONNECTION_LIMIT 0x00000040
  22. BOOL MakeWAMApplication( IN LPCTSTR pszPath, IN BOOL fCreate );
  23. BOOL MyFormatString1( IN LPTSTR pszSource, IN DWORD cchMax, LPTSTR pszReplace );
  24. //--------------------------------------------------------------------
  25. // test if we have proper access to the metabase
  26. BOOL CShellExt::FIsAdmin()
  27. {
  28. BOOL fAnswer = FALSE;
  29. CWrapMetaBase mb;
  30. FInitMetabase();
  31. // first things first. get the state of the server
  32. // init the mb object. If it fails then the server app is probably not running
  33. if ( mb.FInit(m_pMBCom) )
  34. {
  35. BOOL fOpen = mb.Open(_T("/LM/W3SVC"), METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  36. if ( fOpen )
  37. {
  38. // Write some nonsense
  39. DWORD dwDummy = 0x1234;
  40. fAnswer = mb.SetDword( _T(""), MD_ISM_ACCESS_CHECK, IIS_MD_UT_FILE, dwDummy, 0 );
  41. // close the metabase object
  42. mb.Close();
  43. }
  44. }
  45. // Grrrrr!! Boyd, you should clean up after youself
  46. FCloseMetabase();
  47. // return the answer
  48. return fAnswer;
  49. }
  50. //---------------------------------------------------------------
  51. // return FALSE if we do NOT handle the message
  52. BOOL CShellExt::OnCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
  53. {
  54. switch (LOWORD(wParam))
  55. {
  56. case IDC_LIST:
  57. return OnListBoxNotify(hDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
  58. case IDC_ADD:
  59. OnAdd();
  60. return TRUE;
  61. case IDC_EDIT:
  62. OnEdit();
  63. return TRUE;
  64. case IDC_REMOVE:
  65. OnRemove();
  66. return TRUE;
  67. case IDC_RDO_NOT:
  68. OnRdoNot();
  69. break;
  70. case IDC_RDO_SHARE:
  71. OnRdoShare();
  72. break;
  73. case IDC_COMBO_SERVER:
  74. if ( HIWORD(wParam) == CBN_SELCHANGE )
  75. {
  76. OnSelchangeComboServer();
  77. }
  78. break;
  79. }
  80. // we did not handle it
  81. return FALSE;
  82. }
  83. //---------------------------------------------------------------
  84. // return FALSE if we do NOT handle the message
  85. BOOL CShellExt::OnListBoxNotify(HWND hDlg, int idCtrl, WORD code, HWND hwndControl)
  86. {
  87. switch (code)
  88. {
  89. case LBN_DBLCLK:
  90. {
  91. OnEdit();
  92. return TRUE;
  93. }
  94. case LBN_SELCHANGE:
  95. {
  96. EnableItems();
  97. return TRUE;
  98. }
  99. }
  100. return FALSE;
  101. }
  102. //---------------------------------------------------------------
  103. // return FALSE if we do NOT handle the message
  104. BOOL CShellExt::OnMessage(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  105. {
  106. BOOL fHandledMessage = FALSE;
  107. // the BIG dialog switch statement....
  108. switch( uMsg )
  109. {
  110. case WM_INITDIALOG:
  111. m_hwnd = hDlg;
  112. // init the controls
  113. if ( !InitControls() )
  114. return FALSE;
  115. // the big init
  116. if ( FInitMetabase() )
  117. {
  118. Init();
  119. m_fInitialized = TRUE;
  120. }
  121. else
  122. return FALSE;
  123. // return success
  124. fHandledMessage = TRUE;
  125. break;
  126. case WM_DESTROY:
  127. ResetListContent();
  128. break;
  129. case WM_COMMAND:
  130. fHandledMessage = OnCommand(hDlg, wParam, lParam);
  131. break;
  132. case WM_UPDATE_SERVER_STATE:
  133. UpdateState();
  134. EnableItems();
  135. return TRUE;
  136. case WM_UPDATE_ALIAS_LIST:
  137. EmptyList();
  138. BuildAliasList();
  139. EnableItems();
  140. return TRUE;
  141. case WM_SHUTDOWN_NOTIFY:
  142. EnterShutdownMode();
  143. return TRUE;
  144. case WM_INSPECT_SERVER_LIST:
  145. InspectServerList();
  146. return TRUE;
  147. case WM_TIMER:
  148. if ( wParam == PWS_TIMER_CHECKFORSERVERRESTART )
  149. {
  150. OnTimer( (UINT)wParam );
  151. fHandledMessage = TRUE;
  152. }
  153. break;
  154. };
  155. // return whether or not we handled the message
  156. return fHandledMessage;
  157. }
  158. //---------------------------------------------------------------
  159. // obtain all the control handles that we will need as the dialog goes along
  160. BOOL CShellExt::InitControls()
  161. {
  162. m_icon_pws = GetDlgItem( m_hwnd, IDC_STATIC_ICON_PWS );
  163. m_icon_iis = GetDlgItem( m_hwnd, IDC_STATIC_ICON_IIS );
  164. m_static_share_on_title = GetDlgItem( m_hwnd, IDC_STATIC_SHARE_ON );
  165. m_ccombo_server = GetDlgItem( m_hwnd, IDC_COMBO_SERVER );
  166. m_cbtn_share = GetDlgItem( m_hwnd, IDC_RDO_SHARE );
  167. m_cbtn_not = GetDlgItem( m_hwnd, IDC_RDO_NOT );
  168. m_cstatic_alias_title = GetDlgItem( m_hwnd, IDC_STATIC_ALIAS_TITLE );
  169. m_cbtn_add = GetDlgItem( m_hwnd, IDC_ADD );
  170. m_cbtn_remove = GetDlgItem( m_hwnd, IDC_REMOVE );
  171. m_cbtn_edit = GetDlgItem( m_hwnd, IDC_EDIT );
  172. m_clist_list = GetDlgItem( m_hwnd, IDC_LIST );
  173. m_static_status = GetDlgItem( m_hwnd, IDC_STATIC_STATUS );
  174. return TRUE;
  175. }
  176. //--------------------------------------------------------------------
  177. // remove all the alias items in the list
  178. void CShellExt::EmptyList()
  179. {
  180. ListBox_ResetContent( m_clist_list );
  181. }
  182. //---------------------------------------------------------------
  183. // CDialog simulation routines
  184. void CShellExt::UpdateData( BOOL fDialogToData )
  185. {
  186. // get the data
  187. if ( fDialogToData )
  188. {
  189. // set the data
  190. m_int_share = (SendMessage( m_cbtn_share, BM_GETCHECK, 0, 0 ) == BST_CHECKED);
  191. m_int_server = (int)SendMessage( m_ccombo_server, CB_GETCURSEL, 0, 0 );
  192. if ( m_int_server < 0 )
  193. m_int_server = 0;
  194. }
  195. else
  196. {
  197. // set the data
  198. SendMessage( m_ccombo_server, CB_SETCURSEL, m_int_server, 0 );
  199. if ( m_int_share )
  200. {
  201. SendMessage( m_cbtn_not, BM_SETCHECK, BST_UNCHECKED, 0 );
  202. SendMessage( m_cbtn_share, BM_SETCHECK, BST_CHECKED, 0 );
  203. }
  204. else
  205. {
  206. SendMessage( m_cbtn_share, BM_SETCHECK, BST_UNCHECKED, 0 );
  207. SendMessage( m_cbtn_not, BM_SETCHECK, BST_CHECKED, 0 );
  208. }
  209. }
  210. }
  211. //--------------------------------------------------------------------
  212. // This method gets called when an object in the metabase has been
  213. // deleted. The purpose is to see if the current virtual directory in
  214. // the metabase has been deleted or not. If it has been deleted, then
  215. // we go to the default sever. Or the first one. Or whatever is there.
  216. void CShellExt::InspectServerList()
  217. {
  218. BOOL fItsGone = FALSE;
  219. TCHAR szRoot[200];
  220. CWrapMetaBase mb;
  221. if ( !mb.FInit(m_pMBCom) )
  222. return;
  223. // Attempt to open the root. If that fails, its otta here
  224. GetRootString( szRoot, 100 );
  225. if (!mb.Open(szRoot))
  226. return;
  227. mb.Close();
  228. // it is gone. Default to the first one
  229. SendMessage( m_ccombo_server, CB_SETCURSEL, 0, 0 );
  230. }
  231. //------------------------------------------------------------------
  232. // This routine builds the correct metabase path up to /LM/W3SVC/*/ROOT
  233. // where the * is the current virtual server selected in the drop down.
  234. // There are two versions of this routine. One where the string is passed
  235. // in as a variable, and the other returns it
  236. void CShellExt::GetRootString( LPTSTR sz, DWORD cchMax )
  237. {
  238. // get the service part
  239. GetVirtServerString(sz, cchMax);
  240. // add on the ROOT part
  241. StrCatBuff(sz, SZ_ROOT, cchMax);
  242. }
  243. //------------------------------------------------------------------
  244. // This routine builds the correct metabase path up to /LM/W3SVC/*
  245. // where the * is the current virtual server selected in the drop down.
  246. // There are two versions of this routine. One where the string is passed
  247. // in as a variable, and the other returns it
  248. void CShellExt::GetVirtServerString(LPTSTR sz, DWORD cchMax)
  249. {
  250. *sz = 0;
  251. StrCatBuff(sz, SZ_MB_SERVICE, cchMax);
  252. UpdateData( TRUE );
  253. // the private string data on the item
  254. PTCHAR pch = (PTCHAR)SendMessage( m_ccombo_server, CB_GETITEMDATA, m_int_server, 0 );
  255. // do something if it fails
  256. if ( !pch || (pch == (PTCHAR)CB_ERR) )
  257. return;
  258. // the virtual server is indicated by the current selection in the
  259. // server combo box. We get its index and retrieve the path from the
  260. // private data attached to the item in the list
  261. StrCat(sz, pch);
  262. }
  263. //--------------------------------------------------------------------
  264. void CShellExt::ResetListContent()
  265. {
  266. PTCHAR psz;
  267. // first, get the number of strings
  268. DWORD nNumStrings = (DWORD)SendMessage( m_ccombo_server, CB_GETCOUNT, 0, 0 );
  269. if ( nNumStrings == CB_ERR ) return;
  270. // delete all the hidden server path strings
  271. for ( DWORD i = 0; i < nNumStrings; i++ )
  272. {
  273. // get the string pointer
  274. psz = (PTCHAR)SendMessage( m_ccombo_server, CB_GETITEMDATA, i, 0 );
  275. // if it is there, delete it
  276. if (psz != NULL)
  277. LocalFree(psz);
  278. }
  279. // wipe out any items currently in the box before re-adding
  280. SendMessage( m_ccombo_server, CB_RESETCONTENT, 0, 0 );
  281. }
  282. //--------------------------------------------------------------------
  283. // initialize the combo box so the user can select which virtual server
  284. // to administer from the shell extension.
  285. void CShellExt::InitSeverInfo()
  286. {
  287. DWORD err;
  288. CWrapMetaBase mb;
  289. INT i;
  290. if ( !mb.FInit(m_pMBCom) )
  291. return;
  292. TCHAR szKey[MAX_PATH];
  293. TCHAR szDescription[MAX_PATH];
  294. ZeroMemory( szKey, MAX_PATH );
  295. ZeroMemory( szDescription, MAX_PATH );
  296. // wipe out any items currently in the box before re-adding
  297. ResetListContent();
  298. // first open the metabase and get the server capabilities
  299. if ( mb.Open(_T("/LM/W3SVC/")) )
  300. {
  301. DWORD dw;
  302. // test if there is a 10 connection limit and use
  303. // that flag as a test for IIS vs. PWS
  304. if ( mb.GetDword( _T("Info"), MD_SERVER_CAPABILITIES, IIS_MD_UT_SERVER, &dw ) )
  305. m_fIsPWS = (dw & IIS_CAP1_10_CONNECTION_LIMIT) != 0;
  306. #ifdef DEBUG_ALWAYS_IIS
  307. m_fIsPWS = FALSE;
  308. #endif
  309. // now enumerate the children to build the drop down list. Since there could
  310. // be gaps in the list 1,2,4,5,6,8 etc (some may have been deleted) we need
  311. // to keep an additional list of path names that correspond to the positions
  312. // in the combo box. The list of names is stored in m_rgbszServerPaths
  313. TCHAR szServer[MAX_PATH];
  314. DWORD index = 0;
  315. while (mb.EnumObjects( _T(""), szServer, MAX_PATH, index))
  316. {
  317. // before we can add this key we need to inspect its keytype to
  318. // make sure that it is a virtual server
  319. // get the type
  320. BOOL f = mb.GetString( szServer, MD_KEY_TYPE, IIS_MD_UT_SERVER,
  321. szDescription, MAX_PATH, 0 );
  322. // check the type
  323. if ( !f || (StrCmp(szDescription, SZ_SERVER_KEYTYPE) != 0) )
  324. {
  325. // increment to the next key
  326. index++;
  327. continue;
  328. }
  329. // now get the description of the virtual server
  330. f = mb.GetString( szServer, MD_SERVER_COMMENT, IIS_MD_UT_SERVER,
  331. szDescription, MAX_PATH, 0 );
  332. // if the description isn't there, load the default description
  333. if ( !f )
  334. {
  335. LoadString(g_hmodThisDll, IDS_DEFAULT_SERVER_DESCRIPTION, szDescription, MAX_PATH);
  336. StrCatBuff(szDescription, szServer, MAX_PATH);
  337. }
  338. // add the description to the combo box
  339. i = (INT)SendMessage( m_ccombo_server, CB_ADDSTRING, 0, (LPARAM)szDescription );
  340. // hide the server path as private data
  341. LRESULT err = SendMessage( m_ccombo_server, CB_SETITEMDATA, i, (LPARAM)StrDup(szServer));
  342. // increment to the next key
  343. index++;
  344. }
  345. // close the metabase
  346. mb.Close();
  347. // default to selecting the first item in the combo box
  348. SendMessage( m_ccombo_server, CB_SETCURSEL, 0, 0 );
  349. }
  350. else
  351. {
  352. err = GetLastError();
  353. }
  354. // show the correct icon
  355. if ( m_fIsPWS )
  356. ShowWindow( m_icon_iis, SW_HIDE );
  357. else
  358. ShowWindow( m_icon_pws, SW_HIDE );
  359. // if it is pws, then hide the server drop-down
  360. if ( m_fIsPWS )
  361. {
  362. ShowWindow( m_static_share_on_title, SW_HIDE );
  363. ShowWindow( m_ccombo_server, SW_HIDE );
  364. }
  365. }
  366. //--------------------------------------------------------------------
  367. // initialize the page's data - read in any existing info from the metabase
  368. // - or determine that it is not in the metabase
  369. void CShellExt::Init()
  370. {
  371. // attempt to set up the sink
  372. m_fInitializedSink = InitializeSink();
  373. // prepare to set up the data
  374. UpdateData( TRUE );
  375. // initialize the server information and combo box
  376. InitSeverInfo();
  377. // fill in the list of aliases
  378. BuildAliasList();
  379. // set the data into place
  380. UpdateData( FALSE );
  381. // update the state of the server
  382. UpdateState();
  383. EnableItems();
  384. }
  385. //--------------------------------------------------------------------
  386. // update the state of the server
  387. void CShellExt::UpdateState()
  388. {
  389. BOOL fUpdate = FALSE;
  390. CWrapMetaBase mb;
  391. TCHAR sz[MAX_PATH];
  392. TCHAR szVirtServer[MAX_PATH];
  393. TCHAR szStatus[MAX_PATH];
  394. m_state = MD_SERVER_STATE_STOPPED;
  395. // first things first. get the state of the server
  396. // init the mb object. If it fails then the server app is probably not running
  397. if ( mb.FInit(m_pMBCom) )
  398. {
  399. GetVirtServerString( szVirtServer, MAX_PATH );
  400. if ( mb.Open(szVirtServer) )
  401. {
  402. if ( !mb.GetDword( _T(""), MD_SERVER_STATE, IIS_MD_UT_SERVER, &m_state ) )
  403. {
  404. DWORD err = GetLastError( );
  405. if ( err == RPC_E_SERVERCALL_RETRYLATER )
  406. {
  407. // try again later....
  408. mb.Close();
  409. PostMessage( m_hwnd, WM_UPDATE_SERVER_STATE, 0, 0 );
  410. return;
  411. }
  412. }
  413. // close the metabase object
  414. mb.Close();
  415. }
  416. }
  417. // show the appropriate items
  418. switch( m_state )
  419. {
  420. case MD_SERVER_STATE_STARTING:
  421. if ( m_fIsPWS )
  422. LoadString( g_hmodThisDll, IDS_STATUS_STARTING, szStatus, MAX_PATH );
  423. else
  424. LoadString( g_hmodThisDll, IDS_STATUS_IIS_STARTING, szStatus, MAX_PATH );
  425. break;
  426. case MD_SERVER_STATE_STARTED:
  427. if ( m_fIsPWS )
  428. LoadString( g_hmodThisDll, IDS_STATUS_STARTED, szStatus, MAX_PATH );
  429. else
  430. LoadString( g_hmodThisDll, IDS_STATUS_IIS_STARTED, szStatus, MAX_PATH );
  431. break;
  432. case MD_SERVER_STATE_STOPPED:
  433. case MD_SERVER_STATE_STOPPING:
  434. if ( m_fIsPWS )
  435. LoadString( g_hmodThisDll, IDS_STATUS_STOPPED, szStatus, MAX_PATH );
  436. else
  437. LoadString( g_hmodThisDll, IDS_STATUS_IIS_STOPPED, szStatus, MAX_PATH );
  438. break;
  439. case MD_SERVER_STATE_PAUSED:
  440. if ( m_fIsPWS )
  441. LoadString( g_hmodThisDll, IDS_STATUS_PAUSED, szStatus, MAX_PATH );
  442. else
  443. LoadString( g_hmodThisDll, IDS_STATUS_IIS_PAUSED, szStatus, MAX_PATH );
  444. break;
  445. };
  446. // set the string into the dialog
  447. SetWindowText( m_static_status, szStatus );
  448. }
  449. //--------------------------------------------------------------------
  450. // enable items as appropriate
  451. void CShellExt::EnableItems()
  452. {
  453. UpdateData( TRUE );
  454. // if the virtual server is not running, disable most of the items
  455. if ( m_state != MD_SERVER_STATE_STARTED )
  456. {
  457. EnableWindow( m_cbtn_share, FALSE );
  458. EnableWindow( m_cbtn_not, FALSE );
  459. EnableWindow( m_cstatic_alias_title, FALSE );
  460. EnableWindow( m_cbtn_add, FALSE );
  461. EnableWindow( m_cbtn_remove, FALSE );
  462. EnableWindow( m_cbtn_edit, FALSE );
  463. EnableWindow( m_clist_list, FALSE );
  464. }
  465. else
  466. {
  467. EnableWindow( m_cbtn_share, TRUE );
  468. EnableWindow( m_cbtn_not, TRUE );
  469. EnableWindow( m_ccombo_server, TRUE );
  470. EnableWindow( m_static_share_on_title, TRUE );
  471. EnableWindow( m_clist_list, TRUE);
  472. EnableWindow( m_cbtn_add, FALSE);
  473. EnableWindow( m_cbtn_remove, FALSE);
  474. EnableWindow( m_cbtn_edit, FALSE);
  475. m_int_share = 0;
  476. // the virtual server is running. Do the normal thing.
  477. // first, check the overall count of the items in the list
  478. if ( ListBox_GetCount(m_clist_list) > 0 )
  479. {
  480. m_int_share = 1;
  481. // there is stuff in the list - sharing is on
  482. EnableWindow( m_cstatic_alias_title, TRUE );
  483. EnableWindow( m_cbtn_add, TRUE );
  484. // we shouldn't enable Remove for the root directory
  485. TCHAR buffer[MAX_PATH];
  486. int idx = ListBox_GetCurSel(m_clist_list);
  487. if (idx != LB_ERR)
  488. {
  489. EnableWindow( m_cbtn_edit, TRUE );
  490. ListBox_GetText(m_clist_list, idx, buffer);
  491. if (StrCmp(_T("/"), buffer) != 0)
  492. EnableWindow(m_cbtn_remove, TRUE );
  493. }
  494. }
  495. }
  496. UpdateData( FALSE );
  497. }
  498. //------------------------------------------------------------------
  499. BOOL CShellExt::InitializeSink()
  500. {
  501. IConnectionPointContainer * pConnPointContainer = NULL;
  502. HRESULT hRes;
  503. BOOL fSinkConnected = FALSE;
  504. // m_pMBCom is defined in webshrpg.h
  505. IUnknown * pmb = (IUnknown*)m_pMBCom;
  506. m_pEventSink = new CImpIMSAdminBaseSink();
  507. if ( !m_pEventSink )
  508. {
  509. return FALSE;
  510. }
  511. //
  512. // First query the object for its Connection Point Container. This
  513. // essentially asks the object in the server if it is connectable.
  514. //
  515. hRes = pmb->QueryInterface( IID_IConnectionPointContainer,
  516. (PVOID *)&pConnPointContainer);
  517. if SUCCEEDED(hRes)
  518. {
  519. // Find the requested Connection Point. This AddRef's the
  520. // returned pointer.
  521. hRes = pConnPointContainer->FindConnectionPoint( IID_IMSAdminBaseSink,
  522. &m_pConnPoint);
  523. if (SUCCEEDED(hRes))
  524. {
  525. hRes = m_pConnPoint->Advise( (IUnknown *)m_pEventSink,
  526. &m_dwSinkCookie);
  527. if (SUCCEEDED(hRes))
  528. {
  529. fSinkConnected = TRUE;
  530. }
  531. }
  532. if ( pConnPointContainer )
  533. {
  534. pConnPointContainer->Release();
  535. pConnPointContainer = NULL;
  536. }
  537. }
  538. if ( !fSinkConnected )
  539. {
  540. delete m_pEventSink;
  541. m_pEventSink = NULL;
  542. }
  543. else
  544. {
  545. // we are connected. Tell it where to send the udpates
  546. m_pEventSink->SetPage( this );
  547. }
  548. return fSinkConnected;
  549. }
  550. //------------------------------------------------------------------
  551. void CShellExt::TerminateSink()
  552. {
  553. if (m_dwSinkCookie)
  554. {
  555. m_pConnPoint->Unadvise( m_dwSinkCookie );
  556. }
  557. if (m_pEventSink)
  558. {
  559. delete m_pEventSink;
  560. m_pEventSink = NULL;
  561. }
  562. }
  563. //------------------------------------------------------------------------
  564. // recursively add all the items to the tree
  565. void CShellExt::RecurseAddVDItems(CWrapMetaBase * pmb, LPCTSTR szMB)
  566. {
  567. DWORD index = 0;
  568. BOOL fAddAlias;
  569. TCHAR sz[MAX_PATH];
  570. TCHAR szMBPath[MAX_PATH];
  571. // now we need to see if this is already points to us
  572. fAddAlias = FALSE;
  573. if ( pmb->GetString(szMB, MD_VR_PATH, IIS_MD_UT_FILE, sz, MAX_PATH, 0) )
  574. {
  575. // do the comparison - without regard to case
  576. if (StrCmpI(m_szPropSheetFileUserClickedOn, sz) == 0)
  577. {
  578. ListBox_AddString(m_clist_list, *szMB == 0 ? _T("/") : (LPTSTR)szMB);
  579. }
  580. }
  581. // enumerate the sub-directories of the open directory and add them
  582. // to the tree. Recurse each to add its children as well
  583. // enumerate the directories, adding each to the list
  584. while (pmb->EnumObjects(szMB, sz, MAX_PATH, index))
  585. {
  586. // build the display name for this item
  587. StrCpy(szMBPath, szMB);
  588. PathAppend(szMBPath, sz);
  589. // recurse the item
  590. RecurseAddVDItems(pmb, szMBPath);
  591. // advance the index
  592. index++;
  593. }
  594. }
  595. //--------------------------------------------------------------------
  596. // rebuild all the alias items in the list
  597. // NOTE: The only way (for now) to edit the Home directory is in the pws application
  598. void CShellExt::BuildAliasList()
  599. {
  600. DWORD err;
  601. TCHAR szRoot[200];
  602. // create the metabase wrapper
  603. CWrapMetaBase mb;
  604. if ( !mb.FInit(m_pMBCom) )
  605. return;
  606. // go for the root directory first
  607. GetRootString(szRoot, 100);
  608. if ( mb.Open(szRoot) )
  609. {
  610. // do the recursive adding thing
  611. RecurseAddVDItems( &mb, _T("") );
  612. // close the metabase object
  613. mb.Close();
  614. }
  615. else
  616. err = GetLastError();
  617. }
  618. //--------------------------------------------------------------------
  619. void CShellExt::OnRemove()
  620. {
  621. int nItem;
  622. CWrapMetaBase mb;
  623. TCHAR szItem[MAX_PATH];
  624. TCHAR szWAMPath[MAX_PATH];
  625. ZeroMemory( szItem, MAX_PATH );
  626. ZeroMemory( szWAMPath, MAX_PATH );
  627. // get the root string once
  628. TCHAR szRoot[200];
  629. GetRootString( szRoot, 100 );
  630. // get the string of the selected item
  631. nItem = ListBox_GetCurSel(m_clist_list);
  632. ListBox_GetText(m_clist_list, nItem, szItem);
  633. // create the metabase wrapper
  634. if ( !mb.FInit(m_pMBCom) )
  635. return;
  636. // munge the name into the confirm string - reuse the existing wampath string
  637. LoadString( g_hmodThisDll, IDS_CONFIRM_REMOVE, szWAMPath, MAX_PATH );
  638. TCHAR szCaption[80];
  639. LoadString(g_hmodThisDll, IDS_PAGE_TITLE, szCaption, 80);
  640. MyFormatString1( szWAMPath, MAX_PATH, szItem );
  641. // ask the user if the really want to do this
  642. if ( MessageBox( m_hwnd, szWAMPath, szCaption, MB_YESNO ) == IDYES )
  643. {
  644. // the WAM stuff can take some time, so put up the wait cursor
  645. SetCursor( LoadCursor(NULL, IDC_WAIT) );
  646. // remove the WAM application first
  647. StrCpy( szWAMPath, szRoot );
  648. StrCat( szWAMPath, szItem );
  649. MakeWAMApplication( szWAMPath, FALSE );
  650. // open the metabase at the root
  651. if ( mb.Open(szRoot, METADATA_PERMISSION_WRITE) )
  652. {
  653. // remove the item from the metabase
  654. mb.DeleteObject( szItem );
  655. // close the metabase object
  656. mb.Close();
  657. }
  658. // remove the item from the tree
  659. PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
  660. SetCursor( LoadCursor(NULL, IDC_ARROW) );
  661. }
  662. }
  663. //--------------------------------------------------------------------
  664. void CShellExt::OnRdoNot()
  665. {
  666. DWORD nItems;
  667. CWrapMetaBase mb;
  668. TCHAR szItem[MAX_PATH];
  669. TCHAR szWAMPath[MAX_PATH];
  670. ZeroMemory( szItem, WIDE_MAX_PATH );
  671. ZeroMemory( szWAMPath, WIDE_MAX_PATH );
  672. // if there already are no aliases - don't bother
  673. nItems = ListBox_GetCount(m_clist_list);
  674. if ( nItems <= 0 )
  675. return;
  676. // create the metabase wrapper
  677. if ( !mb.FInit(m_pMBCom) )
  678. return;
  679. TCHAR szCaption[80];
  680. LoadString(g_hmodThisDll, IDS_PAGE_TITLE, szCaption, 80);
  681. // reuse the szWAMPath
  682. LoadString( g_hmodThisDll, IDS_CONFIRM_SHARENOT, szWAMPath, MAX_PATH );
  683. // make sure the user wants to do this
  684. if ( MessageBox( m_hwnd, szWAMPath, szCaption, MB_YESNO ) == IDYES )
  685. {
  686. // the WAM stuff can take some time, so put up the wait cursor
  687. SetCursor( LoadCursor(NULL, IDC_WAIT) );
  688. // open the metabase at the root
  689. TCHAR szRoot[200];
  690. GetRootString(szRoot, 100);
  691. if ( mb.Open(szRoot, METADATA_PERMISSION_WRITE) )
  692. {
  693. // loop through the list, deleting each item
  694. for ( DWORD iItem = 0; iItem < nItems; iItem++ )
  695. {
  696. // get the relative path
  697. ListBox_GetText(m_clist_list, iItem, szItem);
  698. // remove the WAM application first
  699. StrCpy( szWAMPath, szRoot );
  700. StrCat( szWAMPath, szItem );
  701. MakeWAMApplication( szWAMPath, FALSE );
  702. // blast it out of existence
  703. mb.DeleteObject( szItem );
  704. }
  705. // close the metabase
  706. mb.Close();
  707. }
  708. // update the display
  709. PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
  710. SetCursor( LoadCursor(NULL, IDC_ARROW) );
  711. }
  712. else
  713. EnableItems();
  714. }
  715. //--------------------------------------------------------------------
  716. void CShellExt::OnAdd()
  717. {
  718. CEditDirectory dlgEdit(m_hwnd);
  719. CWrapMetaBase mb;
  720. DWORD i;
  721. PTCHAR psz, psz2 = NULL;
  722. TCHAR szRoot[MAX_PATH];
  723. TCHAR szFolder[MAX_PATH];
  724. TCHAR szTestName[MAX_PATH];
  725. ZeroMemory(szRoot, MAX_PATH);
  726. ZeroMemory(szFolder, MAX_PATH);
  727. ZeroMemory(szTestName, MAX_PATH);
  728. // get the root string once
  729. GetRootString(dlgEdit.m_szRoot, MAX_PATH);
  730. // get ready //m_sz_alias
  731. dlgEdit.m_fNewItem = TRUE;
  732. dlgEdit.m_pMBCom = m_pMBCom;
  733. StrCpy(dlgEdit.m_sz_path, m_szPropSheetFileUserClickedOn);
  734. // the initial name for the new alias should be the name of the directory itself.
  735. // if there already is a virtual directory with that name, then we append a 2 to
  736. // it. if that exists, increment until we get a valid name.
  737. // find the part after the last '\\' character in the path
  738. psz = PathFindFileName(m_szPropSheetFileUserClickedOn);
  739. // put the short file name into place temporarily
  740. StrCpy(szFolder, psz);
  741. PathMakePretty(szFolder);
  742. // prepare the metabase - as that is where we have to check to see if it is there
  743. // create the metabase wrapper
  744. if ( !mb.FInit(m_pMBCom) )
  745. return;
  746. // prep the test name
  747. StrCpy(dlgEdit.m_sz_alias, szFolder);
  748. wsprintf(szTestName, _T("%s/%s"), dlgEdit.m_szRoot, dlgEdit.m_sz_alias);
  749. // increment the name of the directory until it is valid
  750. i = 1;
  751. while ( mb.Open(szTestName) )
  752. {
  753. // close it right away
  754. mb.Close();
  755. // increment the counter
  756. i++;
  757. // prep the test name
  758. wsprintf(dlgEdit.m_sz_alias, _T("%s%d"), szFolder, i);
  759. wsprintf(szTestName, _T("%s/%s"), dlgEdit.m_szRoot, dlgEdit.m_sz_alias);
  760. }
  761. // record the pointer to alias dlg in case a shutdown event happens
  762. m_pEditAliasDlg = &dlgEdit;
  763. // run it - the dialog handles writing to the metabase
  764. if ( dlgEdit.DoModal() == IDOK )
  765. PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
  766. m_pEditAliasDlg = NULL;
  767. SetCursor( LoadCursor(NULL, IDC_ARROW) );
  768. }
  769. //--------------------------------------------------------------------
  770. void CShellExt::OnEdit()
  771. {
  772. CEditDirectory dlg( m_hwnd );
  773. TCHAR szItem[MAX_PATH];
  774. ZeroMemory( szItem, MAX_PATH );
  775. int nItem;
  776. // get the string of the selected item
  777. nItem = ListBox_GetCurSel(m_clist_list);
  778. ListBox_GetText(m_clist_list, nItem, szItem);
  779. // get ready
  780. dlg.m_pMBCom = m_pMBCom;
  781. StrCpy( dlg.m_sz_alias, szItem );
  782. StrCpy( dlg.m_sz_path, m_szPropSheetFileUserClickedOn );
  783. GetRootString( dlg.m_szRoot, 100 );
  784. // record the pointer to alias dlg in case a shutdown event happens
  785. m_pEditAliasDlg = &dlg;
  786. // run it - the dialog handles writing to the metabase
  787. if ( dlg.DoModal() == IDOK )
  788. PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
  789. m_pEditAliasDlg = NULL;
  790. }
  791. //--------------------------------------------------------------------
  792. // to share an item - all we really have to do is add an alias
  793. void CShellExt::OnRdoShare()
  794. {
  795. if ( ListBox_GetCount(m_clist_list) <= 0 )
  796. OnAdd();
  797. EnableItems();
  798. }
  799. //--------------------------------------------------------------------
  800. // the selection in the server combo box has just changed. This means
  801. // we need to rebuild the alias lsit based on this new server
  802. void CShellExt::OnSelchangeComboServer()
  803. {
  804. PostMessage( m_hwnd, WM_UPDATE_SERVER_STATE, 0, 0 );
  805. PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
  806. }
  807. //------------------------------------------------------------------------
  808. void CShellExt::SinkNotify(
  809. /* [in] */ DWORD dwMDNumElements,
  810. /* [size_is][in] */ MD_CHANGE_OBJECT __RPC_FAR pcoChangeList[ ])
  811. {
  812. BOOL fPostedState = FALSE;
  813. // if a key has been deleted, make sure it wasn't our virtual server
  814. if ( pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_DELETE_OBJECT )
  815. {
  816. PostMessage( m_hwnd, WM_INSPECT_SERVER_LIST, 0, 0 );
  817. }
  818. // do the appropriate action based on the type of change
  819. if ( (pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_DELETE_OBJECT) ||
  820. (pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_ADD_OBJECT) ||
  821. (pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_RENAME_OBJECT) )
  822. {
  823. PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
  824. }
  825. else if ( pcoChangeList->dwMDChangeType & MD_CHANGE_TYPE_SET_DATA )
  826. {
  827. for ( DWORD iElement = 0; iElement < dwMDNumElements; iElement++ )
  828. {
  829. // each change has a list of IDs...
  830. for ( DWORD iID = 0; iID < pcoChangeList[iElement].dwMDNumDataIDs; iID++ )
  831. {
  832. // look for the ids that we are interested in
  833. switch( pcoChangeList[iElement].pdwMDDataIDs[iID] )
  834. {
  835. case MD_SERVER_STATE:
  836. if ( !fPostedState )
  837. PostMessage( m_hwnd, WM_UPDATE_SERVER_STATE, 0, 0 );
  838. fPostedState = TRUE;
  839. break;
  840. default:
  841. // do nothing
  842. break;
  843. };
  844. }
  845. }
  846. }
  847. }
  848. //--------------------------------------------------------------------
  849. // only arrives if shutdown notify has happened
  850. void CShellExt::OnTimer( UINT nIDEvent )
  851. {
  852. CheckIfServerIsRunningAgain();
  853. }
  854. //--------------------------------------------------------------------
  855. // This routine is called called when we process the shutdown notify
  856. // windows message that we posted to our queue when we got the shutdown
  857. // notification event from the metabase. We cant just do this when we
  858. // get the shutdown notify because that could leave the metabse in
  859. // a funky state, and that would be bad.
  860. void CShellExt::EnterShutdownMode()
  861. {
  862. TCHAR szStatus[400];
  863. // if the edit alias dialog is open, start by closing it
  864. if ( m_pEditAliasDlg )
  865. {
  866. m_pEditAliasDlg->EndDialog(IDCANCEL);
  867. m_pEditAliasDlg = NULL;
  868. }
  869. // shutdown the sink attached to the document
  870. TerminateSink();
  871. m_fInitializedSink = FALSE;
  872. // close the link to the metabase - it is going away after all
  873. FCloseMetabase();
  874. // record that we are in shutdown mode
  875. m_fShutdownMode = TRUE;
  876. // start up the timer mechanism
  877. SetTimer( m_hwnd, PWS_TIMER_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
  878. // empty all the items in the list
  879. EmptyList();
  880. // set the current status string
  881. if ( m_fIsPWS )
  882. LoadString( g_hmodThisDll, IDS_STATUS_SHUTDOWN, szStatus, 200 );
  883. else
  884. LoadString( g_hmodThisDll, IDS_STATUS_IIS_SHUTDOWN, szStatus, 200 );
  885. // disable everything
  886. EnableWindow( m_cbtn_share, FALSE );
  887. EnableWindow( m_cbtn_not, FALSE );
  888. EnableWindow( m_cstatic_alias_title, FALSE );
  889. EnableWindow( m_cbtn_add, FALSE );
  890. EnableWindow( m_cbtn_remove, FALSE );
  891. EnableWindow( m_cbtn_edit, FALSE );
  892. EnableWindow( m_clist_list, FALSE );
  893. EnableWindow( m_static_share_on_title, FALSE );
  894. EnableWindow( m_ccombo_server, FALSE );
  895. }
  896. //---------------------------------------------------------------------------
  897. // This routine is called on a timer event. The timer events only come if we
  898. // have received a shutdown notify callback from the metabase. So the server
  899. // is down. We need to wait around until it comes back up, then show ourselves.
  900. void CShellExt::CheckIfServerIsRunningAgain()
  901. {
  902. // see if the server is running. If it is, show the icon and stop the timer.
  903. if ( FIsW3Running() )
  904. {
  905. // if we can't use the metabase, there is no point in this
  906. if ( !FInitMetabase() )
  907. return;
  908. // attempt to set up the sink
  909. m_fInitializedSink = InitializeSink();
  910. // clear the shutdown mode flag
  911. m_fShutdownMode = FALSE;
  912. // stop the timer mechanism
  913. KillTimer( m_hwnd, PWS_TIMER_CHECKFORSERVERRESTART );
  914. // enable any items that need it
  915. EnableWindow( m_cbtn_share, TRUE );
  916. EnableWindow( m_cbtn_not, TRUE );
  917. EnableWindow( m_static_share_on_title, TRUE );
  918. EnableWindow( m_ccombo_server, TRUE );
  919. // tell the main page to update itself
  920. PostMessage( m_hwnd, WM_UPDATE_SERVER_STATE, 0, 0 );
  921. PostMessage( m_hwnd, WM_UPDATE_ALIAS_LIST, 0, 0 );
  922. }
  923. }
  924. // routine to see if w3svc is running
  925. //--------------------------------------------------------------------
  926. // the method we use to see if the service is running is different on
  927. // windows NT from win95
  928. BOOL CShellExt::FIsW3Running()
  929. {
  930. OSVERSIONINFO info_os;
  931. info_os.dwOSVersionInfoSize = sizeof(info_os);
  932. if ( !GetVersionEx( &info_os ) )
  933. return FALSE;
  934. // if the platform is NT, query the service control manager
  935. if ( info_os.dwPlatformId == VER_PLATFORM_WIN32_NT )
  936. {
  937. BOOL fRunning = FALSE;
  938. // open the service manager
  939. SC_HANDLE sch = OpenSCManager(NULL, NULL, GENERIC_READ );
  940. if ( sch == NULL ) return FALSE;
  941. // get the service
  942. SC_HANDLE schW3 = OpenService(sch, _T("W3SVC"), SERVICE_QUERY_STATUS );
  943. if ( sch == NULL )
  944. {
  945. CloseServiceHandle( sch );
  946. return FALSE;
  947. }
  948. // query the service status
  949. SERVICE_STATUS status;
  950. ZeroMemory( &status, sizeof(status) );
  951. if ( QueryServiceStatus(schW3, &status) )
  952. {
  953. fRunning = (status.dwCurrentState == SERVICE_RUNNING);
  954. }
  955. CloseServiceHandle( schW3 );
  956. CloseServiceHandle( sch );
  957. // return the answer
  958. return fRunning;
  959. }
  960. // if the platform is Windows95, see if the object exists
  961. if ( info_os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
  962. {
  963. HANDLE hEvent;
  964. BOOL fFound = FALSE;
  965. hEvent = CreateEvent(NULL, TRUE, FALSE, _T(PWS_SHUTDOWN_EVENT));
  966. if ( hEvent != NULL )
  967. {
  968. fFound = (GetLastError() == ERROR_ALREADY_EXISTS);
  969. CloseHandle(hEvent);
  970. }
  971. return(fFound);
  972. }
  973. return FALSE;
  974. }
  975. //--------------------------------------------------------------------
  976. void CShellExt::OnFinalRelease()
  977. {
  978. CleanUpConnections();
  979. }
  980. //--------------------------------------------------------------------
  981. void CShellExt::CleanUpConnections()
  982. {
  983. // if we have the metabase, release it
  984. if ( m_fInitializedSink )
  985. {
  986. TerminateSink();
  987. m_fInitializedSink = FALSE;
  988. }
  989. if ( m_fInitialized )
  990. {
  991. FCloseMetabase();
  992. m_fInitialized = FALSE;
  993. }
  994. }
  995. //--------------------------------------------------------------------
  996. BOOL CShellExt::FInitMetabase()
  997. {
  998. BOOL f = TRUE;
  999. HRESULT hres;
  1000. if ( !m_pMBCom )
  1001. {
  1002. hres = CoInitialize(NULL);
  1003. if ( SUCCEEDED(hres) )
  1004. {
  1005. f = FInitMetabaseWrapperEx( NULL, &m_pMBCom );
  1006. }
  1007. }
  1008. return f;
  1009. }
  1010. //--------------------------------------------------------------------
  1011. BOOL CShellExt::FCloseMetabase()
  1012. {
  1013. BOOL f = TRUE;
  1014. if ( m_pMBCom )
  1015. {
  1016. f = FCloseMetabaseWrapperEx( &m_pMBCom );
  1017. m_pMBCom = NULL;
  1018. CoUninitialize();
  1019. }
  1020. return f;
  1021. }
  1022. //------------------------------------------------------------------------
  1023. // This routine takes a path to a virutal directory in the metabase and creates
  1024. // a WAM application there. Most of the code is actually obtaining and maintaining
  1025. // the interface to the WAM ole object
  1026. // szPath The path to the metabase
  1027. // fCreate True if creating an application, FALSE if deleting an existing app
  1028. BOOL MakeWAMApplication( IN LPCTSTR pszPath, IN BOOL fCreate )
  1029. {
  1030. IClassFactory* pcsfFactory = NULL;
  1031. IWamAdmin2* pWAM;
  1032. HRESULT hresError;
  1033. BOOL fAnswer = FALSE;
  1034. hresError = CoGetClassObject( CLSID_WamAdmin, CLSCTX_SERVER, NULL,
  1035. IID_IClassFactory, (void**) &pcsfFactory);
  1036. if (FAILED(hresError))
  1037. return FALSE;
  1038. // create the instance of the interface
  1039. hresError = pcsfFactory->CreateInstance(NULL, IID_IWamAdmin2, (void **)&pWAM);
  1040. if (FAILED(hresError))
  1041. return FALSE;
  1042. // release the factory
  1043. pcsfFactory->Release();
  1044. // calc the string length just once
  1045. DWORD szLen = _tcslen(pszPath);
  1046. // this part will be nicer after it is converted to unicode
  1047. WCHAR* pwch;
  1048. // allocate the name buffer
  1049. pwch = new WCHAR[szLen + 2];
  1050. if ( !pwch )
  1051. {
  1052. pWAM->Release();
  1053. return FALSE;
  1054. }
  1055. ZeroMemory( pwch, (szLen + 2)*sizeof(WCHAR) );
  1056. // unicodize the name into the buffer
  1057. if ( pwch )
  1058. {
  1059. #ifdef _UNICODE
  1060. //
  1061. // UNICODE conversion by RonaldM
  1062. //
  1063. // This is actually probably not needed.
  1064. //
  1065. lstrcpy(pwch, pszPath);
  1066. #else
  1067. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszPath, -1,
  1068. pwch, szLen );
  1069. #endif // _UNICODE
  1070. // create the in-proc application, if requested
  1071. if ( fCreate )
  1072. {
  1073. hresError = pWAM->AppCreate2( pwch, eAppRunOutProcInDefaultPool );
  1074. }
  1075. else
  1076. {
  1077. // delete the application. Because the whole virtual dir is going away,
  1078. // delete any applications lower down in the tree as well
  1079. hresError = pWAM->AppDelete( pwch, TRUE );
  1080. }
  1081. // check the error code
  1082. fAnswer = SUCCEEDED( hresError );
  1083. // clean up
  1084. delete pwch;
  1085. }
  1086. // release the logging ui
  1087. pWAM->Release();
  1088. // return the answer
  1089. return fAnswer;
  1090. }
  1091. //------------------------------------------------------------------------
  1092. BOOL MyFormatString1( IN LPTSTR pszSource, IN DWORD cchMax, LPTSTR pszReplace )
  1093. {
  1094. return FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1095. pszSource,
  1096. NULL,
  1097. NULL,
  1098. pszSource,
  1099. cchMax,
  1100. (va_list*)&pszReplace
  1101. ) > 0;
  1102. }