UNICODE tooltips won't work

Windows specific questions.
jdhatpha
Posts: 9
Joined: Jan 26, 2011 18:54

UNICODE tooltips won't work

Postby jdhatpha » Jan 09, 2016 1:35

This is driving me must, why can't I get ToolTip(s) to show when UNICODE is defined (comment out the UNICODE definition and it works)?

Code:

Code: Select all

' Tried compiling using:
'  fbc -s gui TTtest.bas
'  fbc -gen gcc -s gui TTtest.bas
' Both fail when UNICODE is defined!
'
#Define UNICODE   ' if commented out ToolTip(s) works, remove comment and no more ToolTip(s)!
'
#Include "windows.bi"
#Include "win/commctrl.bi"
'
Dim As MSG                   _msg
Dim As WNDCLASSEX          wc
Dim As HWND                mainwdw
Dim Shared As HINSTANCE      Hinst
#Ifdef UNICODE
   Dim As WString*8         NameClass => "MyClass"
   Dim As WString*13         NameWin => "Main Window"
#Else
   Dim As String             NameClass="MyClass", _
                           NameWin="Main Window"
#EndIf
'
Function wndproc(   ByVal _hwnd As HWND, _
                  ByVal _msg As Uinteger, _
                  ByVal _wparam As WPARAM, _
                  ByVal _lparam As LPARAM) As Integer
'
   Dim As HWND         tooltipicon, tooltip, but
   Dim As TOOLINFO   Tool
#Ifdef UNICODE
   Dim As WString*12   tmp1 => "Test TTtest"
   Dim As WString*15   tmp2 => "It is a button"
   Dim As WString*7   tmp3 => "Button", _
                     tmp4 => "Simple"
#Else
   Dim As String      tmp1="Test TTtest", _
                     tmp2="It is a button", _
                     tmp3="Button", _
                     tmp4="Simple"
#EndIf
'
   Select Case _msg
      Case WM_CREATE
#Ifdef UNICODE
         but      = CreateWindowEx(0, _
                                    @tmp3, _
                                    @tmp4, _
                                    WS_VISIBLE Or WS_CHILD, _
                                    10, _
                                    10, _
                                    50, _
                                    20, _
                                    _hwnd, _
                                    Cast(HMENU,1), _
                                    0, _
                                    0)
         tooltip   = CreateWindowEx(WS_EX_TOPMOST, _
                                    @TOOLTIPS_CLASS, _
                                    NULL, _
                                    TTS_ALWAYSTIP Or TTS_NOPREFIX, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    _hwnd, _
                                    0, _
                                    0, _
                                    0)
         tooltipicon   = CreateWindowEx(WS_EX_TOPMOST, _
                                    @TOOLTIPS_CLASS, _
                                    NULL, _
                                    TTS_ALWAYSTIP Or TTS_BALLOON, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    _hwnd, _
                                    0, _
                                    0, _
                                    0)
#Else
         but      = CreateWindowEx(   0, _
                                    StrPtr(tmp3), _
                                    StrPtr(tmp4), _
                                    WS_VISIBLE Or WS_CHILD, _
                                    10, _
                                    10, _
                                    50, _
                                    20, _
                                    _hwnd, _
                                    Cast(HMENU,1), _
                                    0, _
                                    0)
         tooltip   = CreateWindowEx(   WS_EX_TOPMOST, _
                                    StrPtr(TOOLTIPS_CLASS), _
                                    NULL, _
                                    TTS_ALWAYSTIP Or TTS_NOPREFIX, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    _hwnd, _
                                    0, _
                                    0, _
                                    0)
         tooltipicon   = CreateWindowEx(WS_EX_TOPMOST, _
                                    StrPtr(TOOLTIPS_CLASS), _
                                    NULL, _
                                    TTS_ALWAYSTIP Or TTS_BALLOON, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    CW_USEDEFAULT, _
                                    _hwnd, _
                                    0, _
                                    0, _
                                    0)
#EndIf
#Ifdef UNICODE
         Tool.cbSize = SizeOf(TTTOOLINFOW_V2_SIZE)   ' tried this but no luck!
'         Tool.cbSize = SizeOf(TOOLINFO)            ' still no luck!
#Else
         Tool.cbSize = SizeOf(TTTOOLINFOA_V2_SIZE)   ' This works!
'         Tool.cbSize = SizeOf(TOOLINFO)            ' No luck using this!
#EndIf
         Tool.uFlags=TTF_TRACK Or TTF_ABSOLUTE
         Tool.hInst=Hinst
         Tool.uID=cast(UINT_PTR,_hwnd)
#Ifdef UNICODE
         Tool.lpszText=Cast(LPWSTR,@tmp1)
#Else
         Tool.lpszText=Cast(LPTSTR,Strptr(tmp1))
#EndIf
         SendMessage(tooltip,TTM_ADDTOOL,0,Cast(LPARAM,@Tool))
         SendMessage(tooltip,TTM_TRACKACTIVATE,Cast(WPARAM,TRUE),Cast(LPARAM,@Tool))

         Tool.uFlags=TTF_IDISHWND Or TTF_SUBCLASS
         Tool.uID=Cast(UINT_PTR,but)   
#Ifdef UNICODE
         Tool.lpszText=Cast(LPWSTR,@tmp2)
#Else
         Tool.lpszText=Cast(LPTSTR,Strptr(tmp2))
#EndIf
         SendMessage(tooltipicon,TTM_ADDTOOL,0,Cast(LPARAM,@Tool))
