I've unbalanced the stack...oh my!

I need to convert this vb6 sub to work in vb.net...apparently it doesn't like it as-is...

        Dim lhWnd As Long, sTitle As String, lRet As Long
        Do
            lhWnd = FindWindowEx(0, lhWnd, "Qwidget", vbNullString)
            If lhWnd = 0 Then Exit Do
            sTitle = Space(255)
            lRet = GetWindowText(lhWnd, sTitle, Len(sTitle))
            sTitle = Mid(sTitle, lRet)
        Loop

Receiving this:
PInvokeStackImbalance was detected
Message: A call to PInvoke function 'MyApp!Form1.frmMyApp::FindWindowEx' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
LVL 67
sirbountyAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

bchoorCommented:
u need to change
long to integer
and
integer to short

both in your code and in your DLL import declaration

HTH
~BC
sirbountyAuthor Commented:
that sort of worked (no 'error') - but
it doesn't seem to be pulling back the full title...(I had no integers to convert to short)

my two declarations:

Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ByVal hWndl As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer

Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Integer, ByVal lpString As String, ByVal cch As Integer) As Integer
bchoorCommented:
You need to get handle of main window. Then use that handle to get handle of actual object inside the window (you will need additional import declaration to FindWindow)

Dim lHwnd As Integer = FindWindow(vbNullString, "Title of Window")
Dim lObjHwnd As Integer = FindWindowEx(lHwnd, 0, "Qwidget", vbNullString)

Dim ObjectText As New String(Chr(0), 255)
GetWindowText(lObjHwnd, ObjectText, ObjectText.Length)

Note: I haven't tested - so review syntax

HTH
~BC
Learn SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics TeacherCommented:
Hi again SirBounty...

Try this approach to using the GetWindowText() API:

    Public Declare Function GetWindowTextLength Lib "user32.dll" Alias "GetWindowTextLengthA" _
        (ByVal hwnd As IntPtr) As Integer

    Public Declare Function GetWindowText Lib "user32.dll" Alias "GetWindowTextA" _
        (ByVal hWnd As IntPtr, ByVal lpString As String, ByVal cch As Integer) As Integer

    Private Function GetWindowCaption(ByVal hWnd As IntPtr) As String
        Dim caption As New String(" ", GetWindowTextLength(hWnd) + 1)
        GetWindowText(hWnd, caption, caption.Length)
        Return caption.Substring(0, caption.Length - 1)
    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MsgBox(GetWindowCaption(Me.Handle))
    End Sub

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sirbountyAuthor Commented:
IM - that would work great if it would pull the window I'm looking for...
It grabs the caption for Me.Handle - I'm looking for another app's window title.
I've got the class name (Qwidget) and want to search the title for "disconnected*" and if found run another routine...

Increasing points...I think you're on to something. :^)
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics TeacherCommented:
I know you are working with an external app silly....just wanted to make sure you had correct working code for the GetWindowText() part that was using good .Net code.

Is the window you are looking for the MAIN window for you external app?  Or is it a child window?

If it is the MAIN window then you can use the GetProcessesByName() method of the Process class to get a Process instance based on the EXE name.  You pass in the name of the Exe WIHTOUT the path and WITHOUT the extension.  

For instance, to get all instances of Calculator, you could do this:

        Dim ps() As Process = Process.GetProcessesByName("calc")
        If ps.Length > 0 Then
            Dim p As Process = ps(0)
            MsgBox(p.MainWindowTitle)
        End If

In the above example, I grab the first instance of Calculator and display its main window caption via the MainWindowTitle() property.
sirbountyAuthor Commented:
Heh heh...I don't know...
Um - I was using a Find before that woudl reveal the title's captions and I just searched for a match.
Then, I found Erick37 had posted shorter code, provided I knew the class, that I went with..

Now, in .Net it simply doesn't work - which is why I came here with my hand out... : d

But, I'll give the above a shot and come back, showing more of my persistant ignorance... ;^)
sirbountyAuthor Commented:
Nope...that didn't work.  Blank message box...

On a side note, I thought I'd read that in .Net you couldn't (or maybe it was shouldn't) declare a variable in a conditional statement... : \ (I could easily have misread this...)

Anyway - what next chief?
sirbountyAuthor Commented:
This it the function I ended up going with...
        Dim hwnd As IntPtr = FindWindow(lpClassName, vbNullString)
        Dim lpText As String, intStr As Integer, intStp As Integer
        lpText = New String(Chr(0), 100)
        Dim intLength As Integer = GetWindowText(hwnd, lpText, lpText.Length)
        lpText = lpText.Substring(InStr(lpText, ":"), InStr(lpText, "|") - InStr(lpText, ":") - 1)
        Return lpText.Trim

Thanx for the help. :^)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.