VBS send mouse clicks? - vbscript

I need send mouse clicks from VBS. Like SendKeys. I have searched whole google, it seems there is no such function for VBS. Can you give me some solution?

Here is a routine to send a left or right click to a window (using relative references) in VBA for Excel. Similar to AppActivate, you just need the window title.
The arguments when you call the SendClick routine are:
Window Title (String)
Buttons (1 = Left, 2 = Right, -1 = Move mouse only; no click)
x (Relative position to window Left)
y (Relative position to window Top)
Enjoy!
'Declare mouse events
Public Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long
Public Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Public Const MOUSEEVENTF_LEFTDOWN = &H2
Public Const MOUSEEVENTF_LEFTUP = &H4
Public Const MOUSEEVENTF_RIGHTDOWN As Long = &H8
Public Const MOUSEEVENTF_RIGHTUP As Long = &H10
'Declare sleep
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
' Window location
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect As RECT) As Long
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Public Function WindowHandle(ByVal sTitle As String) As Long
WindowHandle = FindWindow(vbNullString, sTitle)
End Function
Public Sub SendClick(sWnd As String, b As Integer, x As Long, y As Long)
Dim pWnd As Long, pRec As RECT
pWnd = WindowHandle(sWnd)
GetWindowRect pWnd, pRec
SetCursorPos pRec.Left + x, pRec.Top + y
Sleep 50
If b = 2 Then
mouse_event MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0
Sleep 50
mouse_event MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0
ElseIf b <> -1 Then
mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
Sleep 50
mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
End If
End Sub

It's not possible with VBScript alone. You'll need to use a third-party tool like nircmd. You can use its setcursor, setcursorwin, movecursor, and sendmouse commands to manipulate the mouse.
For example, here's how to move the cursor to a screen coordinate (measured from the top left) and perform a right-click:
With CreateObject("WScript.Shell")
.Run "nircmd setcursor 100 100", 0, True
.Run "nircmd sendmouse right click", 0, True
End With
See the documentation for parameter information.

Try
Dim x
set x=createobject("wscript.shell")
x.sendkeys"{CLICK LEFT,50,60}"
or
x.SendKeys("+{F10}") 'for a right click
If neither of those work for you I would suggest using something like Autoit or autohotkey, using AutoHotKey you could write a macro that does the clicking and then call the script from your VBScript.

