GetDC_(WindowHandle) liefert falsches handle?

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

GetDC_(WindowHandle) liefert falsches handle?

Beitrag von Kurzer »

Hallo,

ich habe ein Problem mit einem Code aus dem Forum, welcher einen (Teil-)Screenshot von einem fremden Fenster anfertigt. Es muss dazu ein Teil des Fenstertitels des zu grabbenden Fensters in Zeile 21 eingetragen werden. In meinem Fall ist das das Fenster des Programms 'Total Commander', aber ihr könnt hier auch Notepad eintragen oder was auch immer bei Euch gerade für Fenster geöffnet sind.

Das Beispiel ist ein reiner Testcode und daher nicht sonderlich schön.

Das Problem das ich damit habe ist, dass der Screenshot zwar korrekt angefertigt wird, aber sobald über dem gegrabbten Fenster ein anderes Fenster liegt, wird das obere Fenster gegrabbt. Es sieht fast so aus als würde immer der DC des Desktops benutzt werden, was ich nicht verstehe, weil: DC = GetDC_(WindowHandle) und Windowhandle ist nun mal das handle des Fensters im Hintergrund.

Kann das jemand aufklären?

Gruß Kurzer

Code: Alles auswählen

; English forum: http://www.purebasic.fr/english/viewtopic.php?t=8244&highlight=
; Author: freak
; Date: 10. November 2003
; OS: Windows
; Demo: No

EnableExplicit

Global.l Breite = 500, Hoehe = 300, OffsetX = 0, OffsetY = 0

