Louis Solomon / SteelBytes
Written 27/Aug/08
DrawTextW on 2000 and XP will not render to a DIBSection if the string is not WCHAR aligned in memory. But it does work in Vista.
TextOutW will not render to a DIBSection when the string is non WCHAR aligned on any of 2000, XP or Vista.
Both DrawTextW and TextOutW work fine when drawing to either a screen DC or a printer DC on all three Windows flavours.
In the following screen shots of Vista (x64 SP1) and XP (RTM), the first 4 lines are drawing to a DIBSection, and the 2nd 4 lines are drawing to the DC returned from BeginPaint

Source code to demonstrate
#define STRICT
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#if !defined(UNICODE)
#error this test doesn't make sense in Ansi
#endif
#define test_width 250
#define test_height 100
static void DrawStuff(HDC hdc,const RECT &rect)
{
int width = rect.right-rect.left;
int height = rect.bottom-rect.top;
HFONT oldfont = SelectFont(hdc,CreateFont(height*1/4,0,0,0,0,0,0,0,0,0,0,0,0,TEXT("Tahoma")));
SetTextColor(hdc,RGB(0,0,0));
SetTextAlign(hdc,TA_LEFT|TA_TOP|TA_NOUPDATECP);
SetBkMode(hdc,TRANSPARENT);
{
RECT r = {rect.left+0,rect.top+0,rect.left+width,rect.top+height};
FillRect(hdc,&r,(HBRUSH)GetStockObject(WHITE_BRUSH));
}
{
static const TCHAR string[] = TEXT("DrawText Aligned");
RECT r = {rect.left+0,rect.top+height*0/4,rect.left+width,rect.top+height*1/4};
DrawText(hdc,string,lstrlen(string),&r,DT_LEFT|DT_TOP|DT_NOPREFIX|DT_SINGLELINE);
}
{
static const TCHAR string[] = TEXT("TextOut Aligned");
TextOut(hdc,rect.left,rect.top+height*1/4,string,lstrlen(string));
}
{
static const TCHAR _string[] = TEXT("DrawText Unaligned");
BYTE buf[1+sizeof(_string)];
CopyMemory(buf+1,_string,sizeof(_string));
const TCHAR *string = (const TCHAR*)(buf+1);
RECT r = {rect.left+0,rect.top+height*2/4,rect.left+width,rect.top+height*3/4};
DrawText(hdc,string,lstrlen(string),&r,DT_LEFT|DT_TOP|DT_NOPREFIX|DT_SINGLELINE);
}
{
static const TCHAR _string[] = TEXT("TextOut Unaligned");
BYTE buf[1+sizeof(_string)];
CopyMemory(buf+1,_string,sizeof(_string));
const TCHAR *string = (const TCHAR*)(buf+1);
TextOut(hdc,rect.left,rect.top+height*3/4,string,lstrlen(string));
}
DeleteObject(SelectFont(hdc,oldfont));
}
static LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
return FALSE;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd,&ps);
{
HDC pic_hdc = CreateCompatibleDC(NULL);
BITMAPINFO bmInfo;
ZeroMemory(&bmInfo,sizeof(bmInfo));
bmInfo.bmiHeader.biSize = sizeof(bmInfo.bmiHeader);
bmInfo.bmiHeader.biPlanes = 1;
bmInfo.bmiHeader.biWidth = test_width;
bmInfo.bmiHeader.biHeight = test_height;
bmInfo.bmiHeader.biBitCount = 24;
void *pic_buf;
HBITMAP oldbmp = SelectBitmap(pic_hdc,CreateDIBSection(NULL,&bmInfo,DIB_RGB_COLORS,&pic_buf,NULL,NULL));
RECT r = {0,0,test_width,test_height};
DrawStuff(pic_hdc,r);
BitBlt(ps.hdc,0,0,test_width,test_height,pic_hdc,0,0,SRCCOPY);
DeleteObject(SelectBitmap(pic_hdc,oldbmp));
DeleteDC(pic_hdc);
}
{
RECT r = {0,test_height,test_width,test_height*2};
DrawStuff(ps.hdc,r);
}
EndPaint(hwnd,&ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hwnd,msg,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
static const TCHAR szMainWindowClass[] = TEXT("MainWindowClass");
WNDCLASS wc;
ZeroMemory(&wc,sizeof(wc));
wc.lpfnWndProc = MainWndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.lpszClassName = szMainWindowClass;
RegisterClass(&wc);
RECT r = {0,0,test_width,test_height*2};
const DWORD style = WS_POPUPWINDOW|WS_CAPTION|WS_VISIBLE;
const DWORD styleex = WS_EX_APPWINDOW|WS_EX_TOOLWINDOW;
AdjustWindowRectEx(&r,style,FALSE,styleex);
CreateWindowEx(styleex,szMainWindowClass,TEXT("DrawText mem align test"),style,100,100,r.right-r.left,r.bottom-r.top,NULL,NULL,hInstance,0);
MSG msg;
while (GetMessage(&msg,0,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}