VBS is a script, not an application; VBScripts can call other applications or Component Objects to access elements of the host environment, just like batch files; eg. FileSystemObject to manipulate files.
There isn't one provided for mouse, so to move mouse or send mouse clicks, you'd need to call some app or COM object to do it, or make one.
Some apps that can manipulate the mouse are MSWord & MSExcel (via WinAPI calls), NirCmd, AutoIt, AutoHotKey, etc
Here's a VBApp example that calls functions of the User Component: user32.dll:
(Notice how the arguments are formatted before being sent to the DLL. This is not possible in VBS or batch files since they can only pass Strings as args; some functions expect data types eg. Int32, window handles or object references)
Option Strict On
Option Explicit On
Option Infer On
Imports System.Runtime.InteropServices
Public Class Mousing
Private Declare Auto Sub mouse_event Lib "user32" (ByVal dwFlags As Int32, ByVal dx As Int32, ByVal dy As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo As IntPtr)
Private Const MOUSEEVENTF_LEFTDOWN As Int32 = &H2
Private Const MOUSEEVENTF_LEFTUP As Int32 = &H4
Private Const MOUSEEVENTF_RIGHTDOWN As Long = &H8
Private Const MOUSEEVENTF_RIGHTUP As Long = &H10
<StructLayout(LayoutKind.Sequential)>
Private Structure RECT
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
End Structure
<DllImport("user32.dll")> _
Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, EntryPoint:="FindWindow")> _
Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Ansi, SetLastError:=True, ExactSpelling:=True)> _
Private Shared Function SetForegroundWindow(ByVal hwnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
' find the window
Dim hWnd As IntPtr = FindWindow(Nothing, "Some Window")
' check if window found
If hWnd.Equals(IntPtr.Zero) Then
MessageBox.Show("Window Not Found!", "Aborting", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Return ' exit
Else
' bring the window to the foreground
SetForegroundWindow(hWnd)
' get the windows size and location
Dim r As New RECT
GetWindowRect(hWnd, r)
'Move the cursor to the windows location plus our offset (x + 50 , y + 100)
Windows.Forms.Cursor.Position = New System.Drawing.Point(r.Left + 50, r.Top + 100)
' To move relative to screen, just enter coordinates above without offsetting
' click the left mouse button at the current mouse position
mouse_event(MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP, 0, 0, 0, IntPtr.Zero)
End If
End Sub
End Class
The following is a VBScript calling AutoIt to move mouse & click:
Set oAutoIt = WScript.CreateObject("AutoItX.Control")
set oShell = CreateObject("WScript.Shell")
oAutoIt.MouseMove x,y,0
WScript.Sleep 500
oAutoIt.MouseClick($MOUSE_CLICK_PRIMARY)
References:
http://www.vbforums.com/showthread.php?672196-RESOLVED-SetCursorPos
http://www.ericphelps.com/batch/rundll/
https://www.dostips.com/forum/viewtopic.php?t=3931
https://support.microsoft.com/en-au/help/152969/visual-basic-procedure-to-get-set-cursor-position
https://microsoft.public.scripting.vbscript.narkive.com/ZO09Cxnz/moving-mouse-pointer-with-vbs-file

Related

GET COLOR OF POINT

I want to write code in vb6
When the form is placed on the screen. and when click Button Return the colors me.top and me.left position.
I want this to be real-time(use timer)
my code:
Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Sub Command1_Click()
Label3 = (GetPixel(GetDC(Me.hdc), Me.Left, Me.Top))
End Sub
Private Sub Timer1_Timer()
Label1.Caption = Me.Left
Label2.Caption = Me.Top
End Sub
This code does not work and returns a value of -1
please help me
Using code from VB6 - Screen shot function, you should be able to get a valid value from GetPixel using something like this:
Dim Pixel As Long
Dim Left As Long
Dim Top As Long
Dim hDC As Long
' Get Desktop window
hDC = GetWindowDC(GetDesktopWindow)
' Use size of screen
Left = Me.Left \ Screen.TwipsPerPixelX
Top = Me.Top \ Screen.TwipsPerPixelY
Pixel = GetPixel(hDC, Left, Top)
This will give you a COLORREF from which you can extract the color of the pixel at the top left of your form.
You will need to Declare the following functions in a Module:
Declare Function GetPixel Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long) As Long
Declare Function GetDesktopWindow Lib "user32" () As Long
Declare Function GetWindowDC Lib "user32" (ByVal hWnd As Long) As Long
You can then extract the RGB values from that pixel using the following functions:
Function GetRedValue(ByVal color As Long) As Long
GetRedValue = color And &HFF&
End Function
Function GetGreenValue(ByVal color As Long) As Long
GetGreenValue = (color \ &H100&) And &HFF&
End Function
Function GetBlueValue(ByVal color As Long) As Long
GetBlueValue = (color \ &H10000) And &HFF&
End Function

The fastest way to change desktop folder location programmatically

I want to create an application that allows users to have different icons on different Windows 10 desktops. I can deal with the switching of virtual desktops using the Window Station and Desktop functions and the Virtual Desktop Shell Interface. So now I know how to detect that a desktop has been switched and I need to change the location of the Desktop User Folder as fast as possible.
I know there are two ways of doing this in the User Interface:
A) Via User Folders' properties
Open %HomePath%/Desktop in Explorer
Right click on background, open Properties
In tab Location type in the new path
Hit OK and then No (as you don't want to move the files)
Sometimes needed: click on desktop, press F2
.
B) Via Registry
Change Desktop in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders to the new address
Relog
.
The B option would be ideal for a programmatical solution if it wasn't for that relog part. Which is, as you can certainly understand, a bit of a dealbreaker.
The VB.Net code below will save all open desktop folder locations and sizes in the Windows registry and restore them on demand. Run from the command line or a batch file. To save folder attributes add a parameter of 'Set' (no quotes), to restore, no parameter.
Option Explicit On
Imports System.Text
Public Class FixFolders
Structure RECT
Dim Left As Integer
Dim Top As Integer
Dim Right As Integer
Dim Bottom As Integer
End Structure
Structure POINTAPI
Dim x As Integer
Dim y As Integer
End Structure
Structure WINDOWPLACEMENT
Dim length As Integer
Dim flags As Integer
Dim showCmd As Integer
Dim ptMinPosition As POINTAPI
Dim ptMaxPosition As POINTAPI
Dim rcNormalPosition As RECT
End Structure
Private Structure TDeskTopWindow
Dim lhwnd As Integer
Dim WinTitle As String
Dim WinRect As RECT
End Structure
Private Declare Function GetWindowRect Lib "user32" Alias "GetWindowRect" (ByVal hwnd As Integer, ByRef lpRect As RECT) As Integer
Declare Function MoveWindow Lib "user32" (ByVal hwnd As Int32, ByVal x As Int32, ByVal y As Int32, ByVal nWidth As Int32, ByVal nHeight As Int32, ByVal bRepaint As Int32) As Int32
Declare Function GetDesktopWindow Lib "user32" () As Int32
Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Int32, ByVal lpClassName As String, ByVal nMaxCount As Int32) As Int32
Private Delegate Function EnumChildWindowsCallback(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
Private Declare Function EnumChildWindows Lib "user32" (ByVal hWnd As IntPtr, ByVal lpEnumFunc As EnumChildWindowsCallback, ByVal lParam As IntPtr) As Boolean
Private Delegate Function EnumWindowsProcDelegate(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As EnumWindowsProcDelegate, ByVal lParam As IntPtr) As Boolean
Private Declare Auto Function GetWindowText Lib "user32" (ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As Integer
Private Declare Function SetFocusAPI Lib "user32" Alias "SetFocus" (ByVal hwnd As Int32) As Int32
Private Declare Function SetWindowPlacement Lib "user32" (ByVal hwnd As Integer, ByRef lpwndpl As WINDOWPLACEMENT) As Integer
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwbd As Int32) As Int32
'Private Declare Function FlashWindow Lib "User32" (ByVal hWnd As Int32, ByVal Invert As Int32) As Int32
Private Declare Function SetActiveWindow Lib "User32" (ByVal hWnd As Int32) As Int32
Private Shared lpwndplNew As WINDOWPLACEMENT
Private Const SW_SHOWMINIMIZED As Short = 2
Private Const SW_SHOWMAXIMIZED As Short = 3
Private Const SW_SHOWNORMAL As Short = 1
Private Shared Mode As String
Private WindowArray() As String
Private Shared DeskTopWindows() As TDeskTopWindow, DTWinIndex As Integer
Public Shared Sub Main()
Dim left, Right, Top, Bottom As Integer
Dim DTWinIndex As Integer
Dim RetVal1, RetVal2, RetVal3, TimeOut As Integer
Mode = Command()
GetDeskTopFolderWindows()
For DTWinIndex = 0 To DeskTopWindows.GetUpperBound(0)
Select Case Mode
Case ""
With DeskTopWindows(DTWinIndex)
'If it' s not there, put it in
If GetSetting("FixFolders", .WinTitle, "Left") = "" Then
SaveSetting("FixFolders", .WinTitle, "Left", .WinRect.Left.ToString)
SaveSetting("FixFolders", .WinTitle, "Right", .WinRect.Right.ToString)
SaveSetting("FixFolders", .WinTitle, "Top", .WinRect.Top.ToString)
SaveSetting("FixFolders", .WinTitle, "Bottom", .WinRect.Bottom.ToString)
End If
left = Val(GetSetting("FixFolders", .WinTitle, "Left"))
Right = Val(GetSetting("FixFolders", .WinTitle, "Right"))
Top = Val(GetSetting("FixFolders", .WinTitle, "Top"))
Bottom = Val(GetSetting("FixFolders", .WinTitle, "Bottom"))
While .WinRect.Bottom <> Bottom Or .WinRect.Left <> left Or .WinRect.Right <> Right Or .WinRect.Top <> Top
'RetVal1 = SetForegroundWindow(lhWnd)
RetVal2 = SetWindowPlacement(.lhwnd, lpwndplNew) 'This 'restores' the window if minimized
RetVal3 = MoveWindow(.lhwnd, left, Top, Right - left, Bottom - Top, True)
' Log.WriteLine(Now.TimeOfDay.ToString.Substring(0, 8) & " Set " & .WinTitle)
RetVal1 = GetWindowRect(.lhwnd, .WinRect) ' get current size
TimeOut += 1
If TimeOut > 1 And TimeOut < 10 Then Threading.Thread.Sleep(1000)
End While
End With
Case "Set"
With DeskTopWindows(DTWinIndex)
SaveSetting("FixFolders", .WinTitle, "Left", .WinRect.Left.ToString)
SaveSetting("FixFolders", .WinTitle, "Right", .WinRect.Right.ToString)
SaveSetting("FixFolders", .WinTitle, "Top", .WinRect.Top.ToString)
SaveSetting("FixFolders", .WinTitle, "Bottom", .WinRect.Bottom.ToString)
End With
End Select
Next
End Sub
Private Shared Sub GetDeskTopFolderWindows()
Dim lhwnd As Integer, lParam As IntPtr
DTWinIndex = -1
lhwnd = GetDesktopWindow() ' Find the Desktop's Child Windows
EnumChildWindows(lhwnd, AddressOf EnumChildProc, lParam)
End Sub
Shared Function EnumChildProc(ByVal lhWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
Dim RetVal1 As Int32
Dim WinClassBuf As String
Dim WinTitleBuf As New StringBuilder(256)
Dim WinClass As String
Dim WinRect As RECT
WinClassBuf = New String(Chr(0), 256)
WinTitleBuf.Append(Chr(0), 256)
RetVal1 = GetClassName(lhWnd, WinClassBuf, WinClassBuf.Length)
WinClass = WinClassBuf.ToString
WinClass = StripNulls(WinClassBuf) ' remove extra Nulls & spaces
If WinClass = "CabinetWClass" Or WinClass = "ExploreWClass" Then ' TextBox Window
DTWinIndex += 1
ReDim Preserve DeskTopWindows(DTWinIndex)
DeskTopWindows(DTWinIndex).lhwnd = lhWnd
GetWindowText(lhWnd, WinTitleBuf, WinTitleBuf.Capacity)
DeskTopWindows(DTWinIndex).WinTitle = WinTitleBuf.ToString
RetVal1 = GetWindowRect(lhWnd, WinRect) ' get current size
DeskTopWindows(DTWinIndex).WinRect = WinRect
End If
EnumChildProc = True
End Function
Public Shared Function StripNulls(ByVal OriginalStr As String) As String
' This removes the extra Nulls so String comparisons will work
If (InStr(OriginalStr, Chr(0)) > 0) Then
'OriginalStr = Left(OriginalStr, InStr(OriginalStr, Chr(0)) - 1)
OriginalStr = OriginalStr.Substring(0, OriginalStr.IndexOf(Chr(0)))
End If
StripNulls = OriginalStr
End Function
End Class

VB6 mouse hook to capture a control a user clicks

I have a keyboard hook that listens for [shift] + [F12] key button press to activate an edit mode in my program. By edit mode, I mean that any form that is inactive in the program window is disabled and focus is set to the active window. Furthermore, I alter the GUI to reflect that the user is running edit mode.
The purpose is of this all is to customize specific form controls that a user clicks on (e.g If they click on a label or combobox, a user would be able to edit the data that populates this information from a database). What I am really searching for is the ability to access the control name of the control that a user clicks on in the active form, DYNAMICALLY (without setting events on each form). Therefore, once a user clicks on a control such as a label, combo box, listview or listbox (on the active form), I would like to capture the control name clicked and pass that to another form that will handle the editing of this control.
You don't need to go to the trouble of using the API for what you want to do. All of the controls you mention expose a Click event. (If the control you want to use doesn't have a Click event, it almost certainly has a MouseDown event which will work just as well.) Just write a sub that takes the control as an argument and passes what info you want to the other form. Then in each of the controls (you can use control arrays for controls of the same type), call this sub. Something like this:
Sub DoTheWork(cCtl As Control)
Form2.CallSomeMethod(cCtl) 'Passes a reference to the entire control
Form2.CallSomeOtherMethod(cCtl.Name) 'Just passes the name
End Sub
Sub Command1_Click()
DoTheWork Command1
End Sub
Sub Label1_Click(Index As Integer) 'control array
DoTheWork Label1(Index)
End Sub
Now, if you really want to get involved in using SetWindowsHookEx and all that, here's a bit of annotated code that you can use to figure it out. This code allows you to change fonts on the MsgBox function, by substituting itself for any MsgBox call. (FYI, Microsoft implemented "CBT hooking" to support computer-based training back in the day, hence the term.)
'This code allows font changes and various other format customizations of the standard VB6 MsgBox dialog box. It
'uses CBT hooking to intercept an VB6-internal window call. In this case, it intercepts a MsgBox call, then gets
'a handle to the MsgBox window as well as its various child windows (the label containing the message text, any
'buttons, and an icon if it exists). It then resizes the window to accommodate the message text and other windows,
'and repositions the icon and any command buttons. Finally, it positions the msgbox window in the center of the
'screen.
'General Note: notes are above the line of code to which they apply.
Option Explicit
' Window size and position constants
Private Const ICON_WIDTH As Integer = 32
Private Const BTN_WIDTH As Integer = 75
Private Const BTN_HEIGHT As Integer = 23
Private Const BTN_SPACER As Integer = 6 ' Space between 2 buttons
Private Const STW_OFFSET As Integer = 12 ' Standard window offset, minimum distance one window can be from
' the edge of its container
' SendMessage constants that we will use
Private Const WM_SETFONT = &H30
Private Const WM_GETTEXT = &HD
' Necessary constants for CBT hooking
Private Const HCBT_CREATEWND = 3
Private Const HCBT_ACTIVATE = 5
Private Const WH_CBT = 5
' Working variables that require module-wide scope
Private hHook As Long
Private myFont As IFont
Private cPrompt As String
Private hwndStatic As Long
Private ButtonHandles() As Long
Private xPixels As Long
Private yPixels As Long
Private isIcon As Boolean
' The API Type declarations we need
Private Type SIZE
cx As Long
cy As Long
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
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
'GETTEXT needs a String argument for lParam, SETFONT needs an Any argument there, hence 2 declarations for SendMessageA
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Private 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 Long) 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 EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
' Wrapper for the normal MsgBox function
Public Function myMsgBox(Prompt As String, Buttons As VbMsgBoxStyle, ByVal fSize As Integer, ByVal fBold As Boolean, ByVal fItalic As Boolean, ByVal fULine As Boolean, fFaceName As String, Optional Title As String, Optional HelpFile As String, Optional Context As Long, Optional x As Long, Optional y As Long) As Long
'x and y arguments are optional and are in twips. If not specified, msgbox will use default window sizes
'and positions, which work fine if you are using default font sizes. If you aren't they may not.
cPrompt = Prompt
Set myFont = New StdFont
With myFont ' We can make whatever adjustments we like here to the font
.SIZE = fSize
.Bold = fBold
.Italic = fItalic
.Underline = fULine
.Name = fFaceName
End With
'Convert x and y arguments to pixels from twips. (Twips are the same size no matter what the screen resolution; pixels aren't.)
If Not IsMissing(x) Then
xPixels = Int(x / Screen.TwipsPerPixelX)
End If
If Not IsMissing(y) Then
yPixels = Int(y / Screen.TwipsPerPixelY)
End If
'Set up the hook to catch windows messages, call CBTProc when there is one
hHook = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, App.hInstance, 0)
'This will call CBTProc, passing the handle of the MsgBox window to the wParam argument.
myMsgBox = MsgBox(Prompt, Buttons, Title, HelpFile, Context)
End Function
Private Function CBTProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim i As Integer
Dim statX As Integer 'X dimension of static (text) window
Dim statY As Integer 'Y dimension of same
Dim cLeft As Integer 'Current Left value for current button, used to position buttons along x axis
Dim rc As RECT 'Used with GetClientRect
If lMsg = HCBT_ACTIVATE Then
'Immediately unhook (we have the event we're looking for, and don't want to handle any more CBT events)
UnhookWindowsHookEx hHook
'Call EnumChildWindowProc once for each window that is contained in the MsgBox (each button and frame is a child window)
EnumChildWindows wParam, AddressOf EnumChildWindowProc, 0
'Reinitialize the static buttoncount variable, see the notes in the proc
EnumChildWindowProc 0, 1
'Should always be true, but this prevents an abend if for some reason we fail to get the text window
If hwndStatic Then
'If the x parameter has been supplied to the main wrapper, then xPixels <> 0
If xPixels <> 0 Then
With Screen
'Center the MsgBox window in the screen
SetWindowPos wParam, 0, (.Width / .TwipsPerPixelX - xPixels) / 2, _
(.Height / .TwipsPerPixelY - yPixels) / 2, xPixels, yPixels, 0
End With
'Analogous to the ScaleWidth and ScaleHeight properties. Client rectangle's dimensions are
'returned to the rc type and exclude the dimensions of the title bar and the borders.
GetClientRect wParam, rc
'Calculate x and y values for text window. If there's an icon, we need to reduce the size of the
'text window by the width of the icon plus a standard offset value.
statX = rc.Right - rc.Left - STW_OFFSET * 2 - ((isIcon And 1) * (ICON_WIDTH + STW_OFFSET))
statY = rc.Bottom - rc.Top - BTN_HEIGHT - STW_OFFSET * 2
'We need to position the text window along the x axis such that it's a standard offset from the left
'border of the msgbox, plus the width of the icon and another standard offset if the icon exists.
SetWindowPos hwndStatic, 0, STW_OFFSET + (isIcon And 1) * (ICON_WIDTH + STW_OFFSET), STW_OFFSET, statX, statY, 0
isIcon = 0
'Loop through the button handles, calculating the left border position each time.
For i = 0 To UBound(ButtonHandles)
'Current left border is half the container window's width, less the width of half the total
'number of buttons, plus the offset of the current button in the array.
cLeft = Int(xPixels / 2 + BTN_WIDTH * (i - (UBound(ButtonHandles) + 1) / 2))
'Modify the above to add button spacer widths.
cLeft = cLeft + BTN_SPACER * (i - (UBound(ButtonHandles) - 1) + (UBound(ButtonHandles) Mod 2) / 2)
'The Y value is 1 standard offset more than the height of the text window.
SetWindowPos ButtonHandles(i), 0, cLeft, statY + STW_OFFSET, BTN_WIDTH, BTN_HEIGHT, 0
Next
End If
SendMessage hwndStatic, WM_SETFONT, myFont.hFont, True
End If
End If
CBTProc = 0 ' allow operation to continue
End Function
Private Function EnumChildWindowProc(ByVal hChild As Long, ByVal lParam As Long) As Long
Static ButtonCount As Integer
Dim sLen As Integer
Dim wClass As String
Dim wText As String
Dim rc As RECT
If lParam Then
ButtonCount = 0 'See the direct call of this proc in CBTProc: resets the ButtonCount variable to 0
Exit Function
End If
wClass = String(64, 0)
'look up the type of the current window
sLen = GetClassName(hChild, wClass, 63)
wClass = Left(wClass, sLen)
'We have either one or two static windows: optionally the icon (the first window if it's there) and the
'text window (analogous to a label control).
If wClass = "Static" Then
'If we already have the text window's handle, we don't need to do this anymore.
If Not hwndStatic Then
'Find out if the current window's text value is the same as the text passed in to the cPrompt
'argument in the main wrapper function. If it is, it's the text window and we store the handle
'value in hwndStatic. If it isn't, then it's an icon and we set the isIcon flag.
wText = String(Len(cPrompt) + 1, 0)
sLen = SendMessageS(hChild, WM_GETTEXT, 255, wText)
wText = Left(wText, sLen)
If wText = cPrompt Then
hwndStatic = hChild
Else
isIcon = True
End If
End If
ElseIf wClass = "Button" Then
'Store the button's handle in the ButtonHandles array
ReDim Preserve ButtonHandles(ButtonCount)
ButtonHandles(ButtonCount) = hChild
ButtonCount = ButtonCount + 1
End If
EnumChildWindowProc = 1 ' Continue enumeration
End Function

