VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/win/svcmain.cpp@ 69775

Last change on this file since 69775 was 69775, checked in by vboxsync, 7 years ago

VBoxSDS/Plan/B: More complete code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.1 KB
Line 
1/* $Id: svcmain.cpp 69775 2017-11-20 16:36:34Z vboxsync $ */
2/** @file
3 * SVCMAIN - COM out-of-proc server main entry
4 */
5
6/*
7 * Copyright (C) 2004-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <iprt/win/windows.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <tchar.h>
26
27#include "VBox/com/defs.h"
28#include "VBox/com/com.h"
29#include "VBox/com/VirtualBox.h"
30
31#include "VirtualBoxImpl.h"
32#include "Logging.h"
33
34#include "svchlp.h"
35
36#include <VBox/err.h>
37#include <iprt/buildconfig.h>
38#include <iprt/initterm.h>
39#include <iprt/string.h>
40#include <iprt/uni.h>
41#include <iprt/path.h>
42#include <iprt/getopt.h>
43#include <iprt/message.h>
44#include <iprt/asm.h>
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50#define MAIN_WND_CLASS L"VirtualBox Interface"
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56class CExeModule : public ATL::CComModule
57{
58public:
59 LONG Unlock();
60 DWORD dwThreadID;
61 HANDLE hEventShutdown;
62 void MonitorShutdown();
63 bool StartMonitor();
64 bool HasActiveConnection();
65 bool bActivity;
66 static bool isIdleLockCount(LONG cLocks);
67};
68
69
70/*********************************************************************************************************************************
71* Global Variables *
72*********************************************************************************************************************************/
73BEGIN_OBJECT_MAP(ObjectMap)
74 OBJECT_ENTRY(CLSID_VirtualBox, VirtualBox)
75END_OBJECT_MAP()
76
77CExeModule *g_pModule = NULL;
78HWND g_hMainWindow = NULL;
79HINSTANCE g_hInstance = NULL;
80#ifdef VBOX_WITH_SDS_PLAN_B
81/** This is set if we're connected to SDS and should discount a server lock
82 * that it is holding when deciding whether we're idle or not. */
83bool g_fRegisteredWithVBoxSDS = false;
84#endif
85
86/* Normal timeout usually used in Shutdown Monitor */
87const DWORD dwNormalTimeout = 5000;
88volatile uint32_t dwTimeOut = dwNormalTimeout; /* time for EXE to be idle before shutting down. Can be decreased at system shutdown phase. */
89
90
91
92/* Passed to CreateThread to monitor the shutdown event */
93static DWORD WINAPI MonitorProc(void* pv)
94{
95 CExeModule* p = (CExeModule*)pv;
96 p->MonitorShutdown();
97 return 0;
98}
99
100LONG CExeModule::Unlock()
101{
102 LONG cLocks = ATL::CComModule::Unlock();
103 if (isIdleLockCount(cLocks))
104 {
105 bActivity = true;
106 SetEvent(hEventShutdown); /* tell monitor that we transitioned to zero */
107 }
108 return cLocks;
109}
110
111bool CExeModule::HasActiveConnection()
112{
113 return bActivity || !isIdleLockCount(GetLockCount());
114}
115
116/**
117 * Checks if @a cLocks signifies an IDLE server lock load.
118 *
119 * This takes VBoxSDS into account (i.e. ignores it).
120 */
121/*static*/ bool CExeModule::isIdleLockCount(LONG cLocks)
122{
123#ifdef VBOX_WITH_SDS_PLAN_B
124 if (g_fRegisteredWithVBoxSDS)
125 return cLocks <= 1;
126#endif
127 return cLocks <= 0;
128}
129
130/* Monitors the shutdown event */
131void CExeModule::MonitorShutdown()
132{
133 while (1)
134 {
135 WaitForSingleObject(hEventShutdown, INFINITE);
136 DWORD dwWait;
137 do
138 {
139 bActivity = false;
140 dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
141 } while (dwWait == WAIT_OBJECT_0);
142 /* timed out */
143 if (!HasActiveConnection()) /* if no activity let's really bail */
144 {
145 /* Disable log rotation at this point, worst case a log file
146 * becomes slightly bigger than it should. Avoids quirks with
147 * log rotation: there might be another API service process
148 * running at this point which would rotate the logs concurrently,
149 * creating a mess. */
150 PRTLOGGER pReleaseLogger = RTLogRelGetDefaultInstance();
151 if (pReleaseLogger)
152 {
153 char szDest[1024];
154 int rc = RTLogGetDestinations(pReleaseLogger, szDest, sizeof(szDest));
155 if (RT_SUCCESS(rc))
156 {
157 rc = RTStrCat(szDest, sizeof(szDest), " nohistory");
158 if (RT_SUCCESS(rc))
159 {
160 rc = RTLogDestinations(pReleaseLogger, szDest);
161 AssertRC(rc);
162 }
163 }
164 }
165#if _WIN32_WINNT >= 0x0400
166 CoSuspendClassObjects();
167 if (!HasActiveConnection())
168#endif
169 break;
170 }
171 }
172 CloseHandle(hEventShutdown);
173 PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
174}
175
176bool CExeModule::StartMonitor()
177{
178 hEventShutdown = CreateEvent(NULL, false, false, NULL);
179 if (hEventShutdown == NULL)
180 return false;
181 DWORD dwThreadID;
182 HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);
183 return (h != NULL);
184}
185
186
187#ifdef VBOX_WITH_SDS_PLAN_B
188class VBoxSVCRegistration;
189
190/**
191 * Custom class factory for the VirtualBox singleton.
192 *
193 * The implementation of CreateInstance is found in win/svcmain.cpp.
194 */
195class VirtualBoxClassFactory : public ATL::CComClassFactory
196{
197private:
198 /** Tri state: 0=uninitialized or initializing; 1=success; -1=failure.
199 * This will be updated after both m_hrcCreate and m_pObj have been set. */
200 volatile int32_t m_iState;
201 /** The result of the instantiation attempt. */
202 HRESULT m_hrcCreate;
203 /** The IUnknown of the VirtualBox object/interface we're working with. */
204 IUnknown *m_pObj;
205 /** Pointer to the IVBoxSVCRegistration implementation that VBoxSDS works with. */
206 VBoxSVCRegistration *m_pVBoxSVC;
207 /** The VBoxSDS interface. */
208 ComPtr<IVirtualBoxSDS> m_ptrVirtualBoxSDS;
209
210public:
211 VirtualBoxClassFactory() : m_iState(0), m_hrcCreate(S_OK), m_pObj(NULL), m_pVBoxSVC(NULL)
212 { }
213
214 virtual ~VirtualBoxClassFactory()
215 {
216 if (m_pObj)
217 {
218 m_pObj->Release();
219 m_pObj = NULL;
220 }
221
222 /** @todo Need to check if this is okay wrt COM termination. */
223 i_deregisterWithSds();
224 }
225
226 // IClassFactory
227 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj);
228
229 /** Worker for VBoxSVCRegistration::getVirtualBox. */
230 HRESULT i_getVirtualBox(IUnknown **ppResult);
231
232private:
233 HRESULT VirtualBoxClassFactory::i_registerWithSds(IUnknown **ppOtherVirtualBox);
234 void VirtualBoxClassFactory::i_deregisterWithSds(void);
235
236 friend VBoxSVCRegistration;
237};
238
239
240/**
241 * The VBoxSVC class is handed to VBoxSDS so it can call us back and ask for the
242 * VirtualBox object when the next VBoxSVC for this user registers itself.
243 */
244class VBoxSVCRegistration : public IVBoxSVCRegistration
245{
246private:
247 /** Number of references. */
248 uint32_t volatile m_cRefs;
249
250public:
251 /** Pointer to the factory. */
252 VirtualBoxClassFactory *m_pFactory;
253
254public:
255 VBoxSVCRegistration(VirtualBoxClassFactory *pFactory)
256 : m_cRefs(1), m_pFactory(pFactory)
257 { }
258 virtual ~VBoxSVCRegistration()
259 {
260 if (m_pFactory)
261 {
262 if (m_pFactory->m_pVBoxSVC)
263 m_pFactory->m_pVBoxSVC = NULL;
264 m_pFactory = NULL;
265 }
266 }
267 RTMEMEF_NEW_AND_DELETE_OPERATORS();
268
269 // IUnknown
270 STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject)
271 {
272 if (riid == __uuidof(IUnknown))
273 *ppvObject = (void *)(IUnknown *)this;
274 else if (riid == __uuidof(IVBoxSVCRegistration))
275 *ppvObject = (void *)(IVBoxSVCRegistration *)this;
276 else
277 {
278 return E_NOINTERFACE;
279 }
280 AddRef();
281 return S_OK;
282
283 }
284
285 STDMETHOD_(ULONG,AddRef)(void)
286 {
287 uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
288 return cRefs;
289 }
290
291 STDMETHOD_(ULONG,Release)(void)
292 {
293 uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
294 if (cRefs == 0)
295 delete this;
296 return cRefs;
297 }
298
299 // IVBoxSVCRegistration
300 STDMETHOD(GetVirtualBox)(IUnknown **ppResult)
301 {
302 if (m_pFactory)
303 return m_pFactory->i_getVirtualBox(ppResult);
304 return E_FAIL;
305 }
306};
307
308
309HRESULT VirtualBoxClassFactory::i_registerWithSds(IUnknown **ppOtherVirtualBox)
310{
311 /*
312 * Connect to VBoxSDS.
313 */
314 HRESULT hrc = CoCreateInstance(CLSID_VirtualBoxSDS, NULL, CLSCTX_LOCAL_SERVER, IID_IVirtualBoxSDS,
315 (void **)m_ptrVirtualBoxSDS.asOutParam());
316 if (SUCCEEDED(hrc))
317 {
318 /*
319 * Create VBoxSVCRegistration object and hand that to VBoxSDS.
320 */
321 m_pVBoxSVC = new VBoxSVCRegistration(this);
322 hrc = m_ptrVirtualBoxSDS->RegisterVBoxSVC(m_pVBoxSVC, GetCurrentProcessId(), ppOtherVirtualBox);
323 if (SUCCEEDED(hrc))
324 {
325 g_fRegisteredWithVBoxSDS = true;
326 return hrc;
327 }
328 m_pVBoxSVC->Release();
329 }
330 m_ptrVirtualBoxSDS.setNull();
331 m_pVBoxSVC = NULL;
332 *ppOtherVirtualBox = NULL;
333 return hrc;
334}
335
336
337void VirtualBoxClassFactory::i_deregisterWithSds(void)
338{
339 Log(("VirtualBoxClassFactory::i_deregisterWithSds\n"));
340
341 if (m_ptrVirtualBoxSDS.isNotNull())
342 {
343 if (m_pVBoxSVC)
344 {
345 HRESULT hrc = m_ptrVirtualBoxSDS->DeregisterVBoxSVC(m_pVBoxSVC, GetCurrentProcessId());
346 NOREF(hrc);
347 }
348 m_ptrVirtualBoxSDS.setNull();
349 g_fRegisteredWithVBoxSDS = false;
350 }
351 if (m_pVBoxSVC)
352 {
353 m_pVBoxSVC->m_pFactory = NULL;
354 m_pVBoxSVC->Release();
355 m_pVBoxSVC = NULL;
356 }
357}
358
359
360HRESULT VirtualBoxClassFactory::i_getVirtualBox(IUnknown **ppResult)
361{
362 IUnknown *pObj = m_pObj;
363 if (pObj)
364 {
365 /** @todo Do we need to do something regarding server locking? Hopefully COM
366 * deals with that........... */
367 pObj->AddRef();
368 *ppResult = pObj;
369 Log(("VirtualBoxClassFactory::GetVirtualBox: S_OK - %p\n", pObj));
370 return S_OK;
371 }
372 *ppResult = NULL;
373 Log(("VirtualBoxClassFactory::GetVirtualBox: E_FAIL\n"));
374 return E_FAIL;
375}
376
377
378/**
379 * Custom class factory impl for the VirtualBox singleton.
380 *
381 * This will consult with VBoxSDS on whether this VBoxSVC instance should
382 * provide the actual VirtualBox instance or just forward the instance from
383 * some other SVC instance.
384 *
385 * @param pUnkOuter This must be NULL.
386 * @param riid Reference to the interface ID to provide.
387 * @param ppvObj Where to return the pointer to the riid instance.
388 *
389 * @return COM status code.
390 */
391STDMETHODIMP VirtualBoxClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
392{
393 HRESULT hrc = E_POINTER;
394 if (ppvObj != NULL)
395 {
396 *ppvObj = NULL;
397 // no aggregation for singletons
398 AssertReturn(pUnkOuter == NULL, CLASS_E_NOAGGREGATION);
399
400 /*
401 * We must make sure there is only one instance around.
402 * So, we check without locking and then again after locking.
403 */
404 if (ASMAtomicReadS32(&m_iState) == 0)
405 {
406 Lock();
407 __try
408 {
409 if (ASMAtomicReadS32(&m_iState) == 0)
410 {
411 /*
412 * lock the module to indicate activity
413 * (necessary for the monitor shutdown thread to correctly
414 * terminate the module in case when CreateInstance() fails)
415 */
416 ATL::_pAtlModule->Lock();
417 __try
418 {
419 /*
420 * Now we need to connect to VBoxSDS to register ourselves.
421 */
422 IUnknown *pOtherVirtualBox = NULL;
423 m_hrcCreate = hrc = i_registerWithSds(&pOtherVirtualBox);
424 if (SUCCEEDED(hrc) && pOtherVirtualBox)
425 m_pObj = pOtherVirtualBox;
426 else if (SUCCEEDED(hrc))
427 {
428 ATL::_pAtlModule->Lock();
429 ATL::CComObjectCached<VirtualBox> *p;
430 m_hrcCreate = hrc = ATL::CComObjectCached<VirtualBox>::CreateInstance(&p);
431 if (SUCCEEDED(hrc))
432 {
433 m_hrcCreate = hrc = p->QueryInterface(IID_IUnknown, (void **)&m_pObj);
434 if (SUCCEEDED(hrc))
435 RTLogClearFileDelayFlag(RTLogRelGetDefaultInstance(), NULL);
436 else
437 {
438 delete p;
439 i_deregisterWithSds();
440 m_pObj = NULL;
441 }
442 }
443 }
444 ASMAtomicWriteS32(&m_iState, SUCCEEDED(hrc) ? 1 : -1);
445 }
446 __finally
447 {
448 ATL::_pAtlModule->Unlock();
449 }
450 }
451 }
452 __finally
453 {
454 if (ASMAtomicReadS32(&m_iState) == 0)
455 {
456 ASMAtomicWriteS32(&m_iState, -1);
457 if (SUCCEEDED(m_hrcCreate))
458 m_hrcCreate = E_FAIL;
459 }
460 Unlock();
461 }
462 }
463
464 /*
465 * Query the requested interface from the IUnknown one we're keeping around.
466 */
467 if (m_hrcCreate == S_OK)
468 hrc = m_pObj->QueryInterface(riid, ppvObj);
469 else
470 hrc = m_hrcCreate;
471 }
472 return hrc;
473}
474
475#endif /* VBOX_WITH_SDS_PLAN_B */
476
477
478/*
479* Wrapper for Win API function ShutdownBlockReasonCreate
480* This function defined starting from Vista only.
481*/
482static BOOL ShutdownBlockReasonCreateAPI(HWND hWnd, LPCWSTR pwszReason)
483{
484 BOOL fResult = FALSE;
485 typedef BOOL(WINAPI *PFNSHUTDOWNBLOCKREASONCREATE)(HWND hWnd, LPCWSTR pwszReason);
486
487 PFNSHUTDOWNBLOCKREASONCREATE pfn = (PFNSHUTDOWNBLOCKREASONCREATE)GetProcAddress(
488 GetModuleHandle(L"User32.dll"), "ShutdownBlockReasonCreate");
489 AssertPtr(pfn);
490 if (pfn)
491 fResult = pfn(hWnd, pwszReason);
492 return fResult;
493}
494
495/*
496* Wrapper for Win API function ShutdownBlockReasonDestroy
497* This function defined starting from Vista only.
498*/
499static BOOL ShutdownBlockReasonDestroyAPI(HWND hWnd)
500{
501 BOOL fResult = FALSE;
502 typedef BOOL(WINAPI *PFNSHUTDOWNBLOCKREASONDESTROY)(HWND hWnd);
503
504 PFNSHUTDOWNBLOCKREASONDESTROY pfn = (PFNSHUTDOWNBLOCKREASONDESTROY)GetProcAddress(
505 GetModuleHandle(L"User32.dll"), "ShutdownBlockReasonDestroy");
506 AssertPtr(pfn);
507 if (pfn)
508 fResult = pfn(hWnd);
509 return fResult;
510}
511
512static LRESULT CALLBACK WinMainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
513{
514 LRESULT rc = 0;
515 switch (msg)
516 {
517 case WM_QUERYENDSESSION:
518 {
519 if (g_pModule)
520 {
521 bool fActiveConnection = g_pModule->HasActiveConnection();
522 if (fActiveConnection)
523 {
524 /* place the VBoxSVC into system shutdown list */
525 ShutdownBlockReasonCreateAPI(hwnd, L"Has active connections.");
526 /* decrease a latency of MonitorShutdown loop */
527 ASMAtomicXchgU32(&dwTimeOut, 100);
528 Log(("VBoxSVCWinMain: WM_QUERYENDSESSION: VBoxSvc has active connections. bActivity = %d. Loc count = %d\n",
529 g_pModule->bActivity, g_pModule->GetLockCount()));
530 }
531 rc = !fActiveConnection;
532 }
533 else
534 AssertMsgFailed(("VBoxSVCWinMain: WM_QUERYENDSESSION: Error: g_pModule is NULL"));
535 break;
536 }
537 case WM_ENDSESSION:
538 {
539 /* Restore timeout of Monitor Shutdown if user canceled system shutdown */
540 if (wParam == FALSE)
541 {
542 ASMAtomicXchgU32(&dwTimeOut, dwNormalTimeout);
543 Log(("VBoxSVCWinMain: user canceled system shutdown.\n"));
544 }
545 break;
546 }
547 case WM_DESTROY:
548 {
549 ShutdownBlockReasonDestroyAPI(hwnd);
550 PostQuitMessage(0);
551 break;
552 }
553 default:
554 {
555 rc = DefWindowProc(hwnd, msg, wParam, lParam);
556 }
557 }
558 return rc;
559}
560
561static int CreateMainWindow()
562{
563 int rc = VINF_SUCCESS;
564 Assert(g_hMainWindow == NULL);
565
566 LogFlow(("CreateMainWindow\n"));
567
568 g_hInstance = (HINSTANCE)GetModuleHandle(NULL);
569
570 /* Register the Window Class. */
571 WNDCLASS wc;
572 RT_ZERO(wc);
573
574 wc.style = CS_NOCLOSE;
575 wc.lpfnWndProc = WinMainWndProc;
576 wc.hInstance = g_hInstance;
577 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
578 wc.lpszClassName = MAIN_WND_CLASS;
579
580 ATOM atomWindowClass = RegisterClass(&wc);
581 if (atomWindowClass == 0)
582 {
583 Log(("Failed to register main window class\n"));
584 rc = VERR_NOT_SUPPORTED;
585 }
586 else
587 {
588 /* Create the window. */
589 g_hMainWindow = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
590 MAIN_WND_CLASS, MAIN_WND_CLASS,
591 WS_POPUPWINDOW,
592 0, 0, 1, 1, NULL, NULL, g_hInstance, NULL);
593 if (g_hMainWindow == NULL)
594 {
595 Log(("Failed to create main window\n"));
596 rc = VERR_NOT_SUPPORTED;
597 }
598 else
599 {
600 SetWindowPos(g_hMainWindow, HWND_TOPMOST, -200, -200, 0, 0,
601 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
602
603 }
604 }
605 return 0;
606}
607
608
609static void DestroyMainWindow()
610{
611 Assert(g_hMainWindow != NULL);
612 Log(("SVCMain: DestroyMainWindow \n"));
613 if (g_hMainWindow != NULL)
614 {
615 DestroyWindow(g_hMainWindow);
616 g_hMainWindow = NULL;
617 if (g_hInstance != NULL)
618 {
619 UnregisterClass(MAIN_WND_CLASS, g_hInstance);
620 g_hInstance = NULL;
621 }
622 }
623}
624
625
626/////////////////////////////////////////////////////////////////////////////
627//
628int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)
629{
630 int argc = __argc;
631 char **argv = __argv;
632
633 /*
634 * Need to parse the command line before initializing the VBox runtime so we can
635 * change to the user home directory before logs are being created.
636 */
637 for (int i = 1; i < argc; i++)
638 if ( (argv[i][0] == '/' || argv[i][0] == '-')
639 && stricmp(&argv[i][1], "embedding") == 0) /* ANSI */
640 {
641 /* %HOMEDRIVE%%HOMEPATH% */
642 wchar_t wszHome[RTPATH_MAX];
643 DWORD cEnv = GetEnvironmentVariable(L"HOMEDRIVE", &wszHome[0], RTPATH_MAX);
644 if (cEnv && cEnv < RTPATH_MAX)
645 {
646 DWORD cwc = cEnv; /* doesn't include NUL */
647 cEnv = GetEnvironmentVariable(L"HOMEPATH", &wszHome[cEnv], RTPATH_MAX - cwc);
648 if (cEnv && cEnv < RTPATH_MAX - cwc)
649 {
650 /* If this fails there is nothing we can do. Ignore. */
651 SetCurrentDirectory(wszHome);
652 }
653 }
654 }
655
656 /*
657 * Initialize the VBox runtime without loading
658 * the support driver.
659 */
660 RTR3InitExe(argc, &argv, 0);
661
662 static const RTGETOPTDEF s_aOptions[] =
663 {
664 { "--embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
665 { "-embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
666 { "/embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
667 { "--unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
668 { "-unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
669 { "/unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
670 { "--regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
671 { "-regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
672 { "/regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
673 { "--reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
674 { "-reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
675 { "/reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
676 { "--helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
677 { "-helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
678 { "/helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
679 { "--logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
680 { "-logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
681 { "/logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
682 { "--logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
683 { "-logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
684 { "/logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
685 { "--logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
686 { "-logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
687 { "/logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
688 { "--loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
689 { "-loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
690 { "/loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
691 };
692
693 bool fRun = true;
694 bool fRegister = false;
695 bool fUnregister = false;
696 const char *pszPipeName = NULL;
697 const char *pszLogFile = NULL;
698 uint32_t cHistory = 10; // enable log rotation, 10 files
699 uint32_t uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
700 uint64_t uHistoryFileSize = 100 * _1M; // max 100MB per file
701
702 RTGETOPTSTATE GetOptState;
703 int vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
704 AssertRC(vrc);
705
706 RTGETOPTUNION ValueUnion;
707 while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
708 {
709 switch (vrc)
710 {
711 case 'e':
712 /* already handled above */
713 break;
714
715 case 'u':
716 fUnregister = true;
717 fRun = false;
718 break;
719
720 case 'r':
721 fRegister = true;
722 fRun = false;
723 break;
724
725 case 'f':
726 fUnregister = true;
727 fRegister = true;
728 fRun = false;
729 break;
730
731 case 'H':
732 pszPipeName = ValueUnion.psz;
733 if (!pszPipeName)
734 pszPipeName = "";
735 fRun = false;
736 break;
737
738 case 'F':
739 pszLogFile = ValueUnion.psz;
740 break;
741
742 case 'R':
743 cHistory = ValueUnion.u32;
744 break;
745
746 case 'S':
747 uHistoryFileSize = ValueUnion.u64;
748 break;
749
750 case 'I':
751 uHistoryFileTime = ValueUnion.u32;
752 break;
753
754 case 'h':
755 {
756 TCHAR txt[]= L"Options:\n\n"
757 L"/RegServer:\tregister COM out-of-proc server\n"
758 L"/UnregServer:\tunregister COM out-of-proc server\n"
759 L"/ReregServer:\tunregister and register COM server\n"
760 L"no options:\trun the server";
761 TCHAR title[]=_T("Usage");
762 fRun = false;
763 MessageBox(NULL, txt, title, MB_OK);
764 return 0;
765 }
766
767 case 'V':
768 {
769 char *psz = NULL;
770 RTStrAPrintf(&psz, "%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
771 PRTUTF16 txt = NULL;
772 RTStrToUtf16(psz, &txt);
773 TCHAR title[]=_T("Version");
774 fRun = false;
775 MessageBox(NULL, txt, title, MB_OK);
776 RTStrFree(psz);
777 RTUtf16Free(txt);
778 return 0;
779 }
780
781 default:
782 /** @todo this assumes that stderr is visible, which is not
783 * true for standard Windows applications. */
784 /* continue on command line errors... */
785 RTGetOptPrintError(vrc, &ValueUnion);
786 }
787 }
788
789 /* Only create the log file when running VBoxSVC normally, but not when
790 * registering/unregistering or calling the helper functionality. */
791 if (fRun)
792 {
793 /** @todo Merge this code with server.cpp (use Logging.cpp?). */
794 char szLogFile[RTPATH_MAX];
795 if (!pszLogFile || !*pszLogFile)
796 {
797 vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
798 if (RT_SUCCESS(vrc))
799 vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
800 if (RT_FAILURE(vrc))
801 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to construct release log filename, rc=%Rrc", vrc);
802 pszLogFile = szLogFile;
803 }
804
805 RTERRINFOSTATIC ErrInfo;
806 vrc = com::VBoxLogRelCreate("COM Server", pszLogFile,
807 RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
808 VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG",
809#ifdef VBOX_WITH_SDS_PLAN_B
810 RTLOGDEST_FILE | RTLOGDEST_F_DELAY_FILE,
811#else
812 RTLOGDEST_FILE,
813#endif
814 UINT32_MAX /* cMaxEntriesPerGroup */, cHistory, uHistoryFileTime, uHistoryFileSize,
815 RTErrInfoInitStatic(&ErrInfo));
816 if (RT_FAILURE(vrc))
817 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", ErrInfo.Core.pszMsg, vrc);
818 }
819
820 /* Set up a build identifier so that it can be seen from core dumps what
821 * exact build was used to produce the core. Same as in Console::i_powerUpThread(). */
822 static char saBuildID[48];
823 RTStrPrintf(saBuildID, sizeof(saBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s",
824 "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
825
826 int nRet = 0;
827 HRESULT hRes = com::Initialize(false /*fGui*/, fRun /*fAutoRegUpdate*/);
828 AssertLogRelMsg(SUCCEEDED(hRes), ("SVCMAIN: init failed: %Rhrc\n", hRes));
829
830 g_pModule = new CExeModule();
831 if(g_pModule == NULL)
832 return RTMsgErrorExit(RTEXITCODE_FAILURE, "not enough memory to create ExeModule.");
833 g_pModule->Init(ObjectMap, hInstance, &LIBID_VirtualBox);
834 g_pModule->dwThreadID = GetCurrentThreadId();
835
836 if (!fRun)
837 {
838#ifndef VBOX_WITH_MIDL_PROXY_STUB /* VBoxProxyStub.dll does all the registration work. */
839 if (fUnregister)
840 {
841 g_pModule->UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
842 nRet = g_pModule->UnregisterServer(TRUE);
843 }
844 if (fRegister)
845 {
846 g_pModule->UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
847 nRet = g_pModule->RegisterServer(TRUE);
848 }
849#endif
850 if (pszPipeName)
851 {
852 Log(("SVCMAIN: Processing Helper request (cmdline=\"%s\")...\n", pszPipeName));
853
854 if (!*pszPipeName)
855 vrc = VERR_INVALID_PARAMETER;
856
857 if (RT_SUCCESS(vrc))
858 {
859 /* do the helper job */
860 SVCHlpServer server;
861 vrc = server.open(pszPipeName);
862 if (RT_SUCCESS(vrc))
863 vrc = server.run();
864 }
865 if (RT_FAILURE(vrc))
866 {
867 Log(("SVCMAIN: Failed to process Helper request (%Rrc).", vrc));
868 nRet = 1;
869 }
870 }
871 }
872 else
873 {
874 g_pModule->StartMonitor();
875#if _WIN32_WINNT >= 0x0400
876 hRes = g_pModule->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
877 _ASSERTE(SUCCEEDED(hRes));
878 hRes = CoResumeClassObjects();
879#else
880 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
881#endif
882 _ASSERTE(SUCCEEDED(hRes));
883
884 if (RT_SUCCESS(CreateMainWindow()))
885 Log(("SVCMain: Main window succesfully created\n"));
886 else
887 Log(("SVCMain: Failed to create main window\n"));
888
889 MSG msg;
890 while (GetMessage(&msg, 0, 0, 0) > 0)
891 {
892 DispatchMessage(&msg);
893 TranslateMessage(&msg);
894 }
895
896 DestroyMainWindow();
897
898 g_pModule->RevokeClassObjects();
899 }
900
901 g_pModule->Term();
902
903 com::Shutdown();
904
905 if(g_pModule)
906 delete g_pModule;
907 g_pModule = NULL;
908
909 Log(("SVCMAIN: Returning, COM server process ends.\n"));
910 return nRet;
911}
Note: See TracBrowser for help on using the repository browser.

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