FindWindow API

G

Guest

Hello
My build is failing when I call some api's. Could someone help fix this
code. Not sure how to declare the variables....already tried many different
ways.....Thanks

Public Declare Function WaitForSingleObject Lib "kernel32" _
(ByVal hHandle As System.IntPtr, _
ByVal dwMilliseconds As Integer) As Integer
Public Auto Declare Function FindWindow Lib "user32" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As System.IntPtr
Public Declare Auto Function PostMessage Lib "user32" _
(ByVal hWnd As System.IntPtr, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Boolean
Public Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Integer, _
ByVal bInheritHandle As Boolean, _
ByVal dwProcessId As System.IntPtr) As System.IntPtr
Public Declare Function GetWindowThreadProcessId Lib "user32" _
(ByVal hWnd As System.IntPtr, _
ByRef lpdwProcessId As System.IntPtr) As System.IntPtr


Dim hWindow As Long
Dim hThread As Long
Dim hProcess As Long
Dim lProcessId As Long
Dim lngResult As Long
Dim lngReturnValue As Long
Dim iLoopCnt As Integer

hWindow = FindWindow(vbNullString, "(Inactive " & sDir & "\XXXX.EXE)")
hThread = GetWindowThreadProcessId(hWindow, lProcessId)
hProcess = OpenProcess(SYNCHRONIZE, 0&, lProcessId)
lngReturnValue = PostMessage(hWindow, WM_CLOSE, 0&, 0&)
lngResult = WaitForSingleObject(hProcess, 20000)
 
C

Crouchie1998

Your FindWindow is pointing to a filename & not the window caption I think.

Do you have a window caption called:

Inactive " & sDir & "\XXXX.EXE)")

Whatever you have for sDir.

Example Window Caption:
---------------------------

Inactive C:\XXXX.EXE)

I personally would change your 'Long's' for Integers & your IntPtr's to
Integers. In fact I would do it all different. what is your full code & what
is sDir?
 
G

Guest

I changed the 'Long's' for Integers & your IntPtr's to Integers as you
suggested. IT WORKS! THANKS ALOT

You mentioned you would do it differently....I've tried using .NET methods
with no success...

The FindWindow is actually
hWindow = FindWindow(vbNullString, "(Inactive " & "C:\XXXX.EXE)")

What I'm trying to do is this...
My program kicks off an exe that creates a DOS window on the Desktop. I've
tried for days to use the "pure .NET way" to close the spawned window. When
I replace my XXXX.EXE, with for example Calc.exe, the .NET code works great.
But when I use the XXXX.exe the code fails...acts as if the window isn't on
the desktop. (No window hanlde ?) So now I'm trying the API methods which
work with my VB6 version of the app using the XXX.exe. Now that I've got
the declares correct it works.
 
T

Tom Shelton

Hello
My build is failing when I call some api's. Could someone help fix this
code. Not sure how to declare the variables....already tried many different
ways.....Thanks

Public Declare Function WaitForSingleObject Lib "kernel32" _
(ByVal hHandle As System.IntPtr, _
ByVal dwMilliseconds As Integer) As Integer
Public Auto Declare Function FindWindow Lib "user32" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As System.IntPtr
Public Declare Auto Function PostMessage Lib "user32" _
(ByVal hWnd As System.IntPtr, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Boolean
Public Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Integer, _
ByVal bInheritHandle As Boolean, _
ByVal dwProcessId As System.IntPtr) As System.IntPtr
Public Declare Function GetWindowThreadProcessId Lib "user32" _
(ByVal hWnd As System.IntPtr, _
ByRef lpdwProcessId As System.IntPtr) As System.IntPtr


Dim hWindow As Long
Dim hThread As Long
Dim hProcess As Long
Dim lProcessId As Long
Dim lngResult As Long
Dim lngReturnValue As Long
Dim iLoopCnt As Integer

hWindow = FindWindow(vbNullString, "(Inactive " & sDir & "\XXXX.EXE)")
hThread = GetWindowThreadProcessId(hWindow, lProcessId)
hProcess = OpenProcess(SYNCHRONIZE, 0&, lProcessId)
lngReturnValue = PostMessage(hWindow, WM_CLOSE, 0&, 0&)
lngResult = WaitForSingleObject(hProcess, 20000)

No disrespect for Crouchie1998 - he was trying to help you. But, if you
took his suggestion, then your declares are not correct. System handles
should always be declared as IntPtr...

I would leave your declares unchanged - but change your code to use them
like this:

Dim hWindow As IntPtr
Dim hThread As IntPtr
Dim hProcess As IntPtr
Dim lProccessId As IntPtr
Dim bResult As Boolean
Dim iRet As Integer

hWindow = FindWindow(Nothing, "(Inactive " & sDir & "\XXXX.EXE)")
hThread = GetWindowThreadProcessId(hWindow, lProcessId)
hProcess = OpenProcess(SYNCHRONIZE, False, lProcessId)
bResult = PostMessage(hWindow, WM_CLOSE, IntPtr.Zero, IntPtr.Zero)
iRet = WaitForSingleObject(hProcess, 20000)
 
G

Guest

FYI
Tried coding Tom's way...it also works
Don't know who is correct, but both methods work
 
T

Tom Shelton

FYI
Tried coding Tom's way...it also works
Don't know who is correct, but both methods work

Correct maybe a strong word here... Both methods work. It's a matter
of what's best practice. Handles as returned by the windows api's are
the integer size of the underlying hardware. For example, on 32-bit
systems the size of a handle is 32-bits, but on a 64-bit system they are
64-bits. Using Integer for these types of values makes your code
non-portable to these systems. IntPtr is specifically designed to match
that of the underlying platform (32-bit on 32-bit hardware and OS,
64-bit on 64-bit hardware and OS).

This is the reason that the handle properties of controls in
Windows.Forms are System.IntPtr :)

Some go further, and actually use the specific .NET type in their
declares rather then the VB.NET mapped keywords. In other words, they
don't use Integer, Short, or Boolean in their declares - they use
System.Int32, System.Int16, or System.Boolean. They do this to sheild
themselves from future changes in the mapping of VB.NET datatypes.

Anyway, when converting declares from VB.CLASSIC, you should be aware
that data types no longer match. The sizes have changed in VB.NET.
Here is a quick rundown:

VB.CLASSIC VB.NET SIZE
Byte Byte 8-bits
Integer Short 16-bits
Long Integer 32-bits
Currency Long 64-bits

Strings should be treated differently as well. When a string is being
passed as a constant to an API call, then using String is fine. But, if
that String is to be modified by the API call, then it should be passed
as System.Text.StringBuilder instead.... For example, in VB6 you might
declare the function GetUserName like this:

Public Declare Function GetUserName _
Lib "Advapi32.dll" Alias "GetUserNameA" _
(ByVal lpBuffer As String, _
ByRef nSize As Long) As Long

Well, in VB.NET that would translate to:
Public Declare Auto Function GetUserName Lib "Advapi32.dll" _
(ByVal lpBuffer As System.Text.StringBuider,
ByRef nSize As Integer) As Boolean

Notice the lack of the alias? That's because .NET has the ability to
determine the appropriate function to call (A vs W), based on the
current OS. Also, since this buffer is going to be filled by the api, I
declared it with System.Text.StringBuilder. This is not strictly
necessary in VB.NET (it is in C#), since the VB.NET marshaller will
actually do the extra work required to return the value if you were to
declare it as string (remember, strings are immutable in .NET) - but, it
can have a negative impact on performance and memory usage if the call
is made frequently. So, calling it using stringbuilder:

Imports System.Text

....

Dim buffer As New StringBuilder (256)
Dim nSize As Integer = buffer.Capacity

GetUserName (buffer, nSize)

Return buffer.ToString ()

Obviously, you might want to check the return value(s) etc. But, this
should give you an idea. You should read the documentation on p/invoke
and marshalling for further information.
 
G

Guest

Thanks for the explanation and your time! I personally always like to know
the detailed explanation "how and whys" !
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top