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 "gui.h" 13 #include "misc.h" 14 15 static HANDLE hLog = NULL; 16 17 INT GetWindowWidth(HWND hwnd) 18 { 19 RECT Rect; 20 21 GetWindowRect(hwnd, &Rect); 22 return (Rect.right - Rect.left); 23 } 24 25 INT GetWindowHeight(HWND hwnd) 26 { 27 RECT Rect; 28 29 GetWindowRect(hwnd, &Rect); 30 return (Rect.bottom - Rect.top); 31 } 32 33 INT GetClientWindowWidth(HWND hwnd) 34 { 35 RECT Rect; 36 37 GetClientRect(hwnd, &Rect); 38 return (Rect.right - Rect.left); 39 } 40 41 INT GetClientWindowHeight(HWND hwnd) 42 { 43 RECT Rect; 44 45 GetClientRect(hwnd, &Rect); 46 return (Rect.bottom - Rect.top); 47 } 48 49 VOID CopyTextToClipboard(LPCWSTR lpszText) 50 { 51 if (!OpenClipboard(NULL)) 52 { 53 return; 54 } 55 56 HRESULT hr; 57 HGLOBAL ClipBuffer; 58 LPWSTR Buffer; 59 DWORD cchBuffer; 60 61 EmptyClipboard(); 62 cchBuffer = wcslen(lpszText) + 1; 63 ClipBuffer = GlobalAlloc(GMEM_DDESHARE, cchBuffer * sizeof(WCHAR)); 64 65 Buffer = (PWCHAR) GlobalLock(ClipBuffer); 66 hr = StringCchCopyW(Buffer, cchBuffer, lpszText); 67 GlobalUnlock(ClipBuffer); 68 69 if (SUCCEEDED(hr)) 70 SetClipboardData(CF_UNICODETEXT, ClipBuffer); 71 72 CloseClipboard(); 73 } 74 75 VOID SetWelcomeText() 76 { 77 ATL::CStringW szText; 78 79 szText.LoadStringW(IDS_WELCOME_TITLE); 80 NewRichEditText(szText, CFE_BOLD); 81 82 szText.LoadStringW(IDS_WELCOME_TEXT); 83 InsertRichEditText(szText, 0); 84 85 szText.LoadStringW(IDS_WELCOME_URL); 86 InsertRichEditText(szText, CFM_LINK); 87 } 88 89 VOID ShowPopupMenu(HWND hwnd, UINT MenuID, UINT DefaultItem) 90 { 91 HMENU hMenu = NULL; 92 HMENU hPopupMenu; 93 MENUITEMINFO ItemInfo; 94 POINT pt; 95 96 if (MenuID) 97 { 98 hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(MenuID)); 99 hPopupMenu = GetSubMenu(hMenu, 0); 100 } 101 else 102 { 103 hPopupMenu = GetMenu(hwnd); 104 } 105 106 ZeroMemory(&ItemInfo, sizeof(ItemInfo)); 107 ItemInfo.cbSize = sizeof(ItemInfo); 108 ItemInfo.fMask = MIIM_STATE; 109 110 GetMenuItemInfoW(hPopupMenu, DefaultItem, FALSE, &ItemInfo); 111 112 if (!(ItemInfo.fState & MFS_GRAYED)) 113 { 114 SetMenuDefaultItem(hPopupMenu, DefaultItem, FALSE); 115 } 116 117 GetCursorPos(&pt); 118 119 SetForegroundWindow(hwnd); 120 TrackPopupMenu(hPopupMenu, 0, pt.x, pt.y, 0, hMainWnd, NULL); 121 122 if (hMenu) 123 { 124 DestroyMenu(hMenu); 125 } 126 } 127 128 BOOL StartProcess(ATL::CStringW &Path, BOOL Wait) 129 { 130 return StartProcess(const_cast<LPWSTR>(Path.GetString()), Wait);; 131 } 132 133 BOOL StartProcess(LPWSTR lpPath, BOOL Wait) 134 { 135 PROCESS_INFORMATION pi; 136 STARTUPINFOW si; 137 DWORD dwRet; 138 MSG msg; 139 140 ZeroMemory(&si, sizeof(si)); 141 si.cb = sizeof(si); 142 si.dwFlags = STARTF_USESHOWWINDOW; 143 si.wShowWindow = SW_SHOW; 144 145 if (!CreateProcessW(NULL, lpPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) 146 { 147 return FALSE; 148 } 149 150 CloseHandle(pi.hThread); 151 152 if (Wait) 153 { 154 EnableWindow(hMainWnd, FALSE); 155 } 156 157 while (Wait) 158 { 159 dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLEVENTS); 160 if (dwRet == WAIT_OBJECT_0 + 1) 161 { 162 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) 163 { 164 TranslateMessage(&msg); 165 DispatchMessageW(&msg); 166 } 167 } 168 else 169 { 170 if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED) 171 break; 172 } 173 } 174 175 CloseHandle(pi.hProcess); 176 177 if (Wait) 178 { 179 EnableWindow(hMainWnd, TRUE); 180 SetForegroundWindow(hMainWnd); 181 SetFocus(hMainWnd); 182 } 183 184 return TRUE; 185 } 186 187 BOOL GetStorageDirectory(ATL::CStringW& Directory) 188 { 189 if (!SHGetSpecialFolderPathW(NULL, Directory.GetBuffer(MAX_PATH), CSIDL_LOCAL_APPDATA, TRUE)) 190 { 191 Directory.ReleaseBuffer(); 192 return FALSE; 193 } 194 195 Directory.ReleaseBuffer(); 196 Directory += L"\\rapps"; 197 198 return (CreateDirectoryW(Directory.GetString(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS); 199 } 200 201 VOID InitLogs() 202 { 203 if (!SettingsInfo.bLogEnabled) 204 { 205 return; 206 } 207 208 WCHAR szPath[MAX_PATH]; 209 DWORD dwCategoryNum = 1; 210 DWORD dwDisp, dwData; 211 ATL::CRegKey key; 212 213 if (key.Create(HKEY_LOCAL_MACHINE, 214 L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\ReactOS Application Manager", 215 REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &dwDisp) != ERROR_SUCCESS) 216 { 217 return; 218 } 219 220 if (!GetModuleFileNameW(NULL, szPath, _countof(szPath))) 221 { 222 return; 223 } 224 225 dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | 226 EVENTLOG_INFORMATION_TYPE; 227 228 if ((key.SetStringValue(L"EventMessageFile", 229 szPath, 230 REG_EXPAND_SZ) == ERROR_SUCCESS) 231 && (key.SetStringValue(L"CategoryMessageFile", 232 szPath, 233 REG_EXPAND_SZ) == ERROR_SUCCESS) 234 && (key.SetDWORDValue(L"TypesSupported", 235 dwData) == ERROR_SUCCESS) 236 && (key.SetDWORDValue(L"CategoryCount", 237 dwCategoryNum) == ERROR_SUCCESS)) 238 239 { 240 hLog = RegisterEventSourceW(NULL, L"ReactOS Application Manager"); 241 } 242 243 key.Close(); 244 } 245 246 247 VOID FreeLogs() 248 { 249 if (hLog) 250 { 251 DeregisterEventSource(hLog); 252 } 253 } 254 255 256 BOOL WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg) 257 { 258 if (!SettingsInfo.bLogEnabled) 259 { 260 return TRUE; 261 } 262 263 if (!ReportEventW(hLog, wType, 0, dwEventID, 264 NULL, 1, 0, &lpMsg, NULL)) 265 { 266 return FALSE; 267 } 268 269 return TRUE; 270 } 271 272 BOOL GetInstalledVersion_WowUser(ATL::CStringW* szVersionResult, 273 const ATL::CStringW& szRegName, 274 BOOL IsUserKey, 275 REGSAM keyWow) 276 { 277 BOOL bHasSucceded = FALSE; 278 ATL::CRegKey key; 279 ATL::CStringW szVersion; 280 ATL::CStringW szPath = ATL::CStringW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%ls") + szRegName; 281 282 if (key.Open(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, 283 szPath.GetString(), 284 keyWow | KEY_READ) != ERROR_SUCCESS) 285 { 286 return FALSE; 287 } 288 289 if (szVersionResult != NULL) 290 { 291 ULONG dwSize = MAX_PATH * sizeof(WCHAR); 292 293 if (key.QueryStringValue(L"DisplayVersion", 294 szVersion.GetBuffer(MAX_PATH), 295 &dwSize) == ERROR_SUCCESS) 296 { 297 szVersion.ReleaseBuffer(); 298 *szVersionResult = szVersion; 299 bHasSucceded = TRUE; 300 } 301 else 302 { 303 szVersion.ReleaseBuffer(); 304 } 305 } 306 else 307 { 308 bHasSucceded = TRUE; 309 szVersion.ReleaseBuffer(); 310 } 311 key.Close(); 312 313 return bHasSucceded; 314 } 315 316 BOOL GetInstalledVersion(ATL::CStringW *pszVersion, const ATL::CStringW &szRegName) 317 { 318 return (!szRegName.IsEmpty() 319 && (GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_32KEY) 320 || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_32KEY) 321 || GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_64KEY) 322 || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_64KEY))); 323 } 324 325 // CConfigParser 326 327 CConfigParser::CConfigParser(const ATL::CStringW& FileName) : szConfigPath(GetINIFullPath(FileName)) 328 { 329 CacheINILocale(); 330 } 331 332 ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName) 333 { 334 ATL::CStringW szDir; 335 ATL::CStringW szBuffer; 336 337 GetStorageDirectory(szDir); 338 szBuffer.Format(L"%ls\\rapps\\%ls", szDir.GetString(), FileName.GetString()); 339 340 return szBuffer; 341 } 342 343 VOID CConfigParser::CacheINILocale() 344 { 345 // TODO: Set default locale if call fails 346 // find out what is the current system lang code (e.g. "0a") and append it to SectionLocale 347 GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE, 348 m_szLocaleID.GetBuffer(m_cchLocaleSize), m_cchLocaleSize); 349 350 m_szLocaleID.ReleaseBuffer(); 351 m_szCachedINISectionLocale = L"Section." + m_szLocaleID; 352 353 // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part 354 m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale + m_szLocaleID.Right(2); 355 } 356 357 BOOL CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString) 358 { 359 DWORD dwResult; 360 361 LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH); 362 // 1st - find localized strings (e.g. "Section.0c0a") 363 dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocale.GetString(), 364 KeyName.GetString(), 365 NULL, 366 ResultStringBuffer, 367 MAX_PATH, 368 szConfigPath.GetString()); 369 370 if (!dwResult) 371 { 372 // 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a") 373 dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocaleNeutral.GetString(), 374 KeyName.GetString(), 375 NULL, 376 ResultStringBuffer, 377 MAX_PATH, 378 szConfigPath.GetString()); 379 if (!dwResult) 380 { 381 // 3rd - if they weren't present fallback to standard english strings (just "Section") 382 dwResult = GetPrivateProfileStringW(L"Section", 383 KeyName.GetString(), 384 NULL, 385 ResultStringBuffer, 386 MAX_PATH, 387 szConfigPath.GetString()); 388 } 389 } 390 391 ResultString.ReleaseBuffer(); 392 return (dwResult != 0 ? TRUE : FALSE); 393 } 394 395 BOOL CConfigParser::GetInt(const ATL::CStringW& KeyName, INT& iResult) 396 { 397 ATL::CStringW Buffer; 398 399 iResult = 0; 400 401 // grab the text version of our entry 402 if (!GetString(KeyName, Buffer)) 403 return FALSE; 404 405 if (Buffer.IsEmpty()) 406 return FALSE; 407 408 // convert it to an actual integer 409 iResult = StrToIntW(Buffer.GetString()); 410 411 // we only care about values > 0 412 return (iResult > 0); 413 } 414 // CConfigParser 415