Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# PrintScreen之后剪贴板中没有图像_C#_Windows_Interop_Clipboard - Fatal编程技术网

C# PrintScreen之后剪贴板中没有图像

C# PrintScreen之后剪贴板中没有图像,c#,windows,interop,clipboard,C#,Windows,Interop,Clipboard,我正在实现不同的屏幕抓取程序来比较它们。其中一个应使用“printscreen”键和剪贴板 我使用keybd_事件发送击键: 在我的IEnumerable中,我调用此方法,然后尝试抓取图像: ... InputController.PrintScreen(); var img=Clipboard.GetImage(); ... 返回的图像始终为null,并且剪贴簿.ContainsImage()始终为false。我试着在发送钥匙后等待片刻,但也不起作用。 我是否缺少某种设置,或者是否存在根本性

我正在实现不同的屏幕抓取程序来比较它们。其中一个应使用“printscreen”键和剪贴板

我使用keybd_事件发送击键:

在我的IEnumerable中,我调用此方法,然后尝试抓取图像:

...
InputController.PrintScreen();
var img=Clipboard.GetImage();
...
返回的图像始终为null,并且剪贴簿.ContainsImage()始终为false。我试着在发送钥匙后等待片刻,但也不起作用。 我是否缺少某种设置,或者是否存在根本性错误

PS:运行程序后,我可以将正确的图像粘贴到paint或gimp中。

您尝试过使用该类吗

public static Image TakeScreenSnapshot(bool activeWindowOnly)
{
    // PrtSc = Print Screen Key
    string keys = "{PrtSc}";
    if (activeWindowOnly)
        keys = "%" + keys; // % = Alt
    SendKeys.SendWait(keys);
    return Clipboard.GetImage();
}

您尝试过使用该类吗

public static Image TakeScreenSnapshot(bool activeWindowOnly)
{
    // PrtSc = Print Screen Key
    string keys = "{PrtSc}";
    if (activeWindowOnly)
        keys = "%" + keys; // % = Alt
    SendKeys.SendWait(keys);
    return Clipboard.GetImage();
}

但您正在使用:

keybd_event(VK_SNAPSHOT,0,KEYEVENT_EXTENDEDKEY,0);
keybd_event(VK_SNAPSHOT,0,KEYEVENT_KEYUP,0);
使用KEYEVENTF_EXTENDEDKEY和KEYEVENTF_KEYUP可以正常工作


re:整个过程在线程池上的工作线程中运行 我找不到将PrintScreen()发布到“Main SynchronizationContext”的方法,因为它是一个控制台程序

您可以尝试以下方法:

class Program
{        
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern void keybd_event(byte vVK, byte bScan, int dwFlags, int dwExtraInfo);

    public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //key down
    public const int KEYEVENTF_KEYUP = 0x0002; //key up

    public const int VK_SNAPSHOT = 0x2C; //VirtualKey code for print key

