본문 바로가기
C#

[C#] WPF에서 Windows.Graphics.Capture 사용하여 디스플레이, 프로그램 Screen Capture 사용, NET Framework, NET6 모두 사용.

by Jcoder 2022. 8. 19.

windows 7, 8.1에선 Bitblt 방식으로 디스플레이 또는 프로그램 좌표를 통해 캡쳐를 진행했다.

그러나 windows10 sdk에(windrt) Windows.Graphics.Capture 를 이용하여 캡쳐가 가능하다.

해당 링크는 마이크로소프트 깃허브에 있는 Sample 프로젝트 링크이다. 

 - Windows.UI.Composition-Win32-Samples/dotnet/WPF/ScreenCapture at master · microsoft/Windows.UI.Composition-Win32-Samples (github.com)

 

GitHub - microsoft/Windows.UI.Composition-Win32-Samples: Windows.UI.Composition Win32 Samples

Windows.UI.Composition Win32 Samples. Contribute to microsoft/Windows.UI.Composition-Win32-Samples development by creating an account on GitHub.

github.com

위 프로젝트에선 Picker를 통해 WebRTC 처럼 프로그램 선택 화면이 뜬다.

그리고 프로그램 리스트 콤보박스, 모니터 리스트 콤보박스가 별도로 존재하며 프로그램 리스트가 갱신이 되지 않아 별도로 수정을 하려 프로젝트를 생성했다.

또한 IDisposable을 사용하는데 Dispose 패턴을 사용하지 않아 해당 내용도 사용하게 수정을 하였다.

 

tjdskaqks/Windows.UI.Composition-Win32-Samples: Windows.UI.Composition Win32 Samples (github.com)

 

GitHub - tjdskaqks/Windows.UI.Composition-Win32-Samples: Windows.UI.Composition Win32 Samples

Windows.UI.Composition Win32 Samples. Contribute to tjdskaqks/Windows.UI.Composition-Win32-Samples development by creating an account on GitHub.

github.com

해당 master branch를 다운 받으면 기존 sample에 있는 프로젝트 말고 CaptureCore, Composition.WindowsRuntimeHelpers_NETStd, ScreenCaptureDemo 프로젝트가 있다.

아래 리스트는 솔루션 누겟 패키지에서 필요한 라이브러리들이다.

 - Microsoft.Windows.SDK.Contracts (3개 전부 다운로드 및 설치)

 - SharpDX.Direct3D11 ( Composition.WindowsRuntimeHelpers_NETStd 만 설치)

ScreenCaptureDemo 프로젝트에선  CaptureCore, Composition.WindowsRuntimeHelpers_NETStd 프로젝트 참조를 해야하며

CaptureCore 프로젝트는 Composition.WindowsRuntimeHelpers_NETStd 프로젝트 참조를 해야하며

Composition.WindowsRuntimeHelpers_NETStd 프로젝트는 별도 참조를 하지 않아도 된다.

 

CaptureCore, Composition.WindowsRuntimeHelpers_NETStd 프로젝트들은 클래스 라이브러리며 NET Standard 2.0이다.

기존엔 .NET 6 프로젝트들로 구성하려고 하였는데 참조 오류들이 발생하여 우선 WPF .NET Framework 4.8로 구성하였다.

2022-08-19

.NET 6 프로젝트 별도 추가.

 

ScreenCaptureDemo 프로젝트

 - App.xaml.cs

 - MainWindows.xaml.cs

공유 중지, 모니터, 프로그램 리스트를 한번에 하기 위해 enum을 만들었고 FindProcess 클래스를 생성했다.

모니터, 프로그램 리스트를 가져온다.

콤보박스 선택을 하면 리스트를 가져오게 하였다.

private void Cbb_Processes_DropDownOpened(object sender, EventArgs e)
{
    cbb_Processes.ItemsSource = GetProcesses();
}

선택된 프로세스를 캡쳐 중지, 모니터, 프로그램 종류를 확인하여 화면 캡쳐를 진행한다.

 

실행 화면

모니터 1
모니터 2
프로그램 캡쳐

 

참고 : Calling Windows 10 APIs From Your WPF Application (morioh.com)

 

Calling Windows 10 APIs From Your WPF Application

Did you know that you can call Windows 10 WinRT APIs from your WPF and WinForms apps? In this blog post I’ll show you how to display toast messages from a WPF application by using the Windows.

morioh.com

 

- .NET 6 사용

프로젝트 : CaptureCore_NET6, Composition.WindowsRuntimeHelpers_NET6, ScreenCaptureDemo_NET6

 

NET 6에선 Microsoft.Windows.SDK.Contracts 해당 패키지를 설치를 하면 안된다.

대상 os에서 windows와 os 버전을 맞춰주면 자동으로 .NET SDK dll를 사용하게 된다.

 

Composition.WindowsRuntimeHelpers_NET6 에서 새로 설치해야할 패키지가 있다

InteropCompositor 해당 패키지를 검색하여 설치한다.

 

GitHub - Extrimis/InteropCompositor: Interop compositor provides support for ICompositorDesktopInterop in Target Framework Monik

Interop compositor provides support for ICompositorDesktopInterop in Target Framework Moniker .NET5 - GitHub - Extrimis/InteropCompositor: Interop compositor provides support for ICompositorDesktop...

github.com

net 6에서 기존처럼 하면 오류가 발생한다. 

net 5, 6에선 오류가 발생.

해당 코드로 수정.

[ComImport]
[Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
interface ICompositorDesktopInterop
{
    //Windows.UI.Composition.Desktop.DesktopWindowTarget CreateDesktopWindowTarget(IntPtr hwnd, bool isTopmost);
    void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IDesktopWindowTarget test);
}


public static CompositionTarget CreateDesktopWindowTarget(this Compositor compositor, IntPtr hwnd, bool isTopmost)
{
    //var desktopInterop = (ICompositorDesktopInterop)(object)compositor;
    //return desktopInterop.CreateDesktopWindowTarget(hwnd, isTopmost);

    ICompositorDesktopInterop interop = compositor.TryAs<ICompositorDesktopInterop>();
    interop.CreateDesktopWindowTarget(hwnd, isTopmost, out var target);
    ICompositionTarget compositionTarget = (ICompositionTarget)target;
    return (CompositionTarget)compositionTarget;
}

 

그럼 동일하게 실행이 된다.