chrishibler
chrishibler

Reputation: 73

How can I change the background of a window inside a WPF HwndHost?

I created a control derived from HwndHost in a WPF application. The HwndHost derived control is inside a UserControl.

I would like to be able to set the background color of the window created inside the HwndHost (it's white by default, I'd like for it to be black). What is the simplest way to do that?

Upvotes: 0

Views: 1235

Answers (1)

Areon
Areon

Reputation: 46

I was having the same problem changing the background color of an HwndHost as well and I found this on StackOverflow:

Registering a custom win32 window class from c#

I have modified it change the background color to black and it looks like this:

public class CustomWindow : IDisposable
{
   #region Constants

   private const int ERROR_CLASS_ALREADY_EXISTS = 1410;

   #endregion

   #region Fields

   private bool m_disposed;

   private IntPtr m_hwnd;

   private WndProc m_wnd_proc_delegate;

   #endregion

   #region Constructors and Destructors

   /// <summary>
   /// Initializes a new instance of the <see cref="CustomWindow"/> class.
   /// </summary>
   /// <param name="class_name">The class_name.</param>
   /// <exception cref="System.Exception">
   /// class_name is null
   /// or
   /// class_name is empty
   /// or
   /// Could not register window class
   /// </exception>
   public CustomWindow(string class_name)
   {
      if (class_name == null)
      {
         throw new Exception("class_name is null");
      }
      if (class_name == String.Empty)
      {
         throw new Exception("class_name is empty");
      }

      this.m_wnd_proc_delegate = CustomWndProc;

      // Create WNDCLASS
      var wind_class = new WNDCLASS();
      wind_class.lpszClassName = class_name;
      wind_class.lpfnWndProc =  
          Marshal.GetFunctionPointerForDelegate(this.m_wnd_proc_delegate);
      wind_class.hbrBackground = CreateSolidBrush(0);

      var class_atom = RegisterClassW(ref wind_class);

      var last_error = Marshal.GetLastWin32Error();

      if (class_atom == 0 && last_error != ERROR_CLASS_ALREADY_EXISTS)
      {
         throw new Exception("Could not register window class");
      }

      // Create window
      this.m_hwnd = CreateWindowExW(
        0,
        class_name,
        String.Empty,
        0,
        0,
        0,
        0,
        0,
        IntPtr.Zero,
        IntPtr.Zero,
        IntPtr.Zero,
        IntPtr.Zero);
  }

  #endregion

  /// <summary>
  /// Creates the solid brush.
  /// </summary>
  /// <param name="theColor">The color.</param>
  /// <returns>IntPtr.</returns>
  [DllImport("gdi32.dll", EntryPoint = "CreateSolidBrush", CharSet =   CharSet.Unicode)]
  internal static extern IntPtr CreateSolidBrush(uint theColor);

  /// <summary>
  /// Gets the black window.
  /// </summary>
  /// <value>The black window.</value>
  public IntPtr BlackWindow 
  { 
      get
      {
         return this.m_hwnd;
      }
  }

  #region Delegates

  private delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

  #endregion

  #region Public Methods and Operators

  /// <summary>
  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  /// </summary>
  public void Dispose()
  {
     this.Dispose(true);
     GC.SuppressFinalize(this);
  }

  #endregion

  #region Methods

  [DllImport("user32.dll", SetLastError = true)]
  private static extern IntPtr CreateWindowExW(
    UInt32 dwExStyle,
    [MarshalAs(UnmanagedType.LPWStr)] string lpClassName,
    [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName,
    UInt32 dwStyle,
    Int32 x,
    Int32 y,
    Int32 nWidth,
    Int32 nHeight,
    IntPtr hWndParent,
    IntPtr hMenu,
    IntPtr hInstance,
    IntPtr lpParam);

  private static IntPtr CustomWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
  {
     return DefWindowProcW(hWnd, msg, wParam, lParam);
  }

  [DllImport("user32.dll", SetLastError = true)]
  private static extern IntPtr DefWindowProcW(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

  [DllImport("user32.dll", SetLastError = true)]
  private static extern bool DestroyWindow(IntPtr hWnd);

  [DllImport("user32.dll", SetLastError = true)]
  private static extern UInt16 RegisterClassW([In] ref WNDCLASS lpWndClass);

  /// <summary>
  /// Releases unmanaged and - optionally - managed resources.
  /// </summary>
  /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  private void Dispose(bool disposing)
  {
      if (!this.m_disposed)
      {
         if (disposing)
         {
            // Dispose managed resources
         }

         // Dispose unmanaged resources
         if (this.m_hwnd != IntPtr.Zero)
         {
            DestroyWindow(this.m_hwnd);
            this.m_hwnd = IntPtr.Zero;
         }
         this.m_disposed = true;
      }
  }

  #endregion

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  private struct WNDCLASS
  {
     public readonly uint style;

     public IntPtr lpfnWndProc;

     public readonly int cbClsExtra;

     public readonly int cbWndExtra;

     public readonly IntPtr hInstance;

     public readonly IntPtr hIcon;

     public readonly IntPtr hCursor;

     public IntPtr hbrBackground;

     [MarshalAs(UnmanagedType.LPWStr)]
     public readonly string lpszMenuName;

     [MarshalAs(UnmanagedType.LPWStr)]
     public string lpszClassName;
  }
}

Then I used the the window that the CustomWindow creates and parent that in the HwndHost.

Upvotes: 1

Related Questions