VirtualBox

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

Last change on this file since 37667 was 37667, checked in by vboxsync, 14 years ago

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1/** @file
2 *
3 * SVCMAIN - COM out-of-proc server main entry
4 */
5
6/*
7 * Copyright (C) 2006-2011 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#include <stdio.h>
19
20#include "VBox/com/defs.h"
21
22#include "VBox/com/com.h"
23
24#include "VBox/com/VirtualBox.h"
25
26#include "VirtualBoxImpl.h"
27#include "Logging.h"
28
29#include "svchlp.h"
30
31#include <VBox/err.h>
32#include <iprt/getopt.h>
33#include <iprt/initterm.h>
34#include <iprt/path.h>
35
36#include <atlbase.h>
37#include <atlcom.h>
38
39#define _ATL_FREE_THREADED
40
41class CExeModule : public CComModule
42{
43public:
44 LONG Unlock();
45 DWORD dwThreadID;
46 HANDLE hEventShutdown;
47 void MonitorShutdown();
48 bool StartMonitor();
49 bool bActivity;
50};
51
52const DWORD dwTimeOut = 5000; /* time for EXE to be idle before shutting down */
53const DWORD dwPause = 1000; /* time to wait for threads to finish up */
54
55/* Passed to CreateThread to monitor the shutdown event */
56static DWORD WINAPI MonitorProc(void* pv)
57{
58 CExeModule* p = (CExeModule*)pv;
59 p->MonitorShutdown();
60 return 0;
61}
62
63LONG CExeModule::Unlock()
64{
65 LONG l = CComModule::Unlock();
66 if (l == 0)
67 {
68 bActivity = true;
69 SetEvent(hEventShutdown); /* tell monitor that we transitioned to zero */
70 }
71 return l;
72}
73
74/* Monitors the shutdown event */
75void CExeModule::MonitorShutdown()
76{
77 while (1)
78 {
79 WaitForSingleObject(hEventShutdown, INFINITE);
80 DWORD dwWait=0;
81 do
82 {
83 bActivity = false;
84 dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
85 } while (dwWait == WAIT_OBJECT_0);
86 /* timed out */
87 if (!bActivity && m_nLockCnt == 0) /* if no activity let's really bail */
88 {
89#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
90 CoSuspendClassObjects();
91 if (!bActivity && m_nLockCnt == 0)
92#endif
93 break;
94 }
95 }
96 CloseHandle(hEventShutdown);
97 PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
98}
99
100bool CExeModule::StartMonitor()
101{
102 hEventShutdown = CreateEvent(NULL, false, false, NULL);
103 if (hEventShutdown == NULL)
104 return false;
105 DWORD dwThreadID;
106 HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);
107 return (h != NULL);
108}
109
110CExeModule _Module;
111
112BEGIN_OBJECT_MAP(ObjectMap)
113 OBJECT_ENTRY(CLSID_VirtualBox, VirtualBox)
114END_OBJECT_MAP()
115
116
117LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
118{
119 while (p1 != NULL && *p1 != NULL)
120 {
121 LPCTSTR p = p2;
122 while (p != NULL && *p != NULL)
123 {
124 if (*p1 == *p)
125 return CharNext(p1);
126 p = CharNext(p);
127 }
128 p1 = CharNext(p1);
129 }
130 return NULL;
131}
132
133static int WordCmpI(LPCTSTR psz1, LPCTSTR psz2) throw()
134{
135 TCHAR c1 = (TCHAR)CharUpper((LPTSTR)*psz1);
136 TCHAR c2 = (TCHAR)CharUpper((LPTSTR)*psz2);
137 while (c1 != NULL && c1 == c2 && c1 != ' ' && c1 != '\t')
138 {
139 psz1 = CharNext(psz1);
140 psz2 = CharNext(psz2);
141 c1 = (TCHAR)CharUpper((LPTSTR)*psz1);
142 c2 = (TCHAR)CharUpper((LPTSTR)*psz2);
143 }
144 if ((c1 == NULL || c1 == ' ' || c1 == '\t') && (c2 == NULL || c2 == ' ' || c2 == '\t'))
145 return 0;
146
147 return (c1 < c2) ? -1 : 1;
148}
149
150/////////////////////////////////////////////////////////////////////////////
151//
152extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
153 HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
154{
155 lpCmdLine = GetCommandLine(); /* this line necessary for _ATL_MIN_CRT */
156
157 /* Need to parse the command line before initializing the VBox runtime. */
158 TCHAR szTokens[] = _T("-/");
159 LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
160 while (lpszToken != NULL)
161 {
162 if (WordCmpI(lpszToken, _T("Embedding")) == 0)
163 {
164 /* %HOMEDRIVE%%HOMEPATH% */
165 wchar_t wszHome[RTPATH_MAX];
166 DWORD cEnv = GetEnvironmentVariable(L"HOMEDRIVE", &wszHome[0], RTPATH_MAX);
167 if (cEnv && cEnv < RTPATH_MAX)
168 {
169 DWORD cwc = cEnv; /* doesn't include NUL */
170 cEnv = GetEnvironmentVariable(L"HOMEPATH", &wszHome[cEnv], RTPATH_MAX - cwc);
171 if (cEnv && cEnv < RTPATH_MAX - cwc)
172 {
173 /* If this fails there is nothing we can do. Ignore. */
174 SetCurrentDirectory(wszHome);
175 }
176 }
177 }
178
179 lpszToken = FindOneOf(lpszToken, szTokens);
180 }
181
182 /*
183 * Initialize the VBox runtime without loading
184 * the support driver.
185 */
186 RTR3Init();
187
188 /* Note that all options are given lowercase/camel case/uppercase to
189 * approximate case insensitive matching, which RTGetOpt doesn't offer. */
190 static const RTGETOPTDEF s_aOptions[] =
191 {
192 { "--embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
193 { "-embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
194 { "/embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
195 { "--unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
196 { "-unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
197 { "/unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
198 { "--regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
199 { "-regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
200 { "/regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
201 { "--reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
202 { "-reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
203 { "/reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
204 { "--helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
205 { "-helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
206 { "/helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
207 { "--logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
208 { "-logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
209 { "/logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
210 { "--logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
211 { "-logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
212 { "/logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
213 { "--logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
214 { "-logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
215 { "/logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
216 { "--loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
217 { "-loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
218 { "/loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
219 };
220
221 bool fRun = true;
222 bool fRegister = false;
223 bool fUnregister = false;
224 const char *pszPipeName = NULL;
225 const char *pszLogFile = NULL;
226 uint32_t cHistory = 10; // enable log rotation, 10 files
227 uint32_t uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
228 uint64_t uHistoryFileSize = 100 * _1M; // max 100MB per file
229
230 RTGETOPTSTATE GetOptState;
231 int vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
232 AssertRC(vrc);
233
234 RTGETOPTUNION ValueUnion;
235 while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
236 {
237 switch (vrc)
238 {
239 case 'e':
240 /* already handled above */
241 break;
242
243 case 'u':
244 fUnregister = true;
245 fRun = false;
246 break;
247
248 case 'r':
249 fRegister = true;
250 break;
251
252 case 'f':
253 fUnregister = true;
254 fRegister = true;
255 fRun = false;
256 break;
257
258 case 'H':
259 pszPipeName = ValueUnion.psz;
260 if (!pszPipeName)
261 pszPipeName = "";
262 fRun = false;
263 break;
264
265 case 'F':
266 pszLogFile = ValueUnion.psz;
267 break;
268
269 case 'R':
270 cHistory = ValueUnion.u32;
271 break;
272
273 case 'S':
274 uHistoryFileSize = ValueUnion.u64;
275 break;
276
277 case 'I':
278 uHistoryFileTime = ValueUnion.u32;
279 break;
280
281 case 'h':
282 TCHAR txt[]= L"Options:\n\n"
283 L"/RegServer:\tregister COM out-of-proc server\n"
284 L"/UnregServer:\tunregister COM out-of-proc server\n"
285 L"/ReregServer:\tunregister and register COM server\n"
286 L"no options:\trun the server";
287 TCHAR title[]=_T("Usage");
288 fRun = false;
289 MessageBox(NULL, txt, title, MB_OK);
290 break;
291
292 case 'V':
293 char *psz = NULL;
294 RTStrAPrintf(&psz, "%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
295 TCHAR *txt;
296 RTStrToUni(psz, &txt);
297 TCHAR title[]=_T("Version");
298 fRun = false;
299 MessageBox(NULL, txt, title, MB_OK);
300 RTStrFree(psz);
301 RTUniFree(txt);
302 break;
303
304 default:
305 /** @todo this assumes that stderr is visible, which is not
306 * true for standard Windows applications. */
307 return RTGetOptPrintError(vrc, &ValueUnion);
308 }
309 }
310
311 if (!pszLogFile)
312 {
313 char szLogFile[RTPATH_MAX];
314 vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
315 if (RT_SUCCESS(vrc))
316 vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
317 if (RT_SUCCESS(vrc))
318 pszLogFile = RTStrDup(szLogFile);
319 }
320 /* Only create the log file when running VBoxSVC normally, but not when
321 * registering/unregistering or calling the helper functionality. */
322 if (fRun)
323 VBoxSVCLogRelCreate(pszLogFile, cHistory, uHistoryFileTime, uHistoryFileSize);
324
325 int nRet = 0;
326 HRESULT hRes = com::Initialize();
327
328 _ASSERTE(SUCCEEDED(hRes));
329 _Module.Init(ObjectMap, hInstance, &LIBID_VirtualBox);
330 _Module.dwThreadID = GetCurrentThreadId();
331
332 if (!fRun)
333 {
334 if (fUnregister)
335 {
336 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
337 nRet = _Module.UnregisterServer(TRUE);
338 }
339 if (fRegister)
340 {
341 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
342 nRet = _Module.RegisterServer(TRUE);
343 }
344 if (!pszPipeName)
345 {
346 Log(("SVCMAIN: Processing Helper request (cmdline=\"%s\")...\n", pszPipeName));
347
348 if (!*pipeName)
349 vrc = VERR_INVALID_PARAMETER;
350
351 if (RT_SUCCESS(vrc))
352 {
353 /* do the helper job */
354 SVCHlpServer server;
355 vrc = server.open(pipeName.c_str());
356 if (RT_SUCCESS(vrc))
357 vrc = server.run();
358 }
359 if (RT_FAILURE(vrc))
360 {
361 Log(("SVCMAIN: Failed to process Helper request (%Rrc).", vrc));
362 nRet = 1;
363 }
364 }
365 }
366 else
367 {
368 _Module.StartMonitor();
369#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
370 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
371 _ASSERTE(SUCCEEDED(hRes));
372 hRes = CoResumeClassObjects();
373#else
374 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
375#endif
376 _ASSERTE(SUCCEEDED(hRes));
377
378 MSG msg;
379 while (GetMessage(&msg, 0, 0, 0))
380 DispatchMessage(&msg);
381
382 _Module.RevokeClassObjects();
383 Sleep(dwPause); //wait for any threads to finish
384 }
385
386 _Module.Term();
387
388 com::Shutdown();
389
390 Log(("SVCMAIN: Returning, COM server process ends.\n"));
391 return nRet;
392}
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