From 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Tue, 17 Mar 2015 19:50:07 -0700 Subject: Initial publish --- setup/devcon/cmds.cpp | 2408 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2408 insertions(+) create mode 100644 setup/devcon/cmds.cpp (limited to 'setup/devcon/cmds.cpp') diff --git a/setup/devcon/cmds.cpp b/setup/devcon/cmds.cpp new file mode 100644 index 00000000..590decdd --- /dev/null +++ b/setup/devcon/cmds.cpp @@ -0,0 +1,2408 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + devcon.cpp + +Abstract: + + Device Console + command-line interface for managing devices + +--*/ + +#include "devcon.h" + +struct GenericContext { + DWORD count; + DWORD control; + BOOL reboot; + LPCTSTR strSuccess; + LPCTSTR strReboot; + LPCTSTR strFail; +}; + +#define FIND_DEVICE 0x00000001 // display device +#define FIND_STATUS 0x00000002 // display status of device +#define FIND_RESOURCES 0x00000004 // display resources of device +#define FIND_DRIVERFILES 0x00000008 // display drivers used by device +#define FIND_HWIDS 0x00000010 // display hw/compat id's used by device +#define FIND_DRIVERNODES 0x00000020 // display driver nodes for a device. +#define FIND_CLASS 0x00000040 // display device's setup class +#define FIND_STACK 0x00000080 // display device's driver-stack + +struct SetHwidContext { + int argc_right; + LPTSTR * argv_right; + DWORD prop; + int skipped; + int modified; +}; + +int cmdHelp(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + HELP command + allow HELP or HELP + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine (ignored) + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + DWORD helptext = 0; + int dispIndex; + LPCTSTR cmd = NULL; + BOOL unknown = FALSE; + + UNREFERENCED_PARAMETER(Machine); + UNREFERENCED_PARAMETER(Flags); + + if(argc) { + // + // user passed in a command for help on... long help + // + for(dispIndex = 0;DispatchTable[dispIndex].cmd;dispIndex++) { + if(_tcsicmp(argv[0],DispatchTable[dispIndex].cmd)==0) { + cmd = DispatchTable[dispIndex].cmd; + helptext = DispatchTable[dispIndex].longHelp; + break; + } + } + if(!cmd) { + unknown = TRUE; + cmd = argv[0]; + } + } + + if(helptext) { + // + // long help + // + FormatToStream(stdout,helptext,BaseName,cmd); + } else { + // + // help help + // + FormatToStream(stdout,unknown ? MSG_HELP_OTHER : MSG_HELP_LONG,BaseName,cmd); + // + // enumerate through each command and display short help for each + // + for(dispIndex = 0;DispatchTable[dispIndex].cmd;dispIndex++) { + if(DispatchTable[dispIndex].shortHelp) { + FormatToStream(stdout,DispatchTable[dispIndex].shortHelp,DispatchTable[dispIndex].cmd); + fputs("\n",stdout); + } + } + } + return EXIT_OK; +} + +int cmdClasses(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + CLASSES command + lists classes on (optionally) specified machine + format as : + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - ignored + +Return Value: + + EXIT_xxxx + +--*/ +{ + DWORD reqGuids = 128; + DWORD numGuids; + LPGUID guids = NULL; + DWORD index; + int failcode = EXIT_FAIL; + + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + guids = new GUID[reqGuids]; + if(!guids) { + goto final; + } + if(!SetupDiBuildClassInfoListEx(0,guids,reqGuids,&numGuids,Machine,NULL)) { + do { + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + goto final; + } + delete [] guids; + reqGuids = numGuids; + guids = new GUID[reqGuids]; + if(!guids) { + goto final; + } + } while(!SetupDiBuildClassInfoListEx(0,guids,reqGuids,&numGuids,Machine,NULL)); + } + FormatToStream(stdout,Machine?MSG_CLASSES_HEADER:MSG_CLASSES_HEADER_LOCAL,numGuids,Machine); + for(index=0;index.... + lists all devices for each specified class + there can be more than one physical class for a class name (shouldn't be + though) in such cases, list each class + if machine given, list devices for that machine + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - list of class names + +Return Value: + + EXIT_xxxx + +--*/ +{ + DWORD reqGuids = 16; + int argIndex; + int failcode = EXIT_FAIL; + LPGUID guids = NULL; + HDEVINFO devs = INVALID_HANDLE_VALUE; + + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + + guids = new GUID[reqGuids]; + if(!guids) { + goto final; + } + + for(argIndex = 0;argIndexcontrol) { + DumpDevice(Devs,DevInfo); + pFindContext->count++; + return EXIT_OK; + } + if(!DumpDeviceWithInfo(Devs,DevInfo,NULL)) { + return EXIT_OK; + } + if(pFindContext->control&FIND_DEVICE) { + DumpDeviceDescr(Devs,DevInfo); + } + if(pFindContext->control&FIND_CLASS) { + DumpDeviceClass(Devs,DevInfo); + } + if(pFindContext->control&FIND_STATUS) { + DumpDeviceStatus(Devs,DevInfo); + } + if(pFindContext->control&FIND_RESOURCES) { + DumpDeviceResources(Devs,DevInfo); + } + if(pFindContext->control&FIND_DRIVERFILES) { + DumpDeviceDriverFiles(Devs,DevInfo); + } + if(pFindContext->control&FIND_STACK) { + DumpDeviceStack(Devs,DevInfo); + } + if(pFindContext->control&FIND_HWIDS) { + DumpDeviceHwIds(Devs,DevInfo); + } + if (pFindContext->control&FIND_DRIVERNODES) { + DumpDeviceDriverNodes(Devs,DevInfo); + } + pFindContext->count++; + return EXIT_OK; +} + +int cmdFind(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + FIND ... + use EnumerateDevices to do hardwareID matching + for each match, dump to stdout + note that we only enumerate present devices + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + int failcode; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + + context.count = 0; + context.control = 0; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,FindCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine); + } else { + FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine); + } + } + return failcode; +} + +int cmdFindAll(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + FINDALL ... + use EnumerateDevices to do hardwareID matching + for each match, dump to stdout + like find, but also show not-present devices + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + int failcode; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + + context.count = 0; + context.control = 0; + failcode = EnumerateDevices(BaseName,Machine,0,argc,argv,FindCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine); + } else { + FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine); + } + } + return failcode; +} + +int cmdStatus(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + STATUS ... + use EnumerateDevices to do hardwareID matching + for each match, dump status to stdout + note that we only enumerate present devices + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + int failcode; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + + context.count = 0; + context.control = FIND_DEVICE | FIND_STATUS; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,FindCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine); + } else { + FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine); + } + } + return failcode; +} + + +int cmdResources(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + RESOURCES ... + use EnumerateDevices to do hardwareID matching + for each match, dump resources to stdout + note that we only enumerate present devices + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + int failcode; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + + context.count = 0; + context.control = FIND_DEVICE | FIND_RESOURCES; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,FindCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine); + } else { + FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine); + } + } + return failcode; +} + + +int cmdDriverFiles(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + STATUS ... + use EnumerateDevices to do hardwareID matching + for each match, dump driver files to stdout + note that we only enumerate present devices + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + int failcode; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + if(Machine) { + // + // must be local machine as we need to involve class/co installers (FIND_DRIVERFILES) + // + return EXIT_USAGE; + } + + context.count = 0; + context.control = FIND_DEVICE | FIND_DRIVERFILES; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,FindCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine); + } else { + FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine); + } + } + return failcode; +} + +int cmdDriverNodes(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + STATUS ... + use EnumerateDevices to do hardwareID matching + for each match, dump drivernodes to stdout + note that we only enumerate present devices + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + int failcode; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + if(Machine) { + // + // must be local machine as we need to involve class/co installers (FIND_DRIVERNODES) + // + return EXIT_USAGE; + } + + context.count = 0; + context.control = FIND_DEVICE | FIND_DRIVERNODES; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,FindCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine); + } else { + FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine); + } + } + return failcode; +} + +int cmdHwIds(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + HWIDS ... + use EnumerateDevices to do hardwareID matching + for each match, dump hw/compat id's to stdout + note that we only enumerate present devices + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + int failcode; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + + context.count = 0; + context.control = FIND_DEVICE | FIND_HWIDS; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,FindCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine); + } else { + FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine); + } + } + return failcode; +} + +int cmdStack(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + STACK ... + use EnumerateDevices to do hardwareID matching + for each match, dump device class and stack to stdout + note that we only enumerate present devices + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + int failcode; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + + context.count = 0; + context.control = FIND_DEVICE | FIND_CLASS | FIND_STACK; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,FindCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,Machine?MSG_FIND_TAIL_NONE:MSG_FIND_TAIL_NONE_LOCAL,Machine); + } else { + FormatToStream(stdout,Machine?MSG_FIND_TAIL:MSG_FIND_TAIL_LOCAL,context.count,Machine); + } + } + return failcode; +} + + + + +int ControlCallback(_In_ HDEVINFO Devs, _In_ PSP_DEVINFO_DATA DevInfo, _In_ DWORD Index, _In_ LPVOID Context) +/*++ + +Routine Description: + + Callback for use by Enable/Disable/Restart + Invokes DIF_PROPERTYCHANGE with correct parameters + uses SetupDiCallClassInstaller so cannot be done for remote devices + Don't use CM_xxx API's, they bypass class/co-installers and this is bad. + + In Enable case, we try global first, and if still disabled, enable local + +Arguments: + + Devs )_ uniquely identify the device + DevInfo ) + Index - index of device + Context - GenericContext + +Return Value: + + EXIT_xxxx + +--*/ +{ + SP_PROPCHANGE_PARAMS pcp; + GenericContext *pControlContext = (GenericContext*)Context; + SP_DEVINSTALL_PARAMS devParams; + + UNREFERENCED_PARAMETER(Index); + + switch(pControlContext->control) { + case DICS_ENABLE: + // + // enable both on global and config-specific profile + // do global first and see if that succeeded in enabling the device + // (global enable doesn't mark reboot required if device is still + // disabled on current config whereas vice-versa isn't true) + // + pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + pcp.StateChange = pControlContext->control; + pcp.Scope = DICS_FLAG_GLOBAL; + pcp.HwProfile = 0; + // + // don't worry if this fails, we'll get an error when we try config- + // specific. + if(SetupDiSetClassInstallParams(Devs,DevInfo,&pcp.ClassInstallHeader,sizeof(pcp))) { + SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,Devs,DevInfo); + } + // + // now enable on config-specific + // + pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + pcp.StateChange = pControlContext->control; + pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; + pcp.HwProfile = 0; + break; + + default: + // + // operate on config-specific profile + // + pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + pcp.StateChange = pControlContext->control; + pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; + pcp.HwProfile = 0; + break; + + } + + if(!SetupDiSetClassInstallParams(Devs,DevInfo,&pcp.ClassInstallHeader,sizeof(pcp)) || + !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,Devs,DevInfo)) { + // + // failed to invoke DIF_PROPERTYCHANGE + // + DumpDeviceWithInfo(Devs,DevInfo,pControlContext->strFail); + } else { + // + // see if device needs reboot + // + devParams.cbSize = sizeof(devParams); + if(SetupDiGetDeviceInstallParams(Devs,DevInfo,&devParams) && (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT))) { + DumpDeviceWithInfo(Devs,DevInfo,pControlContext->strReboot); + pControlContext->reboot = TRUE; + } else { + // + // appears to have succeeded + // + DumpDeviceWithInfo(Devs,DevInfo,pControlContext->strSuccess); + } + pControlContext->count++; + } + return EXIT_OK; +} + +int cmdEnable(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + ENABLE ... + use EnumerateDevices to do hardwareID matching + for each match, attempt to enable global, and if needed, config specific + +Arguments: + + BaseName - name of executable + Machine - must be NULL (local machine only) + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx (EXIT_REBOOT if reboot is required) + +--*/ +{ + GenericContext context; + TCHAR strEnable[80]; + TCHAR strReboot[80]; + TCHAR strFail[80]; + int failcode = EXIT_FAIL; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + // + // arguments required + // + return EXIT_USAGE; + } + if(Machine) { + // + // must be local machine as we need to involve class/co installers + // + return EXIT_USAGE; + } + if(!LoadString(NULL,IDS_ENABLED,strEnable,ARRAYSIZE(strEnable))) { + return EXIT_FAIL; + } + if(!LoadString(NULL,IDS_ENABLED_REBOOT,strReboot,ARRAYSIZE(strReboot))) { + return EXIT_FAIL; + } + if(!LoadString(NULL,IDS_ENABLE_FAILED,strFail,ARRAYSIZE(strFail))) { + return EXIT_FAIL; + } + + context.control = DICS_ENABLE; // DICS_PROPCHANGE DICS_ENABLE DICS_DISABLE + context.reboot = FALSE; + context.count = 0; + context.strReboot = strReboot; + context.strSuccess = strEnable; + context.strFail = strFail; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,ControlCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,MSG_FIND_TAIL_NONE_LOCAL); + } else if(!context.reboot) { + FormatToStream(stdout,MSG_ENABLE_TAIL,context.count); + } else { + FormatToStream(stdout,MSG_ENABLE_TAIL_REBOOT,context.count); + failcode = EXIT_REBOOT; + } + } + return failcode; +} + +int cmdDisable(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + DISABLE ... + use EnumerateDevices to do hardwareID matching + for each match, attempt to disable global + +Arguments: + + BaseName - name of executable + Machine - must be NULL (local machine only) + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx (EXIT_REBOOT if reboot is required) + +--*/ +{ + GenericContext context; + TCHAR strDisable[80]; + TCHAR strReboot[80]; + TCHAR strFail[80]; + int failcode = EXIT_FAIL; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + // + // arguments required + // + return EXIT_USAGE; + } + if(Machine) { + // + // must be local machine as we need to involve class/co installers + // + return EXIT_USAGE; + } + if(!LoadString(NULL,IDS_DISABLED,strDisable,ARRAYSIZE(strDisable))) { + return EXIT_FAIL; + } + if(!LoadString(NULL,IDS_DISABLED_REBOOT,strReboot,ARRAYSIZE(strReboot))) { + return EXIT_FAIL; + } + if(!LoadString(NULL,IDS_DISABLE_FAILED,strFail,ARRAYSIZE(strFail))) { + return EXIT_FAIL; + } + + context.control = DICS_DISABLE; // DICS_PROPCHANGE DICS_ENABLE DICS_DISABLE + context.reboot = FALSE; + context.count = 0; + context.strReboot = strReboot; + context.strSuccess = strDisable; + context.strFail = strFail; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,ControlCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,MSG_FIND_TAIL_NONE_LOCAL); + } else if(!context.reboot) { + FormatToStream(stdout,MSG_DISABLE_TAIL,context.count); + } else { + FormatToStream(stdout,MSG_DISABLE_TAIL_REBOOT,context.count); + failcode = EXIT_REBOOT; + } + } + return failcode; +} + +int cmdRestart(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + RESTART ... + use EnumerateDevices to do hardwareID matching + for each match, attempt to restart by issueing a PROPCHANGE + +Arguments: + + BaseName - name of executable + Machine - must be NULL (local machine only) + argc/argv - remaining parameters - passed into EnumerateDevices + +Return Value: + + EXIT_xxxx (EXIT_REBOOT if reboot is required) + +--*/ +{ + GenericContext context; + TCHAR strRestarted[80]; + TCHAR strReboot[80]; + TCHAR strFail[80]; + int failcode = EXIT_FAIL; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + // + // arguments required + // + return EXIT_USAGE; + } + if(Machine) { + // + // must be local machine as we need to involve class/co installers + // + return EXIT_USAGE; + } + if(!LoadString(NULL,IDS_RESTARTED,strRestarted,ARRAYSIZE(strRestarted))) { + return EXIT_FAIL; + } + if(!LoadString(NULL,IDS_REQUIRES_REBOOT,strReboot,ARRAYSIZE(strReboot))) { + return EXIT_FAIL; + } + if(!LoadString(NULL,IDS_RESTART_FAILED,strFail,ARRAYSIZE(strFail))) { + return EXIT_FAIL; + } + + context.control = DICS_PROPCHANGE; + context.reboot = FALSE; + context.count = 0; + context.strReboot = strReboot; + context.strSuccess = strRestarted; + context.strFail = strFail; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,ControlCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,MSG_FIND_TAIL_NONE_LOCAL); + } else if(!context.reboot) { + FormatToStream(stdout,MSG_RESTART_TAIL,context.count); + } else { + FormatToStream(stdout,MSG_RESTART_TAIL_REBOOT,context.count); + failcode = EXIT_REBOOT; + } + } + return failcode; +} + +int cmdReboot(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + REBOOT + reboot local machine + +Arguments: + + BaseName - name of executable + Machine - must be NULL (local machine only) + argc/argv - remaining parameters - ignored + +Return Value: + + EXIT_xxxx + +--*/ +{ + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + if(Machine) { + // + // must be local machine + // + return EXIT_USAGE; + } + FormatToStream(stdout,MSG_REBOOT); + return Reboot() ? EXIT_OK : EXIT_FAIL; +} + + +int cmdUpdate(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + UPDATE + update driver for existing device(s) + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + HMODULE newdevMod = NULL; + int failcode = EXIT_FAIL; + UpdateDriverForPlugAndPlayDevicesProto UpdateFn; + BOOL reboot = FALSE; + LPCTSTR hwid = NULL; + LPCTSTR inf = NULL; + DWORD flags = 0; + DWORD res; + TCHAR InfPath[MAX_PATH]; + + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Flags); + + if(Machine) { + // + // must be local machine + // + return EXIT_USAGE; + } + if(argc<2) { + // + // at least HWID required + // + return EXIT_USAGE; + } + inf = argv[0]; + if(!inf[0]) { + return EXIT_USAGE; + } + + hwid = argv[1]; + if(!hwid[0]) { + return EXIT_USAGE; + } + // + // Inf must be a full pathname + // + res = GetFullPathName(inf,MAX_PATH,InfPath,NULL); + if((res >= MAX_PATH) || (res == 0)) { + // + // inf pathname too long + // + return EXIT_FAIL; + } + if(GetFileAttributes(InfPath)==(DWORD)(-1)) { + // + // inf doesn't exist + // + return EXIT_FAIL; + } + inf = InfPath; + flags |= INSTALLFLAG_FORCE; + + // + // make use of UpdateDriverForPlugAndPlayDevices + // + newdevMod = LoadLibrary(TEXT("newdev.dll")); + if(!newdevMod) { + goto final; + } + UpdateFn = (UpdateDriverForPlugAndPlayDevicesProto)GetProcAddress(newdevMod,UPDATEDRIVERFORPLUGANDPLAYDEVICES); + if(!UpdateFn) + { + goto final; + } + + FormatToStream(stdout,inf ? MSG_UPDATE_INF : MSG_UPDATE,hwid,inf); + + if(!UpdateFn(NULL,hwid,inf,flags,&reboot)) { + goto final; + } + + FormatToStream(stdout,MSG_UPDATE_OK); + + failcode = reboot ? EXIT_REBOOT : EXIT_OK; + +final: + + if(newdevMod) { + FreeLibrary(newdevMod); + } + + return failcode; +} + +int cmdInstall(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + CREATE + Creates a root enumerated devnode and installs drivers on it + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + HDEVINFO DeviceInfoSet = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA DeviceInfoData; + GUID ClassGUID; + TCHAR ClassName[MAX_CLASS_NAME_LEN]; + TCHAR hwIdList[LINE_LEN+4]; + TCHAR InfPath[MAX_PATH]; + int failcode = EXIT_FAIL; + LPCTSTR hwid = NULL; + LPCTSTR inf = NULL; + + if(Machine) { + // + // must be local machine + // + return EXIT_USAGE; + } + if(argc<2) { + // + // at least HWID required + // + return EXIT_USAGE; + } + inf = argv[0]; + if(!inf[0]) { + return EXIT_USAGE; + } + + hwid = argv[1]; + if(!hwid[0]) { + return EXIT_USAGE; + } + + // + // Inf must be a full pathname + // + if(GetFullPathName(inf,MAX_PATH,InfPath,NULL) >= MAX_PATH) { + // + // inf pathname too long + // + return EXIT_FAIL; + } + + // + // List of hardware ID's must be double zero-terminated + // + ZeroMemory(hwIdList,sizeof(hwIdList)); + if (FAILED(StringCchCopy(hwIdList,LINE_LEN,hwid))) { + goto final; + } + + // + // Use the INF File to extract the Class GUID. + // + if (!SetupDiGetINFClass(InfPath,&ClassGUID,ClassName,sizeof(ClassName)/sizeof(ClassName[0]),0)) + { + goto final; + } + + // + // Create the container for the to-be-created Device Information Element. + // + DeviceInfoSet = SetupDiCreateDeviceInfoList(&ClassGUID,0); + if(DeviceInfoSet == INVALID_HANDLE_VALUE) + { + goto final; + } + + // + // Now create the element. + // Use the Class GUID and Name from the INF file. + // + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + if (!SetupDiCreateDeviceInfo(DeviceInfoSet, + ClassName, + &ClassGUID, + NULL, + 0, + DICD_GENERATE_ID, + &DeviceInfoData)) + { + goto final; + } + + // + // Add the HardwareID to the Device's HardwareID property. + // + if(!SetupDiSetDeviceRegistryProperty(DeviceInfoSet, + &DeviceInfoData, + SPDRP_HARDWAREID, + (LPBYTE)hwIdList, + (lstrlen(hwIdList)+1+1)*sizeof(TCHAR))) + { + goto final; + } + + // + // Transform the registry element into an actual devnode + // in the PnP HW tree. + // + if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, + DeviceInfoSet, + &DeviceInfoData)) + { + goto final; + } + + FormatToStream(stdout,MSG_INSTALL_UPDATE); + // + // update the driver for the device we just created + // + failcode = cmdUpdate(BaseName,Machine,Flags,argc,argv); + +final: + + if (DeviceInfoSet != INVALID_HANDLE_VALUE) { + SetupDiDestroyDeviceInfoList(DeviceInfoSet); + } + + return failcode; +} + +int cmdUpdateNI(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + UPDATE (non interactive version) + update driver for existing device(s) + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + // + // turn off interactive mode while doing the update + // + HMODULE setupapiMod = NULL; + SetupSetNonInteractiveModeProto SetNIFn; + int res; + BOOL prev; + + setupapiMod = LoadLibrary(TEXT("setupapi.dll")); + if(!setupapiMod) { + return cmdUpdate(BaseName,Machine,Flags,argc,argv); + } + SetNIFn = (SetupSetNonInteractiveModeProto)GetProcAddress(setupapiMod,SETUPSETNONINTERACTIVEMODE); + if(!SetNIFn) + { + FreeLibrary(setupapiMod); + return cmdUpdate(BaseName,Machine,Flags,argc,argv); + } + prev = SetNIFn(TRUE); + res = cmdUpdate(BaseName,Machine,Flags,argc,argv); + SetNIFn(prev); + FreeLibrary(setupapiMod); + return res; +} + +int RemoveCallback(_In_ HDEVINFO Devs, _In_ PSP_DEVINFO_DATA DevInfo, _In_ DWORD Index, _In_ LPVOID Context) +/*++ + +Routine Description: + + Callback for use by Remove + Invokes DIF_REMOVE + uses SetupDiCallClassInstaller so cannot be done for remote devices + Don't use CM_xxx API's, they bypass class/co-installers and this is bad. + +Arguments: + + Devs )_ uniquely identify the device + DevInfo ) + Index - index of device + Context - GenericContext + +Return Value: + + EXIT_xxxx + +--*/ +{ + SP_REMOVEDEVICE_PARAMS rmdParams; + GenericContext *pControlContext = (GenericContext*)Context; + SP_DEVINSTALL_PARAMS devParams; + LPCTSTR action = NULL; + // + // need hardware ID before trying to remove, as we wont have it after + // + TCHAR devID[MAX_DEVICE_ID_LEN]; + SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail; + + UNREFERENCED_PARAMETER(Index); + + devInfoListDetail.cbSize = sizeof(devInfoListDetail); + if((!SetupDiGetDeviceInfoListDetail(Devs,&devInfoListDetail)) || + (CM_Get_Device_ID_Ex(DevInfo->DevInst,devID,MAX_DEVICE_ID_LEN,0,devInfoListDetail.RemoteMachineHandle)!=CR_SUCCESS)) { + // + // skip this + // + return EXIT_OK; + } + + rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE; + rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL; + rmdParams.HwProfile = 0; + if(!SetupDiSetClassInstallParams(Devs,DevInfo,&rmdParams.ClassInstallHeader,sizeof(rmdParams)) || + !SetupDiCallClassInstaller(DIF_REMOVE,Devs,DevInfo)) { + // + // failed to invoke DIF_REMOVE + // + action = pControlContext->strFail; + } else { + // + // see if device needs reboot + // + devParams.cbSize = sizeof(devParams); + if(SetupDiGetDeviceInstallParams(Devs,DevInfo,&devParams) && (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT))) { + // + // reboot required + // + action = pControlContext->strReboot; + pControlContext->reboot = TRUE; + } else { + // + // appears to have succeeded + // + action = pControlContext->strSuccess; + } + pControlContext->count++; + } + _tprintf(TEXT("%-60s: %s\n"),devID,action); + + return EXIT_OK; +} + +int cmdRemove(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + REMOVE + remove devices + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + GenericContext context; + TCHAR strRemove[80]; + TCHAR strReboot[80]; + TCHAR strFail[80]; + int failcode = EXIT_FAIL; + + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + // + // arguments required + // + return EXIT_USAGE; + } + if(Machine) { + // + // must be local machine as we need to involve class/co installers + // + return EXIT_USAGE; + } + if(!LoadString(NULL,IDS_REMOVED,strRemove,ARRAYSIZE(strRemove))) { + return EXIT_FAIL; + } + if(!LoadString(NULL,IDS_REMOVED_REBOOT,strReboot,ARRAYSIZE(strReboot))) { + return EXIT_FAIL; + } + if(!LoadString(NULL,IDS_REMOVE_FAILED,strFail,ARRAYSIZE(strFail))) { + return EXIT_FAIL; + } + + context.reboot = FALSE; + context.count = 0; + context.strReboot = strReboot; + context.strSuccess = strRemove; + context.strFail = strFail; + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,RemoveCallback,&context); + + if(failcode == EXIT_OK) { + + if(!context.count) { + FormatToStream(stdout,MSG_REMOVE_TAIL_NONE); + } else if(!context.reboot) { + FormatToStream(stdout,MSG_REMOVE_TAIL,context.count); + } else { + FormatToStream(stdout,MSG_REMOVE_TAIL_REBOOT,context.count); + failcode = EXIT_REBOOT; + } + } + return failcode; +} + +int cmdRescan(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + RESCAN + rescan for new devices + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + + // + // reenumerate from the root of the devnode tree + // totally CM based + // + int failcode = EXIT_FAIL; + HMACHINE machineHandle = NULL; + DEVINST devRoot; + + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + if(Machine) { + if(CM_Connect_Machine(Machine,&machineHandle) != CR_SUCCESS) { + return failcode; + } + } + + if(CM_Locate_DevNode_Ex(&devRoot,NULL,CM_LOCATE_DEVNODE_NORMAL,machineHandle) != CR_SUCCESS) { + goto final; + } + + FormatToStream(stdout,Machine ? MSG_RESCAN : MSG_RESCAN_LOCAL); + + if(CM_Reenumerate_DevNode_Ex(devRoot, 0, machineHandle) != CR_SUCCESS) { + goto final; + } + + FormatToStream(stdout,MSG_RESCAN_OK); + + failcode = EXIT_OK; + +final: + if(machineHandle) { + CM_Disconnect_Machine(machineHandle); + } + + return failcode; +} + +int cmdClassFilter(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + CLASSFILTER + Allows tweaking of class filters + Useful for filter driver development and for Product Support + + is a list of the following: + @service - sets 'after' to the first match of service after 'after' + (reset to -1 after any other command) + !service - deletes first match of 'service' after 'after' + -service - insert new service directly prior to 'after', or at start + +service - insert new service directly after 'after', or at end + + if no given, list the services + +Arguments: + + BaseName - name of executable + Machine - if non-NULL, remote machine + argc/argv - remaining parameters - list of class names + +Return Value: + + EXIT_xxxx + +--*/ +{ + int failcode = EXIT_FAIL; + int argIndex; + DWORD numGuids = 0; + GUID guid; + LPTSTR regval = NULL; + HKEY hk = (HKEY)INVALID_HANDLE_VALUE; + LPTSTR * multiVal = NULL; + int after; + bool modified = false; + int span; + SC_HANDLE SCMHandle = NULL; + SC_HANDLE ServHandle = NULL; + + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Flags); + + if((argc<2) || !argv[0][0]) { + return EXIT_USAGE; + } + + // + // just take the first guid for the name + // + if(!SetupDiClassGuidsFromNameEx(argv[0],&guid,1,&numGuids,Machine,NULL)) { + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + goto final; + } + } + if(numGuids == 0) { + goto final; + } + if(_tcsicmp(argv[1],TEXT("upper"))==0) { + regval = REGSTR_VAL_UPPERFILTERS; + } else if(_tcsicmp(argv[1],TEXT("lower"))==0) { + regval = REGSTR_VAL_LOWERFILTERS; + } else { + failcode = EXIT_USAGE; + goto final; + } + + hk = SetupDiOpenClassRegKeyEx(&guid, + KEY_READ | (argc>2 ? KEY_WRITE : 0), + DIOCR_INSTALLER, + Machine, + NULL + ); + if(hk == INVALID_HANDLE_VALUE) { + goto final; + } + multiVal = GetRegMultiSz(hk,regval); + + if(argc<=2) { + // + // just display + // + FormatToStream(stdout,MSG_CLASSFILTER_UNCHANGED); + DumpArray(1,multiVal); + failcode = EXIT_OK; + goto final; + } + after = -1; // for the @service expressions + span = 1; + + if(!multiVal) { + multiVal = CopyMultiSz(NULL); + if(!multiVal) { + goto final; + } + } + + for(argIndex=2;argIndex DWORD_MAX) { + goto final; + } + LONG err = RegSetValueEx(hk,regval,0,REG_MULTI_SZ,(LPBYTE)multiSz,(DWORD)len); + if(err==NO_ERROR) { + FormatToStream(stdout,MSG_CLASSFILTER_CHANGED); + DumpArray(1,multiVal); + failcode = EXIT_REBOOT; + } + } else { + LONG err = RegDeleteValue(hk,regval); + if((err == NO_ERROR) || (err == ERROR_FILE_NOT_FOUND)) { + FormatToStream(stdout,MSG_CLASSFILTER_CHANGED); + failcode = EXIT_REBOOT; + } + } + } else { + FormatToStream(stdout,MSG_CLASSFILTER_UNCHANGED); + DumpArray(1,multiVal); + failcode = EXIT_OK; + } + +final: + + if(multiVal) { + DelMultiSz(multiVal); + } + if(hk != (HKEY)INVALID_HANDLE_VALUE) { + RegCloseKey(hk); + } + + return failcode; +} + +int SetHwidCallback(_In_ HDEVINFO Devs, _In_ PSP_DEVINFO_DATA DevInfo, _In_ DWORD Index, _In_ LPVOID Context) +/*++ + +Routine Description: + + Callback for use by SetHwid + +Arguments: + + Devs )_ uniquely identify the device + DevInfo ) + Index - index of device + Context - SetHwidContext + +Return Value: + + EXIT_xxxx + +--*/ +{ + SetHwidContext *pControlContext = (SetHwidContext*)Context; + ULONG status; + ULONG problem; + LPTSTR * hwlist = NULL; + bool modified = false; + int result = EXIT_FAIL; + + // + // processes the sub-commands on each callback + // not most efficient way of doing things, but perf isn't important + // + TCHAR devID[MAX_DEVICE_ID_LEN]; + SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail; + + UNREFERENCED_PARAMETER(Index); + + devInfoListDetail.cbSize = sizeof(devInfoListDetail); + if((!SetupDiGetDeviceInfoListDetail(Devs,&devInfoListDetail)) || + (CM_Get_Device_ID_Ex(DevInfo->DevInst,devID,MAX_DEVICE_ID_LEN,0,devInfoListDetail.RemoteMachineHandle)!=CR_SUCCESS) || + (CM_Get_DevNode_Status_Ex(&status,&problem,DevInfo->DevInst,0,devInfoListDetail.RemoteMachineHandle)!=CR_SUCCESS)) { + // + // skip this + // + return EXIT_OK; + } + // + // this is how to verify it's root enumerated + // + if(!(status & DN_ROOT_ENUMERATED)) { + _tprintf(TEXT("%-60s: "),devID); + FormatToStream(stdout,MSG_SETHWID_NOTROOT); + pControlContext->skipped++; + return EXIT_OK; + } + hwlist = GetDevMultiSz(Devs,DevInfo,pControlContext->prop); + if(hwlist == NULL) { + hwlist = CopyMultiSz(NULL); + if(hwlist == NULL) { + return EXIT_FAIL; + } + } + + // + // modify hwid list (only relevent for root-enumerated devices) + // + int i; + int mark = -1; + + for(i=0;iargc_right;i++) { + LPTSTR op = pControlContext->argv_right[i]; + if(op[0] == TEXT('=')) { + // + // clear the hwid list first + // + hwlist[0] = NULL; + mark = 0; + op++; + } else if(op[0] == TEXT('+')) { + // + // insert as better match + // + mark = 0; + op++; + } else if(op[0] == TEXT('-')) { + // + // insert as worse match + // + mark = -1; + op++; + } else if(op[0] == TEXT('!')) { + // + // delete + // + mark = -2; + op++; + } else { + // + // treat as a hardware id + // + } + if(!*op) { + result = EXIT_USAGE; + goto final; + } + int cnt; + for(cnt = 0;hwlist[cnt];cnt++) { + // nothing + } + if((mark == -1) || (mark>cnt)) { + mark = cnt; + } + LPTSTR * tmpArray = new LPTSTR[cnt+2]; + if(!tmpArray) { + goto final; + } + int dst = 0; + int ent; + for(ent=0;ent=0) { + tmpArray[dst++] = op; + } + for(;ent DWORD_MAX) { + result = EXIT_FAIL; + goto final; + } + if(!SetupDiSetDeviceRegistryProperty(Devs, + DevInfo, + pControlContext->prop, + (LPBYTE)multiSz, + (DWORD)len)) { + result = EXIT_FAIL; + goto final; + } + } else { + // + // delete list + // + if(!SetupDiSetDeviceRegistryProperty(Devs, + DevInfo, + pControlContext->prop, + NULL, + 0)) { + result = EXIT_FAIL; + goto final; + } + } + } + result = EXIT_OK; + pControlContext->modified++; + _tprintf(TEXT("%-60s: "),devID); + for(mark=0;hwlist[mark];mark++) { + if(mark > 0) { + _tprintf(TEXT(",")); + } + _tprintf(TEXT("%s"),hwlist[mark]); + } + _tprintf(TEXT("\n")); + + // + // cleanup + // + + final: + + if(hwlist) { + DelMultiSz(hwlist); + } + + return result; +} + +int cmdSetHwid(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + + SETHWID + changes the hardware ID's of the listed root-enumerated devices + This demonstrates how to differentiate between root-enumerated and + non root-enumerated devices. + It also demonstrates how to get/set hardware ID's of root-enumerated + devices. + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + SetHwidContext context; + int failcode = EXIT_FAIL; + + UNREFERENCED_PARAMETER(Flags); + + if(!SplitCommandLine(argc,argv,context.argc_right,context.argv_right) + || (argc == 0) + || (context.argc_right == 0)) { + // + // arguments required both left and right of ':=' + // + return EXIT_USAGE; + } + context.skipped = 0; + context.modified = 0; + context.prop = SPDRP_HARDWAREID; + + failcode = EnumerateDevices(BaseName,Machine,DIGCF_PRESENT,argc,argv,SetHwidCallback,&context); + + if(failcode == EXIT_OK) { + + if(context.skipped) { + FormatToStream(stdout,MSG_SETHWID_TAIL_SKIPPED,context.skipped,context.modified); + } else if(context.modified) { + FormatToStream(stdout,MSG_SETHWID_TAIL_MODIFIED,context.modified); + } else { + FormatToStream(stdout,MSG_SETHWID_TAIL_NONE); + } + } + return failcode; +} + +int cmdDPAdd(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + dp_add + Add a driver package to the machine. + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + int failcode = EXIT_FAIL; + DWORD res; + TCHAR SourceInfFileName[MAX_PATH]; + TCHAR DestinationInfFileName[MAX_PATH]; + PTSTR DestinationInfFileNameComponent = NULL; + PTSTR FilePart = NULL; + + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Machine); + UNREFERENCED_PARAMETER(Flags); + + if(!argc) { + return EXIT_USAGE; + } + + res = GetFullPathName(argv[0], + ARRAYSIZE(SourceInfFileName), + SourceInfFileName, + &FilePart); + if ((!res) || (res >= ARRAYSIZE(SourceInfFileName))) { + FormatToStream(stdout,MSG_DPADD_INVALID_INF); + goto final; + } + + if (!SetupCopyOEMInf(SourceInfFileName, + NULL, + SPOST_PATH, + 0, + DestinationInfFileName, + ARRAYSIZE(DestinationInfFileName), + NULL, + &DestinationInfFileNameComponent)) { + FormatToStream(stdout,MSG_DPADD_FAILED); + goto final; + } + + // + // Successfully added the driver package to the machine. + // + FormatToStream(stdout,MSG_DPADD_SUCCESS,DestinationInfFileNameComponent); + failcode = EXIT_OK; + +final: + + return failcode; +} + +int cmdDPDelete(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + dp_delete + Deletes a driver package to the machine. + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + int failcode = EXIT_FAIL; + DWORD res; + TCHAR InfFileName[MAX_PATH]; + PTSTR FilePart = NULL; + HMODULE setupapiMod = NULL; + SetupUninstallOEMInfProto SUOIFn; + + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Machine); + + if(!argc) { + return EXIT_USAGE; + } + + res = GetFullPathName(argv[0], + ARRAYSIZE(InfFileName), + InfFileName, + &FilePart); + if ((!res) || (!FilePart)) { + FormatToStream(stdout,MSG_DPADD_INVALID_INF); + goto final; + } + + setupapiMod = LoadLibrary(TEXT("setupapi.dll")); + if(!setupapiMod) { + goto final; + } + SUOIFn = (SetupUninstallOEMInfProto)GetProcAddress(setupapiMod,SETUPUNINSTALLOEMINF); + if(!SUOIFn) + { + goto final; + } + + if (!SUOIFn(FilePart, + ((Flags & DEVCON_FLAG_FORCE) ? 1 : 0), + NULL)) { + if (GetLastError() == ERROR_INF_IN_USE_BY_DEVICES) { + FormatToStream(stdout,MSG_DPDELETE_FAILED_IN_USE); + } else if (GetLastError() == ERROR_NOT_AN_INSTALLED_OEM_INF) { + FormatToStream(stdout,MSG_DPDELETE_FAILED_NOT_OEM_INF); + } else { + FormatToStream(stdout,MSG_DPDELETE_FAILED); + } + goto final; + } + + // + // Successfully added the driver package to the machine. + // + FormatToStream(stdout,MSG_DPDELETE_SUCCESS,FilePart); + failcode = EXIT_OK; + +final: + if (setupapiMod) { + FreeLibrary(setupapiMod); + } + + return failcode; +} + +int cmdDPEnumLegacy(_In_ LPCTSTR BaseName, _In_opt_ LPCTSTR Machine, _In_ DWORD Flags, _In_ int argc, _In_reads_(argc) PTSTR argv[]) +/*++ + +Routine Description: + dp_enumLegacy + Enumerates installed Driver Packages on the machine pre Windows Longhorn + +Arguments: + + BaseName - name of executable + Machine - machine name, must be NULL + argc/argv - remaining parameters + +Return Value: + + EXIT_xxxx + +--*/ +{ + int failcode = EXIT_FAIL; + TCHAR FindName[MAX_PATH]; + HANDLE hFind = INVALID_HANDLE_VALUE; + WIN32_FIND_DATA wfd; + + UNREFERENCED_PARAMETER(BaseName); + UNREFERENCED_PARAMETER(Machine); + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(argv); + + if(argc) { + return EXIT_USAGE; + } + + if (!GetWindowsDirectory(FindName, ARRAYSIZE(FindName)) || + FAILED(StringCchCat(FindName, ARRAYSIZE(FindName), TEXT("\\INF\\OEM*.INF")))) { + goto final; + } + + hFind = FindFirstFile(FindName, &wfd); + if (hFind == INVALID_HANDLE_VALUE) { + // + // No OEM driver packages on this machine. + // + FormatToStream(stdout,MSG_DPENUM_NO_OEM_INF); + failcode = EXIT_OK; + goto final; + } + + FormatToStream(stdout,MSG_DPENUM_LIST_HEADER); + + do { + FormatToStream(stdout,MSG_DPENUM_LIST_ENTRY,wfd.cFileName); + DumpDriverPackageData(wfd.cFileName); + } while (FindNextFile(hFind, &wfd)); + + FindClose(hFind); + + failcode = EXIT_OK; + +final: + + return failcode; +} + + +DispatchEntry DispatchTable[] = { + { TEXT("classfilter"), cmdClassFilter, MSG_CLASSFILTER_SHORT, MSG_CLASSFILTER_LONG }, + { TEXT("classes"), cmdClasses, MSG_CLASSES_SHORT, MSG_CLASSES_LONG }, + { TEXT("disable"), cmdDisable, MSG_DISABLE_SHORT, MSG_DISABLE_LONG }, + { TEXT("driverfiles"), cmdDriverFiles, MSG_DRIVERFILES_SHORT, MSG_DRIVERFILES_LONG }, + { TEXT("drivernodes"), cmdDriverNodes, MSG_DRIVERNODES_SHORT, MSG_DRIVERNODES_LONG }, + { TEXT("enable"), cmdEnable, MSG_ENABLE_SHORT, MSG_ENABLE_LONG }, + { TEXT("find"), cmdFind, MSG_FIND_SHORT, MSG_FIND_LONG }, + { TEXT("findall"), cmdFindAll, MSG_FINDALL_SHORT, MSG_FINDALL_LONG }, + { TEXT("help"), cmdHelp, MSG_HELP_SHORT, 0 }, + { TEXT("hwids"), cmdHwIds, MSG_HWIDS_SHORT, MSG_HWIDS_LONG }, + { TEXT("install"), cmdInstall, MSG_INSTALL_SHORT, MSG_INSTALL_LONG }, + { TEXT("listclass"), cmdListClass, MSG_LISTCLASS_SHORT, MSG_LISTCLASS_LONG }, + { TEXT("reboot"), cmdReboot, MSG_REBOOT_SHORT, MSG_REBOOT_LONG }, + { TEXT("remove"), cmdRemove, MSG_REMOVE_SHORT, MSG_REMOVE_LONG }, + { TEXT("rescan"), cmdRescan, MSG_RESCAN_SHORT, MSG_RESCAN_LONG }, + { TEXT("resources"), cmdResources, MSG_RESOURCES_SHORT, MSG_RESOURCES_LONG }, + { TEXT("restart"), cmdRestart, MSG_RESTART_SHORT, MSG_RESTART_LONG }, + { TEXT("sethwid"), cmdSetHwid, MSG_SETHWID_SHORT, MSG_SETHWID_LONG }, + { TEXT("stack"), cmdStack, MSG_STACK_SHORT, MSG_STACK_LONG }, + { TEXT("status"), cmdStatus, MSG_STATUS_SHORT, MSG_STATUS_LONG }, + { TEXT("update"), cmdUpdate, MSG_UPDATE_SHORT, MSG_UPDATE_LONG }, + { TEXT("updateni"), cmdUpdateNI, MSG_UPDATENI_SHORT, MSG_UPDATENI_LONG }, + { TEXT("dp_add"), cmdDPAdd, MSG_DPADD_SHORT, MSG_DPADD_LONG }, + { TEXT("dp_delete"), cmdDPDelete, MSG_DPDELETE_SHORT, MSG_DPDELETE_LONG }, + { TEXT("dp_enum"), cmdDPEnumLegacy,MSG_DPENUM_SHORT, MSG_DPENUM_LONG }, + { TEXT("?"), cmdHelp, 0, 0 }, + { NULL,NULL } +}; + + + -- cgit v1.3.1