diff --git a/dll/win32/iernonce/CMakeLists.txt b/dll/win32/iernonce/CMakeLists.txt index 76a09b87985..954ffa4b952 100644 --- a/dll/win32/iernonce/CMakeLists.txt +++ b/dll/win32/iernonce/CMakeLists.txt @@ -5,6 +5,7 @@ include_directories(include) spec2def(iernonce.dll iernonce.spec) add_library(iernonce MODULE + dialog.cpp iernonce.cpp registry.cpp iernonce.rc @@ -13,5 +14,5 @@ add_library(iernonce MODULE set_module_type(iernonce win32dll UNICODE) target_link_libraries(iernonce cppstl atl_classes) set_target_cpp_properties(iernonce WITH_EXCEPTIONS) -add_importlibs(iernonce advapi32 msvcrt kernel32 user32 ntdll) +add_importlibs(iernonce advapi32 msvcrt gdi32 ole32 shell32 shlwapi kernel32 user32 ntdll) add_cd_file(TARGET iernonce DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/iernonce/dialog.cpp b/dll/win32/iernonce/dialog.cpp new file mode 100644 index 00000000000..c86e9c68ef4 --- /dev/null +++ b/dll/win32/iernonce/dialog.cpp @@ -0,0 +1,245 @@ +/* + * 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 +#include +#include +#include + +#include "dialog.h" +#include "registry.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) + { + if (DoModal() == -1) + { + return FALSE; + } + } + 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. + EndDialog(0); + } + 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; +} diff --git a/dll/win32/iernonce/dialog.h b/dll/win32/iernonce/dialog.h new file mode 100644 index 00000000000..95ba0a574d0 --- /dev/null +++ b/dll/win32/iernonce/dialog.h @@ -0,0 +1,44 @@ +/* + * 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> + */ + +#pragma once + +#include +#include + +#include "resource.h" +#include "registry.h" + +#define WM_SETINDEX (WM_USER + 1) + +class ProgressDlg : public CDialogImpl +{ +private: + INT_PTR m_DialogID; + HWND m_hListBox; + HFONT m_hBoldFont; + HBITMAP m_hArrowBmp; + BITMAP m_ArrowBmp; + INT m_PointedItem; + +public: + enum { IDD = IDD_DIALOG }; + + RunOnceExInstance &m_RunOnceExInst; + + ProgressDlg(_In_ RunOnceExInstance &RunOnceExInst); + + BOOL RunDialogBox(); + + void CalcTextRect(_In_ LPCWSTR lpText, _Inout_ RECT *pRect); + + void ResizeListBoxAndDialog(_In_ int NewHeight); + + BOOL ProcessWindowMessage(_In_ HWND hwnd, _In_ UINT message, _In_ WPARAM wParam, + _In_ LPARAM lParam, _Out_ LRESULT& lResult, + _In_ DWORD dwMsgMapID); +}; diff --git a/dll/win32/iernonce/iernonce.cpp b/dll/win32/iernonce/iernonce.cpp index 0dec15ab26d..3efd332992b 100644 --- a/dll/win32/iernonce/iernonce.cpp +++ b/dll/win32/iernonce/iernonce.cpp @@ -15,7 +15,7 @@ #include #include "registry.h" - +#include "dialog.h" BOOL WINAPI @@ -26,6 +26,7 @@ DllMain(_In_ HINSTANCE hinstDLL, switch (dwReason) { case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); break; case DLL_PROCESS_DETACH: break; @@ -37,19 +38,42 @@ DllMain(_In_ HINSTANCE hinstDLL, extern "C" VOID WINAPI RunOnceExProcess(_In_ HWND hwnd, _In_ HINSTANCE hInst, - _In_ LPCSTR path, - _In_ int nShow) + _In_ LPCSTR pszCmdLine, + _In_ int nCmdShow) { - RunOnceExInstance RunonceExInst_LM(HKEY_LOCAL_MACHINE); - RunOnceExInstance RunonceExInst_CU(HKEY_CURRENT_USER); - - if (RunonceExInst_LM.m_bSuccess) + // iernonce may use shell32 API. + HRESULT Result = CoInitialize(NULL); + if (Result != S_OK && Result != S_FALSE) { - // TODO: continue coding here + return; } - if (RunonceExInst_CU.m_bSuccess) + HKEY RootKeys[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER }; + for (UINT i = 0; i < _countof(RootKeys); ++i) { - // TODO: continue coding here + RunOnceExInstance Instance(RootKeys[i]); + if (!Instance.m_bSuccess) + continue; + + if ((Instance.m_dwFlags & FLAGS_NO_STAT_DIALOG) || !Instance.m_bShowDialog) + { + Instance.Exec(NULL); + } + else + { + // The dialog is responsible to create a thread and execute. + ProgressDlg dlg(Instance); + dlg.RunDialogBox(); + } } + + CoUninitialize(); +} + +extern "C" VOID WINAPI +InitCallback( + _In_ PVOID Callback, + _In_ BOOL bSilence) +{ + // FIXME: unimplemented } diff --git a/dll/win32/iernonce/iernonce.spec b/dll/win32/iernonce/iernonce.spec index 808989a74af..23898e470b1 100644 --- a/dll/win32/iernonce/iernonce.spec +++ b/dll/win32/iernonce/iernonce.spec @@ -1 +1,2 @@ -@ stdcall RunOnceExProcess(ptr ptr str long) \ No newline at end of file +@ stdcall RunOnceExProcess(ptr ptr str long) +@ stdcall InitCallback(ptr long) diff --git a/dll/win32/iernonce/include/registry.h b/dll/win32/iernonce/include/registry.h index 2afd4f9097c..0d03f7d4282 100644 --- a/dll/win32/iernonce/include/registry.h +++ b/dll/win32/iernonce/include/registry.h @@ -13,6 +13,11 @@ #include #include +#define FLAGS_NO_STAT_DIALOG 0x00000080 + +#ifndef UNICODE +#error This project must be compiled with UNICODE! +#endif class CRegKeyEx : public CRegKey { @@ -26,22 +31,28 @@ public: class RunOnceExEntry { private: - ATL::CStringW m_Name; ATL::CStringW m_Value; + ATL::CStringW m_Name; public: + RunOnceExEntry( _In_ const ATL::CStringW &Name, _In_ const ATL::CStringW &Value); - friend int RunOnceExEntryCmp(_In_ const void *a, _In_ const void *b); + BOOL Delete(_In_ CRegKeyEx &hParentKey); + BOOL Exec() const; + + friend int RunOnceExEntryCmp( + _In_ const void *a, + _In_ const void *b); }; class RunOnceExSection { private: ATL::CStringW m_SectionName; - CSimpleArray m_EntryList; + CRegKeyEx m_RegKey; BOOL HandleValue( _In_ CRegKeyEx &hKey, @@ -50,17 +61,29 @@ private: public: BOOL m_bSuccess; ATL::CStringW m_SectionTitle; + CSimpleArray m_EntryList; + RunOnceExSection( _In_ CRegKeyEx &hParentKey, _In_ const CStringW &lpSubKeyName); - friend int RunOnceExSectionCmp(_In_ const void *a, _In_ const void *b); + RunOnceExSection(_In_ const RunOnceExSection &Section); + + BOOL CloseAndDelete(_In_ CRegKeyEx &hParentKey); + + BOOL Exec(); + + friend int RunOnceExSectionCmp( + _In_ const void *a, + _In_ const void *b); + + friend class RunOnceExInstance; }; class RunOnceExInstance { private: - CSimpleArray m_SectionList; + CRegKeyEx m_RegKey; BOOL HandleSubKey( _In_ CRegKeyEx &hKey, @@ -68,5 +91,12 @@ private: public: BOOL m_bSuccess; + CSimpleArray m_SectionList; + CStringW m_Title; + DWORD m_dwFlags; + BOOL m_bShowDialog; + RunOnceExInstance(_In_ HKEY BaseKey); + + BOOL Exec(_In_opt_ HWND hwnd); }; diff --git a/dll/win32/iernonce/registry.cpp b/dll/win32/iernonce/registry.cpp index 45f135a8d1a..8ac9def1e39 100644 --- a/dll/win32/iernonce/registry.cpp +++ b/dll/win32/iernonce/registry.cpp @@ -8,10 +8,12 @@ #include #include +#include #include #include #include "registry.h" +#include "dialog.h" LONG CRegKeyEx::EnumValueName( _In_ DWORD iIndex, @@ -25,9 +27,59 @@ LONG CRegKeyEx::EnumValueName( RunOnceExEntry::RunOnceExEntry( _In_ const ATL::CStringW &Name, _In_ const ATL::CStringW &Value) : - m_Name(Name), m_Value(Value) + m_Value(Value), m_Name(Name) { ; } +BOOL RunOnceExEntry::Delete( + _In_ CRegKeyEx &hParentKey) +{ + return hParentKey.DeleteValue(m_Name) == ERROR_SUCCESS; +} + +BOOL RunOnceExEntry::Exec() const +{ + CStringW CommandLine; + if (wcsncmp(m_Value, L"||", 2) == 0) + { + // Remove the prefix. + CommandLine = (LPCWSTR)m_Value + 2; + } + else + { + CommandLine = m_Value; + } + + // FIXME: SHEvaluateSystemCommandTemplate is not implemented + // using PathGetArgsW, PathRemoveArgsW as a workaround. + LPWSTR szCommandLine = CommandLine.GetBuffer(); + LPCWSTR szParam = PathGetArgsW(szCommandLine); + PathRemoveArgsW(szCommandLine); + + SHELLEXECUTEINFOW Info = { 0 }; + Info.cbSize = sizeof(Info); + Info.fMask = SEE_MASK_NOCLOSEPROCESS; + Info.lpFile = szCommandLine; + Info.lpParameters = szParam; + Info.nShow = SW_SHOWNORMAL; + + BOOL bSuccess = ShellExecuteExW(&Info); + + CommandLine.ReleaseBuffer(); + + if (!bSuccess) + { + return FALSE; + } + + if (Info.hProcess) + { + WaitForSingleObject(Info.hProcess, INFINITE); + CloseHandle(Info.hProcess); + } + + return TRUE; +} + int RunOnceExEntryCmp( _In_ const void *a, _In_ const void *b) @@ -65,14 +117,19 @@ BOOL RunOnceExSection::HandleValue( szBuffer[cbData / sizeof(WCHAR)] = L'\0'; Buffer.ReleaseBuffer(); + CStringW ExpandStr; + DWORD dwcchExpand = ExpandEnvironmentStringsW(Buffer, NULL, 0); + ExpandEnvironmentStringsW(Buffer, ExpandStr.GetBuffer(dwcchExpand + 1), dwcchExpand); + ExpandStr.ReleaseBuffer(); + if (ValueName.IsEmpty()) { - // this is the default value + // The default value specifies the section title. m_SectionTitle = Buffer; } else { - m_EntryList.Add(RunOnceExEntry(ValueName, Buffer)); + m_EntryList.Add(RunOnceExEntry(ValueName, ExpandStr)); } return TRUE; @@ -84,16 +141,15 @@ RunOnceExSection::RunOnceExSection( m_SectionName(lpSubKeyName) { m_bSuccess = FALSE; - CRegKeyEx hKey; DWORD dwValueNum; DWORD dwMaxValueNameLen; LSTATUS Error; CStringW ValueName; - if (hKey.Open(hParentKey, lpSubKeyName, KEY_READ) != ERROR_SUCCESS) + if (m_RegKey.Open(hParentKey, lpSubKeyName) != ERROR_SUCCESS) return; - Error = RegQueryInfoKeyW(hKey, NULL, 0, NULL, NULL, NULL, NULL, + Error = RegQueryInfoKeyW(m_RegKey, NULL, 0, NULL, NULL, NULL, NULL, &dwValueNum, &dwMaxValueNameLen, NULL, NULL, NULL); if (Error != ERROR_SUCCESS) @@ -105,7 +161,7 @@ RunOnceExSection::RunOnceExSection( DWORD dwcchName = dwMaxValueNameLen + 1; szValueName = ValueName.GetBuffer(dwMaxValueNameLen + 1); - Error = hKey.EnumValueName(i, szValueName, &dwcchName); + Error = m_RegKey.EnumValueName(i, szValueName, &dwcchName); ValueName.ReleaseBuffer(); if (Error != ERROR_SUCCESS) @@ -114,20 +170,50 @@ RunOnceExSection::RunOnceExSection( return; } - if (!HandleValue(hKey, ValueName)) + if (!HandleValue(m_RegKey, ValueName)) return; } - // sort entries by name in string order. - qsort(m_EntryList.GetData(), m_EntryList.GetSize(), sizeof(RunOnceExEntry), - RunOnceExEntryCmp); + // Sort entries by name in string order. + qsort(m_EntryList.GetData(), m_EntryList.GetSize(), + sizeof(RunOnceExEntry), RunOnceExEntryCmp); - hKey.Close(); m_bSuccess = TRUE; return; } -int RunOnceExSectionCmp(_In_ const void *a, _In_ const void *b) +// Copy constructor, CSimpleArray needs it. +RunOnceExSection::RunOnceExSection(_In_ const RunOnceExSection& Section) : + m_SectionName(Section.m_SectionName), + m_bSuccess(Section.m_bSuccess), + m_SectionTitle(Section.m_SectionTitle), + m_EntryList(Section.m_EntryList) +{ + m_RegKey.Attach(Section.m_RegKey); +} + +BOOL RunOnceExSection::CloseAndDelete( + _In_ CRegKeyEx &hParentKey) +{ + m_RegKey.Close(); + return hParentKey.RecurseDeleteKey(m_SectionName) == ERROR_SUCCESS; +} + +BOOL RunOnceExSection::Exec() +{ + BOOL bSuccess = TRUE; + + for (int i = 0; i < m_EntryList.GetSize(); i++) + { + m_EntryList[i].Delete(m_RegKey); + bSuccess &= m_EntryList[i].Exec(); + } + return bSuccess; +} + +int RunOnceExSectionCmp( + _In_ const void *a, + _In_ const void *b) { return lstrcmpW(((RunOnceExSection *)a)->m_SectionName, ((RunOnceExSection *)b)->m_SectionName); @@ -136,32 +222,49 @@ int RunOnceExSectionCmp(_In_ const void *a, _In_ const void *b) RunOnceExInstance::RunOnceExInstance(_In_ HKEY BaseKey) { m_bSuccess = FALSE; - CRegKeyEx hKey; DWORD dwSubKeyNum; DWORD dwMaxSubKeyNameLen; LSTATUS Error; CStringW SubKeyName; - if (hKey.Open(BaseKey, - L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\", - KEY_READ) != ERROR_SUCCESS) + Error = m_RegKey.Open(BaseKey, + L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\"); + if (Error != ERROR_SUCCESS) { return; } - Error = RegQueryInfoKeyW(hKey, NULL, 0, NULL, + ULONG cchTitle; + Error = m_RegKey.QueryStringValue(L"Title", NULL, &cchTitle); + if (Error == ERROR_SUCCESS) + { + Error = m_RegKey.QueryStringValue(L"Title", m_Title.GetBuffer(cchTitle + 1), &cchTitle); + m_Title.ReleaseBuffer(); + if (Error != ERROR_SUCCESS) + return; + } + + Error = m_RegKey.QueryDWORDValue(L"Flags", m_dwFlags); + if (Error != ERROR_SUCCESS) + { + m_dwFlags = 0; + } + + Error = RegQueryInfoKeyW(m_RegKey, NULL, 0, NULL, &dwSubKeyNum, &dwMaxSubKeyNameLen, NULL, NULL, NULL, NULL, NULL, NULL); if (Error != ERROR_SUCCESS) return; + m_bShowDialog = FALSE; + for (DWORD i = 0; i < dwSubKeyNum; i++) { LPWSTR szSubKeyName; DWORD dwcchName = dwMaxSubKeyNameLen + 1; szSubKeyName = SubKeyName.GetBuffer(dwMaxSubKeyNameLen + 1); - Error = hKey.EnumKey(i, szSubKeyName, &dwcchName); + Error = m_RegKey.EnumKey(i, szSubKeyName, &dwcchName); SubKeyName.ReleaseBuffer(); if (Error != ERROR_SUCCESS) @@ -170,29 +273,60 @@ RunOnceExInstance::RunOnceExInstance(_In_ HKEY BaseKey) return; } - if (!HandleSubKey(hKey, SubKeyName)) + if (!HandleSubKey(m_RegKey, SubKeyName)) return; } - // sort sections by name in string order. - qsort(m_SectionList.GetData(), m_SectionList.GetSize(), sizeof(RunOnceExSection), - RunOnceExSectionCmp); + // Sort sections by name in string order. + qsort(m_SectionList.GetData(), m_SectionList.GetSize(), + sizeof(RunOnceExSection), RunOnceExSectionCmp); - hKey.Close(); m_bSuccess = TRUE; return; } +BOOL RunOnceExInstance::Exec(_In_opt_ HWND hwnd) +{ + BOOL bSuccess = TRUE; + + // Execute items from registry one by one, and remove them. + for (int i = 0; i < m_SectionList.GetSize(); i++) + { + if (hwnd) + SendMessageW(hwnd, WM_SETINDEX, i, 0); + + bSuccess &= m_SectionList[i].Exec(); + m_SectionList[i].CloseAndDelete(m_RegKey); + } + + m_RegKey.DeleteValue(L"Title"); + m_RegKey.DeleteValue(L"Flags"); + + // Notify the dialog all sections are handled. + if (hwnd) + SendMessageW(hwnd, WM_SETINDEX, m_SectionList.GetSize(), 0); + return bSuccess; +} + BOOL RunOnceExInstance::HandleSubKey( _In_ CRegKeyEx &hKey, _In_ const CStringW& SubKeyName) { - RunOnceExSection RunOnceExSection(hKey, SubKeyName); - if (!RunOnceExSection.m_bSuccess) + RunOnceExSection Section(hKey, SubKeyName); + if (!Section.m_bSuccess) { return FALSE; } - m_SectionList.Add(RunOnceExSection); + if (!Section.m_SectionTitle.IsEmpty()) + { + m_bShowDialog = TRUE; + } + m_SectionList.Add(Section); + + // The copy constructor of RunOnceExSection didn't detach + // the m_RegKey while it's attached to the one in the array. + // So we have to detach it manually. + Section.m_RegKey.Detach(); return TRUE; }