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