Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DrawText using FONT and SetBkMode in windows Dialog

I'm creating a Dialog using CreateDialog.

in the dialog proc I do some drawing of text in WM_PAINT:

function DialogProc(hDlg: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL; stdcall;
...
case Msg of
  WM_PAINT:
    begin
      dc := BeginPaint(hDlg, ps);    
      bkmodePrev := SetBkMode(dc, TRANSPARENT);
      hfnt := SendMessage(hDlg, WM_GETFONT, 0, 0);
      hfntPrev := SelectObject(dc, hfnt);
      DrawTextW(dc, 'Text', -1, R, DT_SINGLELINE or DT_CENTER or DT_VCENTER);
      SelectObject(dc, hfntPrev);
      // SetBkMode(dc, bkmodePrev); // do I need this?
      EndPaint(hDlg, ps);
      Result := True;
    end;  
  end;
...

Now the question is, am I doing it right with the font, meaning that, is this the correct way to get the font handle of a dialog using SendMessage(hDlg, WM_GETFONT, 0, 0) and restoring it with SelectObject(dc, hfntPrev)? Do I need to restore old BkMode of bkmodePrev using SetBkMode(dc, bkmodePrev);? or will EndPaint do that for me?

P.S: do I need to release the DC?

like image 344
kobik Avatar asked Nov 07 '14 16:11

kobik


1 Answers

Am I doing it right with the font?

Yes.

Do I need to restore the old BkMode of bkmodeprev using SetBkMode(dc, bkmodeprev), or will EndPaint do that for me?

EndPaint won't restore the background mix mode for you. But EndPaint does destroy the device context so it doesn't need to be restored. However, in my view, best practise is to restore the background mix mode whenever you change it. Then if you extend the code in the future you won't be surprised. But that's really a preference. You may take a different stance.

Do I need to release the DC?

No, the call to EndPaint suffices.


I would write this like so:

dc := BeginPaint(hDlg, ps);    
bkmodeprev := SetBkMode(dc, TRANSPARENT);
hfnt := SendMessage(hDlg, WM_GETFONT, 0, 0);
hfntPrev := SelectObject(dc, hfnt);
DrawTextW(dc, 'Text', -1, R, DT_SINGLELINE or DT_CENTER or DT_VCENTER);
SelectObject(dc, hfntPrev);
SetBkMode(dc, bkmodeprev);
EndPaint(hDlg, ps);

Although, one might argue that it would be better to include some error checking.


As is pointed out in the comments you need to provide a return value for the WM_PAINT message. From the docs:

If the dialog box procedure processes a message that requires a specific return value, the dialog box procedure should set the desired return value by calling SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult) immediately before returning TRUE. Note that you must call SetWindowLong immediately before returning TRUE; doing so earlier may result in the DWL_MSGRESULT value being overwritten by a nested dialog box message.

like image 176
David Heffernan Avatar answered Oct 05 '22 22:10

David Heffernan