성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - SharpDX + DXGI를 이용한 윈도우 화면 캡처 소스 코드</h1> <p> 이전 글에서 DXGI를 이용한 화면 캡처 소스 코드를 C++로 알아봤는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > DXGI를 이용한 윈도우 화면 캡처 소스 코드(Visual C++) ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11385'>http://www.sysnet.pe.kr/2/0/11385</a> </pre> <br /> 이번엔 C#으로 옮겨봤습니다. 물론 이를 위해 DirectX를 위한 Interop 라이브러리가 필요한데요, 바로 SharpDX가 그런 역할을 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > A new managed .NET/C# Direct3D 11 API generated from DirectX SDK headers ; <a target='tab' href='http://code4k.blogspot.kr/2010/10/managed-netc-direct3d-11-api-generated.html'>http://code4k.blogspot.kr/2010/10/managed-netc-direct3d-11-api-generated.html</a> </pre> <br /> NuGet에도 배포되어 있는 데다,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > SharpDX ; <a target='tab' href='https://www.nuget.org/packages/SharpDX/'>https://www.nuget.org/packages/SharpDX/</a> SharpDX.DXGI ; <a target='tab' href='https://www.nuget.org/packages/SharpDX.DXGI/4.1.0-ci184'>https://www.nuget.org/packages/SharpDX.DXGI/4.1.0-ci184</a> </pre> <br /> github에 소스 코드와 그 예제 코드가 모두 공개되어 있습니다. 그중에는 화면 캡처 예제도 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > SharpDX-Samples/Desktop/Direct3D11.1/ScreenCapture/Program.cs ; <a target='tab' href='https://github.com/sharpdx/SharpDX-Samples/blob/master/Desktop/Direct3D11.1/ScreenCapture/Program.cs'>https://github.com/sharpdx/SharpDX-Samples/blob/master/Desktop/Direct3D11.1/ScreenCapture/Program.cs</a> </pre> <br /> <hr style='width: 50%' /><br /> <br /> Nuget을 통해 SharpDX를 참조하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Install-Package SharpDX.Direct3D11 -Version 4.0.1 Install-Package SharpDX.DXGI -Version 4.0.1 </pre> <br /> 각각 다음의 DLL을 얻게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > SharpDX.dll SharpDX.DXGI.dll SharpDX.Direct3D11.dll </pre> <br /> 이를 이용해 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/11385'>DXGI를 이용한 윈도우 화면 캡처 소스 코드(Visual C++)</a>" 글의 DXGIManager, DXGIOutputDuplication 클래스를 각각 C#으로 다음과 같이 작성할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // DXGIManager.cs using SharpDX; using SharpDX.DXGI; using System; using System.Collections.Generic; using System.Drawing; using System.Runtime.InteropServices; namespace WindowsFormsApp1 { public class DXGIManager : IDisposable { // ...[생략]... public DXGIManager(CaptureSource source) { Initialize(source); } void Initialize(CaptureSource captureSource) { _captureSource = captureSource; _factory = new Factory4(); _outputs = new List<DXGIOutputDuplication>(); int vgaCardCount = _factory.GetAdapterCount(); foreach (Adapter adapter in _factory.Adapters) { List<Output> outputs = new List<Output>(); foreach (Output output in adapter.Outputs) { OutputDescription desc = output.Description; if (desc.IsAttachedToDesktop == false) { continue; } outputs.Add(output); } if (outputs.Count == 0) { continue; } SharpDX.Direct3D11.Device device = new SharpDX.Direct3D11.Device(adapter); foreach (Output output in outputs) { using (Output1 output1 = output.QueryInterface<Output1>()) { OutputDuplication outputDuplication = output1.DuplicateOutput(device); if (outputDuplication == null) { continue; } _outputs.Add( new DXGIOutputDuplication(adapter, device, outputDuplication, output1.Description)); } } // ...[생략]... } if (this.Initialized == true) { CalcOutputRect(); } } public bool Capture(byte[] buf, int timeout) { foreach (DXGIOutputDuplication dupOutput in GetOutputDuplicationByCaptureSource()) { Rectangle desktopBounds = dupOutput.DesktopCoordinates; if (dupOutput.AcquireNextFrame(timeout, copyBuffer, buf) == false) { return false; } } return true; } private void copyBuffer(Surface1 surface1, Rectangle desktopBounds, byte[] buf) { if (surface1 == null) { return; } DataRectangle map = surface1.Map(MapFlags.Read); GCHandle pinnedArray = GCHandle.Alloc(buf, GCHandleType.Pinned); IntPtr dstPtr = pinnedArray.AddrOfPinnedObject(); IntPtr srcPtr = map.DataPointer; int height = desktopBounds.Height; int width = desktopBounds.Width; Rectangle offsetBounds = desktopBounds; offsetBounds.Offset(-this._outputRect.Left, -this._outputRect.Top); { for (int y = 0; y < height; y++) { Utilities.CopyMemory(dstPtr + (offsetBounds.Left) * 4, srcPtr, width * 4); srcPtr = IntPtr.Add(srcPtr, map.Pitch); dstPtr = IntPtr.Add(dstPtr, this.Width * 4); } } pinnedArray.Free(); surface1.Unmap(); } // ...[생략]... private List<DXGIOutputDuplication> GetOutputDuplicationByCaptureSource() { List<DXGIOutputDuplication> list = new List<DXGIOutputDuplication>(); int nthMonitor = 0; foreach (DXGIOutputDuplication output in _outputs) { switch (_captureSource) { case CaptureSource.Monitor1: if (output.IsPrimary() == true) { list.Add(output); } break; case CaptureSource.Monitor2: if (output.IsPrimary() == false) { list.Add(output); } break; case CaptureSource.Monitor3: if (output.IsPrimary() == false) { nthMonitor++; } if (nthMonitor == ((int)CaptureSource.Monitor3) - 1) { list.Add(output); } break; case CaptureSource.Desktop: list.Add(output); break; } if (_captureSource != CaptureSource.Desktop && list.Count == 1) { break; } } return list; } // ...[생략]... } } </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // DXGIManager.cs using SharpDX; using SharpDX.Direct3D11; using SharpDX.DXGI; using SharpDX.Mathematics.Interop; using System; using System.Drawing; using System.Runtime.InteropServices; namespace WindowsFormsApp1 { class DXGIOutputDuplication { Adapter _adapter; SharpDX.Direct3D11.Device _device; SharpDX.Direct3D11.DeviceContext _deviceContext; OutputDuplication _outputDuplication; OutputDescription _description; [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfoEx lpmi); public DXGIOutputDuplication(Adapter adapter, SharpDX.Direct3D11.Device device, OutputDuplication outputDuplication, OutputDescription description) { _adapter = adapter; _device = device; _deviceContext = _device.ImmediateContext; _outputDuplication = outputDuplication; _description = description; } // ...[생략]... internal bool AcquireNextFrame(int timeout, Action<Surface1, Rectangle, byte []> copyAction, byte[] buf) { OutputDuplicateFrameInformation fi; SharpDX.DXGI.Resource desktopResource = null; try { _outputDuplication.AcquireNextFrame(timeout, out fi, out desktopResource); } catch (SharpDXException e) { if (e.ResultCode == DXGIError.DXGI_ERROR_ACCESS_LOST) { throw; } return false; } if (desktopResource == null) { return false; } try { using (Texture2D textureResource = desktopResource.QueryInterface<Texture2D>()) { Texture2DDescription desc = textureResource.Description; Texture2DDescription textureDescription = desc; textureDescription.MipLevels = 1; textureDescription.ArraySize = 1; textureDescription.SampleDescription.Count = 1; textureDescription.SampleDescription.Quality = 0; textureDescription.Usage = ResourceUsage.Staging; textureDescription.BindFlags = 0; textureDescription.CpuAccessFlags = CpuAccessFlags.Read; textureDescription.OptionFlags = ResourceOptionFlags.None; using (Texture2D d3d11Texture2D = new Texture2D(_device, textureDescription)) { _device.ImmediateContext.CopyResource(textureResource, d3d11Texture2D); using (Surface1 surface = d3d11Texture2D.QueryInterface<Surface1>()) { copyAction(surface, this.DesktopCoordinates, buf); return true; } } } } finally { if (desktopResource != null) { desktopResource.Dispose(); } _outputDuplication.ReleaseFrame(); } } // ...[생략]... } } </pre> <br /> <a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1194&boardid=331301885'>첨부한 파일은 위의 예제 코드를 모두 포함, 동작하는 프로젝트</a>입니다. 실행하면 윈도우가 하나 뜨는데, 그 윈도우에 포커스를 두고 Ctrl + C키를 누르면 1번 모니터의 화면을 캡처해서 윈도우에 출력합니다. 이렇게!<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='dxgi_capture_1.png' src='/SysWebRes/bbs/dxgi_capture_1.png' /><br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, 그래픽 카드 제조사 측에서 제공하는 화면 캡처 SDK도 있습니다. (언어는 C++입니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > NVIDIA Capture SDK ; <a target='tab' href='https://developer.nvidia.com/capture-sdk'>https://developer.nvidia.com/capture-sdk</a> [PDF] NVIDIA CAPTURE SDK PROGRAMMING GUIDE ; <a target='tab' href='http://developer.download.nvidia.com/designworks/capture-sdk/docs/6.1/NVIDIA-Capture-SDK-Programming-Guide.pdf'>http://developer.download.nvidia.com/designworks/capture-sdk/docs/6.1/NVIDIA-Capture-SDK-Programming-Guide.pdf</a> </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
2123
(왼쪽의 숫자를 입력해야 합니다.)