'
      Case WM_DESTROY
         PostQuitMessage(0)
   End Select
   Return DefWindowProc(_hwnd, _msg, _wparam, _lparam)
End Function
'
Hinst = GetModuleHandle(0)
With wc
   .cbSize=SizeOf(WNDCLASSEX)
   .style=CS_HREDRAW Or CS_VREDRAW
   .lpfnWndProc=Cast(WNDPROC,@wndproc)
   .hInstance=Hinst
   .hIcon=LoadIcon(0,IDI_QUESTION)
   .hCursor=LoadCursor(0,IDC_ARROW)
   .hbrBackground=Cast(HBRUSH,COLOR_WINDOW)
#Ifdef UNICODE
   .lpszClassName=@NameClass
#Else
   .lpszClassName=StrPtr(NameClass)
#EndIf
   .hIconSm=.hIcon
End With
'
If RegisterClassEx(@wc)=0 Then
   Print "Register error, press any key"
   Sleep
   End
Endif
'
#Ifdef UNICODE
   mainwdw = CreateWindowEx(   0, _
                              @NameClass, _
                              @NameWin, _
                              WS_OVERLAPPEDWINDOW, _
                              10, _
                              10, _
                              50, _
                              80, _
                              0, _
                              0, _
                              Hinst, _
                              0)
#Else
   mainwdw = CreateWindowEx(   0, _
                              StrPtr(NameClass), _
                              StrPtr(NameWin), _
                              WS_OVERLAPPEDWINDOW, _
                              10, _
                              10, _
                              50, _
                              80, _
                              0, _
                              0, _
                              Hinst, _
                              0)
#EndIf
ShowWindow(mainwdw, SW_SHOW)
UpdateWindow(mainwdw)
'
While GetMessage(@_msg, 0, 0, 0)
   TranslateMessage(@_msg)
   DispatchMessage(@_msg)
Wend


I'm using "FreeBASIC Compiler - Version 1.05.0 (12-19-2015), built for win64 (64bit)" on Windows 7 (64-bit). Please tell me what I'm doing wrong!

Thanks, JDH
albert
Posts: 5916
Joined: Sep 28, 2006 2:41
Location: California, USA

Re: UNICODE tooltips won't work

Postby albert » Jan 10, 2016 20:51

Try these two bas files

Dialogs.bas

Code: Select all


'Dialogs.bas
'====================================================================
'' Version 0.4
''
''  Removed option explicit.
''
''  In the Control procedure changed "class" to "_class".
''
''  Added a ByRef to "lpdt as LPDLGTEMPLATE" and to all string
''  parameters, and added the ByVal that was missing on some of
''  the parameters of other types.
''
''  Should now work for 0.15b, 0.16b, and 0.17b up through the
''  CVS build from February 21, 2007.
''
'' Version 0.3
''
''  First release.
''
'====================================================================

'====================================================================
'' This module contains procedures and definitions to support the
'' creation of a dialog box template in allocated memory, and the
'' creation of a modal or modeless dialog from the template.
''
'' The dialog box template consists of a DLGTEMPLATE structure
'' followed by three or four variable-length arrays, followed by
'' zero or more DLGITEMTEMPLATE structures each followed by three
'' variable-length arrays. The DLGTEMPLATE structure and the
'' associated arrays define the dialog window. The DLGITEMTEMPLATE
'' structures and the associated arrays define the controls in the
'' dialog.
''
'' The variable-length arrays consist of WORD (16-bit) elements.
'' The first three arrays following the DLGTEMPLATE structure
'' specify the menu, class, and title for the dialog. The three
'' arrays following each DLGITEMTEMPLATE structure specify the
'' class, title, and creation data for the control. Each of these
'' arrays will have at least one element, and the system will
'' interpret the contents of the array based on the value of the
'' first element. For the dialog menu, class, and title arrays,
'' and the control creation data array, if the first element is
'' zero, then the array is effectively empty and there are no
'' other elements. For the dialog menu and class arrays, and the
'' control class and title arrays, if the first element is FFFFh,
'' then the second element contains the ordinal value of a
'' resource or a predefined class, and the array contains no other
'' elements. For the dialog menu, class, and title arrays, and the
'' control class and title arrays, if the first element is any
'' value other than zero or FFFFh, then the array is assumed to be
'' a null-terminated Unicode string. Depending on the array, this
'' Unicode string can specify the name of a menu resource, a
'' registered class, the dialog title, or the initial text for a
'' control. For the control creation data array, if the first
'' element is non-zero, then it contains the length, in bytes, of
'' the creation data that follows. The fourth array following the
'' DLGTEMPLATE structure, which is present only when the dialog
'' style includes DS_SETFONT, specifies the font point size value
'' in the first element, followed by the name of the typeface as
'' a null-terminated Unicode string.
''
'' This implementation does not permit a menu or class specification
'' for the dialog, or creation data for the controls.
''
'' The DLGTEMPLATE and DLGITEMTEMPLATE structures must be aligned
'' on a DWORD boundary. The variable-length arrays that follow the
'' structures must start on a WORD boundary, but with WORD-size
'' elements and the structure sizes and alignment requirements,
'' this should be automatic.
''
'' Prior to creating a dialog template your source must declare,
'' for each dialog, a pointer to a DLGTEMPLATE structure:
''
'' dim as LPDLGTEMPLATE lpdt
''
'' This pointer is used to store the starting address of the
'' template memory.
'====================================================================
#include "windows.bi"
#include "win\richedit.bi"
#include "win\commctrl.bi"
#include "win\commdlg.bi"

