VBoxIPC.cpp revision 340134cc37fb7a9b4498a2b13df2fa340a1824c0
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/* $Id$ */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/** @file
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * VboxIPC - IPC thread.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/*
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Copyright (C) 2010 Oracle Corporation
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * available from http://www.virtualbox.org. This file is free software;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * you can redistribute it and/or modify it under the terms of the GNU
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * General Public License (GPL) as published by the Free Software
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <windows.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "VBoxTray.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "VBoxTrayMsg.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "VBoxHelpers.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "VBoxIPC.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <iprt/assert.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <iprt/err.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <VBoxGuestInternal.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynctypedef struct _VBOXIPCCONTEXT
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const VBOXSERVICEENV *pEnv;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync HANDLE hPipe;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync} VBOXIPCCONTEXT, *PVBOXIPCCONTEXT;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define VBOXTRAY_PIPE_BUFSIZE 512
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncstatic VBOXIPCCONTEXT gCtx = {0};
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncint VBoxIPCReadMessage(PVBOXIPCCONTEXT pCtx, BYTE *pMessage, DWORD cbMessage)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int rc = VINF_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync while (RT_SUCCESS(rc))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DWORD dwRead;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!ReadFile(pCtx->hPipe, pMessage, cbMessage, &dwRead, 0))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync rc = RTErrConvertFromWin32(GetLastError());
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (rc == VERR_MORE_DATA)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync rc = VINF_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync pMessage += dwRead;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return rc;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncint VBoxIPCWriteMessage(PVBOXIPCCONTEXT pCtx, BYTE *pMessage, DWORD cbMessage)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int rc = VINF_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync while (RT_SUCCESS(rc))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync DWORD cbWritten;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!WriteFile(pCtx->hPipe, pMessage, cbMessage, &cbWritten, 0))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync rc = RTErrConvertFromWin32(GetLastError());
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync pMessage += cbWritten;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return rc;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
int VBoxIPCPostQuitMessage(PVBOXIPCCONTEXT pCtx)
{
VBOXTRAYIPCHEADER hdr;
hdr.uMsg = VBOXTRAYIPCMSGTYPE_QUIT;
hdr.uVer = 0;
return VBoxIPCWriteMessage(pCtx, (BYTE*)&hdr, sizeof(hdr));
}
/**
* Shows a balloon tooltip message in VBoxTray's
* message area in the Windows main taskbar.
*
* @return IPRT status code.
* @return int
* @param pCtx
* @param uVersion
*/
int VBoxIPCMsgShowBalloonMsg(PVBOXIPCCONTEXT pCtx, UINT uVersion)
{
VBOXTRAYIPCMSG_SHOWBALLOONMSG msg;
int rc = VBoxIPCReadMessage(pCtx,(BYTE*)&msg, sizeof(msg));
if (RT_SUCCESS(rc))
{
hlpShowBalloonTip(gInstance, gToolWindow, ID_TRAYICON,
msg.szBody, msg.szTitle,
msg.uShowMS, msg.uType);
}
return rc;
}
int VBoxIPCInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
{
Log(("VBoxTray: VBoxIPCInit\n"));
*pfStartThread = false;
gCtx.pEnv = pEnv;
SECURITY_ATTRIBUTES sa;
sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!InitializeSecurityDescriptor(sa.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
{
DWORD er = ::GetLastError();
}
if (!SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, TRUE, (PACL)0, FALSE))
{
DWORD er = ::GetLastError();
}
sa.nLength = sizeof sa;
sa.bInheritHandle = TRUE;
int rc = VINF_SUCCESS;
gCtx.hPipe = ::CreateNamedPipe((LPSTR)VBOXTRAY_PIPE_IPC,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
VBOXTRAY_PIPE_BUFSIZE, // output buffer size
VBOXTRAY_PIPE_BUFSIZE, // input buffer size
NMPWAIT_USE_DEFAULT_WAIT,
&sa);
if (gCtx.hPipe == INVALID_HANDLE_VALUE)
{
DWORD dwError = ::GetLastError();
}
else
{
*pfStartThread = true;
*ppInstance = &gCtx;
}
return rc;
}
void VBoxIPCDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
{
Log(("VBoxTray: VBoxIPCDestroy\n"));
PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
AssertPtr(pCtx);
if (pCtx->hPipe)
{
VBoxIPCPostQuitMessage(pCtx);
CloseHandle(pCtx->hPipe);
}
return;
}
/**
* Thread function to wait for and process seamless mode change
* requests
*/
unsigned __stdcall VBoxIPCThread(void *pInstance)
{
Log(("VBoxTray: VBoxIPCThread\n"));
PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
AssertPtr(pCtx);
bool fTerminate = false;
int rc = VINF_SUCCESS;
do
{
DWORD dwErr = ERROR_SUCCESS;
BOOL fConnected = ConnectNamedPipe(pCtx->hPipe, NULL)
? TRUE
: (GetLastError() == ERROR_PIPE_CONNECTED);
/* Are we supposed to stop? */
if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
break;
if (fConnected)
{
VBOXTRAYIPCHEADER hdr;
DWORD read = 0;
if (!ReadFile(pCtx->hPipe, &hdr, sizeof(hdr), &read, 0))
dwErr = GetLastError();
/** @todo We might want to spawn a thread per connected client
* in order to perform longer tasks. */
if (SUCCEEDED(dwErr))
{
switch (hdr.uMsg)
{
case VBOXTRAYIPCMSGTYPE_SHOWBALLOONMSG:
rc = VBoxIPCMsgShowBalloonMsg(pCtx, hdr.uVer);
break;
/* Someone asked us to quit ... */
case VBOXTRAYIPCMSGTYPE_QUIT:
fTerminate = true;
break;
default:
break;
}
}
/* Disconnect the client from the pipe. */
DisconnectNamedPipe(pCtx->hPipe);
}
else
CloseHandle(pCtx->hPipe);
/* Sleep a bit to not eat too much CPU in case the above call always fails. */
if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
{
fTerminate = true;
break;
}
} while (!fTerminate);
Log(("VBoxTray: VBoxIPCThread exited\n"));
return 0;
}