; Procedure that will be called for each window... 
Procedure.l EnumProcedure(WindowHandle.i, Parameter.l) 
	Protected.i DC, MyDC
	Protected.s Title$
	
  ; get Title by windowhandle... 
  Title$ = Space(200) 
  GetWindowText_(WindowHandle, @Title$, 200) 
  
  ; do whatever to check... 
  If FindString(Title$, "Total Commander", 1) <> 0 
	  	DC = GetDC_(WindowHandle)
  		MyDC = StartDrawing(ImageOutput(0))
  		Debug Title$
  		Debug WindowHandle
	  	If DC
		  	Debug DC
        BitBlt_(MyDC,0,0,Breite,Hoehe,DC,OffsetX,OffsetY,#SRCCOPY)
		  	Debug ReleaseDC_(WindowHandle, DC)
		  EndIf
		  StopDrawing()
    ; returning 0 will stop the search 
    ProcedureReturn 0 
  Else 
  
    ; returning <> 0 will continue till all windows are searched 
    ProcedureReturn 1 
  EndIf 
  
EndProcedure 


Procedure ViewImage()
  Protected Event
  
  If OpenWindow(0, 0, 0, ImageWidth(0), ImageHeight(0), "Image", #PB_Window_SystemMenu)
    ImageGadget(0, 0, 0, ImageWidth(0), ImageHeight(0), ImageID(0))
    
    Repeat
      Event = WaitWindowEvent()
    Until Event = #PB_Event_CloseWindow
    CloseWindow(0)
  EndIf
EndProcedure


CreateImage(0,Breite,Hoehe)
; find windows... 
EnumWindows_(@EnumProcedure(), 0)  ; the 0 will be passed in Paremeter.l to the procedure 
ViewImage()
FreeImage(0)
End
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von RSBasic »

Ich habe es mit Notepad und mit dem Taschenrechner getestet. Der Taschenrechner befand sich über das Notepad-Fenster, aber hier kann ich es leider nicht nachstellen und es funktioniert bei mir.
Alternativ kannst du mit PrintWindow_() testen, ob es damit besser funktioniert.
Beispielcode: http://www.rsbasic.de/aktualisierung/wi ... stellen.pb
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von Kurzer »

Danke fürs Testen, RSBasic. Komisch, dass es bei Dir funktioniert.

Die Lösung mit "Printwindow" funktioniert hier zuverlässig. :allright: Trotzdem würde mich schon interessieren warum es mit GetDC_() und BitBlt_() nicht geht. Hmmm, ominös.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von Kurzer »

Ich dachte mir, dass das Problem evtl. daran liegt, dass das BitBlt_ innerhalb der Windows Enumerations-Procedure durchgeführt wird. Daher habe ich meinen eigentlichen Code mal so weit reduziert, dass nur noch die Screenshotfunktion übrig bleibt. Hier wird von der EnumProcedure lediglich das Windowhandle in eine globale Struktur geschrieben und das Screengrabbing ausserhalb durchgeführt.

Leider habe ich hier das gleiche Problem, dass die oben liegenden Fenster gegrabbt werden, statt das, von dem das Windowhandle ermittelt worden ist.

Ich kompiliere das mal und teste es unter Win7 - 64 Bit. Hmm, hier geht es einwandfrei (abgesehen davon, dass in 10% der Versuche unter Win 7 ein weißes Image angezeigt wird. Dies deutet darauf hin, dass das Windowhandle nicht ermittelt werden konnte oder einer der beiden DCs nicht erstellt bzw. ermittelt wurde.

Erklärt noch immer nicht, warum es unter Win XP SP3 32 Bit nicht korrekt funktioniert. Boahhh wie ich solche Fehler hasse. :evil:

Der Fenstertitel wird in der drittletzten Zeile angegeben.

Code: Alles auswählen

EnableExplicit

Structure GrabWindow
	sWindowTitle.s
	iWindowHandle.i
EndStructure

Global stBrowserWindow.GrabWindow
Global.i iWindow, iCanvas_Screenshot

Procedure.i Settings_FindWindowHandleEnumProc(iWindowHandle.i, lParameter.l)
	; +-----------------------------------------------------------------
	; |Description  : EnumProceduere für Settings_GetWindowHandle()
	; |Arguments    : lWindowHandle: Enthält das Windowhandle des aktuell enumerierten Fensters
	; |             : lParameter   : Muss die Speicheradresse der Parameter-Struktur enthalten
	; |Results      : 0, wenn die enumeration gestoppt werden soll, sonst 1
	; |Remarks      : Siehe auch: https://msdn.microsoft.com/de-de/library/windows/desktop/ms633497(v=vs.85).aspx
	; +-----------------------------------------------------------------
	Protected.s sTitle=Space(32)
	
	GetWindowText_(iWindowHandle, sTitle, 32) 
	
	If FindString(sTitle, stBrowserWindow\sWindowTitle) <> 0 
		stBrowserWindow\iWindowHandle = iWindowHandle
		; Das gesuchte Fenster wurde gefunden, EnumProc nicht weiter aufrufen
		ProcedureReturn 0
	Else 
		; Weitere Fenster durchsuchen, EnumProc weiter aufrufen
		ProcedureReturn 1
	EndIf 
EndProcedure
Procedure.l Settings_GetWindowHandle(sWindowTitle.s)
	; +-----------------------------------------------------------------
	; |Description  : Ermittelt das Windowhandle eines Fensters anhand des Fenstertitels
	; |Arguments    : sWindowTitle: Titel des zu suchenden Fensters
	; |Results      : Das gesuchte Windowhandle oder 0, wenn das Fenster nicht gefunden wurde
	; |Remarks      : Es reicht aus, wenn der linke Teil des Fenstertitels angegeben wird.
	; |             : Z.B.: "PureBasi" -< findet auch das Fenster mit dem Titel "PureBasic 5.50 (x86)"
	; +-----------------------------------------------------------------
	
	stBrowserWindow\sWindowTitle = sWindowTitle
	
	If EnumWindows_(@Settings_FindWindowHandleEnumProc(), @stBrowserWindow) = 1
		ProcedureReturn 0
	Else
		ProcedureReturn stBrowserWindow\iWindowHandle
	EndIf
EndProcedure
Procedure   Grab(sWindowTitle.s)
	; +-----------------------------------------------------------------
	; |Description  : -
	; |Arguments    : -
	; |Results      : -
	; |Remarks      : -
	; +-----------------------------------------------------------------
	Protected.i iBrowserWindowHandle, iBrowserDC, iCanvasDC
	
	iBrowserWindowHandle = Settings_GetWindowHandle(sWindowTitle)
	If iBrowserWindowHandle > 0
		iCanvasDC = StartDrawing(CanvasOutput(iCanvas_Screenshot))
		If iCanvasDC
			iBrowserDC = GetWindowDC_(iBrowserWindowHandle)
			If iBrowserDC > 0
				BitBlt_(iCanvasDC, 0, 0, 300, 300, iBrowserDC, 0, 0, #SRCCOPY)
				ReleaseDC_(iBrowserWindowHandle, iBrowserDC)
			EndIf
			StopDrawing()
		EndIf
	EndIf
EndProcedure

iWindow = OpenWindow(#PB_Any, #PB_Ignore, #PB_Ignore, 320, 320, "", #PB_Window_SystemMenu|#PB_Window_TitleBar)
If iWindow
	iCanvas_Screenshot = CanvasGadget(#PB_Any, 10, 10, 300, 300)
	Grab("Total Commander")
EndIf

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Bild
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von RSBasic »

Kurzer hat geschrieben:Erklärt noch immer nicht, warum es unter Win XP SP3 32 Bit nicht korrekt funktioniert. Boahhh wie ich solche Fehler hasse. :evil:
Naja, WinAPI-Funktionen werden ja auch verbessert. Vielleicht war das unter XP ein Bug, der aber ab Windows 7 behoben ist.
Vielleicht kann BitBlt_() unter XP nur de sichtbaren Pixel kopieren. Leider weiß ich auch nicht, woran das genau liegt.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
Rudi
Beiträge: 143
Registriert: 22.04.2010 18:28
Wohnort: #PB_Any

Re: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von Rudi »

Das Problem hatte ich auch erst. Darum teste mal diese Procedure: http://www.purebasic.fr/german/viewtopi ... =8&t=29829
Win7 (x64)PB 5.4x (x86)5,7 Windows-LeistungsindexSuche
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: AW: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von Kurzer »

Hallo Rudi,

ich kann deinen code gerade nicht testen, weil ich unterwegs bin, aber ich glaube, dass ich ihn auch schon mal in der IDE hatte.

Prinzipiell machst du dort das gleiche wie ich. GetWindowDC und BitBlt. Nur grabbst du das eigene window und nicht ein fremdes window. Das scheint meinen aktuellen Recherchen nach genau das Problem zu sein. In irgend einem coder-forum habe ich vorhin gelesen, dass ein DeviceContext immer nur für den ihn besitzenden Prozess gültig ist und nicht für fremde Prozesse.

Von daher muss ich wohl die von RSBasic vorgeschlagene PrintWindow_ Version benutzen, wobei netmaestro im englischen Forum dazu schreibt, dass man dann nicht den DC von StartDrawing benutzen darf. Es geht hier aber trotzdem. Dazu muss ich mir noch weitere Infos einholen, wenn ich wieder zuhause bin.

Außerdem möchte ich nur einen kleinen Ausschnitt des Fensters grabben. PrintWindow grabbt allerdings immer alles.
Zuletzt geändert von Kurzer am 26.09.2016 21:30, insgesamt 1-mal geändert.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Benutzeravatar
Rudi
Beiträge: 143
Registriert: 22.04.2010 18:28
Wohnort: #PB_Any

Re: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von Rudi »

Hallo Kurzer,
experimentiere mal mit den "int" - Parametern von "BitBlt_", insbesondere mit den ersten beiden, dann müsstest Du schon einen Unterschied feststellen können!

Beispiel aus meinem Code:

Code: Alles auswählen

BitBlt_(hImageDC, -BorderWidth, -BorderHeight, ClientWidth+BorderWidth, ClientHeight+BorderHeight, hDC, 0, 0, #SRCCOPY|#SRCPAINT)
Win7 (x64)PB 5.4x (x86)5,7 Windows-LeistungsindexSuche
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von Kurzer »

Hallo Rudi,
das hilft hier leider nicht.

Nehme ich #SRCCOPY|#SRCPAINT, dann kommt nur ein weißes Bild im Ziel an.

Im Prinzip sind dies ja auch nur Modis, die angeben wie die Bilddaten verarbeitet werden sollen. Die Anleitung zu diesem Pramater deutet nicht darauf hin, dass man hier Einfluss auf die zu verwendende Quellbitmap nehmen kann.
dwRop
Specifies a raster-operation code. These codes define how the color data for the source rectangle is to be combined with the color data for the destination rectangle to achieve the final color.
The following list shows some common raster operation codes:

Value Description
BLACKNESS Fills the destination rectangle using the color associated with index 0 in the physical palette. (This color is black for the default physical palette.)
DSTINVERT Inverts the destination rectangle.
MERGECOPY Merges the colors of the source rectangle with the specified pattern by using the Boolean AND operator.
MERGEPAINT Merges the colors of the inverted source rectangle with the colors of the destination rectangle by using the Boolean OR operator.
NOTSRCCOPY Copies the inverted source rectangle to the destination.
NOTSRCERASE Combines the colors of the source and destination rectangles by using the Boolean OR operator and then inverts the resultant color.
PATCOPY Copies the specified pattern into the destination bitmap.
PATINVERT Combines the colors of the specified pattern with the colors of the destination rectangle by using the Boolean XOR operator.
PATPAINT Combines the colors of the pattern with the colors of the inverted source rectangle by using the Boolean OR operator. The result of this operation is combined with the colors of the destination rectangle by using the Boolean OR operator.
SRCAND Combines the colors of the source and destination rectangles by using the Boolean AND operator.
SRCCOPY Copies the source rectangle directly to the destination rectangle.
SRCERASE Combines the inverted colors of the destination rectangle with the colors of the source rectangle by using the Boolean AND operator.
SRCINVERT Combines the colors of the source and destination rectangles by using the Boolean XOR operator.
SRCPAINT Combines the colors of the source and destination rectangles by using the Boolean OR operator.
WHITENESS Fills the destination rectangle using the color associated with index 1 in the physical palette. (This color is white for the default physical palette.)
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Benutzeravatar
Rudi
Beiträge: 143
Registriert: 22.04.2010 18:28
Wohnort: #PB_Any

Re: GetDC_(WindowHandle) liefert falsches handle?

Beitrag von Rudi »

Das meinte ich aber auch nicht, sondern wo in meinem Code:
"-BorderWidth, -BorderHeight, ClientWidth+BorderWidth, ClientHeight+BorderHeight, hDC, 0, 0"
drinnen steht. :?
Win7 (x64)PB 5.4x (x86)5,7 Windows-LeistungsindexSuche
Antworten