Как рисовать в фоне Edit`а?

Хочу сделать пару editbox`ов, однострочный с градиентом в фоне, (типа как на ag) и многострочный, в фоне которого хочу поместить логотип. Посмотрел в MSDN, вроде owner-drawn edit-ов не бывает. Сабкласс на WM_ERASEBACKGROUND (Хм. Откуда я это взял? ) тоже не работает. Какие могут быть ещё варианты?
Пишу на VC7, под Win32.
Вот такой должен быть edit:

А если попробовать WM_CTLCOLOREDIT/WM_CTLCOLORDLG + возвращать brush, созданную из соотв. битмапа ?.
Простейший пример. Берем битмап , на его основе создаем brush, и отдаем brush edit control'у.

procedure TMainWindow.FormCreate(Sender: TObject);
begin
  BaseBitmap  := ImgBitmap.Picture.Bitmap.Handle;
  BitmapBrush := CreatePatternBrush( BaseBitmap );
  OldWndProc  := MainWindow.WindowProc;
  MainWindow.WindowProc := SubclassProc;
end;
 
procedure TMainWindow.FormDestroy(Sender: TObject);
begin
  MainWindow.WindowProc := OldWndProc;
  DeleteObject( BitmapBrush );
end;
 
procedure TMainWindow.SubclassProc(var Msg: TMessage);
begin
  case Msg.Msg of
    WM_CTLCOLOREDIT : begin
      if (THandle(Msg.lParam) = EdDemo.Handle) then begin
        SetBkMode( HDC(Msg.wParam), TRANSPARENT );
        Msg.Result := BitmapBrush;
        Exit;
      end;
    end;
  end;
  OldWndProc( Msg );
end;
На приведенном Вами рисунке нет градиента. Если воспользоваться subclass'ингом и обработкой WM_CTLCOLOREDIT, то можно почти добиться необходимого результата.

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include 
 
#pragma comment(linker, "/subsystem:windows")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "MSImg32.Lib")  /*GradientFill */
 
static WNDPROC oldproc = (WNDPROC) NULL;
 
static HBITMAP gradient(HDC hdc, int height)
{
  HBITMAP hbmMem = NULL;
  HDC     hdcMem = NULL;
 
  if (height > 0 && NULL != hdc)
  {
    if (NULL != (hdcMem = CreateCompatibleDC(hdc)))
    {
      if (NULL != (hbmMem = CreateCompatibleBitmap(hdc, 1, height)))
      {
        HBITMAP       hbm = SelectObject(hdcMem, hbmMem);
        TRIVERTEX     vert[2];
        GRADIENT_RECT gRect;
 
        vert [0] .x      = 0;
        vert [0] .y      = 0;
        vert [0] .Red    = 0xffff;
        vert [0] .Green  = 0xffff;
        vert [0] .Blue   = 0xffff;
        vert [0] .Alpha  = 0x0000;
 
        vert [1] .x      = 1;
        vert [1] .y      = height;
        vert [1] .Red    = 0x8fff;
        vert [1] .Green  = 0x8fff;
        vert [1] .Blue   = 0x8fff;
        vert [1] .Alpha  = 0x0000;
 
        gRect.UpperLeft  = 0;
        gRect.LowerRight = 1;
        GradientFill(hdcMem, vert, 2, &gRect, 1, GRADIENT_FILL_RECT_V);
 
        SelectObject(hdcMem, hbm);
      }
      DeleteDC(hdcMem);
    }
  }
  return hbmMem;
}
 
