CallbackOnCollectedDelegate在Application.Run(new Form1()) [英] CallbackOnCollectedDelegate at Application.Run(new Form1())

查看:206
本文介绍了CallbackOnCollectedDelegate在Application.Run(new Form1())的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了一个非常小的应用程序,使用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 :


回收是在一个垃圾收集的代理类型'CaptureScreen!CaptureScreen.Form1 + WinEventDelegate: :调用。这可能会导致应用程序崩溃,损坏和数据丢失。当代理人通过非托管代码时,托管应用程序必须保持活动状态,直到保证不会被调用为止。

A callback was made on a garbage collected delegate of type 'CaptureScreen!CaptureScreen.Form1+WinEventDelegate::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

在我的program.cs中的这一行:

at this line in my program.cs:


Application.Run(new Form1());

Application.Run(new Form1());

我的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);
        }
    }

可以在这里找到捕获屏幕的类:
http://spazzarama.wordpress.com/2009/ 02/07 / screencapture-with-direct3d /

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())的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