diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-02-25 12:21:59 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-02-25 12:21:59 +0100 |
| commit | 943f4154568ce6892eadcf1b57a9deb436d27e5f (patch) | |
| tree | f651795fede6c02b8734719754cb1729eaaf8bc8 | |
| parent | 807de13a4577db8d97b8718f43fe9aef6be84b6d (diff) | |
| parent | 687a2f7bad4aafc55515def59b1ec07a43f1fa50 (diff) | |
| download | mullvadvpn-943f4154568ce6892eadcf1b57a9deb436d27e5f.tar.xz mullvadvpn-943f4154568ce6892eadcf1b57a9deb436d27e5f.zip | |
Merge branch 'improve-device-error-msg'
| -rw-r--r-- | dist-assets/windows/installer.nsh | 12 | ||||
| -rw-r--r-- | windows/driverlogic/driverlogic.vcxproj | 2 | ||||
| -rw-r--r-- | windows/driverlogic/driverlogic.vcxproj.filters | 2 | ||||
| -rw-r--r-- | windows/driverlogic/src/driverlogic.cpp | 69 | ||||
| -rw-r--r-- | windows/driverlogic/src/error.cpp | 165 | ||||
| -rw-r--r-- | windows/driverlogic/src/error.h | 14 | ||||
| -rw-r--r-- | windows/driverlogic/src/stdafx.h | 5 | ||||
| m--------- | windows/windows-libraries | 0 |
8 files changed, 247 insertions, 22 deletions
diff --git a/dist-assets/windows/installer.nsh b/dist-assets/windows/installer.nsh index 83dd72a6d4..c7adccc49e 100644 --- a/dist-assets/windows/installer.nsh +++ b/dist-assets/windows/installer.nsh @@ -25,8 +25,8 @@ !define MULLVAD_SUCCESS 1 # Return codes from driverlogic -!define DL_GENERAL_ERROR 0 -!define DL_GENERAL_SUCCESS 1 +!define DL_GENERAL_ERROR -1 +!define DL_GENERAL_SUCCESS 0 # Log targets !define LOG_FILE 0 @@ -131,8 +131,9 @@ Pop $0 Pop $1 - ${If} $0 == ${DL_GENERAL_ERROR} - StrCpy $R0 "Failed to remove vanilla TAP adapter" + ${If} $0 != ${DL_GENERAL_SUCCESS} + IntFmt $0 "0x%X" $0 + StrCpy $R0 "Failed to remove vanilla TAP adapter: error $0" log::LogWithDetails $R0 $1 Goto RemoveVanillaTap_return @@ -194,7 +195,8 @@ Pop $1 ${If} $0 != ${DL_GENERAL_SUCCESS} - StrCpy $R0 "Failed to create virtual adapter" + IntFmt $0 "0x%X" $0 + StrCpy $R0 "Failed to create virtual adapter: error $0" log::LogWithDetails $R0 $1 Goto InstallTapDriver_return ${EndIf} diff --git a/windows/driverlogic/driverlogic.vcxproj b/windows/driverlogic/driverlogic.vcxproj index 657e58d9eb..fd9ba06616 100644 --- a/windows/driverlogic/driverlogic.vcxproj +++ b/windows/driverlogic/driverlogic.vcxproj @@ -97,9 +97,11 @@ </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="src\driverlogic.cpp" /> + <ClCompile Include="src\error.cpp" /> <ClCompile Include="src\stdafx.cpp" /> </ItemGroup> <ItemGroup> + <ClInclude Include="src\error.h" /> <ClInclude Include="src\stdafx.h" /> <ClInclude Include="src\targetver.h" /> </ItemGroup> diff --git a/windows/driverlogic/driverlogic.vcxproj.filters b/windows/driverlogic/driverlogic.vcxproj.filters index ba18d9617c..b9c494e241 100644 --- a/windows/driverlogic/driverlogic.vcxproj.filters +++ b/windows/driverlogic/driverlogic.vcxproj.filters @@ -9,9 +9,11 @@ <ItemGroup> <ClCompile Include="src\driverlogic.cpp" /> <ClCompile Include="src\stdafx.cpp" /> + <ClCompile Include="src\error.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="src\stdafx.h" /> <ClInclude Include="src\targetver.h" /> + <ClInclude Include="src\error.h" /> </ItemGroup> </Project>
\ No newline at end of file diff --git a/windows/driverlogic/src/driverlogic.cpp b/windows/driverlogic/src/driverlogic.cpp index c92ad51ed6..3e482c196f 100644 --- a/windows/driverlogic/src/driverlogic.cpp +++ b/windows/driverlogic/src/driverlogic.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "error.h" #include <iostream> #include <sstream> #include <string> @@ -8,6 +9,7 @@ #include <libcommon/guid.h> #include <libcommon/memory.h> #include <libcommon/network/nci.h> +#include <libcommon/registry/registry.h> #include <libcommon/string.h> #include <setupapi.h> #include <initguid.h> @@ -28,8 +30,8 @@ constexpr wchar_t TAP_BASE_ALIAS[] = L"Mullvad"; enum ReturnCodes { - GENERAL_ERROR, - GENERAL_SUCCESS + GENERAL_SUCCESS = 0, + GENERAL_ERROR = -1 }; struct NetworkAdapter @@ -107,7 +109,7 @@ std::optional<std::wstring> GetDeviceRegistryStringProperty( // TODO: Check if there may be other causes. if (ERROR_INVALID_DATA != lastError) { - THROW_WINDOWS_ERROR(lastError, "SetupDiGetDeviceRegistryPropertyW"); + THROW_SETUPAPI_ERROR(lastError, "SetupDiGetDeviceRegistryPropertyW"); } return std::nullopt; @@ -131,7 +133,7 @@ std::optional<std::wstring> GetDeviceRegistryStringProperty( if (FALSE == status) { - THROW_WINDOWS_ERROR(GetLastError(), "Failed to read device property"); + THROW_SETUPAPI_ERROR(GetLastError(), "Failed to read device property"); } return std::make_optional(buffer.data()); @@ -167,7 +169,7 @@ std::wstring GetDeviceStringProperty( if (ERROR_INSUFFICIENT_BUFFER != lastError) { - THROW_WINDOWS_ERROR(lastError, "SetupDiGetDevicePropertyW"); + THROW_SETUPAPI_ERROR(lastError, "SetupDiGetDevicePropertyW"); } } @@ -190,7 +192,7 @@ std::wstring GetDeviceStringProperty( if (FALSE == status) { - THROW_WINDOWS_ERROR(GetLastError(), "Failed to read device property"); + THROW_SETUPAPI_ERROR(GetLastError(), "Failed to read device property"); } return buffer.data(); @@ -223,7 +225,7 @@ std::wstring GetDeviceInstanceId( if (FALSE == status) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiGetDeviceInstanceIdW"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiGetDeviceInstanceIdW"); } return deviceInstanceId.data(); @@ -242,7 +244,7 @@ std::wstring GetNetCfgInstanceId(HDEVINFO devInfo, const SP_DEVINFO_DATA &devInf if (hNet == INVALID_HANDLE_VALUE) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiOpenDevRegKey"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiOpenDevRegKey"); } std::vector<wchar_t> instanceId(MAX_PATH + 1); @@ -288,13 +290,13 @@ bool DeleteDevice(HDEVINFO devInfo, const SP_DEVINFO_DATA &devInfoData) auto status = SetupDiSetClassInstallParamsW(devInfo, data, &rmdParams.ClassInstallHeader, sizeof(rmdParams)); if (FALSE == status) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiSetClassInstallParamsW"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiSetClassInstallParamsW"); } status = SetupDiCallClassInstaller(DIF_REMOVE, devInfo, data); if (FALSE == status) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiCallClassInstaller"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiCallClassInstaller"); } return true; @@ -311,7 +313,7 @@ void ForEachNetworkDevice(const std::optional<std::wstring> hwId, std::function< if (INVALID_HANDLE_VALUE == devInfo) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiGetClassDevsW"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiGetClassDevsW"); } common::memory::ScopeDestructor cleanupDevList; @@ -334,7 +336,7 @@ void ForEachNetworkDevice(const std::optional<std::wstring> hwId, std::function< break; } - THROW_WINDOWS_ERROR(lastError, "Enumerating network adapters"); + THROW_SETUPAPI_ERROR(lastError, "Enumerating network adapters"); } if (hwId.has_value()) @@ -416,7 +418,7 @@ void CreateTapDevice() const auto deviceInfoSet = SetupDiCreateDeviceInfoList(&classGuid, 0); if (INVALID_HANDLE_VALUE == deviceInfoSet) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiCreateDeviceInfoList"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiCreateDeviceInfoList"); } common::memory::ScopeDestructor scopeDestructor; @@ -440,7 +442,7 @@ void CreateTapDevice() if (FALSE == status) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiCreateDeviceInfoW"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiCreateDeviceInfoW"); } status = SetupDiSetDeviceRegistryPropertyW( @@ -453,7 +455,7 @@ void CreateTapDevice() if (FALSE == status) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiSetDeviceRegistryPropertyW"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiSetDeviceRegistryPropertyW"); } // @@ -467,7 +469,7 @@ void CreateTapDevice() if (FALSE == status) { - THROW_WINDOWS_ERROR(GetLastError(), "SetupDiCallClassInstaller"); + THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiCallClassInstaller"); } Log(L"Created new TAP adapter successfully"); @@ -503,7 +505,35 @@ ATTEMPT_UPDATE: goto ATTEMPT_UPDATE; } - THROW_WINDOWS_ERROR(lastError, "UpdateDriverForPlugAndPlayDevicesW"); + if (ERROR_DEVICE_INSTALLER_NOT_READY == lastError) + { + bool deviceInstallDisabled = false; + + try + { + const auto key = common::registry::Registry::OpenKey( + HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\DeviceInstall\\Parameters" + ); + deviceInstallDisabled = (0 != key->readUint32(L"DeviceInstallDisabled")); + } + catch (...) + { + } + + if (deviceInstallDisabled) + { + throw common::error::WindowsException( + "Device installs must be enabled to continue. " + "Enable them in the Local Group Policy editor, or " + "update the registry value DeviceInstallDisabled in " + "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DeviceInstall\\Parameters]", + lastError + ); + } + } + + THROW_SETUPAPI_ERROR(lastError, "UpdateDriverForPlugAndPlayDevicesW"); } // @@ -745,6 +775,11 @@ int wmain(int argc, const wchar_t * argv[], const wchar_t * []) goto INVALID_ARGUMENTS; } } + catch (const common::error::WindowsException &e) + { + LogError(common::string::ToWide(e.what())); + return e.errorCode(); + } catch (const std::exception &e) { LogError(common::string::ToWide(e.what())); diff --git a/windows/driverlogic/src/error.cpp b/windows/driverlogic/src/error.cpp new file mode 100644 index 0000000000..49909784ca --- /dev/null +++ b/windows/driverlogic/src/error.cpp @@ -0,0 +1,165 @@ +#include "stdafx.h" +#include "error.h" +#include <string> +#include <iomanip> +#include <sstream> +#include <map> +#include <setupapi.h> +#include <libcommon/error.h> + + +#define SETUPAPI_ERROR_TABLE_ENTRY(constant) { constant, #constant } + +namespace +{ + +const std::map<uint32_t, const char *> setupApiCodeToString = +{ + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_EXPECTED_SECTION_NAME), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_BAD_SECTION_NAME_LINE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_SECTION_NAME_TOO_LONG), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_GENERAL_SYNTAX), + // + // Inf runtime errors + // + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_WRONG_INF_STYLE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_SECTION_NOT_FOUND), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_LINE_NOT_FOUND), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_BACKUP), + // + // Device Installer/other errors + // + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_ASSOCIATED_CLASS), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_CLASS_MISMATCH), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DUPLICATE_FOUND), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_DRIVER_SELECTED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_KEY_DOES_NOT_EXIST), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_DEVINST_NAME), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_CLASS), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVINST_ALREADY_EXISTS), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVINFO_NOT_REGISTERED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_REG_PROPERTY), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_INF), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_SUCH_DEVINST), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_CANT_LOAD_CLASS_ICON), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_CLASS_INSTALLER), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DI_DO_DEFAULT), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DI_NOFILECOPY), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_HWPROFILE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_DEVICE_SELECTED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVINFO_LIST_LOCKED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVINFO_DATA_LOCKED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DI_BAD_PATH), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_CLASSINSTALL_PARAMS), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_FILEQUEUE_LOCKED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_BAD_SERVICE_INSTALLSECT), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_CLASS_DRIVER_LIST), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_ASSOCIATED_SERVICE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_DEFAULT_DEVICE_INTERFACE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVICE_INTERFACE_ACTIVE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVICE_INTERFACE_REMOVED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_BAD_INTERFACE_INSTALLSECT), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_SUCH_INTERFACE_CLASS), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_REFERENCE_STRING), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_MACHINENAME), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_REMOTE_COMM_FAILURE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_MACHINE_UNAVAILABLE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_CONFIGMGR_SERVICES), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_PROPPAGE_PROVIDER), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_SUCH_DEVICE_INTERFACE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DI_POSTPROCESSING_REQUIRED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_COINSTALLER), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_COMPAT_DRIVERS), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_DEVICE_ICON), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_INF_LOGCONFIG), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DI_DONT_INSTALL), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_FILTER_DRIVER), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NON_WINDOWS_NT_DRIVER), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NON_WINDOWS_DRIVER), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_CATALOG_FOR_OEM_INF), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVINSTALL_QUEUE_NONNATIVE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NOT_DISABLEABLE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_CANT_REMOVE_DEVINST), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INVALID_TARGET), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DRIVER_NONNATIVE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_IN_WOW64), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_SET_SYSTEM_RESTORE_POINT), + + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_SCE_DISABLED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_UNKNOWN_EXCEPTION), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_PNP_REGISTRY_ERROR), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_REMOTE_REQUEST_UNSUPPORTED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NOT_AN_INSTALLED_OEM_INF), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_INF_IN_USE_BY_DEVICES), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DI_FUNCTION_OBSOLETE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_NO_AUTHENTICODE_CATALOG), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_AUTHENTICODE_DISALLOWED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_AUTHENTICODE_TRUSTED_PUBLISHER), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_ONLY_VALIDATE_VIA_AUTHENTICODE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVICE_INSTALLER_NOT_READY), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DRIVER_STORE_ADD_FAILED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DEVICE_INSTALL_BLOCKED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DRIVER_INSTALL_BLOCKED), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_WRONG_INF_TYPE), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_FILE_HASH_NOT_IN_CATALOG), + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_DRIVER_STORE_DELETE_FAILED), + + // + // Setupapi exception codes + // + SETUPAPI_ERROR_TABLE_ENTRY(ERROR_UNRECOVERABLE_STACK_OVERFLOW), +}; + +const char *IsolateFilename(const char *filepath) +{ + const auto slash = strrchr(filepath, '/'); + const auto backslash = strrchr(filepath, '\\'); + + if (nullptr == slash && nullptr == backslash) + { + return filepath; + } + + return max(slash, backslash) + 1; +} + +} // anonymous namespace + +bool IsSetupApiError(uint32_t code) +{ + const auto it = setupApiCodeToString.find(code); + return (setupApiCodeToString.end() != it); +} + +const char * FormatSetupApiError(uint32_t code) +{ + const auto it = setupApiCodeToString.find(code); + + if (setupApiCodeToString.end() == it) + { + return nullptr; + } + + return it->second; +} + +void ThrowSetupApiError(const char *operation, uint32_t code, const char *file, size_t line) +{ + const auto message = FormatSetupApiError(code); + + if (nullptr != message) + { + std::stringstream ss; + ss << operation << ": " << message + << " (0x" << std::setw(8) << std::setfill('0') << std::hex << code << ")" + << " (" << IsolateFilename(file) << ": " << line << ")"; + + throw common::error::WindowsException(ss.str().c_str(), code); + } + + // Fallback: Treat as a regular Windows error + common::error::Throw(operation, code, file, line); +} diff --git a/windows/driverlogic/src/error.h b/windows/driverlogic/src/error.h new file mode 100644 index 0000000000..4895345887 --- /dev/null +++ b/windows/driverlogic/src/error.h @@ -0,0 +1,14 @@ +#pragma once + +#include <cstdint> + + +bool IsSetupApiError(uint32_t code); +const char *FormatSetupApiError(uint32_t code); + +[[noreturn]] void ThrowSetupApiError(const char *operation, uint32_t code, const char *file, size_t line); + +#define THROW_SETUPAPI_ERROR(errorCode, operation)\ +{\ + ThrowSetupApiError(operation, errorCode, __FILE__, __LINE__);\ +} diff --git a/windows/driverlogic/src/stdafx.h b/windows/driverlogic/src/stdafx.h index f3a07375c7..70def10da6 100644 --- a/windows/driverlogic/src/stdafx.h +++ b/windows/driverlogic/src/stdafx.h @@ -11,6 +11,11 @@ // Windows Header Files: #include <windows.h> +#include <string> +#include <iostream> +#include <sstream> +#include <optional> + // TODO: reference additional headers your program requires here diff --git a/windows/windows-libraries b/windows/windows-libraries -Subproject ed2da7cb6b7ddf11b6f824258e842b91b453109 +Subproject c5abcd87bc057f2f0319a56037d1a9a721d6468 |
