VirtualBox

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

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

Main/svcmain.cpp: Backed out r119561 as we won't try instantiate the VirtualBox object without knowing that there aren't competing instances around. This is what we're trying to fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.5 KB
Line 
1/* $Id: svcmain.cpp 70030 2017-12-08 14:09:19Z 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
81/** This is set if we're connected to SDS.
82 *
83 * It means that we should discount a server lock that it is holding when
84 * deciding whether we're idle or not.
85 *
86 * Also, when set we deregister with SDS during class factory destruction. We
87 * exploit this to prevent attempts to deregister during or after COM shutdown.
88 */
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
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
194class VBoxSVCRegistration;
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 IVBoxSVCRegistration implementation that VBoxSDS works with. */
212 VBoxSVCRegistration *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 /* We usually get here during g_pModule->Term() via CoRevokeClassObjec, so COM
229 probably working well enough to talk to SDS when we get here. */
230 if (g_fRegisteredWithVBoxSDS)
231 i_deregisterWithSds();
232 }
233
234 // IClassFactory
235 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj);
236
237 /** Worker for VBoxSVCRegistration::getVirtualBox. */
238 HRESULT i_getVirtualBox(IUnknown **ppResult);
239
240private:
241 HRESULT VirtualBoxClassFactory::i_registerWithSds(IUnknown **ppOtherVirtualBox);
242 void VirtualBoxClassFactory::i_deregisterWithSds(void);
243
244 friend VBoxSVCRegistration;
245};
246
247
248/**
249 * The VBoxSVC class is handed to VBoxSDS so it can call us back and ask for the
250 * VirtualBox object when the next VBoxSVC for this user registers itself.
251 */
252class VBoxSVCRegistration : public IVBoxSVCRegistration
253{
254private:
255 /** Number of references. */
256 uint32_t volatile m_cRefs;
257
258public:
259 /** Pointer to the factory. */
260 VirtualBoxClassFactory *m_pFactory;
261
262public:
263 VBoxSVCRegistration(VirtualBoxClassFactory *pFactory)
264 : m_cRefs(1), m_pFactory(pFactory)
265 { }
266 virtual ~VBoxSVCRegistration()
267 {
268 if (m_pFactory)
269 {
270 if (m_pFactory->m_pVBoxSVC)
271 m_pFactory->m_pVBoxSVC = NULL;
272 m_pFactory = NULL;
273 }
274 }
275 RTMEMEF_NEW_AND_DELETE_OPERATORS();
276
277 // IUnknown
278 STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject)
279 {
280 if (riid == __uuidof(IUnknown))
281 *ppvObject = (void *)(IUnknown *)this;
282 else if (riid == __uuidof(IVBoxSVCRegistration))
283 *ppvObject = (void *)(IVBoxSVCRegistration *)this;
284 else
285 {
286 return E_NOINTERFACE;
287 }
288 AddRef();
289 return S_OK;
290
291 }
292
293 STDMETHOD_(ULONG,AddRef)(void)
294 {
295 uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
296 return cRefs;
297 }
298
299 STDMETHOD_(ULONG,Release)(void)
300 {
301 uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
302 if (cRefs == 0)
303 delete this;
304 return cRefs;
305 }
306
307 // IVBoxSVCRegistration
308 STDMETHOD(GetVirtualBox)(IUnknown **ppResult)
309 {
310 if (m_pFactory)
311 return m_pFactory->i_getVirtualBox(ppResult);
312 return E_FAIL;
313 }
314};
315
316
317HRESULT VirtualBoxClassFactory::i_registerWithSds(IUnknown **ppOtherVirtualBox)
318{
319 /*
320 * Connect to VBoxSDS.
321 */
322 HRESULT hrc = CoCreateInstance(CLSID_VirtualBoxSDS, NULL, CLSCTX_LOCAL_SERVER, IID_IVirtualBoxSDS,
323 (void **)m_ptrVirtualBoxSDS.asOutParam());
324 if (SUCCEEDED(hrc))
325 {
326 /*
327 * Create VBoxSVCRegistration object and hand that to VBoxSDS.
328 */
329 m_pVBoxSVC = new VBoxSVCRegistration(this);
330 hrc = m_ptrVirtualBoxSDS->RegisterVBoxSVC(m_pVBoxSVC, GetCurrentProcessId(), ppOtherVirtualBox);
331 if (SUCCEEDED(hrc))
332 {
333 g_fRegisteredWithVBoxSDS = !*ppOtherVirtualBox;
334 return hrc;
335 }
336 m_pVBoxSVC->Release();
337 }
338 m_ptrVirtualBoxSDS.setNull();
339 m_pVBoxSVC = NULL;
340 *ppOtherVirtualBox = NULL;
341 return hrc;
342}
343
344
345void VirtualBoxClassFactory::i_deregisterWithSds(void)
346{
347 Log(("VirtualBoxClassFactory::i_deregisterWithSds\n"));
348
349 if (m_ptrVirtualBoxSDS.isNotNull())
350 {
351 if (m_pVBoxSVC)
352 {
353 HRESULT hrc = m_ptrVirtualBoxSDS->DeregisterVBoxSVC(m_pVBoxSVC, GetCurrentProcessId());
354 NOREF(hrc);
355 }
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 }
365}
366
367
368HRESULT VirtualBoxClassFactory::i_getVirtualBox(IUnknown **ppResult)
369{
370 IUnknown *pObj = m_pObj;
371 if (pObj)
372 {
373 /** @todo Do we need to do something regarding server locking? Hopefully COM
374 * deals with that........... */
375 pObj->AddRef();
376 *ppResult = pObj;
377 Log(("VirtualBoxClassFactory::GetVirtualBox: S_OK - %p\n", pObj));
378 return S_OK;
379 }
380 *ppResult = NULL;
381 Log(("VirtualBoxClassFactory::GetVirtualBox: E_FAIL\n"));
382 return E_FAIL;
383}
384
385
386/**
387 * Custom class factory impl for the VirtualBox singleton.
388 *
389 * This will consult with VBoxSDS on whether this VBoxSVC instance should
390 * provide the actual VirtualBox instance or just forward the instance from
391 * some other SVC instance.
392 *
393 * @param pUnkOuter This must be NULL.
394 * @param riid Reference to the interface ID to provide.
395 * @param ppvObj Where to return the pointer to the riid instance.
396 *
397 * @return COM status code.
398 */
399STDMETHODIMP VirtualBoxClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
400{
401 HRESULT hrc = E_POINTER;
402 if (ppvObj != NULL)
403 {
404 *ppvObj = NULL;
405 // no aggregation for singletons
406 AssertReturn(pUnkOuter == NULL, CLASS_E_NOAGGREGATION);
407
408 /*
409 * We must make sure there is only one instance around.
410 * So, we check without locking and then again after locking.
411 */
412 if (ASMAtomicReadS32(&m_iState) == 0)
413 {
414 Lock();
415 __try
416 {
417 if (ASMAtomicReadS32(&m_iState) == 0)
418 {
419 /*
420 * lock the module to indicate activity
421 * (necessary for the monitor shutdown thread to correctly
422 * terminate the module in case when CreateInstance() fails)
423 */
424 ATL::_pAtlModule->Lock();
425 __try
426 {
427 /*
428 * Now we need to connect to VBoxSDS to register ourselves.
429 */
430 IUnknown *pOtherVirtualBox = NULL;
431 m_hrcCreate = hrc = i_registerWithSds(&pOtherVirtualBox);
432 if (SUCCEEDED(hrc) && pOtherVirtualBox)
433 m_pObj = pOtherVirtualBox;
434 else if (SUCCEEDED(hrc))
435 {
436 ATL::_pAtlModule->Lock();
437 ATL::CComObjectCached<VirtualBox> *p;
438 m_hrcCreate = hrc = ATL::CComObjectCached<VirtualBox>::CreateInstance(&p);
439 if (SUCCEEDED(hrc))
440 {
441 m_hrcCreate = hrc = p->QueryInterface(IID_IUnknown, (void **)&m_pObj);
442 if (SUCCEEDED(hrc))
443 RTLogClearFileDelayFlag(RTLogRelGetDefaultInstance(), NULL);
444 else
445 {
446 delete p;
447 i_deregisterWithSds();
448 m_pObj = NULL;
449 }
450 }
451 }
452 ASMAtomicWriteS32(&m_iState, SUCCEEDED(hrc) ? 1 : -1);
453 }
454 __finally
455 {
456 ATL::_pAtlModule->Unlock();
457 }
458 }
459 }
460 __finally
461 {
462 if (ASMAtomicReadS32(&m_iState) == 0)
463 {
464 ASMAtomicWriteS32(&m_iState, -1);
465 if (SUCCEEDED(m_hrcCreate))
466 m_hrcCreate = E_FAIL;
467 }
468 Unlock();
469 }
470 }
471
472 /*
473 * Query the requested interface from the IUnknown one we're keeping around.
474 */
475 if (m_hrcCreate == S_OK)
476 hrc = m_pObj->QueryInterface(riid, ppvObj);
477 else
478 hrc = m_hrcCreate;
479 }
480 return hrc;
481}
482
483#endif /* VBOX_WITH_SDS */
484
485
486/*
487* Wrapper for Win API function ShutdownBlockReasonCreate
488* This function defined starting from Vista only.
489*/
490static BOOL ShutdownBlockReasonCreateAPI(HWND hWnd, LPCWSTR pwszReason)
491{
492 BOOL fResult = FALSE;
493 typedef BOOL(WINAPI *PFNSHUTDOWNBLOCKREASONCREATE)(HWND hWnd, LPCWSTR pwszReason);
494
495 PFNSHUTDOWNBLOCKREASONCREATE pfn = (PFNSHUTDOWNBLOCKREASONCREATE)GetProcAddress(
496 GetModuleHandle(L"User32.dll"), "ShutdownBlockReasonCreate");
497 AssertPtr(pfn);
498 if (pfn)
499 fResult = pfn(hWnd, pwszReason);
500 return fResult;
501}
502
503/*
504* Wrapper for Win API function ShutdownBlockReasonDestroy
505* This function defined starting from Vista only.
506*/
507static BOOL ShutdownBlockReasonDestroyAPI(HWND hWnd)
508{
509 BOOL fResult = FALSE;
510 typedef BOOL(WINAPI *PFNSHUTDOWNBLOCKREASONDESTROY)(HWND hWnd);
511
512 PFNSHUTDOWNBLOCKREASONDESTROY pfn = (PFNSHUTDOWNBLOCKREASONDESTROY)GetProcAddress(
513 GetModuleHandle(L"User32.dll"), "ShutdownBlockReasonDestroy");
514 AssertPtr(pfn);
515 if (pfn)
516 fResult = pfn(hWnd);
517 return fResult;
518}
519
520static LRESULT CALLBACK WinMainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
521{
522 LRESULT rc = 0;
523 switch (msg)
524 {
525 case WM_QUERYENDSESSION:
526 {
527 if (g_pModule)
528 {
529 bool fActiveConnection = g_pModule->HasActiveConnection();
530 if (fActiveConnection)
531 {
532 /* place the VBoxSVC into system shutdown list */
533 ShutdownBlockReasonCreateAPI(hwnd, L"Has active connections.");
534 /* decrease a latency of MonitorShutdown loop */
535 ASMAtomicXchgU32(&dwTimeOut, 100);
536 Log(("VBoxSVCWinMain: WM_QUERYENDSESSION: VBoxSvc has active connections. bActivity = %d. Loc count = %d\n",
537 g_pModule->bActivity, g_pModule->GetLockCount()));
538 }
539 rc = !fActiveConnection;
540 }
541 else
542 AssertMsgFailed(("VBoxSVCWinMain: WM_QUERYENDSESSION: Error: g_pModule is NULL"));
543 break;
544 }
545 case WM_ENDSESSION:
546 {
547 /* Restore timeout of Monitor Shutdown if user canceled system shutdown */
548 if (wParam == FALSE)
549 {
550 ASMAtomicXchgU32(&dwTimeOut, dwNormalTimeout);
551 Log(("VBoxSVCWinMain: user canceled system shutdown.\n"));
552 }
553 break;
554 }
555 case WM_DESTROY:
556 {
557 ShutdownBlockReasonDestroyAPI(hwnd);
558 PostQuitMessage(0);
559 break;
560 }
561 default:
562 {
563 rc = DefWindowProc(hwnd, msg, wParam, lParam);
564 }
565 }
566 return rc;
567}
568
569static int CreateMainWindow()
570{
571 int rc = VINF_SUCCESS;
572 Assert(g_hMainWindow == NULL);
573
574 LogFlow(("CreateMainWindow\n"));
575
576 g_hInstance = (HINSTANCE)GetModuleHandle(NULL);
577
578 /* Register the Window Class. */
579 WNDCLASS wc;
580 RT_ZERO(wc);
581
582 wc.style = CS_NOCLOSE;
583 wc.lpfnWndProc = WinMainWndProc;
584 wc.hInstance = g_hInstance;
585 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
586 wc.lpszClassName = MAIN_WND_CLASS;
587
588 ATOM atomWindowClass = RegisterClass(&wc);
589 if (atomWindowClass == 0)
590 {
591 Log(("Failed to register main window class\n"));
592 rc = VERR_NOT_SUPPORTED;
593 }
594 else
595 {
596 /* Create the window. */
597 g_hMainWindow = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
598 MAIN_WND_CLASS, MAIN_WND_CLASS,
599 WS_POPUPWINDOW,
600 0, 0, 1, 1, NULL, NULL, g_hInstance, NULL);
601 if (g_hMainWindow == NULL)
602 {
603 Log(("Failed to create main window\n"));
604 rc = VERR_NOT_SUPPORTED;
605 }
606 else
607 {
608 SetWindowPos(g_hMainWindow, HWND_TOPMOST, -200, -200, 0, 0,
609 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
610
611 }
612 }
613 return 0;
614}
615
616
617static void DestroyMainWindow()
618{
619 Assert(g_hMainWindow != NULL);
620 Log(("SVCMain: DestroyMainWindow \n"));
621 if (g_hMainWindow != NULL)
622 {
623 DestroyWindow(g_hMainWindow);
624 g_hMainWindow = NULL;
625 if (g_hInstance != NULL)
626 {
627 UnregisterClass(MAIN_WND_CLASS, g_hInstance);
628 g_hInstance = NULL;
629 }
630 }
631}
632
633
634/////////////////////////////////////////////////////////////////////////////
635//
636int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)
637{
638 int argc = __argc;
639 char **argv = __argv;
640
641 /*
642 * Need to parse the command line before initializing the VBox runtime so we can
643 * change to the user home directory before logs are being created.
644 */
645 for (int i = 1; i < argc; i++)
646 if ( (argv[i][0] == '/' || argv[i][0] == '-')
647 && stricmp(&argv[i][1], "embedding") == 0) /* ANSI */
648 {
649 /* %HOMEDRIVE%%HOMEPATH% */
650 wchar_t wszHome[RTPATH_MAX];
651 DWORD cEnv = GetEnvironmentVariable(L"HOMEDRIVE", &wszHome[0], RTPATH_MAX);
652 if (cEnv && cEnv < RTPATH_MAX)
653 {
654 DWORD cwc = cEnv; /* doesn't include NUL */
655 cEnv = GetEnvironmentVariable(L"HOMEPATH", &wszHome[cEnv], RTPATH_MAX - cwc);
656 if (cEnv && cEnv < RTPATH_MAX - cwc)
657 {
658 /* If this fails there is nothing we can do. Ignore. */
659 SetCurrentDirectory(wszHome);
660 }
661 }
662 }
663
664 /*
665 * Initialize the VBox runtime without loading
666 * the support driver.
667 */
668 RTR3InitExe(argc, &argv, 0);
669
670 static const RTGETOPTDEF s_aOptions[] =
671 {
672 { "--embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
673 { "-embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
674 { "/embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
675 { "--unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
676 { "-unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
677 { "/unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
678 { "--regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
679 { "-regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
680 { "/regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
681 { "--reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
682 { "-reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
683 { "/reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
684 { "--helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
685 { "-helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
686 { "/helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
687 { "--logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
688 { "-logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
689 { "/logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
690 { "--logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
691 { "-logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
692 { "/logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
693 { "--logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
694 { "-logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
695 { "/logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
696 { "--loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
697 { "-loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
698 { "/loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
699 };
700
701 bool fRun = true;
702 bool fRegister = false;
703 bool fUnregister = false;
704 const char *pszPipeName = NULL;
705 const char *pszLogFile = NULL;
706 uint32_t cHistory = 10; // enable log rotation, 10 files
707 uint32_t uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
708 uint64_t uHistoryFileSize = 100 * _1M; // max 100MB per file
709
710 RTGETOPTSTATE GetOptState;
711 int vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
712 AssertRC(vrc);
713
714 RTGETOPTUNION ValueUnion;
715 while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
716 {
717 switch (vrc)
718 {
719 case 'e':
720 /* already handled above */
721 break;
722
723 case 'u':
724 fUnregister = true;
725 fRun = false;
726 break;
727
728 case 'r':
729 fRegister = true;
730 fRun = false;
731 break;
732
733 case 'f':
734 fUnregister = true;
735 fRegister = true;
736 fRun = false;
737 break;
738
739 case 'H':
740 pszPipeName = ValueUnion.psz;
741 if (!pszPipeName)
742 pszPipeName = "";
743 fRun = false;
744 break;
745
746 case 'F':
747 pszLogFile = ValueUnion.psz;
748 break;
749
750 case 'R':
751 cHistory = ValueUnion.u32;
752 break;
753
754 case 'S':
755 uHistoryFileSize = ValueUnion.u64;
756 break;
757
758 case 'I':
759 uHistoryFileTime = ValueUnion.u32;
760 break;
761
762 case 'h':
763 {
764 TCHAR txt[]= L"Options:\n\n"
765 L"/RegServer:\tregister COM out-of-proc server\n"
766 L"/UnregServer:\tunregister COM out-of-proc server\n"
767 L"/ReregServer:\tunregister and register COM server\n"
768 L"no options:\trun the server";
769 TCHAR title[]=_T("Usage");
770 fRun = false;
771 MessageBox(NULL, txt, title, MB_OK);
772 return 0;
773 }
774
775 case 'V':
776 {
777 char *psz = NULL;
778 RTStrAPrintf(&psz, "%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
779 PRTUTF16 txt = NULL;
780 RTStrToUtf16(psz, &txt);
781 TCHAR title[]=_T("Version");
782 fRun = false;
783 MessageBox(NULL, txt, title, MB_OK);
784 RTStrFree(psz);
785 RTUtf16Free(txt);
786 return 0;
787 }
788
789 default:
790 /** @todo this assumes that stderr is visible, which is not
791 * true for standard Windows applications. */
792 /* continue on command line errors... */
793 RTGetOptPrintError(vrc, &ValueUnion);
794 }
795 }
796
797 /* Only create the log file when running VBoxSVC normally, but not when
798 * registering/unregistering or calling the helper functionality. */
799 if (fRun)
800 {
801 /** @todo Merge this code with server.cpp (use Logging.cpp?). */
802 char szLogFile[RTPATH_MAX];
803 if (!pszLogFile || !*pszLogFile)
804 {
805 vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
806 if (RT_SUCCESS(vrc))
807 vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
808 if (RT_FAILURE(vrc))
809 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to construct release log filename, rc=%Rrc", vrc);
810 pszLogFile = szLogFile;
811 }
812
813 RTERRINFOSTATIC ErrInfo;
814 vrc = com::VBoxLogRelCreate("COM Server", pszLogFile,
815 RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
816 VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG",
817#ifdef VBOX_WITH_SDS
818 RTLOGDEST_FILE | RTLOGDEST_F_DELAY_FILE,
819#else
820 RTLOGDEST_FILE,
821#endif
822 UINT32_MAX /* cMaxEntriesPerGroup */, cHistory, uHistoryFileTime, uHistoryFileSize,
823 RTErrInfoInitStatic(&ErrInfo));
824 if (RT_FAILURE(vrc))
825 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", ErrInfo.Core.pszMsg, vrc);
826 }
827
828 /* Set up a build identifier so that it can be seen from core dumps what
829 * exact build was used to produce the core. Same as in Console::i_powerUpThread(). */
830 static char saBuildID[48];
831 RTStrPrintf(saBuildID, sizeof(saBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s",
832 "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
833
834 int nRet = 0;
835 HRESULT hRes = com::Initialize(false /*fGui*/, fRun /*fAutoRegUpdate*/);
836 AssertLogRelMsg(SUCCEEDED(hRes), ("SVCMAIN: init failed: %Rhrc\n", hRes));
837
838 g_pModule = new CExeModule();
839 if(g_pModule == NULL)
840 return RTMsgErrorExit(RTEXITCODE_FAILURE, "not enough memory to create ExeModule.");
841 g_pModule->Init(ObjectMap, hInstance, &LIBID_VirtualBox);
842 g_pModule->dwThreadID = GetCurrentThreadId();
843
844 if (!fRun)
845 {
846#ifndef VBOX_WITH_MIDL_PROXY_STUB /* VBoxProxyStub.dll does all the registration work. */
847 if (fUnregister)
848 {
849 g_pModule->UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
850 nRet = g_pModule->UnregisterServer(TRUE);
851 }
852 if (fRegister)
853 {
854 g_pModule->UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
855 nRet = g_pModule->RegisterServer(TRUE);
856 }
857#endif
858 if (pszPipeName)
859 {
860 Log(("SVCMAIN: Processing Helper request (cmdline=\"%s\")...\n", pszPipeName));
861
862 if (!*pszPipeName)
863 vrc = VERR_INVALID_PARAMETER;
864
865 if (RT_SUCCESS(vrc))
866 {
867 /* do the helper job */
868 SVCHlpServer server;
869 vrc = server.open(pszPipeName);
870 if (RT_SUCCESS(vrc))
871 vrc = server.run();
872 }
873 if (RT_FAILURE(vrc))
874 {
875 Log(("SVCMAIN: Failed to process Helper request (%Rrc).", vrc));
876 nRet = 1;
877 }
878 }
879 }
880 else
881 {
882 g_pModule->StartMonitor();
883#if _WIN32_WINNT >= 0x0400
884 hRes = g_pModule->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
885 _ASSERTE(SUCCEEDED(hRes));
886 hRes = CoResumeClassObjects();
887#else
888 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
889#endif
890 _ASSERTE(SUCCEEDED(hRes));
891
892 if (RT_SUCCESS(CreateMainWindow()))
893 Log(("SVCMain: Main window succesfully created\n"));
894 else
895 Log(("SVCMain: Failed to create main window\n"));
896
897 MSG msg;
898 while (GetMessage(&msg, 0, 0, 0) > 0)
899 {
900 DispatchMessage(&msg);
901 TranslateMessage(&msg);
902 }
903
904 DestroyMainWindow();
905
906 g_pModule->RevokeClassObjects();
907 }
908
909 g_pModule->Term();
910
911#ifdef VBOX_WITH_SDS
912 g_fRegisteredWithVBoxSDS = false; /* Don't trust COM LPC to work right from now on. */
913#endif
914 com::Shutdown();
915
916 if(g_pModule)
917 delete g_pModule;
918 g_pModule = NULL;
919
920 Log(("SVCMAIN: Returning, COM server process ends.\n"));
921 return nRet;
922}
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