    public static void PrintScreen()
    {
        keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY, 0);
        keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_KEYUP, 0);
    }

    public static void test(Action<Image> action)
    {
        PrintScreen();
        var image = Clipboard.GetImage();
        action.BeginInvoke(image, ar => action.EndInvoke(ar), null);
    }

    [STAThread]
    static void Main(string[] args)
    {
        var processAction = new Action<Image>(img =>
        {
            if (img == null)
                Console.WriteLine("none");
            else
                Console.WriteLine(img.PixelFormat);
        });
        test(processAction);
        System.Console.ReadLine();
}
类程序
{        
[System.Runtime.InteropServices.DllImport(“user32.dll”)]
公共静态外部无效keybd_事件(字节vVK、字节bScan、int-dwFlags、int-dwExtraInfo);
public const int KEYEVENTF_EXTENDEDKEY=0x0001;//向下键
public const int KEYEVENTF_KEYUP=0x0002;//键向上
public const int VK_SNAPSHOT=0x2C;//打印密钥的VirtualKey代码
公共静态无效打印屏幕()
{
keybd_事件(VK_快照,0,KEYEVENTF_扩展键,0);
keybd_事件(VK_快照,0,KEYEVENTF_KEYUP,0);
}
公共静态无效试验(作用)
{
打印屏幕();
var image=Clipboard.GetImage();
action.BeginInvoke(image,ar=>action.EndInvoke(ar),null);
}
[状态线程]
静态void Main(字符串[]参数)
{
var processAction=新操作(img=>
{
如果(img==null)
控制台。写入线(“无”);
其他的
Console.WriteLine(img.PixelFormat);
});
试验(过程作用);
System.Console.ReadLine();
}
但您正在使用:

keybd_event(VK_SNAPSHOT,0,KEYEVENT_EXTENDEDKEY,0);
keybd_event(VK_SNAPSHOT,0,KEYEVENT_KEYUP,0);
使用KEYEVENTF_EXTENDEDKEY和KEYEVENTF_KEYUP可以正常工作


re:整个过程在线程池上的工作线程中运行 我找不到将PrintScreen()发布到“Main SynchronizationContext”的方法,因为它是一个控制台程序

您可以尝试以下方法:

class Program
{        
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern void keybd_event(byte vVK, byte bScan, int dwFlags, int dwExtraInfo);

    public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //key down
    public const int KEYEVENTF_KEYUP = 0x0002; //key up

    public const int VK_SNAPSHOT = 0x2C; //VirtualKey code for print key

    public static void PrintScreen()
    {
        keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY, 0);
        keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_KEYUP, 0);
    }

    public static void test(Action<Image> action)
    {
        PrintScreen();
        var image = Clipboard.GetImage();
        action.BeginInvoke(image, ar => action.EndInvoke(ar), null);
    }

    [STAThread]
    static void Main(string[] args)
    {
        var processAction = new Action<Image>(img =>
        {
            if (img == null)
                Console.WriteLine("none");
            else
                Console.WriteLine(img.PixelFormat);
        });
        test(processAction);
        System.Console.ReadLine();
}
类程序
{        
[System.Runtime.InteropServices.DllImport(“user32.dll”)]
公共静态外部无效keybd_事件(字节vVK、字节bScan、int-dwFlags、int-dwExtraInfo);
public const int KEYEVENTF_EXTENDEDKEY=0x0001;//向下键
public const int KEYEVENTF_KEYUP=0x0002;//键向上
public const int VK_SNAPSHOT=0x2C;//打印密钥的VirtualKey代码
公共静态无效打印屏幕()
{
keybd_事件(VK_快照,0,KEYEVENTF_扩展键,0);
keybd_事件(VK_快照,0,KEYEVENTF_KEYUP,0);
}
公共静态无效试验(作用)
{
打印屏幕();
var image=Clipboard.GetImage();
action.BeginInvoke(image,ar=>action.EndInvoke(ar),null);
}
[状态线程]
静态void Main(字符串[]参数)
{
var processAction=新操作(img=>
{
如果(img==null)
控制台。写入线(“无”);
其他的
Console.WriteLine(img.PixelFormat);
});
试验(过程作用);
System.Console.ReadLine();
}
这是一个控制台程序

这是最相关的细节,你应该把它放在你的问题中。剪贴板是一个系统对象,它的底层api是基于COM的。这使得它对使用api的线程的单元状态很敏感。NET剪贴板类在这方面做了一些摸索,如果线程的状态是错误的,它真的应该抛出一个异常。它是w在控制台模式的应用程序中,其主线程默认为MTA,您需要STA才能使用api

修复方法很简单,您只需在Main()方法上添加一个属性来请求STA:

    [STAThread]
    static void Main(string[] args) {
        // etc...
    }
从技术上讲,STA线程也应该像Winforms或WPF应用程序一样,发送消息循环。但只要您只从主线程进行方法调用,您就不会受到影响

这是一个控制台程序

这是最相关的细节,你应该把它放在你的问题中。剪贴板是一个系统对象,它的底层api是基于COM的。这使得它对使用api的线程的单元状态很敏感。NET剪贴板类在这方面做了一些摸索,如果线程的状态是错误的,它真的应该抛出一个异常。它是w在控制台模式的应用程序中,其主线程默认为MTA,您需要STA才能使用api

修复方法很简单,您只需在Main()方法上添加一个属性来请求STA:

    [STAThread]
    static void Main(string[] args) {
        // etc...
    }

从技术上讲,STA线程也应该像Winforms或WPF应用程序一样启动一个消息循环。但只要你只从主线程调用方法,你就可以摆脱它。

我知道这是一个较老的问题,但我想我会分享我的发现,因为它与此相关。我看到的问题是上面发布的只要代码中有断点,方法就可以工作。如果没有断点,事件将触发,但只有在退出它所在的方法调用后才会触发

这意味着

    InputController.PrintScreen();
    var img=Clipboard.GetImage();
无法工作,因为剪贴板在离开此方法之前不会填充。解决此问题的方法是使用DoEvents()的旧VB技巧。这将允许我们的应用程序处理队列中的所有windows消息。因此,修改后的代码应该可以工作

    InputController.PrintScreen();
    Application.DoEvents();
    var img=Clipboard.GetImage();

我知道这是一个较老的问题,但我想我会分享我的发现,因为它与此相关。我看到的问题是,只要我在代码中有断点,上面发布的方法就可以工作。如果没有断点,事件将触发,但只有在退出它所在的方法调用后才会触发

这意味着