merkwürdiges Screenshot-Problem mit dem Firefox-Bibliothek-Fenster

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    merkwürdiges Screenshot-Problem mit dem Firefox-Bibliothek-Fenster

    Einen angenehmen Heiligen Abend, liebe Leute.

    Es geht um ein Screenshot-Programm, das andere Fenster ausliest, auch wenn sie aus dem Screen-Bereich herausgeschoben wurden.
    Wenn ich das Firefox-Bibliothek-Fenster kopieren will, wird nur beim ersten Aufruf das aktuelle Fenster angezeigt.
    Wird der Inhalt des Firefox-Bibliothek-Fensters manipuliert (z.B. durch Löschen der Chronik), wird beim nächsten Aufruf das ursprüngliche Fenster angezeigt.
    Erst nach Schließen und wieder Öffnen des Firefox-Bibliothek-Fensters wird der neue Inhalt angezeigt.
    Bei anderen Fenster funktioniert das richtig.
    Hat jemand eine Idee, woran das liegen könnte?

    Ich hänge mal den minimalistischen Code an.
    Der Name des Fensters wird in der BtnCopy_Click(..) eingetragen.
    Form-Code

    C#-Quellcode

    1. using System;
    2. using System.Drawing;
    3. using System.Runtime.InteropServices;
    4. using System.Windows.Forms;
    5. namespace ScreenShotOtherProgram
    6. {
    7. public partial class DlgScreenShot : Form
    8. {
    9. #region Win32
    10. private class Win32
    11. {
    12. internal const int SrcCopy = 0xCC0020;
    13. internal const int SwShowNormal = 1;
    14. internal struct RECT
    15. {
    16. internal int left;
    17. internal int top;
    18. internal int right;
    19. internal int bottom;
    20. internal int Width { get { return this.right - this.left; } }
    21. internal int Height { get { return this.bottom - this.top; } }
    22. internal int Area { get { return this.Width * this.Height; } }
    23. }
    24. [DllImport("user32.dll", SetLastError = true)]
    25. internal static extern bool BringWindowToTop(IntPtr hWnd);
    26. [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    27. internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    28. [DllImport("user32")]
    29. internal static extern bool ShowWindow(IntPtr hWnd, int style);
    30. [DllImport("user32.dll")]
    31. internal static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
    32. [DllImport("user32.dll")]
    33. internal static extern IntPtr GetDC(IntPtr hwnd);
    34. [DllImport("gdi32.dll", SetLastError = true)]
    35. internal static extern IntPtr CreateCompatibleDC(IntPtr hRefDC);
    36. [DllImport("gdi32.dll")]
    37. internal static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
    38. [DllImport("Gdi32.dll")]
    39. internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject);
    40. [DllImport("gdi32.dll")]
    41. internal static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
    42. [DllImport("gdi32.dll")]
    43. internal static extern bool DeleteDC(IntPtr hdc);
    44. [DllImport("user32.dll")]
    45. internal static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
    46. [DllImport("gdi32.dll")]
    47. internal static extern bool DeleteObject(IntPtr hObject);
    48. }
    49. #endregion Win32
    50. public DlgScreenShot()
    51. {
    52. this.InitializeComponent();
    53. }
    54. private void BtnCopy_Click(object sender, EventArgs e)
    55. {
    56. // separates Firefox-Download-Fenster
    57. string txt = "Bibliothek";
    58. //txt = "Info.txt - Editor";
    59. this.ScreenShot(txt);
    60. }
    61. /// <summary>
    62. /// Screenshot des benannten Fensters aufnehmen und anzeigen
    63. /// </summary>
    64. /// <param name="txt"></param>
    65. private void ScreenShot(string txt)
    66. {
    67. IntPtr hWnd = Win32.FindWindow(null, txt);
    68. if (hWnd == IntPtr.Zero)
    69. {
    70. MessageBox.Show($"Window not found:\n\n\"{txt}\"", "No Window Match", MessageBoxButtons.OK, MessageBoxIcon.Information);
    71. return;
    72. }
    73. // Capture app to Bitmap
    74. Bitmap bmp = CreateBitmap(hWnd);
    75. if (bmp is null)
    76. {
    77. MessageBox.Show("Capture failed!", "Capture Fail", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
    78. return;
    79. }
    80. if (this.pictureBox1.Image != null)
    81. {
    82. this.pictureBox1.Image.Dispose();
    83. }
    84. // save bitmap to a public folder
    85. this.pictureBox1.Image = bmp;
    86. }
    87. /// <summary>
    88. /// Auslesen des Capture der Form
    89. /// </summary>
    90. /// <param name="hWnd">die Ziel-Form</param>
    91. /// <returns>deren Capture</returns>
    92. private static Bitmap CreateBitmap(IntPtr hWnd)
    93. {
    94. // minimiertes / maximiertes Fenster normal anzeigen
    95. Win32.ShowWindow(hWnd, Win32.SwShowNormal);
    96. // und nach vorn holen
    97. Win32.BringWindowToTop(hWnd);
    98. System.Threading.Thread.Sleep(100);
    99. Win32.RECT rect = default;
    100. Win32.GetWindowRect(hWnd, ref rect);
    101. if (rect.Area == 0)
    102. {
    103. // Fenster ohne Fläche
    104. return null;
    105. }
    106. Bitmap bmp = new Bitmap(rect.Width, rect.Height);
    107. IntPtr hdcFrom = Win32.GetDC(hWnd);
    108. IntPtr hdcTo = Win32.CreateCompatibleDC(hdcFrom);
    109. IntPtr hBitmap = Win32.CreateCompatibleBitmap(hdcFrom, bmp.Width, bmp.Height);
    110. if (hBitmap != IntPtr.Zero)
    111. {
    112. IntPtr hLocalBitmap = Win32.SelectObject(hdcTo, hBitmap);
    113. Win32.BitBlt(hdcTo, 0, 0, bmp.Width, bmp.Height, hdcFrom, 0, 0, Win32.SrcCopy);
    114. Win32.SelectObject(hdcTo, hLocalBitmap);
    115. Win32.DeleteDC(hdcTo);
    116. Win32.ReleaseDC(hWnd, hdcFrom);
    117. bmp = Image.FromHbitmap(hBitmap);
    118. Win32.DeleteObject(hBitmap);
    119. }
    120. return bmp;
    121. }
    122. }
    123. }
    Designer-Code

    C#-Quellcode

    1. namespace ScreenShotOtherProgram
    2. {
    3. partial class DlgScreenShot
    4. {
    5. /// <summary>
    6. /// Required designer variable.
    7. /// </summary>
    8. private System.ComponentModel.IContainer components = null;
    9. /// <summary>
    10. /// Clean up any resources being used.
    11. /// </summary>
    12. /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    13. protected override void Dispose(bool disposing)
    14. {
    15. if (disposing)
    16. {
    17. if (components != null)
    18. {
    19. components.Dispose();
    20. }
    21. }
    22. base.Dispose(disposing);
    23. }
    24. #region Windows Form Designer generated code
    25. /// <summary>
    26. /// Required method for Designer support - do not modify
    27. /// the contents of this method with the code editor.
    28. /// </summary>
    29. private void InitializeComponent()
    30. {
    31. this.pictureBox1 = new System.Windows.Forms.PictureBox();
    32. this.btnCopy = new System.Windows.Forms.Button();
    33. ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
    34. this.SuspendLayout();
    35. //
    36. // pictureBox1
    37. //
    38. this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
    39. | System.Windows.Forms.AnchorStyles.Left)
    40. | System.Windows.Forms.AnchorStyles.Right)));
    41. this.pictureBox1.Location = new System.Drawing.Point(94, 13);
    42. this.pictureBox1.Name = "pictureBox1";
    43. this.pictureBox1.Size = new System.Drawing.Size(694, 425);
    44. this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
    45. this.pictureBox1.TabIndex = 0;
    46. this.pictureBox1.TabStop = false;
    47. //
    48. // btnCopy
    49. //
    50. this.btnCopy.Location = new System.Drawing.Point(13, 13);
    51. this.btnCopy.Name = "btnCopy";
    52. this.btnCopy.Size = new System.Drawing.Size(75, 23);
    53. this.btnCopy.TabIndex = 1;
    54. this.btnCopy.Text = "Copy";
    55. this.btnCopy.UseVisualStyleBackColor = true;
    56. this.btnCopy.Click += new System.EventHandler(this.BtnCopy_Click);
    57. //
    58. // DlgScreenShot
    59. //
    60. this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    61. this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    62. this.ClientSize = new System.Drawing.Size(800, 450);
    63. this.Controls.Add(this.btnCopy);
    64. this.Controls.Add(this.pictureBox1);
    65. this.Name = "DlgScreenShot";
    66. this.Text = "DlgScreenShot";
    67. ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
    68. this.ResumeLayout(false);
    69. }
    70. #endregion
    71. private System.Windows.Forms.PictureBox pictureBox1;
    72. private System.Windows.Forms.Button btnCopy;
    73. }
    74. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hi

    UWP-CapturePicker Fenster für ScreenShots/Videoaufzeichnung anzeigen (ab Windows 10) Zeigt dieses Bsp das entsprechende Fenster an? Wenn ja, dann könntest das Interface IGraphicsCaptureItem per Direct3D weiter verarbeiten oder über den Fensternamen (von IGraphicsCaptureItem auslesen) den HWND, davon den RECT ermitteln und dann entsprechend Capturen. Ein komplettes Bsp, incl. Direct3D-Geschichte, hab ich allerdings im Moment nur für VB6 parat.
    Mfg -Franky-
    @-Franky- OK, der erste Schnelltest sieht gut aus.
    Ich werde mich dann, wenn wieder etwas mehr Zeit ist, damit befassen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hi

    k.A. in wie weit Du VB6-Code lesen und nach .NET übersetzen kannst. Hier das VB6-Bsp. mit dem Direct3D-Part zum Capturen von Fenstern und Screens: activevb.de/cgi-bin/upload/download.pl?id=3904 Der Part über den Fensternamen -> HWND -> RECT usw ist hier aber nicht enthalten.
    Mfg -Franky-

    -Franky- schrieb:

    ist hier aber nicht enthalten.
    Kommtr bei mir oben vor in der Prozedur CreateBitmap() ab Zeile 104.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    -Franky- schrieb:

    Direct3D
    hatte ich noch nichts zu tun mit, aber rein sehen immer.
    ====
    @-Franky- Ich hab mal reingesehen, das zu übertragen ist wohl nix für mich, ich werfe das Handtuch.
    Sorry.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    Hi

    Ja ist schon heftig was man da noch per Direct3D veranstalten muss um am Ende an ein Bitmap zu kommen. Falls Du das Win10 SDK installiert hast und Du arbeitest ja mit dem NET 4.x, dann könntest Du einen Verweis auf die Windows.winmd verwenden. Üblicherweise liegt die Datei unter C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.22621.0\Windows.winmd wobei die 10.0.22621.0 der Version des SDK entspricht. Dann hättest alle WinRT-NameSpaces/Klassen parat. Evtl. benötigt man dann noch ein/zwei Nuget-Pakete für die Async/Await Geschichte falls bei einer Async-Funktion gemeckert wird, das ein entsprechender GetAwaiter erwartet wird.
    Mfg -Franky-
    OK.
    Wenn ich die Forderung aufgebe, dass Fenster aus dem Screen-Bereich herausgeschoben sein können,
    ist das ganze doch simpel zu lösen:
    Spoiler anzeigen

    C#-Quellcode

    1. /// <summary>
    2. /// Auslesen des Capture der Form
    3. /// </summary>
    4. /// <param name="hWnd">die Ziel-Form</param>
    5. /// <returns>deren Capture</returns>
    6. private static Bitmap CreateBitmap(IntPtr hWnd)
    7. {
    8. // minimiertes / maximiertes Fenster normal anzeigen
    9. Win32.ShowWindow(hWnd, Win32.SwShowNormal);
    10. // und nach vorn holen
    11. Win32.BringWindowToTop(hWnd);
    12. System.Threading.Thread.Sleep(100);
    13. Win32.RECT rect = default;
    14. Win32.GetWindowRect(hWnd, ref rect);
    15. if (rect.Area == 0)
    16. {
    17. // Fenster ohne Fläche
    18. return null;
    19. }
    20. Bitmap bmp = new Bitmap(rect.Width, rect.Height);
    21. Rectangle newRect = Rectangle.FromLTRB(rect.left, rect.top, rect.right, rect.bottom);
    22. using(Graphics g = Graphics.FromImage(bmp))
    23. {
    24. g.CopyFromScreen(rect.left, rect.top, 0, 0, newRect.Size);
    25. bmp.Save(@"D:\Temp\Test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
    26. }
    27. //IntPtr hdcFrom = Win32.GetDC(hWnd);
    28. //IntPtr hdcTo = Win32.CreateCompatibleDC(hdcFrom);
    29. //IntPtr hBitmap = Win32.CreateCompatibleBitmap(hdcFrom, bmp.Width, bmp.Height);
    30. //if (hBitmap != IntPtr.Zero)
    31. //{
    32. // IntPtr hLocalBitmap = Win32.SelectObject(hdcTo, hBitmap);
    33. // Win32.BitBlt(hdcTo, 0, 0, bmp.Width, bmp.Height, hdcFrom, 0, 0, Win32.SrcCopy);
    34. // Win32.SelectObject(hdcTo, hLocalBitmap);
    35. // Win32.DeleteDC(hdcTo);
    36. // Win32.ReleaseDC(hWnd, hdcFrom);
    37. // bmp = Image.FromHbitmap(hBitmap);
    38. // Win32.DeleteObject(hBitmap);
    39. //}
    40. return bmp;
    41. }
    @-Franky- Danke für Deine Unterstützung.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!