What's New
Q & A
Tip Jar
C# Helper...
Follow VBHelper on Twitter
MSDN Visual Basic Community
TitleUse SendMessage to make an editor where a single instance handles all requests
DescriptionThis example shows how to use SendMessage to make an editor where a single instance handles all requests in Visual Basic 6.
Keywordsone instance, instance, SendMessage
CategoriesSoftware Engineering, Windows, API
Suppose you have an editor named OnlyOne.exe. When you click and drag .txt files onto OnlyOne.exe, this editor opens and displays the file(s) in separate MDI child windows.

Now suppose OnlyOne.exe is already running and you click and drag a .txt file onto OnlyOne.exe. Instead of opening again, you want to have the running instance of the program open the newly dragged files.

How do you do that?

A program can use App.PrevInstance to see if another instance of the program is already running.

  1. Check App.PrevInstance to see if an existing instance is running. If an existing instance is running:
    1. Tell that application to open the new files.
    2. Activate the existing instance.
    3. Exit.
  2. If no existing instance is running:
    1. Open the new files.

The tricky part is telling the existing instance to open the files.

The program contains a PictureBox in its MDI form. Inside that control is a TextBox named txtCommand. The program sends the file names to the existing instance by using the SendMessage API function to put the names in the existing instance's copy of txtCommand. Then the txtCommand_Change event handler sees the new names and loads the files.

Once it knows there is an existing instance of the program, the program uses the FindWindow API function to get that instance's window handle.

Next it uses the GetWindow API function to traverse the window's child windows looking for one that has a class name starting with "Thunder" and ending with "PictureBoxDC". This is the PictureBox inside the MDI form. In VB6, this window's class name is "ThunderPictureBoxDC" at design time and "ThunderRT6PictureBoxDC" at run time. By searching for the start and end of the class name instead of the exact name, this program should hopefully work at design time or run time in different vesions of Visual Basic. The FindChildByClassPrefixAndPostfix routine in the program wraps this search up so it's easy to use.

Next the program performs a similar search of the PictureBox's children looking for one with class name starting with "Thunder" and ending with "TextBox". This is txtCommand.

To prevent trouble in case another program has just set txtCommand's value, the program then uses the GetWindowText API function to get txtCommand's value. It keeps looking until the value is blank. Then it uses SendMessage to drop the file names into txtCommand.

Having passed the file names to the existing instance, the new instance unloads itself.

Key techniques:

  • Using FindWindow to get a window with a known title
  • Using GetWindow to traverse the main window list
  • Using GetWindow to traverse a window's chidlren
  • Using GetClassName to get a window's class name
  • Using GetWindowText to get a window's text
  • Using SendMessage to set a window's text

Outstanding question: Does anyone know how to get a window's name from its handle? In this case, txtCommand's name?

' See if the program is already running.
Private Sub MDIForm_Load()
Dim app_hwnd As Long
Dim pic_hwnd As Long
Dim txt_hwnd As Long
Dim cmd_text As String

    If App.PrevInstance Then
        ' The program is already running.
        ' Get its handle.
        app_hwnd = FindWindow(ByVal 0&, ByVal "OnlyOne")

        ' Find the Picture1 child window.
        pic_hwnd = _
            FindChildByClassPrefixAndPostfix(app_hwnd, _
            "Thunder", "PictureBoxDC")
        If pic_hwnd = 0 Then
            MsgBox "Error finding Picture1"
            Unload Me
            Exit Sub
        End If

        ' Find the txtCommand child window.
        txt_hwnd = _
            FindChildByClassPrefixAndPostfix(pic_hwnd, _
            "Thunder", "TextBox")
        If txt_hwnd = 0 Then
            MsgBox "Error finding txtCommand"
            Unload Me
            Exit Sub
        End If

        ' Repeatedly try to set the TextBox's text.
            ' See if the TextBox's text is blank.
            If Len(WindowText(txt_hwnd)) = 0 Then
                ' Put our Command line in the TextBox.
                cmd_text = Command$()
                If SendMessageSetWindowText(txt_hwnd, _
                    WM_SETTEXT, 0, cmd_text) = 0 Then
                    MsgBox "Error setting txtCommand text"
                End If
                Exit Do
            End If

            ' The text is not blank. Wait a bit and try
            ' again.

        ' We are done
        Unload Me

        ' Activate the other program.
        AppActivate "OnlyOne"
        ' The program is not already running.
        dlgFile.Filter = "Text Files (*.txt)|*.txt|All " & _
            "Files (*.*)|*.*"
        dlgFile.Flags = _
            cdlOFNHideReadOnly + _
            cdlOFNFileMustExist + _
        dlgFile.CancelError = True
        dlgFile.InitDir = App.Path

        ' Set our caption.
        Caption = "OnlyOne"

        ' Load the files listed in Command$.
        txtCommand.Text = Command$()
    End If
End Sub

' The text has changed. Load the files listed.
Private Sub txtCommand_Change()
Dim pos As Integer
Dim txt As String
Dim file_name As String

    txt = txtCommand.Text
    Do While Len(txt) > 0
        ' Get the next file name.
        pos = InStr(txt, " ")
        If pos > 0 Then
            file_name = Left$(txt, pos - 1)
            txt = Mid$(txt, pos + 1)
            file_name = txt
            txt = ""
        End If

        ' Open the file.
        LoadFile file_name

    ' Blank the TextBox.
    txtCommand.Text = ""
End Sub
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.