VirtualBox

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

Last change on this file since 45434 was 41041, checked in by vboxsync, 13 years ago

Main: fix COM server build error

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