562 lines
14 KiB
C
562 lines
14 KiB
C
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
service.c
|
|
|
|
Abstract: USB Test DLL
|
|
|
|
Author:
|
|
|
|
Chris Robinson
|
|
|
|
ynvironment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <cfgmgr32.h>
|
|
#include <usbioctl.h>
|
|
#include "usbtest.h"
|
|
#include "local.h"
|
|
|
|
#define WIN9X_NTKERN_NAME "\\\\.\\ntkern"
|
|
#define FULL_DRIVER_NAME_LENGTH 1024
|
|
|
|
//
|
|
// Structure used to interface between App and VxD for Win9x. This was
|
|
// pulled from dos\dos386\ntkern\vxd\dioc.h in the Win9x tree.
|
|
//
|
|
|
|
#define INTERFACE_BUF_SIZE 1024
|
|
|
|
#include <pshpack1.h>
|
|
|
|
typedef struct tag_DIOC_Interface
|
|
{
|
|
DWORD dwReturn;
|
|
DWORD dwEAX;
|
|
DWORD dwEBX;
|
|
DWORD dwECX;
|
|
DWORD dwEDX;
|
|
DWORD dwESI;
|
|
DWORD dwEDI;
|
|
DWORD dwCF;
|
|
WORD wDS;
|
|
WORD wBufSize;
|
|
char szBuf[INTERFACE_BUF_SIZE];
|
|
|
|
} DIOC_VXD_INTERFACE , *PDIOC_VXD_INTERFACE ;
|
|
|
|
#include <poppack.h>
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// OpenWin2kService
|
|
//
|
|
//*****************************************************************************
|
|
|
|
SC_HANDLE
|
|
OpenWin2kService(
|
|
IN PSTR ServiceName,
|
|
IN PSTR ServiceDescription,
|
|
IN PSTR DriverPath,
|
|
IN BOOL CreateIfNonExistant
|
|
)
|
|
{
|
|
SC_HANDLE scManagerHandle;
|
|
SC_HANDLE scServiceHandle;
|
|
DWORD errorCode;
|
|
|
|
//
|
|
// Initialize the variables for proper cleanup on exit
|
|
//
|
|
|
|
scServiceHandle = NULL;
|
|
|
|
//
|
|
// Try to get a handle to the service manager
|
|
//
|
|
|
|
scManagerHandle = OpenSCManager(NULL,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (NULL == scManagerHandle)
|
|
{
|
|
errorCode = GetLastError();
|
|
|
|
goto OpenWin2kService_Exit;
|
|
}
|
|
|
|
//
|
|
// Get a handle to the service itself. We want EXECUTE access so that
|
|
// it can be started.
|
|
//
|
|
|
|
scServiceHandle = OpenService(scManagerHandle,
|
|
ServiceName,
|
|
GENERIC_EXECUTE);
|
|
|
|
|
|
if (NULL == scServiceHandle)
|
|
{
|
|
errorCode = GetLastError();
|
|
|
|
if (ERROR_SERVICE_DOES_NOT_EXIST == errorCode && CreateIfNonExistant)
|
|
{
|
|
scServiceHandle = CreateWin2kService(scManagerHandle,
|
|
ServiceName,
|
|
ServiceDescription,
|
|
DriverPath);
|
|
}
|
|
}
|
|
|
|
CloseServiceHandle(scManagerHandle);
|
|
|
|
OpenWin2kService_Exit:
|
|
|
|
SetLastError(errorCode);
|
|
|
|
return (scServiceHandle);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// CreateWin2kService
|
|
//
|
|
//*****************************************************************************
|
|
|
|
SC_HANDLE
|
|
CreateWin2kService(
|
|
IN SC_HANDLE scManagerHandle,
|
|
IN PSTR ServiceName,
|
|
IN PSTR ServiceDescription,
|
|
IN PSTR DriverPath
|
|
)
|
|
{
|
|
SC_HANDLE scServiceHandle;
|
|
|
|
//
|
|
// Initialize the variables for proper cleanup on exit
|
|
//
|
|
|
|
scServiceHandle = NULL;
|
|
|
|
//
|
|
// Check the handle to the service manager
|
|
//
|
|
|
|
if (NULL == scManagerHandle)
|
|
{
|
|
goto CreateWin2kService_Exit;
|
|
}
|
|
|
|
//
|
|
// Create the service...In the process, this will return a handle that
|
|
// can be used just as if an OpenService() had been performed.
|
|
//
|
|
|
|
scServiceHandle = CreateService(scManagerHandle,
|
|
ServiceName,
|
|
ServiceDescription,
|
|
GENERIC_EXECUTE,
|
|
SERVICE_KERNEL_DRIVER,
|
|
SERVICE_DEMAND_START,
|
|
SERVICE_ERROR_IGNORE,
|
|
DriverPath,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
CreateWin2kService_Exit:
|
|
|
|
return (scServiceHandle);
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// IsWindows9x
|
|
//
|
|
//*****************************************************************************
|
|
|
|
BOOLEAN
|
|
IsWindows9x(
|
|
VOID
|
|
)
|
|
{
|
|
OSVERSIONINFO osVersion;
|
|
|
|
//
|
|
// Get the OS version information
|
|
//
|
|
|
|
osVersion.dwOSVersionInfoSize = sizeof(osVersion);
|
|
|
|
GetVersionEx(&osVersion);
|
|
|
|
//
|
|
// For the version to be Windows98 or later:
|
|
// 1) dwPlatformId = VER_PLATFORM_WIN32_WINDOWS
|
|
// 2) dwMajorVersion > 4
|
|
// or
|
|
// 3) dwMajorVersion = 4 and dwMinorVersion > 0
|
|
//
|
|
|
|
return (VER_PLATFORM_WIN32_WINDOWS == osVersion.dwPlatformId &&
|
|
((4 > osVersion.dwMajorVersion) ||
|
|
(4 == osVersion.dwMajorVersion) && (0 < osVersion.dwMinorVersion)));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// LoadWin9xWdmDriver
|
|
//
|
|
//*****************************************************************************
|
|
|
|
BOOLEAN
|
|
LoadWin9xWdmDriver(
|
|
IN PSTR DriverPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
LoadWin9xWdmDriver
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
BOOL bReturn = TRUE;
|
|
HANDLE vxdHandle = INVALID_HANDLE_VALUE;
|
|
DWORD nBytes = 0;
|
|
DIOC_VXD_INTERFACE vxdDataIn = {0};
|
|
DIOC_VXD_INTERFACE vxdDataOut = {0};
|
|
CHAR fullDriverName[FULL_DRIVER_NAME_LENGTH];
|
|
|
|
OutputDebugString("Entering LoadWin9xWdmDriver\n");
|
|
|
|
//
|
|
// Open a handle to NTKern.VxD
|
|
//
|
|
|
|
vxdHandle = CreateFile(WIN9X_NTKERN_NAME,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
|
|
NULL);
|
|
|
|
|
|
//
|
|
// create file failed
|
|
//
|
|
|
|
if (INVALID_HANDLE_VALUE == vxdHandle)
|
|
{
|
|
OutputDebugString("NTKERN vxd handle creation failed\n");
|
|
|
|
bReturn = FALSE;
|
|
goto LoadWin9xWdmDriver_Exit;
|
|
}
|
|
|
|
//
|
|
// NtKern expects two strings in "vxdDataIn.szBuf". The first string should be
|
|
// the full pathname of the driver (including .sys). If no path is given, NtKern
|
|
// will default to \windows\system32\drivers. The second string, which is optional,
|
|
// is the registry key. If a null is passed in, NtKern will use the default path.
|
|
// "vxdDataIn.dwEAX" should contain the offset the second string. Both strings
|
|
// should be null terminated.
|
|
//
|
|
|
|
//
|
|
// We will force the assumption that the driver being loaded is in
|
|
// \\SystemRoot\system32\drivers. Since on load, the full path will
|
|
// be stored in the object representing this driver. Therefore, we
|
|
// need to specify the whole path (ie. Windows directory +
|
|
// \system32\drivers\drivername). Hence, we will construct that path
|
|
// here.
|
|
//
|
|
|
|
GetWindowsDirectory(fullDriverName, FULL_DRIVER_NAME_LENGTH);
|
|
strcat(fullDriverName, "\\system32\\drivers\\");
|
|
strcat(fullDriverName, DriverPath);
|
|
|
|
//
|
|
// Prepare the parameters for the driver search
|
|
//
|
|
|
|
ZeroMemory(vxdDataIn.szBuf, sizeof(vxdDataIn.szBuf));
|
|
lstrcpy(vxdDataIn.szBuf, fullDriverName);
|
|
vxdDataIn.dwEAX = lstrlen(vxdDataIn.szBuf) + sizeof(char);
|
|
|
|
OutputDebugString("Looking for driver ");
|
|
OutputDebugString(vxdDataIn.szBuf);
|
|
OutputDebugString("\n");
|
|
|
|
//
|
|
// Call the find function to see if the driver is already loaded, if it is
|
|
// we don't need to proceed any further.
|
|
//
|
|
|
|
bReturn = DeviceIoControl(vxdHandle,
|
|
0x1003, // NTKERN_DIOC_FIND_DRIVER_A
|
|
&vxdDataIn, // input buffer
|
|
sizeof(DIOC_VXD_INTERFACE),// input size
|
|
&vxdDataOut, // output buffer
|
|
sizeof(DIOC_VXD_INTERFACE),// output size
|
|
&nBytes, // bytes returned.
|
|
NULL); // lpOverlapped
|
|
{
|
|
CHAR msg[512];
|
|
|
|
wsprintf(msg, "On find driver dwReturn is %08x\n", vxdDataOut.dwReturn);
|
|
|
|
OutputDebugString(msg);
|
|
}
|
|
|
|
if (bReturn)
|
|
{
|
|
//
|
|
// If a successful check then the driver is already loaded
|
|
//
|
|
|
|
if (NT_SUCCESS(vxdDataOut.dwReturn))
|
|
{
|
|
OutputDebugString("Driver ");
|
|
OutputDebugString(DriverPath);
|
|
OutputDebugString(" already loaded\n");
|
|
|
|
goto LoadWin9xWdmDriver_Exit;
|
|
}
|
|
|
|
//
|
|
// OK, the driver is not currently loaded, try to load it
|
|
//
|
|
|
|
ZeroMemory(vxdDataIn.szBuf, sizeof(vxdDataIn.szBuf));
|
|
lstrcpy(vxdDataIn.szBuf, DriverPath);
|
|
vxdDataIn.dwEAX = lstrlen(vxdDataIn.szBuf) + sizeof(char);
|
|
|
|
OutputDebugString("Attempting to load driver ");
|
|
OutputDebugString(vxdDataIn.szBuf);
|
|
OutputDebugString("\n");
|
|
|
|
bReturn = DeviceIoControl(vxdHandle,
|
|
0x1000, // NTKERN_DIOC_LOAD_DRIVER_A
|
|
&vxdDataIn, // input buffer
|
|
sizeof(DIOC_VXD_INTERFACE),// input size
|
|
&vxdDataOut, // output buffer
|
|
sizeof(DIOC_VXD_INTERFACE),// output size
|
|
&nBytes, // bytes returned.
|
|
NULL); // lpOverlapped
|
|
|
|
if (bReturn)
|
|
{
|
|
if (!NT_SUCCESS(vxdDataOut.dwReturn))
|
|
{
|
|
if (STATUS_OBJECT_NAME_COLLISION != vxdDataOut.dwReturn)
|
|
{
|
|
CHAR err[512];
|
|
|
|
wsprintf(err, "Error loading %s with error %08x\n",
|
|
DriverPath,
|
|
vxdDataOut.dwReturn);
|
|
|
|
OutputDebugString(err);
|
|
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LoadWin9xWdmDriver_Exit:
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// UnloadWin9xWdmDriver
|
|
//
|
|
//*****************************************************************************
|
|
|
|
BOOLEAN
|
|
UnloadWin9xWdmDriver(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
UnloadWin9xWdmDriver()
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Currently, this feature is not available on the Win9x platform
|
|
// so just return false
|
|
//
|
|
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// LoadWin2kWdmDriver
|
|
//
|
|
//*****************************************************************************
|
|
|
|
BOOLEAN
|
|
LoadWin2kWdmDriver(
|
|
IN PSTR ServiceName,
|
|
IN PSTR ServiceDescription,
|
|
IN PSTR DriverPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
LoadWin2kWdmDriver()
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
SC_HANDLE scServiceHandle;
|
|
BOOL success;
|
|
|
|
//
|
|
// Get a handle to the service itself. We want EXECUTE access so that
|
|
// it can be started.
|
|
//
|
|
|
|
scServiceHandle = OpenWin2kService(ServiceName,
|
|
ServiceDescription,
|
|
DriverPath,
|
|
TRUE);
|
|
|
|
//
|
|
// If error, we cannot go any further
|
|
//
|
|
|
|
if (NULL == scServiceHandle)
|
|
{
|
|
success = FALSE;
|
|
|
|
goto LoadWin2kWdmDriver_Exit;
|
|
}
|
|
|
|
//
|
|
// Try to start the service
|
|
//
|
|
|
|
success = StartService(scServiceHandle, 0, NULL);
|
|
|
|
//
|
|
// If the service sucessfully start, open the file so that we can
|
|
// perform the tests that rely on that handle.
|
|
//
|
|
|
|
if (!success && ERROR_SERVICE_ALREADY_RUNNING == GetLastError())
|
|
{
|
|
success = TRUE;
|
|
}
|
|
|
|
LoadWin2kWdmDriver_Exit:
|
|
|
|
return (success);
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// UnloadWin2kWdmDriver
|
|
//
|
|
//*****************************************************************************
|
|
|
|
BOOLEAN
|
|
UnloadWin2kWdmDriver(
|
|
IN PSTR ServiceName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
UnloadWin2kWdmDriver()
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
SC_HANDLE scServiceHandle;
|
|
BOOL success;
|
|
SERVICE_STATUS serviceStatus;
|
|
|
|
//
|
|
// Initialize the variables for proper cleanup on exit
|
|
//
|
|
|
|
success = FALSE;
|
|
|
|
//
|
|
// Get a handle to the service itself. We want EXECUTE access so that
|
|
// it can be started.
|
|
//
|
|
|
|
scServiceHandle = OpenWin2kService(USBTEST_SERVICE_NAME,
|
|
NULL,
|
|
NULL,
|
|
FALSE);
|
|
|
|
//
|
|
// If the service was opened, try to stop the service
|
|
// If not, just return unsuccessful status (FALSE)
|
|
//
|
|
|
|
if (NULL != scServiceHandle)
|
|
{
|
|
//
|
|
// Try to stop the service
|
|
//
|
|
|
|
success = ControlService(scServiceHandle,
|
|
SERVICE_CONTROL_STOP,
|
|
&serviceStatus);
|
|
|
|
CloseServiceHandle(scServiceHandle);
|
|
}
|
|
|
|
return (success);
|
|
}
|