diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index be83c18d0..903dccb36 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -45,6 +45,9 @@
# Display Kernel
/video/ @microsoft/display-kernel-devs
+# Windows Driver Kit Templates
+/templates/ @microsoft/driver-samples-maintainers
+
# Driver Development Supplemental Tools
/tools/ @microsoft/windows-driver-developers-supplemental-tools-admins
diff --git a/exclusions.csv b/exclusions.csv
index 5352e0d13..b4af110cd 100644
--- a/exclusions.csv
+++ b/exclusions.csv
@@ -6,3 +6,14 @@ network\trans\WFPSampler,Debug|ARM64,,22621,Only NI: Only ARM: Fails to build on
prm,*,,22621,Only NI: Not supported on NI.
powerlimit\plclient,*,,22621,Only NI: Not supported on NI.
powerlimit\plpolicy,*,,22621,Only NI: Not supported on NI.
+templates\driverpackage,*,,,Template intentionally not building. See .\templates\README.md for details.
+templates\emptyapplication,*,,,Template intentionally not building. See .\templates\README.md for details.
+templates\emptydll,*,,,Template intentionally not building. See .\templates\README.md for details.
+templates\kmdfempty,*,,,Template intentionally not building. See .\templates\README.md for details.
+templates\ndisfilter,*,,,Template intentionally not building. See .\templates\README.md for details.
+templates\umdf2empty,*,,,Template intentionally not building. See .\templates\README.md for details.
+templates\v4printdriver,*,,,Template intentionally not building. See .\templates\README.md for details.
+templates\wdmempty,*,,,Template intentionally not building. See .\templates\README.md for details.
+templates\winusbinfpackage,*,,22621,Only NI: Template intentionally not building. See .\templates\README.md for details.
+templates\xpsrenderfilter,*,,,Template intentionally not building. See .\templates\README.md for details.
+tree,*,,,Missing headers
diff --git a/templates/DriverPackage/DriverPackage.sln b/templates/DriverPackage/DriverPackage.sln
new file mode 100644
index 000000000..d93256914
--- /dev/null
+++ b/templates/DriverPackage/DriverPackage.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DriverPackage", "DriverPackage\DriverPackage.vcxproj", "{C086A076-3596-46BD-8B43-CD3702B16E35}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Debug|ARM64.Build.0 = Debug|ARM64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Debug|x64.ActiveCfg = Debug|x64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Debug|x64.Build.0 = Debug|x64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Debug|x64.Deploy.0 = Debug|x64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Release|ARM64.ActiveCfg = Release|ARM64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Release|ARM64.Build.0 = Release|ARM64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Release|ARM64.Deploy.0 = Release|ARM64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Release|x64.ActiveCfg = Release|x64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Release|x64.Build.0 = Release|x64
+ {C086A076-3596-46BD-8B43-CD3702B16E35}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {79E70392-08F7-4CE7-A16C-DD8DF8C094B8}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/DriverPackage/DriverPackage/DriverPackage.vcxproj b/templates/DriverPackage/DriverPackage/DriverPackage.vcxproj
new file mode 100644
index 000000000..04791901e
--- /dev/null
+++ b/templates/DriverPackage/DriverPackage/DriverPackage.vcxproj
@@ -0,0 +1,118 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ {C086A076-3596-46BD-8B43-CD3702B16E35}
+ {4605da2c-74a5-4865-98e1-152ef136825f}
+ v4.5
+ 12.0
+ Debug
+ x64
+ DriverPackage
+
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Utility
+ Package
+ true
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Utility
+ Package
+ true
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Utility
+ Package
+ true
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Utility
+ Package
+ true
+
+
+
+
+
+
+
+
+
+
+ DbgengRemoteDebugger
+
+
+
+ False
+ False
+ True
+
+ 133563
+
+
+ DbgengRemoteDebugger
+
+
+
+ False
+ False
+ True
+
+ 133563
+
+
+ DbgengRemoteDebugger
+
+
+
+ False
+ False
+ True
+
+ 133563
+
+
+ DbgengRemoteDebugger
+
+
+
+ False
+ False
+ True
+
+ 133563
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/DriverPackage/DriverPackage/DriverPackage.vcxproj.filters b/templates/DriverPackage/DriverPackage/DriverPackage.vcxproj.filters
new file mode 100644
index 000000000..e1b34f2aa
--- /dev/null
+++ b/templates/DriverPackage/DriverPackage/DriverPackage.vcxproj.filters
@@ -0,0 +1,9 @@
+
+
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
\ No newline at end of file
diff --git a/templates/EmptyApplication/EmptyApplication.sln b/templates/EmptyApplication/EmptyApplication.sln
new file mode 100644
index 000000000..999e705a8
--- /dev/null
+++ b/templates/EmptyApplication/EmptyApplication.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EmptyApplication", "EmptyApplication\EmptyApplication.vcxproj", "{02AC6F94-7898-4F8E-9A20-ECBA9B462928}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Debug|ARM.ActiveCfg = Debug|ARM
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Debug|ARM.Build.0 = Debug|ARM
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Debug|ARM64.Build.0 = Debug|ARM64
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Debug|x64.ActiveCfg = Debug|x64
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Debug|x64.Build.0 = Debug|x64
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Debug|x86.ActiveCfg = Debug|Win32
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Debug|x86.Build.0 = Debug|Win32
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Release|ARM.ActiveCfg = Release|ARM
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Release|ARM.Build.0 = Release|ARM
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Release|ARM64.ActiveCfg = Release|ARM64
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Release|ARM64.Build.0 = Release|ARM64
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Release|x64.ActiveCfg = Release|x64
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Release|x64.Build.0 = Release|x64
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Release|x86.ActiveCfg = Release|Win32
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {A71BCCFB-A3EC-4E9C-B64A-014BD4D05443}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/EmptyApplication/EmptyApplication/EmptyApplication.vcxproj b/templates/EmptyApplication/EmptyApplication/EmptyApplication.vcxproj
new file mode 100644
index 000000000..29a51f7e0
--- /dev/null
+++ b/templates/EmptyApplication/EmptyApplication/EmptyApplication.vcxproj
@@ -0,0 +1,189 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ {02AC6F94-7898-4F8E-9A20-ECBA9B462928}
+ {504102d4-2172-473c-8adf-cd96e308f257}
+ v4.5
+ 12.0
+ Debug
+ Win32
+ EmptyApplication
+
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+
+
+
+
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/EmptyApplication/EmptyApplication/EmptyApplication.vcxproj.filters b/templates/EmptyApplication/EmptyApplication/EmptyApplication.vcxproj.filters
new file mode 100644
index 000000000..d7ef6a1a3
--- /dev/null
+++ b/templates/EmptyApplication/EmptyApplication/EmptyApplication.vcxproj.filters
@@ -0,0 +1,17 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
\ No newline at end of file
diff --git a/templates/EmptyDll/EmptyDll.sln b/templates/EmptyDll/EmptyDll.sln
new file mode 100644
index 000000000..a880bea54
--- /dev/null
+++ b/templates/EmptyDll/EmptyDll.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EmptyDll", "EmptyDll\EmptyDll.vcxproj", "{BD96DE21-A051-43F7-B9A2-28C18D122BE2}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Debug|ARM.ActiveCfg = Debug|ARM
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Debug|ARM.Build.0 = Debug|ARM
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Debug|ARM64.Build.0 = Debug|ARM64
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Debug|x64.ActiveCfg = Debug|x64
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Debug|x64.Build.0 = Debug|x64
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Debug|x86.ActiveCfg = Debug|Win32
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Debug|x86.Build.0 = Debug|Win32
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Release|ARM.ActiveCfg = Release|ARM
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Release|ARM.Build.0 = Release|ARM
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Release|ARM64.ActiveCfg = Release|ARM64
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Release|ARM64.Build.0 = Release|ARM64
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Release|x64.ActiveCfg = Release|x64
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Release|x64.Build.0 = Release|x64
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Release|x86.ActiveCfg = Release|Win32
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {2C042FCD-9600-4DDA-B792-9F0AE4A32C8D}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/EmptyDll/EmptyDll/EmptyDll.vcxproj b/templates/EmptyDll/EmptyDll/EmptyDll.vcxproj
new file mode 100644
index 000000000..7165a384a
--- /dev/null
+++ b/templates/EmptyDll/EmptyDll/EmptyDll.vcxproj
@@ -0,0 +1,185 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ {BD96DE21-A051-43F7-B9A2-28C18D122BE2}
+ {5ce256cb-a826-4703-9b24-ad2d556ad23b}
+ v4.5
+ 12.0
+ Debug
+ Win32
+ EmptyDll
+
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ DynamicLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ DynamicLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ DynamicLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ DynamicLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ DynamicLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ DynamicLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ DynamicLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ DynamicLibrary
+ Universal
+ Unicode
+
+
+
+
+
+
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ %(AdditionalDependencies);onecoreuap.lib
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/EmptyDll/EmptyDll/EmptyDll.vcxproj.filters b/templates/EmptyDll/EmptyDll/EmptyDll.vcxproj.filters
new file mode 100644
index 000000000..d7ef6a1a3
--- /dev/null
+++ b/templates/EmptyDll/EmptyDll/EmptyDll.vcxproj.filters
@@ -0,0 +1,17 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
\ No newline at end of file
diff --git a/templates/EmptyStatic/EmptyStatic.sln b/templates/EmptyStatic/EmptyStatic.sln
new file mode 100644
index 000000000..5456509ed
--- /dev/null
+++ b/templates/EmptyStatic/EmptyStatic.sln
@@ -0,0 +1,51 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EmptyStatic", "EmptyStatic\EmptyStatic.vcxproj", "{0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|ARM.ActiveCfg = Debug|ARM
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|ARM.Build.0 = Debug|ARM
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|ARM.Deploy.0 = Debug|ARM
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|ARM64.Build.0 = Debug|ARM64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|x64.ActiveCfg = Debug|x64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|x64.Build.0 = Debug|x64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|x64.Deploy.0 = Debug|x64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|x86.ActiveCfg = Debug|Win32
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|x86.Build.0 = Debug|Win32
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Debug|x86.Deploy.0 = Debug|Win32
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|ARM.ActiveCfg = Release|ARM
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|ARM.Build.0 = Release|ARM
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|ARM.Deploy.0 = Release|ARM
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|ARM64.ActiveCfg = Release|ARM64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|ARM64.Build.0 = Release|ARM64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|ARM64.Deploy.0 = Release|ARM64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|x64.ActiveCfg = Release|x64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|x64.Build.0 = Release|x64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|x64.Deploy.0 = Release|x64
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|x86.ActiveCfg = Release|Win32
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|x86.Build.0 = Release|Win32
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {EE3A06F7-01E3-44AE-BA63-5D1AE2357891}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/EmptyStatic/EmptyStatic/EmptyStatic.vcxproj b/templates/EmptyStatic/EmptyStatic/EmptyStatic.vcxproj
new file mode 100644
index 000000000..731040b22
--- /dev/null
+++ b/templates/EmptyStatic/EmptyStatic/EmptyStatic.vcxproj
@@ -0,0 +1,165 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ {0F9EB74F-0501-4186-BDED-0D6FF08DDAB6}
+ {0a049372-4c4d-4ea0-a64e-dc6ad88ceca1}
+ v4.5
+ 12.0
+ Debug
+ Win32
+ EmptyStatic
+ KMDF
+
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+ Unicode
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+ Universal
+ Unicode
+
+
+
+
+
+
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/EmptyStatic/EmptyStatic/EmptyStatic.vcxproj.filters b/templates/EmptyStatic/EmptyStatic/EmptyStatic.vcxproj.filters
new file mode 100644
index 000000000..d7ef6a1a3
--- /dev/null
+++ b/templates/EmptyStatic/EmptyStatic/EmptyStatic.vcxproj.filters
@@ -0,0 +1,17 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
\ No newline at end of file
diff --git a/templates/KMDF/KMDF.sln b/templates/KMDF/KMDF.sln
new file mode 100644
index 000000000..ce1cca7e7
--- /dev/null
+++ b/templates/KMDF/KMDF.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KMDF", "KMDF\KMDF.vcxproj", "{2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Debug|ARM64.Build.0 = Debug|ARM64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Debug|x64.ActiveCfg = Debug|x64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Debug|x64.Build.0 = Debug|x64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Debug|x64.Deploy.0 = Debug|x64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Release|ARM64.ActiveCfg = Release|ARM64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Release|ARM64.Build.0 = Release|ARM64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Release|ARM64.Deploy.0 = Release|ARM64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Release|x64.ActiveCfg = Release|x64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Release|x64.Build.0 = Release|x64
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {90172D63-C47A-4050-B19D-46E6337663DC}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/KMDF/KMDF/Device.c b/templates/KMDF/KMDF/Device.c
new file mode 100644
index 000000000..d1ed741f1
--- /dev/null
+++ b/templates/KMDF/KMDF/Device.c
@@ -0,0 +1,93 @@
+/*++
+
+Module Name:
+
+ device.c - Device handling events for example driver.
+
+Abstract:
+
+ This file contains the device entry points and callbacks.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "driver.h"
+#include "device.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, KMDFCreateDevice)
+#endif
+
+NTSTATUS
+KMDFCreateDevice(
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+
+Routine Description:
+
+ Worker routine called to create a device and its software resources.
+
+Arguments:
+
+ DeviceInit - Pointer to an opaque init structure. Memory for this
+ structure will be freed by the framework when the WdfDeviceCreate
+ succeeds. So don't access the structure after that point.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ PDEVICE_CONTEXT deviceContext;
+ WDFDEVICE device;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
+
+ status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Get a pointer to the device context structure that we just associated
+ // with the device object. We define this structure in the device.h
+ // header file. DeviceGetContext is an inline function generated by
+ // using the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in device.h.
+ // This function will do the type checking and return the device context.
+ // If you pass a wrong object handle it will return NULL and assert if
+ // run under framework verifier mode.
+ //
+ deviceContext = DeviceGetContext(device);
+
+ //
+ // Initialize the context.
+ //
+ deviceContext->PrivateDeviceData = 0;
+
+ //
+ // Create a device interface so that applications can find and talk
+ // to us.
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ &GUID_DEVINTERFACE_KMDF,
+ NULL // ReferenceString
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Initialize the I/O Package and any Queues
+ //
+ status = KMDFQueueInitialize(device);
+ }
+ }
+
+ return status;
+}
diff --git a/templates/KMDF/KMDF/Device.h b/templates/KMDF/KMDF/Device.h
new file mode 100644
index 000000000..d612f762b
--- /dev/null
+++ b/templates/KMDF/KMDF/Device.h
@@ -0,0 +1,46 @@
+/*++
+
+Module Name:
+
+ device.h
+
+Abstract:
+
+ This file contains the device definitions.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "public.h"
+
+EXTERN_C_START
+
+//
+// The device context performs the same job as
+// a WDM device extension in the driver frameworks
+//
+typedef struct _DEVICE_CONTEXT
+{
+ ULONG PrivateDeviceData; // just a placeholder
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// This macro will generate an inline function called DeviceGetContext
+// which will be used to get a pointer to the device context memory
+// in a type safe manner.
+//
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, DeviceGetContext)
+
+//
+// Function to initialize the device and its callbacks
+//
+NTSTATUS
+KMDFCreateDevice(
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ );
+
+EXTERN_C_END
diff --git a/templates/KMDF/KMDF/Driver.c b/templates/KMDF/KMDF/Driver.c
new file mode 100644
index 000000000..84dbb6d38
--- /dev/null
+++ b/templates/KMDF/KMDF/Driver.c
@@ -0,0 +1,165 @@
+/*++
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This file contains the driver entry points and callbacks.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "driver.h"
+#include "driver.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (INIT, DriverEntry)
+#pragma alloc_text (PAGE, KMDFEvtDeviceAdd)
+#pragma alloc_text (PAGE, KMDFEvtDriverContextCleanup)
+#endif
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded. DriverEntry specifies the other entry
+ points in the function driver, such as EvtDevice and DriverUnload.
+
+Parameters Description:
+
+ DriverObject - represents the instance of the function driver that is loaded
+ into memory. DriverEntry must initialize members of DriverObject before it
+ returns to the caller. DriverObject is allocated by the system before the
+ driver is loaded, and it is released by the system after the system unloads
+ the function driver from memory.
+
+ RegistryPath - represents the driver specific path in the Registry.
+ The function driver can use the path to store driver related data between
+ reboots. The path does not store hardware instance specific data.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ WDF_DRIVER_CONFIG config;
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES attributes;
+
+ //
+ // Initialize WPP Tracing
+ //
+ WPP_INIT_TRACING(DriverObject, RegistryPath);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ //
+ // Register a cleanup callback so that we can call WPP_CLEANUP when
+ // the framework driver object is deleted during driver unload.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.EvtCleanupCallback = KMDFEvtDriverContextCleanup;
+
+ WDF_DRIVER_CONFIG_INIT(&config,
+ KMDFEvtDeviceAdd
+ );
+
+ status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ &attributes,
+ &config,
+ WDF_NO_HANDLE
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
+ WPP_CLEANUP(DriverObject);
+ return status;
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
+
+NTSTATUS
+KMDFEvtDeviceAdd(
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ status = KMDFCreateDevice(DeviceInit);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
+
+VOID
+KMDFEvtDriverContextCleanup(
+ _In_ WDFOBJECT DriverObject
+ )
+/*++
+Routine Description:
+
+ Free all the resources allocated in DriverEntry.
+
+Arguments:
+
+ DriverObject - handle to a WDF Driver object.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ //
+ // Stop WPP Tracing
+ //
+ WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject));
+}
diff --git a/templates/KMDF/KMDF/Driver.h b/templates/KMDF/KMDF/Driver.h
new file mode 100644
index 000000000..ca4de02e4
--- /dev/null
+++ b/templates/KMDF/KMDF/Driver.h
@@ -0,0 +1,35 @@
+/*++
+
+Module Name:
+
+ driver.h
+
+Abstract:
+
+ This file contains the driver definitions.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include
+#include
+#include
+
+#include "device.h"
+#include "queue.h"
+#include "trace.h"
+
+EXTERN_C_START
+
+//
+// WDFDRIVER Events
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD KMDFEvtDeviceAdd;
+EVT_WDF_OBJECT_CONTEXT_CLEANUP KMDFEvtDriverContextCleanup;
+
+EXTERN_C_END
diff --git a/templates/KMDF/KMDF/KMDF.inf b/templates/KMDF/KMDF/KMDF.inf
new file mode 100644
index 000000000..550ad7bc0
--- /dev/null
+++ b/templates/KMDF/KMDF/KMDF.inf
@@ -0,0 +1,62 @@
+;
+; KMDF.inf
+;
+
+[Version]
+Signature = "$WINDOWS NT$"
+Class = System ; TODO: specify appropriate Class
+ClassGuid = {4d36e97d-e325-11ce-bfc1-08002be10318} ; TODO: specify appropriate ClassGuid
+Provider = %ManufacturerName%
+CatalogFile = KMDF.cat
+DriverVer = ; TODO: set DriverVer in stampinf property pages
+PnpLockdown = 1
+
+[DestinationDirs]
+DefaultDestDir = 13
+
+[SourceDisksNames]
+1 = %DiskName%,,,""
+
+[SourceDisksFiles]
+KMDF.sys = 1,,
+
+;*****************************************
+; Install Section
+;*****************************************
+
+[Manufacturer]
+%ManufacturerName% = Standard,NT$ARCH$.10.0...16299 ; %13% support introduced in build 16299
+
+[Standard.NT$ARCH$.10.0...16299]
+%KMDF.DeviceDesc% = KMDF_Device, Root\KMDF ; TODO: edit hw-id
+
+[KMDF_Device.NT]
+CopyFiles = File_Copy
+
+[File_Copy]
+KMDF.sys
+
+;-------------- Service installation
+[KMDF_Device.NT.Services]
+AddService = KMDF,%SPSVCINST_ASSOCSERVICE%, KMDF_Service_Inst
+
+; -------------- KMDF driver install sections
+[KMDF_Service_Inst]
+DisplayName = %KMDF.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %13%\KMDF.sys
+
+[KMDF_Device.NT.Wdf]
+KmdfService = KMDF, KMDF_wdfsect
+
+[KMDF_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+[Strings]
+SPSVCINST_ASSOCSERVICE = 0x00000002
+ManufacturerName = "" ;TODO: Replace with your manufacturer name
+DiskName = "KMDF Installation Disk"
+KMDF.DeviceDesc = "KMDF Device"
+KMDF.SVCDESC = "KMDF Service"
diff --git a/templates/KMDF/KMDF/KMDF.vcxproj b/templates/KMDF/KMDF/KMDF.vcxproj
new file mode 100644
index 000000000..037b21bfc
--- /dev/null
+++ b/templates/KMDF/KMDF/KMDF.vcxproj
@@ -0,0 +1,151 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {2BB7E3B5-1172-4628-824C-A7B91B0F6AE6}
+ {497e31cb-056b-4f31-abb8-447fd55ee5a5}
+ v4.5
+ 12.0
+ Debug
+ x64
+ KMDF
+
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+
+
+
+
+
+
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+
+ true
+ true
+ trace.h
+ true
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+ true
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+ true
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+ true
+
+
+ sha256
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/KMDF/KMDF/KMDF.vcxproj.filters b/templates/KMDF/KMDF/KMDF.vcxproj.filters
new file mode 100644
index 000000000..5d1ebec17
--- /dev/null
+++ b/templates/KMDF/KMDF/KMDF.vcxproj.filters
@@ -0,0 +1,57 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+
+
+
+ Driver Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/templates/KMDF/KMDF/Public.h b/templates/KMDF/KMDF/Public.h
new file mode 100644
index 000000000..93192bebc
--- /dev/null
+++ b/templates/KMDF/KMDF/Public.h
@@ -0,0 +1,24 @@
+/*++
+
+Module Name:
+
+ public.h
+
+Abstract:
+
+ This module contains the common declarations shared by driver
+ and user applications.
+
+Environment:
+
+ user and kernel
+
+--*/
+
+//
+// Define an Interface Guid so that apps can find the device and talk to it.
+//
+
+DEFINE_GUID (GUID_DEVINTERFACE_KMDF,
+ 0x8584fca7,0x7a47,0x4056,0x8b,0x7e,0x11,0xa3,0x0a,0x44,0x78,0xe9);
+// {8584fca7-7a47-4056-8b7e-11a30a4478e9}
diff --git a/templates/KMDF/KMDF/Queue.c b/templates/KMDF/KMDF/Queue.c
new file mode 100644
index 000000000..63d3a633e
--- /dev/null
+++ b/templates/KMDF/KMDF/Queue.c
@@ -0,0 +1,199 @@
+/*++
+
+Module Name:
+
+ queue.c
+
+Abstract:
+
+ This file contains the queue entry points and callbacks.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "driver.h"
+#include "queue.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, KMDFQueueInitialize)
+#endif
+
+NTSTATUS
+KMDFQueueInitialize(
+ _In_ WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ The I/O dispatch callbacks for the frameworks device object
+ are configured in this function.
+
+ A single default I/O Queue is configured for parallel request
+ processing, and a driver context memory allocation is created
+ to hold our structure QUEUE_CONTEXT.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ WDFQUEUE queue;
+ NTSTATUS status;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+
+ PAGED_CODE();
+
+ //
+ // Configure a default queue so that requests that are not
+ // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
+ // other queues get dispatched here.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchParallel
+ );
+
+ queueConfig.EvtIoDeviceControl = KMDFEvtIoDeviceControl;
+ queueConfig.EvtIoStop = KMDFEvtIoStop;
+
+ status = WdfIoQueueCreate(
+ Device,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &queue
+ );
+
+ if(!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_QUEUE, "WdfIoQueueCreate failed %!STATUS!", status);
+ return status;
+ }
+
+ return status;
+}
+
+VOID
+KMDFEvtIoDeviceControl(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+/*++
+
+Routine Description:
+
+ This event is invoked when the framework receives IRP_MJ_DEVICE_CONTROL request.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ OutputBufferLength - Size of the output buffer in bytes
+
+ InputBufferLength - Size of the input buffer in bytes
+
+ IoControlCode - I/O control code.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_QUEUE,
+ "%!FUNC! Queue 0x%p, Request 0x%p OutputBufferLength %d InputBufferLength %d IoControlCode %d",
+ Queue, Request, (int) OutputBufferLength, (int) InputBufferLength, IoControlCode);
+
+ WdfRequestComplete(Request, STATUS_SUCCESS);
+
+ return;
+}
+
+VOID
+KMDFEvtIoStop(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ ULONG ActionFlags
+)
+/*++
+
+Routine Description:
+
+ This event is invoked for a power-managed queue before the device leaves the working state (D0).
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ ActionFlags - A bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS-typed flags
+ that identify the reason that the callback function is being called
+ and whether the request is cancelable.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_QUEUE,
+ "%!FUNC! Queue 0x%p, Request 0x%p ActionFlags %d",
+ Queue, Request, ActionFlags);
+
+ //
+ // In most cases, the EvtIoStop callback function completes, cancels, or postpones
+ // further processing of the I/O request.
+ //
+ // Typically, the driver uses the following rules:
+ //
+ // - If the driver owns the I/O request, it calls WdfRequestUnmarkCancelable
+ // (if the request is cancelable) and either calls WdfRequestStopAcknowledge
+ // with a Requeue value of TRUE, or it calls WdfRequestComplete with a
+ // completion status value of STATUS_SUCCESS or STATUS_CANCELLED.
+ //
+ // Before it can call these methods safely, the driver must make sure that
+ // its implementation of EvtIoStop has exclusive access to the request.
+ //
+ // In order to do that, the driver must synchronize access to the request
+ // to prevent other threads from manipulating the request concurrently.
+ // The synchronization method you choose will depend on your driver's design.
+ //
+ // For example, if the request is held in a shared context, the EvtIoStop callback
+ // might acquire an internal driver lock, take the request from the shared context,
+ // and then release the lock. At this point, the EvtIoStop callback owns the request
+ // and can safely complete or requeue the request.
+ //
+ // - If the driver has forwarded the I/O request to an I/O target, it either calls
+ // WdfRequestCancelSentRequest to attempt to cancel the request, or it postpones
+ // further processing of the request and calls WdfRequestStopAcknowledge with
+ // a Requeue value of FALSE.
+ //
+ // A driver might choose to take no action in EvtIoStop for requests that are
+ // guaranteed to complete in a small amount of time.
+ //
+ // In this case, the framework waits until the specified request is complete
+ // before moving the device (or system) to a lower power state or removing the device.
+ // Potentially, this inaction can prevent a system from entering its hibernation state
+ // or another low system power state. In extreme cases, it can cause the system
+ // to crash with bugcheck code 9F.
+ //
+
+ return;
+}
diff --git a/templates/KMDF/KMDF/Queue.h b/templates/KMDF/KMDF/Queue.h
new file mode 100644
index 000000000..2ec64615a
--- /dev/null
+++ b/templates/KMDF/KMDF/Queue.h
@@ -0,0 +1,42 @@
+/*++
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This file contains the queue definitions.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+EXTERN_C_START
+
+//
+// This is the context that can be placed per queue
+// and would contain per queue information.
+//
+typedef struct _QUEUE_CONTEXT {
+
+ ULONG PrivateDeviceData; // just a placeholder
+
+} QUEUE_CONTEXT, *PQUEUE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext)
+
+NTSTATUS
+KMDFQueueInitialize(
+ _In_ WDFDEVICE Device
+ );
+
+//
+// Events from the IoQueue object
+//
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL KMDFEvtIoDeviceControl;
+EVT_WDF_IO_QUEUE_IO_STOP KMDFEvtIoStop;
+
+EXTERN_C_END
diff --git a/templates/KMDF/KMDF/ReadMe.txt b/templates/KMDF/KMDF/ReadMe.txt
new file mode 100644
index 000000000..4efb63c86
--- /dev/null
+++ b/templates/KMDF/KMDF/ReadMe.txt
@@ -0,0 +1,41 @@
+========================================================================
+ KMDF Project Overview
+========================================================================
+
+This file contains a summary of what you will find in each of the files that make up your project.
+
+KMDF.vcxproj
+ This is the main project file for projects generated using an Application Wizard.
+ It contains information about the version of the product that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+KMDF.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+Public.h
+ Header file to be shared with applications.
+
+Driver.c & Driver.h
+ DriverEntry and WDFDRIVER related functionality and callbacks.
+
+Device.c & Device.h
+ WDFDEVICE related functionality and callbacks.
+
+Queue.c & Queue.h
+ WDFQUEUE related functionality and callbacks.
+
+Trace.h
+ Definitions for WPP tracing.
+
+/////////////////////////////////////////////////////////////////////////////
+
+Learn more about Kernel Mode Driver Framework here:
+
+http://msdn.microsoft.com/en-us/library/ff544296(v=VS.85).aspx
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/templates/KMDF/KMDF/Trace.h b/templates/KMDF/KMDF/Trace.h
new file mode 100644
index 000000000..34b718242
--- /dev/null
+++ b/templates/KMDF/KMDF/Trace.h
@@ -0,0 +1,62 @@
+/*++
+
+Module Name:
+
+ Trace.h
+
+Abstract:
+
+ Header file for the debug tracing related function defintions and macros.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+//
+// Define the tracing flags.
+//
+// Tracing GUID - d37d85a1-c931-43ff-bf48-eba9d42a2371
+//
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ KMDFTraceGuid, (d37d85a1,c931,43ff,bf48,eba9d42a2371), \
+ \
+ WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \
+ WPP_DEFINE_BIT(TRACE_DRIVER) \
+ WPP_DEFINE_BIT(TRACE_DEVICE) \
+ WPP_DEFINE_BIT(TRACE_QUEUE) \
+ )
+
+#define WPP_FLAG_LEVEL_LOGGER(flag, level) \
+ WPP_LEVEL_LOGGER(flag)
+
+#define WPP_FLAG_LEVEL_ENABLED(flag, level) \
+ (WPP_LEVEL_ENABLED(flag) && \
+ WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)
+
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \
+ WPP_LEVEL_LOGGER(flags)
+
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \
+ (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+//
+// WPP orders static parameters before dynamic parameters. To support the Trace function
+// defined below which sets FLAGS=MYDRIVER_ALL_INFO, a custom macro must be defined to
+// reorder the arguments to what the .tpl configuration file expects.
+//
+#define WPP_RECORDER_FLAGS_LEVEL_ARGS(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags)
+#define WPP_RECORDER_FLAGS_LEVEL_FILTER(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl, flags)
+
+//
+// This comment block is scanned by the trace preprocessor to define our
+// Trace function.
+//
+// begin_wpp config
+// FUNC Trace{FLAGS=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...);
+// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...);
+// end_wpp
+//
diff --git a/templates/KMDFEmpty/KMDFEmpty.sln b/templates/KMDFEmpty/KMDFEmpty.sln
new file mode 100644
index 000000000..5a95cb9b7
--- /dev/null
+++ b/templates/KMDFEmpty/KMDFEmpty.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KMDFEmpty", "KMDFEmpty\KMDFEmpty.vcxproj", "{5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Debug|ARM64.Build.0 = Debug|ARM64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Debug|x64.ActiveCfg = Debug|x64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Debug|x64.Build.0 = Debug|x64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Debug|x64.Deploy.0 = Debug|x64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Release|ARM64.ActiveCfg = Release|ARM64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Release|ARM64.Build.0 = Release|ARM64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Release|ARM64.Deploy.0 = Release|ARM64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Release|x64.ActiveCfg = Release|x64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Release|x64.Build.0 = Release|x64
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {3AE92CE1-CF63-45A6-A413-62C67BDC771A}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.inf b/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.inf
new file mode 100644
index 000000000..021b42c80
--- /dev/null
+++ b/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.inf
@@ -0,0 +1,62 @@
+;
+; KMDFEmpty.inf
+;
+
+[Version]
+Signature = "$WINDOWS NT$"
+Class = System ; TODO: specify appropriate Class
+ClassGuid = {4d36e97d-e325-11ce-bfc1-08002be10318} ; TODO: specify appropriate ClassGuid
+Provider = %ManufacturerName%
+CatalogFile = KMDFEmpty.cat
+DriverVer = ; TODO: set DriverVer in stampinf property pages
+PnpLockdown = 1
+
+[DestinationDirs]
+DefaultDestDir = 13
+
+[SourceDisksNames]
+1 = %DiskName%,,,""
+
+[SourceDisksFiles]
+KMDFEmpty.sys = 1,,
+
+;*****************************************
+; Install Section
+;*****************************************
+
+[Manufacturer]
+%ManufacturerName% = Standard,NT$ARCH$.10.0...16299 ; %13% support introduced in build 16299
+
+[Standard.NT$ARCH$.10.0...16299]
+%KMDFEmpty.DeviceDesc% = KMDFEmpty_Device, Root\KMDFEmpty ; TODO: edit hw-id
+
+[KMDFEmpty_Device.NT]
+CopyFiles = File_Copy
+
+[File_Copy]
+KMDFEmpty.sys
+
+;-------------- Service installation
+[KMDFEmpty_Device.NT.Services]
+AddService = KMDFEmpty,%SPSVCINST_ASSOCSERVICE%, KMDFEmpty_Service_Inst
+
+; -------------- KMDFEmpty driver install sections
+[KMDFEmpty_Service_Inst]
+DisplayName = %KMDFEmpty.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %13%\KMDFEmpty.sys
+
+[KMDFEmpty_Device.NT.Wdf]
+KmdfService = KMDFEmpty, KMDFEmpty_wdfsect
+
+[KMDFEmpty_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+[Strings]
+SPSVCINST_ASSOCSERVICE = 0x00000002
+ManufacturerName = "" ;TODO: Replace with your manufacturer name
+DiskName = "KMDFEmpty Installation Disk"
+KMDFEmpty.DeviceDesc = "KMDFEmpty Device"
+KMDFEmpty.SVCDESC = "KMDFEmpty Service"
diff --git a/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.vcxproj b/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.vcxproj
new file mode 100644
index 000000000..efdeb8a38
--- /dev/null
+++ b/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.vcxproj
@@ -0,0 +1,112 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ {5A3A1D2A-B268-472F-B1F4-45957F7ABFDD}
+ {1bc93793-694f-48fe-9372-81e2b05556fd}
+ v4.5
+ 12.0
+ Debug
+ x64
+ KMDFEmpty
+
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+
+
+
+
+
+
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+
+ sha256
+
+
+
+
+ sha256
+
+
+
+
+ sha256
+
+
+
+
+ sha256
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.vcxproj.filters b/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.vcxproj.filters
new file mode 100644
index 000000000..3a3badbd3
--- /dev/null
+++ b/templates/KMDFEmpty/KMDFEmpty/KMDFEmpty.vcxproj.filters
@@ -0,0 +1,26 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+ Driver Files
+
+
+
\ No newline at end of file
diff --git a/templates/KmdfUsb/KmdfUsb.sln b/templates/KmdfUsb/KmdfUsb.sln
new file mode 100644
index 000000000..8a1238834
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KmdfUsb", "KmdfUsb\KmdfUsb.vcxproj", "{26AFE9A8-B46E-4497-85DA-EFB180D01A51}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Debug|ARM64.Build.0 = Debug|ARM64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Debug|x64.ActiveCfg = Debug|x64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Debug|x64.Build.0 = Debug|x64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Debug|x64.Deploy.0 = Debug|x64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Release|ARM64.ActiveCfg = Release|ARM64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Release|ARM64.Build.0 = Release|ARM64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Release|ARM64.Deploy.0 = Release|ARM64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Release|x64.ActiveCfg = Release|x64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Release|x64.Build.0 = Release|x64
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {596F056B-2D0E-4804-87AE-B27D312583F4}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/KmdfUsb/KmdfUsb/Device.c b/templates/KmdfUsb/KmdfUsb/Device.c
new file mode 100644
index 000000000..054d8917d
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/Device.c
@@ -0,0 +1,199 @@
+/*++
+
+Module Name:
+
+ device.c - Device handling events for example driver.
+
+Abstract:
+
+ This file contains the device entry points and callbacks.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "driver.h"
+#include "device.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, KmdfUsbCreateDevice)
+#pragma alloc_text (PAGE, KmdfUsbEvtDevicePrepareHardware)
+#endif
+
+
+NTSTATUS
+KmdfUsbCreateDevice(
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+
+Routine Description:
+
+ Worker routine called to create a device and its software resources.
+
+Arguments:
+
+ DeviceInit - Pointer to an opaque init structure. Memory for this
+ structure will be freed by the framework when the WdfDeviceCreate
+ succeeds. So don't access the structure after that point.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ PDEVICE_CONTEXT deviceContext;
+ WDFDEVICE device;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+ pnpPowerCallbacks.EvtDevicePrepareHardware = KmdfUsbEvtDevicePrepareHardware;
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
+
+ status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Get a pointer to the device context structure that we just associated
+ // with the device object. We define this structure in the device.h
+ // header file. DeviceGetContext is an inline function generated by
+ // using the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in device.h.
+ // This function will do the type checking and return the device context.
+ // If you pass a wrong object handle it will return NULL and assert if
+ // run under framework verifier mode.
+ //
+ deviceContext = DeviceGetContext(device);
+
+ //
+ // Initialize the context.
+ //
+ deviceContext->PrivateDeviceData = 0;
+
+ //
+ // Create a device interface so that applications can find and talk
+ // to us.
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ &GUID_DEVINTERFACE_KmdfUsb,
+ NULL // ReferenceString
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Initialize the I/O Package and any Queues
+ //
+ status = KmdfUsbQueueInitialize(device);
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+KmdfUsbEvtDevicePrepareHardware(
+ _In_ WDFDEVICE Device,
+ _In_ WDFCMRESLIST ResourceList,
+ _In_ WDFCMRESLIST ResourceListTranslated
+ )
+/*++
+
+Routine Description:
+
+ In this callback, the driver does whatever is necessary to make the
+ hardware ready to use. In the case of a USB device, this involves
+ reading and selecting descriptors.
+
+Arguments:
+
+ Device - handle to a device
+
+Return Value:
+
+ NT status value
+
+--*/
+{
+ NTSTATUS status;
+ PDEVICE_CONTEXT pDeviceContext;
+ WDF_USB_DEVICE_CREATE_CONFIG createParams;
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams;
+
+ UNREFERENCED_PARAMETER(ResourceList);
+ UNREFERENCED_PARAMETER(ResourceListTranslated);
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ status = STATUS_SUCCESS;
+ pDeviceContext = DeviceGetContext(Device);
+
+ //
+ // Create a USB device handle so that we can communicate with the
+ // underlying USB stack. The WDFUSBDEVICE handle is used to query,
+ // configure, and manage all aspects of the USB device.
+ // These aspects include device properties, bus properties,
+ // and I/O creation and synchronization. We only create the device the first time
+ // PrepareHardware is called. If the device is restarted by pnp manager
+ // for resource rebalance, we will use the same device handle but then select
+ // the interfaces again because the USB stack could reconfigure the device on
+ // restart.
+ //
+ if (pDeviceContext->UsbDevice == NULL) {
+
+ //
+ // Specifying a client contract version of 602 enables us to query for
+ // and use the new capabilities of the USB driver stack for Windows 8.
+ // It also implies that we conform to rules mentioned in MSDN
+ // documentation for WdfUsbTargetDeviceCreateWithParameters.
+ //
+ WDF_USB_DEVICE_CREATE_CONFIG_INIT(&createParams,
+ USBD_CLIENT_CONTRACT_VERSION_602
+ );
+
+ status = WdfUsbTargetDeviceCreateWithParameters(Device,
+ &createParams,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &pDeviceContext->UsbDevice
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "WdfUsbTargetDeviceCreateWithParameters failed 0x%x", status);
+ return status;
+ }
+ }
+
+ //
+ // Select the first configuration of the device, using the first alternate
+ // setting of each interface
+ //
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&configParams,
+ 0,
+ NULL
+ );
+ status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &configParams
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "WdfUsbTargetDeviceSelectConfig failed 0x%x", status);
+ return status;
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
diff --git a/templates/KmdfUsb/KmdfUsb/Device.h b/templates/KmdfUsb/KmdfUsb/Device.h
new file mode 100644
index 000000000..5737abe93
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/Device.h
@@ -0,0 +1,53 @@
+/*++
+
+Module Name:
+
+ device.h
+
+Abstract:
+
+ This file contains the device definitions.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "public.h"
+
+EXTERN_C_START
+
+//
+// The device context performs the same job as
+// a WDM device extension in the driver frameworks
+//
+typedef struct _DEVICE_CONTEXT
+{
+ WDFUSBDEVICE UsbDevice;
+ ULONG PrivateDeviceData; // just a placeholder
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// This macro will generate an inline function called DeviceGetContext
+// which will be used to get a pointer to the device context memory
+// in a type safe manner.
+//
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, DeviceGetContext)
+
+//
+// Function to initialize the device's queues and callbacks
+//
+NTSTATUS
+KmdfUsbCreateDevice(
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ );
+
+//
+// Function to select the device's USB configuration and get a WDFUSBDEVICE
+// handle
+//
+EVT_WDF_DEVICE_PREPARE_HARDWARE KmdfUsbEvtDevicePrepareHardware;
+
+EXTERN_C_END
diff --git a/templates/KmdfUsb/KmdfUsb/Driver.c b/templates/KmdfUsb/KmdfUsb/Driver.c
new file mode 100644
index 000000000..3deb29e9b
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/Driver.c
@@ -0,0 +1,167 @@
+/*++
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This file contains the driver entry points and callbacks.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "driver.h"
+#include "driver.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (INIT, DriverEntry)
+#pragma alloc_text (PAGE, KmdfUsbEvtDeviceAdd)
+#pragma alloc_text (PAGE, KmdfUsbEvtDriverContextCleanup)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded. DriverEntry specifies the other entry
+ points in the function driver, such as EvtDevice and DriverUnload.
+
+Parameters Description:
+
+ DriverObject - represents the instance of the function driver that is loaded
+ into memory. DriverEntry must initialize members of DriverObject before it
+ returns to the caller. DriverObject is allocated by the system before the
+ driver is loaded, and it is released by the system after the system unloads
+ the function driver from memory.
+
+ RegistryPath - represents the driver specific path in the Registry.
+ The function driver can use the path to store driver related data between
+ reboots. The path does not store hardware instance specific data.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ WDF_DRIVER_CONFIG config;
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES attributes;
+
+ //
+ // Initialize WPP Tracing
+ //
+ WPP_INIT_TRACING( DriverObject, RegistryPath );
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ //
+ // Register a cleanup callback so that we can call WPP_CLEANUP when
+ // the framework driver object is deleted during driver unload.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.EvtCleanupCallback = KmdfUsbEvtDriverContextCleanup;
+
+ WDF_DRIVER_CONFIG_INIT(&config,
+ KmdfUsbEvtDeviceAdd
+ );
+
+ status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ &attributes,
+ &config,
+ WDF_NO_HANDLE
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
+ WPP_CLEANUP(DriverObject);
+ return status;
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
+
+NTSTATUS
+KmdfUsbEvtDeviceAdd(
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ status = KmdfUsbCreateDevice(DeviceInit);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
+
+VOID
+KmdfUsbEvtDriverContextCleanup(
+ _In_ WDFOBJECT DriverObject
+ )
+/*++
+Routine Description:
+
+ Free all the resources allocated in DriverEntry.
+
+Arguments:
+
+ DriverObject - handle to a WDF Driver object.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ PAGED_CODE ();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ //
+ // Stop WPP Tracing
+ //
+ WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER) DriverObject) );
+
+}
diff --git a/templates/KmdfUsb/KmdfUsb/Driver.h b/templates/KmdfUsb/KmdfUsb/Driver.h
new file mode 100644
index 000000000..bbe75be9c
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/Driver.h
@@ -0,0 +1,38 @@
+/*++
+
+Module Name:
+
+ driver.h
+
+Abstract:
+
+ This file contains the driver definitions.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "device.h"
+#include "queue.h"
+#include "trace.h"
+
+EXTERN_C_START
+
+//
+// WDFDRIVER Events
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD KmdfUsbEvtDeviceAdd;
+EVT_WDF_OBJECT_CONTEXT_CLEANUP KmdfUsbEvtDriverContextCleanup;
+
+EXTERN_C_END
diff --git a/templates/KmdfUsb/KmdfUsb/KmdfUsb.inf b/templates/KmdfUsb/KmdfUsb/KmdfUsb.inf
new file mode 100644
index 000000000..3c36b902c
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/KmdfUsb.inf
@@ -0,0 +1,70 @@
+;
+; KmdfUsb.inf
+;
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=USBDevice
+ClassGuid={88BAE032-5A81-49f0-BC3D-A4FF138216D6}
+Provider=%ManufacturerName%
+CatalogFile=KmdfUsb.cat
+DriverVer=
+PnpLockDown=1
+
+[DestinationDirs]
+DefaultDestDir = 13
+
+[SourceDisksNames]
+1 = %DiskName%,,,""
+
+[SourceDisksFiles]
+KmdfUsb.sys = 1,,
+
+;*****************************************
+; Install Section
+;*****************************************
+
+[Manufacturer]
+%ManufacturerName%=Standard,NT$ARCH$.10.0...16299 ; %13% support introduced in build 16299
+
+[Standard.NT$ARCH$.10.0...16299]
+%KmdfUsb.DeviceDesc%=KmdfUsb_Device, USB\VID_vvvv&PID_pppp
+
+[KmdfUsb_Device.NT]
+CopyFiles=File_Copy
+
+[File_Copy]
+KmdfUsb.sys
+
+[KmdfUsb_Device.NT.HW]
+AddReg=KmdfUsb_AddReg
+
+[KmdfUsb_AddReg]
+; By default, USBDevice class uses iProduct descriptor to name the device
+; Uncomment for this device to use %KmdfUsb.DeviceDesc%
+;HKR,,FriendlyName,,%KmdfUsb.DeviceDesc%
+
+;-------------- Service installation
+[KmdfUsb_Device.NT.Services]
+AddService = KmdfUsb,%SPSVCINST_ASSOCSERVICE%, KmdfUsb_Service_Inst
+
+; -------------- KmdfUsb driver install sections
+[KmdfUsb_Service_Inst]
+DisplayName = %KmdfUsb.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %13%\KmdfUsb.sys
+
+[KmdfUsb_Device.NT.Wdf]
+KmdfService = KmdfUsb, KmdfUsb_wdfsect
+
+[KmdfUsb_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+[Strings]
+SPSVCINST_ASSOCSERVICE= 0x00000002
+ManufacturerName="" ;TODO: Replace with your manufacturer name
+DiskName = "KmdfUsb Installation Disk"
+KmdfUsb.DeviceDesc = "KmdfUsb Device"
+KmdfUsb.SVCDESC = "KmdfUsb Service"
\ No newline at end of file
diff --git a/templates/KmdfUsb/KmdfUsb/KmdfUsb.vcxproj b/templates/KmdfUsb/KmdfUsb/KmdfUsb.vcxproj
new file mode 100644
index 000000000..46e8c0396
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/KmdfUsb.vcxproj
@@ -0,0 +1,171 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {26AFE9A8-B46E-4497-85DA-EFB180D01A51}
+ {8c0e3d8b-df43-455b-815a-4a0e72973bc6}
+ v4.5
+ 12.0
+ Debug
+ x64
+ KmdfUsb
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ KMDF
+ Universal
+
+
+
+ Windows10
+ true
+
+
+ Windows10
+ false
+
+
+ Windows10
+ true
+
+
+ Windows10
+ false
+
+
+
+
+
+
+
+
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+
+ true
+ true
+ trace.h
+ true
+
+
+ sha256
+
+
+ %(AdditionalDependencies);usbdex.lib;ntstrsafe.lib
+
+
+
+
+ true
+ true
+ trace.h
+ true
+
+
+ sha256
+
+
+ %(AdditionalDependencies);usbdex.lib;ntstrsafe.lib
+
+
+
+
+ true
+ true
+ trace.h
+ true
+
+
+ sha256
+
+
+ %(AdditionalDependencies);usbdex.lib;ntstrsafe.lib
+
+
+
+
+ true
+ true
+ trace.h
+ true
+
+
+ sha256
+
+
+ %(AdditionalDependencies);usbdex.lib;ntstrsafe.lib
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/KmdfUsb/KmdfUsb/KmdfUsb.vcxproj.filters b/templates/KmdfUsb/KmdfUsb/KmdfUsb.vcxproj.filters
new file mode 100644
index 000000000..b8396b9e9
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/KmdfUsb.vcxproj.filters
@@ -0,0 +1,57 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+
+
+
+ Driver Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/templates/KmdfUsb/KmdfUsb/Public.h b/templates/KmdfUsb/KmdfUsb/Public.h
new file mode 100644
index 000000000..0ec9f436c
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/Public.h
@@ -0,0 +1,24 @@
+/*++
+
+Module Name:
+
+ public.h
+
+Abstract:
+
+ This module contains the common declarations shared by driver
+ and user applications.
+
+Environment:
+
+ user and kernel
+
+--*/
+
+//
+// Define an Interface Guid so that app can find the device and talk to it.
+//
+
+DEFINE_GUID (GUID_DEVINTERFACE_KmdfUsb,
+ 0xd4f6a10a,0xeed5,0x4fdd,0xa3,0x76,0x6c,0x6b,0xf6,0x6d,0x34,0x94);
+// {d4f6a10a-eed5-4fdd-a376-6c6bf66d3494}
diff --git a/templates/KmdfUsb/KmdfUsb/Queue.c b/templates/KmdfUsb/KmdfUsb/Queue.c
new file mode 100644
index 000000000..0bceee9ec
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/Queue.c
@@ -0,0 +1,186 @@
+/*++
+
+Module Name:
+
+ queue.c
+
+Abstract:
+
+ This file contains the queue entry points and callbacks.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "driver.h"
+#include "queue.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, KmdfUsbQueueInitialize)
+#endif
+
+NTSTATUS
+KmdfUsbQueueInitialize(
+ _In_ WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+
+ The I/O dispatch callbacks for the frameworks device object
+ are configured in this function.
+
+ A single default I/O Queue is configured for parallel request
+ processing, and a driver context memory allocation is created
+ to hold our structure QUEUE_CONTEXT.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ WDFQUEUE queue;
+ NTSTATUS status;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+
+ PAGED_CODE();
+
+ //
+ // Configure a default queue so that requests that are not
+ // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
+ // other queues get dispatched here.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchParallel
+ );
+
+ queueConfig.EvtIoDeviceControl = KmdfUsbEvtIoDeviceControl;
+ queueConfig.EvtIoStop = KmdfUsbEvtIoStop;
+
+ status = WdfIoQueueCreate(
+ Device,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &queue
+ );
+
+ if( !NT_SUCCESS(status) ) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_QUEUE, "WdfIoQueueCreate failed %!STATUS!", status);
+ return status;
+ }
+
+ return status;
+}
+
+VOID
+KmdfUsbEvtIoDeviceControl(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+/*++
+
+Routine Description:
+
+ This event is invoked when the framework receives IRP_MJ_DEVICE_CONTROL request.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ OutputBufferLength - Size of the output buffer in bytes
+
+ InputBufferLength - Size of the input buffer in bytes
+
+ IoControlCode - I/O control code.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_QUEUE,
+ "%!FUNC! Queue 0x%p, Request 0x%p OutputBufferLength %d InputBufferLength %d IoControlCode %d",
+ Queue, Request, (int) OutputBufferLength, (int) InputBufferLength, IoControlCode);
+
+ WdfRequestComplete(Request, STATUS_SUCCESS);
+
+ return;
+}
+
+VOID
+KmdfUsbEvtIoStop(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ ULONG ActionFlags
+)
+/*++
+
+Routine Description:
+
+ This event is invoked for a power-managed queue before the device leaves the working state (D0).
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ ActionFlags - A bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS-typed flags
+ that identify the reason that the callback function is being called
+ and whether the request is cancelable.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_QUEUE,
+ "%!FUNC! Queue 0x%p, Request 0x%p ActionFlags %d",
+ Queue, Request, ActionFlags);
+
+ //
+ // In most cases, the EvtIoStop callback function completes, cancels, or postpones
+ // further processing of the I/O request.
+ //
+ // Typically, the driver uses the following rules:
+ //
+ // - If the driver owns the I/O request, it either postpones further processing
+ // of the request and calls WdfRequestStopAcknowledge, or it calls WdfRequestComplete
+ // with a completion status value of STATUS_SUCCESS or STATUS_CANCELLED.
+ //
+ // The driver must call WdfRequestComplete only once, to either complete or cancel
+ // the request. To ensure that another thread does not call WdfRequestComplete
+ // for the same request, the EvtIoStop callback must synchronize with the driver's
+ // other event callback functions, for instance by using interlocked operations.
+ //
+ // - If the driver has forwarded the I/O request to an I/O target, it either calls
+ // WdfRequestCancelSentRequest to attempt to cancel the request, or it postpones
+ // further processing of the request and calls WdfRequestStopAcknowledge.
+ //
+ // A driver might choose to take no action in EvtIoStop for requests that are
+ // guaranteed to complete in a small amount of time. For example, the driver might
+ // take no action for requests that are completed in one of the driver’s request handlers.
+ //
+
+ return;
+}
diff --git a/templates/KmdfUsb/KmdfUsb/Queue.h b/templates/KmdfUsb/KmdfUsb/Queue.h
new file mode 100644
index 000000000..636ff4de2
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/Queue.h
@@ -0,0 +1,42 @@
+/*++
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This file contains the queue definitions.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+EXTERN_C_START
+
+//
+// This is the context that can be placed per queue
+// and would contain per queue information.
+//
+typedef struct _QUEUE_CONTEXT {
+
+ ULONG PrivateDeviceData; // just a placeholder
+
+} QUEUE_CONTEXT, *PQUEUE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext)
+
+NTSTATUS
+KmdfUsbQueueInitialize(
+ _In_ WDFDEVICE Device
+ );
+
+//
+// Events from the IoQueue object
+//
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL KmdfUsbEvtIoDeviceControl;
+EVT_WDF_IO_QUEUE_IO_STOP KmdfUsbEvtIoStop;
+
+EXTERN_C_END
diff --git a/templates/KmdfUsb/KmdfUsb/ReadMe.txt b/templates/KmdfUsb/KmdfUsb/ReadMe.txt
new file mode 100644
index 000000000..8a5a18f5c
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/ReadMe.txt
@@ -0,0 +1,55 @@
+========================================================================
+ KmdfUsb Project Overview
+========================================================================
+
+This file contains a summary of what you will find in each of the files that make up your project.
+
+KmdfUsb.vcxproj
+ This is the main project file for projects generated using an Application Wizard.
+ It contains information about the version of the product that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+KmdfUsb.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+KmdfUsb.inf
+ Text file used for driver installation. After creating this driver using the template, the user
+ *must* update the hardware ID from "USB\VID_vvvv&PID_pppp" to the hardware ID of the USB device
+ that the driver should be installed on.
+
+Public.h
+ Header file to be shared with applications.
+
+Driver.c & Driver.h
+ DriverEntry and WDFDRIVER related functionality and callbacks.
+
+Device.cpp & Device.h
+ WDFDEVICE and WDFUSBDEVICE related functionality and callbacks.
+
+IoQueue.cpp & IoQueue.h
+ WDFQUEUE related functionality and callbacks.
+
+Trace.h
+ Definitions for WPP tracing.
+
+/////////////////////////////////////////////////////////////////////////////
+
+Learn more about Kernel Mode Driver Framework here:
+
+http://msdn.microsoft.com/en-us/library/ff544296(v=VS.85).aspx
+
+Learn more about KMDF USB APIs here:
+
+http://msdn.microsoft.com/en-us/library/ff544752(v=vs.85).aspx
+
+Related WDK samples and what they demonstrate:
+
+ osrusbfx2 - bulk/interrupt transfers, continuous readers
+ usbsamp - isochronous transfers
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/templates/KmdfUsb/KmdfUsb/Trace.h b/templates/KmdfUsb/KmdfUsb/Trace.h
new file mode 100644
index 000000000..ce534951b
--- /dev/null
+++ b/templates/KmdfUsb/KmdfUsb/Trace.h
@@ -0,0 +1,62 @@
+/*++
+
+Module Name:
+
+ Trace.h
+
+Abstract:
+
+ Header file for the debug tracing related function defintions and macros.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+//
+// Define the tracing flags.
+//
+// Tracing GUID - 1322ffe6-f20c-4706-9019-a9d5b9ae5421
+//
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ KmdfUsbTraceGuid, (1322ffe6,f20c,4706,9019,a9d5b9ae5421), \
+ \
+ WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \
+ WPP_DEFINE_BIT(TRACE_DRIVER) \
+ WPP_DEFINE_BIT(TRACE_DEVICE) \
+ WPP_DEFINE_BIT(TRACE_QUEUE) \
+ )
+
+#define WPP_FLAG_LEVEL_LOGGER(flag, level) \
+ WPP_LEVEL_LOGGER(flag)
+
+#define WPP_FLAG_LEVEL_ENABLED(flag, level) \
+ (WPP_LEVEL_ENABLED(flag) && \
+ WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)
+
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \
+ WPP_LEVEL_LOGGER(flags)
+
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \
+ (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+//
+// WPP orders static parameters before dynamic parameters. To support the Trace function
+// defined below which sets FLAGS=MYDRIVER_ALL_INFO, a custom macro must be defined to
+// reorder the arguments to what the .tpl configuration file expects.
+//
+#define WPP_RECORDER_FLAGS_LEVEL_ARGS(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags)
+#define WPP_RECORDER_FLAGS_LEVEL_FILTER(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl, flags)
+
+//
+// This comment block is scanned by the trace preprocessor to define our
+// Trace function.
+//
+// begin_wpp config
+// FUNC Trace{FLAGS=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...);
+// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...);
+// end_wpp
+//
diff --git a/templates/NdisFilter/NdisFilter.sln b/templates/NdisFilter/NdisFilter.sln
new file mode 100644
index 000000000..7b745f1ba
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NdisFilter", "NdisFilter\NdisFilter.vcxproj", "{C3793437-22B0-458A-BE45-EEF540CB835B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Debug|ARM64.Build.0 = Debug|ARM64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Debug|x64.ActiveCfg = Debug|x64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Debug|x64.Build.0 = Debug|x64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Debug|x64.Deploy.0 = Debug|x64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Release|ARM64.ActiveCfg = Release|ARM64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Release|ARM64.Build.0 = Release|ARM64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Release|ARM64.Deploy.0 = Release|ARM64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Release|x64.ActiveCfg = Release|x64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Release|x64.Build.0 = Release|x64
+ {C3793437-22B0-458A-BE45-EEF540CB835B}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {70A3FBB2-459A-48E7-B2C9-5FBF99858F2C}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/NdisFilter/NdisFilter/NdisFilter.inf b/templates/NdisFilter/NdisFilter/NdisFilter.inf
new file mode 100644
index 000000000..0f411427a
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/NdisFilter.inf
@@ -0,0 +1,169 @@
+;-------------------------------------------------------------------------
+; NdisFilter.INF -- NDIS LightWeight Filter Driver
+;
+; TODO: Search for comments marked "TODO:", and follow their instructions to
+; customize this INF for your driver. Then delete the "TODO:" comments.
+;-------------------------------------------------------------------------
+
+[version]
+; Do not change these values
+Signature = "$Windows NT$"
+Class = NetService
+ClassGUID = {4D36E974-E325-11CE-BFC1-08002BE10318}
+; TODO: Customize this string for your company name
+Provider = %Msft%
+DriverVer =
+CatalogFile = NdisFilter.cat
+
+
+; TODO: Include each architecture for which your driver package contains a
+; compiled binary. If you do not supply a driver compiled for ia64, delete the
+; NTia64 section.
+[Manufacturer]
+%Msft%=MSFT,NTx86,NTia64,NTamd64,NTarm,NTarm64
+
+; MS_NdisFilter can be used with netcfg.exe to install/uninstall the driver.
+[MSFT.NTx86]
+%NdisFilter_Desc%=Install, MS_NdisFilter
+
+[MSFT.NTia64]
+%NdisFilter_Desc%=Install, MS_NdisFilter
+
+[MSFT.NTamd64]
+%NdisFilter_Desc%=Install, MS_NdisFilter
+
+[MSFT.NTarm]
+%NdisFilter_Desc%=Install, MS_NdisFilter
+
+[MSFT.NTarm64]
+%NdisFilter_Desc%=Install, MS_NdisFilter
+
+;-------------------------------------------------------------------------
+; Installation Section
+;-------------------------------------------------------------------------
+[Install]
+AddReg=Inst_Ndi
+; All LWFs must include the 0x40000 bit (NCF_LW_FILTER). Unlike miniports, you
+; don't usually need to customize this value.
+Characteristics=0x40000
+
+; This must be a random, unique value.
+; FILTER_UNIQUE_NAME in filter.h must match this GUID identically.
+; Both should have {curly braces}.
+NetCfgInstanceId="{1ce83cec-805d-4357-9982-f1fa78a3f617}"
+
+Copyfiles = NdisFilter.copyfiles.sys
+
+[SourceDisksNames]
+1=%NdisFilter_Desc%,"",,
+
+[SourceDisksFiles]
+; TODO: Include any related files that should be installed with your driver.
+NdisFilter.sys=1
+
+[DestinationDirs]
+DefaultDestDir=12
+NdisFilter.copyfiles.sys=12
+
+[NdisFilter.copyfiles.sys]
+NdisFilter.sys,,,2
+
+
+;-------------------------------------------------------------------------
+; Ndi installation support
+;-------------------------------------------------------------------------
+[Inst_Ndi]
+HKR, Ndi,Service,,"NdisFilter"
+HKR, Ndi,CoServices,0x00010000,"NdisFilter"
+HKR, Ndi,HelpText,,%NdisFilter_HelpText%
+; TODO: Set the FilterClass here. The FilterClass controls the order in which
+; filters are bound to the underlying miniport. Possible options include:
+; Custom, Diagnostic, Failover, Loadbalance, Vpn, Compression, Encryption, Scheduler
+; See MSDN for a description of each.
+HKR, Ndi,FilterClass,, compression
+; TODO: Specify whether you have a Modifying or Monitoring filter.
+; For a Monitoring filter, use this:
+; HKR, Ndi,FilterType,0x00010001, 1 ; Monitoring filter
+; For a Modifying filter, use this:
+; HKR, Ndi,FilterType,0x00010001, 2 ; Modifying filter
+HKR, Ndi,FilterType,0x00010001,2
+; Do not change these values
+HKR, Ndi\Interfaces,UpperRange,,"noupper"
+HKR, Ndi\Interfaces,LowerRange,,"nolower"
+; TODO: Ensure that the list of media types below is correct. Typically,
+; filters include "ethernet". Filters may also include "ppip" to include
+; native WWAN stacks, but you must be prepared to handle the packet framing.
+; Possible values are listed on MSDN, but common values include:
+; ethernet, wan, ppip, wlan
+HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet, wan, ppip"
+; TODO: Specify whether you have a Mandatory or Optional filter.
+; For a Mandatory filter, use this:
+; HKR, Ndi,FilterRunType,0x00010001, 1 ; Mandatory filter
+; For an Optional filter, use this:
+; HKR, Ndi,FilterRunType,0x00010001, 2 ; Optional filter
+HKR, Ndi,FilterRunType,0x00010001, 1 ; Mandatory filter
+
+;-------------------------------------------------------------------------
+; Service installation support
+;-------------------------------------------------------------------------
+[Install.Services]
+; TODO: You may want to add the SPSVCINST_STARTSERVICE flag, like this:
+; AddService=NdisFilter,0x800,NdisFilter_Service_Inst ; SPSVCINST_STARTSERVICE
+AddService=NdisFilter,,NdisFilter_Service_Inst
+
+[NdisFilter_Service_Inst]
+DisplayName = %NdisFilter_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+; Typically you will want your filter driver to start with SERVICE_SYSTEM_START.
+; If it is an Optional filter, you may also use 3;SERVICE_DEMAND_START.
+StartType = 1 ;SERVICE_SYSTEM_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\NdisFilter.sys
+LoadOrderGroup = NDIS
+Description = %NdisFilter_Desc%
+AddReg = Common.Params.reg, NdisImPlatformBindingOptions.reg
+
+[Install.Remove.Services]
+; The SPSVCINST_STOPSERVICE flag instructs SCM to stop the NT service
+; before uninstalling the driver.
+DelService=NdisFilter,0x200 ; SPSVCINST_STOPSERVICE
+
+[Common.Params.reg]
+; TODO: You can add any sort of NDIS parameters here. Filter drivers
+; don't always need NDIS parameters, so it's okay to have nothing here.
+
+; TODO: Remove the sample parameters below.
+
+; Sample 1: "DriverParam" is a per-driver parameter.
+HKR, FilterDriverParams\DriverParam, ParamDesc, , "Driverparam for lwf"
+HKR, FilterDriverParams\DriverParam, default, , "5"
+HKR, FilterDriverParams\DriverParam, type, , "int"
+
+; Sample 2: "AdapterParam" is a per-module parameter.
+HKR, FilterAdapterParams\AdapterParam, ParamDesc, , "Adapterparam for lwf"
+HKR, FilterAdapterParams\AdapterParam, default, , "10"
+HKR, FilterAdapterParams\AdapterParam, type, , "int"
+
+[NdisImPlatformBindingOptions.reg]
+; By default, when an LBFO team or Bridge is created, all filters will be
+; unbound from the underlying members and bound to the TNic(s). This keyword
+; allows a component to opt out of the default behavior
+; To prevent binding this filter to the TNic(s):
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,1 ; Do not bind to TNic
+; To prevent unbinding this filter from underlying members:
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,2 ; Do not unbind from Members
+; To prevent both binding to TNic and unbinding from members:
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,3 ; Do not bind to TNic or unbind from Members
+HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,0 ; Subscribe to default behavior
+
+
+
+[Strings]
+; TODO: Customize these strings.
+Msft = "" ;TODO: Replace with your manufacturer name
+NdisFilter_Desc = "NdisFilter NDIS LightWeight Filter"
+NdisFilter_HelpText = "NdisFilter NDIS LightWeight Filter"
+
+
+
+
diff --git a/templates/NdisFilter/NdisFilter/NdisFilter.vcxproj b/templates/NdisFilter/NdisFilter/NdisFilter.vcxproj
new file mode 100644
index 000000000..8acfd3865
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/NdisFilter.vcxproj
@@ -0,0 +1,195 @@
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ {C3793437-22B0-458A-BE45-EEF540CB835B}
+ {8b1800b9-d017-4029-9785-13ef5e5b328e}
+ Converted Driver Project
+ ndislwf.vcxproj
+ 12.0
+ Debug
+ x64
+ NdisFilter
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+ Universal
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+ Universal
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+ Universal
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+ Universal
+
+
+
+ Windows10
+ true
+
+
+ Windows10
+ false
+
+
+ Windows10
+ true
+
+
+ Windows10
+ false
+
+
+
+
+
+
+
+ DbgengKernelDebugger
+ ndislwf
+
+
+ DbgengKernelDebugger
+ ndislwf
+
+
+ DbgengKernelDebugger
+ ndislwf
+
+
+ DbgengKernelDebugger
+ ndislwf
+
+
+
+ Level4
+ true
+ ..;.;%(AdditionalIncludeDirectories)
+ %(PreProcessorDefinitions);NDIS_WDM=1;NDIS630=1
+ %(DisableSpecificWarnings);4201;4214
+ precomp.h
+ Use
+
+
+ %(AdditionalIncludeDirectories);..;.;
+
+
+ %(AdditionalDependencies);ndis.lib
+
+
+ sha256
+
+
+
+
+ Level4
+ true
+ ..;.;%(AdditionalIncludeDirectories)
+ %(PreProcessorDefinitions);NDIS_WDM=1;NDIS630=1
+ %(DisableSpecificWarnings);4201;4214
+ precomp.h
+ Use
+
+
+ %(AdditionalIncludeDirectories);..;.;
+
+
+ %(AdditionalDependencies);ndis.lib
+
+
+ sha256
+
+
+
+
+ Level4
+ true
+ ..;.;%(AdditionalIncludeDirectories)
+ %(PreProcessorDefinitions);NDIS_WDM=1;NDIS630=1
+ %(DisableSpecificWarnings);4201;4214
+ precomp.h
+ Use
+
+
+ %(AdditionalIncludeDirectories);..;.;
+
+
+ %(AdditionalDependencies);ndis.lib
+
+
+ sha256
+
+
+
+
+ Level4
+ true
+ ..;.;%(AdditionalIncludeDirectories)
+ %(PreProcessorDefinitions);NDIS_WDM=1;NDIS630=1
+ %(DisableSpecificWarnings);4201;4214
+ precomp.h
+ Use
+
+
+ %(AdditionalIncludeDirectories);..;.;
+
+
+ %(AdditionalDependencies);ndis.lib
+
+
+ sha256
+
+
+
+
+
+ ..;.;%(AdditionalIncludeDirectories)
+ %(PreProcessorDefinitions);NDIS_WDM=1
+ precomp.h
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/NdisFilter/NdisFilter/NdisFilter.vcxproj.filters b/templates/NdisFilter/NdisFilter/NdisFilter.vcxproj.filters
new file mode 100644
index 000000000..4c5fe11e3
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/NdisFilter.vcxproj.filters
@@ -0,0 +1,59 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+ Driver Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/templates/NdisFilter/NdisFilter/device.c b/templates/NdisFilter/NdisFilter/device.c
new file mode 100644
index 000000000..722c191a0
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/device.c
@@ -0,0 +1,295 @@
+/*++
+ *
+ * The file contains the routines to create a device and handle ioctls
+ *
+-- */
+
+#include "precomp.h"
+
+#pragma NDIS_INIT_FUNCTION(NdisFilterRegisterDevice)
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+NdisFilterRegisterDevice(
+ VOID
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ UNICODE_STRING DeviceName;
+ UNICODE_STRING DeviceLinkUnicodeString;
+ PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
+ NDIS_DEVICE_OBJECT_ATTRIBUTES DeviceAttribute;
+ PFILTER_DEVICE_EXTENSION FilterDeviceExtension;
+ PDRIVER_OBJECT DriverObject;
+
+ DEBUGP(DL_TRACE, "==>NdisFilterRegisterDevice\n");
+
+
+ NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
+
+ DispatchTable[IRP_MJ_CREATE] = NdisFilterDispatch;
+ DispatchTable[IRP_MJ_CLEANUP] = NdisFilterDispatch;
+ DispatchTable[IRP_MJ_CLOSE] = NdisFilterDispatch;
+ DispatchTable[IRP_MJ_DEVICE_CONTROL] = NdisFilterDeviceIoControl;
+
+
+ NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);
+ NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING);
+
+ //
+ // Create a device object and register our dispatch handlers
+ //
+ NdisZeroMemory(&DeviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES));
+
+ DeviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
+ DeviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
+ DeviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES);
+
+ DeviceAttribute.DeviceName = &DeviceName;
+ DeviceAttribute.SymbolicName = &DeviceLinkUnicodeString;
+ DeviceAttribute.MajorFunctions = &DispatchTable[0];
+ DeviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);
+
+ Status = NdisRegisterDeviceEx(
+ FilterDriverHandle,
+ &DeviceAttribute,
+ &NdisDeviceObject,
+ &NdisFilterDeviceHandle
+ );
+
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ FilterDeviceExtension = (PFILTER_DEVICE_EXTENSION) NdisGetDeviceReservedExtension(NdisDeviceObject);
+
+ FilterDeviceExtension->Signature = 'FTDR';
+ FilterDeviceExtension->Handle = FilterDriverHandle;
+
+ //
+ // Workaround NDIS bug
+ //
+ DriverObject = (PDRIVER_OBJECT)FilterDriverObject;
+ }
+
+
+ DEBUGP(DL_TRACE, "<==NdisFilterRegisterDevice: %x\n", Status);
+
+ return (Status);
+
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+NdisFilterDeregisterDevice(
+ VOID
+ )
+
+{
+ if (NdisFilterDeviceHandle != NULL)
+ {
+ NdisDeregisterDeviceEx(NdisFilterDeviceHandle);
+ }
+
+ NdisFilterDeviceHandle = NULL;
+
+}
+
+_Use_decl_annotations_
+NTSTATUS
+NdisFilterDispatch(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION IrpStack;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (IrpStack->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ break;
+
+ case IRP_MJ_CLEANUP:
+ break;
+
+ case IRP_MJ_CLOSE:
+ break;
+
+ default:
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+NdisFilterDeviceIoControl(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PFILTER_DEVICE_EXTENSION FilterDeviceExtension;
+ PUCHAR InputBuffer;
+ PUCHAR OutputBuffer;
+ ULONG InputBufferLength, OutputBufferLength;
+ PLIST_ENTRY Link;
+ PUCHAR pInfo;
+ ULONG InfoLength = 0;
+ PMS_FILTER pFilter = NULL;
+ BOOLEAN bFalse = FALSE;
+
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ if (IrpSp->FileObject == NULL)
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+
+ FilterDeviceExtension = (PFILTER_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(DeviceObject);
+
+ ASSERT(FilterDeviceExtension->Signature == 'FTDR');
+
+ Irp->IoStatus.Information = 0;
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+
+ case IOCTL_FILTER_RESTART_ALL:
+ break;
+
+ case IOCTL_FILTER_RESTART_ONE_INSTANCE:
+ InputBuffer = OutputBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ pFilter = filterFindFilterModule (InputBuffer, InputBufferLength);
+
+ if (pFilter == NULL)
+ {
+
+ break;
+ }
+
+ NdisFRestartFilter(pFilter->FilterHandle);
+
+ break;
+
+ case IOCTL_FILTER_ENUERATE_ALL_INSTANCES:
+
+ InputBuffer = OutputBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+
+ pInfo = OutputBuffer;
+
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+
+ Link = FilterModuleList.Flink;
+
+ while (Link != &FilterModuleList)
+ {
+ pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);
+
+
+ InfoLength += (pFilter->FilterModuleName.Length + sizeof(USHORT));
+
+ if (InfoLength <= OutputBufferLength)
+ {
+ *(PUSHORT)pInfo = pFilter->FilterModuleName.Length;
+ NdisMoveMemory(pInfo + sizeof(USHORT),
+ (PUCHAR)(pFilter->FilterModuleName.Buffer),
+ pFilter->FilterModuleName.Length);
+
+ pInfo += (pFilter->FilterModuleName.Length + sizeof(USHORT));
+ }
+
+ Link = Link->Flink;
+ }
+
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+ if (InfoLength <= OutputBufferLength)
+ {
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ //
+ // Buffer is small
+ //
+ else
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+
+ default:
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = InfoLength;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+
+
+}
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+PMS_FILTER
+filterFindFilterModule(
+ _In_reads_bytes_(BufferLength)
+ PUCHAR Buffer,
+ _In_ ULONG BufferLength
+ )
+{
+
+ PMS_FILTER pFilter;
+ PLIST_ENTRY Link;
+ BOOLEAN bFalse = FALSE;
+
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+
+ Link = FilterModuleList.Flink;
+
+ while (Link != &FilterModuleList)
+ {
+ pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);
+
+ if (BufferLength >= pFilter->FilterModuleName.Length)
+ {
+ if (NdisEqualMemory(Buffer, pFilter->FilterModuleName.Buffer, pFilter->FilterModuleName.Length))
+ {
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+ return pFilter;
+ }
+ }
+
+ Link = Link->Flink;
+ }
+
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+ return NULL;
+}
+
+
+
+
diff --git a/templates/NdisFilter/NdisFilter/filter.c b/templates/NdisFilter/NdisFilter/filter.c
new file mode 100644
index 000000000..c7043a4bc
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/filter.c
@@ -0,0 +1,1906 @@
+/*++
+
+Module Name:
+
+ Filter.c
+
+Abstract:
+
+ Sample NDIS Lightweight filter driver
+
+--*/
+
+#include "precomp.h"
+
+#define __FILENUMBER 'PNPF'
+
+// This directive puts the DriverEntry function into the INIT segment of the
+// driver. To conserve memory, the code will be discarded when the driver's
+// DriverEntry function returns. You can declare other functions used only
+// during initialization here.
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+//
+// Global variables
+//
+NDIS_HANDLE FilterDriverHandle; // NDIS handle for filter driver
+NDIS_HANDLE FilterDriverObject;
+NDIS_HANDLE NdisFilterDeviceHandle = NULL;
+PDEVICE_OBJECT NdisDeviceObject = NULL;
+
+FILTER_LOCK FilterListLock;
+LIST_ENTRY FilterModuleList;
+
+NDIS_FILTER_PARTIAL_CHARACTERISTICS DefaultChars = {
+{ 0, 0, 0},
+ 0,
+ FilterSendNetBufferLists,
+ FilterSendNetBufferListsComplete,
+ NULL,
+ FilterReceiveNetBufferLists,
+ FilterReturnNetBufferLists
+};
+
+
+_Use_decl_annotations_
+NTSTATUS
+DriverEntry(
+ PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ First entry point to be called, when this driver is loaded.
+ Register with NDIS as a filter driver and create a device
+ for communication with user-mode.
+
+Arguments:
+
+ DriverObject - pointer to the system's driver object structure
+ for this driver
+
+ RegistryPath - system's registry path for this driver
+
+Return Value:
+
+ STATUS_SUCCESS if all initialization is successful, STATUS_XXX
+ error code if not.
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
+ NDIS_STRING ServiceName = RTL_CONSTANT_STRING(FILTER_SERVICE_NAME);
+ NDIS_STRING UniqueName = RTL_CONSTANT_STRING(FILTER_UNIQUE_NAME);
+ NDIS_STRING FriendlyName = RTL_CONSTANT_STRING(FILTER_FRIENDLY_NAME);
+ BOOLEAN bFalse = FALSE;
+
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ DEBUGP(DL_TRACE, "===>DriverEntry...\n");
+
+ FilterDriverObject = DriverObject;
+
+ do
+ {
+ NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS));
+ FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
+ FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
+#if NDIS_SUPPORT_NDIS61
+ FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_2;
+#else
+ FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;
+#endif
+ FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION;
+ FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION;
+ FChars.MajorDriverVersion = 1;
+ FChars.MinorDriverVersion = 0;
+ FChars.Flags = 0;
+
+ FChars.FriendlyName = FriendlyName;
+ FChars.UniqueName = UniqueName;
+ FChars.ServiceName = ServiceName;
+
+ //
+ // TODO: Most handlers are optional, however, this sample includes them
+ // all for illustrative purposes. If you do not need a particular
+ // handler, set it to NULL and NDIS will more efficiently pass the
+ // operation through on your behalf.
+ //
+ FChars.SetOptionsHandler = FilterRegisterOptions;
+ FChars.AttachHandler = FilterAttach;
+ FChars.DetachHandler = FilterDetach;
+ FChars.RestartHandler = FilterRestart;
+ FChars.PauseHandler = FilterPause;
+ FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions;
+ FChars.OidRequestHandler = FilterOidRequest;
+ FChars.OidRequestCompleteHandler = FilterOidRequestComplete;
+ FChars.CancelOidRequestHandler = FilterCancelOidRequest;
+
+ FChars.SendNetBufferListsHandler = FilterSendNetBufferLists;
+ FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists;
+ FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;
+ FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;
+ FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify;
+ FChars.NetPnPEventHandler = FilterNetPnPEvent;
+ FChars.StatusHandler = FilterStatus;
+ FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists;
+
+ DriverObject->DriverUnload = FilterUnload;
+
+ FilterDriverHandle = NULL;
+
+ //
+ // Initialize spin locks
+ //
+ FILTER_INIT_LOCK(&FilterListLock);
+
+ InitializeListHead(&FilterModuleList);
+
+ Status = NdisFRegisterFilterDriver(DriverObject,
+ (NDIS_HANDLE)FilterDriverObject,
+ &FChars,
+ &FilterDriverHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, "Register filter driver failed.\n");
+ break;
+ }
+
+ Status = NdisFilterRegisterDevice();
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisFDeregisterFilterDriver(FilterDriverHandle);
+ FILTER_FREE_LOCK(&FilterListLock);
+ DEBUGP(DL_WARN, "Register device for the filter driver failed.\n");
+ break;
+ }
+
+
+ }
+ while(bFalse);
+
+
+ DEBUGP(DL_TRACE, "<===DriverEntry, Status = %8x\n", Status);
+ return Status;
+
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterRegisterOptions(
+ NDIS_HANDLE NdisFilterDriverHandle,
+ NDIS_HANDLE FilterDriverContext
+ )
+/*++
+
+Routine Description:
+
+ Register optional handlers with NDIS. This sample does not happen to
+ have any optional handlers to register, so this routine does nothing
+ and could simply have been omitted. However, for illustrative purposes,
+ it is presented here.
+
+Arguments:
+
+ NdisFilterDriverHandle - pointer the driver handle received from
+ NdisFRegisterFilterDriver
+
+ FilterDriverContext - pointer to our context passed into
+ NdisFRegisterFilterDriver
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+ DEBUGP(DL_TRACE, "===>FilterRegisterOptions\n");
+
+ ASSERT(NdisFilterDriverHandle == FilterDriverHandle);
+ ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);
+
+ if ((NdisFilterDriverHandle != (NDIS_HANDLE)FilterDriverHandle) ||
+ (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject))
+ {
+ return NDIS_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUGP(DL_TRACE, "<===FilterRegisterOptions\n");
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterAttach(
+ NDIS_HANDLE NdisFilterHandle,
+ NDIS_HANDLE FilterDriverContext,
+ PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters
+ )
+/*++
+
+Routine Description:
+
+ Filter attach routine.
+ Create filter's context, allocate NetBufferLists and NetBuffer pools and any
+ other resources, and read configuration if needed.
+
+Arguments:
+
+ NdisFilterHandle - Specify a handle identifying this instance of the filter. FilterAttach
+ should save this handle. It is a required parameter in subsequent calls
+ to NdisFxxx functions.
+ FilterDriverContext - Filter driver context passed to NdisFRegisterFilterDriver.
+
+ AttachParameters - attach parameters
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS: FilterAttach successfully allocated and initialize data structures
+ for this filter instance.
+ NDIS_STATUS_RESOURCES: FilterAttach failed due to insufficient resources.
+ NDIS_STATUS_FAILURE: FilterAttach could not set up this instance of this filter and it has called
+ NdisWriteErrorLogEntry with parameters specifying the reason for failure.
+
+N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
+ layer can send Irps to the filter.
+
+--*/
+{
+ PMS_FILTER pFilter = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_FILTER_ATTRIBUTES FilterAttributes;
+ ULONG Size;
+ BOOLEAN bFalse = FALSE;
+
+
+ DEBUGP(DL_TRACE, "===>FilterAttach: NdisFilterHandle %p\n", NdisFilterHandle);
+
+ do
+ {
+ ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);
+ if (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject)
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ // Verify the media type is supported. This is a last resort; the
+ // the filter should never have been bound to an unsupported miniport
+ // to begin with. If this driver is marked as a Mandatory filter (which
+ // is the default for this sample; see the INF file), failing to attach
+ // here will leave the network adapter in an unusable state.
+ //
+ // Your setup/install code should not bind the filter to unsupported
+ // media types.
+ if ((AttachParameters->MiniportMediaType != NdisMedium802_3)
+ && (AttachParameters->MiniportMediaType != NdisMediumWan)
+ && (AttachParameters->MiniportMediaType != NdisMediumWirelessWan))
+ {
+ DEBUGP(DL_ERROR, "Unsupported media type.\n");
+
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ Size = sizeof(MS_FILTER) +
+ AttachParameters->FilterModuleGuidName->Length +
+ AttachParameters->BaseMiniportInstanceName->Length +
+ AttachParameters->BaseMiniportName->Length;
+
+ pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size);
+ if (pFilter == NULL)
+ {
+ DEBUGP(DL_WARN, "Failed to allocate context structure.\n");
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ NdisZeroMemory(pFilter, sizeof(MS_FILTER));
+
+ pFilter->FilterModuleName.Length = pFilter->FilterModuleName.MaximumLength = AttachParameters->FilterModuleGuidName->Length;
+ pFilter->FilterModuleName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER));
+ NdisMoveMemory(pFilter->FilterModuleName.Buffer,
+ AttachParameters->FilterModuleGuidName->Buffer,
+ pFilter->FilterModuleName.Length);
+
+
+
+ pFilter->MiniportFriendlyName.Length = pFilter->MiniportFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length;
+ pFilter->MiniportFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter->FilterModuleName.Buffer + pFilter->FilterModuleName.Length);
+ NdisMoveMemory(pFilter->MiniportFriendlyName.Buffer,
+ AttachParameters->BaseMiniportInstanceName->Buffer,
+ pFilter->MiniportFriendlyName.Length);
+
+
+ pFilter->MiniportName.Length = pFilter->MiniportName.MaximumLength = AttachParameters->BaseMiniportName->Length;
+ pFilter->MiniportName.Buffer = (PWSTR)((PUCHAR)pFilter->MiniportFriendlyName.Buffer +
+ pFilter->MiniportFriendlyName.Length);
+ NdisMoveMemory(pFilter->MiniportName.Buffer,
+ AttachParameters->BaseMiniportName->Buffer,
+ pFilter->MiniportName.Length);
+
+ pFilter->MiniportIfIndex = AttachParameters->BaseMiniportIfIndex;
+ //
+ // The filter should initialize TrackReceives and TrackSends properly. For this
+ // driver, since its default characteristic has both a send and a receive handler,
+ // these fields are initialized to TRUE.
+ //
+ pFilter->TrackReceives = TRUE;
+ pFilter->TrackSends = TRUE;
+ pFilter->FilterHandle = NdisFilterHandle;
+
+
+ NdisZeroMemory(&FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));
+ FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
+ FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);
+ FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
+ FilterAttributes.Flags = 0;
+
+ NDIS_DECLARE_FILTER_MODULE_CONTEXT(MS_FILTER);
+ Status = NdisFSetAttributes(NdisFilterHandle,
+ pFilter,
+ &FilterAttributes);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, "Failed to set attributes.\n");
+ break;
+ }
+
+ pFilter->State = FilterPaused;
+
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+ InsertHeadList(&FilterModuleList, &pFilter->FilterModuleLink);
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+
+ }
+ while (bFalse);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pFilter != NULL)
+ {
+ FILTER_FREE_MEM(pFilter);
+ }
+ }
+
+ DEBUGP(DL_TRACE, "<===FilterAttach: Status %x\n", Status);
+ return Status;
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterPause(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
+ )
+/*++
+
+Routine Description:
+
+ Filter pause routine.
+ Complete all the outstanding sends and queued sends,
+ wait for all the outstanding recvs to be returned
+ and return all the queued receives.
+
+Arguments:
+
+ FilterModuleContext - pointer to the filter context stucture
+ PauseParameters - additional information about the pause
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if filter pauses successfully, NDIS_STATUS_PENDING
+ if not. No other return value is allowed (pause must succeed, eventually).
+
+N.B.: When the filter is in Pausing state, it can still process OID requests,
+ complete sending, and returning packets to NDIS, and also indicate status.
+ After this function completes, the filter must not attempt to send or
+ receive packets, but it may still process OID requests and status
+ indications.
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)(FilterModuleContext);
+ NDIS_STATUS Status;
+ BOOLEAN bFalse = FALSE;
+
+ UNREFERENCED_PARAMETER(PauseParameters);
+
+ DEBUGP(DL_TRACE, "===>NdisFilter FilterPause: FilterInstance %p\n", FilterModuleContext);
+
+ //
+ // Set the flag that the filter is going to pause
+ //
+ FILTER_ASSERT(pFilter->State == FilterRunning);
+
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+ pFilter->State = FilterPausing;
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+
+ //
+ // Do whatever work is required to bring the filter into the Paused state.
+ //
+ // If you have diverted and queued any send or receive NBLs, return them
+ // now.
+ //
+ // If you send or receive original NBLs, stop doing that and wait for your
+ // NBLs to return to you now.
+ //
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ pFilter->State = FilterPaused;
+
+ DEBUGP(DL_TRACE, "<===FilterPause: Status %x\n", Status);
+ return Status;
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterRestart(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
+ )
+/*++
+
+Routine Description:
+
+ Filter restart routine.
+ Start the datapath - begin sending and receiving NBLs.
+
+Arguments:
+
+ FilterModuleContext - pointer to the filter context stucture.
+ RestartParameters - additional information about the restart operation.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS: if filter restarts successfully
+ NDIS_STATUS_XXX: Otherwise.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_HANDLE ConfigurationHandle = NULL;
+
+
+ PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
+ PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes;
+ NDIS_CONFIGURATION_OBJECT ConfigObject;
+
+ DEBUGP(DL_TRACE, "===>FilterRestart: FilterModuleContext %p\n", FilterModuleContext);
+
+ FILTER_ASSERT(pFilter->State == FilterPaused);
+
+ ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+ ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+ ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
+ ConfigObject.NdisHandle = FilterDriverHandle;
+ ConfigObject.Flags = 0;
+
+ Status = NdisOpenConfigurationEx(&ConfigObject, &ConfigurationHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Filter driver can choose to fail the restart if it cannot open the configuration
+ //
+
+#if 0
+ //
+ // The code is here just to demonstrate how to call NDIS to write an
+ // event to the eventlog.
+ //
+ PWCHAR ErrorString = L"NdisFilter";
+
+ DEBUGP(DL_WARN, "FilterRestart: Cannot open configuration.\n");
+ NdisWriteEventLogEntry(FilterDriverObject,
+ EVENT_NDIS_DRIVER_FAILURE,
+ 0,
+ 1,
+ &ErrorString,
+ sizeof(Status),
+ &Status);
+#endif
+
+ }
+
+ //
+ // This sample doesn't actually do anything with the configuration handle;
+ // it is opened here for illustrative purposes. If you do not need to
+ // read configuration, you may omit the code manipulating the
+ // ConfigurationHandle.
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NdisCloseConfiguration(ConfigurationHandle);
+ }
+
+ NdisRestartAttributes = RestartParameters->RestartAttributes;
+
+ //
+ // If NdisRestartAttributes is not NULL, then the filter can modify generic
+ // attributes and add new media specific info attributes at the end.
+ // Otherwise, if NdisRestartAttributes is NULL, the filter should not try to
+ // modify/add attributes.
+ //
+ if (NdisRestartAttributes != NULL)
+ {
+ PNDIS_RESTART_ATTRIBUTES NextAttributes;
+
+ ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);
+
+ NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data;
+
+ //
+ // Check to see if we need to change any attributes. For example, the
+ // driver can change the current MAC address here. Or the driver can add
+ // media specific info attributes.
+ //
+ NdisGeneralAttributes->LookaheadSize = 128;
+
+ //
+ // Check each attribute to see whether the filter needs to modify it.
+ //
+ NextAttributes = NdisRestartAttributes->Next;
+
+ while (NextAttributes != NULL)
+ {
+ //
+ // If somehow the filter needs to change a attributes which requires more space then
+ // the current attributes:
+ // 1. Remove the attribute from the Attributes list:
+ // TempAttributes = NextAttributes;
+ // NextAttributes = NextAttributes->Next;
+ // 2. Free the memory for the current attributes: NdisFreeMemory(TempAttributes, 0 , 0);
+ // 3. Dynamically allocate the memory for the new attributes by calling
+ // NdisAllocateMemoryWithTagPriority:
+ // NewAttributes = NdisAllocateMemoryWithTagPriority(Handle, size, Priority);
+ // 4. Fill in the new attribute
+ // 5. NewAttributes->Next = NextAttributes;
+ // 6. NextAttributes = NewAttributes; // Just to make the next statement work.
+ //
+ NextAttributes = NextAttributes->Next;
+ }
+
+ //
+ // Add a new attributes at the end
+ // 1. Dynamically allocate the memory for the new attributes by calling
+ // NdisAllocateMemoryWithTagPriority.
+ // 2. Fill in the new attribute
+ // 3. NextAttributes->Next = NewAttributes;
+ // 4. NewAttributes->Next = NULL;
+
+
+
+ }
+
+
+ //
+ // If everything is OK, set the filter in running state.
+ //
+ pFilter->State = FilterRunning; // when successful
+
+
+ Status = NDIS_STATUS_SUCCESS;
+
+
+ //
+ // Ensure the state is Paused if restart failed.
+ //
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ pFilter->State = FilterPaused;
+ }
+
+
+ DEBUGP(DL_TRACE, "<===FilterRestart: FilterModuleContext %p, Status %x\n", FilterModuleContext, Status);
+ return Status;
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterDetach(
+ NDIS_HANDLE FilterModuleContext
+ )
+/*++
+
+Routine Description:
+
+ Filter detach routine.
+ This is a required function that will deallocate all the resources allocated during
+ FilterAttach. NDIS calls FilterAttach to remove a filter instance from a filter stack.
+
+Arguments:
+
+ FilterModuleContext - pointer to the filter context area.
+
+Return Value:
+ None.
+
+NOTE: Called at PASSIVE_LEVEL and the filter is in paused state
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ BOOLEAN bFalse = FALSE;
+
+
+ DEBUGP(DL_TRACE, "===>FilterDetach: FilterInstance %p\n", FilterModuleContext);
+
+
+ //
+ // Filter must be in paused state
+ //
+ FILTER_ASSERT(pFilter->State == FilterPaused);
+
+
+ //
+ // Detach must not fail, so do not put any code here that can possibly fail.
+ //
+
+ //
+ // Free filter instance name if allocated.
+ //
+ if (pFilter->FilterName.Buffer != NULL)
+ {
+ FILTER_FREE_MEM(pFilter->FilterName.Buffer);
+ }
+
+
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+ RemoveEntryList(&pFilter->FilterModuleLink);
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+
+
+ //
+ // Free the memory allocated
+ FILTER_FREE_MEM(pFilter);
+
+ DEBUGP(DL_TRACE, "<===FilterDetach Successfully\n");
+ return;
+}
+
+_Use_decl_annotations_
+VOID
+FilterUnload(
+ PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ Filter driver's unload routine.
+ Deregister the driver from NDIS.
+
+Arguments:
+
+ DriverObject - pointer to the system's driver object structure
+ for this driver
+
+Return Value:
+
+ NONE
+
+--*/
+{
+#if DBG
+ BOOLEAN bFalse = FALSE;
+#endif
+
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ DEBUGP(DL_TRACE, "===>FilterUnload\n");
+
+ //
+ // Should free the filter context list
+ //
+ NdisFilterDeregisterDevice();
+ NdisFDeregisterFilterDriver(FilterDriverHandle);
+
+#if DBG
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+ ASSERT(IsListEmpty(&FilterModuleList));
+
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+
+#endif
+
+ FILTER_FREE_LOCK(&FilterListLock);
+
+ DEBUGP(DL_TRACE, "<===FilterUnload\n");
+
+ return;
+
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterOidRequest(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_OID_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+ Request handler
+ Handle requests from upper layers
+
+Arguments:
+
+ FilterModuleContext - our filter
+ Request - the request passed down
+
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_XXX
+
+NOTE: Called at <= DISPATCH_LEVEL (unlike a miniport's MiniportOidRequest)
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_STATUS Status;
+ PNDIS_OID_REQUEST ClonedRequest=NULL;
+ BOOLEAN bSubmitted = FALSE;
+ PFILTER_REQUEST_CONTEXT Context;
+ BOOLEAN bFalse = FALSE;
+
+
+ DEBUGP(DL_TRACE, "===>FilterOidRequest: Request %p.\n", Request);
+
+ //
+ // Most of the time, a filter will clone the OID request and pass down
+ // the clone. When the clone completes, the filter completes the original
+ // OID request.
+ //
+ // If your filter needs to modify a specific request, it can modify the
+ // request before or after sending down the cloned request. Or, it can
+ // complete the original request on its own without sending down any
+ // clone at all.
+ //
+ // If your filter driver does not need to modify any OID requests, then
+ // you may simply omit this routine entirely; NDIS will pass OID requests
+ // down on your behalf. This is more efficient than implementing a
+ // routine that does nothing but clone all requests, as in the sample here.
+ //
+
+ do
+ {
+ Status = NdisAllocateCloneOidRequest(pFilter->FilterHandle,
+ Request,
+ FILTER_TAG,
+ &ClonedRequest);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, "FilerOidRequest: Cannot Clone Request\n");
+ break;
+ }
+
+ Context = (PFILTER_REQUEST_CONTEXT)(&ClonedRequest->SourceReserved[0]);
+ *Context = Request;
+
+ bSubmitted = TRUE;
+
+ //
+ // Use same request ID
+ //
+ ClonedRequest->RequestId = Request->RequestId;
+
+ pFilter->PendingOidRequest = ClonedRequest;
+
+
+ Status = NdisFOidRequest(pFilter->FilterHandle, ClonedRequest);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+
+
+ FilterOidRequestComplete(pFilter, ClonedRequest, Status);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+
+
+ }while (bFalse);
+
+ if (bSubmitted == FALSE)
+ {
+ switch(Request->RequestType)
+ {
+ case NdisRequestMethod:
+ Request->DATA.METHOD_INFORMATION.BytesRead = 0;
+ Request->DATA.METHOD_INFORMATION.BytesNeeded = 0;
+ Request->DATA.METHOD_INFORMATION.BytesWritten = 0;
+ break;
+
+ case NdisRequestSetInformation:
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ default:
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ }
+ DEBUGP(DL_TRACE, "<===FilterOidRequest: Status %8x.\n", Status);
+
+ return Status;
+
+}
+
+_Use_decl_annotations_
+VOID
+FilterCancelOidRequest(
+ NDIS_HANDLE FilterModuleContext,
+ PVOID RequestId
+ )
+/*++
+
+Routine Description:
+
+ Cancels an OID request
+
+ If your filter driver does not intercept and hold onto any OID requests,
+ then you do not need to implement this routine. You may simply omit it.
+ Furthermore, if the filter only holds onto OID requests so it can pass
+ down a clone (the most common case) the filter does not need to implement
+ this routine; NDIS will then automatically request that the lower-level
+ filter/miniport cancel your cloned OID.
+
+ Most filters do not need to implement this routine.
+
+Arguments:
+
+ FilterModuleContext - our filter
+ RequestId - identifies the request(s) to cancel
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ PNDIS_OID_REQUEST Request = NULL;
+ PFILTER_REQUEST_CONTEXT Context;
+ PNDIS_OID_REQUEST OriginalRequest = NULL;
+ BOOLEAN bFalse = FALSE;
+
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+
+ Request = pFilter->PendingOidRequest;
+
+ if (Request != NULL)
+ {
+ Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);
+
+ OriginalRequest = (*Context);
+ }
+
+ if ((OriginalRequest != NULL) && (OriginalRequest->RequestId == RequestId))
+ {
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+
+ NdisFCancelOidRequest(pFilter->FilterHandle, RequestId);
+ }
+ else
+ {
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+ }
+
+
+}
+
+_Use_decl_annotations_
+VOID
+FilterOidRequestComplete(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_OID_REQUEST Request,
+ NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Notification that an OID request has been completed
+
+ If this filter sends a request down to a lower layer, and the request is
+ pended, the FilterOidRequestComplete routine is invoked when the request
+ is complete. Most requests we've sent are simply clones of requests
+ received from a higher layer; all we need to do is complete the original
+ higher request.
+
+ However, if this filter driver sends original requests down, it must not
+ attempt to complete a pending request to the higher layer.
+
+Arguments:
+
+ FilterModuleContext - our filter context area
+ NdisRequest - the completed request
+ Status - completion status
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ PNDIS_OID_REQUEST OriginalRequest;
+ PFILTER_REQUEST_CONTEXT Context;
+ BOOLEAN bFalse = FALSE;
+
+ DEBUGP(DL_TRACE, "===>FilterOidRequestComplete, Request %p.\n", Request);
+
+ Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);
+ OriginalRequest = (*Context);
+
+ //
+ // This is an internal request
+ //
+ if (OriginalRequest == NULL)
+ {
+ filterInternalRequestComplete(pFilter, Request, Status);
+ return;
+ }
+
+
+
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+
+ ASSERT(pFilter->PendingOidRequest == Request);
+ pFilter->PendingOidRequest = NULL;
+
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+
+
+ //
+ // Copy the information from the returned request to the original request
+ //
+ switch(Request->RequestType)
+ {
+ case NdisRequestMethod:
+ OriginalRequest->DATA.METHOD_INFORMATION.OutputBufferLength = Request->DATA.METHOD_INFORMATION.OutputBufferLength;
+ OriginalRequest->DATA.METHOD_INFORMATION.BytesRead = Request->DATA.METHOD_INFORMATION.BytesRead;
+ OriginalRequest->DATA.METHOD_INFORMATION.BytesNeeded = Request->DATA.METHOD_INFORMATION.BytesNeeded;
+ OriginalRequest->DATA.METHOD_INFORMATION.BytesWritten = Request->DATA.METHOD_INFORMATION.BytesWritten;
+ break;
+
+ case NdisRequestSetInformation:
+ OriginalRequest->DATA.SET_INFORMATION.BytesRead = Request->DATA.SET_INFORMATION.BytesRead;
+ OriginalRequest->DATA.SET_INFORMATION.BytesNeeded = Request->DATA.SET_INFORMATION.BytesNeeded;
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ default:
+ OriginalRequest->DATA.QUERY_INFORMATION.BytesWritten = Request->DATA.QUERY_INFORMATION.BytesWritten;
+ OriginalRequest->DATA.QUERY_INFORMATION.BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded;
+ break;
+ }
+
+
+ (*Context) = NULL;
+
+ NdisFreeCloneOidRequest(pFilter->FilterHandle, Request);
+
+ NdisFOidRequestComplete(pFilter->FilterHandle, OriginalRequest, Status);
+
+ DEBUGP(DL_TRACE, "<===FilterOidRequestComplete.\n");
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterStatus(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_STATUS_INDICATION StatusIndication
+ )
+/*++
+
+Routine Description:
+
+ Status indication handler
+
+Arguments:
+
+ FilterModuleContext - our filter context
+ StatusIndication - the status being indicated
+
+NOTE: called at <= DISPATCH_LEVEL
+
+ FILTER driver may call NdisFIndicateStatus to generate a status indication to
+ all higher layer modules.
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+#if DBG
+ BOOLEAN bFalse = FALSE;
+#endif
+
+ DEBUGP(DL_TRACE, "===>FilterStatus, IndicateStatus = %8x.\n", StatusIndication->StatusCode);
+
+
+ //
+ // The filter may do processing on the status indication here, including
+ // intercepting and dropping it entirely. However, the sample does nothing
+ // with status indications except pass them up to the higher layer. It is
+ // more efficient to omit the FilterStatus handler entirely if it does
+ // nothing, but it is included in this sample for illustrative purposes.
+ //
+
+#if DBG
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+ ASSERT(pFilter->bIndicating == FALSE);
+ pFilter->bIndicating = TRUE;
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+#endif // DBG
+
+ NdisFIndicateStatus(pFilter->FilterHandle, StatusIndication);
+
+#if DBG
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+ ASSERT(pFilter->bIndicating == TRUE);
+ pFilter->bIndicating = FALSE;
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+#endif // DBG
+
+ DEBUGP(DL_TRACE, "<===FilterStatus.\n");
+
+}
+
+_Use_decl_annotations_
+VOID
+FilterDevicePnPEventNotify(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_DEVICE_PNP_EVENT NetDevicePnPEvent
+ )
+/*++
+
+Routine Description:
+
+ Device PNP event handler
+
+Arguments:
+
+ FilterModuleContext - our filter context
+ NetDevicePnPEvent - a Device PnP event
+
+NOTE: called at PASSIVE_LEVEL
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_DEVICE_PNP_EVENT DevicePnPEvent = NetDevicePnPEvent->DevicePnPEvent;
+#if DBG
+ BOOLEAN bFalse = FALSE;
+#endif
+
+ DEBUGP(DL_TRACE, "===>FilterDevicePnPEventNotify: NetPnPEvent = %p.\n", NetDevicePnPEvent);
+
+ //
+ // The filter may do processing on the event here, including intercepting
+ // and dropping it entirely. However, the sample does nothing with Device
+ // PNP events, except pass them down to the next lower* layer. It is more
+ // efficient to omit the FilterDevicePnPEventNotify handler entirely if it
+ // does nothing, but it is included in this sample for illustrative purposes.
+ //
+ // * Trivia: Device PNP events percolate DOWN the stack, instead of upwards
+ // like status indications and Net PNP events. So the next layer is the
+ // LOWER layer.
+ //
+
+ switch (DevicePnPEvent)
+ {
+
+ case NdisDevicePnPEventQueryRemoved:
+ case NdisDevicePnPEventRemoved:
+ case NdisDevicePnPEventSurpriseRemoved:
+ case NdisDevicePnPEventQueryStopped:
+ case NdisDevicePnPEventStopped:
+ case NdisDevicePnPEventPowerProfileChanged:
+ case NdisDevicePnPEventFilterListChanged:
+
+ break;
+
+ default:
+ DEBUGP(DL_ERROR, "FilterDevicePnPEventNotify: Invalid event.\n");
+ FILTER_ASSERT(bFalse);
+
+ break;
+ }
+
+ NdisFDevicePnPEventNotify(pFilter->FilterHandle, NetDevicePnPEvent);
+
+ DEBUGP(DL_TRACE, "<===FilterDevicePnPEventNotify\n");
+
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterNetPnPEvent(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification
+ )
+/*++
+
+Routine Description:
+
+ Net PNP event handler
+
+Arguments:
+
+ FilterModuleContext - our filter context
+ NetPnPEventNotification - a Net PnP event
+
+NOTE: called at PASSIVE_LEVEL
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // The filter may do processing on the event here, including intercepting
+ // and dropping it entirely. However, the sample does nothing with Net PNP
+ // events, except pass them up to the next higher layer. It is more
+ // efficient to omit the FilterNetPnPEvent handler entirely if it does
+ // nothing, but it is included in this sample for illustrative purposes.
+ //
+
+ Status = NdisFNetPnPEvent(pFilter->FilterHandle, NetPnPEventNotification);
+
+ return Status;
+}
+
+_Use_decl_annotations_
+VOID
+FilterSendNetBufferListsComplete(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG SendCompleteFlags
+ )
+/*++
+
+Routine Description:
+
+ Send complete handler
+
+ This routine is invoked whenever the lower layer is finished processing
+ sent NET_BUFFER_LISTs. If the filter does not need to be involved in the
+ send path, you should remove this routine and the FilterSendNetBufferLists
+ routine. NDIS will pass along send packets on behalf of your filter more
+ efficiently than the filter can.
+
+Arguments:
+
+ FilterModuleContext - our filter context
+ NetBufferLists - a chain of NBLs that are being returned to you
+ SendCompleteFlags - flags (see documentation)
+
+Return Value:
+
+ NONE
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ ULONG NumOfSendCompletes = 0;
+ BOOLEAN DispatchLevel;
+ PNET_BUFFER_LIST CurrNbl;
+
+ DEBUGP(DL_TRACE, "===>SendNBLComplete, NetBufferList: %p.\n", NetBufferLists);
+
+
+ //
+ // If your filter injected any send packets into the datapath to be sent,
+ // you must identify their NBLs here and remove them from the chain. Do not
+ // attempt to send-complete your NBLs up to the higher layer.
+ //
+
+ //
+ // If your filter has modified any NBLs (or NBs, MDLs, etc) in your
+ // FilterSendNetBufferLists handler, you must undo the modifications here.
+ // In general, NBLs must be returned in the same condition in which you had
+ // you received them. (Exceptions: the NBLs can be re-ordered on the linked
+ // list, and the scratch fields are don't-care).
+ //
+
+ if (pFilter->TrackSends)
+ {
+ CurrNbl = NetBufferLists;
+ while (CurrNbl)
+ {
+ NumOfSendCompletes++;
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+
+ }
+ DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags);
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ pFilter->OutstandingSends -= NumOfSendCompletes;
+ FILTER_LOG_SEND_REF(2, pFilter, PrevNbl, pFilter->OutstandingSends);
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+ // Send complete the NBLs. If you removed any NBLs from the chain, make
+ // sure the chain isn't empty (i.e., NetBufferLists!=NULL).
+
+ NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, SendCompleteFlags);
+
+ DEBUGP(DL_TRACE, "<===SendNBLComplete.\n");
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterSendNetBufferLists(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ NDIS_PORT_NUMBER PortNumber,
+ ULONG SendFlags
+ )
+/*++
+
+Routine Description:
+
+ Send Net Buffer List handler
+ This function is an optional function for filter drivers. If provided, NDIS
+ will call this function to transmit a linked list of NetBuffers, described by a
+ NetBufferList, over the network. If this handler is NULL, NDIS will skip calling
+ this filter when sending a NetBufferList and will call the next lower
+ driver in the stack. A filter that doesn't provide a FilerSendNetBufferList
+ handler can not originate a send on its own.
+
+Arguments:
+
+ FilterModuleContext - our filter context area
+ NetBufferLists - a List of NetBufferLists to send
+ PortNumber - Port Number to which this send is targeted
+ SendFlags - specifies if the call is at DISPATCH_LEVEL
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ PNET_BUFFER_LIST CurrNbl;
+ BOOLEAN DispatchLevel;
+ BOOLEAN bFalse = FALSE;
+
+ DEBUGP(DL_TRACE, "===>SendNetBufferList: NBL = %p.\n", NetBufferLists);
+
+ do
+ {
+
+ DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);
+#if DBG
+ //
+ // we should never get packets to send if we are not in running state
+ //
+
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ //
+ // If the filter is not in running state, fail the send
+ //
+ if (pFilter->State != FilterRunning)
+ {
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+
+ CurrNbl = NetBufferLists;
+ while (CurrNbl)
+ {
+ NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED;
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ }
+ NdisFSendNetBufferListsComplete(pFilter->FilterHandle,
+ NetBufferLists,
+ DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
+ break;
+
+ }
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+#endif
+ if (pFilter->TrackSends)
+ {
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ CurrNbl = NetBufferLists;
+ while (CurrNbl)
+ {
+ pFilter->OutstandingSends++;
+ FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends);
+
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ }
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+ //
+ // If necessary, queue the NetBufferLists in a local structure for later
+ // processing. However, do not queue them for "too long", or else the
+ // system's performance may be degraded. If you need to hold onto an
+ // NBL for an unbounded amount of time, then allocate memory, perform a
+ // deep copy, and complete the original NBL.
+ //
+
+ NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags);
+
+
+ }
+ while (bFalse);
+
+ DEBUGP(DL_TRACE, "<===SendNetBufferList. \n");
+}
+
+_Use_decl_annotations_
+VOID
+FilterReturnNetBufferLists(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG ReturnFlags
+ )
+/*++
+
+Routine Description:
+
+ FilterReturnNetBufferLists handler.
+ FilterReturnNetBufferLists is an optional function. If provided, NDIS calls
+ FilterReturnNetBufferLists to return the ownership of one or more NetBufferLists
+ and their embedded NetBuffers to the filter driver. If this handler is NULL, NDIS
+ will skip calling this filter when returning NetBufferLists to the underlying
+ miniport and will call the next lower driver in the stack. A filter that doesn't
+ provide a FilterReturnNetBufferLists handler cannot originate a receive indication
+ on its own.
+
+Arguments:
+
+ FilterInstanceContext - our filter context area
+ NetBufferLists - a linked list of NetBufferLists that this
+ filter driver indicated in a previous call to
+ NdisFIndicateReceiveNetBufferLists
+ ReturnFlags - flags specifying if the caller is at DISPATCH_LEVEL
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ PNET_BUFFER_LIST CurrNbl = NetBufferLists;
+ UINT NumOfNetBufferLists = 0;
+ BOOLEAN DispatchLevel;
+ ULONG Ref;
+
+ DEBUGP(DL_TRACE, "===>ReturnNetBufferLists, NetBufferLists is %p.\n", NetBufferLists);
+
+
+ //
+ // If your filter injected any receive packets into the datapath to be
+ // received, you must identify their NBLs here and remove them from the
+ // chain. Do not attempt to receive-return your NBLs down to the lower
+ // layer.
+ //
+
+ //
+ // If your filter has modified any NBLs (or NBs, MDLs, etc) in your
+ // FilterReceiveNetBufferLists handler, you must undo the modifications here.
+ // In general, NBLs must be returned in the same condition in which you had
+ // you received them. (Exceptions: the NBLs can be re-ordered on the linked
+ // list, and the scratch fields are don't-care).
+ //
+
+ if (pFilter->TrackReceives)
+ {
+ while (CurrNbl)
+ {
+ NumOfNetBufferLists ++;
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ }
+ }
+
+
+ // Return the received NBLs. If you removed any NBLs from the chain, make
+ // sure the chain isn't empty (i.e., NetBufferLists!=NULL).
+
+ NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
+
+ if (pFilter->TrackReceives)
+ {
+ DispatchLevel = NDIS_TEST_RETURN_AT_DISPATCH_LEVEL(ReturnFlags);
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+
+ pFilter->OutstandingRcvs -= NumOfNetBufferLists;
+ Ref = pFilter->OutstandingRcvs;
+ FILTER_LOG_RCV_REF(3, pFilter, NetBufferLists, Ref);
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+
+ DEBUGP(DL_TRACE, "<===ReturnNetBufferLists.\n");
+
+
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterReceiveNetBufferLists(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ NDIS_PORT_NUMBER PortNumber,
+ ULONG NumberOfNetBufferLists,
+ ULONG ReceiveFlags
+ )
+/*++
+
+Routine Description:
+
+ FilerReceiveNetBufferLists is an optional function for filter drivers.
+ If provided, this function processes receive indications made by underlying
+ NIC or lower level filter drivers. This function can also be called as a
+ result of loopback. If this handler is NULL, NDIS will skip calling this
+ filter when processing a receive indication and will call the next higher
+ driver in the stack. A filter that doesn't provide a
+ FilterReceiveNetBufferLists handler cannot provide a
+ FilterReturnNetBufferLists handler and cannot a initiate an original receive
+ indication on its own.
+
+Arguments:
+
+ FilterModuleContext - our filter context area.
+ NetBufferLists - a linked list of NetBufferLists
+ PortNumber - Port on which the receive is indicated
+ ReceiveFlags -
+
+N.B.: It is important to check the ReceiveFlags in NDIS_TEST_RECEIVE_CANNOT_PEND.
+ This controls whether the receive indication is an synchronous or
+ asynchronous function call.
+
+--*/
+{
+
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ BOOLEAN DispatchLevel;
+ ULONG Ref;
+ BOOLEAN bFalse = FALSE;
+#if DBG
+ ULONG ReturnFlags;
+#endif
+
+ DEBUGP(DL_TRACE, "===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists);
+ do
+ {
+
+ DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
+#if DBG
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+
+ if (pFilter->State != FilterRunning)
+ {
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+
+ if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
+ {
+ ReturnFlags = 0;
+ if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
+ {
+ NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
+ }
+
+ NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
+ }
+ break;
+ }
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+#endif
+
+ ASSERT(NumberOfNetBufferLists >= 1);
+
+ //
+ // If you would like to drop a received packet, then you must carefully
+ // modify the NBL chain as follows:
+ //
+ // if NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags):
+ // For each NBL that is NOT dropped, temporarily unlink it from
+ // the linked list, and indicate it up alone with
+ // NdisFIndicateReceiveNetBufferLists and the
+ // NDIS_RECEIVE_FLAGS_RESOURCES flag set. Then immediately
+ // relink the NBL back into the chain. When all NBLs have been
+ // indicated up, you may return from this function.
+ // otherwise (NDIS_TEST_RECEIVE_CANNOT_PEND is FALSE):
+ // Divide the linked list of NBLs into two chains: one chain
+ // of packets to drop, and everything else in another chain.
+ // Return the first chain with NdisFReturnNetBufferLists, and
+ // indicate up the rest with NdisFIndicateReceiveNetBufferLists.
+ //
+ // Note: on the receive path for Ethernet packets, one NBL will have
+ // exactly one NB. So (assuming you are receiving on Ethernet, or are
+ // attached above Native WiFi) you do not need to worry about dropping
+ // one NB, but trying to indicate up the remaining NBs on the same NBL.
+ // In other words, if the first NB should be dropped, drop the whole NBL.
+ //
+
+ //
+ // If you would like to modify a packet, and can do so quickly, you may
+ // do it here. However, make sure you save enough information to undo
+ // your modification in the FilterReturnNetBufferLists handler.
+ //
+
+ //
+ // If necessary, queue the NetBufferLists in a local structure for later
+ // processing. However, do not queue them for "too long", or else the
+ // system's performance may be degraded. If you need to hold onto an
+ // NBL for an unbounded amount of time, then allocate memory, perform a
+ // deep copy, and return the original NBL.
+ //
+
+ if (pFilter->TrackReceives)
+ {
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ pFilter->OutstandingRcvs += NumberOfNetBufferLists;
+ Ref = pFilter->OutstandingRcvs;
+
+ FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+ NdisFIndicateReceiveNetBufferLists(
+ pFilter->FilterHandle,
+ NetBufferLists,
+ PortNumber,
+ NumberOfNetBufferLists,
+ ReceiveFlags);
+
+
+ if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) &&
+ pFilter->TrackReceives)
+ {
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
+ Ref = pFilter->OutstandingRcvs;
+ FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+ } while (bFalse);
+
+ DEBUGP(DL_TRACE, "<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags);
+
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterCancelSendNetBufferLists(
+ NDIS_HANDLE FilterModuleContext,
+ PVOID CancelId
+ )
+/*++
+
+Routine Description:
+
+ This function cancels any NET_BUFFER_LISTs pended in the filter and then
+ calls the NdisFCancelSendNetBufferLists to propagate the cancel operation.
+
+ If your driver does not queue any send NBLs, you may omit this routine.
+ NDIS will propagate the cancelation on your behalf more efficiently.
+
+Arguments:
+
+ FilterModuleContext - our filter context area.
+ CancelId - an identifier for all NBLs that should be dequeued
+
+Return Value:
+
+ None
+
+*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+
+ NdisFCancelSendNetBufferLists(pFilter->FilterHandle, CancelId);
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterSetModuleOptions(
+ NDIS_HANDLE FilterModuleContext
+ )
+/*++
+
+Routine Description:
+
+ This function set the optional handlers for the filter
+
+Arguments:
+
+ FilterModuleContext: The FilterModuleContext given to NdisFSetAttributes
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_FAILURE
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_FILTER_PARTIAL_CHARACTERISTICS OptionalHandlers;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ BOOLEAN bFalse = FALSE;
+
+ //
+ // Demonstrate how to change send/receive handlers at runtime.
+ //
+ if (bFalse)
+ {
+ UINT i;
+
+
+ pFilter->CallsRestart++;
+
+ i = pFilter->CallsRestart % 8;
+
+ pFilter->TrackReceives = TRUE;
+ pFilter->TrackSends = TRUE;
+
+ NdisMoveMemory(&OptionalHandlers, &DefaultChars, sizeof(OptionalHandlers));
+ OptionalHandlers.Header.Type = NDIS_OBJECT_TYPE_FILTER_PARTIAL_CHARACTERISTICS;
+ OptionalHandlers.Header.Size = sizeof(OptionalHandlers);
+ switch (i)
+ {
+
+ case 0:
+ OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
+ pFilter->TrackReceives = FALSE;
+ break;
+
+ case 1:
+
+ OptionalHandlers.ReturnNetBufferListsHandler = NULL;
+ pFilter->TrackReceives = FALSE;
+ break;
+
+ case 2:
+ OptionalHandlers.SendNetBufferListsHandler = NULL;
+ pFilter->TrackSends = FALSE;
+ break;
+
+ case 3:
+ OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
+ pFilter->TrackSends = FALSE;
+ break;
+
+ case 4:
+ OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
+ OptionalHandlers.ReturnNetBufferListsHandler = NULL;
+ break;
+
+ case 5:
+ OptionalHandlers.SendNetBufferListsHandler = NULL;
+ OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
+ break;
+
+ case 6:
+
+ OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
+ OptionalHandlers.ReturnNetBufferListsHandler = NULL;
+ OptionalHandlers.SendNetBufferListsHandler = NULL;
+ OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
+ break;
+
+ case 7:
+ break;
+ }
+ Status = NdisSetOptionalHandlers(pFilter->FilterHandle, (PNDIS_DRIVER_OPTIONAL_HANDLERS)&OptionalHandlers );
+ }
+ return Status;
+}
+
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NDIS_STATUS
+filterDoInternalRequest(
+ _In_ PMS_FILTER FilterModuleContext,
+ _In_ NDIS_REQUEST_TYPE RequestType,
+ _In_ NDIS_OID Oid,
+ _Inout_updates_bytes_to_(InformationBufferLength, *pBytesProcessed)
+ PVOID InformationBuffer,
+ _In_ ULONG InformationBufferLength,
+ _In_opt_ ULONG OutputBufferLength,
+ _In_ ULONG MethodId,
+ _Out_ PULONG pBytesProcessed
+ )
+/*++
+
+Routine Description:
+
+ Utility routine that forms and sends an NDIS_OID_REQUEST to the
+ miniport, waits for it to complete, and returns status
+ to the caller.
+
+ NOTE: this assumes that the calling routine ensures validity
+ of the filter handle until this returns.
+
+Arguments:
+
+ FilterModuleContext - pointer to our filter module context
+ RequestType - NdisRequest[Set|Query|method]Information
+ Oid - the object being set/queried
+ InformationBuffer - data for the request
+ InformationBufferLength - length of the above
+ OutputBufferLength - valid only for method request
+ MethodId - valid only for method request
+ pBytesProcessed - place to return bytes read/written
+
+Return Value:
+
+ Status of the set/query request
+
+--*/
+{
+ FILTER_REQUEST FilterRequest;
+ PNDIS_OID_REQUEST NdisRequest = &FilterRequest.Request;
+ NDIS_STATUS Status;
+
+ ASSERT(pBytesProcessed != NULL);
+
+ *pBytesProcessed = 0;
+
+ NdisZeroMemory(NdisRequest, sizeof(NDIS_OID_REQUEST));
+
+ NdisInitializeEvent(&FilterRequest.ReqEvent);
+
+ NdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ NdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ NdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
+ NdisRequest->RequestType = RequestType;
+
+ switch (RequestType)
+ {
+ case NdisRequestQueryInformation:
+ NdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+ break;
+
+ case NdisRequestSetInformation:
+ NdisRequest->DATA.SET_INFORMATION.Oid = Oid;
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+ break;
+
+ case NdisRequestMethod:
+ NdisRequest->DATA.METHOD_INFORMATION.Oid = Oid;
+ NdisRequest->DATA.METHOD_INFORMATION.MethodId = MethodId;
+ NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength =
+ InformationBufferLength;
+ NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;
+ break;
+
+
+
+ default:
+
+ ASSERTMSG("Invalid request type in filterDoInternalRequest",
+ FALSE);
+
+ break;
+ }
+
+ NdisRequest->RequestId = (PVOID)FILTER_REQUEST_ID;
+
+
+ Status = NdisFOidRequest(FilterModuleContext->FilterHandle,
+ NdisRequest);
+
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&FilterRequest.ReqEvent, 0);
+ Status = FilterRequest.Status;
+ }
+
+
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (RequestType == NdisRequestSetInformation)
+ {
+ *pBytesProcessed = NdisRequest->DATA.SET_INFORMATION.BytesRead;
+ }
+
+ if (RequestType == NdisRequestQueryInformation)
+ {
+ *pBytesProcessed = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ }
+
+ if (RequestType == NdisRequestMethod)
+ {
+ *pBytesProcessed = NdisRequest->DATA.METHOD_INFORMATION.BytesWritten;
+ }
+
+ //
+ // The driver below should set the correct value to BytesWritten
+ // or BytesRead. But now, we just truncate the value to InformationBufferLength
+ //
+ if (RequestType == NdisRequestMethod)
+ {
+ if (*pBytesProcessed > OutputBufferLength)
+ {
+ *pBytesProcessed = OutputBufferLength;
+ }
+ }
+ else
+ {
+
+ if (*pBytesProcessed > InformationBufferLength)
+ {
+ *pBytesProcessed = InformationBufferLength;
+ }
+ }
+ }
+
+
+ return Status;
+}
+
+VOID
+filterInternalRequestComplete(
+ _In_ NDIS_HANDLE FilterModuleContext,
+ _In_ PNDIS_OID_REQUEST NdisRequest,
+ _In_ NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ NDIS entry point indicating completion of a pended NDIS_OID_REQUEST.
+
+Arguments:
+
+ FilterModuleContext - pointer to filter module context
+ NdisRequest - pointer to NDIS request
+ Status - status of request completion
+
+Return Value:
+
+ None
+
+--*/
+{
+ PFILTER_REQUEST FilterRequest;
+
+
+ UNREFERENCED_PARAMETER(FilterModuleContext);
+
+ //
+ // Get at the request context.
+ //
+ FilterRequest = CONTAINING_RECORD(NdisRequest, FILTER_REQUEST, Request);
+
+ //
+ // Save away the completion status.
+ //
+ FilterRequest->Status = Status;
+
+ //
+ // Wake up the thread blocked for this request to complete.
+ //
+ NdisSetEvent(&FilterRequest->ReqEvent);
+}
+
diff --git a/templates/NdisFilter/NdisFilter/filter.h b/templates/NdisFilter/NdisFilter/filter.h
new file mode 100644
index 000000000..f4ed6349e
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/filter.h
@@ -0,0 +1,418 @@
+/*++
+
+Module Name:
+
+ Filter.h
+
+Abstract:
+
+ This module contains all prototypes and macros for filter code.
+
+--*/
+#ifndef _FILT_H
+#define _FILT_H
+
+#pragma warning(disable:28930) // Unused assignment of pointer, by design in samples
+#pragma warning(disable:28931) // Unused assignment of variable, by design in samples
+
+// TODO: Customize these to hint at your component for memory leak tracking.
+// These should be treated like a pooltag.
+#define FILTER_REQUEST_ID 'RTLF'
+#define FILTER_ALLOC_TAG 'tliF'
+#define FILTER_TAG 'dnTF'
+
+// TODO: Specify which version of the NDIS contract you will use here.
+// In many cases, 6.0 is the best choice. You only need to select a later
+// version if you need a feature that is not available in 6.0.
+//
+// Legal values include:
+// 6.0 Available starting with Windows Vista RTM
+// 6.1 Available starting with Windows Vista SP1 / Windows Server 2008
+// 6.20 Available starting with Windows 7 / Windows Server 2008 R2
+// 6.30 Available starting with Windows 8 / Windows Server "8"
+#define FILTER_MAJOR_NDIS_VERSION 6
+
+#if defined(NDIS60)
+#define FILTER_MINOR_NDIS_VERSION 0
+#elif defined(NDIS620)
+#define FILTER_MINOR_NDIS_VERSION 20
+#elif defined(NDIS630)
+#define FILTER_MINOR_NDIS_VERSION 30
+#endif
+
+//
+// Global variables
+//
+extern NDIS_HANDLE FilterDriverHandle; // NDIS handle for filter driver
+extern NDIS_HANDLE FilterDriverObject;
+extern NDIS_HANDLE NdisFilterDeviceHandle;
+extern PDEVICE_OBJECT NdisDeviceObject;
+
+extern FILTER_LOCK FilterListLock;
+extern LIST_ENTRY FilterModuleList;
+
+#define FILTER_FRIENDLY_NAME L"NdisFilter NDIS LightWeight Filter"
+#define FILTER_UNIQUE_NAME L"{1ce83cec-805d-4357-9982-f1fa78a3f617}" //unique name, quid name
+#define FILTER_SERVICE_NAME L"NdisFilter"
+
+//
+// The filter needs to handle IOCTLs
+//
+#define LINKNAME_STRING L"\\DosDevices\\NdisFilter"
+#define NTDEVICE_STRING L"\\Device\\NdisFilter"
+
+//
+// Types and macros to manipulate packet queue
+//
+typedef struct _QUEUE_ENTRY
+{
+ struct _QUEUE_ENTRY * Next;
+}QUEUE_ENTRY, *PQUEUE_ENTRY;
+
+typedef struct _QUEUE_HEADER
+{
+ PQUEUE_ENTRY Head;
+ PQUEUE_ENTRY Tail;
+} QUEUE_HEADER, PQUEUE_HEADER;
+
+
+#if TRACK_RECEIVES
+UINT filterLogReceiveRefIndex = 0;
+ULONG_PTR filterLogReceiveRef[0x10000];
+#endif
+
+#if TRACK_SENDS
+UINT filterLogSendRefIndex = 0;
+ULONG_PTR filterLogSendRef[0x10000];
+#endif
+
+#if TRACK_RECEIVES
+#define FILTER_LOG_RCV_REF(_O, _Instance, _NetBufferList, _Ref) \
+ {\
+ filterLogReceiveRef[filterLogReceiveRefIndex++] = (ULONG_PTR)(_O); \
+ filterLogReceiveRef[filterLogReceiveRefIndex++] = (ULONG_PTR)(_Instance); \
+ filterLogReceiveRef[filterLogReceiveRefIndex++] = (ULONG_PTR)(_NetBufferList); \
+ filterLogReceiveRef[filterLogReceiveRefIndex++] = (ULONG_PTR)(_Ref); \
+ if (filterLogReceiveRefIndex >= (0x10000 - 5)) \
+ { \
+ filterLogReceiveRefIndex = 0; \
+ } \
+ }
+#else
+#define FILTER_LOG_RCV_REF(_O, _Instance, _NetBufferList, _Ref)
+#endif
+
+#if TRACK_SENDS
+#define FILTER_LOG_SEND_REF(_O, _Instance, _NetBufferList, _Ref) \
+ {\
+ filterLogSendRef[filterLogSendRefIndex++] = (ULONG_PTR)(_O); \
+ filterLogSendRef[filterLogSendRefIndex++] = (ULONG_PTR)(_Instance); \
+ filterLogSendRef[filterLogSendRefIndex++] = (ULONG_PTR)(_NetBufferList); \
+ filterLogSendRef[filterLogSendRefIndex++] = (ULONG_PTR)(_Ref); \
+ if (filterLogSendRefIndex >= (0x10000 - 5)) \
+ { \
+ filterLogSendRefIndex = 0; \
+ } \
+ }
+
+#else
+#define FILTER_LOG_SEND_REF(_O, _Instance, _NetBufferList, _Ref)
+#endif
+
+
+//
+// DEBUG related macros.
+//
+#if DBG
+#define FILTER_ALLOC_MEM(_NdisHandle, _Size) \
+ filterAuditAllocMem( \
+ _NdisHandle, \
+ _Size, \
+ __FILENUMBER, \
+ __LINE__);
+
+#define FILTER_FREE_MEM(_pMem) \
+ filterAuditFreeMem(_pMem);
+
+#else
+#define FILTER_ALLOC_MEM(_NdisHandle, _Size) \
+ NdisAllocateMemoryWithTagPriority(_NdisHandle, _Size, FILTER_ALLOC_TAG, LowPoolPriority)
+
+#define FILTER_FREE_MEM(_pMem) NdisFreeMemory(_pMem, 0, 0)
+
+#endif //DBG
+
+#if DBG_SPIN_LOCK
+#define FILTER_INIT_LOCK(_pLock) \
+ filterAllocateSpinLock(_pLock, __FILENUMBER, __LINE__)
+
+#define FILTER_FREE_LOCK(_pLock) filterFreeSpinLock(_pLock)
+
+
+#define FILTER_ACQUIRE_LOCK(_pLock, DispatchLevel) \
+ filterAcquireSpinLock(_pLock, __FILENUMBER, __LINE__, DisaptchLevel)
+
+#define FILTER_RELEASE_LOCK(_pLock, DispatchLevel) \
+ filterReleaseSpinLock(_pLock, __FILENUMBER, __LINE__, DispatchLevel)
+
+#else
+#define FILTER_INIT_LOCK(_pLock) NdisAllocateSpinLock(_pLock)
+
+#define FILTER_FREE_LOCK(_pLock) NdisFreeSpinLock(_pLock)
+
+#define FILTER_ACQUIRE_LOCK(_pLock, DispatchLevel) \
+ { \
+ if (DispatchLevel) \
+ { \
+ NdisDprAcquireSpinLock(_pLock); \
+ } \
+ else \
+ { \
+ NdisAcquireSpinLock(_pLock); \
+ } \
+ }
+
+#define FILTER_RELEASE_LOCK(_pLock, DispatchLevel) \
+ { \
+ if (DispatchLevel) \
+ { \
+ NdisDprReleaseSpinLock(_pLock); \
+ } \
+ else \
+ { \
+ NdisReleaseSpinLock(_pLock); \
+ } \
+ }
+#endif //DBG_SPIN_LOCK
+
+
+#define NET_BUFFER_LIST_LINK_TO_ENTRY(_pNBL) ((PQUEUE_ENTRY)(NET_BUFFER_LIST_NEXT_NBL(_pNBL)))
+#define ENTRY_TO_NET_BUFFER_LIST(_pEnt) (CONTAINING_RECORD((_pEnt), NET_BUFFER_LIST, Next))
+
+#define InitializeQueueHeader(_QueueHeader) \
+{ \
+ (_QueueHeader)->Head = (_QueueHeader)->Tail = NULL; \
+}
+
+//
+// Macros for queue operations
+//
+#define IsQueueEmpty(_QueueHeader) ((_QueueHeader)->Head == NULL)
+
+#define RemoveHeadQueue(_QueueHeader) \
+ (_QueueHeader)->Head; \
+ { \
+ PQUEUE_ENTRY pNext; \
+ ASSERT((_QueueHeader)->Head); \
+ pNext = (_QueueHeader)->Head->Next; \
+ (_QueueHeader)->Head = pNext; \
+ if (pNext == NULL) \
+ (_QueueHeader)->Tail = NULL; \
+ }
+
+#define InsertHeadQueue(_QueueHeader, _QueueEntry) \
+ { \
+ ((PQUEUE_ENTRY)(_QueueEntry))->Next = (_QueueHeader)->Head; \
+ (_QueueHeader)->Head = (PQUEUE_ENTRY)(_QueueEntry); \
+ if ((_QueueHeader)->Tail == NULL) \
+ (_QueueHeader)->Tail = (PQUEUE_ENTRY)(_QueueEntry); \
+ }
+
+#define InsertTailQueue(_QueueHeader, _QueueEntry) \
+ { \
+ ((PQUEUE_ENTRY)(_QueueEntry))->Next = NULL; \
+ if ((_QueueHeader)->Tail) \
+ (_QueueHeader)->Tail->Next = (PQUEUE_ENTRY)(_QueueEntry); \
+ else \
+ (_QueueHeader)->Head = (PQUEUE_ENTRY)(_QueueEntry); \
+ (_QueueHeader)->Tail = (PQUEUE_ENTRY)(_QueueEntry); \
+ }
+
+
+//
+// Enum of filter's states
+// Filter can only be in one state at one time
+//
+typedef enum _FILTER_STATE
+{
+ FilterStateUnspecified,
+ FilterInitialized,
+ FilterPausing,
+ FilterPaused,
+ FilterRunning,
+ FilterRestarting,
+ FilterDetaching
+} FILTER_STATE;
+
+
+typedef struct _FILTER_REQUEST
+{
+ NDIS_OID_REQUEST Request;
+ NDIS_EVENT ReqEvent;
+ NDIS_STATUS Status;
+} FILTER_REQUEST, *PFILTER_REQUEST;
+
+//
+// Define the filter struct
+//
+typedef struct _MS_FILTER
+{
+ LIST_ENTRY FilterModuleLink;
+ //Reference to this filter
+ ULONG RefCount;
+
+ NDIS_HANDLE FilterHandle;
+ NDIS_STRING FilterModuleName;
+ NDIS_STRING MiniportFriendlyName;
+ NDIS_STRING MiniportName;
+ NET_IFINDEX MiniportIfIndex;
+
+ NDIS_STATUS Status;
+ NDIS_EVENT Event;
+ ULONG BackFillSize;
+ FILTER_LOCK Lock; // Lock for protection of state and outstanding sends and recvs
+
+ FILTER_STATE State; // Which state the filter is in
+ ULONG OutstandingSends;
+ ULONG OutstandingRequest;
+ ULONG OutstandingRcvs;
+ FILTER_LOCK SendLock;
+ FILTER_LOCK RcvLock;
+ QUEUE_HEADER SendNBLQueue;
+ QUEUE_HEADER RcvNBLQueue;
+
+
+ NDIS_STRING FilterName;
+ ULONG CallsRestart;
+ BOOLEAN TrackReceives;
+ BOOLEAN TrackSends;
+#if DBG
+ BOOLEAN bIndicating;
+#endif
+
+ PNDIS_OID_REQUEST PendingOidRequest;
+
+}MS_FILTER, * PMS_FILTER;
+
+
+typedef struct _FILTER_DEVICE_EXTENSION
+{
+ ULONG Signature;
+ NDIS_HANDLE Handle;
+} FILTER_DEVICE_EXTENSION, *PFILTER_DEVICE_EXTENSION;
+
+
+#define FILTER_READY_TO_PAUSE(_Filter) \
+ ((_Filter)->State == FilterPausing)
+
+//
+// The driver should maintain a list of NDIS filter handles
+//
+typedef struct _FL_NDIS_FILTER_LIST
+{
+ LIST_ENTRY Link;
+ NDIS_HANDLE ContextHandle;
+ NDIS_STRING FilterInstanceName;
+} FL_NDIS_FILTER_LIST, *PFL_NDIS_FILTER_LIST;
+
+//
+// The context inside a cloned request
+//
+typedef struct _NDIS_OID_REQUEST *FILTER_REQUEST_CONTEXT,**PFILTER_REQUEST_CONTEXT;
+
+
+//
+// function prototypes
+//
+
+EXTERN_C_START
+
+DRIVER_INITIALIZE DriverEntry;
+
+FILTER_SET_OPTIONS FilterRegisterOptions;
+
+FILTER_ATTACH FilterAttach;
+
+FILTER_DETACH FilterDetach;
+
+DRIVER_UNLOAD FilterUnload;
+
+FILTER_RESTART FilterRestart;
+
+FILTER_PAUSE FilterPause;
+
+FILTER_OID_REQUEST FilterOidRequest;
+
+FILTER_CANCEL_OID_REQUEST FilterCancelOidRequest;
+
+FILTER_STATUS FilterStatus;
+
+FILTER_DEVICE_PNP_EVENT_NOTIFY FilterDevicePnPEventNotify;
+
+FILTER_NET_PNP_EVENT FilterNetPnPEvent;
+
+FILTER_OID_REQUEST_COMPLETE FilterOidRequestComplete;
+
+FILTER_SEND_NET_BUFFER_LISTS FilterSendNetBufferLists;
+
+FILTER_RETURN_NET_BUFFER_LISTS FilterReturnNetBufferLists;
+
+FILTER_SEND_NET_BUFFER_LISTS_COMPLETE FilterSendNetBufferListsComplete;
+
+FILTER_RECEIVE_NET_BUFFER_LISTS FilterReceiveNetBufferLists;
+
+FILTER_CANCEL_SEND_NET_BUFFER_LISTS FilterCancelSendNetBufferLists;
+
+FILTER_SET_MODULE_OPTIONS FilterSetModuleOptions;
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+NdisFilterRegisterDevice(
+ VOID
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+NdisFilterDeregisterDevice(
+ VOID
+ );
+
+DRIVER_DISPATCH NdisFilterDispatch;
+
+DRIVER_DISPATCH NdisFilterDeviceIoControl;
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+PMS_FILTER
+filterFindFilterModule(
+ _In_reads_bytes_(BufferLength)
+ PUCHAR Buffer,
+ _In_ ULONG BufferLength
+ );
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NDIS_STATUS
+filterDoInternalRequest(
+ _In_ PMS_FILTER FilterModuleContext,
+ _In_ NDIS_REQUEST_TYPE RequestType,
+ _In_ NDIS_OID Oid,
+ _Inout_updates_bytes_to_(InformationBufferLength, *pBytesProcessed)
+ PVOID InformationBuffer,
+ _In_ ULONG InformationBufferLength,
+ _In_opt_ ULONG OutputBufferLength,
+ _In_ ULONG MethodId,
+ _Out_ PULONG pBytesProcessed
+ );
+
+VOID
+filterInternalRequestComplete(
+ _In_ NDIS_HANDLE FilterModuleContext,
+ _In_ PNDIS_OID_REQUEST NdisRequest,
+ _In_ NDIS_STATUS Status
+ );
+
+EXTERN_C_END
+
+#endif //_FILT_H
+
+
diff --git a/templates/NdisFilter/NdisFilter/filter.rc b/templates/NdisFilter/NdisFilter/filter.rc
new file mode 100644
index 000000000..c579011b1
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/filter.rc
@@ -0,0 +1,40 @@
+#include
+#include
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "NdisFilter NDIS 6.0 Filter Driver"
+#define VER_INTERNALNAME_STR "NdisFilter.sys"
+#define VER_ORIGINALFILENAME_STR "NdisFilter.sys"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/templates/NdisFilter/NdisFilter/filteruser.h b/templates/NdisFilter/NdisFilter/filteruser.h
new file mode 100644
index 000000000..e4ce21dd9
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/filteruser.h
@@ -0,0 +1,86 @@
+#ifndef __FILTERUSER_H__
+#define __FILTERUSER_H__
+
+//
+// Temp file to test filter
+//
+
+#define _NDIS_CONTROL_CODE(request,method) \
+ CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, request, method, FILE_ANY_ACCESS)
+
+#define IOCTL_FILTER_RESTART_ALL _NDIS_CONTROL_CODE(0, METHOD_BUFFERED)
+#define IOCTL_FILTER_RESTART_ONE_INSTANCE _NDIS_CONTROL_CODE(1, METHOD_BUFFERED)
+#define IOCTL_FILTER_ENUERATE_ALL_INSTANCES _NDIS_CONTROL_CODE(2, METHOD_BUFFERED)
+#define IOCTL_FILTER_QUERY_ALL_STAT _NDIS_CONTROL_CODE(3, METHOD_BUFFERED)
+#define IOCTL_FILTER_CLEAR_ALL_STAT _NDIS_CONTROL_CODE(4, METHOD_BUFFERED)
+#define IOCTL_FILTER_SET_OID_VALUE _NDIS_CONTROL_CODE(5, METHOD_BUFFERED)
+#define IOCTL_FILTER_QUERY_OID_VALUE _NDIS_CONTROL_CODE(6, METHOD_BUFFERED)
+#define IOCTL_FILTER_CANCEL_REQUEST _NDIS_CONTROL_CODE(7, METHOD_BUFFERED)
+#define IOCTL_FILTER_READ_DRIVER_CONFIG _NDIS_CONTROL_CODE(8, METHOD_BUFFERED)
+#define IOCTL_FILTER_WRITE_DRIVER_CONFIG _NDIS_CONTROL_CODE(9, METHOD_BUFFERED)
+#define IOCTL_FILTER_READ_ADAPTER_CONFIG _NDIS_CONTROL_CODE(10, METHOD_BUFFERED)
+#define IOCTL_FILTER_WRITE_ADAPTER_CONFIG _NDIS_CONTROL_CODE(11, METHOD_BUFFERED)
+#define IOCTL_FILTER_READ_INSTANCE_CONFIG _NDIS_CONTROL_CODE(12, METHOD_BUFFERED)
+#define IOCTL_FILTER_WRITE_INSTANCE_CONFIG _NDIS_CONTROL_CODE(13, METHOD_BUFFERED)
+
+
+#define MAX_FILTER_INSTANCE_NAME_LENGTH 256
+#define MAX_FILTER_CONFIG_KEYWORD_LENGTH 256
+typedef struct _FILTER_DRIVER_ALL_STAT
+{
+ ULONG AttachCount;
+ ULONG DetachCount;
+ ULONG ExternalRequestFailedCount;
+ ULONG ExternalRequestSuccessCount;
+ ULONG InternalRequestFailedCount;
+} FILTER_DRIVER_ALL_STAT, * PFILTER_DRIVER_ALL_STAT;
+
+
+typedef struct _FILTER_SET_OID
+{
+ WCHAR InstanceName[MAX_FILTER_INSTANCE_NAME_LENGTH];
+ ULONG InstanceNameLength;
+ NDIS_OID Oid;
+ NDIS_STATUS Status;
+ UCHAR Data[sizeof(ULONG)];
+
+}FILTER_SET_OID, *PFILTER_SET_OID;
+
+typedef struct _FILTER_QUERY_OID
+{
+ WCHAR InstanceName[MAX_FILTER_INSTANCE_NAME_LENGTH];
+ ULONG InstanceNameLength;
+ NDIS_OID Oid;
+ NDIS_STATUS Status;
+ UCHAR Data[sizeof(ULONG)];
+
+}FILTER_QUERY_OID, *PFILTER_QUERY_OID;
+
+typedef struct _FILTER_READ_CONFIG
+{
+ _Field_size_bytes_part_(MAX_FILTER_INSTANCE_NAME_LENGTH,InstanceNameLength)
+ WCHAR InstanceName[MAX_FILTER_INSTANCE_NAME_LENGTH];
+ ULONG InstanceNameLength;
+ _Field_size_bytes_part_(MAX_FILTER_CONFIG_KEYWORD_LENGTH,KeywordLength)
+ WCHAR Keyword[MAX_FILTER_CONFIG_KEYWORD_LENGTH];
+ ULONG KeywordLength;
+ NDIS_PARAMETER_TYPE ParameterType;
+ NDIS_STATUS Status;
+ UCHAR Data[sizeof(ULONG)];
+}FILTER_READ_CONFIG, *PFILTER_READ_CONFIG;
+
+typedef struct _FILTER_WRITE_CONFIG
+{
+ _Field_size_bytes_part_(MAX_FILTER_INSTANCE_NAME_LENGTH,InstanceNameLength)
+ WCHAR InstanceName[MAX_FILTER_INSTANCE_NAME_LENGTH];
+ ULONG InstanceNameLength;
+ _Field_size_bytes_part_(MAX_FILTER_CONFIG_KEYWORD_LENGTH,KeywordLength)
+ WCHAR Keyword[MAX_FILTER_CONFIG_KEYWORD_LENGTH];
+ ULONG KeywordLength;
+ NDIS_PARAMETER_TYPE ParameterType;
+ NDIS_STATUS Status;
+ UCHAR Data[sizeof(ULONG)];
+}FILTER_WRITE_CONFIG, *PFILTER_WRITE_CONFIG;
+
+#endif //__FILTERUSER_H__
+
diff --git a/templates/NdisFilter/NdisFilter/flt_dbg.c b/templates/NdisFilter/NdisFilter/flt_dbg.c
new file mode 100644
index 000000000..e5ef601c3
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/flt_dbg.c
@@ -0,0 +1,409 @@
+/*++
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ This module contains all debug-related code.
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+
+Notes:
+
+--*/
+
+#include "precomp.h"
+
+#define __FILENUMBER 'GBED'
+
+#if DBG
+
+INT filterDebugLevel = DL_WARN;
+
+NDIS_SPIN_LOCK filterDbgLogLock;
+
+PFILTERD_ALLOCATION filterdMemoryHead = (PFILTERD_ALLOCATION)NULL;
+PFILTERD_ALLOCATION filterdMemoryTail = (PFILTERD_ALLOCATION)NULL;
+ULONG filterdAllocCount = 0; // how many allocated so far (unfreed)
+
+NDIS_SPIN_LOCK filterdMemoryLock;
+BOOLEAN filterdInitDone = FALSE;
+
+
+PVOID
+filterAuditAllocMem(
+ NDIS_HANDLE NdisHandle,
+ ULONG Size,
+ ULONG FileNumber,
+ ULONG LineNumber
+)
+{
+ PVOID pBuffer;
+ PFILTERD_ALLOCATION pAllocInfo;
+
+ if (!filterdInitDone)
+ {
+ NdisAllocateSpinLock(&(filterdMemoryLock));
+ filterdInitDone = TRUE;
+ }
+
+ //
+ // Integer overflow check
+ //
+ if ((ULONG)(Size + sizeof(FILTERD_ALLOCATION)) < Size)
+ {
+ DEBUGP(DL_VERY_LOUD+50,
+ "filterAuditAllocMem: Integer overflow error file %d, line %d, Size %d \n",
+ FileNumber, LineNumber, Size);
+
+ pBuffer = NULL;
+ }
+ else
+ {
+
+ pAllocInfo =
+ (PFILTERD_ALLOCATION)
+ NdisAllocateMemoryWithTagPriority(
+ NdisHandle,
+ Size+sizeof(FILTERD_ALLOCATION),
+ (ULONG)'gdTF',
+ LowPoolPriority
+ );
+
+ if (pAllocInfo == (PFILTERD_ALLOCATION)NULL)
+ {
+ DEBUGP(DL_VERY_LOUD+50,
+ "filterAuditAllocMem: file %d, line %d, Size %d failed!\n",
+ FileNumber, LineNumber, Size);
+ pBuffer = NULL;
+ }
+ else
+ {
+ pBuffer = (PVOID)&(pAllocInfo->UserData);
+ NdisFillMemory(pBuffer, Size, 0xaf);
+ pAllocInfo->Signature = FILTERD_MEMORY_SIGNATURE;
+ pAllocInfo->FileNumber = FileNumber;
+ pAllocInfo->LineNumber = LineNumber;
+ pAllocInfo->Size = Size;
+ pAllocInfo->OwnerHandle = NdisHandle;
+ pAllocInfo->Next = (PFILTERD_ALLOCATION)NULL;
+
+ NdisAcquireSpinLock(&(filterdMemoryLock));
+
+ pAllocInfo->Prev = filterdMemoryTail;
+ if (filterdMemoryTail == (PFILTERD_ALLOCATION)NULL)
+ {
+ //
+ // empty list
+ //
+ filterdMemoryHead = filterdMemoryTail = pAllocInfo;
+ }
+ else
+ {
+ filterdMemoryTail->Next = pAllocInfo;
+ }
+ filterdMemoryTail = pAllocInfo;
+
+ filterdAllocCount++;
+ NdisReleaseSpinLock(&(filterdMemoryLock));
+ }
+ }
+
+ DEBUGP(DL_VERY_LOUD+100,
+ "filterAuditAllocMem: file %c%c%c%c, line %d, %d bytes, OwnerHandle %p, Memory 0x%p\n",
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber, Size, NdisHandle, pBuffer);
+
+ return (pBuffer);
+
+}
+
+
+VOID
+filterAuditFreeMem(
+ PVOID Pointer
+)
+{
+ PFILTERD_ALLOCATION pAllocInfo;
+
+ NdisAcquireSpinLock(&(filterdMemoryLock));
+
+ pAllocInfo = CONTAINING_RECORD(Pointer, FILTERD_ALLOCATION, UserData);
+
+ if (pAllocInfo->Signature != FILTERD_MEMORY_SIGNATURE)
+ {
+ DEBUGP(DL_ERROR,
+ "filterAuditFreeMem: unknown buffer 0x%p!\n", Pointer);
+ NdisReleaseSpinLock(&(filterdMemoryLock));
+#if DBG
+ DbgBreakPoint();
+#endif
+ return;
+ }
+
+ pAllocInfo->Signature = (ULONG)'DEAD';
+ if (pAllocInfo->Prev != (PFILTERD_ALLOCATION)NULL)
+ {
+ pAllocInfo->Prev->Next = pAllocInfo->Next;
+ }
+ else
+ {
+ filterdMemoryHead = pAllocInfo->Next;
+ }
+ if (pAllocInfo->Next != (PFILTERD_ALLOCATION)NULL)
+ {
+ pAllocInfo->Next->Prev = pAllocInfo->Prev;
+ }
+ else
+ {
+ filterdMemoryTail = pAllocInfo->Prev;
+ }
+ filterdAllocCount--;
+ NdisReleaseSpinLock(&(filterdMemoryLock));
+
+ NdisFreeMemory(pAllocInfo, 0, 0);
+}
+
+
+VOID
+filterAuditShutdown(
+ VOID
+)
+{
+ if (filterdInitDone)
+ {
+ if (filterdAllocCount != 0)
+ {
+ DEBUGP(DL_ERROR, "AuditShutdown: unfreed memory, %d blocks!\n",
+ filterdAllocCount);
+ DEBUGP(DL_ERROR, "MemoryHead: 0x%p, MemoryTail: 0x%p\n",
+ filterdMemoryHead, filterdMemoryTail);
+ DbgBreakPoint();
+ {
+ PFILTERD_ALLOCATION pAllocInfo;
+
+ while (filterdMemoryHead != (PFILTERD_ALLOCATION)NULL)
+ {
+ pAllocInfo = filterdMemoryHead;
+ DEBUGP(DL_INFO, "AuditShutdown: will free 0x%p\n", pAllocInfo);
+ filterAuditFreeMem(&(pAllocInfo->UserData));
+ }
+ }
+ }
+ filterdInitDone = FALSE;
+ }
+}
+
+#define MAX_HD_LENGTH 128
+
+VOID
+DbgPrintHexDump(
+ IN PUCHAR pBuffer,
+ IN ULONG Length
+)
+/*++
+
+Routine Description:
+
+ Print a hex dump of the given contiguous buffer. If the length
+ is too long, we truncate it.
+
+Arguments:
+
+ pBuffer - Points to start of data to be dumped
+ Length - Length of above.
+
+Return Value:
+
+ None
+
+--*/
+{
+ ULONG i;
+
+ if (Length > MAX_HD_LENGTH)
+ {
+ Length = MAX_HD_LENGTH;
+ }
+
+ for (i = 0; i < Length; i++)
+ {
+ //
+ // Check if we are at the end of a line
+ //
+ if ((i > 0) && ((i & 0xf) == 0))
+ {
+ DbgPrint("\n");
+ }
+
+ //
+ // Print addr if we are at start of a new line
+ //
+ if ((i & 0xf) == 0)
+ {
+ DbgPrint("%08p ", pBuffer);
+ }
+
+ DbgPrint(" %02x", *pBuffer++);
+ }
+
+ //
+ // Terminate the last line.
+ //
+ if (Length > 0)
+ {
+ DbgPrint("\n");
+ }
+}
+#endif // DBG
+
+
+#if DBG_SPIN_LOCK
+ULONG filterdSpinLockInitDone = 0;
+NDIS_SPIN_LOCK filterdLockLock;
+
+VOID
+filterAllocateSpinLock(
+ _In_ PFILTER_LOCK pLock,
+ _In_ ULONG FileNumber,
+ _In_ ULONG LineNumber
+)
+{
+ if (filterdSpinLockInitDone == 0)
+ {
+ filterdSpinLockInitDone = 1;
+ NdisAllocateSpinLock(&(filterdLockLock));
+ }
+
+ NdisAcquireSpinLock(&(filterdLockLock));
+ pLock->Signature = FILT_LOCK_SIG;
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+ pLock->IsAcquired = 0;
+ pLock->OwnerThread = 0;
+ NdisAllocateSpinLock(&(pLock->NdisLock));
+ NdisReleaseSpinLock(&(filterdLockLock));
+}
+
+VOID
+filterFreeSpinLock(
+ _In_ PFILTER_LOCK pLock
+ )
+{
+ ASSERT(filterdSpinLockInitDone == 1);
+
+
+ NdisFreeSpinLock(&(filterdLockLock));
+ filterdSpinLockInitDone = 0;
+ NdisFreeSpinLock(&(pLock->NdisLock));
+
+}
+
+
+
+VOID
+filterAcquireSpinLock(
+ _In_ PFILTER_LOCK pLock,
+ _In_ ULONG FileNumber,
+ _In_ ULONG LineNumber,
+ _In_ BOOLEAN DispatchLevel
+)
+{
+ if (DispatchLevel)
+ {
+ NdisDprAcquireSpinLock(&(filterdLockLock));
+ }
+ else
+ {
+ NdisAcquireSpinLock(&(filterdLockLock));
+ }
+ if (pLock->Signature != FILT_LOCK_SIG)
+ {
+ DbgPrint("Trying to acquire uninited lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+
+
+ pLock->IsAcquired++;
+
+ if (DispatchLevel)
+ {
+ NdisDprReleaseSpinLock(&(filterdLockLock));
+ NdisDprAcquireSpinLock(&(pLock->NdisLock));
+ }
+ else
+ {
+ NdisReleaseSpinLock(&(filterdLockLock));
+ NdisAcquireSpinLock(&(pLock->NdisLock));
+ }
+
+ //
+ // Mark this lock.
+ //
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+}
+
+
+VOID
+filterReleaseSpinLock(
+ _In_ PFILTER_LOCK pLock,
+ _In_ ULONG FileNumber,
+ _In_ ULONG LineNumber,
+ _In_ BOOLEAN DispatchLevel
+)
+{
+ NdisDprAcquireSpinLock(&(filterdLockLock));
+ if (pLock->Signature != FILT_LOCK_SIG)
+ {
+ DbgPrint("Trying to release uninited lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+
+ if (pLock->IsAcquired == 0)
+ {
+ DbgPrint("Detected release of unacquired lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+ pLock->IsAcquired--;
+ NdisDprReleaseSpinLock(&(filterdLockLock));
+
+ if (DispatchLevel)
+ {
+ NdisDprReleaseSpinLock(&(pLock->NdisLock));
+ }
+ else
+ {
+ NdisReleaseSpinLock(&(pLock->NdisLock));
+ }
+}
+#endif // DBG_SPIN_LOCK
+
diff --git a/templates/NdisFilter/NdisFilter/flt_dbg.h b/templates/NdisFilter/NdisFilter/flt_dbg.h
new file mode 100644
index 000000000..2b3e0812f
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/flt_dbg.h
@@ -0,0 +1,193 @@
+/*++
+
+Module Name:
+
+ debug.h
+
+Abstract:
+
+ This module contains all debug related prototypes for MS FILTER
+
+Revision History:
+
+
+Notes:
+
+--*/
+
+// disable warnings
+
+
+#ifndef _FILTDEBUG__H
+#define _FILTDEBUG__H
+
+//
+// Message verbosity: lower values indicate higher urgency
+//
+#define DL_EXTRA_LOUD 20
+#define DL_VERY_LOUD 10
+#define DL_LOUD 8
+#define DL_INFO 6
+#define DL_TRACE 5
+#define DL_WARN 4
+#define DL_ERROR 2
+#define DL_FATAL 0
+
+#if DBG_SPIN_LOCK
+
+typedef struct _FILTER_LOCK
+{
+ ULONG Signature;
+ ULONG IsAcquired;
+ ULONG TouchedByFileNumber;
+ ULONG TouchedInLineNumber;
+ NDIS_SPIN_LOCK NdisLock;
+} FILTER_LOCK, *PFILTER_LOCK;
+
+#define FILT_LOCK_SIG 'kcoL'
+
+extern NDIS_SPIN_LOCK filterDbgLogLock;
+
+extern
+VOID
+filterAllocateSpinLock(
+ IN PFILTER_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+);
+
+extern
+VOID
+filterFreeSpinLock(
+ IN PFILTER_LOCK pLock
+
+);
+
+
+extern
+VOID
+filterAcquireSpinLock(
+ IN PFILTER_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber,
+ IN BOOLEAN DispatchLevel
+);
+
+extern
+VOID
+filterReleaseSpinLock(
+ IN PFILTER_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber,
+ IN BOOLEAN DispatchLevel
+);
+
+
+#else
+
+typedef NDIS_SPIN_LOCK FILTER_LOCK;
+typedef PNDIS_SPIN_LOCK PFILTER_LOCK;
+
+#endif // DBG_SPIN_LOCK
+
+#if DBG
+
+extern INT filterDebugLevel;
+
+
+#define DEBUGP(lev, ...) \
+ { \
+ if ((lev) <= filterDebugLevel) \
+ { \
+ DbgPrint("NdisFilter: "); DbgPrint(__VA_ARGS__); \
+ } \
+ }
+
+#define DEBUGPDUMP(lev, pBuf, Len) \
+ { \
+ if ((lev) <= filterDebugLevel) \
+ { \
+ DbgPrintHexDump((PUCHAR)(pBuf), (ULONG)(Len)); \
+ } \
+ }
+
+#define FILTER_ASSERT(exp) \
+ { \
+ if (!(exp)) \
+ { \
+ DbgPrint("Filter: assert " #exp " failed in" \
+ " file %s, line %d\n", __FILE__, __LINE__); \
+ DbgBreakPoint(); \
+ } \
+ }
+
+
+
+//
+// Memory Allocation/Freeing Audit:
+//
+
+//
+// The FILTER_ALLOCATION structure stores all info about one allocation
+//
+typedef struct _FILTERD_ALLOCATION {
+
+ ULONG Signature;
+ struct _FILTERD_ALLOCATION *Next;
+ struct _FILTERD_ALLOCATION *Prev;
+ ULONG FileNumber;
+ ULONG LineNumber;
+ ULONG Size;
+ NDIS_HANDLE OwnerHandle;
+ union
+ {
+ ULONGLONG Alignment;
+ UCHAR UserData;
+ };
+
+} FILTERD_ALLOCATION, *PFILTERD_ALLOCATION;
+
+#define FILTERD_MEMORY_SIGNATURE (ULONG)'TFSM'
+
+extern
+PVOID
+filterAuditAllocMem (
+ NDIS_HANDLE NdisHandle,
+ ULONG Size,
+ ULONG FileNumber,
+ ULONG LineNumber
+);
+
+extern
+VOID
+filterAuditFreeMem(
+ PVOID Pointer
+);
+
+extern
+VOID
+filterAuditShutdown(
+ VOID
+);
+
+extern
+VOID
+DbgPrintHexDump(
+ PUCHAR pBuffer,
+ ULONG Length
+);
+
+#else
+
+//
+// No debug
+//
+#define DEBUGP(lev, ...)
+#define DEBUGPDUMP(lev, pBuf, Len)
+
+#define FILTER_ASSERT(exp)
+
+#endif // DBG
+
+
+#endif // _FILTDEBUG__H
diff --git a/templates/NdisFilter/NdisFilter/precomp.c b/templates/NdisFilter/NdisFilter/precomp.c
new file mode 100644
index 000000000..5944cf515
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/precomp.c
@@ -0,0 +1 @@
+#include "precomp.h"
\ No newline at end of file
diff --git a/templates/NdisFilter/NdisFilter/precomp.h b/templates/NdisFilter/NdisFilter/precomp.h
new file mode 100644
index 000000000..96cdb4887
--- /dev/null
+++ b/templates/NdisFilter/NdisFilter/precomp.h
@@ -0,0 +1,6 @@
+#pragma warning(disable:4201) //nonstandard extension used : nameless struct/union
+#include
+#include
+#include "flt_dbg.h"
+#include "filter.h"
+
diff --git a/templates/README.md b/templates/README.md
new file mode 100644
index 000000000..96a104343
--- /dev/null
+++ b/templates/README.md
@@ -0,0 +1,95 @@
+# Windows Driver Kit Templates
+
+## What
+
+The Windows Driver Kit WDK.vsix includes 16 templates to easily get started on building drivers. Once installed you can instantiate these from within Visual Studio using "File -> New -> Project ... -> Type: Driver" .
+
+This folder contains a "snapshot" of these "templates" exported as "samples". In case you do not have access to the Windows Driver Kit WDK.Vvsix or simply if you prefer the "sample version".
+
+## Version
+
+The exact version of the WDK.vsix used was 10.0.26045.0 and instantiated 2024/02/09. It is possible the folder here will be a bit "out of sync" with the latest official WDK.vsix.
+
+## How the Samples was Created
+
+After installation of VSIX in Visual Studio the templates can be found under:
+ C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Extensions\mjmwh1sj.nyr\ProjectTemplates\Windows Drivers\ . However you cannot just copy and use them as various substituions will have to be done as part of instantiating the template. As such this copy of the templates is made by manually instantiating each of these templates.
+
+ After instantiating them all I ran following to remove .vs folder and *.user files:
+```
+ for /F %i in ('dir /s /b /A:DH .vs') do rmdir /s /q %i
+ del /s *.user
+```
+
+## List of Templates
+
+Here are the templates:
+
+```
+ Applications:
+ EmptyApplication: Empty Desktop Application for Drivers (Universal)
+ EmptyDll: Empty DLL for Drivers (Universal) <-- Bug: This is not marked in VS as "Project Type=Driver".
+ EmptyStatic: Empty Static Library for Drivers (Universal)
+ WinUsbApp: WinUSB Application (Universal)
+
+ Devices:
+ KmdfUsb: Kernel Mode Driver, USB (KMDF)
+ NdisFilter: Filter Driver: NDIS
+ Umdf2Usb: User Mode Driver, USB (UMDF V2)
+ v4PrintDriver: Printer Driver V4 <-- This requires filling out fields in Wizard. I left all fields with their default settings.
+ XpsRenderFilter: Printer XPS Render Filter
+
+ Legacy:
+ WDMEmpty: Empty WDM Driver
+
+ Package:
+ DriverPackage: Driver Install Package
+ PrinterDriverPackage: Printer Driver Install Package <-- Bug: This is listed but does not show in VS "File -> New -> Project ..." dialog
+ WinUsbInfPackage: WinUSB INF Driver Package
+
+ WDF:
+ KMDF: Kernel Mode Driver (KMDF)
+ KMDFEmpty: Kernel Mode Driver, Empty (KMDF)
+ UMDF2: User Mode Driver (UMDF V2)
+ UMDF2Empty: User Mode Driver, Empty (UMDF V2)
+
+```
+
+So 16 templates above and a 17th one that is included with WDK.vsix, but I could not find.
+
+## Do they build?
+
+I tested using:
+* Using both EWDK and WDK NuGet (specifically EWDK ge_release_26052_240202-1419 and NuGet 10.0.26052.1000-preview.ge-release ).
+* Targeting both Configurations 'Debug' and 'Release'
+* Targeting both Platform 'x64' and 'arm64'
+* So 16 samples and 8 permutations for each sample. 128 build combinations in total.
+* Great news: I got identical results for all permutations.
+* 7 templates builds and 9 does not build.
+
+How:
+```
+ .\Build-AllSamples -Samples '^templates.' -Configurations 'Debug' -Platforms 'x64'
+```
+
+Results:
+
+```
+Sample Result
+templates.driverpackage Failed <-- TODO: We should annotate why this template does not build.
+templates.emptyapplication Failed <-- TODO: We should annotate why this template does not build.
+templates.emptydll Failed <-- TODO: We should annotate why this template does not build.
+templates.emptystatic Succeeded
+templates.kmdf Succeeded
+templates.kmdfempty Failed <-- TODO: We should annotate why this template does not build.
+templates.kmdfusb Succeeded
+templates.ndisfilter Failed <-- TODO: We should annotate why this template does not build.
+templates.umdf2 Succeeded
+templates.umdf2empty Failed <-- TODO: We should annotate why this template does not build.
+templates.umdf2usb Succeeded
+templates.v4printdriver Failed <-- TODO: We should annotate why this template does not build.
+templates.wdmempty Failed <-- TODO: We should annotate why this template does not build.
+templates.winusbapp Succeeded
+templates.winusbinfpackage GE: Succeeded/NI: Failed <-- TODO: We should annotate why this template builds on GE, but not on NI.
+templates.xpsrenderfilter Failed <-- TODO: We should annotate why this template does not build.
+```
diff --git a/templates/UMDF2/UMDF2.sln b/templates/UMDF2/UMDF2.sln
new file mode 100644
index 000000000..991be5cd0
--- /dev/null
+++ b/templates/UMDF2/UMDF2.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UMDF2", "UMDF2\UMDF2.vcxproj", "{599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Debug|ARM64.Build.0 = Debug|ARM64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Debug|x64.ActiveCfg = Debug|x64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Debug|x64.Build.0 = Debug|x64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Debug|x64.Deploy.0 = Debug|x64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Release|ARM64.ActiveCfg = Release|ARM64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Release|ARM64.Build.0 = Release|ARM64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Release|ARM64.Deploy.0 = Release|ARM64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Release|x64.ActiveCfg = Release|x64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Release|x64.Build.0 = Release|x64
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8ABF59FF-022A-4E1F-9792-841932E7A36B}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/UMDF2/UMDF2/Device.c b/templates/UMDF2/UMDF2/Device.c
new file mode 100644
index 000000000..ca5df5b6f
--- /dev/null
+++ b/templates/UMDF2/UMDF2/Device.c
@@ -0,0 +1,87 @@
+/*++
+
+Module Name:
+
+ device.c - Device handling events for example driver.
+
+Abstract:
+
+ This file contains the device entry points and callbacks.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include "driver.h"
+#include "device.tmh"
+
+NTSTATUS
+UMDF2CreateDevice(
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+
+Routine Description:
+
+ Worker routine called to create a device and its software resources.
+
+Arguments:
+
+ DeviceInit - Pointer to an opaque init structure. Memory for this
+ structure will be freed by the framework when the WdfDeviceCreate
+ succeeds. So don't access the structure after that point.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ PDEVICE_CONTEXT deviceContext;
+ WDFDEVICE device;
+ NTSTATUS status;
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
+
+ status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Get a pointer to the device context structure that we just associated
+ // with the device object. We define this structure in the device.h
+ // header file. DeviceGetContext is an inline function generated by
+ // using the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in device.h.
+ // This function will do the type checking and return the device context.
+ // If you pass a wrong object handle it will return NULL and assert if
+ // run under framework verifier mode.
+ //
+ deviceContext = DeviceGetContext(device);
+
+ //
+ // Initialize the context.
+ //
+ deviceContext->PrivateDeviceData = 0;
+
+ //
+ // Create a device interface so that applications can find and talk
+ // to us.
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ &GUID_DEVINTERFACE_UMDF2,
+ NULL // ReferenceString
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Initialize the I/O Package and any Queues
+ //
+ status = UMDF2QueueInitialize(device);
+ }
+ }
+
+ return status;
+}
diff --git a/templates/UMDF2/UMDF2/Device.h b/templates/UMDF2/UMDF2/Device.h
new file mode 100644
index 000000000..7100e5a11
--- /dev/null
+++ b/templates/UMDF2/UMDF2/Device.h
@@ -0,0 +1,46 @@
+/*++
+
+Module Name:
+
+ device.h
+
+Abstract:
+
+ This file contains the device definitions.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include "public.h"
+
+EXTERN_C_START
+
+//
+// The device context performs the same job as
+// a WDM device extension in the driver frameworks
+//
+typedef struct _DEVICE_CONTEXT
+{
+ ULONG PrivateDeviceData; // just a placeholder
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// This macro will generate an inline function called DeviceGetContext
+// which will be used to get a pointer to the device context memory
+// in a type safe manner.
+//
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, DeviceGetContext)
+
+//
+// Function to initialize the device and its callbacks
+//
+NTSTATUS
+UMDF2CreateDevice(
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ );
+
+EXTERN_C_END
diff --git a/templates/UMDF2/UMDF2/Driver.c b/templates/UMDF2/UMDF2/Driver.c
new file mode 100644
index 000000000..045c71188
--- /dev/null
+++ b/templates/UMDF2/UMDF2/Driver.c
@@ -0,0 +1,167 @@
+/*++
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This file contains the driver entry points and callbacks.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include "driver.h"
+#include "driver.tmh"
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded. DriverEntry specifies the other entry
+ points in the function driver, such as EvtDevice and DriverUnload.
+
+Parameters Description:
+
+ DriverObject - represents the instance of the function driver that is loaded
+ into memory. DriverEntry must initialize members of DriverObject before it
+ returns to the caller. DriverObject is allocated by the system before the
+ driver is loaded, and it is released by the system after the system unloads
+ the function driver from memory.
+
+ RegistryPath - represents the driver specific path in the Registry.
+ The function driver can use the path to store driver related data between
+ reboots. The path does not store hardware instance specific data.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ WDF_DRIVER_CONFIG config;
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES attributes;
+
+ //
+ // Initialize WPP Tracing
+ //
+#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0
+ WPP_INIT_TRACING(MYDRIVER_TRACING_ID);
+#else
+ WPP_INIT_TRACING( DriverObject, RegistryPath );
+#endif
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ //
+ // Register a cleanup callback so that we can call WPP_CLEANUP when
+ // the framework driver object is deleted during driver unload.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.EvtCleanupCallback = UMDF2EvtDriverContextCleanup;
+
+ WDF_DRIVER_CONFIG_INIT(&config,
+ UMDF2EvtDeviceAdd
+ );
+
+ status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ &attributes,
+ &config,
+ WDF_NO_HANDLE
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
+#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0
+ WPP_CLEANUP();
+#else
+ WPP_CLEANUP(DriverObject);
+#endif
+ return status;
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
+
+NTSTATUS
+UMDF2EvtDeviceAdd(
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ status = UMDF2CreateDevice(DeviceInit);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
+
+VOID
+UMDF2EvtDriverContextCleanup(
+ _In_ WDFOBJECT DriverObject
+ )
+/*++
+Routine Description:
+
+ Free all the resources allocated in DriverEntry.
+
+Arguments:
+
+ DriverObject - handle to a WDF Driver object.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ //
+ // Stop WPP Tracing
+ //
+#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0
+ WPP_CLEANUP();
+#else
+ WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject));
+#endif
+}
diff --git a/templates/UMDF2/UMDF2/Driver.h b/templates/UMDF2/UMDF2/Driver.h
new file mode 100644
index 000000000..e08490931
--- /dev/null
+++ b/templates/UMDF2/UMDF2/Driver.h
@@ -0,0 +1,35 @@
+/*++
+
+Module Name:
+
+ driver.h
+
+Abstract:
+
+ This file contains the driver definitions.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include
+#include
+#include
+
+#include "device.h"
+#include "queue.h"
+#include "trace.h"
+
+EXTERN_C_START
+
+//
+// WDFDRIVER Events
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD UMDF2EvtDeviceAdd;
+EVT_WDF_OBJECT_CONTEXT_CLEANUP UMDF2EvtDriverContextCleanup;
+
+EXTERN_C_END
diff --git a/templates/UMDF2/UMDF2/Public.h b/templates/UMDF2/UMDF2/Public.h
new file mode 100644
index 000000000..90dec59cb
--- /dev/null
+++ b/templates/UMDF2/UMDF2/Public.h
@@ -0,0 +1,24 @@
+/*++
+
+Module Name:
+
+ public.h
+
+Abstract:
+
+ This module contains the common declarations shared by driver
+ and user applications.
+
+Environment:
+
+ driver and application
+
+--*/
+
+//
+// Define an Interface Guid so that apps can find the device and talk to it.
+//
+
+DEFINE_GUID (GUID_DEVINTERFACE_UMDF2,
+ 0x8e2c25f0,0xedbe,0x428c,0xac,0xa2,0x7a,0x76,0x27,0xb3,0x43,0x41);
+// {8e2c25f0-edbe-428c-aca2-7a7627b34341}
diff --git a/templates/UMDF2/UMDF2/Queue.c b/templates/UMDF2/UMDF2/Queue.c
new file mode 100644
index 000000000..81fa6beb0
--- /dev/null
+++ b/templates/UMDF2/UMDF2/Queue.c
@@ -0,0 +1,193 @@
+/*++
+
+Module Name:
+
+ queue.c
+
+Abstract:
+
+ This file contains the queue entry points and callbacks.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include "driver.h"
+#include "queue.tmh"
+
+NTSTATUS
+UMDF2QueueInitialize(
+ _In_ WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ The I/O dispatch callbacks for the frameworks device object
+ are configured in this function.
+
+ A single default I/O Queue is configured for parallel request
+ processing, and a driver context memory allocation is created
+ to hold our structure QUEUE_CONTEXT.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ WDFQUEUE queue;
+ NTSTATUS status;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+
+ //
+ // Configure a default queue so that requests that are not
+ // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
+ // other queues get dispatched here.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchParallel
+ );
+
+ queueConfig.EvtIoDeviceControl = UMDF2EvtIoDeviceControl;
+ queueConfig.EvtIoStop = UMDF2EvtIoStop;
+
+ status = WdfIoQueueCreate(
+ Device,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &queue
+ );
+
+ if(!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_QUEUE, "WdfIoQueueCreate failed %!STATUS!", status);
+ return status;
+ }
+
+ return status;
+}
+
+VOID
+UMDF2EvtIoDeviceControl(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+/*++
+
+Routine Description:
+
+ This event is invoked when the framework receives IRP_MJ_DEVICE_CONTROL request.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ OutputBufferLength - Size of the output buffer in bytes
+
+ InputBufferLength - Size of the input buffer in bytes
+
+ IoControlCode - I/O control code.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_QUEUE,
+ "%!FUNC! Queue 0x%p, Request 0x%p OutputBufferLength %d InputBufferLength %d IoControlCode %d",
+ Queue, Request, (int) OutputBufferLength, (int) InputBufferLength, IoControlCode);
+
+ WdfRequestComplete(Request, STATUS_SUCCESS);
+
+ return;
+}
+
+VOID
+UMDF2EvtIoStop(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ ULONG ActionFlags
+)
+/*++
+
+Routine Description:
+
+ This event is invoked for a power-managed queue before the device leaves the working state (D0).
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ ActionFlags - A bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS-typed flags
+ that identify the reason that the callback function is being called
+ and whether the request is cancelable.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_QUEUE,
+ "%!FUNC! Queue 0x%p, Request 0x%p ActionFlags %d",
+ Queue, Request, ActionFlags);
+
+ //
+ // In most cases, the EvtIoStop callback function completes, cancels, or postpones
+ // further processing of the I/O request.
+ //
+ // Typically, the driver uses the following rules:
+ //
+ // - If the driver owns the I/O request, it calls WdfRequestUnmarkCancelable
+ // (if the request is cancelable) and either calls WdfRequestStopAcknowledge
+ // with a Requeue value of TRUE, or it calls WdfRequestComplete with a
+ // completion status value of STATUS_SUCCESS or STATUS_CANCELLED.
+ //
+ // Before it can call these methods safely, the driver must make sure that
+ // its implementation of EvtIoStop has exclusive access to the request.
+ //
+ // In order to do that, the driver must synchronize access to the request
+ // to prevent other threads from manipulating the request concurrently.
+ // The synchronization method you choose will depend on your driver's design.
+ //
+ // For example, if the request is held in a shared context, the EvtIoStop callback
+ // might acquire an internal driver lock, take the request from the shared context,
+ // and then release the lock. At this point, the EvtIoStop callback owns the request
+ // and can safely complete or requeue the request.
+ //
+ // - If the driver has forwarded the I/O request to an I/O target, it either calls
+ // WdfRequestCancelSentRequest to attempt to cancel the request, or it postpones
+ // further processing of the request and calls WdfRequestStopAcknowledge with
+ // a Requeue value of FALSE.
+ //
+ // A driver might choose to take no action in EvtIoStop for requests that are
+ // guaranteed to complete in a small amount of time.
+ //
+ // In this case, the framework waits until the specified request is complete
+ // before moving the device (or system) to a lower power state or removing the device.
+ // Potentially, this inaction can prevent a system from entering its hibernation state
+ // or another low system power state. In extreme cases, it can cause the system
+ // to crash with bugcheck code 9F.
+ //
+
+ return;
+}
diff --git a/templates/UMDF2/UMDF2/Queue.h b/templates/UMDF2/UMDF2/Queue.h
new file mode 100644
index 000000000..3ab502928
--- /dev/null
+++ b/templates/UMDF2/UMDF2/Queue.h
@@ -0,0 +1,42 @@
+/*++
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This file contains the queue definitions.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+EXTERN_C_START
+
+//
+// This is the context that can be placed per queue
+// and would contain per queue information.
+//
+typedef struct _QUEUE_CONTEXT {
+
+ ULONG PrivateDeviceData; // just a placeholder
+
+} QUEUE_CONTEXT, *PQUEUE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext)
+
+NTSTATUS
+UMDF2QueueInitialize(
+ _In_ WDFDEVICE Device
+ );
+
+//
+// Events from the IoQueue object
+//
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL UMDF2EvtIoDeviceControl;
+EVT_WDF_IO_QUEUE_IO_STOP UMDF2EvtIoStop;
+
+EXTERN_C_END
diff --git a/templates/UMDF2/UMDF2/ReadMe.txt b/templates/UMDF2/UMDF2/ReadMe.txt
new file mode 100644
index 000000000..22b965474
--- /dev/null
+++ b/templates/UMDF2/UMDF2/ReadMe.txt
@@ -0,0 +1,33 @@
+========================================================================
+ UMDF2 Project Overview
+========================================================================
+
+This file contains a summary of what you will find in each of the files that make up your project.
+
+UMDF2.vcxproj
+ This is the main project file for projects generated using an Application Wizard.
+ It contains information about the version of the product that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+UMDF2.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+Public.h
+ Header file to be shared with applications.
+
+Driver.c & Driver.h
+ DriverEntry and WDFDRIVER related functionality and callbacks.
+
+Device.c & Device.h
+ WDFDEVICE related functionality and callbacks.
+
+Queue.c & Queue.h
+ WDFQUEUE related functionality and callbacks.
+
+Trace.h
+ Definitions for WPP tracing.
diff --git a/templates/UMDF2/UMDF2/Trace.h b/templates/UMDF2/UMDF2/Trace.h
new file mode 100644
index 000000000..3f744d301
--- /dev/null
+++ b/templates/UMDF2/UMDF2/Trace.h
@@ -0,0 +1,62 @@
+/*++
+
+Module Name:
+
+ Internal.h
+
+Abstract:
+
+ This module contains the local type definitions for the
+ driver.
+
+Environment:
+
+ Windows User-Mode Driver Framework 2
+
+--*/
+
+//
+// Define the tracing flags.
+//
+// Tracing GUID - dcbe127e-2fc9-4808-81c0-c5340058bc25
+//
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ MyDriver1TraceGuid, (dcbe127e,2fc9,4808,81c0,c5340058bc25), \
+ \
+ WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \
+ WPP_DEFINE_BIT(TRACE_DRIVER) \
+ WPP_DEFINE_BIT(TRACE_DEVICE) \
+ WPP_DEFINE_BIT(TRACE_QUEUE) \
+ )
+
+#define WPP_FLAG_LEVEL_LOGGER(flag, level) \
+ WPP_LEVEL_LOGGER(flag)
+
+#define WPP_FLAG_LEVEL_ENABLED(flag, level) \
+ (WPP_LEVEL_ENABLED(flag) && \
+ WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)
+
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \
+ WPP_LEVEL_LOGGER(flags)
+
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \
+ (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+//
+// This comment block is scanned by the trace preprocessor to define our
+// Trace function.
+//
+// begin_wpp config
+// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...);
+// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...);
+// end_wpp
+
+//
+//
+// Driver specific #defines
+//
+#if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0
+ #define MYDRIVER_TRACING_ID L"Microsoft\\UMDF2.0\\UMDF2 V1.0"
+#endif
\ No newline at end of file
diff --git a/templates/UMDF2/UMDF2/UMDF2.inf b/templates/UMDF2/UMDF2/UMDF2.inf
new file mode 100644
index 000000000..f4dbba564
Binary files /dev/null and b/templates/UMDF2/UMDF2/UMDF2.inf differ
diff --git a/templates/UMDF2/UMDF2/UMDF2.vcxproj b/templates/UMDF2/UMDF2/UMDF2.vcxproj
new file mode 100644
index 000000000..ca45f1807
--- /dev/null
+++ b/templates/UMDF2/UMDF2/UMDF2.vcxproj
@@ -0,0 +1,154 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {599FF144-2A3A-4BC7-96C9-7E1BF2FC9CF4}
+ {32909489-7be5-497b-aafa-db6669d9b44b}
+ v4.5
+ 12.0
+ Debug
+ x64
+ UMDF2
+
+
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ Universal
+
+
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ Universal
+
+
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ Universal
+
+
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ Universal
+
+
+
+ Windows10
+ true
+ 2
+
+
+ Windows10
+ false
+ 2
+
+
+ Windows10
+ true
+ 2
+
+
+ Windows10
+ false
+ 2
+
+
+
+
+
+
+
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+
+ true
+ true
+ trace.h
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+
+
+ sha256
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/UMDF2/UMDF2/UMDF2.vcxproj.filters b/templates/UMDF2/UMDF2/UMDF2.vcxproj.filters
new file mode 100644
index 000000000..48f8f8acb
--- /dev/null
+++ b/templates/UMDF2/UMDF2/UMDF2.vcxproj.filters
@@ -0,0 +1,57 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+
+
+
+ Driver Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/templates/UMDF2Empty/UMDF2Empty.sln b/templates/UMDF2Empty/UMDF2Empty.sln
new file mode 100644
index 000000000..afa7fddee
--- /dev/null
+++ b/templates/UMDF2Empty/UMDF2Empty.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UMDF2Empty", "UMDF2Empty\UMDF2Empty.vcxproj", "{61F28AE2-3E5C-43D1-9625-D870CDD38490}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Debug|ARM64.Build.0 = Debug|ARM64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Debug|x64.ActiveCfg = Debug|x64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Debug|x64.Build.0 = Debug|x64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Debug|x64.Deploy.0 = Debug|x64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Release|ARM64.ActiveCfg = Release|ARM64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Release|ARM64.Build.0 = Release|ARM64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Release|ARM64.Deploy.0 = Release|ARM64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Release|x64.ActiveCfg = Release|x64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Release|x64.Build.0 = Release|x64
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D7C9F528-A718-42DF-8275-57B469E9B878}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.inf b/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.inf
new file mode 100644
index 000000000..a1b9b6106
Binary files /dev/null and b/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.inf differ
diff --git a/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.vcxproj b/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.vcxproj
new file mode 100644
index 000000000..dc4ace587
--- /dev/null
+++ b/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.vcxproj
@@ -0,0 +1,120 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+
+
+
+ {61F28AE2-3E5C-43D1-9625-D870CDD38490}
+ {2177f19c-eb4c-4687-9e7f-f9eec1f12cf1}
+ v4.5
+ 12.0
+ Debug
+ x64
+ UMDF2Empty
+
+
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ Universal
+
+
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ Universal
+
+
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ Universal
+
+
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ Universal
+
+
+
+ Windows10
+ true
+ 2
+
+
+ Windows10
+ false
+ 2
+
+
+ Windows10
+ true
+ 2
+
+
+ Windows10
+ false
+ 2
+
+
+
+
+
+
+
+
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+
+ sha256
+
+
+
+
+ sha256
+
+
+
+
+ sha256
+
+
+
+
+ sha256
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.vcxproj.filters b/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.vcxproj.filters
new file mode 100644
index 000000000..aea160d88
--- /dev/null
+++ b/templates/UMDF2Empty/UMDF2Empty/UMDF2Empty.vcxproj.filters
@@ -0,0 +1,26 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+ Driver Files
+
+
+
\ No newline at end of file
diff --git a/templates/Umdf2Usb/Umdf2Usb.sln b/templates/Umdf2Usb/Umdf2Usb.sln
new file mode 100644
index 000000000..523cce986
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Umdf2Usb", "Umdf2Usb\Umdf2Usb.vcxproj", "{034945B8-BD9F-4509-9A9B-93873310CFD4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Debug|ARM64.Build.0 = Debug|ARM64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Debug|x64.ActiveCfg = Debug|x64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Debug|x64.Build.0 = Debug|x64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Debug|x64.Deploy.0 = Debug|x64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Release|ARM64.ActiveCfg = Release|ARM64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Release|ARM64.Build.0 = Release|ARM64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Release|ARM64.Deploy.0 = Release|ARM64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Release|x64.ActiveCfg = Release|x64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Release|x64.Build.0 = Release|x64
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8EEE45B6-3E99-4FE5-861E-CBBC4C273575}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/Umdf2Usb/Umdf2Usb/Device.c b/templates/Umdf2Usb/Umdf2Usb/Device.c
new file mode 100644
index 000000000..e0fd91401
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Device.c
@@ -0,0 +1,192 @@
+/*++
+
+Module Name:
+
+ device.c - Device handling events for example driver.
+
+Abstract:
+
+ This file contains the device entry points and callbacks.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include "driver.h"
+#include "device.tmh"
+
+
+
+NTSTATUS
+Umdf2UsbCreateDevice(
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+
+Routine Description:
+
+ Worker routine called to create a device and its software resources.
+
+Arguments:
+
+ DeviceInit - Pointer to an opaque init structure. Memory for this
+ structure will be freed by the framework when the WdfDeviceCreate
+ succeeds. So don't access the structure after that point.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDF_OBJECT_ATTRIBUTES deviceAttributes;
+ PDEVICE_CONTEXT deviceContext;
+ WDFDEVICE device;
+ NTSTATUS status;
+
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+ pnpPowerCallbacks.EvtDevicePrepareHardware = Umdf2UsbEvtDevicePrepareHardware;
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
+
+ status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Get a pointer to the device context structure that we just associated
+ // with the device object. We define this structure in the device.h
+ // header file. DeviceGetContext is an inline function generated by
+ // using the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in device.h.
+ // This function will do the type checking and return the device context.
+ // If you pass a wrong object handle it will return NULL and assert if
+ // run under framework verifier mode.
+ //
+ deviceContext = DeviceGetContext(device);
+
+ //
+ // Initialize the context.
+ //
+ deviceContext->PrivateDeviceData = 0;
+
+ //
+ // Create a device interface so that applications can find and talk
+ // to us.
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ &GUID_DEVINTERFACE_Umdf2Usb,
+ NULL // ReferenceString
+ );
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Initialize the I/O Package and any Queues
+ //
+ status = Umdf2UsbQueueInitialize(device);
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+Umdf2UsbEvtDevicePrepareHardware(
+ _In_ WDFDEVICE Device,
+ _In_ WDFCMRESLIST ResourceList,
+ _In_ WDFCMRESLIST ResourceListTranslated
+ )
+/*++
+
+Routine Description:
+
+ In this callback, the driver does whatever is necessary to make the
+ hardware ready to use. In the case of a USB device, this involves
+ reading and selecting descriptors.
+
+Arguments:
+
+ Device - handle to a device
+
+Return Value:
+
+ NT status value
+
+--*/
+{
+ NTSTATUS status;
+ PDEVICE_CONTEXT pDeviceContext;
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams;
+
+ UNREFERENCED_PARAMETER(ResourceList);
+ UNREFERENCED_PARAMETER(ResourceListTranslated);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ status = STATUS_SUCCESS;
+ pDeviceContext = DeviceGetContext(Device);
+
+ //
+ // Create a USB device handle so that we can communicate with the
+ // underlying USB stack. The WDFUSBDEVICE handle is used to query,
+ // configure, and manage all aspects of the USB device.
+ // These aspects include device properties, bus properties,
+ // and I/O creation and synchronization. We only create the device the first time
+ // PrepareHardware is called. If the device is restarted by pnp manager
+ // for resource rebalance, we will use the same device handle but then select
+ // the interfaces again because the USB stack could reconfigure the device on
+ // restart.
+ //
+ if (pDeviceContext->UsbDevice == NULL) {
+
+#if UMDF_VERSION_MINOR >= 25
+ WDF_USB_DEVICE_CREATE_CONFIG createParams;
+
+ WDF_USB_DEVICE_CREATE_CONFIG_INIT(&createParams,
+ USBD_CLIENT_CONTRACT_VERSION_602);
+
+ status = WdfUsbTargetDeviceCreateWithParameters(Device,
+ &createParams,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &pDeviceContext->UsbDevice
+ );
+#else
+ status = WdfUsbTargetDeviceCreate(Device,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &pDeviceContext->UsbDevice
+ );
+#endif
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "WdfUsbTargetDeviceCreateWithParameters failed 0x%x", status);
+ return status;
+ }
+ }
+
+ //
+ // Select the first configuration of the device, using the first alternate
+ // setting of each interface
+ //
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&configParams,
+ 0,
+ NULL
+ );
+ status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &configParams
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "WdfUsbTargetDeviceSelectConfig failed 0x%x", status);
+ return status;
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
diff --git a/templates/Umdf2Usb/Umdf2Usb/Device.h b/templates/Umdf2Usb/Umdf2Usb/Device.h
new file mode 100644
index 000000000..af3568dc4
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Device.h
@@ -0,0 +1,51 @@
+/*++
+
+Module Name:
+
+ device.h
+
+Abstract:
+
+ This file contains the device definitions.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+EXTERN_C_START
+
+//
+// The device context performs the same job as
+// a WDM device extension in the driver frameworks
+//
+typedef struct _DEVICE_CONTEXT
+{
+ WDFUSBDEVICE UsbDevice;
+ ULONG PrivateDeviceData; // just a placeholder
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// This macro will generate an inline function called DeviceGetContext
+// which will be used to get a pointer to the device context memory
+// in a type safe manner.
+//
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, DeviceGetContext)
+
+//
+// Function to initialize the device's queues and callbacks
+//
+NTSTATUS
+Umdf2UsbCreateDevice(
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ );
+
+//
+// Function to select the device's USB configuration and get a WDFUSBDEVICE
+// handle
+//
+EVT_WDF_DEVICE_PREPARE_HARDWARE Umdf2UsbEvtDevicePrepareHardware;
+
+EXTERN_C_END
diff --git a/templates/Umdf2Usb/Umdf2Usb/Driver.c b/templates/Umdf2Usb/Umdf2Usb/Driver.c
new file mode 100644
index 000000000..d205de808
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Driver.c
@@ -0,0 +1,157 @@
+/*++
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This file contains the driver entry points and callbacks.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include "driver.h"
+#include "driver.tmh"
+
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded. DriverEntry specifies the other entry
+ points in the function driver, such as EvtDevice and DriverUnload.
+
+Parameters Description:
+
+ DriverObject - represents the instance of the function driver that is loaded
+ into memory. DriverEntry must initialize members of DriverObject before it
+ returns to the caller. DriverObject is allocated by the system before the
+ driver is loaded, and it is released by the system after the system unloads
+ the function driver from memory.
+
+ RegistryPath - represents the driver specific path in the Registry.
+ The function driver can use the path to store driver related data between
+ reboots. The path does not store hardware instance specific data.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ WDF_DRIVER_CONFIG config;
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES attributes;
+
+ //
+ // Initialize WPP Tracing
+ //
+ WPP_INIT_TRACING( DriverObject, RegistryPath );
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ //
+ // Register a cleanup callback so that we can call WPP_CLEANUP when
+ // the framework driver object is deleted during driver unload.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.EvtCleanupCallback = Umdf2UsbEvtDriverContextCleanup;
+
+ WDF_DRIVER_CONFIG_INIT(&config,
+ Umdf2UsbEvtDeviceAdd
+ );
+
+ status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ &attributes,
+ &config,
+ WDF_NO_HANDLE
+ );
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
+ WPP_CLEANUP(DriverObject);
+ return status;
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
+
+NTSTATUS
+Umdf2UsbEvtDeviceAdd(
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ status = Umdf2UsbCreateDevice(DeviceInit);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
+
+ return status;
+}
+
+VOID
+Umdf2UsbEvtDriverContextCleanup(
+ _In_ WDFOBJECT DriverObject
+ )
+/*++
+Routine Description:
+
+ Free all the resources allocated in DriverEntry.
+
+Arguments:
+
+ DriverObject - handle to a WDF Driver object.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
+
+ //
+ // Stop WPP Tracing
+ //
+ WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER) DriverObject) );
+
+}
diff --git a/templates/Umdf2Usb/Umdf2Usb/Driver.h b/templates/Umdf2Usb/Umdf2Usb/Driver.h
new file mode 100644
index 000000000..fc1451172
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Driver.h
@@ -0,0 +1,37 @@
+/*++
+
+Module Name:
+
+ driver.h
+
+Abstract:
+
+ This file contains the driver definitions.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "device.h"
+#include "queue.h"
+#include "trace.h"
+
+EXTERN_C_START
+
+//
+// WDFDRIVER Events
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD Umdf2UsbEvtDeviceAdd;
+EVT_WDF_OBJECT_CONTEXT_CLEANUP Umdf2UsbEvtDriverContextCleanup;
+
+EXTERN_C_END
diff --git a/templates/Umdf2Usb/Umdf2Usb/Queue.c b/templates/Umdf2Usb/Umdf2Usb/Queue.c
new file mode 100644
index 000000000..b7d5621f7
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Queue.c
@@ -0,0 +1,180 @@
+/*++
+
+Module Name:
+
+ queue.c
+
+Abstract:
+
+ This file contains the queue entry points and callbacks.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+#include "driver.h"
+#include "queue.tmh"
+
+NTSTATUS
+Umdf2UsbQueueInitialize(
+ _In_ WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+
+ The I/O dispatch callbacks for the frameworks device object
+ are configured in this function.
+
+ A single default I/O Queue is configured for parallel request
+ processing, and a driver context memory allocation is created
+ to hold our structure QUEUE_CONTEXT.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ WDFQUEUE queue;
+ NTSTATUS status;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+
+ //
+ // Configure a default queue so that requests that are not
+ // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
+ // other queues get dispatched here.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchParallel
+ );
+
+ queueConfig.EvtIoDeviceControl = Umdf2UsbEvtIoDeviceControl;
+ queueConfig.EvtIoStop = Umdf2UsbEvtIoStop;
+
+ status = WdfIoQueueCreate(
+ Device,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &queue
+ );
+
+ if( !NT_SUCCESS(status) ) {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_QUEUE, "WdfIoQueueCreate failed %!STATUS!", status);
+ return status;
+ }
+
+ return status;
+}
+
+VOID
+Umdf2UsbEvtIoDeviceControl(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+/*++
+
+Routine Description:
+
+ This event is invoked when the framework receives IRP_MJ_DEVICE_CONTROL request.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ OutputBufferLength - Size of the output buffer in bytes
+
+ InputBufferLength - Size of the input buffer in bytes
+
+ IoControlCode - I/O control code.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_QUEUE,
+ "%!FUNC! Queue 0x%p, Request 0x%p OutputBufferLength %d InputBufferLength %d IoControlCode %d",
+ Queue, Request, (int) OutputBufferLength, (int) InputBufferLength, IoControlCode);
+
+ WdfRequestComplete(Request, STATUS_SUCCESS);
+
+ return;
+}
+
+VOID
+Umdf2UsbEvtIoStop(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ ULONG ActionFlags
+)
+/*++
+
+Routine Description:
+
+ This event is invoked for a power-managed queue before the device leaves the working state (D0).
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated with the
+ I/O request.
+
+ Request - Handle to a framework request object.
+
+ ActionFlags - A bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS-typed flags
+ that identify the reason that the callback function is being called
+ and whether the request is cancelable.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ TRACE_QUEUE,
+ "%!FUNC! Queue 0x%p, Request 0x%p ActionFlags %d",
+ Queue, Request, ActionFlags);
+
+ //
+ // In most cases, the EvtIoStop callback function completes, cancels, or postpones
+ // further processing of the I/O request.
+ //
+ // Typically, the driver uses the following rules:
+ //
+ // - If the driver owns the I/O request, it either postpones further processing
+ // of the request and calls WdfRequestStopAcknowledge, or it calls WdfRequestComplete
+ // with a completion status value of STATUS_SUCCESS or STATUS_CANCELLED.
+ //
+ // The driver must call WdfRequestComplete only once, to either complete or cancel
+ // the request. To ensure that another thread does not call WdfRequestComplete
+ // for the same request, the EvtIoStop callback must synchronize with the driver's
+ // other event callback functions, for instance by using interlocked operations.
+ //
+ // - If the driver has forwarded the I/O request to an I/O target, it either calls
+ // WdfRequestCancelSentRequest to attempt to cancel the request, or it postpones
+ // further processing of the request and calls WdfRequestStopAcknowledge.
+ //
+ // A driver might choose to take no action in EvtIoStop for requests that are
+ // guaranteed to complete in a small amount of time. For example, the driver might
+ // take no action for requests that are completed in one of the driver’s request handlers.
+ //
+
+ return;
+}
diff --git a/templates/Umdf2Usb/Umdf2Usb/Queue.h b/templates/Umdf2Usb/Umdf2Usb/Queue.h
new file mode 100644
index 000000000..f7d24b48e
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Queue.h
@@ -0,0 +1,42 @@
+/*++
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This file contains the queue definitions.
+
+Environment:
+
+ User-mode Driver Framework 2
+
+--*/
+
+EXTERN_C_START
+
+//
+// This is the context that can be placed per queue
+// and would contain per queue information.
+//
+typedef struct _QUEUE_CONTEXT {
+
+ ULONG PrivateDeviceData; // just a placeholder
+
+} QUEUE_CONTEXT, *PQUEUE_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext)
+
+NTSTATUS
+Umdf2UsbQueueInitialize(
+ _In_ WDFDEVICE Device
+ );
+
+//
+// Events from the IoQueue object
+//
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL Umdf2UsbEvtIoDeviceControl;
+EVT_WDF_IO_QUEUE_IO_STOP Umdf2UsbEvtIoStop;
+
+EXTERN_C_END
diff --git a/templates/Umdf2Usb/Umdf2Usb/ReadMe.txt b/templates/Umdf2Usb/Umdf2Usb/ReadMe.txt
new file mode 100644
index 000000000..336f02d3e
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/ReadMe.txt
@@ -0,0 +1,39 @@
+========================================================================
+ Umdf2Usb Project Overview
+========================================================================
+
+This file contains a summary of what you will find in each of the files that make up your project.
+The project supports UMDF 2.15 on Windows 10.
+
+Umdf2Usb.vcxproj
+ This is the main project file for projects generated using an Application Wizard.
+ It contains information about the version of the product that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+Umdf2Usb.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+Umdf2Usb.inf
+ Text file used for driver installation. After creating this driver using the template, the user
+ *must* update the hardware ID from "USB\VID_vvvv&PID_pppp" to the hardware ID of the USB device
+ that the driver should be installed on.
+
+Public.h
+ Header file to be shared with applications.
+
+Driver.c & Driver.h
+ DriverEntry and WDFDRIVER related functionality and callbacks.
+
+Device.cpp & Device.h
+ WDFDEVICE and WDFUSBDEVICE related functionality and callbacks.
+
+IoQueue.cpp & IoQueue.h
+ WDFQUEUE related functionality and callbacks.
+
+Trace.h
+ Definitions for WPP tracing.
\ No newline at end of file
diff --git a/templates/Umdf2Usb/Umdf2Usb/Trace.h b/templates/Umdf2Usb/Umdf2Usb/Trace.h
new file mode 100644
index 000000000..b690a86d5
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Trace.h
@@ -0,0 +1,63 @@
+/*++
+
+Module Name:
+
+ Trace.h
+
+Abstract:
+
+ This module contains the local type definitions for the
+ driver.
+
+Environment:
+
+ Windows User-Mode Driver Framework 2
+
+--*/
+
+//
+// Device Interface GUID
+// 4d7269f1-7f2c-4e80-bc1b-389b8b1af9eb
+//
+DEFINE_GUID(GUID_DEVINTERFACE_Umdf2Usb,
+ 0x4d7269f1,0x7f2c,0x4e80,0xbc,0x1b,0x38,0x9b,0x8b,0x1a,0xf9,0xeb);
+
+//
+// Define the tracing flags.
+//
+// Tracing GUID - 583fc2ba-4607-4580-ae19-336adb76cc96
+//
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ MyDriver1TraceGuid, (583fc2ba,4607,4580,ae19,336adb76cc96), \
+ \
+ WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \
+ WPP_DEFINE_BIT(TRACE_DRIVER) \
+ WPP_DEFINE_BIT(TRACE_DEVICE) \
+ WPP_DEFINE_BIT(TRACE_QUEUE) \
+ )
+
+#define WPP_FLAG_LEVEL_LOGGER(flag, level) \
+ WPP_LEVEL_LOGGER(flag)
+
+#define WPP_FLAG_LEVEL_ENABLED(flag, level) \
+ (WPP_LEVEL_ENABLED(flag) && \
+ WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)
+
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \
+ WPP_LEVEL_LOGGER(flags)
+
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \
+ (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+//
+// This comment block is scanned by the trace preprocessor to define our
+// Trace function.
+//
+// begin_wpp config
+// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...);
+// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...);
+// end_wpp
+//
+
diff --git a/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.inf b/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.inf
new file mode 100644
index 000000000..1c344c958
Binary files /dev/null and b/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.inf differ
diff --git a/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.vcxproj b/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.vcxproj
new file mode 100644
index 000000000..e38094486
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.vcxproj
@@ -0,0 +1,146 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {034945B8-BD9F-4509-9A9B-93873310CFD4}
+ {9181db3b-298d-4e39-a572-55bca4e4ac89}
+ v4.5
+ 12.0
+ Debug
+ x64
+ Umdf2Usb
+
+
+
+ Windows10
+ true
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ 2
+ Universal
+
+
+ Windows10
+ false
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ 2
+ Universal
+
+
+ Windows10
+ true
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ 2
+ Universal
+
+
+ Windows10
+ false
+ WindowsUserModeDriver10.0
+ DynamicLibrary
+ 2
+ Universal
+
+
+
+
+
+
+
+
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+
+ true
+ true
+ trace.h
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+
+
+ sha256
+
+
+
+
+ true
+ true
+ trace.h
+
+
+ sha256
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.vcxproj.filters b/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.vcxproj.filters
new file mode 100644
index 000000000..4c2b89994
--- /dev/null
+++ b/templates/Umdf2Usb/Umdf2Usb/Umdf2Usb.vcxproj.filters
@@ -0,0 +1,54 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+
+
+
+ Driver Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/templates/WDMEmpty/WDMEmpty.sln b/templates/WDMEmpty/WDMEmpty.sln
new file mode 100644
index 000000000..1e99d8996
--- /dev/null
+++ b/templates/WDMEmpty/WDMEmpty.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WDMEmpty", "WDMEmpty\WDMEmpty.vcxproj", "{ADAC3B4C-3757-4463-8433-B86C8AB09ABD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Debug|ARM64.Build.0 = Debug|ARM64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Debug|x64.ActiveCfg = Debug|x64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Debug|x64.Build.0 = Debug|x64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Debug|x64.Deploy.0 = Debug|x64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Release|ARM64.ActiveCfg = Release|ARM64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Release|ARM64.Build.0 = Release|ARM64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Release|ARM64.Deploy.0 = Release|ARM64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Release|x64.ActiveCfg = Release|x64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Release|x64.Build.0 = Release|x64
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {3BFEB7A6-138E-4088-9BAF-9640DA634930}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/WDMEmpty/WDMEmpty/WDMEmpty.inf b/templates/WDMEmpty/WDMEmpty/WDMEmpty.inf
new file mode 100644
index 000000000..c57c7e9d2
--- /dev/null
+++ b/templates/WDMEmpty/WDMEmpty/WDMEmpty.inf
@@ -0,0 +1,29 @@
+;
+; WDMEmpty.inf
+;
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=System
+ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}
+Provider=%ManufacturerName%
+DriverVer=
+CatalogFile=WDMEmpty.cat
+PnpLockdown=1
+
+[DestinationDirs]
+DefaultDestDir = 13
+
+[SourceDisksNames]
+1 = %DiskName%,,,""
+
+[SourceDisksFiles]
+
+[Manufacturer]
+%ManufacturerName%=Standard,NT$ARCH$.10.0...16299 ; %13% support introduced in build 16299
+
+[Standard.NT$ARCH$.10.0...16299]
+
+[Strings]
+ManufacturerName="" ;TODO: Replace with your manufacturer name
+DiskName="WDMEmpty Source Disk"
diff --git a/templates/WDMEmpty/WDMEmpty/WDMEmpty.vcxproj b/templates/WDMEmpty/WDMEmpty/WDMEmpty.vcxproj
new file mode 100644
index 000000000..6af0aee76
--- /dev/null
+++ b/templates/WDMEmpty/WDMEmpty/WDMEmpty.vcxproj
@@ -0,0 +1,98 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ {ADAC3B4C-3757-4463-8433-B86C8AB09ABD}
+ {dd38f7fc-d7bd-488b-9242-7d8754cde80d}
+ v4.5
+ 12.0
+ Debug
+ x64
+ WDMEmpty
+
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+
+
+
+
+
+
+
+
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+ DbgengKernelDebugger
+
+
+
+ sha256
+
+
+
+
+ sha256
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/WDMEmpty/WDMEmpty/WDMEmpty.vcxproj.filters b/templates/WDMEmpty/WDMEmpty/WDMEmpty.vcxproj.filters
new file mode 100644
index 000000000..0cc4ead80
--- /dev/null
+++ b/templates/WDMEmpty/WDMEmpty/WDMEmpty.vcxproj.filters
@@ -0,0 +1,26 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+ Driver Files
+
+
+
\ No newline at end of file
diff --git a/templates/WinUsbApp/WinUsbApp.sln b/templates/WinUsbApp/WinUsbApp.sln
new file mode 100644
index 000000000..4e1063104
--- /dev/null
+++ b/templates/WinUsbApp/WinUsbApp.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinUsbApp", "WinUsbApp\WinUsbApp.vcxproj", "{6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Debug|ARM.ActiveCfg = Debug|ARM
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Debug|ARM.Build.0 = Debug|ARM
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Debug|ARM64.Build.0 = Debug|ARM64
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Debug|x64.ActiveCfg = Debug|x64
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Debug|x64.Build.0 = Debug|x64
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Debug|x86.ActiveCfg = Debug|Win32
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Debug|x86.Build.0 = Debug|Win32
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Release|ARM.ActiveCfg = Release|ARM
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Release|ARM.Build.0 = Release|ARM
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Release|ARM64.ActiveCfg = Release|ARM64
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Release|ARM64.Build.0 = Release|ARM64
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Release|x64.ActiveCfg = Release|x64
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Release|x64.Build.0 = Release|x64
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Release|x86.ActiveCfg = Release|Win32
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {4C096222-8444-49E4-B0AB-C5B1F6EF86CA}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/WinUsbApp/WinUsbApp/ReadMe.txt b/templates/WinUsbApp/WinUsbApp/ReadMe.txt
new file mode 100644
index 000000000..30da6b54a
--- /dev/null
+++ b/templates/WinUsbApp/WinUsbApp/ReadMe.txt
@@ -0,0 +1,47 @@
+========================================================================
+ WinUsbApp Project Overview
+========================================================================
+
+This file contains a summary of what you will find in each of the files that make up your solution.
+
+WinUsbApp.inf
+ Text file used for WinUSB driver installation. After creating this driver using the template,
+ you *must* update the hardware ID from "USB\VID_vvvv&PID_pppp" to the hardware ID of the USB
+ device that the driver should be installed on.
+
+ When the solution is built, a driver package is generated around the INF, separate from the
+ compiled application. The driver package must be installed in order for the application to find
+ a device.
+
+WinUsbApp.vcxproj
+ This is the main project file for projects generated using an Application Wizard.
+ It contains information about the version of the product that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+WinUsbApp.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+pch.h
+ Header file for project
+
+device.cpp & device.h
+ Basic code to find the WinUSB device, if connected. Defines the device interface GUID for the
+ application to look for (same value as defined in the INF).
+
+main.cpp
+ Simple console application demonstrating finding the device using device.h, and communicating
+ with the device.
+
+/////////////////////////////////////////////////////////////////////////////
+
+Learn more about WinUSB here:
+
+http://msdn.microsoft.com/library/windows/hardware/ff540196.aspx
+http://msdn.microsoft.com/en-us/windows/hardware/gg487341
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/templates/WinUsbApp/WinUsbApp/WinUsbApp.vcxproj b/templates/WinUsbApp/WinUsbApp/WinUsbApp.vcxproj
new file mode 100644
index 000000000..0aa1a8993
--- /dev/null
+++ b/templates/WinUsbApp/WinUsbApp/WinUsbApp.vcxproj
@@ -0,0 +1,249 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {6FB8D1F9-248E-4317-94D3-3BBBF01FD7C2}
+ {b287f7f7-abf3-440d-b608-cb36380f2981}
+ v4.5
+ 12.0
+ Debug
+ Win32
+ WinUsbApp
+
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ true
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+ Windows10
+ false
+ WindowsApplicationForDrivers10.0
+ Application
+ Universal
+ Unicode
+
+
+
+
+
+
+
+
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ sha256
+
+
+ %(AdditionalDependencies);onecoreuap.lib;winusb.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ sha256
+
+
+ %(AdditionalDependencies);onecoreuap.lib;winusb.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ sha256
+
+
+ %(AdditionalDependencies);onecoreuap.lib;winusb.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ sha256
+
+
+ %(AdditionalDependencies);onecoreuap.lib;winusb.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ sha256
+
+
+ %(AdditionalDependencies);onecoreuap.lib;winusb.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ sha256
+
+
+ %(AdditionalDependencies);onecoreuap.lib;winusb.lib
+
+
+
+
+ _DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+
+
+ sha256
+
+
+ %(AdditionalDependencies);onecoreuap.lib;winusb.lib
+
+
+
+
+ WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)
+
+
+ sha256
+
+
+ %(AdditionalDependencies);onecoreuap.lib;winusb.lib
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/WinUsbApp/WinUsbApp/WinUsbApp.vcxproj.filters b/templates/WinUsbApp/WinUsbApp/WinUsbApp.vcxproj.filters
new file mode 100644
index 000000000..763c40aaa
--- /dev/null
+++ b/templates/WinUsbApp/WinUsbApp/WinUsbApp.vcxproj.filters
@@ -0,0 +1,40 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
diff --git a/templates/WinUsbApp/WinUsbApp/device.cpp b/templates/WinUsbApp/WinUsbApp/device.cpp
new file mode 100644
index 000000000..b924eec6d
--- /dev/null
+++ b/templates/WinUsbApp/WinUsbApp/device.cpp
@@ -0,0 +1,235 @@
+#include "pch.h"
+
+#include
+
+HRESULT
+RetrieveDevicePath(
+ _Out_bytecap_(BufLen) LPTSTR DevicePath,
+ _In_ ULONG BufLen,
+ _Out_opt_ PBOOL FailureDeviceNotFound
+ );
+
+HRESULT
+OpenDevice(
+ _Out_ PDEVICE_DATA DeviceData,
+ _Out_opt_ PBOOL FailureDeviceNotFound
+ )
+/*++
+
+Routine description:
+
+ Open all needed handles to interact with the device.
+
+ If the device has multiple USB interfaces, this function grants access to
+ only the first interface.
+
+ If multiple devices have the same device interface GUID, there is no
+ guarantee of which one will be returned.
+
+Arguments:
+
+ DeviceData - Struct filled in by this function. The caller should use the
+ WinusbHandle to interact with the device, and must pass the struct to
+ CloseDevice when finished.
+
+ FailureDeviceNotFound - TRUE when failure is returned due to no devices
+ found with the correct device interface (device not connected, driver
+ not installed, or device is disabled in Device Manager); FALSE
+ otherwise.
+
+Return value:
+
+ HRESULT
+
+--*/
+{
+ HRESULT hr = S_OK;
+ BOOL bResult;
+
+ DeviceData->HandlesOpen = FALSE;
+
+ hr = RetrieveDevicePath(DeviceData->DevicePath,
+ sizeof(DeviceData->DevicePath),
+ FailureDeviceNotFound);
+
+ if (FAILED(hr)) {
+
+ return hr;
+ }
+
+ DeviceData->DeviceHandle = CreateFile(DeviceData->DevicePath,
+ GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (INVALID_HANDLE_VALUE == DeviceData->DeviceHandle) {
+
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ return hr;
+ }
+
+ bResult = WinUsb_Initialize(DeviceData->DeviceHandle,
+ &DeviceData->WinusbHandle);
+
+ if (FALSE == bResult) {
+
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ CloseHandle(DeviceData->DeviceHandle);
+ return hr;
+ }
+
+ DeviceData->HandlesOpen = TRUE;
+ return hr;
+}
+
+VOID
+CloseDevice(
+ _Inout_ PDEVICE_DATA DeviceData
+ )
+/*++
+
+Routine description:
+
+ Perform required cleanup when the device is no longer needed.
+
+ If OpenDevice failed, do nothing.
+
+Arguments:
+
+ DeviceData - Struct filled in by OpenDevice
+
+Return value:
+
+ None
+
+--*/
+{
+ if (FALSE == DeviceData->HandlesOpen) {
+
+ //
+ // Called on an uninitialized DeviceData
+ //
+ return;
+ }
+
+ WinUsb_Free(DeviceData->WinusbHandle);
+ CloseHandle(DeviceData->DeviceHandle);
+ DeviceData->HandlesOpen = FALSE;
+
+ return;
+}
+
+HRESULT
+RetrieveDevicePath(
+ _Out_bytecap_(BufLen) LPTSTR DevicePath,
+ _In_ ULONG BufLen,
+ _Out_opt_ PBOOL FailureDeviceNotFound
+ )
+/*++
+
+Routine description:
+
+ Retrieve the device path that can be used to open the WinUSB-based device.
+
+ If multiple devices have the same device interface GUID, there is no
+ guarantee of which one will be returned.
+
+Arguments:
+
+ DevicePath - On successful return, the path of the device (use with CreateFile).
+
+ BufLen - The size of DevicePath's buffer, in bytes
+
+ FailureDeviceNotFound - TRUE when failure is returned due to no devices
+ found with the correct device interface (device not connected, driver
+ not installed, or device is disabled in Device Manager); FALSE
+ otherwise.
+
+Return value:
+
+ HRESULT
+
+--*/
+{
+ CONFIGRET cr = CR_SUCCESS;
+ HRESULT hr = S_OK;
+ PTSTR DeviceInterfaceList = NULL;
+ ULONG DeviceInterfaceListLength = 0;
+
+ if (NULL != FailureDeviceNotFound) {
+
+ *FailureDeviceNotFound = FALSE;
+ }
+
+ //
+ // Enumerate all devices exposing the interface. Do this in a loop
+ // in case a new interface is discovered while this code is executing,
+ // causing CM_Get_Device_Interface_List to return CR_BUFFER_SMALL.
+ //
+ do {
+ cr = CM_Get_Device_Interface_List_Size(&DeviceInterfaceListLength,
+ (LPGUID)&GUID_DEVINTERFACE_WinUsbApp,
+ NULL,
+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+
+ if (cr != CR_SUCCESS) {
+ hr = HRESULT_FROM_WIN32(CM_MapCrToWin32Err(cr, ERROR_INVALID_DATA));
+ break;
+ }
+
+ DeviceInterfaceList = (PTSTR)HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ DeviceInterfaceListLength * sizeof(TCHAR));
+
+ if (DeviceInterfaceList == NULL) {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+
+ cr = CM_Get_Device_Interface_List((LPGUID)&GUID_DEVINTERFACE_WinUsbApp,
+ NULL,
+ DeviceInterfaceList,
+ DeviceInterfaceListLength,
+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+
+ if (cr != CR_SUCCESS) {
+ HeapFree(GetProcessHeap(), 0, DeviceInterfaceList);
+
+ if (cr != CR_BUFFER_SMALL) {
+ hr = HRESULT_FROM_WIN32(CM_MapCrToWin32Err(cr, ERROR_INVALID_DATA));
+ }
+ }
+ } while (cr == CR_BUFFER_SMALL);
+
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ //
+ // If the interface list is empty, no devices were found.
+ //
+ if (*DeviceInterfaceList == TEXT('\0')) {
+ if (NULL != FailureDeviceNotFound) {
+ *FailureDeviceNotFound = TRUE;
+ }
+
+ hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+ HeapFree(GetProcessHeap(), 0, DeviceInterfaceList);
+ return hr;
+ }
+
+ //
+ // Give path of the first found device interface instance to the caller. CM_Get_Device_Interface_List ensured
+ // the instance is NULL-terminated.
+ //
+ hr = StringCbCopy(DevicePath,
+ BufLen,
+ DeviceInterfaceList);
+
+ HeapFree(GetProcessHeap(), 0, DeviceInterfaceList);
+
+ return hr;
+}
diff --git a/templates/WinUsbApp/WinUsbApp/device.h b/templates/WinUsbApp/WinUsbApp/device.h
new file mode 100644
index 000000000..6ef569027
--- /dev/null
+++ b/templates/WinUsbApp/WinUsbApp/device.h
@@ -0,0 +1,33 @@
+//
+// Define below GUIDs
+//
+#include
+
+//
+// Device Interface GUID.
+// Used by all WinUsb devices that this application talks to.
+// Must match "DeviceInterfaceGUIDs" registry value specified in the INF file.
+// 50bf27a6-dbf4-490f-8d0e-3d1973e50edf
+//
+DEFINE_GUID(GUID_DEVINTERFACE_WinUsbApp,
+ 0x50bf27a6,0xdbf4,0x490f,0x8d,0x0e,0x3d,0x19,0x73,0xe5,0x0e,0xdf);
+
+typedef struct _DEVICE_DATA {
+
+ BOOL HandlesOpen;
+ WINUSB_INTERFACE_HANDLE WinusbHandle;
+ HANDLE DeviceHandle;
+ TCHAR DevicePath[MAX_PATH];
+
+} DEVICE_DATA, *PDEVICE_DATA;
+
+HRESULT
+OpenDevice(
+ _Out_ PDEVICE_DATA DeviceData,
+ _Out_opt_ PBOOL FailureDeviceNotFound
+ );
+
+VOID
+CloseDevice(
+ _Inout_ PDEVICE_DATA DeviceData
+ );
diff --git a/templates/WinUsbApp/WinUsbApp/main.cpp b/templates/WinUsbApp/WinUsbApp/main.cpp
new file mode 100644
index 000000000..fc1fa884e
--- /dev/null
+++ b/templates/WinUsbApp/WinUsbApp/main.cpp
@@ -0,0 +1,78 @@
+#include "pch.h"
+
+#include
+
+LONG __cdecl
+_tmain(
+ LONG Argc,
+ LPTSTR * Argv
+ )
+/*++
+
+Routine description:
+
+ Sample program that communicates with a USB device using WinUSB
+
+--*/
+{
+ DEVICE_DATA deviceData;
+ HRESULT hr;
+ USB_DEVICE_DESCRIPTOR deviceDesc;
+ BOOL bResult;
+ BOOL noDevice;
+ ULONG lengthReceived;
+
+ UNREFERENCED_PARAMETER(Argc);
+ UNREFERENCED_PARAMETER(Argv);
+
+ //
+ // Find a device connected to the system that has WinUSB installed using our
+ // INF
+ //
+ hr = OpenDevice(&deviceData, &noDevice);
+
+ if (FAILED(hr)) {
+
+ if (noDevice) {
+
+ wprintf(L"Device not connected or driver not installed\n");
+
+ } else {
+
+ wprintf(L"Failed looking for device, HRESULT 0x%x\n", hr);
+ }
+
+ return 0;
+ }
+
+ //
+ // Get device descriptor
+ //
+ bResult = WinUsb_GetDescriptor(deviceData.WinusbHandle,
+ USB_DEVICE_DESCRIPTOR_TYPE,
+ 0,
+ 0,
+ (PBYTE) &deviceDesc,
+ sizeof(deviceDesc),
+ &lengthReceived);
+
+ if (FALSE == bResult || lengthReceived != sizeof(deviceDesc)) {
+
+ wprintf(L"Error among LastError %d or lengthReceived %d\n",
+ FALSE == bResult ? GetLastError() : 0,
+ lengthReceived);
+ CloseDevice(&deviceData);
+ return 0;
+ }
+
+ //
+ // Print a few parts of the device descriptor
+ //
+ wprintf(L"Device found: VID_%04X&PID_%04X; bcdUsb %04X\n",
+ deviceDesc.idVendor,
+ deviceDesc.idProduct,
+ deviceDesc.bcdUSB);
+
+ CloseDevice(&deviceData);
+ return 0;
+}
diff --git a/templates/WinUsbApp/WinUsbApp/pch.h b/templates/WinUsbApp/WinUsbApp/pch.h
new file mode 100644
index 000000000..1c9bd9ee4
--- /dev/null
+++ b/templates/WinUsbApp/WinUsbApp/pch.h
@@ -0,0 +1,7 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "device.h"
diff --git a/templates/WinUsbInfPackage/WinUsbInfPackage.sln b/templates/WinUsbInfPackage/WinUsbInfPackage.sln
new file mode 100644
index 000000000..9b3841836
--- /dev/null
+++ b/templates/WinUsbInfPackage/WinUsbInfPackage.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinUsbInfPackage", "WinUsbInfPackage\WinUsbInfPackage.vcxproj", "{BC5EA8BD-782D-4817-AF26-8031ED889994}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Debug|ARM64.Build.0 = Debug|ARM64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Debug|x64.ActiveCfg = Debug|x64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Debug|x64.Build.0 = Debug|x64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Debug|x64.Deploy.0 = Debug|x64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Release|ARM64.ActiveCfg = Release|ARM64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Release|ARM64.Build.0 = Release|ARM64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Release|ARM64.Deploy.0 = Release|ARM64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Release|x64.ActiveCfg = Release|x64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Release|x64.Build.0 = Release|x64
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {05821BBE-45F1-46BE-99BB-A83ED05A4CCA}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/WinUsbInfPackage/WinUsbInfPackage/MyDriver.inf b/templates/WinUsbInfPackage/WinUsbInfPackage/MyDriver.inf
new file mode 100644
index 000000000..c569e6289
Binary files /dev/null and b/templates/WinUsbInfPackage/WinUsbInfPackage/MyDriver.inf differ
diff --git a/templates/WinUsbInfPackage/WinUsbInfPackage/WinUsbInfPackage.vcxproj b/templates/WinUsbInfPackage/WinUsbInfPackage/WinUsbInfPackage.vcxproj
new file mode 100644
index 000000000..91c2d7756
--- /dev/null
+++ b/templates/WinUsbInfPackage/WinUsbInfPackage/WinUsbInfPackage.vcxproj
@@ -0,0 +1,170 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ {BC5EA8BD-782D-4817-AF26-8031ED889994}
+ {a1357fe7-03e0-4d61-85f4-09c7ed38c0c1}
+ v4.5
+ 12.0
+ $driverCurrentWindowsConfigurationName$ Debug
+ Win32
+ WinUsbInfPackage
+
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Utility
+ Package
+ true
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Utility
+ Package
+ true
+
+
+ Windows10
+ true
+ WindowsKernelModeDriver10.0
+ Utility
+ Package
+ true
+
+
+ Windows10
+ false
+ WindowsKernelModeDriver10.0
+ Utility
+ Package
+ true
+
+
+
+
+
+
+
+
+
+
+
+ DbgengRemoteDebugger
+
+
+
+ False
+ False
+ True
+
+ 133563
+
+
+
+ DbgengRemoteDebugger
+
+
+
+ False
+ False
+ True
+
+ 133563
+
+
+
+ DbgengRemoteDebugger
+
+
+
+ False
+ False
+ True
+
+ 133563
+
+
+
+ DbgengRemoteDebugger
+
+
+
+ False
+ False
+ True
+
+ 133563
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR)
+
+
+ sha256
+
+
+
+
+
+
+ $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR)
+
+
+ sha256
+
+
+
+
+
+
+ $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR)
+
+
+ sha256
+
+
+
+
+
+
+ $(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR)
+
+
+ sha256
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/WinUsbInfPackage/WinUsbInfPackage/WinUsbInfPackage.vcxproj.filters b/templates/WinUsbInfPackage/WinUsbInfPackage/WinUsbInfPackage.vcxproj.filters
new file mode 100644
index 000000000..12c957912
--- /dev/null
+++ b/templates/WinUsbInfPackage/WinUsbInfPackage/WinUsbInfPackage.vcxproj.filters
@@ -0,0 +1,14 @@
+
+
+
+
+ {8E41214B-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+ Driver Files
+
+
+
diff --git a/templates/XpsRenderFilter/XpsRenderFilter.sln b/templates/XpsRenderFilter/XpsRenderFilter.sln
new file mode 100644
index 000000000..9fdbcf6ec
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XpsRenderFilter", "XpsRenderFilter\XpsRenderFilter.vcxproj", "{93E3E6CA-632B-4C02-9457-1647C65C7629}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Debug|ARM64.Build.0 = Debug|ARM64
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Debug|x64.ActiveCfg = Debug|x64
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Debug|x64.Build.0 = Debug|x64
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Debug|x86.ActiveCfg = Debug|Win32
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Debug|x86.Build.0 = Debug|Win32
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Release|ARM64.ActiveCfg = Release|ARM64
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Release|ARM64.Build.0 = Release|ARM64
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Release|x64.ActiveCfg = Release|x64
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Release|x64.Build.0 = Release|x64
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Release|x86.ActiveCfg = Release|Win32
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {94FBB1B5-DF3A-4EB8-87F2-40A8508D8100}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/CustomWppCommands.cpp b/templates/XpsRenderFilter/XpsRenderFilter/CustomWppCommands.cpp
new file mode 100644
index 000000000..e09c53884
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/CustomWppCommands.cpp
@@ -0,0 +1,36 @@
+//
+// File Name:
+//
+// CustomWppCommands.cpp
+//
+// Abstract:
+//
+// Custom WPP Tracing functions.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+
+#include "CustomWppCommands.tmh"
+
+namespace XpsRenderFilter
+{
+
+void TraceFailedHRESULT(
+ HRESULT hr,
+ char const *fileName,
+ int lineNum,
+ wchar_t const *extraText
+ )
+{
+ DoTraceMessage(
+ RENDERFILTER_TRACE_ERROR,
+ "Failed HRESULT (%!HRESULT!) at %s:%d (%S)",
+ hr,
+ fileName,
+ lineNum,
+ extraText
+ );
+}
+
+} // namespace XpsRenderFilter
\ No newline at end of file
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/CustomWppCommands.h b/templates/XpsRenderFilter/XpsRenderFilter/CustomWppCommands.h
new file mode 100644
index 000000000..2fa1889f7
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/CustomWppCommands.h
@@ -0,0 +1,45 @@
+//
+// File Name:
+//
+// CustomWppCommands.h
+//
+// Abstract:
+//
+// Custom WPP Tracing function declarations/macro definitions.
+//
+
+#pragma once
+
+namespace XpsRenderFilter
+{
+
+void
+TraceFailedHRESULT(
+ HRESULT hr,
+ char const *fileName,
+ int lineNum,
+ wchar_t const *extraText
+ );
+
+} // namespace XpsRenderFilter
+
+
+#define WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(func_,text_) \
+ { \
+ HRESULT hr_ = func_; \
+ if (FAILED(hr_)) \
+ { \
+ XpsRenderFilter::TraceFailedHRESULT( \
+ hr_, \
+ __FILE__, \
+ __LINE__, \
+ text_ \
+ ); \
+ } \
+ }
+
+#define WPP_LOG_ON_FAILED_HRESULT(func_) \
+ { \
+ WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(func_, L"") \
+ }
+
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/Exception.cpp b/templates/XpsRenderFilter/XpsRenderFilter/Exception.cpp
new file mode 100644
index 000000000..2e9c94fa5
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/Exception.cpp
@@ -0,0 +1,39 @@
+//
+// File Name:
+//
+// Exception.cpp
+//
+// Abstract:
+//
+// Exception routine definitions.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+
+#include "Exception.tmh"
+
+namespace XpsRenderFilter
+{
+
+void ThrowHRException(
+ HRESULT hr,
+ char const *fileName,
+ int lineNum
+ )
+{
+ DoTraceMessage(
+ RENDERFILTER_TRACE_ERROR,
+ L"Throwing HRESULT Exception from %s:%d (HRESULT=%!HRESULT!)",
+ fileName,
+ lineNum,
+ hr
+ );
+
+ throw hr_error(hr);
+}
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/Exception.h b/templates/XpsRenderFilter/XpsRenderFilter/Exception.h
new file mode 100644
index 000000000..e2e06b990
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/Exception.h
@@ -0,0 +1,79 @@
+//
+// File Name:
+//
+// Exception.h
+//
+// Abstract:
+//
+// Exception macro and class declarations.
+//
+
+#pragma once
+//
+// Macro to convert HRESULT into an exception throw
+//
+#ifndef THROW_ON_FAILED_HRESULT
+#define THROW_ON_FAILED_HRESULT(func_) \
+{ \
+ HRESULT hr_ = func_; \
+ if (FAILED(hr_)) { XpsRenderFilter::ThrowHRException(hr_, __FILE__, __LINE__); } \
+}
+#endif // THROW_ON_FAILED_HRESULT
+
+#ifndef THROW_LAST_ERROR
+#define THROW_LAST_ERROR() \
+{ \
+ HRESULT errhr_ = HRESULT_FROM_WIN32(::GetLastError()); \
+ THROW_ON_FAILED_HRESULT(errhr_); \
+}
+#endif // THROW_LAST_ERROR
+
+//
+// Macro to catch various exceptions, including
+// HRESULT-turned-exceptions.
+//
+// Because we have defined USE_NATIVE_EH=1, the
+// catch(...) block will not catch structural
+// exceptions.
+//
+#ifndef CATCH_VARIOUS
+#define CATCH_VARIOUS(hr_) \
+ catch(std::bad_alloc const& ) \
+ { \
+ hr_ = E_OUTOFMEMORY; \
+ } \
+ catch(XpsRenderFilter::hr_error const& e) \
+ { \
+ hr_ = e.hr; \
+ } \
+ catch(std::exception const& ) \
+ { \
+ hr_ = E_FAIL; \
+ } \
+ catch(...) \
+ { \
+ hr_ = E_UNEXPECTED; \
+ }
+#endif // CATCH_VARIOUS
+
+namespace XpsRenderFilter
+{
+
+//
+// HRESULT exception
+//
+struct hr_error
+{
+ HRESULT hr;
+
+ hr_error(HRESULT hr_in) : hr(hr_in)
+ { }
+};
+
+void ThrowHRException(
+ HRESULT hr,
+ char const *fileName,
+ int lineNum
+ );
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/OMConvertor.cpp b/templates/XpsRenderFilter/XpsRenderFilter/OMConvertor.cpp
new file mode 100644
index 000000000..a7aef3f84
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/OMConvertor.cpp
@@ -0,0 +1,766 @@
+//
+// File Name:
+//
+// omconvertor.cpp
+//
+// Abstract:
+//
+// Object model conversion routines. This class provides routines
+// to convert from filter pipeline objects into Xps Object Model
+// objects.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+#include "UnknownBase.h"
+#include "OMConvertor.h"
+
+#include "OMConvertor.tmh"
+
+namespace XpsRenderFilter
+{
+
+//
+//Routine Name:
+//
+// CreateXpsOMPageFromIFixedPage
+//
+//Routine Description:
+//
+// This is the main method called by the filter. It
+// proceeds to call the remaining Create* methods
+// to convert from the print pipeline Object Model
+// to the Xps Object Model.
+//
+// Takes an IFixedPage (print pipeline Object Model)
+// and converts it to an IXpsOMPage (Xps Object Model).
+//
+//Arguments:
+//
+// pPageIn - IFixedPage to convert
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMPage_t (smart pointer)
+// Result IXpsOMPage
+//
+IXpsOMPage_t
+CreateXpsOMPageFromIFixedPage(
+ const IFixedPage_t &pPageIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ //
+ // Get additional page parameters (uri and stream)
+ //
+ IOpcPartUri_t pPartUri;
+ IStream_t pPartStream;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pPageIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pPageIn),
+ pOpcFactory
+ );
+
+ //
+ // Call Xps Object Model to create the page resource
+ //
+ IXpsOMPage_t pPageOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreatePageFromStream(
+ pPartStream,
+ pPartUri,
+ CollectPageResources(pPageIn, pOMFactory, pOpcFactory),
+ FALSE, // Do not reuse objects
+ &pPageOut
+ )
+ );
+
+ return pPageOut;
+}
+
+//
+//Routine Name:
+//
+// CreateImageFromIPartImage
+//
+//Routine Description:
+//
+// Takes an IPartImage (print pipeline Object Model)
+// and converts it to an IXpsOMImageResource (Xps Object Model).
+//
+//Arguments:
+//
+// pImageIn - IPartImage to convert
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMImageResource_t (smart pointer)
+// Result IXpsOMImageResource
+//
+IXpsOMImageResource_t
+CreateImageFromIPartImage(
+ const IPartImage_t &pImageIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ //
+ // Get IPartBase parameters (stream and uri)
+ //
+ IStream_t pPartStream;
+ IOpcPartUri_t pPartUri;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pImageIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pImageIn),
+ pOpcFactory
+ );
+
+ //
+ // Get the image type and convert it to the corresponding enum
+ //
+ BSTR_t strContentType;
+ XPS_IMAGE_TYPE type = XPS_IMAGE_TYPE_WDP;
+
+ THROW_ON_FAILED_HRESULT(
+ pImageIn->GetImageProperties(&strContentType)
+ );
+
+ if (0 == _wcsicmp(strContentType, L"image/jpeg"))
+ {
+ type = XPS_IMAGE_TYPE_JPEG;
+ }
+ else if (0 == _wcsicmp(strContentType, L"image/png"))
+ {
+ type = XPS_IMAGE_TYPE_PNG;
+ }
+ else if (0 == _wcsicmp(strContentType, L"image/tiff"))
+ {
+ type = XPS_IMAGE_TYPE_TIFF;
+ }
+ else if (0 == _wcsicmp(strContentType, L"image/vnd.ms-photo"))
+ {
+ type = XPS_IMAGE_TYPE_WDP;
+ }
+ else
+ {
+ //
+ // unknown content type
+ //
+ THROW_ON_FAILED_HRESULT(E_INVALIDARG);
+ }
+
+ //
+ // Call Xps Object Model to create the image resource
+ //
+ IXpsOMImageResource_t pImageOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreateImageResource(
+ pPartStream,
+ type,
+ pPartUri,
+ &pImageOut
+ )
+ );
+
+ return pImageOut;
+}
+
+//
+//Routine Name:
+//
+// CreateProfileFromIPartColorProfile
+//
+//Routine Description:
+//
+// Takes an IPartColorProfile (print pipeline Object Model)
+// and converts it to an IXpsOMColorProfileResource (Xps Object Model).
+//
+//Arguments:
+//
+// pProfileIn - IPartColorProfile to convert
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMColorProfileResource_t (smart pointer)
+// Result IXpsOMColorProfileResource
+//
+IXpsOMColorProfileResource_t
+CreateProfileFromIPartColorProfile(
+ const IPartColorProfile_t &pProfileIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ //
+ // Get IPartBase parameters (stream and uri)
+ //
+ IStream_t pPartStream;
+ IOpcPartUri_t pPartUri;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pProfileIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pProfileIn),
+ pOpcFactory
+ );
+
+ //
+ // Call Xps Object Model to create the color profile resource
+ //
+ IXpsOMColorProfileResource_t pProfileOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreateColorProfileResource(
+ pPartStream,
+ pPartUri,
+ &pProfileOut
+ )
+ );
+
+ return pProfileOut;
+}
+
+//
+//Routine Name:
+//
+// CreateDictionaryFromIPartResourceDictionary
+//
+//Routine Description:
+//
+// Takes an IPartResourceDictionary (print pipeline Object Model)
+// and converts it to an IXpsOMRemoteDictionaryResource (Xps Object Model).
+//
+//Arguments:
+//
+// pDictionaryIn - IPartResourceDictionary to convert
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+// pResources - The resources of the fixed page
+//
+//Return Value:
+//
+// IXpsOMRemoteDictionaryResource_t (smart pointer)
+// Result IXpsOMRemoteDictionaryResource
+//
+IXpsOMRemoteDictionaryResource_t
+CreateDictionaryFromIPartResourceDictionary(
+ const IPartResourceDictionary_t &pDictionaryIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory,
+ const IXpsOMPartResources_t &pResources
+ )
+{
+ //
+ // Get IPartBase parameters (stream and uri)
+ //
+ IStream_t pPartStream;
+ IOpcPartUri_t pPartUri;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pDictionaryIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pDictionaryIn),
+ pOpcFactory
+ );
+
+ //
+ // Call Xps Object Model to create the remote dictionary resource
+ //
+ IXpsOMRemoteDictionaryResource_t pDictionaryOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreateRemoteDictionaryResourceFromStream(
+ pPartStream,
+ pPartUri,
+ pResources,
+ &pDictionaryOut)
+ );
+
+ return pDictionaryOut;
+}
+
+//
+//Routine Name:
+//
+// CreateFontFromIPartFont
+//
+//Routine Description:
+//
+// Takes an IPartFont (print pipeline Object Model)
+// and converts it to an IXpsOMFontResource (Xps Object Model).
+//
+//Arguments:
+//
+// pFontIn - IPartFont to convert
+// pFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMFontResource_t (smart pointer)
+// Result IXpsOMFontResource
+//
+IXpsOMFontResource_t
+CreateFontFromIPartFont(
+ const IPartFont_t &pFontIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ //
+ // Get IPartBase parameters (stream and uri)
+ //
+ IStream_t pPartStream;
+ IOpcPartUri_t pPartUri;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pFontIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pFontIn),
+ pOpcFactory
+ );
+
+ //
+ // Get the font restriction
+ //
+ EXpsFontRestriction eFontRestriction = Xps_Restricted_Font_Installable;
+
+ {
+ IPartFont2_t pFont2In;
+
+ if (SUCCEEDED(pFontIn->QueryInterface(__uuidof(IPartFont2), reinterpret_cast(&pFont2In))))
+ {
+ pFont2In->GetFontRestriction(&eFontRestriction);
+ }
+ }
+
+ //
+ // Get the font obfuscation
+ //
+ EXpsFontOptions eFontOptions;
+
+ {
+ BSTR_t contentType;
+
+ THROW_ON_FAILED_HRESULT(
+ pFontIn->GetFontProperties(&contentType, &eFontOptions)
+ );
+ }
+
+ //
+ // It is necessary to combine the obfuscation and restriction
+ // attributes from the print pipeline into the one parameter that
+ // the Xps Object Model consumes.
+ //
+
+ XPS_FONT_EMBEDDING omEmbedding;
+
+ if (eFontOptions == Font_Normal)
+ {
+ omEmbedding = XPS_FONT_EMBEDDING_NORMAL;
+ }
+ else if (eFontOptions == Font_Obfusticate &&
+ (eFontRestriction &
+ (Xps_Restricted_Font_PreviewPrint |
+ Xps_Restricted_Font_NoEmbedding)))
+ {
+ //
+ // If the font is obfuscated, and either the PreviewPrint or
+ // NoEmbedding restriction flags are set, then create a
+ // Restricted font
+ //
+ omEmbedding = XPS_FONT_EMBEDDING_RESTRICTED;
+ }
+ else
+ {
+ omEmbedding = XPS_FONT_EMBEDDING_OBFUSCATED;
+ }
+
+ //
+ // Call Xps Object Model to create the font resource
+ //
+ IXpsOMFontResource_t pFontOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreateFontResource(
+ pPartStream,
+ omEmbedding,
+ pPartUri,
+ FALSE, // fonts received from the pipeline are already de-obfuscated
+ &pFontOut
+ )
+ );
+
+ return pFontOut;
+}
+
+//
+//Routine Name:
+//
+// CollectPageResources
+//
+//Routine Description:
+//
+// Iterates over all of the resources related to
+// a fixed page and adds them to a resource
+// collection.
+//
+//Arguments:
+//
+// pPage - The page to query for resources
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMPartResources_t (smart pointer)
+// The resource collection of all of the resources of the page
+//
+IXpsOMPartResources_t
+CollectPageResources(
+ const IFixedPage_t &pPage,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ IXpsOMPartResources_t pResources;
+
+ IXpsOMFontResourceCollection_t pFonts;
+ IXpsOMImageResourceCollection_t pImages;
+ IXpsOMColorProfileResourceCollection_t pProfiles;
+ IXpsOMRemoteDictionaryResourceCollection_t pDictionaries;
+
+ //
+ // collection of resource dictionaries saved for later processing.
+ //
+ ResourceDictionaryList_t dictionaryList;
+
+ //
+ // Create the resource collection and get all of the
+ // resource-specific sub-collections.
+ //
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreatePartResources(&pResources)
+ );
+ THROW_ON_FAILED_HRESULT(
+ pResources->GetFontResources(&pFonts)
+ );
+ THROW_ON_FAILED_HRESULT(
+ pResources->GetImageResources(&pImages)
+ );
+ THROW_ON_FAILED_HRESULT(
+ pResources->GetColorProfileResources(&pProfiles)
+ );
+ THROW_ON_FAILED_HRESULT(
+ pResources->GetRemoteDictionaryResources(&pDictionaries)
+ );
+ //
+ // Get the XpsPartIterator and iterate through all of the parts
+ // related to this fixed page.
+ //
+ IXpsPartIterator_t itPart;
+
+ THROW_ON_FAILED_HRESULT(
+ pPage->GetXpsPartIterator(&itPart)
+ );
+
+ for (; !itPart->IsDone(); itPart->Next())
+ {
+ BSTR_t uri;
+ IUnknown_t pUnkPart;
+
+ THROW_ON_FAILED_HRESULT(
+ itPart->Current(&uri, &pUnkPart)
+ );
+
+ IPartFont_t pFontPart;
+ IPartImage_t pImagePart;
+ IPartColorProfile_t pProfilePart;
+ IPartResourceDictionary_t pDictionaryPart;
+
+ if (SUCCEEDED(pUnkPart.QueryInterface(&pFontPart)))
+ {
+ //
+ // Convert the font part to Xps Object Model and add it to the
+ // font resource collection
+ //
+ THROW_ON_FAILED_HRESULT(
+ pFonts->Append(
+ CreateFontFromIPartFont(
+ pFontPart,
+ pOMFactory,
+ pOpcFactory
+ )
+ )
+ );
+ }
+ else if (SUCCEEDED(pUnkPart.QueryInterface(&pImagePart)))
+ {
+ //
+ // Convert the image part to Xps Object Model and add it to the
+ // image resource collection
+ //
+ THROW_ON_FAILED_HRESULT(
+ pImages->Append(
+ CreateImageFromIPartImage(
+ pImagePart,
+ pOMFactory,
+ pOpcFactory
+ )
+ )
+ );
+ }
+ else if (SUCCEEDED(pUnkPart.QueryInterface(&pProfilePart)))
+ {
+ //
+ // Convert the color profile part to Xps Object Model and add it
+ // to the color profile resource collection
+ //
+ THROW_ON_FAILED_HRESULT(
+ pProfiles->Append(
+ CreateProfileFromIPartColorProfile(
+ pProfilePart,
+ pOMFactory,
+ pOpcFactory
+ )
+ )
+ );
+ }
+ else if (SUCCEEDED(pUnkPart.QueryInterface(&pDictionaryPart)))
+ {
+ //
+ // In order to process the remote resource dictionary, all of
+ // its linked resources must be present in pResources. To ensure
+ // this, we delay the conversion of the remote resource
+ // dictionaries until all of the other resources have been converted.
+ //
+ dictionaryList.push_back(pDictionaryPart);
+ }
+ else
+ {
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Unhandled Page Resource");
+ }
+ }
+
+ for (ResourceDictionaryList_t::const_iterator it = dictionaryList.begin();
+ it != dictionaryList.end();
+ ++it)
+ {
+ //
+ // Convert the remote dictionary to Xps Object Model and add it
+ // to the remote dictionary collection
+ //
+ THROW_ON_FAILED_HRESULT(
+ pDictionaries->Append(
+ CreateDictionaryFromIPartResourceDictionary(
+ *it,
+ pOMFactory,
+ pOpcFactory,
+ pResources
+ )
+ )
+ );
+ }
+
+ return pResources;
+}
+
+//
+//Routine Name:
+//
+// GetStreamFromPart
+//
+//Routine Description:
+//
+// Gets the IStream from this part.
+//
+//Arguments:
+//
+// pPart - An Xps Part
+//
+//Return Value:
+//
+// IStream_t (smart pointer)
+// The stream of the part's content
+//
+IStream_t
+GetStreamFromPart(
+ const IPartBase_t &pPart
+ )
+{
+ //
+ // Get the IPrintReadStream for the part from the pipeline Object Model
+ //
+ IPrintReadStream_t pStream;
+ THROW_ON_FAILED_HRESULT(
+ pPart->GetStream(&pStream)
+ );
+
+ return CreateIStreamFromIPrintReadStream(pStream);
+}
+
+//
+//Routine Name:
+//
+// CreateIStreamFromIPrintReadStream
+//
+//Routine Description:
+//
+// Creates an IStream from an IPrintReadStream.
+//
+//Arguments:
+//
+// pReadStream - A Print Pipeline IPrintReadStream
+//
+//Return Value:
+//
+// IStream_t (smart pointer)
+// A stream with the same content as the argument stream.
+//
+IStream_t
+CreateIStreamFromIPrintReadStream(
+ const IPrintReadStream_t &pReadStream
+ )
+{
+ //
+ // Get the size of the stream
+ //
+ ULONGLONG tmpPos;
+ size_t partSize;
+
+ THROW_ON_FAILED_HRESULT(
+ pReadStream->Seek(0, SEEK_END, &tmpPos)
+ );
+
+ //
+ // GlobalAlloc can only allocate size_t bytes, so
+ // throw if the part is larger than that
+ //
+ THROW_ON_FAILED_HRESULT(
+ ULongLongToSizeT(tmpPos, &partSize)
+ );
+
+ THROW_ON_FAILED_HRESULT(
+ pReadStream->Seek(0, SEEK_SET, &tmpPos)
+ );
+
+ //
+ // Allocate an HGLOBAL for the part cache
+ //
+ SafeHGlobal_t pHBuf(
+ new SafeHGlobal(GMEM_FIXED, partSize)
+ );
+
+ //
+ // Read the part into the cache
+ //
+ {
+ //
+ // Lock the HGLOBAL and get the address of the buffer
+ // from the RAII lock object
+ //
+ HGlobalLock_t lock = pHBuf->Lock();
+ BYTE *pBuffer = lock->GetAddress();
+
+ //
+ // Allow the number of bytes to read to be clipped to max ULONG
+ // and then spin on fEOF until the stream is exhausted
+ //
+ ULONG numToRead;
+
+ if (FAILED(SizeTToULong(partSize, &numToRead)))
+ {
+ numToRead = MAXUINT;
+ }
+
+ BOOL fEOF;
+ ULONG numRead;
+ size_t pos = 0;
+
+ //
+ // Iterate until all bytes from the stream
+ // have been read into the buffer
+ //
+ do
+ {
+ THROW_ON_FAILED_HRESULT(
+ pReadStream->ReadBytes(pBuffer + pos, numToRead, &numRead, &fEOF)
+ );
+
+ pos += numRead;
+ } while (!fEOF && numRead);
+ }
+
+ //
+ // Create an IStream from the part cache
+ //
+ IStream_t pIStream = pHBuf->ConvertToIStream();
+
+ LARGE_INTEGER zero = {0};
+ THROW_ON_FAILED_HRESULT(
+ pIStream->Seek(zero, SEEK_SET, NULL)
+ );
+
+ return pIStream;
+}
+
+//
+//Routine Name:
+//
+// CreateOpcPartUriFromPart
+//
+//Routine Description:
+//
+// Gets the Opc Uri from the Xps Part.
+//
+//Arguments:
+//
+// pPart - An Xps Part
+// pFactory - Opc Factory
+//
+//Return Value:
+//
+// IOpcPartUri_t (smart pointer)
+// The Uri of the part
+//
+IOpcPartUri_t
+CreateOpcPartUriFromPart(
+ const IPartBase_t &pPart,
+ const IOpcFactory_t &pFactory
+ )
+{
+ BSTR_t strPartUri;
+
+ THROW_ON_FAILED_HRESULT(
+ pPart->GetUri(&strPartUri)
+ );
+
+ IOpcPartUri_t pPartUri;
+ THROW_ON_FAILED_HRESULT(
+ pFactory->CreatePartUri(strPartUri, &pPartUri)
+ );
+ return pPartUri;
+}
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/OMConvertor.h b/templates/XpsRenderFilter/XpsRenderFilter/OMConvertor.h
new file mode 100644
index 000000000..0a8c94940
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/OMConvertor.h
@@ -0,0 +1,84 @@
+//
+// File Name:
+//
+// omconvertor.h
+//
+// Abstract:
+//
+// Object model conversion routines.
+//
+
+#pragma once
+
+namespace XpsRenderFilter
+{
+
+//
+// Top-level Create Page routine
+//
+IXpsOMPage_t
+CreateXpsOMPageFromIFixedPage(
+ const IFixedPage_t &pPageIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+//
+// Individual Part conversion routines
+//
+IXpsOMImageResource_t
+CreateImageFromIPartImage(
+ const IPartImage_t &pImageIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+IXpsOMColorProfileResource_t
+CreateProfileFromIPartColorProfile(
+ const IPartColorProfile_t &pProfileIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+IXpsOMRemoteDictionaryResource_t
+CreateDictionaryFromIPartResourceDictionary(
+ const IPartResourceDictionary_t &pDictionaryIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory,
+ const IXpsOMPartResources_t &pResources
+ );
+
+IXpsOMFontResource_t
+CreateFontFromIPartFont(
+ const IPartFont_t &pFontIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+//
+// Utility Routines
+//
+IStream_t
+GetStreamFromPart(
+ const IPartBase_t &pPart
+ );
+
+IOpcPartUri_t
+CreateOpcPartUriFromPart(
+ const IPartBase_t &pPart,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+IXpsOMPartResources_t
+CollectPageResources(
+ const IFixedPage_t &pPage,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+IStream_t
+CreateIStreamFromIPrintReadStream(
+ const IPrintReadStream_t &pReadStream
+ );
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/PThandler.cpp b/templates/XpsRenderFilter/XpsRenderFilter/PThandler.cpp
new file mode 100644
index 000000000..230e13c52
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/PThandler.cpp
@@ -0,0 +1,379 @@
+//
+// File Name:
+//
+// PThandler.cpp
+//
+// Abstract:
+//
+// Print Ticket Handler class definition.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+#include "UnknownBase.h"
+#include "OMConvertor.h"
+#include "RenderFilter.h"
+#include "PTHandler.h"
+
+#include "PThandler.tmh"
+
+namespace XpsRenderFilter
+{
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::CreatePrintTicketHandler
+//
+//Routine Description:
+//
+// Static factory method that creates an instance of
+// PrintTicketHandler.
+//
+//Arguments:
+//
+// pPropertyBag - Property Bag
+//
+//Return Value:
+//
+// PrintTicketHandler_t (smart ptr)
+// The new PrintTicketHandler.
+//
+PrintTicketHandler_t
+PrintTicketHandler::CreatePrintTicketHandler(
+ const IPrintPipelinePropertyBag_t &pPropertyBag
+ )
+{
+ //
+ // Create MSXML DOM document
+ //
+ IXMLDOMDocument2_t pDOMDoc;
+
+ THROW_ON_FAILED_HRESULT(
+ ::CoCreateInstance(
+ __uuidof(DOMDocument60),
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IXMLDOMDocument2),
+ reinterpret_cast(&pDOMDoc)
+ )
+ );
+
+ //
+ // Get the default user Print Ticket Stream Factory
+ //
+ Variant_t varUserPrintTicket;
+ THROW_ON_FAILED_HRESULT(
+ pPropertyBag->GetProperty(
+ XPS_FP_USER_PRINT_TICKET,
+ &varUserPrintTicket
+ )
+ );
+ IUnknown_t pUnk = varUserPrintTicket.punkVal;
+
+ IPrintReadStreamFactory_t pStreamFactory;
+
+ THROW_ON_FAILED_HRESULT(
+ pUnk.QueryInterface(&pStreamFactory)
+ );
+
+ //
+ // Get the default user Print Ticket stream
+ // and wrap it in an IStream
+ //
+
+ IPrintReadStream_t pUserPrintTicketStream;
+
+ THROW_ON_FAILED_HRESULT(
+ pStreamFactory->GetStream(&pUserPrintTicketStream)
+ );
+
+ IStream_t pUserPrintTicket =
+ CreateIStreamFromIPrintReadStream(pUserPrintTicketStream);
+
+ //
+ // Get the Printer Name
+ //
+ Variant_t varPrinterName;
+ THROW_ON_FAILED_HRESULT(
+ pPropertyBag->GetProperty(
+ XPS_FP_PRINTER_NAME,
+ &varPrinterName
+ )
+ );
+
+ BSTR_t pPrinterName(varPrinterName.bstrVal);
+
+ //
+ // Get the User Security Token
+ // Avoid CComVariant if getting the XPS_FP_USER_TOKEN property.
+ // Please refer to http://go.microsoft.com/fwlink/?LinkID=255534 for detailed information.
+ //
+ SafeVariant varUserSecurityToken;
+ THROW_ON_FAILED_HRESULT(
+ pPropertyBag->GetProperty(
+ XPS_FP_USER_TOKEN,
+ &varUserSecurityToken
+ )
+ );
+
+ //
+ // Open the Print Ticket Provider
+ //
+ SafeHPTProvider_t pHProvider(
+ new SafeHPTProvider(
+ pPrinterName,
+ varUserSecurityToken.byref
+ )
+ );
+
+ PrintTicketHandler_t toReturn(
+ new PrintTicketHandler(
+ pDOMDoc,
+ pHProvider,
+ pUserPrintTicket
+ )
+ );
+
+ return toReturn;
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::PrintTicketHandler
+//
+//Routine Description:
+//
+// Constructor for the Print Ticket Handler.
+//
+//Arguments:
+//
+// pDoc - initialized MSXML DOM document
+// pHProvider - handle to the Print Ticket Provider
+//
+PrintTicketHandler::PrintTicketHandler(
+ const IXMLDOMDocument2_t &pDoc,
+ SafeHPTProvider_t pHProvider,
+ const IStream_t &pUserPrintTicket
+ ) : m_pDOMDoc(pDoc),
+ m_pHProvider(pHProvider),
+ m_pDefaultUserPrintTicket(pUserPrintTicket)
+{
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::ProcessPrintTicket
+//
+//Routine Description:
+//
+// Gets the print ticket from the part, merges with
+// the base ticket, and returns the result.
+//
+//Arguments:
+//
+// pBasePrintTicket - Base Print Ticket
+// pDeltaPrintTicketPart - Delta Print Pipeline Print Ticket Part
+// scope - Scope of the merged Print Ticket
+//
+//Return Value:
+//
+// IStream_t (smart pointer)
+// Merged stream
+//
+IStream_t
+PrintTicketHandler::ProcessPrintTicket(
+ const IStream_t &pBasePrintTicket,
+ const IPartPrintTicket_t &pDeltaPrintTicketPart,
+ EPrintTicketScope scope
+ )
+{
+ IStream_t pMergedPrintTicket;
+ IStream_t pDeltaPrintTicket;
+
+ pDeltaPrintTicket = GetStreamFromPart(
+ static_cast(pDeltaPrintTicketPart)
+ );
+
+ //
+ // Before calling PTMergeAndValidatePrintTicket, both input
+ // Print Ticket streams MUST be at position 0. The temp Print
+ // Ticket stream is already at position 0, but the Base Print
+ // Ticket may not be. Seek it to 0 to be sure.
+ //
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+ THROW_ON_FAILED_HRESULT(
+ pBasePrintTicket->Seek(zero, SEEK_SET, NULL)
+ );
+
+ //
+ // Merge the delta Print Ticket with the
+ // base Print Ticket
+ //
+ THROW_ON_FAILED_HRESULT(
+ ::CreateStreamOnHGlobal(
+ NULL,
+ TRUE, // delete on release
+ &pMergedPrintTicket
+ )
+ );
+
+ m_pHProvider->PTMergeAndValidatePrintTicket(
+ pBasePrintTicket,
+ pDeltaPrintTicket,
+ scope,
+ pMergedPrintTicket
+ );
+
+ return pMergedPrintTicket;
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::ProcessPart
+//
+//Routine Description:
+//
+// Merges the Fixed Document Sequence Print Ticket with
+// the default user Print Ticket and caches the result.
+//
+//Arguments:
+//
+// pFDS - Fixed Document Sequence part
+//
+void
+PrintTicketHandler::ProcessPart(
+ const IFixedDocumentSequence_t &pFDS
+ )
+{
+ IPartPrintTicket_t pPrintTicket;
+
+ HRESULT hr = pFDS->GetPrintTicket(&pPrintTicket);
+
+ //
+ // E_ELEMENT_NOT_FOUND means that this Fixed Document Sequence
+ // does not have a Print Ticket. Propagate the Default User
+ // Print Ticket.
+ // All other failed HRESULTs should be thrown.
+ //
+ if (hr == E_ELEMENT_NOT_FOUND)
+ {
+ m_pJobPrintTicket = m_pDefaultUserPrintTicket;
+ return;
+ }
+
+ THROW_ON_FAILED_HRESULT(hr);
+
+ m_pDocumentPrintTicket = NULL;
+ m_pPagePrintTicket = NULL;
+
+ m_pJobPrintTicket = ProcessPrintTicket(
+ m_pDefaultUserPrintTicket,
+ pPrintTicket,
+ kPTJobScope
+ );
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::ProcessPart
+//
+//Routine Description:
+//
+// Merges the Fixed Document Print Ticket with the
+// Fixed Document Sequence Print Ticket and caches
+// the result. The tickets are merged at the Document
+// scope, so the result contains no job-level features.
+//
+//Arguments:
+//
+// pFD - Fixed Document part
+//
+void
+PrintTicketHandler::ProcessPart(
+ const IFixedDocument_t &pFD
+ )
+{
+ IPartPrintTicket_t pPrintTicket;
+
+ HRESULT hr = pFD->GetPrintTicket(&pPrintTicket);
+
+ //
+ // E_ELEMENT_NOT_FOUND means that this Fixed Document
+ // does not have a Print Ticket. Propagate the Job
+ // Print Ticket.
+ // All other failed HRESULTs should be thrown.
+ //
+ if (hr == E_ELEMENT_NOT_FOUND)
+ {
+ m_pDocumentPrintTicket = m_pJobPrintTicket;
+ return;
+ }
+
+ THROW_ON_FAILED_HRESULT(hr);
+
+ m_pPagePrintTicket = NULL;
+
+ m_pDocumentPrintTicket = ProcessPrintTicket(
+ m_pJobPrintTicket,
+ pPrintTicket,
+ kPTDocumentScope
+ );
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::ProcessPart
+//
+//Routine Description:
+//
+// Merges the Fixed Page Print Ticket with the
+// Fixed Document Print Ticket and caches the result.
+// The tickets are merged at the Page scope, so the
+// result contains no job-level or document-level features.
+//
+//Arguments:
+//
+// pFP - Fixed Page part
+//
+void
+PrintTicketHandler::ProcessPart(
+ const IFixedPage_t &pFP
+ )
+{
+ IPartPrintTicket_t pPrintTicket;
+
+ HRESULT hr = pFP->GetPrintTicket(&pPrintTicket);
+
+ //
+ // E_ELEMENT_NOT_FOUND means that this Fixed Page
+ // does not have a Print Ticket. Propagate the Document
+ // Print Ticket.
+ // All other failed HRESULTs should be thrown.
+ //
+ if (hr == E_ELEMENT_NOT_FOUND)
+ {
+ m_pPagePrintTicket = m_pDocumentPrintTicket;
+ return;
+ }
+
+ THROW_ON_FAILED_HRESULT(hr);
+
+ m_pPagePrintTicket = ProcessPrintTicket(
+ m_pDocumentPrintTicket,
+ pPrintTicket,
+ kPTPageScope
+ );
+}
+
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/PThandler.h b/templates/XpsRenderFilter/XpsRenderFilter/PThandler.h
new file mode 100644
index 000000000..ad480ff23
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/PThandler.h
@@ -0,0 +1,92 @@
+//
+// File Name:
+//
+// PThandler.h
+//
+// Abstract:
+//
+// Print Ticket Handler class declaration.
+//
+
+#pragma once
+
+namespace XpsRenderFilter
+{
+
+class PrintTicketHandler
+{
+public:
+ static
+ PrintTicketHandler_t
+ CreatePrintTicketHandler(
+ const IPrintPipelinePropertyBag_t &pPropertyBag
+ );
+
+ void
+ ProcessPart(
+ const IFixedDocumentSequence_t &pFDS
+ );
+
+ void
+ ProcessPart(
+ const IFixedDocument_t &pFD
+ );
+
+ void
+ ProcessPart(
+ const IFixedPage_t &pFP
+ );
+
+private:
+ //
+ // Constructor is private; use CreatePrintTicketHandler
+ // to create instances.
+ //
+ PrintTicketHandler(
+ const IXMLDOMDocument2_t &pDoc,
+ SafeHPTProvider_t pHProvider,
+ const IStream_t &pUserPrintTicket
+ );
+
+ IStream_t
+ ProcessPrintTicket(
+ const IStream_t &pBasePrintTicket,
+ const IPartPrintTicket_t &pDeltaPrintTicketPart,
+ EPrintTicketScope scope
+ );
+
+ //
+ // Inline function to convert from microns to Xps Units
+ //
+ inline
+ FLOAT
+ MicronsToXpsUnits(
+ long dimensionInMicrons
+ )
+ {
+ const FLOAT xpsDPI = 96.0f;
+ const FLOAT micronsPerInch = 25400.0f; // 2.54 cm/in --> 25400 um/in
+
+ return ((static_cast(dimensionInMicrons) / micronsPerInch) * xpsDPI);
+ }
+
+ //
+ // MSXML DOM document
+ //
+ IXMLDOMDocument2_t m_pDOMDoc;
+
+ //
+ // Handle to the Print Ticket Provider
+ //
+ SafeHPTProvider_t m_pHProvider;
+
+ //
+ // Cached Print Tickets
+ //
+ IStream_t m_pDefaultUserPrintTicket;
+ IStream_t m_pJobPrintTicket;
+ IStream_t m_pDocumentPrintTicket;
+ IStream_t m_pPagePrintTicket;
+};
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.cpp b/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.cpp
new file mode 100644
index 000000000..b852d3778
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.cpp
@@ -0,0 +1,365 @@
+//
+// File Name:
+//
+// RenderFilter.cpp
+//
+// Abstract:
+//
+// XPS Rendering filter implementation.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+#include "UnknownBase.h"
+#include "OMConvertor.h"
+#include "PThandler.h"
+#include "RenderFilter.h"
+
+#include "RenderFilter.tmh"
+
+namespace XpsRenderFilter
+{
+
+long RenderFilter::ms_numObjects = 0; // Initialize static object count
+
+//
+//Routine Name:
+//
+// RenderFilter::RenderFilter
+//
+//Routine Description:
+//
+// XPS Rendering filter default constructor.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// None
+//
+RenderFilter::RenderFilter()
+{
+ //
+ // Take ownership with no AddRef
+ //
+ m_pLiveness.Attach(new FilterLiveness());
+
+ ::InterlockedIncrement(&ms_numObjects);
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::~RenderFilter
+//
+//Routine Description:
+//
+// XPS Rendering sample filter destructor.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// None
+//
+RenderFilter::~RenderFilter()
+{
+ ::InterlockedDecrement(&ms_numObjects);
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::InitializeFilter
+//
+//Routine Description:
+//
+// Exception boundary wrapper for IPrintPipelineFilter initialization.
+//
+//Arguments:
+//
+// pICommunicator - interface to interfilter communicator
+// pIPropertyBag - interface to pipeline property bag
+// pIPipelineControl - interface to pipeline control methods
+//
+//Return Value:
+//
+// ULONG
+// New reference count
+//
+_Check_return_
+HRESULT STDMETHODCALLTYPE
+RenderFilter::InitializeFilter(
+ _In_ IInterFilterCommunicator *pICommunicator,
+ _In_ IPrintPipelinePropertyBag *pIPropertyBag,
+ _In_ IPrintPipelineManagerControl *pIPipelineControl
+ )
+{
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Initializing Filter");
+
+ if (pICommunicator == NULL ||
+ pIPropertyBag == NULL ||
+ pIPipelineControl == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_POINTER);
+
+ return E_POINTER;
+ }
+
+ HRESULT hr = S_OK;
+
+ try
+ {
+ InitializeFilter_throws(
+ pICommunicator,
+ pIPropertyBag
+ );
+ }
+ CATCH_VARIOUS(hr);
+
+ return hr;
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::InitializeFilter_throws
+//
+//Routine Description:
+//
+// Implements IPrintPipelineFilter initialization. Gets
+// all necessary communication interfaces.
+//
+//Arguments:
+//
+// pICommunicator - interface to interfilter communicator
+// pIPropertyBag - interface to pipeline property bag
+//
+VOID
+RenderFilter::InitializeFilter_throws(
+ const IInterFilterCommunicator_t &pICommunicator,
+ const IPrintPipelinePropertyBag_t &pIPropertyBag
+ )
+{
+ //
+ // Get the pipeline communication interfaces
+ //
+ THROW_ON_FAILED_HRESULT(
+ pICommunicator->RequestReader(reinterpret_cast(&m_pReader))
+ );
+ THROW_ON_FAILED_HRESULT(
+ pICommunicator->RequestWriter(reinterpret_cast(&m_pWriter))
+ );
+
+ {
+ //
+ // Check to ensure that the provided interfaces are as expected.
+ // That is, that the GUIDs were correctly listed in the
+ // pipeline configuration file
+ //
+ IXpsDocumentProvider_t pReaderCheck;
+ IPrintWriteStream_t pWriterCheck;
+
+ THROW_ON_FAILED_HRESULT(
+ m_pReader.QueryInterface(&pReaderCheck)
+ );
+ THROW_ON_FAILED_HRESULT(
+ m_pWriter.QueryInterface(&pWriterCheck)
+ );
+ }
+
+ //
+ // Save a pointer to the Property Bag for further
+ // initialization, later.
+ //
+ m_pIPropertyBag = pIPropertyBag;
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::ShutdownOperation
+//
+//Routine Description:
+//
+// Called asynchronously by the pipeline manager
+// to shutdown filter operation.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - On success
+//
+_Check_return_
+HRESULT
+RenderFilter::ShutdownOperation()
+{
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Shutting Down Operation");
+ m_pLiveness->Cancel();
+ return S_OK;
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::StartOperation
+//
+//Routine Description:
+//
+// Called by the pipeline manager to start processing
+// a document. Exception boundary for page processing.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - On success
+// Otherwise - Failure
+//
+_Check_return_
+HRESULT
+RenderFilter::StartOperation()
+{
+ HRESULT hr = S_OK;
+
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Starting Operation");
+
+ //
+ // Process the Xps Package
+ //
+ try {
+ StartOperation_throws();
+ }
+ CATCH_VARIOUS(hr);
+
+ m_pWriter->Close();
+
+ return hr;
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::StartOperation_throws
+//
+//Routine Description:
+//
+// Iterates over the 'trunk' parts of the document
+// and calls appropriate processing methods.
+//
+//Arguments:
+//
+// None
+//
+void
+RenderFilter::StartOperation_throws()
+{
+ //
+ // CoInitialize/CoUninitialize RAII object.
+ // COM is inititalized for the lifetime of this method.
+ //
+ SafeCoInit coInit;
+
+ IXpsOMObjectFactory_t pOMFactory;
+
+ //
+ // Create Xps Object Model Object Factory instance
+ //
+ THROW_ON_FAILED_HRESULT(
+ ::CoCreateInstance(
+ __uuidof(XpsOMObjectFactory),
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IXpsOMObjectFactory),
+ reinterpret_cast(&pOMFactory)
+ )
+ );
+
+ IOpcFactory_t pOpcFactory;
+
+ //
+ // Create Opc Object Factory instance
+ //
+ THROW_ON_FAILED_HRESULT(
+ ::CoCreateInstance(
+ __uuidof(OpcFactory),
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IOpcFactory),
+ reinterpret_cast(&pOpcFactory)
+ )
+ );
+
+
+ //
+ // Create the Print Ticket Handler
+ //
+ PrintTicketHandler_t pPrintTicketHandler =
+ PrintTicketHandler::CreatePrintTicketHandler(
+ m_pIPropertyBag
+ );
+
+ IUnknown_t pUnk;
+
+ //
+ // Get first part
+ //
+ THROW_ON_FAILED_HRESULT(m_pReader->GetXpsPart(&pUnk));
+
+ while (m_pLiveness->IsAlive() &&
+ pUnk != NULL)
+ {
+ IXpsDocument_t pDoc;
+ IFixedDocumentSequence_t pFDS;
+ IFixedDocument_t pFD;
+ IFixedPage_t pFP;
+
+ if (SUCCEEDED(pUnk.QueryInterface(&pFP)))
+ {
+ DoTraceMessage(RENDERFILTER_TRACE_VERBOSE, L"Handling a Page");
+
+ pPrintTicketHandler->ProcessPart(pFP);
+ }
+ else if (SUCCEEDED(pUnk.QueryInterface(&pFD)))
+ {
+ pPrintTicketHandler->ProcessPart(pFD);
+ }
+ else if (SUCCEEDED(pUnk.QueryInterface(&pFDS)))
+ {
+ pPrintTicketHandler->ProcessPart(pFDS);
+ }
+ else if (SUCCEEDED(pUnk.QueryInterface(&pDoc)))
+ {
+ //
+ // Do nothing with the XML Document part
+ //
+ }
+ else
+ {
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Unhandled Document Part");
+ }
+
+ pUnk.Release();
+
+ //
+ // Get Next Part
+ //
+ THROW_ON_FAILED_HRESULT(m_pReader->GetXpsPart(&pUnk));
+ }
+}
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.def b/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.def
new file mode 100644
index 000000000..52b0c434b
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.def
@@ -0,0 +1,15 @@
+;
+; File Name:
+;
+; RenderFilter.def
+;
+; Abstract:
+;
+; Defines DLL exports for XpsRenderFilter.dll
+;
+
+LIBRARY XpsRenderFilter
+
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.h b/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.h
new file mode 100644
index 000000000..008d47376
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.h
@@ -0,0 +1,135 @@
+//
+// File Name:
+//
+// RenderFilter.h
+//
+// Abstract:
+//
+// RenderFilter provides the interface to the filter pipeline manager.
+// It implements the IPrintPipelineFilter interface
+//
+
+#pragma once
+
+namespace XpsRenderFilter
+{
+
+
+//
+// Class to maintain the shared state of operation between multiple components
+// of the filter. Also provides the callback for the Xps Rasterization Service.
+//
+class FilterLiveness : public UnknownBase
+{
+public:
+
+ FilterLiveness() :
+ m_isAlive(TRUE)
+ {}
+
+ virtual
+ ~FilterLiveness() {}
+
+ BOOL
+ IsAlive()
+ {
+ return m_isAlive;
+ }
+
+ void
+ Cancel()
+ {
+ //
+ // May be called from a different thread
+ //
+ m_isAlive = FALSE;
+ }
+
+ //
+ // IXpsRasterizerNotificationCallback Method
+ //
+ virtual _Must_inspect_result_
+ HRESULT STDMETHODCALLTYPE
+ Continue()
+ {
+ return (m_isAlive) ? (S_OK) : (HRESULT_FROM_WIN32(ERROR_PRINT_CANCELLED));
+ }
+
+private:
+ volatile BOOL m_isAlive;
+
+ //
+ // prevent copy semantics
+ //
+ FilterLiveness(const FilterLiveness&);
+ FilterLiveness& operator=(const FilterLiveness&);
+};
+
+class RenderFilter : public UnknownBase
+{
+
+public:
+
+ static LONG ms_numObjects; // Number of instances of RenderFilter
+
+ RenderFilter();
+
+ virtual
+ ~RenderFilter();
+
+ //
+ // IPrintPipelineFilter Methods
+ //
+ virtual _Check_return_
+ HRESULT STDMETHODCALLTYPE
+ InitializeFilter(
+ _In_ IInterFilterCommunicator *pICommunicator,
+ _In_ IPrintPipelinePropertyBag *pIPropertyBag,
+ _In_ IPrintPipelineManagerControl *pIPipelineControl
+ );
+
+ virtual _Check_return_
+ HRESULT STDMETHODCALLTYPE
+ ShutdownOperation();
+
+ virtual _Check_return_
+ HRESULT STDMETHODCALLTYPE
+ StartOperation();
+
+private:
+ //
+ // prevent copy semantics
+ //
+ RenderFilter(const RenderFilter&);
+ RenderFilter& operator=(const RenderFilter&);
+
+ //
+ // Xps package part reader
+ //
+ IXpsDocumentProvider_t m_pReader;
+ IPrintWriteStream_t m_pWriter;
+
+ //
+ // Pipeline Property Bag
+ //
+ IPrintPipelinePropertyBag_t m_pIPropertyBag;
+
+ //
+ // IPrintPipelineFilter Methods (throwing)
+ //
+ VOID
+ StartOperation_throws();
+
+ VOID
+ InitializeFilter_throws(
+ const IInterFilterCommunicator_t &pICommunicator,
+ const IPrintPipelinePropertyBag_t &pIPropertyBag
+ );
+
+ //
+ // Keeps track of whether the operation has been cancelled
+ //
+ FilterLiveness_t m_pLiveness;
+};
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.rc b/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.rc
new file mode 100644
index 000000000..be23b2e45
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/RenderFilter.rc
@@ -0,0 +1,20 @@
+//
+// File Name:
+//
+// RenderFilter.rc
+//
+// Abstract:
+//
+// Xps Rasterization Service filter resource file.
+//
+
+#include
+#include
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "XPS Rendering Filter"
+#define VER_INTERNALNAME_STR "XpsRenderFilter.dll"
+#define VER_ORIGINALFILENAME_STR "XpsRenderFilter.dll"
+
+#include "common.ver"
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/UnknownBase.h b/templates/XpsRenderFilter/XpsRenderFilter/UnknownBase.h
new file mode 100644
index 000000000..e634378ca
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/UnknownBase.h
@@ -0,0 +1,151 @@
+//
+// File Name:
+//
+// UnknownBase.h
+//
+// Abstract:
+//
+// IUnknown implementation common to filter components derived from
+// IUnknown.
+//
+
+#pragma once
+
+namespace XpsRenderFilter
+{
+
+template
+class UnknownBase : public Interface
+{
+public:
+ UnknownBase() : m_cRef(1) { }
+ virtual ~UnknownBase() { };
+
+ //
+ //Routine Name:
+ //
+ // UnknownBase::QueryInterface
+ //
+ //Routine Description:
+ //
+ // Implements IUnknown QueryInterface.
+ //
+ //Arguments:
+ //
+ // riid - id of the interface
+ // ppv - void pointer to the requested interface
+ //
+ //Return Value:
+ //
+ // HRESULT
+ // S_OK - On success
+ // E_NOINTERFACE - Invalid interface
+ //
+ _Check_return_
+ HRESULT STDMETHODCALLTYPE
+ QueryInterface(
+ _In_ REFIID riid,
+ _Outptr_ PVOID *ppv
+ )
+ {
+ HRESULT hr = S_OK;
+
+ if (ppv == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_POINTER);
+
+ return E_POINTER;
+ }
+
+ if (riid == IID_IUnknown)
+ {
+ *ppv = static_cast(this);
+ }
+ else if (riid == __uuidof(Interface))
+ {
+ *ppv = static_cast(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ WPP_LOG_ON_FAILED_HRESULT(
+ hr = E_NOINTERFACE
+ );
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ AddRef();
+ }
+
+ return hr;
+ }
+
+ //
+ //Routine Name:
+ //
+ // UnknownBase::AddRef
+ //
+ //Routine Description:
+ //
+ // Implements IUnknown reference count increment
+ // on the current interface.
+ //
+ //Arguments:
+ //
+ // None
+ //
+ //Return Value:
+ //
+ // ULONG
+ // New reference count
+ //
+ ULONG STDMETHODCALLTYPE
+ AddRef()
+ {
+ return ::InterlockedIncrement(&m_cRef);
+ }
+
+ //
+ //Routine Name:
+ //
+ // UnknownBase::Release
+ //
+ //Routine Description:
+ //
+ // Implements IUnknown reference count decrement
+ // on the current interface.
+ //
+ //Arguments:
+ //
+ // None
+ //
+ //Return Value:
+ //
+ // ULONG
+ // New reference count
+ //
+ //Note:
+ //
+ // The drv_at annotation tells Prefast to consider this object's memory
+ // freed after Release has been called.
+ //
+ _At_(this, __drv_freesMem(object))
+ ULONG STDMETHODCALLTYPE
+ Release()
+ {
+ ULONG cRef = ::InterlockedDecrement(&m_cRef);
+
+ if (0 == cRef)
+ {
+ delete this;
+ }
+
+ return cRef;
+ }
+
+private:
+ volatile ULONG m_cRef; // interface reference count
+};
+
+} // namespace XpsRenderFilter
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/WppTrace.h b/templates/XpsRenderFilter/XpsRenderFilter/WppTrace.h
new file mode 100644
index 000000000..f70289355
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/WppTrace.h
@@ -0,0 +1,24 @@
+//
+// File Name:
+//
+// WppTrace.h
+//
+// Abstract:
+//
+// WPP tracing definitions.
+//
+
+#pragma once
+
+
+
+#define WPP_CONTROL_GUIDS WPP_DEFINE_CONTROL_GUID( \
+ XpsRenderFilter, \
+ (d091e354,5abc,4f62,b52c,c6fecd5ab6cd), \
+ WPP_DEFINE_BIT(RENDERFILTER_TRACE_ERROR) \
+ WPP_DEFINE_BIT(RENDERFILTER_TRACE_WARNING) \
+ WPP_DEFINE_BIT(RENDERFILTER_TRACE_INFO) \
+ WPP_DEFINE_BIT(RENDERFILTER_TRACE_VERBOSE) \
+ )
+
+
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter-PipelineConfig.xml b/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter-PipelineConfig.xml
new file mode 100644
index 000000000..494188144
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter-PipelineConfig.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter.vcxproj b/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter.vcxproj
new file mode 100644
index 000000000..805edeb54
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter.vcxproj
@@ -0,0 +1,377 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ v4.5
+ 12.0
+ Debug
+ Win32
+ DbgengRemoteDebugger
+ {93E3E6CA-632B-4C02-9457-1647C65C7629}
+ {cb9d22bf-ff52-42f4-95bf-8676f0fbdeb0}
+ Win32Proj
+ XpsRenderFilter
+ XpsRenderFilter
+
+
+
+ Windows10
+ true
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ false
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ true
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ false
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ true
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ false
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+
+
+
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Use
+
+
+ Use
+
+
+ Use
+
+
+ Use
+
+
+ Use
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy XpsRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy XpsRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy XpsRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy XpsRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy XpsRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy XpsRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy XpsRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy XpsRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter.vcxproj.filters b/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter.vcxproj.filters
new file mode 100644
index 000000000..9f8ef2327
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/XpsRenderFilter.vcxproj.filters
@@ -0,0 +1,85 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ true
+ WppTrace.h
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ true
+ WppTrace.h
+
+
+
+
+ Source Files
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/dllentry.cpp b/templates/XpsRenderFilter/XpsRenderFilter/dllentry.cpp
new file mode 100644
index 000000000..b4627cf5f
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/dllentry.cpp
@@ -0,0 +1,319 @@
+//
+// File Name:
+//
+// dllentry.cpp
+//
+// Abstract:
+//
+// XPS Rendering Filter DLL entry points.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+#include "UnknownBase.h"
+#include "RenderFilter.h"
+
+#include "dllentry.tmh"
+
+namespace XpsRenderFilter
+{
+
+//
+// Class Factory returned by DllGetClassObject()
+//
+class __declspec(uuid("8147f1fd-e661-4929-9012-9d405edab478")) RenderFilterFactory : public UnknownBase
+{
+public:
+ RenderFilterFactory() :
+ m_serverLocks(0)
+ {
+ ::InterlockedIncrement(&RenderFilter::ms_numObjects);
+ }
+
+ ~RenderFilterFactory()
+ {
+ ::InterlockedDecrement(&RenderFilter::ms_numObjects);
+ }
+
+ //
+ //Routine Name:
+ //
+ // RenderFilterFactory::CreateInstance
+ //
+ //Routine Description:
+ //
+ // Returns an instance of RenderFilter.
+ //
+ //Arguments:
+ //
+ // pUnkOuter - Outer class (must be NULL)
+ // riid - Requested interface (IPrintPipelineFilter)
+ // ppvObject - Pointer to the requested interface
+ //
+ //Return Value:
+ //
+ // HRESULT
+ // S_OK - On success
+ // Otherwise - Failure
+ //
+ HRESULT
+ STDMETHODCALLTYPE
+ CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject
+ )
+ {
+ HRESULT hr = S_OK;
+
+ if (pUnkOuter != NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(CLASS_E_NOAGGREGATION);
+
+ return CLASS_E_NOAGGREGATION;
+ }
+
+ if (ppvObject == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_POINTER);
+
+ return E_POINTER;
+ }
+
+ *ppvObject = NULL;
+
+ XpsRenderFilter::RenderFilter *pFilter = NULL;
+
+ //
+ // RenderFilter::RenderFilter() can throw, as can new
+ //
+ try
+ {
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Instantiating filter");
+ pFilter = new XpsRenderFilter::RenderFilter();
+ }
+ CATCH_VARIOUS(hr)
+
+ if (SUCCEEDED(hr))
+ {
+ WPP_LOG_ON_FAILED_HRESULT(
+ hr = pFilter->QueryInterface(riid, ppvObject)
+ );
+
+ pFilter->Release();
+ }
+
+ return hr;
+ }
+
+ //
+ //Routine Name:
+ //
+ // RenderFilterFactory::LockServer
+ //
+ //Routine Description:
+ //
+ // Allows clients to lock the filter factory in
+ // memory.
+ //
+ //Arguments:
+ //
+ // fLock - TRUE - lock; FALSE - unlock
+ //
+ //Return Value:
+ //
+ // HRESULT
+ // S_OK - On success
+ //
+ HRESULT
+ STDMETHODCALLTYPE
+ LockServer(
+ BOOL fLock
+ )
+ {
+ LONG result;
+
+ if (fLock) // lock
+ {
+ result = ::InterlockedIncrement(&m_serverLocks);
+
+ if (result == 1)
+ {
+ //
+ // This was the first 'lock' call; increment the
+ // global numObjects
+ //
+ ::InterlockedIncrement(&RenderFilter::ms_numObjects);
+ }
+ }
+ else // unlock
+ {
+ result = ::InterlockedDecrement(&m_serverLocks);
+
+ if (result == 0)
+ {
+ //
+ // All locks have been unlocked; decrement the
+ // global numObjects
+ //
+ ::InterlockedDecrement(&RenderFilter::ms_numObjects);
+ }
+ }
+
+ return S_OK;
+ }
+
+private:
+ volatile LONG m_serverLocks;
+};
+
+} // namespace XpsRenderFilter
+
+//
+//Routine Name:
+//
+// DllGetClassObject
+//
+//Routine Description:
+//
+// Returns an instance of RenderFilterFactory.
+//
+//Arguments:
+//
+// rclsid - Requested class (RenderFilter)
+// riid - Requested interface (IClassFactory)
+// ppv - Pointer to the requested interface
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - On success
+// Otherwise - Failure
+//
+STDAPI
+DllGetClassObject(
+ _In_ REFCLSID rclsid,
+ _In_ REFIID riid,
+ _Outptr_ LPVOID *ppv
+ )
+{
+ HRESULT hr = S_OK;
+
+ if (ppv == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_POINTER);
+
+ return E_POINTER;
+ }
+
+ *ppv = NULL;
+
+ if (rclsid != __uuidof(XpsRenderFilter::RenderFilterFactory))
+ {
+ WPP_LOG_ON_FAILED_HRESULT(CLASS_E_CLASSNOTAVAILABLE);
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+ }
+
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Instantiating class factory");
+
+ XpsRenderFilter::RenderFilterFactory *pFactory = NULL;
+ pFactory = new(std::nothrow) XpsRenderFilter::RenderFilterFactory();
+
+ if (pFactory == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_OUTOFMEMORY);
+
+ hr = E_OUTOFMEMORY;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ WPP_LOG_ON_FAILED_HRESULT(
+ hr = pFactory->QueryInterface(riid, ppv)
+ );
+
+ pFactory->Release();
+ }
+
+ return hr;
+}
+
+//
+//Routine Name:
+//
+// DllCanUnloadNow
+//
+//Routine Description:
+//
+// Checks whether the DLL can be unloaded. That is,
+// whether there are any instances of RenderFilter.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - Can unload.
+// Otherwise - Cannot unload.
+//
+STDAPI
+DllCanUnloadNow()
+{
+ return (0 == XpsRenderFilter::RenderFilter::ms_numObjects) ? S_OK : S_FALSE;
+}
+
+//
+//Routine Name:
+//
+// DllMain
+//
+//Routine Description:
+//
+// Initializes WPP tracing when the DLL is loaded
+// and cleans up WPP tracing when the DLL is unloaded.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - On success.
+// Otherwise - Otherwise.
+//
+extern "C"
+BOOL
+WINAPI
+DllMain(
+ _In_ HINSTANCE hinstDLL,
+ _In_ DWORD fdwReason,
+ _In_opt_ LPVOID /*lpvReserved*/
+ )
+{
+ switch(fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+
+ ::DisableThreadLibraryCalls(hinstDLL);
+
+ WPP_INIT_TRACING(L"XpsRenderFilter");
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"DLL_PROCESS_ATTACH");
+ break;
+
+ case DLL_PROCESS_DETACH:
+
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"DLL_PROCESS_DETACH");
+ WPP_CLEANUP();
+
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/filtertypes.h b/templates/XpsRenderFilter/XpsRenderFilter/filtertypes.h
new file mode 100644
index 000000000..c7c068f47
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/filtertypes.h
@@ -0,0 +1,434 @@
+//
+// File Name:
+//
+// filtertypes.h
+//
+// Abstract:
+//
+// Smart pointer types. Shared structures and enums.
+//
+
+#pragma once
+
+//
+// XpsDrv Print Pipeline types
+//
+typedef CComPtr IXpsDocument_t;
+typedef CComPtr IFixedDocumentSequence_t;
+typedef CComPtr IFixedDocument_t;
+typedef CComPtr IFixedPage_t;
+typedef CComPtr IPrintReadStreamFactory_t;
+typedef CComPtr IPrintReadStream_t;
+typedef CComPtr IPrintWriteStream_t;
+typedef CComPtr IInterFilterCommunicator_t;
+typedef CComPtr IPrintPipelinePropertyBag_t;
+typedef CComPtr IPrintPipelineManagerControl_t;
+typedef CComPtr IXpsDocumentProvider_t;
+typedef CComPtr IXpsDocumentConsumer_t;
+typedef CComPtr IXpsPartIterator_t;
+typedef CComPtr IPartBase_t;
+typedef CComPtr IPartFont2_t;
+typedef CComPtr IPartFont_t;
+typedef CComPtr IPartImage_t;
+typedef CComPtr IPartColorProfile_t;
+typedef CComPtr IPartResourceDictionary_t;
+typedef std::vector> ResourceDictionaryList_t;
+typedef CComPtr IPartPrintTicket_t;
+
+//
+// Xps Object Model types
+//
+typedef CComPtr IXpsOMObjectFactory_t;
+typedef CComPtr IXpsOMPartResources_t;
+typedef CComPtr IXpsOMFontResourceCollection_t;
+typedef CComPtr IXpsOMImageResourceCollection_t;
+typedef CComPtr IXpsOMColorProfileResourceCollection_t;
+typedef CComPtr IXpsOMRemoteDictionaryResourceCollection_t;
+typedef CComPtr IXpsOMFontResource_t;
+typedef CComPtr IXpsOMImageResource_t;
+typedef CComPtr IXpsOMColorProfileResource_t;
+typedef CComPtr IXpsOMRemoteDictionaryResource_t;
+typedef CComPtr IXpsOMPage_t;
+
+//
+// Opc Types
+//
+typedef CComPtr IOpcFactory_t;
+typedef CComPtr IOpcPartUri_t;
+
+//
+// Common types
+//
+typedef CComPtr IStream_t;
+typedef CComPtr IUnknown_t;
+typedef CComBSTR BSTR_t;
+typedef CComVariant Variant_t;
+typedef CComPtr IPropertyBag2_t;
+
+//
+// MSXML DOM types
+//
+typedef CComPtr IXMLDOMDocument2_t;
+typedef CComPtr IXMLDOMNode_t;
+typedef CComPtr IXMLDOMNodeList_t;
+
+//
+// This class handles setting and clearing the security
+// context, based on a token. This token is retrieved from
+// the filter pipeline, and we do not want to free it.
+//
+class ScopeImpersonation
+{
+public:
+ ScopeImpersonation(
+ HANDLE token
+ )
+ {
+ if (
+ !SetThreadToken(
+ NULL, // set the current thread's token
+ token
+ )
+ )
+ {
+ THROW_LAST_ERROR();
+ }
+ }
+
+ ~ScopeImpersonation()
+ {
+ if (
+ !SetThreadToken(
+ NULL, // set the current thread's token
+ NULL // revert to default security context
+ )
+ )
+ {
+ //
+ // We couldn't revert the security context. The filter pipeline
+ // manager will clean up the thread when operation is complete,
+ // when it is determined that the security context was not
+ // reverted. Since there are no security implications with
+ // running this filter in an elevated context, we can log the
+ // error and continue to run.
+ //
+ DWORD error = ::GetLastError();
+
+ WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(
+ HRESULT_FROM_WIN32(error),
+ L"Failed to revert thread security context."
+ );
+ }
+ }
+
+private:
+ ScopeImpersonation(ScopeImpersonation const&);
+ ScopeImpersonation& operator=(ScopeImpersonation const&);
+};
+
+//
+// RAII object to make HGLOBAL locks exception-safe. This requires
+// unlocking during unwind.
+//
+class HGlobalLock
+{
+public:
+ HGlobalLock(
+ HGLOBAL hG
+ ) :
+ m_hGlobal(hG)
+ {
+ m_pAddress = static_cast(
+ ::GlobalLock(m_hGlobal)
+ );
+
+ if (!m_pAddress)
+ {
+ THROW_LAST_ERROR();
+ }
+ }
+
+ ~HGlobalLock()
+ {
+ if (!::GlobalUnlock(m_hGlobal))
+ {
+ WPP_LOG_ON_FAILED_HRESULT(
+ HRESULT_FROM_WIN32(::GetLastError())
+ );
+ }
+ }
+
+ BYTE*
+ GetAddress()
+ {
+ return m_pAddress;
+ }
+private:
+ HGLOBAL m_hGlobal;
+ BYTE *m_pAddress;
+
+ HGlobalLock(HGlobalLock const&);
+ HGlobalLock& operator=(HGlobalLock const&);
+
+};
+
+typedef std::auto_ptr HGlobalLock_t;
+
+//
+// Safe handle to make HGLOBAL exception-safe. This requires both
+// freeing and unlocking during unwind.
+//
+class SafeHGlobal
+{
+public:
+
+ SafeHGlobal(
+ UINT flags,
+ SIZE_T size
+ )
+ {
+ m_hGlobal = ::GlobalAlloc(flags, size);
+
+ if (!m_hGlobal)
+ {
+ THROW_ON_FAILED_HRESULT(E_OUTOFMEMORY);
+ }
+ }
+
+ virtual
+ ~SafeHGlobal()
+ {
+ if (m_hGlobal)
+ {
+ //
+ // Free the HGLOBAL
+ //
+ ::GlobalFree(m_hGlobal);
+ }
+ }
+
+ operator HGLOBAL()
+ {
+ return m_hGlobal;
+ }
+
+ //
+ // Passes ownership of the HGLOBAL from this safe handle
+ // to a new IStream.
+ //
+ IStream_t
+ ConvertToIStream()
+ {
+ IStream_t pStream;
+
+ THROW_ON_FAILED_HRESULT(
+ ::CreateStreamOnHGlobal(
+ m_hGlobal,
+ TRUE, // Free the HGLOBAL on Release of the stream
+ &pStream
+ )
+ );
+
+ m_hGlobal = NULL;
+
+ return pStream;
+ }
+
+ HGlobalLock_t
+ Lock()
+ {
+ HGlobalLock_t toReturn(
+ new HGlobalLock(m_hGlobal)
+ );
+ return toReturn;
+ }
+
+private:
+
+ HGLOBAL m_hGlobal;
+
+ SafeHGlobal(SafeHGlobal const&);
+ SafeHGlobal& operator=(SafeHGlobal const&);
+
+};
+
+//
+// Safe handle to make HPTPROVIDER exception safe. This
+// requires closing the provider during unwind.
+//
+class SafeHPTProvider
+{
+public:
+ SafeHPTProvider(
+ const wchar_t *printerName,
+ HANDLE userSecurityToken
+ ) :
+ m_token(userSecurityToken)
+ {
+ //
+ // We impersonate the user while we call PTQuerySchemaVersionSupport
+ // and PTOpenProviderEx.
+ //
+ ScopeImpersonation impersonate(m_token);
+
+ DWORD maxVersion,
+ tempVersion;
+
+ THROW_ON_FAILED_HRESULT(
+ ::PTQuerySchemaVersionSupport(
+ printerName,
+ &maxVersion
+ )
+ );
+
+ THROW_ON_FAILED_HRESULT(
+ ::PTOpenProviderEx(
+ printerName,
+ maxVersion, // maximum version
+ maxVersion, // preferred version
+ &m_hProvider,
+ &tempVersion // version used by the provider
+ )
+ );
+ }
+
+ virtual
+ ~SafeHPTProvider()
+ {
+ WPP_LOG_ON_FAILED_HRESULT(
+ ::PTCloseProvider(m_hProvider)
+ );
+ }
+
+ void
+ PTMergeAndValidatePrintTicket(
+ const IStream_t &pBasePrintTicket,
+ const IStream_t &pDeltaPrintTicket,
+ EPrintTicketScope scope,
+ _Inout_ IStream_t &pMergedPrintTicket
+ )
+ {
+ //
+ // We impersonate the user while we call PTMergeAndValidatePrintTicket.
+ //
+ ScopeImpersonation impersonate(m_token);
+
+ BSTR_t error;
+
+ HRESULT hr = ::PTMergeAndValidatePrintTicket(
+ m_hProvider,
+ pBasePrintTicket,
+ pDeltaPrintTicket,
+ scope,
+ pMergedPrintTicket,
+ &error
+ );
+
+ WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(
+ hr,
+ error
+ );
+
+ THROW_ON_FAILED_HRESULT(hr);
+ }
+
+private:
+
+ HPTPROVIDER m_hProvider;
+ HANDLE m_token;
+
+ SafeHPTProvider(SafeHPTProvider const&);
+ SafeHPTProvider& operator=(SafeHPTProvider const&);
+};
+
+//
+// CoInitialize/CoUninitialize RAII object
+//
+// This object ensures that COM is initialized for the duration
+// of the Rendering Filter's lifetime, and then uninitialized after
+// all of the COM objects, regardless of how the filter exits
+//
+class SafeCoInit
+{
+public:
+ SafeCoInit() :
+ m_doCoUninitialize(FALSE)
+ {
+ //
+ // Initialize COM
+ //
+ HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ if (FAILED(hr) &&
+ hr != RPC_E_CHANGED_MODE)
+ {
+ //
+ // RPC_E_CHANGED_MODE indicates that we attempted to change the
+ // threading model. It is safe to ignore since we do not *require*
+ // multi-threading. Throw on any other errors.
+ //
+
+ THROW_ON_FAILED_HRESULT(hr);
+ }
+ else if (SUCCEEDED(hr))
+ {
+ //
+ // It is important that we only call CoUninitialize() if we
+ // succeeded in setting the threading model.
+ //
+
+ m_doCoUninitialize = TRUE;
+ }
+ }
+
+ ~SafeCoInit()
+ {
+ if (m_doCoUninitialize)
+ {
+ ::CoUninitialize();
+ }
+ }
+private:
+ SafeCoInit(SafeCoInit const&);
+ SafeCoInit& operator=(SafeCoInit const&);
+
+ BOOL m_doCoUninitialize;
+};
+
+//
+// RAII object to make VARIANT exception-safe. This requires
+// VariantClear during unwind.
+//
+class SafeVariant : public VARIANT
+{
+public:
+ SafeVariant()
+ {
+ ::VariantInit(this);
+ }
+
+ ~SafeVariant()
+ {
+ ::VariantClear(this);
+ }
+private:
+ SafeVariant(SafeVariant const&);
+ SafeVariant& operator=(SafeVariant const&);
+};
+
+//
+// Forward Declarations
+//
+namespace XpsRenderFilter
+{
+class PrintTicketHandler;
+class FilterLiveness;
+} // namespace XpsRenderFilter
+
+//
+// Internal Types
+//
+typedef std::auto_ptr PrintTicketHandler_t;
+typedef std::auto_ptr SafeHGlobal_t;
+typedef std::auto_ptr SafeHPTProvider_t;
+typedef CComPtr FilterLiveness_t;
diff --git a/templates/XpsRenderFilter/XpsRenderFilter/precomp.h b/templates/XpsRenderFilter/XpsRenderFilter/precomp.h
new file mode 100644
index 000000000..2e6d85924
--- /dev/null
+++ b/templates/XpsRenderFilter/XpsRenderFilter/precomp.h
@@ -0,0 +1,81 @@
+//
+// File Name:
+//
+// precomp.h
+//
+// Abstract:
+//
+// Precompiled header for the Xps Rendering Filter template
+//
+
+
+#pragma once
+
+//
+// Define this as a usermode driver for analysis purposes
+//
+#include
+__user_driver
+
+//
+// Standard Annotation Language include
+//
+#include
+
+//
+// Windows includes
+//
+#include
+
+// Standard includes
+#include
+#include
+#include
+#include
+
+// STL
+#include
+
+//
+// COM includes
+//
+#include
+#include
+
+//
+// Filter pipeline includes
+//
+#include
+#include
+#include
+#include
+
+//
+// ATL
+//
+#include
+
+//
+// WIC
+//
+#include
+
+//
+// MSXML
+//
+#include
+
+//
+// OPC Layer
+//
+#include
+
+//
+// Xps Object Model
+//
+#include
+
+//
+// Xps Rasterization Service
+//
+#include
\ No newline at end of file
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/CustomWppCommands.cpp b/templates/v4PrintDriver/v4PrintDriver Render Filter/CustomWppCommands.cpp
new file mode 100644
index 000000000..bf2a7a355
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/CustomWppCommands.cpp
@@ -0,0 +1,36 @@
+//
+// File Name:
+//
+// CustomWppCommands.cpp
+//
+// Abstract:
+//
+// Custom WPP Tracing functions.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+
+#include "CustomWppCommands.tmh"
+
+namespace v4PrintDriver_Render_Filter
+{
+
+void TraceFailedHRESULT(
+ HRESULT hr,
+ char const *fileName,
+ int lineNum,
+ wchar_t const *extraText
+ )
+{
+ DoTraceMessage(
+ RENDERFILTER_TRACE_ERROR,
+ "Failed HRESULT (%!HRESULT!) at %s:%d (%S)",
+ hr,
+ fileName,
+ lineNum,
+ extraText
+ );
+}
+
+} // namespace v4PrintDriver_Render_Filter
\ No newline at end of file
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/CustomWppCommands.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/CustomWppCommands.h
new file mode 100644
index 000000000..ce05004b2
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/CustomWppCommands.h
@@ -0,0 +1,45 @@
+//
+// File Name:
+//
+// CustomWppCommands.h
+//
+// Abstract:
+//
+// Custom WPP Tracing function declarations/macro definitions.
+//
+
+#pragma once
+
+namespace v4PrintDriver_Render_Filter
+{
+
+void
+TraceFailedHRESULT(
+ HRESULT hr,
+ char const *fileName,
+ int lineNum,
+ wchar_t const *extraText
+ );
+
+} // namespace v4PrintDriver_Render_Filter
+
+
+#define WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(func_,text_) \
+ { \
+ HRESULT hr_ = func_; \
+ if (FAILED(hr_)) \
+ { \
+ v4PrintDriver_Render_Filter::TraceFailedHRESULT( \
+ hr_, \
+ __FILE__, \
+ __LINE__, \
+ text_ \
+ ); \
+ } \
+ }
+
+#define WPP_LOG_ON_FAILED_HRESULT(func_) \
+ { \
+ WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(func_, L"") \
+ }
+
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/Exception.cpp b/templates/v4PrintDriver/v4PrintDriver Render Filter/Exception.cpp
new file mode 100644
index 000000000..211537d0a
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/Exception.cpp
@@ -0,0 +1,39 @@
+//
+// File Name:
+//
+// Exception.cpp
+//
+// Abstract:
+//
+// Exception routine definitions.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+
+#include "Exception.tmh"
+
+namespace v4PrintDriver_Render_Filter
+{
+
+void ThrowHRException(
+ HRESULT hr,
+ char const *fileName,
+ int lineNum
+ )
+{
+ DoTraceMessage(
+ RENDERFILTER_TRACE_ERROR,
+ L"Throwing HRESULT Exception from %s:%d (HRESULT=%!HRESULT!)",
+ fileName,
+ lineNum,
+ hr
+ );
+
+ throw hr_error(hr);
+}
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/Exception.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/Exception.h
new file mode 100644
index 000000000..050808588
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/Exception.h
@@ -0,0 +1,79 @@
+//
+// File Name:
+//
+// Exception.h
+//
+// Abstract:
+//
+// Exception macro and class declarations.
+//
+
+#pragma once
+//
+// Macro to convert HRESULT into an exception throw
+//
+#ifndef THROW_ON_FAILED_HRESULT
+#define THROW_ON_FAILED_HRESULT(func_) \
+{ \
+ HRESULT hr_ = func_; \
+ if (FAILED(hr_)) { v4PrintDriver_Render_Filter::ThrowHRException(hr_, __FILE__, __LINE__); } \
+}
+#endif // THROW_ON_FAILED_HRESULT
+
+#ifndef THROW_LAST_ERROR
+#define THROW_LAST_ERROR() \
+{ \
+ HRESULT errhr_ = HRESULT_FROM_WIN32(::GetLastError()); \
+ THROW_ON_FAILED_HRESULT(errhr_); \
+}
+#endif // THROW_LAST_ERROR
+
+//
+// Macro to catch various exceptions, including
+// HRESULT-turned-exceptions.
+//
+// Because we have defined USE_NATIVE_EH=1, the
+// catch(...) block will not catch structural
+// exceptions.
+//
+#ifndef CATCH_VARIOUS
+#define CATCH_VARIOUS(hr_) \
+ catch(std::bad_alloc const& ) \
+ { \
+ hr_ = E_OUTOFMEMORY; \
+ } \
+ catch(v4PrintDriver_Render_Filter::hr_error const& e) \
+ { \
+ hr_ = e.hr; \
+ } \
+ catch(std::exception const& ) \
+ { \
+ hr_ = E_FAIL; \
+ } \
+ catch(...) \
+ { \
+ hr_ = E_UNEXPECTED; \
+ }
+#endif // CATCH_VARIOUS
+
+namespace v4PrintDriver_Render_Filter
+{
+
+//
+// HRESULT exception
+//
+struct hr_error
+{
+ HRESULT hr;
+
+ hr_error(HRESULT hr_in) : hr(hr_in)
+ { }
+};
+
+void ThrowHRException(
+ HRESULT hr,
+ char const *fileName,
+ int lineNum
+ );
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/OMConvertor.cpp b/templates/v4PrintDriver/v4PrintDriver Render Filter/OMConvertor.cpp
new file mode 100644
index 000000000..ac99438bf
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/OMConvertor.cpp
@@ -0,0 +1,766 @@
+//
+// File Name:
+//
+// omconvertor.cpp
+//
+// Abstract:
+//
+// Object model conversion routines. This class provides routines
+// to convert from filter pipeline objects into Xps Object Model
+// objects.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+#include "UnknownBase.h"
+#include "OMConvertor.h"
+
+#include "OMConvertor.tmh"
+
+namespace v4PrintDriver_Render_Filter
+{
+
+//
+//Routine Name:
+//
+// CreateXpsOMPageFromIFixedPage
+//
+//Routine Description:
+//
+// This is the main method called by the filter. It
+// proceeds to call the remaining Create* methods
+// to convert from the print pipeline Object Model
+// to the Xps Object Model.
+//
+// Takes an IFixedPage (print pipeline Object Model)
+// and converts it to an IXpsOMPage (Xps Object Model).
+//
+//Arguments:
+//
+// pPageIn - IFixedPage to convert
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMPage_t (smart pointer)
+// Result IXpsOMPage
+//
+IXpsOMPage_t
+CreateXpsOMPageFromIFixedPage(
+ const IFixedPage_t &pPageIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ //
+ // Get additional page parameters (uri and stream)
+ //
+ IOpcPartUri_t pPartUri;
+ IStream_t pPartStream;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pPageIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pPageIn),
+ pOpcFactory
+ );
+
+ //
+ // Call Xps Object Model to create the page resource
+ //
+ IXpsOMPage_t pPageOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreatePageFromStream(
+ pPartStream,
+ pPartUri,
+ CollectPageResources(pPageIn, pOMFactory, pOpcFactory),
+ FALSE, // Do not reuse objects
+ &pPageOut
+ )
+ );
+
+ return pPageOut;
+}
+
+//
+//Routine Name:
+//
+// CreateImageFromIPartImage
+//
+//Routine Description:
+//
+// Takes an IPartImage (print pipeline Object Model)
+// and converts it to an IXpsOMImageResource (Xps Object Model).
+//
+//Arguments:
+//
+// pImageIn - IPartImage to convert
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMImageResource_t (smart pointer)
+// Result IXpsOMImageResource
+//
+IXpsOMImageResource_t
+CreateImageFromIPartImage(
+ const IPartImage_t &pImageIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ //
+ // Get IPartBase parameters (stream and uri)
+ //
+ IStream_t pPartStream;
+ IOpcPartUri_t pPartUri;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pImageIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pImageIn),
+ pOpcFactory
+ );
+
+ //
+ // Get the image type and convert it to the corresponding enum
+ //
+ BSTR_t strContentType;
+ XPS_IMAGE_TYPE type = XPS_IMAGE_TYPE_WDP;
+
+ THROW_ON_FAILED_HRESULT(
+ pImageIn->GetImageProperties(&strContentType)
+ );
+
+ if (0 == _wcsicmp(strContentType, L"image/jpeg"))
+ {
+ type = XPS_IMAGE_TYPE_JPEG;
+ }
+ else if (0 == _wcsicmp(strContentType, L"image/png"))
+ {
+ type = XPS_IMAGE_TYPE_PNG;
+ }
+ else if (0 == _wcsicmp(strContentType, L"image/tiff"))
+ {
+ type = XPS_IMAGE_TYPE_TIFF;
+ }
+ else if (0 == _wcsicmp(strContentType, L"image/vnd.ms-photo"))
+ {
+ type = XPS_IMAGE_TYPE_WDP;
+ }
+ else
+ {
+ //
+ // unknown content type
+ //
+ THROW_ON_FAILED_HRESULT(E_INVALIDARG);
+ }
+
+ //
+ // Call Xps Object Model to create the image resource
+ //
+ IXpsOMImageResource_t pImageOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreateImageResource(
+ pPartStream,
+ type,
+ pPartUri,
+ &pImageOut
+ )
+ );
+
+ return pImageOut;
+}
+
+//
+//Routine Name:
+//
+// CreateProfileFromIPartColorProfile
+//
+//Routine Description:
+//
+// Takes an IPartColorProfile (print pipeline Object Model)
+// and converts it to an IXpsOMColorProfileResource (Xps Object Model).
+//
+//Arguments:
+//
+// pProfileIn - IPartColorProfile to convert
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMColorProfileResource_t (smart pointer)
+// Result IXpsOMColorProfileResource
+//
+IXpsOMColorProfileResource_t
+CreateProfileFromIPartColorProfile(
+ const IPartColorProfile_t &pProfileIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ //
+ // Get IPartBase parameters (stream and uri)
+ //
+ IStream_t pPartStream;
+ IOpcPartUri_t pPartUri;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pProfileIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pProfileIn),
+ pOpcFactory
+ );
+
+ //
+ // Call Xps Object Model to create the color profile resource
+ //
+ IXpsOMColorProfileResource_t pProfileOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreateColorProfileResource(
+ pPartStream,
+ pPartUri,
+ &pProfileOut
+ )
+ );
+
+ return pProfileOut;
+}
+
+//
+//Routine Name:
+//
+// CreateDictionaryFromIPartResourceDictionary
+//
+//Routine Description:
+//
+// Takes an IPartResourceDictionary (print pipeline Object Model)
+// and converts it to an IXpsOMRemoteDictionaryResource (Xps Object Model).
+//
+//Arguments:
+//
+// pDictionaryIn - IPartResourceDictionary to convert
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+// pResources - The resources of the fixed page
+//
+//Return Value:
+//
+// IXpsOMRemoteDictionaryResource_t (smart pointer)
+// Result IXpsOMRemoteDictionaryResource
+//
+IXpsOMRemoteDictionaryResource_t
+CreateDictionaryFromIPartResourceDictionary(
+ const IPartResourceDictionary_t &pDictionaryIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory,
+ const IXpsOMPartResources_t &pResources
+ )
+{
+ //
+ // Get IPartBase parameters (stream and uri)
+ //
+ IStream_t pPartStream;
+ IOpcPartUri_t pPartUri;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pDictionaryIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pDictionaryIn),
+ pOpcFactory
+ );
+
+ //
+ // Call Xps Object Model to create the remote dictionary resource
+ //
+ IXpsOMRemoteDictionaryResource_t pDictionaryOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreateRemoteDictionaryResourceFromStream(
+ pPartStream,
+ pPartUri,
+ pResources,
+ &pDictionaryOut)
+ );
+
+ return pDictionaryOut;
+}
+
+//
+//Routine Name:
+//
+// CreateFontFromIPartFont
+//
+//Routine Description:
+//
+// Takes an IPartFont (print pipeline Object Model)
+// and converts it to an IXpsOMFontResource (Xps Object Model).
+//
+//Arguments:
+//
+// pFontIn - IPartFont to convert
+// pFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMFontResource_t (smart pointer)
+// Result IXpsOMFontResource
+//
+IXpsOMFontResource_t
+CreateFontFromIPartFont(
+ const IPartFont_t &pFontIn,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ //
+ // Get IPartBase parameters (stream and uri)
+ //
+ IStream_t pPartStream;
+ IOpcPartUri_t pPartUri;
+
+ pPartStream = GetStreamFromPart(
+ static_cast(pFontIn)
+ );
+ pPartUri = CreateOpcPartUriFromPart(
+ static_cast(pFontIn),
+ pOpcFactory
+ );
+
+ //
+ // Get the font restriction
+ //
+ EXpsFontRestriction eFontRestriction = Xps_Restricted_Font_Installable;
+
+ {
+ IPartFont2_t pFont2In;
+
+ if (SUCCEEDED(pFontIn->QueryInterface(__uuidof(IPartFont2), reinterpret_cast(&pFont2In))))
+ {
+ pFont2In->GetFontRestriction(&eFontRestriction);
+ }
+ }
+
+ //
+ // Get the font obfuscation
+ //
+ EXpsFontOptions eFontOptions;
+
+ {
+ BSTR_t contentType;
+
+ THROW_ON_FAILED_HRESULT(
+ pFontIn->GetFontProperties(&contentType, &eFontOptions)
+ );
+ }
+
+ //
+ // It is necessary to combine the obfuscation and restriction
+ // attributes from the print pipeline into the one parameter that
+ // the Xps Object Model consumes.
+ //
+
+ XPS_FONT_EMBEDDING omEmbedding;
+
+ if (eFontOptions == Font_Normal)
+ {
+ omEmbedding = XPS_FONT_EMBEDDING_NORMAL;
+ }
+ else if (eFontOptions == Font_Obfusticate &&
+ (eFontRestriction &
+ (Xps_Restricted_Font_PreviewPrint |
+ Xps_Restricted_Font_NoEmbedding)))
+ {
+ //
+ // If the font is obfuscated, and either the PreviewPrint or
+ // NoEmbedding restriction flags are set, then create a
+ // Restricted font
+ //
+ omEmbedding = XPS_FONT_EMBEDDING_RESTRICTED;
+ }
+ else
+ {
+ omEmbedding = XPS_FONT_EMBEDDING_OBFUSCATED;
+ }
+
+ //
+ // Call Xps Object Model to create the font resource
+ //
+ IXpsOMFontResource_t pFontOut;
+
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreateFontResource(
+ pPartStream,
+ omEmbedding,
+ pPartUri,
+ FALSE, // fonts received from the pipeline are already de-obfuscated
+ &pFontOut
+ )
+ );
+
+ return pFontOut;
+}
+
+//
+//Routine Name:
+//
+// CollectPageResources
+//
+//Routine Description:
+//
+// Iterates over all of the resources related to
+// a fixed page and adds them to a resource
+// collection.
+//
+//Arguments:
+//
+// pPage - The page to query for resources
+// pOMFactory - Xps Object Model Object Factory
+// pOpcFactory - Opc Object Factory
+//
+//Return Value:
+//
+// IXpsOMPartResources_t (smart pointer)
+// The resource collection of all of the resources of the page
+//
+IXpsOMPartResources_t
+CollectPageResources(
+ const IFixedPage_t &pPage,
+ const IXpsOMObjectFactory_t &pOMFactory,
+ const IOpcFactory_t &pOpcFactory
+ )
+{
+ IXpsOMPartResources_t pResources;
+
+ IXpsOMFontResourceCollection_t pFonts;
+ IXpsOMImageResourceCollection_t pImages;
+ IXpsOMColorProfileResourceCollection_t pProfiles;
+ IXpsOMRemoteDictionaryResourceCollection_t pDictionaries;
+
+ //
+ // collection of resource dictionaries saved for later processing.
+ //
+ ResourceDictionaryList_t dictionaryList;
+
+ //
+ // Create the resource collection and get all of the
+ // resource-specific sub-collections.
+ //
+ THROW_ON_FAILED_HRESULT(
+ pOMFactory->CreatePartResources(&pResources)
+ );
+ THROW_ON_FAILED_HRESULT(
+ pResources->GetFontResources(&pFonts)
+ );
+ THROW_ON_FAILED_HRESULT(
+ pResources->GetImageResources(&pImages)
+ );
+ THROW_ON_FAILED_HRESULT(
+ pResources->GetColorProfileResources(&pProfiles)
+ );
+ THROW_ON_FAILED_HRESULT(
+ pResources->GetRemoteDictionaryResources(&pDictionaries)
+ );
+ //
+ // Get the XpsPartIterator and iterate through all of the parts
+ // related to this fixed page.
+ //
+ IXpsPartIterator_t itPart;
+
+ THROW_ON_FAILED_HRESULT(
+ pPage->GetXpsPartIterator(&itPart)
+ );
+
+ for (; !itPart->IsDone(); itPart->Next())
+ {
+ BSTR_t uri;
+ IUnknown_t pUnkPart;
+
+ THROW_ON_FAILED_HRESULT(
+ itPart->Current(&uri, &pUnkPart)
+ );
+
+ IPartFont_t pFontPart;
+ IPartImage_t pImagePart;
+ IPartColorProfile_t pProfilePart;
+ IPartResourceDictionary_t pDictionaryPart;
+
+ if (SUCCEEDED(pUnkPart.QueryInterface(&pFontPart)))
+ {
+ //
+ // Convert the font part to Xps Object Model and add it to the
+ // font resource collection
+ //
+ THROW_ON_FAILED_HRESULT(
+ pFonts->Append(
+ CreateFontFromIPartFont(
+ pFontPart,
+ pOMFactory,
+ pOpcFactory
+ )
+ )
+ );
+ }
+ else if (SUCCEEDED(pUnkPart.QueryInterface(&pImagePart)))
+ {
+ //
+ // Convert the image part to Xps Object Model and add it to the
+ // image resource collection
+ //
+ THROW_ON_FAILED_HRESULT(
+ pImages->Append(
+ CreateImageFromIPartImage(
+ pImagePart,
+ pOMFactory,
+ pOpcFactory
+ )
+ )
+ );
+ }
+ else if (SUCCEEDED(pUnkPart.QueryInterface(&pProfilePart)))
+ {
+ //
+ // Convert the color profile part to Xps Object Model and add it
+ // to the color profile resource collection
+ //
+ THROW_ON_FAILED_HRESULT(
+ pProfiles->Append(
+ CreateProfileFromIPartColorProfile(
+ pProfilePart,
+ pOMFactory,
+ pOpcFactory
+ )
+ )
+ );
+ }
+ else if (SUCCEEDED(pUnkPart.QueryInterface(&pDictionaryPart)))
+ {
+ //
+ // In order to process the remote resource dictionary, all of
+ // its linked resources must be present in pResources. To ensure
+ // this, we delay the conversion of the remote resource
+ // dictionaries until all of the other resources have been converted.
+ //
+ dictionaryList.push_back(pDictionaryPart);
+ }
+ else
+ {
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Unhandled Page Resource");
+ }
+ }
+
+ for (ResourceDictionaryList_t::const_iterator it = dictionaryList.begin();
+ it != dictionaryList.end();
+ ++it)
+ {
+ //
+ // Convert the remote dictionary to Xps Object Model and add it
+ // to the remote dictionary collection
+ //
+ THROW_ON_FAILED_HRESULT(
+ pDictionaries->Append(
+ CreateDictionaryFromIPartResourceDictionary(
+ *it,
+ pOMFactory,
+ pOpcFactory,
+ pResources
+ )
+ )
+ );
+ }
+
+ return pResources;
+}
+
+//
+//Routine Name:
+//
+// GetStreamFromPart
+//
+//Routine Description:
+//
+// Gets the IStream from this part.
+//
+//Arguments:
+//
+// pPart - An Xps Part
+//
+//Return Value:
+//
+// IStream_t (smart pointer)
+// The stream of the part's content
+//
+IStream_t
+GetStreamFromPart(
+ const IPartBase_t &pPart
+ )
+{
+ //
+ // Get the IPrintReadStream for the part from the pipeline Object Model
+ //
+ IPrintReadStream_t pStream;
+ THROW_ON_FAILED_HRESULT(
+ pPart->GetStream(&pStream)
+ );
+
+ return CreateIStreamFromIPrintReadStream(pStream);
+}
+
+//
+//Routine Name:
+//
+// CreateIStreamFromIPrintReadStream
+//
+//Routine Description:
+//
+// Creates an IStream from an IPrintReadStream.
+//
+//Arguments:
+//
+// pReadStream - A Print Pipeline IPrintReadStream
+//
+//Return Value:
+//
+// IStream_t (smart pointer)
+// A stream with the same content as the argument stream.
+//
+IStream_t
+CreateIStreamFromIPrintReadStream(
+ const IPrintReadStream_t &pReadStream
+ )
+{
+ //
+ // Get the size of the stream
+ //
+ ULONGLONG tmpPos;
+ size_t partSize;
+
+ THROW_ON_FAILED_HRESULT(
+ pReadStream->Seek(0, SEEK_END, &tmpPos)
+ );
+
+ //
+ // GlobalAlloc can only allocate size_t bytes, so
+ // throw if the part is larger than that
+ //
+ THROW_ON_FAILED_HRESULT(
+ ULongLongToSizeT(tmpPos, &partSize)
+ );
+
+ THROW_ON_FAILED_HRESULT(
+ pReadStream->Seek(0, SEEK_SET, &tmpPos)
+ );
+
+ //
+ // Allocate an HGLOBAL for the part cache
+ //
+ SafeHGlobal_t pHBuf(
+ new SafeHGlobal(GMEM_FIXED, partSize)
+ );
+
+ //
+ // Read the part into the cache
+ //
+ {
+ //
+ // Lock the HGLOBAL and get the address of the buffer
+ // from the RAII lock object
+ //
+ HGlobalLock_t lock = pHBuf->Lock();
+ BYTE *pBuffer = lock->GetAddress();
+
+ //
+ // Allow the number of bytes to read to be clipped to max ULONG
+ // and then spin on fEOF until the stream is exhausted
+ //
+ ULONG numToRead;
+
+ if (FAILED(SizeTToULong(partSize, &numToRead)))
+ {
+ numToRead = MAXUINT;
+ }
+
+ BOOL fEOF;
+ ULONG numRead;
+ size_t pos = 0;
+
+ //
+ // Iterate until all bytes from the stream
+ // have been read into the buffer
+ //
+ do
+ {
+ THROW_ON_FAILED_HRESULT(
+ pReadStream->ReadBytes(pBuffer + pos, numToRead, &numRead, &fEOF)
+ );
+
+ pos += numRead;
+ } while (!fEOF && numRead);
+ }
+
+ //
+ // Create an IStream from the part cache
+ //
+ IStream_t pIStream = pHBuf->ConvertToIStream();
+
+ LARGE_INTEGER zero = {0};
+ THROW_ON_FAILED_HRESULT(
+ pIStream->Seek(zero, SEEK_SET, NULL)
+ );
+
+ return pIStream;
+}
+
+//
+//Routine Name:
+//
+// CreateOpcPartUriFromPart
+//
+//Routine Description:
+//
+// Gets the Opc Uri from the Xps Part.
+//
+//Arguments:
+//
+// pPart - An Xps Part
+// pFactory - Opc Factory
+//
+//Return Value:
+//
+// IOpcPartUri_t (smart pointer)
+// The Uri of the part
+//
+IOpcPartUri_t
+CreateOpcPartUriFromPart(
+ const IPartBase_t &pPart,
+ const IOpcFactory_t &pFactory
+ )
+{
+ BSTR_t strPartUri;
+
+ THROW_ON_FAILED_HRESULT(
+ pPart->GetUri(&strPartUri)
+ );
+
+ IOpcPartUri_t pPartUri;
+ THROW_ON_FAILED_HRESULT(
+ pFactory->CreatePartUri(strPartUri, &pPartUri)
+ );
+ return pPartUri;
+}
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/OMConvertor.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/OMConvertor.h
new file mode 100644
index 000000000..8c8c447f0
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/OMConvertor.h
@@ -0,0 +1,84 @@
+//
+// File Name:
+//
+// omconvertor.h
+//
+// Abstract:
+//
+// Object model conversion routines.
+//
+
+#pragma once
+
+namespace v4PrintDriver_Render_Filter
+{
+
+//
+// Top-level Create Page routine
+//
+IXpsOMPage_t
+CreateXpsOMPageFromIFixedPage(
+ const IFixedPage_t &pPageIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+//
+// Individual Part conversion routines
+//
+IXpsOMImageResource_t
+CreateImageFromIPartImage(
+ const IPartImage_t &pImageIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+IXpsOMColorProfileResource_t
+CreateProfileFromIPartColorProfile(
+ const IPartColorProfile_t &pProfileIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+IXpsOMRemoteDictionaryResource_t
+CreateDictionaryFromIPartResourceDictionary(
+ const IPartResourceDictionary_t &pDictionaryIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory,
+ const IXpsOMPartResources_t &pResources
+ );
+
+IXpsOMFontResource_t
+CreateFontFromIPartFont(
+ const IPartFont_t &pFontIn,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+//
+// Utility Routines
+//
+IStream_t
+GetStreamFromPart(
+ const IPartBase_t &pPart
+ );
+
+IOpcPartUri_t
+CreateOpcPartUriFromPart(
+ const IPartBase_t &pPart,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+IXpsOMPartResources_t
+CollectPageResources(
+ const IFixedPage_t &pPage,
+ const IXpsOMObjectFactory_t &pFactory,
+ const IOpcFactory_t &pOpcFactory
+ );
+
+IStream_t
+CreateIStreamFromIPrintReadStream(
+ const IPrintReadStream_t &pReadStream
+ );
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/PThandler.cpp b/templates/v4PrintDriver/v4PrintDriver Render Filter/PThandler.cpp
new file mode 100644
index 000000000..aa360aa0a
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/PThandler.cpp
@@ -0,0 +1,379 @@
+//
+// File Name:
+//
+// PThandler.cpp
+//
+// Abstract:
+//
+// Print Ticket Handler class definition.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+#include "UnknownBase.h"
+#include "OMConvertor.h"
+#include "RenderFilter.h"
+#include "PTHandler.h"
+
+#include "PThandler.tmh"
+
+namespace v4PrintDriver_Render_Filter
+{
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::CreatePrintTicketHandler
+//
+//Routine Description:
+//
+// Static factory method that creates an instance of
+// PrintTicketHandler.
+//
+//Arguments:
+//
+// pPropertyBag - Property Bag
+//
+//Return Value:
+//
+// PrintTicketHandler_t (smart ptr)
+// The new PrintTicketHandler.
+//
+PrintTicketHandler_t
+PrintTicketHandler::CreatePrintTicketHandler(
+ const IPrintPipelinePropertyBag_t &pPropertyBag
+ )
+{
+ //
+ // Create MSXML DOM document
+ //
+ IXMLDOMDocument2_t pDOMDoc;
+
+ THROW_ON_FAILED_HRESULT(
+ ::CoCreateInstance(
+ __uuidof(DOMDocument60),
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IXMLDOMDocument2),
+ reinterpret_cast(&pDOMDoc)
+ )
+ );
+
+ //
+ // Get the default user Print Ticket Stream Factory
+ //
+ Variant_t varUserPrintTicket;
+ THROW_ON_FAILED_HRESULT(
+ pPropertyBag->GetProperty(
+ XPS_FP_USER_PRINT_TICKET,
+ &varUserPrintTicket
+ )
+ );
+ IUnknown_t pUnk = varUserPrintTicket.punkVal;
+
+ IPrintReadStreamFactory_t pStreamFactory;
+
+ THROW_ON_FAILED_HRESULT(
+ pUnk.QueryInterface(&pStreamFactory)
+ );
+
+ //
+ // Get the default user Print Ticket stream
+ // and wrap it in an IStream
+ //
+
+ IPrintReadStream_t pUserPrintTicketStream;
+
+ THROW_ON_FAILED_HRESULT(
+ pStreamFactory->GetStream(&pUserPrintTicketStream)
+ );
+
+ IStream_t pUserPrintTicket =
+ CreateIStreamFromIPrintReadStream(pUserPrintTicketStream);
+
+ //
+ // Get the Printer Name
+ //
+ Variant_t varPrinterName;
+ THROW_ON_FAILED_HRESULT(
+ pPropertyBag->GetProperty(
+ XPS_FP_PRINTER_NAME,
+ &varPrinterName
+ )
+ );
+
+ BSTR_t pPrinterName(varPrinterName.bstrVal);
+
+ //
+ // Get the User Security Token
+ // Avoid CComVariant if getting the XPS_FP_USER_TOKEN property.
+ // Please refer to http://go.microsoft.com/fwlink/?LinkID=255534 for detailed information.
+ //
+ SafeVariant varUserSecurityToken;
+ THROW_ON_FAILED_HRESULT(
+ pPropertyBag->GetProperty(
+ XPS_FP_USER_TOKEN,
+ &varUserSecurityToken
+ )
+ );
+
+ //
+ // Open the Print Ticket Provider
+ //
+ SafeHPTProvider_t pHProvider(
+ new SafeHPTProvider(
+ pPrinterName,
+ varUserSecurityToken.byref
+ )
+ );
+
+ PrintTicketHandler_t toReturn(
+ new PrintTicketHandler(
+ pDOMDoc,
+ pHProvider,
+ pUserPrintTicket
+ )
+ );
+
+ return toReturn;
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::PrintTicketHandler
+//
+//Routine Description:
+//
+// Constructor for the Print Ticket Handler.
+//
+//Arguments:
+//
+// pDoc - initialized MSXML DOM document
+// pHProvider - handle to the Print Ticket Provider
+//
+PrintTicketHandler::PrintTicketHandler(
+ const IXMLDOMDocument2_t &pDoc,
+ SafeHPTProvider_t pHProvider,
+ const IStream_t &pUserPrintTicket
+ ) : m_pDOMDoc(pDoc),
+ m_pHProvider(pHProvider),
+ m_pDefaultUserPrintTicket(pUserPrintTicket)
+{
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::ProcessPrintTicket
+//
+//Routine Description:
+//
+// Gets the print ticket from the part, merges with
+// the base ticket, and returns the result.
+//
+//Arguments:
+//
+// pBasePrintTicket - Base Print Ticket
+// pDeltaPrintTicketPart - Delta Print Pipeline Print Ticket Part
+// scope - Scope of the merged Print Ticket
+//
+//Return Value:
+//
+// IStream_t (smart pointer)
+// Merged stream
+//
+IStream_t
+PrintTicketHandler::ProcessPrintTicket(
+ const IStream_t &pBasePrintTicket,
+ const IPartPrintTicket_t &pDeltaPrintTicketPart,
+ EPrintTicketScope scope
+ )
+{
+ IStream_t pMergedPrintTicket;
+ IStream_t pDeltaPrintTicket;
+
+ pDeltaPrintTicket = GetStreamFromPart(
+ static_cast(pDeltaPrintTicketPart)
+ );
+
+ //
+ // Before calling PTMergeAndValidatePrintTicket, both input
+ // Print Ticket streams MUST be at position 0. The temp Print
+ // Ticket stream is already at position 0, but the Base Print
+ // Ticket may not be. Seek it to 0 to be sure.
+ //
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+ THROW_ON_FAILED_HRESULT(
+ pBasePrintTicket->Seek(zero, SEEK_SET, NULL)
+ );
+
+ //
+ // Merge the delta Print Ticket with the
+ // base Print Ticket
+ //
+ THROW_ON_FAILED_HRESULT(
+ ::CreateStreamOnHGlobal(
+ NULL,
+ TRUE, // delete on release
+ &pMergedPrintTicket
+ )
+ );
+
+ m_pHProvider->PTMergeAndValidatePrintTicket(
+ pBasePrintTicket,
+ pDeltaPrintTicket,
+ scope,
+ pMergedPrintTicket
+ );
+
+ return pMergedPrintTicket;
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::ProcessPart
+//
+//Routine Description:
+//
+// Merges the Fixed Document Sequence Print Ticket with
+// the default user Print Ticket and caches the result.
+//
+//Arguments:
+//
+// pFDS - Fixed Document Sequence part
+//
+void
+PrintTicketHandler::ProcessPart(
+ const IFixedDocumentSequence_t &pFDS
+ )
+{
+ IPartPrintTicket_t pPrintTicket;
+
+ HRESULT hr = pFDS->GetPrintTicket(&pPrintTicket);
+
+ //
+ // E_ELEMENT_NOT_FOUND means that this Fixed Document Sequence
+ // does not have a Print Ticket. Propagate the Default User
+ // Print Ticket.
+ // All other failed HRESULTs should be thrown.
+ //
+ if (hr == E_ELEMENT_NOT_FOUND)
+ {
+ m_pJobPrintTicket = m_pDefaultUserPrintTicket;
+ return;
+ }
+
+ THROW_ON_FAILED_HRESULT(hr);
+
+ m_pDocumentPrintTicket = NULL;
+ m_pPagePrintTicket = NULL;
+
+ m_pJobPrintTicket = ProcessPrintTicket(
+ m_pDefaultUserPrintTicket,
+ pPrintTicket,
+ kPTJobScope
+ );
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::ProcessPart
+//
+//Routine Description:
+//
+// Merges the Fixed Document Print Ticket with the
+// Fixed Document Sequence Print Ticket and caches
+// the result. The tickets are merged at the Document
+// scope, so the result contains no job-level features.
+//
+//Arguments:
+//
+// pFD - Fixed Document part
+//
+void
+PrintTicketHandler::ProcessPart(
+ const IFixedDocument_t &pFD
+ )
+{
+ IPartPrintTicket_t pPrintTicket;
+
+ HRESULT hr = pFD->GetPrintTicket(&pPrintTicket);
+
+ //
+ // E_ELEMENT_NOT_FOUND means that this Fixed Document
+ // does not have a Print Ticket. Propagate the Job
+ // Print Ticket.
+ // All other failed HRESULTs should be thrown.
+ //
+ if (hr == E_ELEMENT_NOT_FOUND)
+ {
+ m_pDocumentPrintTicket = m_pJobPrintTicket;
+ return;
+ }
+
+ THROW_ON_FAILED_HRESULT(hr);
+
+ m_pPagePrintTicket = NULL;
+
+ m_pDocumentPrintTicket = ProcessPrintTicket(
+ m_pJobPrintTicket,
+ pPrintTicket,
+ kPTDocumentScope
+ );
+}
+
+//
+//Routine Name:
+//
+// PrintTicketHandler::ProcessPart
+//
+//Routine Description:
+//
+// Merges the Fixed Page Print Ticket with the
+// Fixed Document Print Ticket and caches the result.
+// The tickets are merged at the Page scope, so the
+// result contains no job-level or document-level features.
+//
+//Arguments:
+//
+// pFP - Fixed Page part
+//
+void
+PrintTicketHandler::ProcessPart(
+ const IFixedPage_t &pFP
+ )
+{
+ IPartPrintTicket_t pPrintTicket;
+
+ HRESULT hr = pFP->GetPrintTicket(&pPrintTicket);
+
+ //
+ // E_ELEMENT_NOT_FOUND means that this Fixed Page
+ // does not have a Print Ticket. Propagate the Document
+ // Print Ticket.
+ // All other failed HRESULTs should be thrown.
+ //
+ if (hr == E_ELEMENT_NOT_FOUND)
+ {
+ m_pPagePrintTicket = m_pDocumentPrintTicket;
+ return;
+ }
+
+ THROW_ON_FAILED_HRESULT(hr);
+
+ m_pPagePrintTicket = ProcessPrintTicket(
+ m_pDocumentPrintTicket,
+ pPrintTicket,
+ kPTPageScope
+ );
+}
+
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/PThandler.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/PThandler.h
new file mode 100644
index 000000000..152ea5041
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/PThandler.h
@@ -0,0 +1,92 @@
+//
+// File Name:
+//
+// PThandler.h
+//
+// Abstract:
+//
+// Print Ticket Handler class declaration.
+//
+
+#pragma once
+
+namespace v4PrintDriver_Render_Filter
+{
+
+class PrintTicketHandler
+{
+public:
+ static
+ PrintTicketHandler_t
+ CreatePrintTicketHandler(
+ const IPrintPipelinePropertyBag_t &pPropertyBag
+ );
+
+ void
+ ProcessPart(
+ const IFixedDocumentSequence_t &pFDS
+ );
+
+ void
+ ProcessPart(
+ const IFixedDocument_t &pFD
+ );
+
+ void
+ ProcessPart(
+ const IFixedPage_t &pFP
+ );
+
+private:
+ //
+ // Constructor is private; use CreatePrintTicketHandler
+ // to create instances.
+ //
+ PrintTicketHandler(
+ const IXMLDOMDocument2_t &pDoc,
+ SafeHPTProvider_t pHProvider,
+ const IStream_t &pUserPrintTicket
+ );
+
+ IStream_t
+ ProcessPrintTicket(
+ const IStream_t &pBasePrintTicket,
+ const IPartPrintTicket_t &pDeltaPrintTicketPart,
+ EPrintTicketScope scope
+ );
+
+ //
+ // Inline function to convert from microns to Xps Units
+ //
+ inline
+ FLOAT
+ MicronsToXpsUnits(
+ long dimensionInMicrons
+ )
+ {
+ const FLOAT xpsDPI = 96.0f;
+ const FLOAT micronsPerInch = 25400.0f; // 2.54 cm/in --> 25400 um/in
+
+ return ((static_cast(dimensionInMicrons) / micronsPerInch) * xpsDPI);
+ }
+
+ //
+ // MSXML DOM document
+ //
+ IXMLDOMDocument2_t m_pDOMDoc;
+
+ //
+ // Handle to the Print Ticket Provider
+ //
+ SafeHPTProvider_t m_pHProvider;
+
+ //
+ // Cached Print Tickets
+ //
+ IStream_t m_pDefaultUserPrintTicket;
+ IStream_t m_pJobPrintTicket;
+ IStream_t m_pDocumentPrintTicket;
+ IStream_t m_pPagePrintTicket;
+};
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.cpp b/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.cpp
new file mode 100644
index 000000000..c9d0b0650
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.cpp
@@ -0,0 +1,365 @@
+//
+// File Name:
+//
+// RenderFilter.cpp
+//
+// Abstract:
+//
+// XPS Rendering filter implementation.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+#include "UnknownBase.h"
+#include "OMConvertor.h"
+#include "PThandler.h"
+#include "RenderFilter.h"
+
+#include "RenderFilter.tmh"
+
+namespace v4PrintDriver_Render_Filter
+{
+
+long RenderFilter::ms_numObjects = 0; // Initialize static object count
+
+//
+//Routine Name:
+//
+// RenderFilter::RenderFilter
+//
+//Routine Description:
+//
+// XPS Rendering filter default constructor.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// None
+//
+RenderFilter::RenderFilter()
+{
+ //
+ // Take ownership with no AddRef
+ //
+ m_pLiveness.Attach(new FilterLiveness());
+
+ ::InterlockedIncrement(&ms_numObjects);
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::~RenderFilter
+//
+//Routine Description:
+//
+// XPS Rendering sample filter destructor.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// None
+//
+RenderFilter::~RenderFilter()
+{
+ ::InterlockedDecrement(&ms_numObjects);
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::InitializeFilter
+//
+//Routine Description:
+//
+// Exception boundary wrapper for IPrintPipelineFilter initialization.
+//
+//Arguments:
+//
+// pICommunicator - interface to interfilter communicator
+// pIPropertyBag - interface to pipeline property bag
+// pIPipelineControl - interface to pipeline control methods
+//
+//Return Value:
+//
+// ULONG
+// New reference count
+//
+_Check_return_
+HRESULT STDMETHODCALLTYPE
+RenderFilter::InitializeFilter(
+ _In_ IInterFilterCommunicator *pICommunicator,
+ _In_ IPrintPipelinePropertyBag *pIPropertyBag,
+ _In_ IPrintPipelineManagerControl *pIPipelineControl
+ )
+{
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Initializing Filter");
+
+ if (pICommunicator == NULL ||
+ pIPropertyBag == NULL ||
+ pIPipelineControl == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_POINTER);
+
+ return E_POINTER;
+ }
+
+ HRESULT hr = S_OK;
+
+ try
+ {
+ InitializeFilter_throws(
+ pICommunicator,
+ pIPropertyBag
+ );
+ }
+ CATCH_VARIOUS(hr);
+
+ return hr;
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::InitializeFilter_throws
+//
+//Routine Description:
+//
+// Implements IPrintPipelineFilter initialization. Gets
+// all necessary communication interfaces.
+//
+//Arguments:
+//
+// pICommunicator - interface to interfilter communicator
+// pIPropertyBag - interface to pipeline property bag
+//
+VOID
+RenderFilter::InitializeFilter_throws(
+ const IInterFilterCommunicator_t &pICommunicator,
+ const IPrintPipelinePropertyBag_t &pIPropertyBag
+ )
+{
+ //
+ // Get the pipeline communication interfaces
+ //
+ THROW_ON_FAILED_HRESULT(
+ pICommunicator->RequestReader(reinterpret_cast(&m_pReader))
+ );
+ THROW_ON_FAILED_HRESULT(
+ pICommunicator->RequestWriter(reinterpret_cast(&m_pWriter))
+ );
+
+ {
+ //
+ // Check to ensure that the provided interfaces are as expected.
+ // That is, that the GUIDs were correctly listed in the
+ // pipeline configuration file
+ //
+ IXpsDocumentProvider_t pReaderCheck;
+ IPrintWriteStream_t pWriterCheck;
+
+ THROW_ON_FAILED_HRESULT(
+ m_pReader.QueryInterface(&pReaderCheck)
+ );
+ THROW_ON_FAILED_HRESULT(
+ m_pWriter.QueryInterface(&pWriterCheck)
+ );
+ }
+
+ //
+ // Save a pointer to the Property Bag for further
+ // initialization, later.
+ //
+ m_pIPropertyBag = pIPropertyBag;
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::ShutdownOperation
+//
+//Routine Description:
+//
+// Called asynchronously by the pipeline manager
+// to shutdown filter operation.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - On success
+//
+_Check_return_
+HRESULT
+RenderFilter::ShutdownOperation()
+{
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Shutting Down Operation");
+ m_pLiveness->Cancel();
+ return S_OK;
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::StartOperation
+//
+//Routine Description:
+//
+// Called by the pipeline manager to start processing
+// a document. Exception boundary for page processing.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - On success
+// Otherwise - Failure
+//
+_Check_return_
+HRESULT
+RenderFilter::StartOperation()
+{
+ HRESULT hr = S_OK;
+
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Starting Operation");
+
+ //
+ // Process the Xps Package
+ //
+ try {
+ StartOperation_throws();
+ }
+ CATCH_VARIOUS(hr);
+
+ m_pWriter->Close();
+
+ return hr;
+}
+
+//
+//Routine Name:
+//
+// RenderFilter::StartOperation_throws
+//
+//Routine Description:
+//
+// Iterates over the 'trunk' parts of the document
+// and calls appropriate processing methods.
+//
+//Arguments:
+//
+// None
+//
+void
+RenderFilter::StartOperation_throws()
+{
+ //
+ // CoInitialize/CoUninitialize RAII object.
+ // COM is inititalized for the lifetime of this method.
+ //
+ SafeCoInit coInit;
+
+ IXpsOMObjectFactory_t pOMFactory;
+
+ //
+ // Create Xps Object Model Object Factory instance
+ //
+ THROW_ON_FAILED_HRESULT(
+ ::CoCreateInstance(
+ __uuidof(XpsOMObjectFactory),
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IXpsOMObjectFactory),
+ reinterpret_cast(&pOMFactory)
+ )
+ );
+
+ IOpcFactory_t pOpcFactory;
+
+ //
+ // Create Opc Object Factory instance
+ //
+ THROW_ON_FAILED_HRESULT(
+ ::CoCreateInstance(
+ __uuidof(OpcFactory),
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IOpcFactory),
+ reinterpret_cast(&pOpcFactory)
+ )
+ );
+
+
+ //
+ // Create the Print Ticket Handler
+ //
+ PrintTicketHandler_t pPrintTicketHandler =
+ PrintTicketHandler::CreatePrintTicketHandler(
+ m_pIPropertyBag
+ );
+
+ IUnknown_t pUnk;
+
+ //
+ // Get first part
+ //
+ THROW_ON_FAILED_HRESULT(m_pReader->GetXpsPart(&pUnk));
+
+ while (m_pLiveness->IsAlive() &&
+ pUnk != NULL)
+ {
+ IXpsDocument_t pDoc;
+ IFixedDocumentSequence_t pFDS;
+ IFixedDocument_t pFD;
+ IFixedPage_t pFP;
+
+ if (SUCCEEDED(pUnk.QueryInterface(&pFP)))
+ {
+ DoTraceMessage(RENDERFILTER_TRACE_VERBOSE, L"Handling a Page");
+
+ pPrintTicketHandler->ProcessPart(pFP);
+ }
+ else if (SUCCEEDED(pUnk.QueryInterface(&pFD)))
+ {
+ pPrintTicketHandler->ProcessPart(pFD);
+ }
+ else if (SUCCEEDED(pUnk.QueryInterface(&pFDS)))
+ {
+ pPrintTicketHandler->ProcessPart(pFDS);
+ }
+ else if (SUCCEEDED(pUnk.QueryInterface(&pDoc)))
+ {
+ //
+ // Do nothing with the XML Document part
+ //
+ }
+ else
+ {
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Unhandled Document Part");
+ }
+
+ pUnk.Release();
+
+ //
+ // Get Next Part
+ //
+ THROW_ON_FAILED_HRESULT(m_pReader->GetXpsPart(&pUnk));
+ }
+}
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.def b/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.def
new file mode 100644
index 000000000..66e7882a1
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.def
@@ -0,0 +1,15 @@
+;
+; File Name:
+;
+; RenderFilter.def
+;
+; Abstract:
+;
+; Defines DLL exports for v4PrintDriverRenderFilter.dll
+;
+
+LIBRARY v4PrintDriverRenderFilter
+
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.h
new file mode 100644
index 000000000..9a881ce7e
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.h
@@ -0,0 +1,135 @@
+//
+// File Name:
+//
+// RenderFilter.h
+//
+// Abstract:
+//
+// RenderFilter provides the interface to the filter pipeline manager.
+// It implements the IPrintPipelineFilter interface
+//
+
+#pragma once
+
+namespace v4PrintDriver_Render_Filter
+{
+
+
+//
+// Class to maintain the shared state of operation between multiple components
+// of the filter. Also provides the callback for the Xps Rasterization Service.
+//
+class FilterLiveness : public UnknownBase
+{
+public:
+
+ FilterLiveness() :
+ m_isAlive(TRUE)
+ {}
+
+ virtual
+ ~FilterLiveness() {}
+
+ BOOL
+ IsAlive()
+ {
+ return m_isAlive;
+ }
+
+ void
+ Cancel()
+ {
+ //
+ // May be called from a different thread
+ //
+ m_isAlive = FALSE;
+ }
+
+ //
+ // IXpsRasterizerNotificationCallback Method
+ //
+ virtual _Must_inspect_result_
+ HRESULT STDMETHODCALLTYPE
+ Continue()
+ {
+ return (m_isAlive) ? (S_OK) : (HRESULT_FROM_WIN32(ERROR_PRINT_CANCELLED));
+ }
+
+private:
+ volatile BOOL m_isAlive;
+
+ //
+ // prevent copy semantics
+ //
+ FilterLiveness(const FilterLiveness&);
+ FilterLiveness& operator=(const FilterLiveness&);
+};
+
+class RenderFilter : public UnknownBase
+{
+
+public:
+
+ static LONG ms_numObjects; // Number of instances of RenderFilter
+
+ RenderFilter();
+
+ virtual
+ ~RenderFilter();
+
+ //
+ // IPrintPipelineFilter Methods
+ //
+ virtual _Check_return_
+ HRESULT STDMETHODCALLTYPE
+ InitializeFilter(
+ _In_ IInterFilterCommunicator *pICommunicator,
+ _In_ IPrintPipelinePropertyBag *pIPropertyBag,
+ _In_ IPrintPipelineManagerControl *pIPipelineControl
+ );
+
+ virtual _Check_return_
+ HRESULT STDMETHODCALLTYPE
+ ShutdownOperation();
+
+ virtual _Check_return_
+ HRESULT STDMETHODCALLTYPE
+ StartOperation();
+
+private:
+ //
+ // prevent copy semantics
+ //
+ RenderFilter(const RenderFilter&);
+ RenderFilter& operator=(const RenderFilter&);
+
+ //
+ // Xps package part reader
+ //
+ IXpsDocumentProvider_t m_pReader;
+ IPrintWriteStream_t m_pWriter;
+
+ //
+ // Pipeline Property Bag
+ //
+ IPrintPipelinePropertyBag_t m_pIPropertyBag;
+
+ //
+ // IPrintPipelineFilter Methods (throwing)
+ //
+ VOID
+ StartOperation_throws();
+
+ VOID
+ InitializeFilter_throws(
+ const IInterFilterCommunicator_t &pICommunicator,
+ const IPrintPipelinePropertyBag_t &pIPropertyBag
+ );
+
+ //
+ // Keeps track of whether the operation has been cancelled
+ //
+ FilterLiveness_t m_pLiveness;
+};
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.rc b/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.rc
new file mode 100644
index 000000000..937c04899
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/RenderFilter.rc
@@ -0,0 +1,20 @@
+//
+// File Name:
+//
+// RenderFilter.rc
+//
+// Abstract:
+//
+// Xps Rasterization Service filter resource file.
+//
+
+#include
+#include
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "XPS Rendering Filter"
+#define VER_INTERNALNAME_STR "v4PrintDriver_Render_Filter.dll"
+#define VER_ORIGINALFILENAME_STR "v4PrintDriver_Render_Filter.dll"
+
+#include "common.ver"
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/UnknownBase.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/UnknownBase.h
new file mode 100644
index 000000000..2685f7ed0
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/UnknownBase.h
@@ -0,0 +1,151 @@
+//
+// File Name:
+//
+// UnknownBase.h
+//
+// Abstract:
+//
+// IUnknown implementation common to filter components derived from
+// IUnknown.
+//
+
+#pragma once
+
+namespace v4PrintDriver_Render_Filter
+{
+
+template
+class UnknownBase : public Interface
+{
+public:
+ UnknownBase() : m_cRef(1) { }
+ virtual ~UnknownBase() { };
+
+ //
+ //Routine Name:
+ //
+ // UnknownBase::QueryInterface
+ //
+ //Routine Description:
+ //
+ // Implements IUnknown QueryInterface.
+ //
+ //Arguments:
+ //
+ // riid - id of the interface
+ // ppv - void pointer to the requested interface
+ //
+ //Return Value:
+ //
+ // HRESULT
+ // S_OK - On success
+ // E_NOINTERFACE - Invalid interface
+ //
+ _Check_return_
+ HRESULT STDMETHODCALLTYPE
+ QueryInterface(
+ _In_ REFIID riid,
+ _Outptr_ PVOID *ppv
+ )
+ {
+ HRESULT hr = S_OK;
+
+ if (ppv == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_POINTER);
+
+ return E_POINTER;
+ }
+
+ if (riid == IID_IUnknown)
+ {
+ *ppv = static_cast(this);
+ }
+ else if (riid == __uuidof(Interface))
+ {
+ *ppv = static_cast(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ WPP_LOG_ON_FAILED_HRESULT(
+ hr = E_NOINTERFACE
+ );
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ AddRef();
+ }
+
+ return hr;
+ }
+
+ //
+ //Routine Name:
+ //
+ // UnknownBase::AddRef
+ //
+ //Routine Description:
+ //
+ // Implements IUnknown reference count increment
+ // on the current interface.
+ //
+ //Arguments:
+ //
+ // None
+ //
+ //Return Value:
+ //
+ // ULONG
+ // New reference count
+ //
+ ULONG STDMETHODCALLTYPE
+ AddRef()
+ {
+ return ::InterlockedIncrement(&m_cRef);
+ }
+
+ //
+ //Routine Name:
+ //
+ // UnknownBase::Release
+ //
+ //Routine Description:
+ //
+ // Implements IUnknown reference count decrement
+ // on the current interface.
+ //
+ //Arguments:
+ //
+ // None
+ //
+ //Return Value:
+ //
+ // ULONG
+ // New reference count
+ //
+ //Note:
+ //
+ // The drv_at annotation tells Prefast to consider this object's memory
+ // freed after Release has been called.
+ //
+ _At_(this, __drv_freesMem(object))
+ ULONG STDMETHODCALLTYPE
+ Release()
+ {
+ ULONG cRef = ::InterlockedDecrement(&m_cRef);
+
+ if (0 == cRef)
+ {
+ delete this;
+ }
+
+ return cRef;
+ }
+
+private:
+ volatile ULONG m_cRef; // interface reference count
+};
+
+} // namespace v4PrintDriver_Render_Filter
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/WppTrace.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/WppTrace.h
new file mode 100644
index 000000000..53773a592
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/WppTrace.h
@@ -0,0 +1,24 @@
+//
+// File Name:
+//
+// WppTrace.h
+//
+// Abstract:
+//
+// WPP tracing definitions.
+//
+
+#pragma once
+
+
+
+#define WPP_CONTROL_GUIDS WPP_DEFINE_CONTROL_GUID( \
+ v4PrintDriverRenderFilter, \
+ (bb85bce3,b458,457a,ba34,631f619fe7e2), \
+ WPP_DEFINE_BIT(RENDERFILTER_TRACE_ERROR) \
+ WPP_DEFINE_BIT(RENDERFILTER_TRACE_WARNING) \
+ WPP_DEFINE_BIT(RENDERFILTER_TRACE_INFO) \
+ WPP_DEFINE_BIT(RENDERFILTER_TRACE_VERBOSE) \
+ )
+
+
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/dllentry.cpp b/templates/v4PrintDriver/v4PrintDriver Render Filter/dllentry.cpp
new file mode 100644
index 000000000..efff30105
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/dllentry.cpp
@@ -0,0 +1,319 @@
+//
+// File Name:
+//
+// dllentry.cpp
+//
+// Abstract:
+//
+// XPS Rendering Filter DLL entry points.
+//
+
+#include "precomp.h"
+#include "WppTrace.h"
+#include "CustomWppCommands.h"
+#include "Exception.h"
+#include "filtertypes.h"
+#include "UnknownBase.h"
+#include "RenderFilter.h"
+
+#include "dllentry.tmh"
+
+namespace v4PrintDriver_Render_Filter
+{
+
+//
+// Class Factory returned by DllGetClassObject()
+//
+class __declspec(uuid("ac9d373b-610e-4490-8129-aff0ff4e0e53")) RenderFilterFactory : public UnknownBase
+{
+public:
+ RenderFilterFactory() :
+ m_serverLocks(0)
+ {
+ ::InterlockedIncrement(&RenderFilter::ms_numObjects);
+ }
+
+ ~RenderFilterFactory()
+ {
+ ::InterlockedDecrement(&RenderFilter::ms_numObjects);
+ }
+
+ //
+ //Routine Name:
+ //
+ // RenderFilterFactory::CreateInstance
+ //
+ //Routine Description:
+ //
+ // Returns an instance of RenderFilter.
+ //
+ //Arguments:
+ //
+ // pUnkOuter - Outer class (must be NULL)
+ // riid - Requested interface (IPrintPipelineFilter)
+ // ppvObject - Pointer to the requested interface
+ //
+ //Return Value:
+ //
+ // HRESULT
+ // S_OK - On success
+ // Otherwise - Failure
+ //
+ HRESULT
+ STDMETHODCALLTYPE
+ CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject
+ )
+ {
+ HRESULT hr = S_OK;
+
+ if (pUnkOuter != NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(CLASS_E_NOAGGREGATION);
+
+ return CLASS_E_NOAGGREGATION;
+ }
+
+ if (ppvObject == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_POINTER);
+
+ return E_POINTER;
+ }
+
+ *ppvObject = NULL;
+
+ v4PrintDriver_Render_Filter::RenderFilter *pFilter = NULL;
+
+ //
+ // RenderFilter::RenderFilter() can throw, as can new
+ //
+ try
+ {
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Instantiating filter");
+ pFilter = new v4PrintDriver_Render_Filter::RenderFilter();
+ }
+ CATCH_VARIOUS(hr)
+
+ if (SUCCEEDED(hr))
+ {
+ WPP_LOG_ON_FAILED_HRESULT(
+ hr = pFilter->QueryInterface(riid, ppvObject)
+ );
+
+ pFilter->Release();
+ }
+
+ return hr;
+ }
+
+ //
+ //Routine Name:
+ //
+ // RenderFilterFactory::LockServer
+ //
+ //Routine Description:
+ //
+ // Allows clients to lock the filter factory in
+ // memory.
+ //
+ //Arguments:
+ //
+ // fLock - TRUE - lock; FALSE - unlock
+ //
+ //Return Value:
+ //
+ // HRESULT
+ // S_OK - On success
+ //
+ HRESULT
+ STDMETHODCALLTYPE
+ LockServer(
+ BOOL fLock
+ )
+ {
+ LONG result;
+
+ if (fLock) // lock
+ {
+ result = ::InterlockedIncrement(&m_serverLocks);
+
+ if (result == 1)
+ {
+ //
+ // This was the first 'lock' call; increment the
+ // global numObjects
+ //
+ ::InterlockedIncrement(&RenderFilter::ms_numObjects);
+ }
+ }
+ else // unlock
+ {
+ result = ::InterlockedDecrement(&m_serverLocks);
+
+ if (result == 0)
+ {
+ //
+ // All locks have been unlocked; decrement the
+ // global numObjects
+ //
+ ::InterlockedDecrement(&RenderFilter::ms_numObjects);
+ }
+ }
+
+ return S_OK;
+ }
+
+private:
+ volatile LONG m_serverLocks;
+};
+
+} // namespace v4PrintDriver_Render_Filter
+
+//
+//Routine Name:
+//
+// DllGetClassObject
+//
+//Routine Description:
+//
+// Returns an instance of RenderFilterFactory.
+//
+//Arguments:
+//
+// rclsid - Requested class (RenderFilter)
+// riid - Requested interface (IClassFactory)
+// ppv - Pointer to the requested interface
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - On success
+// Otherwise - Failure
+//
+STDAPI
+DllGetClassObject(
+ _In_ REFCLSID rclsid,
+ _In_ REFIID riid,
+ _Outptr_ LPVOID *ppv
+ )
+{
+ HRESULT hr = S_OK;
+
+ if (ppv == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_POINTER);
+
+ return E_POINTER;
+ }
+
+ *ppv = NULL;
+
+ if (rclsid != __uuidof(v4PrintDriver_Render_Filter::RenderFilterFactory))
+ {
+ WPP_LOG_ON_FAILED_HRESULT(CLASS_E_CLASSNOTAVAILABLE);
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+ }
+
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"Instantiating class factory");
+
+ v4PrintDriver_Render_Filter::RenderFilterFactory *pFactory = NULL;
+ pFactory = new(std::nothrow) v4PrintDriver_Render_Filter::RenderFilterFactory();
+
+ if (pFactory == NULL)
+ {
+ WPP_LOG_ON_FAILED_HRESULT(E_OUTOFMEMORY);
+
+ hr = E_OUTOFMEMORY;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ WPP_LOG_ON_FAILED_HRESULT(
+ hr = pFactory->QueryInterface(riid, ppv)
+ );
+
+ pFactory->Release();
+ }
+
+ return hr;
+}
+
+//
+//Routine Name:
+//
+// DllCanUnloadNow
+//
+//Routine Description:
+//
+// Checks whether the DLL can be unloaded. That is,
+// whether there are any instances of RenderFilter.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - Can unload.
+// Otherwise - Cannot unload.
+//
+STDAPI
+DllCanUnloadNow()
+{
+ return (0 == v4PrintDriver_Render_Filter::RenderFilter::ms_numObjects) ? S_OK : S_FALSE;
+}
+
+//
+//Routine Name:
+//
+// DllMain
+//
+//Routine Description:
+//
+// Initializes WPP tracing when the DLL is loaded
+// and cleans up WPP tracing when the DLL is unloaded.
+//
+//Arguments:
+//
+// None
+//
+//Return Value:
+//
+// HRESULT
+// S_OK - On success.
+// Otherwise - Otherwise.
+//
+extern "C"
+BOOL
+WINAPI
+DllMain(
+ _In_ HINSTANCE hinstDLL,
+ _In_ DWORD fdwReason,
+ _In_opt_ LPVOID /*lpvReserved*/
+ )
+{
+ switch(fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+
+ ::DisableThreadLibraryCalls(hinstDLL);
+
+ WPP_INIT_TRACING(L"v4PrintDriverRenderFilter");
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"DLL_PROCESS_ATTACH");
+ break;
+
+ case DLL_PROCESS_DETACH:
+
+ DoTraceMessage(RENDERFILTER_TRACE_INFO, L"DLL_PROCESS_DETACH");
+ WPP_CLEANUP();
+
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/filtertypes.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/filtertypes.h
new file mode 100644
index 000000000..b0cc75438
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/filtertypes.h
@@ -0,0 +1,434 @@
+//
+// File Name:
+//
+// filtertypes.h
+//
+// Abstract:
+//
+// Smart pointer types. Shared structures and enums.
+//
+
+#pragma once
+
+//
+// XpsDrv Print Pipeline types
+//
+typedef CComPtr IXpsDocument_t;
+typedef CComPtr IFixedDocumentSequence_t;
+typedef CComPtr IFixedDocument_t;
+typedef CComPtr IFixedPage_t;
+typedef CComPtr IPrintReadStreamFactory_t;
+typedef CComPtr IPrintReadStream_t;
+typedef CComPtr IPrintWriteStream_t;
+typedef CComPtr IInterFilterCommunicator_t;
+typedef CComPtr IPrintPipelinePropertyBag_t;
+typedef CComPtr IPrintPipelineManagerControl_t;
+typedef CComPtr IXpsDocumentProvider_t;
+typedef CComPtr IXpsDocumentConsumer_t;
+typedef CComPtr IXpsPartIterator_t;
+typedef CComPtr IPartBase_t;
+typedef CComPtr IPartFont2_t;
+typedef CComPtr IPartFont_t;
+typedef CComPtr IPartImage_t;
+typedef CComPtr IPartColorProfile_t;
+typedef CComPtr IPartResourceDictionary_t;
+typedef std::vector> ResourceDictionaryList_t;
+typedef CComPtr IPartPrintTicket_t;
+
+//
+// Xps Object Model types
+//
+typedef CComPtr IXpsOMObjectFactory_t;
+typedef CComPtr IXpsOMPartResources_t;
+typedef CComPtr IXpsOMFontResourceCollection_t;
+typedef CComPtr IXpsOMImageResourceCollection_t;
+typedef CComPtr IXpsOMColorProfileResourceCollection_t;
+typedef CComPtr IXpsOMRemoteDictionaryResourceCollection_t;
+typedef CComPtr IXpsOMFontResource_t;
+typedef CComPtr IXpsOMImageResource_t;
+typedef CComPtr IXpsOMColorProfileResource_t;
+typedef CComPtr IXpsOMRemoteDictionaryResource_t;
+typedef CComPtr IXpsOMPage_t;
+
+//
+// Opc Types
+//
+typedef CComPtr IOpcFactory_t;
+typedef CComPtr IOpcPartUri_t;
+
+//
+// Common types
+//
+typedef CComPtr IStream_t;
+typedef CComPtr IUnknown_t;
+typedef CComBSTR BSTR_t;
+typedef CComVariant Variant_t;
+typedef CComPtr IPropertyBag2_t;
+
+//
+// MSXML DOM types
+//
+typedef CComPtr IXMLDOMDocument2_t;
+typedef CComPtr IXMLDOMNode_t;
+typedef CComPtr IXMLDOMNodeList_t;
+
+//
+// This class handles setting and clearing the security
+// context, based on a token. This token is retrieved from
+// the filter pipeline, and we do not want to free it.
+//
+class ScopeImpersonation
+{
+public:
+ ScopeImpersonation(
+ HANDLE token
+ )
+ {
+ if (
+ !SetThreadToken(
+ NULL, // set the current thread's token
+ token
+ )
+ )
+ {
+ THROW_LAST_ERROR();
+ }
+ }
+
+ ~ScopeImpersonation()
+ {
+ if (
+ !SetThreadToken(
+ NULL, // set the current thread's token
+ NULL // revert to default security context
+ )
+ )
+ {
+ //
+ // We couldn't revert the security context. The filter pipeline
+ // manager will clean up the thread when operation is complete,
+ // when it is determined that the security context was not
+ // reverted. Since there are no security implications with
+ // running this filter in an elevated context, we can log the
+ // error and continue to run.
+ //
+ DWORD error = ::GetLastError();
+
+ WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(
+ HRESULT_FROM_WIN32(error),
+ L"Failed to revert thread security context."
+ );
+ }
+ }
+
+private:
+ ScopeImpersonation(ScopeImpersonation const&);
+ ScopeImpersonation& operator=(ScopeImpersonation const&);
+};
+
+//
+// RAII object to make HGLOBAL locks exception-safe. This requires
+// unlocking during unwind.
+//
+class HGlobalLock
+{
+public:
+ HGlobalLock(
+ HGLOBAL hG
+ ) :
+ m_hGlobal(hG)
+ {
+ m_pAddress = static_cast(
+ ::GlobalLock(m_hGlobal)
+ );
+
+ if (!m_pAddress)
+ {
+ THROW_LAST_ERROR();
+ }
+ }
+
+ ~HGlobalLock()
+ {
+ if (!::GlobalUnlock(m_hGlobal))
+ {
+ WPP_LOG_ON_FAILED_HRESULT(
+ HRESULT_FROM_WIN32(::GetLastError())
+ );
+ }
+ }
+
+ BYTE*
+ GetAddress()
+ {
+ return m_pAddress;
+ }
+private:
+ HGLOBAL m_hGlobal;
+ BYTE *m_pAddress;
+
+ HGlobalLock(HGlobalLock const&);
+ HGlobalLock& operator=(HGlobalLock const&);
+
+};
+
+typedef std::auto_ptr HGlobalLock_t;
+
+//
+// Safe handle to make HGLOBAL exception-safe. This requires both
+// freeing and unlocking during unwind.
+//
+class SafeHGlobal
+{
+public:
+
+ SafeHGlobal(
+ UINT flags,
+ SIZE_T size
+ )
+ {
+ m_hGlobal = ::GlobalAlloc(flags, size);
+
+ if (!m_hGlobal)
+ {
+ THROW_ON_FAILED_HRESULT(E_OUTOFMEMORY);
+ }
+ }
+
+ virtual
+ ~SafeHGlobal()
+ {
+ if (m_hGlobal)
+ {
+ //
+ // Free the HGLOBAL
+ //
+ ::GlobalFree(m_hGlobal);
+ }
+ }
+
+ operator HGLOBAL()
+ {
+ return m_hGlobal;
+ }
+
+ //
+ // Passes ownership of the HGLOBAL from this safe handle
+ // to a new IStream.
+ //
+ IStream_t
+ ConvertToIStream()
+ {
+ IStream_t pStream;
+
+ THROW_ON_FAILED_HRESULT(
+ ::CreateStreamOnHGlobal(
+ m_hGlobal,
+ TRUE, // Free the HGLOBAL on Release of the stream
+ &pStream
+ )
+ );
+
+ m_hGlobal = NULL;
+
+ return pStream;
+ }
+
+ HGlobalLock_t
+ Lock()
+ {
+ HGlobalLock_t toReturn(
+ new HGlobalLock(m_hGlobal)
+ );
+ return toReturn;
+ }
+
+private:
+
+ HGLOBAL m_hGlobal;
+
+ SafeHGlobal(SafeHGlobal const&);
+ SafeHGlobal& operator=(SafeHGlobal const&);
+
+};
+
+//
+// Safe handle to make HPTPROVIDER exception safe. This
+// requires closing the provider during unwind.
+//
+class SafeHPTProvider
+{
+public:
+ SafeHPTProvider(
+ const wchar_t *printerName,
+ HANDLE userSecurityToken
+ ) :
+ m_token(userSecurityToken)
+ {
+ //
+ // We impersonate the user while we call PTQuerySchemaVersionSupport
+ // and PTOpenProviderEx.
+ //
+ ScopeImpersonation impersonate(m_token);
+
+ DWORD maxVersion,
+ tempVersion;
+
+ THROW_ON_FAILED_HRESULT(
+ ::PTQuerySchemaVersionSupport(
+ printerName,
+ &maxVersion
+ )
+ );
+
+ THROW_ON_FAILED_HRESULT(
+ ::PTOpenProviderEx(
+ printerName,
+ maxVersion, // maximum version
+ maxVersion, // preferred version
+ &m_hProvider,
+ &tempVersion // version used by the provider
+ )
+ );
+ }
+
+ virtual
+ ~SafeHPTProvider()
+ {
+ WPP_LOG_ON_FAILED_HRESULT(
+ ::PTCloseProvider(m_hProvider)
+ );
+ }
+
+ void
+ PTMergeAndValidatePrintTicket(
+ const IStream_t &pBasePrintTicket,
+ const IStream_t &pDeltaPrintTicket,
+ EPrintTicketScope scope,
+ _Inout_ IStream_t &pMergedPrintTicket
+ )
+ {
+ //
+ // We impersonate the user while we call PTMergeAndValidatePrintTicket.
+ //
+ ScopeImpersonation impersonate(m_token);
+
+ BSTR_t error;
+
+ HRESULT hr = ::PTMergeAndValidatePrintTicket(
+ m_hProvider,
+ pBasePrintTicket,
+ pDeltaPrintTicket,
+ scope,
+ pMergedPrintTicket,
+ &error
+ );
+
+ WPP_LOG_ON_FAILED_HRESULT_WITH_TEXT(
+ hr,
+ error
+ );
+
+ THROW_ON_FAILED_HRESULT(hr);
+ }
+
+private:
+
+ HPTPROVIDER m_hProvider;
+ HANDLE m_token;
+
+ SafeHPTProvider(SafeHPTProvider const&);
+ SafeHPTProvider& operator=(SafeHPTProvider const&);
+};
+
+//
+// CoInitialize/CoUninitialize RAII object
+//
+// This object ensures that COM is initialized for the duration
+// of the Rendering Filter's lifetime, and then uninitialized after
+// all of the COM objects, regardless of how the filter exits
+//
+class SafeCoInit
+{
+public:
+ SafeCoInit() :
+ m_doCoUninitialize(FALSE)
+ {
+ //
+ // Initialize COM
+ //
+ HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ if (FAILED(hr) &&
+ hr != RPC_E_CHANGED_MODE)
+ {
+ //
+ // RPC_E_CHANGED_MODE indicates that we attempted to change the
+ // threading model. It is safe to ignore since we do not *require*
+ // multi-threading. Throw on any other errors.
+ //
+
+ THROW_ON_FAILED_HRESULT(hr);
+ }
+ else if (SUCCEEDED(hr))
+ {
+ //
+ // It is important that we only call CoUninitialize() if we
+ // succeeded in setting the threading model.
+ //
+
+ m_doCoUninitialize = TRUE;
+ }
+ }
+
+ ~SafeCoInit()
+ {
+ if (m_doCoUninitialize)
+ {
+ ::CoUninitialize();
+ }
+ }
+private:
+ SafeCoInit(SafeCoInit const&);
+ SafeCoInit& operator=(SafeCoInit const&);
+
+ BOOL m_doCoUninitialize;
+};
+
+//
+// RAII object to make VARIANT exception-safe. This requires
+// VariantClear during unwind.
+//
+class SafeVariant : public VARIANT
+{
+public:
+ SafeVariant()
+ {
+ ::VariantInit(this);
+ }
+
+ ~SafeVariant()
+ {
+ ::VariantClear(this);
+ }
+private:
+ SafeVariant(SafeVariant const&);
+ SafeVariant& operator=(SafeVariant const&);
+};
+
+//
+// Forward Declarations
+//
+namespace v4PrintDriver_Render_Filter
+{
+class PrintTicketHandler;
+class FilterLiveness;
+} // namespace v4PrintDriver_Render_Filter
+
+//
+// Internal Types
+//
+typedef std::auto_ptr PrintTicketHandler_t;
+typedef std::auto_ptr SafeHGlobal_t;
+typedef std::auto_ptr SafeHPTProvider_t;
+typedef CComPtr FilterLiveness_t;
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/precomp.h b/templates/v4PrintDriver/v4PrintDriver Render Filter/precomp.h
new file mode 100644
index 000000000..2e6d85924
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/precomp.h
@@ -0,0 +1,81 @@
+//
+// File Name:
+//
+// precomp.h
+//
+// Abstract:
+//
+// Precompiled header for the Xps Rendering Filter template
+//
+
+
+#pragma once
+
+//
+// Define this as a usermode driver for analysis purposes
+//
+#include
+__user_driver
+
+//
+// Standard Annotation Language include
+//
+#include
+
+//
+// Windows includes
+//
+#include
+
+// Standard includes
+#include
+#include
+#include
+#include
+
+// STL
+#include
+
+//
+// COM includes
+//
+#include
+#include
+
+//
+// Filter pipeline includes
+//
+#include
+#include
+#include
+#include
+
+//
+// ATL
+//
+#include
+
+//
+// WIC
+//
+#include
+
+//
+// MSXML
+//
+#include
+
+//
+// OPC Layer
+//
+#include
+
+//
+// Xps Object Model
+//
+#include
+
+//
+// Xps Rasterization Service
+//
+#include
\ No newline at end of file
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriver Render Filter.vcxproj b/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriver Render Filter.vcxproj
new file mode 100644
index 000000000..c6ef649ae
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriver Render Filter.vcxproj
@@ -0,0 +1,377 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+ v4.5
+ 12.0
+ Debug
+ Win32
+ DbgengRemoteDebugger
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}
+ {cb9d22bf-ff52-42f4-95bf-8676f0fbdeb0}
+ Win32Proj
+ v4PrintDriver_Render_Filter
+ v4PrintDriver Render Filter
+
+
+
+ Windows10
+ true
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ false
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ true
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ false
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ true
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+ Windows10
+ false
+ DynamicLibrary
+ WindowsApplicationForDrivers10.0
+ Debug
+ Static
+
+
+
+
+
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Level4
+ Create
+ _WINDOWS;_USRDLL;RENDERFILTER_EXPORTS;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+ Windows
+ true
+ true
+ true
+
+
+
+
+ Use
+
+
+ Use
+
+
+ Use
+
+
+ Use
+
+
+ Use
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy v4PrintDriverRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy v4PrintDriverRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy v4PrintDriverRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy v4PrintDriverRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy v4PrintDriverRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy v4PrintDriverRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy v4PrintDriverRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+ true
+ Sync
+ true
+ WppTrace.h
+ precomp.h
+ $(IntDir)precomp.pch
+
+
+ Windows
+ RenderFilter.def
+ prntvpt.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)
+
+
+
+ copy v4PrintDriverRenderFilter-PipelineConfig.xml "$(OutDir)"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriver Render Filter.vcxproj.filters b/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriver Render Filter.vcxproj.filters
new file mode 100644
index 000000000..026a0ed71
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriver Render Filter.vcxproj.filters
@@ -0,0 +1,85 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ true
+ WppTrace.h
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ true
+ WppTrace.h
+
+
+
+
+ Source Files
+
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriverRenderFilter-PipelineConfig.xml b/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriverRenderFilter-PipelineConfig.xml
new file mode 100644
index 000000000..c53ac0c15
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver Render Filter/v4PrintDriverRenderFilter-PipelineConfig.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/templates/v4PrintDriver/v4PrintDriver.sln b/templates/v4PrintDriver/v4PrintDriver.sln
new file mode 100644
index 000000000..fd2fac98e
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver.sln
@@ -0,0 +1,57 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34525.116
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v4PrintDriver", "v4PrintDriver\v4PrintDriver.vcxproj", "{3143C300-7917-4938-A704-D052324349D7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v4PrintDriver Render Filter", "v4PrintDriver Render Filter\v4PrintDriver Render Filter.vcxproj", "{2902E58C-C279-4CFF-B085-FE9B211E2929}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|ARM64.Build.0 = Debug|ARM64
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|x64.ActiveCfg = Debug|x64
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|x64.Build.0 = Debug|x64
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|x64.Deploy.0 = Debug|x64
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|x86.ActiveCfg = Debug|Win32
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|x86.Build.0 = Debug|Win32
+ {3143C300-7917-4938-A704-D052324349D7}.Debug|x86.Deploy.0 = Debug|Win32
+ {3143C300-7917-4938-A704-D052324349D7}.Release|ARM64.ActiveCfg = Release|ARM64
+ {3143C300-7917-4938-A704-D052324349D7}.Release|ARM64.Build.0 = Release|ARM64
+ {3143C300-7917-4938-A704-D052324349D7}.Release|ARM64.Deploy.0 = Release|ARM64
+ {3143C300-7917-4938-A704-D052324349D7}.Release|x64.ActiveCfg = Release|x64
+ {3143C300-7917-4938-A704-D052324349D7}.Release|x64.Build.0 = Release|x64
+ {3143C300-7917-4938-A704-D052324349D7}.Release|x64.Deploy.0 = Release|x64
+ {3143C300-7917-4938-A704-D052324349D7}.Release|x86.ActiveCfg = Release|Win32
+ {3143C300-7917-4938-A704-D052324349D7}.Release|x86.Build.0 = Release|Win32
+ {3143C300-7917-4938-A704-D052324349D7}.Release|x86.Deploy.0 = Release|Win32
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Debug|ARM64.Build.0 = Debug|ARM64
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Debug|x64.ActiveCfg = Debug|x64
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Debug|x64.Build.0 = Debug|x64
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Debug|x86.ActiveCfg = Debug|Win32
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Debug|x86.Build.0 = Debug|Win32
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Release|ARM64.ActiveCfg = Release|ARM64
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Release|ARM64.Build.0 = Release|ARM64
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Release|x64.ActiveCfg = Release|x64
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Release|x64.Build.0 = Release|x64
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Release|x86.ActiveCfg = Release|Win32
+ {2902E58C-C279-4CFF-B085-FE9B211E2929}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {21495A91-C26F-4A96-8777-CADFC3EFE4A2}
+ EndGlobalSection
+EndGlobal
diff --git a/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-Intellisense-Windows8.1.js b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-Intellisense-Windows8.1.js
new file mode 100644
index 000000000..bbbc31a01
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-Intellisense-Windows8.1.js
@@ -0,0 +1,126 @@
+///
+
+v4PrintDriverIntellisense.appendInterfaceMethods(
+ IPrintSchemaTicket,
+ {
+ GetParameterInitializer: function (name, namespaceUri) {
+ ///
+ /// Method maps to COM IPrintSchemaTicket2::GetParameterInitializer.
+ ///
+ ///
+ ///
+ ///
+ }
+ });
+
+v4PrintDriverIntellisense.appendInterfaceMethods(
+ IPrintSchemaCapabilities,
+ {
+ GetParameterDefinition: function (name, namespaceUri) {
+ ///
+ /// Method maps to COM IPrintSchemaCapabilities2::GetParameterDefinition.
+ ///
+ ///
+ ///
+ ///
+ }
+ });
+
+IPrintSchemaParameterInitializer = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaParameterInitializer,
+ IPrintSchemaElement,
+ {
+ ///
+ /// Property-get/set maps to COM IPrintSchemaParameterInitializer::Value.
+ ///
+ Value: null,
+ });
+
+IPrintSchemaParameterDefinition = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaParameterDefinition,
+ IPrintSchemaDisplayableElement,
+ {
+ ///
+ /// Property-get maps to COM IPrintSchemaParameterDefinition::UserInputRequired.
+ ///
+ UserInputRequired: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaParameterDefinition::UnitType.
+ ///
+ UnitType: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaParameterDefinition::DataType.
+ ///
+ DataType: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaParameterDefinition::RangeMin.
+ ///
+ RangeMin: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaParameterDefinition::RangeMax.
+ ///
+ RangeMax: null
+ });
+
+IPrinterScriptUsbJobContextReturnCodes = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterScriptUsbJobContextReturnCodes,
+ null,
+ {
+ ///
+ /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::Success.
+ ///
+ Success: null,
+ ///
+ /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::Failure.
+ ///
+ Failure: null,
+ ///
+ /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::Retry.
+ ///
+ Retry: null,
+ ///
+ /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::DeviceBusy.
+ ///
+ DeviceBusy: null,
+ ///
+ /// Property-get maps to COM IPrinterScriptUsbJobContextReturnCodes::AbortTheJob.
+ ///
+ AbortTheJob: null
+ });
+
+IPrinterScriptUsbWritePrintDataProgress = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterScriptUsbWritePrintDataProgress,
+ null,
+ {
+ ///
+ /// Property-get/set maps to COM IPrinterScriptUsbWritePrintDataProgress::ProcessedByteCount.
+ ///
+ ProcessedByteCount: null
+ });
+
+IPrinterScriptUsbJobContext = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterScriptUsbJobContext,
+ null,
+ {
+ ///
+ /// Property-get maps to COM IPrinterScriptUsbJobContext::JobPropertyBag.
+ ///
+ JobPropertyBag: null,
+ ///
+ /// Property-get maps to COM IPrinterScriptUsbJobContext::ReturnCodes.
+ ///
+ ReturnCodes: null,
+ ///
+ /// Property-get maps to COM IPrinterScriptUsbJobContext::TemporaryStreams. Provides an array of IPrinterScriptableSequentialStream.
+ ///
+ TemporaryStreams: null,
+ ///
+ /// Property-get/set maps to COM IPrinterScriptUsbJobContext::PrintedPageCount.
+ ///
+ PrintedPageCount: null
+ });
\ No newline at end of file
diff --git a/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-Intellisense.js b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-Intellisense.js
new file mode 100644
index 000000000..2386541d2
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-Intellisense.js
@@ -0,0 +1,513 @@
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//
+// Copyright (c) Microsoft Corporation. All rights reserved
+//
+// File Name:
+//
+// v4PrintDriver-Intellisense.js
+//
+// Abstract:
+//
+// This file defines intellisense to be used by JavaScript extensions in v4 print drivers.
+
+var v4PrintDriverIntellisense = {
+ /// Intended for use by v4 print driver JavaScript Intellisense.
+ createInterface: function (childInterface, baseType, prototype) {
+ /// Intended for use by v4 print driver JavaScript Intellisense.
+ childInterface.__class = true;
+
+ if (prototype) {
+ childInterface.prototype = prototype;
+ }
+
+ if (baseType) {
+ childInterface.__baseType = baseType;
+ childInterface.__basePrototypePending = true;
+ v4PrintDriverIntellisense.resolveInheritance(childInterface);
+ }
+ },
+ appendInterfaceMethods: function (baseType, prototype) {
+ /// Intended for use by v4 print driver JavaScript Intellisense.
+ for (var memberName in prototype) {
+ baseType.prototype[memberName] = prototype[memberName];
+ }
+ },
+ resolveInheritance: function (childInterface) {
+ /// Intended for use by v4 print driver JavaScript Intellisense.
+ var baseType = childInterface.__baseType;
+ if (!baseType) {
+ return;
+ }
+
+ if (baseType.__baseType) {
+ resolveInheritance(baseType);
+ }
+
+ if (!childInterface.__basePrototypePending) {
+ return;
+ }
+
+ for (var memberName in baseType.prototype) {
+ var memberValue = baseType.prototype[memberName];
+ if (!childInterface.prototype[memberName]) {
+ childInterface.prototype[memberName] = memberValue;
+ }
+ }
+
+ delete childInterface.__basePrototypePending;
+ }
+}
+
+IPrintSchemaElement = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaElement,
+ null,
+ {
+ ///
+ /// Property-get maps to COM IPrintSchemaElement::XmlNode.
+ ///
+ XmlNode: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaElement::Name.
+ ///
+ Name: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaElement::NamespaceUri.
+ ///
+ NamespaceUri: null
+ });
+
+IPrintSchemaDisplayableElement = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaDisplayableElement,
+ IPrintSchemaElement,
+ {
+ ///
+ /// Property-get maps to COM IPrintSchemaDisplayableElement::DisplayName.
+ ///
+ DisplayName: null
+ });
+
+
+IPrintSchemaOption = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaOption,
+ IPrintSchemaDisplayableElement,
+ {
+ ///
+ /// Property-get maps to COM IPrintSchemaOption::Selected.
+ ///
+ Selected: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaOption::Constrained.
+ ///
+ Constrained: null,
+ GetPropertyValue: function (name, namespaceUri) {
+ ///
+ /// Method maps to COM IPrintSchemaOption::GetPropertyValue.
+ ///
+ ///
+ ///
+ ///
+ },
+ ///
+ /// Property-get maps to COM IPrintSchemaNUpOption::PagesPerSheet. Valid for NUp option only.
+ ///
+ PagesPerSheet: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaPageMediaSizeOption::WidthInMicrons. Valid for PageMediaSize option only.
+ ///
+ WidthInMicrons: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaPageMediaSizeOption::HeightInMicrons. Valid for PageMediaSize option only.
+ ///
+ HeightInMicrons: null
+
+ });
+
+IPrintSchemaOptionCollection = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaOptionCollection,
+ null,
+ {
+ ///
+ /// Property-get maps to COM IPrintSchemaOptionCollection::Count.
+ ///
+ Count: null,
+ GetAt: function (index) {
+ ///
+ /// Property-get maps to COM IPrintSchemaOptionCollection::GetAt.
+ ///
+ ///
+ ///
+ }
+ });
+
+
+IPrintSchemaFeature = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaFeature,
+ IPrintSchemaDisplayableElement,
+ {
+ ///
+ /// Property-set/get maps to COM IPrintSchemaFeature::SelectedOption.
+ ///
+ SelectedOption: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaFeature::SelectionType.
+ ///
+ SelectionType: null,
+ GetOption: function (name, namespaceUri) {
+ ///
+ /// Method maps to COM IPrintSchemaFeature::GetOption.
+ ///
+ ///
+ ///
+ ///
+ },
+ ///
+ /// Property-get maps to COM IPrintSchemaFeature::DisplayUI.
+ ///
+ DisplayUI: null
+ });
+
+
+IPrintSchemaPageImageableSize = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaPageImageableSize,
+ IPrintSchemaElement,
+ {
+ ///
+ /// Property-get maps to COM IPrintSchemaPageImageableSize::ImageableSizeWidthInMicrons.
+ ///
+ ImageableSizeWidthInMicrons: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaPageImageableSize::ImageableSizeHeightInMicrons.
+ ///
+ ImageableSizeHeightInMicrons: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaPageImageableSize::OriginWidthInMicrons.
+ ///
+ OriginWidthInMicrons: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaPageImageableSize::OriginHeightInMicrons.
+ ///
+ OriginHeightInMicrons: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaPageImageableSize::ExtentWidthInMicrons.
+ ///
+ ExtentWidthInMicrons: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaPageImageableSize::ExtentHeightInMicrons.
+ ///
+ ExtentHeightInMicrons: null
+ });
+
+
+IPrintSchemaCapabilities = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaCapabilities,
+ IPrintSchemaElement,
+ {
+ GetFeatureByKeyName: function (keyName) {
+ ///
+ /// Method maps to COM IPrintSchemaCapabilities::GetFeatureByKeyName.
+ ///
+ ///
+ ///
+ },
+ GetFeature: function (name, namespaceUri) {
+ ///
+ /// Method maps to COM IPrintSchemaCapabilities::GetFeature.
+ ///
+ ///
+ ///
+ ///
+ },
+ ///
+ /// Property-get maps to COM IPrintSchemaCapabilities::PageImageableSize.
+ ///
+ PageImageableSize: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaCapabilities::JobCopiesAllDocumentsMinValue.
+ ///
+ JobCopiesAllDocumentsMinValue: null,
+ ///
+ /// Property-get maps to COM IPrintSchemaCapabilities::JobCopiesAllDocumentsMaxValue.
+ ///
+ JobCopiesAllDocumentsMaxValue: null,
+ GetSelectedOptionInPrintTicket: function (feature) {
+ ///
+ /// Method maps to COM IPrintSchemaCapabilities::GetSelectedOptionInPrintTicket.
+ ///
+ ///
+ ///
+ },
+ GetOptions: function (feature) {
+ ///
+ /// Method maps to COM IPrintSchemaCapabilities::GetOptions.
+ ///
+ ///
+ ///
+ }
+ });
+
+
+IPrintSchemaTicket = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrintSchemaTicket,
+ IPrintSchemaElement,
+ {
+ GetFeatureByKeyName: function (keyName) {
+ ///
+ /// Method maps to COM IPrintSchemaTicket::GetFeatureByKeyName.
+ ///
+ ///
+ ///
+ },
+ GetFeature: function (name, namespaceUri) {
+ ///
+ /// Method maps to COM IPrintSchemaTicket::GetFeature.
+ ///
+ ///
+ ///
+ ///
+ },
+ NotifyXmlChanged: function () {
+ ///
+ /// Method maps to COM IPrintSchemaTicket::NotifyXmlChanged.
+ ///
+ },
+ GetCapabilities: function () {
+ ///
+ /// Method maps to COM IPrintSchemaTicket::GetCapabilities.
+ ///
+ ///
+ },
+ ///
+ /// Property-get/put maps to IPrintSchemaTicket::JobCopiesAllDocuments.
+ ///
+ JobCopiesAllDocuments: null
+ });
+
+
+IPrinterScriptableSequentialStream = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterScriptableSequentialStream,
+ null,
+ {
+ Read: function (count) {
+ ///
+ /// Method maps to COM IPrinterScriptableSequentialStream::Read.
+ ///
+ ///
+ ///
+ },
+ Write: function (array) {
+ ///
+ /// Method maps to COM IPrinterScriptableSequentialStream::Write.
+ ///
+ ///
+ ///
+ }
+ });
+
+IPrinterScriptableStream = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterScriptableStream,
+ IPrinterScriptableSequentialStream,
+ {
+ Commit: function () {
+ ///
+ /// Method maps to COM IPrinterScriptableStream::Commit.
+ ///
+ },
+ Seek: function (offset, streamSeek) {
+ ///
+ /// Method maps to COM IPrinterScriptableStream::Seek
+ ///
+ ///
+ ///
+ ///
+ },
+ SetSize: function (size) {
+ ///
+ /// Method maps to COM IPrinterScriptableStream::SetSize.
+ ///
+ ///
+ }
+ });
+
+
+IPrinterScriptablePropertyBag = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterScriptablePropertyBag,
+ null,
+ {
+ GetBool: function (name) {
+ ///
+ /// Method maps to COM IPrinterScriptablePropertyBag::GetBool.
+ ///
+ ///
+ ///
+ },
+ SetBool: function (name, value) {
+ ///
+ /// Method maps to COM IPrinterScriptablePropertyBag::SetBool.
+ ///
+ ///
+ ///
+ },
+ GetInt32: function (name) {
+ ///
+ /// Method maps to COM IPrinterScriptablePropertyBag::GetInt32.
+ ///
+ ///
+ ///
+ },
+ SetInt32: function (name, value) {
+ ///
+ /// Method maps to COM IPrinterScriptablePropertyBag::SetInt32.
+ ///
+ ///
+ ///
+ },
+ GetString: function (name) {
+ ///
+ /// Method maps to COM IPrinterScriptablePropertyBag::GetString.
+ ///
+ ///
+ ///
+ },
+ SetString: function (name, value) {
+ ///
+ /// Method maps to COM IPrinterScriptablePropertyBag::SetString.
+ ///
+ ///
+ ///
+ },
+ GetReadStream: function (name) {
+ ///
+ /// Method maps to COM IPrinterScriptablePropertyBag::GetReadStream.
+ ///
+ ///
+ ///
+ },
+ GetWriteStream: function (name) {
+ ///
+ /// Method maps to COM IPrinterScriptablePropertyBag::GetWriteStream.
+ ///
+ ///
+ ///
+ }
+ });
+
+
+IPrinterScriptContext = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterScriptContext,
+ null,
+ {
+ ///
+ /// Property-get maps to COM IPrinterScriptContext::DriverProperties.
+ ///
+ DriverProperties: null,
+ ///
+ /// Property-get maps to COM IPrinterScriptContext::QueueProperties.
+ ///
+ QueueProperties: null,
+ ///
+ /// Property-get maps to COM IPrinterScriptContext::UserProperties.
+ ///
+ UserProperties: null
+ });
+
+IPrinterBidiSchemaElement = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterBidiSchemaElement,
+ null,
+ {
+ ///
+ /// Property-get maps to COM IPrinterBidiSchemaElement::Name.
+ ///
+ Name: null,
+ ///
+ /// Property-get maps to COM IPrinterBidiSchemaElement::BidiType.
+ ///
+ BidiType: null,
+ ///
+ /// Property-get maps to COM IPrinterBidiSchemaElement::Value.
+ ///
+ Value: null
+ });
+
+IPrinterBidiSchemaResponses = function () { }
+v4PrintDriverIntellisense.createInterface(
+ IPrinterBidiSchemaResponses,
+ null,
+ {
+ AddNull: function (schema) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddNull.
+ ///
+ ///
+ },
+ AddString: function (schema, value) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddString.
+ ///
+ ///
+ ///
+ },
+ AddText: function (schema, value) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddText.
+ ///
+ ///
+ ///
+ },
+ AddEnum: function (schema, value) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddEnum.
+ ///
+ ///
+ ///
+ },
+ AddInt32: function (schema, value) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddInt32.
+ ///
+ ///
+ ///
+ },
+ AddBool: function (schema, value) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddBool.
+ ///
+ ///
+ ///
+ },
+ AddFloat: function (schema, value) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddFloat.
+ ///
+ ///
+ ///
+ },
+ AddBlob: function (schema, array) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddBlob.
+ ///
+ ///
+ ///
+ },
+ AddRequeryKey: function (queryKey) {
+ ///
+ /// Method maps to COM IPrinterBidiSchemaResponses::AddRequeryKey.
+ ///
+ ///
+ }
+ });
diff --git a/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-manifest.ini b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-manifest.ini
new file mode 100644
index 000000000..9b9ca0d3d
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver-manifest.ini
@@ -0,0 +1,19 @@
+[DriverConfig]
+DataFile=v4PrintDriver.gpd
+PrinterDriverID={8785de1d-62e1-4a41-9de2-3c977fce0432}
+
+
+
+
+
+
+RequiredFiles=UNIRES.DLL,STDNAMES.GPD,MSXPSINC.GPD
+DriverCategory=PrintFax.Printer
+
+
+UserPropertyBagScope=Queue
+
+[DriverRender]
+XpsFormat=XPS
+
+
diff --git a/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.gpd b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.gpd
new file mode 100644
index 000000000..4ece90f98
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.gpd
@@ -0,0 +1,219 @@
+*%
+*% This file is a sample GPD demonstrating basic printer features/options
+*%
+*%
+
+*%******************************************************************************
+*%: The following root-level attributes should be modified to suit your printer
+*%******************************************************************************
+*GPDFileName: "v4PrintDriver.GPD"
+*GPDFileVersion: "1.0"
+*GPDSpecVersion: "1.0"
+*Include: "StdNames.gpd"
+*%**************************************************
+*% V4 GPD-based printer drivers must include msxpsinc.GPD file
+*%**************************************************
+*Include: "msxpsinc.gpd"
+*ModelName: "Model name goes here"
+*MasterUnits: PAIR(1200, 1200)
+*PrinterType: PAGE
+*MaxCopies: 1
+*Command: CmdSendBlockData { *Cmd : "" }
+
+*PrintSchemaPrivateNamespaceURI: "Your private namespace URI goes here"
+
+
+
+*%******************************************************************************
+*% Orientation
+*%******************************************************************************
+*Feature: Orientation
+{
+ *rcNameID: =ORIENTATION_DISPLAY
+ *DefaultOption: PORTRAIT
+
+ *Option: PORTRAIT
+ {
+ *rcNameID: =PORTRAIT_DISPLAY
+ }
+
+ *Option: LANDSCAPE_CC270
+ {
+ *rcNameID: =LANDSCAPE_DISPLAY
+ }
+}
+
+*%******************************************************************************
+*% Input Bin
+*% The "InputBin" feature demonstrates an example of how to use
+*% GPD-based constraints
+*% TODO: Add the A4 constraint
+*%
+*% Learn more: Selection Constraints
+*% http://msdn.microsoft.com/en-us/library/ff562063(VS.85).aspx
+*%******************************************************************************
+*Feature: InputBin
+{
+ *rcNameID: =PAPER_SOURCE_DISPLAY
+ *DefaultOption: FORMSOURCE
+
+ *Option: FORMSOURCE
+ {
+ *rcNameID: =AUTO_DISPLAY
+ *Constraints: PaperSize.LETTER
+ }
+ *Option: UPPER
+ {
+ *rcNameID: =UPPER_TRAY_DISPLAY
+ }
+}
+
+*%******************************************************************************
+*% Resolution
+*%******************************************************************************
+*Feature: Resolution
+{
+ *rcNameID: =RESOLUTION_DISPLAY
+ *DefaultOption: Option1
+
+ *Option: Option1
+ {
+ *Name: "600 x 600 " =DOTS_PER_INCH
+ *DPI: PAIR(600, 600)
+ *TextDPI: PAIR(600, 600)
+ *SpotDiameter: 100
+ }
+}
+
+*%******************************************************************************
+*% Paper Size
+*%******************************************************************************
+*Feature: PaperSize
+{
+ *rcNameID: =PAPER_SIZE_DISPLAY
+ *DefaultOption: LETTER
+
+ *Option: LETTER
+ {
+ *rcNameID: =RCID_DMPAPER_SYSTEM_NAME *% 1000
+ *switch: Orientation
+ {
+ *case: PORTRAIT
+ {
+ *PrintableArea: PAIR(9000, 12600)
+ *PrintableOrigin: PAIR(200, 200)
+ *CursorOrigin: PAIR(0, 0)
+ }
+ *case: LANDSCAPE_CC270
+ {
+ *PrintableArea: PAIR(9000, 12600)
+ *PrintableOrigin: PAIR(200, 200)
+ *CursorOrigin: PAIR(0, 0)
+ }
+ }
+ }
+
+ *Option: A4
+ {
+ *rcNameID: =RCID_DMPAPER_SYSTEM_NAME *% 1008
+ *switch: Orientation
+ {
+ *case: PORTRAIT
+ {
+ *PrintableArea: PAIR(9000, 12600)
+ *PrintableOrigin: PAIR(200, 200)
+ *CursorOrigin: PAIR(0, 0)
+ }
+ *case: LANDSCAPE_CC270
+ {
+ *PrintableArea: PAIR(9000, 12600)
+ *PrintableOrigin: PAIR(200, 200)
+ *CursorOrigin: PAIR(0, 0)
+ }
+ }
+ }
+}
+
+
+
+
+*%******************************************************************************************
+*% Sample GDL Autoconfiguration feature: Duplex Unit
+*%******************************************************************************************
+*Feature: DuplexUnit
+{
+ *Name: "Optional Duplex Unit"
+ *FeatureType: PRINTER_PROPERTY
+ *DefaultOption: FALSE
+ *Option: FALSE
+ {
+ *Name: "Not Installed"
+ *DisabledFeatures: LIST(Duplex.VERTICAL, Duplex.HORIZONTAL)
+ }
+ *Option: TRUE
+ {
+ *Name: "Installed"
+ }
+}
+
+
+
+*%******************************************************************************************
+*% Duplex Type
+*%******************************************************************************************
+*Feature: Duplex
+{
+ *rcNameID: =TWO_SIDED_PRINTING_DISPLAY
+ *DefaultOption: NONE
+ *Option: NONE
+ {
+ *rcNameID: =NONE_DISPLAY
+ }
+ *Option: VERTICAL
+ {
+ *rcNameID: =FLIP_ON_LONG_EDGE_DISPLAY
+ }
+ *Option: HORIZONTAL
+ {
+ *rcNameID: =FLIP_ON_SHORT_EDGE_DISPLAY
+ }
+}
+
+
+*%******************************************************************************************
+*% Example of a IHV private feature. This feature demonstrates usage of the
+*% PrintSchemaKeywordMap keyword to map the GPD custom feature/option to
+*% public Print Schema keywords
+*%
+*% Learn more: New root-level-only GPD attributes for Windows Vista
+*% http://msdn.microsoft.com/en-us/library/ff550564(VS.85).aspx
+*%******************************************************************************************
+*Feature: IHVStapling
+{
+ *Name: "Staple"
+ *DefaultOption: Off
+ *PrintSchemaKeywordMap: "JobStapleAllDocuments"
+
+ *Option: Off
+ {
+ *Name: "Off"
+ *PrintSchemaKeywordMap: "None"
+ }
+
+ *Option: StapleTopLeft
+ {
+ *Name: "Staple Top left"
+ *PrintSchemaKeywordMap: "StapleTopLeft"
+ }
+}
+
+*%******************************************************************************
+*% Cursor Commands
+*% The following cursor commands are mandatory
+*%
+*% Learn more: Cursor Commands
+*% http://msdn.microsoft.com/en-us/library/ff547223(VS.85).aspx
+*%******************************************************************************
+*Command: CmdCR { *Cmd : "" }
+*Command: CmdLF { *Cmd : "" }
+*Command: CmdFF { *Cmd : "" }
diff --git a/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.inf b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.inf
new file mode 100644
index 000000000..a9b1e5892
Binary files /dev/null and b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.inf differ
diff --git a/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.vcxproj b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.vcxproj
new file mode 100644
index 000000000..42087ca69
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.vcxproj
@@ -0,0 +1,198 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+
+
+
+
+
+
+
+
+ {3143C300-7917-4938-A704-D052324349D7}
+ {68fdc621-7e7b-47c5-acd7-ddcfa68cb8c4}
+ v4.5
+ 12.0
+ Off
+ Package
+ Debug
+ Win32
+ Tools\x86\
+ v4PrintDriver
+
+
+
+ Windows10
+ WindowsUserModeDriver10.0
+ Utility
+
+
+ Windows10
+ WindowsUserModeDriver10.0
+ Utility
+
+
+ Windows10
+ WindowsUserModeDriver10.0
+ Utility
+
+
+ Windows10
+ WindowsUserModeDriver10.0
+ Utility
+
+
+ Windows10
+ WindowsUserModeDriver10.0
+ Utility
+
+
+ Windows10
+ WindowsUserModeDriver10.0
+ Utility
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+ DbgengRemoteDebugger
+
+
+
+ true
+
+
+ sha256
+
+
+ "$(WDKContentRoot)$(INFGateToolPath)INFGate.exe" v4PrintDriver.inf /WDK
+ Running INFGate...
+
+
+
+
+ true
+
+
+ sha256
+
+
+ "$(WDKContentRoot)$(INFGateToolPath)INFGate.exe" v4PrintDriver.inf /WDK
+ Running INFGate...
+
+
+
+
+ true
+
+
+ sha256
+
+
+ "$(WDKContentRoot)$(INFGateToolPath)INFGate.exe" v4PrintDriver.inf /WDK
+ Running INFGate...
+
+
+
+
+ true
+
+
+ sha256
+
+
+ "$(WDKContentRoot)$(INFGateToolPath)INFGate.exe" v4PrintDriver.inf /WDK
+ Running INFGate...
+
+
+
+
+ true
+
+
+ sha256
+
+
+ "$(WDKContentRoot)$(INFGateToolPath)INFGate.exe" v4PrintDriver.inf /WDK
+ Running INFGate...
+
+
+
+
+ true
+
+
+ sha256
+
+
+ "$(WDKContentRoot)$(INFGateToolPath)INFGate.exe" v4PrintDriver.inf /WDK
+ Running INFGate...
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.vcxproj.filters b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.vcxproj.filters
new file mode 100644
index 000000000..fe2327d11
--- /dev/null
+++ b/templates/v4PrintDriver/v4PrintDriver/v4PrintDriver.vcxproj.filters
@@ -0,0 +1,18 @@
+
+
+
+
+ {67DA6AB6-6785-4CFE-B992-037D68949A14}
+ inf;inv;inx;mof;mc;
+
+
+
+
+ Driver Files
+
+
+
+
+
+
+
\ No newline at end of file