c - Referencenummer for barnemaleri

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg forstår fra MSDN, hvordan Windows håndterer WM\_PAINT-meddelelser, der sendes til et bestemt vindue.


En ting, MSDN synes ikke at dokumentere, er den egentlige proces, hvormed vindueslederen bestemmer hvilke vinduer der skal modtage WM\_PAINT-meddelelser, og i hvilken rækkefølge.


Da jeg forstår ting (fra at læse Raymond Chen og MSDN), er der ingen ugyldige regioner i forbindelse med børnevinduer - når barnevinduer er ugyldige, bliver det tilsvarende område i overordnede vindue ugyldiggjort.


Dens WM\_PAINT generationen, der forvirrer mig ... og det nøjagtige punkt (især wrt multithreading), at en windows ugyldig region bliver markeret som gyldig - når barnevinduer er involveret bliver det særligt interessant. Hvordan bestemmer GetMessage hvilket af vindueserne (forældre + børnevinduer, der krydser det ugyldige område), få ​​WM\_PAINT-meddelelser, og i hvilken rækkefølge? og hvordan ændres det i ansigtet af WS\_CLIPSIBLINGS, WS\_CLIPCHILDREN, WS\_EX\_COMPOSITED, WS\_EX\_TRANSPARENT og så videre? Og hvad sker der, hvis en anden tråd invaliderer en del af vinduet på øverste niveau halvvejs igennem denne proces?


Og så, på Windows V6.0 +, hvordan går DWM ind i denne proces?





Dette er et eksempel C-program, der viser den fejl, der opstår, når du bruger WS\_EX\_COMPOSITED: -


#include <windows.h>
#include <windowsx.h>
INT delay = 50;
INT nPad = 32;

struct wnd\_ctx {
  COLORREF base;
  char index;
};

HMODULE GetWindowModuleHandle(HWND hwnd){
  return (HMODULE)GetWindowLongPtr(hwnd,GWLP\_HINSTANCE);
}

struct wnd\_ctx* GetContext(HWND hWnd){
  struct wnd\_ctx* pctx = (LPVOID)GetWindowLongPtr(hWnd,GWLP\_USERDATA);
  if(!pctx)
  {
    pctx = malloc(sizeof(struct wnd\_ctx));
    SetWindowLongPtr(hWnd,GWLP\_USERDATA,(LONG\_PTR)pctx);
  }
  return pctx;
}

LRESULT CALLBACK wnd\_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
  PAINTSTRUCT ps;
  HDC hdc;
  RECT rect;
  HBRUSH hbr;
  struct wnd\_ctx* self;
  switch (message){
  case WM\_LBUTTONUP:
    GetClientRect(hWnd,&rect);
    rect.top += nPad;
    rect.bottom -= nPad;
    rect.left += nPad;
    rect.right -= nPad;
    InvalidateRect(hWnd,&rect,TRUE);
    return 0;
  case WM\_ERASEBKGND:
    DefWindowProc(hWnd, message, wParam, lParam);
    Sleep(delay);
    return 0;
  case WM\_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    if(self = GetContext(hWnd)){
      hbr = CreateSolidBrush(self->base + ((self->index++ <<5) & 0x7f));
      GetClientRect(hWnd,&rect);
      FillRect(hdc,&rect,hbr);
      DeleteObject(hbr);
    }
    EndPaint(hWnd, &ps);
    Sleep(delay);
    break;
  case WM\_DESTROY:
    PostQuitMessage(0);
    break;
  default:
    return DefWindowProc(hWnd, message, wParam, lParam);
  }
  return 0;
}

ATOM CreateClass(HINSTANCE hInstance,LPCTSTR strClass,COLORREF brush,HICON hIcon){
  WNDCLASSEX wcex;
  wcex.cbSize = sizeof(WNDCLASSEX);
  wcex.style            = CS\_HREDRAW|CS\_VREDRAW;
  wcex.lpfnWndProc  = wnd\_WndProc;
  wcex.cbClsExtra       = 0;
  wcex.cbWndExtra       = 0;
  wcex.hInstance        = hInstance;
  wcex.hIcon            = hIcon;
  wcex.hCursor      = LoadCursor(NULL, IDC\_ARROW);
  wcex.hbrBackground    = CreateSolidBrush(brush);
  wcex.lpszMenuName = 0;
  wcex.lpszClassName    = strClass;
  wcex.hIconSm      = hIcon;
  return RegisterClassEx(&wcex);
}

