diff --git a/HidUtil/HidUtil.vcxproj b/HidUtil/HidUtil.vcxproj
index a7c56586..802848ad 100644
--- a/HidUtil/HidUtil.vcxproj
+++ b/HidUtil/HidUtil.vcxproj
@@ -1,5 +1,6 @@
+
Debug
@@ -120,12 +121,26 @@
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
\ No newline at end of file
diff --git a/HidUtil/HidUtil.vcxproj.filters b/HidUtil/HidUtil.vcxproj.filters
index b75e5b0d..aa873169 100644
--- a/HidUtil/HidUtil.vcxproj.filters
+++ b/HidUtil/HidUtil.vcxproj.filters
@@ -2,9 +2,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/HidUtil/Main.cpp b/HidUtil/Main.cpp
index 9bbb8890..24b59662 100644
--- a/HidUtil/Main.cpp
+++ b/HidUtil/Main.cpp
@@ -1,18 +1,46 @@
#include "HID.hpp"
#include "TailLight.hpp"
+#include "Wbem.h"
+#define SWITCH_BIST "/bist"
+#define CB_SWITCH_BIST_ONLY (sizeof(SWITCH_BIST) - 1)
+
+void PrintUsage() {
+ wprintf(L"IntelliMouse tail-light shifter .\n");
+ wprintf(L"Usage:\n\"HidUtil.exe [/bist] [ \""
+ " (example: \"HidUtil.exe 0 0 255\" or\n \"HidUtil.exe /bist\"]).\n");
+}
int main(int argc, char* argv[]) {
- if (argc < 4) {
- wprintf(L"IntelliMouse tail-light shifter.\n");
- wprintf(L"Usage: \"HidUtil.exe \" (example: \"HidUtil.exe 0 0 255\").\n");
+
+ BYTE red = 0;
+ BYTE green = 0;
+ BYTE blue = 0;
+
+ if (argc == 2 && lstrlenA(argv[1]) == CB_SWITCH_BIST_ONLY) {
+ if (memcmp(argv[1], SWITCH_BIST, CB_SWITCH_BIST_ONLY) == 0) {
+ if (SUCCEEDED(ConnectToWbem())) {
+ return 0;
+ }
+ else {
+ return -4;
+ }
+ }
+ else {
+ PrintUsage();
+ return -1;
+ }
+ }
+ else if (argc == 4) {
+ red = (BYTE)atoi(argv[1]);
+ green = (BYTE)atoi(argv[2]);
+ blue = (BYTE)atoi(argv[3]);
+ }
+ else {
+ PrintUsage();
return -1;
}
- auto red = (BYTE)atoi(argv[1]);
- auto green = (BYTE)atoi(argv[2]);
- auto blue = (BYTE)atoi(argv[3]);
-
HID::Query query;
query.VendorID = 0x045E; // Microsoft
query.ProductID = 0x082A; // Pro IntelliMouse
diff --git a/HidUtil/Wbem.h b/HidUtil/Wbem.h
new file mode 100644
index 00000000..90dcdc9f
--- /dev/null
+++ b/HidUtil/Wbem.h
@@ -0,0 +1,34 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+
+HRESULT
+ConnectToWbem();
+
+HRESULT
+SetInterfaceSecurity(
+ _In_ IUnknown* InterfaceObj,
+ _In_opt_ PWSTR UserId,
+ _In_opt_ PWSTR Password,
+ _In_opt_ PWSTR DomainName
+);
+
+HRESULT
+ExecuteMethod_NoArgs_ReturnsValue(
+ _In_ winrt::com_ptr* pWbemServices,
+ _In_ winrt::com_ptr* pClassObj,
+ _In_ const BSTR InstancePath,
+ _In_ const OLECHAR* psz,
+ _Out_ HRESULT& wmiMethodRet
+);
+
+HRESULT
+ExecuteBISTOnAllDevices(
+ _In_ winrt::com_ptr* pWbemServices,
+ _In_opt_ PWSTR UserId,
+ _In_opt_ PWSTR Password,
+ _In_opt_ PWSTR DomainName
+);
\ No newline at end of file
diff --git a/HidUtil/WbemCore.cpp b/HidUtil/WbemCore.cpp
new file mode 100644
index 00000000..cabbb7f1
--- /dev/null
+++ b/HidUtil/WbemCore.cpp
@@ -0,0 +1,322 @@
+#include "Wbem.h"
+#include "roapi.h"
+#include
+
+#pragma comment(lib, "comsupp")
+#pragma comment(lib, "wbemuuid")
+
+// Blatantly stolen from the Toaster sample
+
+HRESULT ConnectToWbem() {
+ HRESULT status = S_OK;
+ BOOLEAN initialized = FALSE;
+
+ BSTR temp = NULL;
+ BSTR wmiRoot = NULL;
+ BSTR userIdString = NULL;
+ BSTR passwordString = NULL;
+
+ PWSTR ComputerName = NULL;
+ PWSTR userId = NULL;
+ PWSTR password = NULL;
+ PWSTR domain = NULL;
+
+ winrt::com_ptr wbemLocator;
+ winrt::com_ptr wbemServices;
+
+ //
+ // Initialize COM environment for multi-threaded concurrency.
+ //
+ status = Windows::Foundation::Initialize(RO_INIT_MULTITHREADED);
+ if (FAILED(status)) {
+ return status;
+ }
+
+ initialized = TRUE;
+
+ //
+ // Initialize the security layer and set the specified values as the
+ // security default for the process.
+ //
+ status = CoInitializeSecurity(NULL,
+ -1,
+ NULL,
+ NULL,
+ RPC_C_AUTHN_LEVEL_PKT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL,
+ EOAC_NONE,
+ 0);
+
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ //
+ // Create a single uninitialized object associated with the class id
+ // CLSID_WbemLocator.
+ //
+ status = CoCreateInstance(CLSID_WbemLocator,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator,
+ wbemLocator.put_void());
+
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ //
+ // Construct the object path for the WMI namespace. For local access to the
+ // WMI namespace, use a simple object path: "\\.\root\WMI". For access to
+ // the WMI namespace on a remote computer, include the computer name in the
+ // object path: "\\myserver\root\WMI".
+ //
+ if (ComputerName != NULL) {
+
+ status = VarBstrCat(_bstr_t(L"\\\\"), _bstr_t(ComputerName), &temp);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ }
+ else {
+
+ status = VarBstrCat(_bstr_t(L"\\\\"), _bstr_t(L"."), &temp);
+ if (FAILED(status)) {
+ goto exit;
+ }
+ }
+
+ status = VarBstrCat(temp, _bstr_t(L"\\root\\WMI"), &wmiRoot);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ SysFreeString(temp);
+ temp = NULL;
+
+ //
+ // Construct the user id and password strings.
+ //
+ if (userId != NULL) {
+
+ if (domain != NULL) {
+
+ status = VarBstrCat(_bstr_t(domain), _bstr_t(L"\\"), &temp);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ status = VarBstrCat(temp, _bstr_t(userId), &userIdString);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ SysFreeString(temp);
+ temp = NULL;
+
+ }
+ else {
+
+ userIdString = SysAllocString(userId);
+ if (userIdString == NULL) {
+ status = E_OUTOFMEMORY;
+ goto exit;
+ }
+ }
+
+ passwordString = SysAllocString(password);
+ if (passwordString == NULL) {
+ status = E_OUTOFMEMORY;
+ goto exit;
+ }
+ }
+
+ //
+ // Connect to the WMI server on this computer and, possibly, through it to another system.
+ //
+ status = wbemLocator->ConnectServer(wmiRoot,
+ userIdString,
+ passwordString,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ wbemServices.put());
+ if (FAILED(status)) {
+ if (status != WBEM_E_LOCAL_CREDENTIALS) {
+ goto exit;
+ }
+
+ //
+ // Use the identity inherited from the current process.
+ //
+ status = wbemLocator->ConnectServer(wmiRoot,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ wbemServices.put());
+ if (FAILED(status)) {
+ goto exit;
+ }
+ }
+
+ //
+ // Set authentication information for the interface.
+ //
+ status = SetInterfaceSecurity(wbemServices.get(), userId, password, domain);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ //
+ // Execute the methods in each instance of the desired class.
+ //
+ printf("\n1. Execute Methods in class ...\n");
+ status = ExecuteBISTOnAllDevices(&wbemServices,
+ userId,
+ password,
+ domain);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+exit:
+
+ if (temp != NULL) {
+ SysFreeString(temp);
+ }
+
+ if (userIdString != NULL) {
+ SysFreeString(userIdString);
+ }
+
+ if (passwordString != NULL) {
+ SysFreeString(passwordString);
+ }
+
+ if (wmiRoot != NULL) {
+ SysFreeString(wmiRoot);
+ }
+
+ if (initialized == TRUE) {
+ CoUninitialize();
+ }
+
+ if (FAILED(status)) {
+ printf("FAILED with Status = 0x%08x\n", status);
+ }
+ return status;
+}
+
+HRESULT
+SetInterfaceSecurity(
+ _In_ IUnknown* InterfaceObj,
+ _In_opt_ PWSTR UserId,
+ _In_opt_ PWSTR Password,
+ _In_opt_ PWSTR DomainName
+)
+
+/*++
+
+Routine Description:
+
+ Set the interface security to allow the server to impersonate the specified
+ user.
+
+Arguments:
+
+ InterfaceObj - Pointer to interface for which the security settings need
+ to be applied.
+
+ UserId - Pointer to the user id information or NULL.
+
+ Password - Pointer to password or NULL. If the user id is not specified,
+ this parameter is ignored.
+
+ DomainName - Pointer to domain name or NULL. If the user id is not specified,
+ this parameter is ignored.
+
+Return Value:
+
+ HRESULT Status code.
+
+--*/
+
+{
+ HRESULT hr;
+
+ COAUTHIDENTITY AuthIdentity;
+ DWORD AuthnSvc;
+ DWORD AuthzSvc;
+ DWORD AuthnLevel;
+ DWORD ImpLevel;
+ DWORD Capabilities;
+ PWSTR pServerPrinName = NULL;
+ RPC_AUTH_IDENTITY_HANDLE pAuthHndl = NULL;
+
+ //
+ // Get current authentication information for interface.
+ //
+ hr = CoQueryProxyBlanket(InterfaceObj,
+ &AuthnSvc,
+ &AuthzSvc,
+ &pServerPrinName,
+ &AuthnLevel,
+ &ImpLevel,
+ &pAuthHndl,
+ &Capabilities);
+
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ if (UserId == NULL) {
+
+ AuthIdentity.User = NULL;
+ AuthIdentity.UserLength = 0;
+ AuthIdentity.Password = NULL;
+ AuthIdentity.PasswordLength = 0;
+ AuthIdentity.Domain = NULL;
+ AuthIdentity.DomainLength = 0;
+
+ }
+ else {
+
+ AuthIdentity.User = (USHORT*)UserId;
+#pragma prefast(suppress:6387, "0 length UserId is valid")
+ AuthIdentity.UserLength = (ULONG)wcslen(UserId);
+ AuthIdentity.Password = (USHORT*)Password;
+#pragma prefast(suppress:6387, "0 length Password is valid")
+ AuthIdentity.PasswordLength = (ULONG)wcslen(Password);
+ AuthIdentity.Domain = (USHORT*)DomainName;
+ AuthIdentity.DomainLength = (DomainName == NULL) ? 0 : (ULONG)wcslen(DomainName);
+
+ }
+
+ AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+
+ //
+ // Change authentication information for interface, providing the identity
+ // information and "echoing back" everything else.
+ //
+ hr = CoSetProxyBlanket(InterfaceObj,
+ AuthnSvc,
+ AuthzSvc,
+ pServerPrinName,
+ AuthnLevel,
+ ImpLevel,
+ &AuthIdentity,
+ Capabilities);
+
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+exit:
+ return hr;
+}
\ No newline at end of file
diff --git a/HidUtil/WbemExecute.cpp b/HidUtil/WbemExecute.cpp
new file mode 100644
index 00000000..3da148d4
--- /dev/null
+++ b/HidUtil/WbemExecute.cpp
@@ -0,0 +1,185 @@
+#include "wbem.h"
+#include
+
+#define TAILLIGHT_WMI_BIST_CLASS L"TailLightBIST"
+#define TAILLIGHT_WMI_BIST_METHOD L"BIST"
+
+// Blatantly stolen from the Toaster samples.
+// Just like most other driver code.
+// From WmiExecute.cpp
+// Updated to use WinRT and RAII
+
+using namespace winrt;
+
+HRESULT
+ExecuteMethod_NoArgs_ReturnsValue(
+ _In_ com_ptr* pWbemServices,
+ _In_ com_ptr* pClassObj,
+ _In_ const BSTR InstancePath,
+ _In_ const OLECHAR* psz,
+ _Out_ HRESULT& wmiMethodRet)
+{
+ HRESULT status;
+
+ com_ptr inputParamsObj;
+ com_ptr resultControlObj;
+
+ const BSTR methodName = SysAllocString(psz);
+ VARIANT retVal;
+
+ //
+ // Get the input parameters class objects for the method.
+ //
+ status = (*pClassObj)->GetMethod(methodName, 0, inputParamsObj.put(), NULL);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ //
+ // Set the output variables values (i.e., return value for BIST).
+ //
+ retVal.vt = VT_I4;
+ retVal.ulVal = wmiMethodRet;
+
+ //
+ // Call the method.
+ //
+ printf("\n");
+ printf(" Start waiting for method : %ws to finish.\n", (wchar_t*)methodName);
+ status = (*pWbemServices)->ExecMethod(InstancePath,
+ methodName,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ resultControlObj.put());
+
+ if (FAILED(status) || NULL == resultControlObj) {
+ goto exit;
+ }
+
+ //
+ // Get the result of the method call.
+ //
+ status = resultControlObj->GetCallStatus(4 * 1000, &wmiMethodRet);
+ printf(" Return value...: 0x%x\n", wmiMethodRet);
+exit:
+
+ if (methodName != NULL) {
+ SysFreeString(methodName);
+ }
+
+ return status;
+}
+
+
+HRESULT
+ExecuteBISTOnAllDevices(
+ _In_ com_ptr* pWbemServices,
+ _In_opt_ PWSTR UserId,
+ _In_opt_ PWSTR Password,
+ _In_opt_ PWSTR DomainName
+)
+{
+ HRESULT status = S_OK;
+
+ com_ptr enumerator;
+ com_ptr classObj;
+ com_ptr instanceObj;
+
+ const BSTR className = SysAllocString(TAILLIGHT_WMI_BIST_CLASS);
+
+ VARIANT pathVariable;
+ _bstr_t instancePath;
+ ULONG nbrObjsSought = 1;
+ ULONG nbrObjsReturned;
+
+ VariantInit(&pathVariable);
+
+ //
+ // Create an Enumeration object to enumerate the instances of the given class.
+ //
+ status = (*pWbemServices)->CreateInstanceEnum(className,
+ WBEM_FLAG_SHALLOW | WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
+ NULL,
+ enumerator.put());
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ //
+ // Set authentication information for the interface.
+ //
+ status = SetInterfaceSecurity(enumerator.get(), UserId, Password, DomainName);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ //
+ // Get the class object for the method definition.
+ //
+ status = (*pWbemServices)->GetObject(className, 0, NULL, classObj.put(), NULL);
+ if (FAILED(status) || NULL == classObj) {
+ goto exit;
+ }
+
+ do {
+
+ //
+ // Get the instance object for each instance of the class.
+ //
+ status = enumerator->Next(WBEM_INFINITE,
+ nbrObjsSought,
+ instanceObj.put(),
+ &nbrObjsReturned);
+
+ if (status == WBEM_S_FALSE) {
+ status = S_OK;
+ break;
+ }
+
+ if (FAILED(status)) {
+ if (status == WBEM_E_INVALID_CLASS) {
+ printf("ERROR: TailLight driver may not be active on the system.\n");
+ }
+ goto exit;
+ }
+
+ //
+ // To obtain the object path of the object for which the method has to be
+ // executed, query the "__PATH" property of the WMI instance object.
+ //
+
+
+ status = instanceObj->Get(_bstr_t(L"__PATH"), 0, &pathVariable, NULL, NULL);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ instancePath = pathVariable.bstrVal;
+ printf("Instance Path .: %ws\n", (wchar_t*)instancePath);
+
+ HRESULT hr = E_FAIL;
+
+ //
+ // Execute the methods in this instance of the class.
+ //
+ status = ExecuteMethod_NoArgs_ReturnsValue(pWbemServices,
+ &classObj,
+ instancePath,
+ TAILLIGHT_WMI_BIST_METHOD,
+ hr);
+ if (FAILED(status)) {
+ goto exit;
+ }
+
+ } while (!FAILED(status));
+
+exit:
+
+ if (className != NULL) {
+ SysFreeString(className);
+ }
+
+ return status;
+}
\ No newline at end of file
diff --git a/HidUtil/packages.config b/HidUtil/packages.config
new file mode 100644
index 00000000..7a9561b2
--- /dev/null
+++ b/HidUtil/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file