415 lines
14 KiB
C
415 lines
14 KiB
C
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#define BUFFERSIZE 1024
|
||
|
|
||
|
typedef struct _DEVICEINFO {
|
||
|
BOOL DevNodeStarted;
|
||
|
} DEVICEINFO, *PDEVICEINFO;
|
||
|
|
||
|
BOOL
|
||
|
IsDriverLoaded(
|
||
|
PTSTR ServiceName
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
BOOL bObjectIsLoaded = FALSE;
|
||
|
UCHAR Buffer[BUFFERSIZE];
|
||
|
UNICODE_STRING UnicodeStringDriver, UnicodeStringServiceName;
|
||
|
OBJECT_ATTRIBUTES Attributes;
|
||
|
HANDLE DirectoryHandle;
|
||
|
POBJECT_DIRECTORY_INFORMATION DirInfo;
|
||
|
POBJECT_NAME_INFORMATION NameInfo;
|
||
|
ULONG Context = 0;
|
||
|
ULONG ReturnedLength;
|
||
|
|
||
|
RtlZeroMemory(Buffer, BUFFERSIZE);
|
||
|
|
||
|
RtlInitUnicodeString(&UnicodeStringServiceName, ServiceName);
|
||
|
RtlInitUnicodeString(&UnicodeStringDriver, TEXT("\\Driver"));
|
||
|
|
||
|
InitializeObjectAttributes(&Attributes,
|
||
|
&UnicodeStringDriver,
|
||
|
OBJ_CASE_INSENSITIVE,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
Status = NtOpenDirectoryObject(&DirectoryHandle,
|
||
|
DIRECTORY_QUERY,
|
||
|
&Attributes
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
printf("NtOpenDirectoryObject failed with 0x%X\n", Status);
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the actual name of the object directory object.
|
||
|
//
|
||
|
NameInfo = (POBJECT_NAME_INFORMATION)&Buffer[0];
|
||
|
if (!NT_SUCCESS(Status = NtQueryObject(DirectoryHandle,
|
||
|
ObjectNameInformation,
|
||
|
NameInfo,
|
||
|
BUFFERSIZE,
|
||
|
(PULONG)NULL))) {
|
||
|
printf( "Unexpected error obtaining actual object directory name\n" );
|
||
|
printf( "Error was: %X\n", Status );
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Grab the driver objects in chuncks instead of one at a time.
|
||
|
//
|
||
|
for (Status = NtQueryDirectoryObject(DirectoryHandle,
|
||
|
&Buffer,
|
||
|
BUFFERSIZE,
|
||
|
FALSE,
|
||
|
FALSE,
|
||
|
&Context,
|
||
|
&ReturnedLength
|
||
|
);
|
||
|
NT_SUCCESS(Status) && !bObjectIsLoaded;
|
||
|
Status = NtQueryDirectoryObject(DirectoryHandle,
|
||
|
&Buffer,
|
||
|
BUFFERSIZE,
|
||
|
FALSE,
|
||
|
FALSE,
|
||
|
&Context,
|
||
|
&ReturnedLength
|
||
|
)) {
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
if (Status != STATUS_NO_MORE_FILES) {
|
||
|
printf("NtQueryDirectoryObject failed with 0x%X\n", Status);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DirInfo = (POBJECT_DIRECTORY_INFORMATION)&Buffer[0];
|
||
|
|
||
|
while (TRUE) {
|
||
|
//
|
||
|
// Check if there is another record. If there isn't, then get out
|
||
|
// of the loop now.
|
||
|
//
|
||
|
if (DirInfo->Name.Length == 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (RtlCompareUnicodeString(&UnicodeStringServiceName, &(DirInfo->Name), TRUE) == 0) {
|
||
|
bObjectIsLoaded = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DirInfo = (POBJECT_DIRECTORY_INFORMATION)(((PUCHAR)DirInfo) +
|
||
|
sizeof(OBJECT_DIRECTORY_INFORMATION));
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory(Buffer, BUFFERSIZE);
|
||
|
}
|
||
|
|
||
|
clean0:
|
||
|
NtClose(DirectoryHandle);
|
||
|
|
||
|
return bObjectIsLoaded;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
RestartDevicesUsingService(
|
||
|
LPTSTR ServiceName
|
||
|
)
|
||
|
{
|
||
|
BOOL b = TRUE;
|
||
|
CONFIGRET cr;
|
||
|
DEVNODE DevNode;
|
||
|
BOOL bIsDriverLoaded;
|
||
|
INT count, i;
|
||
|
TCHAR VetoName[512];
|
||
|
ULONG VetoNameLength;
|
||
|
PNP_VETO_TYPE VetoType;
|
||
|
ULONG Status, Problem;
|
||
|
ULONG BufferLen;
|
||
|
OSVERSIONINFO osvi;
|
||
|
PTSTR Buffer = NULL;
|
||
|
PTSTR p;
|
||
|
PDEVICEINFO DeviceInfo = NULL;
|
||
|
|
||
|
printf("Stopping all devices that are using the service %ws\n", ServiceName);
|
||
|
|
||
|
try {
|
||
|
bIsDriverLoaded = IsDriverLoaded(ServiceName);
|
||
|
|
||
|
printf("%ws %ws loaded\n",
|
||
|
ServiceName,
|
||
|
bIsDriverLoaded
|
||
|
? TEXT("is")
|
||
|
: TEXT("is NOT")
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// If this service is not loaded then we don't need to do anything.
|
||
|
//
|
||
|
if (!bIsDriverLoaded) {
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find out how large a buffer it will take to hold all the devices that
|
||
|
// are using this service.
|
||
|
//
|
||
|
if (((cr = CM_Get_Device_ID_List_Size(&BufferLen,
|
||
|
ServiceName,
|
||
|
CM_GETIDLIST_FILTER_SERVICE
|
||
|
)) != CR_SUCCESS) ||
|
||
|
(BufferLen == 0)) {
|
||
|
if (cr != CR_SUCCESS) {
|
||
|
b = FALSE;
|
||
|
printf("CM_Get_Device_ID_List_Size failed with 0x%X\n", cr);
|
||
|
} else {
|
||
|
printf("There are no devices using this service!\n");
|
||
|
}
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
Buffer = LocalAlloc(LPTR, BufferLen*sizeof(TCHAR));
|
||
|
|
||
|
if (Buffer == NULL) {
|
||
|
b = FALSE;
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get all of the devices that are using this service.
|
||
|
//
|
||
|
if (CM_Get_Device_ID_List(ServiceName,
|
||
|
Buffer,
|
||
|
BufferLen,
|
||
|
CM_GETIDLIST_FILTER_SERVICE | CM_GETIDLIST_DONOTGENERATE
|
||
|
) != CR_SUCCESS) {
|
||
|
b = FALSE;
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Count up how many devices we are dealing with.
|
||
|
//
|
||
|
count = 0;
|
||
|
for (p = Buffer; *p; p += (lstrlen(p) + 1)) {
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
if (count == 0) {
|
||
|
printf("There are no devices using this service!\n");
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
printf("%d devices are using this service\n", count);
|
||
|
|
||
|
//
|
||
|
// Allocate an array of our DEVICEINFO structures so we can keep
|
||
|
// track of the Devnodes and whether a device was started or not
|
||
|
// before we tried to unloade the specified driver.
|
||
|
//
|
||
|
DeviceInfo = LocalAlloc(LPTR, count*sizeof(DEVICEINFO));
|
||
|
|
||
|
if (DeviceInfo == NULL) {
|
||
|
b = FALSE;
|
||
|
goto clean0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Enumerate through all of the devices and stop each one.
|
||
|
//
|
||
|
for (p=Buffer, i=0; *p; p+=(lstrlen(p) + 1),i++) {
|
||
|
printf("Stopping device %ws\n", p);
|
||
|
|
||
|
if ((cr = CM_Locate_DevNode(&DevNode, p, 0)) == CR_SUCCESS) {
|
||
|
if ((CM_Get_DevNode_Status(&Status, &Problem, DevNode, 0) == CR_SUCCESS) &&
|
||
|
(Status & DN_STARTED)) {
|
||
|
DeviceInfo[i].DevNodeStarted = TRUE;
|
||
|
} else {
|
||
|
printf("\tdevice is not started...skipping\n");
|
||
|
DeviceInfo[i].DevNodeStarted = FALSE;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We will pass in the VetoType and VetoName to
|
||
|
// CM_Query_And_Remove_Subtree so we can log while a specific
|
||
|
// device could not be stopped. This will also prevent the
|
||
|
// kernel from poping up a dialog telling the user that the
|
||
|
// device could not be removed.
|
||
|
//
|
||
|
// NOTE: It is important to note that on Whistler we pass in the
|
||
|
// CM_REMOVE_NO_RESTART flag. This ensures that the devnode
|
||
|
// will not be restarted until we call CM_Setup_DevNode to
|
||
|
// restart it at a later time. Without this flag (like in
|
||
|
// Windows 2000) it is possible for the device to restart again
|
||
|
// due to some other program or driver triggering a
|
||
|
// reenumeration.
|
||
|
//
|
||
|
VetoNameLength = sizeof(VetoName)/sizeof(TCHAR);
|
||
|
cr = CM_Query_And_Remove_SubTree(DevNode,
|
||
|
&VetoType,
|
||
|
VetoName,
|
||
|
VetoNameLength,
|
||
|
CM_QUERY_REMOVE_UI_NOT_OK |
|
||
|
CM_REMOVE_NO_RESTART
|
||
|
);
|
||
|
|
||
|
if (cr == CR_REMOVE_VETOED) {
|
||
|
//
|
||
|
// Someone vetoed the removal of this device!
|
||
|
//
|
||
|
// This is here for logging purposes only. If no logging is
|
||
|
// required then there is no need for this check.
|
||
|
//
|
||
|
printf("\tVetoed 0x%X %ws\n", VetoType, VetoName);
|
||
|
}
|
||
|
|
||
|
if (cr != CR_SUCCESS) {
|
||
|
//
|
||
|
// If we couldn't stop one of the devices then we might as well
|
||
|
// stop since we are going to need a reboot.
|
||
|
//
|
||
|
printf("\tFailed with 0x%X!\n", cr);
|
||
|
b = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// If we couldn't locate one of the devices then there is no need to
|
||
|
// continue through the list since a reboot will be needed.
|
||
|
//
|
||
|
printf("\tCouldn't locate the devnode, error 0x%X!\n", cr);
|
||
|
b = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
printf("\n");
|
||
|
|
||
|
if (b) {
|
||
|
bIsDriverLoaded = IsDriverLoaded(ServiceName);
|
||
|
|
||
|
printf("%ws %ws loaded\n\n",
|
||
|
ServiceName,
|
||
|
bIsDriverLoaded
|
||
|
? TEXT("is")
|
||
|
: TEXT("is NOT")
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// If the driver did not unload, even after we stopped all the
|
||
|
// devices using it, the we need to reboot!
|
||
|
//
|
||
|
if (bIsDriverLoaded) {
|
||
|
b = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// At this point we need to enumerate through all the devices once again
|
||
|
// and restart them all. It doesn't matter whether we succeeded or not in
|
||
|
// stopping them all, we still need to restart them.
|
||
|
//
|
||
|
for (p=Buffer, i=0; *p; p+=(lstrlen(p) + 1), i++) {
|
||
|
printf("Starting device %ws\n", p);
|
||
|
|
||
|
if ((cr = CM_Locate_DevNode(&DevNode, p, 0)) == CR_SUCCESS) {
|
||
|
//
|
||
|
// NOTE: For Whistler we will call CM_Setup_DevNode with the
|
||
|
// CM_SETUP_DEVNODE_RESET flag which will clear the
|
||
|
// CM_REMOVE_NO_RESTART flag we set earlier. These two flags
|
||
|
// ensure that the devnode will not get restarted by some other
|
||
|
// program or driver until we want them to.
|
||
|
//
|
||
|
if ((cr = CM_Setup_DevNode(DevNode, CM_SETUP_DEVNODE_READY)) == CR_SUCCESS) {
|
||
|
//
|
||
|
// We successfully restarted the device, lets make sure that it
|
||
|
// started and doesn't have any problems. We will only make
|
||
|
// this check if the device was started before.
|
||
|
//
|
||
|
if (DeviceInfo[i].DevNodeStarted == TRUE) {
|
||
|
if ((CM_Get_DevNode_Status(&Status, &Problem, DevNode, 0) != CR_SUCCESS) ||
|
||
|
!(Status & DN_STARTED)) {
|
||
|
//
|
||
|
// We couldn't get the status of this device, or it did not
|
||
|
// restart properly, so we will need to reboot.
|
||
|
//
|
||
|
printf("\tDevice could not be restarted!\n");
|
||
|
b = FALSE;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// We couldn't restart this device, so we will need to reboot.
|
||
|
//
|
||
|
printf("\tDevice could not be restarted, error 0x%X!\n", cr);
|
||
|
b = FALSE;
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// We couldn't locate the devnode to restart it.
|
||
|
//
|
||
|
printf("\tCouldn't locate the devnode, error 0x%X!\n", cr);
|
||
|
b = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
printf("%ws %ws loaded\n",
|
||
|
ServiceName,
|
||
|
IsDriverLoaded(ServiceName)
|
||
|
? TEXT("is")
|
||
|
: TEXT("is NOT")
|
||
|
);
|
||
|
|
||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
Buffer = Buffer;
|
||
|
DeviceInfo = DeviceInfo;
|
||
|
b = FALSE;
|
||
|
}
|
||
|
|
||
|
clean0:
|
||
|
|
||
|
if (Buffer) {
|
||
|
LocalFree(Buffer);
|
||
|
}
|
||
|
|
||
|
if (DeviceInfo) {
|
||
|
LocalFree(DeviceInfo);
|
||
|
}
|
||
|
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
wmain(
|
||
|
IN int argc,
|
||
|
IN char *argv[]
|
||
|
)
|
||
|
{
|
||
|
BOOL bDriverUnloaded;
|
||
|
|
||
|
if (argc != 2) {
|
||
|
printf("Usage: StopDevs X\n");
|
||
|
printf("\twhere X is the name of the service.\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bDriverUnloaded = RestartDevicesUsingService((LPTSTR)argv[1]);
|
||
|
|
||
|
if (bDriverUnloaded) {
|
||
|
printf("\n\nThe driver unloaded, no need to reboot!\n\n");
|
||
|
return 1;
|
||
|
} else {
|
||
|
printf("\n\nThe driver did NOT unload, a reboot is required!\n\n");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|