1

I am attempting to use the FindWindow API using Visual Studio 2017 (.NET Framework 4.6.1) and VB.NET to retrieve the window handle for a currently running instance of Microsoft Word. I am finding that, although it has worked in the past (and is working in another area of the code) in one particular instance, although the FindWindow call is returning a value, I am not able to assign it to a variable. I have verified this in debug mode (screenshots available). I am trying to figure why the API call is not working in this particular instance.

Screenshots link: https://i.stack.imgur.com/iTRm1.jpg

I have executed this call in some areas of the .NET code I am working with, so I know that it does work. I've changed the type in the definition of the "assignee" variable (from Object, to Integer, to IntPtr, etc., etc.) and rerun the application, with the same results (the "assignee" variable ends up with a value of zero, but the FindWindow call itself returns a integer value which appears to be the correct window handle.

The FindWindow API definition:


<DllImport("user32.dll")>
Public Shared Function FindWindow(ByVal strclassName As String, ByVal strWindowName As String) As Integer

End Function

The FindWindow API call:


. . . Public hndMDIWord As Integer . . . . If Word_Previously_Running Then Try _mdiWordApp = GetObject(, "Word.Application") Catch ex As Exception _mdiWordApp = New Word.Application End Try Else _mdiWordApp = New Word.Application End If hndMDIWord = FindWindow("Opusapp", "") If hndMDIWord <> 0 Then SetParent(hndMDIWord, Me.Handle.ToInt32()) End If


I am expecting FindWindow to return an integer representing the window handle of the currently running instance of Word and than have that result assigned to the hndMDIWord variable. FindWindow does return the expected result, but the assignment statement for the hndMDIWord variable does not execute properly; hndMDIWord ends up with a value of zero. There is no error and no exception is thrown.

Any suggestions and/or insights will, of course, be greatly appreciated.

Regards,

Chris Fleetwood

2 Answers2

0

I think the problem is: IntPtr is not compatible with Integer.

You need to declare return type as IntPtr:

<DllImport("user32.dll")>
Public Shared Function FindWindow(ByVal strclassName As String, ByVal strWindowName As String) As IntPtr

End Function

Because:

  • FindWindow has HWND return type
  • From MSDN handles are marshaled as IntPtr

Also there is a pinvoke.net website with examples of .net interop with wast majority of WinAPI functions.

Also hndMDIWord need to be declared as IntPtr and used accordingly, and other WinAPI functions need to be declared to use IntPtr for handlers too:

Public hndMDIWord As IntPtr 
. . . . 
If hndMDIWord <> IntPtr.Zero Then 
Renat
  • 7,718
  • 2
  • 20
  • 34
  • Actually, I have tried changing return type to IntPtr as well as Integer and Object. Yep, I've looked at pinvoke.net as well. FindWindow is returning a value, but the variable I have defined simply won't take the value in the assignment statement. The attached screenshots illustrate the behavior I'm describing. – Christopher H. Fleetwood Jun 06 '19 at 22:40
  • Could `hndMDIWord` be declared as `IntPtr` as well? I would avoid converting `IntPtr` to `int`, as they are different kinds and `IntPtr` could be 64 bits while `int` is 32, so could not fit in 64-bit apps – Renat Jun 06 '19 at 22:56
  • hndMDIWord is IntPtr, as well as the value returned from FindWindow. FindWindow does return a value, but hndMDWord won't take the value in the assignment state (noted in screenshot). However, I have hndMDIWord established as a Watch variable and I also have the FindWindow call set up in the Watch window, and I can copy/paste the return value from FindWindow into the hndMDIWord variable, and it allows the assignment that way. I just can't figure out why the assignment wouldn't work normally as coded. – Christopher H. Fleetwood Jun 07 '19 at 15:50
  • @ChristopherH.Fleetwood, Does assignment fail in case of assignment to a local variable as well?, `Dim localVar = A.FindWindow(...` . I'm making another guess: `hndMDIWord` is a mutable field of the class, so it could be changed from outside, e.g. in parallel thread. (btw, I failed to reproduce the issue, always got handle variable assigned, tried .net 4.6.1 both 32- and 64-bit) – Renat Jun 07 '19 at 19:00
  • I realized that my FindWindow call had the value of one of the parameters incorrectly set. One of those situations where you stare at the code for an eternity and suddenly realize what was wrong. Wish it hadn't taken so long. Thanks for the assistance. – Christopher H. Fleetwood Jun 11 '19 at 13:28
  • No problem, usually all that's needed is just a fresh eye – Renat Jun 11 '19 at 13:53
0

At the top of my form or module I declare the API like this:

Private Declare Auto Function FindWindow Lib "user32.dll" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr

Then I use FindWindow like this:

Dim hndMDIWord As IntPtr = FindWindow("OpusApp", "Word")
If hndMDIWord <> IntPtr.Zero Then
   MsgBox(hndMDIWord)
End If

That works for me. The class name parameter is a pain if you don't know it. I use a great little app called WinLister to get class names. Google it.

Ray E
  • 134
  • 1
  • 9