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 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 VOID FreeLogs() 219 { 220 if (hLog) 221 { 222 DeregisterEventSource(hLog); 223 } 224 } 225 226 BOOL WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg) 227 { 228 if (!SettingsInfo.bLogEnabled) 229 { 230 return TRUE; 231 } 232 233 if (!ReportEventW(hLog, wType, 0, dwEventID, 234 NULL, 1, 0, &lpMsg, NULL)) 235 { 236 return FALSE; 237 } 238 239 return TRUE; 240 } 241 242 BOOL GetInstalledVersion_WowUser(ATL::CStringW* szVersionResult, 243 const ATL::CStringW& szRegName, 244 BOOL IsUserKey, 245 REGSAM keyWow) 246 { 247 BOOL bHasSucceded = FALSE; 248 ATL::CRegKey key; 249 ATL::CStringW szVersion; 250 ATL::CStringW szPath = ATL::CStringW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\") + szRegName; 251 252 if (key.Open(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, 253 szPath.GetString(), 254 keyWow | KEY_READ) != ERROR_SUCCESS) 255 { 256 return FALSE; 257 } 258 259 if (szVersionResult != NULL) 260 { 261 ULONG dwSize = MAX_PATH * sizeof(WCHAR); 262 263 if (key.QueryStringValue(L"DisplayVersion", 264 szVersion.GetBuffer(MAX_PATH), 265 &dwSize) == ERROR_SUCCESS) 266 { 267 szVersion.ReleaseBuffer(); 268 *szVersionResult = szVersion; 269 bHasSucceded = TRUE; 270 } 271 else 272 { 273 szVersion.ReleaseBuffer(); 274 } 275 } 276 else 277 { 278 bHasSucceded = TRUE; 279 szVersion.ReleaseBuffer(); 280 } 281 282 return bHasSucceded; 283 } 284 285 BOOL GetInstalledVersion(ATL::CStringW *pszVersion, const ATL::CStringW &szRegName) 286 { 287 return (!szRegName.IsEmpty() 288 && (GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_32KEY) 289 || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_32KEY) 290 || GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_64KEY) 291 || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_64KEY))); 292 } 293 294 BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore) 295 { 296 WCHAR pszPathBuffer[MAX_PATH]; // buffer to store result 297 WCHAR pszPathCopy[MAX_PATH]; 298 299 if (!PathCanonicalizeW(pszPathCopy, pszPath)) 300 { 301 return FALSE; 302 } 303 304 PathRemoveBackslashW(pszPathCopy); 305 306 if (StringCchCopyW(pszPathBuffer, _countof(pszPathBuffer), pszPathCopy) != S_OK) 307 { 308 return FALSE; 309 } 310 311 if (!PathAppendW(pszPathBuffer, pszMore)) 312 { 313 return FALSE; 314 } 315 316 size_t PathLen; 317 if (StringCchLengthW(pszPathCopy, _countof(pszPathCopy), &PathLen) != S_OK) 318 { 319 return FALSE; 320 } 321 int CommonPrefixLen = PathCommonPrefixW(pszPathCopy, pszPathBuffer, NULL); 322 323 if ((unsigned int)CommonPrefixLen != PathLen) 324 { 325 // pszPathBuffer should be a file/folder under pszPath. 326 // but now common prefix len is smaller than length of pszPathCopy 327 // hacking use ".." ? 328 return FALSE; 329 } 330 331 if (StringCchCopyW(pszPath, MAX_PATH, pszPathBuffer) != S_OK) 332 { 333 return FALSE; 334 } 335 336 return TRUE; 337 } 338 339 BOOL IsSystem64Bit() 340 { 341 if (bIsSys64ResultCached) 342 { 343 // just return cached result 344 return bIsSys64Result; 345 } 346 347 SYSTEM_INFO si; 348 typedef void (WINAPI *LPFN_PGNSI)(LPSYSTEM_INFO); 349 LPFN_PGNSI pGetNativeSystemInfo = (LPFN_PGNSI)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetNativeSystemInfo"); 350 if (pGetNativeSystemInfo) 351 { 352 pGetNativeSystemInfo(&si); 353 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) 354 { 355 bIsSys64Result = TRUE; 356 } 357 } 358 else 359 { 360 bIsSys64Result = FALSE; 361 } 362 363 bIsSys64ResultCached = TRUE; // next time calling this function, it will directly return bIsSys64Result 364 return bIsSys64Result; 365 } 366 367 INT GetSystemColorDepth() 368 { 369 DEVMODEW pDevMode; 370 INT ColorDepth; 371 372 pDevMode.dmSize = sizeof(pDevMode); 373 pDevMode.dmDriverExtra = 0; 374 375 if (!EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &pDevMode)) 376 { 377 /* TODO: Error message */ 378 return ILC_COLOR; 379 } 380 381 switch (pDevMode.dmBitsPerPel) 382 { 383 case 32: ColorDepth = ILC_COLOR32; break; 384 case 24: ColorDepth = ILC_COLOR24; break; 385 case 16: ColorDepth = ILC_COLOR16; break; 386 case 8: ColorDepth = ILC_COLOR8; break; 387 case 4: ColorDepth = ILC_COLOR4; break; 388 default: ColorDepth = ILC_COLOR; break; 389 } 390 391 return ColorDepth; 392 } 393 394 void UnixTimeToFileTime(DWORD dwUnixTime, LPFILETIME pFileTime) 395 { 396 // Note that LONGLONG is a 64-bit value 397 LONGLONG ll; 398 399 ll = Int32x32To64(dwUnixTime, 10000000) + 116444736000000000; 400 pFileTime->dwLowDateTime = (DWORD)ll; 401 pFileTime->dwHighDateTime = ll >> 32; 402 } 403 404 BOOL SearchPatternMatch(LPCWSTR szHaystack, LPCWSTR szNeedle) 405 { 406 if (!*szNeedle) 407 return TRUE; 408 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */ 409 return StrStrIW(szHaystack, szNeedle) != NULL; 410 } 411