mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[UMPNPMGR] Split the monolithic monster: service, rpc and installer.
This commit is contained in:
parent
e71a94da20
commit
fe3ae24369
5 changed files with 4220 additions and 4087 deletions
|
@ -4,6 +4,8 @@ add_rpc_files(server ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/pnp.idl)
|
|||
spec2def(umpnpmgr.dll umpnpmgr.spec ADD_IMPORTLIB)
|
||||
|
||||
add_library(umpnpmgr MODULE
|
||||
install.c
|
||||
rpcserver.c
|
||||
umpnpmgr.c
|
||||
umpnpmgr.rc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pnp_s.c
|
||||
|
|
377
base/services/umpnpmgr/install.c
Normal file
377
base/services/umpnpmgr/install.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* ReactOS kernel
|
||||
* Copyright (C) 2005 ReactOS Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: base/services/umpnpmgr/install.c
|
||||
* PURPOSE: Device installer
|
||||
* PROGRAMMER: Eric Kohl (eric.kohl@reactos.org)
|
||||
* Hervé Poussineau (hpoussin@reactos.org)
|
||||
* Colin Finck (colin@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
|
||||
/* GLOBALS ******************************************************************/
|
||||
|
||||
HANDLE hUserToken = NULL;
|
||||
HANDLE hInstallEvent = NULL;
|
||||
HANDLE hNoPendingInstalls = NULL;
|
||||
|
||||
SLIST_HEADER DeviceInstallListHead;
|
||||
HANDLE hDeviceInstallListNotEmpty;
|
||||
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
static BOOL
|
||||
InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
|
||||
{
|
||||
BOOL DeviceInstalled = FALSE;
|
||||
DWORD BytesWritten;
|
||||
DWORD Value;
|
||||
HANDLE hInstallEvent;
|
||||
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
||||
LPVOID Environment = NULL;
|
||||
PROCESS_INFORMATION ProcessInfo;
|
||||
STARTUPINFOW StartupInfo;
|
||||
UUID RandomUuid;
|
||||
HKEY DeviceKey;
|
||||
|
||||
/* The following lengths are constant (see below), they cannot overflow */
|
||||
WCHAR CommandLine[116];
|
||||
WCHAR InstallEventName[73];
|
||||
WCHAR PipeName[74];
|
||||
WCHAR UuidString[39];
|
||||
|
||||
DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
|
||||
|
||||
ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
|
||||
|
||||
if (RegOpenKeyExW(hEnumKey,
|
||||
DeviceInstance,
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
&DeviceKey) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueExW(DeviceKey,
|
||||
L"Class",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL) == ERROR_SUCCESS)
|
||||
{
|
||||
DPRINT("No need to install: %S\n", DeviceInstance);
|
||||
RegCloseKey(DeviceKey);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BytesWritten = sizeof(DWORD);
|
||||
if (RegQueryValueExW(DeviceKey,
|
||||
L"ConfigFlags",
|
||||
NULL,
|
||||
NULL,
|
||||
(PBYTE)&Value,
|
||||
&BytesWritten) == ERROR_SUCCESS)
|
||||
{
|
||||
if (Value & CONFIGFLAG_FAILEDINSTALL)
|
||||
{
|
||||
DPRINT("No need to install: %S\n", DeviceInstance);
|
||||
RegCloseKey(DeviceKey);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(DeviceKey);
|
||||
}
|
||||
|
||||
DPRINT1("Installing: %S\n", DeviceInstance);
|
||||
|
||||
/* Create a random UUID for the named pipe & event*/
|
||||
UuidCreate(&RandomUuid);
|
||||
swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
||||
RandomUuid.Data1, RandomUuid.Data2, RandomUuid.Data3,
|
||||
RandomUuid.Data4[0], RandomUuid.Data4[1], RandomUuid.Data4[2],
|
||||
RandomUuid.Data4[3], RandomUuid.Data4[4], RandomUuid.Data4[5],
|
||||
RandomUuid.Data4[6], RandomUuid.Data4[7]);
|
||||
|
||||
/* Create the event */
|
||||
wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
|
||||
wcscat(InstallEventName, UuidString);
|
||||
hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
|
||||
if (!hInstallEvent)
|
||||
{
|
||||
DPRINT1("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Create the named pipe */
|
||||
wcscpy(PipeName, L"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
|
||||
wcscat(PipeName, UuidString);
|
||||
hPipe = CreateNamedPipeW(PipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 512, 512, 0, NULL);
|
||||
if (hPipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Launch rundll32 to call ClientSideInstallW */
|
||||
wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
|
||||
wcscat(CommandLine, PipeName);
|
||||
|
||||
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
|
||||
StartupInfo.cb = sizeof(StartupInfo);
|
||||
|
||||
if (hUserToken)
|
||||
{
|
||||
/* newdev has to run under the environment of the current user */
|
||||
if (!CreateEnvironmentBlock(&Environment, hUserToken, FALSE))
|
||||
{
|
||||
DPRINT1("CreateEnvironmentBlock failed with error %d\n", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!CreateProcessAsUserW(hUserToken, NULL, CommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &StartupInfo, &ProcessInfo))
|
||||
{
|
||||
DPRINT1("CreateProcessAsUserW failed with error %u\n", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: This is probably not correct, I guess newdev should never be run with SYSTEM privileges.
|
||||
|
||||
Still, we currently do that in 2nd stage setup and probably Console mode as well, so allow it here.
|
||||
(ShowWizard is only set to FALSE for these two modes) */
|
||||
ASSERT(!ShowWizard);
|
||||
|
||||
if (!CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
|
||||
{
|
||||
DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the function to connect to our pipe */
|
||||
if (!ConnectNamedPipe(hPipe, NULL))
|
||||
{
|
||||
if (GetLastError() != ERROR_PIPE_CONNECTED)
|
||||
{
|
||||
DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
|
||||
Value = sizeof(InstallEventName);
|
||||
WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
|
||||
WriteFile(hPipe, InstallEventName, Value, &BytesWritten, NULL);
|
||||
|
||||
/* I couldn't figure out what the following value means under WinXP. It's usually 0 in my tests, but was also 5 once.
|
||||
Therefore the following line is entirely ReactOS-specific. We use the value here to pass the ShowWizard variable. */
|
||||
WriteFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesWritten, NULL);
|
||||
|
||||
Value = (wcslen(DeviceInstance) + 1) * sizeof(WCHAR);
|
||||
WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
|
||||
WriteFile(hPipe, DeviceInstance, Value, &BytesWritten, NULL);
|
||||
|
||||
/* Wait for newdev.dll to finish processing */
|
||||
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
|
||||
|
||||
/* If the event got signalled, this is success */
|
||||
DeviceInstalled = WaitForSingleObject(hInstallEvent, 0) == WAIT_OBJECT_0;
|
||||
|
||||
cleanup:
|
||||
if (hInstallEvent)
|
||||
CloseHandle(hInstallEvent);
|
||||
|
||||
if (hPipe != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hPipe);
|
||||
|
||||
if (Environment)
|
||||
DestroyEnvironmentBlock(Environment);
|
||||
|
||||
if (ProcessInfo.hProcess)
|
||||
CloseHandle(ProcessInfo.hProcess);
|
||||
|
||||
if (ProcessInfo.hThread)
|
||||
CloseHandle(ProcessInfo.hThread);
|
||||
|
||||
if (!DeviceInstalled)
|
||||
{
|
||||
DPRINT1("InstallDevice failed for DeviceInstance '%ws'\n", DeviceInstance);
|
||||
}
|
||||
|
||||
return DeviceInstalled;
|
||||
}
|
||||
|
||||
|
||||
static LONG
|
||||
ReadRegSzKey(
|
||||
IN HKEY hKey,
|
||||
IN LPCWSTR pszKey,
|
||||
OUT LPWSTR* pValue)
|
||||
{
|
||||
LONG rc;
|
||||
DWORD dwType;
|
||||
DWORD cbData = 0;
|
||||
LPWSTR Value;
|
||||
|
||||
if (!pValue)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
*pValue = NULL;
|
||||
rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
if (dwType != REG_SZ)
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
|
||||
if (!Value)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, Value);
|
||||
return rc;
|
||||
}
|
||||
/* NULL-terminate the string */
|
||||
Value[cbData / sizeof(WCHAR)] = '\0';
|
||||
|
||||
*pValue = Value;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
SetupIsActive(VOID)
|
||||
{
|
||||
HKEY hKey = NULL;
|
||||
DWORD regType, active, size;
|
||||
LONG rc;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_QUERY_VALUE, &hKey);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
size = sizeof(DWORD);
|
||||
rc = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, ®Type, (LPBYTE)&active, &size);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
if (regType != REG_DWORD || size != sizeof(DWORD))
|
||||
goto cleanup;
|
||||
|
||||
ret = (active != 0);
|
||||
|
||||
cleanup:
|
||||
if (hKey != NULL)
|
||||
RegCloseKey(hKey);
|
||||
|
||||
DPRINT("System setup in progress? %S\n", ret ? L"YES" : L"NO");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
IsConsoleBoot(VOID)
|
||||
{
|
||||
HKEY ControlKey = NULL;
|
||||
LPWSTR SystemStartOptions = NULL;
|
||||
LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
|
||||
BOOL ConsoleBoot = FALSE;
|
||||
LONG rc;
|
||||
|
||||
rc = RegOpenKeyExW(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SYSTEM\\CurrentControlSet\\Control",
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
&ControlKey);
|
||||
|
||||
rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
/* Check for CONSOLE switch in SystemStartOptions */
|
||||
CurrentOption = SystemStartOptions;
|
||||
while (CurrentOption)
|
||||
{
|
||||
NextOption = wcschr(CurrentOption, L' ');
|
||||
if (NextOption)
|
||||
*NextOption = L'\0';
|
||||
if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
|
||||
{
|
||||
DPRINT("Found %S. Switching to console boot\n", CurrentOption);
|
||||
ConsoleBoot = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
CurrentOption = NextOption ? NextOption + 1 : NULL;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (ControlKey != NULL)
|
||||
RegCloseKey(ControlKey);
|
||||
HeapFree(GetProcessHeap(), 0, SystemStartOptions);
|
||||
return ConsoleBoot;
|
||||
}
|
||||
|
||||
|
||||
/* Loop to install all queued devices installations */
|
||||
DWORD
|
||||
WINAPI
|
||||
DeviceInstallThread(LPVOID lpParameter)
|
||||
{
|
||||
PSLIST_ENTRY ListEntry;
|
||||
DeviceInstallParams* Params;
|
||||
BOOL showWizard;
|
||||
|
||||
UNREFERENCED_PARAMETER(lpParameter);
|
||||
|
||||
WaitForSingleObject(hInstallEvent, INFINITE);
|
||||
|
||||
showWizard = !SetupIsActive() && !IsConsoleBoot();
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
ListEntry = InterlockedPopEntrySList(&DeviceInstallListHead);
|
||||
|
||||
if (ListEntry == NULL)
|
||||
{
|
||||
SetEvent(hNoPendingInstalls);
|
||||
WaitForSingleObject(hDeviceInstallListNotEmpty, INFINITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetEvent(hNoPendingInstalls);
|
||||
Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
|
||||
InstallDevice(Params->DeviceIds, showWizard);
|
||||
HeapFree(GetProcessHeap(), 0, Params);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
75
base/services/umpnpmgr/precomp.h
Normal file
75
base/services/umpnpmgr/precomp.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: base/services/umpnpmgr/install.c
|
||||
* PURPOSE: Device installer
|
||||
* PROGRAMMER: Eric Kohl (eric.kohl@reactos.org)
|
||||
* Hervé Poussineau (hpoussin@reactos.org)
|
||||
* Colin Finck (colin@reactos.org)
|
||||
*/
|
||||
|
||||
#ifndef _UMPNPMGR_PCH_
|
||||
#define _UMPNPMGR_PCH_
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#define _INC_WINDOWS
|
||||
#define COM_NO_WINDOWS_H
|
||||
#include <stdarg.h>
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winreg.h>
|
||||
#include <winsvc.h>
|
||||
#include <winuser.h>
|
||||
#include <dbt.h>
|
||||
#include <stdio.h>
|
||||
#include <cmfuncs.h>
|
||||
#include <rtlfuncs.h>
|
||||
#include <setypes.h>
|
||||
#include <umpnpmgr/sysguid.h>
|
||||
#include <cfgmgr32.h>
|
||||
#include <regstr.h>
|
||||
#include <userenv.h>
|
||||
#include <shlwapi.h>
|
||||
#include <pnp_s.h>
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SLIST_ENTRY ListEntry;
|
||||
WCHAR DeviceIds[1];
|
||||
} DeviceInstallParams;
|
||||
|
||||
|
||||
/* install.c */
|
||||
|
||||
extern HANDLE hUserToken;
|
||||
extern HANDLE hInstallEvent;
|
||||
extern HANDLE hNoPendingInstalls;
|
||||
|
||||
extern SLIST_HEADER DeviceInstallListHead;
|
||||
extern HANDLE hDeviceInstallListNotEmpty;
|
||||
|
||||
BOOL
|
||||
SetupIsActive(VOID);
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
DeviceInstallThread(
|
||||
LPVOID lpParameter);
|
||||
|
||||
|
||||
/* rpcserver.c */
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
RpcServerThread(
|
||||
LPVOID lpParameter);
|
||||
|
||||
|
||||
/* umpnpmgr.c */
|
||||
|
||||
extern HKEY hEnumKey;
|
||||
extern HKEY hClassKey;
|
||||
|
||||
|
||||
#endif /* _UMPNPMGR_PCH_ */
|
3762
base/services/umpnpmgr/rpcserver.c
Normal file
3762
base/services/umpnpmgr/rpcserver.c
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue