打印屏幕后剪贴板中没有图像
本文关键字:图像 剪贴板 屏幕 打印 | 更新日期: 2023-09-27 18:32:04
我正在实现不同的屏幕采集卡来比较它们。其中一个应该使用"打印屏幕"键和剪贴板。
我发送带有keybd_事件的击键:
[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);
}
在我的IEnumerable中,我调用此方法,然后尝试抓取图像:
...
InputController.PrintScreen();
var img=Clipboard.GetImage();
...
返回的图像始终为 null,并且 Clipboards.ContainsImage() 始终为假。我尝试在发送密钥后等待片刻,但它也不起作用。我是否缺少某种设置,或者是否存在根本错误?
PS:运行程序后,我可以将正确的图像粘贴到油漆或gimp中。
这是一个控制台程序
这是最相关的细节,你应该把它放在你的问题中。 剪贴板是一个系统对象,其基础 API 基于 COM。 这使得它对使用 API 的线程的单元状态敏感。 .NET 剪贴板类对此进行了一些摸索,如果线程的状态错误,它应该真正引发异常。 在控制台模式应用程序的情况下是错误的,默认情况下其主线程是 MTA,您需要 STA 才能使用 API。
修复很简单,您只需在 Main() 方法上放置一个属性来请求 STA:
[STAThread]
static void Main(string[] args) {
// etc...
}
从技术上讲,STA 线程还应该泵送消息循环,就像 Winforms 或 WPF 应用一样。 但是,只要您只从主线程进行方法调用,您就可以侥幸逃脱。
您是否尝试过使用 SendKeys 类?
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 const int KEYEVENTF_EXTENDEDKEY=0x0001; //key down
public const int KEYEVENTF_KEYUP=0x0002; //key up
但您正在使用:
keybd_event(VK_SNAPSHOT,0,KEYEVENT_EXTENDEDKEY,0);
keybd_event(VK_SNAPSHOT,0,KEYEVENT_KEYUP,0);
使用KEYEVENTF_EXTENDEDKEY并KEYEVENTF_KEYUP工作
回复:整个事情在线程池的工作线程中运行我找不到将 PrintScreen() 发布到"主同步上下文"的方法,因为它是一个控制台程序
你可以试试这个:
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();
}
这是一个较老的问题,但我想我会分享我的发现,因为它与此有关。 我看到的问题是,只要我在代码中有断点,上面发布的方法就可以工作。 如果没有断点,事件将触发,但只有在退出它所在的方法调用后才会触发。
这意味着类似
InputController.PrintScreen();
var img=Clipboard.GetImage();
不起作用,因为剪贴板在离开此方法之前不会填充。 解决这个问题的解决方法是使用 DoEvents() 的旧 VB 技巧。 这将允许我们的应用程序处理队列中的所有窗口消息。 因此,修订后的代码应该有效。
InputController.PrintScreen();
Application.DoEvents();
var img=Clipboard.GetImage();