LibreOffice Module onlineupdate (master) 1
progressui_win.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim:set ts=2 sw=2 sts=2 et cindent: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifdef _WIN32
8#include <stdio.h>
9#ifndef UNICODE
10#define UNICODE
11#endif
12#include <windows.h>
13#include <commctrl.h>
14#include <process.h>
15#include <io.h>
16
17#include "resource.h"
18#include "progressui.h"
19#include "readstrings.h"
20#include "errors.h"
21
22#define TIMER_ID 1
23#define TIMER_INTERVAL 100
24
25#define RESIZE_WINDOW(hwnd, extrax, extray) \
26 { \
27 RECT windowSize; \
28 GetWindowRect(hwnd, &windowSize); \
29 SetWindowPos(hwnd, 0, 0, 0, windowSize.right - windowSize.left + extrax, \
30 windowSize.bottom - windowSize.top + extray, \
31 SWP_NOMOVE | SWP_NOZORDER); \
32 }
33
34#define MOVE_WINDOW(hwnd, dx, dy) \
35 { \
36 RECT rc; \
37 POINT pt; \
38 GetWindowRect(hwnd, &rc); \
39 pt.x = rc.left; \
40 pt.y = rc.top; \
41 ScreenToClient(GetParent(hwnd), &pt); \
42 SetWindowPos(hwnd, 0, pt.x + dx, pt.y + dy, 0, 0, \
43 SWP_NOSIZE | SWP_NOZORDER); \
44 }
45
46static float sProgress; // between 0 and 100
47static BOOL sQuit = FALSE;
48static BOOL sIndeterminate = FALSE;
49static StringTable sUIStrings;
50
51static BOOL
52GetStringsFile(WCHAR filename[MAX_PATH])
53{
54 if (!GetModuleFileNameW(nullptr, filename, MAX_PATH))
55 return FALSE;
56
57 WCHAR *dot = wcsrchr(filename, '.');
58 if (!dot || wcsicmp(dot + 1, L"exe"))
59 return FALSE;
60
61 wcscpy(dot + 1, L"ini");
62 return TRUE;
63}
64
65static void
66UpdateDialog(HWND hDlg)
67{
68 int pos = int(sProgress + 0.5f);
69 HWND hWndPro = GetDlgItem(hDlg, IDC_PROGRESS);
70 SendMessage(hWndPro, PBM_SETPOS, pos, 0);
71}
72
73// The code in this function is from MSDN:
74// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/usingdialogboxes.asp
75static void
76CenterDialog(HWND hDlg)
77{
78 RECT rc, rcOwner, rcDlg;
79
80 // Get the owner window and dialog box rectangles.
81 HWND desktop = GetDesktopWindow();
82
83 GetWindowRect(desktop, &rcOwner);
84 GetWindowRect(hDlg, &rcDlg);
85 CopyRect(&rc, &rcOwner);
86
87 // Offset the owner and dialog box rectangles so that
88 // right and bottom values represent the width and
89 // height, and then offset the owner again to discard
90 // space taken up by the dialog box.
91
92 OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
93 OffsetRect(&rc, -rc.left, -rc.top);
94 OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
95
96 // The new position is the sum of half the remaining
97 // space and the owner's original position.
98
99 SetWindowPos(hDlg,
100 HWND_TOP,
101 rcOwner.left + (rc.right / 2),
102 rcOwner.top + (rc.bottom / 2),
103 0, 0, // ignores size arguments
104 SWP_NOSIZE);
105}
106
107static void
108InitDialog(HWND hDlg)
109{
110 WCHAR szwTitle[MAX_TEXT_LEN];
111 WCHAR szwInfo[MAX_TEXT_LEN];
112
113 MultiByteToWideChar(CP_UTF8, 0, sUIStrings.title, -1, szwTitle,
114 sizeof(szwTitle)/sizeof(szwTitle[0]));
115 MultiByteToWideChar(CP_UTF8, 0, sUIStrings.info, -1, szwInfo,
116 sizeof(szwInfo)/sizeof(szwInfo[0]));
117
118 SetWindowTextW(hDlg, szwTitle);
119 SetWindowTextW(GetDlgItem(hDlg, IDC_INFO), szwInfo);
120
121 // Set dialog icon
122 HICON hIcon = LoadIcon(GetModuleHandle(nullptr),
123 MAKEINTRESOURCE(IDI_DIALOG));
124 if (hIcon)
125 SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
126
127 HWND hWndPro = GetDlgItem(hDlg, IDC_PROGRESS);
128 SendMessage(hWndPro, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
129 if (sIndeterminate)
130 {
131 LONG_PTR val = GetWindowLongPtr(hWndPro, GWL_STYLE);
132 SetWindowLongPtr(hWndPro, GWL_STYLE, val|PBS_MARQUEE);
133 SendMessage(hWndPro,(UINT) PBM_SETMARQUEE,(WPARAM) TRUE,(LPARAM)50 );
134 }
135
136 // Resize the dialog to fit all of the text if necessary.
137 RECT infoSize, textSize;
138 HWND hWndInfo = GetDlgItem(hDlg, IDC_INFO);
139
140 // Get the control's font for calculating the new size for the control
141 HDC hDCInfo = GetDC(hWndInfo);
142 HFONT hInfoFont;
143 HFONT hOldFont = 0;
144 hInfoFont = (HFONT)SendMessage(hWndInfo, WM_GETFONT, 0, 0);
145
146 if (hInfoFont)
147 hOldFont = (HFONT)SelectObject(hDCInfo, hInfoFont);
148
149 // Measure the space needed for the text on a single line. DT_CALCRECT means
150 // nothing is drawn.
151 if (DrawText(hDCInfo, szwInfo, -1, &textSize,
152 DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE))
153 {
154 GetClientRect(hWndInfo, &infoSize);
155 SIZE extra;
156 // Calculate the additional space needed for the text by subtracting from
157 // the rectangle returned by DrawText the existing client rectangle's width
158 // and height.
159 extra.cx = (textSize.right - textSize.left) - \
160 (infoSize.right - infoSize.left);
161 extra.cy = (textSize.bottom - textSize.top) - \
162 (infoSize.bottom - infoSize.top);
163 if (extra.cx < 0)
164 extra.cx = 0;
165 if (extra.cy < 0)
166 extra.cy = 0;
167 if ((extra.cx > 0) || (extra.cy > 0))
168 {
169 RESIZE_WINDOW(hDlg, extra.cx, extra.cy);
170 RESIZE_WINDOW(hWndInfo, extra.cx, extra.cy);
171 RESIZE_WINDOW(hWndPro, extra.cx, 0);
172 MOVE_WINDOW(hWndPro, 0, extra.cy);
173 }
174 }
175
176 if (hOldFont)
177 SelectObject(hDCInfo, hOldFont);
178
179 ReleaseDC(hWndInfo, hDCInfo);
180
181 CenterDialog(hDlg); // make dialog appear in the center of the screen
182
183 SetTimer(hDlg, TIMER_ID, TIMER_INTERVAL, nullptr);
184}
185
186// Message handler for update dialog.
187static LRESULT CALLBACK
188DialogProc(HWND hDlg, UINT message, WPARAM /*wParam*/, LPARAM /*lParam*/)
189{
190 switch (message)
191 {
192 case WM_INITDIALOG:
193 InitDialog(hDlg);
194 return TRUE;
195
196 case WM_TIMER:
197 if (sQuit)
198 {
199 EndDialog(hDlg, 0);
200 }
201 else
202 {
203 UpdateDialog(hDlg);
204 }
205 return TRUE;
206
207 case WM_COMMAND:
208 return TRUE;
209 }
210 return FALSE;
211}
212
213int
214InitProgressUI(int* /*argc*/, WCHAR*** /*argv*/)
215{
216 return 0;
217}
218
224int
225InitProgressUIStrings()
226{
227 // If we do not have updater.ini, then we should not bother showing UI.
228 WCHAR filename[MAX_PATH];
229 if (!GetStringsFile(filename))
230 {
231 strcpy(sUIStrings.title, "LibreOffice Update");
232 strcpy(sUIStrings.info, "Please wait while we update your installation.");
233 return 0;
234 }
235
236 if (_waccess(filename, 04))
237 {
238 strcpy(sUIStrings.title, "LibreOffice Update");
239 strcpy(sUIStrings.info, "Please wait while we update your installation.");
240 return 0;
241 }
242
243 // If the updater.ini doesn't have the required strings, then we should not
244 // bother showing UI.
245 if (ReadStrings(filename, &sUIStrings) != OK)
246 {
247 strcpy(sUIStrings.title, "LibreOffice Update");
248 strcpy(sUIStrings.info, "Please wait while we update your installation.");
249 }
250
251 return 0;
252}
253
254int
255ShowProgressUI(bool indeterminate, bool initUIStrings)
256{
257 sIndeterminate = indeterminate;
258 if (!indeterminate)
259 {
260 // Only show the Progress UI if the process is taking a significant amount of
261 // time where a significant amount of time is defined as .5 seconds after
262 // ShowProgressUI is called sProgress is less than 70.
263 Sleep(500);
264
265 if (sQuit || sProgress > 70.0f)
266 return 0;
267 }
268
269 // Don't load the UI if there's an <exe_name>.Local directory for redirection.
270 WCHAR appPath[MAX_PATH + 1] = { L'\0' };
271 if (!GetModuleFileNameW(nullptr, appPath, MAX_PATH))
272 {
273 return -1;
274 }
275
276 if (wcslen(appPath) + wcslen(L".Local") >= MAX_PATH)
277 {
278 return -1;
279 }
280
281 wcscat(appPath, L".Local");
282
283 if (!_waccess(appPath, 04))
284 {
285 return -1;
286 }
287
288 // Don't load the UI if the strings for the UI are not provided.
289 if (initUIStrings && InitProgressUIStrings() == -1)
290 {
291 return -1;
292 }
293
294 if (!GetModuleFileNameW(nullptr, appPath, MAX_PATH))
295 {
296 return -1;
297 }
298
299 // Use an activation context that supports visual styles for the controls.
300 ACTCTXW actx = {0};
301 actx.cbSize = sizeof(ACTCTXW);
302 actx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
303 actx.hModule = GetModuleHandle(NULL); // Use the embedded manifest
304 // This is needed only for Win XP but doesn't cause a problem with other
305 // versions of Windows.
306 actx.lpSource = appPath;
307 actx.lpResourceName = MAKEINTRESOURCE(IDR_COMCTL32_MANIFEST);
308
309 HANDLE hactx = CreateActCtxW(&actx);
310 ULONG_PTR actxCookie = NULL;
311 if (hactx != INVALID_HANDLE_VALUE)
312 {
313 // Push the specified activation context to the top of the activation stack.
314 ActivateActCtx(hactx, &actxCookie);
315 }
316
317 INITCOMMONCONTROLSEX icc =
318 {
319 sizeof(INITCOMMONCONTROLSEX),
320 ICC_PROGRESS_CLASS
321 };
322 InitCommonControlsEx(&icc);
323
324 DialogBox(GetModuleHandle(nullptr),
325 MAKEINTRESOURCE(IDD_DIALOG), nullptr,
326 (DLGPROC) DialogProc);
327
328 if (hactx != INVALID_HANDLE_VALUE)
329 {
330 // Deactivate the context now that the comctl32.dll is loaded.
331 DeactivateActCtx(0, actxCookie);
332 }
333
334 return 0;
335}
336
337void
339{
340 sQuit = TRUE;
341}
342
343void
344UpdateProgressUI(float progress)
345{
346 sProgress = progress; // 32-bit writes are atomic
347}
348#endif // _WIN32
virtual void EndDialog(sal_Int32 nResult) override
#define OK
Definition: errors.h:10
#define TRUE
#define FALSE
#define MAX_PATH
return NULL
constexpr tools::Long SIZE
indeterminate
#define CALLBACK
int InitProgressUI(int *argc, char ***argv)
int ShowProgressUI()
void QuitProgressUI()
void UpdateProgressUI(float progress)
static gboolean UpdateDialog(gpointer)
#define TIMER_INTERVAL
static BOOL sQuit
int ReadStrings(const NS_tchar *path, const char *keyList, unsigned int numStrings, char results[][MAX_TEXT_LEN], const char *section)
A very basic parser for updater.ini taken mostly from nsINIParser.cpp that can be used by standalone ...
#define MAX_TEXT_LEN
Definition: readstrings.h:10
const wchar_t *typedef BOOL
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
#define IDR_COMCTL32_MANIFEST
Definition: resource.h:18
#define IDC_PROGRESS
Definition: resource.h:10
#define IDC_INFO
Definition: resource.h:11
#define IDD_DIALOG
Definition: resource.h:9
#define IDI_DIALOG
Definition: resource.hxx:9
char title[MAX_TEXT_LEN]
Definition: readstrings.h:20
char info[MAX_TEXT_LEN]
Definition: readstrings.h:21
size_t pos