
Originally Posted by
Chris H
Surprisingly C++ understands what BM_CLICK is without having to set it. Different than VB
Actually, this is not precisely the case. There is nothing inherent in the C++ language, or the C language for that matter, that recognizes Windows Constants like BM_CLICK. Both languages need their constants defined, just as VB does.
The difference is that most C/C++ programmers who write programs for Windows have downloaded the Win32SDK package from Microsoft, which contains "Header files" that can be "included" in a program's source code. These Header files contain, among other things, definitions/prototypes for the tens of thousands of Win32 API functions, and definitions of the Windows Constants. You can see for yourself by downloading the Platform SDK from Microsoft. Here is a page on using the free Visual Studio C++ Express; it states clearly that, in order to write programs using the Win32 API functions, you need to download the SDK.
Also, all major C/C++ compilers on the Windows platform come with copies of the same or similar Header files, since without them, you would be unable to program for Windows at all. And some frameworks like MFC for C++ define the functions and constants for you, under the hood...but they're still there somewhere, if you dig through the generated code.
So it is easy to pick up the mistaken assumption that C/C++ somehow natively understand the Windows Constants. But just try writing a Windows C program without including the "Windows.h" file...In fact, a large part of being a Windows C/C++ programmer is knowing, or looking up, the specific Header file to include in order to use a given constant or API function - very similar to calling API functions from VB!
Next -
There are a couple of caveats to using SendMessage() to click a button in another program's window. First, if that window doesn't currently have the focus, the call may fail. It's safer to use the SetActiveWindow() function first to set focus on the window itself, if it's a top-level window, or the parent window, if you're clicking a button or something similar.
Second, the SendMessage() function, when called from a VB program, blocks the VB program from executing further while the Message is sent from your program, by Windows, to the other program; while the other program takes action; while the other program responds to the Message; and while Windows returns the response to your program. This is a long period of time for your program to be "locked up" and waiting, unable to do anything. It can cause all sorts of trouble if your program is interacting further with the other program, expecting to be able to react to what the other app does as a result of your Message. This is especially true if your Message was intended to click OK on a MessageBox window, as the other program is also blocked while its MessageBox is open.
I generally avoid this problem by using another, similar API function, SendNotifyMessage(), instead of SendMessage(). SendNotifyMessage() doesn't block while waiting for the return Message, thereby avoiding the problem. I do sometimes find it necessary to wait a few hundred milliseconds for the other program to process the Message and do whatever needs doing, such as opening or closing a dialog or MessageBox, etc.; but the difference is, you're controlling the period of time that your app waits.
To have your program wait a few seconds, you can use the System.Threading.Thread.Sleep() function if you're programming in VB.NET; in VB6 you can call the Sleep() API function.
Declarations for API functions mentioned above:
VB Code:
VB6:
Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
Declare Function SendNotifyMessage Lib "user32.dll" Alias "SendNotifyMessageA" (ByVal hWnd As Long, ByVal Msg As Long, _ wParam As Any, lParam As Any) As Long
'---------------------------------------------
VB.NET:
' You can overload a function in VB.NET, so the third parameter of
' SendMessage() or SendNotifyMessage(), "wParam", which is declared
' "As Any" in VB6, is declared differently, as needed, in several declarations in ' VB.NET:
Declare Function SendNotifyMessage Lib "user32.dll" Alias "SendNotifyMessageA" (ByVal hWnd As Integer, _
ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Declare Function SendNotifyMessage Lib "user32.dll" Alias "SendNotifyMessageA" (ByVal hWnd As Integer, _
ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
' Note that the 4th parameter, "lParam", is declared "As Integer" in the
' first declaration, but declared "As String" in the second; and that that
' is the only difference in the 2 declarations. This would cause an error
' in VB6, but is allowed as function overloading in VB.NET.
Finally, note that, if you are trying to find the Window Handle of a MessageBox in another application with FindWindow(), using code like Chris' above, you should replace the NULL in the first parameter of the call to FindWindow() with "#32770", which is the Window Class of a MessageBox. Otherwise, the call will likely fail to find the handle of the MessageBox. I don't know why this is so, but in my tests, FindWindow() repeatedly failed to return the handle of a MessageBox in another app. Using the class name in the first parameter, if you know what it is, will always increase your odds of finding the Handle. It also helps to have the class name when trying to find the Window Handle of any program written in VB6 (other than your own app), or trying to find the Handle of a VB Control, like a VB textbox, Frame control, etc.
You can use Spy++, which comes with various versions of Visual Studio and also with some versions of the free Platform SDK (see link above), to determine the name of the Window Class of an application: open the other application, then open Spy++. Under the Search menu, click "Find Window". Click and Drag the Finder Tool, the little crosshair inside the miniature window, onto the other application, then let go. The dialog in Spy++ will tell you the Window Handle, Caption, and Class name of the other application.
In general, you will want to find the Handle of the other window programatically, because it will be different every time the app is launched, but Spy++ is great for debugging your app. And, the class name won't change from one instance of an app to another, so you can use Spy++ to get the class name, then use it in your call to FindWindow() or FindWindowEx()
-Andrew