Gateway_man Geschrieben 4. März 2012 Teilen Geschrieben 4. März 2012 Hi leute, gleich noch ein zweites Problem. Ich möchte Screenshots über die WinApi machen. Beim dem Primary Screen ist das kein Problem. Für diesen hol ich mir das Handle über GetDesktopWindow aus der User32.dll. Das klappt auch wunderbar. Allerdings möchte ich auch weitere Screens supporten. Ich bin dann auf EnumDisplayMonitors gestoßen. Die Funktion liefert mir im Grunde schon alle Screens zurück, jedoch ist das Handle Invalid. Ich hab das Handle meines Hauptbildschirmes das ich mit EnumDisplayMonitors mit dem Handle verglichen, das ich mit GetDesktopWindow bekomme. Sie sind unterschiedlich (aber kein Zero). Und wenn ich dann natürlich ein Screenshot machen möchte sagt mir GetLastError das das Handle Invalid ist. Das ist die Klasse die mir die Informationen über alle MonitorDevices geben soll: public sealed class MonitorIdentifier { #region Fields private int counter = 0; private int maxDevices = System.Windows.Forms.Screen.AllScreens.Count(); private CloneableList<ScreenDevice> availableScreens = null; private AsyncStateChanged asyncResult = null; USER32.MonitorEnumDelegate med; #endregion public MonitorIdentifier() { med = new USER32.MonitorEnumDelegate(EnumDisplayMonitorsCallBack); } public MonitorIdentifier(AsyncStateChanged result) { med = new USER32.MonitorEnumDelegate(EnumDisplayMonitorsCallBack); asyncResult = result; if (asyncResult == null) throw new InvalidOperationException("AsyncResult can't be null!"); } #region Public Functions public bool BeginEnumMonitors() { if (AsyncResult == null) throw new InvalidOperationException("AsyncResult can't be null!"); else return USER32.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, med, IntPtr.Zero); } #endregion #region Properties public AsyncStateChanged AsyncResult { get { return asyncResult; } set { asyncResult = value; } } #endregion #region Private Functions private bool EnumDisplayMonitorsCallBack(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeStructures.RECT lprcMonitor, IntPtr dwData){ counter++; IntPtr ptr = Utillity.WinApi.USER32.GetDesktopWindow(); NativeStructures.MonitorInfo mi = new NativeStructures.MonitorInfo(); mi.size = (uint)Marshal.SizeOf(mi); bool success = USER32.GetMonitorInfo(hMonitor, ref mi); if (availableScreens == null) { availableScreens = new CloneableList<ScreenDevice>(); } if (success) { ScreenDevice dev = new ScreenDevice(); dev.mInfo = mi; dev.hMonitor = hMonitor; dev.dwData = dwData; dev.hdcMonitor = hdcMonitor; availableScreens.Add(dev); } if (counter == maxDevices) { asyncResult.Invoke(this, new object[] { availableScreens.Clone() }); counter = 0; availableScreens.Clear(); availableScreens = null; } return success; } #endregion } Das ist die ScreenDevice Structure: public struct ScreenDevice { #region Fields public Utillity.NativeStructures.MonitorInfo mInfo; public IntPtr hMonitor; public IntPtr hdcMonitor; public NativeStructures.RECT Rect; public IntPtr dwData; #endregion }; Das ist die MonitorInfo Structure: [StructLayout(LayoutKind.Sequential)] public struct MonitorInfo { public uint size; public RECT monitor; public RECT work; public uint flags; }; Die User32 Signaturen sehen bei mir so aus: [DllImport("user32.dll")] public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData); [DllImport("user32.dll")] public static extern bool GetMonitorInfo(IntPtr hmon, ref NativeStructures.MonitorInfo mi); Definition des MonitorEnumDelegate: public delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeStructures.RECT lprcMonitor, IntPtr dwData); Das AsyncStateChanged Delegate ist eigentlich nicht relevant aber falls es jemand wissen möchte wie es definiert wurde: public delegate void AsyncStateChanged(object sender, object[] data); Ein Beispielaufruf sieht so aus: public partial class Form1 : Form { private ScreenDevice dev = new ScreenDevice(); private Utillity.Templates.CloneableList<Utillity.Devices.ScreenDevice> screens = null; private Utillity.Devices.MonitorIdentifier monitoridentifier = null; public Form1() { InitializeComponent(); monitoridentifier = new Utillity.Devices.MonitorIdentifier(new Utillity.AsyncStateChanged(AsyncFinished)); monitoridentifier.BeginEnumMonitors(); } private void AsyncFinished(object sender, object[] data) { if (data != null) { screens = (Utillity.Templates.CloneableList<Utillity.Devices.ScreenDevice>)data[0]; //dev = screens.Where(P => P.mInfo.monitor.Left > 0).ToList()[0]; dev = screens[1]; } private void CaptureScreen() { Bitmap bmp; if (dev.hMonitor != IntPtr.Zero) bmp = (Bitmap)Utillity.ImageUtil.CaptureScreen.CaptureWindow(dev.hMonitor); else bmp = Utillity.ImageUtil.CaptureScreen.GetDesktopImage(); if (bmp != null) { pictureBox1.Image = bmp; } } } Um das Wertetechnisch hier mal zu erfassen. Laut GetDesktopWindow hat mein Primärer Desktop das handle 65552. Laut EnumDisplayMonitors hat mein Primärer Desktop das handle 65537. Das handle das ich über GetDesktopWindow() ist gültig, hingegen EnumDisplayMonitors ein ungültiges Handle zurückgibt. Hat jemand eine Idee? lg Gateway Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Klotzkopp Geschrieben 4. März 2012 Teilen Geschrieben 4. März 2012 Das handle das ich über GetDesktopWindow() ist gültig, hingegen EnumDisplayMonitors ein ungültiges Handle zurückgibt.Das Handle ist nicht ungültig. Es ist ein gültiges Monitor-Handle. Nur kann eine Funktion, die ein Fenster-Handle erwartet, damit einfach nichts anfangen. Das Problem ist eigentlich die Verwendung von GetDesktopWindow, denn diese Funktion beschränkt sich selbst aus Kompatibilitätsgründen auf den Primären Monitor. Wenn du deinen Desktop auf weitere Monitore erweiterst, ist deine Desktopfläche dementsprechend größer. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Gateway_man Geschrieben 4. März 2012 Autor Teilen Geschrieben 4. März 2012 Ah okay. Kennst du zufällig eine ApiFunktion mit der ich den kompletten Bildschirmbereich für das bild erfassen kann? Ich kann ja dannach mit BitBlt den entsprechend relevanten Bereich herauskopieren. Alternativvorschläge sind auch erwünsch . Wichtig für mich ist, das das ganze über pInvoke geschieht. lg Gateway Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Gateway_man Geschrieben 4. März 2012 Autor Teilen Geschrieben 4. März 2012 hat sich erledigt danke. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.