[0.4.15][RAPPS] Backport current RAPPS into 0.4.15

This is a squashed backport of RAPPS from current master into the 0.4.15 release tree. All of these changes were deemed stable and complete.

This backport includes the following commits:
5bc6d59142 [RAPPS] Refresh item info after installer completes (#7697)
d5ce3d28ab [RAPPS] Don't display Freeware license string if the type is also Freeware (#7689)
b35becef2e [RAPPS] Set working directory for zip generated shortcuts (#7674)
a23db39c8a [RAPPS] Allow database to override download filename (#7668)
c8b2c4c94d [RAPPS] Check Let's Encrypt issuer prefix (#7650)
72951421e6 [RAPPS] Reuse active pending downloads window (#7648)
91b8923601 [RAPPS] Allow .zip generated installers to skip writing the DisplayIcon value (#7609)
2834e5b3c8 [RAPPS] Initialize SHBrowseForFolder to current download folder (#7505)
9164e9f85f [RAPPS] Update Slovak (sk-SK) translation (#7450)
8734889272 [RAPPS] Update Turkish (tr-TR) translation (#7372)
16f1abe1c8 [RAPPS] Improve Romanian (ro-RO) translation (#7360)
2f83e6a65d [RAPPS] Use different mutex and title for AppWiz mode (#7350)
301675c112 [RAPPS] Respect partial settings configuration (#7247)
053939e27c [RAPPS] Hide the main window during active download/install if the user closes it (#7014)
3ff8adc553 [RAPPS] Protect database update with a mutex (#7006)
4e59858941 [RAPPS] Change the "Welcome" text with a suitable explanatory one in APPWIZ-mode (#6655)
2af6fd4def [PSDK] Add GetMenuPosFromID() declaration in shlwapi.h
This commit is contained in:
Carl J. Bialorucki 2025-02-17 20:01:35 -07:00
parent 7791a36fc2
commit b5c1fdc1cc
45 changed files with 1605 additions and 1402 deletions

View file

@ -16,6 +16,50 @@ using namespace Gdiplus;
HICON g_hDefaultPackageIcon = NULL;
static int g_DefaultPackageIconILIdx = I_IMAGENONE;
// **** Menu helpers ****
BOOL
DeleteMenuEx(
_In_ HMENU hMenu,
_In_ UINT uPosition,
_In_ UINT uFlags)
{
INT pos;
MENUITEMINFOW mii = { sizeof(mii), MIIM_FTYPE, 0 };
bool bIsValidItem1, bIsValidItem2;
bool bIsSep1, bIsSep2;
if (uFlags & MF_BYPOSITION)
pos = (INT)uPosition;
else
pos = ::GetMenuPosFromID(hMenu, uPosition);
if (pos < 0)
return FALSE;
bIsValidItem1 = ((pos > 0) && ::GetMenuItemInfoW(hMenu, pos - 1, TRUE, &mii));
bIsSep1 = bIsValidItem1 && !!(mii.fType & MFT_SEPARATOR);
bIsValidItem2 = ::GetMenuItemInfoW(hMenu, pos + 1, TRUE, &mii);
bIsSep2 = bIsValidItem2 && !!(mii.fType & MFT_SEPARATOR);
if (bIsSep1 && !bIsSep2 && !bIsValidItem2)
pos = pos - 1; // Delete separator only if pos+1 has no item
else if (!bIsSep1 && bIsSep2 && !bIsValidItem1)
pos = pos + 1; // Delete separator only if pos-1 has no item
else if (bIsSep1 && bIsSep2)
pos = pos + 1;
else
pos = -1;
// Delete one of the separators if necessary
if (pos != -1)
::DeleteMenu(hMenu, pos, MF_BYPOSITION);
// Finally, delete the menu item itself.
return ::DeleteMenu(hMenu, uPosition, uFlags);
}
// **** Menu helpers ****
// **** CMainToolbar ****
VOID
@ -149,26 +193,28 @@ CMainToolbar::Create(HWND hwndParent)
AddButtons(_countof(Buttons), Buttons);
/* Remember ideal width to use as a max width of buttons */
SIZE size;
GetIdealSize(FALSE, &size);
m_dButtonsWidthMax = size.cx;
/* Remember the ideal width to use as a max width of buttons */
UpdateMaxButtonsWidth();
return m_hWnd;
}
VOID
CMainToolbar::HideButtonCaption()
void
CMainToolbar::ShowButtonCaption(bool bShow)
{
DWORD dCurrentExStyle = (DWORD)SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle | TBSTYLE_EX_MIXEDBUTTONS);
if (bShow)
SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle & ~TBSTYLE_EX_MIXEDBUTTONS);
else
SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle | TBSTYLE_EX_MIXEDBUTTONS);
}
VOID
CMainToolbar::ShowButtonCaption()
void
CMainToolbar::UpdateMaxButtonsWidth()
{
DWORD dCurrentExStyle = (DWORD)SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle & ~TBSTYLE_EX_MIXEDBUTTONS);
SIZE size;
GetIdealSize(FALSE, &size);
m_dButtonsWidthMax = size.cx;
}
DWORD
@ -267,21 +313,6 @@ CAppRichEdit::InsertTextWithString(UINT StringID, const CStringW &Text, DWORD Te
LoadAndInsertText(StringID, Text, TextFlags);
}
}
VOID
CAppRichEdit::SetWelcomeText()
{
CStringW szText;
szText.LoadStringW(IDS_WELCOME_TITLE);
SetText(szText, CFE_BOLD);
szText.LoadStringW(IDS_WELCOME_TEXT);
InsertText(szText, 0);
szText.LoadStringW(IDS_WELCOME_URL);
InsertText(szText, CFM_LINK);
}
// **** CAppRichEdit ****
int
@ -924,27 +955,59 @@ CAppInfoDisplay::Create(HWND hwndParent)
}
VOID
CAppInfoDisplay::ShowAppInfo(CAppInfo *Info)
CAppInfoDisplay::ShowAppInfo(CAppInfo &Info, bool OnlyUpdateText)
{
CStringW ScrnshotLocation;
if (Info->RetrieveScreenshot(ScrnshotLocation))
if (!OnlyUpdateText)
{
ScrnshotPrev->DisplayImage(ScrnshotLocation);
CStringW ScrnshotLocation;
if (Info.RetrieveScreenshot(ScrnshotLocation))
{
ScrnshotPrev->DisplayImage(ScrnshotLocation);
}
else
{
ScrnshotPrev->DisplayEmpty();
}
}
ResizeChildren();
Info.ShowAppInfo(RichEdit);
}
void
CAppInfoDisplay::SetWelcomeText(bool bAppwiz)
{
CStringW szText;
ScrnshotPrev->DisplayEmpty();
ResizeChildren();
// Display the standard banner in normal mode, or
// the specific "Add/Remove Programs" in APPWIZ-mode.
if (!bAppwiz)
{
szText.LoadStringW(IDS_WELCOME_TITLE);
RichEdit->SetText(szText, CFE_BOLD);
RichEdit->InsertText(L"\n\n", 0);
szText.LoadStringW(IDS_WELCOME_TEXT);
RichEdit->InsertText(szText, 0);
szText.LoadStringW(IDS_WELCOME_URL);
RichEdit->InsertText(szText, CFM_LINK);
}
else
{
ScrnshotPrev->DisplayEmpty();
}
ResizeChildren();
Info->ShowAppInfo(RichEdit);
}
szText.LoadStringW(IDS_APPWIZ_TITLE);
RichEdit->SetText(szText, CFE_BOLD);
RichEdit->InsertText(L"\n\n", 0);
VOID
CAppInfoDisplay::SetWelcomeText()
{
ScrnshotPrev->DisplayEmpty();
ResizeChildren();
RichEdit->SetWelcomeText();
szText.LoadStringW(IDS_APPWIZ_TEXT1);
RichEdit->InsertText(szText, 0);
RichEdit->InsertText(L"\n", 0);
szText.LoadStringW(IDS_APPWIZ_TEXT2);
RichEdit->InsertText(szText, 0);
}
}
VOID
@ -1113,19 +1176,11 @@ CAppsListView::SetWatermark(const CStringW &Text)
m_Watermark = Text;
}
VOID
CAppsListView::SetCheckboxesVisible(BOOL bIsVisible)
void
CAppsListView::ShowCheckboxes(bool bShow)
{
if (bIsVisible)
{
SetExtendedListViewStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
}
else
{
SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
}
bHasCheckboxes = bIsVisible;
SetExtendedListViewStyle((bShow ? LVS_EX_CHECKBOXES : 0) | LVS_EX_FULLROWSELECT);
bHasCheckboxes = bShow;
}
VOID
@ -1258,7 +1313,7 @@ CAppsListView::Create(HWND hwndParent)
if (hwnd)
{
SetCheckboxesVisible(FALSE);
ShowCheckboxes(false);
}
#pragma push_macro("SubclassWindow")
@ -1359,16 +1414,18 @@ CAppsListView::SetDisplayAppType(APPLICATION_VIEW_TYPE AppType)
/* Add columns to ListView */
szText.LoadStringW(IDS_APP_NAME);
AddColumn(ColumnCount++, szText, 250, LVCFMT_LEFT);
AddColumn(ColumnCount++, szText, 368, LVCFMT_LEFT);
szText.LoadStringW(IDS_APP_INST_VERSION);
AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
#if 0 // This column is not currently useful for installed apps.
szText.LoadStringW(IDS_APP_DESCRIPTION);
AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
#endif
// disable checkboxes
SetCheckboxesVisible(FALSE);
// Disable checkboxes
ShowCheckboxes(false);
break;
case AppViewTypeAvailableApps:
@ -1383,8 +1440,8 @@ CAppsListView::SetDisplayAppType(APPLICATION_VIEW_TYPE AppType)
szText.LoadStringW(IDS_APP_DESCRIPTION);
AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
// enable checkboxes
SetCheckboxesVisible(TRUE);
// Enable checkboxes
ShowCheckboxes(true);
break;
default:
@ -1490,6 +1547,41 @@ CApplicationView::ProcessWindowMessage(
bSuccess &= CreateListView();
bSuccess &= CreateAppInfoDisplay();
/* APPWIZ-mode: Remove the unneeded menu items and toolbar buttons */
if (m_MainWindow->m_bAppwizMode)
{
HMENU hMenu;
/* Delete the "Settings" item in the "File" sub-menu */
hMenu = ::GetSubMenu(m_MainWindow->GetMenu(), 0);
DeleteMenuEx(hMenu, ID_SETTINGS, MF_BYCOMMAND);
/* Remove the menu items: ID_INSTALL, ID_RESETDB */
hMenu = GetMenu();
DeleteMenuEx(hMenu, ID_INSTALL, MF_BYCOMMAND);
DeleteMenuEx(hMenu, ID_RESETDB, MF_BYCOMMAND);
/* Remove the toolbar buttons:
* ID_INSTALL, ID_CHECK_ALL, ID_RESETDB
* We only keep:
* ID_UNINSTALL, ID_MODIFY, ID_REFRESH */
TBBUTTONINFO info = { sizeof(info), 0 };
int index;
index = m_Toolbar->GetButtonInfo(ID_INSTALL, &info);
if (index >= 0) m_Toolbar->DeleteButton(index);
index = m_Toolbar->GetButtonInfo(ID_CHECK_ALL, &info);
if (index >= 0) m_Toolbar->DeleteButton(index);
index = m_Toolbar->GetButtonInfo(ID_RESETDB, &info);
if (index >= 0) m_Toolbar->DeleteButton(index);
/* Update the ideal width to use as a max width of buttons */
m_Toolbar->UpdateMaxButtonsWidth();
}
/* Resize the toolbar */
m_Toolbar->AutoSize();
RECT rTop;
@ -1716,6 +1808,22 @@ CApplicationView::SetRedraw(BOOL bRedraw)
m_ListView->SetRedraw(bRedraw);
}
void
CApplicationView::RefreshAvailableItem(PCWSTR PackageName)
{
if (ApplicationViewType != AppViewTypeAvailableApps || !PackageName)
return;
CAppInfo *pApp;
for (UINT i = 0; (pApp = (CAppInfo*)m_ListView->GetItemData(i)) != NULL; ++i)
{
if (pApp->szIdentifier.CompareNoCase(PackageName) == 0)
{
RefreshDetailsPane(*pApp, true);
break;
}
}
}
void
CApplicationView::SetFocusOnSearchBar()
{
@ -1728,7 +1836,7 @@ CApplicationView::OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
if (wParam == SIZE_MINIMIZED)
return;
/* Size tool bar */
/* Resize the toolbar */
m_Toolbar->AutoSize();
/* Automatically hide captions */
@ -1737,11 +1845,11 @@ CApplicationView::OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
if (dSearchbarMargin > dToolbarTreshold)
{
m_Toolbar->ShowButtonCaption();
m_Toolbar->ShowButtonCaption(true);
}
else if (dSearchbarMargin < dToolbarTreshold)
{
m_Toolbar->HideButtonCaption();
m_Toolbar->ShowButtonCaption(false);
}
RECT r = {0, 0, LOWORD(lParam), HIWORD(lParam)};
@ -1917,9 +2025,10 @@ CApplicationView::Create(HWND hwndParent)
{
RECT r = {0, 0, 0, 0};
HMENU menu = GetSubMenu(LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATIONMENU)), 0);
// Pick the "Programs" sub-menu for building the context menu.
HMENU hMenu = ::GetSubMenu(m_MainWindow->GetMenu(), 1);
return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, menu);
return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, hMenu);
}
BOOL
@ -1930,32 +2039,41 @@ CApplicationView::SetDisplayAppType(APPLICATION_VIEW_TYPE AppType)
return FALSE;
}
ApplicationViewType = AppType;
m_AppsInfo->SetWelcomeText();
m_AppsInfo->SetWelcomeText(m_MainWindow->m_bAppwizMode);
HMENU hMenu = ::GetMenu(m_hWnd);
switch (AppType)
{
case AppViewTypeInstalledApps:
EnableMenuItem(hMenu, ID_REGREMOVE, MF_ENABLED);
{
EnableMenuItem(hMenu, ID_INSTALL, MF_GRAYED);
EnableMenuItem(hMenu, ID_UNINSTALL, MF_ENABLED);
EnableMenuItem(hMenu, ID_MODIFY, MF_ENABLED);
EnableMenuItem(hMenu, ID_REGREMOVE, MF_ENABLED);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_CHECK_ALL, FALSE);
break;
}
case AppViewTypeAvailableApps:
EnableMenuItem(hMenu, ID_REGREMOVE, MF_GRAYED);
{
// We shouldn't get there in APPWIZ-mode.
ATLASSERT(!m_MainWindow->m_bAppwizMode);
EnableMenuItem(hMenu, ID_INSTALL, MF_ENABLED);
EnableMenuItem(hMenu, ID_UNINSTALL, MF_GRAYED);
EnableMenuItem(hMenu, ID_MODIFY, MF_GRAYED);
EnableMenuItem(hMenu, ID_REGREMOVE, MF_GRAYED);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_CHECK_ALL, TRUE);
break;
}
}
return TRUE;
}
@ -2035,6 +2153,12 @@ CApplicationView::RestoreListSelection(const RESTORELISTSELECTION &Restore)
}
}
VOID
CApplicationView::RefreshDetailsPane(CAppInfo &Info, bool OnlyUpdateText)
{
m_AppsInfo->ShowAppInfo(Info, OnlyUpdateText);
}
// this function is called when a item of listview get focus.
// CallbackParam is the param passed to listview when adding the item (the one getting focus now).
VOID
@ -2043,7 +2167,7 @@ CApplicationView::ItemGetFocus(LPVOID CallbackParam)
if (CallbackParam)
{
CAppInfo *Info = static_cast<CAppInfo *>(CallbackParam);
m_AppsInfo->ShowAppInfo(Info);
RefreshDetailsPane(*Info);
if (ApplicationViewType == AppViewTypeInstalledApps)
{