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