├── .gitignore
├── LICENSE
├── README.md
└── Source
├── CsharpWindowCapture.sln
├── Win32.BitBlt
├── App.config
├── BitBlt.cs
├── Interop
│ ├── DeviceContextValues.cs
│ ├── NativeMethods.cs
│ ├── RECT.cs
│ └── TernaryRasterOperations.cs
├── Program.cs
├── Shader.fx
├── Win32.BitBlt.csproj
└── packages.config
├── Win32.DesktopDuplication
├── App.config
├── DesktopDuplication.cs
├── Program.cs
├── Shader.fx
├── Win32.DesktopDuplication.csproj
└── packages.config
├── Win32.DwmSharedSurface
├── App.config
├── DwmSharedSurface.cs
├── Interop
│ └── NativeMethods.cs
├── Program.cs
├── Shader.fx
├── Win32.DwmSharedSurface.csproj
└── packages.config
├── Win32.DwmThumbnail
├── App.config
├── App.xaml
├── App.xaml.cs
├── Interop
│ ├── DWMWINDOWATTRIBUTE.cs
│ ├── DWM_THUMBNAIL_PROPERTIES.cs
│ ├── DWM_TNP.cs
│ ├── NativeMethods.cs
│ └── RECT.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
└── Win32.DwmThumbnail.csproj
├── Win32.Shared
├── App.config
├── DxWindow.cs
├── Interfaces
│ └── ICaptureMethod.cs
├── Interop
│ └── NativeMethods.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Vertex.cs
├── Win32.Shared.csproj
├── WindowPicker.xaml
├── WindowPicker.xaml.cs
└── packages.config
└── WinRT.GraphicsCapture
├── App.config
├── GraphicsCapture.cs
├── Interop
├── ComObjects.cs
└── NativeMethods.cs
├── Program.cs
├── Shader.fx
└── WinRT.GraphicsCapture.csproj
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Natsuneko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # .NET Window Capture Samples
2 |
3 | > NOTE: This is an experimental project. Please use it at your own risk.
4 |
5 | Captures a window or desktop screen and renders it in WPF or DirectX.
6 |
7 | ## System Requirements
8 |
9 | - Windows 10 (64-bit, April 2018 Update)
10 | - DirectX 11
11 | - .NET Framework 4.7.2
12 | - Visual Studio 2019
13 |
14 | ## Capture Methods
15 |
16 | | Project Name | Minimal Windows Version | Render To | Platform |
17 | | -------------------------- | ----------------------- | --------- | -------- |
18 | | `Win32.BitBlt` | Windows 95 | DirectX | Win32 |
19 | | `Win32.DesktopDuplication` | Windows 8 | DirectX | Win32 |
20 | | `Win32.DwmSharedSurface` | Windows 7 | DirectX | Win32 |
21 | | `Win32.DwmThumbnail` | Windows 7 | WPF | Win32 |
22 | | `WinRT.GraphicsCapture` | Windows 10 1803 | DirectX | WinRT |
23 |
24 | ## Comparison
25 |
26 | ### Compare with capture target
27 |
28 | | Capture Method | Window Capture | Desktop Capture | Outside of Desktop | HW Acceleration | DirectX Games |
29 | | -------------------------- | :------------: | :-------------: | :----------------: | :-------------: | :-----------: |
30 | | `Win32.BitBlt` | Yes | Yes | Yes | No | Yes |
31 | | `Win32.DesktopDuplication` | No | Yes | No | Yes | Yes |
32 | | `Win32.DwmSharedSurface` | Yes | No | Yes | No | Yes |
33 | | `Win32.DwmThumbnail` | Yes | No | Yes | Yes | Yes |
34 | | `WinRT.GraphicsCapture` | Yes | Yes | Yes | Yes | Yes |
35 |
36 | - `Games` is checked using [Märchen Forest](https://anemonecoronaria.sakura.ne.jp/merufore/).
37 |
38 | ### Compare with capture source
39 |
40 | | Capture Method | Window Handle | Monitor Handle | Another |
41 | | -------------------------- | :-----------: | :------------: | :--------------: |
42 | | `Win32.BitBlt` | Yes | No | - |
43 | | `Win32.DesktopDuplication` | No | No | Device (Monitor) |
44 | | `Win32.DwmSharedSurface` | Yes | No | - |
45 | | `Win32.DwmThumbnail` | Yes | No | - |
46 | | `WinRT.GraphicsCapture` | Yes \* | Yes \* | Embedded Picker |
47 |
48 | - \*: Require Windows 10 1903 or greater.
49 |
50 | ### Compare with delay
51 |
52 | | Capture Method | Delay (ms) |
53 | | -------------------------- | :--------: |
54 | | `Win32.BitBlt` | ~ 20ms |
55 | | `Win32.DesktopDuplication` | N/A |
56 | | `Win32.DwmSharedSurface` | ~ 20ms |
57 | | `Win32.DwmThumbnail` | **0ms** |
58 | | `WinRT.GraphicsCapture` | ~ 40ms |
59 |
60 | - I used [this video](https://www.youtube.com/watch?v=rf2Lmfqi5ZM) to investigate the delay.
61 | - It is just a reference value, but it is certain that the delay of `Win32.DwmThumbnail` is 0 ms.
62 | - This is because it uses a drawing method that is entirely common to other windows.
63 |
64 | ## License
65 |
66 | This project is licensed under the MIT license.
67 |
68 | ## Third-Party Notices
69 |
70 | ### Dependencies
71 |
72 | - [Microsoft.Windows.SDK.Contracts](https://www.nuget.org/packages/Microsoft.Windows.SDK.Contracts/)
73 | - [SharpDX](https://www.nuget.org/packages/SharpDX/)
74 |
75 | ### Code Includes
76 |
77 | - [SharpDX Samples](https://github.com/sharpdx/SharpDX-Samples) (MIT)
78 | - [Windows Universal Samples](https://github.com/microsoft/Windows-universal-samples) (MIT)
79 | - [Windows.UI.Composition Win32 Samples](https://github.com/microsoft/Windows.UI.Composition-Win32-Samples) (MIT)
80 |
--------------------------------------------------------------------------------
/Source/CsharpWindowCapture.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28803.352
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinRT.GraphicsCapture", "WinRT.GraphicsCapture\WinRT.GraphicsCapture.csproj", "{0654DF3F-FBB5-44CD-B5D8-6715D2A73531}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32.DwmThumbnail", "Win32.DwmThumbnail\Win32.DwmThumbnail.csproj", "{121F4F48-4383-4A01-A026-54C49E653FD9}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32.Shared", "Win32.Shared\Win32.Shared.csproj", "{6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32.DwmSharedSurface", "Win32.DwmSharedSurface\Win32.DwmSharedSurface.csproj", "{70C9B2CA-C253-41CB-87AD-AE18394D202F}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32.DesktopDuplication", "Win32.DesktopDuplication\Win32.DesktopDuplication.csproj", "{674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Win32.BitBlt", "Win32.BitBlt\Win32.BitBlt.csproj", "{5383738F-DCF5-4845-95B9-FFC1CD4830A3}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Debug|x64 = Debug|x64
22 | Release|Any CPU = Release|Any CPU
23 | Release|x64 = Release|x64
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}.Debug|x64.ActiveCfg = Debug|Any CPU
29 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}.Debug|x64.Build.0 = Debug|Any CPU
30 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}.Release|x64.ActiveCfg = Release|Any CPU
33 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}.Release|x64.Build.0 = Release|Any CPU
34 | {121F4F48-4383-4A01-A026-54C49E653FD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {121F4F48-4383-4A01-A026-54C49E653FD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {121F4F48-4383-4A01-A026-54C49E653FD9}.Debug|x64.ActiveCfg = Debug|Any CPU
37 | {121F4F48-4383-4A01-A026-54C49E653FD9}.Debug|x64.Build.0 = Debug|Any CPU
38 | {121F4F48-4383-4A01-A026-54C49E653FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {121F4F48-4383-4A01-A026-54C49E653FD9}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {121F4F48-4383-4A01-A026-54C49E653FD9}.Release|x64.ActiveCfg = Release|Any CPU
41 | {121F4F48-4383-4A01-A026-54C49E653FD9}.Release|x64.Build.0 = Release|Any CPU
42 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}.Debug|x64.ActiveCfg = Debug|Any CPU
45 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}.Debug|x64.Build.0 = Debug|Any CPU
46 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}.Release|x64.ActiveCfg = Release|Any CPU
49 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}.Release|x64.Build.0 = Release|Any CPU
50 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}.Debug|x64.ActiveCfg = Debug|Any CPU
53 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}.Debug|x64.Build.0 = Debug|Any CPU
54 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}.Release|Any CPU.Build.0 = Release|Any CPU
56 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}.Release|x64.ActiveCfg = Release|Any CPU
57 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}.Release|x64.Build.0 = Release|Any CPU
58 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
60 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}.Debug|x64.ActiveCfg = Debug|Any CPU
61 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}.Debug|x64.Build.0 = Debug|Any CPU
62 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
63 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}.Release|Any CPU.Build.0 = Release|Any CPU
64 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}.Release|x64.ActiveCfg = Release|Any CPU
65 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}.Release|x64.Build.0 = Release|Any CPU
66 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
67 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
68 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}.Debug|x64.ActiveCfg = Debug|Any CPU
69 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}.Debug|x64.Build.0 = Debug|Any CPU
70 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
71 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}.Release|Any CPU.Build.0 = Release|Any CPU
72 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}.Release|x64.ActiveCfg = Release|Any CPU
73 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}.Release|x64.Build.0 = Release|Any CPU
74 | EndGlobalSection
75 | GlobalSection(SolutionProperties) = preSolution
76 | HideSolutionNode = FALSE
77 | EndGlobalSection
78 | GlobalSection(ExtensibilityGlobals) = postSolution
79 | SolutionGuid = {52E13334-9638-44E6-856A-FDB9B302A147}
80 | EndGlobalSection
81 | EndGlobal
82 |
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/BitBlt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Drawing.Imaging;
4 |
5 | using SharpDX;
6 | using SharpDX.Direct3D11;
7 | using SharpDX.DXGI;
8 |
9 | using Win32.BitBlt.Interop;
10 | using Win32.Shared;
11 | using Win32.Shared.Interfaces;
12 |
13 | using Device = SharpDX.Direct3D11.Device;
14 | using Rectangle = System.Drawing.Rectangle;
15 |
16 | namespace Win32.BitBlt
17 | {
18 | internal class BitBlt : ICaptureMethod
19 | {
20 | private IntPtr _hWnd;
21 |
22 | public void Dispose()
23 | {
24 | // Nothing to do
25 | }
26 |
27 | public bool IsCapturing { get; private set; }
28 |
29 | public void StartCapture(IntPtr hWnd, Device device, Factory factory)
30 | {
31 | var picker = new WindowPicker();
32 | _hWnd = picker.PickCaptureTarget(hWnd);
33 | if (_hWnd == IntPtr.Zero)
34 | return;
35 |
36 | IsCapturing = true;
37 | }
38 |
39 | public Texture2D TryGetNextFrameAsTexture2D(Device device)
40 | {
41 | if (_hWnd == IntPtr.Zero)
42 | return null;
43 |
44 | var hdcSrc = NativeMethods.GetDCEx(_hWnd, IntPtr.Zero, DeviceContextValues.Window | DeviceContextValues.Cache | DeviceContextValues.LockWindowUpdate);
45 | var hdcDest = NativeMethods.CreateCompatibleDC(hdcSrc);
46 | NativeMethods.GetWindowRect(_hWnd, out var rect);
47 | var (width, height) = (rect.Right - rect.Left, rect.Bottom - rect.Top);
48 | var hBitmap = NativeMethods.CreateCompatibleBitmap(hdcSrc, width, height);
49 | var hOld = NativeMethods.SelectObject(hdcDest, hBitmap);
50 | NativeMethods.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, TernaryRasterOperations.SRCCOPY);
51 | NativeMethods.SelectObject(hdcDest, hOld);
52 | NativeMethods.DeleteDC(hdcDest);
53 | NativeMethods.ReleaseDC(_hWnd, hdcSrc);
54 |
55 | using var img = Image.FromHbitmap(hBitmap);
56 | NativeMethods.DeleteObject(hBitmap);
57 |
58 | using var bitmap = img.Clone(Rectangle.FromLTRB(0, 0, width, height), PixelFormat.Format32bppArgb);
59 | var bits = bitmap.LockBits(Rectangle.FromLTRB(0, 0, width, height), ImageLockMode.ReadOnly, img.PixelFormat);
60 |
61 | var data = new DataBox { DataPointer = bits.Scan0, RowPitch = bits.Width * 4, SlicePitch = bits.Height };
62 |
63 | var texture2dDescription = new Texture2DDescription
64 | {
65 | ArraySize = 1,
66 | BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
67 | CpuAccessFlags = CpuAccessFlags.None,
68 | Format = Format.B8G8R8A8_UNorm,
69 | Height = height,
70 | MipLevels = 1,
71 | SampleDescription = new SampleDescription(1, 0),
72 | Usage = ResourceUsage.Default,
73 | Width = width
74 | };
75 | var texture2d = new Texture2D(device, texture2dDescription, new[] { data });
76 | bitmap.UnlockBits(bits);
77 |
78 | return texture2d;
79 | }
80 |
81 | public void StopCapture()
82 | {
83 | _hWnd = IntPtr.Zero;
84 | }
85 | }
86 | }
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/Interop/DeviceContextValues.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Win32.BitBlt.Interop
4 | {
5 | [Flags]
6 | internal enum DeviceContextValues : uint
7 | {
8 | ///
9 | /// DCX_WINDOW: Returns a DC that corresponds to the window rectangle rather
10 | /// than the client rectangle.
11 | ///
12 | Window = 0x00000001,
13 |
14 | ///
15 | /// DCX_CACHE: Returns a DC from the cache, rather than the OWNDC or CLASSDC
16 | /// window. Essentially overrides CS_OWNDC and CS_CLASSDC.
17 | ///
18 | Cache = 0x00000002,
19 |
20 | ///
21 | /// DCX_NORESETATTRS: Does not reset the attributes of this DC to the
22 | /// default attributes when this DC is released.
23 | ///
24 | NoResetAttrs = 0x00000004,
25 |
26 | ///
27 | /// DCX_CLIPCHILDREN: Excludes the visible regions of all child windows
28 | /// below the window identified by hWnd.
29 | ///
30 | ClipChildren = 0x00000008,
31 |
32 | ///
33 | /// DCX_CLIPSIBLINGS: Excludes the visible regions of all sibling windows
34 | /// above the window identified by hWnd.
35 | ///
36 | ClipSiblings = 0x00000010,
37 |
38 | ///
39 | /// DCX_PARENTCLIP: Uses the visible region of the parent window. The
40 | /// parent's WS_CLIPCHILDREN and CS_PARENTDC style bits are ignored. The origin is
41 | /// set to the upper-left corner of the window identified by hWnd.
42 | ///
43 | ParentClip = 0x00000020,
44 |
45 | ///
46 | /// DCX_EXCLUDERGN: The clipping region identified by hrgnClip is excluded
47 | /// from the visible region of the returned DC.
48 | ///
49 | ExcludeRgn = 0x00000040,
50 |
51 | ///
52 | /// DCX_INTERSECTRGN: The clipping region identified by hrgnClip is
53 | /// intersected with the visible region of the returned DC.
54 | ///
55 | IntersectRgn = 0x00000080,
56 |
57 | /// DCX_EXCLUDEUPDATE: Unknown...Undocumented
58 | ExcludeUpdate = 0x00000100,
59 |
60 | /// DCX_INTERSECTUPDATE: Unknown...Undocumented
61 | IntersectUpdate = 0x00000200,
62 |
63 | ///
64 | /// DCX_LOCKWINDOWUPDATE: Allows drawing even if there is a LockWindowUpdate
65 | /// call in effect that would otherwise exclude this window. Used for drawing during
66 | /// tracking.
67 | ///
68 | LockWindowUpdate = 0x00000400,
69 |
70 | ///
71 | /// DCX_VALIDATE When specified with DCX_INTERSECTUPDATE, causes the DC to
72 | /// be completely validated. Using this function with both DCX_INTERSECTUPDATE and
73 | /// DCX_VALIDATE is identical to using the BeginPaint function.
74 | ///
75 | Validate = 0x00200000
76 | }
77 | }
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/Interop/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Win32.BitBlt.Interop
5 | {
6 | internal static class NativeMethods
7 | {
8 | [DllImport("user32.dll")]
9 | internal static extern IntPtr GetDCEx(IntPtr hWnd, IntPtr hrgnClip, DeviceContextValues flags);
10 |
11 | [DllImport("user32.dll", SetLastError = true)]
12 | [return: MarshalAs(UnmanagedType.Bool)]
13 | internal static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
14 |
15 | [DllImport("user32.dll")]
16 | internal static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
17 |
18 | [DllImport("gdi32.dll", SetLastError = true)]
19 | [return: MarshalAs(UnmanagedType.Bool)]
20 | internal static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
21 |
22 | [DllImport("gdi32.dll", SetLastError = true)]
23 | internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);
24 |
25 | [DllImport("gdi32.dll")]
26 | internal static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
27 |
28 | [DllImport("gdi32.dll")]
29 | internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
30 |
31 | [DllImport("gdi32.dll")]
32 | internal static extern bool DeleteDC(IntPtr hdc);
33 |
34 | [DllImport("gdi32.dll")]
35 | [return: MarshalAs(UnmanagedType.Bool)]
36 | internal static extern bool DeleteObject(IntPtr hObject);
37 | }
38 | }
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/Interop/RECT.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Win32.BitBlt.Interop
4 | {
5 | [StructLayout(LayoutKind.Sequential)]
6 | internal struct RECT
7 | {
8 | public int Left; // x position of upper-left corner
9 | public int Top; // y position of upper-left corner
10 | public int Right; // x position of lower-right corner
11 | public int Bottom; // y position of lower-right corner
12 | }
13 | }
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/Interop/TernaryRasterOperations.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable InconsistentNaming
2 | // ReSharper disable UnusedMember.Global
3 | // ReSharper disable IdentifierTypo
4 |
5 | namespace Win32.BitBlt.Interop
6 | {
7 | internal enum TernaryRasterOperations : uint
8 | {
9 | /// dest = source
10 | SRCCOPY = 0x00CC0020,
11 |
12 | /// dest = source OR dest
13 | SRCPAINT = 0x00EE0086,
14 |
15 | /// dest = source AND dest
16 | SRCAND = 0x008800C6,
17 |
18 | /// dest = source XOR dest
19 | SRCINVERT = 0x00660046,
20 |
21 | /// dest = source AND (NOT dest)
22 | SRCERASE = 0x00440328,
23 |
24 | /// dest = (NOT source)
25 | NOTSRCCOPY = 0x00330008,
26 |
27 | /// dest = (NOT src) AND (NOT dest)
28 | NOTSRCERASE = 0x001100A6,
29 |
30 | /// dest = (source AND pattern)
31 | MERGECOPY = 0x00C000CA,
32 |
33 | /// dest = (NOT source) OR dest
34 | MERGEPAINT = 0x00BB0226,
35 |
36 | /// dest = pattern
37 | PATCOPY = 0x00F00021,
38 |
39 | /// dest = DPSnoo
40 | PATPAINT = 0x00FB0A09,
41 |
42 | /// dest = pattern XOR dest
43 | PATINVERT = 0x005A0049,
44 |
45 | /// dest = (NOT dest)
46 | DSTINVERT = 0x00550009,
47 |
48 | /// dest = BLACK
49 | BLACKNESS = 0x00000042,
50 |
51 | /// dest = WHITE
52 | WHITENESS = 0x00FF0062,
53 |
54 | ///
55 | /// Capture window as seen on screen. This includes layered windows
56 | /// such as WPF windows with AllowsTransparency="true"
57 | ///
58 | CAPTUREBLT = 0x40000000
59 | }
60 | }
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using Win32.Shared;
4 |
5 | namespace Win32.BitBlt
6 | {
7 | internal static class Program
8 | {
9 | [STAThread]
10 | public static void Main()
11 | {
12 | using var window = new DxWindow(".NET Window Capture Samples - Win32.DwmSharedSurface", new BitBlt());
13 | window.Show();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_INPUT {
2 | float4 position: POSITION;
3 | float2 uv : TEXCOORD;
4 | };
5 |
6 | struct PS_INPUT {
7 | float4 position : SV_POSITION;
8 | float2 uv : TEXCOORD;
9 | };
10 |
11 | Texture2D g_texture : register(t0);
12 | SamplerState g_sampler : register(s0);
13 |
14 | PS_INPUT VS(VS_INPUT input)
15 | {
16 | PS_INPUT output = (PS_INPUT)0;
17 | output.position = input.position;
18 | output.uv = input.uv;
19 |
20 | return output;
21 | }
22 |
23 | float4 PS(PS_INPUT input) : SV_TARGET
24 | {
25 | return g_texture.Sample(g_sampler, input.uv);
26 | }
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/Win32.BitBlt.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {5383738F-DCF5-4845-95B9-FFC1CD4830A3}
8 | WinExe
9 | Win32.BitBlt
10 | Win32.BitBlt
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | 8.0
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | 8.0
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | {6f7e0e32-f8be-44af-a21c-78f0fce1baa3}
47 | Win32.Shared
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | ..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll
63 |
64 |
65 | ..\packages\SharpDX.D3DCompiler.4.2.0\lib\net45\SharpDX.D3DCompiler.dll
66 |
67 |
68 | ..\packages\SharpDX.Desktop.4.2.0\lib\net45\SharpDX.Desktop.dll
69 |
70 |
71 | ..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll
72 |
73 |
74 | ..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll
75 |
76 |
77 | ..\packages\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | PreserveNewest
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/Source/Win32.BitBlt/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Source/Win32.DesktopDuplication/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Source/Win32.DesktopDuplication/DesktopDuplication.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using SharpDX.Direct3D11;
4 | using SharpDX.DXGI;
5 |
6 | using Win32.Shared.Interfaces;
7 |
8 | using Device = SharpDX.Direct3D11.Device;
9 |
10 | namespace Win32.DesktopDuplication
11 | {
12 | internal class DesktopDuplication : ICaptureMethod
13 | {
14 | private OutputDuplication _duplication;
15 |
16 | public void Dispose()
17 | {
18 | StopCapture();
19 | }
20 |
21 | public bool IsCapturing { get; private set; }
22 |
23 | public void StartCapture(IntPtr hWnd, Device device, Factory factory)
24 | {
25 | using var factory1 = factory.QueryInterface();
26 | using var adapter = factory1.GetAdapter1(0);
27 | using var output1 = adapter.GetOutput(0).QueryInterface();
28 |
29 | _duplication = output1.DuplicateOutput(device);
30 | IsCapturing = true;
31 | }
32 |
33 | public Texture2D TryGetNextFrameAsTexture2D(Device device)
34 | {
35 | if (_duplication == null)
36 | return null;
37 |
38 | var hr = _duplication.TryAcquireNextFrame(100, out _, out var desktopResourceOut);
39 | if (hr.Failure)
40 | return null;
41 |
42 | using var desktopTexture = desktopResourceOut.QueryInterface();
43 | var texture2dDescription = new Texture2DDescription
44 | {
45 | ArraySize = 1,
46 | BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
47 | CpuAccessFlags = CpuAccessFlags.None,
48 | Format = Format.B8G8R8A8_UNorm,
49 | Height = desktopTexture.Description.Height,
50 | MipLevels = 1,
51 | SampleDescription = new SampleDescription(1, 0),
52 | Usage = ResourceUsage.Default,
53 | Width = desktopTexture.Description.Width
54 | };
55 | var texture2d = new Texture2D(device, texture2dDescription);
56 | device.ImmediateContext.CopyResource(desktopTexture, texture2d);
57 |
58 | // release resources
59 | desktopResourceOut.Dispose();
60 | _duplication.ReleaseFrame();
61 |
62 | return texture2d;
63 | }
64 |
65 | public void StopCapture()
66 | {
67 | _duplication?.Dispose();
68 | IsCapturing = false;
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/Source/Win32.DesktopDuplication/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using Win32.Shared;
4 |
5 | namespace Win32.DesktopDuplication
6 | {
7 | internal static class Program
8 | {
9 | [STAThread]
10 | public static void Main()
11 | {
12 | var window = new DxWindow(".NET Window Capture Samples - Win32.DesktopDuplication", new DesktopDuplication());
13 | window.Show();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Source/Win32.DesktopDuplication/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_INPUT {
2 | float4 position: POSITION;
3 | float2 uv : TEXCOORD;
4 | };
5 |
6 | struct PS_INPUT {
7 | float4 position : SV_POSITION;
8 | float2 uv : TEXCOORD;
9 | };
10 |
11 | Texture2D g_texture : register(t0);
12 | SamplerState g_sampler : register(s0);
13 |
14 | PS_INPUT VS(VS_INPUT input)
15 | {
16 | PS_INPUT output = (PS_INPUT)0;
17 | output.position = input.position;
18 | output.uv = input.uv;
19 |
20 | return output;
21 | }
22 |
23 | float4 PS(PS_INPUT input) : SV_TARGET
24 | {
25 | return g_texture.Sample(g_sampler, input.uv);
26 | }
--------------------------------------------------------------------------------
/Source/Win32.DesktopDuplication/Win32.DesktopDuplication.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {674C59CA-34FD-41A3-8FE8-F2C8DA8801A4}
8 | WinExe
9 | Win32.DesktopDuplication
10 | Win32.DesktopDuplication
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | 8.0
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | {6f7e0e32-f8be-44af-a21c-78f0fce1baa3}
46 | Win32.Shared
47 |
48 |
49 |
50 |
51 | ..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll
52 |
53 |
54 | ..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll
55 |
56 |
57 | ..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | PreserveNewest
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/Source/Win32.DesktopDuplication/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Source/Win32.DwmSharedSurface/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Source/Win32.DwmSharedSurface/DwmSharedSurface.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using SharpDX.Direct3D11;
4 | using SharpDX.DXGI;
5 |
6 | using Win32.DwmSharedSurface.Interop;
7 | using Win32.Shared;
8 | using Win32.Shared.Interfaces;
9 |
10 | using Device = SharpDX.Direct3D11.Device;
11 |
12 | namespace Win32.DwmSharedSurface
13 | {
14 | internal class DwmSharedSurface : ICaptureMethod
15 | {
16 | private IntPtr _hWnd;
17 |
18 | public DwmSharedSurface()
19 | {
20 | IsCapturing = false;
21 | }
22 |
23 | public void Dispose()
24 | {
25 | StopCapture();
26 | }
27 |
28 | public bool IsCapturing { get; private set; }
29 |
30 | public void StartCapture(IntPtr hWnd, Device device, Factory factory)
31 | {
32 | var picker = new WindowPicker();
33 | _hWnd = picker.PickCaptureTarget(hWnd);
34 | if (_hWnd == IntPtr.Zero)
35 | return;
36 |
37 | IsCapturing = true;
38 | }
39 |
40 | public Texture2D TryGetNextFrameAsTexture2D(Device device)
41 | {
42 | if (_hWnd == IntPtr.Zero)
43 | return null;
44 |
45 | NativeMethods.DwmGetDxSharedSurface(_hWnd, out var phSurface, out _, out _, out _, out _);
46 | if (phSurface == IntPtr.Zero)
47 | {
48 | // Window Lost
49 | StopCapture();
50 | return null;
51 | }
52 |
53 | using var surfaceTexture = device.OpenSharedResource(phSurface);
54 |
55 | // using var surfaceTexture = new Texture2D(phSurface);
56 | var texture2dDescription = new Texture2DDescription
57 | {
58 | ArraySize = 1,
59 | BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
60 | CpuAccessFlags = CpuAccessFlags.None,
61 | Format = Format.B8G8R8A8_UNorm,
62 | Height = surfaceTexture.Description.Height,
63 | MipLevels = 1,
64 | SampleDescription = new SampleDescription(1, 0),
65 | Usage = ResourceUsage.Default,
66 | Width = surfaceTexture.Description.Width
67 | };
68 | var texture2d = new Texture2D(device, texture2dDescription);
69 | device.ImmediateContext.CopyResource(surfaceTexture, texture2d);
70 |
71 | return texture2d;
72 | }
73 |
74 | public void StopCapture()
75 | {
76 | _hWnd = IntPtr.Zero;
77 | IsCapturing = false;
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmSharedSurface/Interop/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Win32.DwmSharedSurface.Interop
5 | {
6 | public static class NativeMethods
7 | {
8 | public delegate bool DwmGetDxSharedSurfaceDelegate(IntPtr hWnd, out IntPtr phSurface, out long pAdapterLuid, out long pFmtWindow, out long pPresentFlags, out long pWin32KUpdateId);
9 |
10 | public static DwmGetDxSharedSurfaceDelegate DwmGetDxSharedSurface;
11 |
12 | static NativeMethods()
13 | {
14 | var ptr = GetProcAddress(GetModuleHandle("user32"), "DwmGetDxSharedSurface");
15 | DwmGetDxSharedSurface = Marshal.GetDelegateForFunctionPointer(ptr);
16 | }
17 |
18 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
19 | private static extern IntPtr GetModuleHandle(string lpModuleName);
20 |
21 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
22 | private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
23 | }
24 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmSharedSurface/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using Win32.Shared;
4 |
5 | namespace Win32.DwmSharedSurface
6 | {
7 | internal static class Program
8 | {
9 | [STAThread]
10 | public static void Main()
11 | {
12 | using var window = new DxWindow(".NET Window Capture Samples - Win32.DwmSharedSurface", new DwmSharedSurface());
13 | window.Show();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmSharedSurface/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_INPUT {
2 | float4 position: POSITION;
3 | float2 uv : TEXCOORD;
4 | };
5 |
6 | struct PS_INPUT {
7 | float4 position : SV_POSITION;
8 | float2 uv : TEXCOORD;
9 | };
10 |
11 | Texture2D g_texture : register(t0);
12 | SamplerState g_sampler : register(s0);
13 |
14 | PS_INPUT VS(VS_INPUT input)
15 | {
16 | PS_INPUT output = (PS_INPUT)0;
17 | output.position = input.position;
18 | output.uv = input.uv;
19 |
20 | return output;
21 | }
22 |
23 | float4 PS(PS_INPUT input) : SV_TARGET
24 | {
25 | return g_texture.Sample(g_sampler, input.uv);
26 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmSharedSurface/Win32.DwmSharedSurface.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {70C9B2CA-C253-41CB-87AD-AE18394D202F}
8 | WinExe
9 | Win32.DwmSharedSurface
10 | Win32.DwmSharedSurface
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | 8.0
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll
48 |
49 |
50 | ..\packages\SharpDX.D3DCompiler.4.2.0\lib\net45\SharpDX.D3DCompiler.dll
51 |
52 |
53 | ..\packages\SharpDX.Desktop.4.2.0\lib\net45\SharpDX.Desktop.dll
54 |
55 |
56 | ..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll
57 |
58 |
59 | ..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll
60 |
61 |
62 | ..\packages\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | PreserveNewest
77 |
78 |
79 |
80 |
81 | {6f7e0e32-f8be-44af-a21c-78f0fce1baa3}
82 | Win32.Shared
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/Source/Win32.DwmSharedSurface/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace Win32.DwmThumbnail
10 | {
11 | ///
12 | /// App.xaml の相互作用ロジック
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Interop/DWMWINDOWATTRIBUTE.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable FieldCanBeMadeReadOnly.Global
2 | // ReSharper disable InconsistentNaming
3 | // ReSharper disable MemberCanBePrivate.Global
4 |
5 | namespace Win32.DwmThumbnail.Interop
6 | {
7 | public enum DWMWINDOWATTRIBUTE
8 | {
9 | NCRenderingEnabled = 1,
10 | NCRenderingPolicy,
11 | TransitionsForceDisabled,
12 | AllowNCPaint,
13 | CaptionButtonBounds,
14 | NonClientRtlLayout,
15 | ForceIconicRepresentation,
16 | Flip3DPolicy,
17 | ExtendedFrameBounds,
18 | HasIconicBitmap,
19 | DisallowPeek,
20 | ExcludedFromPeek,
21 | Cloak,
22 | Cloaked,
23 | FreezeRepresentation
24 | }
25 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Interop/DWM_THUMBNAIL_PROPERTIES.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | // ReSharper disable FieldCanBeMadeReadOnly.Global
4 | // ReSharper disable InconsistentNaming
5 | // ReSharper disable MemberCanBePrivate.Global
6 |
7 | namespace Win32.DwmThumbnail.Interop
8 | {
9 | [StructLayout(LayoutKind.Sequential)]
10 | public struct DWM_THUMBNAIL_PROPERTIES
11 | {
12 | public int dwFlags;
13 | public RECT rcDestination;
14 | public RECT rcSource;
15 | public byte opacity;
16 |
17 | [MarshalAs(UnmanagedType.Bool, SizeConst = 4)]
18 | public bool fVisible;
19 |
20 | public bool fSourceClientAreaOnly;
21 | }
22 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Interop/DWM_TNP.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | // ReSharper disable FieldCanBeMadeReadOnly.Global
4 | // ReSharper disable InconsistentNaming
5 | // ReSharper disable MemberCanBePrivate.Global
6 |
7 | namespace Win32.DwmThumbnail.Interop
8 | {
9 | [Flags]
10 | public enum DWM_TNP
11 | {
12 | DWM_TNP_RECTDESTINATION = 0x00000001,
13 |
14 | DWM_TNP_RECTSOURCE = 0x00000002,
15 |
16 | DWM_TNP_OPACITY = 0x00000004,
17 |
18 | DWM_TNP_VISIBLE = 0x00000008,
19 |
20 | DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010
21 | }
22 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Interop/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Windows;
4 |
5 | namespace Win32.DwmThumbnail.Interop
6 | {
7 | public static class NativeMethods
8 | {
9 | [DllImport("dwmapi.dll", SetLastError = true)]
10 | public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb);
11 |
12 | [DllImport("dwmapi.dll")]
13 | public static extern int DwmUnregisterThumbnail(IntPtr thumb);
14 |
15 | [DllImport("dwmapi.dll", PreserveSig = false)]
16 | public static extern void DwmQueryThumbnailSourceSize(IntPtr hThumbnail, out Size size);
17 |
18 | [DllImport("dwmapi.dll", PreserveSig = true)]
19 | public static extern int DwmUpdateThumbnailProperties(IntPtr hThumbnail, ref DWM_THUMBNAIL_PROPERTIES props);
20 |
21 | [DllImport("dwmapi.dll")]
22 | public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute);
23 | }
24 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Interop/RECT.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | // ReSharper disable FieldCanBeMadeReadOnly.Global
4 | // ReSharper disable InconsistentNaming
5 | // ReSharper disable MemberCanBePrivate.Global
6 |
7 | namespace Win32.DwmThumbnail.Interop
8 | {
9 | [StructLayout(LayoutKind.Sequential)]
10 | public struct RECT
11 | {
12 | public int left;
13 | public int top;
14 | public int right;
15 | public int bottom;
16 |
17 | public bool IsEmpty()
18 | {
19 | return left == 0 && top == 0 && right == 0 && bottom == 0;
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Interop;
4 |
5 | using Win32.DwmThumbnail.Interop;
6 | using Win32.Shared;
7 |
8 | namespace Win32.DwmThumbnail
9 | {
10 | ///
11 | /// MainWindow.xaml の相互作用ロジック
12 | ///
13 | public partial class MainWindow : Window
14 | {
15 | private IntPtr _hThumbnail = IntPtr.Zero;
16 | private IntPtr _hWnd = IntPtr.Zero;
17 |
18 | public MainWindow()
19 | {
20 | InitializeComponent();
21 | Loaded += OnLoaded;
22 | SizeChanged += OnSizeChanged;
23 | }
24 |
25 | private void OnLoaded(object sender, RoutedEventArgs e)
26 | {
27 | do
28 | {
29 | _hWnd = new WindowPicker().PickCaptureTarget(new WindowInteropHelper(this).Handle);
30 | } while (_hWnd == IntPtr.Zero);
31 |
32 | var hr = NativeMethods.DwmRegisterThumbnail(new WindowInteropHelper(this).Handle, _hWnd, out _hThumbnail);
33 | if (hr != 0)
34 | return;
35 |
36 | UpdateThumbnailProperties();
37 | }
38 |
39 | private void OnSizeChanged(object sender, SizeChangedEventArgs e)
40 | {
41 | if (_hThumbnail == IntPtr.Zero)
42 | return;
43 |
44 | UpdateThumbnailProperties();
45 | }
46 |
47 | private void UpdateThumbnailProperties()
48 | {
49 | var dpi = GetDpiScaleFactor();
50 | var props = new DWM_THUMBNAIL_PROPERTIES
51 | {
52 | fVisible = true,
53 | dwFlags = (int) (DWM_TNP.DWM_TNP_VISIBLE | DWM_TNP.DWM_TNP_OPACITY | DWM_TNP.DWM_TNP_RECTDESTINATION | DWM_TNP.DWM_TNP_SOURCECLIENTAREAONLY),
54 | opacity = 255,
55 | rcDestination = new RECT { left = 0, top = 0, bottom = (int) (Grid.ActualHeight * dpi.Y), right = (int) (Grid.ActualWidth * dpi.X) },
56 | fSourceClientAreaOnly = true
57 | };
58 |
59 | NativeMethods.DwmUpdateThumbnailProperties(_hThumbnail, ref props);
60 | }
61 |
62 | private Point GetDpiScaleFactor()
63 | {
64 | var source = PresentationSource.FromVisual(this);
65 | return source?.CompositionTarget != null ? new Point(source.CompositionTarget.TransformToDevice.M11, source.CompositionTarget.TransformToDevice.M22) : new Point(1.0d, 1.0d);
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // アセンブリに関する一般情報は以下の属性セットをとおして制御されます。
8 | // アセンブリに関連付けられている情報を変更するには、
9 | // これらの属性値を変更してください。
10 | [assembly: AssemblyTitle("Win32.DwmThumbnail")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("Win32.DwmThumbnail")]
15 | [assembly: AssemblyCopyright("Copyright © 2019")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから
20 | // 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、
21 | // その型の ComVisible 属性を true に設定してください。
22 | [assembly: ComVisible(false)]
23 |
24 | //ローカライズ可能なアプリケーションのビルドを開始するには、
25 | //.csproj ファイルの CultureYouAreCodingWith を
26 | // 内部で設定します。たとえば、
27 | //ソース ファイルで英語を使用している場合、 を en-US に設定します。次に、
28 | //下の NeutralResourceLanguage 属性のコメントを解除します。下の行の "en-US" を
29 | //プロジェクト ファイルの UICulture 設定と一致するよう更新します。
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //テーマ固有のリソース ディクショナリが置かれている場所
36 | //(リソースがページ、
37 | // またはアプリケーション リソース ディクショナリに見つからない場合に使用されます)
38 | ResourceDictionaryLocation.SourceAssembly //汎用リソース ディクショナリが置かれている場所
39 | //(リソースがページ、
40 | //アプリケーション、またはいずれのテーマ固有のリソース ディクショナリにも見つからない場合に使用されます)
41 | )]
42 |
43 |
44 | // アセンブリのバージョン情報は次の 4 つの値で構成されています:
45 | //
46 | // メジャー バージョン
47 | // マイナー バージョン
48 | // ビルド番号
49 | // リビジョン
50 | //
51 | // すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます
52 | // 既定値にすることができます:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // このコードはツールによって生成されました。
4 | // ランタイム バージョン:4.0.30319.42000
5 | //
6 | // このファイルへの変更は、正しくない動作の原因になったり、
7 | // コードが再生成されるときに失われたりします。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Win32.DwmThumbnail.Properties
12 | {
13 |
14 |
15 | ///
16 | /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。
17 | ///
18 | // このクラスは StronglyTypedResourceBuilder クラスによって ResGen
19 | // または Visual Studio のようなツールを使用して自動生成されました。
20 | // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に
21 | // ResGen を実行し直すか、または VS プロジェクトをリビルドします。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// このクラスで使用されるキャッシュされた ResourceManager インスタンスを返します。
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Win32.DwmThumbnail.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// すべてについて、現在のスレッドの CurrentUICulture プロパティをオーバーライドします
56 | /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Win32.DwmThumbnail.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Source/Win32.DwmThumbnail/Win32.DwmThumbnail.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {121F4F48-4383-4A01-A026-54C49E653FD9}
8 | WinExe
9 | Win32.DwmThumbnail
10 | Win32.DwmThumbnail
11 | v4.7.2
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 | true
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 4.0
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | MSBuild:Compile
56 | Designer
57 |
58 |
59 | MSBuild:Compile
60 | Designer
61 |
62 |
63 | App.xaml
64 | Code
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | MainWindow.xaml
73 | Code
74 |
75 |
76 |
77 |
78 | Code
79 |
80 |
81 | True
82 | True
83 | Resources.resx
84 |
85 |
86 | True
87 | Settings.settings
88 | True
89 |
90 |
91 | ResXFileCodeGenerator
92 | Resources.Designer.cs
93 |
94 |
95 | SettingsSingleFileGenerator
96 | Settings.Designer.cs
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | {6f7e0e32-f8be-44af-a21c-78f0fce1baa3}
105 | Win32.Shared
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/DxWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using SharpDX;
4 | using SharpDX.D3DCompiler;
5 | using SharpDX.Direct3D;
6 | using SharpDX.Direct3D11;
7 | using SharpDX.DXGI;
8 | using SharpDX.Mathematics.Interop;
9 | using SharpDX.Windows;
10 |
11 | using Win32.Shared.Interfaces;
12 |
13 | using Buffer = SharpDX.Direct3D11.Buffer;
14 | using Device = SharpDX.Direct3D11.Device;
15 | using Resource = SharpDX.Direct3D11.Resource;
16 |
17 | namespace Win32.Shared
18 | {
19 | public class DxWindow : IDisposable
20 | {
21 | private readonly ICaptureMethod _captureMethod;
22 | private readonly string _title;
23 |
24 | public DxWindow(string title, ICaptureMethod captureMethod)
25 | {
26 | _title = title;
27 | _captureMethod = captureMethod;
28 | }
29 |
30 | public void Dispose()
31 | {
32 | _captureMethod?.Dispose();
33 | }
34 |
35 | public void Show()
36 | {
37 | using var form = new RenderForm(_title);
38 |
39 | // create a Device and SwapChain
40 | var swapChainDescription = new SwapChainDescription
41 | {
42 | BufferCount = 2,
43 | Flags = SwapChainFlags.None,
44 | IsWindowed = true,
45 | ModeDescription = new ModeDescription(form.ClientSize.Width, form.ClientSize.Height, new Rational(60, 1), Format.B8G8R8A8_UNorm),
46 | OutputHandle = form.Handle,
47 | SampleDescription = new SampleDescription(1, 0),
48 | SwapEffect = SwapEffect.Discard,
49 | Usage = Usage.RenderTargetOutput
50 | };
51 | Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, swapChainDescription, out var device, out var swapChain);
52 | using var swapChain1 = swapChain.QueryInterface();
53 |
54 | // ignore all Windows events
55 | using var factory = swapChain1.GetParent();
56 | factory.MakeWindowAssociation(form.Handle, WindowAssociationFlags.IgnoreAll);
57 |
58 | using var vertexShaderByteCode = ShaderBytecode.CompileFromFile("./Shader.fx", "VS", "vs_5_0");
59 | using var vertexShader = new VertexShader(device, vertexShaderByteCode);
60 |
61 | using var pixelShaderByteCode = ShaderBytecode.CompileFromFile("./Shader.fx", "PS", "ps_5_0");
62 | using var pixelShader = new PixelShader(device, pixelShaderByteCode);
63 |
64 | using var layout = new InputLayout(device, vertexShaderByteCode, new[]
65 | {
66 | new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0),
67 | new InputElement("TEXCOORD", 0, Format.R32G32_Float, 12, 0)
68 | });
69 |
70 | using var vertexes = Buffer.Create(device, BindFlags.VertexBuffer, new[]
71 | {
72 | new Vertex { Position = new RawVector3(-1.0f, 1.0f, 0.5f), TexCoord = new RawVector2(0.0f, 0.0f) },
73 | new Vertex { Position = new RawVector3(1.0f, 1.0f, 0.5f), TexCoord = new RawVector2(1.0f, 0.0f) },
74 | new Vertex { Position = new RawVector3(-1.0f, -1.0f, 0.5f), TexCoord = new RawVector2(0.0f, 1.0f) },
75 | new Vertex { Position = new RawVector3(1.0f, -1.0f, 0.5f), TexCoord = new RawVector2(1.0f, 1.0f) }
76 | });
77 |
78 | var samplerStateDescription = new SamplerStateDescription
79 | {
80 | AddressU = TextureAddressMode.Wrap,
81 | AddressV = TextureAddressMode.Wrap,
82 | AddressW = TextureAddressMode.Wrap,
83 | Filter = Filter.MinMagMipLinear
84 | };
85 |
86 | device.ImmediateContext.InputAssembler.InputLayout = layout;
87 | device.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;
88 | device.ImmediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexes, Utilities.SizeOf(), 0));
89 | device.ImmediateContext.VertexShader.Set(vertexShader);
90 | device.ImmediateContext.PixelShader.SetSampler(0, new SamplerState(device, samplerStateDescription));
91 | device.ImmediateContext.PixelShader.Set(pixelShader);
92 |
93 | // create a first views
94 | var backBuffer = Resource.FromSwapChain(swapChain1, 0);
95 | var renderView = new RenderTargetView(device, backBuffer);
96 |
97 | device.ImmediateContext.Rasterizer.SetViewport(0, 0, form.ClientSize.Width, form.ClientSize.Height);
98 | device.ImmediateContext.OutputMerger.SetTargets(renderView);
99 |
100 | // listen events (but processed in render loop)
101 | var isResized = false;
102 | form.UserResized += (_, __) => isResized = true;
103 |
104 | RenderLoop.Run(form, () =>
105 | {
106 | // ReSharper disable AccessToDisposedClosure
107 | if (!_captureMethod.IsCapturing)
108 | _captureMethod.StartCapture(form.Handle, device, factory);
109 |
110 | if (isResized)
111 | {
112 | Utilities.Dispose(ref backBuffer);
113 | Utilities.Dispose(ref renderView);
114 |
115 | swapChain1.ResizeBuffers(swapChainDescription.BufferCount, form.ClientSize.Width, form.ClientSize.Height, Format.Unknown, SwapChainFlags.None);
116 | backBuffer = Resource.FromSwapChain(swapChain1, 0);
117 | renderView = new RenderTargetView(device, backBuffer);
118 |
119 | device.ImmediateContext.Rasterizer.SetViewport(0, 0, form.ClientSize.Width, form.ClientSize.Height);
120 | device.ImmediateContext.OutputMerger.SetTargets(renderView);
121 |
122 | isResized = false;
123 | }
124 |
125 | // clear view
126 | device.ImmediateContext.ClearRenderTargetView(renderView, new RawColor4(1.0f, 1.0f, 1.0f, 1.0f));
127 |
128 | using var texture2d = _captureMethod.TryGetNextFrameAsTexture2D(device);
129 | if (texture2d != null)
130 | {
131 | using var shaderResourceView = new ShaderResourceView(device, texture2d);
132 | device.ImmediateContext.PixelShader.SetShaderResource(0, shaderResourceView);
133 | }
134 |
135 | // draw it
136 | device.ImmediateContext.Draw(4, 0);
137 | swapChain1.Present(1, PresentFlags.None, new PresentParameters());
138 |
139 | // ReSharper restore AccessToDisposedClosure
140 | });
141 |
142 | renderView.Dispose();
143 | backBuffer.Dispose();
144 | swapChain.Dispose();
145 | device.Dispose();
146 | }
147 | }
148 | }
--------------------------------------------------------------------------------
/Source/Win32.Shared/Interfaces/ICaptureMethod.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using SharpDX.Direct3D11;
4 | using SharpDX.DXGI;
5 |
6 | using Device = SharpDX.Direct3D11.Device;
7 |
8 | namespace Win32.Shared.Interfaces
9 | {
10 | public interface ICaptureMethod : IDisposable
11 | {
12 | bool IsCapturing { get; }
13 |
14 | void StartCapture(IntPtr hWnd, Device device, Factory factory);
15 |
16 | Texture2D TryGetNextFrameAsTexture2D(Device device);
17 |
18 | void StopCapture();
19 | }
20 | }
--------------------------------------------------------------------------------
/Source/Win32.Shared/Interop/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Text;
4 |
5 | namespace Win32.Shared.Interop
6 | {
7 | public static class NativeMethods
8 | {
9 | public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
10 |
11 | [DllImport("user32.dll")]
12 | [return: MarshalAs(UnmanagedType.Bool)]
13 | public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
14 |
15 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
16 | public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
17 |
18 | [DllImport("user32.dll")]
19 | public static extern bool IsWindowVisible(IntPtr hWnd);
20 |
21 | [DllImport("user32.dll", SetLastError = true)]
22 | public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
23 | }
24 | }
--------------------------------------------------------------------------------
/Source/Win32.Shared/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // アセンブリに関する一般情報は以下の属性セットをとおして制御されます。
8 | // アセンブリに関連付けられている情報を変更するには、
9 | // これらの属性値を変更してください。
10 | [assembly: AssemblyTitle("Win32.Shared")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("Win32.Shared")]
15 | [assembly: AssemblyCopyright("Copyright © 2019")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから
20 | // 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、
21 | // その型の ComVisible 属性を true に設定してください。
22 | [assembly: ComVisible(false)]
23 |
24 | //ローカライズ可能なアプリケーションのビルドを開始するには、
25 | //.csproj ファイルの CultureYouAreCodingWith を
26 | // 内部で設定します。たとえば、
27 | //ソース ファイルで英語を使用している場合、 を en-US に設定します。次に、
28 | //下の NeutralResourceLanguage 属性のコメントを解除します。下の行の "en-US" を
29 | //プロジェクト ファイルの UICulture 設定と一致するよう更新します。
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //テーマ固有のリソース ディクショナリが置かれている場所
36 | //(リソースがページ、
37 | // またはアプリケーション リソース ディクショナリに見つからない場合に使用されます)
38 | ResourceDictionaryLocation.SourceAssembly //汎用リソース ディクショナリが置かれている場所
39 | //(リソースがページ、
40 | //アプリケーション、またはいずれのテーマ固有のリソース ディクショナリにも見つからない場合に使用されます)
41 | )]
42 |
43 |
44 | // アセンブリのバージョン情報は次の 4 つの値で構成されています:
45 | //
46 | // メジャー バージョン
47 | // マイナー バージョン
48 | // ビルド番号
49 | // リビジョン
50 | //
51 | // すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます
52 | // 既定値にすることができます:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // このコードはツールによって生成されました。
4 | // ランタイム バージョン:4.0.30319.42000
5 | //
6 | // このファイルへの変更は、正しくない動作の原因になったり、
7 | // コードが再生成されるときに失われたりします。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Win32.Shared.Properties
12 | {
13 |
14 |
15 | ///
16 | /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。
17 | ///
18 | // このクラスは StronglyTypedResourceBuilder クラスによって ResGen
19 | // または Visual Studio のようなツールを使用して自動生成されました。
20 | // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に
21 | // ResGen を実行し直すか、または VS プロジェクトをリビルドします。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// このクラスで使用されるキャッシュされた ResourceManager インスタンスを返します。
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Win32.Shared.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// すべてについて、現在のスレッドの CurrentUICulture プロパティをオーバーライドします
56 | /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Win32.Shared.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/Vertex.cs:
--------------------------------------------------------------------------------
1 | using SharpDX.Mathematics.Interop;
2 |
3 | namespace Win32.Shared
4 | {
5 | internal struct Vertex
6 | {
7 | public RawVector3 Position;
8 | public RawVector2 TexCoord;
9 | }
10 | }
--------------------------------------------------------------------------------
/Source/Win32.Shared/Win32.Shared.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {6F7E0E32-F8BE-44AF-A21C-78F0FCE1BAA3}
8 | Library
9 | Win32.Shared
10 | Win32.Shared
11 | v4.7.2
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 | true
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 | 8.0
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 |
41 |
42 |
43 | ..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll
44 |
45 |
46 | ..\packages\SharpDX.D3DCompiler.4.2.0\lib\net45\SharpDX.D3DCompiler.dll
47 |
48 |
49 | ..\packages\SharpDX.Desktop.4.2.0\lib\net45\SharpDX.Desktop.dll
50 |
51 |
52 | ..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll
53 |
54 |
55 | ..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll
56 |
57 |
58 | ..\packages\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | 4.0
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | MSBuild:Compile
80 | Designer
81 |
82 |
83 |
84 |
85 |
86 |
87 | WindowPicker.xaml
88 | Code
89 |
90 |
91 |
92 |
93 | Code
94 |
95 |
96 | True
97 | True
98 | Resources.resx
99 |
100 |
101 | True
102 | Settings.settings
103 | True
104 |
105 |
106 | ResXFileCodeGenerator
107 | Resources.Designer.cs
108 |
109 |
110 |
111 | SettingsSingleFileGenerator
112 | Settings.Designer.cs
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/WindowPicker.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Source/Win32.Shared/WindowPicker.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows;
6 | using System.Windows.Input;
7 | using System.Windows.Interop;
8 |
9 | using Win32.Shared.Interop;
10 |
11 | namespace Win32.Shared
12 | {
13 | ///
14 | /// MainWindow.xaml の相互作用ロジック
15 | ///
16 | public partial class WindowPicker : Window
17 | {
18 | private readonly string[] _ignoreProcesses = { "applicationframehost", "shellexperiencehost", "systemsettings", "winstore.app", "searchui" };
19 |
20 | public WindowPicker()
21 | {
22 | InitializeComponent();
23 | Loaded += OnLoaded;
24 | }
25 |
26 | private void OnLoaded(object sender, RoutedEventArgs e)
27 | {
28 | FindWindows();
29 | }
30 |
31 | public IntPtr PickCaptureTarget(IntPtr hWnd)
32 | {
33 | new WindowInteropHelper(this).Owner = hWnd;
34 | ShowDialog();
35 |
36 | return ((CapturableWindow?) Windows.SelectedItem)?.Handle ?? IntPtr.Zero;
37 | }
38 |
39 | private void FindWindows()
40 | {
41 | var wih = new WindowInteropHelper(this);
42 | NativeMethods.EnumWindows((hWnd, lParam) =>
43 | {
44 | // ignore invisible windows
45 | if (!NativeMethods.IsWindowVisible(hWnd))
46 | return true;
47 |
48 | // ignore untitled windows
49 | var title = new StringBuilder(1024);
50 | NativeMethods.GetWindowText(hWnd, title, title.Capacity);
51 | if (string.IsNullOrWhiteSpace(title.ToString()))
52 | return true;
53 |
54 | // ignore me
55 | if (wih.Handle == hWnd)
56 | return true;
57 |
58 | NativeMethods.GetWindowThreadProcessId(hWnd, out var processId);
59 |
60 | // ignore by process name
61 | var process = Process.GetProcessById((int) processId);
62 | if (_ignoreProcesses.Contains(process.ProcessName.ToLower()))
63 | return true;
64 |
65 | Windows.Items.Add(new CapturableWindow
66 | {
67 | Handle = hWnd,
68 | Name = $"{title} ({process.ProcessName}.exe)"
69 | });
70 |
71 | return true;
72 | }, IntPtr.Zero);
73 | }
74 |
75 | private void WindowsOnMouseDoubleClick(object sender, MouseButtonEventArgs e)
76 | {
77 | Close();
78 | }
79 | }
80 |
81 | public struct CapturableWindow
82 | {
83 | public string Name { get; set; }
84 | public IntPtr Handle { get; set; }
85 | }
86 | }
--------------------------------------------------------------------------------
/Source/Win32.Shared/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Source/WinRT.GraphicsCapture/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Source/WinRT.GraphicsCapture/GraphicsCapture.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Runtime.InteropServices.WindowsRuntime;
4 |
5 | using Windows.Graphics.Capture;
6 | using Windows.Graphics.DirectX;
7 | using Windows.Graphics.DirectX.Direct3D11;
8 |
9 | using SharpDX.Direct3D11;
10 | using SharpDX.DXGI;
11 |
12 | using Win32.Shared;
13 | using Win32.Shared.Interfaces;
14 |
15 | using WinRT.GraphicsCapture.Interop;
16 |
17 | using Device = SharpDX.Direct3D11.Device;
18 |
19 | namespace WinRT.GraphicsCapture
20 | {
21 | internal class GraphicsCapture : ICaptureMethod
22 | {
23 | private static readonly Guid _graphicsCaptureItemIid = new Guid("79C3F95B-31F7-4EC2-A464-632EF5D30760");
24 | private Direct3D11CaptureFramePool _captureFramePool;
25 | private GraphicsCaptureItem _captureItem;
26 | private GraphicsCaptureSession _captureSession;
27 |
28 | public GraphicsCapture()
29 | {
30 | IsCapturing = false;
31 | }
32 |
33 | public bool IsCapturing { get; private set; }
34 |
35 | public void Dispose()
36 | {
37 | StopCapture();
38 | }
39 |
40 | public void StartCapture(IntPtr hWnd, Device device, Factory factory)
41 | {
42 | #region GraphicsCapturePicker version
43 |
44 | /*
45 | var capturePicker = new GraphicsCapturePicker();
46 |
47 | // ReSharper disable once PossibleInvalidCastException
48 | // ReSharper disable once SuspiciousTypeConversion.Global
49 | var initializer = (IInitializeWithWindow)(object)capturePicker;
50 | initializer.Initialize(hWnd);
51 |
52 | _captureItem = capturePicker.PickSingleItemAsync().AsTask().Result;
53 | */
54 |
55 | #endregion
56 |
57 | #region Window Handle version
58 |
59 | var capturePicker = new WindowPicker();
60 | var captureHandle = capturePicker.PickCaptureTarget(hWnd);
61 | if (captureHandle == IntPtr.Zero)
62 | return;
63 |
64 | _captureItem = CreateItemForWindow(captureHandle);
65 |
66 | #endregion
67 |
68 | if (_captureItem == null)
69 | return;
70 |
71 | _captureItem.Closed += CaptureItemOnClosed;
72 |
73 | var hr = NativeMethods.CreateDirect3D11DeviceFromDXGIDevice(device.NativePointer, out var pUnknown);
74 | if (hr != 0)
75 | {
76 | StopCapture();
77 | return;
78 | }
79 |
80 | var winrtDevice = (IDirect3DDevice) Marshal.GetObjectForIUnknown(pUnknown);
81 | Marshal.Release(pUnknown);
82 |
83 | _captureFramePool = Direct3D11CaptureFramePool.Create(winrtDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, _captureItem.Size);
84 | _captureSession = _captureFramePool.CreateCaptureSession(_captureItem);
85 | _captureSession.StartCapture();
86 | IsCapturing = true;
87 | }
88 |
89 | public Texture2D TryGetNextFrameAsTexture2D(Device device)
90 | {
91 | using var frame = _captureFramePool?.TryGetNextFrame();
92 | if (frame == null)
93 | return null;
94 |
95 | // ReSharper disable once SuspiciousTypeConversion.Global
96 | var surfaceDxgiInterfaceAccess = (IDirect3DDxgiInterfaceAccess) frame.Surface;
97 | var pResource = surfaceDxgiInterfaceAccess.GetInterface(new Guid("dc8e63f3-d12b-4952-b47b-5e45026a862d"));
98 |
99 | using var surfaceTexture = new Texture2D(pResource); // shared resource
100 | var texture2dDescription = new Texture2DDescription
101 | {
102 | ArraySize = 1,
103 | BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
104 | CpuAccessFlags = CpuAccessFlags.None,
105 | Format = Format.B8G8R8A8_UNorm,
106 | Height = surfaceTexture.Description.Height,
107 | MipLevels = 1,
108 | SampleDescription = new SampleDescription(1, 0),
109 | Usage = ResourceUsage.Default,
110 | Width = surfaceTexture.Description.Width
111 | };
112 | var texture2d = new Texture2D(device, texture2dDescription);
113 | device.ImmediateContext.CopyResource(surfaceTexture, texture2d);
114 |
115 | return texture2d;
116 | }
117 |
118 | public void StopCapture() // ...or release resources
119 | {
120 | _captureSession?.Dispose();
121 | _captureFramePool?.Dispose();
122 | _captureSession = null;
123 | _captureFramePool = null;
124 | _captureItem = null;
125 | IsCapturing = false;
126 | }
127 |
128 | // ReSharper disable once SuspiciousTypeConversion.Global
129 | private static GraphicsCaptureItem CreateItemForWindow(IntPtr hWnd)
130 | {
131 | var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem));
132 | var interop = (IGraphicsCaptureItemInterop) factory;
133 | var pointer = interop.CreateForWindow(hWnd, typeof(GraphicsCaptureItem).GetInterface("IGraphicsCaptureItem").GUID);
134 | var capture = Marshal.GetObjectForIUnknown(pointer) as GraphicsCaptureItem;
135 | Marshal.Release(pointer);
136 |
137 | return capture;
138 | }
139 |
140 | private void CaptureItemOnClosed(GraphicsCaptureItem sender, object args)
141 | {
142 | StopCapture();
143 | }
144 | }
145 | }
--------------------------------------------------------------------------------
/Source/WinRT.GraphicsCapture/Interop/ComObjects.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace WinRT.GraphicsCapture.Interop
5 | {
6 | [ComImport]
7 | [Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")]
8 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
9 | public interface IInitializeWithWindow
10 | {
11 | void Initialize(IntPtr hWnd);
12 | }
13 |
14 | [ComImport]
15 | [Guid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1")]
16 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
17 | public interface IDirect3DDxgiInterfaceAccess : IDisposable
18 | {
19 | IntPtr GetInterface([In] ref Guid iid);
20 | }
21 |
22 | [ComImport]
23 | [Guid("3628E81B-3CAC-4C60-B7F4-23CE0E0C3356")]
24 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
25 | public interface IGraphicsCaptureItemInterop
26 | {
27 | IntPtr CreateForWindow([In] IntPtr hWnd, ref Guid iid);
28 |
29 | IntPtr CreateForMonitor([In] IntPtr hMonitor, ref Guid iid);
30 | }
31 | }
--------------------------------------------------------------------------------
/Source/WinRT.GraphicsCapture/Interop/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace WinRT.GraphicsCapture.Interop
5 | {
6 | internal static class NativeMethods
7 | {
8 | [DllImport("d3d11.dll", EntryPoint = "CreateDirect3D11DeviceFromDXGIDevice", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
9 | public static extern uint CreateDirect3D11DeviceFromDXGIDevice(IntPtr dxgiDevice, out IntPtr graphicsDevice);
10 | }
11 | }
--------------------------------------------------------------------------------
/Source/WinRT.GraphicsCapture/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using Win32.Shared;
4 |
5 | namespace WinRT.GraphicsCapture
6 | {
7 | internal static class Program
8 | {
9 | [STAThread]
10 | public static void Main()
11 | {
12 | using var window = new DxWindow(".NET Window Capture Samples - WinRT.GraphicsCapture", new GraphicsCapture());
13 | window.Show();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Source/WinRT.GraphicsCapture/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_INPUT {
2 | float4 position: POSITION;
3 | float2 uv : TEXCOORD;
4 | };
5 |
6 | struct PS_INPUT {
7 | float4 position : SV_POSITION;
8 | float2 uv : TEXCOORD;
9 | };
10 |
11 | Texture2D g_texture : register(t0);
12 | SamplerState g_sampler : register(s0);
13 |
14 | PS_INPUT VS(VS_INPUT input)
15 | {
16 | PS_INPUT output = (PS_INPUT)0;
17 | output.position = input.position;
18 | output.uv = input.uv;
19 |
20 | return output;
21 | }
22 |
23 | float4 PS(PS_INPUT input) : SV_TARGET
24 | {
25 | return g_texture.Sample(g_sampler, input.uv);
26 | }
--------------------------------------------------------------------------------
/Source/WinRT.GraphicsCapture/WinRT.GraphicsCapture.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {0654DF3F-FBB5-44CD-B5D8-6715D2A73531}
8 | WinExe
9 | WinRT.GraphicsCapture
10 | WinRT.GraphicsCapture
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 | 8.0
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | PreserveNewest
61 |
62 |
63 |
64 |
65 | 10.0.18362.2002-preview
66 |
67 |
68 | 4.2.0
69 |
70 |
71 | 4.6.0-preview4.19212.13
72 |
73 |
74 | 4.6.0-preview4.19212.13
75 |
76 |
77 |
78 |
79 | {6f7e0e32-f8be-44af-a21c-78f0fce1baa3}
80 | Win32.Shared
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------