original Window Farben auslesen

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Varistor
Beiträge: 18
Registriert: 12.10.2004 21:38
Wohnort: Schwerin

Re: original Window Farben auslesen

Beitrag von Varistor »

Sicherlich muss dass alles irgendwie mit den ermittelten Farben "verrechnet" werden, um den wirklichen Farbwert zu bekommen. Nur wie ?! Im Netz und mit anderen Programmiersprachen ist man da auch nicht wirklich zu einer Lösung gekommen. Das ist halt mal wieder eines der zahlreichen Rätsel von Microsoft... Die Dokumentation zur dwmapi.dll wird jedenfalls allgemein bemängelt.
Lord
Beiträge: 313
Registriert: 21.01.2008 19:11

Re: original Window Farben auslesen

Beitrag von Lord »

Wenn man sich den Fensterrahmen z.B. bei Win7 ansieht, wird dieser durch dahinterliegende
Fenster beinflußt. Schiebt man ein kleineres Fenster über den Desktop mit weiteren geöff-
neten Fenstern hin und her, sieht man doch, daß der Rahmen und damit die Rahmenfarbe sich
durch die darunterliegenden Fenster ändert und damit an jedem Punkt des Rahmens anders
aussehen kann.
Damit erscheint eine 'Berechnung' der Rahmenfarbe zumindest für Win7 nicht möglich.
Mir steht allerdings nur Win7 zur Verfügung, so daß es für höhere Win-Version anders aussehen
kann.
Bild
Benutzeravatar
Varistor
Beiträge: 18
Registriert: 12.10.2004 21:38
Wohnort: Schwerin

Re: original Window Farben auslesen

Beitrag von Varistor »

Das ist richtig. Bei Win 7 sind die Bedingungen ganz anders. Schließlich war das der Anfang mit diesen "Glas-Effekten", also den "Durchsichtigbarkeiten" der Fenster. In Win 8 und 10 ist das etwas anders geregelt worden, man hat dort nur wieder einen einfarbigen Fenstertitel und Rahmen, der allerdings teilweise wie bei Win 7 durchsichtig werden kann. Mit gewissen Tricks kann man bei den späteren Versionen von Windows aber die Win7 Effekte wieder realisieren - machen aber wohl nicht so viele. Also bleibt es bei einfarbiger Titelzeile und Rahmen, von dem ich immer noch gerne ohne Tricks die Werte auslesen möchte.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: original Window Farben auslesen

Beitrag von Mijikai »

Evtl. hilft die Funktion:

Code: Alles auswählen

DWMAPI DwmGetColorizationColor(
  DWORD *pcrColorization,
  BOOL  *pfOpaqueBlend
);
Benutzeravatar
Varistor
Beiträge: 18
Registriert: 12.10.2004 21:38
Wohnort: Schwerin

Re: original Window Farben auslesen

Beitrag von Varistor »

Genau hier viewtopic.php?p=360558#p360558 also 1 Seite vorher, wurde diese Funktion verwendet. Bringt aber nichts, weil die Farben nicht ganz stimmen. (Zu hell oder zu dunkel.)
Ich möchte daher bitten, mal diesen Code auszuführen und die Ergebnisse hier mitzuteilen.
Und zwar möglichst unter Win 8 (8.1) und Win 10 - denn da gibt es auch noch Unterschiede zwischen den Farben.
Sollte es jemand gelingen, damit die richtigen Farben auszulesen :allright:
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: original Window Farben auslesen

Beitrag von Mijikai »

Ok hier ein Beispiel

Code: Alles auswählen

EnableExplicit