'' This shared integer is used to implement automatic horizontal
'' centering of a control in a dialog.
''
dim shared as integer g_dialog_width

'' This shared pointer to a WORD is used by the Dialog and
'' control definition procedures to store the current address
'' in the template memory, and by the CreateModalDialog and
'' CreateModelessDialog procedures to resize the memory block
'' before the dialog is created. It is shared as a convenience,
'' because doing so eliminates one parameter from each of the
'' procedures.
''
dim shared as LPWORD g_lpw

'' Because of these shared variables dialog definitions cannot
'' be interleaved.

'====================================================================

'' This procedure generates a Unicode string starting at the
'' address specified by g_lpw, and then adds the length, in
'' wide characters, of the string and null terminator to g_lpw.
'' For compatibility with 95/98/Me, the MuliByteToWideChar
'' function is used to generate the strings.
''
sub GenUstring( byref asciiString as string )

  '' If asciiString is null, skip the first element of
  '' the array, leaving it set to zero (no string).
  ''
  if asciiString = "" then
    g_lpw += 1
  else
    '' CP_ACP specifies that the function should use
    '' the current system ANSI code page to perform
    '' the conversion to Unicode.
    ''
    g_lpw += MultiByteToWideChar( CP_ACP, _
                                  MB_PRECOMPOSED , _
                                  0 , _
                                  -1, _
                                  cast(LPWSTR,g_lpw), _
                                  len(asciiString) + 2 )
  end if

end sub

'====================================================================

'' This function creates a modal dialog from the dialog box
'' template pointed to by lpdt. Parameter hParent should be
'' zero if the dialog is the main window of the application.
'' Parameter dwInitParam specifies a value that is passed to
'' the dialog box procedure in the lParam parameter of the
'' WM_INITDIALOG message.
''
'' The DialogBoxIndirectParam function does not return until
'' the dialog box is destroyed with the EndDialog function.
'' After freeing the allocated memory, this function returns
'' whatever was specified in the nResult parameter of the
'' EndDialog function.
''
function CreateModalDialog( byval hParent as HWND, _
                            byval lpDialogProc as DLGPROC, _
                            byval dwInitParam as LPARAM, _
                            byval lpdt as LPDLGTEMPLATE ) as integer

  dim as integer rval

  '' Resize the memory block to fit the template.
  ''
  GlobalReAlloc( lpdt,cast(integer,g_lpw) - cast(integer,lpdt),0 )

  rval = DialogBoxIndirectParam( GetModuleHandle(null), _
                                 lpdt, _
                                 hParent, _
                                 lpDialogProc, _
                                 dwInitParam )
  GlobalFree( lpdt )

  return rval

end function


'====================================================================

'' This function creates a modeless dialog from the dialog box
'' template pointed to by lpdt. Parameter hParent should be
'' zero if the dialog is the main window of the application.
'' Parameter lParamInit specifies a value that is passed to
'' the dialog box procedure in the lParam parameter of the
'' WM_INITDIALOG message.
''
'' After freeing the allocated memory, this function returns
'' whatever the CreateDialogIndirectParam function returned,
'' which would normally be the handle to the dialog window.
''
'' Note that the WS_VISIBLE style is required for a modeless
'' dialog to be visible.
''
function CreateModelessDialog( byval hParent as HWND, _
                               byval lpDialogProc as DLGPROC, _
                               byval lParamInit as LPARAM, _
                               byval lpdt as LPDLGTEMPLATE ) as HWND

  dim as HWND rval

  '' Resize the memory block to fit the template.
  ''
  GlobalReAlloc( lpdt,cast(integer,g_lpw) - cast(integer,lpdt),0 )

  rval = CreateDialogIndirectParam( GetModuleHandle(null), _
                                    lpdt, _
                                    hParent, _
                                    lpDialogProc, _
                                    lParamInit )
  GlobalFree( lpdt )

  return rval

end function

'====================================================================

'' This procedure allocates memory for a dialog template and
'' initializes the essential members of the DLGTEMPLATE structure,
'' the menu, class, and title arrays, and optionally the font
'' point size and typeface array. Returns a pointer to the next
'' WORD following the title or typeface array in g_lpw, and a
'' pointer to the allocated memory in lpdt.
''
'' The initial allocation size, 10KB, should be sufficient even
'' for a large and complex dialog. In the unlikely event that
'' the allocation is not sufficient, the likely result will be a
'' memory access violation at run time. For troubleshooting this
'' problem, the number of bytes of template memory used, at any
'' point in the creation of the template, can be displayed with
'' a statement like this:
''
'' MessageBox( 0, str(cint(g_lpw) - cint(lpdt)), "Bytes Used", 0 )
''
'' The CreateModalDialog and CreateModelessDialog functions resize
'' the memory block to fit the template, freeing any excess.
''
'' Parameter cdit must match the number of controls defined.
'' If the value is too high then the function that creates the
'' dialog will fail. If the value is too low then one or more
'' of the controls will not be created.
''
sub Dialog( byval cdit as WORD, _
            byval x as short, _
            byval y as short, _
            byval cx as short, _
            byval cy as short, _
            byref title as string, _
            byref lpdt as LPDLGTEMPLATE, _
            byval style as DWORD, _
            byval pointSize as short = 0, _
            byref typeFace as string = "" )

  g_dialog_width = cx

  lpdt = GlobalAlloc( GMEM_FIXED or GMEM_ZEROINIT, 1024 * 10 )

  '' Memory allocated by GlobalAlloc is guaranteed to be
  '' aligned on an 8-byte boundary. Initialize the essential
  '' members of the structure.
  ''
  lpdt->style = style
  lpdt->cdit = cdit
  lpdt->x  = x
  lpdt->y  = y
  lpdt->cx = cx
  lpdt->cy = cy

  '' Set g_lpw to the menu array that follows the structure.
  ''
  g_lpw = cast(LPWORD,lpdt + 1)

  '' Skip the first element of the menu array, leaving it
  '' set to zero (no menu).
  ''
  g_lpw += 1

  '' Skip the first element of the class array, leaving it
  '' set to zero (no class), so the system will use the
  '' predefined dialog box class.
  ''
  g_lpw += 1

  '' Initialize the title array and set g_lpw to next WORD
  '' following the title array.
  ''
  GenUstring( title )

  '' If the DS_SETFONT style was specified, set the font
  '' point size, initialize the typeface array, and set
  '' g_lpw to next WORD following the typeface array.
  ''
  if style and DS_SETFONT then
    *g_lpw = pointSize
    g_lpw += 1
    GenUstring( typeFace )
  end if

