diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index d4a18d4..9c2aee7 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -18,7 +18,6 @@ env: # Configuration type to build. # You can convert this to a build matrix if you need coverage of multiple configuration types. # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - BUILD_CONFIGURATION: Release (Console) BUILD_PLATFORM: x64 permissions: @@ -38,8 +37,14 @@ jobs: working-directory: ${{env.GITHUB_WORKSPACE}} run: vcpkg integrate install - - name: Build + - name: Build Console Edition working-directory: ${{env.GITHUB_WORKSPACE}} # Add additional options to the MSBuild command line here (like platform or verbosity level). # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference - run: msbuild /m /p:Configuration="${{env.BUILD_CONFIGURATION}}" /p:Platform=${{env.BUILD_PLATFORM}} ${{env.SOLUTION_FILE_PATH}} + run: msbuild /m /p:Configuration="Release (Console)" /p:Platform=${{env.BUILD_PLATFORM}} ${{env.SOLUTION_FILE_PATH}} + + - name: Build WinMain Edition + working-directory: ${{env.GITHUB_WORKSPACE}} + # Add additional options to the MSBuild command line here (like platform or verbosity level). + # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference + run: msbuild /m /p:Configuration="Release (WinMain)" /p:Platform=${{env.BUILD_PLATFORM}} ${{env.SOLUTION_FILE_PATH}} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3fadfaa --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "cSpell.words": [ + "devcon", + "nefcon", + "nefconc", + "nefconw", + "pkgs", + "pnputil", + "winget" + ] +} diff --git a/NefConUtil.sln.DotSettings b/NefConUtil.sln.DotSettings index c788d2e..a3ed424 100644 --- a/NefConUtil.sln.DotSettings +++ b/NefConUtil.sln.DotSettings @@ -1,18 +1,31 @@  True True + True True True True True True True + True True True + True + True True True + True + True True + True + True + True True True + True True - True \ No newline at end of file + True + True + True + True \ No newline at end of file diff --git a/NefConUtil.vcxproj b/NefConUtil.vcxproj index 88e00ab..9ff2ee8 100644 --- a/NefConUtil.vcxproj +++ b/NefConUtil.vcxproj @@ -295,7 +295,7 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug - stdcpp17 + stdcpplatest Console @@ -313,7 +313,7 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug - stdcpp17 + stdcpplatest Console @@ -331,7 +331,7 @@ NEFCON_WINMAIN;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug - stdcpp17 + stdcpplatest Windows @@ -349,7 +349,7 @@ NEFCON_WINMAIN;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug - stdcpp17 + stdcpplatest Windows @@ -367,7 +367,7 @@ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug - stdcpp17 + stdcpplatest Console @@ -385,7 +385,7 @@ NEFCON_WINMAIN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug - stdcpp17 + stdcpplatest Windows @@ -406,7 +406,7 @@ true MultiThreaded None - stdcpp17 + stdcpplatest Console @@ -429,7 +429,7 @@ true MultiThreaded None - stdcpp17 + stdcpplatest Windows @@ -452,7 +452,7 @@ true MultiThreaded None - stdcpp17 + stdcpplatest Console @@ -475,7 +475,7 @@ true MultiThreaded None - stdcpp17 + stdcpplatest Console @@ -498,7 +498,7 @@ true MultiThreaded None - stdcpp17 + stdcpplatest Windows @@ -521,7 +521,7 @@ true MultiThreaded None - stdcpp17 + stdcpplatest Windows @@ -532,24 +532,20 @@ - - - - - - + + diff --git a/NefConUtil.vcxproj.filters b/NefConUtil.vcxproj.filters index 0c2800a..d0536ff 100644 --- a/NefConUtil.vcxproj.filters +++ b/NefConUtil.vcxproj.filters @@ -18,12 +18,6 @@ Source Files - - Source Files - - - Source Files - @@ -35,19 +29,10 @@ Header Files - - Header Files - Header Files - - Header Files - - - Header Files - - + Header Files @@ -58,5 +43,6 @@ + \ No newline at end of file diff --git a/README.md b/README.md index f9b0d39..da0084c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # nefcon -[![MSBuild](https://github.com/nefarius/nefcon/actions/workflows/msbuild.yml/badge.svg)](https://github.com/nefarius/nefcon/actions/workflows/msbuild.yml) [![GitHub All Releases](https://img.shields.io/github/downloads/nefarius/nefcon/total)](https://somsubhra.github.io/github-release-stats/?username=nefarius&repository=nefcon) +[![MSBuild](https://github.com/nefarius/nefcon/actions/workflows/msbuild.yml/badge.svg)](https://github.com/nefarius/nefcon/actions/workflows/msbuild.yml) +[![GitHub All Releases](https://img.shields.io/github/downloads/nefarius/nefcon/total)](https://somsubhra.github.io/github-release-stats/?username=nefarius&repository=nefcon) +[![Discord](https://img.shields.io/discord/346756263763378176.svg)](https://discord.nefarius.at) +[![GitHub followers](https://img.shields.io/github/followers/nefarius.svg?style=social&label=Follow)](https://github.com/nefarius) +[![Mastodon Follow](https://img.shields.io/mastodon/follow/109321120351128938?domain=https%3A%2F%2Ffosstodon.org%2F&style=social)](https://fosstodon.org/@Nefarius) Windows device driver installation and management tool. @@ -8,19 +12,34 @@ Windows device driver installation and management tool. This little self-contained, no-dependency tool can be built either as a console application or a Windows application which has no visible window (ideal to use in combination with setup makers). It offers a command-line-based driver (un-)installer and allows for simple manipulation of class filter entries. Run `nefconc.exe --help` to see all the options offered. +## Motivation + +Windows Device Driver management is and always has been hard. The APIs involved are old, moody and come with pitfalls. Historically the [`devcon`](https://github.com/microsoft/Windows-driver-samples/tree/b3af8c8f9bd508f54075da2f2516b31d05cd52c8/setup/devcon) tool or nowadays `pnputil` have been used to offload these tedious tasks, but unintuitive and sparsely documented command line arguments and error propagation make them poor candidates for automation in e.g. setup engines. Grown tired of these limitations I made this "devcon clone" available under a permissive license which offers the following highlighted features and more: + +- Allows for true window-less execution +- Actively suppresses and works around user interaction inconsistencies ("reboot required" dialogs and OS-included bugs) +- Offers optional logging to `stdout` or file +- *Sane* command line arguments 😁 +- [Class filter](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/filter-drivers) values manipulation +- Supports installation of [primitive drivers](https://learn.microsoft.com/en-us/windows-hardware/drivers/develop/creating-a-primitive-driver) + ## Installation Binaries are available to download in the [releases](https://github.com/nefarius/nefcon/releases/latest) page, just download and extract. However, if you are using a package manager, you can use one of the following options: ### Scoop + [`nefcon`](https://scoop.sh/#/apps?q=nefcon&s=0&d=1&o=true) is available in the [Extras](https://github.com/ScoopInstaller/Extras) bucket: + ```text scoop bucket add extras scoop install nefcon ``` ### Winget + [`nefcon`](https://github.com/microsoft/winget-pkgs/tree/master/manifests/n/Nefarius/nefcon) is available in the [winget-pkgs](https://github.com/microsoft/winget-pkgs) repository: + ```text winget install nefcon ``` @@ -74,3 +93,9 @@ This project uses the following 3rd party resources: - [Convenient high-level C++ wrappers around Windows Registry Win32 APIs](https://github.com/GiovanniDicanio/WinReg) - [Single header C++ logging library](https://github.com/amrayn/easyloggingpp) - [Microsoft Detours](https://github.com/microsoft/Detours) +- [A modern C++ scope guard that is easy to use but hard to misuse](https://github.com/ricab/scope_guard) +- [Windows Implementation Libraries (WIL)](https://github.com/microsoft/wil) +- [My opinionated collection of C++ utilities](https://github.com/nefarius/neflib) +- [Replacing Device Console (DevCon.exe)](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/devcon-migration) +- [PnPUtil](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/pnputil) +- [DevCon Install](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/devcon-install) diff --git a/src/ColorLogging.hpp b/src/ColorLogging.hpp new file mode 100644 index 0000000..85f8a05 --- /dev/null +++ b/src/ColorLogging.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include "colorwin.hpp" +#include + +/** + * Custom log dispatcher printing on the console (terminal) with color support. + * + * @author Benjamin "Nefarius" Hoeglinger-Stelzer + * @date 08.08.2024 + */ +class ConsoleColorLogDispatchCallback : public el::LogDispatchCallback +{ + std::unordered_map logLevelToColor = { + {el::Level::Debug, colorwin::white}, + {el::Level::Info, colorwin::green}, + {el::Level::Warning, colorwin::yellow}, + {el::Level::Error, colorwin::red}, + {el::Level::Fatal, colorwin::magenta}, + {el::Level::Verbose, colorwin::white} + }; + +protected: + void handle(const el::LogDispatchData* data) noexcept override + { + // Extract log message details + const el::LogMessage* logMessage = data->logMessage(); + const auto now = std::chrono::system_clock::now(); + std::string timestamp = std::format("{:%FT%TZ}", std::chrono::time_point_cast(now)); + std::string level = logMessage->level() == el::Level::Debug + ? "DEBUG" + : logMessage->level() == el::Level::Info + ? "INFO" + : logMessage->level() == el::Level::Warning + ? "WARNING" + : logMessage->level() == el::Level::Error + ? "ERROR" + : logMessage->level() == el::Level::Fatal + ? "FATAL" + : "VERBOSE"; + std::string message = logMessage->message(); + + // scoped color + { + std::cout << timestamp << " " << colorwin::color(logLevelToColor[logMessage->level()]) << level; + } + std::cout << " " << message << '\n'; + } +}; diff --git a/src/Devcon.cpp b/src/Devcon.cpp deleted file mode 100644 index 7b1a8f1..0000000 --- a/src/Devcon.cpp +++ /dev/null @@ -1,1371 +0,0 @@ -#include "Devcon.h" - -// -// WinAPI -// -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include -#include - -// -// STL -// -#include -#include -#include - - -// -// Logging -// -#include "easylogging++.h" - -// -// Dynamic module helper -// -#include "LibraryHelper.hpp" - -// -// Hooking -// -#include - -static decltype(MessageBoxW)* real_MessageBoxW = MessageBoxW; - -int DetourMessageBoxW( - HWND hWnd, - LPCWSTR lpText, - LPCWSTR lpCaption, - UINT uType -); - -static BOOL g_MbCalled = FALSE; - -static decltype(RestartDialogEx)* real_RestartDialogEx = RestartDialogEx; - -int DetourRestartDialogEx( - HWND hwnd, - PCWSTR pszPrompt, - DWORD dwReturn, - DWORD dwReasonCode -); - -static BOOL g_RestartDialogExCalled = FALSE; - - -// Helper function to build a multi-string from a vector -inline std::vector BuildMultiString(const std::vector& data) -{ - // Special case of the empty multi-string - if (data.empty()) - { - // Build a vector containing just two NULs - return std::vector(2, L'\0'); - } - - // Get the total length in wchar_ts of the multi-string - size_t totalLen = 0; - for (const auto& s : data) - { - // Add one to current string's length for the terminating NUL - totalLen += (s.length() + 1); - } - - // Add one for the last NUL terminator (making the whole structure double-NUL terminated) - totalLen++; - - // Allocate a buffer to store the multi-string - std::vector multiString; - multiString.reserve(totalLen); - - // Copy the single strings into the multi-string - for (const auto& s : data) - { - multiString.insert(multiString.end(), s.begin(), s.end()); - - // Don't forget to NUL-terminate the current string - multiString.push_back(L'\0'); - } - - // Add the last NUL-terminator - multiString.push_back(L'\0'); - - return multiString; -} - -bool devcon::create(const std::wstring& className, const GUID* classGuid, const std::wstring& hardwareId) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - const auto deviceInfoSet = SetupDiCreateDeviceInfoList(classGuid, nullptr); - - if (INVALID_HANDLE_VALUE == deviceInfoSet) - { - logger->error("SetupDiCreateDeviceInfoList failed with error code %v", GetLastError()); - return false; - } - - SP_DEVINFO_DATA deviceInfoData; - deviceInfoData.cbSize = sizeof(deviceInfoData); - - const auto cdiRet = SetupDiCreateDeviceInfoW( - deviceInfoSet, - className.c_str(), - classGuid, - nullptr, - nullptr, - DICD_GENERATE_ID, - &deviceInfoData - ); - - if (!cdiRet) - { - logger->error("SetupDiCreateDeviceInfoW failed with error code %v", GetLastError()); - SetupDiDestroyDeviceInfoList(deviceInfoSet); - return false; - } - - const auto sdrpRet = SetupDiSetDeviceRegistryPropertyW( - deviceInfoSet, - &deviceInfoData, - SPDRP_HARDWAREID, - (const PBYTE)hardwareId.c_str(), - static_cast(hardwareId.size() * sizeof(WCHAR)) - ); - - if (!sdrpRet) - { - logger->error("SetupDiSetDeviceRegistryPropertyW failed with error code %v", GetLastError()); - SetupDiDestroyDeviceInfoList(deviceInfoSet); - return false; - } - - const auto cciRet = SetupDiCallClassInstaller( - DIF_REGISTERDEVICE, - deviceInfoSet, - &deviceInfoData - ); - - if (!cciRet) - { - logger->error("SetupDiCallClassInstaller failed with error code %v", GetLastError()); - SetupDiDestroyDeviceInfoList(deviceInfoSet); - return false; - } - - SetupDiDestroyDeviceInfoList(deviceInfoSet); - - return true; -} - -bool devcon::restart_bth_usb_device() -{ - DWORD i, err; - bool found = false, succeeded = false; - - HDEVINFO hDevInfo; - SP_DEVINFO_DATA spDevInfoData; - - hDevInfo = SetupDiGetClassDevs( - &GUID_DEVCLASS_BLUETOOTH, - nullptr, - nullptr, - DIGCF_PRESENT - ); - if (hDevInfo == INVALID_HANDLE_VALUE) - { - return succeeded; - } - - spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); - for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++) - { - DWORD DataT; - LPTSTR p, buffer = nullptr; - DWORD buffersize = 0; - - // get all devices info - while (!SetupDiGetDeviceRegistryProperty(hDevInfo, - &spDevInfoData, - SPDRP_ENUMERATOR_NAME, - &DataT, - (PBYTE)buffer, - buffersize, - &buffersize)) - { - if (GetLastError() == ERROR_INVALID_DATA) - { - break; - } - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - if (buffer) - LocalFree(buffer); - buffer = static_cast(LocalAlloc(LPTR, buffersize)); - } - else - { - goto cleanup_DeviceInfo; - } - } - - if (GetLastError() == ERROR_INVALID_DATA) - continue; - - //find device with enumerator name "USB" - for (p = buffer; *p && (p < &buffer[buffersize]); p += lstrlen(p) + sizeof(TCHAR)) - { - if (!_tcscmp(TEXT("USB"), p)) - { - found = true; - break; - } - } - - if (buffer) - LocalFree(buffer); - - // if device found restart - if (found) - { - if (!SetupDiRestartDevices(hDevInfo, &spDevInfoData)) - { - err = GetLastError(); - break; - } - - succeeded = true; - - break; - } - } - -cleanup_DeviceInfo: - err = GetLastError(); - SetupDiDestroyDeviceInfoList(hDevInfo); - SetLastError(err); - - return succeeded; -} - -bool devcon::enable_disable_bth_usb_device(bool state) -{ - DWORD i, err; - bool found = false, succeeded = false; - - HDEVINFO hDevInfo; - SP_DEVINFO_DATA spDevInfoData; - - hDevInfo = SetupDiGetClassDevs( - &GUID_DEVCLASS_BLUETOOTH, - nullptr, - nullptr, - DIGCF_PRESENT - ); - if (hDevInfo == INVALID_HANDLE_VALUE) - { - return succeeded; - } - - spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); - for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++) - { - DWORD DataT; - LPTSTR p, buffer = nullptr; - DWORD buffersize = 0; - - // get all devices info - while (!SetupDiGetDeviceRegistryProperty(hDevInfo, - &spDevInfoData, - SPDRP_ENUMERATOR_NAME, - &DataT, - (PBYTE)buffer, - buffersize, - &buffersize)) - { - if (GetLastError() == ERROR_INVALID_DATA) - { - break; - } - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - if (buffer) - LocalFree(buffer); - buffer = static_cast(LocalAlloc(LPTR, buffersize)); - } - else - { - goto cleanup_DeviceInfo; - } - } - - if (GetLastError() == ERROR_INVALID_DATA) - continue; - - //find device with enumerator name "USB" - for (p = buffer; *p && (p < &buffer[buffersize]); p += lstrlen(p) + sizeof(TCHAR)) - { - if (!_tcscmp(TEXT("USB"), p)) - { - found = true; - break; - } - } - - if (buffer) - LocalFree(buffer); - - // if device found change it's state - if (found) - { - SP_PROPCHANGE_PARAMS params; - - params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); - params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; - params.Scope = DICS_FLAG_GLOBAL; - params.StateChange = (state) ? DICS_ENABLE : DICS_DISABLE; - - // setup proper parameters - if (!SetupDiSetClassInstallParams(hDevInfo, &spDevInfoData, ¶ms.ClassInstallHeader, sizeof(params))) - { - err = GetLastError(); - } - else - { - // use parameters - if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, &spDevInfoData)) - { - err = GetLastError(); // error here - } - else { succeeded = true; } - } - - break; - } - } - -cleanup_DeviceInfo: - err = GetLastError(); - SetupDiDestroyDeviceInfoList(hDevInfo); - SetLastError(err); - - return succeeded; -} - -bool devcon::install_driver(const std::wstring& fullInfPath, bool* rebootRequired) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - - Newdev newdev; - BOOL reboot; - - if (!newdev.pDiInstallDriverW) - { - logger->error("Couldn't find DiInstallDriverW export"); - SetLastError(ERROR_INVALID_FUNCTION); - return false; - } - - logger->verbose(1, "Invoking DiInstallDriverW"); - - const auto ret = newdev.pDiInstallDriverW( - nullptr, - fullInfPath.c_str(), - DIIRFLAG_FORCE_INF, - &reboot - ); - - logger->verbose(1, "DiInstallDriverW returned %v, reboot required: %v", ret, reboot); - - if (rebootRequired) - *rebootRequired = reboot > 0; - - return ret > 0; -} - -bool devcon::uninstall_driver(const std::wstring& fullInfPath, bool* rebootRequired) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - - Newdev newdev; - BOOL reboot; - - if (!newdev.pDiUninstallDriverW) - { - logger->error("Couldn't find DiUninstallDriverW export"); - SetLastError(ERROR_INVALID_FUNCTION); - return false; - } - - logger->verbose(1, "Invoking DiUninstallDriverW"); - - const auto ret = newdev.pDiUninstallDriverW( - nullptr, - fullInfPath.c_str(), - 0, - &reboot - ); - - logger->verbose(1, "DiUninstallDriverW returned %v, reboot required: %v", ret, reboot); - - if (rebootRequired) - *rebootRequired = reboot > 0; - - return ret > 0; -} - -bool devcon::add_device_class_filter(const GUID* classGuid, const std::wstring& filterName, - DeviceClassFilterPosition::Value position) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - auto key = SetupDiOpenClassRegKey(classGuid, KEY_ALL_ACCESS); - - if (INVALID_HANDLE_VALUE == key) - { - logger->error("SetupDiOpenClassRegKey failed with error code %v", GetLastError()); - return false; - } - - LPCWSTR filterValue = (position == DeviceClassFilterPosition::Lower) ? L"LowerFilters" : L"UpperFilters"; - DWORD type, size; - std::vector filters; - - auto status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - nullptr, - &size - ); - - // - // Value exists already, read it with returned buffer size - // - if (status == ERROR_SUCCESS) - { - std::vector temp(size / sizeof(wchar_t)); - - status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - reinterpret_cast(&temp[0]), - &size - ); - - if (status != ERROR_SUCCESS) - { - logger->error("RegQueryValueExW failed with status %v", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - size_t index = 0; - size_t len = wcslen(&temp[0]); - while (len > 0) - { - filters.emplace_back(&temp[index]); - index += len + 1; - len = wcslen(&temp[index]); - } - - // - // Filter not there yet, add - // - if (std::find(filters.begin(), filters.end(), filterName) == filters.end()) - { - filters.emplace_back(filterName); - } - - const std::vector multiString = BuildMultiString(filters); - - const DWORD dataSize = static_cast(multiString.size() * sizeof(wchar_t)); - - status = RegSetValueExW( - key, - filterValue, - 0, // reserved - REG_MULTI_SZ, - reinterpret_cast(&multiString[0]), - dataSize - ); - - if (status != ERROR_SUCCESS) - { - logger->error("RegSetValueExW failed with status %v", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - RegCloseKey(key); - return true; - } - // - // Value doesn't exist, create and populate - // - if (status == ERROR_FILE_NOT_FOUND) - { - filters.emplace_back(filterName); - - const std::vector multiString = BuildMultiString(filters); - - const DWORD dataSize = static_cast(multiString.size() * sizeof(wchar_t)); - - status = RegSetValueExW( - key, - filterValue, - 0, // reserved - REG_MULTI_SZ, - reinterpret_cast(&multiString[0]), - dataSize - ); - - if (status != ERROR_SUCCESS) - { - logger->error("RegSetValueExW failed with status %v", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - RegCloseKey(key); - return true; - } - - RegCloseKey(key); - return false; -} - -bool devcon::remove_device_class_filter(const GUID* classGuid, const std::wstring& filterName, - DeviceClassFilterPosition::Value position) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - auto key = SetupDiOpenClassRegKey(classGuid, KEY_ALL_ACCESS); - - if (INVALID_HANDLE_VALUE == key) - { - logger->error("SetupDiOpenClassRegKey failed with error code %v", GetLastError()); - return false; - } - - LPCWSTR filterValue = (position == DeviceClassFilterPosition::Lower) ? L"LowerFilters" : L"UpperFilters"; - DWORD type, size; - std::vector filters; - - auto status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - nullptr, - &size - ); - - // - // Value exists already, read it with returned buffer size - // - if (status == ERROR_SUCCESS) - { - std::vector temp(size / sizeof(wchar_t)); - - status = RegQueryValueExW( - key, - filterValue, - nullptr, - &type, - reinterpret_cast(&temp[0]), - &size - ); - - if (status != ERROR_SUCCESS) - { - logger->error("RegQueryValueExW failed with status %v", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - // - // Remove value, if found - // - size_t index = 0; - size_t len = wcslen(&temp[0]); - while (len > 0) - { - if (filterName != &temp[index]) - { - filters.emplace_back(&temp[index]); - } - index += len + 1; - len = wcslen(&temp[index]); - } - - const std::vector multiString = BuildMultiString(filters); - - const DWORD dataSize = static_cast(multiString.size() * sizeof(wchar_t)); - - status = RegSetValueExW( - key, - filterValue, - 0, // reserved - REG_MULTI_SZ, - reinterpret_cast(&multiString[0]), - dataSize - ); - - if (status != ERROR_SUCCESS) - { - logger->error("RegSetValueExW failed with status %v", status); - RegCloseKey(key); - SetLastError(status); - return false; - } - - RegCloseKey(key); - return true; - } - // - // Value doesn't exist, return - // - if (status == ERROR_FILE_NOT_FOUND) - { - RegCloseKey(key); - return true; - } - - RegCloseKey(key); - return false; -} - -inline bool uninstall_device_and_driver(HDEVINFO hDevInfo, PSP_DEVINFO_DATA spDevInfoData, bool* rebootRequired) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - BOOL drvNeedsReboot = FALSE, devNeedsReboot = FALSE; - DWORD requiredBufferSize = 0; - DWORD err = ERROR_SUCCESS; - bool ret = false; - - Newdev newdev; - - if (!newdev.pDiUninstallDevice || !newdev.pDiUninstallDriverW) - { - logger->error("Couldn't get DiUninstallDevice or DiUninstallDriverW function exports"); - SetLastError(ERROR_INVALID_FUNCTION); - return false; - } - - SP_DRVINFO_DATA_W drvInfoData; - drvInfoData.cbSize = sizeof(drvInfoData); - - PSP_DRVINFO_DETAIL_DATA_W pDrvInfoDetailData = nullptr; - - do - { - logger->verbose(1, "Enumerating"); - - // - // Start building driver info - // - if (!SetupDiBuildDriverInfoList( - hDevInfo, - spDevInfoData, - SPDIT_COMPATDRIVER - )) - { - err = GetLastError(); - logger->error("SetupDiBuildDriverInfoList failed, error code: %v", err); - break; - } - - if (!SetupDiEnumDriverInfo( - hDevInfo, - spDevInfoData, - SPDIT_COMPATDRIVER, - 0, // One result expected - &drvInfoData - )) - { - err = GetLastError(); - logger->error("SetupDiEnumDriverInfo failed, error code: %v", err); - break; - } - - // - // Details will contain the INF path to driver store copy - // - SP_DRVINFO_DETAIL_DATA_W drvInfoDetailData; - drvInfoDetailData.cbSize = sizeof(drvInfoDetailData); - - // - // Request required buffer size - // - (void)SetupDiGetDriverInfoDetail( - hDevInfo, - spDevInfoData, - &drvInfoData, - &drvInfoDetailData, - drvInfoDetailData.cbSize, - &requiredBufferSize - ); - - if (requiredBufferSize == 0) - { - err = GetLastError(); - logger->error("SetupDiGetDriverInfoDetail (size) failed, error code: %v", err); - break; - } - - // - // Allocate required amount - // - pDrvInfoDetailData = static_cast(malloc(requiredBufferSize)); - - if (pDrvInfoDetailData == nullptr) - { - logger->error("Out of memory"); - err = ERROR_INSUFFICIENT_BUFFER; - break; - } - - pDrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W); - - // - // Query full driver details - // - if (!SetupDiGetDriverInfoDetail( - hDevInfo, - spDevInfoData, - &drvInfoData, - pDrvInfoDetailData, - requiredBufferSize, - nullptr - )) - { - err = GetLastError(); - logger->error("SetupDiGetDriverInfoDetail (payload) failed, error code: %v", err); - break; - } - - // - // Remove device - // - if (!newdev.pDiUninstallDevice( - nullptr, - hDevInfo, - spDevInfoData, - 0, - &devNeedsReboot - )) - { - err = GetLastError(); - logger->error("DiUninstallDevice failed, error code: %v", err); - break; - } - - // - // Uninstall from driver store - // - if (!newdev.pDiUninstallDriverW( - nullptr, - pDrvInfoDetailData->InfFileName, - 0, - &drvNeedsReboot - )) - { - err = GetLastError(); - logger->error("DiUninstallDriverW failed, error code: %v", err); - break; - } - - *rebootRequired = (drvNeedsReboot > 0) || (devNeedsReboot > 0); - ret = true; - - logger->verbose(1, "Reboot required: %v", *rebootRequired); - } while (FALSE); - - if (pDrvInfoDetailData) - free(pDrvInfoDetailData); - - (void)SetupDiDestroyDriverInfoList( - hDevInfo, - spDevInfoData, - SPDIT_COMPATDRIVER - ); - - SetLastError(err); - - logger->verbose(1, "Freed memory, returning with %v and error code %v", ret, err); - - return ret; -} - -static PWSTR wstristr(PCWSTR haystack, PCWSTR needle) -{ - do - { - PCWSTR h = haystack; - PCWSTR n = needle; - while (towlower(*h) == towlower(*n) && *n) - { - h++; - n++; - } - if (*n == 0) - { - return (PWSTR)haystack; - } - } while (*haystack++); - return nullptr; -} - -bool devcon::uninstall_device_and_driver(const GUID* classGuid, const std::wstring& hardwareId, bool* rebootRequired) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - DWORD err = ERROR_SUCCESS; - bool succeeded = false; - - HDEVINFO hDevInfo; - SP_DEVINFO_DATA spDevInfoData; - - hDevInfo = SetupDiGetClassDevs( - classGuid, - nullptr, - nullptr, - DIGCF_PRESENT - ); - if (hDevInfo == INVALID_HANDLE_VALUE) - { - logger->error("SetupDiGetClassDevs failed, error code: %v", GetLastError()); - return succeeded; - } - - spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); - - for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++) - { - logger->verbose(1, "SetupDiEnumDeviceInfo with index %v", i); - - DWORD DataT; - LPWSTR p, buffer = nullptr; - DWORD buffersize = 0; - - // get all devices info - while (!SetupDiGetDeviceRegistryProperty(hDevInfo, - &spDevInfoData, - SPDRP_HARDWAREID, - &DataT, - reinterpret_cast(buffer), - buffersize, - &buffersize)) - { - if (GetLastError() == ERROR_INVALID_DATA) - { - logger->verbose(1, "SetupDiGetDeviceRegistryProperty returned ERROR_INVALID_DATA"); - break; - } - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - logger->verbose(1, "(Re-)allocating property buffer, bytes: %v", buffersize); - if (buffer) - LocalFree(buffer); - buffer = static_cast(LocalAlloc(LPTR, buffersize)); - } - else - { - logger->error("Unexpected error during SetupDiGetDeviceRegistryProperty: %v", GetLastError()); - goto cleanup_DeviceInfo; - } - } - - if (GetLastError() == ERROR_INVALID_DATA) - { - logger->verbose(1, "SetupDiGetDeviceRegistryProperty returned ERROR_INVALID_DATA"); - continue; - } - - logger->verbose(1, "Got Hardware ID property, starting enumeration"); - - // - // find device matching hardware ID - // - for (p = buffer; p && *p && (p < &buffer[buffersize]); p += lstrlenW(p) + sizeof(TCHAR)) - { - logger->verbose(1, "Enumerating ID: %v", std::wstring(p)); - - if (wstristr(p, hardwareId.c_str())) - { - logger->verbose(1, "Found match against %v, attempting removal", hardwareId); - - succeeded = ::uninstall_device_and_driver(hDevInfo, &spDevInfoData, rebootRequired); - err = GetLastError(); - logger->verbose(1, "Removal response: %v, error code: %v", succeeded, err); - break; - } - } - - logger->verbose(1, "Done enumerating Hardware IDs"); - - if (buffer) - LocalFree(buffer); - } - -cleanup_DeviceInfo: - err = GetLastError(); - SetupDiDestroyDeviceInfoList(hDevInfo); - SetLastError(err); - - logger->verbose(1, "Freed memory and returning with status: %v", succeeded); - - return succeeded; -} - -bool devcon::inf_default_install(const std::wstring& fullInfPath, bool* rebootRequired) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - uint32_t errCode = ERROR_SUCCESS; - SYSTEM_INFO sysInfo; - auto hInf = INVALID_HANDLE_VALUE; - WCHAR InfSectionWithExt[255]; - WCHAR pszDest[280]; - BOOLEAN defaultSection = FALSE; - - GetNativeSystemInfo(&sysInfo); - - hInf = SetupOpenInfFileW(fullInfPath.c_str(), nullptr, INF_STYLE_WIN4, nullptr); - - do - { - if (hInf == INVALID_HANDLE_VALUE) - { - errCode = GetLastError(); - logger->error("SetupOpenInfFileW failed with error code %v", errCode); - break; - } - - if (SetupDiGetActualSectionToInstallW( - hInf, - L"DefaultInstall", - InfSectionWithExt, - 0xFFu, - reinterpret_cast(&sysInfo.lpMinimumApplicationAddress), - nullptr) - && SetupFindFirstLineW(hInf, InfSectionWithExt, nullptr, - reinterpret_cast(&sysInfo.lpMaximumApplicationAddress))) - { - logger->verbose(1, "DefaultInstall section found"); - defaultSection = TRUE; - - if (StringCchPrintfW(pszDest, 280ui64, L"DefaultInstall 132 %ws", fullInfPath.c_str()) < 0) - { - errCode = GetLastError(); - logger->error("StringCchPrintfW failed with error code %v", errCode); - break; - } - - logger->verbose(1, "Calling InstallHinfSectionW"); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - DetourAttach((void**)&real_MessageBoxW, DetourMessageBoxW); - DetourAttach((void**)&real_RestartDialogEx, DetourRestartDialogEx); - DetourTransactionCommit(); - - g_MbCalled = FALSE; - g_RestartDialogExCalled = FALSE; - - InstallHinfSectionW(nullptr, nullptr, pszDest, 0); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - DetourDetach((void**)&real_MessageBoxW, DetourMessageBoxW); - DetourDetach((void**)&real_RestartDialogEx, DetourRestartDialogEx); - DetourTransactionCommit(); - - logger->verbose(1, "InstallHinfSectionW finished"); - - // - // If a message box call was intercepted, we encountered an error - // - if (g_MbCalled) - { - logger->error( - "The installation encountered an error, make sure there's no reboot pending and try again afterwards"); - g_MbCalled = FALSE; - errCode = ERROR_PNP_REBOOT_REQUIRED; - break; - } - } - - if (!SetupFindFirstLineW(hInf, L"Manufacturer", nullptr, - reinterpret_cast(&sysInfo.lpMaximumApplicationAddress))) - { - logger->verbose(1, "No Manufacturer section found"); - - if (!defaultSection) - { - logger->error("No DefaultInstall and no Manufacturer section, can't continue"); - errCode = ERROR_SECTION_NOT_FOUND; - break; - } - } - - Newdev newdev; - BOOL reboot = FALSE; - - if (!newdev.pDiInstallDriverW) - { - logger->error("Couldn't find DiInstallDriverW export"); - SetLastError(ERROR_INVALID_FUNCTION); - return false; - } - - logger->verbose(1, "Invoking DiInstallDriverW"); - - const auto ret = newdev.pDiInstallDriverW( - nullptr, - fullInfPath.c_str(), - 0, - &reboot - ); - - logger->verbose(1, "DiInstallDriverW returned with %v, reboot required: %v", ret, reboot); - - if (rebootRequired) - { - *rebootRequired = reboot > 0 || g_RestartDialogExCalled; - logger->verbose(1, "Set rebootRequired to: %v", *rebootRequired); - } - } while (FALSE); - - if (hInf != INVALID_HANDLE_VALUE) - { - SetupCloseInfFile(hInf); - } - - logger->verbose(1, "Returning with error code %v", errCode); - - SetLastError(errCode); - return errCode == ERROR_SUCCESS; -} - -bool devcon::inf_default_uninstall(const std::wstring& fullInfPath, bool* rebootRequired) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - uint32_t errCode = ERROR_SUCCESS; - SYSTEM_INFO sysInfo; - auto hInf = INVALID_HANDLE_VALUE; - WCHAR InfSectionWithExt[255]; - WCHAR pszDest[280]; - - GetNativeSystemInfo(&sysInfo); - - hInf = SetupOpenInfFileW(fullInfPath.c_str(), nullptr, INF_STYLE_WIN4, nullptr); - - do - { - if (hInf == INVALID_HANDLE_VALUE) - { - errCode = GetLastError(); - logger->error("SetupOpenInfFileW failed with error code %v", errCode); - break; - } - - if (SetupDiGetActualSectionToInstallW( - hInf, - L"DefaultUninstall", - InfSectionWithExt, - 0xFFu, - reinterpret_cast(&sysInfo.lpMinimumApplicationAddress), - nullptr) - && SetupFindFirstLineW(hInf, InfSectionWithExt, nullptr, - reinterpret_cast(&sysInfo.lpMaximumApplicationAddress))) - { - if (StringCchPrintfW(pszDest, 280ui64, L"DefaultUninstall 132 %ws", fullInfPath.c_str()) < 0) - { - errCode = GetLastError(); - logger->error("StringCchPrintfW failed with error code %v", errCode); - break; - } - - logger->verbose(1, "Calling InstallHinfSectionW"); - - g_RestartDialogExCalled = FALSE; - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - DetourAttach((void**)&real_RestartDialogEx, DetourRestartDialogEx); - DetourTransactionCommit(); - - InstallHinfSectionW(nullptr, nullptr, pszDest, 0); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - DetourDetach((void**)&real_RestartDialogEx, DetourRestartDialogEx); - DetourTransactionCommit(); - - logger->verbose(1, "InstallHinfSectionW finished"); - - if (rebootRequired) - { - *rebootRequired = g_RestartDialogExCalled; - logger->verbose(1, "Set rebootRequired to: %v", *rebootRequired); - } - } - else - { - logger->error("No DefaultUninstall section found"); - errCode = ERROR_SECTION_NOT_FOUND; - } - } while (FALSE); - - if (hInf != INVALID_HANDLE_VALUE) - { - SetupCloseInfFile(hInf); - } - - logger->verbose(1, "Returning with error code %v", errCode); - - SetLastError(errCode); - return errCode == ERROR_SUCCESS; -} - -bool devcon::find_by_hwid(const std::wstring& matchstring) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - bool found = FALSE; - DWORD err, total = 0; - SP_DEVINFO_DATA spDevInfoData; - - DWORD DataT; - LPTSTR buffer = nullptr; - DWORD buffersize = 0; - - const HDEVINFO hDevInfo = SetupDiGetClassDevs( - nullptr, - nullptr, - nullptr, - DIGCF_ALLCLASSES | DIGCF_PRESENT - ); - if (hDevInfo == INVALID_HANDLE_VALUE) - { - return found; - } - - spDevInfoData.cbSize = sizeof(spDevInfoData); - - for (DWORD devIndex = 0; SetupDiEnumDeviceInfo(hDevInfo, devIndex, &spDevInfoData); devIndex++) - { - // get all devices info - while (!SetupDiGetDeviceRegistryProperty(hDevInfo, - &spDevInfoData, - SPDRP_HARDWAREID, - &DataT, - (PBYTE)buffer, - buffersize, - &buffersize)) - { - if (GetLastError() == ERROR_INVALID_DATA) - { - break; - } - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - if (buffer) - LocalFree(buffer); - buffer = static_cast(LocalAlloc(LPTR, buffersize)); - } - else - { - goto cleanup_DeviceInfo; - } - } - if (GetLastError() == ERROR_INVALID_DATA) - continue; - - std::vector entries; - const TCHAR* p = buffer; - - while (*p) - { - entries.emplace_back(p); - p += _tcslen(p) + 1; - } - - bool foundMatch = FALSE; - - for (auto& i : entries) - { - if (i.find(matchstring) != std::wstring::npos) { - foundMatch = TRUE; - break; - } - } - - // If we have a match, print out the whole array - if (foundMatch) - { - found = TRUE; - total++; - - std::wstring idValue = std::accumulate(std::begin(entries), std::end(entries), std::wstring(), - [](const std::wstring& ss, const std::wstring& s) - { - return ss.empty() ? s : ss + L", " + s; - }); - - logger->info("Hardware IDs: %v", idValue); - - while (!SetupDiGetDeviceRegistryProperty(hDevInfo, - &spDevInfoData, - SPDRP_DEVICEDESC, - &DataT, - (PBYTE)buffer, - buffersize, - &buffersize)) - { - if (GetLastError() == ERROR_INVALID_DATA) - { - break; - } - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - if (buffer) - LocalFree(buffer); - buffer = static_cast(LocalAlloc(LPTR, buffersize)); - } - else - { - goto cleanup_DeviceInfo; - } - } - if (GetLastError() == ERROR_INVALID_DATA) - { - // Lets try SPDRP_DEVICEDESC - while (!SetupDiGetDeviceRegistryProperty(hDevInfo, - &spDevInfoData, - SPDRP_FRIENDLYNAME, - &DataT, - (PBYTE)buffer, - buffersize, - &buffersize)) - { - if (GetLastError() == ERROR_INVALID_DATA) - { - break; - } - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - if (buffer) - LocalFree(buffer); - buffer = static_cast(LocalAlloc(LPTR, buffersize)); - } - else - { - goto cleanup_DeviceInfo; - } - } - if (GetLastError() != ERROR_INVALID_DATA) - { - logger->info("Name: %v", std::wstring(buffer)); - } - } - else - { - logger->info("Name: %v", std::wstring(buffer)); - } - - // Build a list of driver info items that we will retrieve below - if (!SetupDiBuildDriverInfoList(hDevInfo, &spDevInfoData, SPDIT_COMPATDRIVER)) - { - goto cleanup_DeviceInfo; - } - - // Get the first info item for this driver - SP_DRVINFO_DATA drvInfo; - drvInfo.cbSize = sizeof(SP_DRVINFO_DATA); - - if (!SetupDiEnumDriverInfo(hDevInfo, &spDevInfoData, SPDIT_COMPATDRIVER, 0, &drvInfo)) - { - goto cleanup_DeviceInfo; // Still fails with "no more items" - } - - logger->info("Version: %v.%v.%v.%v", std::to_wstring((drvInfo.DriverVersion >> 48) & 0xFFFF), - std::to_wstring((drvInfo.DriverVersion >> 32) & 0xFFFF), - std::to_wstring((drvInfo.DriverVersion >> 16) & 0xFFFF), - std::to_wstring(drvInfo.DriverVersion & 0x0000FFFF)); - } - } - -cleanup_DeviceInfo: - err = GetLastError(); - SetupDiDestroyDeviceInfoList(hDevInfo); - SetLastError(err); - logger->verbose(1, "Total Found:: %v", std::to_wstring(total)); - return found; -} - - -// -// Hooks MessageBoxW which is called if an error occurred, even when instructed to suppress any UI interaction -// -int DetourMessageBoxW( - HWND hWnd, - LPCWSTR lpText, - LPCWSTR lpCaption, - UINT uType -) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - - UNREFERENCED_PARAMETER(hWnd); - UNREFERENCED_PARAMETER(lpCaption); - UNREFERENCED_PARAMETER(uType); - - logger->verbose(1, "DetourMessageBoxW called with message: %v", std::wstring(lpText)); - logger->verbose(1, "GetLastError: %v", GetLastError()); - - g_MbCalled = TRUE; - - return IDOK; -} - -// -// Hooks RestartDialogEx which is called if a reboot is required, even when instructed to suppress any UI interaction -// -int DetourRestartDialogEx( - HWND hwnd, - PCWSTR pszPrompt, - DWORD dwReturn, - DWORD dwReasonCode -) -{ - el::Logger* logger = el::Loggers::getLogger("default"); - - UNREFERENCED_PARAMETER(hwnd); - UNREFERENCED_PARAMETER(pszPrompt); - - logger->verbose(1, "DetourRestartDialogEx called"); - logger->verbose(1, "GetLastError: %v", GetLastError()); - logger->verbose(1, "DetourRestartDialogEx - dwReturn: %v", dwReturn); - logger->verbose(1, "DetourRestartDialogEx - dwReasonCode: %v", dwReasonCode); - - /* for debugging - - const int result = real_RestartDialogEx(hwnd, pszPrompt, dwReturn, dwReasonCode); - - logger->verbose(1, "RestartDialogEx returned: %v", result); - */ - - g_RestartDialogExCalled = TRUE; - - return IDCANCEL; // equivalent to the user clicking "Restart Later" -} diff --git a/src/Devcon.h b/src/Devcon.h deleted file mode 100644 index b43b77f..0000000 --- a/src/Devcon.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include - -namespace devcon -{ - struct DeviceClassFilterPosition - { - enum Value - { - Upper, - Lower - }; - }; - - bool create(const std::wstring& className, const GUID* classGuid, const std::wstring& hardwareId); - - bool restart_bth_usb_device(); - - bool enable_disable_bth_usb_device(bool state); - - bool install_driver(const std::wstring& fullInfPath, bool* rebootRequired); - - bool uninstall_driver(const std::wstring& fullInfPath, bool* rebootRequired); - - bool add_device_class_filter(const GUID* classGuid, const std::wstring& filterName, DeviceClassFilterPosition::Value position); - - bool remove_device_class_filter(const GUID* classGuid, const std::wstring& filterName, DeviceClassFilterPosition::Value position); - - bool uninstall_device_and_driver(const GUID* classGuid, const std::wstring& hardwareId, bool* rebootRequired); - - bool inf_default_install(const std::wstring& fullInfPath, bool* rebootRequired); - - bool inf_default_uninstall(const std::wstring& fullInfPath, bool* rebootRequired); - - bool find_by_hwid(const std::wstring& matchstring); -}; diff --git a/src/LibraryHelper.hpp b/src/LibraryHelper.hpp deleted file mode 100644 index fc665e3..0000000 --- a/src/LibraryHelper.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include - -#include - -class ProcPtr { -public: - explicit ProcPtr(FARPROC ptr) : _ptr(ptr) {} - - template >> - operator T* () const { - return reinterpret_cast(_ptr); - } - -private: - FARPROC _ptr; -}; - -class DllHelper { -public: - explicit DllHelper(LPCTSTR filename) : _module(LoadLibrary(filename)) {} - - ~DllHelper() { FreeLibrary(_module); } - - ProcPtr operator[](LPCSTR proc_name) const { - return ProcPtr(GetProcAddress(_module, proc_name)); - } - - static HMODULE _parent_module; - -private: - HMODULE _module; -}; - - -class Newdev { - DllHelper _dll{ L"Newdev.dll" }; - -public: - decltype(DiUninstallDriverW)* pDiUninstallDriverW = _dll["DiUninstallDriverW"]; - decltype(DiInstallDriverW)* pDiInstallDriverW = _dll["DiInstallDriverW"]; - decltype(DiUninstallDevice)* pDiUninstallDevice = _dll["DiUninstallDevice"]; -}; - diff --git a/src/NefConSetup.cpp b/src/NefConSetup.cpp deleted file mode 100644 index 1e5e772..0000000 --- a/src/NefConSetup.cpp +++ /dev/null @@ -1,400 +0,0 @@ -#include "NefConSetup.h" - -BOOL winapi::AdjustProcessPrivileges() -{ - HANDLE procToken; - LUID luid; - TOKEN_PRIVILEGES tp; - BOOL bRetVal; - DWORD err; - - bRetVal = OpenProcessToken( - GetCurrentProcess(), - TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, - &procToken - ); - - if (!bRetVal) - { - err = GetLastError(); - goto exit; - } - - bRetVal = LookupPrivilegeValue(nullptr, SE_LOAD_DRIVER_NAME, &luid); - if (!bRetVal) - { - err = GetLastError(); - goto exit1; - } - - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - // - // AdjustTokenPrivileges can succeed even when privileges are not adjusted. - // In such case GetLastError returns ERROR_NOT_ALL_ASSIGNED. - // - // Hence we check for GetLastError in both success and failure case. - // - - (void)AdjustTokenPrivileges( - procToken, - FALSE, - &tp, - sizeof(TOKEN_PRIVILEGES), - nullptr, - nullptr - ); - err = GetLastError(); - - if (err != ERROR_SUCCESS) - { - bRetVal = FALSE; - } - -exit1: - CloseHandle(procToken); -exit: - return bRetVal; -} - -BOOL winapi::CreateDriverService(PCSTR ServiceName, PCSTR DisplayName, PCSTR BinaryPath) -{ - SC_HANDLE hSCManager; - SC_HANDLE hService; - - hSCManager = OpenSCManagerA( - nullptr, - nullptr, - SC_MANAGER_CREATE_SERVICE - ); - - if (!hSCManager) - { - return FALSE; - } - - hService = CreateServiceA( - hSCManager, - ServiceName, - DisplayName, - SERVICE_START | DELETE | SERVICE_STOP, - SERVICE_KERNEL_DRIVER, - SERVICE_DEMAND_START, - SERVICE_ERROR_IGNORE, - BinaryPath, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr - ); - - if (!hService) - { - CloseServiceHandle(hSCManager); - return FALSE; - } - - CloseServiceHandle(hService); - CloseServiceHandle(hSCManager); - - return TRUE; -} - -BOOL winapi::DeleteDriverService(PCSTR ServiceName) -{ - SC_HANDLE hSCManager; - SC_HANDLE hService; - BOOL ret; - - hSCManager = OpenSCManagerA( - nullptr, - nullptr, - SC_MANAGER_CREATE_SERVICE - ); - - if (!hSCManager) - { - return FALSE; - } - - hService = OpenServiceA( - hSCManager, - ServiceName, - SERVICE_START | DELETE | SERVICE_STOP - ); - - if (!hService) - { - CloseServiceHandle(hSCManager); - return FALSE; - } - - ret = DeleteService(hService); - - CloseServiceHandle(hService); - CloseServiceHandle(hSCManager); - - return ret; -} - -std::string winapi::GetLastErrorStdStr(DWORD errorCode) -{ - DWORD error = (errorCode == ERROR_SUCCESS) ? GetLastError() : errorCode; - if (error) - { - LPVOID lpMsgBuf; - DWORD bufLen = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&lpMsgBuf, - 0, nullptr); - if (bufLen) - { - auto lpMsgStr = static_cast(lpMsgBuf); - std::string result(lpMsgStr, lpMsgStr + bufLen); - - LocalFree(lpMsgBuf); - - return result; - } - } - return std::string("LEER"); -} - -std::string winapi::GetVersionFromFile(std::string FilePath) -{ - DWORD verHandle = 0; - UINT size = 0; - LPBYTE lpBuffer = nullptr; - DWORD verSize = GetFileVersionInfoSizeA(FilePath.c_str(), &verHandle); - std::stringstream versionString; - - if (verSize != NULL) - { - auto verData = new char[verSize]; - - if (GetFileVersionInfoA(FilePath.c_str(), verHandle, verSize, verData)) - { - if (VerQueryValueA(verData, "\\", (VOID FAR * FAR*)&lpBuffer, &size)) - { - if (size) - { - auto* verInfo = (VS_FIXEDFILEINFO*)lpBuffer; - if (verInfo->dwSignature == 0xfeef04bd) - { - versionString - << static_cast(HIWORD(verInfo->dwProductVersionMS)) << "." - << static_cast(LOWORD(verInfo->dwProductVersionMS)) << "." - << static_cast(HIWORD(verInfo->dwProductVersionLS)); - } - } - } - } - delete[] verData; - } - - return versionString.str(); -} - -std::string winapi::GetImageBasePath() -{ - char myPath[MAX_PATH + 1] = {0}; - - GetModuleFileNameA( - reinterpret_cast(&__ImageBase), - myPath, - MAX_PATH + 1 - ); - - return std::string(myPath); -} - -DWORD winapi::IsAppRunningAsAdminMode(PBOOL IsAdmin) -{ - DWORD dwError = ERROR_SUCCESS; - PSID pAdministratorsGroup = nullptr; - - // Allocate and initialize a SID of the administrators group. - SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; - if (!AllocateAndInitializeSid( - &NtAuthority, - 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &pAdministratorsGroup)) - { - dwError = GetLastError(); - goto Cleanup; - } - - // Determine whether the SID of administrators group is enabled in - // the primary access token of the process. - if (!CheckTokenMembership(nullptr, pAdministratorsGroup, IsAdmin)) - { - dwError = GetLastError(); - } - -Cleanup: - // Centralized cleanup for all allocated resources. - if (pAdministratorsGroup) - { - FreeSid(pAdministratorsGroup); - pAdministratorsGroup = nullptr; - } - - return dwError; -} - -BOOL winapi::GetLogonSID(HANDLE hToken, PSID* ppsid) -{ - BOOL bSuccess = FALSE; - DWORD dwLength = 0; - PTOKEN_GROUPS ptg = nullptr; - - // Get required buffer size and allocate the TOKEN_GROUPS buffer. - GetTokenInformation(hToken, TokenGroups, ptg, 0, &dwLength); - - ptg = static_cast(HeapAlloc( - GetProcessHeap(), - HEAP_ZERO_MEMORY, - dwLength - )); - - // Get the token group information from the access token. - GetTokenInformation(hToken, TokenGroups, ptg, dwLength, &dwLength); - - // Loop through the groups to find the logon SID. - for (DWORD dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) - { - if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) - == SE_GROUP_LOGON_ID) - { - // Found the logon SID; make a copy of it. - - dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid); - *ppsid = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, dwLength); - CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid); - - break; - } - } - - return TRUE; -} - -BOOL winapi::TakeFileOwnership(el::Logger* logger, LPCWSTR file) -{ - HANDLE token; - DWORD len; - PSECURITY_DESCRIPTOR security = nullptr; - PSID sid = nullptr; - BOOL ret = FALSE; - - do - { - // Get the privileges you need - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) - { - if (!SetPrivilege(L"SeTakeOwnershipPrivilege", 1)) - { - logger->error("SeTakeOwnershipPrivilege failed, error: %v", - GetLastErrorStdStr()); - break; - } - if (!SetPrivilege(L"SeSecurityPrivilege", 1)) - { - logger->error("SeSecurityPrivilege failed, error: %v", - GetLastErrorStdStr()); - break; - } - if (!SetPrivilege(L"SeBackupPrivilege", 1)) - { - logger->error("SeBackupPrivilege failed, error: %v", - GetLastErrorStdStr()); - break; - } - if (!SetPrivilege(L"SeRestorePrivilege", 1)) - { - logger->error("SeRestorePrivilege failed, error: %v", - GetLastErrorStdStr()); - break; - } - } - else - { - logger->error("OpenProcessToken failed, error: %v", - GetLastErrorStdStr()); - break; - } - - // Create the security descriptor - GetFileSecurity(file, OWNER_SECURITY_INFORMATION, security, 0, &len); - - security = malloc(len); - - if (!InitializeSecurityDescriptor(security, SECURITY_DESCRIPTOR_REVISION)) - { - logger->error("InitializeSecurityDescriptor failed, error: %v", - GetLastErrorStdStr()); - break; - } - - // Get the sid for the username - if (!GetLogonSID(token, &sid)) - { - logger->error("GetLogonSID failed, error: %v", - GetLastErrorStdStr()); - break; - } - - // Set the sid to be the new owner - if (sid && !SetSecurityDescriptorOwner(security, sid, 0)) - { - logger->error("SetSecurityDescriptorOwner failed, error: %v", - GetLastErrorStdStr()); - break; - } - - // Save the security descriptor - if (!SetFileSecurity(file, OWNER_SECURITY_INFORMATION, security)) - { - logger->error("SetFileSecurity failed, error: %v", - GetLastErrorStdStr()); - break; - } - - ret = TRUE; - } - while (FALSE); - - if (security) - free(security); - - return ret; -} - -BOOL winapi::SetPrivilege(LPCWSTR privilege, int enable) -{ - TOKEN_PRIVILEGES tp; - LUID luid; - HANDLE token; - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) return FALSE; - if (!LookupPrivilegeValue(nullptr, privilege, &luid)) return FALSE; - - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : FALSE; - - // Enable the privilege or disable all privileges. - return AdjustTokenPrivileges(token, 0, &tp, NULL, nullptr, nullptr); -} diff --git a/src/NefConSetup.h b/src/NefConSetup.h deleted file mode 100644 index a2f48bd..0000000 --- a/src/NefConSetup.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "easylogging++.h" -#include "framework.h" - -EXTERN_C IMAGE_DOS_HEADER __ImageBase; - -namespace winapi -{ - BOOL AdjustProcessPrivileges(); - - BOOL CreateDriverService(PCSTR ServiceName, PCSTR DisplayName, PCSTR BinaryPath); - - BOOL DeleteDriverService(PCSTR ServiceName); - - std::string GetLastErrorStdStr(DWORD errorCode = ERROR_SUCCESS); - - std::string GetVersionFromFile(std::string FilePath); - - std::string GetImageBasePath(); - - DWORD IsAppRunningAsAdminMode(PBOOL IsAdmin); - - BOOL GetLogonSID(HANDLE hToken, PSID *ppsid); - - BOOL TakeFileOwnership(el::Logger* logger, LPCWSTR file); - - BOOL SetPrivilege(LPCWSTR privilege, int enable); -}; diff --git a/src/NefConUtil.cpp b/src/NefConUtil.cpp index aea9a07..1a6ada9 100644 --- a/src/NefConUtil.cpp +++ b/src/NefConUtil.cpp @@ -3,6 +3,10 @@ // ReSharper disable CppClangTidyHicppAvoidGoto #include "NefConUtil.h" +#include + +EXTERN_C IMAGE_DOS_HEADER __ImageBase; + using namespace colorwin; INITIALIZE_EASYLOGGINGPP @@ -14,12 +18,16 @@ INITIALIZE_EASYLOGGINGPP name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +namespace +{ + bool IsAdmin(int& errorCode); -static bool IsAdmin(int& errorCode); - -using GUIDFromString_t = BOOL(WINAPI*)(_In_ LPCSTR, _Out_ LPGUID); + std::string GetImageBasePath(); -static bool GUIDFromString(const std::string& input, GUID* guid); +#if !defined(NEFCON_WINMAIN) + void CustomizeEasyLoggingColoredConsole(); +#endif +} #if defined(NEFCON_WINMAIN) @@ -47,40 +55,82 @@ int main(int argc, char* argv[]) "--file-path" }); -#if defined(NEFCON_WINMAIN) - LPWSTR* szArglist; - int nArgs; - int i; + auto cliArgs = nefarius::winapi::cli::GetCommandLineArgs(); - szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs); - if (nullptr == szArglist) + if (!cliArgs) { - std::cout << color(red) << "CommandLineToArgvW failed" << std::endl; + std::cout << color(red) << cliArgs.error().getErrorMessageA() << '\n'; return EXIT_FAILURE; } - std::vector argv; - std::vector narrow; - - for (i = 0; i < nArgs; i++) - { - narrow.push_back(ConvertWideToANSI(std::wstring(szArglist[i]))); - } - - argv.resize(nArgs); - std::transform(narrow.begin(), narrow.end(), argv.begin(), [](const std::string& arg) { return arg.c_str(); }); - - argv.push_back(nullptr); +#if defined(NEFCON_WINMAIN) + int argc = 0; + auto argv = cliArgs.value().AsArgv(&argc); - START_EASYLOGGINGPP(nArgs, &argv[0]); - cmdl.parse(nArgs, &argv[0]); + START_EASYLOGGINGPP(argc, argv.data()); + cmdl.parse(argc, argv.data()); #else START_EASYLOGGINGPP(argc, argv); + CustomizeEasyLoggingColoredConsole(); cmdl.parse(argv); #endif el::Logger* logger = el::Loggers::getLogger("default"); + const auto arguments = cliArgs.value().Arguments; + +#pragma region Devcon emulation + + // + // Before testing any "regular" arguments, see if the user has used "devcon" tool compatible syntax + // + if (arguments.size() > 3 && arguments[1] == "install") + { + int errorCode; + if (!IsAdmin(errorCode)) return errorCode; + + const std::wstring infFilePath = nefarius::utilities::ConvertToWide(arguments[2]); + const std::wstring hardwareId = nefarius::utilities::ConvertToWide(arguments[3]); + + const auto infClassResult = nefarius::devcon::GetINFClass(infFilePath); + + if (!infClassResult) + { + logger->error("Failed to get class information from INF file, error: %v", + infClassResult.error().getErrorMessageA()); + return infClassResult.error().getErrorCode(); + } + + const auto& infClass = infClassResult.value(); + + if (const auto createResult = nefarius::devcon::Create( + infClass.ClassName, + &infClass.ClassGUID, + nefarius::utilities::WideMultiStringArray(hardwareId)); + !createResult) + { + logger->error("Failed to create device node, error: %v", createResult.error().getErrorMessageA()); + return createResult.error().getErrorCode(); + } + + bool rebootRequired = false; + + if (const auto updateResult = nefarius::devcon::Update(hardwareId, infFilePath, &rebootRequired); !updateResult) + { + logger->error("Failed to update device node(s) with driver, error: %v", + updateResult.error().getErrorMessageA()); + return updateResult.error().getErrorCode(); + } + + logger->info((rebootRequired) + ? "Device and driver installed successfully, but a reboot is required" + : "Device and driver installed successfully" + ); + return (rebootRequired) ? ERROR_SUCCESS_REBOOT_REQUIRED : EXIT_SUCCESS; + } + +#pragma endregion + std::string infPath, binPath, hwId, className, classGuid, serviceName, displayName, position, filePath; #pragma region Filter Driver actions @@ -93,73 +143,59 @@ int main(int argc, char* argv[]) if (!(cmdl({"--position"}) >> position)) { logger->error("Position missing"); - std::cout << color(red) << "Position missing" << std::endl; return EXIT_FAILURE; } if (!(cmdl({"--service-name"}) >> serviceName)) { logger->error("Filter Service Name missing"); - std::cout << color(red) << "Filter Service Name missing" << std::endl; return EXIT_FAILURE; } if (!(cmdl({"--class-guid"}) >> classGuid)) { logger->error("Device Class GUID missing"); - std::cout << color(red) << "Device Class GUID missing" << std::endl; return EXIT_FAILURE; } - GUID clID; + const auto guid = nefarius::winapi::GUIDFromString(classGuid); - if (!GUIDFromString(classGuid, &clID)) + if (!guid) { logger->error( "Device Class GUID format invalid, expected format (with or without brackets): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); - std::cout << color(red) << - "Device Class GUID format invalid, expected format (with or without brackets): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - << std::endl; return EXIT_FAILURE; } - devcon::DeviceClassFilterPosition::Value pos; + nefarius::devcon::DeviceClassFilterPosition pos; if (position == "upper") { logger->verbose(1, "Modifying upper filters"); - pos = devcon::DeviceClassFilterPosition::Upper; + pos = nefarius::devcon::DeviceClassFilterPosition::Upper; } else if (position == "lower") { logger->verbose(1, "Modifying lower filters"); - pos = devcon::DeviceClassFilterPosition::Lower; + pos = nefarius::devcon::DeviceClassFilterPosition::Lower; } else { logger->error("Unsupported position received. Valid values include: upper, lower"); - std::cout << color(red) << "Unsupported position received. Valid values include: upper, lower" << std::endl; return EXIT_FAILURE; } - auto ret = add_device_class_filter(&clID, ConvertAnsiToWide(serviceName), pos); + auto ret = AddDeviceClassFilter(&guid.value(), + nefarius::utilities::ConvertAnsiToWide(serviceName), pos); if (ret) { logger->warn("Filter enabled. Reconnect affected devices or reboot system to apply changes!"); - std::cout << color(yellow) << - "Filter enabled. Reconnect affected devices or reboot system to apply changes!" - << std::endl; - return EXIT_SUCCESS; } - logger->error("Failed to modify filter value, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to modify filter value, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to modify filter value, error: %v", ret.error().getErrorMessageA()); + return ret.error().getErrorCode(); } if (cmdl[{"--remove-class-filter"}]) @@ -170,73 +206,58 @@ int main(int argc, char* argv[]) if (!(cmdl({"--position"}) >> position)) { logger->error("Position missing"); - std::cout << color(red) << "Position missing" << std::endl; return EXIT_FAILURE; } if (!(cmdl({"--service-name"}) >> serviceName)) { logger->error("Filter Service Name missing"); - std::cout << color(red) << "Filter Service Name missing" << std::endl; return EXIT_FAILURE; } if (!(cmdl({"--class-guid"}) >> classGuid)) { logger->error("Device Class GUID missing"); - std::cout << color(red) << "Device Class GUID missing" << std::endl; return EXIT_FAILURE; } - GUID clID; + const auto guid = nefarius::winapi::GUIDFromString(classGuid); - if (!GUIDFromString(classGuid, &clID)) + if (!guid) { logger->error( "Device Class GUID format invalid, expected format (with or without brackets): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); - std::cout << color(red) << - "Device Class GUID format invalid, expected format (with or without brackets): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - << std::endl; return EXIT_FAILURE; } - devcon::DeviceClassFilterPosition::Value pos; + nefarius::devcon::DeviceClassFilterPosition pos; if (position == "upper") { logger->verbose(1, "Modifying upper filters"); - pos = devcon::DeviceClassFilterPosition::Upper; + pos = nefarius::devcon::DeviceClassFilterPosition::Upper; } else if (position == "lower") { logger->verbose(1, "Modifying lower filters"); - pos = devcon::DeviceClassFilterPosition::Lower; + pos = nefarius::devcon::DeviceClassFilterPosition::Lower; } else { logger->error("Unsupported position received. Valid values include: upper, lower"); - std::cout << color(red) << "Unsupported position received. Valid values include: upper, lower" << std::endl; return EXIT_FAILURE; } - auto ret = remove_device_class_filter(&clID, ConvertAnsiToWide(serviceName), pos); + auto ret = RemoveDeviceClassFilter(&guid.value(), nefarius::utilities::ConvertAnsiToWide(serviceName), pos); if (ret) { logger->warn("Filter enabled. Reconnect affected devices or reboot system to apply changes!"); - std::cout << color(yellow) << - "Filter enabled. Reconnect affected devices or reboot system to apply changes!" - << std::endl; - return EXIT_SUCCESS; } - logger->error("Failed to modify filter value, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to modify filter value, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to modify filter value, error: %v", ret.error().getErrorMessageA()); + return ret.error().getErrorCode(); } #pragma endregion @@ -253,14 +274,12 @@ int main(int argc, char* argv[]) if (infPath.empty()) { logger->error("INF path missing"); - std::cout << color(red) << "INF path missing" << std::endl; return EXIT_FAILURE; } if (_access(infPath.c_str(), 0) != 0) { logger->error("The given INF file doesn't exist, is the path correct?"); - std::cout << color(red) << "The given INF file doesn't exist, is the path correct?" << std::endl; return EXIT_FAILURE; } @@ -269,24 +288,19 @@ int main(int argc, char* argv[]) if (attribs & FILE_ATTRIBUTE_DIRECTORY) { logger->error("The given INF path is a directory, not a file"); - std::cout << color(red) << "The given INF path is a directory, not a file" << std::endl; return EXIT_FAILURE; } bool rebootRequired; - if (!devcon::install_driver(ConvertAnsiToWide(infPath), &rebootRequired)) + if (const auto result = nefarius::devcon::InstallDriver(nefarius::utilities::ConvertAnsiToWide(infPath), + &rebootRequired); !result) { - logger->error("Failed to install driver, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to install driver, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to install driver, error: %v", result.error().getErrorMessageA()); + return result.error().getErrorCode(); } logger->info("Driver installed successfully"); - std::cout << color(green) << "Driver installed successfully" << std::endl; return (rebootRequired) ? ERROR_SUCCESS_REBOOT_REQUIRED : EXIT_SUCCESS; } @@ -301,14 +315,12 @@ int main(int argc, char* argv[]) if (infPath.empty()) { logger->error("INF path missing"); - std::cout << color(red) << "INF path missing" << std::endl; return EXIT_FAILURE; } if (_access(infPath.c_str(), 0) != 0) { logger->error("The given INF file doesn't exist, is the path correct?"); - std::cout << color(red) << "The given INF file doesn't exist, is the path correct?" << std::endl; return EXIT_FAILURE; } @@ -317,24 +329,19 @@ int main(int argc, char* argv[]) if (attribs & FILE_ATTRIBUTE_DIRECTORY) { logger->error("The given INF path is a directory, not a file"); - std::cout << color(red) << "The given INF path is a directory, not a file" << std::endl; return EXIT_FAILURE; } bool rebootRequired; - if (!devcon::uninstall_driver(ConvertAnsiToWide(infPath), &rebootRequired)) + if (const auto result = nefarius::devcon::UninstallDriver(nefarius::utilities::ConvertAnsiToWide(infPath), + &rebootRequired); !result) { - logger->error("Failed to uninstall driver, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to uninstall driver, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to uninstall driver, error: %v", result.error().getErrorMessageA()); + return result.error().getErrorCode(); } logger->info("Driver uninstalled successfully"); - std::cout << color(green) << "Driver uninstalled successfully" << std::endl; return (rebootRequired) ? ERROR_SUCCESS_REBOOT_REQUIRED : EXIT_SUCCESS; } @@ -349,14 +356,12 @@ int main(int argc, char* argv[]) if (binPath.empty()) { logger->error("Binary path missing"); - std::cout << color(red) << "Binary path missing" << std::endl; return EXIT_FAILURE; } if (_access(binPath.c_str(), 0) != 0) { logger->error("The given binary file doesn't exist, is the path correct?"); - std::cout << color(red) << "The given binary file doesn't exist, is the path correct?" << std::endl; return EXIT_FAILURE; } @@ -365,14 +370,12 @@ int main(int argc, char* argv[]) if (attribs & FILE_ATTRIBUTE_DIRECTORY) { logger->error("The given binary path is a directory, not a file"); - std::cout << color(red) << "The given binary path is a directory, not a file" << std::endl; return EXIT_FAILURE; } if (!(cmdl({"--service-name"}) >> serviceName)) { logger->error("Service name missing"); - std::cout << color(red) << "Service name missing" << std::endl; return EXIT_FAILURE; } @@ -381,22 +384,17 @@ int main(int argc, char* argv[]) if (displayName.empty()) { logger->error("Display name missing"); - std::cout << color(red) << "Display name missing" << std::endl; return EXIT_FAILURE; } - if (!winapi::CreateDriverService(serviceName.c_str(), displayName.c_str(), binPath.c_str())) + if (const auto result = nefarius::winapi::services::CreateDriverService(serviceName, displayName, binPath); ! + result) { - logger->error("Failed to create driver service, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to create driver service, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to create driver service, error: %v", result.error().getErrorMessageA()); + return result.error().getErrorCode(); } logger->info("Driver service created successfully"); - std::cout << color(green) << "Driver service created successfully" << std::endl; return EXIT_SUCCESS; } @@ -409,22 +407,16 @@ int main(int argc, char* argv[]) if (!(cmdl({"--service-name"}) >> serviceName)) { logger->error("Service name missing"); - std::cout << color(red) << "Service name missing" << std::endl; return EXIT_FAILURE; } - if (!winapi::DeleteDriverService(serviceName.c_str())) + if (const auto result = nefarius::winapi::services::DeleteDriverService(serviceName); !result) { - logger->error("Failed to remove driver service, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to remove driver service, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to remove driver service, error: %v", result.error().getErrorMessageA()); + return result.error().getErrorCode(); } logger->info("Driver service removed successfully"); - std::cout << color(green) << "Driver service removed successfully" << std::endl; return EXIT_SUCCESS; } @@ -437,50 +429,41 @@ int main(int argc, char* argv[]) if (!(cmdl({"--hardware-id"}) >> hwId)) { logger->error("Hardware ID missing"); - std::cout << color(red) << "Hardware ID missing" << std::endl; return EXIT_FAILURE; } if (!(cmdl({"--class-name"}) >> className)) { logger->error("Device Class Name missing"); - std::cout << color(red) << "Device Class Name missing" << std::endl; return EXIT_FAILURE; } if (!(cmdl({"--class-guid"}) >> classGuid)) { logger->error("Device Class GUID missing"); - std::cout << color(red) << "Device Class GUID missing" << std::endl; return EXIT_FAILURE; } - GUID clID; + const auto guid = nefarius::winapi::GUIDFromString(classGuid); - if (!GUIDFromString(classGuid, &clID)) + if (!guid) { logger->error( "Device Class GUID format invalid, expected format (with or without brackets): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); - std::cout << color(red) << - "Device Class GUID format invalid, expected format (with or without brackets): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - << std::endl; return EXIT_FAILURE; } - auto ret = devcon::create(ConvertAnsiToWide(className), &clID, ConvertAnsiToWide(hwId)); + auto ret = nefarius::devcon::Create(nefarius::utilities::ConvertAnsiToWide(className), &guid.value(), + nefarius::utilities::WideMultiStringArray( + nefarius::utilities::ConvertAnsiToWide(hwId))); if (!ret) { - logger->error("Failed to create device node, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to create device node, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to create device node, error: %v", ret.error().getErrorMessageA()); + return ret.error().getErrorCode(); } logger->info("Device node created successfully"); - std::cout << color(green) << "Device node created successfully" << std::endl; return EXIT_SUCCESS; } @@ -495,45 +478,40 @@ int main(int argc, char* argv[]) if (!(cmdl({"--hardware-id"}) >> hwId)) { logger->error("Hardware ID missing"); - std::cout << color(red) << "Hardware ID missing" << std::endl; return EXIT_FAILURE; } if (!(cmdl({"--class-guid"}) >> classGuid)) { logger->error("Device Class GUID missing"); - std::cout << color(red) << "Device Class GUID missing" << std::endl; return EXIT_FAILURE; } - GUID clID; + const auto guid = nefarius::winapi::GUIDFromString(classGuid); - if (!GUIDFromString(classGuid, &clID)) + if (!guid) { logger->error( "Device Class GUID format invalid, expected format (with or without brackets): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); - std::cout << color(red) << - "Device Class GUID format invalid, expected format (with or without brackets): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - << std::endl; return EXIT_FAILURE; } bool rebootRequired; - auto ret = devcon::uninstall_device_and_driver(&clID, ConvertAnsiToWide(hwId), &rebootRequired); + auto results = nefarius::devcon::UninstallDeviceAndDriver(&guid.value(), + nefarius::utilities::ConvertAnsiToWide(hwId), + &rebootRequired); - if (!ret) + for (const auto& item : results) { - logger->error("Failed to delete device node, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to delete device node, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + if (!item) + { + logger->error("Failed to delete device node, error: %v", item.error().getErrorMessageA()); + return item.error().getErrorCode(); + } } logger->info("Device and driver removed successfully"); - std::cout << color(green) << "Device and driver removed successfully" << std::endl; return (rebootRequired) ? ERROR_SUCCESS_REBOOT_REQUIRED : EXIT_SUCCESS; } @@ -550,14 +528,12 @@ int main(int argc, char* argv[]) if (infPath.empty()) { logger->error("INF path missing"); - std::cout << color(red) << "INF path missing" << std::endl; return EXIT_FAILURE; } if (_access(infPath.c_str(), 0) != 0) { logger->error("The given INF file doesn't exist, is the path correct?"); - std::cout << color(red) << "The given INF file doesn't exist, is the path correct?" << std::endl; return EXIT_FAILURE; } @@ -566,31 +542,25 @@ int main(int argc, char* argv[]) if (attribs & FILE_ATTRIBUTE_DIRECTORY) { logger->error("The given INF path is a directory, not a file"); - std::cout << color(red) << "The given INF path is a directory, not a file" << std::endl; return EXIT_FAILURE; } bool rebootRequired = false; - if (!devcon::inf_default_install(ConvertAnsiToWide(infPath), &rebootRequired)) + if (const auto result = nefarius::devcon::InfDefaultInstall(nefarius::utilities::ConvertAnsiToWide(infPath), + &rebootRequired); !result) { - logger->error("Failed to install INF file, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to install INF file, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to install INF file, error: %v", result.error().getErrorMessageA()); + return result.error().getErrorCode(); } if (!rebootRequired) { logger->info("INF file installed successfully"); - std::cout << color(green) << "INF file installed successfully" << std::endl; } else { logger->info("INF file installed successfully, but a reboot is required"); - std::cout << color(yellow) << "INF file installed successfully, but a reboot is required" << std::endl; } return (rebootRequired) ? ERROR_SUCCESS_REBOOT_REQUIRED : EXIT_SUCCESS; @@ -606,14 +576,12 @@ int main(int argc, char* argv[]) if (infPath.empty()) { logger->error("INF path missing"); - std::cout << color(red) << "INF path missing" << std::endl; return EXIT_FAILURE; } if (_access(infPath.c_str(), 0) != 0) { logger->error("The given INF file doesn't exist, is the path correct?"); - std::cout << color(red) << "The given INF file doesn't exist, is the path correct?" << std::endl; return EXIT_FAILURE; } @@ -622,31 +590,25 @@ int main(int argc, char* argv[]) if (attribs & FILE_ATTRIBUTE_DIRECTORY) { logger->error("The given INF path is a directory, not a file"); - std::cout << color(red) << "The given INF path is a directory, not a file" << std::endl; return EXIT_FAILURE; } bool rebootRequired = false; - if (!devcon::inf_default_uninstall(ConvertAnsiToWide(infPath), &rebootRequired)) + if (const auto result = nefarius::devcon::InfDefaultUninstall(nefarius::utilities::ConvertAnsiToWide(infPath), + &rebootRequired); !result) { - logger->error("Failed to uninstall INF file, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to uninstall INF file, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to uninstall INF file, error: %v", result.error().getErrorMessageA()); + return result.error().getErrorCode(); } if (!rebootRequired) { logger->info("INF file uninstalled successfully"); - std::cout << color(green) << "INF file uninstalled successfully" << std::endl; } else { logger->info("INF file uninstalled successfully, but a reboot is required"); - std::cout << color(yellow) << "INF file uninstalled successfully, but a reboot is required" << std::endl; } return (rebootRequired) ? ERROR_SUCCESS_REBOOT_REQUIRED : EXIT_SUCCESS; @@ -666,14 +628,12 @@ int main(int argc, char* argv[]) if (filePath.empty()) { logger->error("File path missing"); - std::cout << color(red) << "File path missing" << std::endl; return EXIT_FAILURE; } if (_access(filePath.c_str(), 0) != 0) { logger->error("The given file path doesn't exist, is the path correct?"); - std::cout << color(red) << "The given file path doesn't exist, is the path correct?" << std::endl; return EXIT_FAILURE; } @@ -682,7 +642,6 @@ int main(int argc, char* argv[]) if (attribs & FILE_ATTRIBUTE_DIRECTORY) { logger->error("The given file path is a directory, not a file"); - std::cout << color(red) << "The given file path is a directory, not a file" << std::endl; return EXIT_FAILURE; } @@ -693,14 +652,10 @@ int main(int argc, char* argv[]) if (!ret && GetLastError() == ERROR_ACCESS_DENIED) { // ...take ownership of protected file (e.g. within the system directories)... - if (!winapi::TakeFileOwnership(logger, ConvertAnsiToWide(filePath).c_str())) + if (const auto result = nefarius::winapi::fs::TakeFileOwnership(filePath); !result) { - logger->error("Failed to take ownership of file, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to take ownership of file, error: " - << winapi::GetLastErrorStdStr() << std::endl; - return GetLastError(); + logger->error("Failed to take ownership of file, error: %v", result.error().getErrorMessageA()); + return result.error().getErrorCode(); } // ...and try again @@ -710,15 +665,11 @@ int main(int argc, char* argv[]) if (!ret) { logger->error("Failed to register file for removal, error: %v", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to register file for removal, error: " - << winapi::GetLastErrorStdStr() << std::endl; + nefarius::utilities::Win32Error("MoveFileExA").getErrorMessageA()); return GetLastError(); } logger->info("File removal registered successfully"); - std::cout << color(green) << "File removal registered successfully" << std::endl; return EXIT_SUCCESS; } @@ -730,24 +681,54 @@ int main(int argc, char* argv[]) if (hwId.empty()) { logger->error("Hardware ID missing"); - std::cout << color(red) << "Hardware ID missing" << std::endl; return EXIT_FAILURE; } - if (!devcon::find_by_hwid(ConvertAnsiToWide(hwId))) + + const auto findResult = nefarius::devcon::FindByHwId(nefarius::utilities::ConvertAnsiToWide(hwId)); + + if (!findResult) + { + logger->error("Failed to register search for devices, error: %v", findResult.error().getErrorMessageA()); + return findResult.error().getErrorCode(); + } + + if (findResult.value().empty()) { return ERROR_NOT_FOUND; } + + for (const auto& [HardwareIds, Name, Version] : findResult.value()) + { + std::wstring idValue = std::accumulate( + std::begin(HardwareIds), std::end(HardwareIds), std::wstring(), + [](const std::wstring& ss, const std::wstring& s) + { + return ss.empty() ? s : ss + L", " + s; + }); + + logger->info("Hardware IDs: %v", idValue); + logger->info("Name: %v", Name); + logger->info("Version: %v.%v.%v.%v", + std::to_wstring(Version.Major), + std::to_wstring(Version.Minor), + std::to_wstring(Version.Build), + std::to_wstring(Version.Private) + ); + } + return EXIT_SUCCESS; } #pragma endregion +#pragma region Version + if (cmdl[{"-v", "--version"}]) { std::cout << "nefcon version " << - winapi::GetVersionFromFile(winapi::GetImageBasePath()) + to_string(nefarius::winapi::fs::GetProductVersionFromFile(GetImageBasePath()).value()) << " (C) Nefarius Software Solutions e.U." - << std::endl; + << '\n'; return EXIT_SUCCESS; } @@ -758,104 +739,117 @@ int main(int argc, char* argv[]) #if defined(NEFCON_WINMAIN) std::cout << "usage: .\\nefconw [options] [logging]" << std::endl << std::endl; #else - std::cout << "usage: .\\nefconc [options] [logging]" << std::endl << std::endl; + std::cout << "usage: .\\nefconc [options] [logging]" << '\n' << '\n'; #endif - std::cout << " options:" << std::endl; - std::cout << " --install-driver Invoke the installation of a given PNP driver" << std::endl; - std::cout << " --inf-path Absolute path to the INF file to install (required)" << std::endl; - std::cout << " --uninstall-driver Invoke the removal of a given PNP driver" << std::endl; - std::cout << " --inf-path Absolute path to the INF file to uninstall (required)" << std::endl; - std::cout << " --create-device-node Create a new ROOT enumerated virtual device" << std::endl; - std::cout << " --hardware-id Hardware ID of the new device (required)" << std::endl; - std::cout << " --class-name Device Class Name of the new device (required)" << std::endl; - std::cout << " --class-guid Device Class GUID of the new device (required)" << std::endl; - std::cout << " --remove-device-node Removes a device and its driver" << std::endl; - std::cout << " --hardware-id Hardware ID of the device (required)" << std::endl; - std::cout << " --class-guid Device Class GUID of the device (required)" << std::endl; - std::cout << " --add-class-filter Adds a service to a device class' filter collection" << std::endl; - std::cout << " --position Which filter to modify (required)" << std::endl; - std::cout << " Valid values include: upper|lower" << std::endl; - std::cout << " --service-name The driver service name to insert (required)" << std::endl; - std::cout << " --class-guid Device Class GUID to modify (required)" << std::endl; - std::cout << " --remove-class-filter Removes a service to a device class' filter collection" << std::endl; - std::cout << " --position Which filter to modify (required)" << std::endl; - std::cout << " Valid values include: upper|lower" << std::endl; - std::cout << " --service-name The driver service name to insert (required)" << std::endl; - std::cout << " --class-guid Device Class GUID to modify (required)" << std::endl; - std::cout << " --create-driver-service Creates a new service with a kernel driver as binary" << std::endl; - std::cout << " --bin-path Absolute path to the .sys file (required)" << std::endl; - std::cout << " --service-name The driver service name to create (required)" << std::endl; - std::cout << " --display-name The friendly name of the service (required)" << std::endl; - std::cout << " --remove-driver-service Removes an existing kernel driver service" << std::endl; - std::cout << " --service-name The driver service name to remove (required)" << std::endl; - std::cout << " --inf-default-install Installs an INF file with a [DefaultInstall] section" << std::endl; - std::cout << " --inf-path Absolute path to the INF file to install (required)" << std::endl; - std::cout << " --inf-default-uninstall Uninstalls an INF file with a [DefaultUninstall] section" << std::endl; - std::cout << " --inf-path Absolute path to the INF file to uninstall (required)" << std::endl; - std::cout << " --delete-file-on-reboot Marks a given file to get deleted on next reboot" << std::endl; - std::cout << " --file-path The absolute path of the file to remove (required)" << std::endl; - std::cout << " --find-hwid Shows one or more devices matching a partial Hardware ID" << std::endl; + std::cout << " options:" << '\n'; + std::cout << " --install-driver Invoke the installation of a given PNP driver" << '\n'; + std::cout << " --inf-path Absolute path to the INF file to install (required)" << '\n'; + std::cout << " --uninstall-driver Invoke the removal of a given PNP driver" << '\n'; + std::cout << " --inf-path Absolute path to the INF file to uninstall (required)" << '\n'; + std::cout << " --create-device-node Create a new ROOT enumerated virtual device" << '\n'; + std::cout << " --hardware-id Hardware ID of the new device (required)" << '\n'; + std::cout << " --class-name Device Class Name of the new device (required)" << '\n'; + std::cout << " --class-guid Device Class GUID of the new device (required)" << '\n'; + std::cout << " --remove-device-node Removes a device and its driver" << '\n'; + std::cout << " --hardware-id Hardware ID of the device (required)" << '\n'; + std::cout << " --class-guid Device Class GUID of the device (required)" << '\n'; + std::cout << " --add-class-filter Adds a service to a device class' filter collection" << '\n'; + std::cout << " --position Which filter to modify (required)" << '\n'; + std::cout << " Valid values include: upper|lower" << '\n'; + std::cout << " --service-name The driver service name to insert (required)" << '\n'; + std::cout << " --class-guid Device Class GUID to modify (required)" << '\n'; + std::cout << " --remove-class-filter Removes a service to a device class' filter collection" << '\n'; + std::cout << " --position Which filter to modify (required)" << '\n'; + std::cout << " Valid values include: upper|lower" << '\n'; + std::cout << " --service-name The driver service name to insert (required)" << '\n'; + std::cout << " --class-guid Device Class GUID to modify (required)" << '\n'; + std::cout << " --create-driver-service Creates a new service with a kernel driver as binary" << '\n'; + std::cout << " --bin-path Absolute path to the .sys file (required)" << '\n'; + std::cout << " --service-name The driver service name to create (required)" << '\n'; + std::cout << " --display-name The friendly name of the service (required)" << '\n'; + std::cout << " --remove-driver-service Removes an existing kernel driver service" << '\n'; + std::cout << " --service-name The driver service name to remove (required)" << '\n'; + std::cout << " --inf-default-install Installs an INF file with a [DefaultInstall] section" << '\n'; + std::cout << " --inf-path Absolute path to the INF file to install (required)" << '\n'; + std::cout << " --inf-default-uninstall Uninstalls an INF file with a [DefaultUninstall] section" << '\n'; + std::cout << " --inf-path Absolute path to the INF file to uninstall (required)" << '\n'; + std::cout << " --delete-file-on-reboot Marks a given file to get deleted on next reboot" << '\n'; + std::cout << " --file-path The absolute path of the file to remove (required)" << '\n'; + std::cout << " --find-hwid Shows one or more devices matching a partial Hardware ID" << '\n'; std::cout << " ---hardware-id (Partial) Hardware ID of the device to match against (required)" << - std::endl; - std::cout << " -v, --version Display version of this utility" << std::endl; - std::cout << std::endl; - std::cout << " logging:" << std::endl; + '\n'; + std::cout << " -v, --version Display version of this utility" << '\n'; + std::cout << '\n'; + std::cout << " logging:" << '\n'; std::cout << " --default-log-file=.\\log.txt Write details of execution to a log file (optional)" << - std::endl; - std::cout << " --verbose Turn on verbose/diagnostic logging (optional)" << std::endl; - std::cout << std::endl; + '\n'; + std::cout << " --verbose Turn on verbose/diagnostic logging (optional)" << '\n'; + std::cout << '\n'; #pragma endregion return EXIT_SUCCESS; } -static bool IsAdmin(int& errorCode) +namespace { - el::Logger* logger = el::Loggers::getLogger("default"); - BOOL isAdmin = FALSE; - - if (winapi::IsAppRunningAsAdminMode(&isAdmin) != ERROR_SUCCESS) + bool IsAdmin(int& errorCode) { - logger->error("Failed to determine elevation status, error: ", - winapi::GetLastErrorStdStr()); - std::cout << color(red) << - "Failed to determine elevation status, error: " - << winapi::GetLastErrorStdStr() << std::endl; - errorCode = EXIT_FAILURE; - return false; + el::Logger* logger = el::Loggers::getLogger("default"); + + const auto isAdmin = nefarius::winapi::security::IsAppRunningAsAdminMode(); + + if (!isAdmin) + { + logger->error("Failed to determine elevation status, error: ", isAdmin.error().getErrorMessageA()); + errorCode = EXIT_FAILURE; + return false; + } + + if (!isAdmin.value()) + { + logger->error( + "This command requires elevated privileges. Please run as Administrator and make sure the UAC is enabled."); + errorCode = EXIT_FAILURE; + return false; + } + + return true; } - if (!isAdmin) + std::string GetImageBasePath() { - logger->error( - "This command requires elevated privileges. Please run as Administrator and make sure the UAC is enabled."); - std::cout << color(red) << - "This command requires elevated privileges. Please run as Administrator and make sure the UAC is enabled." - << std::endl; - errorCode = EXIT_FAILURE; - return false; - } + char myPath[MAX_PATH + 1] = {}; - return true; -} + GetModuleFileNameA( + reinterpret_cast(&__ImageBase), + myPath, + MAX_PATH + 1 + ); -static bool GUIDFromString(const std::string& input, GUID* guid) -{ - // try without brackets... - if (UuidFromStringA(RPC_CSTR(input.data()), guid) == RPC_S_INVALID_STRING_UUID) + return {myPath}; + } + +#if !defined(NEFCON_WINMAIN) + void CustomizeEasyLoggingColoredConsole() { - const HMODULE shell32 = LoadLibraryA("Shell32.dll"); + el::Configurations conf; + conf.setToDefault(); - if (shell32 == nullptr) - return false; + // Disable STDOUT logging for all log levels + conf.set(el::Level::Global, el::ConfigurationType::ToStandardOutput, "false"); - const auto pFnGUIDFromString = reinterpret_cast( - GetProcAddress(shell32, MAKEINTRESOURCEA(703))); + el::Loggers::addFlag(el::LoggingFlag::ImmediateFlush); - // ...finally try with brackets - return pFnGUIDFromString(input.c_str(), guid); - } + // Register the custom log dispatch callback + el::Helpers::installLogDispatchCallback("ConsoleColorLogDispatchCallback"); + + // Enable the custom log dispatch callback + el::Helpers::logDispatchCallback("ConsoleColorLogDispatchCallback")-> + setEnabled(true); - return true; + // Apply the configuration + el::Loggers::reconfigureLogger("default", conf); + } +#endif } diff --git a/src/NefConUtil.h b/src/NefConUtil.h index 0370c58..cef6b01 100644 --- a/src/NefConUtil.h +++ b/src/NefConUtil.h @@ -27,11 +27,8 @@ #include #include #include - -// -// CLI argument parser -// -#include +#include +#include // // Add some colors to console @@ -39,13 +36,26 @@ #include "colorwin.hpp" // -// Logging +// Vcpkg Packages // +#include #include // -// Setup helpers +// Internal +// +#include "ColorLogging.hpp" + +// +// neflib // -#include "Devcon.h" -#include "NefConSetup.h" -#include "UniUtil.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/UniUtil.h b/src/UniUtil.h deleted file mode 100644 index d11e837..0000000 --- a/src/UniUtil.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1 -#include // wstring_convert - -std::string ConvertWideToANSI(const std::wstring& wstr) -{ - int count = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL); - std::string str(count, 0); - WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL); - return str; -} - -std::wstring ConvertAnsiToWide(const std::string& str) -{ - int count = MultiByteToWideChar(CP_ACP, 0, str.c_str(), (int)str.length(), NULL, 0); - std::wstring wstr(count, 0); - MultiByteToWideChar(CP_ACP, 0, str.c_str(), (int)str.length(), &wstr[0], count); - return wstr; -} diff --git a/src/colorwin.hpp b/src/colorwin.hpp index 12e73a1..929846e 100644 --- a/src/colorwin.hpp +++ b/src/colorwin.hpp @@ -167,4 +167,4 @@ namespace colorwin } } -#endif // COLORWIN_HPP_INCLUDED \ No newline at end of file +#endif // COLORWIN_HPP_INCLUDED diff --git a/src/framework.h b/src/framework.h index a62b623..c72be1e 100644 --- a/src/framework.h +++ b/src/framework.h @@ -14,5 +14,3 @@ #include #include - -#include "LibraryHelper.hpp" diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json new file mode 100644 index 0000000..d4cd73f --- /dev/null +++ b/vcpkg-configuration.json @@ -0,0 +1,14 @@ +{ + "registries": [ + { + "kind": "git", + "repository": "https://github.com/nefarius/nefarius-vcpkg-registry.git", + "baseline": "a012f87f807c6c45a372b5a3a2dcf562a356f1dc", + "packages": [ "neflib" ] + } + ], + "default-registry": { + "kind": "builtin", + "baseline": "2024.07.12" + } +} diff --git a/vcpkg.json b/vcpkg.json index a455afd..26cfc66 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -5,8 +5,12 @@ "license": "MIT", "supports": "!(arm | uwp)", "dependencies": [ + "neflib", "argh", "easyloggingpp", - "detours" + "detours", + "scope-guard", + "wil", + "color-console" ] }