BOOL CreateWindows(HINSTANCE hInstance, INT nCmdShow, LPCTSTR strTitle){
  HWND hWnd, hChild;
  ATOM atm;
  RECT rect;
  DWORD dwStyleEx, dwStyle, dwChildStyle, dwChildStyleEx;
  struct  wnd\_ctx* pctx;
  dwStyleEx = WS\_EX\_COMPOSITED;
  dwStyle = WS\_OVERLAPPEDWINDOW;//|WS\_CLIPCHILDREN;
  dwChildStyle = WS\_CHILD|WS\_VISIBLE;//|WS\_CLIPSIBLINGS;
  atm = CreateClass( hInstance, TEXT("APPWINDOW"), RGB(0x80,0x80,0x80), LoadIcon(NULL,IDI\_APPLICATION));
  hWnd = CreateWindowEx(dwStyleEx,(LPCTSTR)atm, strTitle, dwStyle,
      CW\_USEDEFAULT, 0, 256, 256, NULL, NULL, hInstance, NULL);
   pctx = GetContext(hWnd);
   pctx->base = RGB(0x00,0xff,0xff);
   pctx->index=0;
   atm = CreateClass(hInstance,TEXT("CONTROL1"),RGB(0x00,0x80,0x40),0);
   GetClientRect(hWnd,&rect);
   hChild = CreateWindowEx(0L,(LPCTSTR)atm, TEXT("Top"), dwChildStyle,
     rect.right/2, rect.top, rect.right/2, rect.bottom, hWnd, NULL, hInstance, NULL);
   pctx = GetContext(hChild);
   pctx->base = RGB(0x00,0xff,0x80);
   pctx->index=0;
   atm = CreateClass(hInstance,TEXT("CONTROL2"),RGB(0x00,0x40,0x80),0);
   hChild = CreateWindowEx(0L,(LPCTSTR)atm, TEXT("Bottom"), dwChildStyle,
     rect.left, rect.bottom/2, rect.right , rect.bottom/2, hWnd, NULL, hInstance, NULL);
   pctx = GetContext(hChild);
   pctx->base = RGB(0x00,0x80,0xff);
   pctx->index=0;
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   return TRUE;
 }

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow){
  MSG msg;
  CreateWindows(hInstance,nCmdShow,TEXT("Test Child Painting"));
  while(GetMessage(&msg, NULL, 0, 0)>0){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int) msg.wParam;
}

Bedste reference


Den traditionelle model var, at intet blev husket (fordi hukommelsen var dyr), derfor var et vindue dækket, og indholdet blev glemt, og det blev rejst som svar på WM\_PAINT.


Men du vidste det her.


Fra applikationssynspunktet er hovedændringen til denne model, at DWM-mærket ikke skal male, men til ugyldighed , det vil sige, at der kræves maling. Regioner er ikke (nødvendigvis) ugyldige, når de er dækket af andre vinduer, da DWM husker, hvad vinduet ligner, og det behøver ikke at spørge applikationen 'Erindring mig, hvad du ønskede at vise der igen?'.


Hvis du selv ugyldiggør en region enten eksplicit eller implicit (via SetWindowText for eksempel), så vil den stadig få WM\_PAINT.


Når man maler forældrene, kan eller ikke børnene klippes, afhængigt af om det er indstillet. Jeg tror, ​​at maleri er lavet bagfra, så børnekontrol til (for eksempel) tegner 3D-grænser uden for deres eget rektangel, som i Microsoft Word 6, hvis du husker det langt tilbage!


Så vidt jeg ved, er dette ikke dokumenteret, og siden du citerede Raymond Chen, vil du vide, at han ville forsigtige dig mod at stole på rækkefølgen af ​​WM\_PAINT-meddelelser.