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

This commit is contained in:
He Yang 2021-08-22 17:13:56 +08:00 committed by George Bișoc
parent 83eaa87304
commit 32340a2ae6
7 changed files with 523 additions and 44 deletions

View file

@ -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)

View file

@ -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 <atlbase.h>
#include <atlwin.h>
#include <windowsx.h>
#include <process.h>
#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;
}

View file

@ -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 <atlbase.h>
#include <atlwin.h>
#include "resource.h"
#include "registry.h"
#define WM_SETINDEX (WM_USER + 1)
class ProgressDlg : public CDialogImpl<ProgressDlg>
{
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);
};

View file

@ -15,7 +15,7 @@
#include <debug.h>
#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
}

View file

@ -1 +1,2 @@
@ stdcall RunOnceExProcess(ptr ptr str long)
@ stdcall RunOnceExProcess(ptr ptr str long)
@ stdcall InitCallback(ptr long)

View file

@ -13,6 +13,11 @@
#include <atlcoll.h>
#include <atlsimpcoll.h>
#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<RunOnceExEntry> m_EntryList;
CRegKeyEx m_RegKey;
BOOL HandleValue(
_In_ CRegKeyEx &hKey,
@ -50,17 +61,29 @@ private:
public:
BOOL m_bSuccess;
ATL::CStringW m_SectionTitle;
CSimpleArray<RunOnceExEntry> 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<RunOnceExSection> m_SectionList;
CRegKeyEx m_RegKey;
BOOL HandleSubKey(
_In_ CRegKeyEx &hKey,
@ -68,5 +91,12 @@ private:
public:
BOOL m_bSuccess;
CSimpleArray<RunOnceExSection> m_SectionList;
CStringW m_Title;
DWORD m_dwFlags;
BOOL m_bShowDialog;
RunOnceExInstance(_In_ HKEY BaseKey);
BOOL Exec(_In_opt_ HWND hwnd);
};

View file

@ -8,10 +8,12 @@
#include <cassert>
#include <cstdlib>
#include <shlwapi.h>
#include <windows.h>
#include <winreg.h>
#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;
}