VirtualBox

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

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

Main: Outlined a possible plan B for the VBoxSDS stuff.

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