VirtualBox

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

Last change on this file since 69749 was 69749, checked in by vboxsync, 8 years ago

Changed RTLogCreateEx[V] to take a RTERRINFO pointer rather than plain char * and size_t. Turned out a several callers didn't actually make use of the error message even.

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

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