VBoxHook.cpp revision bd22ae3b86e9b0ed466109e988d302674ecf4aee
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync/** @file
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync *
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync * VBoxHook -- Global windows hook dll
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync *
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2010 Oracle Corporation
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync *
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync * available from http://www.virtualbox.org. This file is free software;
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync */
35396ee506ef68dd1c161f1ef2c3c0b68a146ff2vboxsync#include <Windows.h>
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#include <VBoxHook.h>
0758ccd1bec500cced35c8dfe52fcceacc2469d5vboxsync#include <VBox/VBoxGuestLib.h>
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#include <stdio.h>
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
35396ee506ef68dd1c161f1ef2c3c0b68a146ff2vboxsync#pragma data_seg("SHARED")
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncstatic HWINEVENTHOOK hWinEventHook[2] = {0};
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncstatic HWINEVENTHOOK hDesktopEventHook = NULL;
35396ee506ef68dd1c161f1ef2c3c0b68a146ff2vboxsync#pragma data_seg()
35396ee506ef68dd1c161f1ef2c3c0b68a146ff2vboxsync#pragma comment(linker, "/section:SHARED,RWS")
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncstatic HANDLE hWinNotifyEvent = 0;
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncstatic HANDLE hDesktopNotifyEvent = 0;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#ifdef DEBUG
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsyncvoid WriteLog(char *String, ...);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#define dprintf(a) do { WriteLog a; } while (0)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#else
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#define dprintf(a) do {} while (0)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#endif /* DEBUG */
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncstatic void CALLBACK VBoxHandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
35396ee506ef68dd1c161f1ef2c3c0b68a146ff2vboxsync LONG idObject, LONG idChild,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync DWORD dwEventThread, DWORD dwmsEventTime)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync{
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync DWORD dwStyle;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync if ( idObject != OBJID_WINDOW
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync || !hwnd)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync return;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync dwStyle = GetWindowLong(hwnd, GWL_STYLE);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync if (dwStyle & WS_CHILD)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync return;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync switch(event)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync {
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_LOCATIONCHANGE:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync if (!(dwStyle & WS_VISIBLE))
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync return;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_CREATE:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_DESTROY:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_HIDE:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_SHOW:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#ifdef DEBUG
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync switch(event)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync {
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_LOCATIONCHANGE:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync dprintf(("VBoxHandleWinEvent EVENT_OBJECT_LOCATIONCHANGE for window %x\n", hwnd));
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync break;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_CREATE:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync dprintf(("VBoxHandleWinEvent EVENT_OBJECT_CREATE for window %x\n", hwnd));
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync break;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_HIDE:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync dprintf(("VBoxHandleWinEvent EVENT_OBJECT_HIDE for window %x\n", hwnd));
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync break;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_SHOW:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync dprintf(("VBoxHandleWinEvent EVENT_OBJECT_SHOW for window %x\n", hwnd));
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync break;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync case EVENT_OBJECT_DESTROY:
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync dprintf(("VBoxHandleWinEvent EVENT_OBJECT_DESTROY for window %x\n", hwnd));
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync break;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync }
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#endif
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync if (!hWinNotifyEvent)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync {
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync hWinNotifyEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, VBOXHOOK_GLOBAL_WT_EVENT_NAME);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync dprintf(("OpenEvent returned %x (last err=%x)\n", hWinNotifyEvent, GetLastError()));
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync }
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync BOOL ret = SetEvent(hWinNotifyEvent);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync dprintf(("SetEvent %x returned %d (last error %x)\n", hWinNotifyEvent, ret, GetLastError()));
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync break;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync }
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync}
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncstatic void CALLBACK VBoxHandleDesktopEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync LONG idObject, LONG idChild,
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync DWORD dwEventThread, DWORD dwmsEventTime)
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync{
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync if (!hDesktopNotifyEvent)
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync {
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync hDesktopNotifyEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, VBOXHOOK_GLOBAL_DT_EVENT_NAME);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync dprintf(("OpenEvent returned %x (last err=%x)\n", hDesktopNotifyEvent, GetLastError()));
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync }
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync BOOL ret = SetEvent(hDesktopNotifyEvent);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync dprintf(("SetEvent %x returned %d (last error %x)\n", hDesktopNotifyEvent, ret, GetLastError()));
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync}
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncBOOL VBoxHookInstallActiveDesktopTracker(HMODULE hDll)
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync{
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync if (hDesktopEventHook)
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync return TRUE;
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync CoInitialize(NULL);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync hDesktopEventHook = SetWinEventHook(EVENT_SYSTEM_DESKTOPSWITCH, EVENT_SYSTEM_DESKTOPSWITCH,
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync hDll,
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync VBoxHandleDesktopEvent,
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync 0, 0,
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync 0);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync return !!hDesktopEventHook;
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync}
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncBOOL VBoxHookRemoveActiveDesktopTracker()
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync{
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync if (hDesktopEventHook)
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync {
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync UnhookWinEvent(hDesktopEventHook);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync CoUninitialize();
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync }
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync hDesktopEventHook = 0;
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync return TRUE;
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync}
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync/* Install the global message hook */
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncBOOL VBoxHookInstallWindowTracker(HMODULE hDll)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync{
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync if (hWinEventHook[0] || hWinEventHook[1])
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync return TRUE;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync CoInitialize(NULL);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync hWinEventHook[0] = SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync hDll,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync VBoxHandleWinEvent,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync 0, 0,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync WINEVENT_INCONTEXT | WINEVENT_SKIPOWNPROCESS);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync hWinEventHook[1] = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_HIDE,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync hDll,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync VBoxHandleWinEvent,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync 0, 0,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync WINEVENT_INCONTEXT | WINEVENT_SKIPOWNPROCESS);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync return !!hWinEventHook[0];
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync}
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync/* Remove the global message hook */
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsyncBOOL VBoxHookRemoveWindowTracker()
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync{
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync if (hWinEventHook[0] && hWinEventHook[1])
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync {
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync UnhookWinEvent(hWinEventHook[0]);
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync UnhookWinEvent(hWinEventHook[1]);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync CoUninitialize();
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync }
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync hWinEventHook[0] = hWinEventHook[1] = 0;
bd22ae3b86e9b0ed466109e988d302674ecf4aeevboxsync return TRUE;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync}
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#ifdef DEBUG
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#include <VBox/VBoxGuest.h>
35396ee506ef68dd1c161f1ef2c3c0b68a146ff2vboxsync#include <VBox/VMMDev.h>
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsyncstatic char LogBuffer[1024];
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsyncstatic HANDLE gVBoxDriver = INVALID_HANDLE_VALUE;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsyncVBGLR3DECL(int) VbglR3GRPerform(VMMDevRequestHeader *pReq)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync{
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync DWORD cbReturned;
ba2e65ca2c6ee70366bca6b355a22b44899490e7vboxsync DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(pReq->size), pReq, pReq->size,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync pReq, pReq->size, &cbReturned, NULL);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync return VINF_SUCCESS;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync}
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsyncvoid WriteLog(char *pszStr, ...)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync{
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync VMMDevReqLogString *pReq = (VMMDevReqLogString *)LogBuffer;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync int rc;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync /* open VBox guest driver */
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync if (gVBoxDriver == INVALID_HANDLE_VALUE)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync gVBoxDriver = CreateFile(VBOXGUEST_DEVICE_NAME,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync GENERIC_READ | GENERIC_WRITE,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync FILE_SHARE_READ | FILE_SHARE_WRITE,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync NULL,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync OPEN_EXISTING,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync NULL);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync if (gVBoxDriver == INVALID_HANDLE_VALUE)
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync return;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync va_list va;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync va_start(va, pszStr);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync vmmdevInitRequest(&pReq->header, VMMDevReq_LogString);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync vsprintf(pReq->szString, pszStr, va);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync pReq->header.size += strlen(pReq->szString);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync rc = VbglR3GRPerform(&pReq->header);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync va_end (va);
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync return;
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync}
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync
4604ab7d38c2bd2dfc255aa1facffdf81c1c9153vboxsync#endif