end sub

'====================================================================

'' Starting at the address specified by g_lpw, this general-purpose
'' control definition procedure initializes the essential members
'' of a DLGITEMTEMPLATE structure and the class, title and creation
'' data arrays.
''
'' For the class array, for the six predefined system (User32)
'' classes, use the strings "BUTTON", "EDIT", "STATIC", "LISTBOX",
'' "SCROLLBAR", and "COMBOBOX". For common controls use the class
'' strings defined in commctrl.bi.
''
'' The title array can specify the caption or initial text for the
'' control, or the ordinal value of a resource in the executable
'' file. Specify a caption or initial text in the title parameter,
'' or an ordinal value in the rid (ResourceID) parameter. If the
'' rid parameter is non-zero then the title parameter is ignored.
''
'' There is no support for creation data.
''
'' * FOR WINDOWS 95/98/ME, ONLY THE LOW-ORDER BYTE OF THE CONTROL
'' ID (parameter cid) IS USED, SO THE MAXIMUM VALUE IS 255 *
''
'' The tab order of the controls in a dialog is determined by the
'' order in which the controls are created, and by which controls
'' have the WS_TABSTOP style.
''
'' To center the control in the dialog horizontally specify -1
'' for the x parameter. This feature will not work correctly for
'' an auto-sized control where the width is not specified.
''
sub Control( byval cid as WORD, _
             byval x as short, _
             byval y as short, _
             byval cx as short, _
             byval cy as short, _
             byref title as string, _
             byval rid as short, _
             byref _class as string, _
             byval style as DWORD = 0 )

  if x = -1 then x = (g_dialog_width - cx) / 2

  dim as LPDLGITEMTEMPLATE lpdit
  dim as ULONGint ul

  '' The DLGITEMTEMPLATE structure must be aligned on a
  '' DWORD boundary.
  ''
  ul = cast(ULONGint,g_lpw) + 3
  ul shr= 2
  ul shl= 2
  g_lpw = cast(LPWORD,ul)

  '' Initialize the essential members of the structure.
  ''
  '' The establishes the base style as WS_CHILD or WS_VISIBLE.
  ''
  lpdit = cast(LPDLGITEMTEMPLATE,g_lpw)
  lpdit->style = WS_CHILD or WS_VISIBLE or style
  lpdit->x  = x
  lpdit->y  = y
  lpdit->cx = cx
  lpdit->cy = cy
  lpdit->id = cid

  '' Set g_lpw to the class array that follows the structure.
  ''
  g_lpw = cast(LPWORD,lpdit + 1)

  '' Initialize the class array and set g_lpw to the next WORD
  '' following the class array.
  ''
  GenUstring( _class )


  '' Initialize the title array and set g_lpw to the next WORD
  '' following the title array.
  ''
  if rid then
    *g_lpw = &hffff
    g_lpw += 1
    *g_lpw = rid
    g_lpw += 1
  else
    GenUstring( title )
  end if

  '' Skip the first element of the creation data array, leaving
  '' it set to zero (no creation data).
  ''
  g_lpw += 1

end sub

'====================================================================
'' The following specialized control definition procedures are
'' simply wrappers for the general-purpose procedure.
'====================================================================

sub PushButton( byval cid as WORD, _
                byval x as short, _
                byval y as short, _
                byval cx as short, _
                byval cy as short, _
                byref caption as string, _
                byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, caption, 0, "BUTTON", _
           BS_PUSHBUTTON or style )
end sub

'====================================================================

sub DefPushButton( byval cid as WORD, _
                   byval x as short, _
                   byval y as short, _
                   byval cx as short, _
                   byval cy as short, _
                   byref caption as string, _
                   byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, caption, 0, "BUTTON", _
           BS_DEFPUSHBUTTON or style )
end sub

'====================================================================

sub AutoCheckBox( byval cid as WORD, _
                  byval x as short, _
                  byval y as short, _
                  byval cx as short, _
                  byval cy as short, _
                  byref caption as string, _
                  byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, caption, 0, "BUTTON", _
           BS_AUTOCHECKBOX or style )
end sub

'====================================================================

