Something went wrong. Try again.
Reactos
Something went wrong. Try again.
19 kB · 715 lines
C++
at listview
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716/* * PROJECT: ReactOS Applications Manager * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Misc functions * COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org) * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com) * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) */
#include "rapps.h"#include "misc.h"
static HANDLE hLog = NULL;
UINTErrorBox(HWND hOwner, UINT Error){ if (!Error) Error = ERROR_INTERNAL_ERROR; // Note: geninst.cpp depends on this WCHAR buf[400]; UINT fmf = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM; FormatMessageW(fmf, NULL, Error, 0, buf, _countof(buf), NULL); MessageBoxW(hOwner, buf, 0, MB_OK | MB_ICONSTOP); return Error;}
VOIDCopyTextToClipboard(LPCWSTR lpszText){ if (!OpenClipboard(NULL)) { return; }
HRESULT hr; HGLOBAL ClipBuffer; LPWSTR Buffer; DWORD cchBuffer;
EmptyClipboard(); cchBuffer = wcslen(lpszText) + 1; ClipBuffer = GlobalAlloc(GMEM_DDESHARE, cchBuffer * sizeof(WCHAR));
Buffer = (PWCHAR)GlobalLock(ClipBuffer); hr = StringCchCopyW(Buffer, cchBuffer, lpszText); GlobalUnlock(ClipBuffer);
if (SUCCEEDED(hr)) SetClipboardData(CF_UNICODETEXT, ClipBuffer);
CloseClipboard();}
static INT_PTR CALLBACKNothingDlgProc(HWND hDlg, UINT uMsg, WPARAM, LPARAM){ return uMsg == WM_CLOSE ? DestroyWindow(hDlg) : FALSE;}
VOIDEmulateDialogReposition(HWND hwnd){ static const DWORD DlgTmpl[] = { WS_POPUP | WS_CAPTION | WS_SYSMENU, 0, 0, 0, 0, 0 }; HWND hDlg = CreateDialogIndirectW(NULL, (LPDLGTEMPLATE)DlgTmpl, NULL, NothingDlgProc); if (hDlg) { RECT r; GetWindowRect(hwnd, &r); if (SetWindowPos(hDlg, hDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE)) { SendMessage(hDlg, DM_REPOSITION, 0, 0); if (GetWindowRect(hDlg, &r)) SetWindowPos(hwnd, hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE); } SendMessage(hDlg, WM_CLOSE, 0, 0); }}
VOIDShowPopupMenuEx(HWND hwnd, HWND hwndOwner, UINT MenuID, UINT DefaultItem, POINT *Point){ HMENU hMenu = NULL; HMENU hPopupMenu; MENUITEMINFO ItemInfo; POINT pt;
if (MenuID) { hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(MenuID)); hPopupMenu = GetSubMenu(hMenu, 0); } else { hPopupMenu = GetMenu(hwnd); }
ZeroMemory(&ItemInfo, sizeof(ItemInfo)); ItemInfo.cbSize = sizeof(ItemInfo); ItemInfo.fMask = MIIM_STATE;
GetMenuItemInfoW(hPopupMenu, DefaultItem, FALSE, &ItemInfo);
if (!(ItemInfo.fState & MFS_GRAYED)) { SetMenuDefaultItem(hPopupMenu, DefaultItem, FALSE); }
if (!Point) { GetCursorPos(Point = &pt); }
SetForegroundWindow(hwnd); TrackPopupMenu(hPopupMenu, 0, Point->x, Point->y, 0, hwndOwner, NULL);
if (hMenu) { DestroyMenu(hMenu); }}
extern BOOL IsZipFile(PCWSTR Path);
UINTClassifyFile(PCWSTR Path){ const UINT share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; HANDLE hFile = CreateFileW(Path, GENERIC_READ, share, NULL, OPEN_EXISTING, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) { BYTE buf[8]; DWORD io; if (!ReadFile(hFile, buf, sizeof(buf), &io, NULL) || io != sizeof(buf)) buf[0] = 0; CloseHandle(hFile);
if (buf[0] == 0xD0 && buf[1] == 0xCF && buf[2] == 0x11 && buf[3] == 0xE0 && buf[4] == 0xA1 && buf[5] == 0xB1 && buf[6] == 0x1A && buf[7] == 0xE1) { return MAKEWORD('M', PERCEIVED_TYPE_APPLICATION); // MSI } if (buf[0] == 'M' || buf[0] == 'Z') { SHFILEINFO shfi; if (SHGetFileInfoW(Path, 0, &shfi, sizeof(shfi), SHGFI_EXETYPE)) return MAKEWORD('E', PERCEIVED_TYPE_APPLICATION); } if (buf[0] == 'M' && buf[1] == 'S' && buf[2] == 'C' && buf[3] == 'F') { return MAKEWORD('C', PERCEIVED_TYPE_COMPRESSED); // CAB } }
if (IsZipFile(Path)) // .zip last because we want to return SFX.exe with higher priority { return MAKEWORD('Z', PERCEIVED_TYPE_COMPRESSED); } return PERCEIVED_TYPE_UNKNOWN;}
BOOLOpensWithExplorer(PCWSTR Path){ WCHAR szCmd[MAX_PATH * 2]; DWORD cch = _countof(szCmd); PCWSTR pszExt = PathFindExtensionW(Path); HRESULT hr = AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN | ASSOCF_NOTRUNCATE, ASSOCSTR_COMMAND, pszExt, NULL, szCmd, &cch); if (SUCCEEDED(hr) && StrStrIW(szCmd, L" zipfldr.dll,")) // .zip return TRUE; PathRemoveArgsW(szCmd); return SUCCEEDED(hr) && !StrCmpIW(PathFindFileNameW(szCmd), L"explorer.exe"); // .cab}
BOOLStartProcess(const CStringW &Path, BOOL Wait){ PROCESS_INFORMATION pi; STARTUPINFOW si; DWORD dwRet; MSG msg;
ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW;
// The Unicode version of CreateProcess can modify the contents of this string. CStringW Tmp = Path; BOOL fSuccess = CreateProcessW(NULL, Tmp.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); Tmp.ReleaseBuffer(); if (!fSuccess) { return FALSE; }
CloseHandle(pi.hThread);
if (Wait) { EnableWindow(hMainWnd, FALSE); }
while (Wait) { dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLEVENTS); if (dwRet == WAIT_OBJECT_0 + 1) { while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageW(&msg); } } else { if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED) break; } }
CloseHandle(pi.hProcess);
if (Wait) { EnableWindow(hMainWnd, TRUE); SetForegroundWindow(hMainWnd); // We got the real activation message during MsgWaitForMultipleObjects while // we were disabled, we need to set the focus again now. SetFocus(hMainWnd); }
return TRUE;}
BOOLGetStorageDirectory(CStringW &Directory){ static CStringW CachedDirectory; static BOOL CachedDirectoryInitialized = FALSE;
if (!CachedDirectoryInitialized) { LPWSTR DirectoryStr = CachedDirectory.GetBuffer(MAX_PATH); BOOL bHasPath = SHGetSpecialFolderPathW(NULL, DirectoryStr, CSIDL_LOCAL_APPDATA, TRUE); if (bHasPath) { PathAppendW(DirectoryStr, RAPPS_NAME); } CachedDirectory.ReleaseBuffer();
if (bHasPath) { if (!CreateDirectoryW(CachedDirectory, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { CachedDirectory.Empty(); } } else { CachedDirectory.Empty(); }
CachedDirectoryInitialized = TRUE; }
Directory = CachedDirectory; return !Directory.IsEmpty();}
VOIDInitLogs(){ if (!SettingsInfo.bLogEnabled) { return; }
WCHAR szPath[MAX_PATH]; DWORD dwCategoryNum = 1; DWORD dwDisp, dwData; ATL::CRegKey key;
if (key.Create( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\ReactOS Application Manager", REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &dwDisp) != ERROR_SUCCESS) { return; }
if (!GetModuleFileNameW(NULL, szPath, _countof(szPath))) { return; }
dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
if ((key.SetStringValue(L"EventMessageFile", szPath, REG_EXPAND_SZ) == ERROR_SUCCESS) && (key.SetStringValue(L"CategoryMessageFile", szPath, REG_EXPAND_SZ) == ERROR_SUCCESS) && (key.SetDWORDValue(L"TypesSupported", dwData) == ERROR_SUCCESS) && (key.SetDWORDValue(L"CategoryCount", dwCategoryNum) == ERROR_SUCCESS))
{ hLog = RegisterEventSourceW(NULL, L"ReactOS Application Manager"); }}
VOIDFreeLogs(){ if (hLog) { DeregisterEventSource(hLog); }}
BOOLWriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg){ if (!SettingsInfo.bLogEnabled) { return TRUE; }
if (!ReportEventW(hLog, wType, 0, dwEventID, NULL, 1, 0, &lpMsg, NULL)) { return FALSE; }
return TRUE;}
BOOLGetInstalledVersion_WowUser(CStringW *szVersionResult, const CStringW &szRegName, BOOL IsUserKey, REGSAM keyWow){ BOOL bHasSucceded = FALSE; ATL::CRegKey key; CStringW szVersion; CStringW szPath = CStringW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\") + szRegName;
if (key.Open(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szPath.GetString(), keyWow | KEY_READ) != ERROR_SUCCESS) { return FALSE; }
if (szVersionResult != NULL) { ULONG dwSize = MAX_PATH * sizeof(WCHAR);
if (key.QueryStringValue(L"DisplayVersion", szVersion.GetBuffer(MAX_PATH), &dwSize) == ERROR_SUCCESS) { szVersion.ReleaseBuffer(); *szVersionResult = szVersion; bHasSucceded = TRUE; } else { szVersion.ReleaseBuffer(); } } else { bHasSucceded = TRUE; }
return bHasSucceded;}
BOOLGetInstalledVersion(CStringW *pszVersion, const CStringW &szRegName){ return ( !szRegName.IsEmpty() && (GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_32KEY) || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_32KEY) || GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_64KEY) || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_64KEY)));}
BOOLIsSystem64Bit(){#ifdef _WIN64 return TRUE;#else static UINT cache = 0; if (!cache) cache = 1 + (IsOS(OS_WOW6432) != FALSE); return cache - 1;#endif}
ULONGGetNTVersion(){ RTL_OSVERSIONINFOW osvi = {0}; osvi.dwOSVersionInfoSize = sizeof(osvi); RtlGetVersion(&osvi);
return (osvi.dwMajorVersion << 8) | (osvi.dwMinorVersion);}
INTGetSystemColorDepth(){ DEVMODEW pDevMode; INT ColorDepth;
pDevMode.dmSize = sizeof(pDevMode); pDevMode.dmDriverExtra = 0;
if (!EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &pDevMode)) { /* TODO: Error message */ return ILC_COLOR; }
switch (pDevMode.dmBitsPerPel) { case 32: ColorDepth = ILC_COLOR32; break; case 24: ColorDepth = ILC_COLOR24; break; case 16: ColorDepth = ILC_COLOR16; break; case 8: ColorDepth = ILC_COLOR8; break; case 4: ColorDepth = ILC_COLOR4; break; default: ColorDepth = ILC_COLOR; break; }
return ColorDepth;}
voidUnixTimeToFileTime(DWORD dwUnixTime, LPFILETIME pFileTime){ // Note that LONGLONG is a 64-bit value LONGLONG ll;
ll = Int32x32To64(dwUnixTime, 10000000) + 116444736000000000; pFileTime->dwLowDateTime = (DWORD)ll; pFileTime->dwHighDateTime = ll >> 32;}
HRESULTRegKeyHasValues(HKEY hKey, LPCWSTR Path, REGSAM wowsam){ CRegKey key; LONG err = key.Open(hKey, Path, KEY_QUERY_VALUE | wowsam); if (err == ERROR_SUCCESS) { WCHAR name[1]; DWORD cchname = _countof(name), cbsize = 0; err = RegEnumValueW(key, 0, name, &cchname, NULL, NULL, NULL, &cbsize); if (err == ERROR_NO_MORE_ITEMS) return S_FALSE; if (err == ERROR_MORE_DATA) err = ERROR_SUCCESS; } return HRESULT_FROM_WIN32(err);}
LPCWSTRGetRegString(CRegKey &Key, LPCWSTR Name, CStringW &Value){ for (;;) { ULONG cb = 0, cch; ULONG err = Key.QueryValue(Name, NULL, NULL, &cb); if (err) break; cch = cb / sizeof(WCHAR); LPWSTR p = Value.GetBuffer(cch + 1); p[cch] = UNICODE_NULL; err = Key.QueryValue(Name, NULL, (BYTE*)p, &cb); if (err == ERROR_MORE_DATA) continue; if (err) break; Value.ReleaseBuffer(); return Value.GetString(); } return NULL;}
boolExpandEnvStrings(CStringW &Str){ CStringW buf; DWORD cch = ExpandEnvironmentStringsW(Str, NULL, 0); if (cch) { if (ExpandEnvironmentStringsW(Str, buf.GetBuffer(cch), cch) == cch) { buf.ReleaseBuffer(cch - 1); Str = buf; return true; } } return false;}
BOOLSearchPatternMatch(LPCWSTR szHaystack, LPCWSTR szNeedle){ if (!*szNeedle) return TRUE; /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */ return StrStrIW(szHaystack, szNeedle) != NULL;}
BOOLDeleteDirectoryTree(LPCWSTR Dir, HWND hwnd){ CStringW from(Dir); UINT cch = from.GetLength(); from.Append(L"00"); LPWSTR p = from.GetBuffer(); p[cch] = p[cch + 1] = L'\0'; // Double null-terminate UINT fof = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT; SHFILEOPSTRUCT shfos = { hwnd, FO_DELETE, p, NULL, (FILEOP_FLAGS)fof }; return SHFileOperationW(&shfos);}
UINTCreateDirectoryTree(LPCWSTR Dir){ UINT err = SHCreateDirectory(NULL, Dir); return err == ERROR_ALREADY_EXISTS ? 0 : err;}
CStringWSplitFileAndDirectory(LPCWSTR FullPath, CStringW *pDir){ CPathW dir = FullPath; //int win = dir.ReverseFind(L'\\'), nix = dir.ReverseFind(L'/'), sep = max(win, nix); int sep = dir.FindFileName(); CStringW file = dir.m_strPath.Mid(sep); if (pDir) *pDir = sep == -1 ? L"" : dir.m_strPath.Left(sep - 1); return file;}
HRESULTGetSpecialPath(UINT csidl, CStringW &Path, HWND hwnd){ if (!SHGetSpecialFolderPathW(hwnd, Path.GetBuffer(MAX_PATH), csidl, TRUE)) return E_FAIL; Path.ReleaseBuffer(); return S_OK;}
HRESULTGetKnownPath(REFKNOWNFOLDERID kfid, CStringW &Path, DWORD Flags){ PWSTR p; FARPROC f = GetProcAddress(LoadLibraryW(L"SHELL32"), "SHGetKnownFolderPath"); if (!f) return HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); HRESULT hr = ((HRESULT(WINAPI*)(REFKNOWNFOLDERID,UINT,HANDLE,PWSTR*))f)(kfid, Flags, NULL, &p); if (FAILED(hr)) return hr; Path = p; CoTaskMemFree(p); return hr;}
HRESULTGetProgramFilesPath(CStringW &Path, BOOL PerUser, HWND hwnd){ if (!PerUser) return GetSpecialPath(CSIDL_PROGRAM_FILES, Path, hwnd);
HRESULT hr = GetKnownPath(FOLDERID_UserProgramFiles, Path); if (FAILED(hr)) { hr = GetSpecialPath(CSIDL_LOCAL_APPDATA, Path, hwnd); // Use the correct path on NT6 (on NT5 the path becomes a bit long) if (SUCCEEDED(hr) && LOBYTE(GetVersion()) >= 6) { Path = BuildPath(Path, L"Programs"); // Should not be localized } } return hr;}
static BOOLReadAt(HANDLE Handle, UINT Offset, LPVOID Buffer, UINT Size){ OVERLAPPED ol = {}; ol.Offset = Offset; DWORD cb; return ReadFile(Handle, Buffer, Size, &cb, &ol) && cb == Size;}
InstallerTypeGuessInstallerType(LPCWSTR Installer, UINT &ExtraInfo){ ExtraInfo = 0; InstallerType it = INSTALLER_UNKNOWN;
HANDLE hFile = CreateFileW(Installer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) return it;
BYTE buf[0x30 + 12]; if (!ReadAt(hFile, 0, buf, sizeof(buf))) goto done;
if (buf[0] == 0xD0 && buf[1] == 0xCF && buf[2] == 0x11 && buf[3] == 0xE0) { if (!StrCmpIW(L".msi", PathFindExtensionW(Installer))) { it = INSTALLER_MSI; goto done; } }
if (buf[0] != 'M' || buf[1] != 'Z') goto done;
// <= Inno 5.1.4 { UINT sig[3]; C_ASSERT(sizeof(buf) >= 0x30 + sizeof(sig)); CopyMemory(sig, buf + 0x30, sizeof(sig)); if (sig[0] == 0x6F6E6E49 && sig[1] == ~sig[2]) { it = INSTALLER_INNO; ExtraInfo = 1; goto done; } }
// NSIS 1.6+ { UINT nsis[1+1+3+1+1], nsisskip = 512; for (UINT nsisoffset = nsisskip * 20; nsisoffset < 1024 * 1024 * 50; nsisoffset += nsisskip) { if (ReadAt(hFile, nsisoffset, nsis, sizeof(nsis)) && nsis[1] == 0xDEADBEEF) { if (nsis[2] == 0x6C6C754E && nsis[3] == 0x74666F73 && nsis[4] == 0x74736E49) { it = INSTALLER_NSIS; goto done; } } } }
if (HMODULE hMod = LoadLibraryEx(Installer, NULL, LOAD_LIBRARY_AS_DATAFILE)) { // Inno enum { INNORCSETUPLDR = 11111 }; HGLOBAL hGlob; HRSRC hRsrc = FindResourceW(hMod, MAKEINTRESOURCE(INNORCSETUPLDR), RT_RCDATA); if (hRsrc && (hGlob = LoadResource(hMod, hRsrc)) != NULL) { if (BYTE *p = (BYTE*)LockResource(hGlob)) { if (p[0] == 'r' && p[1] == 'D' && p[2] == 'l' && p[3] == 'P' && p[4] == 't' && p[5] == 'S') it = INSTALLER_INNO; UnlockResource((void*)p); } } FreeLibrary(hMod); }done: CloseHandle(hFile); return it;}
BOOLGetSilentInstallParameters(InstallerType InstallerType, UINT ExtraInfo, LPCWSTR Installer, CStringW &Parameters){ switch (InstallerType) { case INSTALLER_MSI: { Parameters.Format(L"/i \"%s\" /qn", Installer); return TRUE; }
case INSTALLER_INNO: { LPCWSTR pszInnoParams = L"/SILENT /VERYSILENT /SP-"; if (ExtraInfo) Parameters.Format(L"%s", pszInnoParams); else Parameters.Format(L"%s /SUPPRESSMSGBOXES", pszInnoParams); // https://jrsoftware.org/files/is5.5-whatsnew.htm return TRUE; }
case INSTALLER_NSIS: { Parameters = L"/S"; return TRUE; }
default: { return FALSE; } }}