VirtualBox

Ignore:
Timestamp:
Feb 27, 2018 5:48:13 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
121027
Message:

Main/VBoxSVC,VBoxSDS: fix for ​bugref:8161: added API client list interface to VBoxSDS, forcibly closes all VirtualBox clients process on Windows 7 at system shutdown. Added functionality to close VBoxSDS and VBoxSVC services automatically if the API client finished unexpectedly (crashed).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/win/svcmain.cpp

    r70030 r71139  
    2828#include "VBox/com/com.h"
    2929#include "VBox/com/VirtualBox.h"
     30#include "VBox/com/array.h"
    3031
    3132#include "VirtualBoxImpl.h"
     
    4445#include <iprt/asm.h>
    4546
     47#include <TlHelp32.h>
    4648
    4749/*********************************************************************************************************************************
     
    9496volatile uint32_t dwTimeOut = dwNormalTimeout; /* time for EXE to be idle before shutting down. Can be decreased at system shutdown phase. */
    9597
     98
     99BOOL CALLBACK CloseWindowProc(_In_ HWND   hWnd, _In_ LPARAM /* lParam */)
     100{
     101    _ASSERTE(hWnd);
     102    DWORD_PTR dwResult;
     103    // Close topmost windows in the thread
     104    LRESULT lResult = SendMessageTimeout(hWnd, WM_CLOSE, NULL, NULL,
     105        SMTO_ABORTIFHUNG | SMTO_BLOCK, 0, &dwResult);
     106    if (lResult != 0)
     107    {
     108        LogRel(("EnumThreadWndProc: Close message sent to window %x successfully \n", hWnd));
     109    }
     110    else
     111    {
     112        LogRel(("EnumThreadWndProc: Cannot send event to window %x. result: %d, last error: %x\n",
     113            hWnd, dwResult, GetLastError()));
     114    }
     115    return TRUE;
     116}
     117
     118void SendCloseToAllThreads(DWORD dwTargetPid)
     119{
     120    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
     121    if (hSnapshot == NULL)
     122    {
     123        LogRel(("SendCloseToAllThreads: cannot get threads snapshot. error: 0x%x \n",
     124            GetLastError()));
     125        return;
     126    }
     127
     128    THREADENTRY32 threadEntry;
     129    ZeroMemory(&threadEntry, sizeof(threadEntry));
     130    threadEntry.dwSize = sizeof(threadEntry);
     131
     132    if (Thread32First(hSnapshot, &threadEntry))
     133    {
     134        do
     135        {
     136            LogRel(("SendCloseToAllThreads: process: %d thread: %x \n",
     137                threadEntry.th32OwnerProcessID, threadEntry.th32ThreadID));
     138            if (threadEntry.th32OwnerProcessID == dwTargetPid)
     139            {
     140                BOOL bRes = EnumThreadWindows(threadEntry.th32ThreadID, CloseWindowProc, NULL);
     141                if (!bRes)
     142                {
     143                    LogRel(("SendCloseToAllThreads: EnumThreadWindows() failed to enumerate threads. error: %x \n",
     144                        GetLastError()));
     145                }
     146                else
     147                {
     148                    LogRel(("SendCloseToAllThreads: about to close window in thread %x of process d\n",
     149                        threadEntry.th32ThreadID, dwTargetPid));
     150                }
     151            }
     152        } while (Thread32Next(hSnapshot, &threadEntry));
     153    }
     154    CloseHandle(hSnapshot);
     155}
     156
     157static int CloseActiveClients()
     158{
     159    ComPtr<IVirtualBoxClientList> ptrClientList;
     160    /*
     161    * Connect to VBoxSDS.
     162    */
     163    // TODO: here we close all API client processes: our own and customers
     164    LogRelFunc(("Forcibly close API clients during system shutdown on Windows 7:\n"));
     165    HRESULT hrc = CoCreateInstance(CLSID_VirtualBoxClientList, NULL, CLSCTX_LOCAL_SERVER, IID_IVirtualBoxClientList,
     166        (void **)ptrClientList.asOutParam());
     167    if (SUCCEEDED(hrc))
     168    {
     169        com::SafeArray<LONG> aCllients;
     170        hrc = ptrClientList->get_Clients(aCllients.__asOutParam());
     171        RTCList<LONG> clientsList = aCllients.toList();
     172        LogRel(("==========Client list begin ========\n"));
     173        for (int i = 0; i < clientsList.size(); i++)
     174        {
     175            LogRel(("About to close client pid: %d\n", clientsList[i]));
     176            SendCloseToAllThreads(clientsList[i]);
     177        }
     178        LogRel(("==========Client list end ========\n"));
     179    }
     180    else
     181    {
     182        LogFunc(("Error to connect to VBoxSDS: hr=%Rhrf\n", hrc));
     183    }
     184    return 0;
     185}
     186
     187// These are copies of functions defined in VersionHelpers.h
     188bool IsWindowsVersionOrGreaterWrap(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
     189{
     190    OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0,{ 0 }, 0, 0 };
     191    DWORDLONG        const dwlConditionMask = VerSetConditionMask(
     192        VerSetConditionMask(
     193            VerSetConditionMask(
     194                0, VER_MAJORVERSION, VER_GREATER_EQUAL),
     195            VER_MINORVERSION, VER_GREATER_EQUAL),
     196        VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
     197
     198    osvi.dwMajorVersion = wMajorVersion;
     199    osvi.dwMinorVersion = wMinorVersion;
     200    osvi.wServicePackMajor = wServicePackMajor;
     201
     202    return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
     203}
     204
     205
     206#if !defined _WIN32_WINNT_WIN8
     207
     208#define _WIN32_WINNT_WIN8                   0x0602
     209
     210#endif  // #if !defined _WIN32_WINNT_WIN8
     211
     212bool IsWindows8OrGreaterWrap()
     213{
     214    return IsWindowsVersionOrGreaterWrap(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
     215}
    96216
    97217
     
    241361    HRESULT VirtualBoxClassFactory::i_registerWithSds(IUnknown **ppOtherVirtualBox);
    242362    void    VirtualBoxClassFactory::i_deregisterWithSds(void);
     363    void    VirtualBoxClassFactory::i_finishVBoxSvc();
    243364
    244365    friend VBoxSVCRegistration;
     
    311432            return m_pFactory->i_getVirtualBox(ppResult);
    312433        return E_FAIL;
     434    }
     435
     436    // IVBoxSVCRegistration: called from
     437    STDMETHOD(NotifyClientsFinished)()
     438    {
     439        LogRelFunc(("All clients gone - shutdown sequence initiated\n"));
     440
     441        m_pFactory->i_finishVBoxSvc();
     442
     443        // This is not enough to finish VBoxSvc such as reference to crashed client still is in action
     444        // So I forcebly shutdown VBoxSvc
     445        while (g_pModule->Unlock() > 0)
     446        {};
     447
     448        return S_OK;
    313449    }
    314450};
     
    354490            NOREF(hrc);
    355491        }
    356         m_ptrVirtualBoxSDS.setNull();
    357         g_fRegisteredWithVBoxSDS = false;
    358     }
    359     if (m_pVBoxSVC)
    360     {
    361         m_pVBoxSVC->m_pFactory = NULL;
    362         m_pVBoxSVC->Release();
    363         m_pVBoxSVC = NULL;
    364     }
     492    }
     493    i_finishVBoxSvc();
    365494}
    366495
     
    381510    Log(("VirtualBoxClassFactory::GetVirtualBox: E_FAIL\n"));
    382511    return E_FAIL;
     512}
     513
     514
     515void    VirtualBoxClassFactory::i_finishVBoxSvc()
     516{
     517    LogRelFunc(("Finish work of VBoxSVc and VBoxSDS\n"));
     518    if (m_ptrVirtualBoxSDS.isNotNull())
     519    {
     520        m_ptrVirtualBoxSDS.setNull();
     521        g_fRegisteredWithVBoxSDS = false;
     522    }
     523    if (m_pVBoxSVC)
     524    {
     525        m_pVBoxSVC->m_pFactory = NULL;
     526        m_pVBoxSVC->Release();
     527        m_pVBoxSVC = NULL;
     528    }
    383529}
    384530
     
    536682                    Log(("VBoxSVCWinMain: WM_QUERYENDSESSION: VBoxSvc has active connections. bActivity = %d. Loc count = %d\n",
    537683                         g_pModule->bActivity, g_pModule->GetLockCount()));
     684
     685                    // On Windows 7 our clients doesn't receive right sequence of Session End events
     686                    // So we send them all WM_QUIT to forcible close them.
     687                    // Windows 10 sends end session events correctly
     688                    // Note: the IsWindows8Point1() and IsWindows10OrGreater() doesnt work in
     689                    // application without manifest so I use old compatible functions for detection of Win 7
     690                    if(!IsWindows8OrGreaterWrap())
     691                        CloseActiveClients();
    538692                }
    539693                rc = !fActiveConnection;
     
    629783        }
    630784    }
     785}
     786
     787
     788int SetServiceEnvFlag()
     789{
     790    int rc = VINF_SUCCESS;
     791    if (!SetEnvironmentVariable(L"VBOX_SERVICE_PROCESS", L""))
     792    {
     793        rc = RTErrConvertFromWin32(GetLastError());
     794        LogRel(("Error: cannot set service environment flag:  %Rrs\n", rc));
     795    }
     796    return rc;
    631797}
    632798
     
    667833     */
    668834    RTR3InitExe(argc, &argv, 0);
     835
     836    SetServiceEnvFlag();
    669837
    670838    static const RTGETOPTDEF s_aOptions[] =
     
    8731041            if (RT_FAILURE(vrc))
    8741042            {
    875                 Log(("SVCMAIN: Failed to process Helper request (%Rrc).", vrc));
     1043                Log(("SVCMAIN: Failed to process Helper request (%Rrc).\n", vrc));
    8761044                nRet = 1;
    8771045            }
Note: See TracChangeset for help on using the changeset viewer.

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