static int vboxClipboardInit (VBOXCLIPBOARDCONTEXT *pCtx) { /* Register the Window Class. */ WNDCLASS wc; wc.style = CS_NOCLOSE; wc.lpfnWndProc = vboxClipboardWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = pCtx->pEnv->hInstance; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); wc.lpszMenuName = NULL; wc.lpszClassName = gachWindowClassName; pCtx->atomWindowClass = RegisterClass (&wc); int rc = VINF_SUCCESS; if (pCtx->atomWindowClass == 0) { rc = VERR_NOT_SUPPORTED; } else { /* Create the window. */ pCtx->hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST, gachWindowClassName, gachWindowClassName, WS_POPUPWINDOW, -200, -200, 100, 100, NULL, NULL, pCtx->pEnv->hInstance, NULL); if (pCtx->hwnd == NULL) { rc = VERR_NOT_SUPPORTED; } else { SetWindowPos(pCtx->hwnd, HWND_TOPMOST, -200, -200, 0, 0, SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE); addToCBChain(pCtx); pCtx->timerRefresh = SetTimer(pCtx->hwnd, 0, 10 * 1000, NULL); } } Log(("VBoxTray: vboxClipboardInit returned with rc = %Rrc\n", rc)); return rc; }
static LRESULT vboxClipboardProcessMsg(VBOXCLIPBOARDCONTEXT *pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT rc = 0; switch (msg) { case WM_CHANGECBCHAIN: { HWND hwndRemoved = (HWND)wParam; HWND hwndNext = (HWND)lParam; Log(("VBoxTray: vboxClipboardProcessMsg: WM_CHANGECBCHAIN: hwndRemoved %p, hwndNext %p, hwnd %p\n", hwndRemoved, hwndNext, pCtx->hwnd)); if (hwndRemoved == pCtx->hwndNextInChain) { /* The window that was next to our in the chain is being removed. * Relink to the new next window. */ pCtx->hwndNextInChain = hwndNext; } else { if (pCtx->hwndNextInChain) { /* Pass the message further. */ DWORD_PTR dwResult; rc = SendMessageTimeout(pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult); if (!rc) rc = (LRESULT) dwResult; } } } break; case WM_DRAWCLIPBOARD: { Log(("VBoxTray: vboxClipboardProcessMsg: WM_DRAWCLIPBOARD, hwnd %p\n", pCtx->hwnd)); if (GetClipboardOwner () != hwnd) { /* Clipboard was updated by another application. */ /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */ int vboxrc = vboxClipboardChanged(pCtx); if (RT_FAILURE(vboxrc)) Log(("VBoxTray: vboxClipboardProcessMsg: vboxClipboardChanged failed, rc = %Rrc\n", vboxrc)); } /* Pass the message to next windows in the clipboard chain. */ SendMessageTimeout(pCtx->hwndNextInChain, msg, wParam, lParam, 0, CBCHAIN_TIMEOUT, NULL); } break; case WM_TIMER: { HWND hViewer = GetClipboardViewer(); /* Re-register ourselves in the clipboard chain if our last ping * timed out or there seems to be no valid chain. */ if (!hViewer || pCtx->fCBChainPingInProcess) { removeFromCBChain(pCtx); addToCBChain(pCtx); } /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be * processed by ourselves to the chain. */ pCtx->fCBChainPingInProcess = TRUE; hViewer = GetClipboardViewer(); if (hViewer) SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pCtx->hwndNextInChain, (LPARAM)pCtx->hwndNextInChain, CBChainPingProc, (ULONG_PTR) pCtx); } break; case WM_CLOSE: { /* Do nothing. Ignore the message. */ } break; case WM_RENDERFORMAT: { /* Insert the requested clipboard format data into the clipboard. */ uint32_t u32Format = 0; UINT format = (UINT)wParam; Log(("VBoxTray: vboxClipboardProcessMsg: WM_RENDERFORMAT, format = %x\n", format)); switch (format) { case CF_UNICODETEXT: u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; break; case CF_DIB: u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP; break; default: if (format >= 0xC000) { TCHAR szFormatName[256]; int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR)); if (cActual) { if (strcmp (szFormatName, "HTML Format") == 0) { u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML; } } } break; } if (u32Format == 0) { /* Unsupported clipboard format is requested. */ Log(("VBoxTray: vboxClipboardProcessMsg: Unsupported clipboard format requested: %ld\n", u32Format)); EmptyClipboard(); } else { const uint32_t cbPrealloc = 4096; /* @todo r=andy Make it dynamic for supporting larger text buffers! */ uint32_t cb = 0; /* Preallocate a buffer, most of small text transfers will fit into it. */ HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc); Log(("VBoxTray: vboxClipboardProcessMsg: Preallocated handle hMem = %p\n", hMem)); if (hMem) { void *pMem = GlobalLock(hMem); Log(("VBoxTray: vboxClipboardProcessMsg: Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cbPrealloc, &cb); Log(("VBoxTray: vboxClipboardProcessMsg: VbglR3ClipboardReadData returned with rc = %Rrc\n", vboxrc)); if (RT_SUCCESS(vboxrc)) { if (cb == 0) { /* 0 bytes returned means the clipboard is empty. * Deallocate the memory and set hMem to NULL to get to * the clipboard empty code path. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else if (cb > cbPrealloc) { GlobalUnlock(hMem); /* The preallocated buffer is too small, adjust the size. */ hMem = GlobalReAlloc(hMem, cb, 0); Log(("VBoxTray: vboxClipboardProcessMsg: Reallocated hMem = %p\n", hMem)); if (hMem) { pMem = GlobalLock(hMem); Log(("VBoxTray: vboxClipboardProcessMsg: Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ uint32_t cbNew = 0; vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cb, &cbNew); Log(("VBoxTray: VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew)); if (RT_SUCCESS (vboxrc) && cbNew <= cb) { cb = cbNew; } else { GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } } else { GlobalFree(hMem); hMem = NULL; } } } if (hMem) { /* pMem is the address of the data. cb is the size of returned data. */ /* Verify the size of returned text, the memory block for clipboard * must have the exact string size. */ if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { size_t cbActual = 0; HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual); if (FAILED (hrc)) { /* Discard invalid data. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else { /* cbActual is the number of bytes, excluding those used * for the terminating null character. */ cb = (uint32_t)(cbActual + 2); } } } if (hMem) { GlobalUnlock(hMem); hMem = GlobalReAlloc(hMem, cb, 0); Log(("VBoxTray: vboxClipboardProcessMsg: Reallocated hMem = %p\n", hMem)); if (hMem) { /* 'hMem' contains the host clipboard data. * size is 'cb' and format is 'format'. */ HANDLE hClip = SetClipboardData(format, hMem); Log(("VBoxTray: vboxClipboardProcessMsg: WM_RENDERFORMAT hClip = %p\n", hClip)); if (hClip) { /* The hMem ownership has gone to the system. Finish the processing. */ break; } /* Cleanup follows. */ } } } if (hMem) GlobalUnlock(hMem); } if (hMem) GlobalFree(hMem); } /* Something went wrong. */ EmptyClipboard(); } } break; case WM_RENDERALLFORMATS: { /* Do nothing. The clipboard formats will be unavailable now, because the * windows is to be destroyed and therefore the guest side becomes inactive. */ if (OpenClipboard(hwnd)) { EmptyClipboard(); CloseClipboard(); } } break; case WM_USER: { /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */ uint32_t u32Formats = (uint32_t)lParam; if (FALSE == OpenClipboard(hwnd)) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: Failed to open clipboard! Last error = %ld\n", GetLastError())); } else { EmptyClipboard(); HANDLE hClip = NULL; if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n")); hClip = SetClipboardData(CF_UNICODETEXT, NULL); } if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n")); hClip = SetClipboardData(CF_DIB, NULL); } if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat ("HTML Format"); Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format)); if (format != 0) { hClip = SetClipboardData(format, NULL); } } CloseClipboard(); Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: hClip = %p, err = %ld\n", hClip, GetLastError ())); } } break; case WM_USER + 1: { /* Send data in the specified format to the host. */ uint32_t u32Formats = (uint32_t)lParam; HANDLE hClip = NULL; if (FALSE == OpenClipboard(hwnd)) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER: Failed to open clipboard! Last error = %ld\n", GetLastError())); } else { int vboxrc; if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { hClip = GetClipboardData(CF_DIB); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_DIB\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { hClip = GetClipboardData(CF_UNICODETEXT); if (hClip != NULL) { LPWSTR uniString = (LPWSTR)GlobalLock(hClip); if (uniString != NULL) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_UNICODETEXT\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat ("HTML Format"); if (format != 0) { hClip = GetClipboardData(format); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { Log(("VBoxTray: vboxClipboardProcessMsg: WM_USER + 1: CF_HTML\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } } CloseClipboard(); } if (hClip == NULL) { /* Requested clipboard format is not available, send empty data. */ VbglR3ClipboardWriteData(pCtx->u32ClientID, 0, NULL, 0); } } break; default: { rc = DefWindowProc(hwnd, msg, wParam, lParam); } } Log(("VBoxTray: vboxClipboardProcessMsg returned with rc = %ld\n", rc)); return rc; }
static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT rc = 0; VBOXCLIPBOARDCONTEXT *pCtx = &g_ctx; switch (msg) { case WM_CHANGECBCHAIN: { Log(("WM_CHANGECBCHAIN\n")); HWND hwndRemoved = (HWND)wParam; HWND hwndNext = (HWND)lParam; if (hwndRemoved == pCtx->hwndNextInChain) { /* The window that was next to our in the chain is being removed. * Relink to the new next window. */ pCtx->hwndNextInChain = hwndNext; } else { if (pCtx->hwndNextInChain) { /* Pass the message further. */ DWORD_PTR dwResult; rc = SendMessageTimeout(pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult); if (!rc) rc = (LRESULT)dwResult; } } } break; case WM_DRAWCLIPBOARD: { Log(("WM_DRAWCLIPBOARD next %p\n", pCtx->hwndNextInChain)); if (GetClipboardOwner () != hwnd) { /* Clipboard was updated by another application. */ vboxClipboardChanged (pCtx); } if (pCtx->hwndNextInChain) { /* Pass the message to next windows in the clipboard chain. */ DWORD_PTR dwResult; rc = SendMessageTimeout(pCtx->hwndNextInChain, msg, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult); if (!rc) rc = dwResult; } } break; case WM_TIMER: { HWND hViewer = GetClipboardViewer(); /* Re-register ourselves in the clipboard chain if our last ping * timed out or there seems to be no valid chain. */ if (!hViewer || pCtx->fCBChainPingInProcess) { removeFromCBChain(pCtx); addToCBChain(pCtx); } /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be * processed by ourselves to the chain. */ pCtx->fCBChainPingInProcess = TRUE; hViewer = GetClipboardViewer(); if (hViewer) SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pCtx->hwndNextInChain, (LPARAM)pCtx->hwndNextInChain, CBChainPingProc, (ULONG_PTR) pCtx); } break; case WM_CLOSE: { /* Do nothing. Ignore the message. */ } break; case WM_RENDERFORMAT: { /* Insert the requested clipboard format data into the clipboard. */ uint32_t u32Format = 0; UINT format = (UINT)wParam; Log(("WM_RENDERFORMAT %d\n", format)); switch (format) { case CF_UNICODETEXT: u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; break; case CF_DIB: u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP; break; default: if (format >= 0xC000) { TCHAR szFormatName[256]; int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR)); if (cActual) { if (strcmp (szFormatName, "HTML Format") == 0) { u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML; } } } break; } if (u32Format == 0 || pCtx->pClient == NULL) { /* Unsupported clipboard format is requested. */ Log(("WM_RENDERFORMAT unsupported format requested or client is not active.\n")); EmptyClipboard (); } else { int vboxrc = vboxClipboardReadDataFromClient (pCtx, u32Format); dprintf(("vboxClipboardReadDataFromClient vboxrc = %d\n", vboxrc)); if ( RT_SUCCESS (vboxrc) && pCtx->pClient->data.pv != NULL && pCtx->pClient->data.cb > 0 && pCtx->pClient->data.u32Format == u32Format) { HANDLE hMem = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClient->data.cb); dprintf(("hMem %p\n", hMem)); if (hMem) { void *pMem = GlobalLock (hMem); dprintf(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem))); if (pMem) { Log(("WM_RENDERFORMAT setting data\n")); if (pCtx->pClient->data.pv) { memcpy (pMem, pCtx->pClient->data.pv, pCtx->pClient->data.cb); RTMemFree (pCtx->pClient->data.pv); pCtx->pClient->data.pv = NULL; } pCtx->pClient->data.cb = 0; pCtx->pClient->data.u32Format = 0; /* The memory must be unlocked before inserting to the Clipboard. */ GlobalUnlock (hMem); /* 'hMem' contains the host clipboard data. * size is 'cb' and format is 'format'. */ HANDLE hClip = SetClipboardData (format, hMem); dprintf(("vboxClipboardHostEvent hClip %p\n", hClip)); if (hClip) { /* The hMem ownership has gone to the system. Nothing to do. */ break; } } GlobalFree (hMem); } } RTMemFree (pCtx->pClient->data.pv); pCtx->pClient->data.pv = NULL; pCtx->pClient->data.cb = 0; pCtx->pClient->data.u32Format = 0; /* Something went wrong. */ EmptyClipboard (); } } break; case WM_RENDERALLFORMATS: { Log(("WM_RENDERALLFORMATS\n")); /* Do nothing. The clipboard formats will be unavailable now, because the * windows is to be destroyed and therefore the guest side becomes inactive. */ if (OpenClipboard (hwnd)) { EmptyClipboard(); CloseClipboard(); } } break; case WM_USER: { if (pCtx->pClient == NULL || pCtx->pClient->fMsgFormats) { /* Host has pending formats message. Ignore the guest announcement, * because host clipboard has more priority. */ break; } /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */ uint32_t u32Formats = (uint32_t)lParam; Log(("WM_USER u32Formats = %02X\n", u32Formats)); if (OpenClipboard (hwnd)) { EmptyClipboard(); Log(("WM_USER emptied clipboard\n")); HANDLE hClip = NULL; if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n")); hClip = SetClipboardData (CF_UNICODETEXT, NULL); } if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n")); hClip = SetClipboardData (CF_DIB, NULL); } if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat ("HTML Format"); dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format)); if (format != 0) { hClip = SetClipboardData (format, NULL); } } CloseClipboard(); dprintf(("window proc WM_USER: hClip %p, err %d\n", hClip, GetLastError ())); } else { dprintf(("window proc WM_USER: failed to open clipboard\n")); } } break; default: { Log(("WM_ %p\n", msg)); rc = DefWindowProc (hwnd, msg, wParam, lParam); } } Log(("WM_ rc %d\n", rc)); return rc; }
DECLCALLBACK(int) VBoxClipboardThread (RTTHREAD ThreadSelf, void *pInstance) { /* Create a window and make it a clipboard viewer. */ int rc = VINF_SUCCESS; LogFlow(("VBoxClipboardThread\n")); VBOXCLIPBOARDCONTEXT *pCtx = &g_ctx; HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL); /* Register the Window Class. */ WNDCLASS wc; wc.style = CS_NOCLOSE; wc.lpfnWndProc = vboxClipboardWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); wc.lpszMenuName = NULL; wc.lpszClassName = gachWindowClassName; ATOM atomWindowClass = RegisterClass (&wc); if (atomWindowClass == 0) { Log(("Failed to register window class\n")); rc = VERR_NOT_SUPPORTED; } else { /* Create the window. */ pCtx->hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST, gachWindowClassName, gachWindowClassName, WS_POPUPWINDOW, -200, -200, 100, 100, NULL, NULL, hInstance, NULL); if (pCtx->hwnd == NULL) { Log(("Failed to create window\n")); rc = VERR_NOT_SUPPORTED; } else { SetWindowPos(pCtx->hwnd, HWND_TOPMOST, -200, -200, 0, 0, SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE); addToCBChain(pCtx); pCtx->timerRefresh = SetTimer(pCtx->hwnd, 0, 10 * 1000, NULL); MSG msg; while (GetMessage(&msg, NULL, 0, 0) && !pCtx->fTerminate) { TranslateMessage(&msg); DispatchMessage(&msg); } } } if (pCtx->hwnd) { removeFromCBChain(pCtx); if (pCtx->timerRefresh) KillTimer(pCtx->hwnd, 0); DestroyWindow (pCtx->hwnd); pCtx->hwnd = NULL; } if (atomWindowClass != 0) { UnregisterClass (gachWindowClassName, hInstance); atomWindowClass = 0; } return 0; }
DECLCALLBACK(int) VBoxClipboardThread (RTTHREAD ThreadSelf, void *pInstance) { /* Create a window and make it a clipboard viewer. */ int rc = VINF_SUCCESS; LogFlow(("VBoxClipboardThread\n")); VBOXCLIPBOARDCONTEXT *pCtx = &g_ctx; HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL); /* Register the Window Class. */ WNDCLASS wc; RT_ZERO(wc); wc.style = CS_NOCLOSE; wc.lpfnWndProc = vboxClipboardWndProc; wc.hInstance = hInstance; wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); wc.lpszClassName = gachWindowClassName; ATOM atomWindowClass = RegisterClass(&wc); if (atomWindowClass == 0) { Log(("Failed to register window class\n")); rc = VERR_NOT_SUPPORTED; } else { /* Create the window. */ pCtx->hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST, gachWindowClassName, gachWindowClassName, WS_POPUPWINDOW, -200, -200, 100, 100, NULL, NULL, hInstance, NULL); if (pCtx->hwnd == NULL) { Log(("Failed to create window\n")); rc = VERR_NOT_SUPPORTED; } else { SetWindowPos(pCtx->hwnd, HWND_TOPMOST, -200, -200, 0, 0, SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE); addToCBChain(pCtx); if (!vboxClipboardIsNewAPI(pCtx)) pCtx->timerRefresh = SetTimer(pCtx->hwnd, 0, 10 * 1000, NULL); MSG msg; BOOL msgret = 0; while ((msgret = GetMessage(&msg, NULL, 0, 0)) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } /* * Window procedure can return error, * but this is exceptional situation * that should be identified in testing */ Assert(msgret >= 0); Log(("VBoxClipboardThread Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message)); } } pCtx->hwnd = NULL; if (atomWindowClass != 0) { UnregisterClass (gachWindowClassName, hInstance); atomWindowClass = 0; } return 0; }