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