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
Line 
1/* $Id: VBoxHelpers.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * helpers - Guest Additions Service helper functions
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
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
26 */
27
28#include <iprt/win/windows.h>
29
30#include <iprt/string.h>
31#include <iprt/alloca.h>
32#include <iprt/system.h>
33#include <iprt/utf16.h>
34#include <VBox/Log.h>
35#include <VBox/VBoxGuestLib.h>
36
37#include "VBoxHelpers.h"
38
39
40int hlpReportStatus(VBoxGuestFacilityStatus statusCurrent)
41{
42 int rc = VbglR3ReportAdditionsStatus(VBoxGuestFacilityType_VBoxTrayClient,
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}
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;
61 GetCursorPos(&mousePos);
62
63 DWORD hThread = 0; /* Shut up MSC */
64 DWORD hCurrentThread = 0; /* Ditto */
65 HWND hWin = WindowFromPoint(mousePos);
66 if (hWin)
67 {
68 hThread = GetWindowThreadProcessId(hWin, NULL);
69 hCurrentThread = GetCurrentThreadId();
70 if (hCurrentThread != hThread)
71 AttachThreadInput(hCurrentThread, hThread, TRUE);
72 }
73
74 ShowCursor(false);
75 ShowCursor(true);
76
77 if (hWin && hCurrentThread != hThread)
78 AttachThreadInput(hCurrentThread, hThread, FALSE);
79}
80
81static unsigned hlpNextAdjacentRectXP(RECTL *paRects, unsigned nRects, unsigned uRect)
82{
83 unsigned i;
84 for (i = 0; i < nRects; i++)
85 {
86 if (paRects[uRect].right == paRects[i].left)
87 return i;
88 }
89 return ~0U;
90}
91
92static unsigned hlpNextAdjacentRectXN(RECTL *paRects, unsigned nRects, unsigned uRect)
93{
94 unsigned i;
95 for (i = 0; i < nRects; i++)
96 {
97 if (paRects[uRect].left == paRects[i].right)
98 return i;
99 }
100 return ~0U;
101}
102
103static unsigned hlpNextAdjacentRectYP(RECTL *paRects, unsigned nRects, unsigned uRect)
104{
105 unsigned i;
106 for (i = 0; i < nRects; i++)
107 {
108 if (paRects[uRect].bottom == paRects[i].top)
109 return i;
110 }
111 return ~0U;
112}
113
114static unsigned hlpNextAdjacentRectYN(RECTL *paRects, unsigned nRects, unsigned uRect)
115{
116 unsigned i;
117 for (i = 0; i < nRects; i++)
118 {
119 if (paRects[uRect].top == paRects[i].bottom)
120 return i;
121 }
122 return ~0U;
123}
124
125void hlpResizeRect(RECTL *paRects, unsigned nRects, unsigned uPrimary,
126 unsigned uResized, int iNewWidth, int iNewHeight,
127 int iNewPosX, int iNewPosY)
128{
129 Log4Func(("nRects %d, iPrimary %d, iResized %d, NewWidth %d, NewHeight %d\n", nRects, uPrimary, uResized, iNewWidth, iNewHeight));
130
131 RECTL *paNewRects = (RECTL *)alloca (sizeof (RECTL) * nRects);
132 memcpy (paNewRects, paRects, sizeof (RECTL) * nRects);
133 paNewRects[uResized].right += iNewWidth - (paNewRects[uResized].right - paNewRects[uResized].left);
134 paNewRects[uResized].bottom += iNewHeight - (paNewRects[uResized].bottom - paNewRects[uResized].top);
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;
139
140 /* Verify all pairs of originally adjacent rectangles for all 4 directions.
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 */
145
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. */
151 unsigned iNextRect = hlpNextAdjacentRectXP(paRects, nRects, iRect);
152 Log4Func(("next %d -> %d\n", iRect, iNextRect));
153
154 if (iNextRect == ~0 || iNextRect == uPrimary)
155 {
156 continue;
157 }
158
159 /* Check whether there is an X intersection between these adjacent rects in the new rectangles
160 * and fix the intersection if delta is "good".
161 */
162 int delta = paNewRects[iRect].right - paNewRects[iNextRect].left;
163
164 if (delta != 0)
165 {
166 Log4Func(("XP intersection right %d left %d, diff %d\n",
167 paNewRects[iRect].right, paNewRects[iNextRect].left,
168 delta));
169
170 paNewRects[iNextRect].left += delta;
171 paNewRects[iNextRect].right += delta;
172 }
173 }
174
175 /* X negative. */
176 for (iRect = 0; iRect < nRects; iRect++)
177 {
178 /* Find the next adjacent original rect in x negative direction. */
179 unsigned iNextRect = hlpNextAdjacentRectXN(paRects, nRects, iRect);
180 Log4Func(("next %d -> %d\n", iRect, iNextRect));
181
182 if (iNextRect == ~0 || iNextRect == uPrimary)
183 {
184 continue;
185 }
186
187 /* Check whether there is an X intersection between these adjacent rects in the new rectangles
188 * and fix the intersection if delta is "good".
189 */
190 int delta = paNewRects[iRect].left - paNewRects[iNextRect].right;
191
192 if (delta != 0)
193 {
194 Log4Func(("XN intersection left %d right %d, diff %d\n",
195 paNewRects[iRect].left, paNewRects[iNextRect].right,
196 delta));
197
198 paNewRects[iNextRect].left += delta;
199 paNewRects[iNextRect].right += delta;
200 }
201 }
202
203 /* Y positive (in the computer sense, top->down). */
204 for (iRect = 0; iRect < nRects; iRect++)
205 {
206 /* Find the next adjacent original rect in y positive direction. */
207 unsigned iNextRect = hlpNextAdjacentRectYP(paRects, nRects, iRect);
208 Log4Func(("next %d -> %d\n", iRect, iNextRect));
209
210 if (iNextRect == ~0 || iNextRect == uPrimary)
211 {
212 continue;
213 }
214
215 /* Check whether there is an Y intersection between these adjacent rects in the new rectangles
216 * and fix the intersection if delta is "good".
217 */
218 int delta = paNewRects[iRect].bottom - paNewRects[iNextRect].top;
219
220 if (delta != 0)
221 {
222 Log4Func(("YP intersection bottom %d top %d, diff %d\n",
223 paNewRects[iRect].bottom, paNewRects[iNextRect].top,
224 delta));
225
226 paNewRects[iNextRect].top += delta;
227 paNewRects[iNextRect].bottom += delta;
228 }
229 }
230
231 /* Y negative (in the computer sense, down->top). */
232 for (iRect = 0; iRect < nRects; iRect++)
233 {
234 /* Find the next adjacent original rect in x negative direction. */
235 unsigned iNextRect = hlpNextAdjacentRectYN(paRects, nRects, iRect);
236 Log4Func(("next %d -> %d\n", iRect, iNextRect));
237
238 if (iNextRect == ~0 || iNextRect == uPrimary)
239 {
240 continue;
241 }
242
243 /* Check whether there is an Y intersection between these adjacent rects in the new rectangles
244 * and fix the intersection if delta is "good".
245 */
246 int delta = paNewRects[iRect].top - paNewRects[iNextRect].bottom;
247
248 if (delta != 0)
249 {
250 Log4Func(("YN intersection top %d bottom %d, diff %d\n",
251 paNewRects[iRect].top, paNewRects[iNextRect].bottom,
252 delta));
253
254 paNewRects[iNextRect].top += delta;
255 paNewRects[iNextRect].bottom += delta;
256 }
257 }
258
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;
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": ""));
277 }
278 return;
279}
280
281int hlpShowBalloonTip(HINSTANCE hInst, HWND hWnd, UINT uID,
282 const char *pszMsg, const char *pszTitle,
283 UINT uTimeout, DWORD dwInfoFlags)
284{
285 NOTIFYICONDATA niData;
286 ZeroMemory(&niData, sizeof(NOTIFYICONDATA));
287 niData.cbSize = sizeof(NOTIFYICONDATA);
288 niData.uFlags = NIF_INFO; /* Display a balloon notification. */
289 niData.hWnd = hWnd;
290 niData.uID = uID;
291 /* If not timeout set, set it to 5sec. */
292 if (uTimeout == 0)
293 uTimeout = 5000;
294 niData.uTimeout = uTimeout;
295 /* If no info flag (info, warning, error) set,
296 * set it to info by default. */
297 if (dwInfoFlags == 0)
298 dwInfoFlags = NIIF_INFO;
299 niData.dwInfoFlags = dwInfoFlags;
300
301 /* Do we want to have */
302
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? */
305 uint64_t const uNtVersion = RTSystemGetNtVersion();
306 if ( uNtVersion >= RTSYSTEM_MAKE_NT_VERSION(5, 0, 0)
307 && (dwInfoFlags & NIIF_INFO))
308 {
309 /* Load (or retrieve handle of) the app's icon. */
310 HICON hIcon = LoadIcon(hInst, "IDI_ICON1"); /* see Artwork/win/TemplateR3.rc */
311 if (hIcon)
312 niData.dwInfoFlags = NIIF_USER; /* Use an own notification icon. */
313
314 if (uNtVersion >= RTSYSTEM_MAKE_NT_VERSION(5, 1, 0)) /* WinXP. */
315 {
316 /* Use an own icon instead of the default one. */
317 niData.hIcon = hIcon;
318 }
319 else if (uNtVersion >= RTSYSTEM_MAKE_NT_VERSION(6, 0, 0)) /* Vista and up. */
320 {
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;
325 }
326 }
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 }
332
333 strcpy(niData.szInfo, pszMsg ? pszMsg : "-");
334 strcpy(niData.szInfoTitle, pszTitle ? pszTitle : "Information");
335
336 if (!Shell_NotifyIcon(NIM_MODIFY, &niData))
337 {
338 DWORD dwErr = GetLastError();
339 return RTErrConvertFromWin32(dwErr);
340 }
341 return VINF_SUCCESS;
342}
343
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