xref: /reactos/base/applications/rapps/misc.cpp (revision 7d5e1591)
1 /*
2  * PROJECT:     ReactOS Applications Manager
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Misc functions
5  * COPYRIGHT:   Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org)
6  *              Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
7  *              Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
8  */
9 
10 #include "rapps.h"
11 #include "misc.h"
12 
13 static HANDLE hLog = NULL;
14 
15 static BOOL bIsSys64ResultCached = FALSE;
16 static BOOL bIsSys64Result = FALSE;
17 
18 VOID
19 CopyTextToClipboard(LPCWSTR lpszText)
20 {
21     if (!OpenClipboard(NULL))
22     {
23         return;
24     }
25 
26     HRESULT hr;
27     HGLOBAL ClipBuffer;
28     LPWSTR Buffer;
29     DWORD cchBuffer;
30 
31     EmptyClipboard();
32     cchBuffer = wcslen(lpszText) + 1;
33     ClipBuffer = GlobalAlloc(GMEM_DDESHARE, cchBuffer * sizeof(WCHAR));
34 
35     Buffer = (PWCHAR)GlobalLock(ClipBuffer);
36     hr = StringCchCopyW(Buffer, cchBuffer, lpszText);
37     GlobalUnlock(ClipBuffer);
38 
39     if (SUCCEEDED(hr))
40         SetClipboardData(CF_UNICODETEXT, ClipBuffer);
41 
42     CloseClipboard();
43 }
44 
45 VOID
46 ShowPopupMenuEx(HWND hwnd, HWND hwndOwner, UINT MenuID, UINT DefaultItem)
47 {
48     HMENU hMenu = NULL;
49     HMENU hPopupMenu;
50     MENUITEMINFO ItemInfo;
51     POINT pt;
52 
53     if (MenuID)
54     {
55         hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(MenuID));
56         hPopupMenu = GetSubMenu(hMenu, 0);
57     }
58     else
59     {
60         hPopupMenu = GetMenu(hwnd);
61     }
62 
63     ZeroMemory(&ItemInfo, sizeof(ItemInfo));
64     ItemInfo.cbSize = sizeof(ItemInfo);
65     ItemInfo.fMask = MIIM_STATE;
66 
67     GetMenuItemInfoW(hPopupMenu, DefaultItem, FALSE, &ItemInfo);
68 
69     if (!(ItemInfo.fState & MFS_GRAYED))
70     {
71         SetMenuDefaultItem(hPopupMenu, DefaultItem, FALSE);
72     }
73 
74     GetCursorPos(&pt);
75 
76     SetForegroundWindow(hwnd);
77     TrackPopupMenu(hPopupMenu, 0, pt.x, pt.y, 0, hwndOwner, NULL);
78 
79     if (hMenu)
80     {
81         DestroyMenu(hMenu);
82     }
83 }
84 
85 BOOL
86 StartProcess(const CStringW &Path, BOOL Wait)
87 {
88     PROCESS_INFORMATION pi;
89     STARTUPINFOW si;
90     DWORD dwRet;
91     MSG msg;
92 
93     ZeroMemory(&si, sizeof(si));
94     si.cb = sizeof(si);
95     si.dwFlags = STARTF_USESHOWWINDOW;
96     si.wShowWindow = SW_SHOW;
97 
98     // The Unicode version of CreateProcess can modify the contents of this string.
99     CStringW Tmp = Path;
100     BOOL fSuccess = CreateProcessW(NULL, Tmp.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
101     Tmp.ReleaseBuffer();
102     if (!fSuccess)
103     {
104         return FALSE;
105     }
106 
107     CloseHandle(pi.hThread);
108 
109     if (Wait)
110     {
111         EnableWindow(hMainWnd, FALSE);
112     }
113 
114     while (Wait)
115     {
116         dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLEVENTS);
117         if (dwRet == WAIT_OBJECT_0 + 1)
118         {
119             while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
120             {
121                 TranslateMessage(&msg);
122                 DispatchMessageW(&msg);
123             }
124         }
125         else
126         {
127             if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED)
128                 break;
129         }
130     }
131 
132     CloseHandle(pi.hProcess);
133 
134     if (Wait)
135     {
136         EnableWindow(hMainWnd, TRUE);
137         SetForegroundWindow(hMainWnd);
138         SetFocus(hMainWnd);
139     }
140 
141     return TRUE;
142 }
143 
144 BOOL
145 GetStorageDirectory(CStringW &Directory)
146 {
147     static CStringW CachedDirectory;
148     static BOOL CachedDirectoryInitialized = FALSE;
149 
150     if (!CachedDirectoryInitialized)
151     {
152         LPWSTR DirectoryStr = CachedDirectory.GetBuffer(MAX_PATH);
153         BOOL bHasPath = SHGetSpecialFolderPathW(NULL, DirectoryStr, CSIDL_LOCAL_APPDATA, TRUE);
154         if (bHasPath)
155         {
156             PathAppendW(DirectoryStr, RAPPS_NAME);
157         }
158         CachedDirectory.ReleaseBuffer();
159 
160         if (bHasPath)
161         {
162             if (!CreateDirectoryW(CachedDirectory, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
163             {
164                 CachedDirectory.Empty();
165             }
166         }
167         else
168         {
169             CachedDirectory.Empty();
170         }
171 
172         CachedDirectoryInitialized = TRUE;
173     }
174 
175     Directory = CachedDirectory;
176     return !Directory.IsEmpty();
177 }
178 
179 VOID
180 InitLogs()
181 {
182     if (!SettingsInfo.bLogEnabled)
183     {
184         return;
185     }
186 
187     WCHAR szPath[MAX_PATH];
188     DWORD dwCategoryNum = 1;
189     DWORD dwDisp, dwData;
190     ATL::CRegKey key;
191 
192     if (key.Create(
193             HKEY_LOCAL_MACHINE,
194             L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\ReactOS Application Manager", REG_NONE,
195             REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &dwDisp) != ERROR_SUCCESS)
196     {
197         return;
198     }
199 
200     if (!GetModuleFileNameW(NULL, szPath, _countof(szPath)))
201     {
202         return;
203     }
204 
205     dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
206 
207     if ((key.SetStringValue(L"EventMessageFile", szPath, REG_EXPAND_SZ) == ERROR_SUCCESS) &&
208         (key.SetStringValue(L"CategoryMessageFile", szPath, REG_EXPAND_SZ) == ERROR_SUCCESS) &&
209         (key.SetDWORDValue(L"TypesSupported", dwData) == ERROR_SUCCESS) &&
210         (key.SetDWORDValue(L"CategoryCount", dwCategoryNum) == ERROR_SUCCESS))
211 
212     {
213         hLog = RegisterEventSourceW(NULL, L"ReactOS Application Manager");
214     }
215 }
216 
217 VOID
218 FreeLogs()
219 {
220     if (hLog)
221     {
222         DeregisterEventSource(hLog);
223     }
224 }
225 
226 BOOL
227 WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg)
228 {
229     if (!SettingsInfo.bLogEnabled)
230     {
231         return TRUE;
232     }
233 
234     if (!ReportEventW(hLog, wType, 0, dwEventID, NULL, 1, 0, &lpMsg, NULL))
235     {
236         return FALSE;
237     }
238 
239     return TRUE;
240 }
241 
242 BOOL
243 GetInstalledVersion_WowUser(CStringW *szVersionResult, const CStringW &szRegName, BOOL IsUserKey, REGSAM keyWow)
244 {
245     BOOL bHasSucceded = FALSE;
246     ATL::CRegKey key;
247     CStringW szVersion;
248     CStringW szPath = CStringW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\") + szRegName;
249 
250     if (key.Open(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szPath.GetString(), keyWow | KEY_READ) !=
251         ERROR_SUCCESS)
252     {
253         return FALSE;
254     }
255 
256     if (szVersionResult != NULL)
257     {
258         ULONG dwSize = MAX_PATH * sizeof(WCHAR);
259 
260         if (key.QueryStringValue(L"DisplayVersion", szVersion.GetBuffer(MAX_PATH), &dwSize) == ERROR_SUCCESS)
261         {
262             szVersion.ReleaseBuffer();
263             *szVersionResult = szVersion;
264             bHasSucceded = TRUE;
265         }
266         else
267         {
268             szVersion.ReleaseBuffer();
269         }
270     }
271     else
272     {
273         bHasSucceded = TRUE;
274     }
275 
276     return bHasSucceded;
277 }
278 
279 BOOL
280 GetInstalledVersion(CStringW *pszVersion, const CStringW &szRegName)
281 {
282     return (
283         !szRegName.IsEmpty() && (GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_32KEY) ||
284                                  GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_32KEY) ||
285                                  GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_64KEY) ||
286                                  GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_64KEY)));
287 }
288 
289 BOOL
290 IsSystem64Bit()
291 {
292     if (bIsSys64ResultCached)
293     {
294         // just return cached result
295         return bIsSys64Result;
296     }
297 
298     SYSTEM_INFO si;
299     typedef void(WINAPI * LPFN_PGNSI)(LPSYSTEM_INFO);
300     LPFN_PGNSI pGetNativeSystemInfo =
301         (LPFN_PGNSI)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetNativeSystemInfo");
302     if (pGetNativeSystemInfo)
303     {
304         pGetNativeSystemInfo(&si);
305         if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
306             si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
307         {
308             bIsSys64Result = TRUE;
309         }
310     }
311     else
312     {
313         bIsSys64Result = FALSE;
314     }
315 
316     bIsSys64ResultCached = TRUE; // next time calling this function, it will directly return bIsSys64Result
317     return bIsSys64Result;
318 }
319 
320 INT
321 GetSystemColorDepth()
322 {
323     DEVMODEW pDevMode;
324     INT ColorDepth;
325 
326     pDevMode.dmSize = sizeof(pDevMode);
327     pDevMode.dmDriverExtra = 0;
328 
329     if (!EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &pDevMode))
330     {
331         /* TODO: Error message */
332         return ILC_COLOR;
333     }
334 
335     switch (pDevMode.dmBitsPerPel)
336     {
337         case 32:
338             ColorDepth = ILC_COLOR32;
339             break;
340         case 24:
341             ColorDepth = ILC_COLOR24;
342             break;
343         case 16:
344             ColorDepth = ILC_COLOR16;
345             break;
346         case 8:
347             ColorDepth = ILC_COLOR8;
348             break;
349         case 4:
350             ColorDepth = ILC_COLOR4;
351             break;
352         default:
353             ColorDepth = ILC_COLOR;
354             break;
355     }
356 
357     return ColorDepth;
358 }
359 
360 void
361 UnixTimeToFileTime(DWORD dwUnixTime, LPFILETIME pFileTime)
362 {
363     // Note that LONGLONG is a 64-bit value
364     LONGLONG ll;
365 
366     ll = Int32x32To64(dwUnixTime, 10000000) + 116444736000000000;
367     pFileTime->dwLowDateTime = (DWORD)ll;
368     pFileTime->dwHighDateTime = ll >> 32;
369 }
370 
371 BOOL
372 SearchPatternMatch(LPCWSTR szHaystack, LPCWSTR szNeedle)
373 {
374     if (!*szNeedle)
375         return TRUE;
376     /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
377     return StrStrIW(szHaystack, szNeedle) != NULL;
378 }
379