VirtualBox

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

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

Main/win/svcmain.cpp: Switch to the user's home directory if VBoxSVC is started through COM. Avoids dropping debug log files in the system32 directory. On manual start the current directory isn't changed.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.7 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.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 <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/initterm.h>
33#include <iprt/path.h>
34
35#include <atlbase.h>
36#include <atlcom.h>
37
38#define _ATL_FREE_THREADED
39
40class CExeModule : public CComModule
41{
42public:
43 LONG Unlock();
44 DWORD dwThreadID;
45 HANDLE hEventShutdown;
46 void MonitorShutdown();
47 bool StartMonitor();
48 bool bActivity;
49};
50
51const DWORD dwTimeOut = 5000; /* time for EXE to be idle before shutting down */
52const DWORD dwPause = 1000; /* time to wait for threads to finish up */
53
54/* Passed to CreateThread to monitor the shutdown event */
55static DWORD WINAPI MonitorProc(void* pv)
56{
57 CExeModule* p = (CExeModule*)pv;
58 p->MonitorShutdown();
59 return 0;
60}
61
62LONG CExeModule::Unlock()
63{
64 LONG l = CComModule::Unlock();
65 if (l == 0)
66 {
67 bActivity = true;
68 SetEvent(hEventShutdown); /* tell monitor that we transitioned to zero */
69 }
70 return l;
71}
72
73/* Monitors the shutdown event */
74void CExeModule::MonitorShutdown()
75{
76 while (1)
77 {
78 WaitForSingleObject(hEventShutdown, INFINITE);
79 DWORD dwWait=0;
80 do
81 {
82 bActivity = false;
83 dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
84 } while (dwWait == WAIT_OBJECT_0);
85 /* timed out */
86 if (!bActivity && m_nLockCnt == 0) /* if no activity let's really bail */
87 {
88#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
89 CoSuspendClassObjects();
90 if (!bActivity && m_nLockCnt == 0)
91#endif
92 break;
93 }
94 }
95 CloseHandle(hEventShutdown);
96 PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
97}
98
99bool CExeModule::StartMonitor()
100{
101 hEventShutdown = CreateEvent(NULL, false, false, NULL);
102 if (hEventShutdown == NULL)
103 return false;
104 DWORD dwThreadID;
105 HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);
106 return (h != NULL);
107}
108
109CExeModule _Module;
110
111BEGIN_OBJECT_MAP(ObjectMap)
112 OBJECT_ENTRY(CLSID_VirtualBox, VirtualBox)
113END_OBJECT_MAP()
114
115
116LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
117{
118 while (p1 != NULL && *p1 != NULL)
119 {
120 LPCTSTR p = p2;
121 while (p != NULL && *p != NULL)
122 {
123 if (*p1 == *p)
124 return CharNext(p1);
125 p = CharNext(p);
126 }
127 p1 = CharNext(p1);
128 }
129 return NULL;
130}
131
132static int WordCmpI(LPCTSTR psz1, LPCTSTR psz2) throw()
133{
134 TCHAR c1 = (TCHAR)CharUpper((LPTSTR)*psz1);
135 TCHAR c2 = (TCHAR)CharUpper((LPTSTR)*psz2);
136 while (c1 != NULL && c1 == c2 && c1 != ' ' && c1 != '\t')
137 {
138 psz1 = CharNext(psz1);
139 psz2 = CharNext(psz2);
140 c1 = (TCHAR)CharUpper((LPTSTR)*psz1);
141 c2 = (TCHAR)CharUpper((LPTSTR)*psz2);
142 }
143 if ((c1 == NULL || c1 == ' ' || c1 == '\t') && (c2 == NULL || c2 == ' ' || c2 == '\t'))
144 return 0;
145
146 return (c1 < c2) ? -1 : 1;
147}
148
149/////////////////////////////////////////////////////////////////////////////
150//
151extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
152 HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
153{
154 lpCmdLine = GetCommandLine(); /* this line necessary for _ATL_MIN_CRT */
155
156 /* Need to parse the command line before initializing the VBox runtime. */
157 TCHAR szTokens[] = _T("-/");
158 LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
159 while (lpszToken != NULL)
160 {
161 if (WordCmpI(lpszToken, _T("Embedding")) == 0)
162 {
163 /* %HOMEDRIVE%%HOMEPATH% */
164 wchar_t wszHome[RTPATH_MAX];
165 DWORD cEnv = GetEnvironmentVariable(L"HOMEDRIVE", &wszHome[0], RTPATH_MAX);
166 if (cEnv && cEnv < RTPATH_MAX)
167 {
168 DWORD cwc = cEnv; /* doesn't include NUL */
169 cEnv = GetEnvironmentVariable(L"HOMEPATH", &wszHome[cEnv], RTPATH_MAX - cwc);
170 if (cEnv && cEnv < RTPATH_MAX - cwc)
171 {
172 /* If this fails there is nothing we can do. Ignore. */
173 SetCurrentDirectory(wszHome);
174 }
175 }
176 }
177
178 lpszToken = FindOneOf(lpszToken, szTokens);
179 }
180
181 /*
182 * Initialize the VBox runtime without loading
183 * the support driver.
184 */
185 RTR3Init();
186
187 HRESULT hRes = com::Initialize();
188
189 _ASSERTE(SUCCEEDED(hRes));
190 _Module.Init(ObjectMap, hInstance, &LIBID_VirtualBox);
191 _Module.dwThreadID = GetCurrentThreadId();
192
193 int nRet = 0;
194 BOOL bRun = TRUE;
195 lpszToken = FindOneOf(lpCmdLine, szTokens);
196 while (lpszToken != NULL)
197 {
198 if (WordCmpI(lpszToken, _T("UnregServer")) == 0)
199 {
200 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
201 nRet = _Module.UnregisterServer(TRUE);
202 bRun = FALSE;
203 break;
204 }
205 else if (WordCmpI(lpszToken, _T("RegServer")) == 0)
206 {
207 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
208 nRet = _Module.RegisterServer(TRUE);
209 bRun = FALSE;
210 break;
211 }
212 else if (WordCmpI(lpszToken, _T("ReregServer")) == 0)
213 {
214 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
215 nRet = _Module.UnregisterServer(TRUE);
216 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
217 nRet = _Module.RegisterServer(TRUE);
218 bRun = FALSE;
219 break;
220 }
221 else if ( (WordCmpI(lpszToken, _T("h")) == 0)
222 || (WordCmpI(lpszToken, _T("?")) == 0))
223 {
224 TCHAR txt[]= L"Options:\n\n"
225 L"/RegServer:\tregister COM out-of-proc server\n"
226 L"/UnregServer:\tunregister COM out-of-proc server\n"
227 L"/ReregServer:\tunregister and register COM server\n"
228 L"no options:\trun the server";
229 TCHAR title[]=_T("Usage");
230 nRet = -1;
231 bRun = FALSE;
232 MessageBox(NULL, txt, title, MB_OK);
233 break;
234 }
235 else if (WordCmpI (lpszToken, _T("Helper")) == 0)
236 {
237 Log (("SVCMAIN: Processing Helper request (cmdline=\"%ls\")...\n",
238 lpszToken + 6));
239
240 TCHAR szTokens[] = _T (" \t");
241
242 int vrc = VINF_SUCCESS;
243 Utf8Str pipeName;
244
245 lpszToken = FindOneOf (lpszToken, szTokens);
246 if (lpszToken)
247 {
248 while (*lpszToken != NULL &&
249 (*lpszToken == ' ' || *lpszToken == '\t'))
250 ++ lpszToken;
251
252 if (*lpszToken != NULL)
253 pipeName = Utf8Str(lpszToken);
254 }
255
256 if (pipeName.isEmpty())
257 vrc = VERR_INVALID_PARAMETER;
258
259 if (RT_SUCCESS(vrc))
260 {
261 /* do the helper job */
262 SVCHlpServer server;
263 vrc = server.open(pipeName.c_str());
264 if (RT_SUCCESS(vrc))
265 vrc = server.run();
266 }
267 if (RT_FAILURE(vrc))
268 {
269 Utf8Str err = Utf8StrFmt (
270 "Failed to process Helper request (%Rrc).", vrc);
271 Log (("SVCMAIN: %s\n", err.c_str()));
272 }
273
274 /* don't run the COM server */
275 bRun = FALSE;
276 break;
277 }
278
279 lpszToken = FindOneOf(lpszToken, szTokens);
280 }
281
282 if (bRun)
283 {
284 _Module.StartMonitor();
285#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
286 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
287 _ASSERTE(SUCCEEDED(hRes));
288 hRes = CoResumeClassObjects();
289#else
290 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
291#endif
292 _ASSERTE(SUCCEEDED(hRes));
293
294 MSG msg;
295 while (GetMessage(&msg, 0, 0, 0))
296 DispatchMessage(&msg);
297
298 _Module.RevokeClassObjects();
299 Sleep(dwPause); //wait for any threads to finish
300 }
301
302 _Module.Term();
303
304 com::Shutdown();
305
306 Log(("SVCMAIN: Returning, COM server process ends.\n"));
307 return nRet;
308}
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