static LRESULT CALLBACK newproc(HWND hWnd, UINT uMsg,
                                WPARAM wParam, LPARAM lParam)
{
  if (WM_VSCROLL == uMsg ||
      WM_HSCROLL == uMsg ||
      0x020A     == uMsg || /* WM_MOUSEWHEEL */
      WM_KEYDOWN == uMsg)
    InvalidateRect(hWnd, NULL, TRUE);
 
  else if (WM_PAINT == uMsg || WM_ERASEBKGND == uMsg)
  {
    HDC     hdc     = (WM_PAINT != uMsg) ? (HDC) wParam : GetDC(hWnd);
    HDC     hdcMem  = NULL;
    HBITMAP hbmMem  = NULL;
    HBRUSH  hbrGrad = NULL;
    HBITMAP hbmGrad = NULL;
    HBITMAP hbm     = NULL;
    HBRUSH  hbr     = NULL;
    RECT    rc;
    int     mmode;
  
    GetClientRect(hWnd, &rc);
    OffsetRect(&rc, rc.left, rc.top);
 
    if (NULL != (hdcMem  = CreateCompatibleDC(hdc)))
    {
      if (NULL != (hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom)))
      {
        hbm = SelectObject(hdcMem, hbmMem);
        if (NULL != (hbmGrad = gradient(hdcMem, rc.bottom)))
        {
          hbrGrad = CreatePatternBrush(hbmGrad);
          DeleteObject(hbmGrad);
        }
        hbm = SelectObject(hdcMem, hbmMem);
        if (NULL != hbrGrad)
        {
          hbr = SelectObject(hdcMem, hbrGrad);
          PatBlt(hdcMem, 0, 0, rc.right, rc.bottom, PATCOPY);
        }
        mmode = SetBkMode(hdcMem, TRANSPARENT);
        CallWindowProc(oldproc, hWnd, WM_PRINTCLIENT, (WPARAM) hdcMem, 0);
        BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY);
        SetBkMode(hdcMem, mmode);
        if (NULL != hbrGrad)
        {
          SelectObject(hdcMem, hbr);
          DeleteObject(hbrGrad);
        }
        SelectObject(hdcMem, hbm);
        DeleteObject(hbmMem);
      }
      DeleteObject(hdcMem);
    }
 
    ValidateRect(hWnd, NULL);
 
    if (WM_PAINT == uMsg)
    {
      ReleaseDC(hWnd, hdc);
      return 0;
    }
    return 1;
  }
  return CallWindowProc(oldproc, hWnd, uMsg, wParam, lParam);
}
 
 
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg,
                                WPARAM wParam, LPARAM lParam)
{
  static HWND   hwndEdit = NULL;
  static HBRUSH hbrBack  = NULL;
 
  switch (uMsg)
  {
  case WM_CREATE:
    {
      RECT rc;
 
      GetClientRect(hWnd, &rc);
 
      hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT",
                   "Hello, world!",
                   WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
                     WS_HSCROLL | ES_MULTILINE | ES_NOHIDESEL,
                   0, 0, rc.right, rc.bottom,
                   hWnd, NULL, ((LPCREATESTRUCT) lParam)->hInstance,
                   NULL);
      if (NULL != hwndEdit)
        oldproc = (WNDPROC) SetWindowLong(hwndEdit, GWL_WNDPROC,
                                          (LONG) newproc);
    }
    return 0;
 
  case WM_SIZE:
    if (NULL != hwndEdit)
      MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
    break;
 
  case WM_COMMAND:
    if (EN_CHANGE == HIWORD(wParam) &&
        hwndEdit  == (HWND) lParam  &&
        NULL      != hwndEdit)
      InvalidateRect(hWnd, NULL, TRUE);
    break;
 
  case WM_CTLCOLOREDIT:
    if (NULL != hwndEdit && (HWND) lParam == hwndEdit)
    {
      HBITMAP hbm;
      RECT    rc;
 
      GetClientRect(hWnd, &rc);
      OffsetRect(&rc, 0, rc.top);
 
      if (NULL != (hbm = gradient((HDC) wParam, rc.bottom)))
      {
        if (NULL != hbrBack) DeleteObject(hbrBack);
        hbrBack = CreatePatternBrush(hbm);
        DeleteObject(hbm);
      }
      if (NULL != hbrBack)
      {
        SetBkMode((HDC) wParam, TRANSPARENT);
        return (LRESULT) hbrBack;
      }
    }
    break;
 
  case WM_ERASEBKGND:
    if (NULL != hwndEdit)
      return 1;
    break;
 
  case WM_SETFOCUS:
    if (NULL != hwndEdit)
      SetFocus(hwndEdit);
    break;
 
  case WM_DESTROY:
    if (NULL != hbrBack) DeleteObject(hbrBack);
    PostQuitMessage(0);
    return 0;
  }
  return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
 
 
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hpinst,
                   LPSTR cmdl, int show)
{
  WNDCLASSEX wcex;
  MSG        msg;
  HWND       hwnd;
 
  UNREFERENCED_PARAMETER(hpinst);
 
  RtlZeroMemory(&wcex, sizeof(wcex));
  wcex.cbSize        = sizeof(wcex);
  wcex.style         = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc   = WndProc;
  wcex.hInstance     = hinst;
  wcex.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE+1);
  wcex.lpszClassName = "BackgroundEditControlDemo_Class";
 
  if (0 != RegisterClassEx(&wcex))
  {
    if (NULL != (hwnd = CreateWindowEx(0, wcex.lpszClassName,
                          "Background Edit control demo",
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, wcex.hInstance,
                          (LPVOID) cmdl)))
    {
      ShowWindow(hwnd, show);
      UpdateWindow(hwnd);
 
      while (GetMessage(&msg, (HWND) NULL, 0, 0))
      {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }
  }
  return 0;
}
Почти, потому что мне не удалось полностью подавить мерцание при скроллинге.
Это работает и с многострочным edit'ом, в отличии от варианта, приведенного выше.

TopList Rambler's Top100