Procedure.i GetColorization(*ColorRGB.Integer,*Alpha.Ascii = #Null,*Opaque.Integer = #Null);Minimum supported client:	Windows Vista
  Static hlib.i
  Protected *ascii
  Protected *proc
  Protected opaque.i
  Protected color.RGBQUAD
  If Not hlib
    hlib = LoadLibrary_("Dwmapi.dll")
  EndIf
  *ascii = Ascii("DwmGetColorizationColor")
  If *ascii
    *proc = GetProcAddress_(hlib,*ascii)
    FreeMemory(*ascii)
    If *proc
      If CallFunctionFast(*proc,@color,@opaque) = #S_OK
        Swap color\rgbRed,color\rgbBlue
        If *Alpha
          *Alpha\a = color\rgbReserved
        EndIf
        If *Opaque
          *Opaque\i = opaque
        EndIf
        color\rgbReserved = #Null
        CopyMemory(@color,*ColorRGB,4)
        ProcedureReturn #True
      EndIf
    EndIf
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure.i Main()
  Protected color.i
  If OpenWindow(0,0,0,320,320,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
    GetColorization(@color)
    If StartDrawing(WindowOutput(0))
      Box(0,0,WindowWidth(0),WindowHeight(0),color)
      StopDrawing()  
    EndIf
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Break
      EndSelect
    ForEver
    CloseWindow(0)  
  EndIf  
  ProcedureReturn #Null
EndProcedure

Main()

End
Benutzeravatar
Varistor
Beiträge: 18
Registriert: 12.10.2004 21:38
Wohnort: Schwerin

Re: original Window Farben auslesen

Beitrag von Varistor »

Sieht gut aus, allerdings sind da wieder die Farbunterschiede. Bei mir: Titelleiste: R=181 G=164 B=148 Innen: R=166 G=148 B=131
Also etwas dunkler innen als die Titelleiste. Bei dir sind die Farben tatsächlich gleich ?!
Benutzeravatar
chi
Beiträge: 90
Registriert: 17.05.2007 09:30
Wohnort: Linz - Austria

Re: original Window Farben auslesen

Beitrag von chi »

Probier mal...

Code: Alles auswählen

Procedure RegReadDWord(section, path$, key$)
  value=-1 : datasize.l=4 ; 4 bytes = 32 bits (long).
  If RegOpenKeyEx_(section, path$, 0, #KEY_READ, @tmp) = #ERROR_SUCCESS
    If RegQueryValueEx_(tmp, key$, 0, 0, @value, @datasize) <> #ERROR_SUCCESS : value=-1 : EndIf
    RegCloseKey_(tmp)
  EndIf
  ProcedureReturn value
EndProcedure

Global active   = RegReadDWord(#HKEY_CURRENT_USER, "Software\Microsoft\Windows\DWM", "AccentColor") & $FFFFFFFF
Global inactive = RegReadDWord(#HKEY_CURRENT_USER, "Software\Microsoft\Windows\DWM", "AccentColorInactive") & $FFFFFFFF

Procedure Callback(hWnd, msg, wParam, lParam)
  If msg = #WM_NCACTIVATE
    If wParam & $FFFF
      SetWindowColor(0, RGB(Red(active), Green(active), Blue(active)))
    Else
      SetWindowColor(0, RGB(Red(inactive), Green(inactive), Blue(inactive)))
    EndIf
  EndIf
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

OpenWindow(0, 0, 0, 800, 500, "", #WS_OVERLAPPEDWINDOW|#PB_Window_ScreenCentered)
SetWindowColor(0, RGB(Red(active), Green(active), Blue(active)))
SetWindowCallback(@Callback())
While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: original Window Farben auslesen

Beitrag von Mijikai »

Ich glaube die Farbe muss noch mit der ColorBalance und dem Standard Grauwert vermischt werden.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: original Window Farben auslesen

Beitrag von Mijikai »

Korrigierter Farbwert :)

Es wird wie schon vermutet die Farbintensität benötigt.
Diese kann auch über die Registry ausgelesen werden (der vernünftige, offizielle Weg).
Ich werde in meinem Beispiel jedoch die undokumentierte API DwmGetColorizationParameters() verwenden.
Um an die Adresse der Funktion zu kommen scanne ich in der Funktion DwmGetColorizationColor() nach dem Call
zu DwmGetColorizationParameters() und extrahiere die Addresse.
Wenn die Addresse gefunden wurde wird die Funktion aufgerufen welche die Struktur DwmColorizationParams füllt.
Anhand der Farbe ColorizationColor und der Intensität ColorizationColorBalance kann nun die korrekte Farbe berechnet werden.

Hier der Code:

Code: Alles auswählen

EnableExplicit

 Procedure.i GetColorizationColor(*Color)
   Structure DwmColorizationParams
     ColorizationColor.l
     ColorizationAfterglow.l
     ColorizationColorBalance.l
     ColorizationAfterglowBalance.l
     ColorizationBlurBalance.l
     ColorizationGlassReflectionIntensity.l
     ColorizationOpaqueBlend.l
   EndStructure
   Static hlib.i
   Protected *ascii
   Protected *proc.Long
   Protected *dummy
   Protected count.i
   Protected param.DwmColorizationParams
   Protected color.i
   Protected color_r.d
   Protected color_g.d
   Protected color_b.d
   If Not hlib
     hlib = LoadLibrary_("Dwmapi.dll")
   EndIf
   *ascii = Ascii("DwmGetColorizationColor")
   If *ascii
     *proc = GetProcAddress_(hlib,*ascii)
     FreeMemory(*ascii)
     If *proc
       Repeat
         If *proc\l = $244C8D48
           *proc + 6
           *dummy = *proc - hlib + *proc\l + 5
           *dummy + hlib
           Break
         EndIf
         If count = 160
           Break
         EndIf
         *proc + 1
         count + 1
       ForEver
       If *dummy
         If CallFunctionFast(*dummy,@param) = #S_OK
           count = 100 - param\ColorizationColorBalance
           color = (param\ColorizationColor >> 16) & $FF
           color_r = Round(color + (127 - color) * count / 100.0,#PB_Round_Nearest)
           color =  (param\ColorizationColor>> 8) & $FF
           color_g = Round(color + (127 - color) * count / 100.0,#PB_Round_Nearest)
           color =   param\ColorizationColor & $FF
           color_b = Round(color + (127 - color) * count / 100.0,#PB_Round_Nearest)
           If color_r > 255.0
             color_r = 255.0
           EndIf
           If color_g > 255.0
             color_g = 255.0
           EndIf
           If color_b > 255.0
             color_b = 255.0
           EndIf
           color = RGB(color_r,color_g,color_b)
           CopyMemory(@color,*Color,4)
           ProcedureReturn #True
         EndIf
       EndIf
     EndIf
   EndIf
   ProcedureReturn #False
 EndProcedure
 
Procedure.i Main()
  Protected color.i
  If OpenWindow(0,0,0,320,320,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_Tool)
    GetColorizationColor(@color)
    SetWindowColor(0,color)
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Break
      EndSelect
    ForEver
    CloseWindow(0)  
  EndIf  
  ProcedureReturn #Null
EndProcedure

Main()

End
Antworten