Sign in to follow this  
Followers 0

_WinAPI_DrawShadowText UDF: Draw text with a drop shadow

10 posts in this topic

#1 ·  Posted (edited)

DrawShadowText API, An export function of ComCtl32.dll

came across this while reading on MSDN

Minimum OS: Windows XP, ComCtl32.dll version 6 or later

tested on Win XP and Vista

same text formatting and alignment options as _WinAPI_DrawText in helpfile

with addition of text color, shadow color and X/Y shadow offset.

DrawShadowText Function

There are GDI+ drop shadow text examples on the forum that offer more shadow formatting options than this API

the _CreateShadowTextBitmap bitmap text on a background jpg example is not exactly the best implementation... :)

if the window is hidden, the bitmap is taken from a background window.

more XP drop shadow fun:

Add a drop shadow to native AutoIt GUI Forms and Dialogs

Edit: fixed function header lines wrapping in code boxes

;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

#include <GUIConstantsEX.au3>

#include <WindowsConstants.au3>

#include <FontConstants.au3>

#include <WinAPI.au3>

Opt('MustDeclareVars', 1)

Local $hFont2, $hBmp1, $hBmp2, $hDC1, $hDC2, $hMemDC1, $hMemDC2, $tRECT1, $tRECT2, $pRECT1, $pRECT2



Func _DrawShadowTextDemo()

Local Const $CLEARTYPE_QUALITY = 0x05

Local $hGUI, $Msg, $sTime, $hFont1

Local $cLabel1, $cLabel2, $cLabel3, $cLabel4, $cLabel5

Local $hLabel4, $hLabel5, $hBitmap1, $hBitmap2, $hBitmap3

$hGUI = GUICreate("DrawShadowText API Demo", 400, 420)

_GuiSetDropShadow($hGUI, False)

If @OSVersion == "WIN_VISTA" Then

GUICtrlCreatePic(@WindowsDir & "\Web\Wallpaper\img25.jpg", -1, -1, 401, 300)


GUICtrlCreatePic(@WindowsDir & "\Web\Wallpaper\Windows XP.jpg", -1, -1, 401, 300)


GUICtrlSetState(-1, $GUI_DISABLE)


