0

I am dealing with some old drawing code used to draw parts of styled system controls in a WinFroms app. One of the core routines that does this work looks like the following:

private bool DrawTheme(Graphics graphics, XPThemeClasses themeClass, int themePart, int themeState, int x, int y, int width, int height)
{
    bool myResult;
    IntPtr myHdc = graphics.GetHdc();
    try
    {
        NativeMethods.RECT myRect = new NativeMethods.RECT(x, y, width, height);
        IntPtr myThemeData = GetThemeData(themeClass);
        if (NativeMethods.IsThemeBackgroundPartiallyTransparent(myThemeData, themePart, themeState))
        {
            IntPtr hwnd = NativeMethods.WindowFromDC(myHdc);
            int res = NativeMethods.DrawThemeParentBackground(hwnd, myHdc, ref myRect);
        }
        myResult = (0 <= NativeMethods.DrawThemeBackground(
          myThemeData,
          myHdc,
          themePart,
          themeState,
          ref myRect, ref myRect));
    }
    catch
    {
        myResult = false;
    }
    finally
    {
        graphics.ReleaseHdc(myHdc);
    }
    return myResult;
}

It turned out that the DrawThemeParentBackground function fails. It returns the error code 0x80070006 (E_HANDLE), which means 'Handle that is not valid'. It seems, this occurs because of the zero window handle retrieved with the prior WindowFromDC API call.

Is there a way to obtain the correct hwnd from the Graphics object passed to this function to pass it to DrawThemeParentBackground? I know I can pass the handle of the window to draw in from the outer calling code, but this would require rewriting of a big part of the infrastructure of this project. So I am searching for a simple solution of this problem without rewriting much code.

TecMan
  • 2,743
  • 2
  • 30
  • 64
  • The method has the wrong signature, there is no guarantee whatsoever that you can map a Graphics object back to a window. Double-buffering would be a basic fail whale for example. You do need to also pass the parent window handle. – Hans Passant May 31 '19 at 12:55
  • Where is the `graphics` object coming from? If it's from the PaintEventArgs, it's the wrong object. This is one of the cases when you need to use `Control.CreateGraphics()`. Otherwise, `WindowFromDC` will return `0` with controls and a variety of handles (and also `0`) if it's a Form's `graphics` object. It will also compromise the graphics rendering itself. – Jimi May 31 '19 at 14:05
  • I understand that you're trying to perform a code refactoring without actually refactoring it. But these handles are usually retrived when responding to `WM_` messages, like [WM_CTLCOLORSTATIC](https://learn.microsoft.com/en-us/windows/desktop/controls/wm-ctlcolorstatic), for example, where `lParam` and `wParam` return the window handle and its hDC. – Jimi May 31 '19 at 14:19
  • @Jimi and Hans, I was also afraid that I would need to pass the window handle. It seems, there is no other way to solve this problem. – TecMan May 31 '19 at 15:09

0 Answers0