How to find VB window/form id - vb6

Reqirement: Need to close/kill a particular VB Window.
I heard like on specifying the window name - we can trace the window id and using that id we can kill/close that active window.
Does this function help me - HWND ID by (Hwnd ID)
Please correct me if im wrong and help me on how to find the window id.

Here is how to find a window (and determine its window handle or hWnd) given the caption or part of the caption
Here is how to close the window once you know the window handle
From Karl Peterson's excellent VB6 website.

use me.close or unload(me) for closing active window
to close a form1 from form2, u can use unload(form1) or form1.close( working in vb.net)

If the window has a title, you could do something like
Private Declare Function FindWIndow Lib "user32" _
Alias "FindWindowA" _
(ByVal lpClassName As Any, _
ByVal lpWindowName As Any) _
As Long
...
Dim hWnd As Long
Dim strTitle As String
strTitle = "whatever your title is"
hWnd = FindWIndow(vbNullString, strTitle)
If hWnd <> 0 Then
Debug.Print "Window ID or Handle is " & Hex(hWnd)
Else
Debug.Print "Cannot find handle"
End If

Related

How to bring the application to the front?

Currently copied and modifying a portion of a coding within the same program to create a button that when clicked will bring the Vision application to the front of the GUI.
Created a button called "btVisionCam_Click()"
Declared "Private lVideo As Long"
CEIVidCap is the Vision application that is running behind of the GUI when the GUI is opened
Private Sub btVisionCam_Click()
If btVisionCam.Value = 1 Then
lVideo = FindWindow(vbNullString, "CEIVidCap")
If lVideo = 0 Then
lVideo = Shell("C:\machine\appls\CEIVidCap.exe", vbNormalFocus)
End If
End If
End Sub
When the button is clicked, it does not bring the Vision application to the front of the GUI. Please help, thanks!
Create a module and copy the following declarations:
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Then in your button, as you are already doing, use FindWindow to get the window handle and use ShowWindow to bring it up:
Dim lnghWnd As Long
lnghWnd = FindWindow(vbNullString, "CEIVidCap")
ShowWindow lnghWnd, 1
Supported values for nCmdShow parameter of ShowWindow:
SW_HIDE = 0
Hide the window.
SW_MAXIMIZE = 3
Maximize the window.
SW_MINIMIZE = 6
Minimize the window.
SW_RESTORE = 9
Restore the window (not maximized nor minimized).
SW_SHOW = 5
Show the window.
SW_SHOWMAXIMIZED = 3
Show the window maximized.
SW_SHOWMINIMIZED = 2
Show the window minimized.
SW_SHOWMINNOACTIVE = 7
Show the window minimized but do not activate it.
SW_SHOWNA = 8
Show the window in its current state but do not activate it.
SW_SHOWNOACTIVATE = 4
Show the window in its most recent size and position but do not activate it.
SW_SHOWNORMAL = 1
Show the window and activate it (as usual).
Try setting it as the foreground window.
Add this to your other API calls:
Declare Function Win32_SetForegroundWindow Lib "user32" _
Alias "SetForegroundWindow" ( _
ByVal hWnd As Long) _
As Long
Then add:
Dim Ret As Long
Ret = Win32_SetForegroundWindow(lnghWnd)
If Ret Then
' Your window should be foreground
End If

FindWindow() not working

