summaryrefslogtreecommitdiffhomepage
path: root/windows/windns/src
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2018-05-25 16:31:35 +0200
committerOdd Stranne <odd@mullvad.net>2018-06-18 08:45:13 +0200
commit96d551f1126fa74dfc9bdb92573c9029efbbc411 (patch)
treeff52f453370b8c95f892b2ad21d074e8546fddbe /windows/windns/src
parent0107dc9c1c5b4ff630991a031ce528697967686e (diff)
downloadmullvadvpn-96d551f1126fa74dfc9bdb92573c9029efbbc411.tar.xz
mullvadvpn-96d551f1126fa74dfc9bdb92573c9029efbbc411.zip
Move windns into windows/windns
Diffstat (limited to 'windows/windns/src')
-rw-r--r--windows/windns/src/dnstest/dnstest.cppbin0 -> 8556 bytes
-rw-r--r--windows/windns/src/dnstest/dnstest.vcxproj218
-rw-r--r--windows/windns/src/dnstest/dnstest.vcxproj.filters111
-rw-r--r--windows/windns/src/dnstest/dnstest.vcxproj.user4
-rw-r--r--windows/windns/src/dnstest/stdafx.cppbin0 -> 590 bytes
-rw-r--r--windows/windns/src/dnstest/stdafx.hbin0 -> 642 bytes
-rw-r--r--windows/windns/src/dnstest/targetver.hbin0 -> 630 bytes
-rw-r--r--windows/windns/src/windns/comhelpers.cpp72
-rw-r--r--windows/windns/src/windns/comhelpers.h26
-rw-r--r--windows/windns/src/windns/configmanager.cpp86
-rw-r--r--windows/windns/src/windns/configmanager.h65
-rw-r--r--windows/windns/src/windns/consoletracesink.cpp8
-rw-r--r--windows/windns/src/windns/consoletracesink.h8
-rw-r--r--windows/windns/src/windns/dllmain.cppbin0 -> 378 bytes
-rw-r--r--windows/windns/src/windns/dnsconfig.cpp20
-rw-r--r--windows/windns/src/windns/dnsconfig.h42
-rw-r--r--windows/windns/src/windns/dnsreverter.cpp32
-rw-r--r--windows/windns/src/windns/dnsreverter.h19
-rw-r--r--windows/windns/src/windns/itracesink.h48
-rw-r--r--windows/windns/src/windns/macroargument.h23
-rw-r--r--windows/windns/src/windns/netconfigeventsink.cpp31
-rw-r--r--windows/windns/src/windns/netconfigeventsink.h20
-rw-r--r--windows/windns/src/windns/netconfighelpers.cpp55
-rw-r--r--windows/windns/src/windns/netconfighelpers.h25
-rw-r--r--windows/windns/src/windns/stdafx.cppbin0 -> 588 bytes
-rw-r--r--windows/windns/src/windns/stdafx.hbin0 -> 840 bytes
-rw-r--r--windows/windns/src/windns/targetver.hbin0 -> 766 bytes
-rw-r--r--windows/windns/src/windns/windns.cpp156
-rw-r--r--windows/windns/src/windns/windns.h80
-rw-r--r--windows/windns/src/windns/windns.vcxproj224
-rw-r--r--windows/windns/src/windns/windns.vcxproj.filters69
-rw-r--r--windows/windns/src/windns/windnscontext.cpp102
-rw-r--r--windows/windns/src/windns/windnscontext.h31
-rw-r--r--windows/windns/src/windns/wmi/connection.cpp69
-rw-r--r--windows/windns/src/windns/wmi/connection.h44
-rw-r--r--windows/windns/src/windns/wmi/eventsink.cpp93
-rw-r--r--windows/windns/src/windns/wmi/eventsink.h55
-rw-r--r--windows/windns/src/windns/wmi/iconnection.h20
-rw-r--r--windows/windns/src/windns/wmi/methodcall.cpp104
-rw-r--r--windows/windns/src/windns/wmi/methodcall.h75
-rw-r--r--windows/windns/src/windns/wmi/notification.cpp72
-rw-r--r--windows/windns/src/windns/wmi/notification.h34
-rw-r--r--windows/windns/src/windns/wmi/resultset.cpp34
-rw-r--r--windows/windns/src/windns/wmi/resultset.h31
44 files changed, 2206 insertions, 0 deletions
diff --git a/windows/windns/src/dnstest/dnstest.cpp b/windows/windns/src/dnstest/dnstest.cpp
new file mode 100644
index 0000000000..76ae8615a4
--- /dev/null
+++ b/windows/windns/src/dnstest/dnstest.cpp
Binary files differ
diff --git a/windows/windns/src/dnstest/dnstest.vcxproj b/windows/windns/src/dnstest/dnstest.vcxproj
new file mode 100644
index 0000000000..4e8b9776a6
--- /dev/null
+++ b/windows/windns/src/dnstest/dnstest.vcxproj
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{1476A8B9-4A9E-4358-8744-A350CB97E152}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>dnstest</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
+ <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
+ <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
+ <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
+ <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../wfpctl/libwfp/src</AdditionalIncludeDirectories>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
+ <AdditionalDependencies>windns.lib;libcommon.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../wfpctl/libwfp/src</AdditionalIncludeDirectories>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
+ <AdditionalDependencies>windns.lib;libcommon.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../wfpctl/libwfp/src</AdditionalIncludeDirectories>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
+ <AdditionalDependencies>windns.lib;libcommon.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../wfpctl/libwfp/src</AdditionalIncludeDirectories>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
+ <AdditionalDependencies>windns.lib;libcommon.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\windns\comhelpers.h" />
+ <ClInclude Include="..\windns\configmanager.h" />
+ <ClInclude Include="..\windns\consoletracesink.h" />
+ <ClInclude Include="..\windns\dnsconfig.h" />
+ <ClInclude Include="..\windns\dnsreverter.h" />
+ <ClInclude Include="..\windns\netconfigeventsink.h" />
+ <ClInclude Include="..\windns\netconfighelpers.h" />
+ <ClInclude Include="..\windns\wmi\connection.h" />
+ <ClInclude Include="..\windns\wmi\eventsink.h" />
+ <ClInclude Include="..\windns\wmi\iconnection.h" />
+ <ClInclude Include="..\windns\wmi\methodcall.h" />
+ <ClInclude Include="..\windns\wmi\notification.h" />
+ <ClInclude Include="..\windns\wmi\resultset.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\windns\comhelpers.cpp" />
+ <ClCompile Include="..\windns\configmanager.cpp" />
+ <ClCompile Include="..\windns\consoletracesink.cpp" />
+ <ClCompile Include="..\windns\dnsconfig.cpp" />
+ <ClCompile Include="..\windns\dnsreverter.cpp" />
+ <ClCompile Include="..\windns\netconfigeventsink.cpp" />
+ <ClCompile Include="..\windns\netconfighelpers.cpp" />
+ <ClCompile Include="..\windns\wmi\connection.cpp" />
+ <ClCompile Include="..\windns\wmi\eventsink.cpp" />
+ <ClCompile Include="..\windns\wmi\methodcall.cpp" />
+ <ClCompile Include="..\windns\wmi\notification.cpp" />
+ <ClCompile Include="..\windns\wmi\resultset.cpp" />
+ <ClCompile Include="dnstest.cpp" />
+ <ClCompile Include="stdafx.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/windows/windns/src/dnstest/dnstest.vcxproj.filters b/windows/windns/src/dnstest/dnstest.vcxproj.filters
new file mode 100644
index 0000000000..07cecae9a7
--- /dev/null
+++ b/windows/windns/src/dnstest/dnstest.vcxproj.filters
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="other files">
+ <UniqueIdentifier>{f6f1a55f-c90a-4972-9986-37b42d9ae7a0}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="stdafx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="targetver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\wmi\connection.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\wmi\iconnection.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\wmi\resultset.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\wmi\methodcall.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\comhelpers.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\configmanager.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\dnsconfig.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\consoletracesink.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\wmi\eventsink.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\netconfigeventsink.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\netconfighelpers.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\wmi\notification.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\windns\dnsreverter.h">
+ <Filter>other files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="stdafx.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dnstest.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\wmi\connection.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\wmi\resultset.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\wmi\methodcall.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\comhelpers.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\configmanager.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\dnsconfig.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\consoletracesink.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\wmi\eventsink.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\netconfigeventsink.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\netconfighelpers.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\wmi\notification.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\windns\dnsreverter.cpp">
+ <Filter>other files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/windows/windns/src/dnstest/dnstest.vcxproj.user b/windows/windns/src/dnstest/dnstest.vcxproj.user
new file mode 100644
index 0000000000..be25078707
--- /dev/null
+++ b/windows/windns/src/dnstest/dnstest.vcxproj.user
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup />
+</Project> \ No newline at end of file
diff --git a/windows/windns/src/dnstest/stdafx.cpp b/windows/windns/src/dnstest/stdafx.cpp
new file mode 100644
index 0000000000..cb6d7f782d
--- /dev/null
+++ b/windows/windns/src/dnstest/stdafx.cpp
Binary files differ
diff --git a/windows/windns/src/dnstest/stdafx.h b/windows/windns/src/dnstest/stdafx.h
new file mode 100644
index 0000000000..94d4ed877d
--- /dev/null
+++ b/windows/windns/src/dnstest/stdafx.h
Binary files differ
diff --git a/windows/windns/src/dnstest/targetver.h b/windows/windns/src/dnstest/targetver.h
new file mode 100644
index 0000000000..567cd346ef
--- /dev/null
+++ b/windows/windns/src/dnstest/targetver.h
Binary files differ
diff --git a/windows/windns/src/windns/comhelpers.cpp b/windows/windns/src/windns/comhelpers.cpp
new file mode 100644
index 0000000000..dea61b40d9
--- /dev/null
+++ b/windows/windns/src/windns/comhelpers.cpp
@@ -0,0 +1,72 @@
+#include "stdafx.h"
+#include "comhelpers.h"
+#include <algorithm>
+
+_variant_t ComGetProperty(CComPtr<IWbemClassObject> obj, const std::wstring &name)
+{
+ _variant_t val;
+
+ const auto status = obj->Get(name.c_str(), 0, &val, nullptr, nullptr);
+
+ VALIDATE_COM(status, "Retrieve COM property value");
+
+ return val;
+}
+
+_variant_t ComGetPropertyAlways(CComPtr<IWbemClassObject> obj, const std::wstring &name)
+{
+ auto val = ComGetProperty(obj, name);
+
+ if (VT_EMPTY == V_VT(&val) || VT_NULL == V_VT(&val))
+ {
+ throw std::runtime_error("A required COM property value is empty.");
+ }
+
+ return val;
+}
+
+std::wstring ComConvertString(BSTR src)
+{
+ return std::wstring(src, SysStringLen(src));
+}
+
+std::vector<std::wstring> ComConvertStringArray(SAFEARRAY *src)
+{
+ CComSafeArray<BSTR> safeArray(src);
+
+ std::vector<std::wstring> result;
+ result.reserve(safeArray.GetCount());
+
+ for (ULONG i = 0; i < safeArray.GetCount(); ++i)
+ {
+ result.emplace_back(ComConvertString(safeArray.GetAt(i)));
+ }
+
+ return result;
+}
+
+CComSafeArray<BSTR> ComConvertIntoStringArray(const std::vector<std::wstring> &src)
+{
+ CComSafeArray<BSTR> result;
+
+ std::for_each(src.begin(), src.end(), [&](const std::wstring &str)
+ {
+ result.Add(_bstr_t(str.c_str()));
+ });
+
+ return result;
+}
+
+_variant_t ComPackageStringArray(CComSafeArray<BSTR> &src)
+{
+ VARIANT v;
+
+ V_VT(&v) = VT_ARRAY | VT_BSTR;
+ V_ARRAY(&v) = src.Detach();
+
+ _variant_t vv;
+
+ vv.Attach(v);
+
+ return vv;
+} \ No newline at end of file
diff --git a/windows/windns/src/windns/comhelpers.h b/windows/windns/src/windns/comhelpers.h
new file mode 100644
index 0000000000..67e1a46aea
--- /dev/null
+++ b/windows/windns/src/windns/comhelpers.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "libcommon/error.h"
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <winerror.h>
+#include <atlbase.h>
+#include <comutil.h>
+#include <atlsafe.h>
+#include <wbemidl.h>
+
+#define VALIDATE_COM(status, operation)\
+if(FAILED(status))\
+{\
+ ::common::error::Throw(operation, status);\
+}
+
+_variant_t ComGetProperty(CComPtr<IWbemClassObject> obj, const std::wstring &name);
+_variant_t ComGetPropertyAlways(CComPtr<IWbemClassObject> obj, const std::wstring &name);
+std::wstring ComConvertString(BSTR src);
+std::vector<std::wstring> ComConvertStringArray(SAFEARRAY *src);
+CComSafeArray<BSTR> ComConvertIntoStringArray(const std::vector<std::wstring> &src);
+
+// NOTE: This consumes the source variable
+_variant_t ComPackageStringArray(CComSafeArray<BSTR> &src);
diff --git a/windows/windns/src/windns/configmanager.cpp b/windows/windns/src/windns/configmanager.cpp
new file mode 100644
index 0000000000..5efb48d2d0
--- /dev/null
+++ b/windows/windns/src/windns/configmanager.cpp
@@ -0,0 +1,86 @@
+#include "stdafx.h"
+#include "configmanager.h"
+#include <utility>
+#include <algorithm>
+
+ConfigManager::ConfigManager
+(
+ const std::vector<std::wstring> &servers,
+ std::shared_ptr<ITraceSink> traceSink
+)
+ : m_servers(servers)
+ , m_traceSink(traceSink)
+{
+}
+
+void ConfigManager::lock()
+{
+ m_mutex.lock();
+}
+
+void ConfigManager::unlock()
+{
+ m_mutex.unlock();
+}
+
+void ConfigManager::updateServers(const std::vector<std::wstring> &servers)
+{
+ XTRACE(L"Updating DNS server list");
+ m_servers = servers;
+}
+
+const std::vector<std::wstring> &ConfigManager::getServers() const
+{
+ return m_servers;
+}
+
+bool ConfigManager::updateConfig(DnsConfig &&config)
+{
+ XTRACE(L"Interface configuration update for interface =", config.interfaceIndex());
+
+ if (false == validUpdate(config))
+ {
+ XTRACE(L"Ignoring interface configuration update");
+ return false;
+ }
+
+ auto iter = m_configs.find(config.id());
+
+ if (m_configs.end() == iter)
+ {
+ XTRACE(L"Creating new interface configuration entry");
+ m_configs.insert(std::make_pair(config.id(), std::move(config)));
+ }
+ else
+ {
+ XTRACE(L"Updating interface configuration entry");
+ iter->second = std::move(config);
+ }
+
+ return true;
+}
+
+bool ConfigManager::processConfigs(std::function<bool(const DnsConfig &)> configSink)
+{
+ for (auto it = m_configs.begin(); it != m_configs.end(); ++it)
+ {
+ if (false == configSink(it->second))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ConfigManager::validUpdate(const DnsConfig &config)
+{
+ auto updatedServers = config.servers();
+
+ if (nullptr == updatedServers)
+ {
+ return true;
+ }
+
+ return false == std::equal(m_servers.begin(), m_servers.end(), updatedServers->begin(), updatedServers->end());
+}
diff --git a/windows/windns/src/windns/configmanager.h b/windows/windns/src/windns/configmanager.h
new file mode 100644
index 0000000000..3760319bbb
--- /dev/null
+++ b/windows/windns/src/windns/configmanager.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "dnsconfig.h"
+#include "itracesink.h"
+#include <map>
+#include <string>
+#include <mutex>
+#include <memory>
+#include <functional>
+
+class ConfigManager
+{
+public:
+
+ struct Mutex
+ {
+ Mutex(const Mutex &) = delete;
+ Mutex &operator=(const Mutex &) = delete;
+ Mutex(Mutex &&) = delete;
+ Mutex &operator=(Mutex &&) = delete;
+
+ Mutex(ConfigManager &manager)
+ : m_manager(manager)
+ {
+ m_manager.lock();
+ }
+
+ ~Mutex()
+ {
+ m_manager.unlock();
+ }
+
+ ConfigManager &m_manager;
+ };
+
+ //
+ // "servers" specifies the set of servers used when overriding settings.
+ // This enables filtering out the corresponding event.
+ //
+ ConfigManager
+ (
+ const std::vector<std::wstring> &servers,
+ std::shared_ptr<ITraceSink> traceSink = std::make_shared<NullTraceSink>()
+ );
+
+ void lock();
+ void unlock();
+
+ void updateServers(const std::vector<std::wstring> &servers);
+ const std::vector<std::wstring> &getServers() const;
+
+ bool updateConfig(DnsConfig &&config);
+
+ bool processConfigs(std::function<bool(const DnsConfig &)> configSink);
+
+private:
+
+ std::mutex m_mutex;
+ std::vector<std::wstring> m_servers;
+ std::map<std::wstring, DnsConfig> m_configs;
+
+ std::shared_ptr<ITraceSink> m_traceSink;
+
+ bool validUpdate(const DnsConfig &config);
+};
diff --git a/windows/windns/src/windns/consoletracesink.cpp b/windows/windns/src/windns/consoletracesink.cpp
new file mode 100644
index 0000000000..6e3d415303
--- /dev/null
+++ b/windows/windns/src/windns/consoletracesink.cpp
@@ -0,0 +1,8 @@
+#include "stdafx.h"
+#include "consoletracesink.h"
+#include <iostream>
+
+void ConsoleTraceSink::trace(const wchar_t *msg)
+{
+ std::wcout << msg << std::endl;
+}
diff --git a/windows/windns/src/windns/consoletracesink.h b/windows/windns/src/windns/consoletracesink.h
new file mode 100644
index 0000000000..765fb4a2a0
--- /dev/null
+++ b/windows/windns/src/windns/consoletracesink.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "itracesink.h"
+
+struct ConsoleTraceSink : public ITraceSink
+{
+ void trace(const wchar_t *msg) override;
+};
diff --git a/windows/windns/src/windns/dllmain.cpp b/windows/windns/src/windns/dllmain.cpp
new file mode 100644
index 0000000000..dfde574841
--- /dev/null
+++ b/windows/windns/src/windns/dllmain.cpp
Binary files differ
diff --git a/windows/windns/src/windns/dnsconfig.cpp b/windows/windns/src/windns/dnsconfig.cpp
new file mode 100644
index 0000000000..5a7ca42096
--- /dev/null
+++ b/windows/windns/src/windns/dnsconfig.cpp
@@ -0,0 +1,20 @@
+#include "stdafx.h"
+#include "dnsconfig.h"
+#include "windns/comhelpers.h"
+
+DnsConfig::DnsConfig(CComPtr<IWbemClassObject> instance)
+{
+ m_configId = nchelpers::GetConfigId(instance);
+ m_interfaceIndex = ComGetPropertyAlways(instance, L"InterfaceIndex").uintVal;
+ m_servers = nchelpers::GetDnsServers(instance);
+}
+
+const std::vector<std::wstring> *DnsConfig::servers() const
+{
+ return m_servers.get();
+}
+
+//void DnsConfig::update(CComPtr<IWbemClassObject> instance)
+//{
+// m_servers = nchelpers::GetDnsServers(instance);
+//}
diff --git a/windows/windns/src/windns/dnsconfig.h b/windows/windns/src/windns/dnsconfig.h
new file mode 100644
index 0000000000..bb9a841c8e
--- /dev/null
+++ b/windows/windns/src/windns/dnsconfig.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "windns/netconfighelpers.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+#include <memory>
+#include <atlbase.h>
+#include <wbemidl.h>
+
+class DnsConfig
+{
+public:
+
+ // instance = Win32_NetworkAdapterConfiguration.
+ DnsConfig(CComPtr<IWbemClassObject> instance);
+
+ DnsConfig(const DnsConfig &) = delete;
+ DnsConfig &operator=(const DnsConfig &) = delete;
+ DnsConfig(DnsConfig &&) = default;
+ DnsConfig &operator=(DnsConfig &&) = default;
+
+ const std::wstring &id() const
+ {
+ return m_configId;
+ }
+
+ uint32_t interfaceIndex() const
+ {
+ return m_interfaceIndex;
+ }
+
+ const std::vector<std::wstring> *servers() const;
+
+// void update(CComPtr<IWbemClassObject> instance);
+
+private:
+
+ std::wstring m_configId;
+ uint32_t m_interfaceIndex;
+ nchelpers::OptionalStringList m_servers;
+};
diff --git a/windows/windns/src/windns/dnsreverter.cpp b/windows/windns/src/windns/dnsreverter.cpp
new file mode 100644
index 0000000000..12d15e7bbc
--- /dev/null
+++ b/windows/windns/src/windns/dnsreverter.cpp
@@ -0,0 +1,32 @@
+#include "stdafx.h"
+#include "dnsreverter.h"
+#include "wmi/methodcall.h"
+#include <sstream>
+
+DnsReverter::DnsReverter(std::shared_ptr<ITraceSink> traceSink)
+ : m_traceSink(traceSink)
+{
+}
+
+void DnsReverter::revert(wmi::IConnection &connection, const DnsConfig &config)
+{
+ XTRACE("Reverting DNS configuration for interface with index=", config.interfaceIndex());
+
+ std::wstringstream ss;
+
+ ss << L"SELECT * FROM Win32_NetworkAdapterConfiguration "
+ << L"WHERE SettingID = '" << config.id() << L"'";
+
+ auto resultSet = connection.query(ss.str().c_str());
+
+ if (false == resultSet.advance())
+ {
+ XTRACE("Unable to retrieve active configuration");
+ return;
+ }
+
+ auto activeConfig = resultSet.result();
+ auto targetDns = config.servers();
+
+ nchelpers::SetDnsServers(connection, activeConfig, targetDns);
+}
diff --git a/windows/windns/src/windns/dnsreverter.h b/windows/windns/src/windns/dnsreverter.h
new file mode 100644
index 0000000000..98de9caa8c
--- /dev/null
+++ b/windows/windns/src/windns/dnsreverter.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "wmi/iconnection.h"
+#include "dnsconfig.h"
+#include "itracesink.h"
+#include <memory>
+
+class DnsReverter
+{
+public:
+
+ DnsReverter(std::shared_ptr<ITraceSink> traceSink = std::make_shared<NullTraceSink>());
+
+ void revert(wmi::IConnection &connection, const DnsConfig &config);
+
+private:
+
+ std::shared_ptr<ITraceSink> m_traceSink;
+};
diff --git a/windows/windns/src/windns/itracesink.h b/windows/windns/src/windns/itracesink.h
new file mode 100644
index 0000000000..496a7df1b9
--- /dev/null
+++ b/windows/windns/src/windns/itracesink.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <sstream>
+
+struct ITraceSink
+{
+ virtual ~ITraceSink() = 0
+ {
+ }
+
+ virtual void trace(const wchar_t *msg) = 0;
+};
+
+struct NullTraceSink : public ITraceSink
+{
+ void trace(const wchar_t *) override
+ {
+ }
+};
+
+#ifdef _DEBUG
+#define TRACING_ENABLED 1
+#else
+#define TRACING_ENABLED 0
+#endif
+
+#if TRACING_ENABLED == 1
+
+#include "macroargument.h"
+#define XTRACE(...) VFUNC(XTRACE, __VA_ARGS__)
+
+#define XTRACE1(x)\
+{\
+std::wstringstream xtrace_ss;\
+xtrace_ss << __FUNCTIONW__ << L": " << x;\
+m_traceSink->trace(xtrace_ss.str().c_str());\
+}
+
+#define XTRACE2(x, y)\
+{\
+std::wstringstream xtrace_ss;\
+xtrace_ss << __FUNCTIONW__ << L": " << x << L" " << y;\
+m_traceSink->trace(xtrace_ss.str().c_str());\
+}
+
+#else
+#define XTRACE(...)
+#endif
diff --git a/windows/windns/src/windns/macroargument.h b/windows/windns/src/windns/macroargument.h
new file mode 100644
index 0000000000..bb27c124c8
--- /dev/null
+++ b/windows/windns/src/windns/macroargument.h
@@ -0,0 +1,23 @@
+#pragma once
+
+//http://www.neff.co.at/2017/04/04/Overloading-Macros-on-the-Number-of-Arguments.html
+
+// Some auxiliary macros
+#define EMPTY()
+#define EXPAND(X) X
+#define CONCAT(X,Y) X##Y
+
+// Get number of arguments passed by __VA_ARGS__
+// http://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments
+// NUMARGS: all arguments must be castable to int
+// NARGS: pure preprocessor macro, maximum 9 arguments
+#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
+#define NARGS(...) _NARGS_I(_AUGMENT(__VA_ARGS__))
+#define _AUGMENT(...) _UNUSED_, __VA_ARGS__
+#define _NARGS_I(...) EXPAND(_ARG_N(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+#define _ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, count, ...) count
+
+// Overloading Macro on Number of Arguments
+// http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments
+#define _VFUNC(NAME, N) CONCAT(NAME, N)
+#define VFUNC(FUNC, ...) CONCAT(_VFUNC(FUNC, NARGS(__VA_ARGS__))(__VA_ARGS__),EMPTY())
diff --git a/windows/windns/src/windns/netconfigeventsink.cpp b/windows/windns/src/windns/netconfigeventsink.cpp
new file mode 100644
index 0000000000..6a506e3f3f
--- /dev/null
+++ b/windows/windns/src/windns/netconfigeventsink.cpp
@@ -0,0 +1,31 @@
+#include "stdafx.h"
+#include "netconfigeventsink.h"
+#include "windns/netconfighelpers.h"
+
+NetConfigEventSink::NetConfigEventSink(std::shared_ptr<wmi::IConnection> connection, std::shared_ptr<ConfigManager> configManager)
+ : m_connection(connection)
+ , m_configManager(configManager)
+{
+}
+
+void NetConfigEventSink::update(CComPtr<IWbemClassObject> instance)
+{
+ DnsConfig config(instance);
+
+ ConfigManager::Mutex mutex(*m_configManager);
+
+ //
+ // This is OK because the config manager will reject updates
+ // that set our DNS servers.
+ //
+ auto updated = m_configManager->updateConfig(std::move(config));
+
+ if (updated)
+ {
+ //
+ // Override current settings to use our DNS servers.
+ //
+ auto servers = m_configManager->getServers();
+ nchelpers::SetDnsServers(*m_connection, instance, &servers);
+ }
+}
diff --git a/windows/windns/src/windns/netconfigeventsink.h b/windows/windns/src/windns/netconfigeventsink.h
new file mode 100644
index 0000000000..35ab829a08
--- /dev/null
+++ b/windows/windns/src/windns/netconfigeventsink.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "windns/wmi/eventsink.h"
+#include "windns/wmi/iconnection.h"
+#include "windns/configmanager.h"
+#include <memory>
+
+class NetConfigEventSink : public wmi::IEventSink
+{
+public:
+
+ explicit NetConfigEventSink(std::shared_ptr<wmi::IConnection> connection, std::shared_ptr<ConfigManager> configManager);
+
+ void update(CComPtr<IWbemClassObject> instance) override;
+
+private:
+
+ std::shared_ptr<wmi::IConnection> m_connection;
+ std::shared_ptr<ConfigManager> m_configManager;
+};
diff --git a/windows/windns/src/windns/netconfighelpers.cpp b/windows/windns/src/windns/netconfighelpers.cpp
new file mode 100644
index 0000000000..f95dd39ee4
--- /dev/null
+++ b/windows/windns/src/windns/netconfighelpers.cpp
@@ -0,0 +1,55 @@
+#include "stdafx.h"
+#include "netconfighelpers.h"
+#include "comhelpers.h"
+#include "wmi/methodcall.h"
+
+namespace nchelpers
+{
+
+std::wstring GetConfigId(CComPtr<IWbemClassObject> instance)
+{
+ return ComConvertString(V_BSTR(&ComGetPropertyAlways(instance, L"SettingID")));
+}
+
+OptionalStringList GetDnsServers(CComPtr<IWbemClassObject> instance)
+{
+ OptionalStringList result;
+
+ auto servers = ComGetProperty(instance, L"DNSServerSearchOrder");
+
+ if (VT_EMPTY == V_VT(&servers) || VT_NULL == V_VT(&servers))
+ {
+ return result;
+ }
+
+ result = std::make_unique<std::vector<std::wstring> >(
+ ComConvertStringArray(V_ARRAY(&servers)));
+
+ return result;
+}
+
+void SetDnsServers(wmi::IConnection &connection, CComPtr<IWbemClassObject> instance,
+ const std::vector<std::wstring> *servers)
+{
+ wmi::MethodCall methodCall;
+
+ if (nullptr == servers)
+ {
+ methodCall.addNullArgument(L"DNSServerSearchOrder", VT_ARRAY | VT_BSTR);
+ }
+ else
+ {
+ auto comServers = ComConvertIntoStringArray(*servers);
+ methodCall.addArgument(L"DNSServerSearchOrder", ComPackageStringArray(comServers));
+ }
+
+ auto status = methodCall.invoke(connection, instance, L"SetDNSServerSearchOrder");
+
+ //
+ // TODO check status, (type? expected value?)
+ //
+
+ return;
+}
+
+}
diff --git a/windows/windns/src/windns/netconfighelpers.h b/windows/windns/src/windns/netconfighelpers.h
new file mode 100644
index 0000000000..6949eced7e
--- /dev/null
+++ b/windows/windns/src/windns/netconfighelpers.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "wmi/iconnection.h"
+#include <string>
+#include <memory>
+#include <vector>
+#include <atlbase.h>
+#include <wbemidl.h>
+
+namespace nchelpers
+{
+
+// instance = Win32_NetworkAdapterConfiguration
+std::wstring GetConfigId(CComPtr<IWbemClassObject> instance);
+
+using OptionalStringList = std::unique_ptr<std::vector<std::wstring> >;
+
+// instance = Win32_NetworkAdapterConfiguration
+OptionalStringList GetDnsServers(CComPtr<IWbemClassObject> instance);
+
+// instance = Win32_NetworkAdapterConfiguration
+void SetDnsServers(wmi::IConnection &connection, CComPtr<IWbemClassObject> instance,
+ const std::vector<std::wstring> *servers);
+
+}
diff --git a/windows/windns/src/windns/stdafx.cpp b/windows/windns/src/windns/stdafx.cpp
new file mode 100644
index 0000000000..4fdd5990e4
--- /dev/null
+++ b/windows/windns/src/windns/stdafx.cpp
Binary files differ
diff --git a/windows/windns/src/windns/stdafx.h b/windows/windns/src/windns/stdafx.h
new file mode 100644
index 0000000000..b937b12ccd
--- /dev/null
+++ b/windows/windns/src/windns/stdafx.h
Binary files differ
diff --git a/windows/windns/src/windns/targetver.h b/windows/windns/src/windns/targetver.h
new file mode 100644
index 0000000000..932a2e87b6
--- /dev/null
+++ b/windows/windns/src/windns/targetver.h
Binary files differ
diff --git a/windows/windns/src/windns/windns.cpp b/windows/windns/src/windns/windns.cpp
new file mode 100644
index 0000000000..7a9977951f
--- /dev/null
+++ b/windows/windns/src/windns/windns.cpp
@@ -0,0 +1,156 @@
+#include "stdafx.h"
+#include "windns.h"
+#include "windnscontext.h"
+#include <vector>
+#include <string>
+
+namespace
+{
+
+WinDnsErrorSink g_ErrorSink = nullptr;
+void *g_ErrorContext = nullptr;
+
+WinDnsContext *g_Context = nullptr;
+
+std::vector<std::wstring> MakeStringArray(const wchar_t **strings, uint32_t numStrings)
+{
+ std::vector<std::wstring> v;
+
+ while (numStrings--)
+ {
+ v.emplace_back(*strings++);
+ }
+
+ return v;
+}
+
+} // anonymous namespace
+
+WINDNS_LINKAGE
+bool
+WINDNS_API
+WinDns_Initialize(
+ WinDnsErrorSink errorSink,
+ void *errorContext
+)
+{
+ if (nullptr != g_Context)
+ {
+ return false;
+ }
+
+ g_ErrorSink = errorSink;
+ g_ErrorContext = errorContext;
+
+ try
+ {
+ g_Context = new WinDnsContext;
+ }
+ catch (std::exception &err)
+ {
+ if (nullptr != g_ErrorSink)
+ {
+ g_ErrorSink(err.what(), g_ErrorContext);
+ }
+
+ return false;
+ }
+ catch (...)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+WINDNS_LINKAGE
+bool
+WINDNS_API
+WinDns_Deinitialize(
+)
+{
+ if (nullptr == g_Context)
+ {
+ return true;
+ }
+
+ delete g_Context;
+ g_Context = nullptr;
+
+ return true;
+}
+
+WINDNS_LINKAGE
+bool
+WINDNS_API
+WinDns_Set(
+ const wchar_t **servers,
+ uint32_t numServers
+)
+{
+ if (nullptr == g_Context)
+ {
+ return false;
+ }
+
+ try
+ {
+ //
+ // TODO: This is a temporary hack to enable alpha version. Review.
+ //
+
+ delete g_Context;
+ g_Context = nullptr;
+
+ g_Context = new WinDnsContext;
+
+ //
+ // Onwards.
+ //
+
+ return g_Context->set(MakeStringArray(servers, numServers), g_ErrorSink, g_ErrorContext);
+ }
+ catch (std::exception &err)
+ {
+ if (nullptr != g_ErrorSink)
+ {
+ g_ErrorSink(err.what(), g_ErrorContext);
+ }
+
+ return false;
+ }
+ catch (...)
+ {
+ return false;
+ }
+}
+
+WINDNS_LINKAGE
+bool
+WINDNS_API
+WinDns_Reset(
+)
+{
+ if (nullptr == g_Context)
+ {
+ return false;
+ }
+
+ try
+ {
+ return g_Context->reset();
+ }
+ catch (std::exception &err)
+ {
+ if (nullptr != g_ErrorSink)
+ {
+ g_ErrorSink(err.what(), g_ErrorContext);
+ }
+
+ return false;
+ }
+ catch (...)
+ {
+ return false;
+ }
+}
diff --git a/windows/windns/src/windns/windns.h b/windows/windns/src/windns/windns.h
new file mode 100644
index 0000000000..000913ad53
--- /dev/null
+++ b/windows/windns/src/windns/windns.h
@@ -0,0 +1,80 @@
+#pragma once
+#include <cstdint>
+
+//
+// WINDNS public API
+//
+
+#ifdef WINDNS_EXPORTS
+#define WINDNS_LINKAGE __declspec(dllexport)
+#else
+#define WINDNS_LINKAGE __declspec(dllimport)
+#endif
+
+#define WINDNS_API __stdcall
+
+///////////////////////////////////////////////////////////////////////////////
+// Functions
+///////////////////////////////////////////////////////////////////////////////
+
+typedef void (WINDNS_API *WinDnsErrorSink)(const char *errorMessage, void *context);
+
+//
+// WinDns_Initialize:
+//
+// Call this function once at startup, to acquire resources etc.
+//
+// The OPTIONAL error callback is remembered and used to report exceptions that
+// occur as a direct or indirect result of calling into WINDNS.
+//
+// (Recall that the monitoring provided by WINDNS is threaded.)
+//
+extern "C"
+WINDNS_LINKAGE
+bool
+WINDNS_API
+WinDns_Initialize(
+ WinDnsErrorSink errorSink,
+ void *errorContext
+);
+
+//
+// WinDns_Deinitialize:
+//
+// Call this function once before unloading WINDNS or exiting the process.
+//
+extern "C"
+WINDNS_LINKAGE
+bool
+WINDNS_API
+WinDns_Deinitialize(
+);
+
+//
+// WinDns_Set:
+//
+// Configure which DNS servers should be used and start enforcing these settings.
+//
+extern "C"
+WINDNS_LINKAGE
+bool
+WINDNS_API
+WinDns_Set(
+ const wchar_t **servers,
+ uint32_t numServers
+);
+
+//
+// Windns_Reset:
+//
+// Revert server settings to what they were before calling WinDns_Set.
+//
+// (Also taking into account external changes to DNS settings that have occurred
+// during the period of enforcing specific settings.)
+//
+extern "C"
+WINDNS_LINKAGE
+bool
+WINDNS_API
+WinDns_Reset(
+);
diff --git a/windows/windns/src/windns/windns.vcxproj b/windows/windns/src/windns/windns.vcxproj
new file mode 100644
index 0000000000..6554ca06ce
--- /dev/null
+++ b/windows/windns/src/windns/windns.vcxproj
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{A5344205-FC37-4572-9C63-8564ECC410AC}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>windns</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
+ <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
+ <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
+ <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
+ <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../wfpctl/libwfp/src</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libcommon.lib;wbemuuid.lib;comsuppw.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;_DEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../wfpctl/libwfp/src</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libcommon.lib;wbemuuid.lib;comsuppw.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;NDEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../wfpctl/libwfp/src</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libcommon.lib;wbemuuid.lib;comsuppw.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../wfpctl/libwfp/src</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libcommon.lib;wbemuuid.lib;comsuppw.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="comhelpers.h" />
+ <ClInclude Include="configmanager.h" />
+ <ClInclude Include="consoletracesink.h" />
+ <ClInclude Include="dnsconfig.h" />
+ <ClInclude Include="dnsreverter.h" />
+ <ClInclude Include="itracesink.h" />
+ <ClInclude Include="macroargument.h" />
+ <ClInclude Include="netconfigeventsink.h" />
+ <ClInclude Include="netconfighelpers.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="windns.h" />
+ <ClInclude Include="windnscontext.h" />
+ <ClInclude Include="wmi\connection.h" />
+ <ClInclude Include="wmi\eventsink.h" />
+ <ClInclude Include="wmi\iconnection.h" />
+ <ClInclude Include="wmi\methodcall.h" />
+ <ClInclude Include="wmi\notification.h" />
+ <ClInclude Include="wmi\resultset.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="comhelpers.cpp" />
+ <ClCompile Include="configmanager.cpp" />
+ <ClCompile Include="consoletracesink.cpp" />
+ <ClCompile Include="dllmain.cpp" />
+ <ClCompile Include="dnsconfig.cpp" />
+ <ClCompile Include="dnsreverter.cpp" />
+ <ClCompile Include="netconfigeventsink.cpp" />
+ <ClCompile Include="netconfighelpers.cpp" />
+ <ClCompile Include="stdafx.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="windns.cpp" />
+ <ClCompile Include="windnscontext.cpp" />
+ <ClCompile Include="wmi\connection.cpp" />
+ <ClCompile Include="wmi\eventsink.cpp" />
+ <ClCompile Include="wmi\methodcall.cpp" />
+ <ClCompile Include="wmi\notification.cpp" />
+ <ClCompile Include="wmi\resultset.cpp" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/windows/windns/src/windns/windns.vcxproj.filters b/windows/windns/src/windns/windns.vcxproj.filters
new file mode 100644
index 0000000000..2e7658c7a7
--- /dev/null
+++ b/windows/windns/src/windns/windns.vcxproj.filters
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="wmi\connection.h">
+ <Filter>wmi</Filter>
+ </ClInclude>
+ <ClInclude Include="wmi\resultset.h">
+ <Filter>wmi</Filter>
+ </ClInclude>
+ <ClInclude Include="wmi\iconnection.h">
+ <Filter>wmi</Filter>
+ </ClInclude>
+ <ClInclude Include="windns.h" />
+ <ClInclude Include="windnscontext.h" />
+ <ClInclude Include="wmi\methodcall.h">
+ <Filter>wmi</Filter>
+ </ClInclude>
+ <ClInclude Include="comhelpers.h" />
+ <ClInclude Include="configmanager.h" />
+ <ClInclude Include="dnsconfig.h" />
+ <ClInclude Include="itracesink.h" />
+ <ClInclude Include="consoletracesink.h" />
+ <ClInclude Include="wmi\eventsink.h">
+ <Filter>wmi</Filter>
+ </ClInclude>
+ <ClInclude Include="netconfigeventsink.h" />
+ <ClInclude Include="netconfighelpers.h" />
+ <ClInclude Include="macroargument.h" />
+ <ClInclude Include="wmi\notification.h">
+ <Filter>wmi</Filter>
+ </ClInclude>
+ <ClInclude Include="dnsreverter.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dllmain.cpp" />
+ <ClCompile Include="stdafx.cpp" />
+ <ClCompile Include="wmi\connection.cpp">
+ <Filter>wmi</Filter>
+ </ClCompile>
+ <ClCompile Include="wmi\resultset.cpp">
+ <Filter>wmi</Filter>
+ </ClCompile>
+ <ClCompile Include="windns.cpp" />
+ <ClCompile Include="windnscontext.cpp" />
+ <ClCompile Include="wmi\methodcall.cpp">
+ <Filter>wmi</Filter>
+ </ClCompile>
+ <ClCompile Include="comhelpers.cpp" />
+ <ClCompile Include="configmanager.cpp" />
+ <ClCompile Include="dnsconfig.cpp" />
+ <ClCompile Include="consoletracesink.cpp" />
+ <ClCompile Include="wmi\eventsink.cpp">
+ <Filter>wmi</Filter>
+ </ClCompile>
+ <ClCompile Include="netconfigeventsink.cpp" />
+ <ClCompile Include="netconfighelpers.cpp" />
+ <ClCompile Include="wmi\notification.cpp">
+ <Filter>wmi</Filter>
+ </ClCompile>
+ <ClCompile Include="dnsreverter.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="wmi">
+ <UniqueIdentifier>{5deb73ee-53cc-49ac-bcdd-0a4b38914f0e}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/windows/windns/src/windns/windnscontext.cpp b/windows/windns/src/windns/windnscontext.cpp
new file mode 100644
index 0000000000..c7cc10c4b9
--- /dev/null
+++ b/windows/windns/src/windns/windnscontext.cpp
@@ -0,0 +1,102 @@
+#include "stdafx.h"
+#include "windnscontext.h"
+#include "wmi/connection.h"
+#include "netconfigeventsink.h"
+#include "dnsreverter.h"
+
+WinDnsContext::WinDnsContext()
+{
+ m_connection = std::make_shared<wmi::Connection>(wmi::Connection::Namespace::Cimv2);
+}
+
+bool WinDnsContext::set(const std::vector<std::wstring> &servers, WinDnsErrorSink /*errorSink*/, void * /*errorContext*/)
+{
+ m_configManager = std::make_shared<ConfigManager>(servers);
+
+ //
+ // See test app for details.
+ //
+ // Discover all active interface configurations.
+ //
+
+ auto resultSet = m_connection->query(L"SELECT * from Win32_NetworkAdapterConfiguration WHERE IPEnabled = True");
+
+ while (resultSet.advance())
+ {
+ auto config = DnsConfig(resultSet.result());
+ m_configManager->updateConfig(std::move(config));
+ }
+
+ //
+ // Register interface configuration monitoring.
+ //
+
+ auto eventSink = std::make_shared<NetConfigEventSink>(m_connection, m_configManager);
+ auto eventSinkWrapper = CComPtr<wmi::EventSink>(new wmi::EventSink(eventSink));
+
+ m_notification = std::make_unique<wmi::Notification>(m_connection, eventSinkWrapper);
+
+ m_notification->activate
+ (
+ L"SELECT * "
+ L"FROM __InstanceModificationEvent "
+ L"WITHIN 1 "
+ L"WHERE TargetInstance ISA 'Win32_NetworkAdapterConfiguration'"
+ L"AND TargetInstance.IPEnabled = True"
+ );
+
+ //
+ // Apply our DNS settings
+ //
+
+ {
+ ConfigManager::Mutex mutex(*m_configManager);
+
+ m_configManager->processConfigs([&](const DnsConfig &config)
+ {
+ std::wstringstream ss;
+
+ ss << L"SELECT * FROM Win32_NetworkAdapterConfiguration "
+ << L"WHERE SettingID = '" << config.id() << L"'";
+
+ auto resultSet = m_connection->query(ss.str().c_str());
+
+ if (resultSet.advance())
+ {
+ auto activeConfig = resultSet.result();
+ nchelpers::SetDnsServers(*m_connection, activeConfig, &servers);
+ }
+
+ // Continue with the next interface configuration.
+ return true;
+ });
+ }
+
+ return true;
+}
+
+bool WinDnsContext::reset()
+{
+ if (nullptr == m_notification)
+ {
+ return true;
+ }
+
+ m_notification->deactivate();
+
+ //
+ // Revert configs
+ // Safe to do without a mutex guarding the config manager
+ //
+
+ DnsReverter dnsReverter;
+
+ m_configManager->processConfigs([&](const DnsConfig &config)
+ {
+ dnsReverter.revert(*m_connection, config);
+
+ return true;
+ });
+
+ return true;
+}
diff --git a/windows/windns/src/windns/windnscontext.h b/windows/windns/src/windns/windnscontext.h
new file mode 100644
index 0000000000..086969cc76
--- /dev/null
+++ b/windows/windns/src/windns/windnscontext.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "windns.h"
+#include "wmi/connection.h"
+#include "wmi/notification.h"
+#include "configmanager.h"
+#include <vector>
+#include <string>
+#include <memory>
+
+class WinDnsContext
+{
+public:
+
+ WinDnsContext();
+
+ // TODO: Review.
+ ~WinDnsContext()
+ {
+ reset();
+ }
+
+ bool set(const std::vector<std::wstring> &servers, WinDnsErrorSink errorSink, void *errorContext);
+ bool reset();
+
+private:
+
+ std::shared_ptr<wmi::Connection> m_connection;
+ std::shared_ptr<ConfigManager> m_configManager;
+ std::unique_ptr<wmi::Notification> m_notification;
+};
diff --git a/windows/windns/src/windns/wmi/connection.cpp b/windows/windns/src/windns/wmi/connection.cpp
new file mode 100644
index 0000000000..225586a11d
--- /dev/null
+++ b/windows/windns/src/windns/wmi/connection.cpp
@@ -0,0 +1,69 @@
+#include "stdafx.h"
+#include "connection.h"
+#include "windns/comhelpers.h"
+#include <stdexcept>
+#define _WIN32_DCOM
+#include <windows.h>
+#include <wbemidl.h>
+
+namespace
+{
+
+const wchar_t *LiteralNamespace(wmi::Connection::Namespace ns)
+{
+ switch (ns)
+ {
+ case wmi::Connection::Namespace::Default: return L"root\\Default";
+ case wmi::Connection::Namespace::Cimv2: return L"root\\CIMV2";
+ case wmi::Connection::Namespace::StandardCimv2: return L"root\\StandardCIMV2";
+ default:
+ {
+ throw std::logic_error("Missing case handler in switch clause");
+ }
+ }
+}
+
+} // anonymous namespace
+
+namespace wmi
+{
+
+Connection::Connection(Namespace ns) : m_queryLanguage(L"WQL")
+{
+ auto status = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator, (LPVOID *)&m_locator);
+
+ if (CO_E_NOTINITIALIZED == status)
+ {
+ VALIDATE_COM(CoInitializeEx(nullptr, COINIT_MULTITHREADED), "Initialize COM");
+
+ status = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator, (LPVOID *)&m_locator);
+ }
+
+ VALIDATE_COM(status, "Create COM locator instance");
+
+ status = m_locator->ConnectServer(_bstr_t(LiteralNamespace(ns)), nullptr, nullptr,
+ nullptr, 0, nullptr, nullptr, &m_services);
+
+ VALIDATE_COM(status, "Create COM services instance");
+
+ status = CoSetProxyBlanket(m_services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
+ RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
+
+ VALIDATE_COM(status, "Configure COM services auth");
+}
+
+ResultSet Connection::query(const wchar_t *query)
+{
+ CComPtr<IEnumWbemClassObject> result;
+
+ auto status = m_services->ExecQuery(m_queryLanguage, _bstr_t(query),
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, &result);
+
+ VALIDATE_COM(status, "Execute WMI query");
+
+ return ResultSet(result);
+}
+
+}
diff --git a/windows/windns/src/windns/wmi/connection.h b/windows/windns/src/windns/wmi/connection.h
new file mode 100644
index 0000000000..07e5066d1c
--- /dev/null
+++ b/windows/windns/src/windns/wmi/connection.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "iconnection.h"
+#include <string>
+#define _WIN32_DCOM
+#include <windows.h>
+#include <atlbase.h>
+#include <comutil.h>
+#include <comdef.h>
+
+#pragma comment(lib, "wbemuuid.lib")
+
+namespace wmi
+{
+
+class Connection : public IConnection
+{
+public:
+
+ enum class Namespace
+ {
+ Default,
+ Cimv2,
+ StandardCimv2
+ };
+
+ explicit Connection(Namespace ns);
+
+ ResultSet query(const wchar_t *query) override;
+
+ CComPtr<IWbemServices> services() override
+ {
+ return m_services;
+ }
+
+private:
+
+ CComPtr<IWbemLocator> m_locator;
+ CComPtr<IWbemServices> m_services;
+
+ _bstr_t m_queryLanguage;
+};
+
+}
diff --git a/windows/windns/src/windns/wmi/eventsink.cpp b/windows/windns/src/windns/wmi/eventsink.cpp
new file mode 100644
index 0000000000..516660ff0a
--- /dev/null
+++ b/windows/windns/src/windns/wmi/eventsink.cpp
@@ -0,0 +1,93 @@
+#include "stdafx.h"
+#include "eventsink.h"
+#include "windns/comhelpers.h"
+
+namespace wmi
+{
+
+EventSink::EventSink(std::shared_ptr<IEventSink> eventSink)
+ : m_references(0)
+ , m_callbacks(0)
+ , m_eventSink(eventSink)
+{
+}
+
+EventSink::~EventSink()
+{
+}
+
+bool EventSink::processing() const
+{
+ //
+ // Cancelling the notification registration WILL NOT wait for the completion of
+ // callbacks currently in progress :-(
+ //
+ // (Observed on Win10)
+ //
+
+ return 0 != InterlockedAdd(&m_callbacks, 0);
+}
+
+ULONG STDMETHODCALLTYPE EventSink::AddRef()
+{
+ return InterlockedIncrement(&m_references);
+}
+
+ULONG STDMETHODCALLTYPE EventSink::Release()
+{
+ auto refs = InterlockedDecrement(&m_references);
+
+ if (refs == 0)
+ {
+ delete this;
+ }
+
+ return refs;
+}
+
+HRESULT STDMETHODCALLTYPE EventSink::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IID_IUnknown == riid || IID_IWbemObjectSink == riid)
+ {
+ *ppv = (IWbemObjectSink *)this;
+ AddRef();
+
+ return WBEM_S_NO_ERROR;
+ }
+
+ return E_NOINTERFACE;
+}
+
+HRESULT STDMETHODCALLTYPE EventSink::Indicate
+(
+ LONG numObjects,
+ IWbemClassObject __RPC_FAR *__RPC_FAR *objects
+)
+{
+ InterlockedIncrement(&m_callbacks);
+
+ for (LONG i = 0; i < numObjects; ++i)
+ {
+ CComPtr<IWbemClassObject> eventRecord(objects[i]);
+
+ auto rawTarget = ComGetPropertyAlways(eventRecord, L"TargetInstance");
+
+ CComQIPtr<IWbemClassObject> target(V_UNKNOWN(&rawTarget));
+
+ m_eventSink->update(target);
+ }
+
+ InterlockedDecrement(&m_callbacks);
+
+ return WBEM_S_NO_ERROR;
+}
+
+HRESULT STDMETHODCALLTYPE EventSink::SetStatus
+(
+ LONG, HRESULT, BSTR, IWbemClassObject __RPC_FAR *
+)
+{
+ return WBEM_S_NO_ERROR;
+}
+
+}
diff --git a/windows/windns/src/windns/wmi/eventsink.h b/windows/windns/src/windns/wmi/eventsink.h
new file mode 100644
index 0000000000..2f0783d81f
--- /dev/null
+++ b/windows/windns/src/windns/wmi/eventsink.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <memory>
+#include <atlbase.h>
+#include <wbemidl.h>
+
+namespace wmi
+{
+
+struct IEventSink
+{
+ virtual ~IEventSink() = 0
+ {
+ }
+
+ virtual void update(CComPtr<IWbemClassObject> instance) = 0;
+};
+
+class EventSink : public IWbemObjectSink
+{
+public:
+
+ EventSink(std::shared_ptr<IEventSink> eventSink);
+ ~EventSink();
+
+ bool processing() const;
+
+ ULONG STDMETHODCALLTYPE AddRef() override;
+ ULONG STDMETHODCALLTYPE Release() override;
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) override;
+
+ HRESULT STDMETHODCALLTYPE Indicate
+ (
+ LONG numObjects,
+ IWbemClassObject __RPC_FAR *__RPC_FAR *objects
+ )
+ override;
+
+ HRESULT STDMETHODCALLTYPE SetStatus
+ (
+ LONG flags,
+ HRESULT result,
+ BSTR param,
+ IWbemClassObject __RPC_FAR *object
+ )
+ override;
+
+private:
+
+ LONG m_references;
+ mutable LONG m_callbacks;
+ std::shared_ptr<IEventSink> m_eventSink;
+};
+
+}
diff --git a/windows/windns/src/windns/wmi/iconnection.h b/windows/windns/src/windns/wmi/iconnection.h
new file mode 100644
index 0000000000..8683dd6ac5
--- /dev/null
+++ b/windows/windns/src/windns/wmi/iconnection.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "resultset.h"
+#include <atlbase.h>
+#include <wbemidl.h>
+
+namespace wmi
+{
+
+struct IConnection
+{
+ virtual ~IConnection() = 0
+ {
+ }
+
+ virtual ResultSet query(const wchar_t *query) = 0;
+ virtual CComPtr<IWbemServices> services() = 0;
+};
+
+}
diff --git a/windows/windns/src/windns/wmi/methodcall.cpp b/windows/windns/src/windns/wmi/methodcall.cpp
new file mode 100644
index 0000000000..fcd4f738c8
--- /dev/null
+++ b/windows/windns/src/windns/wmi/methodcall.cpp
@@ -0,0 +1,104 @@
+#include "stdafx.h"
+#include "methodcall.h"
+#include "windns/comhelpers.h"
+#include <algorithm>
+
+namespace wmi
+{
+
+void MethodCall::addArgument(const std::wstring &name, _variant_t value)
+{
+ m_arguments.emplace_back(Argument(name, value));
+}
+
+void MethodCall::addNullArgument(const std::wstring &name, CIMTYPE type)
+{
+ m_arguments.emplace_back(Argument(name, type));
+}
+
+_variant_t MethodCall::invoke(IConnection &connection, CComPtr<IWbemClassObject> instance, const std::wstring &methodName)
+{
+ std::for_each(m_arguments.begin(), m_arguments.end(), [&](const Argument &arg)
+ {
+ HRESULT status;
+
+ if (arg.nullValue())
+ {
+ status = instance->Put(arg.name().c_str(), 0, nullptr, arg.type());
+ }
+ else
+ {
+ _variant_t &value = const_cast<variant_t &>(arg.value());
+
+ status = instance->Put(arg.name().c_str(), 0, &value, 0);
+ }
+
+ VALIDATE_COM(status, "Register COM method argument");
+ });
+
+ _variant_t path;
+
+ auto status = instance->Get(_bstr_t(L"__PATH"), 0, &path, nullptr, nullptr);
+
+ VALIDATE_COM(status, "Get COM instance path");
+
+ CComPtr<IWbemClassObject> result;
+
+ status = connection.services()->ExecMethod(V_BSTR(&path), _bstr_t(methodName.c_str()), 0, nullptr, instance, &result, nullptr);
+
+ VALIDATE_COM(status, "Execute COM method call");
+
+ return ComGetProperty(result, L"ReturnValue");
+}
+
+
+//
+// the following code is almost what is needed for static method calls
+// just remove the path and the in-arg instance
+// also, update first arg to ExecMethod
+//
+//_variant_t MethodCall::call(Connection &connection, CComPtr<IWbemClassObject> instance, const std::wstring &methodName)
+//{
+// CComPtr<IWbemClassObject> cls;
+//
+// auto status = connection.m_services->GetObject(_bstr_t(L"Win32_NetworkAdapterConfiguration"), 0, nullptr, &cls, nullptr);
+// VALIDATE_COM(status, "Resolve COM class");
+//
+// CComPtr<IWbemClassObject> methodDefinition;
+//
+// status = cls->GetMethod(methodName.c_str(), 0, &methodDefinition, nullptr);
+// VALIDATE_COM(status, "Resolve COM instance method");
+//
+// CComPtr<IWbemClassObject> methodInstance;
+//
+// status = methodDefinition->SpawnInstance(0, &methodInstance);
+// VALIDATE_COM(status, "Instantiate COM class for method call");
+//
+// std::for_each(m_arguments.begin(), m_arguments.end(), [&](const Argument &arg)
+// {
+// _variant_t value(arg.value);
+//
+// // This works for all values except NULL
+// auto hr = methodInstance->Put(arg.name.c_str(), 0, &value, 0);
+//
+// VALIDATE_COM(hr, "Register COM method argument");
+// });
+//
+// _variant_t path;
+//
+// status = instance->Get(_bstr_t(L"__PATH"), 0, &path, nullptr, nullptr);
+// VALIDATE_COM(status, "Get COM instance path");
+//
+// CComPtr<IWbemClassObject> result;
+//
+// status = connection.m_services->ExecMethod(path.bstrVal, _bstr_t(methodName.c_str()), 0, nullptr, methodInstance, &result, nullptr/*?*/);
+// VALIDATE_COM(status, "Execute COM method call");
+//
+// return ComGetProperty(result, L"ReturnValue");
+//}
+//
+
+
+
+
+}
diff --git a/windows/windns/src/windns/wmi/methodcall.h b/windows/windns/src/windns/wmi/methodcall.h
new file mode 100644
index 0000000000..4d964b60db
--- /dev/null
+++ b/windows/windns/src/windns/wmi/methodcall.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "iconnection.h"
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <comutil.h>
+
+namespace wmi
+{
+
+class MethodCall
+{
+public:
+
+ void addArgument(const std::wstring &name, _variant_t value);
+ void addNullArgument(const std::wstring &name, CIMTYPE type);
+
+ _variant_t invoke(IConnection &connection, CComPtr<IWbemClassObject> instance, const std::wstring &methodName);
+
+private:
+
+ class Argument
+ {
+ public:
+
+ Argument(const std::wstring &name, _variant_t value)
+ : m_name(name)
+ , m_value(value)
+ {
+ if (VT_NULL == V_VT(&value) || VT_EMPTY == V_VT(&value))
+ {
+ throw std::runtime_error("Cannot add null-argument without specifying type.");
+ }
+ }
+
+ Argument(const std::wstring &name, CIMTYPE type)
+ : m_name(name)
+ , m_type(type)
+ {
+ }
+
+ bool nullValue() const
+ {
+ return VT_EMPTY == V_VT(&m_value);
+ }
+
+ const std::wstring &name() const
+ {
+ return m_name;
+ }
+
+ const _variant_t &value() const
+ {
+ return m_value;
+ }
+
+ CIMTYPE type() const
+ {
+ return m_type;
+ }
+
+ private:
+
+ std::wstring m_name;
+ _variant_t m_value;
+
+ // Explicitly specify type when the value is NULL.
+ CIMTYPE m_type;
+ };
+
+ std::vector<Argument> m_arguments;
+};
+
+}
diff --git a/windows/windns/src/windns/wmi/notification.cpp b/windows/windns/src/windns/wmi/notification.cpp
new file mode 100644
index 0000000000..a9427f6520
--- /dev/null
+++ b/windows/windns/src/windns/wmi/notification.cpp
@@ -0,0 +1,72 @@
+#include "stdafx.h"
+#include "notification.h"
+#include "windns/comhelpers.h"
+
+namespace wmi
+{
+
+Notification::Notification(std::shared_ptr<IConnection> connection, CComPtr<EventSink> eventSink)
+ : m_connection(connection)
+ , m_eventSink(eventSink)
+{
+}
+
+Notification::~Notification()
+{
+ //
+ // TODO: Revise to avoid exceptions in dtor.
+ //
+ deactivate();
+}
+
+void Notification::activate(const std::wstring &query)
+{
+ CComPtr<IUnsecuredApartment> apartment;
+
+ auto status = CoCreateInstance(CLSID_UnsecuredApartment, nullptr, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, (void**)&apartment);
+ VALIDATE_COM(status, "Create unsecured COM apartment");
+
+ CComPtr<IUnknown> unknownEventSink;
+
+ status = m_eventSink->QueryInterface(IID_IUnknown, (void**)&unknownEventSink);
+ VALIDATE_COM(status, "Retrieve IUnkown interface for event sink");
+
+ CComPtr<IUnknown> unknownForwarder;
+
+ status = apartment->CreateObjectStub(unknownEventSink, &unknownForwarder);
+ VALIDATE_COM(status, "Create forwarder for event sink");
+
+ status = unknownForwarder->QueryInterface(IID_IWbemObjectSink, (void**)&m_forwarder);
+ VALIDATE_COM(status, "Retrieve sink interface on event sink forwarder");
+
+ status = m_connection->services()->ExecNotificationQueryAsync(_bstr_t("WQL"), _bstr_t(query.c_str()), 0, nullptr, m_forwarder);
+ VALIDATE_COM(status, "Register notification query with WMI");
+}
+
+void Notification::deactivate()
+{
+ if (nullptr == m_forwarder)
+ {
+ return;
+ }
+
+ auto status = m_connection->services()->CancelAsyncCall(m_forwarder);
+ VALIDATE_COM(status, "Cancel notification query");
+
+ m_forwarder.Release();
+
+ //
+ // This is a hack-solution for a corner case issue.
+ //
+ // Since cancelling the notification registration does not wait for in-progress callbacks
+ // to complete, we have to implement the corresponding logic ourselves.
+ //
+ // Using a Sleep() here is preferable to introducing a critical section in the callback.
+ //
+ while (m_eventSink->processing())
+ {
+ Sleep(100);
+ }
+}
+
+}
diff --git a/windows/windns/src/windns/wmi/notification.h b/windows/windns/src/windns/wmi/notification.h
new file mode 100644
index 0000000000..40a57f1e57
--- /dev/null
+++ b/windows/windns/src/windns/wmi/notification.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "iconnection.h"
+#include "eventsink.h"
+#include <atlbase.h>
+#include <memory>
+
+namespace wmi
+{
+
+class Notification
+{
+public:
+
+ Notification(std::shared_ptr<IConnection> connection, CComPtr<EventSink> eventSink);
+ ~Notification();
+
+ Notification(const Notification &) = delete;
+ Notification &operator=(const Notification &) = delete;
+ Notification(Notification &&) = delete;
+ Notification &operator=(Notification &&) = delete;
+
+ void activate(const std::wstring &query);
+ void deactivate();
+
+private:
+
+ std::shared_ptr<IConnection> m_connection;
+ CComPtr<EventSink> m_eventSink;
+
+ CComPtr<IWbemObjectSink> m_forwarder;
+};
+
+}
diff --git a/windows/windns/src/windns/wmi/resultset.cpp b/windows/windns/src/windns/wmi/resultset.cpp
new file mode 100644
index 0000000000..cea147fa76
--- /dev/null
+++ b/windows/windns/src/windns/wmi/resultset.cpp
@@ -0,0 +1,34 @@
+#include "stdafx.h"
+#include "resultset.h"
+#include "windns/comhelpers.h"
+#include "libcommon/error.h"
+
+namespace wmi
+{
+
+ResultSet::ResultSet(CComPtr<IEnumWbemClassObject> rs) : m_resultset(rs)
+{
+}
+
+bool ResultSet::advance()
+{
+ if (nullptr != m_result)
+ {
+ m_result.Release();
+ }
+
+ ULONG dummy;
+
+ const auto status = m_resultset->Next(WBEM_INFINITE, 1, &m_result, &dummy);
+
+ VALIDATE_COM(status, "Retrieve next object in COM resultset");
+
+ return WBEM_S_FALSE != status;
+}
+
+CComPtr<IWbemClassObject> ResultSet::result()
+{
+ return m_result;
+}
+
+}
diff --git a/windows/windns/src/windns/wmi/resultset.h b/windows/windns/src/windns/wmi/resultset.h
new file mode 100644
index 0000000000..6139a6051a
--- /dev/null
+++ b/windows/windns/src/windns/wmi/resultset.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <string>
+#include <atlbase.h>
+#include <wbemidl.h>
+
+namespace wmi
+{
+
+class ResultSet
+{
+public:
+
+ ResultSet(CComPtr<IEnumWbemClassObject> rs);
+
+ ResultSet(const ResultSet &) = delete;
+ ResultSet &operator=(const ResultSet &) = delete;
+ ResultSet(ResultSet &&) = default;
+ ResultSet &operator=(ResultSet &&) = default;
+
+ bool advance();
+
+ CComPtr<IWbemClassObject> result();
+
+private:
+
+ CComPtr<IEnumWbemClassObject> m_resultset;
+ CComPtr<IWbemClassObject> m_result;
+};
+
+}