You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB6中用Win32 API创建工具栏:解决按钮文本重复问题

解决VB6中Win32 API工具栏按钮文本重复问题

问题原因

出现第二个按钮文本重复的核心原因有两个:

  • TBBUTTON结构体定义错误:如果结构体的成员顺序、大小与Win32官方定义不符,会导致传递给TB_ADDBUTTONSA的参数错位,使得iString(文本索引)未被正确设置。
  • 字符串传递方式错误:直接传递字符串字面量给TB_ADDSTRINGA时,VB6会将字符串临时分配在栈上,SendMessage返回后栈内存被回收,工具栏控件后续读取时会获取到无效内容,导致文本索引指向错误。

修正后的代码

首先确保结构体定义正确,然后调整字符串传递和索引获取逻辑:

'Form1
Option Explicit

' 严格按照Win32 API定义TBBUTTON结构体
Private Type TBBUTTON
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(1) As Byte ' 保留字节,占2个Byte
    dwData As Long
    iString As Long
End Type

Private Type TBADDBITMAP
    hInst As Long
    nID As Long
End Type

Private hWndTb As Long
Private tbb As TBBUTTON
Private tbab As TBADDBITMAP

Private Const WS_EX_CLIENTEDGE As Long = &H200&
Private Const WS_CHILD As Long = &H40000000
Private Const WS_VISIBLE As Long = &H10000000
Private Const TBSTYLE_TOOLTIPS As Long = &H80
Private Const TBSTYLE_BUTTON As Long = &H0
Private Const TBSTATE_ENABLED As Long = &H4
Private Const HINST_COMMCTRL As Long = (-1)
Private Const IDB_STD_SMALL_COLOR As Long = &H1

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 SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Const TB_BUTTONSTRUCTSIZE As Long = &H402
Private Const TB_ADDBITMAP As Long = &H407
Private Const TB_ADDSTRINGA As Long = &H403
Private Const TB_ADDBUTTONSA As Long = &H408
Private Const TB_AUTOSIZE As Long = &H410

Private Sub Form_Load()
    Dim strText1 As String, strText2 As String
    Dim txtIdx1 As Long, txtIdx2 As Long
    
    Show
    
    ' 创建工具栏窗口
    hWndTb = CreateWindowEx(WS_EX_CLIENTEDGE, "ToolbarWindow32", "", WS_CHILD Or WS_VISIBLE Or TBSTYLE_TOOLTIPS, 0, 0, 100, 100, Me.hwnd, 1001, App.hInstance, ByVal 0&)
    ' 设置按钮结构体大小(必须与定义的TBBUTTON大小一致)
    SendMessage hWndTb, TB_BUTTONSTRUCTSIZE, Len(tbb), 0
    
    ' 添加标准小图标位图
    tbab.hInst = HINST_COMMCTRL
    tbab.nID = IDB_STD_SMALL_COLOR
    SendMessage hWndTb, TB_ADDBITMAP, 0, ByVal VarPtr(tbab)
    
    ' 准备NULL结尾的ANSI字符串,使用变量确保内存有效
    strText1 = "Text1" & vbNullChar
    strText2 = "Text2" & vbNullChar
    
    ' 添加字符串并获取返回的索引(避免手动设置索引出错)
    txtIdx1 = SendMessage(hWndTb, TB_ADDSTRINGA, 0, ByVal StrPtr(strText1))
    txtIdx2 = SendMessage(hWndTb, TB_ADDSTRINGA, 0, ByVal StrPtr(strText2))
    
    ' 添加第一个按钮
    With tbb
        .iBitmap = 0
        .idCommand = 101
        .fsState = TBSTATE_ENABLED
        .fsStyle = TBSTYLE_BUTTON
        .iString = txtIdx1
        .dwData = 0
    End With
    SendMessage hWndTb, TB_ADDBUTTONSA, 1, ByVal VarPtr(tbb)
    
    ' 添加第二个按钮
    With tbb
        .iBitmap = 1
        .idCommand = 102
        .fsState = TBSTATE_ENABLED
        .fsStyle = TBSTYLE_BUTTON
        .iString = txtIdx2
        .dwData = 0
    End With
    SendMessage hWndTb, TB_ADDBUTTONSA, 1, ByVal VarPtr(tbb)
    
    Form_Resize
End Sub

Private Sub Form_Resize()
    SendMessage hWndTb, TB_AUTOSIZE, 0, 0
End Sub

关键修正点

  • 结构体定义:严格对齐Win32的TBBUTTON结构,包含bReserved保留字节,确保成员顺序和大小正确,避免参数传递错位。
  • 字符串传递:使用字符串变量并追加vbNullChar生成标准NULL结尾的ANSI字符串,通过StrPtr传递字符串地址,保证内存有效性。
  • 索引获取:捕获TB_ADDSTRINGA的返回值作为文本索引,而非手动硬编码0/1,确保索引与实际添加的字符串一一对应。

内容的提问来源于stack exchange,提问作者Carlos Domingo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 04:11:03