I am writing a Little VBA Programm that Needs to wait until a specific windows is open. I want to do this using FindFindow form the user32.dll but i cant get it run. Weird Thing is that even if i set the 2 Parameters of the function to Null, i still get a negative return, although in that case all windows should match. Basically i dont get a result different from 0 for hwnd Independent of how i call FindWindow. I searched Stack OPverflow and i also Googled the Problem but i cant find what i am doing wrong. Any help is appreciated.
Declare Function FindWindow Lib "user32" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Sub Main
Dim hwnd As Long
hwnd = FindWindow(vbNullString, vbNullString)
If (hwnd = 0) Then MsgBox ("failure")
End Sub
The Solutions to similar Problems like How to use FindWindow to find a visible or invisible window with a partial name in VBA dont seem to work either.
The problem is that vbNullString is a length 0 string, the same as "". When that is marshalled to the unmanaged code a non-null pointer to a null-terminated array of characters is passed. Because the length is 0 then a pointer to a null-terminator is passed. That's different from NULL which is the null pointer.
I'm far from a VBA expert, but I think the solution is like so:
Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByRef lpClassName As Any, ByRef lpWindowName As Any) As Long
If you want to call this passing NULL for both arguments do so like this:
window = FindWindow(ByVal 0&, ByVal 0&)
Alternatively, if you want to pass a string value do it like this:
window = FindWindow(ByVal 0&, ByVal "Untitled - Notepad")

On Window Resize Event

The Problem
Call a procedure whenever the Main Excel Window is resized.
First attempt:
Sub Workbook_WindowResize(ByVal Wn As Window)
Debug.Print Wn.Width & "x" & Wn.Height
End Sub
Results:
The sub routine is called whenever the 'inner' workbook window is resized but not when the application window is resized. I.E. occcurs on resize of the Multiple Document Interface child containing the application instance.
Second attempt
Dim WithEvents App As Application
Private Sub App_WindowResize(ByVal Wb As Workbook, ByVal Wn As Window)
Debug.Print Wn.Width & "x" & Wn.Height
End Sub
Results:
Oddly, the same thing that happened before occurs, which definitely surprised me. The event only occurs when the workbook window is resized instead of the application window.
For this reason I started looking into using the windows API.
There are many examples of setting SystemWide keyboard and mouse hooks using the windows APIs. This is along the same lines:
Public Enum enHookTypes
WH_CALLWNDPROC = 4
WH_CALLWNDPROCRET = 12
WH_CBT = 5
WH_DEBUG = 9
WH_FOREGROUNDIDLE = 11
WH_GETMESSAGE = 3
WH_HARDWARE = 8
WH_JOURNALPLAYBACK = 1
WH_JOURNALRECORD = 0
WH_MOUSE = 7
WH_MSGFILTER = (-1)
WH_SHELL = 10
WH_SYSMSGFILTER = 6
WH_KEYBOARD_LL = 13
WH_MOUSE_LL = 14
WH_KEYBOARD = 2
End Enum
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As LongPtr, ByVal lpfn As Long, ByVal hMod As Long, ByVal dwThreadId As Long) As LongPtr
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function GetLastError Lib "kernel32" () As Long
'Ensure that your hook procedure does not interfere with the normal operation of other hook procedures
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Public hndl As Long
Sub HookWindow()
hndl = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf measureWindow, Application.Hinstance, 0&)
Debug.Print hndl & "~~" & GetLastError()
End Sub
Sub unhookWindow()
ret = UnhookWindowsHookEx(hndl)
Debug.Print ret
End Sub
Public Sub measureWindow(code As Long, wParam As Long, lParam As Long)
If code > 0 Then
Debug.Print ThisWorkbook.Windows(1).Width & "x" & ThisWorkbook.Windows(1).Height
Else
ret = CallNextHookEx(measureWindow, code, wParam, lParam)
End If
End Sub
Results:
If I replace the WH_CALLWNDPROC in:
hndl = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf measureWindow, Application.Hinstance, 0&)
with WH_KEYBOARD_LL the sub-routine is called whenever a key is pressed. Similarly, if I replace it with WH_MOUSE_LL the sub-routine is called whenever the mouse is moved or a mouse button pressed.
The problem is that when I try to hook the sub-routine to WH_CALLWNDPROC nothing happens?
Why?
I'm still not sure, but the same is true for all ENUMS in enHookTypes except WH_MOUSE_LL and WH_KEYBOARD_LL. Looking through the WinAPI documentation I read that you can use GetLastError from Kernel32.dll do get some indication of why the operation failed.
The error numbers I have got so far are (in decimal) error 5 (for JOURNAL hooks) and error 1428 for the rest.
Ultimately this also failed.
Application.Windows is a collection of window objects of Worbooks opened within the Application. The WindowResize event is raised when a non-maximized window changes size. The Workbook_WindowResize(ByVal Wn As Window) is exposed within the workbook object itself. The Application_WindowResize(ByVal Wb as Workbook, ByVal Wn As Window) event has to do with ANY/ALL of the workbooks within the Application when a non-maximized workbook's window changes size. Hence the difference in references passed in by the events. It is just a Window in the first case, of the workbook that raised the event, within the workbook object, and there is no question here which window it is (it's the "Me" workbook's window). It is both the Workbook and that workbook's window when it is raised at the Application level since the workbook the event relates to needs identification :) And no, Excel does not have a "Resize" event for the App window itself and you would need to go to APIs for that.
With the later Excel versions (past the 2010), there is ONE workbook per Excel Application window, the workbook's window is always maximized in the old sense, and both Workbook and Application events refer to the same workbook and would work just as you would want them to.
Solution , create a timer event that checks and compares the width every few seconds...
Sub my_ONTIME()
application.OnTime Now + TimeValue("00:00:2"), "my_TIMEREVENT"
End Sub
Sub my_TIMEREVENT()
If application.Width <> EWIDTHR Then ESCREENRESIZE
my_ONTIME
End Sub
Sub ESCREENRESIZE()
Dim EWIDTH As Single
Dim ESIDE As Single
Dim EMID As Single
EWIDTH = application.Width
EWIDTHR = EWIDTH
If EWIDTH < 500 Then
EWIDTH = 500
application.Width = 500
End If
EMID = 80 * 5.41
ESIDE = ((EWIDTH - EMID) / 2) / 5.41
Sheet1.Columns("A:A").ColumnWidth = ESIDE
Sheet1.Columns("C:C").ColumnWidth = ESIDE
End Sub

