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