Using strings in API calls from Visual Basic


This page shows how to use strings with API calls from Visual Basic.

Example code

The example below reads the title bar text of a window.

Using strings in API calls:
' API to make the process sleep for some milliseconds
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

' To get and set the window caption
Private Declare Function GetWindowText Lib "user32" _
  Alias "GetWindowTextA" (ByVal hWnd As Long, _
                          ByVal lpString As String, _
                          ByVal cch As Long) As Long

Private Declare Function SetWindowText Lib "user32" _
  Alias "SetWindowTextA" (ByVal hWnd As Long, _
                          ByVal lpString As String) As Long

Private Declare Function GetWindowTextLength Lib "user32" _
  Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long

' Get the class name
Private Declare Function GetClassName Lib "user32" _
  Alias "GetClassNameA" (ByVal hWnd As Long, _
                         ByVal lpClassName As String, _
                         ByVal nMaxCount As Long) As Long

' Validate the window handle
Private Declare Function IsWindow Lib "user32" _
                                  (ByVal hWnd As Long) As Long

' Class name

Public Function GetWindowClassName(hWnd As Long) As String
  Dim ClsName As String
  Dim ClsLen As String

  If IsWindow(hWnd) = 0 Then Error 5

  ClsLen  = 128
  ClsName = Space(ClsLen)
  ClsLen  = GetClassName(hWnd, ClsName, ClsLen)

  GetWindowClassName = Left(ClsName, ClsLen)
End Function

' Caption Property

Public Property Get WindowCaption(hWnd As Long) As String
  Dim CapLen As Long
  Dim CapBuf As String

  If IsWindow(hWnd) = 0 Then Error 5

  CapLen = GetWindowTextLength(hWnd) + 1
  CapBuf = Space(CapLen)
  CapLen = GetWindowText(hWnd, CapBuf, CapLen)

  WindowCaption = Left(CapBuf, CapLen)
End Property

Public Property Let WindowCaption(hWnd As Long, NewValue As String)
  If SetWindowText(hWnd, NewValue) = 0 Then Error 5
End Property

' Main

Public Sub Main()
  ' This is just a sample what you can do with
  ' the previous functions, not a complete listing

  Dim Handle As Long
  Dim I As Long

  Handle = Form1.hWnd
  DoEvents ' Let Form1 draw correctly first

  Debug.Print "The caption text of form1 is: " & WindowCaption(Handle)
  Debug.Print "The window class name is: " & GetWindowClassName(Handle)

  WindowCaption(Handle) = "The Caption Changes"

  Debug.Print "The caption text of form1 is: " & WindowCaption(Handle)

  For I = 1 To 3
    Sleep 500
    WindowCaption(Handle) = WindowCaption(Handle) & "."
End Sub

Each windows has a unique identifier, also called the "window handle". To read the caption from a window, the GetWindowName() API needs to know the window handle in question. This value is provided with the hWnd argument.

The next next two arguments of the GetWindowName() API provide the location and size of your buffer. Unlike the previous data structures example, strings are passed by value using the ByVal keyword. Using ByVal causes Visual Basic to supply the actual value of your variable to the API function, instead of it's memory location.

The String conversion

It's interesting to note that the Windows API uses an entirely different format to store text/Strings. Visual Basic uses a so called "UNICODE BSTR" to store the text. This data-type has knowledge of the string size.

Software written in C has a different representation of a string. Often, an simple array of characters is used. The character array is terminated with a final ASCII-zero character; a CHR(0) in Visual Basic.

Just to let you know...
The appearance of a CHR(0) character indicates a string has ended. This character is added at the end of each string (character array). Because of this extra character, buffer lengths always need to be one character longer then the actual string you like to store or receive.

Fortunately, the conversion between these data types is done automatically. If you create a string buffer, and pass it as ByVal something As String, Visual Basic converts the string to the correct type. Right before Visul Basic resumes execution, the (modified) string is copied back automatically to your string buffer.

Because the C-style string type has no real knowledge of it's length, you often need to provide the length of your string in an additional argument. This is also done to make the Windows API accessable by a lot of different higher-level programming languages. Both the GetWindowText() and GetClassName() API return the size of the actual text in the buffer. Use that size to chop off the remaining part of the string buffer.

Strings and structures

To store a String type in a structure, there are a few options. Which option you can use depends on the declaration of the structure.

blog comments powered by Disqus