Alright cool well let me know when its open for business :)
Printable View
Alright cool well let me know when its open for business :)
Cool, but how can I list all open windows with API calls? Task Manager can do that, and it can even show all running EXE files for programs without windows. It also can close any window/EXE by just selecting it and pushing end task or end process. How can I make a program like that in VB6 using API calls?
Ben321, this is an FAQ thread containing API code snippets - it is not a place to have all of your questions related to API's answered.
Please post your questions (and you have 3 or 4 different ones in that post) as new threads in apt forums. If there is a reason to refer to code in an existing thread (there is not in this case) link to it rather than posting in it.
Well... its been two years, I think its time for a bump on this idea :D
Anyway, the main reason I was posting in this thread is to mention that I've made a class library that provides .NET definitions for over 50 Windows APIs as well as about 30 managed .NET methods that use these Windows APIs to do specific tasks (examples include: enumerating all open windows, installing a window service, joining a computer to a domain, extracting icons from a DLL). So if anyone is interested, here's some more info and a download link: http://cjwdev.wordpress.com/2010/07/...pack-released/
While using Environ is slightly simpler, it is also far less reliable - the values can be changed by users or other programs, and the item names can vary between versions of Windows.
Thats true. But i mean those values can be changed anyway. So it doesn't matter.
That was a rather slow response! :eek:
It does matter, because they are not the same values - the ones that you get from Environ are just copies, which (in some circumstances at least) can be easily changed without changing the "originals", while the API gets the actual value.
Even without that, the issue of Environ item names changing still applies, and thus makes it unsafe.
Alright, i am not that much on the computer anymore. i am busy in real life. And also have a life i guess haha
Later mate and thanks for the info i'lll keep it in mind if i ever make a program again i'll use the api's for the safety
Regards,
NiTrOwow
Click a button
Code:Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As long, ByVal lParam As Any) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Const WM_SETTEXT As Long = &HC
Private Declare Function SetActiveWindow Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Const BM_CLICK = &HF5
Sub press_button()
Dim hwnd As Long
Dim OK_button As Long
hwnd = FindWindow("#32770", "Export")
OK_button = FindWindowEx(hwnd, 0&, "Button", "Ok")
Call SendMessage(OK_button, BM_CLICK, 0, ByVal 0&)
End Sub
Close window
Code:Option Explicit
Private Declare Function PostMessage Lib "user32" _
Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function FindWindow Lib "user32" _
Alias "FindWindowA" (ByVal szClass$, ByVal szTitle$) As Long
Private Const WM_CLOSE = &H10
Private Sub Close()
Dim hWnd, retval As Long
Dim WinTitle As String
WinTitle = "Reports list" '<- Title of Window
hWnd = FindWindow(vbNullString, WinTitle)
retval = PostMessage(hWnd, WM_CLOSE, 0&, 0&)
End Sub
Write into notepad
Note: in theory this works with other editable fields like textboxes for passwords.
Code:Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'Finds a window with the name, returns the handle.
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As long, ByVal lParam As Any) As Long
'Sends a specified message to the window handle that you give it.
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
'Gets a controls window handle. The form window handle must be specified to get a decent control.
Const WM_SETTEXT As Long = &HC
'Sets the text of this control.
Sub Write2Notepad()
Dim hWnd As Long
Dim chWnd As Long
'start Notepad
Call Shell("NOTEPAD.EXE", vbNormalFocus)
hWnd = FindWindow("Notepad", vbNullString)
'Find a control window handle... in Notepad, there's the main Textbox that you want.
chWnd = FindWindowEx(hWnd, 0&, vbNullString, vbNullString)
SendMessage chWnd, WM_SETTEXT, ByVal 0&, "text"
End Sub
Enumerate windows
Only use it on an empty worksheet. It gives you classnames, windowtitles, subwindows and handles in a format where the hierarchy is clear. I know spy++ can do this and more, but in my workplace I'm not allowed to install anything, plus I find it easier to search windows in this format.
Code:Option Explicit
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private x As Integer
'Used a user defined type here rather than Enum so that it works on 97
Private Type winEnum
winHandle As Integer
winClass As Integer
winTitle As Integer
winHandleClass As Integer
winHandleTitle As Integer
winHandleClassTitle As Integer
End Type
Dim winOutputType As winEnum
Public Sub GetWindows()
x = 0
winOutputType.winHandle = 0
winOutputType.winClass = 1
winOutputType.winTitle = 2
winOutputType.winHandleClass = 3
winOutputType.winHandleTitle = 4
winOutputType.winHandleClassTitle = 5
GetWinInfo 0&, 0, winOutputType.winHandleClassTitle
End Sub
Private Sub GetWinInfo(hParent As Long, intOffset As Integer, OutputType As Integer)
'Sub to recursively obtain window handles, classes and text
'given a parent window to search
'Written by Mark Rowlinson
'www.markrowlinson.co.uk - The Programming Emporium
Dim hWnd As Long, lngRet As Long, y As Integer
Dim strText As String
hWnd = FindWindowEx(hParent, 0&, vbNullString, vbNullString)
While hWnd <> 0
Select Case OutputType
Case winOutputType.winClass
strText = String$(100, Chr$(0))
lngRet = GetClassName(hWnd, strText, 100)
Range("a1").Offset(x, intOffset) = Left$(strText, lngRet)
Case winOutputType.winHandle
Range("a1").Offset(x, intOffset) = hWnd
Case winOutputType.winTitle
strText = String$(100, Chr$(0))
lngRet = GetWindowText(hWnd, strText, 100)
If lngRet > 0 Then
Range("a1").Offset(x, intOffset) = Left$(strText, lngRet)
Else
Range("a1").Offset(x, intOffset) = "N/A"
End If
Case winOutputType.winHandleClass
Range("a1").Offset(x, intOffset) = hWnd
strText = String$(100, Chr$(0))
lngRet = GetClassName(hWnd, strText, 100)
Range("a1").Offset(x, intOffset + 1) = Left$(strText, lngRet)
Case winOutputType.winHandleTitle
Range("a1").Offset(x, intOffset) = hWnd
strText = String$(100, Chr$(0))
lngRet = GetWindowText(hWnd, strText, 100)
If lngRet > 0 Then
Range("a1").Offset(x, intOffset + 1) = Left$(strText, lngRet)
Else
Range("a1").Offset(x, intOffset + 1) = "N/A"
End If
Case winOutputType.winHandleClassTitle
Range("a1").Offset(x, intOffset) = hWnd
strText = String$(100, Chr$(0))
lngRet = GetClassName(hWnd, strText, 100)
Range("a1").Offset(x, intOffset + 1) = Left$(strText, lngRet)
strText = String$(100, Chr$(0))
lngRet = GetWindowText(hWnd, strText, 100)
If lngRet > 0 Then
Range("a1").Offset(x, intOffset + 2) = Left$(strText, lngRet)
Else
Range("a1").Offset(x, intOffset + 2) = "N/A"
End If
End Select
'check for children
y = x
Select Case OutputType
Case Is > 4
GetWinInfo hWnd, intOffset + 3, OutputType
Case Is > 2
GetWinInfo hWnd, intOffset + 2, OutputType
Case Else
GetWinInfo hWnd, intOffset + 1, OutputType
End Select
'increment by 1 row if no children found
If y = x Then
x = x + 1
End If
'now get next window
hWnd = FindWindowEx(hParent, hWnd, vbNullString, vbNullString)
Wend
End Sub
Thanks for mentioning that. I usually just search these declarations on the internet and I never really go through them. If the incorrect declaration ever caused a problem I'd never find it. I changed them in my posts.
Select menubar item with sendmessage
Assuming you have a "New text document.txt" open this program will choose the "File" -> "Save As" menu. Please note: Instead of giving the name of the menu you have to specify it's zero-based position. (Eg.: File = 0, Edit = 1, Format = 2 etc.) For example if you wanted to get "Format" -> "Font" you would change the code "Call RunMenu(hwnd, 0, 3)" to "Call RunMenu(hwnd, 2, 1)". This code is only made for when the menu item to be selected is a submenu of the topmenu. In notepad all the menus are like that, but if you need to reach a menu item which is located in a submenu of a submenu you would have to make small changes. Unfortunately this code didn't work for the "Help" menu for me. I don't understand why.
Code:Private Declare Function GetMenu Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function GetSubMenu Lib "user32.dll" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetMenuItemID Lib "user32.dll" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Const WM_COMMAND As Long = &H111
Sub test()
Dim hwnd As Long
hwnd = FindWindow(vbNullString, "New text document.txt - Notepad")
Call RunMenu(hwnd, 0, 3)
End Sub
Public Sub RunMenu(ByVal parentWindow As Long, ByVal rtopMenu As Long, ByVal rsubMenu As Long)
Dim rmenu, rmenu2, rthemenu As Long
rmenu = GetMenu(parentWindow)
rmenu2 = GetSubMenu(rmenu, rtopMenu)
rthemenu = GetMenuItemID(rmenu2, rsubMenu)
Call SendMessage(parentWindow, WM_COMMAND, rthemenu, 0&)
End Sub
I tried this and it works great! I know it's a very old post but that's irrelevant to a question I have.
While the routine works great, it does seem very sensitive to crashing and burning with news at 11. I've found that while the hook is set the form will respond nicely when the edges are sized via dragging. However, any attempt to resize the window with standard vb code results in a crash. No problem, I just stay away from doing that.
However, when I change font size of some text on the form, I need to change the minimum window size and resize the window if it's below the new minimum. But pray tell, how? Calling Form_Resize does not trigger the NewWndProc function which enforces the minimum. The only way I've found is to drag the edge of the window. Surely there must be a way to do it through code and I'm hoping an expert or two here might have an answer.
BTW, one thing I tried upon changing font size was to Call Unhook, then attempt to resize with standard vb, then Call Hook again, but no good - crash and burn!
Any help would be appreciated!
BTW, my questions was in reference to:
http://vbforums.com/showpost.php?p=1263307&postcount=7
To set min/max height, you should use the WM_GETMINMAXINFO mesage instead of WM_SIZING.
Code:Public Type POINTAPI
X As Long
Y As Long
End Type
Public Type MINMAXINFO
ptReserved As POINTAPI
ptMaxSize As POINTAPI
ptMaxPosition As POINTAPI
ptMinTrackSize As POINTAPI
ptMaxTrackSize As POINTAPI
End Type
Public Const WM_GETMINMAXINFO As Long = &H24
Dim mmi As MINMAXINFO
Select Case uMsg
Case WM_GETMINMAXINFO
' Snatch copy of current minmax.
Call CopyMemory(mmi, ByVal lParam, Len(mmi))
mmi.ptMinTrackSize.X = MinWidthInPixels
mmi.ptMinTrackSize.Y = MinHeightInPixels
' Make sure maximum really is maximum, to avoid flash.
mmi.ptMaxSize = mmi.ptMaxTrackSize
' Send altered values back to Windows.
Call CopyMemory(ByVal lParam, mmi, Len(mmi))
Exit Function
Thanks for the info fafalone! Your routine works very nicely.
However, I still have the problem of how to invoke the routine through code instead of dragging the edges of the form.
Let's say I have two menu options to set font size: Small font and large font. I have small font selected and calculate a minimum form size based on that. I then drag my form's edges until it reaches the minimum and then I then select large font. I now recalculate the minimum form size and need to increase the form size to this new minimum. I can do it by dragging the edges but I'd rather be able to do it in code the moment that the large font is selected on the menu.
P.S. I responded earlier but don't see it here, so I hope this doesn't end up being double-posted.
Code:Public Enum SWP_Flags
SWP_NOSIZE = &H1
SWP_NOMOVE = &H2
SWP_NOZORDER = &H4
SWP_NOREDRAW = &H8
SWP_NOACTIVATE = &H10
SWP_FRAMECHANGED = &H20
SWP_DRAWFRAME = SWP_FRAMECHANGED
SWP_SHOWWINDOW = &H40
SWP_HIDEWINDOW = &H80
SWP_NOCOPYBITS = &H100
SWP_NOOWNERZORDER = &H200
SWP_NOREPOSITION = SWP_NOOWNERZORDER
SWP_NOSENDCHANGING = &H400
SWP_DEFERERASE = &H2000
SWP_ASYNCWINDOWPOS = &H4000
End Enum
Public Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal CX As Long, ByVal CY As Long, ByVal wFlags As SWP_Flags) As Long
SetWindowPos Me.hWnd, 0, 0, 0, DesiredWidthInPixels, DesiredHeightInPixels, SWP_NOMOVE Or SWP_NOZORDER
Rock on fafalone!! Works great!! I was thinking that the solution had to involve the NewWndProc function and then on seeing your reply I wondered if I'd have to unHook the window first. But I tried it without unHooking and it works like a champ.
May I pick your brain with one more api question?
I have a prog that runs with a vb timer showing a countdown in the background. When certain events take place, I'm displaying a modal form containing some text and a few buttons to gather a response (similar to msgbox). During this time I expect that the timer will stop, and it usually does. However, there are occasions when the timer does NOT stop and the countdown continues. For the life of me I can't figure out why. It's the same modal form that's displayed each time although the amount of text and number of buttons changes. To tell the truth I'd prefer to always keep the timer running. I tried moving it to the main form thinking that might put it in another thread or some such thing, but it didn't change anything. So I was wondering if an api timer would do the trick. What do you think? Is an api timer worth a shot?
Thanks again for your help!
It's pretty weird that it wouldn't either consistently stop or not... not sure why that would happen.
An API based timer is pretty easy to use; you've already got a subclass proc set up so you can just use SetTimer to send periodic WM_TIMER messages.
Is there a specific reason or scenario where the standard VB Timer control might inconsistently fail to stop during the display of a modal form, and does using an API-based timer, as suggested, seem like a reasonable approach to address this issue?