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.

761 lines
23 KiB

  1. #define INITGUID
  2. #include <windows.h>
  3. #include <tchar.h>
  4. #include <shellapi.h>
  5. #include <ole2.h>
  6. #include <coguid.h>
  7. #include <iadmw.h>
  8. #include <iiscnfg.h>
  9. #include "pwstray.h"
  10. #include "resource.h"
  11. #include "sink.h"
  12. #include <pwsdata.hxx>
  13. #define MB_TIMEOUT 5000
  14. // not a string!
  15. #define DW_TRAY_ICON_ID 'PWSt'
  16. #define REGKEY_STP _T("SOFTWARE\\Microsoft\\INetStp")
  17. #define REGKEY_INSTALLKEY _T("InstallPath")
  18. //USE_MFC=1
  19. //========================================================= globals
  20. HINSTANCE g_hInstance = NULL;
  21. HWND g_hwnd = NULL;
  22. HMENU g_hMenuMain = NULL;
  23. UINT g_dwNewTaskbarMessage = 0;
  24. DWORD g_dwSinkCookie = 0;
  25. CImpIMSAdminBaseSink* g_pEventSink = NULL;
  26. IConnectionPoint* g_pConnPoint = NULL;
  27. IMSAdminBase* g_pMBCom = NULL;
  28. DWORD g_dwServerState = 0;
  29. //========================================================= forwards
  30. DWORD DWGetServerState();
  31. BOOL FUpdateTrayIcon( DWORD dwMessage );
  32. BOOL InitializeMetabase( OLECHAR* pocMachineName );
  33. void TerminateMetabase();
  34. BOOL InitializeSink();
  35. void TerminateSink();
  36. BOOL GetAdminPath( TCHAR* pch, WORD cch );
  37. BOOL SetServerState( DWORD dwControlCode );
  38. BOOL LaunchAdminUI();
  39. void RunContextMenu();
  40. BOOL FIsW3Running();
  41. void CheckIfServerIsRunningAgain();
  42. void CheckIfServerUpAndDied();
  43. // routine to see if w3svc is running
  44. //--------------------------------------------------------------------
  45. // the method we use to see if the service is running is different on
  46. // windows NT from win95
  47. BOOL FIsW3Running()
  48. {
  49. OSVERSIONINFO info_os;
  50. info_os.dwOSVersionInfoSize = sizeof(info_os);
  51. if ( !GetVersionEx( &info_os ) )
  52. return FALSE;
  53. // if the platform is NT, query the service control manager
  54. if ( info_os.dwPlatformId == VER_PLATFORM_WIN32_NT )
  55. {
  56. BOOL fRunning = FALSE;
  57. // open the service manager
  58. SC_HANDLE sch = OpenSCManager(NULL, NULL, GENERIC_READ );
  59. if ( sch == NULL ) return FALSE;
  60. // get the service
  61. SC_HANDLE schW3 = OpenService(sch, _T("W3SVC"), SERVICE_QUERY_STATUS );
  62. if ( sch == NULL )
  63. {
  64. CloseServiceHandle( sch );
  65. return FALSE;
  66. }
  67. // query the service status
  68. SERVICE_STATUS status;
  69. ZeroMemory( &status, sizeof(status) );
  70. if ( QueryServiceStatus(schW3, &status) )
  71. {
  72. fRunning = (status.dwCurrentState == SERVICE_RUNNING);
  73. }
  74. CloseServiceHandle( schW3 );
  75. CloseServiceHandle( sch );
  76. // return the answer
  77. return fRunning;
  78. }
  79. // if the platform is Windows95, see if the object exists
  80. if ( info_os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
  81. {
  82. HANDLE hEvent;
  83. BOOL fFound = FALSE;
  84. hEvent = CreateEvent(NULL, TRUE, FALSE, _T(PWS_SHUTDOWN_EVENT));
  85. if ( hEvent != NULL )
  86. {
  87. fFound = (GetLastError() == ERROR_ALREADY_EXISTS);
  88. CloseHandle(hEvent);
  89. }
  90. return(fFound);
  91. }
  92. return FALSE;
  93. }
  94. //---------------------------------------------------------------------------
  95. // This routine is called on a timer event. The timer events only come if we
  96. // have received a shutdown notify callback from the metabase. So the server
  97. // is down. We need to wait around until it comes back up, then show ourselves.
  98. void CheckIfServerIsRunningAgain()
  99. {
  100. // see if the server is running. If it is, show the icon and stop the timer.
  101. if ( FIsW3Running() && g_hwnd )
  102. {
  103. // if we can't use the metabase, there is no point in this
  104. if ( !g_pMBCom && !InitializeMetabase(NULL) )
  105. {
  106. return;
  107. }
  108. // if we can't use the sink, there is no point in this
  109. if ( !g_pEventSink && !InitializeSink() )
  110. {
  111. TerminateMetabase();
  112. return;
  113. }
  114. // stop the life timer mechanism
  115. KillTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART );
  116. // start the unexpected server death test timer
  117. SetTimer( g_hwnd, PWS_TRAY_CHECKTOSEEIFINETINFODIED, TIMER_SERVERDIED, NULL );
  118. // show the tray icon
  119. g_dwServerState = DWGetServerState();
  120. FUpdateTrayIcon( NIM_ADD );
  121. }
  122. }
  123. //---------------------------------------------------------------------------
  124. // This routine is called on a timer event. The timer events only come if we know
  125. // the server is running. To avoid wasting too many extra cycles it is called rather
  126. // infrequently. What we are doing here is attempting to see if the server died
  127. // without sending us proper notification. If it did, we should clean up the
  128. // icon and start waiting for it to come back.
  129. void CheckIfServerUpAndDied()
  130. {
  131. if ( !FIsW3Running() )
  132. {
  133. // hide the tray icon
  134. FUpdateTrayIcon( NIM_DELETE );
  135. // disconnect the sink mechanism
  136. TerminateSink();
  137. // disconnect from the metabase
  138. TerminateMetabase();
  139. // stop the death timer
  140. KillTimer( g_hwnd, PWS_TRAY_CHECKTOSEEIFINETINFODIED );
  141. // start the life timer
  142. SetTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
  143. }
  144. }
  145. //---------------------------------------------------------------------------
  146. BOOL FUpdateTrayIcon( DWORD dwMessage )
  147. {
  148. NOTIFYICONDATA dataIcon;
  149. // prepare the common parts of the icon data structure
  150. dataIcon.cbSize = sizeof( dataIcon );
  151. dataIcon.hWnd = g_hwnd;
  152. dataIcon.uID = DW_TRAY_ICON_ID;
  153. dataIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  154. dataIcon.uCallbackMessage = WM_PWS_TRAY_SHELL_NOTIFY;
  155. // prepare the state-dependant icon handle
  156. switch( g_dwServerState )
  157. {
  158. case MD_SERVER_STATE_PAUSED:
  159. case MD_SERVER_STATE_PAUSING:
  160. dataIcon.hIcon = LoadIcon( g_hInstance, MAKEINTRESOURCE(IDI_PAUSED) );
  161. break;
  162. case MD_SERVER_STATE_STARTED:
  163. case MD_SERVER_STATE_STARTING:
  164. dataIcon.hIcon = LoadIcon( g_hInstance, MAKEINTRESOURCE(IDI_RUNNING) );
  165. break;
  166. case MD_SERVER_STATE_STOPPED:
  167. case MD_SERVER_STATE_STOPPING:
  168. dataIcon.hIcon = LoadIcon( g_hInstance, MAKEINTRESOURCE(IDI_STOPPED) );
  169. break;
  170. };
  171. // prepare the state-dependant tip strings
  172. switch( g_dwServerState )
  173. {
  174. case MD_SERVER_STATE_PAUSED:
  175. LoadString( g_hInstance, IDS_PAUSED, dataIcon.szTip, 63 );
  176. break;
  177. case MD_SERVER_STATE_PAUSING:
  178. LoadString( g_hInstance, IDS_PAUSING, dataIcon.szTip, 63 );
  179. break;
  180. case MD_SERVER_STATE_STARTED:
  181. LoadString( g_hInstance, IDS_STARTED, dataIcon.szTip, 63 );
  182. break;
  183. case MD_SERVER_STATE_STARTING:
  184. LoadString( g_hInstance, IDS_STARTING, dataIcon.szTip, 63 );
  185. break;
  186. case MD_SERVER_STATE_STOPPED:
  187. LoadString( g_hInstance, IDS_STOPPED, dataIcon.szTip, 63 );
  188. break;
  189. case MD_SERVER_STATE_STOPPING:
  190. LoadString( g_hInstance, IDS_STOPPING, dataIcon.szTip, 63 );
  191. break;
  192. };
  193. DWORD err = GetLastError();
  194. // make the shell call
  195. return Shell_NotifyIcon( dwMessage, &dataIcon );
  196. }
  197. //---------------------------------------------------------------------------
  198. DWORD DWGetServerState()
  199. {
  200. HRESULT hErr;
  201. METADATA_HANDLE hMeta;
  202. METADATA_RECORD mdRecord;
  203. DWORD state = 1000;
  204. DWORD dwRequiredLen;
  205. // open the w3svc key so we can get its state
  206. // since this is a pws thing, we only care about the first
  207. // server instance
  208. hErr = g_pMBCom->OpenKey(
  209. METADATA_MASTER_ROOT_HANDLE,
  210. L"/LM/W3SVC/1/",
  211. METADATA_PERMISSION_READ,
  212. MB_TIMEOUT,
  213. &hMeta);
  214. if ( FAILED(hErr) )
  215. return state;
  216. // prepare the metadata record
  217. mdRecord.dwMDIdentifier = MD_SERVER_STATE;
  218. mdRecord.dwMDAttributes = METADATA_INHERIT;
  219. mdRecord.dwMDUserType = IIS_MD_UT_SERVER;
  220. mdRecord.dwMDDataType = DWORD_METADATA;
  221. mdRecord.dwMDDataLen = sizeof(DWORD);
  222. mdRecord.pbMDData = (PBYTE)&state;
  223. // get the data
  224. hErr = g_pMBCom->GetData(
  225. hMeta,
  226. L"",
  227. &mdRecord,
  228. &dwRequiredLen );
  229. // close the key
  230. hErr = g_pMBCom->CloseKey( hMeta );
  231. // return the answer
  232. return state;
  233. }
  234. //---------------------------------------------------------------------------
  235. // deal with mouse messages that occur on the tray icon
  236. void On_WM_PWS_TRAY_SHELL_NOTIFY(UINT uID, UINT uMouseMsg)
  237. {
  238. if ( uID != DW_TRAY_ICON_ID )
  239. return;
  240. // act on the mouse message
  241. switch( uMouseMsg )
  242. {
  243. case WM_LBUTTONDBLCLK:
  244. LaunchAdminUI();
  245. break;
  246. case WM_RBUTTONDOWN:
  247. RunContextMenu();
  248. break;
  249. }
  250. }
  251. //---------------------------------------------------------------------------
  252. // the window proc callback procedure
  253. LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  254. {
  255. switch( message )
  256. {
  257. case WM_CREATE:
  258. // get the registered windows message signifying that there is a new
  259. // taskbar. When this message is triggered, we need to re-insert the icon
  260. // into the taskbar. This is usually done when the shell restarts.
  261. // see http://www.microsoft.com/msdn/sdk/inetsdk/help/itt/shell/taskbar.htm
  262. // also see the default case for processing of the message
  263. g_dwNewTaskbarMessage = RegisterWindowMessage(TEXT("TaskbarCreated"));
  264. break;
  265. case WM_PWS_TRAY_SHUTDOWN_NOTIFY:
  266. // hide the tray icon
  267. FUpdateTrayIcon( NIM_DELETE );
  268. // disconnect the sink mechanism
  269. TerminateSink();
  270. // disconnect from the metabase
  271. TerminateMetabase();
  272. // start the time mechanism
  273. SetTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
  274. break;
  275. case WM_TIMER:
  276. switch ( wParam )
  277. {
  278. case PWS_TRAY_CHECKFORSERVERRESTART:
  279. CheckIfServerIsRunningAgain();
  280. break;
  281. case PWS_TRAY_CHECKTOSEEIFINETINFODIED:
  282. CheckIfServerUpAndDied();
  283. break;
  284. };
  285. break;
  286. case WM_PWS_TRAY_SHELL_NOTIFY:
  287. On_WM_PWS_TRAY_SHELL_NOTIFY( (UINT)wParam, (UINT)lParam );
  288. break;
  289. case WM_PWS_TRAY_UPDATE_STATE:
  290. g_dwServerState = DWGetServerState();
  291. FUpdateTrayIcon( NIM_MODIFY );
  292. break;
  293. case WM_DESTROY:
  294. FUpdateTrayIcon( NIM_DELETE );
  295. PostQuitMessage(0);
  296. break;
  297. case WM_COMMAND:
  298. switch( LOWORD(wParam) )
  299. {
  300. case ID_START:
  301. SetServerState( MD_SERVER_COMMAND_START );
  302. break;
  303. case ID_STOP:
  304. SetServerState( MD_SERVER_COMMAND_STOP );
  305. break;
  306. case ID_PAUSE:
  307. SetServerState( MD_SERVER_COMMAND_PAUSE );
  308. break;
  309. case ID_CONTINUE:
  310. SetServerState( MD_SERVER_COMMAND_CONTINUE );
  311. break;
  312. case ID_PROPERTIES:
  313. LaunchAdminUI();
  314. break;
  315. };
  316. break;
  317. default:
  318. // cannot case directly on g_dwNewTaskbarMessage because it is not a constant
  319. if ( message == g_dwNewTaskbarMessage )
  320. {
  321. // Just go straight into waitin' for the server mode. If the server is
  322. // running it will catch the first time throught the timer. If it is not,
  323. // then we just sit around and wait for it
  324. // start the time mechanism
  325. SetTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
  326. }
  327. break;
  328. }
  329. return(DefWindowProc(hWnd, message, wParam, lParam ));
  330. }
  331. //---------------------------------------------------------------------------
  332. // main routine
  333. int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow )
  334. {
  335. WNDCLASS wndclass;
  336. MSG msg;
  337. // record the instance handle
  338. g_hInstance = hInstance;
  339. // do nothing if this app is already running
  340. if ( hPrevInstance )
  341. return 0;
  342. // one more test of previous instances
  343. if ( FindWindow(PWS_TRAY_WINDOW_CLASS,NULL) )
  344. return 0;
  345. // start ole
  346. if ( FAILED(CoInitialize( NULL )) )
  347. return 0;
  348. // get the menu handle
  349. g_hMenuMain = LoadMenu( g_hInstance, MAKEINTRESOURCE(IDR_POPUP) );
  350. // prepare and register the window class
  351. wndclass.style = 0;
  352. wndclass.lpfnWndProc = WndProc;
  353. wndclass.cbClsExtra = 0;
  354. wndclass.cbWndExtra = 0;
  355. wndclass.hInstance = hInstance;
  356. wndclass.hIcon = NULL;
  357. wndclass.hCursor = NULL;
  358. wndclass.hbrBackground = NULL;
  359. wndclass.lpszMenuName = NULL;
  360. wndclass.lpszClassName = PWS_TRAY_WINDOW_CLASS;
  361. RegisterClass( &wndclass );
  362. // create the window
  363. g_hwnd = CreateWindow(
  364. PWS_TRAY_WINDOW_CLASS, // pointer to registered class name
  365. _T(""), // pointer to window name
  366. 0, // window style
  367. 0, // horizontal position of window
  368. 0, // vertical position of window
  369. 0, // window width
  370. 0, // window height
  371. NULL, // handle to parent or owner window
  372. NULL, // handle to menu or child-window identifier
  373. hInstance, // handle to application instance
  374. NULL // pointer to window-creation data
  375. );
  376. // Just go straight into waitin' for the server mode. If the server is
  377. // running it will catch the first time throught the timer. If it is not,
  378. // then we just sit around and wait for it
  379. // start the time mechanism
  380. SetTimer( g_hwnd, PWS_TRAY_CHECKFORSERVERRESTART, TIMER_RESTART, NULL );
  381. // run the message loop
  382. while (GetMessage(&msg, NULL, 0, 0))
  383. {
  384. TranslateMessage(&msg);
  385. DispatchMessage( &msg);
  386. }
  387. // clean up the sink and the metabase
  388. DestroyMenu( g_hMenuMain );
  389. TerminateSink();
  390. TerminateMetabase();
  391. CoUninitialize();
  392. return((int)msg.wParam);
  393. }
  394. //------------------------------------------------------------------
  395. BOOL InitializeSink()
  396. {
  397. IConnectionPointContainer * pConnPointContainer = NULL;
  398. HRESULT hRes;
  399. BOOL fSinkConnected = FALSE;
  400. // g_pMBCom is defined in wrapmb
  401. IUnknown* pmb = (IUnknown*)g_pMBCom;
  402. g_pEventSink = new CImpIMSAdminBaseSink();
  403. if ( !g_pEventSink )
  404. {
  405. return FALSE;
  406. }
  407. //
  408. // First query the object for its Connection Point Container. This
  409. // essentially asks the object in the server if it is connectable.
  410. //
  411. hRes = pmb->QueryInterface( IID_IConnectionPointContainer,
  412. (PVOID *)&pConnPointContainer);
  413. if SUCCEEDED(hRes)
  414. {
  415. // Find the requested Connection Point. This AddRef's the
  416. // returned pointer.
  417. hRes = pConnPointContainer->FindConnectionPoint( IID_IMSAdminBaseSink,
  418. &g_pConnPoint);
  419. if (SUCCEEDED(hRes))
  420. {
  421. hRes = g_pConnPoint->Advise( (IUnknown *)g_pEventSink,
  422. &g_dwSinkCookie);
  423. if (SUCCEEDED(hRes))
  424. {
  425. fSinkConnected = TRUE;
  426. }
  427. }
  428. if ( pConnPointContainer )
  429. {
  430. pConnPointContainer->Release();
  431. pConnPointContainer = NULL;
  432. }
  433. }
  434. if ( !fSinkConnected )
  435. {
  436. delete g_pEventSink;
  437. g_pEventSink = NULL;
  438. }
  439. return fSinkConnected;
  440. }
  441. //------------------------------------------------------------------
  442. void TerminateSink()
  443. {
  444. HRESULT hRes;
  445. if ( g_dwSinkCookie && g_pConnPoint )
  446. hRes = g_pConnPoint->Unadvise( g_dwSinkCookie );
  447. }
  448. //------------------------------------------------------------------
  449. BOOL InitializeMetabase( OLECHAR* pocMachineName )
  450. {
  451. IClassFactory* pcsfFactory = NULL;
  452. COSERVERINFO csiMachineName;
  453. COSERVERINFO* pcsiParam = NULL;
  454. HRESULT hresError;
  455. //release previous interface if needed
  456. if( g_pMBCom != NULL )
  457. {
  458. g_pMBCom->Release();
  459. g_pMBCom = NULL;
  460. }
  461. //fill the structure for CoGetClassObject
  462. ZeroMemory( &csiMachineName, sizeof(csiMachineName) );
  463. // csiMachineName.pAuthInfo = NULL;
  464. // csiMachineName.dwFlags = 0;
  465. // csiMachineName.pServerInfoExt = NULL;
  466. csiMachineName.pwszName = pocMachineName;
  467. pcsiParam = &csiMachineName;
  468. hresError = CoGetClassObject(GETAdminBaseCLSID(TRUE), CLSCTX_SERVER, pcsiParam,
  469. IID_IClassFactory, (void**) &pcsfFactory);
  470. if (FAILED(hresError))
  471. return FALSE;
  472. // create the instance of the interface
  473. hresError = pcsfFactory->CreateInstance(NULL, IID_IMSAdminBase, (void **)&g_pMBCom);
  474. if (FAILED(hresError))
  475. {
  476. g_pMBCom = FALSE;
  477. return FALSE;
  478. }
  479. // release the factory
  480. pcsfFactory->Release();
  481. // success
  482. return TRUE;
  483. }
  484. //------------------------------------------------------------------
  485. void TerminateMetabase()
  486. {
  487. if ( g_pMBCom )
  488. {
  489. g_pMBCom->Release();
  490. g_pMBCom = NULL;
  491. }
  492. }
  493. //======================================== control actions
  494. //------------------------------------------------------------------------
  495. // get the inetinfo path
  496. BOOL LaunchAdminUI()
  497. {
  498. TCHAR chPath[MAX_PATH+1];
  499. // get the path to the admin UI
  500. if ( !GetAdminPath( chPath, MAX_PATH ) )
  501. {
  502. LoadString( g_hInstance, IDS_ADMINUI_ERR, chPath, MAX_PATH );
  503. MessageBox( g_hwnd, chPath, NULL, MB_OK|MB_ICONERROR );
  504. return FALSE;
  505. }
  506. // do it
  507. ShellExecute(
  508. NULL, // handle to parent window
  509. NULL, // pointer to string that specifies operation to perform
  510. chPath, // pointer to filename or folder name string
  511. NULL, // pointer to string that specifies executable-file parameters
  512. NULL, // pointer to string that specifies default directory
  513. SW_SHOW // whether file is shown when opened
  514. );
  515. return TRUE;
  516. }
  517. //------------------------------------------------------------------------
  518. // get the inetinfo path
  519. BOOL GetAdminPath( TCHAR* pch, WORD cch )
  520. {
  521. HKEY hKey;
  522. DWORD err, type;
  523. DWORD cbBuff = cch * sizeof(TCHAR);
  524. // get the server install path from the registry
  525. // open the registry key, if it exists
  526. err = RegOpenKeyEx(
  527. HKEY_LOCAL_MACHINE, // handle of open key
  528. REGKEY_STP, // address of name of subkey to open
  529. 0, // reserved
  530. KEY_READ, // security access mask
  531. &hKey // address of handle of open key
  532. );
  533. // if we did not open the key for any reason (say... it doesn't exist)
  534. // then leave right away
  535. if ( err != ERROR_SUCCESS )
  536. return FALSE;
  537. type = REG_SZ;
  538. err = RegQueryValueEx(
  539. hKey, // handle of key to query
  540. REGKEY_INSTALLKEY, // address of name of value to query
  541. NULL, // reserved
  542. &type, // address of buffer for value type
  543. (PUCHAR)pch, // address of data buffer
  544. &cbBuff // address of data buffer size
  545. );
  546. // close the key
  547. RegCloseKey( hKey );
  548. // if we did get the key for any reason (say... it doesn't exist)
  549. // then leave right away
  550. if ( err != ERROR_SUCCESS )
  551. return FALSE;
  552. // tack on the file name itself
  553. TCHAR chFile[64];
  554. if ( LoadString( g_hInstance, IDS_ADMIN_UI, chFile, 63 ) == 0 )
  555. return FALSE;
  556. _tcscat( pch, chFile );
  557. // success
  558. return TRUE;
  559. }
  560. //------------------------------------------------------------------------
  561. BOOL SetServerState( DWORD dwControlCode )
  562. {
  563. HRESULT hErr;
  564. METADATA_HANDLE hMeta;
  565. METADATA_RECORD mdRecord;
  566. // open the w3svc key so we can get its state
  567. // since this is a pws thing, we only care about the first
  568. // server instance
  569. hErr = g_pMBCom->OpenKey(
  570. METADATA_MASTER_ROOT_HANDLE,
  571. L"/LM/W3SVC/1/",
  572. METADATA_PERMISSION_WRITE,
  573. MB_TIMEOUT,
  574. &hMeta);
  575. if ( FAILED(hErr) )
  576. return FALSE;
  577. // prepare the metadata record
  578. mdRecord.dwMDIdentifier = MD_SERVER_COMMAND;
  579. mdRecord.dwMDAttributes = 0;
  580. mdRecord.dwMDUserType = IIS_MD_UT_SERVER;
  581. mdRecord.dwMDDataType = DWORD_METADATA;
  582. mdRecord.dwMDDataLen = sizeof(DWORD);
  583. mdRecord.pbMDData = (PBYTE)&dwControlCode;
  584. // get the data
  585. hErr = g_pMBCom->SetData(
  586. hMeta,
  587. L"",
  588. &mdRecord );
  589. // close the key
  590. hErr = g_pMBCom->CloseKey( hMeta );
  591. // return the answer
  592. return TRUE;
  593. }
  594. //---------------------------------------------------------------------------
  595. void RunContextMenu()
  596. {
  597. POINT pos;
  598. HMENU hMenuSub;
  599. RECT rect = {0,0,1,1};
  600. BOOL f;
  601. static BOOL fTracking = FALSE;
  602. if ( fTracking ) return;
  603. fTracking = TRUE;
  604. // where is the mouse? This tells us where to put the menu
  605. if ( !g_hMenuMain || !GetCursorPos(&pos) )
  606. return;
  607. // get the menu handle
  608. hMenuSub = GetSubMenu( g_hMenuMain, 0 );
  609. // easiest to start by disabling all the state based items
  610. f = EnableMenuItem( hMenuSub, ID_START, MF_BYCOMMAND|MF_GRAYED );
  611. f = EnableMenuItem( hMenuSub, ID_STOP, MF_BYCOMMAND|MF_GRAYED );
  612. f = EnableMenuItem( hMenuSub, ID_PAUSE, MF_BYCOMMAND|MF_GRAYED );
  613. f = EnableMenuItem( hMenuSub, ID_CONTINUE, MF_BYCOMMAND|MF_GRAYED );
  614. // prepare the state based menu items
  615. switch( g_dwServerState )
  616. {
  617. case MD_SERVER_STATE_PAUSED:
  618. case MD_SERVER_STATE_PAUSING:
  619. EnableMenuItem( hMenuSub, ID_STOP, MF_BYCOMMAND|MF_ENABLED );
  620. EnableMenuItem( hMenuSub, ID_CONTINUE, MF_BYCOMMAND|MF_ENABLED );
  621. break;
  622. case MD_SERVER_STATE_STARTED:
  623. case MD_SERVER_STATE_STARTING:
  624. EnableMenuItem( hMenuSub, ID_STOP, MF_BYCOMMAND|MF_ENABLED );
  625. EnableMenuItem( hMenuSub, ID_PAUSE, MF_BYCOMMAND|MF_ENABLED );
  626. break;
  627. case MD_SERVER_STATE_STOPPED:
  628. case MD_SERVER_STATE_STOPPING:
  629. EnableMenuItem( hMenuSub, ID_START, MF_BYCOMMAND|MF_ENABLED );
  630. break;
  631. };
  632. // this is necessary, because we need to get a lose focus message for the menu
  633. // to go down when the user click on some other process outside the up menu
  634. SetForegroundWindow(g_hwnd);
  635. // run the menu
  636. TrackPopupMenu(hMenuSub, TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x, pos.y, 0, g_hwnd, NULL);
  637. fTracking = FALSE;
  638. }