Dan Rowe
Dan Rowe

Reputation: 151

API SendMessage() does not work for external app dialog

I created a form that has 2 buttons. One button pops a msgbox and the other runs form frmAPI (code is listed below) listed below. If I open the msgbox and leave it open and then run the frmAPI it will list the msgbox and its text and then close it. THis is what I expect it to do. If I open another application and generate a msgbox in that app with my frmAPI still running it will in fact list the other apps msgbox and the text but it does not close the msgbox from the other app. If Irun the frmAPI from the other app and do the same test the results are reversed. So in short it will only close the dialog from within the same app.

I would like to be able to close a dialog from any app based on it being a dialog and having text that will match my criteria. Any help on what I am doing wrong?

Thanks

Imports System.Runtime.InteropServices
Imports System.Text

Partial Public Class TestMSgBoxStuff
    Inherits Form
    Public Sub New()
        InitializeComponent()
    End Sub

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function FindWindow(lpClassName As String, lpWindowName As String) As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function FindWindowEx(hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Private Shared Function GetWindowText(hWnd As IntPtr, lpString As StringBuilder, nMaxCount As Integer) As Integer
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function GetWindowTextLength(hWnd As IntPtr) As Integer
    End Function

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function SendMessage(hWnd As HandleRef, Msg As UInteger, wParam As IntPtr, lParam As IntPtr) As IntPtr
    End Function
    <DllImport("user32", CharSet:=Runtime.InteropServices.CharSet.Auto, SetLastError:=True, ExactSpelling:=True)>
    Private Shared Function SetForegroundWindow(ByVal hwnd As IntPtr) As IntPtr
    End Function


    Private Const WM_IME_NOTIFY As Integer = &H282
    Private Const WM_DESTROY As Integer = &H2
    Private Const WM_NCDESTROY As Integer = &H82
    Private Const WM_CLOSE As Integer = &H10
    Private Const IMN_CLOSESTATUSWINDOW As Integer = &H1
    Private Const WM_KILLFOCUS As Integer = &H8
    Private Const WM_COMMAND As Integer = &H11



    Private Sub TestMSgBoxStuff_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim timer As New Timer()
        Timer1.Interval = 10000
        'detect the MessageBox every seconds
        'Timer1.Tick += New EventHandler(Timer1_Tick)
        Timer1.Start()
    End Sub

    Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
        'Get the MessageBox handle
        Dim handle As IntPtr = FindWindow("#32770", Nothing)
        Me.RichTextBox1.AppendText("Handle: " + handle.ToString() + vbLf)

        'Get the Text window handle
        Dim txtHandle As IntPtr = FindWindowEx(handle, IntPtr.Zero, "Static", Nothing)
        Me.RichTextBox1.AppendText(vbTab & "text handle: " + txtHandle.ToString() + vbLf)
        Dim len As Integer = GetWindowTextLength(txtHandle)
        Dim sb As New StringBuilder()

        'Get the text
        GetWindowText(txtHandle, sb, len + 1)
        Me.RichTextBox1.AppendText(vbTab & "text: " + sb.ToString() + vbLf & vbLf)
        Me.RichTextBox1.ScrollToCaret()

        SetForegroundWindow(handle)

        'close the messagebox WM_CLOSE
        Dim lResults As Integer = SendMessage(New HandleRef(Nothing, handle), WM_NCDESTROY, IntPtr.Zero, IntPtr.Zero)

    End Sub
End Class

Upvotes: 0

Views: 1121

Answers (1)

HerrJoebob
HerrJoebob

Reputation: 2313

You may be running into User Interface Privilege Isolation. That'll block your messages from going to a higher privilege process. See also ChangeWindowsMessageFilter()

I'd suggest trying to send it a WM_COMMAND instead of a WM_CLOSE; WM_COMMAND is generally treated more gently by the system and may get through. Use BN_CLICKED as the high word of WPARAM and IDOK as the low word (assuming it has an OK button), and the handle to the OK button in LPARAM.. Other button messages are here.

Upvotes: 1

Related Questions