Valhalla Legends Forums Archive | General Programming | ListBox inside StarCraft: how to add items to it?

AuthorMessageTime
LockesRabb
So far, this is the code I have (the form has one text area and one button, named as text1 and command1):

[code]---Form1.frm---

Private Sub Command1_Click()
    Dim BW As Long, TXT As Long, SM As Long, CHILD As Long, Stuff As String
    BW = FindWindow("SWarClass", "Brood War") 'Find hwnd of brood war window
    If (BW = 0) Then
        MsgBox "Window not found!"
        Exit Sub
    End If
    CHILD = FindWindow("SDlgDialog", vbNullString) 'find dialog of brood war window
    TXT = FindWindowEx(CHILD, 0, "ListBox", vbNullString) 'find hwnd of the textbox
    Stuff = Text1.text 'add the text to a string
    SendMessage TXT, WM_SETTEXT, 0, ByVal Stuff 'use settext to send the text string to the listbox on brood war
End Sub

---Module1.bas---

Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpszClassName As String, ByVal lpszWindow As String) As Long
Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long[/code]

The program isn't working though- nothing is added to the chat (listbox) of the StarCraft client. Any idea what I'm doing wrong? Thanks in advance for any assistance rendered.
February 12, 2006, 1:05 AM
UserLoser
Maybe you should use a Listbox message id instead of a text box window message id.  Try seeing LB_* messages and not WM_* messages... Setting the text of a listbox--what will that set? what text? nothing at all
February 12, 2006, 2:16 AM
LockesRabb
from what i can see using Winspector, there are the following:

LBS_HASSTRINGS
LBS_NOSEL
LBS_OWNERDRAWFIXED
LBS_OWNERDRAWVARIABLE
LBS_USETABSTOPS
LBS_WANTKEYBOARDINPUT
LBS_DISABLENOSCROLL
LBS_EXTENDEDSEL
LBS_MULTICOLUMN
LBS_MULTIPLESEL
LBS_NODATA
LBS_NOINTEGRALHEIGHT
LBS_NOREDRAW
LBS_NOTIFY
LBS_OWNERDRAWVARIABLE
LBS_SORT

Using winspector, I saw there were three listboxes (i only see two, which is the chat window and the channel list, so i'm guessing the third one is the friends list?). I had winspector disable/enable viewing for each listbox until i saw the chat disappeared. But I'm not sure as to how to have it target THAT listbox, seeing how there's three of them. Winspector says for that listbox: 003C0412: ListBox. I'm not sure what the numbers/letter mean-- I'm guessing that's the address for the listbox in hex? And how exactly do I add text to the chat listbox? If I sound like a newb, my apologies, I'm just trying my best to understand this. I'm fairly new to hooking/subclassing.

Thanks for your help!
February 12, 2006, 3:10 AM
Myndfyr
More likely that is the listbox window handle (HWND).
February 12, 2006, 6:21 AM
LockesRabb
I found the correct command to use to add items to an external listbox, I think. I'm not sure. In any case, I tried putting in the hex address, but that doesn't work. Also everytime i restart SC, the hex address for the chat listbox changes. So that route can't really be done.

I fixed the overflow error thanks to |2-shadow. However the program is far from working-- when I click command1, it sends nothing to the chat. Or to be more accurate, in the chat, the string that was supposed to be displayed wasn't displayed. The chat remained the same.

Here's new code:

form1.frm:
[code]Private Sub Command1_Click()
    Dim BW As Long, TXT As Long, SM As Long, CHILD As Long, Stuff As String
    BW = FindWindow("SWarClass", "Brood War") 'Find hwnd of brood war window
    If (BW = 0) Then
        MsgBox "Window not found!"
        Exit Sub
    End If
    CHILD = FindWindow("SDlgDialog", vbNullString) 'find dialog of brood war window
    TXT = FindWindowEx(CHILD, 0, "ListBox", vbNullString)    'find hwnd of the first listbox then skip
    Stuff = "TEXT YOU WANT TO SEND" 'add the text to a string
    'Send the text string to the chat listbox on brood war
    SendDlgItemMessage TXT, IDC_LIST, LB_ADDSTRING, 0, ByVal Stuff
End Sub[/code]

module1.bas:
[code]Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpszClassName As String, ByVal lpszWindow As String) As Long
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function SendDlgItemMessage Lib "user32" Alias "SendDlgItemMessageA" (ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Any) As Long

