/** @file * * SVCMAIN - COM out-of-proc server main entry */ /* * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include #include "VBox/com/defs.h" #include "VBox/com/com.h" #include "VBox/com/VirtualBox.h" #include "VirtualBoxImpl.h" #include "Logging.h" #include "svchlp.h" #include #include #include #include #include #define _ATL_FREE_THREADED class CExeModule : public CComModule { public: LONG Unlock(); DWORD dwThreadID; HANDLE hEventShutdown; void MonitorShutdown(); bool StartMonitor(); bool bActivity; }; const DWORD dwTimeOut = 5000; /* time for EXE to be idle before shutting down */ const DWORD dwPause = 1000; /* time to wait for threads to finish up */ /* Passed to CreateThread to monitor the shutdown event */ static DWORD WINAPI MonitorProc(void* pv) { CExeModule* p = (CExeModule*)pv; p->MonitorShutdown(); return 0; } LONG CExeModule::Unlock() { LONG l = CComModule::Unlock(); if (l == 0) { bActivity = true; SetEvent(hEventShutdown); /* tell monitor that we transitioned to zero */ } return l; } /* Monitors the shutdown event */ void CExeModule::MonitorShutdown() { while (1) { WaitForSingleObject(hEventShutdown, INFINITE); DWORD dwWait=0; do { bActivity = false; dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut); } while (dwWait == WAIT_OBJECT_0); /* timed out */ if (!bActivity && m_nLockCnt == 0) /* if no activity let's really bail */ { #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED) CoSuspendClassObjects(); if (!bActivity && m_nLockCnt == 0) #endif break; } } CloseHandle(hEventShutdown); PostThreadMessage(dwThreadID, WM_QUIT, 0, 0); } bool CExeModule::StartMonitor() { hEventShutdown = CreateEvent(NULL, false, false, NULL); if (hEventShutdown == NULL) return false; DWORD dwThreadID; HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID); return (h != NULL); } CExeModule _Module; BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_VirtualBox, VirtualBox) END_OBJECT_MAP() LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2) { while (p1 != NULL && *p1 != NULL) { LPCTSTR p = p2; while (p != NULL && *p != NULL) { if (*p1 == *p) return CharNext(p1); p = CharNext(p); } p1 = CharNext(p1); } return NULL; } static int WordCmpI(LPCTSTR psz1, LPCTSTR psz2) throw() { TCHAR c1 = (TCHAR)CharUpper((LPTSTR)*psz1); TCHAR c2 = (TCHAR)CharUpper((LPTSTR)*psz2); while (c1 != NULL && c1 == c2 && c1 != ' ' && c1 != '\t') { psz1 = CharNext(psz1); psz2 = CharNext(psz2); c1 = (TCHAR)CharUpper((LPTSTR)*psz1); c2 = (TCHAR)CharUpper((LPTSTR)*psz2); } if ((c1 == NULL || c1 == ' ' || c1 == '\t') && (c2 == NULL || c2 == ' ' || c2 == '\t')) return 0; return (c1 < c2) ? -1 : 1; } ///////////////////////////////////////////////////////////////////////////// // extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/) { lpCmdLine = GetCommandLine(); /* this line necessary for _ATL_MIN_CRT */ /* Need to parse the command line before initializing the VBox runtime. */ TCHAR szTokens[] = _T("-/"); LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens); while (lpszToken != NULL) { if (WordCmpI(lpszToken, _T("Embedding")) == 0) { /* %HOMEDRIVE%%HOMEPATH% */ wchar_t wszHome[RTPATH_MAX]; DWORD cEnv = GetEnvironmentVariable(L"HOMEDRIVE", &wszHome[0], RTPATH_MAX); if (cEnv && cEnv < RTPATH_MAX) { DWORD cwc = cEnv; /* doesn't include NUL */ cEnv = GetEnvironmentVariable(L"HOMEPATH", &wszHome[cEnv], RTPATH_MAX - cwc); if (cEnv && cEnv < RTPATH_MAX - cwc) { /* If this fails there is nothing we can do. Ignore. */ SetCurrentDirectory(wszHome); } } } lpszToken = FindOneOf(lpszToken, szTokens); } /* * Initialize the VBox runtime without loading * the support driver. */ RTR3Init(); HRESULT hRes = com::Initialize(); _ASSERTE(SUCCEEDED(hRes)); _Module.Init(ObjectMap, hInstance, &LIBID_VirtualBox); _Module.dwThreadID = GetCurrentThreadId(); int nRet = 0; BOOL bRun = TRUE; lpszToken = FindOneOf(lpCmdLine, szTokens); while (lpszToken != NULL) { if (WordCmpI(lpszToken, _T("UnregServer")) == 0) { _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE); nRet = _Module.UnregisterServer(TRUE); bRun = FALSE; break; } else if (WordCmpI(lpszToken, _T("RegServer")) == 0) { _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE); nRet = _Module.RegisterServer(TRUE); bRun = FALSE; break; } else if (WordCmpI(lpszToken, _T("ReregServer")) == 0) { _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE); nRet = _Module.UnregisterServer(TRUE); _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE); nRet = _Module.RegisterServer(TRUE); bRun = FALSE; break; } else if ( (WordCmpI(lpszToken, _T("h")) == 0) || (WordCmpI(lpszToken, _T("?")) == 0)) { TCHAR txt[]= L"Options:\n\n" L"/RegServer:\tregister COM out-of-proc server\n" L"/UnregServer:\tunregister COM out-of-proc server\n" L"/ReregServer:\tunregister and register COM server\n" L"no options:\trun the server"; TCHAR title[]=_T("Usage"); nRet = -1; bRun = FALSE; MessageBox(NULL, txt, title, MB_OK); break; } else if (WordCmpI (lpszToken, _T("Helper")) == 0) { Log (("SVCMAIN: Processing Helper request (cmdline=\"%ls\")...\n", lpszToken + 6)); TCHAR szTokens[] = _T (" \t"); int vrc = VINF_SUCCESS; Utf8Str pipeName; lpszToken = FindOneOf (lpszToken, szTokens); if (lpszToken) { while (*lpszToken != NULL && (*lpszToken == ' ' || *lpszToken == '\t')) ++ lpszToken; if (*lpszToken != NULL) pipeName = Utf8Str(lpszToken); } if (pipeName.isEmpty()) vrc = VERR_INVALID_PARAMETER; if (RT_SUCCESS(vrc)) { /* do the helper job */ SVCHlpServer server; vrc = server.open(pipeName.c_str()); if (RT_SUCCESS(vrc)) vrc = server.run(); } if (RT_FAILURE(vrc)) { Utf8Str err = Utf8StrFmt ( "Failed to process Helper request (%Rrc).", vrc); Log (("SVCMAIN: %s\n", err.c_str())); } /* don't run the COM server */ bRun = FALSE; break; } lpszToken = FindOneOf(lpszToken, szTokens); } if (bRun) { _Module.StartMonitor(); #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED) hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED); _ASSERTE(SUCCEEDED(hRes)); hRes = CoResumeClassObjects(); #else hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE); #endif _ASSERTE(SUCCEEDED(hRes)); MSG msg; while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg); _Module.RevokeClassObjects(); Sleep(dwPause); //wait for any threads to finish } _Module.Term(); com::Shutdown(); Log(("SVCMAIN: Returning, COM server process ends.\n")); return nRet; }