reactos/dll/win32/iernonce/dialog.cpp
He Yang 4d0cc20681
[IERNONCE] [RUNONCEEX] Add RunOnceEx functionality for ReactOS (#3926)
* [IERNONCE] Implement the registry management code.

* [EXPLORER] handle RunOnceEx by invoking RunOnceEx in iernonce.dll

* [IERNONCE] Display a dialog to show progress, and execute entries.

* [IERNONCE] Add `InitCallback` function
2021-09-29 11:30:32 +02:00

238 lines
6.9 KiB
C++

/*
* PROJECT: ReactOS system libraries
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Classes for displaying progress dialog.
* COPYRIGHT: Copyright 2021 He Yang <1160386205@qq.com>
*/
#include "iernonce.h"
#include <process.h>
#define ITEM_VPADDING 3
#define ITEM_LEFTPADDING 22
HFONT CreateBoldFont(_In_ HFONT hOrigFont)
{
LOGFONTW fontAttributes = { 0 };
GetObjectW(hOrigFont, sizeof(fontAttributes), &fontAttributes);
fontAttributes.lfWeight = FW_BOLD;
return CreateFontIndirectW(&fontAttributes);
}
ProgressDlg::ProgressDlg(_In_ RunOnceExInstance &RunOnceExInst) :
m_hListBox(NULL),
m_hBoldFont(NULL),
m_PointedItem(0),
m_RunOnceExInst(RunOnceExInst)
{ ; }
BOOL ProgressDlg::RunDialogBox()
{
// Show the dialog and run the items only when the list is not empty.
if (m_RunOnceExInst.m_SectionList.GetSize() != 0)
{
return (DoModal() == 1);
}
return TRUE;
}
void ProgressDlg::CalcTextRect(
_In_ LPCWSTR lpText,
_Inout_ PRECT pRect)
{
HDC hdc = ::GetDC(m_hListBox);
::GetClientRect(m_hListBox, pRect);
pRect->bottom = pRect->top;
pRect->left += ITEM_LEFTPADDING;
HFONT OldFont = SelectFont(hdc, GetFont());
DrawTextW(hdc, lpText, -1, pRect, DT_CALCRECT | DT_WORDBREAK);
SelectFont(hdc, OldFont);
::ReleaseDC(m_hListBox, hdc);
pRect->bottom -= pRect->top;
pRect->bottom += ITEM_VPADDING * 2;
pRect->top = 0;
pRect->right -= pRect->left;
pRect->left = 0;
}
void ProgressDlg::ResizeListBoxAndDialog(_In_ int NewHeight)
{
RECT ListBoxRect;
RECT DlgRect;
::GetWindowRect(m_hListBox, &ListBoxRect);
GetWindowRect(&DlgRect);
int HeightDiff = NewHeight - (ListBoxRect.bottom - ListBoxRect.top);
::SetWindowPos(m_hListBox, NULL, 0, 0,
ListBoxRect.right - ListBoxRect.left, NewHeight,
SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
SetWindowPos(HWND_TOP, 0, 0,
DlgRect.right - DlgRect.left,
DlgRect.bottom - DlgRect.top + HeightDiff,
SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
}
unsigned int __stdcall
RunOnceExExecThread(_In_ void *Param)
{
ProgressDlg *pProgressDlg = (ProgressDlg *)Param;
pProgressDlg->m_RunOnceExInst.Exec(pProgressDlg->m_hWnd);
return 0;
}
BOOL
ProgressDlg::ProcessWindowMessage(
_In_ HWND hwnd,
_In_ UINT message,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_Out_ LRESULT& lResult,
_In_ DWORD dwMsgMapID)
{
lResult = 0;
switch (message)
{
case WM_INITDIALOG:
{
if (!m_RunOnceExInst.m_Title.IsEmpty())
{
SetWindowTextW(m_RunOnceExInst.m_Title);
}
m_hListBox = GetDlgItem(IDC_LB_ITEMS);
m_hBoldFont = CreateBoldFont(GetFont());
m_hArrowBmp = LoadBitmapW(NULL, MAKEINTRESOURCE(OBM_MNARROW));
GetObjectW(m_hArrowBmp, sizeof(BITMAP), &m_ArrowBmp);
// Add all sections with non-empty title into listbox
int TotalHeight = 0;
for (int i = 0; i < m_RunOnceExInst.m_SectionList.GetSize(); i++)
{
RunOnceExSection &Section = m_RunOnceExInst.m_SectionList[i];
if (!Section.m_SectionTitle.IsEmpty())
{
INT Index = ListBox_AddString(m_hListBox, Section.m_SectionTitle);
TotalHeight += ListBox_GetItemHeight(m_hListBox, Index);
ListBox_SetItemData(m_hListBox, Index, i);
}
}
// Remove the sunken-edged border from the listbox.
::SetWindowLongPtr(m_hListBox, GWL_EXSTYLE, ::GetWindowLongPtr(m_hListBox, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE);
ResizeListBoxAndDialog(TotalHeight);
// Launch a thread to execute tasks.
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, RunOnceExExecThread, (void *)this, 0, NULL);
if (hThread == INVALID_HANDLE_VALUE)
{
EndDialog(0);
return TRUE;
}
CloseHandle(hThread);
lResult = TRUE; // set keyboard focus to the dialog box control.
break;
}
case WM_MEASUREITEM:
{
PMEASUREITEMSTRUCT pMeasureItem = (PMEASUREITEMSTRUCT)lParam;
RECT TextRect = { 0 };
CStringW ItemText;
ListBox_GetText(m_hListBox, pMeasureItem->itemID,
ItemText.GetBuffer(ListBox_GetTextLen(m_hListBox,
pMeasureItem->itemID) + 1));
CalcTextRect(ItemText, &TextRect);
ItemText.ReleaseBuffer();
pMeasureItem->itemHeight = TextRect.bottom - TextRect.top;
pMeasureItem->itemWidth = TextRect.right - TextRect.left;
break;
}
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT pDrawItem = (PDRAWITEMSTRUCT)lParam;
CStringW ItemText;
ListBox_GetText(m_hListBox, pDrawItem->itemID,
ItemText.GetBuffer(ListBox_GetTextLen(m_hListBox,
pDrawItem->itemID) + 1));
SetBkMode(pDrawItem->hDC, TRANSPARENT);
HFONT hOldFont = NULL;
if (m_PointedItem == (INT)pDrawItem->itemData)
{
HDC hCompDC = CreateCompatibleDC(pDrawItem->hDC);
SelectBitmap(hCompDC, m_hArrowBmp);
int IconLeftPadding = (ITEM_LEFTPADDING - m_ArrowBmp.bmWidth) / 2;
int IconTopPadding = (pDrawItem->rcItem.bottom - pDrawItem->rcItem.top - m_ArrowBmp.bmHeight) / 2;
BitBlt(pDrawItem->hDC, IconLeftPadding, pDrawItem->rcItem.top + IconTopPadding,
m_ArrowBmp.bmWidth, m_ArrowBmp.bmHeight, hCompDC, 0, 0, SRCAND);
DeleteDC(hCompDC);
hOldFont = SelectFont(pDrawItem->hDC, m_hBoldFont);
}
pDrawItem->rcItem.left += ITEM_LEFTPADDING;
pDrawItem->rcItem.top += ITEM_VPADDING;
DrawTextW(pDrawItem->hDC, ItemText, -1,
&(pDrawItem->rcItem), DT_WORDBREAK);
if (hOldFont)
{
SelectFont(pDrawItem->hDC, hOldFont);
}
ItemText.ReleaseBuffer();
break;
}
case WM_SETINDEX:
{
if ((int)wParam == m_RunOnceExInst.m_SectionList.GetSize())
{
// All sections are handled, lParam is bSuccess.
EndDialog(lParam);
}
m_PointedItem = wParam;
InvalidateRect(NULL);
break;
}
case WM_CTLCOLORLISTBOX:
{
lResult = (LRESULT)GetStockBrush(NULL_BRUSH);
break;
}
case WM_DESTROY:
{
DeleteObject(m_hArrowBmp);
DeleteFont(m_hBoldFont);
break;
}
}
return TRUE;
}