├── .gitignore
├── DesktopDuplication.Demo
├── App.config
├── DesktopDuplication.Demo.csproj
├── FormDemo.Designer.cs
├── FormDemo.cs
├── FormDemo.resx
├── Program.cs
└── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── DesktopDuplication.sln
└── DesktopDuplication
├── DesktopDuplication.csproj
├── DesktopDuplicationException.cs
├── DesktopDuplicator.cs
├── DesktopFrame.cs
├── MovedRegion.cs
├── PointerInfo.cs
├── Properties
└── AssemblyInfo.cs
└── packages.config
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | # DNX
42 | project.lock.json
43 | artifacts/
44 |
45 | *_i.c
46 | *_p.c
47 | *_i.h
48 | *.ilk
49 | *.meta
50 | *.obj
51 | *.pch
52 | *.pdb
53 | *.pgc
54 | *.pgd
55 | *.rsp
56 | *.sbr
57 | *.tlb
58 | *.tli
59 | *.tlh
60 | *.tmp
61 | *.tmp_proj
62 | *.log
63 | *.vspscc
64 | *.vssscc
65 | .builds
66 | *.pidb
67 | *.svclog
68 | *.scc
69 |
70 | # Chutzpah Test files
71 | _Chutzpah*
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 |
86 | # TFS 2012 Local Workspace
87 | $tf/
88 |
89 | # Guidance Automation Toolkit
90 | *.gpState
91 |
92 | # ReSharper is a .NET coding add-in
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings.user
96 |
97 | # JustCode is a .NET coding add-in
98 | .JustCode
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | _NCrunch_*
108 | .*crunch*.local.xml
109 |
110 | # MightyMoose
111 | *.mm.*
112 | AutoTest.Net/
113 |
114 | # Web workbench (sass)
115 | .sass-cache/
116 |
117 | # Installshield output folder
118 | [Ee]xpress/
119 |
120 | # DocProject is a documentation generator add-in
121 | DocProject/buildhelp/
122 | DocProject/Help/*.HxT
123 | DocProject/Help/*.HxC
124 | DocProject/Help/*.hhc
125 | DocProject/Help/*.hhk
126 | DocProject/Help/*.hhp
127 | DocProject/Help/Html2
128 | DocProject/Help/html
129 |
130 | # Click-Once directory
131 | publish/
132 |
133 | # Publish Web Output
134 | *.[Pp]ublish.xml
135 | *.azurePubxml
136 | # TODO: Comment the next line if you want to checkin your web deploy settings
137 | # but database connection strings (with potential passwords) will be unencrypted
138 | *.pubxml
139 | *.publishproj
140 |
141 | # NuGet Packages
142 | *.nupkg
143 | # The packages folder can be ignored because of Package Restore
144 | **/packages/*
145 | # except build/, which is used as an MSBuild target.
146 | !**/packages/build/
147 | # Uncomment if necessary however generally it will be regenerated when needed
148 | #!**/packages/repositories.config
149 |
150 | # Windows Azure Build Output
151 | csx/
152 | *.build.csdef
153 |
154 | # Windows Store app package directory
155 | AppPackages/
156 |
157 | # Visual Studio cache files
158 | # files ending in .cache can be ignored
159 | *.[Cc]ache
160 | # but keep track of directories ending in .cache
161 | !*.[Cc]ache/
162 |
163 | # Others
164 | ClientBin/
165 | [Ss]tyle[Cc]op.*
166 | ~$*
167 | *~
168 | *.dbmdl
169 | *.dbproj.schemaview
170 | *.pfx
171 | *.publishsettings
172 | node_modules/
173 | bower_components/
174 | orleans.codegen.cs
175 |
176 | # RIA/Silverlight projects
177 | Generated_Code/
178 |
179 | # Backup & report files from converting an old project file
180 | # to a newer Visual Studio version. Backup files are not needed,
181 | # because we have git ;-)
182 | _UpgradeReport_Files/
183 | Backup*/
184 | UpgradeLog*.XML
185 | UpgradeLog*.htm
186 |
187 | # SQL Server files
188 | *.mdf
189 | *.ldf
190 |
191 | # Business Intelligence projects
192 | *.rdl.data
193 | *.bim.layout
194 | *.bim_*.settings
195 |
196 | # Microsoft Fakes
197 | FakesAssemblies/
198 |
199 | # Node.js Tools for Visual Studio
200 | .ntvs_analysis.dat
201 |
202 | # Visual Studio 6 build log
203 | *.plg
204 |
205 | # Visual Studio 6 workspace options file
206 | *.opt
207 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/DesktopDuplication.Demo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {74CC9032-E6E6-4620-B9B7-36251023A1C9}
8 | WinExe
9 | Properties
10 | DesktopDuplication.Demo
11 | DesktopDuplication.Demo
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | Form
49 |
50 |
51 | FormDemo.cs
52 |
53 |
54 |
55 |
56 | FormDemo.cs
57 |
58 |
59 | ResXFileCodeGenerator
60 | Resources.Designer.cs
61 | Designer
62 |
63 |
64 | True
65 | Resources.resx
66 |
67 |
68 | SettingsSingleFileGenerator
69 | Settings.Designer.cs
70 |
71 |
72 | True
73 | Settings.settings
74 | True
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | {222c215b-663f-4bd6-9b3e-8fa99c867b22}
83 | DesktopDuplication
84 |
85 |
86 |
87 |
94 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/FormDemo.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace DesktopDuplication.Demo
2 | {
3 | partial class FormDemo
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.UpdatedRegion = new System.Windows.Forms.Label();
32 | this.MovedRegion = new System.Windows.Forms.Label();
33 | this.LabelCursor = new System.Windows.Forms.Label();
34 | this.SuspendLayout();
35 | //
36 | // UpdatedRegion
37 | //
38 | this.UpdatedRegion.BackColor = System.Drawing.Color.Orange;
39 | this.UpdatedRegion.Location = new System.Drawing.Point(37, 109);
40 | this.UpdatedRegion.Name = "UpdatedRegion";
41 | this.UpdatedRegion.Size = new System.Drawing.Size(1, 1);
42 | this.UpdatedRegion.TabIndex = 0;
43 | //
44 | // MovedRegion
45 | //
46 | this.MovedRegion.BackColor = System.Drawing.Color.Purple;
47 | this.MovedRegion.Location = new System.Drawing.Point(308, 215);
48 | this.MovedRegion.Name = "MovedRegion";
49 | this.MovedRegion.Size = new System.Drawing.Size(1, 1);
50 | this.MovedRegion.TabIndex = 1;
51 | //
52 | // LabelCursor
53 | //
54 | this.LabelCursor.BackColor = System.Drawing.Color.Red;
55 | this.LabelCursor.Location = new System.Drawing.Point(141, 97);
56 | this.LabelCursor.Name = "LabelCursor";
57 | this.LabelCursor.Size = new System.Drawing.Size(15, 15);
58 | this.LabelCursor.TabIndex = 2;
59 | //
60 | // FormDemo
61 | //
62 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
63 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
64 | this.ClientSize = new System.Drawing.Size(616, 431);
65 | this.Controls.Add(this.LabelCursor);
66 | this.Controls.Add(this.MovedRegion);
67 | this.Controls.Add(this.UpdatedRegion);
68 | this.DoubleBuffered = true;
69 | this.Name = "FormDemo";
70 | this.Text = "Desktop Duplication API Demo";
71 | this.Shown += new System.EventHandler(this.FormDemo_Shown);
72 | this.ResumeLayout(false);
73 |
74 | }
75 |
76 | #endregion
77 |
78 | private System.Windows.Forms.Label UpdatedRegion;
79 | private System.Windows.Forms.Label MovedRegion;
80 | private System.Windows.Forms.Label LabelCursor;
81 | }
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/FormDemo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Diagnostics;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace DesktopDuplication.Demo
13 | {
14 | public partial class FormDemo : Form
15 | {
16 | private DesktopDuplicator desktopDuplicator;
17 |
18 | public FormDemo()
19 | {
20 | InitializeComponent();
21 |
22 | try
23 | {
24 | desktopDuplicator = new DesktopDuplicator(0);
25 | }
26 | catch (Exception ex)
27 | {
28 | MessageBox.Show(ex.ToString());
29 | }
30 | }
31 |
32 | private void FormDemo_Shown(object sender, EventArgs e)
33 | {
34 | while (true)
35 | {
36 | Application.DoEvents();
37 |
38 | DesktopFrame frame = null;
39 | try
40 | {
41 | frame = desktopDuplicator.GetLatestFrame();
42 | }
43 | catch
44 | {
45 | desktopDuplicator = new DesktopDuplicator(0);
46 | continue;
47 | }
48 |
49 | if (frame != null)
50 | {
51 | LabelCursor.Location = frame.CursorLocation;
52 | LabelCursor.Visible = frame.CursorVisible;
53 | //Debug.WriteLine("--------------------------------------------------------");
54 | //foreach (var moved in frame.MovedRegions)
55 | //{
56 | // Debug.WriteLine(String.Format("Moved: {0} -> {1}", moved.Source, moved.Destination));
57 | // MovedRegion.Location = moved.Destination.Location;
58 | // MovedRegion.Size = moved.Destination.Size;
59 | //}
60 | //foreach (var updated in frame.UpdatedRegions)
61 | //{
62 | // Debug.WriteLine(String.Format("Updated: {0}", updated.ToString()));
63 | // UpdatedRegion.Location = updated.Location;
64 | // UpdatedRegion.Size = updated.Size;
65 | //}
66 | this.BackgroundImage = frame.DesktopImage;
67 | }
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/FormDemo.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 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace DesktopDuplication.Demo
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// The main entry point for the application.
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | Application.EnableVisualStyles();
18 | Application.SetCompatibleTextRenderingDefault(false);
19 | Application.Run(new FormDemo());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DesktopDuplication.Demo")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DesktopDuplication.Demo")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("c7dab9ab-a2bd-4a06-bfd7-5a9f7f6bd08d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.33440
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 DesktopDuplication.Demo.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
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 | /// Returns the cached ResourceManager instance used by this class.
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("DesktopDuplication.Demo.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
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 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/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 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.33440
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 DesktopDuplication.Demo.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 |
--------------------------------------------------------------------------------
/DesktopDuplication.Demo/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DesktopDuplication.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.30501.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DesktopDuplication", "DesktopDuplication\DesktopDuplication.csproj", "{222C215B-663F-4BD6-9B3E-8FA99C867B22}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DesktopDuplication.Demo", "DesktopDuplication.Demo\DesktopDuplication.Demo.csproj", "{74CC9032-E6E6-4620-B9B7-36251023A1C9}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {222C215B-663F-4BD6-9B3E-8FA99C867B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {222C215B-663F-4BD6-9B3E-8FA99C867B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {222C215B-663F-4BD6-9B3E-8FA99C867B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {222C215B-663F-4BD6-9B3E-8FA99C867B22}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {74CC9032-E6E6-4620-B9B7-36251023A1C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {74CC9032-E6E6-4620-B9B7-36251023A1C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {74CC9032-E6E6-4620-B9B7-36251023A1C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {74CC9032-E6E6-4620-B9B7-36251023A1C9}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/DesktopDuplication/DesktopDuplication.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DirectX11_2
6 | Debug
7 | AnyCPU
8 | {222C215B-663F-4BD6-9B3E-8FA99C867B22}
9 | Library
10 | Properties
11 | DesktopDuplication
12 | DesktopDuplication
13 | v4.5
14 | 512
15 | 512a20ac
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 | true
35 |
36 |
37 |
38 | False
39 | $(SharpDXPackageBinDir)\SharpDX.dll
40 |
41 |
42 | False
43 | $(SharpDXPackageBinDir)\SharpDX.Direct3D11.dll
44 |
45 |
46 | False
47 | $(SharpDXPackageBinDir)\SharpDX.DXGI.dll
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
75 |
76 |
77 |
78 |
85 |
--------------------------------------------------------------------------------
/DesktopDuplication/DesktopDuplicationException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DesktopDuplication
8 | {
9 | public class DesktopDuplicationException : Exception
10 | {
11 | public DesktopDuplicationException(string message)
12 | : base(message) { }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/DesktopDuplication/DesktopDuplicator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing.Imaging;
3 | using System.IO;
4 |
5 | using SharpDX;
6 | using SharpDX.Direct3D11;
7 | using SharpDX.DXGI;
8 | using Device = SharpDX.Direct3D11.Device;
9 | using MapFlags = SharpDX.Direct3D11.MapFlags;
10 | using Rectangle = SharpDX.Rectangle;
11 | using System.Drawing;
12 | using System.Diagnostics;
13 | using System.Runtime.InteropServices;
14 |
15 | namespace DesktopDuplication
16 | {
17 | ///
18 | /// Provides access to frame-by-frame updates of a particular desktop (i.e. one monitor), with image and cursor information.
19 | ///
20 | public class DesktopDuplicator
21 | {
22 | private Device mDevice;
23 | private Texture2DDescription mTextureDesc;
24 | private OutputDescription mOutputDesc;
25 | private OutputDuplication mDeskDupl;
26 |
27 | private Texture2D desktopImageTexture = null;
28 | private OutputDuplicateFrameInformation frameInfo = new OutputDuplicateFrameInformation();
29 | private int mWhichOutputDevice = -1;
30 |
31 | private Bitmap finalImage1, finalImage2;
32 | private bool isFinalImage1 = false;
33 | private Bitmap FinalImage
34 | {
35 | get
36 | {
37 | return isFinalImage1 ? finalImage1 : finalImage2;
38 | }
39 | set
40 | {
41 | if (isFinalImage1)
42 | {
43 | finalImage2 = value;
44 | if (finalImage1 != null) finalImage1.Dispose();
45 | }
46 | else
47 | {
48 | finalImage1 = value;
49 | if (finalImage2 != null) finalImage2.Dispose();
50 | }
51 | isFinalImage1 = !isFinalImage1;
52 | }
53 | }
54 |
55 | ///
56 | /// Duplicates the output of the specified monitor.
57 | ///
58 | /// The output device to duplicate (i.e. monitor). Begins with zero, which seems to correspond to the primary monitor.
59 | public DesktopDuplicator(int whichMonitor)
60 | : this(0, whichMonitor) { }
61 |
62 | ///
63 | /// Duplicates the output of the specified monitor on the specified graphics adapter.
64 | ///
65 | /// The adapter which contains the desired outputs.
66 | /// The output device to duplicate (i.e. monitor). Begins with zero, which seems to correspond to the primary monitor.
67 | public DesktopDuplicator(int whichGraphicsCardAdapter, int whichOutputDevice)
68 | {
69 | this.mWhichOutputDevice = whichOutputDevice;
70 | Adapter1 adapter = null;
71 | try
72 | {
73 | adapter = new Factory1().GetAdapter1(whichGraphicsCardAdapter);
74 | }
75 | catch (SharpDXException)
76 | {
77 | throw new DesktopDuplicationException("Could not find the specified graphics card adapter.");
78 | }
79 | this.mDevice = new Device(adapter);
80 | Output output = null;
81 | try
82 | {
83 | output = adapter.GetOutput(whichOutputDevice);
84 | }
85 | catch (SharpDXException)
86 | {
87 | throw new DesktopDuplicationException("Could not find the specified output device.");
88 | }
89 | var output1 = output.QueryInterface();
90 | this.mOutputDesc = output.Description;
91 | this.mTextureDesc = new Texture2DDescription()
92 | {
93 | CpuAccessFlags = CpuAccessFlags.Read,
94 | BindFlags = BindFlags.None,
95 | Format = Format.B8G8R8A8_UNorm,
96 | Width = this.mOutputDesc.DesktopBounds.Width,
97 | Height = this.mOutputDesc.DesktopBounds.Height,
98 | OptionFlags = ResourceOptionFlags.None,
99 | MipLevels = 1,
100 | ArraySize = 1,
101 | SampleDescription = { Count = 1, Quality = 0 },
102 | Usage = ResourceUsage.Staging
103 | };
104 |
105 | try
106 | {
107 | this.mDeskDupl = output1.DuplicateOutput(mDevice);
108 | }
109 | catch (SharpDXException ex)
110 | {
111 | if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.NotCurrentlyAvailable.Result.Code)
112 | {
113 | throw new DesktopDuplicationException("There is already the maximum number of applications using the Desktop Duplication API running, please close one of the applications and try again.");
114 | }
115 | }
116 | }
117 |
118 | ///
119 | /// Retrieves the latest desktop image and associated metadata.
120 | ///
121 | public DesktopFrame GetLatestFrame()
122 | {
123 | var frame = new DesktopFrame();
124 | // Try to get the latest frame; this may timeout
125 | bool retrievalTimedOut = RetrieveFrame();
126 | if (retrievalTimedOut)
127 | return null;
128 | try
129 | {
130 | RetrieveFrameMetadata(frame);
131 | RetrieveCursorMetadata(frame);
132 | ProcessFrame(frame);
133 | }
134 | catch
135 | {
136 | ReleaseFrame();
137 | }
138 | try
139 | {
140 | ReleaseFrame();
141 | }
142 | catch {
143 | // throw new DesktopDuplicationException("Couldn't release frame.");
144 | }
145 | return frame;
146 | }
147 |
148 | private bool RetrieveFrame()
149 | {
150 | if (desktopImageTexture == null)
151 | desktopImageTexture = new Texture2D(mDevice, mTextureDesc);
152 | SharpDX.DXGI.Resource desktopResource = null;
153 | frameInfo = new OutputDuplicateFrameInformation();
154 | try
155 | {
156 | mDeskDupl.AcquireNextFrame(500, out frameInfo, out desktopResource);
157 | }
158 | catch (SharpDXException ex)
159 | {
160 | if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
161 | {
162 | return true;
163 | }
164 | if (ex.ResultCode.Failure)
165 | {
166 | throw new DesktopDuplicationException("Failed to acquire next frame.");
167 | }
168 | }
169 | using (var tempTexture = desktopResource.QueryInterface())
170 | mDevice.ImmediateContext.CopyResource(tempTexture, desktopImageTexture);
171 | desktopResource.Dispose();
172 | return false;
173 | }
174 |
175 | private void RetrieveFrameMetadata(DesktopFrame frame)
176 | {
177 |
178 | if (frameInfo.TotalMetadataBufferSize > 0)
179 | {
180 | // Get moved regions
181 | int movedRegionsLength = 0;
182 | OutputDuplicateMoveRectangle[] movedRectangles = new OutputDuplicateMoveRectangle[frameInfo.TotalMetadataBufferSize];
183 | mDeskDupl.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out movedRegionsLength);
184 | frame.MovedRegions = new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];
185 | for (int i = 0; i < frame.MovedRegions.Length; i++)
186 | {
187 | frame.MovedRegions[i] = new MovedRegion()
188 | {
189 | Source = new System.Drawing.Point(movedRectangles[i].SourcePoint.X, movedRectangles[i].SourcePoint.Y),
190 | Destination = new System.Drawing.Rectangle(movedRectangles[i].DestinationRect.X, movedRectangles[i].DestinationRect.Y, movedRectangles[i].DestinationRect.Width, movedRectangles[i].DestinationRect.Height)
191 | };
192 | }
193 |
194 | // Get dirty regions
195 | int dirtyRegionsLength = 0;
196 | Rectangle[] dirtyRectangles = new Rectangle[frameInfo.TotalMetadataBufferSize];
197 | mDeskDupl.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out dirtyRegionsLength);
198 | frame.UpdatedRegions = new System.Drawing.Rectangle[dirtyRegionsLength / Marshal.SizeOf(typeof(Rectangle))];
199 | for (int i = 0; i < frame.UpdatedRegions.Length; i++)
200 | {
201 | frame.UpdatedRegions[i] = new System.Drawing.Rectangle(dirtyRectangles[i].X, dirtyRectangles[i].Y, dirtyRectangles[i].Width, dirtyRectangles[i].Height);
202 | }
203 | }
204 | else
205 | {
206 | frame.MovedRegions = new MovedRegion[0];
207 | frame.UpdatedRegions = new System.Drawing.Rectangle[0];
208 | }
209 | }
210 |
211 | private void RetrieveCursorMetadata(DesktopFrame frame)
212 | {
213 | var pointerInfo = new PointerInfo();
214 |
215 | // A non-zero mouse update timestamp indicates that there is a mouse position update and optionally a shape change
216 | if (frameInfo.LastMouseUpdateTime == 0)
217 | return;
218 |
219 | bool updatePosition = true;
220 |
221 | // Make sure we don't update pointer position wrongly
222 | // If pointer is invisible, make sure we did not get an update from another output that the last time that said pointer
223 | // was visible, if so, don't set it to invisible or update.
224 |
225 | if (!frameInfo.PointerPosition.Visible && (pointerInfo.WhoUpdatedPositionLast != this.mWhichOutputDevice))
226 | updatePosition = false;
227 |
228 | // If two outputs both say they have a visible, only update if new update has newer timestamp
229 | if (frameInfo.PointerPosition.Visible && pointerInfo.Visible && (pointerInfo.WhoUpdatedPositionLast != this.mWhichOutputDevice) && (pointerInfo.LastTimeStamp > frameInfo.LastMouseUpdateTime))
230 | updatePosition = false;
231 |
232 | // Update position
233 | if (updatePosition)
234 | {
235 | pointerInfo.Position = new SharpDX.Point(frameInfo.PointerPosition.Position.X, frameInfo.PointerPosition.Position.Y);
236 | pointerInfo.WhoUpdatedPositionLast = mWhichOutputDevice;
237 | pointerInfo.LastTimeStamp = frameInfo.LastMouseUpdateTime;
238 | pointerInfo.Visible = frameInfo.PointerPosition.Visible;
239 | }
240 |
241 | // No new shape
242 | if (frameInfo.PointerShapeBufferSize == 0)
243 | return;
244 |
245 | if (frameInfo.PointerShapeBufferSize > pointerInfo.BufferSize)
246 | {
247 | pointerInfo.PtrShapeBuffer = new byte[frameInfo.PointerShapeBufferSize];
248 | pointerInfo.BufferSize = frameInfo.PointerShapeBufferSize;
249 | }
250 |
251 | try
252 | {
253 | unsafe
254 | {
255 | fixed (byte* ptrShapeBufferPtr = pointerInfo.PtrShapeBuffer)
256 | {
257 | mDeskDupl.GetFramePointerShape(frameInfo.PointerShapeBufferSize, (IntPtr)ptrShapeBufferPtr, out pointerInfo.BufferSize, out pointerInfo.ShapeInfo);
258 | }
259 | }
260 | }
261 | catch (SharpDXException ex)
262 | {
263 | if (ex.ResultCode.Failure)
264 | {
265 | throw new DesktopDuplicationException("Failed to get frame pointer shape.");
266 | }
267 | }
268 |
269 | //frame.CursorVisible = pointerInfo.Visible;
270 | frame.CursorLocation = new System.Drawing.Point(pointerInfo.Position.X, pointerInfo.Position.Y);
271 | }
272 |
273 | private void ProcessFrame(DesktopFrame frame)
274 | {
275 | // Get the desktop capture texture
276 | var mapSource = mDevice.ImmediateContext.MapSubresource(desktopImageTexture, 0, MapMode.Read, MapFlags.None);
277 |
278 | FinalImage = new System.Drawing.Bitmap(mOutputDesc.DesktopBounds.Width, mOutputDesc.DesktopBounds.Height, PixelFormat.Format32bppRgb);
279 | var boundsRect = new System.Drawing.Rectangle(0, 0, mOutputDesc.DesktopBounds.Width, mOutputDesc.DesktopBounds.Height);
280 | // Copy pixels from screen capture Texture to GDI bitmap
281 | var mapDest = FinalImage.LockBits(boundsRect, ImageLockMode.WriteOnly, FinalImage.PixelFormat);
282 | var sourcePtr = mapSource.DataPointer;
283 | var destPtr = mapDest.Scan0;
284 | for (int y = 0; y < mOutputDesc.DesktopBounds.Height; y++)
285 | {
286 | // Copy a single line
287 | Utilities.CopyMemory(destPtr, sourcePtr, mOutputDesc.DesktopBounds.Width * 4);
288 |
289 | // Advance pointers
290 | sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
291 | destPtr = IntPtr.Add(destPtr, mapDest.Stride);
292 | }
293 |
294 | // Release source and dest locks
295 | FinalImage.UnlockBits(mapDest);
296 | mDevice.ImmediateContext.UnmapSubresource(desktopImageTexture, 0);
297 | frame.DesktopImage = FinalImage;
298 | }
299 |
300 | private void ReleaseFrame()
301 | {
302 | try
303 | {
304 | mDeskDupl.ReleaseFrame();
305 | }
306 | catch (SharpDXException ex)
307 | {
308 | if (ex.ResultCode.Failure)
309 | {
310 | throw new DesktopDuplicationException("Failed to release frame.");
311 | }
312 | }
313 | }
314 | }
315 | }
316 |
--------------------------------------------------------------------------------
/DesktopDuplication/DesktopFrame.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DesktopDuplication
9 | {
10 | ///
11 | /// Provides image data, cursor data, and image metadata about the retrieved desktop frame.
12 | ///
13 | public class DesktopFrame
14 | {
15 | ///
16 | /// Gets the bitmap representing the last retrieved desktop frame. This image spans the entire bounds of the specified monitor.
17 | ///
18 | public Bitmap DesktopImage { get; internal set; }
19 |
20 | ///
21 | /// Gets a list of the rectangles of pixels in the desktop image that the operating system moved to another location within the same image.
22 | ///
23 | ///
24 | /// To produce a visually accurate copy of the desktop, an application must first process all moved regions before it processes updated regions.
25 | ///
26 | public MovedRegion[] MovedRegions { get; internal set; }
27 |
28 | ///
29 | /// Returns the list of non-overlapping rectangles that indicate the areas of the desktop image that the operating system updated since the last retrieved frame.
30 | ///
31 | ///
32 | /// To produce a visually accurate copy of the desktop, an application must first process all moved regions before it processes updated regions.
33 | ///
34 | public Rectangle[] UpdatedRegions { get; internal set; }
35 |
36 | ///
37 | /// The number of frames that the operating system accumulated in the desktop image surface since the last retrieved frame.
38 | ///
39 | public int AccumulatedFrames { get; internal set; }
40 |
41 | ///
42 | /// Gets the location of the top-left-hand corner of the cursor. This is not necessarily the same position as the cursor's hot spot, which is the location in the cursor that interacts with other elements on the screen.
43 | ///
44 | public Point CursorLocation { get; internal set; }
45 |
46 | ///
47 | /// Gets whether the cursor on the last retrieved desktop image was visible.
48 | ///
49 | public bool CursorVisible { get; internal set; }
50 |
51 | ///
52 | /// Gets whether the desktop image contains protected content that was already blacked out in the desktop image.
53 | ///
54 | public bool ProtectedContentMaskedOut { get; internal set; }
55 |
56 | ///
57 | /// Gets whether the operating system accumulated updates by coalescing updated regions. If so, the updated regions might contain unmodified pixels.
58 | ///
59 | public bool RectanglesCoalesced { get; internal set; }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/DesktopDuplication/MovedRegion.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DesktopDuplication
9 | {
10 | ///
11 | /// Describes the movement of an image rectangle within a desktop frame.
12 | ///
13 | ///
14 | /// Move regions are always non-stretched regions so the source is always the same size as the destination.
15 | ///
16 | public struct MovedRegion
17 | {
18 | ///
19 | /// Gets the location from where the operating system copied the image region.
20 | ///
21 | public Point Source { get; internal set; }
22 |
23 | ///
24 | /// Gets the target region to where the operating system moved the image region.
25 | ///
26 | public Rectangle Destination { get; internal set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/DesktopDuplication/PointerInfo.cs:
--------------------------------------------------------------------------------
1 | using SharpDX.DXGI;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DesktopDuplication
9 | {
10 | internal class PointerInfo
11 | {
12 | public byte[] PtrShapeBuffer;
13 | public OutputDuplicatePointerShapeInformation ShapeInfo;
14 | public SharpDX.Point Position;
15 | public bool Visible;
16 | public int BufferSize;
17 | public int WhoUpdatedPositionLast;
18 | public long LastTimeStamp;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/DesktopDuplication/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DesktopDuplication")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DesktopDuplication")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("edd6f18d-3120-4f8d-84bd-157ad8881019")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/DesktopDuplication/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------