sub AutoRadioButton( byval cid as WORD, _
                     byval x as short, _
                     byval y as short, _
                     byval cx as short, _
                     byval cy as short, _
                     byref caption as string, _
                     byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, caption, 0, "BUTTON", _
           BS_AUTORADIOBUTTON or style )
end sub

'====================================================================

sub GroupBox( byval cid as WORD, _
              byval x as short, _
              byval y as short, _
              byval cx as short, _
              byval cy as short, _
              byref caption as string, _
              byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, caption, 0, "BUTTON", _
           BS_GROUPBOX or style )
end sub

'====================================================================

sub EditText( byval cid as WORD, _
              byval x as short, _
              byval y as short, _
              byval cx as short, _
              byval cy as short, _
              byref text as string, _
              byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, text, 0, "EDIT", _
           style )
end sub

'====================================================================

sub LText( byval cid as WORD, _
           byval x as short, _
           byval y as short, _
           byval cx as short, _
           byval cy as short, _
           byref text as string, _
           byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, text, 0, "STATIC", _
           SS_LEFT or style )
end sub

'====================================================================

sub RText( byval cid as WORD, _
           byval x as short, _
           byval y as short, _
           byval cx as short, _
           byval cy as short, _
           byref text as string, _
           byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, text, 0, "STATIC", _
           SS_RIGHT or style )
end sub

'====================================================================

sub CText( byval cid as WORD, _
           byval x as short, _
           byval y as short, _
           byval cx as short, _
           byval cy as short, _
           byref text as string, _
           byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, text, 0, "STATIC", _
           SS_CENTER or style )
end sub

'====================================================================

sub ListBox( byval cid as WORD, _
             byval x as short, _
             byval y as short, _
             byval cx as short, _
             byval cy as short, _
             byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, "", 0, "LISTBOX", _
           style )
end sub

'====================================================================

sub ComboBox( byval cid as WORD, _
              byval x as short, _
              byval y as short, _
              byval cx as short, _
              byval cy as short, _
              byval style as DWORD = 0 )

    Control( cid, x, y, cx, cy, "", 0, "COMBOBOX", _
             style )
end sub

'====================================================================

sub ScrollBar( byval cid as WORD, _
               byval x as short, _
               byval y as short, _
               byval cx as short, _
               byval cy as short, _
               byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, "", 0, "SCROLLBAR", _
           style )
end sub

'====================================================================
'' To use a Rich Edit control your app must first call LoadLibrary
'' to load the appropriate DLL - RICHED20.DLL for version 2 or 3,
'' or RICHED32.DLL for version 1.
'====================================================================

'' This procedure is coded for version 2 or 3.
''
sub RichEdit( byval cid as WORD, _
              byval x as short, _
              byval y as short, _
              byval cx as short, _
              byval cy as short, _
              byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, "", 0, RICHEDIT_CLASS, _
           style )
end sub

'' This procedure is coded for version 1.
''
sub RichEdit1( byval cid as WORD, _
               byval x as short, _
               byval y as short, _
               byval cx as short, _
               byval cy as short, _
               byval style as DWORD = 0 )

  Control( cid, x, y, cx, cy, "", 0, RICHEDIT_CLASS10A, _
           style )
end sub

'====================================================================

'' To use controls from the common control DLL, specific common
'' control classes must first be initialized. This procedure
'' initializes 14 of the commonly used common control classes
'' in a single call.
''
'' This procedure uses the InitCommonControlsEx function, which
'' should work for all recent versions of Windows, but it may
'' be necessary to substitute the older InitCommonControls
'' function for Windows 95 or NT.
''
sub InitializeCommonControls

  dim as INITCOMMONCONTROLSEX icce

  icce.dwSize = sizeof( INITCOMMONCONTROLSEX )
  icce.dwICC = ICC_ANIMATE_CLASS _
            or ICC_BAR_CLASSES _
            or ICC_COOL_CLASSES _
            or ICC_DATE_CLASSES _
            or ICC_HOTKEY_CLASS _
            or ICC_INTERNET_CLASSES _
            or ICC_LISTVIEW_CLASSES _
            or ICC_PAGESCROLLER_CLASS _
            or ICC_PROGRESS_CLASS _
            or ICC_TAB_CLASSES _
            or ICC_TREEVIEW_CLASSES _
            or ICC_UPDOWN_CLASS _
            or ICC_USEREX_CLASSES _
            or ICC_WIN95_CLASSES

  InitCommonControlsEx( @icce )

end sub

'====================================================================
 


Tooltips.bas

Code: Select all


'Tooltip.bas


''=============================================================================
'' Tooltip demo, modal dialog as main.
''=============================================================================

#include once "C:\USB\MY-FB-PROGRAMS-023\Huh-Yuh\Dialogs.bas"
#include once "C:\USB\MY-FB-PROGRAMS-023\Huh-Yuh\Tooltip.bas"

#define IDC_EDIT 1000
#define IDC_BTN1 1001


''=============================================================================

function DialogProc( byval hwndDlg as  HWND, _
                     byval uMsg as UINT, _
                     byval wParam as WPARAM, _
                     byval lParam as LPARAM ) as integer

    static as HWND hwndEdit, hwndButton

    select case uMsg

        case WM_INITDIALOG

            hwndEdit = GetDlgItem( hwndDlg, IDC_EDIT )
            hwndButton = GetDlgItem( hwndDlg, IDC_BTN1 )

            CreateToolTip( hwndEdit, "Edit" )
            CreateToolTip( hwndButton, "Button" )
            CreateToolTip( hwndDlg, "Window" )

        case WM_COMMAND

            select case loword(wParam)
                case IDC_BTN1, IDCANCEL
                    EndDialog( hwndDlg, 0 )
            end select

        case WM_CLOSE

            EndDialog( hwndDlg, 0 )

    end select

    return 0

