VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.cpp@ 46757

Last change on this file since 46757 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.3 KB
Line 
1/* $Id: VBoxIPC.cpp 44529 2013-02-04 15:54:15Z vboxsync $ */
2/** @file
3 * VboxIPC - IPC thread.
4 */
5
6/*
7 * Copyright (C) 2010-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#include <windows.h>
18#include "VBoxTray.h"
19#include "VBoxTrayMsg.h"
20#include "VBoxHelpers.h"
21#include "VBoxIPC.h"
22
23#include <iprt/assert.h>
24#include <iprt/err.h>
25#include <iprt/mem.h>
26#include <VBoxGuestInternal.h>
27
28
29typedef struct _VBOXIPCCONTEXT
30{
31 const VBOXSERVICEENV *pEnv;
32 HANDLE hPipe;
33
34} VBOXIPCCONTEXT, *PVBOXIPCCONTEXT;
35
36static VBOXIPCCONTEXT gCtx = {0};
37
38
39/**
40 * Reads an IPC message from a connected client, represented by the IPC
41 * context.
42 *
43 * @return IPRT status code.
44 * @param pCtx The IPC context.
45 * @param pMessage Buffer for receiving the message to be read.
46 * @param cbMessage Size (in bytes) of buffer for received message.
47 */
48int VBoxIPCReadMessage(PVBOXIPCCONTEXT pCtx, BYTE *pMessage, DWORD cbMessage)
49{
50 int rc = VINF_SUCCESS;
51 do
52 {
53 DWORD dwRead;
54 if (!ReadFile(pCtx->hPipe, pMessage, cbMessage, &dwRead, 0))
55 {
56 rc = RTErrConvertFromWin32(GetLastError());
57 }
58 else
59 {
60 if (rc == VERR_MORE_DATA)
61 rc = VINF_SUCCESS;
62 pMessage += dwRead;
63 cbMessage -= dwRead;
64 }
65 }
66 while (cbMessage && RT_SUCCESS(rc));
67 return rc;
68}
69
70/**
71 * Skips an IPC message by reading out the outstanding message
72 * body to discard it.
73 *
74 * @return IPRT status code.
75 * @param pCtx The IPC context.
76 * @param pHdr The header of message to skip.
77 */
78int VBoxIPCSkipMessage(PVBOXIPCCONTEXT pCtx, PVBOXTRAYIPCHEADER pHdr)
79{
80 Assert(pHdr->cbBody);
81 BYTE *pbBuf = (BYTE*)RTMemAlloc(pHdr->cbBody);
82 if (!pbBuf)
83 return VERR_NO_MEMORY;
84 int rc = VBoxIPCReadMessage(pCtx, pbBuf, pHdr->cbBody);
85 RTMemFree(pbBuf);
86 return rc;
87}
88
89/**
90 * Writes an IPC message to the IPC context's client.
91 *
92 * @return IPRT status code.
93 * @param pCtx The IPC context.
94 * @param pMessage Pointer to message to send.
95 * @param cbMessage Size (in bytes) of message to send.
96 */
97int VBoxIPCWriteMessage(PVBOXIPCCONTEXT pCtx, BYTE *pMessage, DWORD cbMessage)
98{
99 int rc = VINF_SUCCESS;
100 while (RT_SUCCESS(rc))
101 {
102 DWORD cbWritten;
103 if (!WriteFile(pCtx->hPipe, pMessage, cbMessage, &cbWritten, 0))
104 rc = RTErrConvertFromWin32(GetLastError());
105 pMessage += cbWritten;
106 }
107 return rc;
108}
109
110int VBoxIPCPostQuitMessage(PVBOXIPCCONTEXT pCtx)
111{
112 VBOXTRAYIPCHEADER hdr;
113 hdr.ulMsg = VBOXTRAYIPCMSGTYPE_IPC_QUIT;
114 return VBoxIPCWriteMessage(pCtx, (BYTE*)&hdr, sizeof(hdr));
115}
116
117/**
118 * Shows a balloon tooltip message in VBoxTray's
119 * message area in the Windows main taskbar.
120 *
121 * @return IPRT status code.
122 * @param pCtx IPC context of the caller.
123 * @param wParam wParam of received IPC message.
124 * @param lParam lParam of received IPC message.
125 */
126int VBoxIPCMsgShowBalloonMsg(PVBOXIPCCONTEXT pCtx, UINT wParam, UINT lParam)
127{
128 VBOXTRAYIPCMSG_SHOWBALLOONMSG msg;
129 int rc = VBoxIPCReadMessage(pCtx,(BYTE*)&msg, sizeof(msg));
130 if (RT_SUCCESS(rc))
131 {
132 hlpShowBalloonTip(ghInstance, ghwndToolWindow, ID_TRAYICON,
133 msg.szContent, msg.szTitle,
134 msg.ulShowMS, msg.ulType);
135 }
136 return rc;
137}
138
139/**
140 * Takes action to restart VBoxTray (this application).
141 *
142 * @return IPRT status code.
143 * @param pCtx IPC context of the caller.
144 * @param wParam wParam of received IPC message.
145 * @param lParam lParam of received IPC message.
146 */
147int VBoxIPCMsgRestart(PVBOXIPCCONTEXT pCtx, UINT wParam, UINT lParam)
148{
149 return 0;
150}
151
152/**
153 * Initializes the IPC communication.
154 *
155 * @return IPRT status code.
156 * @param pEnv The IPC service's environment.
157 * @param ppInstance The instance pointer which refer to this object.
158 * @param pfStartThread Pointer to flag whether the IPC service can be started or not.
159 */
160int VBoxIPCInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
161{
162 Log(("VBoxTray: VBoxIPCInit\n"));
163
164 *pfStartThread = false;
165 gCtx.pEnv = pEnv;
166
167 int rc = VINF_SUCCESS;
168 SECURITY_ATTRIBUTES sa;
169 sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)RTMemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
170 if (!sa.lpSecurityDescriptor)
171 rc = VERR_NO_MEMORY;
172 else
173 {
174 if (!InitializeSecurityDescriptor(sa.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
175 rc = RTErrConvertFromWin32(GetLastError());
176 else
177 {
178 if (!SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, TRUE, (PACL)0, FALSE))
179 rc = RTErrConvertFromWin32(GetLastError());
180 else
181 {
182 sa.nLength = sizeof(sa);
183 sa.bInheritHandle = TRUE;
184 }
185 }
186
187 if (RT_SUCCESS(rc))
188 {
189 gCtx.hPipe = CreateNamedPipe((LPSTR)VBOXTRAY_PIPE_IPC,
190 PIPE_ACCESS_DUPLEX,
191 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
192 PIPE_UNLIMITED_INSTANCES,
193 VBOXTRAY_PIPE_IPC_BUFSIZE, /* Output buffer size. */
194 VBOXTRAY_PIPE_IPC_BUFSIZE, /* Input buffer size. */
195 NMPWAIT_USE_DEFAULT_WAIT,
196 &sa);
197 if (gCtx.hPipe == INVALID_HANDLE_VALUE)
198 rc = RTErrConvertFromWin32(GetLastError());
199 else
200 {
201 *pfStartThread = true;
202 *ppInstance = &gCtx;
203 }
204 }
205 RTMemFree(sa.lpSecurityDescriptor);
206 }
207 return rc;
208}
209
210
211void VBoxIPCDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
212{
213 Log(("VBoxTray: VBoxIPCDestroy\n"));
214
215 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
216 AssertPtr(pCtx);
217
218 if (pCtx->hPipe)
219 {
220 VBoxIPCPostQuitMessage(pCtx);
221 CloseHandle(pCtx->hPipe);
222 }
223 return;
224}
225
226/**
227 * Thread function to wait for and process seamless mode change
228 * requests
229 */
230unsigned __stdcall VBoxIPCThread(void *pInstance)
231{
232 Log(("VBoxTray: VBoxIPCThread\n"));
233
234 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
235 AssertPtr(pCtx);
236
237 bool fTerminate = false;
238 int rc = VINF_SUCCESS;
239
240 do
241 {
242 DWORD dwErr = ERROR_SUCCESS;
243 BOOL fConnected = ConnectNamedPipe(pCtx->hPipe, NULL)
244 ? TRUE
245 : (GetLastError() == ERROR_PIPE_CONNECTED);
246
247 /* Are we supposed to stop? */
248 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
249 break;
250
251 if (fConnected)
252 {
253 VBOXTRAYIPCHEADER hdr;
254 DWORD read = 0;
255
256 if (!ReadFile(pCtx->hPipe, &hdr, sizeof(hdr), &read, 0))
257 dwErr = GetLastError();
258
259 /** @todo We might want to spawn a thread per connected client
260 * in order to perform longer tasks. */
261
262 if (SUCCEEDED(dwErr))
263 {
264 Log(("VBoxTray: VBoxIPCThread: Received message %ld ...\n", hdr.ulMsg));
265 switch (hdr.ulMsg)
266 {
267 case VBOXTRAYIPCMSGTYPE_RESTART:
268 rc = VBoxIPCMsgRestart(pCtx, hdr.wParam, hdr.lParam);
269 if (RT_SUCCESS(rc))
270 fTerminate = true;
271 break;
272
273 case VBOXTRAYIPCMSGTYPE_IPC_QUIT:
274 fTerminate = true;
275 break;
276
277 case VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG:
278 rc = VBoxIPCMsgShowBalloonMsg(pCtx, hdr.wParam, hdr.lParam);
279 break;
280
281 default:
282 /* Unknown message received, try to receive the body and
283 * just skip it. */
284 Log(("VBoxTray: VBoxIPCThread: Unknown message %ld, skipping ...\n", hdr.ulMsg));
285 if (hdr.cbBody)
286 rc = VBoxIPCSkipMessage(pCtx, &hdr);
287 break;
288 }
289 }
290
291 /* Disconnect the client from the pipe. */
292 DisconnectNamedPipe(pCtx->hPipe);
293 }
294 else
295 CloseHandle(pCtx->hPipe);
296
297 /* Sleep a bit to not eat too much CPU in case the above call always fails. */
298 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
299 fTerminate = true;
300 if (fTerminate)
301 Log(("VBoxTray: VBoxIPCThread: Terminating ...\n"));
302 } while (!fTerminate);
303
304 Log(("VBoxTray: VBoxIPCThread exited\n"));
305 return 0;
306}
307
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