' Listbox Notification Codes
Public Const LBN_ERRSPACE = (-2)
Public Const LBN_SELCHANGE = 1
Public Const LBN_DBLCLK = 2
Public Const LBN_SELCANCEL = 3
Public Const LBN_SETFOCUS = 4
Public Const LBN_KILLFOCUS = 5

' Listbox messages
Public Const LB_ADDSTRING = &H180
Public Const LB_INSERTSTRING = &H181
Public Const LB_DELETESTRING = &H182
Public Const LB_SELITEMRANGEEX = &H183
Public Const LB_RESETCONTENT = &H184
Public Const LB_SETSEL = &H185
Public Const LB_SETCURSEL = &H186
Public Const LB_GETSEL = &H187
Public Const LB_GETCURSEL = &H188
Public Const LB_GETTEXT = &H189
Public Const LB_GETTEXTLEN = &H18A
Public Const LB_GETCOUNT = &H18B
Public Const LB_SELECTSTRING = &H18C
Public Const LB_DIR = &H18D
Public Const LB_GETTOPINDEX = &H18E
Public Const LB_FINDSTRING = &H18F
Public Const LB_GETSELCOUNT = &H190
Public Const LB_GETSELITEMS = &H191
Public Const LB_SETTABSTOPS = &H192
Public Const LB_GETHORIZONTALEXTENT = &H193
Public Const LB_SETHORIZONTALEXTENT = &H194
Public Const LB_SETCOLUMNWIDTH = &H195
Public Const LB_ADDFILE = &H196
Public Const LB_SETTOPINDEX = &H197
Public Const LB_GETITEMRECT = &H198
Public Const LB_GETITEMDATA = &H199
Public Const LB_SETITEMDATA = &H19A
Public Const LB_SELITEMRANGE = &H19B
Public Const LB_SETANCHORINDEX = &H19C
Public Const LB_GETANCHORINDEX = &H19D
Public Const LB_SETCARETINDEX = &H19E
Public Const LB_GETCARETINDEX = &H19F
Public Const LB_SETITEMHEIGHT = &H1A0
Public Const LB_GETITEMHEIGHT = &H1A1
Public Const LB_FINDSTRINGEXACT = &H1A2
Public Const LB_SETLOCALE = &H1A5
Public Const LB_GETLOCALE = &H1A6
Public Const LB_SETCOUNT = &H1A7
Public Const LB_MSGMAX = &H1A8

' Listbox Styles
Public Const LBS_NOTIFY = &H1&
Public Const LBS_SORT = &H2&
Public Const LBS_NOREDRAW = &H4&
Public Const LBS_MULTIPLESEL = &H8&
Public Const LBS_OWNERDRAWFIXED = &H10&
Public Const LBS_OWNERDRAWVARIABLE = &H20&
Public Const LBS_HASSTRINGS = &H40&
Public Const LBS_USETABSTOPS = &H80&
Public Const LBS_NOINTEGRALHEIGHT = &H100&
Public Const LBS_MULTICOLUMN = &H200&
Public Const LBS_WANTKEYBOARDINPUT = &H400&
Public Const LBS_EXTENDEDSEL = &H800&
Public Const LBS_DISABLENOSCROLL = &H1000&
Public Const LBS_NODATA = &H2000&[/code]


Any idea what I'm doing wrong?
February 14, 2006, 4:00 AM
Skywing
Maybe you're trying to insert items into the wrong listbox?  Starcraft uses several listboxes in the Battle.net chat UI, and just assuming the first one you get with FindWindow is the right one is probably a bad idea.

