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)
13 static HANDLE hLog
= NULL
;
15 static BOOL bIsSys64ResultCached
= FALSE
;
16 static BOOL bIsSys64Result
= FALSE
;
18 INT
GetWindowWidth(HWND hwnd
)
22 GetWindowRect(hwnd
, &Rect
);
23 return (Rect
.right
- Rect
.left
);
26 INT
GetWindowHeight(HWND hwnd
)
30 GetWindowRect(hwnd
, &Rect
);
31 return (Rect
.bottom
- Rect
.top
);
34 INT
GetClientWindowWidth(HWND hwnd
)
38 GetClientRect(hwnd
, &Rect
);
39 return (Rect
.right
- Rect
.left
);
42 INT
GetClientWindowHeight(HWND hwnd
)
46 GetClientRect(hwnd
, &Rect
);
47 return (Rect
.bottom
- Rect
.top
);
50 VOID
CopyTextToClipboard(LPCWSTR lpszText
)
52 if (!OpenClipboard(NULL
))
63 cchBuffer
= wcslen(lpszText
) + 1;
64 ClipBuffer
= GlobalAlloc(GMEM_DDESHARE
, cchBuffer
* sizeof(WCHAR
));
66 Buffer
= (PWCHAR
) GlobalLock(ClipBuffer
);
67 hr
= StringCchCopyW(Buffer
, cchBuffer
, lpszText
);
68 GlobalUnlock(ClipBuffer
);
71 SetClipboardData(CF_UNICODETEXT
, ClipBuffer
);
76 VOID
ShowPopupMenuEx(HWND hwnd
, HWND hwndOwner
, UINT MenuID
, UINT DefaultItem
)
80 MENUITEMINFO ItemInfo
;
85 hMenu
= LoadMenuW(hInst
, MAKEINTRESOURCEW(MenuID
));
86 hPopupMenu
= GetSubMenu(hMenu
, 0);
90 hPopupMenu
= GetMenu(hwnd
);
93 ZeroMemory(&ItemInfo
, sizeof(ItemInfo
));
94 ItemInfo
.cbSize
= sizeof(ItemInfo
);
95 ItemInfo
.fMask
= MIIM_STATE
;
97 GetMenuItemInfoW(hPopupMenu
, DefaultItem
, FALSE
, &ItemInfo
);
99 if (!(ItemInfo
.fState
& MFS_GRAYED
))
101 SetMenuDefaultItem(hPopupMenu
, DefaultItem
, FALSE
);
106 SetForegroundWindow(hwnd
);
107 TrackPopupMenu(hPopupMenu
, 0, pt
.x
, pt
.y
, 0, hwndOwner
, NULL
);
115 VOID
ShowPopupMenu(HWND hwnd
, UINT MenuID
, UINT DefaultItem
)
117 ShowPopupMenuEx(hwnd
, hMainWnd
, MenuID
, DefaultItem
);
121 BOOL
StartProcess(ATL::CStringW
&Path
, BOOL Wait
)
123 return StartProcess(const_cast<LPWSTR
>(Path
.GetString()), Wait
);;
126 BOOL
StartProcess(LPWSTR lpPath
, BOOL Wait
)
128 PROCESS_INFORMATION pi
;
133 ZeroMemory(&si
, sizeof(si
));
135 si
.dwFlags
= STARTF_USESHOWWINDOW
;
136 si
.wShowWindow
= SW_SHOW
;
138 if (!CreateProcessW(NULL
, lpPath
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
))
143 CloseHandle(pi
.hThread
);
147 EnableWindow(hMainWnd
, FALSE
);
152 dwRet
= MsgWaitForMultipleObjects(1, &pi
.hProcess
, FALSE
, INFINITE
, QS_ALLEVENTS
);
153 if (dwRet
== WAIT_OBJECT_0
+ 1)
155 while (PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
))
157 TranslateMessage(&msg
);
158 DispatchMessageW(&msg
);
163 if (dwRet
== WAIT_OBJECT_0
|| dwRet
== WAIT_FAILED
)
168 CloseHandle(pi
.hProcess
);
172 EnableWindow(hMainWnd
, TRUE
);
173 SetForegroundWindow(hMainWnd
);
180 BOOL
GetStorageDirectory(ATL::CStringW
& Directory
)
182 LPWSTR DirectoryStr
= Directory
.GetBuffer(MAX_PATH
);
183 if (!SHGetSpecialFolderPathW(NULL
, DirectoryStr
, CSIDL_LOCAL_APPDATA
, TRUE
))
185 Directory
.ReleaseBuffer();
189 PathAppendW(DirectoryStr
, L
"rapps");
190 Directory
.ReleaseBuffer();
192 return (CreateDirectoryW(Directory
.GetString(), NULL
) || GetLastError() == ERROR_ALREADY_EXISTS
);
197 if (!SettingsInfo
.bLogEnabled
)
202 WCHAR szPath
[MAX_PATH
];
203 DWORD dwCategoryNum
= 1;
204 DWORD dwDisp
, dwData
;
207 if (key
.Create(HKEY_LOCAL_MACHINE
,
208 L
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\ReactOS Application Manager",
209 REG_NONE
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &dwDisp
) != ERROR_SUCCESS
)
214 if (!GetModuleFileNameW(NULL
, szPath
, _countof(szPath
)))
219 dwData
= EVENTLOG_ERROR_TYPE
| EVENTLOG_WARNING_TYPE
|
220 EVENTLOG_INFORMATION_TYPE
;
222 if ((key
.SetStringValue(L
"EventMessageFile",
224 REG_EXPAND_SZ
) == ERROR_SUCCESS
)
225 && (key
.SetStringValue(L
"CategoryMessageFile",
227 REG_EXPAND_SZ
) == ERROR_SUCCESS
)
228 && (key
.SetDWORDValue(L
"TypesSupported",
229 dwData
) == ERROR_SUCCESS
)
230 && (key
.SetDWORDValue(L
"CategoryCount",
231 dwCategoryNum
) == ERROR_SUCCESS
))
234 hLog
= RegisterEventSourceW(NULL
, L
"ReactOS Application Manager");
245 DeregisterEventSource(hLog
);
250 BOOL
WriteLogMessage(WORD wType
, DWORD dwEventID
, LPCWSTR lpMsg
)
252 if (!SettingsInfo
.bLogEnabled
)
257 if (!ReportEventW(hLog
, wType
, 0, dwEventID
,
258 NULL
, 1, 0, &lpMsg
, NULL
))
266 BOOL
GetInstalledVersion_WowUser(ATL::CStringW
* szVersionResult
,
267 const ATL::CStringW
& szRegName
,
271 BOOL bHasSucceded
= FALSE
;
273 ATL::CStringW szVersion
;
274 ATL::CStringW szPath
= ATL::CStringW(L
"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%ls") + szRegName
;
276 if (key
.Open(IsUserKey
? HKEY_CURRENT_USER
: HKEY_LOCAL_MACHINE
,
278 keyWow
| KEY_READ
) != ERROR_SUCCESS
)
283 if (szVersionResult
!= NULL
)
285 ULONG dwSize
= MAX_PATH
* sizeof(WCHAR
);
287 if (key
.QueryStringValue(L
"DisplayVersion",
288 szVersion
.GetBuffer(MAX_PATH
),
289 &dwSize
) == ERROR_SUCCESS
)
291 szVersion
.ReleaseBuffer();
292 *szVersionResult
= szVersion
;
297 szVersion
.ReleaseBuffer();
303 szVersion
.ReleaseBuffer();
310 BOOL
GetInstalledVersion(ATL::CStringW
*pszVersion
, const ATL::CStringW
&szRegName
)
312 return (!szRegName
.IsEmpty()
313 && (GetInstalledVersion_WowUser(pszVersion
, szRegName
, TRUE
, KEY_WOW64_32KEY
)
314 || GetInstalledVersion_WowUser(pszVersion
, szRegName
, FALSE
, KEY_WOW64_32KEY
)
315 || GetInstalledVersion_WowUser(pszVersion
, szRegName
, TRUE
, KEY_WOW64_64KEY
)
316 || GetInstalledVersion_WowUser(pszVersion
, szRegName
, FALSE
, KEY_WOW64_64KEY
)));
321 CConfigParser::CConfigParser(const ATL::CStringW
& FileName
) : szConfigPath(GetINIFullPath(FileName
))
326 ATL::CStringW
CConfigParser::GetINIFullPath(const ATL::CStringW
& FileName
)
329 ATL::CStringW szBuffer
;
331 GetStorageDirectory(szDir
);
332 szBuffer
.Format(L
"%ls\\rapps\\%ls", szDir
.GetString(), FileName
.GetString());
337 VOID
CConfigParser::CacheINILocale()
339 // TODO: Set default locale if call fails
340 // find out what is the current system lang code (e.g. "0a") and append it to SectionLocale
341 GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE
,
342 m_szLocaleID
.GetBuffer(m_cchLocaleSize
), m_cchLocaleSize
);
344 m_szLocaleID
.ReleaseBuffer();
345 m_szCachedINISectionLocale
= L
"Section." + m_szLocaleID
;
347 // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part
348 if (m_szLocaleID
.GetLength() >= 2)
349 m_szCachedINISectionLocaleNeutral
= L
"Section." + m_szLocaleID
.Right(2);
351 m_szCachedINISectionLocaleNeutral
= m_szCachedINISectionLocale
;
354 BOOL
CConfigParser::GetStringWorker(const ATL::CStringW
& KeyName
, PCWSTR Suffix
, ATL::CStringW
& ResultString
)
358 LPWSTR ResultStringBuffer
= ResultString
.GetBuffer(MAX_PATH
);
359 // 1st - find localized strings (e.g. "Section.0c0a")
360 dwResult
= GetPrivateProfileStringW((m_szCachedINISectionLocale
+ Suffix
).GetString(),
365 szConfigPath
.GetString());
369 // 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a")
370 dwResult
= GetPrivateProfileStringW((m_szCachedINISectionLocaleNeutral
+ Suffix
).GetString(),
375 szConfigPath
.GetString());
378 // 3rd - if they weren't present fallback to standard english strings (just "Section")
379 dwResult
= GetPrivateProfileStringW((ATL::CStringW(L
"Section") + Suffix
).GetString(),
384 szConfigPath
.GetString());
388 ResultString
.ReleaseBuffer();
389 return (dwResult
!= 0 ? TRUE
: FALSE
);
392 BOOL
CConfigParser::GetString(const ATL::CStringW
& KeyName
, ATL::CStringW
& ResultString
)
395 if (GetStringWorker(KeyName
, L
"." CurrentArchitecture
, ResultString
))
401 /* On non-x86 architecture we need the architecture specific URL */
402 if (KeyName
== L
"URLDownload")
408 /* Fall back to default */
409 return GetStringWorker(KeyName
, L
"", ResultString
);
412 BOOL
CConfigParser::GetInt(const ATL::CStringW
& KeyName
, INT
& iResult
)
414 ATL::CStringW Buffer
;
418 // grab the text version of our entry
419 if (!GetString(KeyName
, Buffer
))
422 if (Buffer
.IsEmpty())
425 // convert it to an actual integer
426 iResult
= StrToIntW(Buffer
.GetString());
428 // we only care about values > 0
429 return (iResult
> 0);
434 BOOL
PathAppendNoDirEscapeW(LPWSTR pszPath
, LPCWSTR pszMore
)
436 WCHAR pszPathBuffer
[MAX_PATH
]; // buffer to store result
437 WCHAR pszPathCopy
[MAX_PATH
];
439 if (!PathCanonicalizeW(pszPathCopy
, pszPath
))
444 PathRemoveBackslashW(pszPathCopy
);
446 if (StringCchCopyW(pszPathBuffer
, _countof(pszPathBuffer
), pszPathCopy
) != S_OK
)
451 if (!PathAppendW(pszPathBuffer
, pszMore
))
457 if (StringCchLengthW(pszPathCopy
, _countof(pszPathCopy
), &PathLen
) != S_OK
)
461 int CommonPrefixLen
= PathCommonPrefixW(pszPathCopy
, pszPathBuffer
, NULL
);
463 if ((unsigned int)CommonPrefixLen
!= PathLen
)
465 // pszPathBuffer should be a file/folder under pszPath.
466 // but now common prefix len is smaller than length of pszPathCopy
467 // hacking use ".." ?
471 if (StringCchCopyW(pszPath
, MAX_PATH
, pszPathBuffer
) != S_OK
)
483 if (bIsSys64ResultCached
)
485 // just return cached result
486 return bIsSys64Result
;
490 typedef void (WINAPI
*LPFN_PGNSI
)(LPSYSTEM_INFO
);
491 LPFN_PGNSI pGetNativeSystemInfo
= (LPFN_PGNSI
)GetProcAddress(GetModuleHandle(L
"kernel32.dll"), "GetNativeSystemInfo");
492 if (pGetNativeSystemInfo
)
494 pGetNativeSystemInfo(&si
);
495 if (si
.wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
|| si
.wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_IA64
)
497 bIsSys64Result
= TRUE
;
502 bIsSys64Result
= FALSE
;
505 bIsSys64ResultCached
= TRUE
; // next time calling this function, it will directly return bIsSys64Result
506 return bIsSys64Result
;
509 INT
GetSystemColorDepth()
514 pDevMode
.dmSize
= sizeof(pDevMode
);
515 pDevMode
.dmDriverExtra
= 0;
517 if (!EnumDisplaySettingsW(NULL
, ENUM_CURRENT_SETTINGS
, &pDevMode
))
519 /* TODO: Error message */
523 switch (pDevMode
.dmBitsPerPel
)
525 case 32: ColorDepth
= ILC_COLOR32
; break;
526 case 24: ColorDepth
= ILC_COLOR24
; break;
527 case 16: ColorDepth
= ILC_COLOR16
; break;
528 case 8: ColorDepth
= ILC_COLOR8
; break;
529 case 4: ColorDepth
= ILC_COLOR4
; break;
530 default: ColorDepth
= ILC_COLOR
; break;
536 void UnixTimeToFileTime(DWORD dwUnixTime
, LPFILETIME pFileTime
)
538 // Note that LONGLONG is a 64-bit value
541 ll
= Int32x32To64(dwUnixTime
, 10000000) + 116444736000000000;
542 pFileTime
->dwLowDateTime
= (DWORD
)ll
;
543 pFileTime
->dwHighDateTime
= ll
>> 32;
546 BOOL
SearchPatternMatch(LPCWSTR szHaystack
, LPCWSTR szNeedle
)
550 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
551 return StrStrIW(szHaystack
, szNeedle
) != NULL
;