end function

''=============================================================================

dim as LPDLGTEMPLATE lpdt

Dialog( 2, 0, 0, 200, 125, "Tooltip Demo", lpdt, _
        WS_OVERLAPPED or WS_SYSMENU or DS_CENTER  )

#define EDIT_STYLE WS_BORDER or WS_VSCROLL or WS_HSCROLL or ES_MULTILINE or _
              ES_AUTOVSCROLL or ES_AUTOHSCROLL or WS_TABSTOP or ES_WANTRETURN

EditText( IDC_EDIT, 5, 5, 187, 80, "", EDIT_STYLE )

PushButton( IDC_BTN1, 85, 95, 25, 10, "OK" )

CreateModalDialog( 0, @DialogProc, 0, lpdt )

''=============================================================================
 


In your main program include dialogs.bas and tooltips.bas
and include these

#define WIN_INCLUDEALL
#include "windows.bi"
#include "win\commdlg.bi"
#include "win\commctrl.bi"


Use CreateToolTip( control here , text here , 0 )
jdhatpha
Posts: 9
Joined: Jan 26, 2011 18:54

Re: UNICODE tooltips won't work

Postby jdhatpha » Jan 11, 2016 20:30

Thanks Albert,

Problem is that using your bas files shows the exact same issue. ToolTips work fine when compiled without "#Define UNICODE" but when defining UNICODE no ToolTip is shown, anywhere!

I did find one interesting thing and that is the ToolTips do work WITH UNICODE defined when using:
FreeBASIC Compiler - Version 1.01.0 (10-31-2014), built for win32 (32bit)
Copyright (C) 2004-2014 The FreeBASIC development team.
standalone

But it fails using FB 1.02 and up...

Oh and yes I forgot to say in my first post, but I do use a manifest, i.e. an rc file which specifies:

Code: Select all

#define MANIFEST 24
#define MY_MANIFEST 100

MY_MANIFEST MANIFEST "TTtest.xml"

and the xml file contains:

Code: Select all

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assemblyIdentity
        version="1.0.0.0"
        processorArchitecture="*"
        Name="TTtest.exe"
        Type="win32"
/>
<description>Application Description</description>
<dependency>
        <dependentAssembly>
                <assemblyIdentity
                        Type="win32"
                        Name="Microsoft.Windows.Common-Controls"
                        version="6.0.0.0"
                        processorArchitecture="*"
                        publicKeyToken="6595b64144ccf1df"
                        language="*"
                />
        </dependentAssembly>
</dependency>
</assembly>


Thanks
jdhatpha
Posts: 9
Joined: Jan 26, 2011 18:54

Re: UNICODE tooltips won't work

Postby jdhatpha » Jan 11, 2016 21:04

I though it was going to be a lot of working finding the reason why ToolTips in FBC 1.01 would work with UNICODE defined and fail in FBC 1.02 and up, but in the end it was a very easily found!

In FBC 1.01: SizeOf(TOOLINFOW) returns 44!
In FBC 1.02 and up SizeOf(TOOLINFOW) returns 48!

That 4 bytes too many, so setting "Tool.cbSize = SizeOf(TOOLINFOW) - 4" fixes this issue and ToolTips start working when using #Define UNICODE!

Now obviously SizeOf is working fine so most likely the TOOLINFOW struct is defined incorrectly! And indeed the TOOLINFO on msdn is defined as

Code: Select all

typedef struct {
  UINT      cbSize;
  UINT      uFlags;
  HWND      hwnd;
  UINT_PTR  uId;
  RECT      rect;
  HINSTANCE hinst;
  LPTSTR    lpszText;
#if (_WIN32_IE >= 0x0300)
  LPARAM    lParam;
#endif
#if (_WIN32_WINNT >= Ox0501)
  void      *lpReserved;
#endif
} TOOLINFO, *PTOOLINFO, *LPTOOLINFO;

win/commctrl.bi has:

Code: Select all

type tagTOOLINFOW
   cbSize as UINT
   uFlags as UINT
   hwnd as HWND
   uId as UINT_PTR
   rect as RECT
   hinst as HINSTANCE
   lpszText as LPWSTR
   lParam as LPARAM
   lpReserved as any ptr
end type

This is incorrect as per msdn for _WIN32_WINNT >= Ox0501 TOOLINFOW should be defined as:

Code: Select all

type tagTOOLINFOW
   cbSize as UINT
   uFlags as UINT
   hwnd as HWND
   uId as UINT_PTR
   rect as RECT
   hinst as HINSTANCE
   lpszText as LPWSTR
   lpReserved as any ptr
end type
AGS
Posts: 1284
Joined: Sep 25, 2007 0:26
Location: the Netherlands

Re: UNICODE tooltips won't work

Postby AGS » Jan 13, 2016 21:19

Great find. Have you posted a bug report?
St_W
Posts: 1508
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: UNICODE tooltips won't work

Postby St_W » Jan 14, 2016 23:27

jdhatpha wrote:This is incorrect as per msdn for _WIN32_WINNT >= Ox0501 TOOLINFOW should be defined as:[...]