GetWindowText does not work

I'm trying to retrieve the text from an EDIT control using GetWindowText and GetWindowTextLength. The application retrieves the text from the window under the cursor and it works on all windows with a caption or text with the exception of the EDIT control. The EDIT control is the result window on the Windows XP Calculator, calc.exe.
Dim S As String
Dim L As Long
L = GetWindowTextLength(handle) + 1
Receiving string = GetWindowText(handle, S, L)
EDIT:
According to SPY++ the Edit class control does not receive the EM_GETSELTEXT or the WM_GETTEXT message.The code below retrieves the text from the Edit class control on the Windows XP calc.exe calculator every time that I press a button on my UI. It is not the method that I would have preferred to use, however, it accomplishes my task.
Const EM_SETSEL = &HB1
Const ES_READONLY = &H800
Const WM_COPY = &H301
Const EM_GETSELTEXT = &H43E
Const WM_GETTEXTLENGTH = &HE
Const WM_SETFOCUS As Long = &H7
Dim L As Long
L = SendMessage(EditHwnd, WM_GETTEXTLENGTH, 0&, 0)
SendMessage EditHwnd, WM_SETFOCUS, 0&, 0
SendMessage EditHwnd, EM_SETSEL, 0&, L
SendMessage EditHwnd, ES_READONLY, 0&, 0 ' read only = false
Clipboard.Clear
SendMessage EditHwnd, WM_COPY, 0&, 0
SendMessage EditHwnd, ES_READONLY, 1&, 0 ' read only = true
Receiving string = Clipboard.GetText
Clipboard.Clear
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd 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
Function GetText(handle As Long) As String
Dim S As String, L As Integer, cch As Long
L = GetWindowTextLength(handle) + 1
S = String(L, 0)
GetText = Mid(S, 1, GetWindowText(handle, S, L))
End Function
Private Sub Form_Load()
Dim hw As Long
hw = Me.hwnd
MsgBox GetText(hw)
End Sub
But it will not work with controls like EDIT, as it is written in help. ;( In order to get the text of the child window (control), try to get a list of all windows using API EnumWindows/EnumThreadWindows/GetWindowThreadProcessId, to find the desired control.
What is the name of the class to EDIT You need? What is its width and height? I could write code specifically for the search for this control.
this code works fine in Windows XP (virtual machine)
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As Any, ByVal lpsz2 As Any) 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 AttachThreadInput Lib "user32.dll" _
(ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long
Private Const WM_GETTEXT As Long = &HD&
Private Const WM_GETTEXTLENGTH As Long = &HE&
Function WindowText(ByVal hWnd As Long) As String
Dim ret As Long
ret = SendMessage(hWnd, WM_GETTEXTLENGTH, 0, ByVal 0&)
WindowText = String(ret, 0)
ret = SendMessage(hWnd, WM_GETTEXT, ret + 1, ByVal WindowText)
End Function
Private Sub Command1_Click()
Dim hCalc As Long, hEdit As Long
hCalc = FindWindow("SciCalc", vbNullString)
hEdit = FindWindowEx(hCalc, 0&, "Edit", vbNullString)
MsgBox WindowText(hEdit)
End Sub

Visual Basic RBG Capture from Screen

I am needing code that will run in visual basic to capture the screen and convert it to a RBG array of pixel values - needs to be quite fast.
Any help?
This code will capture a screenshot from a window or the entire desktop (virtual screen) and draw it to a custom picturebox.
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect As RECT) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
Private Const SM_XVIRTUALSCREEN = 76
Private Const SM_YVIRTUALSCREEN = 77
Private Const SM_CYVIRTUALSCREEN = 79
Private Const SM_CXVIRTUALSCREEN = 78
Private Sub GetScreenshot(Optional ByVal hWnd As Long = 0)
Dim hDC As Long
Dim WindowRect As RECT
Dim Left As Long
Dim Top As Long
Dim Width As Long
Dim Height As Long
If hWnd = 0 Then
'Get the DC of the desktop
hDC = GetWindowDC(GetDesktopWindow)
'Get the virtual screen coordinates (this handles multiple monitors too :)
Left = GetSystemMetrics(SM_XVIRTUALSCREEN)
Top = GetSystemMetrics(SM_YVIRTUALSCREEN)
Width = GetSystemMetrics(SM_CXVIRTUALSCREEN)
Height = GetSystemMetrics(SM_CYVIRTUALSCREEN)
Else
'Get the DC of the window we want to capture
hDC = GetWindowDC(hWnd)
'Get the window coordinates
GetWindowRect hWnd, WindowRect
Left = 0
Top = 0
Width = WindowRect.Right - WindowRect.Left
Height = WindowRect.Bottom - WindowRect.Top
End If
'BitBlt into our own DC
BitBlt picScreen.hDC, 0, 0, Width, Height, hDC, Left, Top, vbSrcCopy
'Delete our reference to the windows's DC
ReleaseDC hWnd, hDC
End Function
Note the use of GetSystemMetrics() when capturing the desktop. This allows it to get the full virtual screen screen dimensions when multiple monitors are in use instead of just the primary monitor.

Resources