Image auf Desktop ausgeben [gelöst]

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
sibru
Beiträge: 265
Registriert: 15.09.2004 18:11
Wohnort: hamburg

Image auf Desktop ausgeben [gelöst]

Beitrag von sibru »

Hallo allerseits,

ich möchte ´n Image direkt auf´m Desktop ausgeben

Code: Alles auswählen

Procedure ScreenDraw(ImgNr, x, y)   ;- Image aufs Desktop malen
  Protected Br, hdcDesktop, Ho
  If IsImage(ImgNr)
    hdcDesktop = GetDC_(GetDesktopWindow_()) ;Ziel-Handle
    Br = ImageWidth(ImgNr) : Ho = ImageHeight(ImgNr) ;Ziel-Größe
    Debug "Pos = " + Str(x) + " / " + Str(y) + ", Size = " + Str(Br) + " x " + Str(Ho)
    hdc = StartDrawing(ImageOutput(ImgNr)) ;Quell-Handle
    res = BitBlt_(hdcDesktop, x, y, Br, Ho, hdc, 1, 1, #SRCCOPY) 
    Debug "Result = "+Str(res)
    StopDrawing()
    ReleaseDC_(GetDesktopWindow_(), hdcDesktop) ;DC zum Desktop freigeben
  Else : Debug "no Image"
  EndIf
EndProcedure

GetClipboardImage(1)
ScreenDraw(1, 2000, 100)
Obwohl BitBlt_() erfolgreich (Result<>#false), passiert aufm Bildschirm nix :cry:
Weiß wer, wie´s geht ?

Das Gegenstück -ScreenShot- klappt wunderbar:

Code: Alles auswählen

;Modul      ScreenShot Version 1.02 vom 20.10.2017 
;
;Funktion:  erstelle Image vom aktuellen Desktop(-Ausschnitt)  !!eigenes Startdrawing() !!
;
;Aufruf:    ImageNr = ScreenShot({x, y {, b, h {, Bits}}})
;           x, y: Start-Position (Pixel vom linker und von oberen Monitor-Seite)
;                 wenn nicht angegeben, so beginnt ScreenShot an oberer, linker Monitorecke
;           b, h: Breite und Höhe [Pixel]
;                 wenn nicht angegeben, so wird vollständiger Desktop (auch über mehrere Monitore) benutzt
;           Bits: Tiefenangabe, gültige Werte können sein: 1, 2, 4, 8, 16, 24 oder 32 Bit.
;                 wenn nicht angegeben, so wird 24 benutzt
;
;           Diese Funktion liefert die #ImageNr des generierten Images
;
;#jaPBeExt exit
Procedure ScreenShot(x = 0, y = 0, b = 0, h = 0, Bits = 24);- liefert #Image mit aktuellem Desktop(Ausschnitt)-Inhalt  !!eigenes Startdrawing() !!
  Protected *DeskTop, Bitmap, DeskTop_DC, hdcMem
  If b <1 Or h <1 : x = 0 : y = 0             ;Breite oder Höhe nicht definiert: gesammten Desktop benutzten
    b = GetSystemMetrics_(#SM_CXVIRTUALSCREEN);GesammtBreite (über alle Monitore)
    h = GetSystemMetrics_(#SM_CYVIRTUALSCREEN);GesammtHöhe (über alle Monitore)
  EndIf
  If x<0 : x = 0 : EndIf : If y<0 : y = 0 : EndIf
  *DeskTop = GetDesktopWindow_()
  DeskTop_DC = GetDC_(*DeskTop)
  Bitmap = CreateCompatibleBitmap_(DeskTop_DC, b, h)
  hdcMem = CreateCompatibleDC_(DeskTop_DC)
  SelectObject_(hdcMem, Bitmap)
  BitBlt_(hdcMem, 0, 0, b, h, DeskTop_DC, x, y, #SRCCOPY)
  DeleteDC_(hdcMem)
  ReleaseDC_(*DeskTop, DeskTop_DC)
  x = CreateImage(#PB_Any, b, h, Bits);x hier mißbraucht als #ImgNr
  StartDrawing(ImageOutput(x))
  DrawImage(Bitmap, 0, 0)
  StopDrawing()
  ReleaseDC_(hdcMem,DeskTop_DC)
  DeleteObject_(Bitmap)
  DeleteDC_(DeskTop_DC)
  ProcedureReturn x ;Rückgabewert = #ImageNr
EndProcedure

;Test-Routine
;img=ScreenShot(10,10,500,500)
;SetClipboardImage(img)
Zuletzt geändert von sibru am 27.01.2019 13:08, insgesamt 1-mal geändert.
Bild Bild
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Image auf Desktop ausgeben

Beitrag von Kiffi »

<ShotInTheDark>
Soweit ich weiß, muss man dem System noch mitteilen, dass sich das Wallpaper geändert hat Irgendwas mit SystemParametersInfo?
</ShotInTheDark>
Hygge
sibru
Beiträge: 265
Registriert: 15.09.2004 18:11
Wohnort: hamburg

Re: Image auf Desktop ausgeben

Beitrag von sibru »

@Kiffi
danke für den Tip, bringt leider nicht viel :cry: :
via SystemParametersInfo(#SPI_SETDESKWALLPAPER) ändere ich das Hintergrund-Image des Desktops und Wieder-Aufbau der Icon´s, der dann meine schöne Grafik tlw. wieder übermalt...

Das Ganze ist u.A. für einen MausText gedacht: hier soll am Mauszeiger ein Text angezeigt werden: via SystemParametersInfo(#SPI_SETDESKWALLPAPER) flackerts wie wild bei Mausbewegung.

früher mal (bis PB 4.20?) ging´s ja noch vial

Code: Alles auswählen

;Modul      DesktopOutput Version 1.03 vom 18.12.2008
;
;Funktion:  ermöglicht 2DDrawing-Operationen direkt auf´m Desktop
;
;Aufruf:    StartDrawing(DesktopOutput())
;           
;
;#jaPBeExt exit

Procedure DesktopOutput()
    Global DesktopOutput_Memory = AllocateMemory(1024)
    PokeL(DesktopOutput_Memory, 1)
    ProcedureReturn DesktopOutput_Memory
EndProcedure
Bild Bild
sibru
Beiträge: 265
Registriert: 15.09.2004 18:11
Wohnort: hamburg

Re: Image auf Desktop ausgeben

Beitrag von sibru »

bei

Code: Alles auswählen

 hdc = StartDrawing(ImageOutput(ImgNr)) 
geht´s um die Bestimmung des Image-DeviceContents als Quell-HDC für BitBlt_(), das Image selbst wird ja auch gar nicht angefasst (außer eben halt via HDC in BitBlt_()),
müßte also so korrekt sein...
Bild Bild
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: Image auf Desktop ausgeben

Beitrag von Mijikai »

Mit SetWindowsHookEx_() das Fenster 'SysListView32' hooken.
Damit die Nachrichten #WM_PAINT & #WM_ERASEBKGND abfangen und ersetzen.
Dies ermöglicht das Zeichnen auf dem Desktop und hinter den Icons.

Info:
'SysListView32' ist ein Unterfenster von 'SHELLDLL_DefView'
'SHELLDLL_DefView' wiederum von 'ProgMan' (Parent).

Sonst gibt es nur Overlay Lösungen.
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Image auf Desktop ausgeben

Beitrag von GPI »

Von auf den Desktop pinseln halte ich persönlich relativ wenig.
Wäre nicht ein Transparentes Fenster mit "Click-Through" nicht die bessere Lösung?
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: Image auf Desktop ausgeben

Beitrag von Mijikai »

GPI hat geschrieben:Von auf den Desktop pinseln halte ich persönlich relativ wenig.
Wäre nicht ein Transparentes Fenster mit "Click-Through" nicht die bessere Lösung?
Eine Overlay Lösung ist schöner allerdings werden Icons (und andere Desktop-Elemente) überzeichnet.
Eventuell geht aber auch Subclassing anstelle eines Hooks.
sibru
Beiträge: 265
Registriert: 15.09.2004 18:11
Wohnort: hamburg

Re: Image auf Desktop ausgeben [gelöst]

Beitrag von sibru »

Problem gelöst via transparentem Fenster, via ja auch schon von GPI vorgeschlagen:

Code: Alles auswählen

;Modul      DesktopOutput Version 1.04 vom 26.01.2019 
;
;Funktion:  ermöglicht 2DDrawing-AusgabeOperationen direkt auf´m Desktop     !!eigenes Startdrawing() !!
;           für´s Auslesen siehe Module ScreenShot() oder Desktop_Point()
;
;Aufruf:    DeskTopOutput = DesktopOutput({Exit}))
;           Exit: wenn <>0, so werden belegte Resourcen wieder freigegeben
;                 ansonsten liefert diese Funktion die Output-ID für StartDrawing()
;
;AnwendungsBeispiel:
;  StartDrawing(DesktopOutput())
;  DrawImage(ImgId, x, y) ;...oder sonstige 2D-Operationen auf´m Desktop
;  StopDrawing()
;  DesktopOutput(1) ;belegte Resourcen freigeben, ganz wichtig bei häufigem Aufruf !!!
;
;#jaPBeExt exit
Global DesktopOutput_WinNr

Procedure DesktopOutput(Exit = 0)
      Protected WinID
  CompilerIf #PB_Compiler_Version > 420                 ;{ ab PB4.20 via transparentem Window
    If Exit                                             ;{ Resourcen wieder freigeben
      If IsWindow(DesktopOutput_WinNr): CloseWindow(DesktopOutput_WinNr): EndIf
      DesktopOutput_WinNr = 0 ;}
    Else                                                ;{ transparentes Hintergrund-Fester über alle Monitore aufbauen
      ;basierend auf PB-ForumsEintrag von Fluid Byte am 09.10.2007 04:46
      DesktopOutput_WinNr = OpenWindow(#PB_Any, 0, 0, GetSystemMetrics_(#SM_CXVIRTUALSCREEN), GetSystemMetrics_(#SM_CYVIRTUALSCREEN), "hidden Window", #WS_SYSMENU | #WS_POPUP | #PB_Window_Invisible|#WS_EX_TOOLWINDOW)
      WinID = WindowID(DesktopOutput_WinNr)
      SetWindowColor(DesktopOutput_WinNr, $FF00FF)
      SetWindowLong_(WinID, #GWL_EXSTYLE, #WS_EX_LAYERED|#WS_EX_TOOLWINDOW)
      SetLayeredWindowAttributes_(WinID, $FF00FF, 0, #LWA_COLORKEY)
      HideWindow(DesktopOutput_WinNr, 0)
      ProcedureReturn WindowOutput(DesktopOutput_WinNr);}
    EndIf ;}
  CompilerElse                                          ;{ bis PB4.20 ging´s noch StartDrawing(Memory)
    If Exit                                             ;{ Desktop-Ausgabe abschließen
      FreeMemory(DesktopOutput_WinNr)                  ;Speicher freigeben
      DesktopOutput_WinNr = 0 ;}
    Else                                                ;{ Desktop-Ausgabe in reservierten Speicher
      DesktopOutput_WinNr = AllocateMemory(1024)       ;wg. einheitlichem globalem VarName, eigentlich MemNr...
      PokeL(DesktopOutput_WinNr, 1)
      ProcedureReturn DesktopOutput_WinNr;}
    EndIf;}
  CompilerEndIf
EndProcedure
Klappt leider nur für 2D-Ausgabe-Funktionen, zum Einlesen gibt´s Funktion ScreenShot() (siehe ganz oben) oder

Code: Alles auswählen

;Modul      Desktop_Point Version 1.00 vom 26.01.2019 
;
;Funktion:  liefert Pixel(=RGB-Farbwert) eines Punktes auf dem Desktop (über alle Monitore) !!eigenes Startdrawing() !!
;
;Aufruf:  RGB_Farbe = Desktop_Point(x,y)
;         x / y: Monitor-Position, dessen RGB-Fareb ausgelesen werden soll
;
;         liefert den 24Bit-RGB-Wert des Pixels lt. x/y
;
;#jaPBeExt exit
Procedure Desktop_Point(x, y)
  Protected Bitmap, DeskImg, DeskTop_DC, hdcMem
  DeskTop_DC = GetDC_(GetDesktopWindow_())
  hdcMem = CreateCompatibleDC_(DeskTop_DC)
  Bitmap = CreateCompatibleBitmap_(DeskTop_DC, 1, 1)
  SelectObject_(hdcMem, Bitmap)
  If BitBlt_(hdcMem, 0, 0, 1, 1, DeskTop_DC, x, y, #SRCCOPY)
    DeskImg = CreateImage(#PB_Any, 1, 1, 24)
    StartDrawing(ImageOutput(DeskImg))
    DrawImage(Bitmap, 0, 0)
    ReleaseDC_(hdcMem, DeskTop_DC)
    DeleteObject_(Bitmap)
    DeleteDC_(DeskTop_DC)
    Bitmap = Point(0, 0)
    StopDrawing()
    FreeImage(DeskImg)
  EndIf
  ProcedureReturn Bitmap
EndProcedure
Bild Bild
Antworten