So the "lParam" value should not be in the structure. I'm just wondering why / where you do have that information from - can you provide some link/reference? Because (_WIN32_IE >= 0x0300) should be true when (_WIN32_WINNT >= Ox0501) is true, shouldn't it?
albert
Posts: 5916
Joined: Sep 28, 2006 2:41
Location: California, USA

Re: UNICODE tooltips won't work

Postby albert » Jan 16, 2016 18:46

I'm having the same problem #define unicode and tooltips stop working..

But if you define unicode at the end of your include the tooltips work..
This is with tooltip.bas and dialogs.bas

Code: Select all


#define WIN_INCLUDEALL
#include once "windows.bi"
#include once "win\commdlg.bi"
#include once "win\commctrl.bi"

'set below to path of ToolTip.bas and Dialogs.bas
#include once "C:\USB\MY-FB-PROGRAMS-023\Huh-Yuh\Dialogs.bas"
#include once "C:\USB\MY-FB-PROGRAMS-023\Huh-Yuh\Tooltip.bas"

#define unicode   ' define unicode at end of includes... and tooltips work

dkl
Site Admin
Posts: 3212
Joined: Jul 28, 2005 14:45
Location: Germany

Re: UNICODE tooltips won't work

Postby dkl » Jan 16, 2016 22:02

Yea, it looks like a bug in win/commctrl.bi. I'm going to fix it (and also send a corresponding patch to MinGW-w64).

MSDN and the Windows SDK have #if checks to sometimes exclude lParam and lpReserved - MinGW-w64 and FB are missing those #ifs.
jdhatpha
Posts: 9
Joined: Jan 26, 2011 18:54

Re: UNICODE tooltips won't work

Postby jdhatpha » Jan 17, 2016 18:19

dkl: Thanks!

Albert: Hey never thought of doing that, great tip!

AGS: Yeah started to, but had to register get approval bla, bla, bla.. just gave up, stupid I know but real live interfered!

Part of what made live a bit harder is that I decided to install windows 10 on all the home PC's, ugh. But once it got everything working again ToolTips work fine when compiling with FB 1.05 and UNICODE defined. So I did fix my problem, but hint site being 20/20, that was certainly doing it the hard way!
jdhatpha
Posts: 9
Joined: Jan 26, 2011 18:54

Re: UNICODE tooltips won't work

Postby jdhatpha » Jan 18, 2016 22:26

St_W: You are right if you go by the TOOLINFO stuct as defined on msdn. The definition _WIN32_IE >= 0x0300 would be any IE version 3 or up, and with _WIN32_WINNT >= Ox0501 meaning Windows Server 2003 and up, so the TOOLINFO struct supposedly should looks like:
typedef struct {
UINT cbSize;
UINT uFlags;
HWND hwnd;
UINT_PTR uId;
RECT rect;
HINSTANCE hinst;
LPTSTR lpszText;
LPARAM lParam;
void *lpReserved;
} TOOLINFO
But with the above definition, the SizeOf(TOOLINFO) will return 44. And setting .cbSize=44 will prevent the ToolTips from working! Only when setting .cbSize=40 will the ToolTip work again! So obviously either Microsoft changed the TOOLINFO struct but forgot to change the size check, or the size check is correct but the TOOLINFO struct is defined wrong, take your pick!

Now keep in mind this is when using UNICODE, if you are NOT using UNICODE code then the .cbSize should be define to be 4, at least in Windows 7 and up, I have not tested it but I do believe in Windows XP .cbSize must be 40 again.
dkl
Site Admin
Posts: 3212
Joined: Jul 28, 2005 14:45
Location: Germany

Re: UNICODE tooltips won't work

Postby dkl » Jan 19, 2016 7:36

Hmm, so it's a problem on Windows XP (i.e. older versions) only? Maybe MSDN and the Windows SDK headers removed support for Windows XP... we should also check MinGW.org and Wine headers.
albert
Posts: 5916
Joined: Sep 28, 2006 2:41
Location: California, USA

Re: UNICODE tooltips won't work

Postby albert » Jan 19, 2016 18:08

I'm having the same problem , no tooltips
I'm running an AMD quad core processor with Windows 10 64 bit mode..with FB 1.04 64 bit..
Tooltips work under FB 0.23 but not under 1.03 or 1.04

Heres my tooltip code i think it was writen by D.JPeters or maybe MichaelW??

Code: Select all

''=============================================================================
'' This procedure creates a tooltip for the client area of a window, where the
'' window can be a control window, an application window, or a dialog window.
''
'' Based on a Microsoft example from the PSDK.
''=============================================================================