BTW, some of the Starcraft listboxs also have internal data structures associated with them and simply adding a string will be insufficient in some of these cases.
February 14, 2006, 6:11 PM
LockesRabb
Any suggestions as to how I can add text to that chat then without having it be broadcast to bnet?
February 14, 2006, 7:14 PM
Skywing
Looking back on how I did it with SCE, there's a special window message you could send that would update all the internal state in addition to adding a listbox item so that the text would show up properly.

As I recall, it was something like so:

[code]

//
// Add a line to the chat output listbox.
//
// wParam is the default color for the line. [in] SC_COLOR wParam
// lParam is a pointer to the text (ANSI) to be added. [in] CONST CHAR* lParam
//
#define WM_STARCRAFT_ADD_LINE  (WM_USER+0x68)

enum SC_COLOR
{
  WHITE = 0x10,
  GRAY = 0x11,
  GREEN = 0x12,
  YELLOW = 0x13,
  BLUE = 0x14,
  RED = 0x19
};

[/code]

I don't recall if this was sent to the parent SDlgDialog itself or the listbox; I found the window by watching for any window that Starcraft sent that window message to and caching the HWND for later use.

Remember that you will need to do custom marshalling for your text string (i.e. VirtualAllocEx a buffer in Starcraft address space, WriteProcessMemory the contents of the buffer, pass the Starcraft-space-relative pointer to SendMessage as the lParam, and call VirtualFreeEx to release the buffer after SendMessage returns).  If you pass a buffer pointer relative to your address space, Starcraft will either crash or write garbage to the screen.

There is a bug in Battle.snp's UI handling that will cause garbage data to be written to the screen if you write a line that is exactly the length for a line wrap, but not enough to write an additional character on the wrapped line.
February 14, 2006, 9:27 PM
LockesRabb
How would this be done in VB? Also, what is custom marshalling? Thanks for the help thus far, by the way!
February 15, 2006, 4:49 PM
LockesRabb
whats the hex for the wm_user const?
February 15, 2006, 5:32 PM
l2k-Shadow
[quote author=Kyro link=topic=14227.msg146116#msg146116 date=1140024747]
whats the hex for the wm_user const?
[/quote]
[code]
Public Const WM_USER = &H400
[/code]
February 15, 2006, 5:34 PM
LockesRabb
[quote author=Skywing link=topic=14227.msg146051#msg146051 date=1139952455]
Looking back on how I did it with SCE, there's a special window message you could send that would update all the internal state in addition to adding a listbox item so that the text would show up properly.

I don't recall if this was sent to the parent SDlgDialog itself or the listbox; I found the window by watching for any window that Starcraft sent that window message to and caching the HWND for later use.[/quote]

How was that done, finding the window? What program did you use?

And |2-Shadow- thanks for help!
February 15, 2006, 6:02 PM
Grok
Spy++ can watch for specific messages, specific window traffic, and more.  You can find Spy++ in your tools directory of the Visual Studio install.
February 15, 2006, 7:40 PM
LockesRabb
I only have VB, I don't have Visual Studio.
February 15, 2006, 7:53 PM
Skywing
[quote author=Kyro link=topic=14227.msg146119#msg146119 date=1140026554]
How was that done, finding the window? What program did you use?

And |2-Shadow- thanks for help!
[/quote]

SCE itself hooked SendMessage to do this dynamically at runtime.  I'm sure you could find a different way to find the window without injecting a DLL with a bit of research.
February 15, 2006, 8:03 PM
LockesRabb
What's SCE
February 15, 2006, 8:41 PM
Yegg
[quote author=Kyro link=topic=14227.msg146134#msg146134 date=1140036108]
What's SCE
[/quote]

Starcraft Enhancements. A plugin for Starcraft he designed to improve gameplay.
February 15, 2006, 10:26 PM

Search