mirror of
https://github.com/reactos/reactos.git
synced 2024-09-28 21:44:31 +00:00
[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
This commit is contained in:
parent
b5fae844de
commit
4d0cc20681
|
@ -3,6 +3,7 @@
|
||||||
* Copyright (C) 2002 Shachar Shemesh
|
* Copyright (C) 2002 Shachar Shemesh
|
||||||
* Copyright (C) 2013 Edijs Kolesnikovics
|
* Copyright (C) 2013 Edijs Kolesnikovics
|
||||||
* Copyright (C) 2018 Katayama Hirofumi MZ
|
* Copyright (C) 2018 Katayama Hirofumi MZ
|
||||||
|
* Copyright (C) 2021 He Yang
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -28,7 +29,7 @@
|
||||||
* The operations performed are (by order of execution):
|
* The operations performed are (by order of execution):
|
||||||
*
|
*
|
||||||
* After log in
|
* After log in
|
||||||
* - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnceEx (synch, no imp)
|
* - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnceEx (synch)
|
||||||
* - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce (synch)
|
* - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce (synch)
|
||||||
* - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run (asynch)
|
* - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run (asynch)
|
||||||
* - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run (asynch)
|
* - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run (asynch)
|
||||||
|
@ -36,7 +37,7 @@
|
||||||
* - Current user Startup folder "%USERPROFILE%\Start Menu\Programs\Startup" (asynch, no imp)
|
* - Current user Startup folder "%USERPROFILE%\Start Menu\Programs\Startup" (asynch, no imp)
|
||||||
* - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce (asynch)
|
* - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce (asynch)
|
||||||
*
|
*
|
||||||
* None is processed in Safe Mode // FIXME: Check RunOnceEx in Safe Mode
|
* None is processed in Safe Mode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
@ -317,6 +318,68 @@ end:
|
||||||
return res == ERROR_SUCCESS ? TRUE : FALSE;
|
return res == ERROR_SUCCESS ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process "RunOnceEx" type registry key.
|
||||||
|
* rundll32.exe will be invoked if the corresponding key has items inside, and wait for it.
|
||||||
|
* hkRoot is the HKEY from which
|
||||||
|
* "Software\Microsoft\Windows\CurrentVersion\RunOnceEx"
|
||||||
|
* is opened.
|
||||||
|
*/
|
||||||
|
static BOOL ProcessRunOnceEx(HKEY hkRoot)
|
||||||
|
{
|
||||||
|
HKEY hkRunOnceEx = NULL;
|
||||||
|
LONG res = ERROR_SUCCESS;
|
||||||
|
WCHAR cmdLine[] = L"rundll32 iernonce.dll RunOnceExProcess";
|
||||||
|
DWORD dwSubKeyCnt;
|
||||||
|
|
||||||
|
res = RegOpenKeyExW(hkRoot,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx",
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&hkRunOnceEx);
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
TRACE("RegOpenKeyW failed on Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx (%ld)\n", res);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = RegQueryInfoKeyW(hkRunOnceEx,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&dwSubKeyCnt,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
TRACE("RegQueryInfoKeyW failed on Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx (%ld)\n", res);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwSubKeyCnt != 0)
|
||||||
|
{
|
||||||
|
if (runCmd(cmdLine, NULL, TRUE, TRUE) == INVALID_RUNCMD_RETURN)
|
||||||
|
{
|
||||||
|
TRACE("runCmd failed (%ld)\n", res = GetLastError());
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (hkRunOnceEx != NULL)
|
||||||
|
RegCloseKey(hkRunOnceEx);
|
||||||
|
|
||||||
|
TRACE("done\n");
|
||||||
|
|
||||||
|
return res == ERROR_SUCCESS ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
AutoStartupApplications(INT nCSIDL_Folder)
|
AutoStartupApplications(INT nCSIDL_Folder)
|
||||||
{
|
{
|
||||||
|
@ -414,7 +477,9 @@ INT ProcessStartupItems(VOID)
|
||||||
* stopping if one fails, skipping if necessary.
|
* stopping if one fails, skipping if necessary.
|
||||||
*/
|
*/
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
/* TODO: RunOnceEx */
|
|
||||||
|
if (res && bNormalBoot)
|
||||||
|
ProcessRunOnceEx(HKEY_LOCAL_MACHINE);
|
||||||
|
|
||||||
if (res && (SHRestricted(REST_NOLOCALMACHINERUNONCE) == 0))
|
if (res && (SHRestricted(REST_NOLOCALMACHINERUNONCE) == 0))
|
||||||
res = ProcessRunKeys(HKEY_LOCAL_MACHINE, L"RunOnce", TRUE, TRUE);
|
res = ProcessRunKeys(HKEY_LOCAL_MACHINE, L"RunOnce", TRUE, TRUE);
|
||||||
|
|
|
@ -1,11 +1,23 @@
|
||||||
|
project(iernonce)
|
||||||
|
|
||||||
|
include_directories(include)
|
||||||
|
|
||||||
spec2def(iernonce.dll iernonce.spec)
|
spec2def(iernonce.dll iernonce.spec)
|
||||||
|
|
||||||
|
list(APPEND SOURCE
|
||||||
|
dialog.cpp
|
||||||
|
iernonce.cpp
|
||||||
|
registry.cpp
|
||||||
|
iernonce.h)
|
||||||
|
|
||||||
add_library(iernonce MODULE
|
add_library(iernonce MODULE
|
||||||
iernonce.c
|
${SOURCE}
|
||||||
iernonce.rc
|
iernonce.rc
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/iernonce.def)
|
${CMAKE_CURRENT_BINARY_DIR}/iernonce.def)
|
||||||
|
|
||||||
set_module_type(iernonce win32dll UNICODE)
|
set_module_type(iernonce win32dll UNICODE)
|
||||||
add_importlibs(iernonce msvcrt kernel32 ntdll)
|
target_link_libraries(iernonce cppstl atl_classes)
|
||||||
|
set_target_cpp_properties(iernonce WITH_EXCEPTIONS)
|
||||||
|
add_importlibs(iernonce advapi32 msvcrt gdi32 ole32 shell32 shlwapi kernel32 user32 ntdll)
|
||||||
|
add_pch(iernonce iernonce.h SOURCE)
|
||||||
add_cd_file(TARGET iernonce DESTINATION reactos/system32 FOR all)
|
add_cd_file(TARGET iernonce DESTINATION reactos/system32 FOR all)
|
||||||
|
|
237
dll/win32/iernonce/dialog.cpp
Normal file
237
dll/win32/iernonce/dialog.cpp
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
46
dll/win32/iernonce/dialog.h
Normal file
46
dll/win32/iernonce/dialog.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
// When wParam < item count ==> wParam is item index (0 based)
|
||||||
|
// wParam = item count ==> all finished, lParam = bSuccess
|
||||||
|
#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);
|
||||||
|
};
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* PROJECT: ReactOS system libraries
|
|
||||||
* LICENSE: GPL - See COPYING in the top level directory
|
|
||||||
* FILE: dll\win32\iernonce\iernonce.c
|
|
||||||
* PURPOSE: ReactOS Extended RunOnce processing with UI
|
|
||||||
* PROGRAMMERS: Copyright 2013-2016 Robert Naumann
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#define WIN32_NO_STATUS
|
|
||||||
#include <windef.h>
|
|
||||||
#include <winbase.h>
|
|
||||||
|
|
||||||
#define NDEBUG
|
|
||||||
#include <debug.h>
|
|
||||||
|
|
||||||
HINSTANCE hInstance;
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
WINAPI
|
|
||||||
DllMain(HINSTANCE hinstDLL,
|
|
||||||
DWORD dwReason,
|
|
||||||
LPVOID reserved)
|
|
||||||
{
|
|
||||||
switch (dwReason)
|
|
||||||
{
|
|
||||||
case DLL_PROCESS_ATTACH:
|
|
||||||
break;
|
|
||||||
case DLL_PROCESS_DETACH:
|
|
||||||
hInstance = hinstDLL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID WINAPI RunOnceExProcess(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow)
|
|
||||||
{
|
|
||||||
DPRINT1("RunOnceExProcess() not implemented\n");
|
|
||||||
}
|
|
61
dll/win32/iernonce/iernonce.cpp
Normal file
61
dll/win32/iernonce/iernonce.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS system libraries
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: ReactOS Extended RunOnce processing with UI.
|
||||||
|
* COPYRIGHT: Copyright 2013-2016 Robert Naumann
|
||||||
|
* Copyright 2021 He Yang <1160386205@qq.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "iernonce.h"
|
||||||
|
|
||||||
|
RUNONCEEX_CALLBACK g_Callback = NULL;
|
||||||
|
BOOL g_bSilence = FALSE;
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
WINAPI
|
||||||
|
DllMain(_In_ HINSTANCE hinstDLL,
|
||||||
|
_In_ DWORD dwReason,
|
||||||
|
_In_ LPVOID reserved)
|
||||||
|
{
|
||||||
|
switch (dwReason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
DisableThreadLibraryCalls(hinstDLL);
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VOID WINAPI
|
||||||
|
RunOnceExProcess(_In_ HWND hwnd,
|
||||||
|
_In_ HINSTANCE hInst,
|
||||||
|
_In_ LPCSTR pszCmdLine,
|
||||||
|
_In_ int nCmdShow)
|
||||||
|
{
|
||||||
|
// iernonce may use shell32 API.
|
||||||
|
HRESULT Result = CoInitialize(NULL);
|
||||||
|
if (Result != S_OK && Result != S_FALSE)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HKEY RootKeys[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
|
||||||
|
for (UINT i = 0; i < _countof(RootKeys); ++i)
|
||||||
|
{
|
||||||
|
RunOnceExInstance Instance(RootKeys[i]);
|
||||||
|
Instance.Run(g_bSilence);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VOID WINAPI
|
||||||
|
InitCallback(_In_ RUNONCEEX_CALLBACK Callback,
|
||||||
|
_In_ BOOL bSilence)
|
||||||
|
{
|
||||||
|
g_Callback = Callback;
|
||||||
|
g_bSilence = bSilence;
|
||||||
|
}
|
24
dll/win32/iernonce/iernonce.h
Normal file
24
dll/win32/iernonce/iernonce.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS system libraries
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: ReactOS Extended RunOnce processing with UI.
|
||||||
|
* COPYRIGHT: Copyright 2021 He Yang <1160386205@qq.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#define WIN32_NO_STATUS
|
||||||
|
#include <windef.h>
|
||||||
|
#include <winbase.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <iernonce_undoc.h>
|
||||||
|
|
||||||
|
#include <atlbase.h>
|
||||||
|
#include <atlwin.h>
|
||||||
|
|
||||||
|
#include "registry.h"
|
||||||
|
#include "dialog.h"
|
|
@ -1 +1,2 @@
|
||||||
@ stdcall RunOnceExProcess(ptr ptr str long)
|
@ stdcall RunOnceExProcess(ptr ptr str long)
|
||||||
|
@ stdcall InitCallback(ptr long)
|
||||||
|
|
107
dll/win32/iernonce/include/registry.h
Normal file
107
dll/win32/iernonce/include/registry.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS system libraries
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Functions to read RunOnceEx registry.
|
||||||
|
* COPYRIGHT: Copyright 2021 He Yang <1160386205@qq.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <atlbase.h>
|
||||||
|
#include <atlstr.h>
|
||||||
|
#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
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LONG EnumValueName(
|
||||||
|
_In_ DWORD iIndex,
|
||||||
|
_Out_ LPTSTR pszName,
|
||||||
|
_Inout_ LPDWORD pnNameLength);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RunOnceExEntry
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ATL::CStringW m_Value;
|
||||||
|
ATL::CStringW m_Name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RunOnceExEntry(
|
||||||
|
_In_ const ATL::CStringW &Name,
|
||||||
|
_In_ const ATL::CStringW &Value);
|
||||||
|
|
||||||
|
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;
|
||||||
|
CRegKeyEx m_RegKey;
|
||||||
|
|
||||||
|
BOOL HandleValue(
|
||||||
|
_In_ CRegKeyEx &hKey,
|
||||||
|
_In_ const CStringW &ValueName);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BOOL m_bSuccess;
|
||||||
|
ATL::CStringW m_SectionTitle;
|
||||||
|
CSimpleArray<RunOnceExEntry> m_EntryList;
|
||||||
|
|
||||||
|
RunOnceExSection(
|
||||||
|
_In_ CRegKeyEx &hParentKey,
|
||||||
|
_In_ const CStringW &lpSubKeyName);
|
||||||
|
|
||||||
|
RunOnceExSection(_In_ const RunOnceExSection &Section);
|
||||||
|
|
||||||
|
BOOL CloseAndDelete(_In_ CRegKeyEx &hParentKey);
|
||||||
|
|
||||||
|
UINT GetEntryCnt() const;
|
||||||
|
|
||||||
|
BOOL Exec(
|
||||||
|
_Inout_ UINT& iCompleteCnt,
|
||||||
|
_In_ const UINT iTotalCnt);
|
||||||
|
|
||||||
|
friend int RunOnceExSectionCmp(
|
||||||
|
_In_ const void *a,
|
||||||
|
_In_ const void *b);
|
||||||
|
|
||||||
|
friend class RunOnceExInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RunOnceExInstance
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CRegKeyEx m_RegKey;
|
||||||
|
|
||||||
|
BOOL HandleSubKey(
|
||||||
|
_In_ CRegKeyEx &hKey,
|
||||||
|
_In_ const CStringW &SubKeyName);
|
||||||
|
|
||||||
|
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);
|
||||||
|
BOOL Run(_In_ BOOL bSilence);
|
||||||
|
};
|
360
dll/win32/iernonce/registry.cpp
Normal file
360
dll/win32/iernonce/registry.cpp
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS system libraries
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Functions to read RunOnceEx registry.
|
||||||
|
* COPYRIGHT: Copyright 2021 He Yang <1160386205@qq.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "iernonce.h"
|
||||||
|
|
||||||
|
extern RUNONCEEX_CALLBACK g_Callback;
|
||||||
|
|
||||||
|
LONG CRegKeyEx::EnumValueName(
|
||||||
|
_In_ DWORD iIndex,
|
||||||
|
_Out_ LPTSTR pszName,
|
||||||
|
_Inout_ LPDWORD pnNameLength)
|
||||||
|
{
|
||||||
|
return RegEnumValueW(m_hKey, iIndex, pszName, pnNameLength,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunOnceExEntry::RunOnceExEntry(
|
||||||
|
_In_ const ATL::CStringW &Name,
|
||||||
|
_In_ const ATL::CStringW &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)
|
||||||
|
{
|
||||||
|
return lstrcmpW(((RunOnceExEntry *)a)->m_Name,
|
||||||
|
((RunOnceExEntry *)b)->m_Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RunOnceExSection::HandleValue(
|
||||||
|
_In_ CRegKeyEx &hKey,
|
||||||
|
_In_ const CStringW &ValueName)
|
||||||
|
{
|
||||||
|
DWORD dwType;
|
||||||
|
DWORD cbData;
|
||||||
|
|
||||||
|
// Query data size
|
||||||
|
if (hKey.QueryValue(ValueName, &dwType, NULL, &cbData) != ERROR_SUCCESS)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// Validate its format and size.
|
||||||
|
if (dwType != REG_SZ)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (cbData % sizeof(WCHAR) != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
CStringW Buffer;
|
||||||
|
LPWSTR szBuffer = Buffer.GetBuffer((cbData / sizeof(WCHAR)) + 1);
|
||||||
|
|
||||||
|
if (hKey.QueryValue(ValueName, &dwType, szBuffer, &cbData) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
Buffer.ReleaseBuffer();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
// The default value specifies the section title.
|
||||||
|
m_SectionTitle = Buffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_EntryList.Add(RunOnceExEntry(ValueName, ExpandStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunOnceExSection::RunOnceExSection(
|
||||||
|
_In_ CRegKeyEx &hParentKey,
|
||||||
|
_In_ const CStringW &lpSubKeyName) :
|
||||||
|
m_SectionName(lpSubKeyName)
|
||||||
|
{
|
||||||
|
m_bSuccess = FALSE;
|
||||||
|
DWORD dwValueNum;
|
||||||
|
DWORD dwMaxValueNameLen;
|
||||||
|
LSTATUS Error;
|
||||||
|
CStringW ValueName;
|
||||||
|
|
||||||
|
if (m_RegKey.Open(hParentKey, lpSubKeyName) != ERROR_SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Error = RegQueryInfoKeyW(m_RegKey, NULL, 0, NULL, NULL, NULL, NULL,
|
||||||
|
&dwValueNum, &dwMaxValueNameLen,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
if (Error != ERROR_SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (DWORD i = 0; i < dwValueNum; i++)
|
||||||
|
{
|
||||||
|
LPWSTR szValueName;
|
||||||
|
DWORD dwcchName = dwMaxValueNameLen + 1;
|
||||||
|
|
||||||
|
szValueName = ValueName.GetBuffer(dwMaxValueNameLen + 1);
|
||||||
|
Error = m_RegKey.EnumValueName(i, szValueName, &dwcchName);
|
||||||
|
ValueName.ReleaseBuffer();
|
||||||
|
|
||||||
|
if (Error != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
// TODO: error handling
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HandleValue(m_RegKey, ValueName))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort entries by name in string order.
|
||||||
|
qsort(m_EntryList.GetData(), m_EntryList.GetSize(),
|
||||||
|
sizeof(RunOnceExEntry), RunOnceExEntryCmp);
|
||||||
|
|
||||||
|
m_bSuccess = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT RunOnceExSection::GetEntryCnt() const
|
||||||
|
{
|
||||||
|
return m_EntryList.GetSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RunOnceExSection::Exec(
|
||||||
|
_Inout_ UINT& iCompleteCnt,
|
||||||
|
_In_ const UINT iTotalCnt)
|
||||||
|
{
|
||||||
|
BOOL bSuccess = TRUE;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_EntryList.GetSize(); i++)
|
||||||
|
{
|
||||||
|
m_EntryList[i].Delete(m_RegKey);
|
||||||
|
bSuccess &= m_EntryList[i].Exec();
|
||||||
|
iCompleteCnt++;
|
||||||
|
// TODO: the meaning of the third param is still unknown, seems it's always 0.
|
||||||
|
if (g_Callback)
|
||||||
|
g_Callback(iCompleteCnt, iTotalCnt, NULL);
|
||||||
|
}
|
||||||
|
return bSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RunOnceExSectionCmp(
|
||||||
|
_In_ const void *a,
|
||||||
|
_In_ const void *b)
|
||||||
|
{
|
||||||
|
return lstrcmpW(((RunOnceExSection *)a)->m_SectionName,
|
||||||
|
((RunOnceExSection *)b)->m_SectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunOnceExInstance::RunOnceExInstance(_In_ HKEY BaseKey)
|
||||||
|
{
|
||||||
|
m_bSuccess = FALSE;
|
||||||
|
DWORD dwSubKeyNum;
|
||||||
|
DWORD dwMaxSubKeyNameLen;
|
||||||
|
LSTATUS Error;
|
||||||
|
CStringW SubKeyName;
|
||||||
|
|
||||||
|
Error = m_RegKey.Open(BaseKey,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\");
|
||||||
|
if (Error != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = m_RegKey.EnumKey(i, szSubKeyName, &dwcchName);
|
||||||
|
SubKeyName.ReleaseBuffer();
|
||||||
|
|
||||||
|
if (Error != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
// TODO: error handling
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HandleSubKey(m_RegKey, SubKeyName))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort sections by name in string order.
|
||||||
|
qsort(m_SectionList.GetData(), m_SectionList.GetSize(),
|
||||||
|
sizeof(RunOnceExSection), RunOnceExSectionCmp);
|
||||||
|
|
||||||
|
m_bSuccess = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RunOnceExInstance::Exec(_In_opt_ HWND hwnd)
|
||||||
|
{
|
||||||
|
BOOL bSuccess = TRUE;
|
||||||
|
|
||||||
|
UINT TotalCnt = 0;
|
||||||
|
UINT CompleteCnt = 0;
|
||||||
|
for (int i = 0; i < m_SectionList.GetSize(); i++)
|
||||||
|
{
|
||||||
|
TotalCnt += m_SectionList[i].GetEntryCnt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(CompleteCnt, TotalCnt);
|
||||||
|
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(), bSuccess);
|
||||||
|
return bSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RunOnceExInstance::Run(_In_ BOOL bSilence)
|
||||||
|
{
|
||||||
|
if (bSilence ||
|
||||||
|
(m_dwFlags & FLAGS_NO_STAT_DIALOG) ||
|
||||||
|
!m_bShowDialog)
|
||||||
|
{
|
||||||
|
return Exec(NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The dialog is responsible to create a thread and execute.
|
||||||
|
ProgressDlg dlg(*this);
|
||||||
|
return dlg.RunDialogBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RunOnceExInstance::HandleSubKey(
|
||||||
|
_In_ CRegKeyEx &hKey,
|
||||||
|
_In_ const CStringW& SubKeyName)
|
||||||
|
{
|
||||||
|
RunOnceExSection Section(hKey, SubKeyName);
|
||||||
|
if (!Section.m_bSuccess)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
30
sdk/include/reactos/iernonce_undoc.h
Normal file
30
sdk/include/reactos/iernonce_undoc.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef _IERNONCE_UNDOC_H_
|
||||||
|
#define _IERNONCE_UNDOC_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef VOID
|
||||||
|
(CALLBACK *RUNONCEEX_CALLBACK)(
|
||||||
|
_In_ UINT CompleteCnt,
|
||||||
|
_In_ UINT TotalCnt,
|
||||||
|
_In_ DWORD_PTR dwReserved);
|
||||||
|
|
||||||
|
VOID WINAPI
|
||||||
|
InitCallback(
|
||||||
|
_In_ RUNONCEEX_CALLBACK Callback,
|
||||||
|
_In_ BOOL bSilence);
|
||||||
|
|
||||||
|
VOID WINAPI
|
||||||
|
RunOnceExProcess(
|
||||||
|
_In_ HWND hwnd,
|
||||||
|
_In_ HINSTANCE hInst,
|
||||||
|
_In_ LPCSTR pszCmdLine,
|
||||||
|
_In_ int nCmdShow);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _IERNONCE_UNDOC_H_ */
|
Loading…
Reference in a new issue