Load shortcut then close form automatically

i want achieve when shortcut link runs ... the form closes automatically, btw im new to vb coding so any help will be much appreciated, here's my code so far
Private Sub Form_Load()
Set ss = CreateObject("WScript.Shell")
ss.Run Chr(34) & ss.specialfolders("Desktop") & "\app\SOMEGAME.lnk" & Chr(34)
End Sub
Assuming you're using VB6 (which is what your code looks like) you can close your form by calling
Unload Me
at the end of the Form_Load event handler.
However, you don't need to use a form to launch a shortcut - you can add a module to your project (right-click your project, select Add -> Module) and then just call the ShellExecute() function to launch your shortcut like so:
'Declare the ShellExecute() API function
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
Private Const SW_SHOWNORMAL As Long = 1
'Entry point of your program
Public Sub Main()
Dim sPath As String
sPath = "C:\app\SOMEGAME.lnk"
ShellExecute 0, vbNullString, sPath, vbNullString, "C:\", SW_SHOWNORMAL
End Sub
To make this work, set the Startup Object under Project Properties to Sub Main.
Using this approach, you don't have a form - your program just runs from the command-line (or from its own shortcut). It's generally better not to create / show a form if your program doesn't need it since forms use extra resources.
With that said, you should try using VB.Net or C# to write programs for Windows - VB6 is old technology without support and it can't handle a number of new technologies. If you don't already know VB6 there's little point in learning it now - your time could be put to much better use by learning VB.Net / C#.

How can I show a message box with two buttons?

