1825 lines
73 KiB
C++
1825 lines
73 KiB
C++
/************************************************************\
|
||
FILE: iernonce.cpp
|
||
|
||
CREATED: October 16, 1996
|
||
|
||
HISTORY:
|
||
Initial version from BryanSt.
|
||
Modified extensively for UI, root dependencies, bug fixes, etc. by PritObla.
|
||
|
||
COPYRIGHT:
|
||
Copyright (c) 1996 Microsoft Coporation.
|
||
|
||
|
||
DEFINITIONS:
|
||
SECTION - The old RunOnce API is in a flat section. The RunOnceEx
|
||
API groups entries into sections for managability. If the
|
||
Status dialog is displayed, it will display each section
|
||
name while it's being processed. Example sections for
|
||
Internet Explorer would be: ActiveX, Java, Internet Explorer.
|
||
ENTRY - Entries are listed in a section. These are commands
|
||
that need to be carried out. The commands can be a string
|
||
to execute, a DLL to register (regsvr32), a DLL to unregister (regsvr32 -u),
|
||
or to call a function in a DLL that has WinMain parameters (rundll32).
|
||
|
||
DESCRIPTION:
|
||
1.0 Goal
|
||
Currently the "Run" and "RunOnce" feature in Explorer.exe will shell
|
||
execute commands when the shell starts up. Several features are
|
||
needed for this to be more robust for Internet Explorer 4.0.
|
||
|
||
The replacements are RunEx for Run and RunOnceEx for RunOnce. The
|
||
main features are:
|
||
· Status - A dialog will be displayed while the items are being
|
||
processed. Internet Explorer 4.0 adds at least 30 items which
|
||
take more than a minute on 486 machines. The entries to be
|
||
processed will be grouped into sections and the dialog will
|
||
highlight the current section being processed. The status dialog
|
||
feature can be turned off by using a flag.
|
||
· Performance - The majority of the Run and RunOnce commands are
|
||
calls to regsvr32.exe and runonce32.exe. These create separate
|
||
processes which is very inefficient. This API will not create
|
||
separate processes for DLLs that need to be called in the same way
|
||
that regsvr32.exe or rundll32.exe calls DLLs. This API also supports
|
||
a dependency list of DLLs that should remain loaded while either all
|
||
the sections or some of the sections are being processed.
|
||
· Error Handling - If an exception occurs while calling a function in
|
||
a DLL, the exception will be caught and error dialog will be
|
||
displayed to the user. This error dialog can be suppressed using a
|
||
flag in the API, but this is recommended only for cases where a
|
||
debug is installed because it will crash explorer.exe. If a flag is
|
||
set, an error and/or logging file can be generated in %WinDir% for
|
||
debugging purposes.
|
||
· Deterministic - Currently the order that the entries are processed
|
||
is not deterministic. This new API will sort the entries and
|
||
sections alphabetically to force a deterministic order. The current
|
||
API will not wait until one entry is finished before starting the
|
||
next entry, except for RunOnce items in Local_Machine. In order to
|
||
be deterministic, this API will process command synchronously unless
|
||
a flag is set to turned off this functionality.
|
||
· Export Functionality - This API will be added to shell32.dll and
|
||
called from explorer.exe. API functions will be exported so other
|
||
applications can use this functionality if needed.
|
||
|
||
2.0 Registry Structure
|
||
2.1 RegistryFormat
|
||
Text in italics are strings generated by the user.
|
||
|
||
[Local_Machine] or [Current_User]
|
||
SOFTWARE\Microsoft\Windows\CurrentVersion\RunEx (same as RunOnceEx below)
|
||
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx
|
||
Flags = [DWORD] 0x0000000
|
||
Title = [STR] "Status Dialog Title" (Example, "Installing Internet Explorer 4.0")
|
||
Depend\
|
||
<PlaceHolder1> = [STR] "<DLL/OCX Filename>" (filename with or without the path)
|
||
<PlaceHolder...> = [STR] "<DLL/OCX Filename>" (filename with or without the path)
|
||
<SectionPlaceHolder1>\
|
||
@="SectionName1"
|
||
<Entry1> = [STR] "<EntryFormat>" (See Entry Format description below)
|
||
<Entry...> = [STR] "<EntryFormat >"
|
||
Depend\
|
||
<PlaceHolder1> = [STR] "<DLL/OCX Filename>"
|
||
<PlaceHolder...> = [STR] "<DLL/OCX Filename>"
|
||
< SectionPlaceHolder2>\
|
||
|
||
2.1.1 Flags
|
||
// Old RunOnce Flags
|
||
#define RRA_DEFAULT 0x0000
|
||
#define RRA_DELETE 0x0001
|
||
#define RRA_WAIT 0x0002
|
||
#define RRA_SHELLSERVICEOBJECTS 0x0004
|
||
|
||
// New RunOnceEx Flags
|
||
#define RRAEX_NO_ERROR_DIALOGS 0x0008
|
||
#define RRAEX_ERRORFILE 0x0010
|
||
#define RRAEX_LOG_FILE 0x0020
|
||
#define RRAEX_NO_EXCEPTION_TRAPPING 0x0040
|
||
#define RRAEX_NO_STATUS_DIALOG 0x0080
|
||
#define RRAEX_IGNORE_REG_FLAGS 0x0100
|
||
|
||
|
||
RRA_DEFAULT - All features are off but can be turned on by the flags
|
||
in the Flags registry key.
|
||
RRA_DELETE - Delete the registry entries after processing them.
|
||
Normally used for RunOnceEx and not used for RunEx.
|
||
RRA_WAIT - If the entry is a command to be executed, this flag causes
|
||
the items to be processed synchronously.
|
||
RRA_SHELLSERVICEOBJECTS - If this flag is set, we load inproc dlls
|
||
from the registry key and QI them for IOleCommandTarget.
|
||
CGID_ShellServiceObject notifications are sent to these objects
|
||
letting them know about shell status.
|
||
RRAEX_NO_STATUS_DIALOG - Use this flag to cause the Status dialog to
|
||
not be displayed while processing the entries.
|
||
RRAEX_ NO_ERROR_DIALOGS - This flag will turn off error dialogs from
|
||
being displayed.
|
||
RRAEX_ERRORFILE - This flag will cause the file "C:\Windows\RunOnceEx.err"
|
||
to be created if errors occur.
|
||
RRAEX_LOG_FILE - This flag will cause the file "C:\Windows\RunOnceEx.log"
|
||
to be created giving the status of commands being executed. (For debugging)
|
||
RRAEX_ NO_EXCEPTION_TRAPPING - If this flag is set, exceptions will
|
||
not be caught when registering DLLs. This should only be used when a
|
||
debug is setup or buggy DLLs will cause explorer.exe to crash.
|
||
RRAEX_IGNORE_REG_FLAGS - If this flag is set, then the Flags registry
|
||
entry will be ignored.
|
||
|
||
The Flags registry key will be deleted if the RRAEX_DELETE flag was
|
||
set.
|
||
|
||
2.1.2 Title
|
||
The Status Dialog’s title will be set to Title registry key if it
|
||
exists. This key will be deleted if the RRAEX_DELETE flag was set.
|
||
2.1.3 Top Level Depend Entries
|
||
Each entry under the Depend branch will be read. These registry
|
||
entries need to be type STR and the data needs to be a valid filename
|
||
with or without a path. The registry value will be ignored.
|
||
LoadLibrary() will be called on each entry and they will remain loaded
|
||
until all the sections have been processed. This key will be deleted
|
||
if the RRA_DELETE flag was set.
|
||
|
||
Example:
|
||
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\Depend
|
||
"Should stay loaded" = [STR] "shell32.dll"
|
||
2.1.4 Sections
|
||
Each non-"Depend" keys under RunEx and RunOnceEx is considered a
|
||
section. The names of the Sections are read into memory, sorted
|
||
alphabetically. The key name is displayed in the Status Dialog if
|
||
the key doesn’t have data to specify the Display Name. The sections
|
||
will be processed in alphabetic order. The Section’s branch in the
|
||
registry will be deleted after being processed if the RRAEX_DELETE
|
||
flag was set.
|
||
|
||
Each Section will contain "entries" which are string registry keys.
|
||
The registry entry value is only used to sort the entries. The
|
||
registry entry data will be in the format specified in 2.2 Entry
|
||
Format.
|
||
|
||
Example:
|
||
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\IE4 03 Java
|
||
@="Java"
|
||
"IE4 01 Java" = [STR] "||my.exe -quiet -url http://www.microsft.com/"
|
||
"IE4 02 Main Java File" = [STR] "msjava.dll|DllRegisterServer"
|
||
|
||
If the Section has a Display Name, then the key name should contain
|
||
an abbreviation of the product followed by a number that specifies
|
||
the order that this section should be processed in. Because the
|
||
section names are sorted alphabetically, this will make sure that
|
||
all entries for one product are processed together and that the number
|
||
makes the order obvious.
|
||
|
||
An Example:
|
||
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\IE4 03 Java
|
||
@="Java"
|
||
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\IE4 04 Scripting
|
||
@="ActiveX Scripting"
|
||
|
||
2.1.4.1 Section Dependencies
|
||
The list off DLLs in the section’s Depend key are loaded before a
|
||
section’s entries are executed and then unloaded after they have
|
||
been executed. This key will be deleted if the RRA_DELETE flag was
|
||
set.
|
||
|
||
Example:
|
||
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\Java
|
||
"IE4 01 Java" = [STR] "||my.exe -quiet -url http://www.microsft.com/"
|
||
"IE4 02 Java" = [STR] "shdocvw.dll|DllRegisterServer"
|
||
SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\Java\Depend
|
||
"Keep Loaded" = [STR] "urlmon.dll"
|
||
|
||
2.2 Entry Format
|
||
"<DllFileName>|<FunctionName>|<CmdLineArgs>"
|
||
|
||
The Entry Format will fall into one of three categories,
|
||
1) Shell Execute (same as old RunOnce method),
|
||
2) Call DllRegisterServer or DllUnregisterServer in the
|
||
specified DLL (same as regsvr32.exe), and 3) Call a function
|
||
in the specified DLL with WinMain parameters (same as rundll32.exe)
|
||
and the <CmdLineArgs> will be passed in the CmdLine parameter.
|
||
· Register DLL - The <DllFileName> is required to be non-empty. The
|
||
<FunctionName> sections must equal "DllRegisterServer" or
|
||
"DllUnregisterServer". The <CmdLineArgs> must be empty and there
|
||
must not be a semicolon after <FunctionName>.
|
||
Example: "shdocvw.dll|DllRegisterServer".
|
||
· Calling a Function - The <DllFileName> and <FunctionName> sections
|
||
are required to be non-empty. The <CmdLineArgs> can be empty and there
|
||
must be a semicolon after <FunctionName>.
|
||
Example: "C:\winnt\system32\my.dll|MyWinMain|-Start".
|
||
· Shell Execute - The <DllFileName> and <FunctionName> sections are
|
||
required to be empty. The <DllFileName> string will be executed in
|
||
same way the old RunOnce items where executed.
|
||
Example: "||iexplore.exe http://www.microsoft.com/".
|
||
|
||
3.0 Function Calls
|
||
void ProcessRunOnceEx(DWORD dwFlags);
|
||
This function will call RunRegAppsAndObjectsEx() with the RunEx and
|
||
RunOnceEx registry keys in both Local_Machine and Current_User
|
||
sections of the registry with the Flags passed in. RRA_WAIT will be
|
||
passed because it’s on be default. RRA_DELETE will be passed for
|
||
RunOnceEx.
|
||
|
||
void RunRegAppsAndObjectsEx(HKEY hkeyParent, LPCTSTR szSubkey, DWORD dwFlags);
|
||
This function will process the entries in this section of the registry.
|
||
The szSubKey cannot point to a section of the registry that has the
|
||
old Run or RunOnce format.
|
||
|
||
|
||
\************************************************************/
|
||
|
||
/*Includes---------------------------------------------------------*/
|
||
|
||
#include "iernonce.h"
|
||
#include "resource.h"
|
||
|
||
#ifdef WX86
|
||
#include <wx86ofl.h>
|
||
#endif // WX86
|
||
|
||
//////////////////////////////////////////////////////////////////
|
||
// Constants:
|
||
//////////////////////////////////////////////////////////////////
|
||
#define MAX_REG_PATH 256 // Registry paths should not get much longer than this or there is a major perf hit
|
||
#define MAX_REG_VALUE 80 // Registry values should not get much longer than this or there is a major perf hit
|
||
#define ARRAY_GROW_RATE 32 // This should be large enough to cover most applications
|
||
#define SEPERATOR_CHAR TEXT('|')
|
||
|
||
//////////////////////////////////////////////////////////////////
|
||
// TYPES:
|
||
//////////////////////////////////////////////////////////////////
|
||
|
||
typedef enum
|
||
{
|
||
eHDL_Load,
|
||
eHDL_Unload
|
||
} HDL_Type;
|
||
|
||
typedef int (*WINMAIN_PARAMS)(HINSTANCE, HINSTANCE, LPSTR, int);
|
||
typedef LONG (*DLLREGISTERSERVER_PARAMS)();
|
||
typedef HRESULT (*DLLINSTALL_PARAMS)(BOOL bInstall, LPCWSTR pszCmdLine);
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////
|
||
// GLOBALS:
|
||
//////////////////////////////////////////////////////////////////
|
||
|
||
const TCHAR * c_szDependencyName = TEXT("Depend");
|
||
const TCHAR * c_szFlagsRegValue = TEXT("Flags");
|
||
const TCHAR * g_c_szTitleRegValue = TEXT("Title");
|
||
const TCHAR * g_c_szSystemDat = TEXT("system.dat");
|
||
const TCHAR * g_c_szSystem1st = TEXT("system.1st");
|
||
const TCHAR * g_c_szSetupKey = TEXT("Software\\Microsoft\\IE Setup\\Setup");
|
||
const TCHAR * g_c_szRegBackupPath = TEXT("RegistryBackup");
|
||
const TCHAR * g_c_szServicesRegValue = TEXT("Services");
|
||
|
||
|
||
HINSTANCE g_hinst = NULL;
|
||
HANDLE g_hHeap = NULL;
|
||
|
||
RUNONCEEXPROCESSCALLBACK g_pCallbackProc = NULL;
|
||
BOOL g_bQuiet = FALSE;
|
||
int g_nTotal = 0;
|
||
int g_nCurrent = 0;
|
||
|
||
BOOL g_bRunningOnNT = FALSE;
|
||
BOOL g_bBackupSystemDat = FALSE;
|
||
#if 0
|
||
BOOL g_bDeleteSystemIE4 = FALSE;
|
||
#endif
|
||
int g_iNDisplaySections = 0;
|
||
TCHAR g_szTitleString[256] = TEXT("");
|
||
|
||
// related to logging
|
||
HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
|
||
|
||
#ifdef WX86
|
||
// If Wx86 has to be loaded we use this flag to make sure it is unloaded
|
||
// at the end of RunOnceExProcess.
|
||
BOOL g_fWx86Loaded = FALSE;
|
||
#endif
|
||
|
||
//////////////////////////////////////////////////////////////////
|
||
// Internal Functions
|
||
//////////////////////////////////////////////////////////////////
|
||
void WINAPI RunOnceExProcess(HWND hWnd, HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow);
|
||
void RunOnceExProcessReg(HKEY hkeyParent, LPCTSTR pszSubkey, DWORD dwFlags);
|
||
HDPA GetSections(HKEY hkeyParent, LPCTSTR szSubkey, DWORD dwFlags, int * pNumberOfSections);
|
||
HDPA GetEntries(HKEY hRootKey, LPCTSTR szSectionName, DWORD dwFlags, int * pNumberOfEntries);
|
||
void HandleDependencyDLLs(HKEY hkeyParent, LPCTSTR szRegPath, LPCTSTR szRegSubPath, DWORD dwFlags, HDL_Type hdlDirection);
|
||
DWORD GetFlagsInRegistry(HKEY hkeyParent, LPCTSTR szSubkey);
|
||
void ShellExecuteRegApp(LPTSTR pszCmdLine, DWORD dwFlags);
|
||
BOOL HaveDependServices(SC_HANDLE hService);
|
||
void CheckServices(DWORD dwFlags);
|
||
|
||
BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
|
||
{
|
||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||
{
|
||
OSVERSIONINFO osvi;
|
||
|
||
DisableThreadLibraryCalls(hDLLInst);
|
||
|
||
// The DLL is being loaded for the first time by a given process.
|
||
// Perform per-process initialization here. If the initialization
|
||
// is successful, return TRUE; if unsuccessful, return FALSE.
|
||
|
||
// Initialize the global variable holding the hinstance:
|
||
g_hinst = hDLLInst;
|
||
g_hHeap = GetProcessHeap();
|
||
|
||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||
GetVersionEx(&osvi);
|
||
if (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
|
||
g_bRunningOnNT = TRUE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
#ifdef WX86
|
||
|
||
/****************************************************\
|
||
FUNCTION: RunOnceLoadLibrary
|
||
|
||
PARAMETERS:
|
||
LPCTSTR lpszFileName - DLL to load
|
||
|
||
BOOL* pfWx86DLL - Ptr to a BOOL that we set to
|
||
TRUE if the DLL is x86.
|
||
|
||
DESCRIPTION:
|
||
This function will is a wrapper for LoadLibraryEx()
|
||
that will also load x86 DLLs on RISC.
|
||
\***************************************************/
|
||
|
||
HINSTANCE RunOnceLoadLibrary( LPCTSTR lpszFileName, BOOL* pfWx86DLL )
|
||
{
|
||
HINSTANCE hInstance = LoadLibraryEx(lpszFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||
if ( (hInstance == NULL) && (GetLastError() == ERROR_BAD_EXE_FORMAT) )
|
||
{
|
||
WCHAR achDllToLoad[ MAX_PATH ];
|
||
#ifdef UNICODE
|
||
lstrcpy(achDllToLoad, lpszFileName);
|
||
#else // UNICODE
|
||
MultiByteToWideChar(CP_ACP, 0, lpszFileName, -1,
|
||
achDllToLoad, ARRAYSIZE(achDllToLoad));
|
||
#endif // UNICODE
|
||
if ( !g_fWx86Loaded )
|
||
{
|
||
g_fWx86Loaded = Wx86Load();
|
||
}
|
||
|
||
if ( g_fWx86Loaded )
|
||
{
|
||
hInstance = Wx86LoadX86Dll(achDllToLoad, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||
if ( hInstance != NULL )
|
||
{
|
||
*pfWx86DLL = TRUE;
|
||
}
|
||
}
|
||
}
|
||
return hInstance;
|
||
}
|
||
|
||
#else // WX86
|
||
|
||
// If we're on x86 then a simple macro works...
|
||
#define RunOnceLoadLibrary(_arg1, _arg2) LoadLibraryEx(_arg1, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)
|
||
|
||
#endif // WX86
|
||
|
||
void BackupRegistry()
|
||
{
|
||
HKEY hkSetup = NULL;
|
||
DWORD unused;
|
||
TCHAR szSystemDatPath[MAX_PATH] = TEXT("");
|
||
TCHAR szSystemIE4Path[MAX_PATH] = TEXT("");
|
||
|
||
// flush the registry and copy system.dat to system.ie4;
|
||
// this is for the PSS folks; if the registry gets corrupt after IE4 has been installed, user can copy system.ie4 to system.dat
|
||
// quite an expensive operation!
|
||
RegFlushKey(HKEY_CLASSES_ROOT);
|
||
RegFlushKey(HKEY_CURRENT_USER);
|
||
RegFlushKey(HKEY_LOCAL_MACHINE);
|
||
RegFlushKey(HKEY_USERS);
|
||
|
||
GetWindowsDirectory(szSystemDatPath, ARRAYSIZE(szSystemDatPath));
|
||
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, g_c_szSetupKey, 0, NULL,
|
||
REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
|
||
NULL, &hkSetup, &unused) == ERROR_SUCCESS)
|
||
{
|
||
unused = sizeof(szSystemIE4Path);
|
||
RegQueryValueEx(hkSetup, g_c_szRegBackupPath, 0, NULL, (BYTE *)szSystemIE4Path, &unused);
|
||
}
|
||
// if we don't have a path yet default to root of windows drive
|
||
if(szSystemIE4Path[0] == TEXT('\0'))
|
||
{
|
||
lstrcpy(szSystemIE4Path, szSystemDatPath);
|
||
GetParentDir(szSystemIE4Path);
|
||
AddPath(szSystemIE4Path, g_c_szSystem1st);
|
||
}
|
||
|
||
AddPath(szSystemDatPath, g_c_szSystemDat);
|
||
|
||
SetFileAttributes(szSystemDatPath, FILE_ATTRIBUTE_NORMAL);
|
||
SetFileAttributes(szSystemIE4Path, FILE_ATTRIBUTE_NORMAL);
|
||
|
||
if(CopyFile(szSystemDatPath, szSystemIE4Path, FALSE))
|
||
{
|
||
// Record where we put it in the registry
|
||
if(hkSetup)
|
||
RegSetValueEx(hkSetup, g_c_szRegBackupPath, 0, REG_SZ,
|
||
(BYTE *)szSystemIE4Path, sizeof(TCHAR) * (lstrlen(szSystemIE4Path) + 1));
|
||
|
||
// Write something to the active setup log
|
||
|
||
|
||
}
|
||
|
||
if(hkSetup)
|
||
RegCloseKey(hkSetup);
|
||
|
||
SetFileAttributes(szSystemDatPath, FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM);
|
||
SetFileAttributes(szSystemIE4Path, FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM);
|
||
}
|
||
|
||
VOID InitCallback(RUNONCEEXPROCESSCALLBACK pCallbackProc, BOOL bQuiet)
|
||
{
|
||
g_pCallbackProc = pCallbackProc;
|
||
g_bQuiet = bQuiet;
|
||
}
|
||
|
||
/****************************************************\
|
||
FUNCTION: RunOnceExProcess
|
||
|
||
PARAMETERS:
|
||
DWORD dwFlags - Caller can specify behavior
|
||
with flags.
|
||
|
||
DESCRIPTION:
|
||
This function will run the RunEx API. It will
|
||
process RunOnceEx and RunEx in both Current_User
|
||
and Local_Machine
|
||
\***************************************************/
|
||
void WINAPI RunOnceExProcess(HWND hWnd, HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow)
|
||
{
|
||
const TCHAR * szRunOnceExPath = REGSTR_PATH_RUNONCEEX;
|
||
//const TCHAR * szRunExPath = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunEx");
|
||
DWORD dwFlags = RRA_DEFAULT;
|
||
|
||
if (lpCmdLine != NULL)
|
||
dwFlags |= AtoL(lpCmdLine);
|
||
|
||
if (g_bQuiet)
|
||
dwFlags |= RRAEX_NO_STATUS_DIALOG | RRAEX_NO_ERROR_DIALOGS;
|
||
|
||
RunOnceExProcessReg(HKEY_LOCAL_MACHINE, szRunOnceExPath, dwFlags | RRA_DELETE | RRA_WAIT);
|
||
RunOnceExProcessReg(HKEY_CURRENT_USER, szRunOnceExPath, dwFlags | RRA_DELETE | RRA_WAIT);
|
||
|
||
#ifdef WX86
|
||
if ( g_fWx86Loaded )
|
||
{
|
||
Wx86Unload();
|
||
}
|
||
#endif
|
||
|
||
//RunOnceExProcessReg(HKEY_LOCAL_MACHINE, szRunExPath, dwFlags);
|
||
//RunOnceExProcessReg(HKEY_CURRENT_USER, szRunExPath, dwFlags);
|
||
|
||
if (!g_bRunningOnNT && g_bBackupSystemDat)
|
||
{
|
||
BackupRegistry();
|
||
}
|
||
if (g_bRunningOnNT)
|
||
{
|
||
CheckServices(dwFlags);
|
||
}
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: RunOnceExProcessReg
|
||
|
||
PARAMETERS:
|
||
HKEY hkeyParent - Registry Branch to process.
|
||
LPCTSTR pszSubkey - Registry Path to process.
|
||
DWORD dwFlags - Registry Entry to modify.
|
||
|
||
DESCRIPTION:
|
||
This function will run the API on one part of
|
||
the registry.
|
||
\***************************************************/
|
||
void RunOnceExProcessReg(HKEY hkeyParent, LPCTSTR pszSubkey, DWORD dwFlags)
|
||
{
|
||
HDPA hdpaSections = NULL;
|
||
HKEY hRunExKey = NULL;
|
||
RunOnceExSection * pCurrentSection = NULL;
|
||
int iNumberOfSections = 0;
|
||
int iIndex;
|
||
ARGSINFO aiArgs;
|
||
static DWORD dwCreationFlags = CREATE_ALWAYS; // first time the log file is opened, the contents should be truncated
|
||
static TCHAR szLogFileName[MAX_PATH] = TEXT("");
|
||
|
||
if (!(RRAEX_IGNORE_REG_FLAGS & dwFlags))
|
||
dwFlags |= GetFlagsInRegistry(hkeyParent, pszSubkey);
|
||
|
||
*g_szTitleString = TEXT('\0');
|
||
if (RegOpenKeyEx(hkeyParent, pszSubkey, NULL, KEY_READ, &hRunExKey) == ERROR_SUCCESS)
|
||
{
|
||
DWORD dwTitleSize = sizeof(g_szTitleString);
|
||
|
||
// if a value for Title is specified, read it in
|
||
RegQueryValueEx(hRunExKey, g_c_szTitleRegValue, NULL, NULL, (LPBYTE) g_szTitleString, &dwTitleSize);
|
||
RegCloseKey(hRunExKey);
|
||
}
|
||
|
||
// don't process if there are entries in wininit.ini or PendingFileRenameOperations
|
||
if ((dwFlags & RRAEX_QUIT_IF_REBOOT_NEEDED) && NeedReboot(0))
|
||
return;
|
||
|
||
if (g_bRunningOnNT && (dwFlags & RRAEX_CHECK_NT_ADMIN) && !IsNTAdmin(0, NULL))
|
||
{
|
||
// user has no NT Admin privileges; we cannot process the RunOnceEx items
|
||
|
||
// make sure that the msg box is displayed
|
||
ReportError((dwFlags & ~RRAEX_NO_ERROR_DIALOGS), IDS_RUNONCEEX_NOT_NT_ADMIN);
|
||
LogOff(FALSE);
|
||
|
||
// won't reach here
|
||
return;
|
||
}
|
||
|
||
if (dwFlags & RRAEX_BACKUP_SYSTEM_DAT)
|
||
g_bBackupSystemDat = TRUE;
|
||
|
||
if (dwFlags & RRAEX_LOG_FILE)
|
||
{
|
||
if (*szLogFileName == TEXT('\0'))
|
||
GetLogFileName(TEXT("RunOnceExLogFile"), szLogFileName, ARRAYSIZE(szLogFileName));
|
||
|
||
if (*szLogFileName)
|
||
{
|
||
if (hkeyParent == HKEY_LOCAL_MACHINE)
|
||
{
|
||
TCHAR szBuf[MAX_PATH + MAX_REG_PATH + 16];
|
||
|
||
// dump the registry entries before we process them so that if some error occurs,
|
||
// it is easy to cut and paste the entries to a reg file and import it.
|
||
wsprintf(szBuf, TEXT("regedit /e \"%s\" HKEY_LOCAL_MACHINE\\%s"), szLogFileName, pszSubkey);
|
||
ShellExecuteRegApp(szBuf, RRA_WAIT);
|
||
dwCreationFlags = OPEN_ALWAYS; // from now on, the log file should be opened in append mode
|
||
}
|
||
|
||
StartLogging(szLogFileName, dwCreationFlags);
|
||
dwCreationFlags = OPEN_ALWAYS; // from now on, the log file should be opened in append mode
|
||
}
|
||
}
|
||
|
||
// Log that we are starting to process these commands.
|
||
WriteToLog(TEXT("[%1:%2]\r\n"), (HKEY_LOCAL_MACHINE == hkeyParent) ? TEXT("HKLM"):TEXT("HKCU"), pszSubkey);
|
||
LogFlags(dwFlags);
|
||
|
||
g_iNDisplaySections = 0;
|
||
hdpaSections = GetSections(hkeyParent, pszSubkey, dwFlags, &iNumberOfSections);
|
||
|
||
// Load the dependency DLLs that are common to all sections
|
||
HandleDependencyDLLs(hkeyParent, pszSubkey, "", dwFlags, eHDL_Load);
|
||
|
||
if (iNumberOfSections) // call ProcessSections only if there is atleast one section to process
|
||
{
|
||
// show UI if the NO_STATUS_DIALOG flag is NOT specified, and
|
||
// there is atleast one section that has display text
|
||
if (0 == (RRAEX_NO_STATUS_DIALOG & dwFlags) && g_iNDisplaySections)
|
||
{
|
||
// pack the args of ProcessSections into aiArgs
|
||
aiArgs.hkeyParent = hkeyParent;
|
||
aiArgs.pszSubkey = pszSubkey;
|
||
aiArgs.dwFlags = dwFlags;
|
||
aiArgs.hdpaSections = hdpaSections;
|
||
aiArgs.iNumberOfSections = iNumberOfSections;
|
||
|
||
DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_RUNONCE), NULL, (DLGPROC) DlgProcRunOnceEx, (LPARAM) &aiArgs);
|
||
}
|
||
else
|
||
ProcessSections(hkeyParent, pszSubkey, dwFlags, hdpaSections, iNumberOfSections, NULL);
|
||
}
|
||
|
||
// Unload the dependency DLLs that are common to all sections
|
||
HandleDependencyDLLs(hkeyParent, pszSubkey, "", dwFlags, eHDL_Unload);
|
||
|
||
// We iterate twice. Once to process all the entries, and the second time to delete
|
||
// the entries. We do this because some code (like Dialog Status drawing) might want
|
||
// to access previously processed entries.
|
||
for (iIndex = 0; iIndex < iNumberOfSections; iIndex++)
|
||
{
|
||
pCurrentSection = (RunOnceExSection *) DPA_GetPtr(hdpaSections, iIndex);
|
||
if (pCurrentSection)
|
||
{
|
||
delete pCurrentSection;
|
||
}
|
||
}
|
||
|
||
if (hdpaSections)
|
||
{
|
||
DPA_Destroy(hdpaSections);
|
||
hdpaSections = NULL;
|
||
}
|
||
|
||
// Delete the Flags and Title registry entry if the Delete flag is set.
|
||
if (RRA_DELETE & dwFlags)
|
||
{
|
||
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyParent, pszSubkey, NULL, KEY_READ | KEY_WRITE, &hRunExKey))
|
||
{
|
||
// Delete this key if the Delete key is set anywhere.
|
||
RegDeleteValue(hRunExKey, c_szFlagsRegValue);
|
||
RegDeleteValue(hRunExKey, g_c_szTitleRegValue);
|
||
RegCloseKey(hRunExKey);
|
||
}
|
||
}
|
||
|
||
WriteToLog(TEXT("\r\n"));
|
||
|
||
if (dwFlags & RRAEX_LOG_FILE)
|
||
StopLogging();
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: ProcessSections
|
||
|
||
PARAMETERS:
|
||
HKEY hkeyParent - Registry Branch to process.
|
||
LPCTSTR pszSubkey - Registry Path to process.
|
||
DWORD dwFlags - Registry Entry to modify.
|
||
HDPA hdpaSections - Array of Sections
|
||
int iNumberOfSections - Number of Sections in the Array
|
||
|
||
DESCRIPTION:
|
||
This function will call to have each Section
|
||
processed.
|
||
\***************************************************/
|
||
void ProcessSections(HKEY hkeyParent, LPCTSTR pszSubkey, DWORD dwFlags, HDPA hdpaSections, int iNumberOfSections, HWND hWnd)
|
||
{
|
||
RunOnceExSection * pCurrentSection = NULL;
|
||
int iIndex, iDisplayIndex;
|
||
BOOL fOleInitialized = TRUE;
|
||
|
||
// Got to initialize it here; if it's done in RunOnceExProcess, i.e., process level initialization,
|
||
// registration of asctrls.ocx fails -- looks like OleInitialize needs to be done per thread
|
||
if (FAILED(OleInitialize(NULL)))
|
||
fOleInitialized = FALSE;
|
||
|
||
iDisplayIndex = -1;
|
||
|
||
// If there's a callback, count total things to do...
|
||
if (g_pCallbackProc)
|
||
{
|
||
g_nTotal = 0;
|
||
g_nCurrent = 0;
|
||
for (iIndex = 0; iIndex < iNumberOfSections; iIndex++)
|
||
{
|
||
if ((pCurrentSection = (RunOnceExSection *) DPA_GetPtr(hdpaSections, iIndex)) == NULL)
|
||
continue;
|
||
g_nTotal += pCurrentSection->m_NumberOfEntries;
|
||
}
|
||
}
|
||
|
||
for (iIndex = 0; iIndex < iNumberOfSections; iIndex++)
|
||
{
|
||
if ((pCurrentSection = (RunOnceExSection *) DPA_GetPtr(hdpaSections, iIndex)) == NULL)
|
||
continue;
|
||
|
||
if (hWnd != NULL)
|
||
{
|
||
if (*pCurrentSection->m_szDisplayName != TEXT('\0'))
|
||
SendMessage(hWnd, LB_SETCURSEL, ++iDisplayIndex, 0);
|
||
else if (iDisplayIndex == -1)
|
||
SendMessage(hWnd, LB_SETCURSEL, 0, 0);
|
||
}
|
||
|
||
pCurrentSection->Process(hkeyParent, pszSubkey, dwFlags);
|
||
}
|
||
|
||
if (fOleInitialized)
|
||
OleUninitialize();
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: GetFlagsInRegistry
|
||
|
||
PARAMETERS:
|
||
HKEY hkeyParent - What branch of the registry to look.
|
||
LPCTSTR szSubkey - What path in the registry to look.
|
||
DWORD return - Flags that were found in the registry
|
||
|
||
DESCRIPTION:
|
||
Return with the Flags found in the registry
|
||
or RRA_DEFAULT if none where found.
|
||
\***************************************************/
|
||
DWORD GetFlagsInRegistry(HKEY hkeyParent, LPCTSTR szSubkey)
|
||
{
|
||
DWORD dwFlagsInRegistry = RRA_DEFAULT;
|
||
HKEY hFlagsKey = NULL;
|
||
DWORD dwKeySize = sizeof(dwFlagsInRegistry);
|
||
|
||
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyParent, szSubkey, NULL, KEY_QUERY_VALUE, &hFlagsKey))
|
||
{
|
||
RegQueryValueEx(hFlagsKey, c_szFlagsRegValue, NULL, NULL, (LPBYTE) &dwFlagsInRegistry, &dwKeySize);
|
||
RegCloseKey(hFlagsKey);
|
||
}
|
||
|
||
return(dwFlagsInRegistry);
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: HandleDependencyDLLs
|
||
|
||
PARAMETERS:
|
||
HKEY hkeyParent - Registry Branch to process.
|
||
LPCTSTR szRegPath - Registry Path to process.
|
||
LPCTSTR szRegSubPath - Registry Path to process.
|
||
DWORD dwFlags - Flags. Do we want to delete after Unload?
|
||
HDL_Type hdlDirection - Load or Unload?
|
||
|
||
DESCRIPTION:
|
||
This function will be passed a "Depend" section
|
||
of the registry that will contain registry keys.
|
||
These STR registry keys have filenames and data.
|
||
These filenames need to be loaded (LoadLibrary())
|
||
or freed (FreeLibrary()) depending on the HDL_Type
|
||
parameter to this function.
|
||
\***************************************************/
|
||
void HandleDependencyDLLs(HKEY hkeyParent, LPCTSTR szRegPath, LPCTSTR szRegSubPath, DWORD dwFlags, HDL_Type hdlDirection)
|
||
{
|
||
TCHAR szBasePath[MAX_REG_PATH];
|
||
TCHAR szValueName[MAX_REG_VALUE];
|
||
TCHAR szDLLFileName[MAX_PATH];
|
||
HKEY hBaseKey = NULL;
|
||
HKEY hDependKey = NULL;
|
||
DWORD dwCurrDLL = 0;
|
||
DWORD dwKeyType = 0;
|
||
DWORD dwValueSize = ARRAYSIZE(szValueName);
|
||
DWORD dwDLLNameSize = sizeof(szDLLFileName);
|
||
long lEnumError;
|
||
|
||
if ((NULL != szRegSubPath) && (TEXT('\0') != *szRegSubPath)) // If the szRegSubPath isn't empty, we concatonate the two strings.
|
||
wsprintf(szBasePath, TEXT("%s\\%s"), szRegPath, szRegSubPath);
|
||
else
|
||
lstrcpy(szBasePath, szRegPath);
|
||
|
||
// Open the key for Read only if we are doing a load or an unload where the registry does not need to be deleted.
|
||
// If we are unloading and we need to remove the registry entry, this function will fail if the user doesn't have
|
||
// permission.
|
||
|
||
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyParent, szBasePath, NULL,
|
||
(KEY_READ | (((eHDL_Unload == hdlDirection) && (dwFlags & RRA_DELETE)) ? KEY_WRITE:0)), &hBaseKey))
|
||
{
|
||
if (ERROR_SUCCESS == RegOpenKeyEx(hBaseKey, c_szDependencyName, NULL,
|
||
(KEY_READ | (((eHDL_Unload == hdlDirection) && (dwFlags & RRA_DELETE)) ? KEY_WRITE:0)), &hDependKey))
|
||
{
|
||
// Iterate through each value
|
||
for (dwCurrDLL = 0;
|
||
ERROR_NO_MORE_ITEMS != (lEnumError = RegEnumValue(hDependKey, dwCurrDLL, szValueName, &dwValueSize, NULL, &dwKeyType, (LPBYTE) szDLLFileName, &dwDLLNameSize));
|
||
dwCurrDLL++)
|
||
{
|
||
if ((REG_SZ == dwKeyType) && (ERROR_SUCCESS == lEnumError))
|
||
{
|
||
if (eHDL_Load == hdlDirection)
|
||
{
|
||
// We need to load this library to keep it in memory.
|
||
BOOL fWx86DLL;
|
||
if (NULL == RunOnceLoadLibrary( szDLLFileName, &fWx86DLL ))
|
||
ReportError(dwFlags, IDS_RUNONCEEX_LOAD_DEPEND_FAILED, szDLLFileName);
|
||
else
|
||
WriteToLog(TEXT("Dependency DLL loaded: %1\r\n"), szDLLFileName);
|
||
}
|
||
else // Else Unload
|
||
{
|
||
// We need to unload this library
|
||
HINSTANCE hInst = GetModuleHandle(szDLLFileName);
|
||
if (NULL != hInst)
|
||
{
|
||
if (FreeLibrary(hInst))
|
||
WriteToLog(TEXT("Dependency DLL unloaded: %1\r\n"), szDLLFileName);
|
||
}
|
||
}
|
||
}
|
||
|
||
dwValueSize = ARRAYSIZE(szValueName);
|
||
dwDLLNameSize = sizeof(szDLLFileName);
|
||
}
|
||
|
||
RegCloseKey(hDependKey);
|
||
|
||
if ((eHDL_Unload == hdlDirection) && (dwFlags & RRA_DELETE))
|
||
{
|
||
// We need to remove the registry key so we don't process this again next time.
|
||
RegDeleteKey(hBaseKey, c_szDependencyName);
|
||
}
|
||
}
|
||
|
||
RegCloseKey(hBaseKey);
|
||
}
|
||
}
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////
|
||
// CLASS: RunOnceExEntry
|
||
/////////////////////////////////////////////////////////////////////
|
||
|
||
/****************************************************\
|
||
FUNCTION: RunOnceExEntry
|
||
|
||
PARAMETERS:
|
||
LPTSTR lpszNewEntryName - Name of Entry
|
||
LPTSTR lpszNewCmd - Entry Command
|
||
DWORD dwFlags - Flags
|
||
|
||
DESCRIPTION:
|
||
This function will create a RunOnceEx Entry
|
||
and set it's Name, Cmd, and section.
|
||
\***************************************************/
|
||
RunOnceExEntry::RunOnceExEntry(LPTSTR lpszNewEntryName, LPTSTR lpszNewCmd, DWORD dwFlags)
|
||
{
|
||
const TCHAR * szRegisterFunctionName = TEXT("DllRegisterServer");
|
||
const TCHAR * szUnregisterFunctionName = TEXT("DllUnregisterServer");
|
||
const TCHAR * szInstallFunctionName = TEXT("DllInstall");
|
||
LPTSTR lpszFileName = lpszNewCmd;
|
||
LPTSTR lpszFunctionName = NULL;
|
||
LPTSTR lpszCmdLineArgs = NULL;
|
||
LPTSTR lpszCurrentChar = lpszNewCmd;
|
||
|
||
lstrcpy(m_szRunOnceExEntryName, lpszNewEntryName);
|
||
m_ROAction = eRO_Unknown;
|
||
*m_szFileName = TEXT('\0');
|
||
*m_szFunctionName = TEXT('\0');
|
||
*m_szCmdLineArgs = TEXT('\0');
|
||
|
||
// These entries come in this format "<FileName>|<FunctionName>|<CmdLineArgs>".
|
||
// We first need to find the end of the <FileName>.
|
||
|
||
// Find the end of the filename.
|
||
if (NULL == (lpszCurrentChar = LocalStrChr(lpszCurrentChar, SEPERATOR_CHAR)))
|
||
{
|
||
// It must be an EXE (or something that is executable) because it doesn't have a function name.
|
||
lstrcpy(m_szCmdLineArgs, lpszNewCmd);
|
||
m_ROAction = eRO_Exe; // Remember that we will need to ShellExec this later.
|
||
}
|
||
else
|
||
{
|
||
// We found a '|' so we have the <FileName>.
|
||
*lpszCurrentChar = TEXT('\0'); // Terminate the filename.
|
||
lstrcpy(m_szFileName, lpszNewCmd);
|
||
*lpszCurrentChar = SEPERATOR_CHAR; // Remove the temporary termination.
|
||
lpszCurrentChar = CharNext(lpszCurrentChar);
|
||
|
||
// Now lets work on Getting the <FunctionName>.
|
||
|
||
lpszFunctionName = lpszCurrentChar; // Remember the beginning of the FunctionName before iterating.
|
||
|
||
if (NULL == (lpszCurrentChar = LocalStrChr(lpszCurrentChar, SEPERATOR_CHAR)))
|
||
{
|
||
// If we have found the end of the string without the second '|', then
|
||
// this needs to be a DllRegisterServer or DllUnregisterServer.
|
||
|
||
lstrcpy(m_szFunctionName, lpszFunctionName);
|
||
if (2 == CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpszFunctionName, -1, szRegisterFunctionName, -1))
|
||
{
|
||
m_ROAction = eRO_Register;
|
||
}
|
||
else
|
||
{
|
||
if (2 == CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpszFunctionName, -1, szUnregisterFunctionName, -1))
|
||
{
|
||
m_ROAction = eRO_Unregister;
|
||
}
|
||
else
|
||
{
|
||
m_ROAction = eRO_Unknown;
|
||
// An error has occured. The user didn't specify a valid FunctionName.
|
||
ReportError(dwFlags, IDS_RUNONCEEX_BAD_FUNCTIONNAME, m_szFunctionName);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// We have enountered the second '|' which delemites the <CmdLineArgs> section. By this point, the function we
|
||
// are calling needs WinMain() parameters.or it's a DllInstall function
|
||
|
||
*lpszCurrentChar = TEXT('\0');
|
||
lstrcpy(m_szFunctionName, lpszFunctionName);
|
||
*lpszCurrentChar = SEPERATOR_CHAR; // Remove the temporary termination.
|
||
lpszCurrentChar = CharNext(lpszCurrentChar);
|
||
lstrcpy(m_szCmdLineArgs, lpszCurrentChar);
|
||
|
||
if (TEXT('\0') == *m_szFunctionName)
|
||
{
|
||
if (TEXT('\0') == *m_szFileName)
|
||
{
|
||
m_ROAction = eRO_Exe;
|
||
}
|
||
else
|
||
{
|
||
// This command is invalid because commands to be shell execed need to start
|
||
// Need to have the <FileName> and <FunctionName> parameters empty.
|
||
m_ROAction = eRO_Unknown;
|
||
ReportError(dwFlags, IDS_RUNONCEEX_BAD_SHELLEXEC_CMD, lpszNewCmd);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// check if it's DllInstall
|
||
if (2 == CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, m_szFunctionName, -1, szInstallFunctionName, -1))
|
||
{
|
||
m_ROAction = eRO_Install;
|
||
}
|
||
else
|
||
{
|
||
m_ROAction = eRO_WinMainFunction;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: ~RunOnceExEntry
|
||
|
||
PARAMETERS:
|
||
none
|
||
|
||
DESCRIPTION:
|
||
This destructor will free memory that it used.
|
||
\***************************************************/
|
||
RunOnceExEntry::~RunOnceExEntry()
|
||
{
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: RunOnceExEntry::Process
|
||
|
||
PARAMETERS:
|
||
HKEY hkeyParent - Section of the registry being processed.
|
||
LPCTSTR szSubkey - Path to the registry entries being processed.
|
||
LPCTSTR szSectonName - Only used for logging purposes.
|
||
DWORD dwFlags - Flags to determine if we delete command after executing it.
|
||
|
||
DESCRIPTION:
|
||
This function will Processes the entry.
|
||
This means it will execute the command or
|
||
call a function in a DLL. After it finishes,
|
||
it will delete the registry entry if appropriate.
|
||
\***************************************************/
|
||
void RunOnceExEntry::Process(HKEY hkeyParent, LPCTSTR szSubkey, LPCTSTR szSectionName, DWORD dwFlags)
|
||
{
|
||
HINSTANCE hInstance = NULL;
|
||
WINMAIN_PARAMS pfWinMainFunction = NULL;
|
||
DLLREGISTERSERVER_PARAMS pfDllRegisterServer = NULL;
|
||
DLLINSTALL_PARAMS pfDllInstall = NULL;
|
||
|
||
TCHAR szRegKeyPath[MAX_REG_PATH] = TEXT("");
|
||
HKEY hCurrentSectionKey = NULL;
|
||
|
||
BOOL fWx86DLL = FALSE;
|
||
|
||
// Delete Registry Entry
|
||
if ((NULL != szSectionName) && (RRA_DELETE & dwFlags))
|
||
{
|
||
wsprintf(szRegKeyPath, TEXT("%s\\%s"), szSubkey, szSectionName);
|
||
LocalSHDeleteValue(hkeyParent, szRegKeyPath, m_szRunOnceExEntryName);
|
||
}
|
||
|
||
WriteToLog(TEXT("File:%1; Function:%2; Args:%3; Action:"), m_szFileName, m_szFunctionName, m_szCmdLineArgs);
|
||
|
||
switch(m_ROAction)
|
||
{
|
||
case eRO_Register:
|
||
case eRO_Unregister:
|
||
WriteToLog(m_ROAction == eRO_Register ? TEXT("DllRegisterServer()\r\n") : TEXT("DllUnRegisterServer()\r\n"));
|
||
hInstance = RunOnceLoadLibrary( m_szFileName, &fWx86DLL );
|
||
if (NULL != hInstance)
|
||
{
|
||
HRESULT hResult = S_OK;
|
||
char pcstrDLLToLoad[MAX_PATH];
|
||
|
||
#ifdef UNICODE
|
||
WideCharToMultiByte(CP_ACP, 0, m_szFunctionName, -1,
|
||
pcstrDLLToLoad, ARRAYSIZE(pcstrDLLToLoad), NULL, NULL);
|
||
#else // UNICODE
|
||
lstrcpy(pcstrDLLToLoad, m_szFunctionName);
|
||
#endif // UNICODE
|
||
|
||
if (NULL != (pfDllRegisterServer = (DLLREGISTERSERVER_PARAMS) GetProcAddress(hInstance, pcstrDLLToLoad)))
|
||
{
|
||
if (RRAEX_NO_EXCEPTION_TRAPPING & dwFlags) // Don't trap exceptions if that's what the user wants.
|
||
{
|
||
// This flag is off be default because you better have a debugger installed if you don't catch
|
||
// these exceptions
|
||
#ifdef WX86
|
||
if ( fWx86DLL )
|
||
{
|
||
hResult = Wx86EmulateX86(pfDllRegisterServer, 0, NULL );
|
||
}
|
||
else
|
||
#endif
|
||
hResult = (*pfDllRegisterServer)();
|
||
}
|
||
else
|
||
{
|
||
_try
|
||
{
|
||
#ifdef WX86
|
||
if ( fWx86DLL )
|
||
{
|
||
hResult = Wx86EmulateX86(pfDllRegisterServer, 0, NULL );
|
||
}
|
||
else
|
||
#endif
|
||
hResult = (*pfDllRegisterServer)();
|
||
}
|
||
_except(EXCEPTION_EXECUTE_HANDLER) // Catch all exceptions.
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_EXCEPTION, m_szFunctionName, m_szFileName);
|
||
}
|
||
}
|
||
if (FAILED(hResult))
|
||
{
|
||
WriteToLog(TEXT("An error occurred calling ""%1"" in ""%2"". (HRESULT = %3!lx!)\r\n"), m_szFunctionName, m_szFileName, hResult);
|
||
ReportError(dwFlags, IDS_RUNONCEEX_REGISTER_ERROR, m_szFileName);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_FIND_FUNC_FAILED, m_szFunctionName, m_szFileName);
|
||
}
|
||
FreeLibrary(hInstance);
|
||
}
|
||
else
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_CANNOT_LOAD_DLL, m_szFileName);
|
||
}
|
||
|
||
break;
|
||
|
||
case eRO_Install:
|
||
WriteToLog(TEXT("DllInstall()\r\n"));
|
||
hInstance = RunOnceLoadLibrary( m_szFileName, &fWx86DLL );
|
||
if (NULL != hInstance)
|
||
{
|
||
char pcstrDLLToLoad[MAX_PATH];
|
||
WCHAR pwstrDLLCmdLineArgs[MAX_PATH];
|
||
HRESULT hResult = S_OK;
|
||
|
||
#ifdef UNICODE
|
||
WideCharToMultiByte(CP_ACP, 0, m_szFunctionName, -1,
|
||
pcstrDLLToLoad, ARRAYSIZE(pcstrDLLToLoad), NULL, NULL);
|
||
lstrcpy(pwstrDLLCmdLineArgs, m_szCmdLineArgs);
|
||
#else // UNICODE
|
||
lstrcpy(pcstrDLLToLoad, m_szFunctionName);
|
||
MultiByteToWideChar(CP_ACP, 0, m_szCmdLineArgs, -1, pwstrDLLCmdLineArgs, ARRAYSIZE(pwstrDLLCmdLineArgs));
|
||
#endif // UNICODE
|
||
|
||
if (NULL != (pfDllInstall = (DLLINSTALL_PARAMS) GetProcAddress(hInstance, pcstrDLLToLoad)))
|
||
{
|
||
BOOL bInstall;
|
||
WCHAR *pwszArgs;
|
||
|
||
// parse the command line
|
||
for (pwszArgs = pwstrDLLCmdLineArgs; *pwszArgs != L',' && *pwszArgs != L'\0'; pwszArgs++)
|
||
;
|
||
if (*pwszArgs == L',')
|
||
*pwszArgs++ = L'\0';
|
||
|
||
// args to DllInstall is (BOOL, LPWSTR)
|
||
bInstall = (*pwstrDLLCmdLineArgs != L'u') && (*pwstrDLLCmdLineArgs != L'U');
|
||
|
||
if (RRAEX_NO_EXCEPTION_TRAPPING & dwFlags) // Don't trap exceptions if that's what the caller wants.
|
||
{
|
||
// This flag is off by default because you better have a debugger installed if you don't catch
|
||
// these exceptions
|
||
|
||
#ifdef WX86
|
||
if ( fWx86DLL )
|
||
{
|
||
DWORD dwArgs[ 2 ];
|
||
dwArgs[ 0 ] = (DWORD) bInstall;
|
||
dwArgs[ 1 ] = (DWORD) pwszArgs;
|
||
hResult = Wx86EmulateX86(pfDllInstall, ARRAYSIZE(dwArgs), dwArgs);
|
||
}
|
||
else
|
||
#endif
|
||
hResult = (*pfDllInstall)(bInstall, pwszArgs);
|
||
}
|
||
else
|
||
{
|
||
_try
|
||
{
|
||
#ifdef WX86
|
||
if ( fWx86DLL )
|
||
{
|
||
DWORD dwArgs[ 2 ];
|
||
dwArgs[ 0 ] = (DWORD) bInstall;
|
||
dwArgs[ 1 ] = (DWORD) pwszArgs;
|
||
hResult = Wx86EmulateX86(pfDllInstall, ARRAYSIZE(dwArgs), dwArgs);
|
||
}
|
||
else
|
||
#endif
|
||
hResult = (*pfDllInstall)(bInstall, pwszArgs);
|
||
}
|
||
_except(EXCEPTION_EXECUTE_HANDLER) // Catch all exceptions.
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_EXCEPTION, m_szFunctionName, m_szFileName);
|
||
}
|
||
}
|
||
if (FAILED(hResult))
|
||
{
|
||
WriteToLog(TEXT("An error occurred calling ""%1"" in ""%2"". (HRESULT = %3!lx!)\r\n"), m_szFunctionName, m_szFileName, hResult);
|
||
ReportError(dwFlags, IDS_RUNONCEEX_REGISTER_ERROR, m_szFileName);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_CANNOT_FIND_FUNCTION, m_szFunctionName, m_szFileName);
|
||
}
|
||
FreeLibrary(hInstance);
|
||
}
|
||
else
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_CANNOT_LOAD_DLL, m_szFileName);
|
||
}
|
||
break;
|
||
|
||
case eRO_WinMainFunction:
|
||
WriteToLog(TEXT("WinMain type function\r\n"));
|
||
hInstance = RunOnceLoadLibrary( m_szFileName, &fWx86DLL );
|
||
if (NULL != hInstance)
|
||
{
|
||
char pcstrDLLToLoad[MAX_PATH];
|
||
char pcstrDLLCmdLineArgs[MAX_PATH];
|
||
|
||
#ifdef UNICODE
|
||
WideCharToMultiByte(CP_ACP, 0, m_szFunctionName, -1,
|
||
pcstrDLLToLoad, ARRAYSIZE(pcstrDLLToLoad), NULL, NULL);
|
||
WideCharToMultiByte(CP_ACP, 0, m_szCmdLineArgs, -1,
|
||
pcstrDLLCmdLineArgs, ARRAYSIZE(pcstrDLLCmdLineArgs), NULL, NULL);
|
||
#else // UNICODE
|
||
lstrcpy(pcstrDLLToLoad, m_szFunctionName);
|
||
lstrcpy(pcstrDLLCmdLineArgs, m_szCmdLineArgs);
|
||
#endif // UNICODE
|
||
|
||
if (NULL != (pfWinMainFunction = (WINMAIN_PARAMS) GetProcAddress(hInstance, pcstrDLLToLoad)))
|
||
{
|
||
if (RRAEX_NO_EXCEPTION_TRAPPING & dwFlags) // Don't trap exceptions if that's what the caller wants.
|
||
{
|
||
// This flag is off be default because you better have a debugger installed if you don't catch
|
||
// these exceptions
|
||
|
||
#ifdef WX86
|
||
if ( fWx86DLL )
|
||
{
|
||
DWORD dwArgs[ 4 ];
|
||
dwArgs[ 0 ] = (DWORD) NULL;
|
||
dwArgs[ 1 ] = (DWORD) NULL;
|
||
dwArgs[ 2 ] = (DWORD) pcstrDLLCmdLineArgs;
|
||
dwArgs[ 3 ] = (DWORD) 0;
|
||
Wx86EmulateX86(pfWinMainFunction, ARRAYSIZE(dwArgs), dwArgs);
|
||
}
|
||
else
|
||
#endif
|
||
(*pfWinMainFunction)(NULL, NULL, pcstrDLLCmdLineArgs, 0);
|
||
}
|
||
else
|
||
{
|
||
_try
|
||
{
|
||
#ifdef WX86
|
||
if ( fWx86DLL )
|
||
{
|
||
DWORD dwArgs[ 4 ];
|
||
dwArgs[ 0 ] = (DWORD) NULL;
|
||
dwArgs[ 1 ] = (DWORD) NULL;
|
||
dwArgs[ 2 ] = (DWORD) pcstrDLLCmdLineArgs;
|
||
dwArgs[ 3 ] = (DWORD) 0;
|
||
Wx86EmulateX86(pfWinMainFunction, ARRAYSIZE(dwArgs), dwArgs);
|
||
}
|
||
else
|
||
#endif
|
||
(*pfWinMainFunction)(NULL, NULL, pcstrDLLCmdLineArgs, 0);
|
||
}
|
||
_except(EXCEPTION_EXECUTE_HANDLER) // Catch all exceptions.
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_EXCEPTION, m_szFunctionName, m_szFileName);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_CANNOT_FIND_FUNCTION, m_szFunctionName, m_szFileName);
|
||
}
|
||
FreeLibrary(hInstance);
|
||
}
|
||
else
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_CANNOT_LOAD_DLL, m_szFileName);
|
||
}
|
||
break;
|
||
|
||
case eRO_Exe:
|
||
WriteToLog(TEXT("ShellExec Command\r\n"));
|
||
{
|
||
if (RRAEX_NO_EXCEPTION_TRAPPING & dwFlags) // Don't trap exceptions if that's what the caller wants.
|
||
{
|
||
// This flag is off be default because you better have a debugger installed if you don't catch
|
||
// these exceptions
|
||
ShellExecuteRegApp(m_szCmdLineArgs, dwFlags);
|
||
}
|
||
else
|
||
{
|
||
_try
|
||
{
|
||
ShellExecuteRegApp(m_szCmdLineArgs, dwFlags);
|
||
}
|
||
_except(EXCEPTION_EXECUTE_HANDLER) // Catch all exceptions.
|
||
{
|
||
ReportError(dwFlags, IDS_RUNONCEEX_EXE_EXCEPTION, m_szCmdLineArgs);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case eRO_Unknown:
|
||
default:
|
||
WriteToLog(TEXT("Unknown\r\n"));
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////
|
||
// CLASS: RunOnceExSection
|
||
/////////////////////////////////////////////////////////////////////
|
||
|
||
/****************************************************\
|
||
FUNCTION: RunOnceExSection
|
||
|
||
PARAMETERS:
|
||
LPTSTR lpszNewSectionName - The name of the new section
|
||
LPTSTR lpszNewDisplayName - The display name of the new section
|
||
|
||
DESCRIPTION:
|
||
This constructor will set the name of the newly
|
||
created section.
|
||
\***************************************************/
|
||
RunOnceExSection::RunOnceExSection(LPTSTR lpszNewSectionName, LPTSTR lpszNewDisplayName)
|
||
{
|
||
lstrcpy(m_szRunOnceExSectionName, lpszNewSectionName);
|
||
|
||
if ((NULL != lpszNewDisplayName) && (TEXT('\0') != *lpszNewDisplayName))
|
||
{
|
||
// Set the DisplayName as long as it was valid.
|
||
lstrcpy(m_szDisplayName, lpszNewDisplayName);
|
||
}
|
||
else
|
||
{
|
||
// It was invalid, so we use the SectionName for the DisplayName.
|
||
//lstrcpy(m_szDisplayName, lpszNewSectionName);
|
||
*m_szDisplayName = TEXT('\0'); // just don't display anything
|
||
}
|
||
m_hEntryArray = NULL;
|
||
m_NumberOfEntries = 0;
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: ~RunOnceExSection
|
||
|
||
PARAMETERS:
|
||
none
|
||
|
||
DESCRIPTION:
|
||
This destructor will free memory that it used.
|
||
\***************************************************/
|
||
RunOnceExSection::~RunOnceExSection()
|
||
{
|
||
if (NULL != m_hEntryArray)
|
||
{
|
||
RunOnceExEntry * pFirstSection;
|
||
|
||
for (int iIndex = 0; iIndex < m_NumberOfEntries; iIndex++)
|
||
{
|
||
pFirstSection = (RunOnceExEntry *) DPA_GetPtr(m_hEntryArray, iIndex);
|
||
delete pFirstSection;
|
||
}
|
||
|
||
DPA_Destroy(m_hEntryArray);
|
||
}
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: RunOnceExSection::Process
|
||
|
||
PARAMETERS:
|
||
HKEY hkeyParent - Section of the registry being processed.
|
||
LPCTSTR szSubkey - Path to the registry entries being processed.
|
||
DWORD dwFlags - Flags to determine if we delete command after executing it.
|
||
|
||
DESCRIPTION:
|
||
This function will process each entry in it,
|
||
delete the registry key it used, and then
|
||
repeat the process with the next section.
|
||
\***************************************************/
|
||
void RunOnceExSection::Process(HKEY hkeyParent, LPCTSTR szSubkey, DWORD dwFlags)
|
||
{
|
||
RunOnceExEntry * pCurrentEntry = NULL;
|
||
HKEY hSectionKey = NULL;
|
||
int iEntryIndex;
|
||
|
||
WriteToLog(TEXT("\r\n"));
|
||
LogDateAndTime();
|
||
WriteToLog(TEXT("Section:%1\r\n"), m_szRunOnceExSectionName);
|
||
|
||
// Load the dependency DLLs for this sections
|
||
HandleDependencyDLLs(hkeyParent, szSubkey, m_szRunOnceExSectionName, dwFlags, eHDL_Load);
|
||
|
||
if (NULL != m_hEntryArray)
|
||
{
|
||
for (iEntryIndex = 0; iEntryIndex < m_NumberOfEntries; iEntryIndex++)
|
||
{
|
||
pCurrentEntry = (RunOnceExEntry *) DPA_GetPtr(m_hEntryArray, iEntryIndex);
|
||
if (pCurrentEntry)
|
||
pCurrentEntry->Process(hkeyParent, szSubkey, m_szRunOnceExSectionName, dwFlags);
|
||
|
||
// If there is a call back, send back information
|
||
if (g_pCallbackProc)
|
||
{
|
||
g_nCurrent++;
|
||
g_pCallbackProc(g_nCurrent, g_nTotal, NULL);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Unload the dependency DLLs for this sections
|
||
HandleDependencyDLLs(hkeyParent, szSubkey, m_szRunOnceExSectionName, dwFlags, eHDL_Unload);
|
||
|
||
LogDateAndTime();
|
||
|
||
if (RRA_DELETE & dwFlags)
|
||
{
|
||
TCHAR szKeyToDelete[MAX_REG_PATH];
|
||
wsprintf(szKeyToDelete, TEXT("%s\\%s"), szSubkey, m_szRunOnceExSectionName);
|
||
LocalSHDeleteKey(hkeyParent, szKeyToDelete);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: CompareSection
|
||
|
||
PARAMETERS:
|
||
RunOnceExSection * pSection1 - The first Section to be compared
|
||
RunOnceExSection * pSection2 - The second Section to be compared
|
||
LPARAM lpNotUsed - Not used.
|
||
int return - (-1) if the first is smaller.
|
||
|
||
DESCRIPTION:
|
||
The following function will determine which
|
||
comes first when sorted.
|
||
\***************************************************/
|
||
INT CALLBACK CompareSection(RunOnceExSection * pSection1, RunOnceExSection * pSection2, LPARAM lpNotUsed)
|
||
{
|
||
if (1 == CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, pSection1->m_szRunOnceExSectionName, -1, pSection2->m_szRunOnceExSectionName, -1))
|
||
return(-1);
|
||
|
||
return(1);
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: CompareEntries
|
||
|
||
PARAMETERS:
|
||
RunOnceExEntry * pEntry1 - The first Entry to be compared
|
||
RunOnceExEntry * pEntry2 - The second Entry to be compared
|
||
LPARAM lpNotUsed - Not used.
|
||
int return - (-1) if the first is smaller.
|
||
|
||
DESCRIPTION:
|
||
The following function will determine which
|
||
comes first when sorted.
|
||
\***************************************************/
|
||
INT CALLBACK CompareEntries(RunOnceExEntry * pEntry1, RunOnceExEntry * pEntry2, LPARAM lpNotUsed)
|
||
{
|
||
if (1 == CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, pEntry1->m_szRunOnceExEntryName, -1, pEntry2->m_szRunOnceExEntryName, -1))
|
||
return(-1);
|
||
|
||
return(1);
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: GetSections
|
||
|
||
PARAMETERS:
|
||
HKEY hkeyParent - Section of the registry being processed.
|
||
LPCTSTR szSubkey - Path to the registry entries being processed.
|
||
DWORD dwFlags - Flags.
|
||
|
||
DESCRIPTION:
|
||
This function will open the RunOnceEx registry
|
||
key and read all the sections and entries. It will
|
||
read these into memory and set *ppFirstSection to
|
||
the first (root) section.
|
||
\***************************************************/
|
||
HDPA GetSections(HKEY hkeyParent, LPCTSTR szSubkey, DWORD dwFlags, int * pNumberOfSections)
|
||
{
|
||
TCHAR szCurrentSectionName[MAX_ENTRYNAME] = TEXT("");
|
||
TCHAR szCurrSectionDisplayName[MAX_ENTRYNAME] = TEXT("");
|
||
HKEY hRootKey = NULL;
|
||
DWORD dwCurrentSection = 0;
|
||
|
||
DWORD dwRegType = 0;
|
||
long lDisplayNameSize = ARRAYSIZE(szCurrSectionDisplayName);
|
||
long lEnumError;
|
||
HDPA hDPA_Sections = DPA_Create(ARRAY_GROW_RATE);
|
||
RunOnceExSection * pNewSection = NULL;
|
||
|
||
*pNumberOfSections = 0;
|
||
|
||
if (NULL != hDPA_Sections)
|
||
{
|
||
// Do we have any RegOpenKeyEx sections to process/read?
|
||
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyParent, szSubkey, NULL, KEY_READ, &hRootKey))
|
||
{
|
||
// IthkeyParenterate through each section
|
||
for (dwCurrentSection = 0;
|
||
ERROR_NO_MORE_ITEMS != (lEnumError = RegEnumKey(hRootKey, dwCurrentSection, szCurrentSectionName, ARRAYSIZE(szCurrentSectionName)));
|
||
dwCurrentSection++)
|
||
{
|
||
if (ERROR_SUCCESS == lEnumError)
|
||
{
|
||
lDisplayNameSize = sizeof(szCurrSectionDisplayName);
|
||
if (RegQueryValue(hRootKey, szCurrentSectionName, szCurrSectionDisplayName, &lDisplayNameSize) != ERROR_SUCCESS)
|
||
*szCurrSectionDisplayName = TEXT('\0');
|
||
|
||
// Only Process non-"Depend" entries.
|
||
if (2 != CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szCurrentSectionName, -1, c_szDependencyName, -1))
|
||
{
|
||
pNewSection = new RunOnceExSection(szCurrentSectionName, szCurrSectionDisplayName);
|
||
if (NULL != pNewSection)
|
||
{
|
||
if (*szCurrSectionDisplayName)
|
||
g_iNDisplaySections++;
|
||
DPA_SetPtr(hDPA_Sections, *pNumberOfSections, (void *) pNewSection);
|
||
pNewSection->m_hEntryArray = GetEntries(hRootKey, szCurrentSectionName, dwFlags, &(pNewSection->m_NumberOfEntries));
|
||
(*pNumberOfSections)++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
RegCloseKey(hRootKey);
|
||
}
|
||
|
||
DPA_Sort(hDPA_Sections, (PFNDPACOMPARE) CompareSection, 0);
|
||
}
|
||
|
||
return(hDPA_Sections);
|
||
}
|
||
|
||
|
||
/****************************************************\
|
||
FUNCTION: GetEntries
|
||
|
||
PARAMETERS:
|
||
HKEY hkeyParent - Section of the registry being processed.
|
||
LPCTSTR szSubkey - Path to the registry entries being processed.
|
||
DWORD dwFlags - Flags.
|
||
int * pNumberOfEntries - OUT: Number of sections read.
|
||
|
||
DESCRIPTION:
|
||
This function will open the RunOnceEx registry
|
||
section key and read all the entries.
|
||
\***************************************************/
|
||
HDPA GetEntries(HKEY hRootKey, LPCTSTR szSectionName, DWORD dwFlags, int * pNumberOfEntries)
|
||
{
|
||
HKEY hCurrentSectionKey = NULL;
|
||
|
||
TCHAR szCurrentEntryName[MAX_ENTRYNAME] = TEXT("");
|
||
TCHAR szCurrentEntryCmd[MAX_PATH] = TEXT("");
|
||
DWORD dwEntrySize = 0;
|
||
DWORD dwEntryCmdSize = 0;
|
||
|
||
DWORD dwCurrentEntry = 0;
|
||
DWORD dwRegType = 0;
|
||
long lEnumError;
|
||
HDPA hDPA_Entries = DPA_Create(ARRAY_GROW_RATE);
|
||
RunOnceExEntry * pNewEntry = NULL;
|
||
|
||
*pNumberOfEntries = 0;
|
||
|
||
if (NULL != hDPA_Entries)
|
||
{
|
||
if (ERROR_SUCCESS == RegOpenKeyEx(hRootKey, szSectionName, NULL, KEY_READ, &hCurrentSectionKey))
|
||
{
|
||
DWORD dwKeyType;
|
||
|
||
// Iterate through each value
|
||
dwEntrySize = ARRAYSIZE(szCurrentEntryName);
|
||
dwEntryCmdSize = sizeof(szCurrentEntryCmd);
|
||
|
||
for (dwCurrentEntry = 0;
|
||
ERROR_NO_MORE_ITEMS != (lEnumError = RegEnumValue(hCurrentSectionKey, dwCurrentEntry, szCurrentEntryName, &dwEntrySize, NULL, &dwKeyType, (LPBYTE) szCurrentEntryCmd, &dwEntryCmdSize));
|
||
dwCurrentEntry++)
|
||
{
|
||
if (ERROR_SUCCESS == lEnumError)
|
||
{
|
||
// An empty Entry Name is not acceptable because that is the Display Name for the section.
|
||
if ((REG_SZ == dwKeyType) && (TEXT('\0') != *szCurrentEntryName))
|
||
{
|
||
pNewEntry = new RunOnceExEntry(szCurrentEntryName, szCurrentEntryCmd, dwFlags);
|
||
if (NULL != pNewEntry)
|
||
{
|
||
if (eRO_Unknown != pNewEntry->m_ROAction)
|
||
{
|
||
DPA_SetPtr(hDPA_Entries, *pNumberOfEntries, (void *) pNewEntry);
|
||
(*pNumberOfEntries)++;
|
||
}
|
||
else
|
||
delete pNewEntry;
|
||
}
|
||
}
|
||
}
|
||
|
||
dwEntrySize = ARRAYSIZE(szCurrentEntryName);
|
||
dwEntryCmdSize = sizeof(szCurrentEntryCmd);
|
||
}
|
||
|
||
RegCloseKey(hCurrentSectionKey);
|
||
}
|
||
|
||
DPA_Sort(hDPA_Entries, (PFNDPACOMPARE) CompareEntries, 0);
|
||
}
|
||
|
||
return(hDPA_Entries);
|
||
}
|
||
|
||
|
||
// taken from \\trango\slmadd\src\shell\shell32\shellprv.h
|
||
#define FillExecInfo(_info, _hwnd, _verb, _file, _params, _dir, _show) \
|
||
(_info).hwnd = _hwnd; \
|
||
(_info).lpVerb = _verb; \
|
||
(_info).lpFile = _file; \
|
||
(_info).lpParameters = _params; \
|
||
(_info).lpDirectory = _dir; \
|
||
(_info).nShow = _show; \
|
||
(_info).fMask = 0; \
|
||
(_info).cbSize = sizeof(SHELLEXECUTEINFO);
|
||
|
||
//
|
||
// Path processing function
|
||
//
|
||
#define PPCF_ADDQUOTES 0x00000001 // return a quoted name if required
|
||
#define PPCF_ADDARGUMENTS 0x00000003 // appends arguments (and wraps in quotes if required)
|
||
#define PPCF_NODIRECTORIES 0x00000010 // don't match to directories
|
||
#define PPCF_NORELATIVEOBJECTQUALIFY 0x00000020 // don't return fully qualified relative objects
|
||
#define PPCF_FORCEQUALIFY 0x00000040 // qualify even non-relative names
|
||
|
||
typedef LONG WINSHELLAPI (WINAPI * LPPATHPROCESSCOMMAND)(LPCTSTR, LPTSTR, int, DWORD);
|
||
|
||
/****************************************************\
|
||
FUNCTION: ShellExecuteRegApp
|
||
|
||
PARAMETERS:
|
||
LPCTSTR pszCmdLine - Cmd line to execute
|
||
DWORD dwFlags - Flags to specify if we need to wait for command to finish.
|
||
|
||
DESCRIPTION:
|
||
The following handles running an application
|
||
and optionally waiting for it to terminate.
|
||
\***************************************************/
|
||
void ShellExecuteRegApp(LPTSTR pszCmdLine, DWORD dwFlags)
|
||
{
|
||
TCHAR szBuf[MAX_PATH];
|
||
|
||
GetSystemDirectory(szBuf, ARRAYSIZE(szBuf));
|
||
|
||
if (RunningOnIE4())
|
||
{
|
||
HINSTANCE hShell32DLL = NULL;
|
||
LPPATHPROCESSCOMMAND pfnPathProcessCommand;
|
||
TCHAR szQuotedCmdLine[MAX_PATH+2];
|
||
SHELLEXECUTEINFO ExecInfo;
|
||
LPTSTR lpszArgs;
|
||
BOOL fPPCSuccess = FALSE; // PathProcessCommand succeeded
|
||
|
||
AddPath(szBuf, TEXT("shell32.dll"));
|
||
|
||
if ((hShell32DLL = LoadLibraryEx(szBuf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) != NULL)
|
||
{
|
||
if ((pfnPathProcessCommand = (LPPATHPROCESSCOMMAND) GetProcAddress(hShell32DLL, (LPCSTR) 653)) != NULL)
|
||
{
|
||
//
|
||
// We used to call CreateProcess( NULL, szCmdLine, ...) here,
|
||
// but thats not useful for people with apppaths stuff.
|
||
//
|
||
|
||
// Gross, but if the process command fails, copy the command line to let
|
||
// shell execute report the errors
|
||
|
||
if ((pfnPathProcessCommand)(pszCmdLine, szQuotedCmdLine, ARRAYSIZE(szQuotedCmdLine), PPCF_ADDARGUMENTS|PPCF_FORCEQUALIFY) != -1)
|
||
fPPCSuccess = TRUE;
|
||
}
|
||
|
||
FreeLibrary(hShell32DLL);
|
||
}
|
||
|
||
if (!fPPCSuccess)
|
||
lstrcpy(szQuotedCmdLine, pszCmdLine);
|
||
|
||
lpszArgs = LocalPathGetArgs(szQuotedCmdLine);
|
||
if (*lpszArgs)
|
||
*(lpszArgs-1) = TEXT('\0'); // Strip args
|
||
|
||
LocalPathUnquoteSpaces(szQuotedCmdLine);
|
||
|
||
FillExecInfo(ExecInfo, NULL, NULL, szQuotedCmdLine, lpszArgs, szBuf, SW_SHOWNORMAL);
|
||
ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
|
||
if (dwFlags & RRAEX_NO_ERROR_DIALOGS) // Don't display Error dialog
|
||
ExecInfo.fMask |= SEE_MASK_FLAG_NO_UI;
|
||
|
||
if (ShellExecuteEx(&ExecInfo))
|
||
{
|
||
if ((dwFlags & RRA_WAIT) && (ExecInfo.hProcess != NULL))
|
||
{
|
||
MsgWaitForMultipleObjectsLoop(ExecInfo.hProcess, INFINITE);
|
||
}
|
||
|
||
CloseHandle(ExecInfo.hProcess);
|
||
}
|
||
}
|
||
else // old Win95 logic -- just call CreateProcess
|
||
{
|
||
STARTUPINFO startup;
|
||
PROCESS_INFORMATION pi;
|
||
|
||
ZeroMemory(&startup, sizeof(startup));
|
||
startup.cb = sizeof(startup);
|
||
|
||
if (CreateProcess(NULL, pszCmdLine, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, szBuf, &startup, &pi))
|
||
{
|
||
if (dwFlags & RRA_WAIT)
|
||
{
|
||
MsgWaitForMultipleObjectsLoop(pi.hProcess, INFINITE);
|
||
}
|
||
|
||
CloseHandle(pi.hProcess);
|
||
CloseHandle(pi.hThread);
|
||
}
|
||
}
|
||
}
|
||
|
||
#define BUFFER_SIZE 1024
|
||
BOOL HaveDependServices(SC_HANDLE hService)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
LPBYTE lpBuffer = NULL;
|
||
DWORD dwSize = BUFFER_SIZE; // Start with 1k
|
||
DWORD dwBytesNeeded;
|
||
DWORD dwNumServices;
|
||
BOOL bDependServices = FALSE;
|
||
|
||
lpBuffer = (LPBYTE) LocalAlloc(LPTR, dwSize);
|
||
if (lpBuffer)
|
||
{
|
||
if (!EnumDependentServices(hService, SERVICE_STATE_ALL,
|
||
(LPENUM_SERVICE_STATUS)lpBuffer, dwSize,
|
||
&dwBytesNeeded, &dwNumServices))
|
||
{
|
||
if (GetLastError() == ERROR_MORE_DATA)
|
||
{
|
||
dwSize = dwBytesNeeded + 32;
|
||
LocalFree(lpBuffer);
|
||
lpBuffer = (LPBYTE) LocalAlloc(LPTR, dwSize);
|
||
if (lpBuffer)
|
||
{
|
||
if (!EnumDependentServices(hService, SERVICE_STATE_ALL,
|
||
(LPENUM_SERVICE_STATUS)lpBuffer, dwSize,
|
||
&dwBytesNeeded, &dwNumServices))
|
||
{
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
}
|
||
}
|
||
else
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
}
|
||
else
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
||
}
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
// If at least one service depends on this one?
|
||
bDependServices = (dwNumServices != 0);
|
||
}
|
||
if (lpBuffer)
|
||
LocalFree(lpBuffer);
|
||
}
|
||
return bDependServices;
|
||
}
|
||
|
||
void CheckServices(DWORD dwFlags)
|
||
{
|
||
SC_HANDLE hSCM = NULL;
|
||
SC_HANDLE hService = NULL;
|
||
BOOL bRebootNeeded = FALSE;
|
||
HKEY hKey = NULL;
|
||
LPSTR pServices = NULL;
|
||
LPSTR pCheckService = NULL;
|
||
LONG lRet = 0;
|
||
DWORD dwSize;
|
||
|
||
pServices = (LPSTR)LocalAlloc(LPTR, BUFFER_SIZE);
|
||
if (pServices)
|
||
{
|
||
// Get the services to check for from the registry.
|
||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCEEX, NULL, KEY_READ|KEY_WRITE, &hKey) == ERROR_SUCCESS)
|
||
{
|
||
dwSize = BUFFER_SIZE - 1;
|
||
lRet = RegQueryValueEx(hKey, g_c_szServicesRegValue, NULL, NULL, (LPBYTE)pServices, &dwSize);
|
||
if (lRet == ERROR_MORE_DATA)
|
||
{
|
||
dwSize += 32;
|
||
LocalFree(pServices);
|
||
pServices = (LPSTR)LocalAlloc(LPTR, dwSize);
|
||
|
||
if (pServices)
|
||
{
|
||
lRet = RegQueryValueEx(hKey, g_c_szServicesRegValue, NULL, NULL, (LPBYTE)pServices, &dwSize);
|
||
}
|
||
}
|
||
if (lRet != ERROR_SUCCESS)
|
||
{
|
||
if (pServices)
|
||
{
|
||
LocalFree(pServices);
|
||
pServices = NULL;
|
||
}
|
||
}
|
||
RegDeleteValue(hKey, g_c_szServicesRegValue);
|
||
RegCloseKey(hKey);
|
||
}
|
||
|
||
if ((pServices) && (*pServices))
|
||
{
|
||
hSCM = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||
if (hSCM)
|
||
{
|
||
pCheckService = pServices;
|
||
// zero out all forward slashes to get the services terminated
|
||
while (*pCheckService)
|
||
{
|
||
if (*pCheckService == '/')
|
||
{
|
||
*pCheckService = '\0';
|
||
pCheckService++;
|
||
}
|
||
else
|
||
pCheckService = CharNext(pCheckService);
|
||
}
|
||
// RegQueryValueExA is using the same buffer to convert the UNICODE
|
||
// string to a ANSI string. This will leave some UNICODE characters
|
||
// after the ANSI strings and the services are not realy double 0
|
||
// terminated anymore. This will ensure that the list is still
|
||
// double 0 terminated
|
||
pCheckService++;
|
||
*pCheckService = '\0';
|
||
|
||
pCheckService = pServices;
|
||
while (!bRebootNeeded && (*pCheckService))
|
||
{
|
||
hService = OpenService(hSCM,
|
||
(LPCSTR)pCheckService,
|
||
STANDARD_RIGHTS_REQUIRED | SERVICE_ENUMERATE_DEPENDENTS);
|
||
if (hService)
|
||
{
|
||
bRebootNeeded = HaveDependServices(hService);
|
||
CloseServiceHandle(hService);
|
||
}
|
||
|
||
pCheckService += lstrlen(pCheckService) + 1;
|
||
}
|
||
CloseServiceHandle(hSCM);
|
||
}
|
||
}
|
||
if (pServices)
|
||
LocalFree(pServices);
|
||
}
|
||
if (bRebootNeeded)
|
||
{
|
||
ReportError((dwFlags & ~RRAEX_NO_ERROR_DIALOGS), IDS_RUNONCEEX_SERVICE_REQUIRES_REBOOT);
|
||
LogOff(TRUE);
|
||
}
|
||
}
|