;$hFont1 = _WinAPI_CreateFont(60, 0, 0, 0, 400, False, False, False, $DEFAULT_CHARSET, _


$hFont1 = _WinAPI_CreateFont(60, 0, 0, 0, 400, False, False, False, $DEFAULT_CHARSET, _


$hFont2 = _WinAPI_CreateFont(70, 0, 0, 0, 400, False, False, False, $DEFAULT_CHARSET, _


$cLabel1 = GUICtrlCreatePic("", 10, 20, 380, 50)

$cLabel2 = GUICtrlCreatePic("", 10, 80, 380, 50)

$cLabel3 = GUICtrlCreatePic("", 90, 140, 220, 50)

$cLabel4 = GUICtrlCreateLabel("", 80, 305, 240, 50)

$hLabel4 = GUICtrlGetHandle(-1)

$cLabel5 = GUICtrlCreateLabel("", 80, 365, 240, 50)

$hLabel5 = GUICtrlGetHandle(-1)

$tRECT1 = _WinAPI_GetClientRect($hLabel4)

$tRECT2 = _WinAPI_GetClientRect($hLabel5)

$pRECT1 = DllStructGetPtr($tRECT1)

$pRECT2 = DllStructGetPtr($tRECT2)

$hDC1 = _WinAPI_GetWindowDC($hLabel4)

$hDC2 = _WinAPI_GetWindowDC($hLabel5)

$hMemDC1 = _WinAPI_CreateCompatibleDC($hDC1)

$hMemDC2 = _WinAPI_CreateCompatibleDC($hDC2)

$hBmp1 = _WinAPI_CreateCompatibleBitmap($hDC1, 240, 50)

$hBmp2 = _WinAPI_CreateCompatibleBitmap($hDC2, 240, 50)

AdlibEnable("_Time", 100)


$sTime = StringFormat("%02d:%02d:%02d", @HOUR, @MIN, @SEC)

$hBitmap1 = _CreateShadowTextBitmap($cLabel1, $hFont1, 380, 50, "Shadow Text", $iTextFlags, 0x00FFFFFF, 0x00000000, 6, 6) ;White text/Black shadow

_SetBitmapToCtrl($cLabel1, $hBitmap1)

Local $sText = "The quick brown fox jumps over the lazy dog"

$hBitmap2 = _CreateShadowTextBitmap($cLabel2, 0, 380, 50, $sText, $iTextFlags, 0x00FFFFFF, 0x00000000, 3, 3) ;White text/Black shadow

_SetBitmapToCtrl($cLabel2, $hBitmap2)

$hBitmap3 = _CreateShadowTextBitmap($cLabel3, $hFont1, 220, 50, $sTime, $iTextFlags, 0x0000D7FF, 0x00000000, -3, -3) ;Gold text/Black shadow

_SetBitmapToCtrl($cLabel3, $hBitmap3)


$hBitmap3 = _CreateShadowTextBitmap($cLabel3, $hFont1, 220, 50, $sTime, $iTextFlags, 0x00000001, 0x0000D7FF , 3, 3) ;Black text/Gold shadow

_SetBitmapToCtrl($cLabel3, $hBitmap3)


$hBitmap3 = _CreateShadowTextBitmap($cLabel3, $hFont1, 220, 50, $sTime, $iTextFlags, 0x0000001, 0x0000CC00, 3, 3) ;Black text/Green shadow

_SetBitmapToCtrl($cLabel3, $hBitmap3)


$hBitmap3 = _CreateShadowTextBitmap($cLabel3, $hFont1, 220, 50, $sTime, $iTextFlags, 0x0000001, 0x00FF0000, 3, 3) ;Black text/Blue shadow

_SetBitmapToCtrl($cLabel3, $hBitmap3)


$hBitmap3 = _CreateShadowTextBitmap($cLabel3, $hFont1, 220, 50, $sTime, $iTextFlags, 0x00000001, 0x00C0C0C0, 3, 3) ;Black text/Grey shadow

_SetBitmapToCtrl($cLabel3, $hBitmap3)

While 1

$Msg = GUIGetMsg()

Switch $Msg

Case -3


Case $cLabel1

Case $cLabel2

Case $cLabel3

Case $cLabel4

Case $cLabel5




_WinAPI_ReleaseDC($hLabel4, $hDC1)

_WinAPI_ReleaseDC($hLabel5, $hDC2)













; Name...........: _WinAPI_DrawShadowText

; Description ...: Draws formatted text in the specified rectangle with a drop shadow

; Syntax.........: _WinAPI_DrawShadowText($hDC, $szText, ByRef $tRect, $iFlags, $crText, $crShadow, $ixOffset, $iyOffset)

; Parameters ....: $hDC - Identifies the device context

; $sText - The string to be drawn

; $tRect - $tagRECT structure that contains the rectangle for the text

; $iFlags - Specifies the method of formatting the text: *** See Remarks ***

; |$DT_BOTTOM - Justifies the text to the bottom of the rectangle

; |$DT_CALCRECT - Determines the width and height of the rectangle

; |$DT_CENTER - Centers text horizontally in the rectangle

; |$DT_EDITCONTROL - Duplicates the text-displaying characteristics of a multiline edit control

; |$DT_END_ELLIPSIS - Replaces part of the given string with ellipses if necessary

; |$DT_EXPANDTABS - Expands tab characters

; |$DT_EXTERNALLEADING - Includes the font external leading in line height

; |$DT_HIDEPREFIX - Ignores the ampersand (&) prefix character in the text.

; | The letter that follows will not be underlined, but other mnemonic-prefix characters are still processed.

; |$DT_INTERNAL - Uses the system font to calculate text metrics

; |$DT_LEFT - Aligns text to the left

; |$DT_MODIFYSTRING - Modifies the given string to match the displayed text

; |$DT_NOCLIP - Draws without clipping

; |$DT_NOFULLWIDTHCHARBREAK - Prevents a line break at a DBCS (double-wide character string),

; so that the line breaking rule is equivalent to SBCS strings.

; | For example, this can be used in Korean windows, for more readability of icon labels.

; | This value has no effect unless $DT_WORDBREAK is specified

; |$DT_NOPREFIX - Turns off processing of prefix characters

; |$DT_PATH_ELLIPSIS - For displayed text, replaces characters in the middle of the string with ellipses

; | so that the result fits in the specified rectangle.

; | If the string contains backslash (\) characters,

; | $DT_PATH_ELLIPSIS preserves as much as possible of the text after the last backslash.

; | The string is not modified unless the $DT_MODIFYSTRING flag is specified

; |$DT_PREFIXONLY - Draws only an underline at the position of the character following the ampersand (&) prefix character.

; | Does not draw any other characters in the string

; |$DT_RIGHT - Aligns text to the right

; |$DT_RTLREADING - Layout in right to left reading order for bi-directional text

; |$DT_SINGLELINE - Displays text on a single line only

; |$DT_TABSTOP - Sets tab stops. Bits 15-8 of $iFlags specify the number of characters for each tab

; |$DT_TOP - Top-justifies text (single line only)

; |$DT_VCENTER - Centers text vertically (single line only)

; |$DT_WORDBREAK - Breaks words

; |$DT_WORD_ELLIPSIS - Truncates any word that does not fit in the rectangle and adds ellipses

; $crText - Color of the text in hexadecimal COLORREF format: (ABGR) 0x00FFFFFF

; $crShadow - Color of the text shadow in hexadecimal COLORREF format: (ABGR) 0x00FFFFFF

; $ixOffset - Drop shadow X offset integer - positive and negative values

; $iyOffset - Drop shadow Y offset integer - positive and negative values

; "The low-order byte contains a value for the relative intensity of red

; the second byte contains a value for green; and the third byte contains a value for blue.

; The high-order byte must be zero. The maximum value for a single byte is 0xFF".

; Return values .: Success - The height of the text*

; Failure - 0 and error set

; Author ........: rover

; Modified.......:

; Remarks .......: *** Detailed remarks are absent on the MSDN web page, so it is an assumption that the following applies to DrawShadowText as well.

; * "If the function succeeds, the return value is the height of the text in logical units.

; If DT_VCENTER or DT_BOTTOM is specified, the return value is the offset from lpRect->top to the bottom of the drawn text".

; "The DrawText function uses the device context's selected font, text color, and background color to draw the

; text. Unless the $DT_NOCLIP format is used, DrawText clips the text so that it does not appear outside the

; specified rectangle. All formatting is assumed to have multiple lines unless the $DT_SINGLELINE format is

; specified. If the selected font is too large, DrawText does not attempt to substitute a smaller font".


; Needs WindowsConstants.au3 for pre-defined constants

; Related .......: DrawText, $tagRECT

; Link ..........; @@MsdnLink@@ DrawShadowText

; Example .......; Yes

; ===================================================================================================

Func _WinAPI_DrawShadowText($hDC, $szText, ByRef $tRect, $iFlags = 0, $crText = 0, $crShadow = 0, $ixOffset = 0, $iyOffset = 0)

If IsDllStruct($tRect) = 0 Or DllStructGetSize($tRect) <> 16 Then Return SetError(1, 1, 0)

Local $aResult, $iError

$aResult = DllCall("ComCtl32.dll", "int", "DrawShadowText", "hwnd", $hDC, "wstr", $szText, "int", -1, "ptr", _ ;StringLen($szText)

DllStructGetPtr($tRect), "dword", $iFlags, "dword", $crText, "dword", $crShadow, "int", $ixOffset, "int", $iyOffset)

$iError = @error

If @error Or UBound($aResult) <> 10 Then Return SetError($iError, 2, 0)

Return SetError($iError, 0, $aResult[0])

EndFunc ;==>_WinAPI_DrawShadowText

Func _CreateShadowTextBitmap($CtrlId, $hFont, $iWidth, $iHeight, $sText, $iFlags, $iColText, $iColShadow, $iXOffset, $iYOffset)

Local $hDC, $hMemDC, $hBMP, $hOldhBMP, $hOldFont, $tRECT, $hWnd, $hBMP

Local Const $STM_GETIMAGE = 0x173

$hWnd = GUICtrlGetHandle($CtrlId)

$hBMP = GUICtrlSendMsg($CtrlId, $STM_GETIMAGE, 0, 0)

If $hBMP <> 0 Then


GUICtrlSetState($CtrlId, $GUI_SHOW)


$tRECT = _WinAPI_GetClientRect($hWnd)

$hDC = _WinAPI_GetWindowDC($hWnd)

$hMemDC = _WinAPI_CreateCompatibleDC($hDC)

$hBMP = _WinAPI_CreateCompatibleBitmap($hDC, $iWidth, $iHeight)

$hOldhBMP = _WinAPI_SelectObject($hMemDC, $hBMP)

$hOldFont = _WinAPI_SelectObject($hDC, $hFont)

_WinAPI_DrawShadowText($hDC, $sText, $tRECT, $iFlags, $iColText, $iColShadow, $iXOffset, $iYOffset)

_WinAPI_BitBlt($hMemDC, 0, 0, $iWidth, $iHeight, $hDC, 0, 0, $MERGECOPY)

_WinAPI_SelectObject($hMemDC, $hOldFont)

_WinAPI_SelectObject($hMemDC, $hOldhBMP)

_WinAPI_ReleaseDC($hWnd, $hDC)


Return $hBMP


; from Zedna's Resources.au3

Func _SetBitmapToCtrl($CtrlId, $hBitmap)

Local Const $STM_SETIMAGE = 0x0172

Local Const $IMAGE_BITMAP = 0

Local Const $SS_BITMAP = 0xE

Local Const $GWL_STYLE = -16

Local $hWnd = GUICtrlGetHandle($CtrlId)

If $hWnd = 0 Then Return SetError(1, 0, 0)

; set SS_BITMAP style to control

;Local $oldStyle = DllCall("user32.dll", "long", "GetWindowLong", _

;"hwnd", $hWnd, "int", $GWL_STYLE)

;If @error Then Return SetError(2, 0, 0)

;DllCall("user32.dll", "long", "SetWindowLong", "hwnd", $hWnd, _

;"int", $GWL_STYLE, "long", BitOR($oldStyle[0], $SS_BITMAP))

;If @error Then Return SetError(3, 0, 0)

Local $oldBmp = DllCall("user32.dll", "hwnd", "SendMessage", _

"hwnd", $hWnd, "int", $STM_SETIMAGE, "int", $IMAGE_BITMAP, "int", $hBitmap)

If @error Then Return SetError(4, 0, 0)

If $oldBmp[0] <> 0 Then _WinAPI_DeleteObject($oldBmp[0])

Return 1


Func _Time()

Local $obj_orig1 = _WinAPI_SelectObject($hMemDC1, $hBmp1)

Local $obj_orig2 = _WinAPI_SelectObject($hMemDC2, $hBmp2)

Local $hOldFont1 = _WinAPI_SelectObject($hMemDC1, $hFont2)

Local $hOldFont2 = _WinAPI_SelectObject($hMemDC2, $hFont2)

_WinAPI_FillRect($hMemDC1, $pRECT1, 0)

_WinAPI_FillRect($hMemDC2, $pRECT2, 0)

Local $sTime = StringFormat("%02d:%02d:%02d", @HOUR, @MIN, @SEC)

_WinAPI_DrawShadowText($hMemDC1, $sTime, $tRECT1, $iTextFlags, 0x00000001, 0x00C0C0C0, -3, -3)

_WinAPI_DrawShadowText($hMemDC2, $sTime, $tRECT2, $iTextFlags, 0x00FFFFFF, 0x00C0C0C0, 3, 3)

_WinAPI_BitBlt($hDC1, 0, 0, 240, 50, $hMemDC1, 0, 0, $SRCCOPY)

_WinAPI_BitBlt($hDC2, 0, 0, 240, 50, $hMemDC2, 0, 0, $SRCCOPY)

_WinAPI_SelectObject($hMemDC1, $obj_orig1)

_WinAPI_SelectObject($hMemDC2, $obj_orig2)

_WinAPI_SelectObject($hMemDC1, $hOldFont1)

_WinAPI_SelectObject($hMemDC2, $hOldFont2)



; Name...........: _GuiSetDropShadow

; Description ...: Sets the drop shadow effect on forms and dialogs for current process

; Syntax.........: _GuiSetDropShadow($hwnd, $fDisrespectUser = True)

; Parameters ....: $hWnd - Handle to parent form or child dialog (GuiCreate(), MsgBox(), FileOpenDialog(), etc.)

; $fDisrespectUser - True: (Default) - set system option for drop shadow if disabled by user

; - False: - do not set system option for drop shadow if disabled by user

; Return values .: Success - 1

; Failure - 0 @error set and @extended set to point of failure

; Author(s) ........: rover, (lod3n, Rasim for Get/SetClassLong, Kip - RegisterclassEx() for drop shadow idea, ProgAndy - xMsgBox hook)

; Remarks .......: Note: drop shadow is lost if parent form clicked on (If MsgBox created with parent handle)

; hiding, then restoring MsgBox to foreground or moving MsgBox off of form restores drop shadow.

; use 262144 or 4096 flags with MsgBox if using with hParent handle to prevent loss of drop shadow if parent clicked on.

; this behaviour is apparently by design.


; Minimum Operating Systems: Windows XP

; Related .......:

; Link ..........; @@MsdnLink@@ SetClassLong Function

; Example .......; Yes

; ===================================================================================================

Func _GuiSetDropShadow($hwnd, $fDisrespectUser = True)

If Not IsHWnd($hwnd) Then Return SetError(1, 1, 0)

;check if hWnd is from current process

Local $aResult = DllCall("User32.dll", "int", "GetWindowThreadProcessId", "hwnd", $hwnd, "int*", 0)

If @error Or $aResult[2] <> @AutoItPID Then Return SetError(@error, 2, 0)

If Not IsDeclared("SPI_GETDROPSHADOW") Then Local Const $SPI_GETDROPSHADOW = 0x1024

If Not IsDeclared("SPI_SETDROPSHADOW") Then Local Const $SPI_SETDROPSHADOW = 0x1025

If Not IsDeclared("CS_DROPSHADOW") Then Local Const $CS_DROPSHADOW = 0x00020000

If Not IsDeclared("GCL_STYLE") Then Local Const $GCL_STYLE = -26

$aResult = DllCall("user32.dll", "int", "SystemParametersInfo", "int", $SPI_GETDROPSHADOW, "int", 0, "int*", 0, "int", 0)

Local $iErr = @error

If $iErr Or Not IsArray($aResult) Then Return SetError($iErr, 3, 0)

;if 'Show shadows under menus' option not set, try activating it.

If Not $aResult[3] And $fDisrespectUser Then

;turn on drop shadows

$aResult = DllCall("user32.dll", "int", "SystemParametersInfo", "int", $SPI_SETDROPSHADOW, "int", 0, "int", True, "int", 0)

$iErr = @error

If $iErr Or Not IsArray($aResult) Or $aResult[0] <> 1 Then Return SetError($iErr, 4, 0)


;get styles from WndClassEx struct

$aResult = DllCall("user32.dll", "dword", "GetClassLong", "hwnd", $hwnd, "int", $GCL_STYLE)

$iErr = @error

If $iErr Or Not IsArray($aResult) Or Not $aResult[0] Then Return SetError($iErr, 5, 0)

Local $OldStyle = $aResult[0]

;add drop shadow style to styles

Local $Style = BitOR($OldStyle, $CS_DROPSHADOW)

If StringRight(@OSArch, 2) == "64" Then

;if 64 bit windows (NOT TESTED)

;see MSDN SetClassLong remarks

;$aResult = DllCall("user32.dll", "ulong_ptr", "SetClassLongPtr", "hwnd", $hWnd, "int", $GCL_STYLE, "long_ptr", $Style)

;$iErr = @error

;If $iErr Or Not IsArray($aResult) Or Not $aResult[0] Then Return SetError($iErr, 6, 0)


$aResult = DllCall("user32.dll", "dword", "SetClassLong", "hwnd", $hwnd, "int", $GCL_STYLE, "long", $Style)

$iErr = @error

If $iErr Or Not IsArray($aResult) Or Not $aResult[0] Then Return SetError($iErr, 7, 0)

If $aResult[0] = $OldStyle Then Return SetError($iErr, 0, 1)

Return SetError($iErr, 8, 0)





Edited by rover
1 person likes this

I see fascists...

Share this post

Link to post
Share on other sites

Neat, looks good!

Thanks JRowe

I wonder how this was overlooked and not previously posted, as its not undocumented on MSDN


I see fascists...

Share this post

Link to post
Share on other sites

Looks very nice!

Good job :)


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!

Share this post

Link to post
Share on other sites

SWEET! I like it...

Share this post

Link to post
Share on other sites

Very Nice rover!!!

Here's my "Hobbyist" approach...

_3DTEXT("3D Text Machine..", 90, 30, 300, 50)
_3DTEXT("Shadow Text", 70, 90, 300, 50, 0x0000FF, 0xBBBBBB, 30, 5)
_3DTEXT(@HOUR & ":" & @MIN & ":" & @SEC, 100, 170, 300, 50, 0x0000D7FF, 0x00000000, 35)
_3DTEXT(@HOUR & ":" & @MIN & ":" & @SEC, 100, 250, 300, 50, 0x0000D7FF, 0x00000000, 35, 4)
_3DTEXT("Valuater... 8)", 75, 330, 300, 50, 0xF8F8FF, 0x00000000, 30, 1, 1)

While GUIGetMsg() <> -3

Func _3DTEXT($text, $top, $left, $length = 100, $height = 20, $Font_Color = "", $Shadow_Color = 0xBBBBBB, $Font_Size = 20, $style = 1, $adj = 2.5)
    Local $Ret[2], $adj2 = $adj
    If $style = 2 Or $style = 5 Then $adj2 = 0
    If $style = 3 Or $style = 6 Then $adj = 0
    If $style <= 3 Then $Ret[0] = GUICtrlCreateLabel($text, $top + $adj, $left + $adj2, $length, $height)
    If $style >= 4 Then $Ret[0] = GUICtrlCreateLabel($text, $top - $adj, $left - $adj2, $length, $height)
    GUICtrlSetColor(-1, $Shadow_Color)
    GUICtrlSetFont(-1, $Font_Size, 700)
    $Ret[1] = GUICtrlCreateLabel($text, $top, $left, $length, $height)
    GUICtrlSetBkColor(-1, -2)
    GUICtrlSetColor(-1, $Font_Color)
    GUICtrlSetFont(-1, $Font_Size, 700)
    Return $Ret
EndFunc   ;==>_3DTEXT



Share this post

Link to post
Share on other sites

#8 ·  Posted (edited)

Very nice!!

Can you make it to a UDF?

Edited by nend

Share this post

Link to post
Share on other sites

Thanks UEZ, Gseller, Yashied, Valuater, nend

excuse my usually late reply, was absent from forums (and city) for awhile

Nice results Valuater!

working with device contexts isn't as straightforward

with the v3.3.1.0 beta we can now select font quality

GUICtrlSetFont(-1, $Font_Size, 700, -1, "Arial", $ANTIALIASED_QUALITY)

your example is similar to this text effect by Jex, the user with the great cat avatar :)


a bit of a pain to make a UDF when repainting message handling is required

and the label background can be color, bitmap or layered etc. let alone painting controls other than labels.

I'll post an example with labels and WM_CTLCOLORSTATIC repaint in a bit...

I see fascists...

Share this post

Link to post
Share on other sites

If anyone is watching this topic, I have a couple of questions about using _CreateShadowTextBitmap and, I guess by indirection _WinAPI_DrawShadowText,

  • If I use a text color of 0x00000000, I get black text but NO shadow regards less of what color I use for the shadow. However, if I set text color to 0x00000001, then I get "black" text with the shadow I specify. Anyone know why?
  • My application gets a font size in the normal external format, ie. 12, 14, 16, etc. but the _WinAPI_CreateFont takes a font height and font width. Is there a formula, function, or WAG as how to produce font height from font size?


Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  
Followers 0