250d40c527f1aad48192c1df8c968b95ad7b8af3
[reactos.git] / reactos / base / applications / rapps / misc.cpp
1 /*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * FILE: base/applications/rapps/misc.cpp
5 * PURPOSE: Misc functions
6 * COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org)
7 * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
8 * Copyright 2017 Alexander Shaposhnikov (chaez.san@gmail.com)
9 */
10 #include "defines.h"
11
12 #include "gui.h"
13 #include "misc.h"
14
15 /* SESSION Operation */
16 #define EXTRACT_FILLFILELIST 0x00000001
17 #define EXTRACT_EXTRACTFILES 0x00000002
18
19 static HANDLE hLog = NULL;
20
21 struct ERF
22 {
23 INT erfOper;
24 INT erfType;
25 BOOL fError;
26 };
27
28 struct FILELIST
29 {
30 LPSTR FileName;
31 FILELIST *next;
32 BOOL DoExtract;
33 };
34
35 struct SESSION
36 {
37 INT FileSize;
38 ERF Error;
39 FILELIST *FileList;
40 INT FileCount;
41 INT Operation;
42 CHAR Destination[MAX_PATH];
43 CHAR CurrentFile[MAX_PATH];
44 CHAR Reserved[MAX_PATH];
45 FILELIST *FilterList;
46 };
47
48 typedef HRESULT(WINAPI *fnExtract)(SESSION *dest, LPCSTR szCabName);
49 fnExtract pfnExtract;
50
51 INT GetWindowWidth(HWND hwnd)
52 {
53 RECT Rect;
54
55 GetWindowRect(hwnd, &Rect);
56 return (Rect.right - Rect.left);
57 }
58
59 INT GetWindowHeight(HWND hwnd)
60 {
61 RECT Rect;
62
63 GetWindowRect(hwnd, &Rect);
64 return (Rect.bottom - Rect.top);
65 }
66
67 INT GetClientWindowWidth(HWND hwnd)
68 {
69 RECT Rect;
70
71 GetClientRect(hwnd, &Rect);
72 return (Rect.right - Rect.left);
73 }
74
75 INT GetClientWindowHeight(HWND hwnd)
76 {
77 RECT Rect;
78
79 GetClientRect(hwnd, &Rect);
80 return (Rect.bottom - Rect.top);
81 }
82
83 VOID CopyTextToClipboard(LPCWSTR lpszText)
84 {
85 if (!OpenClipboard(NULL))
86 {
87 return;
88 }
89
90 HRESULT hr;
91 HGLOBAL ClipBuffer;
92 LPWSTR Buffer;
93 DWORD cchBuffer;
94
95 EmptyClipboard();
96 cchBuffer = wcslen(lpszText) + 1;
97 ClipBuffer = GlobalAlloc(GMEM_DDESHARE, cchBuffer * sizeof(WCHAR));
98
99 Buffer = (PWCHAR) GlobalLock(ClipBuffer);
100 hr = StringCchCopyW(Buffer, cchBuffer, lpszText);
101 GlobalUnlock(ClipBuffer);
102
103 if (SUCCEEDED(hr))
104 SetClipboardData(CF_UNICODETEXT, ClipBuffer);
105
106 CloseClipboard();
107 }
108
109 VOID SetWelcomeText()
110 {
111 ATL::CStringW szText;
112
113 szText.LoadStringW(IDS_WELCOME_TITLE);
114 NewRichEditText(szText, CFE_BOLD);
115
116 szText.LoadStringW(IDS_WELCOME_TEXT);
117 InsertRichEditText(szText, 0);
118
119 szText.LoadStringW(IDS_WELCOME_URL);
120 InsertRichEditText(szText, CFM_LINK);
121 }
122
123 VOID ShowPopupMenu(HWND hwnd, UINT MenuID, UINT DefaultItem)
124 {
125 HMENU hMenu = NULL;
126 HMENU hPopupMenu;
127 MENUITEMINFO ItemInfo;
128 POINT pt;
129
130 if (MenuID)
131 {
132 hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(MenuID));
133 hPopupMenu = GetSubMenu(hMenu, 0);
134 }
135 else
136 {
137 hPopupMenu = GetMenu(hwnd);
138 }
139
140 ZeroMemory(&ItemInfo, sizeof(ItemInfo));
141 ItemInfo.cbSize = sizeof(ItemInfo);
142 ItemInfo.fMask = MIIM_STATE;
143
144 GetMenuItemInfoW(hPopupMenu, DefaultItem, FALSE, &ItemInfo);
145
146 if (!(ItemInfo.fState & MFS_GRAYED))
147 {
148 SetMenuDefaultItem(hPopupMenu, DefaultItem, FALSE);
149 }
150
151 GetCursorPos(&pt);
152
153 SetForegroundWindow(hwnd);
154 TrackPopupMenu(hPopupMenu, 0, pt.x, pt.y, 0, hMainWnd, NULL);
155
156 if (hMenu)
157 {
158 DestroyMenu(hMenu);
159 }
160 }
161
162 BOOL StartProcess(ATL::CStringW &Path, BOOL Wait)
163 {
164 return StartProcess(const_cast<LPWSTR>(Path.GetString()), Wait);;
165 }
166
167 BOOL StartProcess(LPWSTR lpPath, BOOL Wait)
168 {
169 PROCESS_INFORMATION pi;
170 STARTUPINFOW si;
171 DWORD dwRet;
172 MSG msg;
173
174 ZeroMemory(&si, sizeof(si));
175 si.cb = sizeof(si);
176 si.dwFlags = STARTF_USESHOWWINDOW;
177 si.wShowWindow = SW_SHOW;
178
179 if (!CreateProcessW(NULL, lpPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
180 {
181 return FALSE;
182 }
183
184 CloseHandle(pi.hThread);
185
186 if (Wait)
187 {
188 EnableWindow(hMainWnd, FALSE);
189 }
190
191 while (Wait)
192 {
193 dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLEVENTS);
194 if (dwRet == WAIT_OBJECT_0 + 1)
195 {
196 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
197 {
198 TranslateMessage(&msg);
199 DispatchMessageW(&msg);
200 }
201 }
202 else
203 {
204 if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED)
205 break;
206 }
207 }
208
209 CloseHandle(pi.hProcess);
210
211 if (Wait)
212 {
213 EnableWindow(hMainWnd, TRUE);
214 SetForegroundWindow(hMainWnd);
215 SetFocus(hMainWnd);
216 }
217
218 return TRUE;
219 }
220
221 BOOL GetStorageDirectory(ATL::CStringW& Directory)
222 {
223 if (!SHGetSpecialFolderPathW(NULL, Directory.GetBuffer(MAX_PATH), CSIDL_LOCAL_APPDATA, TRUE))
224 {
225 Directory.ReleaseBuffer();
226 return FALSE;
227 }
228
229 Directory.ReleaseBuffer();
230 Directory += L"\\rapps";
231
232 return (CreateDirectoryW(Directory.GetString(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS);
233 }
234
235 BOOL ExtractFilesFromCab(const ATL::CStringW &CabName, const ATL::CStringW &OutputPath)
236 {
237 return ExtractFilesFromCab(CabName.GetString(), OutputPath.GetString());
238 }
239
240 BOOL ExtractFilesFromCab(LPCWSTR lpCabName, LPCWSTR lpOutputPath)
241 {
242 HINSTANCE hCabinetDll;
243 CHAR szCabName[MAX_PATH];
244 SESSION Dest;
245 HRESULT Result;
246
247 hCabinetDll = LoadLibraryW(L"cabinet.dll");
248 if (hCabinetDll)
249 {
250 pfnExtract = (fnExtract) GetProcAddress(hCabinetDll, "Extract");
251 if (pfnExtract)
252 {
253 ZeroMemory(&Dest, sizeof(Dest));
254
255 WideCharToMultiByte(CP_ACP, 0, lpOutputPath, -1, Dest.Destination, MAX_PATH, NULL, NULL);
256 WideCharToMultiByte(CP_ACP, 0, lpCabName, -1, szCabName, MAX_PATH, NULL, NULL);
257 Dest.Operation = EXTRACT_FILLFILELIST;
258
259 Result = pfnExtract(&Dest, szCabName);
260 if (Result == S_OK)
261 {
262 Dest.Operation = EXTRACT_EXTRACTFILES;
263 CreateDirectoryW(lpOutputPath, NULL);
264
265 Result = pfnExtract(&Dest, szCabName);
266 if (Result == S_OK)
267 {
268 FreeLibrary(hCabinetDll);
269 return TRUE;
270 }
271 else
272 {
273 RemoveDirectoryW(lpOutputPath);
274 }
275 }
276 }
277 FreeLibrary(hCabinetDll);
278 }
279
280 return FALSE;
281 }
282
283 VOID InitLogs()
284 {
285 if (!SettingsInfo.bLogEnabled)
286 {
287 return;
288 }
289
290 WCHAR szPath[MAX_PATH];
291 DWORD dwCategoryNum = 1;
292 DWORD dwDisp, dwData;
293 ATL::CRegKey key;
294
295 if (key.Create(HKEY_LOCAL_MACHINE,
296 L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\ReactOS Application Manager",
297 REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &dwDisp) != ERROR_SUCCESS)
298 {
299 return;
300 }
301
302 if (!GetModuleFileNameW(NULL, szPath, _countof(szPath)))
303 {
304 return;
305 }
306
307 dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
308 EVENTLOG_INFORMATION_TYPE;
309
310 if ((key.SetStringValue(L"EventMessageFile",
311 szPath,
312 REG_EXPAND_SZ) == ERROR_SUCCESS)
313 && (key.SetStringValue(L"CategoryMessageFile",
314 szPath,
315 REG_EXPAND_SZ) == ERROR_SUCCESS)
316 && (key.SetDWORDValue(L"TypesSupported",
317 dwData) == ERROR_SUCCESS)
318 && (key.SetDWORDValue(L"CategoryCount",
319 dwCategoryNum) == ERROR_SUCCESS))
320
321 {
322 hLog = RegisterEventSourceW(NULL, L"ReactOS Application Manager");
323 }
324
325 key.Close();
326 }
327
328
329 VOID FreeLogs()
330 {
331 if (hLog)
332 {
333 DeregisterEventSource(hLog);
334 }
335 }
336
337
338 BOOL WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg)
339 {
340 if (!SettingsInfo.bLogEnabled)
341 {
342 return TRUE;
343 }
344
345 if (!ReportEventW(hLog, wType, 0, dwEventID,
346 NULL, 1, 0, &lpMsg, NULL))
347 {
348 return FALSE;
349 }
350
351 return TRUE;
352 }
353
354 BOOL GetInstalledVersion_WowUser(ATL::CStringW* szVersionResult,
355 const ATL::CStringW& RegName,
356 BOOL IsUserKey,
357 REGSAM keyWow)
358 {
359 BOOL bHasSucceded = FALSE;
360 ATL::CRegKey key;
361 ATL::CStringW szVersion;
362 ATL::CStringW szPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + RegName;
363
364 if (key.Open(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
365 szPath.GetString(),
366 keyWow | KEY_READ) != ERROR_SUCCESS)
367 {
368 return FALSE;
369 }
370
371 if (szVersionResult != NULL)
372 {
373 ULONG dwSize = MAX_PATH * sizeof(WCHAR);
374
375 if (key.QueryStringValue(L"DisplayVersion",
376 szVersion.GetBuffer(MAX_PATH),
377 &dwSize) == ERROR_SUCCESS)
378 {
379 szVersion.ReleaseBuffer();
380 *szVersionResult = szVersion;
381 bHasSucceded = TRUE;
382 }
383 else
384 {
385 szVersion.ReleaseBuffer();
386 }
387 }
388 else
389 {
390 bHasSucceded = TRUE;
391 szVersion.ReleaseBuffer();
392 }
393 key.Close();
394
395 return bHasSucceded;
396 }
397
398 BOOL GetInstalledVersion(ATL::CStringW *pszVersion, const ATL::CStringW &szRegName)
399 {
400 return (!szRegName.IsEmpty()
401 && (GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_32KEY)
402 || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_32KEY)
403 || GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_64KEY)
404 || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_64KEY)));
405 }
406
407 // CConfigParser
408
409 CConfigParser::CConfigParser(const ATL::CStringW& FileName) : szConfigPath(GetINIFullPath(FileName))
410 {
411 CacheINILocale();
412 }
413
414 ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName)
415 {
416 ATL::CStringW szDir;
417 ATL::CStringW szBuffer;
418
419 GetStorageDirectory(szDir);
420 szBuffer.Format(L"%ls\\rapps\\%ls", szDir, FileName);
421
422 return szBuffer;
423 }
424
425 VOID CConfigParser::CacheINILocale()
426 {
427 // TODO: Set default locale if call fails
428 // find out what is the current system lang code (e.g. "0a") and append it to SectionLocale
429 GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE,
430 m_szLocaleID.GetBuffer(m_cchLocaleSize), m_cchLocaleSize);
431
432 m_szLocaleID.ReleaseBuffer();
433 m_szCachedINISectionLocale = L"Section." + m_szLocaleID;
434
435 // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part
436 m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale + m_szLocaleID.Right(2);
437 }
438
439 UINT CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString)
440 {
441 DWORD dwResult;
442
443 LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH);
444 // 1st - find localized strings (e.g. "Section.0c0a")
445 dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocale.GetString(),
446 KeyName.GetString(),
447 NULL,
448 ResultStringBuffer,
449 MAX_PATH,
450 szConfigPath.GetString());
451
452 if (!dwResult)
453 {
454 // 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a")
455 dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocaleNeutral.GetString(),
456 KeyName.GetString(),
457 NULL,
458 ResultStringBuffer,
459 MAX_PATH,
460 szConfigPath.GetString());
461 if (!dwResult)
462 {
463 // 3rd - if they weren't present fallback to standard english strings (just "Section")
464 dwResult = GetPrivateProfileStringW(L"Section",
465 KeyName.GetString(),
466 NULL,
467 ResultStringBuffer,
468 MAX_PATH,
469 szConfigPath.GetString());
470 }
471 }
472
473 ResultString.ReleaseBuffer();
474 return (dwResult != 0 ? TRUE : FALSE);
475 }
476
477 UINT CConfigParser::GetInt(const ATL::CStringW& KeyName)
478 {
479 ATL::CStringW Buffer;
480
481 // grab the text version of our entry
482 if (!GetString(KeyName, Buffer))
483 return FALSE;
484
485 if (Buffer.IsEmpty())
486 return FALSE;
487
488 // convert it to an actual integer
489 INT result = StrToIntW(Buffer.GetString());
490
491 return (UINT) (result <= 0) ? 0 : result;
492 }
493 // CConfigParser