问题描述
我做了一个非常小的应用程序,使用SlimDX捕获游戏中的屏幕。
(我按左键捕获)
I made a very small application that captures the screen inside games using SlimDX.(I press left click to capture)
捕获工作(至少当我点击表单本身),但一旦我点击Firefox或任何其他应用程序,我得到这个例外:
The capture works (atleast when I click on the form itself) but as soon as I click on firefox or any other application, I get this exception :
在我的program.cs中的这一行:
at this line in my program.cs:
我的Form1.cs(设计器本身没有控件)
My Form1.cs (the designer itself has no controls)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX.Direct3D;
namespace CaptureScreen
{
public partial class Form1 : Form
{
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
private const int WH_MOUSE_LL = 14;
private const int WM_LBUTTONDOWN = 513;
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
IntPtr m_hhook;
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public Form1()
{
m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
hookProc = new HookProc(LowLevelMouseProc);
hook = SetWindowsHookEx(WH_MOUSE_LL, hookProc, GetModuleHandle(null), 0);
InitializeComponent();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
UnhookWinEvent(m_hhook);
UnhookWindowsHookEx(hook);
}
void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (eventType == EVENT_SYSTEM_FOREGROUND)
{
StringBuilder sb = new StringBuilder(500);
GetWindowText(hwnd, sb, sb.Capacity);
}
}
[DllImport("kernel32.dll")]
static extern IntPtr GetModuleHandle(string moduleName);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
public static extern int UnhookWindowsHookEx(IntPtr hhook);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, uint wParam, IntPtr lParam);
delegate IntPtr HookProc(int nCode, uint wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
private HookProc hookProc;
private IntPtr hook;
IntPtr LowLevelMouseProc(int nCode, uint wParam, IntPtr lParam)
{
if (nCode >= 0 && (IntPtr)wParam == (IntPtr)WM_LBUTTONDOWN)
{
CaptureScreen();
}
return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
private void CaptureScreen()
{
StreamReader reader = new StreamReader(Path.GetFullPath("../../Counter.txt"));
string currentpic = reader.ReadLine();
if (string.IsNullOrEmpty(currentpic))
currentpic = "0";
reader.Close();
Bitmap bitmap = Direct3DCapture.CaptureWindow(GetForegroundWindow());
bitmap.Save(Path.GetFullPath("../../ScreenCapture/Test" + currentpic + ".gif"), ImageFormat.Gif);
StreamWriter writer = new StreamWriter(Path.GetFullPath("../../Counter.txt"));
writer.Write((int.Parse(currentpic)) + 1);
writer.Close();
}
public readonly uint DWM_EC_DISABLECOMPOSITION = 0;
public readonly uint DWM_EC_ENABLECOMPOSITION = 1;
[DllImport("dwmapi.dll", EntryPoint = "DwmEnableComposition")]
protected static extern uint Win32DwmEnableComposition(uint uCompositionAction);
}
}
可以在这里找到捕获屏幕的类:
the class that captures the screen can be found here:http://spazzarama.wordpress.com/2009/02/07/screencapture-with-direct3d/
任何想法如何解决这个问题?
Any idea on how I can fix this?
推荐答案
您的问题是您只是将WinEventProc传递给SetWinEventHook,它将隐式创建一个当前方法退出时有资格进行GCed的代理(如果不是更快)看到这个事实的后果。
Your problem is that you are just passing WinEventProc to SetWinEventHook, which will implicitly create a delegate that is eligible to be GCed once the current method exits (if not sooner!) You are seeing the consequences of that fact.
您将需要创建一个类型为WinEventDelegate的Form1的新成员,并将其用作参数:
You will need to create a new member of Form1 of type WinEventDelegate, and use that as the parameter:
private WinEventDelegate winEventProc;
然后在调用SetWinEventHook时使用它:
and then make use of it in your call to SetWinEventHook:
this.winEventProc = new WinEventDelegate(WinEventProc);
m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, this.winEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
应该确保您的代理在需要时保持活着。
That should ensure that your delegate stays alive as long as you need.
这篇关于CallbackOnCollectedDelegate在Application.Run(new Form1())的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!