VirtualBox

Changeset 89095 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
May 17, 2021 12:55:55 PM (4 years ago)
Author:
vboxsync
Message:

FE/VBoxHeadless: On Windows create a hidden window and monitor
WM_QUERYENDSESSION messages. Terminate the VBox event loop and power
down the VM when we've got it. bugref:8161.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp

    r89017 r89095  
    3737#include <iprt/initterm.h>
    3838#include <iprt/message.h>
     39#include <iprt/semaphore.h>
    3940#include <iprt/path.h>
    4041#include <iprt/stream.h>
     
    750751
    751752#endif /* RT_OS_DARWIN */
     753
     754
     755#ifdef RT_OS_WINDOWS
     756
     757#define MAIN_WND_CLASS L"VirtualBox Headless Interface"
     758
     759HINSTANCE g_hInstance = NULL;
     760HWND g_hWindow = NULL;
     761RTSEMEVENT g_hCanQuit;
     762
     763static DECLCALLBACK(int) windowsMessageMonitor(RTTHREAD ThreadSelf, void *pvUser);
     764static int createWindow();
     765static LRESULT CALLBACK WinMainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
     766static void destroyWindow();
     767
     768
     769static DECLCALLBACK(int)
     770windowsMessageMonitor(RTTHREAD ThreadSelf, void *pvUser)
     771{
     772    RT_NOREF(ThreadSelf, pvUser);
     773    int rc;
     774
     775    rc = createWindow();
     776    if (RT_FAILURE(rc))
     777        return rc;
     778
     779    RTSemEventCreate(&g_hCanQuit);
     780
     781    MSG msg;
     782    BOOL b;
     783    while ((b = ::GetMessage(&msg, 0, 0, 0)) > 0)
     784    {
     785        ::TranslateMessage(&msg);
     786        ::DispatchMessage(&msg);
     787    }
     788
     789    if (b < 0)
     790        LogRel(("VBoxHeadless: GetMessage failed\n"));
     791    LogRel(("VBoxHeadless: stopping windows message loop\n"));
     792
     793    destroyWindow();
     794    return VINF_SUCCESS;
     795}
     796
     797
     798static int
     799createWindow()
     800{
     801    /* program instance handle */
     802    g_hInstance = (HINSTANCE)::GetModuleHandle(NULL);
     803    if (g_hInstance == NULL)
     804    {
     805        LogRel(("VBoxHeadless: failed to obtain module handle\n"));
     806        return VERR_GENERAL_FAILURE;
     807    }
     808
     809    /* window class */
     810    WNDCLASS wc;
     811    RT_ZERO(wc);
     812
     813    wc.style = CS_NOCLOSE;
     814    wc.lpfnWndProc = WinMainWndProc;
     815    wc.hInstance = g_hInstance;
     816    wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
     817    wc.lpszClassName = MAIN_WND_CLASS;
     818
     819    ATOM atomWindowClass = ::RegisterClass(&wc);
     820    if (atomWindowClass == 0)
     821    {
     822        LogRel(("VBoxHeadless: failed to register window class\n"));
     823        return VERR_GENERAL_FAILURE;
     824    }
     825
     826    /* secret window, secret garden */
     827    g_hWindow = ::CreateWindowEx(0, MAIN_WND_CLASS, MAIN_WND_CLASS, 0,
     828                                 0, 0, 1, 1, NULL, NULL, g_hInstance, NULL);
     829    if (g_hWindow == NULL)
     830    {
     831        LogRel(("VBoxHeadless: failed to create window\n"));
     832        return VERR_GENERAL_FAILURE;
     833    }
     834
     835    return VINF_SUCCESS;
     836}
     837
     838
     839static void
     840destroyWindow()
     841{
     842    if (g_hWindow == NULL)
     843        return;
     844
     845    ::DestroyWindow(g_hWindow);
     846    g_hWindow = NULL;
     847
     848    if (g_hInstance == NULL)
     849        return;
     850
     851    ::UnregisterClass(MAIN_WND_CLASS, g_hInstance);
     852    g_hInstance = NULL;
     853}
     854
     855
     856static LRESULT CALLBACK
     857WinMainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     858{
     859    int rc;
     860
     861    LRESULT lResult = 0;
     862    switch (msg)
     863    {
     864        case WM_QUERYENDSESSION:
     865            if (lParam != 0)
     866                LogRel(("VBoxHeadless: WM_QUERYENDSESSION (0x%08lx)\n", (unsigned long)lParam));
     867            else
     868                LogRel(("VBoxHeadless: WM_QUERYENDSESSION\n"));
     869
     870            /* tell the user what we are doing */
     871            ::ShutdownBlockReasonCreate(hwnd, L"Waiting for VM to terminate");
     872
     873            /* tell the VM to save state/power off */
     874            g_fTerminateFE = true;
     875            gEventQ->interruptEventQueueProcessing();
     876
     877            /* do not block windows session termination */
     878            lResult = TRUE;
     879            break;
     880
     881        case WM_ENDSESSION:
     882            if (g_hCanQuit != NIL_RTSEMEVENT)
     883            {
     884                LogRel(("VBoxHeadless: WM_ENDSESSION: waiting for VM termination...\n"));
     885
     886                rc = RTSemEventWait(g_hCanQuit, RT_INDEFINITE_WAIT);
     887                if (RT_SUCCESS(rc))
     888                    LogRel(("VBoxHeadless: WM_ENDSESSION: done\n"));
     889                else
     890                    LogRel(("VBoxHeadless: WM_ENDSESSION: failed to wait for VM termination: %Rrc\n", rc));
     891            }
     892            else
     893            {
     894                LogRel(("VBoxHeadless: WM_ENDSESSION: cannot wait for VM termination\n"));
     895            }
     896            lResult = TRUE;
     897            break;
     898
     899        default:
     900            lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
     901            break;
     902    }
     903    return lResult;
     904}
     905#endif /* RT_OS_WINDOWS */
    752906
    753907
     
    10751229
    10761230    HRESULT rc;
     1231    int irc;
    10771232
    10781233    rc = com::Initialize();
     
    14191574#endif
    14201575
     1576#ifdef RT_OS_WINDOWS
     1577        /*
     1578         * Spawn windows message pump to monitor session events.
     1579         */
     1580        RTTHREAD hThrMsg;
     1581        irc = RTThreadCreate(&hThrMsg,
     1582                            windowsMessageMonitor, NULL,
     1583                            0, /* :cbStack */
     1584                            RTTHREADTYPE_MSG_PUMP, 0,
     1585                            "MSG");
     1586        if (RT_FAILURE(irc))    /* not fatal */
     1587            LogRel(("VBoxHeadless: failed to start windows message monitor: %Rrc\n", irc));
     1588#endif /* RT_OS_WINDOWS */
     1589
    14211590
    14221591        /*
     
    14261595        for (;;)
    14271596        {
    1428             int irc = gEventQ->processEventQueue(RT_INDEFINITE_WAIT);
     1597            irc = gEventQ->processEventQueue(RT_INDEFINITE_WAIT);
    14291598
    14301599            /*
     
    15671736    com::Shutdown();
    15681737
    1569     LogFlow(("VBoxHeadless FINISHED.\n"));
    1570 
     1738#ifdef RT_OS_WINDOWS
     1739    /* tell the session monitor it can ack WM_ENDSESSION */
     1740    if (g_hCanQuit != NIL_RTSEMEVENT)
     1741    {
     1742        RTSemEventSignal(g_hCanQuit);
     1743    }
     1744
     1745    /* tell the session monitor to quit */
     1746    if (g_hWindow != NULL)
     1747    {
     1748        ::PostMessage(g_hWindow, WM_QUIT, 0, 0);
     1749    }
     1750#endif
     1751
     1752    LogRel(("VBoxHeadless: exiting\n"));
    15711753    return FAILED(rc) ? 1 : 0;
    15721754}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette