VirtualBox

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

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

Main: More SDS plan B sketching.

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