If you just want to change the text color of any button, you can do something similar to the way in the post below.
Note that if you want to create a button with a canvas gadget, the #PB_Canvas_DrawFocus and #PB_Canvas_Keyboard flags will be helpful.
Code: Select all
DeclareModule API_HookEngine
Declare.i Hook(*OldFunctionAddress, *NewFunctionAddress)
Declare.i UnHook(*hook_ptr)
Declare.i ProcAddress(ModuleName$, ProcName$)
EndDeclareModule
Module API_HookEngine
EnableExplicit
Structure opcode
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
mov.u
CompilerElse
mov.a
CompilerEndIf
addr.i
push.a
ret.a
EndStructure
Structure hookstruct
addr.i
hook.opcode
orig.a[SizeOf(opcode)]
EndStructure
CompilerIf #PB_Compiler_Unicode
Import "kernel32.lib"
GetProcAddress(hModule, lpProcName.p-ascii)
EndImport
CompilerElse
Import "kernel32.lib"
GetProcAddress(hModule, lpProcName.s)
EndImport
CompilerEndIf
Procedure.i ProcAddress(ModuleName$, ProcName$)
Protected moduleH.i
moduleH = GetModuleHandle_(ModuleName$)
If moduleH = #Null
moduleH = LoadLibrary_(ModuleName$)
If moduleH = #Null
ProcedureReturn #Null
EndIf
EndIf
ProcedureReturn GetProcAddress(moduleH, ProcName$)
EndProcedure
Procedure Hook(*OldFunctionAddress, *NewFunctionAddress)
Protected *hook_ptr.hookstruct
If Not *OldFunctionAddress
ProcedureReturn #Null
EndIf
*hook_ptr = AllocateMemory(SizeOf(hookstruct))
*hook_ptr\addr = *OldFunctionAddress
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
*hook_ptr\hook\mov = $B848
CompilerElse
*hook_ptr\hook\mov = $B8
CompilerEndIf
*hook_ptr\hook\addr = *NewFunctionAddress
*hook_ptr\hook\push = $50
*hook_ptr\hook\ret = $C3
CopyMemory(*OldFunctionAddress, @*hook_ptr\orig, SizeOf(opcode))
If Not WriteProcessMemory_(GetCurrentProcess_(), *OldFunctionAddress, @*hook_ptr\hook, SizeOf(opcode), #Null)
FreeMemory(*hook_ptr)
ProcedureReturn #Null
Else
ProcedureReturn *hook_ptr
EndIf
EndProcedure
Procedure.i UnHook(*hook_ptr.hookstruct)
Protected retValue.i
If *hook_ptr
If *hook_ptr\addr
If WriteProcessMemory_(GetCurrentProcess_(), *hook_ptr\addr, @*hook_ptr\orig, SizeOf(opcode), #Null)
retValue = *hook_ptr\addr
FreeMemory(*hook_ptr)
ProcedureReturn retValue
EndIf
EndIf
EndIf
ProcedureReturn #Null
EndProcedure
Procedure DisableHook(*hook_ptr.hookstruct)
If *hook_ptr
If *hook_ptr\addr
If WriteProcessMemory_(GetCurrentProcess_(), *hook_ptr\addr, @*hook_ptr\orig, SizeOf(opcode), #Null)
ProcedureReturn *hook_ptr\addr
EndIf
EndIf
EndIf
ProcedureReturn #Null
EndProcedure
Procedure EnableHook(*hook_ptr.hookstruct)
If *hook_ptr
If *hook_ptr\hook\addr
If WriteProcessMemory_(GetCurrentProcess_(), *hook_ptr\addr, @*hook_ptr\hook, SizeOf(opcode), #Null)
ProcedureReturn *hook_ptr\addr
EndIf
EndIf
EndIf
ProcedureReturn #Null
EndProcedure
EndModule
UseModule API_HookEngine
EnumerationBinary
#DTT_TEXTCOLOR ;(1 << 0) ;// crText has been specified
#DTT_BORDERCOLOR ;(1 << 1) ;// crBorder has been specified
#DTT_SHADOWCOLOR ;(1 << 2) ;// crShadow has been specified
#DTT_SHADOWTYPE ;(1 << 3) ;// iTextShadowType has been specified
#DTT_SHADOWOFFSET ;(1 << 4) ;// ptShadowOffset has been specified
#DTT_BORDERSIZE ;(1 << 5) ;// iBorderSize has been specified
#DTT_FONTPROP ;(1 << 6) ;// iFontPropId has been specified
#DTT_COLORPROP ;(1 << 7) ;// iColorPropId has been specified
#DTT_STATEID ;(1 << 8) ;// IStateId has been specified
#DTT_CALCRECT ;(1 << 9) ;// Use pRect as and in/out parameter
#DTT_APPLYOVERLAY ;(1 << 10) ;// fApplyOverlay has been specified
#DTT_GLOWSIZE ;(1 << 11) ;// iGlowSize has been specified
#DTT_CALLBACK ;(1 << 12) ;// pfnDrawTextCallback has been specified
#DTT_COMPOSITED ;(1 << 13) ;// Draws text with antialiased alpha (needs a DIB section)
EndEnumeration
#DTT_VALIDBITS = #DTT_TEXTCOLOR | #DTT_BORDERCOLOR | #DTT_SHADOWCOLOR | #DTT_SHADOWTYPE | #DTT_SHADOWOFFSET |
#DTT_BORDERSIZE | #DTT_FONTPROP | #DTT_COLORPROP | #DTT_STATEID | #DTT_CALCRECT |
#DTT_APPLYOVERLAY | #DTT_GLOWSIZE | #DTT_COMPOSITED
#BP_PUSHBUTTON = 1
#BP_RADIOBUTTON = 2
#BP_CHECKBOX = 3
Structure DTTOPTS
dwSize.l
dwFlags.l
crText.l
crBorder.l
crShadow.l
iTextShadowType.l
ptShadowOffset.POINT
iBorderSize.l
iFontPropId.l
iColorPropId.l
iStateId.l
fApplyOverlay.l
iGlowSize.l
*pfnDrawTextCallback
lParam.l
EndStructure
Prototype DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, *pszText, cchText, dwTextFlags.l, *pRect, *pOptions)
Global DrawThemeTextEx.DrawThemeTextEx
Structure ColoredGadgetInfo
FrontColor.i
hBrushBackColor.i
EndStructure
Global NewMap ColoredGadget.ColoredGadgetInfo()
#App_BrushWidth = 2000 ;Set the value large enough in consideration of changing a gadget width.
Procedure MainWindow_Callback(hWnd, uMsg, wParam, lParam)
Protected Gadget, Result = #PB_ProcessPureBasicEvents
Select uMsg
Case #WM_CTLCOLORBTN
Gadget = GetProp_(lParam, "pb_id")
If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Button
If FindMapElement(ColoredGadget(), Str(lParam))
;SetBkMode_(wParam, #TRANSPARENT)
Result = ColoredGadget()\hBrushBackColor
EndIf
EndIf
EndSelect
ProcedureReturn Result
EndProcedure
Procedure CreateBackgroundBrush(hwnd)
Protected hBrush, Img
If hwnd = 0 : ProcedureReturn 0 : EndIf
Img = CreateImage(#PB_Any, #App_BrushWidth, 1, 24, GetSysColor_(#COLOR_3DFACE))
If Img
If StartDrawing(ImageOutput(Img))
;Write the handle value in the last few bytes of the pattern brush.
Plot(#App_BrushWidth - 1, 0, hwnd & $FFFF)
Plot(#App_BrushWidth - 2, 0, (hwnd >> 16) & $FFFF)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
Plot(#App_BrushWidth - 3, 0, (hwnd >> 32) & $FFFF)
Plot(#App_BrushWidth - 4, 0, (hwnd >> 48) & $FFFF)
CompilerEndIf
StopDrawing()
hBrush = CreatePatternBrush_(ImageID(Img))
EndIf
FreeImage(Img)
EndIf
ProcedureReturn hBrush
EndProcedure
Procedure SetButtonGadgetTextColor(Gadget, FrontColor = #PB_Default)
Protected Result, hwnd
If IsGadget(Gadget)
If GadgetType(Gadget) <> #PB_GadgetType_Button
ProcedureReturn 0
EndIf
hwnd = GadgetID(Gadget)
If hwnd
SendMessage_(hwnd, #WM_SETREDRAW, 0, 0)
Repeat
With ColoredGadget()
;Check if the gadget already exists in the map.
If FindMapElement(ColoredGadget(), Str(hwnd))
If FrontColor = #PB_Default
;Remove the gadget from the map.
DeleteObject_(\hBrushBackColor)
DeleteMapElement(ColoredGadget())
Result = 1
Break
EndIf
If \FrontColor <> FrontColor
\FrontColor = FrontColor
If \hBrushBackColor
DeleteObject_(\hBrushBackColor)
\hBrushBackColor = 0
EndIf
\hBrushBackColor = CreateBackgroundBrush(hwnd)
EndIf
Result = 1
Break
EndIf
;If not, add it to the map.
If AddMapElement(ColoredGadget(), Str(hwnd))
\FrontColor = FrontColor
\hBrushBackColor = CreateBackgroundBrush(hwnd)
Result = 1
EndIf
Break
EndWith
ForEver
SendMessage_(hwnd, #WM_SETREDRAW, 1, 0)
RedrawWindow_(hwnd, 0, 0, #RDW_ERASE | #RDW_FRAME | #RDW_INVALIDATE | #RDW_ALLCHILDREN)
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure My_DrawThemeText(hTheme, hdc, iPartId, iStateId, *pszText, cchText, dwTextFlags, dwTextFlags2, *pRect)
Protected opt.DTTOPTS\dwSize = SizeOf(DTTOPTS)
Protected hBrush, BrushInfo.LOGBRUSH, hdcTemp, rt.RECT, hBitmap, old, hwnd
If iPartId = #BP_PUSHBUTTON
hBrush = GetCurrentObject_(hdc, #OBJ_BRUSH)
If hBrush
If GetObject_(hBrush, SizeOf(LOGBRUSH), @BrushInfo)
If BrushInfo\lbStyle = #BS_PATTERN
hdcTemp = CreateCompatibleDC_(hdc)
If hdcTemp
hBitmap = CreateCompatibleBitmap_(hdc, #App_BrushWidth, 1)
If hBitmap
old = SelectObject_(hdcTemp, hBitmap)
rt\right = #App_BrushWidth
rt\bottom = 1
FillRect_(hdcTemp, rt, hBrush)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
hwnd = (GetPixel_(hdcTemp, #App_BrushWidth - 1, 0) & $FFFF) | ((GetPixel_(hdcTemp, #App_BrushWidth - 2, 0) & $FFFF) << 16) |
((GetPixel_(hdcTemp, #App_BrushWidth - 3, 0) & $FFFF) << 32) | ((GetPixel_(hdcTemp, #App_BrushWidth - 4, 0) & $FFFF) << 48)
CompilerElse
hwnd = (GetPixel_(hdcTemp, #App_BrushWidth - 1, 0) & $FFFF) | ((GetPixel_(hdcTemp, #App_BrushWidth - 2, 0) & $FFFF) << 16)
CompilerEndIf
If FindMapElement(ColoredGadget(), Str(hwnd))
If ColoredGadget()\FrontColor <> #PB_Default
opt\dwFlags = #DTT_TEXTCOLOR
opt\crText = ColoredGadget()\FrontColor
EndIf
EndIf
DeleteObject_(SelectObject_(hdcTemp, old))
EndIf
DeleteDC_(hdcTemp)
EndIf
EndIf
EndIf
EndIf
EndIf
ProcedureReturn DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, *pszText, cchText, dwTextFlags, *pRect, @opt)
EndProcedure
If OpenLibrary(0, "UxTheme.dll")
DrawThemeTextEx = GetFunction(0, "DrawThemeTextEx") ;There is no DrawThemeTextEx in Windows XP, so this method is not available.
EndIf
If DrawThemeTextEx
*DrawThemeText = Hook(ProcAddress("UxTheme.dll", "DrawThemeText"), @My_DrawThemeText())
EndIf
Enumeration Window
#MainWindow
EndEnumeration
Enumeration Gadgets
#g_0
#g_1
#g_2
#g_3
#g_4
#g_5
#g_6
EndEnumeration
If OpenWindow(#MainWindow, 0, 0, 400, 350, "Button Text Color", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
SetWindowColor(#MainWindow, RGB(54, 54, 54))
ButtonGadget(#g_0, 20, 20, 160, 30, "Default")
ButtonGadget(#g_1, 220, 20, 160, 30, "#Yellow")
ContainerGadget(#g_2, 10, 60, 390, 90, #PB_Container_Flat)
SetGadgetColor(#g_2, #PB_Gadget_BackColor, RGB(128, 128, 128))
TextGadget(#g_3, 5, 5, 160, 20, "Container_1")
SetGadgetColor(#g_3, #PB_Gadget_BackColor, GetGadgetColor(#g_2, #PB_Gadget_BackColor))
ButtonGadget(#g_4, 10, 30, 160, 30, "#Blue")
ButtonGadget(#g_5, 190, 30, 180, 40, "#Magenta")
CloseGadgetList()
CheckBoxGadget(#g_6, 20, 230, 180, 40, "enable/disable")
hFont = LoadFont(0, "arial", 20, #PB_Font_Bold)
SetGadgetFont(#g_5, hFont)
SetButtonGadgetTextColor(#g_1, #Yellow)
SetButtonGadgetTextColor(#g_4, #Blue)
SetButtonGadgetTextColor(#g_5, #Magenta)
;SetButtonGadgetTextColor(#g_4)
;SetButtonGadgetTextColor(#g_5)
;DisableGadget(#g_5, 1)
SetWindowCallback(@MainWindow_Callback(), #MainWindow)
Repeat
e = WaitWindowEvent()
If e = #PB_Event_Gadget And EventGadget() = #g_6
If GetGadgetState(#g_6)
SetButtonGadgetTextColor(#g_5)
Else
SetButtonGadgetTextColor(#g_5, #Magenta)
EndIf
DisableGadget(#g_5, GetGadgetState(#g_6))
EndIf
Until e = #PB_Event_CloseWindow
EndIf
If *DrawThemeText
UnHook(*DrawThemeText)
EndIf
CloseLibrary(0)
ForEach ColoredGadget()
DeleteObject_(ColoredGadget()\hBrushBackColor)
Next