sub CreateToolTip( byval hwnd as HWND, byref text as Wstring , byref tthwnd as HWND )

    dim as INITCOMMONCONTROLSEX iccex
    dim as TOOLINFOW ti
    dim as HWND hwndTT

    ''-------------------------------------------
    '' This not necessary for Windows XP, but it
    '' may be for earlier versions of Windows.
    ''-------------------------------------------

    dim as HINSTANCE hInst = GetModuleHandle(NULL)

    ''------------------------------------------------
    '' Initialize the necessary common control class.
    ''------------------------------------------------

    iccex.dwICC = ICC_WIN95_CLASSES
    iccex.dwSize = sizeof(INITCOMMONCONTROLSEX)
    InitCommonControlsEx(@iccex)

    ''----------------------------
    '' Create the tooltip window.
    ''----------------------------

    hwndTT = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL, _
                            WS_POPUP or TTS_NOPREFIX or TTS_ALWAYSTIP, _
                            CW_USEDEFAULT, CW_USEDEFAULT, _
                            CW_USEDEFAULT, CW_USEDEFAULT, _
                            tthwnd, NULL, 0, NULL)

    ''------------------------------------------------------
    '' Position the window at the top of the Z order but do
    '' not move or size it, or change its activation status.
    ''
    '' This was not necessary in my tests, but there may be
    '' conditions where it is necessary.
    ''------------------------------------------------------

    SetWindowPos( hwndTT, _
                  HWND_TOPMOST, _
                  0, _
                  0, _
                  0, _
                  0, _
                  SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE )

    ''-------------------------------------------------------------
    '' Initialize the necessary members of the TOOLINFO structure.
    ''-------------------------------------------------------------

    ti.cbSize = sizeof(TOOLINFOW)
    ti.uFlags = TTF_SUBCLASS
    ti.hwnd = hwnd
    ti.hinst = NULL
    ti.lpszText = strptr(text)
    GetClientRect( hwnd, @ti.rect)

    ''------------------------------------------------------
    '' Register the tool (window) with the tooltip control.
    ''------------------------------------------------------

    SendMessage( hwndTT, TTM_ADDTOOL, 0 , cast(LPARAM, @ti) )

end sub



You call it with CreateTooltip( control here , text here , 0 )
St_W
Posts: 1508
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: UNICODE tooltips won't work

Postby St_W » Jan 20, 2016 13:37

Today I've tried your examples and I think the behavior is correct. Let me explain why:

The tooltip window class is implemented in the "Comctl32.dll", which comes with windows. There exist several versions of that DLL, the most common ones nowadays are probably version 5 and version 6.
As with the DLL there exist also several extensions of the TOOLINFO structure. Therefore the headers define the following sizes for different versions:
  • TTTOOLINFOA_V1_SIZE / TTTOOLINFOW_V1_SIZE (or TTTOOLINFO_V1_SIZE, which depends on the definition of UNICODE)
  • TTTOOLINFOA_V2_SIZE / TTTOOLINFOW_V2_SIZE
  • TTTOOLINFOA_V3_SIZE / TTTOOLINFOW_V3_SIZE
Of course, older versions of the DLL support only older versions of the TOOLINFO structure, so here is the compatibility information:
Comctl32.dll version 5: TOOLINFO V1 or V2
Comctl32.dll version 6: TOOLINFO V1 or V2 or V3

Popular versions of Windows (XP, 7, ...) come with both versions of Comctl32.dll, version 5 and version 6. The issue is: they default to version 5. You have to embed a "XP manifest" in your application and call InitCommonControls(Ex) to use version 6 of the Comctl32.dll.
see https://msdn.microsoft.com/en-us/librar ... 73175.aspx for more information

As your application does not have a XP manifest embedded (so: Comctrl32.dll version 5) and the headers default to the most current version of the TOOLINFO structure (V3) your tooltips don't work (don't ask me why they do work in non-unicode mode, though). To fix it you have two options:
  • set the cbSize to TTTOOLINFO_V1_SIZE or TTTOOLINFOA_V2_SIZE / TTTOOLINFOW_V2_SIZE or
  • embed an XP manifest in your application (recommended)

btw: In the code in the initial post you use sizeof(TTTOOLINFO_V1_SIZE), which does not make sense. Just use TTTOOLINFO_V1_SIZE (without sizeof())
dkl
Site Admin
Posts: 3212
Joined: Jul 28, 2005 14:45
Location: Germany

Re: UNICODE tooltips won't work

Postby dkl » Jan 21, 2016 17:44

Well, that makes sense. I had seen some similar information on the web but couldn't piece it together as nicely. (just google for "unicode tooltips windows" or "sizeof toolinfo" etc.)

And I checked the current MinGW.org headers too, there is no lpReserved field there (but there still is TTTOOLINFOW_V3_SIZE which references the lpReserved and thus would probably cause a compiler error).
http://sourceforge.net/p/mingw/mingw-or ... rl.h#l1377

Since FB's old Windows API headers were based on MinGW.org, and the new ones are based on the MinGW-w64 ones, they have the same difference.
jdhatpha
Posts: 9
Joined: Jan 26, 2011 18:54

Re: UNICODE tooltips won't work

Postby jdhatpha » Jan 22, 2016 17:31

On Jan 20, 2016 8:37 St_W wrote:
You have to embed a "XP manifest" in your application and call InitCommonControls(Ex)......
On Jan 11, 2016 15:30 jdhatpha wrote:
Oh and yes I forgot to say in my first post, but I do use a manifest....
So including a manifest and calling InitCommonControls did not fix it
On Jan 20, 2016 8:37 St_W wrote:
btw: In the code in the initial post you use sizeof(TTTOOLINFO_V1_SIZE), which does not make sense..
Correct that does not make sense, but correcting it does cause the ToolTips to show.

The Comctl ToolTip definition on msdn really don't make sense and FBC is more a victim than the causer, and unless FBC would be able to check for Windows version I don't see how this could be fixed. For me the easiest is to simply #undef the needed TOOLINFO header(s)/definition(s) and define my own based on the environment I'm compiling for. The hardest part was finding the proper value for the .cbSize parameter in each of these environments. Now that I have that figured out, ToolTips are working rather nicely!

Return to “Windows”

Who is online

Users browsing this forum: No registered users and 6 guests