I'm trying to create a tooltip in VBA using winapi calls, basically following the tutorial from MSDN remapped to VBA with Declare statements etc. The call to CreateWindowsEx()
returns NULL
and the follow-on GetLastError()
returns 0 as well. I've tried both in Excel and Outlook, but it gives the same result. Is this simply not possible, or is there anything wrong with the parameters I pass to CreateWindowsEx()
?
Here is the complete code snippet:
Private Type INITCOMMONCONTROLSEX_REC
dwSize As Long
dwICC As Long
End Type
Private Const ICC_WIN95_CLASSES = &HFF
Private Declare PtrSafe Function InitCommonControlsEx Lib "Comctl32.dll" (ByRef icce As INITCOMMONCONTROLSEX_REC) As Long
Private Const WS_EX_TOPMOST As Long = &H8
Private Const WS_POPUP As Long = &H80000000
Private Const TTS_ALWAYSTIP As Long = &H1
Private Const TTS_NOPREFIX As Long = &H2
Private Const TOOLTIPS_CLASS = "tooltips_class32"
Private Declare PtrSafe Function CreateWindowEx Lib "user32.dll" Alias "CreateWindowExA" (dwExStyle As Long, lpClassName As String, lpWindowName As String, _
ByVal dwStyle As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As LongPtr, ByVal hMenu As LongPtr, _
ByVal hInstance As LongPtr, lpParam As Any) As LongPtr
Public Sub CreateToolTip()
Dim ret As Long
Dim retLng As LongPtr
Dim iccRec As INITCOMMONCONTROLSEX_REC
iccRec.dwSize = LenB(iccRec)
iccRec.dwICC = ICC_WIN95_CLASSES
ret = InitCommonControlsEx(iccRec)
Dim hWndTip As LongPtr
hWndTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, vbNullString, _
WS_POPUP Or TTS_NOPREFIX Or TTS_ALWAYSTIP, _
0, 0, 0, 0, 0, 0, 0, ByVal 0)
End Sub
I wrote a class almost 10 years ago that still works and maybe you can play around and change it to your needs. You can examine and see exactly what it does.
Insert a new class module into your VBA project and call it ToolTip
. Add this code:
Option Explicit
Private Type LOGFONT 'to use with CreateFontIndirect function (https://msdn.microsoft.com/en-us/library/windows/desktop/dd183500%28v=vs.85%29.aspx)
lfHeight As Long
lfWidth As Long
lfEscapement As Long
lfOrientation As Long
lfWeight As Long
lfItalic As Byte
lfUnderline As Byte
lfStrikeOut As Byte
lfCharSet As Byte
lfOutPrecision As Byte
lfClipPrecision As Byte
lfQuality As Byte
lfPitchAndFamily As Byte
lfFaceName As String * 32
End Type
Private Type RECT 'rectangle type
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type POINTAPI '2D cartezian point
X As Long
Y As Long
End Type
Private Type LOGBRUSH 'to use with CreateBrushIndirect API function (https://msdn.microsoft.com/en-us/library/windows/desktop/dd183487%28v=vs.85%29.aspx)
lbStyle As Long
lbColor As Long
lbHatch As Long
End Type
Private Type PAINTSTRUCT 'to use with BeginPaint, EndPaint API functions
hDC As Long
fErase As Long
rcPaint As RECT
fRestore As Long
fIncUpdate As Long
rgbReserved(32) As Byte
End Type
Private Enum WND_STYLES 'Window Styles (https://msdn.microsoft.com/en-gb/library/windows/desktop/ms632600(v=vs.85).aspx)
WS_BORDER = &H800000
WS_CAPTION = &HC00000
WS_CHILD = &H40000000
WS_CLIPCHILDREN = &H2000000
WS_CLIPSIBLINGS = &H4000000
WS_DISABLED = &H8000000
WS_DLGFRAME = &H400000
WS_GROUP = &H20000
WS_HSCROLL = &H100000
WS_MAXIMIZE = &H1000000
WS_MINIMIZE = &H20000000
WS_OVERLAPPED = &H0&
WS_POPUP = &H80000000
WS_SYSMENU = &H80000
WS_TABSTOP = &H10000
WS_THICKFRAME = &H40000
WS_VISIBLE = &H10000000
WS_VSCROLL = &H200000
End Enum
Private Enum ECS 'Edit Control Styles (https://msdn.microsoft.com/en-us/library/windows/desktop/bb775464%28v=vs.85%29.aspx)
ES_AUTOHSCROLL = &H80
ES_AUTOVSCROLL = &H40
ES_CENTER = &H1
ES_LEFT = &H0
ES_LOWERCASE = &H10
ES_MULTILINE = &H4
ES_NOHIDESEL = &H100
ES_OEMCONVERT = &H400
ES_PASSWORD = &H20
ES_READONLY = &H800
ES_RIGHT = &H2
ES_UPPERCASE = &H8
ES_WANTRETURN = &H1000
End Enum
Private Enum EXT_WND_STYLES 'Extended Window Styles (https://msdn.microsoft.com/en-gb/library/windows/desktop/ff700543(v=vs.85).aspx)
WS_EX_ACCEPTFILES = &H10
WS_EX_APPWINDOW = &H40000
WS_EX_CLIENTEDGE = &H200
WS_EX_COMPOSITED = &H2000000
WS_EX_CONTEXTHELP = &H400
WS_EX_CONTROLPARENT = &H10000
WS_EX_DLGMODALFRAME = &H1
WS_EX_LAYERED = &H80000
WS_EX_LAYOUTRTL = &H400000
WS_EX_LEFT = &H0
WS_EX_LEFTSCROLLBAR = &H4000
WS_EX_LTRREADING = &H0
WS_EX_MDICHILD = &H40
WS_EX_NOACTIVATE = &H8000000
WS_EX_NOINHERITLAYOUT = &H100000
WS_EX_NOPARENTNOTIFY = &H4
WS_EX_NOREDIRECTIONBITMAP = &H200000
WS_EX_RIGHT = &H1000
WS_EX_RIGHTSCROLLBAR = &H0
WS_EX_RTLREADING = &H2000
WS_EX_STATICEDGE = &H20000
WS_EX_TOOLWINDOW = &H80
WS_EX_TOPMOST = &H8
WS_EX_TRANSPARENT = &H20
WS_EX_WINDOWEDGE = &H100
WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE Or WS_EX_CLIENTEDGE
WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE Or WS_EX_TOOLWINDOW Or WS_EX_TOPMOST
End Enum
Private Enum DRAWTEXT_FORMAT 'to use for DrawText function (https://msdn.microsoft.com/en-us/library/windows/desktop/dd162498%28v=vs.85%29.aspx)
DT_TOP = &H0
DT_LEFT = &H0
DT_CENTER = &H1
DT_RIGHT = &H2
DT_VCENTER = &H4
DT_BOTTOM = &H8
DT_WORDBREAK = &H10
DT_SINGLELINE = &H20
DT_EXPANDTABS = &H40
DT_TABSTOP = &H80
DT_NOCLIP = &H100
DT_EXTERNALLEADING = &H200
DT_CALCRECT = &H400
DT_NOPREFIX = &H800
DT_INTERNAL = &H1000
End Enum
Private Enum BK_MODE 'background mode to use with SetBkMode function (https://msdn.microsoft.com/en-us/library/windows/desktop/dd162965(v=vs.85).aspx)
TRANSPARENT = 1
OPAQUE = 2
End Enum
Private Enum CHARSET
ANSI_CHARSET = 0
ARABIC_CHARSET = 178
BALTIC_CHARSET = 186
CHINESEBIG5_CHARSET = 136
DEFAULT_CHARSET = 1
EASTEUROPE_CHARSET = 238
GREEK_CHARSET = 161
HANGUL_CHARSET = 129
HEBREW_CHARSET = 177
JOHAB_CHARSET = 130
MAC_CHARSET = 77
OEM_CHARSET = 255
RUSSIAN_CHARSET = 204
SHIFTJIS_CHARSET = 128
SYMBOL_CHARSET = 2
THAI_CHARSET = 222
TURKISH_CHARSET = 162
End Enum
Private Enum DRAW_ICON_FLAG 'to use with DrawIconEx function (https://msdn.microsoft.com/en-us/library/windows/desktop/ms648065(v=vs.85).aspx)
DI_COMPAT = &H4
DI_DEFAULTSIZE = &H8
DI_IMAGE = &H2
DI_MASK = &H1
DI_NOMIRROR = &H10
DI_NORMAL = 3 'DI_IMAGE and DI_MASK
End Enum
Private Enum BORDER
BDR_RAISEDOUTER = &H1
BDR_SUNKENOUTER = &H2
BDR_RAISEDINNER = &H4
BDR_SUNKENINNER = &H8
BDR_OUTER = &H3
BDR_INNER = &HC
BDR_RAISED = &H5
BDR_SUNKEN = &HA
End Enum
Private Enum EDGE
EDGE_RAISED = BDR_RAISEDOUTER Or BDR_RAISEDINNER
EDGE_SUNKEN = BDR_SUNKENOUTER Or BDR_SUNKENINNER
EDGE_ETCHED = BDR_SUNKENOUTER Or BDR_RAISEDINNER
EDGE_BUMP = BDR_RAISEDOUTER Or BDR_SUNKENINNER
End Enum
Private Enum EDGE_FLAG
BF_LEFT = &H1
BF_TOP = &H2
BF_RIGHT = &H4
BF_BOTTOM = &H8
BF_TOPLEFT = (BF_TOP Or BF_LEFT)
BF_TOPRIGHT = (BF_TOP Or BF_RIGHT)
BF_BOTTOMLEFT = (BF_BOTTOM Or BF_LEFT)
BF_BOTTOMRIGHT = (BF_BOTTOM Or BF_RIGHT)
BF_RECT = BF_LEFT Or BF_TOP Or BF_RIGHT Or BF_BOTTOM
BF_DIAGONAL = &H10
BF_DIAGONAL_ENDTOPRIGHT = (BF_DIAGONAL Or BF_TOP Or BF_RIGHT)
BF_DIAGONAL_ENDTOPLEFT = (BF_DIAGONAL Or BF_TOP Or BF_LEFT)
BF_DIAGONAL_ENDBOTTOMLEFT = (BF_DIAGONAL Or BF_BOTTOM Or BF_LEFT)
BF_DIAGONAL_ENDBOTTOMRIGHT = (BF_DIAGONAL Or BF_BOTTOM Or BF_RIGHT)
BF_MIDDLE = &H800 ' Fill in the middle
BF_SOFT = &H1000 ' Use for softer buttons
BF_ADJUST = &H2000 ' Calculate the space left over
BF_FLAT = &H4000 ' For flat rather than 3-D borders
BF_MONO = &H8000 ' For monochrome borders
End Enum
Private Const SC_EDIT = "Edit" 'System Classes (https://msdn.microsoft.com/en-gb/library/windows/desktop/ms633574(v=vs.85).aspx#system)
'
'API functions
#If VBA7 Then
Private Declare PtrSafe Function BeginPaint Lib "user32" (ByVal hwnd As LongPtr, lpPaint As PAINTSTRUCT) As LongPtr
Private Declare PtrSafe Function CreateBrushIndirect Lib "gdi32" (lpLogBrush As LOGBRUSH) As LongPtr
Private Declare PtrSafe Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As LongPtr
Private Declare PtrSafe Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, _
ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hWndParent As LongPtr, ByVal hMenu As LongPtr, ByVal hInstance As LongPtr, lpParam As Any) As LongPtr
Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As Long
Private Declare PtrSafe Function DestroyWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
Private Declare PtrSafe Function DrawEdge Lib "user32" (ByVal hDC As LongPtr, qrc As RECT, ByVal EDGE As Long, ByVal grfFlags As Long) As Long
Private Declare PtrSafe Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hDC As LongPtr, ByVal lpStr As String, ByVal nCount As Long, _
lpRect As RECT, ByVal wFormat As Long) As Long
Private Declare PtrSafe Function EndPaint Lib "user32" (ByVal hwnd As LongPtr, lpPaint As PAINTSTRUCT) As Long
Private Declare PtrSafe Function FillRect Lib "user32" (ByVal hDC As LongPtr, lpRect As RECT, ByVal hBrush As LongPtr) As Long
Private Declare PtrSafe Function GetClientRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDC As LongPtr) As Long
Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hDC As LongPtr, ByVal hObject As LongPtr) As LongPtr
Private Declare PtrSafe Function SetBkMode Lib "gdi32" (ByVal hDC As LongPtr, ByVal nBkMode As Long) As Long
Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hwnd As LongPtr, ByVal hWndInsertAfter As LongPtr, ByVal X As Long, _
ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare PtrSafe Function ShowWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal nCmdShow As Long) As Long
Private Declare PtrSafe Function DrawIconEx Lib "user32" (ByVal hDC As LongPtr, ByVal xLeft As Long, ByVal yTop As Long, _
ByVal hIcon As LongPtr, ByVal cxWidth As Long, ByVal cyWidth As Long, ByVal istepIfAniCur As Long, _
ByVal hbrFlickerFreeDraw As LongPtr, ByVal diFlags As Long) As Long
#Else
Private Declare Function BeginPaint Lib "User32.dll" (ByVal hwnd As Long, ByRef lpPaint As PAINTSTRUCT) As Long
Private Declare Function CreateBrushIndirect Lib "gdi32" (lpLogBrush As LOGBRUSH) As Long
Private Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long
Private Declare Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, _
ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function DestroyWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function DrawEdge Lib "user32" (ByVal hDC As Long, qrc As RECT, ByVal EDGE As Long, ByVal grfFlags As Long) As Long
Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hDC As Long, ByVal lpStr As String, ByVal nCount As Long, _
lpRect As RECT, ByVal wFormat As Long) As Long
Private Declare Function EndPaint Lib "User32.dll" (ByVal hwnd As Long, ByRef lpPaint As PAINTSTRUCT) As Long
Private Declare Function FillRect Lib "User32.dll" (ByVal hDC As Long, ByRef lpRect As RECT, ByVal hBrush As Long) As Long
Private Declare Function GetClientRect Lib "User32.dll" (ByVal hwnd As Long, ByRef lpRect As RECT) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long
Private Declare Function SetBkMode Lib "gdi32" (ByVal hDC As Long, ByVal nBkMode As Long) As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, _
ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function DrawIconEx Lib "user32" (ByVal hDC As Long, ByVal xLeft As Long, ByVal yTop As Long, _
ByVal hIcon As Long, ByVal cxWidth As Long, ByVal cyWidth As Long, ByVal istepIfAniCur As Long, _
ByVal hbrFlickerFreeDraw As Long, ByVal diFlags As Long) As Long
#End If
'handles
#If VBA7 Then
Private m_hWndToolTip As LongPtr 'handle for window
Private m_hDCToolTip As LongPtr 'handle for device context
Private m_hIcon As LongPtr 'handle for Icon
#Else
Private m_hWndToolTip As Long
Private m_hDCToolTip As Long
Private m_hIcon As Long
#End If
'primary class members
Private m_objParent As Object
Private m_font As LOGFONT
Private m_strMessage As String
'position and size
Private m_sngLeft As Single
Private m_sngTop As Single
Private m_sngWidth As Single
Private m_sngHeight As Single
Private m_sngOffsetFromCursorX As Single
Private m_sngOffsetFromCursorY As Single
Private m_sngTextOffsetLeft As Single
Private m_sngTextOffsetTop As Single
Private m_sngTextOffsetRight As Single
Private m_sngTextOffsetBottom As Single
Private m_sngIconLeft As Single
Private m_sngIconTop As Single
Private m_sngIconWidth As Single
Private m_sngIconHeight As Single
'visibility
Private m_bVisible As Boolean
'auto resize
Private m_bAutoResize As Boolean
'custom types variables
Private m_tClientAreaRect As RECT
Private m_tLogBrush As LOGBRUSH
'Class constructor with default values
Private Sub Class_Initialize()
'position, size and visibility
m_sngLeft = 0
m_sngTop = 0
m_sngWidth = 100
m_sngHeight = 100
m_sngOffsetFromCursorX = 0
m_sngOffsetFromCursorY = 0
m_sngTextOffsetLeft = 10
m_sngTextOffsetTop = 10
m_sngTextOffsetRight = 10
m_sngTextOffsetBottom = 10
m_sngIconLeft = 0
m_sngIconTop = 0
m_sngIconWidth = 0
m_sngIconHeight = 0
m_strMessage = vbNullString
m_bVisible = False
m_bAutoResize = False
'font
With m_font
.lfFaceName = "Arial" & chr(0)
.lfHeight = 16
.lfWidth = 6
.lfEscapement = 0
.lfWeight = 0
.lfItalic = 0
.lfUnderline = 0
.lfStrikeOut = 0
.lfCharSet = CHARSET.DEFAULT_CHARSET
'.lfOutPrecision
'.lfClipPrecision
'.lfQuality
'.lfPitchAndFamily
End With
m_tLogBrush.lbColor = &HE1FFFF 'the usual back color (bright yellow)
'create toolTip window (child of desktop) and get the window handle
'Make it work for both AutoCAD and Excel
#If VBA7 Then
Dim hWndApp As LongPtr
#Else
Dim hWndApp As Long
#End If
If InStr(LCase(Application.Name), "autocad") > 0 Then
hWndApp = Application.hwnd
ElseIf InStr(LCase(Application.Name), "excel") > 0 Then
#If VBA7 Then
hWndApp = Application.HinstancePtr
#Else
hWndApp Application.hInstance
#End If
Else
MsgBox "ToolTip class is not set to retrive the Handle for this application!", vbCritical, "hWnd"
Exit Sub
End If
m_hWndToolTip = CreateWindowEx(EXT_WND_STYLES.WS_EX_TOOLWINDOW, SC_EDIT, vbNullString, _
ECS.ES_MULTILINE + ECS.ES_LEFT + ECS.ES_READONLY + WND_STYLES.WS_CHILD, _
0, 0, 0, 0, GetDesktopWindow, 0, hWndApp, 0)
'
'get the Device Context handle for the toolTip window
m_hDCToolTip = GetDC(m_hWndToolTip)
End Sub
Private Sub Class_Terminate()
'release device context
ReleaseDC m_hWndToolTip, m_hDCToolTip
'destroy toolTip window
DestroyWindow m_hWndToolTip
End Sub
Public Property Get Parent() As Object
Set Parent = m_objParent
End Property
Public Property Let Parent(ByVal objParent As Object)
Set m_objParent = objParent
End Property
Public Property Get Left() As Single
Left = m_sngLeft
End Property
Public Property Let Left(ByVal sngLeft As Single)
m_sngLeft = sngLeft
Call Position(m_sngLeft, m_sngTop)
End Property
Public Property Get Top() As Single
Top = m_sngTop
End Property
Public Property Let Top(ByVal sngTop As Single)
m_sngTop = sngTop
Call Position(m_sngLeft, m_sngTop)
End Property
Public Property Get Width() As Single
Width = m_sngWidth
End Property
Public Property Let Width(ByVal sngWidth As Single)
m_sngWidth = sngWidth
End Property
Public Property Get Height() As Single
Height = m_sngHeight
End Property
Public Property Let Height(ByVal sngHeight As Single)
m_sngHeight = sngHeight
End Property
Public Property Get TextOffsetLeft() As Single
TextOffsetLeft = m_sngTextOffsetLeft
End Property
Public Property Let TextOffsetLeft(ByVal sngTextOffsetLeft As Single)
m_sngTextOffsetLeft = sngTextOffsetLeft
End Property
Public Property Get TextOffsetTop() As Single
TextOffsetTop = m_sngTextOffsetTop
End Property
Public Property Let TextOffsetTop(ByVal sngTextOffsetTop As Single)
m_sngTextOffsetTop = sngTextOffsetTop
End Property
Public Property Get TextOffsetRight() As Single
TextOffsetRight = m_sngTextOffsetRight
End Property
Public Property Let TextOffsetRight(ByVal sngTextOffsetRight As Single)
m_sngTextOffsetRight = sngTextOffsetRight
End Property
Public Property Get TextOffsetBottom() As Single
TextOffsetBottom = m_sngTextOffsetBottom
End Property
Public Property Let TextOffsetBottom(ByVal sngTextOffsetBottom As Single)
m_sngTextOffsetBottom = sngTextOffsetBottom
End Property
Public Property Get BackColor() As Long
BackColor = m_tLogBrush.lbColor
End Property
Public Property Let BackColor(ByVal lngBackColor As Long)
m_tLogBrush.lbColor = lngBackColor
End Property
Public Property Get Message() As String
Message = m_strMessage
End Property
Public Property Let Message(ByVal strMessage As String)
Select Case strMessage
Case vbNullString
Call Hide
Exit Property
Case m_strMessage
If m_bVisible Then Exit Property
Case Else
m_strMessage = strMessage
End Select
'
'declare font
#If VBA7 Then
Dim lngFontHWnd As LongPtr
Dim lngOldFontHWnd As LongPtr
#Else
Dim lngFontHWnd As Long
Dim lngOldFontHWnd As Long
#End If
'
Call show
'create new font object
lngFontHWnd = CreateFontIndirect(m_font)
'remember old font while replacing with new font
lngOldFontHWnd = SelectObject(m_hDCToolTip, lngFontHWnd)
'get client rectangle
GetClientRect m_hWndToolTip, m_tClientAreaRect
'autoResize by text
If m_bAutoResize Then
'get the text rectangle (nothing is drawn by using DT_CALCRECT)
DrawText m_hDCToolTip, m_strMessage, Len(m_strMessage), m_tClientAreaRect, DRAWTEXT_FORMAT.DT_NOCLIP + _
DRAWTEXT_FORMAT.DT_LEFT + DRAWTEXT_FORMAT.DT_CALCRECT
'resize toolTip window
With m_tClientAreaRect
m_sngWidth = .Right - .Left + m_sngTextOffsetLeft + m_sngTextOffsetRight
m_sngHeight = .Bottom - .Top + m_sngTextOffsetTop + m_sngTextOffsetBottom
End With
SetWindowPos m_hWndToolTip, 0, m_sngLeft, m_sngTop, m_sngWidth, m_sngHeight, 0
'get client new rectangle
GetClientRect m_hWndToolTip, m_tClientAreaRect
End If
'draw the colored rectangle into DC
Call DrawRect
'draw the edge of the rectangle
DrawEdge m_hDCToolTip, m_tClientAreaRect, EDGE.EDGE_RAISED, EDGE_FLAG.BF_RECT
'set background before text placing
SetBkMode m_hDCToolTip, BK_MODE.TRANSPARENT
'resize rectangle for placing text and offset-ing text rectangle from main colored rectangle
With m_tClientAreaRect
.Left = .Left + m_sngTextOffsetLeft
.Top = .Top + m_sngTextOffsetTop
.Right = .Right - m_sngTextOffsetRight
.Bottom = .Bottom - m_sngTextOffsetBottom
End With
'draw the text
DrawText m_hDCToolTip, m_strMessage, Len(m_strMessage), m_tClientAreaRect, DRAWTEXT_FORMAT.DT_NOCLIP + DRAWTEXT_FORMAT.DT_LEFT
'selected object [oldFont] releases the previous object of the same type in the Device Context (no memory leaks)
Call SelectObject(m_hDCToolTip, lngOldFontHWnd)
'delete new font object
DeleteObject lngFontHWnd
'draw icon
If m_hIcon <> 0 Then
DrawIconEx m_hDCToolTip, 5, 5, m_hIcon, 16, 16, 0, 0, DRAW_ICON_FLAG.DI_NORMAL
End If
End Property
Public Sub OffsetFromCursor(ByVal sngOffsetFromCursorX As Single, ByVal sngOffsetFromCursorY As Single)
m_sngOffsetFromCursorX = sngOffsetFromCursorX
m_sngOffsetFromCursorY = sngOffsetFromCursorY
End Sub
Public Sub Position(ByVal X As Single, ByVal Y As Single)
m_sngLeft = X + m_sngOffsetFromCursorX
m_sngTop = Y + m_sngOffsetFromCursorY
SetWindowPos m_hWndToolTip, 0, m_sngLeft, m_sngTop, m_sngWidth, m_sngHeight, 0
End Sub
Public Sub PositionByMouse()
Dim mouseXY As POINTAPI
GetCursorPos mouseXY
Position mouseXY.X, mouseXY.Y
End Sub
Public Sub show()
If Not m_bVisible Then
Call ShowWindow(m_hWndToolTip, 1)
m_bVisible = True
End If
End Sub
Public Sub Hide()
If m_bVisible Then
Call ShowWindow(m_hWndToolTip, 0)
m_bVisible = False
End If
End Sub
Public Sub DrawRect()
Dim tPS As PAINTSTRUCT
'declare brush
#If VBA7 Then
Dim lngBrush As LongPtr
#Else
Dim lngBrush As Long
#End If
'
On Error Resume Next
'begin paint
BeginPaint m_hWndToolTip, tPS
'create a new brush
lngBrush = CreateBrushIndirect(m_tLogBrush)
'fill the device context of the toolTip window with the newly created brush inside the client rectangle
FillRect m_hDCToolTip, m_tClientAreaRect, lngBrush
'delete the brush
Call DeleteObject(lngBrush)
'end paint
Call EndPaint(m_hWndToolTip, tPS)
End Sub
Public Property Get Font_Height() As Long
Font_Height = m_font.lfHeight
End Property
Public Property Let Font_Height(ByVal lngFont_Height As Long)
m_font.lfHeight = lngFont_Height
End Property
Public Property Get Font_Width() As Long
Font_Width = m_font.lfWidth
End Property
Public Property Let Font_Width(ByVal lngFont_Width As Long)
m_font.lfWidth = lngFont_Width
End Property
Public Property Get Font_Text_Rotation() As Long
Font_Text_Rotation = m_font.lfEscapement
End Property
Public Property Let Font_Text_Rotation(ByVal lngFontTextRotation As Long)
m_font.lfEscapement = lngFontTextRotation
End Property
Public Property Get Font_Orientation() As Long
Font_Orientation = m_font.lfOrientation
End Property
Public Property Let Font_Orientation(ByVal lngFont_Orientation As Long)
m_font.lfOrientation = lngFont_Orientation
End Property
Public Property Get Font_Italic() As Boolean
Font_Italic = CBool(m_font.lfItalic)
End Property
Public Property Let Font_Italic(ByVal bFontItalic As Boolean)
m_font.lfItalic = CByte(bFontItalic)
End Property
Public Property Get Font_Underline() As Boolean
Font_Underline = CBool(m_font.lfUnderline)
End Property
Public Property Let Font_Underline(ByVal bFontUnderline As Boolean)
m_font.lfUnderline = CByte(bFontUnderline)
End Property
Public Property Get Font_StrikeOut() As Boolean
Font_StrikeOut = CBool(m_font.lfStrikeOut)
End Property
Public Property Let Font_StrikeOut(ByVal bFontStrikeOut As Boolean)
m_font.lfStrikeOut = CByte(bFontStrikeOut)
End Property
#If VBA7 Then
Public Property Let IconHandle(ByVal lngHandle As LongPtr)
m_hIcon = lngHandle
End Property
Public Property Get IconHandle() As LongPtr
IconHandle = m_hIcon
End Property
#Else
Public Property Let IconHandle(ByVal lngHandle As Long)
m_hIcon = lngHandle
End Property
Public Property Get IconHandle() As Long
IconHandle = m_hIcon
End Property
#End If
Public Property Get IconLeft() As Single
IconLeft = m_sngIconLeft
End Property
Public Property Let IconLeft(ByVal sngIconLeft As Single)
m_sngIconLeft = sngIconLeft
End Property
Public Property Get IconTop() As Single
IconTop = m_sngIconTop
End Property
Public Property Let IconTop(ByVal sngIconTop As Single)
m_sngIconTop = sngIconTop
End Property
Public Property Get IconWidth() As Single
IconWidth = m_sngIconWidth
End Property
Public Property Let IconWidth(ByVal sngIconWidth As Single)
m_sngIconWidth = sngIconWidth
End Property
Public Property Get IconHeight() As Single
IconHeight = m_sngIconHeight
End Property
Public Property Let IconHeight(ByVal sngIconHeight As Single)
m_sngIconHeight = sngIconHeight
End Property
Public Property Get AutoResize() As Boolean
AutoResize = m_bAutoResize
End Property
Public Property Let AutoResize(ByVal bAutoResize As Boolean)
m_bAutoResize = bAutoResize
End Property
This is a simple code to test. Add this to a standard code module:
Option Explicit
Private m_toolTip As ToolTip
Sub TestToolTip()
Set m_toolTip = New ToolTip
With m_toolTip
.AutoResize = True
.OffsetFromCursor 30, 0
.PositionByMouse
.Message = .Left & ", " & .Top & vbNewLine & "These are the mouse coordinates!"
End With
End Sub
Sub TestToolTip2()
If m_toolTip Is Nothing Then TestToolTip
m_toolTip.Message = Join(Split("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", ". "), "." & vbNewLine)
End Sub
Sub TerminateTooltip()
Set m_toolTip = Nothing
End Sub
When you run one of the two test procedures a tooltip will appear. When you run the terminate procedure the tooltip will dissapear.
You can of course have a control mouse move event on a userform or on a chart or maybe a timer that makes the tooltip move around and update all the time but I am sure you will be able to adapt it.
The code I wrote does not use the control you were trying to use in your question but rather builds everything from scratch. Regardless, I hope this is helpful.