aardio 文档

aardio 范例: WGC 截图

import console;
import dotNet.uwpCompiler;

var uwpCompiler; 
try{

    /*
    创建启用 WinRT / UWP 接口的 .NET 编译器,
    请先安装 Windows 10 SDK,安装 SDK 后 aardio 会自动引用 Windows.winmd 。
    可选用参数 @2 显式指定 WinRT 元数据文件 Windows.winmd 的路径(一般不必要)。
    Windows.winmd 是一个大集合,一般不需要额外再引用其他系统 winmd。
    调用编译后的 DLL 不需要 Windows.winmd ,仅编译时需要。

    dotNet.uwpCompiler 基于 CLR 4.0 编译器,
    在 Win10 以及更新系统支持并且仅支持 C# 5.0 语法。

    已默认添加引用 System.Runtime.dll,System.Runtime.WindowsRuntime.dll,System.Runtime.InteropServices.WindowsRuntim
    */  
    uwpCompiler = dotNet.uwpCompiler("/aardio.WindowsRuntime.dll")  
}
console.assert(uwpCompiler,"请先安装 Windows 10 SDK") 

uwpCompiler.Source = /******
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
using Windows.Graphics.DirectX.Direct3D11;
using Windows.Graphics.Imaging;
using Windows.Storage;

namespace Aardio.WGC {

    [ComImport]
    [Guid("3628E81B-3CAC-4C60-B7F4-23CE0E0C3356")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IGraphicsCaptureItemInterop {
        void CreateForWindow([In] IntPtr window, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object result);
    }

    public class CaptureService {

        [DllImport("d3d11.dll")]
        static extern int D3D11CreateDevice(IntPtr pAdapter, int DriverType, IntPtr Software, uint Flags, 
            IntPtr pFeatureLevels, uint FeatureLevels, uint SDKVersion, 
            out IntPtr ppDevice, IntPtr pFeatureLevel, out IntPtr ppImmediateContext);

        [DllImport("d3d11.dll")]
        static extern int CreateDirect3D11DeviceFromDXGIDevice(IntPtr dxgiDevice, out IntPtr graphicsDevice);

        public string TakeWindowScreenshot(IntPtr hwnd, string savePath) {
            try {
                string fullPath = Path.GetFullPath(savePath);
                return Task.Run(() => TakeScreenshotAsync(hwnd, fullPath)).Result;
            } catch (Exception ex) {
                string errorMsg = ex.Message;
                if (ex.InnerException != null) {
                    errorMsg = ex.InnerException.Message;
                }
                return "抓取失败: " + errorMsg;
            }
        }

        private async Task<string> TakeScreenshotAsync(IntPtr hwnd, string savePath) {
            var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem));
            var interop = (IGraphicsCaptureItemInterop)factory;
            Guid itemGuid = new Guid("79C3F95B-31F7-4EC2-A464-632EF5D30760");
            object itemObject;
            interop.CreateForWindow(hwnd, ref itemGuid, out itemObject);
            GraphicsCaptureItem item = (GraphicsCaptureItem)itemObject;

            if (item.Size.Width == 0 || item.Size.Height == 0) {
                return "抓取失败: 窗口不可见或已被最小化。";
            }

            IntPtr pDevice = IntPtr.Zero;
            IntPtr pContext = IntPtr.Zero;
            IntPtr pWinRTDevice = IntPtr.Zero;

            try {
                int hr = D3D11CreateDevice(IntPtr.Zero, 1, IntPtr.Zero, 0x20, IntPtr.Zero, 0, 7, out pDevice, IntPtr.Zero, out pContext);
                if (hr < 0) return "D3D11CreateDevice 失败。";

                object dxgiDevice = Marshal.GetObjectForIUnknown(pDevice);
                IntPtr pUnkDxgi = Marshal.GetIUnknownForObject(dxgiDevice);
                hr = CreateDirect3D11DeviceFromDXGIDevice(pUnkDxgi, out pWinRTDevice);
                Marshal.Release(pUnkDxgi);
                if (hr < 0) return "转码设备失败。";

                var device = (IDirect3DDevice)Marshal.GetObjectForIUnknown(pWinRTDevice);

                var framePool = Direct3D11CaptureFramePool.Create(device, DirectXPixelFormat.B8G8R8A8UIntNormalized, 1, item.Size);
                var session = framePool.CreateCaptureSession(item);

                session.StartCapture();

                Direct3D11CaptureFrame capturedFrame = null;

                /*
                不使用事件,改为主动轮询(尝试获取,没有就等 20ms),最多等 1 秒。
                完美避开老版本 C# 编译器对 WinRT 事件处理的各种坑。
                当然,也可以直接改用 VS 编辑器先行编译 DLL 程序集。
                */
                for (int i = 0; i < 50; i++) {
                    capturedFrame = framePool.TryGetNextFrame();
                    if (capturedFrame != null) {
                        break; // 拿到画面了,跳出循环
                    }
                    await Task.Delay(20);
                }

                // 拿到一帧或者超时后,即可停止捕获释放资源
                session.Dispose();
                framePool.Dispose();
                device.Dispose();

                if (capturedFrame == null) {
                    return "抓取失败: 等待画面帧超时。";
                }

                using (capturedFrame)
                {
                    // 转换为可编码的图像位图
                    var softwareBitmap = await SoftwareBitmap.CreateCopyFromSurfaceAsync(capturedFrame.Surface);

                    var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetDirectoryName(savePath));
                    var file = await folder.CreateFileAsync(Path.GetFileName(savePath), CreationCollisionOption.ReplaceExisting);

                    using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite)) {
                        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
                        encoder.SetSoftwareBitmap(softwareBitmap);
                        await encoder.FlushAsync();
                    }
                }

                return "截图成功!";
            }
            finally {
                if (pContext != IntPtr.Zero) Marshal.Release(pContext);
                if (pDevice != IntPtr.Zero) Marshal.Release(pDevice);
                if (pWinRTDevice != IntPtr.Zero) Marshal.Release(pWinRTDevice);
            }
        }
    }
}
******/

console.showLoading("正在编译 C# 代码并执行 WGC 截屏...");

var ret = uwpCompiler.Compile();
if(!ret){
    console.error("编译错误:\n" + uwpCompiler.getLastError());
    console.pause(true);
    return;
}

var assembly = dotNet.load("/WgcCapture.dll");
assembly.import("Aardio.WGC");

var captureService = Aardio.WGC.CaptureService();

// 指定保存路径
var savePath = io.tmpname("wgc_screenshot",".png")

// 获取当前控制台句柄进行测试
var hwnd = console.getWindow(); 

// 调用抓取
var result = captureService.TakeWindowScreenshot(hwnd, savePath);

console.log(result);

if(string.startWith(result, "截图成功")){
    console.log("图片路径: ", savePath);
    raw.execute(savePath); 
}

console.pause(true);
Markdown 格式