VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxHelpers.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
RevLine 
[55401]1/* $Id: VBoxHelpers.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
[3260]2/** @file
3 * helpers - Guest Additions Service helper functions
4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[3260]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[3260]26 */
27
[62679]28#include <iprt/win/windows.h>
[3260]29
[23053]30#include <iprt/string.h>
[69361]31#include <iprt/alloca.h>
[78937]32#include <iprt/system.h>
[95827]33#include <iprt/utf16.h>
[35863]34#include <VBox/Log.h>
[23053]35#include <VBox/VBoxGuestLib.h>
36
[33966]37#include "VBoxHelpers.h"
[3260]38
[34025]39
[35907]40int hlpReportStatus(VBoxGuestFacilityStatus statusCurrent)
[35863]41{
[35907]42 int rc = VbglR3ReportAdditionsStatus(VBoxGuestFacilityType_VBoxTrayClient,
[35863]43 statusCurrent,
44 0 /* Flags */);
45 if (RT_FAILURE(rc))
46 Log(("VBoxTray: Could not report VBoxTray status \"%ld\", rc=%Rrc\n", statusCurrent, rc));
47 return rc;
48}
[34025]49
50/**
51 * Attempt to force Windows to reload the cursor image by attaching to the
52 * thread of the window currently under the mouse, hiding the cursor and
53 * showing it again. This could fail to work in any number of ways (no
54 * window under the cursor, the cursor has moved to a different window while
55 * we are processing), but we just accept this, as the cursor will be reloaded
56 * at some point anyway.
57 */
58void hlpReloadCursor(void)
59{
60 POINT mousePos;
[63100]61 GetCursorPos(&mousePos);
[34025]62
[63100]63 DWORD hThread = 0; /* Shut up MSC */
64 DWORD hCurrentThread = 0; /* Ditto */
65 HWND hWin = WindowFromPoint(mousePos);
[34025]66 if (hWin)
67 {
68 hThread = GetWindowThreadProcessId(hWin, NULL);
69 hCurrentThread = GetCurrentThreadId();
70 if (hCurrentThread != hThread)
71 AttachThreadInput(hCurrentThread, hThread, TRUE);
72 }
[63100]73
[34025]74 ShowCursor(false);
75 ShowCursor(true);
[63100]76
77 if (hWin && hCurrentThread != hThread)
[34025]78 AttachThreadInput(hCurrentThread, hThread, FALSE);
79}
80
[33966]81static unsigned hlpNextAdjacentRectXP(RECTL *paRects, unsigned nRects, unsigned uRect)
[3260]82{
83 unsigned i;
84 for (i = 0; i < nRects; i++)
85 {
[33966]86 if (paRects[uRect].right == paRects[i].left)
[3260]87 return i;
88 }
[63100]89 return ~0U;
[3260]90}
91
[33966]92static unsigned hlpNextAdjacentRectXN(RECTL *paRects, unsigned nRects, unsigned uRect)
[3260]93{
94 unsigned i;
95 for (i = 0; i < nRects; i++)
96 {
[33966]97 if (paRects[uRect].left == paRects[i].right)
[3260]98 return i;
99 }
[63100]100 return ~0U;
[3260]101}
102
[33966]103static unsigned hlpNextAdjacentRectYP(RECTL *paRects, unsigned nRects, unsigned uRect)
[3260]104{
105 unsigned i;
106 for (i = 0; i < nRects; i++)
107 {
[33966]108 if (paRects[uRect].bottom == paRects[i].top)
[3260]109 return i;
110 }
[63100]111 return ~0U;
[3260]112}
113
[33966]114static unsigned hlpNextAdjacentRectYN(RECTL *paRects, unsigned nRects, unsigned uRect)
[3260]115{
116 unsigned i;
117 for (i = 0; i < nRects; i++)
118 {
[33966]119 if (paRects[uRect].top == paRects[i].bottom)
[3260]120 return i;
121 }
[63100]122 return ~0U;
[3260]123}
124
[33966]125void hlpResizeRect(RECTL *paRects, unsigned nRects, unsigned uPrimary,
[48070]126 unsigned uResized, int iNewWidth, int iNewHeight,
127 int iNewPosX, int iNewPosY)
[3260]128{
[95964]129 Log4Func(("nRects %d, iPrimary %d, iResized %d, NewWidth %d, NewHeight %d\n", nRects, uPrimary, uResized, iNewWidth, iNewHeight));
[27164]130
[3260]131 RECTL *paNewRects = (RECTL *)alloca (sizeof (RECTL) * nRects);
132 memcpy (paNewRects, paRects, sizeof (RECTL) * nRects);
[33966]133 paNewRects[uResized].right += iNewWidth - (paNewRects[uResized].right - paNewRects[uResized].left);
134 paNewRects[uResized].bottom += iNewHeight - (paNewRects[uResized].bottom - paNewRects[uResized].top);
[48070]135 paNewRects[uResized].right += iNewPosX - paNewRects[uResized].left;
136 paNewRects[uResized].bottom += iNewPosY - paNewRects[uResized].top;
137 paNewRects[uResized].left = iNewPosX;
138 paNewRects[uResized].top = iNewPosY;
[23053]139
140 /* Verify all pairs of originally adjacent rectangles for all 4 directions.
[3260]141 * If the pair has a "good" delta (that is the first rectangle intersects the second)
142 * at a direction and the second rectangle is not primary one (which can not be moved),
143 * move the second rectangle to make it adjacent to the first one.
144 */
[23053]145
[3260]146 /* X positive. */
147 unsigned iRect;
148 for (iRect = 0; iRect < nRects; iRect++)
149 {
150 /* Find the next adjacent original rect in x positive direction. */
[33966]151 unsigned iNextRect = hlpNextAdjacentRectXP(paRects, nRects, iRect);
[95964]152 Log4Func(("next %d -> %d\n", iRect, iNextRect));
[23053]153
[33966]154 if (iNextRect == ~0 || iNextRect == uPrimary)
[3260]155 {
156 continue;
157 }
[23053]158
[33540]159 /* Check whether there is an X intersection between these adjacent rects in the new rectangles
[3260]160 * and fix the intersection if delta is "good".
161 */
162 int delta = paNewRects[iRect].right - paNewRects[iNextRect].left;
[23053]163
[27164]164 if (delta != 0)
[3260]165 {
[95964]166 Log4Func(("XP intersection right %d left %d, diff %d\n",
167 paNewRects[iRect].right, paNewRects[iNextRect].left,
168 delta));
[23053]169
[3260]170 paNewRects[iNextRect].left += delta;
171 paNewRects[iNextRect].right += delta;
172 }
173 }
[23053]174
[3260]175 /* X negative. */
176 for (iRect = 0; iRect < nRects; iRect++)
177 {
178 /* Find the next adjacent original rect in x negative direction. */
[33966]179 unsigned iNextRect = hlpNextAdjacentRectXN(paRects, nRects, iRect);
[95964]180 Log4Func(("next %d -> %d\n", iRect, iNextRect));
[23053]181
[33966]182 if (iNextRect == ~0 || iNextRect == uPrimary)
[3260]183 {
184 continue;
185 }
[23053]186
[33540]187 /* Check whether there is an X intersection between these adjacent rects in the new rectangles
[3260]188 * and fix the intersection if delta is "good".
189 */
190 int delta = paNewRects[iRect].left - paNewRects[iNextRect].right;
[23053]191
[27164]192 if (delta != 0)
[3260]193 {
[95964]194 Log4Func(("XN intersection left %d right %d, diff %d\n",
195 paNewRects[iRect].left, paNewRects[iNextRect].right,
196 delta));
[23053]197
[3260]198 paNewRects[iNextRect].left += delta;
199 paNewRects[iNextRect].right += delta;
200 }
201 }
[23053]202
[33540]203 /* Y positive (in the computer sense, top->down). */
[3260]204 for (iRect = 0; iRect < nRects; iRect++)
205 {
206 /* Find the next adjacent original rect in y positive direction. */
[33966]207 unsigned iNextRect = hlpNextAdjacentRectYP(paRects, nRects, iRect);
[95964]208 Log4Func(("next %d -> %d\n", iRect, iNextRect));
[23053]209
[33966]210 if (iNextRect == ~0 || iNextRect == uPrimary)
[3260]211 {
212 continue;
213 }
[23053]214
[33540]215 /* Check whether there is an Y intersection between these adjacent rects in the new rectangles
[3260]216 * and fix the intersection if delta is "good".
217 */
218 int delta = paNewRects[iRect].bottom - paNewRects[iNextRect].top;
[23053]219
[27164]220 if (delta != 0)
[3260]221 {
[95964]222 Log4Func(("YP intersection bottom %d top %d, diff %d\n",
223 paNewRects[iRect].bottom, paNewRects[iNextRect].top,
224 delta));
[23053]225
[3260]226 paNewRects[iNextRect].top += delta;
227 paNewRects[iNextRect].bottom += delta;
228 }
229 }
[23053]230
[33540]231 /* Y negative (in the computer sense, down->top). */
[3260]232 for (iRect = 0; iRect < nRects; iRect++)
233 {
234 /* Find the next adjacent original rect in x negative direction. */
[33966]235 unsigned iNextRect = hlpNextAdjacentRectYN(paRects, nRects, iRect);
[95964]236 Log4Func(("next %d -> %d\n", iRect, iNextRect));
[23053]237
[33966]238 if (iNextRect == ~0 || iNextRect == uPrimary)
[3260]239 {
240 continue;
241 }
[23053]242
[33540]243 /* Check whether there is an Y intersection between these adjacent rects in the new rectangles
[3260]244 * and fix the intersection if delta is "good".
245 */
246 int delta = paNewRects[iRect].top - paNewRects[iNextRect].bottom;
[23053]247
[27164]248 if (delta != 0)
[3260]249 {
[95964]250 Log4Func(("YN intersection top %d bottom %d, diff %d\n",
251 paNewRects[iRect].top, paNewRects[iNextRect].bottom,
252 delta));
[23053]253
[3260]254 paNewRects[iNextRect].top += delta;
255 paNewRects[iNextRect].bottom += delta;
256 }
257 }
[23053]258
[61620]259 /* Primary rectangle must remain at 0,0. */
260 int32_t iOffsetX = paNewRects[uPrimary].left;
261 int32_t iOffsetY = paNewRects[uPrimary].top;
262 for (iRect = 0; iRect < nRects; iRect++)
263 {
264 paRects[iRect].left = paNewRects[iRect].left - iOffsetX;
265 paRects[iRect].right = paNewRects[iRect].right - iOffsetX;
266 paRects[iRect].top = paNewRects[iRect].top - iOffsetY;
267 paRects[iRect].bottom = paNewRects[iRect].bottom - iOffsetY;
[95964]268 Log4Func((" [%d]: %d,%d %dx%d -> %d,%d %dx%d%s\n",
269 iRect,
270 paRects[iRect].left, paRects[iRect].top,
271 paRects[iRect].right - paRects[iRect].left,
272 paRects[iRect].bottom - paRects[iRect].top,
273 paNewRects[iRect].left, paNewRects[iRect].top,
274 paNewRects[iRect].right - paNewRects[iRect].left,
275 paNewRects[iRect].bottom - paNewRects[iRect].top,
276 iRect == uPrimary? " <- primary": ""));
[61620]277 }
[3260]278 return;
279}
[23053]280
[33966]281int hlpShowBalloonTip(HINSTANCE hInst, HWND hWnd, UINT uID,
282 const char *pszMsg, const char *pszTitle,
283 UINT uTimeout, DWORD dwInfoFlags)
[23053]284{
285 NOTIFYICONDATA niData;
[34025]286 ZeroMemory(&niData, sizeof(NOTIFYICONDATA));
[23053]287 niData.cbSize = sizeof(NOTIFYICONDATA);
[34025]288 niData.uFlags = NIF_INFO; /* Display a balloon notification. */
[23053]289 niData.hWnd = hWnd;
290 niData.uID = uID;
[34025]291 /* If not timeout set, set it to 5sec. */
292 if (uTimeout == 0)
293 uTimeout = 5000;
[23053]294 niData.uTimeout = uTimeout;
[34025]295 /* If no info flag (info, warning, error) set,
296 * set it to info by default. */
[23053]297 if (dwInfoFlags == 0)
298 dwInfoFlags = NIIF_INFO;
299 niData.dwInfoFlags = dwInfoFlags;
300
[34025]301 /* Do we want to have */
[23053]302
[34025]303 /* Is the current OS supported (at least WinXP) for displaying
304 * our own icon and do we actually *want* to display our own stuff? */
[78937]305 uint64_t const uNtVersion = RTSystemGetNtVersion();
306 if ( uNtVersion >= RTSYSTEM_MAKE_NT_VERSION(5, 0, 0)
[34025]307 && (dwInfoFlags & NIIF_INFO))
[23053]308 {
[34025]309 /* Load (or retrieve handle of) the app's icon. */
[83072]310 HICON hIcon = LoadIcon(hInst, "IDI_ICON1"); /* see Artwork/win/TemplateR3.rc */
[34025]311 if (hIcon)
312 niData.dwInfoFlags = NIIF_USER; /* Use an own notification icon. */
313
[78937]314 if (uNtVersion >= RTSYSTEM_MAKE_NT_VERSION(5, 1, 0)) /* WinXP. */
[23053]315 {
[34025]316 /* Use an own icon instead of the default one. */
317 niData.hIcon = hIcon;
[23053]318 }
[78937]319 else if (uNtVersion >= RTSYSTEM_MAKE_NT_VERSION(6, 0, 0)) /* Vista and up. */
[23053]320 {
[34025]321 /* Use an own icon instead of the default one. */
322 niData.dwInfoFlags |= NIIF_LARGE_ICON; /* Use a large icon if available! */
323 niData.hIcon = hIcon;
324 niData.hBalloonIcon = hIcon;
[23053]325 }
326 }
[34025]327 else
328 {
329 /* This might be a warning, error message or a to old OS. Use the
330 * standard icons provided by Windows (if any). */
331 }
[23053]332
[34025]333 strcpy(niData.szInfo, pszMsg ? pszMsg : "-");
334 strcpy(niData.szInfoTitle, pszTitle ? pszTitle : "Information");
[23053]335
336 if (!Shell_NotifyIcon(NIM_MODIFY, &niData))
[34025]337 {
338 DWORD dwErr = GetLastError();
339 return RTErrConvertFromWin32(dwErr);
340 }
341 return VINF_SUCCESS;
[23053]342}
[31002]343
[95827]344/**
345 * Shows a message box with a printf() style formatted string.
346 *
347 * @param pszTitle Title of the message box.
348 * @param uStyle Style of message box to use (see MSDN, MB_ defines).
349 * When 0 is specified, MB_ICONINFORMATION will be used.
350 * @param pszFmt Printf-style format string to show in the message box body.
351 * @param ... Arguments for format string.
352 */
353void hlpShowMessageBox(const char *pszTitle, UINT uStyle, const char *pszFmt, ...)
354{
355 if (!uStyle)
356 uStyle = MB_ICONINFORMATION;
357
358 char *pszMsg;
359 va_list va;
360 va_start(va, pszFmt);
361 int rc = RTStrAPrintfV(&pszMsg, pszFmt, va);
362 va_end(va);
363 if (rc >= 0)
364 {
365 PRTUTF16 pwszTitle;
366 rc = RTStrToUtf16(pszTitle, &pwszTitle);
367 if (RT_SUCCESS(rc))
368 {
369 PRTUTF16 pwszMsg;
370 rc = RTStrToUtf16(pszMsg, &pwszMsg);
371 if (RT_SUCCESS(rc))
372 {
373 MessageBoxW(GetDesktopWindow(), pwszMsg, pwszTitle, uStyle);
374 RTUtf16Free(pwszMsg);
375 }
376 else
377 MessageBoxA(GetDesktopWindow(), pszMsg, pszTitle, uStyle);
378 RTUtf16Free(pwszTitle);
379 }
380 }
381 else /* Should never happen! */
382 AssertMsgFailed(("Failed to format error text of format string: %s!\n", pszFmt));
383 RTStrFree(pszMsg);
384}
385
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use