Windows Fensterrahmenfarbe ermitteln

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    Windows Fensterrahmenfarbe ermitteln

    Hallo.
    Ich habe folgendes Problem (vermutlich ist die Lösung äußerst einfach...):

    Ich möchte, dass die Hintergrundfarbe meines Fensters mit der des Fensterrahmen (dem klassischen Fensterrahmen von Windows, wo man die Farbe in den Systemsteuerungen ändern kann) übereinstimmt. Bisher sieht mein Code wie folgend aus:

    VB.NET-Quellcode

    1. Dim colorizationValue As String = String.Format("{0:x}", Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", "00000000"))
    2. Dim s As String = colorizationValue.Substring(0, colorizationValue.Length - 2) 'Das mache ich, um den Alpha-Channel zu entfernen, da ich davon ausgehe, dass die beiden letzten Zeichen in einem rgba-Farbcode für die Transparenz steht (?), und da keine Transparenz als Hintergrundfarbe bei Fenstern akzeptiert wird... Und ich glaube dass sich hier mein Fehler befindet...
    3. MsgBox(colorizationValue & " <> " & s)
    4. End
    5. Me.BackColor = Color.FromName("#" & s)

    Möglicherweise ist der gesamte Code müll, deshalb frage ich ja. Regt euch also nicht auf.

    Danke im Voraus!
    There are only 10 types of poeple in the world: Those who understand binary and those who don't.
    Ich würde Dir die Win32-API DwmGetColorizationParameters empfehlen.
    Prinzipiell funktioniert das so:

    VB.NET-Quellcode

    1. <DllImport("dwmapi.dll", EntryPoint:="#127")> _
    2. Private Shared Sub DwmGetColorizationParameters(ByRef dp As DwmColorizationParams)
    3. End Sub
    4. <StructLayout(LayoutKind.Sequential)> _
    5. Friend Structure DwmColorizationParams
    6. Public ColorizationColor As UInt32
    7. Public ColorizationAfterglow As UInt32
    8. Public ColorizationColorBalance As UInt32
    9. Public ColorizationAfterglowBalance As UInt32
    10. Public ColorizationBlurBalance As UInt32
    11. Public ColorizationGlassReflectionIntensity As UInt32
    12. Public ColorizationOpaqueBlend As UInt32
    13. End Structure
    14. Public Shared Function GetDwmColorization() As Color
    15. Dim Temp As New DwmColorizationParams
    16. DwmGetColorizationParameters(Temp)
    17. Return Color.FromArgb(
    18. CByte(Temp.ColorizationColor >> 24 And 255)
    19. CByte(Temp.ColorizationColor >> 16 And 255)
    20. CByte(Temp.ColorizationColor >> 8 And 255)
    21. CByte(Temp.ColorizationColor And 255))
    22. End Function
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ja davon habe ich schon gehört. Da ich allerdings bisher kaum mit API's gearbeitet habe wollte ich es als erstes ohne versuchen. Und wie man RGBA in RGB umwandeln kann interessiert mich auch sonst.
    Wenn das allerdings zu umständlich wird, da ich nach einem kleinen unkomplizierten Code suche, welchen ich nur zur Gestaltung eines Fensters benötige, dann werde ich auf die API zugreifen. Auf jeden Fall werde ich mir das notieren.
    Danke!


    Edit: Habe jetzt versucht, deinen Code einfach aus Neugier per CP einzubauen, allerdings
    1. musste ich die "System.Runtime.InteropServices" importieren,
    2. bekomme ich hier

      VB.NET-Quellcode

      1. [...]
      2. CByte(Temp.ColorizationColor >> 16 And 255)
      3. CByte(Temp.ColorizationColor >> 8 And 255)
      4. CByte(Temp.ColorizationColor And 255))
      5. [...]
      folgende Fehlermeldung:

      Quellcode

      1. Der Ausdruck ist keine Methode
    There are only 10 types of poeple in the world: Those who understand binary and those who don't.

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Sky Super“ ()

    Was genau ist denn überhaupt der Fehler?
    Ich würde btw. davon ausgehen, dass der Alpha-Kanal das erste Byte ist, nicht das letzte (ARGB). Dann kannst du dir die Farbe einfach mit Color.FromArgb holen und den Alpha-Kanal im Nachhinein auf 255 setzen.
    Wow!!! Genau nach sowas habe ich gesucht!
    Ich dachte es seie genau umgekehrt: rgba; aber da habe ich wohl vb.net mit css verwechselt... Peinlich...

    Edit: Irgendwie hilft mir das nicht weiter... So sieht's bei mir gerade aus:

    VB.NET-Quellcode

    1. Private Sub Fenster_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. 'SetStyle(ControlStyles.SupportsTransparentBackColor, True)
    3. Dim colorizationValue As String = String.Format("{0:x}", Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", "00000000"))
    4. Dim c As Color = Color.FromName("#" & colorizationValue)
    5. Dim cc As Color = Color.FromName("#" & c.R & c.G & c.B)
    6. '(255, c.R, c.G, c.B)
    7. 'c.A.CompareTo(cc)
    8. Me.BackColor = cc
    9. 'Dim s As String = colorizationValue.Substring(0, Mid(colorizationValue, 2))
    10. 'MsgBox(colorizationValue & " <> " & s)
    11. 'End
    12. 'Me.BackColor = Color.FromName("#" & s)
    13. End Sub

    Chaos pur!
    There are only 10 types of poeple in the world: Those who understand binary and those who don't.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Sky Super“ ()

    Oh, hab da beim Kopieren vergessen, die Beistriche einzufügen:

    VB.NET-Quellcode

    1. Return Color.FromArgb(
    2. CByte(Temp.ColorizationColor >> 24 And 255),
    3. CByte(Temp.ColorizationColor >> 16 And 255),
    4. CByte(Temp.ColorizationColor >> 8 And 255),
    5. CByte(Temp.ColorizationColor And 255))

    Es geht ja weniger um das Konvertieren von ARGB in RGB (einfach einen Wert weglassen), sondern um das Parsen des Dings, was da in der Registry steht. Und das ist unter Umständen etwas schwieriger, wenn man nicht 100%-ig sicher ist, was da drin stehen kann.
    Dagegen gibt Dir die API-Funktion garantiert das zurück, was Du brauchst.
    Und wenn Du nicht-transparente Farben brauchst, kannst Du einfach den Alpha-Wert weglassen:

    VB.NET-Quellcode

    1. Return Color.FromArgb(
    2. CByte(Temp.ColorizationColor >> 16 And 255),
    3. CByte(Temp.ColorizationColor >> 8 And 255),
    4. CByte(Temp.ColorizationColor And 255))
    Die FromArgb-Funktion nimmt dann für Alpha einfach 255 an.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Dein Fehler ist, dass du viel zu viel mit Formatierungen rumhantierst und dabei nicht wirklich weißt, was du vorhast. Lese den Wert einfach als das aus, was er ist, nämlich ein Int32, und übergib ihn dann einfach direkt an Color.FromArgb.

    Oder machs einfach so wie Niko Ortner es vorschlägt und wie es von Microsoft gedacht ist.
    Da ich allerdings bisher kaum mit API's gearbeitet habe wollte ich es als erstes ohne versuchen.


    VB.NET-Quellcode

    1. Private Function GetWindowborderColor() As Color
    2. Dim iARGB As Integer = CInt(Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", "00000000"))
    3. Dim col As Color = System.Drawing.Color.FromArgb(iARGB)
    4. Return System.Drawing.Color.FromArgb(255, col.R, col.G, col.B)
    5. End Function
    Danke an @Fakiz für deinen Code! Ich habe es gleich ausprobiert und es funzt einwandfrei. Danke! Dafür gibt es ein Hilfreich.


    So! Jetzt habe ich wieder ein ganz anders Problem (Siehe Bilder). Wie kann ich diesen unschönen Rahmen entfernen, ohne den typischen Fensterrahmen entfernen zu müssen?
    Bilder
    • SRC1.png

      411,6 kB, 1.000×647, 604 mal angesehen
    There are only 10 types of poeple in the world: Those who understand binary and those who don't.

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

    Wenn du vorhast, den Fensterrahmen auf diese Weise zu erweitern, solltest du lieber mal nen Blick auf DwmExtendFrameIntoClientArea werfen. Dann kümmert sich Windows um das Zeichnen dieses Bereichs (z.B. wird in Windows 7 dann dieser Bereich auch transparent dargestellt).

    Ansonsten kannst du diesen Rahmen nur wegbekommen, indem du auf den Fensterrahmen zeichnest, und das erfordert, dass du die Message WM_NCPAINT deines Fensters hookst (das Framework bietet keinen passenden Handler dafür an).
    Danke! Ich werde mich mal informieren! :thumbup:

    Edit: Ich würde mich über einen Beispielcode freuen, da der, den MSDN anbietet, nur in C# verfügbar ist, und mein C# miserabel ist.
    There are only 10 types of poeple in the world: Those who understand binary and those who don't.

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

    Bezüglich der API:

    VB.NET-Quellcode

    1. <StructLayout(LayoutKind.Sequential)>
    2. Public Structure Margins
    3. Public CxLeftWidth As Int32
    4. Public CxRightWidth As Int32
    5. Public CyTopHeight As Int32
    6. Public CyBottomHeight As Int32
    7. End Structure
    8. Private Declare Function DwmExtendFrameIntoClientArea Lib "DwmApi" (hwnd As IntPtr, ByRef pMarInset As Margins) As Int32
    9. bzw.
    10. <System.Runtime.InteropServices.DllImport("DwmApi")>
    11. Private Shared Function DwmExtendFrameIntoClientArea(hwnd As IntPtr, ByRef pMarInset As Margins) As Int32
    12. 'Aufruf:
    13. ExtendFrameIntoClientArea(DeinFenster.Handle, new Margins With {.CxLeftWidth = ..., ...})
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils