Visual Basic Code Help - Printable Version
-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Skype & Technology (/forumdisplay.php?fid=9)
+---- Forum: Tech Talk (/forumdisplay.php?fid=17)
+----- Thread: Visual Basic Code Help (/showthread.php?tid=53358)
Visual Basic Code Help by DJeX on 11-27-2005 at 05:05 AM
I found this code on planetsourcecode and I need to know how to get it to work.
code: Private Sub Click(Btnhwnd As Integer)
Dim ChildID As Integer
Dim Nul As Integer
Const GWW_ID = (-12)
ChildID = GetWindowWord(Btnhwnd, GWW_ID)
Nul = SendMessageByNum(GetParent(Btnhwnd), WM_COMMAND, ChildID, ByVal CLng(Btnhwnd))
End Sub
Private Sub Command1_Click()
'On Error Resume Next
Dim Btn As Integer, CurHwnd As Integer, T As String
Dim Length As Integer, x As Integer, y As Integer
' Trying to find the handle of the View
' Code Button so that
' by clicking this program's button, we
' can see the code
' window for this form.
CurHwnd = GetDesktopWindow() 'Get Desktop handle
CurHwnd = GetWindow(CurHwnd, GW_Child) 'Find Child Windows of Desktop
Do
If CurHwnd = 0 Then Exit Do 'No (more) matches found
' Find out how Integer the text in this win
' dow is
Length = GetWindowTextLength(CurHwnd)
T = Space$(Length + 1) 'Allocate buffer space
Length = GetWindowText(CurHwnd, T, Length + 1)
If InStr(UCase$, "PROJECT") Then
' The word "Project" was found in this W
' indow's text
' so this is likely VB's "Project" windo
' w
CurHwnd = GetWindow(CurHwnd, GW_Child)
' Looking now for the Project Window's c
' hild windows
Do
If CurHwnd = 0 Then Exit Sub 'No (more) matches found
' Find out how Integer the text in this win
' dow is
Length = GetWindowTextLength(CurHwnd)
T = Space$(Length + 1) 'Allocate buffer space
Length = GetWindowText(CurHwnd, T, Length + 1)
If InStr(UCase$, "VIEW CODE") Then
' This is the handle we want
Click CurHwnd 'Click the View Code Button
Exit Sub 'Exit the Sub
End If
CurHwnd = GetWindow(CurHwnd, GW_HWNDNEXT) 'Keep looking
Loop
End If
CurHwnd = GetWindow(CurHwnd, GW_HWNDNEXT) 'Keep looking
Loop
End Sub
Module Code:
code: Global Const WM_COMMAND = &H111
Global Const GW_Child = 5
Global Const GW_HWNDFIRST = 0
Global Const GW_HWNDLAST = 1
Global Const GW_HWNDNEXT = 2
Global Const GW_HWNDPREV = 3
Global Const GW_OWNER = 4
Declare Function GetDesktopWindow Lib "User32" () As Integer
Declare Function GetParent Lib "User32" (ByVal hWnd As Integer) As Integer
Declare Function GetWindow Lib "User32" (ByVal hWnd%, ByVal wCmd%) As Integer
Declare Function GetWindowText Lib "User32" (ByVal hWnd%, ByVal lpString$, ByVal nMaxCount%) As Integer
Declare Function GetWindowTextLength Lib "User32" (ByVal hWnd As Integer) As Integer
Declare Function GetWindowWord Lib "User32" (ByVal hWnd As Integer, ByVal nIndex As Integer) As Integer
Declare Function SendMessageByNum& Lib "User32" Alias "SendMessage" (ByVal hWnd%, ByVal wMsg%, ByVal wparam%, ByVal lparam&)
I get this error when I run the code
RE: Visual Basic Code Help by Mnjul on 11-27-2005 at 05:15 AM
Since GetWindowTextLength has something to do with Strings, it may have two versions (GetWindowTextLengthA and GetWindowTextLengthW) in User32. In fact, it does. This is what VB's API Viewer gives me:
code: Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Try it and report if it doesn't work
By the way, you also need to add "Alias GetWindowTextA" for GetWindowText, otherwise VB will complain about it too.
Another by the way is that you should use Long to store hWnd values in VB (I mean VB6), I guess...
RE: Visual Basic Code Help by DJeX on 11-27-2005 at 05:38 AM
Ok I did what you said and now I get this error
My Code With Changes:
code: Private Sub Click(Btnhwnd As Long)
Dim ChildID As Long
Dim Nul As Long
Const GWW_ID = (-12)
ChildID = GetWindowWord(Btnhwnd, GWW_ID)
Nul = SendMessageByNum(GetParent(Btnhwnd), WM_COMMAND, ChildID, ByVal CLng(Btnhwnd))
End Sub
Private Sub Command1_Click()
'On Error Resume Next
Dim Btn As Long, CurHwnd As Long, T As String
Dim Length As Long, x As Long, y As Long
' Trying to find the handle of the View
' Code Button so that
' by clicking this program's button, we
' can see the code
' window for this form.
CurHwnd = GetDesktopWindow() 'Get Desktop handle
CurHwnd = GetWindow(CurHwnd, GW_Child) 'Find Child Windows of Desktop
Do
If CurHwnd = 0 Then Exit Do 'No (more) matches found
' Find out how Long the text in this win
' dow is
Length = GetWindowTextLength(CurHwnd)
T = Space$(Length + 1) 'Allocate buffer space
Length = GetWindowText(CurHwnd, T, Length + 1)
If InStr(UCase$, "PROJECT") Then
' The word "Project" was found in this W
' indow's text
' so this is likely VB's "Project" windo
' w
CurHwnd = GetWindow(CurHwnd, GW_Child)
' Looking now for the Project Window's c
' hild windows
Do
If CurHwnd = 0 Then Exit Sub 'No (more) matches found
' Find out how Long the text in this win
' dow is
Length = GetWindowTextLength(CurHwnd)
T = Space$(Length + 1) 'Allocate buffer space
Length = GetWindowText(CurHwnd, T, Length + 1)
If InStr(UCase$, "VIEW CODE") Then
' This is the handle we want
Click CurHwnd 'Click the View Code Button
Exit Sub 'Exit the Sub
End If
CurHwnd = GetWindow(CurHwnd, GW_HWNDNEXT) 'Keep looking
Loop
End If
CurHwnd = GetWindow(CurHwnd, GW_HWNDNEXT) 'Keep looking
Loop
End Sub
Module
code: Global Const WM_COMMAND = &H111
Global Const GW_Child = 5
Global Const GW_HWNDFIRST = 0
Global Const GW_HWNDLAST = 1
Global Const GW_HWNDNEXT = 2
Global Const GW_HWNDPREV = 3
Global Const GW_OWNER = 4
Declare Function GetDesktopWindow Lib "user32" () As Long
Declare Function GetParent Lib "user32" (ByVal hwnd As Integer) As Long
Declare Function GetWindow Lib "user32" (ByVal hwnd%, ByVal wCmd%) As Long
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd%, ByVal lpString$, ByVal nMaxCount%) As Long
Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Declare Function GetWindowWord Lib "user32" (ByVal hwnd As Integer, ByVal nIndex As Integer) As Long
Declare Function SendMessageByNum& Lib "user32" Alias "SendMessage" (ByVal hwnd%, ByVal wMsg%, ByVal wparam%, ByVal lparam&)
RE: Visual Basic Code Help by Mnjul on 11-27-2005 at 05:56 AM
quote: Originally posted by Mnjul
Another by the way is that you should use Long to store hWnd values in VB (I mean VB6), I guess...
Try that
By the way, where did you get these codes from?
RE: Visual Basic Code Help by DJeX on 11-27-2005 at 07:15 AM
Ok I did try it and still the same error. And I got the code from www.planetsourcecode.com
RE: Visual Basic Code Help by Mike on 11-27-2005 at 08:07 AM
Try pasting this into your module, removing the previous code:
code: Option Explicit
Global Const WM_COMMAND = &H111
Global Const GW_Child = 5
Global Const GW_HWNDFIRST = 0
Global Const GW_HWNDLAST = 1
Global Const GW_HWNDNEXT = 2
Global Const GW_HWNDPREV = 3
Global Const GW_OWNER = 4
Declare Function GetDesktopWindow Lib "user32" () As Long
Declare Function GetParent Lib "user32" (ByVal hwnd As Integer) As Long
Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Declare Function GetWindowWord Lib "user32" (ByVal hwnd As Integer, ByVal nIndex As Integer) As Long
Declare Function SendMessageByNum& Lib "user32" Alias "SendMessage" (ByVal hwnd%, ByVal wMsg%, ByVal wparam%, ByVal lparam&)
I dont get any overflow errors anymore...
RE: Visual Basic Code Help by IKillThings on 11-27-2005 at 08:13 AM
Change 2 a double?
RE: Visual Basic Code Help by Mike on 11-27-2005 at 08:22 AM
quote: Originally posted by IKillThings
Change 2 a double?
For which line of code are you talking?
RE: Visual Basic Code Help by CookieRevised on 11-27-2005 at 10:21 AM
DJeX,
In future, can you say what purpose this code has? Or at least link to the exact source from where you got it? It's a bitch to find out what a program does by only looking at the (buggy) code.
Anyways...
- What's the use of a seperate module with just simple declarations?
- What's the use of global variables if you only have 1 form?
- Always use "Option Explicit" in ALL modules, forms, etc at the beginning of your code.
In short: the code you've downloaded is made by someone who don't know how to properly code stuff, and has all the markings of copy/pasting... The code is altered from the original by some stupid kid (he did a "replace all" of all "Long"'s with "Integer"'s, proof: see the many Integer declarations and especially the comment: ' Find out how Integer the text in this window is'). Not to mention the original code was most likely made for VB3.0 or 4.0...
After all these years, that crappy code has spread all over the place (as such code usually do):
http://www.vbexplorer.com/VBExplorer/tips/src09.htm
http://www.andreavb.com/forum/viewtopic.php?TopicID=1014
http://spazioinwind.libero.it/vbprogzone/articles/art006.html
etc...
etc...
Instead of copy/pasting, try to understand what the code does (or tries to do) and rewrite the whole thing from scratch.
quote: Originally posted by IKillThings
Change 2 a double?
If you get overflow problems, changing to Double is not the proper thing to do, rather fix the bug itself instead of applying crappy workarounds (which wouldn't work anyways).
This is the proper code:
- Note that everything is put in the form, you don't need any module.
- Note that the code works, but if you're using VB6, you will most likely not see anything happening as VB6 doesn't have a button with "View Code" in it's main parent window.
In other words, this code of yours will not work afterall, but the method behind it will work. Thus the code needs serious adaptations or you need to be specific in what you want.
code: 'C' Always use "Option Explicit" to avoid undeclared variable errors
Option Explicit
Private Declare Function GetDesktopWindow Lib "User32" () As Long
Private Declare Function GetParent Lib "User32" (ByVal hWnd As Long) As Long
Private Declare Function GetWindow Lib "User32" (ByVal hWnd As Long, ByVal uCmd As Long) As Long
Private Declare Function GetWindowText Lib "User32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowTextLength Lib "User32" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long
'C' Note that the GetWindowWord() function is obsolete and should be replaced
'C' with GetWindowLong() function. See the MSDN Library for more details.
'C' EDIT: I've replaced it for you...
Private Declare Function GetWindowLong Lib "User32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SendMessageByNum Lib "User32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wparam As Long, ByVal lparam As Long) As Long
Private Const WM_COMMAND As Long = &H111
Private Const GW_HWNDFIRST As Long = 0
Private Const GW_HWNDLAST As Long = 1
Private Const GW_HWNDNEXT As Long = 2
Private Const GW_HWNDPREV As Long = 3
Private Const GW_OWNER As Long = 4
Private Const GW_CHILD As Long = 5
Private Const GWL_ID As Long = -12
Private Sub Click(BtnhWnd As Long)
'C' This will send the command id associated with the button to the parent
'C' of the button. In other words: it 'clicks' that button...
SendMessageByNum GetParent(BtnhWnd), WM_COMMAND, GetWindowLong(BtnhWnd, GWL_ID), BtnhWnd
MsgBox "done"
End Sub
Private Sub Command1_Click()
'C' The method used here to find the handle to a button works (almost),
'C' but can greatly be optimized using the proper API's.
'C'
'C' Using the method depict here, has his flaws. eg: if a (child) window
'C' is moved in the Z-order (which can happen all the time!!) it will not
'C' be properly enumerated and even some errors may occur.
'C'
'C' To properly enumerate all (child) windows use the proper API's instead
'C' of a half-baked method. eg: use the EnumWindows() and especially
'C' EnumChildWindows() functions. See the MSDN Library for more details.
Dim T As String
Dim Length As Long
Dim CurHwnd As Long
' Trying to find the handle of the View Code Button so that
' by clicking this program's button, we can see the code
' window for this form.
CurHwnd = GetDesktopWindow() 'Get Desktop handle
CurHwnd = GetWindow(CurHwnd, GW_CHILD) 'Find Child Windows of Desktop
Do Until CurHwnd = 0
' Find out how long the text in this window is
Length = GetWindowTextLength(CurHwnd) 'Get buffer length
T = Space$(Length) 'Allocate buffer space
GetWindowText CurHwnd, T, Length + 1 'Fill buffer
If InStr(UCase$(T), "PROJECT") Then
' The word "Project" was found in this Window's text
' so this is likely VB's "Project" window
' Looking now for the Project Window's child windows/controls
CurHwnd = GetWindow(CurHwnd, GW_CHILD)
Do Until CurHwnd = 0
' Find out how long the text in this window is
Length = GetWindowTextLength(CurHwnd)
T = Space$(Length)
GetWindowText CurHwnd, T, Length + 1
If InStr(UCase$(T), "VIEW CODE") Then
' This is the handle we want
Click CurHwnd 'Click the View Code Button
Exit Sub 'Exit the Sub
End If
CurHwnd = GetWindow(CurHwnd, GW_HWNDNEXT) 'Keep looking
Loop
End If
CurHwnd = GetWindow(CurHwnd, GW_HWNDNEXT) 'Keep looking
Loop
End Sub
Lines starting with 'C' are my added comments
Thus, the important thing about this is to understand the method behind this and write your own code based on that (and using the proper API's instead). The important thing is not to get this code to work (as it is only a dodgy example anyways)...
If you want to press on a button from another program automatically:
- You need to find the control ID of that button
- Send that control ID to the parent of the button
To do this:
- You need to enumerate all child windows of the parent window
- In most cases (but which is not done in this code) you need to enumerate all child windows of all the child windows also, etc...
- Find the button on the current (child) window you're at (the method used here is to search for its caption text, but there are many methods and ways and all depend on what you exactly want)
But, judging from your questions, you might to program/try much easier and basic stuff first before attempting something like this as you don't seem to understand how such stuff works (no offense though! everything needs to be learned and we all need to start somewhere. But starting with something like this, without understanding it isn't the proper way of learning something... "don't run, if you can't walk")
----------------
As a "bonus", I've added a module to this post which shows a better way of doing this, but the principle stays the same. All you need is have MSN Messenger 6.x English running an execute the module (no form needed). It will click the "Add a contact" button.
RE: Visual Basic Code Help by DJeX on 11-27-2005 at 07:41 PM
Thank you CookieRevised for your reply. I tryed your module but it didn't work.
I tryed the code you posted and that aswell did not work. This is what I did:
I made a test program called Notepad with a button called Test on it. I replaced the correct words in the code above (PROJECT and VIEW CODE) with NOTEPAD and TEST. Then I ran my test program then run the code above but still didn't work.
I just need a simple code that will find a button on another program that is running and press it. Like for example how that Hit Man Pro anti-spyware program works, it controls the other programs that it downloads.
I guess like you said I should learn it but I dont know where to start. I'll study your code some more.
RE: RE: Visual Basic Code Help by CookieRevised on 11-27-2005 at 08:29 PM
quote: Originally posted by DJeX
I tryed your module but it didn't work.
I tryed the code you posted and that aswell did not work.
They both work perfect if you follow the instructions though.
eg: for the module, did you tried it out with an unpatched english MSN Messenger version 6.x while the main window was not minimized to the system tray, as stated in the first comment in that module and in my post? It will not work on Messenger 7 or whatever as the controls there are build up in another way (without windows)...
quote: Originally posted by DJeX
This is what I did:
I made a test program called Notepad with a button called Test on it. I replaced the correct words in the code above (PROJECT and VIEW CODE) with NOTEPAD and TEST. Then I ran my test program then run the code above but still didn't work.
First of all, everything is made specifically for a certain situation; The code in the form doesn't work for everything.
Nevertheless, this time the blame was on my part. Though, you could've found where it went wrong if you'd understand what the code does (instead of simply copy/pasting).
Both lines with
GetWindowText CurHwnd, T, Length
must be
GetWindowText CurHwnd, T, Length + 1
and you should have replaced the obsolete GetWindowWord() API with GetWindowLong(), as stated in the comments...
I've done both edits in the source for you now... Sorry about the misleading.
quote: Originally posted by DJeX
I just need a simple code that will find a button on another program that is running and press it. Like for example how that Hit Man Pro anti-spyware program works, it controls the other programs that it downloads.
The code shown is exactly what you want. Nobody can give you anything more specific if you aren't specific.
If you understand how the method works, you'll see that you can not make something general, working for everything in every situation as each situation is totally different. Even the code in Hitman Pro is specifically made for specific programs.
The big key here is to understand every line of code and understand what every API call exactly does. The MSDN Library can help you in that (http://www.msdn.com/).
-
To further help you and as asked in my previous post, be specific of what you want (and I mean really specific with all the small details and stuff)...
RE: Visual Basic Code Help by DJeX on 11-27-2005 at 09:44 PM
quote: Originally posted by CookieRevised
Nevertheless, this time the blame was on my part. Though, you could've found where it went wrong if you'd understand what the code does (instead of simply copy/pasting).
Both lines with
GetWindowText CurHwnd, T, Length
must be
GetWindowText CurHwnd, T, Length + 1
and you should have replaced the obsolete GetWindowWord() API with GetWindowLong(), as stated in the comments...
I've done both edits in the source for you now...
It worked this time. Thank you
What I'm trying to do is make a program that will automaticly update my computer when clicked. So like it will update norton antivirus and anti-spyware programs by its self. I makeing it for my Grand father since hes not the best on computers and often gets confused.
EDIT: I tryed that code with Norton System Works and MS Anti-Spyware and it finds the Window but cant find the button in the window to click.
RE: Visual Basic Code Help by CookieRevised on 11-27-2005 at 11:01 PM
First of all, Norton has his own auto-update features, check out the help files and manuals.
Second, even if you are able to press on a button, there are extremely many things which can go wrong and extremely many things which needs to be done first or after pressing the button.
I don't recommend making this for your grandfather (as good as the intention might be) as it will most likely produce more problems (not to mention crashes or whatever) which he can't solve at all. Instead teach him how to update such stuff for himself (or write it down or something)...
---------
For the problem itself, again I emphesize on understanding the code and understanding the methods used to find the button.
The button can be a child of another control which on his turn can be a child of another control which on his turn (...) etc (...), which on his turn is a child of the main window. You need to enumerate the complete tree. The Form code only looks at buttons directly placed on the main window. The Module code looks at buttons in all child windows and childs of those child windows.
Note that the term "window" is not the thing you think of as a window. A control like a button is also a window... Anything that has a window handle is called a window.
Note that not all programs work in the same way and not all programs have window controls which you could subclass or control (eg: MSN Messenger 7.x is a good example of this).
RE: Visual Basic Code Help by DJeX on 11-27-2005 at 11:50 PM
Ahh ok, I see what your saying. But because I want to learn this I still want to get it to work. Just for my own knoledge. Now your saying I should use EnumWindows() and EnumChildWindows() funtions right? Would they work the same as the GetWindow() and GetDesktopWindow()? Like for example:
CurHwnd = GetWindow(CurHwnd, GW_CHILD) < -- Original code.
CurHwnd = EnumWindows (CurHwnd, GW_CHILD) <-- Would that work?
RE: Visual Basic Code Help by CookieRevised on 11-28-2005 at 12:11 AM
quote: Originally posted by DJeX
Ahh ok, I see what your saying. But because I want to learn this I still want to get it to work. Just for my own knoledge. Now your saying I should use EnumWindows() and EnumChildWindows() funtions right? Would they work the same as the GetWindow() and GetDesktopWindow()? Like for example:
CurHwnd = GetWindow(CurHwnd, GW_CHILD) < -- Original code.
CurHwnd = EnumWindows (CurHwnd, GW_CHILD) <-- Would that work?
nope... they are completely different. See the code in the Module for an example of EnumChildWindows()...
The enumuration functions use something which is called a "callback function" to work. The functions are called only once, and they in turn will call the function you provided as a parameter (hence the "callback") for each window they find.
For the complete detailed info about these API's (and any other API for that matter) see the msdn library and search for those API functions.
EnumWindows()
EnumChildWindows()
You should also never use the GetWindow() API for the purpose of enumerating/scrolling thru all the windows (hence the Form code isn't that good). Reasons for this can be read in the msdn library again.
|