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