How can I show a message box with two buttons (For example: "on", "off")?
You probably want to do something like this:
result = MsgBox ("Yes or No?", vbYesNo, "Yes No Example")
Select Case result
Case vbYes
MsgBox("You chose Yes")
Case vbNo
MsgBox("You chose No")
End Select
To add an icon:
result = MsgBox ("Yes or No?", vbYesNo + vbQuestion, "Yes No Example")
Other icon options:
vbCritical or vbExclamation
The VBScript Messagebox is fairly limited as to the labels you can apply to the buttons, your choices are pretty much limited to:
OK
Cancel
Retry
Abort
Ignore
Yes
No
So you are going to have to build your own form if you want "ON"/"OFF"
Better yet, why not rephrase the prompt in the box so one of the above options works.
For example:
Do you want the light on?
[Yes] [No]
And for God's sake don't do one of these UI monstrosities!
Switch setting? (Click "yes" for ON and "No" for Off)
[Yes] [No]
Remember - if you set the buttons to vbOkOnly - it will always return 1.
So you can't decide if a user clicked on the close or the OK button. You just have to add a vbOk option.
Cannot be done. MsgBox buttons can only have specific values.
You'll have to roll your own form for this.
To create a MsgBox with two options (Yes/No):
MsgBox("Some Text", vbYesNo)
It can be done, I found it elsewhere on the web...this is no way my work ! :)
Option Explicit
' Import
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare Function SetDlgItemText Lib "user32" _
Alias "SetDlgItemTextA" _
(ByVal hDlg As Long, _
ByVal nIDDlgItem As Long, _
ByVal lpString As String) As Long
Private Declare Function SetWindowsHookEx Lib "user32" _
Alias "SetWindowsHookExA" _
(ByVal idHook As Long, _
ByVal lpfn As Long, _
ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
' Handle to the Hook procedure
Private hHook As Long
' Hook type
Private Const WH_CBT = 5
Private Const HCBT_ACTIVATE = 5
' Constants
Public Const IDOK = 1
Public Const IDCANCEL = 2
Public Const IDABORT = 3
Public Const IDRETRY = 4
Public Const IDIGNORE = 5
Public Const IDYES = 6
Public Const IDNO = 7
Public Sub MsgBoxSmile()
' Set Hook
hHook = SetWindowsHookEx(WH_CBT, _
AddressOf MsgBoxHookProc, _
0, _
GetCurrentThreadId)
' Run MessageBox
MsgBox "Smiling Message Box", vbYesNo, "Message Box Hooking"
End Sub
Private Function MsgBoxHookProc(ByVal lMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
If lMsg = HCBT_ACTIVATE Then
SetDlgItemText wParam, IDYES, "Yes :-)"
SetDlgItemText wParam, IDNO, "No :-("
' Release the Hook
UnhookWindowsHookEx hHook
End If
MsgBoxHookProc = False
End Function
msgbox ("Message goes here",0+16,"Title goes here")
if the user is supposed to make a decision the variable can be added like this.
variable=msgbox ("Message goes here",0+16,"Title goes here")
The numbers in the middle vary what the message box looks like.
Here is the list
0 - ok button only
1 - ok and cancel
2 - abort, retry and ignore
3 - yes no and cancel
4 - yes and no
5 - retry and cancel
TO CHANGE THE SYMBOL (RIGHT NUMBER)
16 - critical message icon
32 - warning icon
48 - warning message
64 - info message
DEFAULT BUTTON
0 = vbDefaultButton1 - First button is default
256 = vbDefaultButton2 - Second button is default
512 = vbDefaultButton3 - Third button is default
768 = vbDefaultButton4 - Fourth button is default
SYSTEM MODAL
4096 = System modal, alert will be on top of all applications
Note: There are some extra numbers. You just have to add them to the numbers already there like
msgbox("Hello World", 0+16+0+4096)
from https://www.instructables.com/id/The-Ultimate-VBS-Tutorial/
I did
msgbox "TEXT HERE",3,"TITLE HERE"
If Yes=true then
(result)
else
msgbox "Closing..."
It is possible to make Custom Dialog boxes in 2021 that are just as easy as Msgboxes! Note this is for VB, not VB script.
First make a new form using the dialog box template. It includes two boxes already of which you can change the names/text:
Then back in your main code put this, where "Dialog1" is the name of your new dialog. This allows you to treat this form as a msgbox with just one line of code:
Dim dialogInstance As New Dialog1
Dim result As dialogResult = dialogInstance.ShowDialog()
The variable "result" will behave like a traditional OK/Cancel msgbox exactly like the options above, but will display your custom text on the buttons. From here you can add custom pictures to your msgbox and more!

Resources