I have a code to perform data entry from an excel sheet to a website which opens in google chrome. The code is working absolutely fine. I just want both the excel and chrome windows positioned on top side by side while macro is running. The excel window gets positioned to left perfectly however there is no impact on chrome window. I couldn't figure out the solution after googling a lot. Chrome and data entry is being controlled by Selenium.
'This part has code to import window resizing functions.
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function GetWindowRect Lib "user32" ( _
ByVal hWnd As Long, lpRect As RECT) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _
ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long
Private Declare Function MoveWindow Lib "user32" ( _
ByVal hWnd As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, _
ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Declare Function BringWindowToTop Lib "user32" (ByVal hWnd As Long) As Long
Sub Selenuim_Upload()
Dim test1 As Long, test2 As Long
test1 = Timer
Dim obj As New WebDriver
obj.Start "chrome", ""
obj.Get "https://csa.xyz.com/"
obj.FindElementById("ContentPlaceHolder1_ddlUserProfile").SendKeys ("Collector")
obj.FindElementById("ContentPlaceHolder1_btn_login").Click
obj.Get "https://csa.xyz.com/Collector_view.aspx/Default.aspx/"
'------------------------------------------------------------------------
' This part calculates window sizes and moves Excel window to left and IE window to right.
Dim hWnd As Long
Dim R As RECT, LW As RECT, RW As RECT
'Get the size of the deskop
If GetWindowRect(GetDesktopWindow, R) = 0 Then Exit Sub
'Calculate the left and right side
LW = R
LW.Right = R.Left + (R.Right - R.Left) / 2
RW = R
RW.Left = R.Right - (R.Right - R.Left) / 2
'Move Excel to the left
hWnd = FindWindow("XLMAIN", vbEmpty)
With LW
MoveWindow hWnd, .Left, .Top, .Right - .Left, .Bottom - .Top, True
End With
BringWindowToTop hWnd
'Move Chrome to the right
hWnd = FindWindow("Chrome_WidgetWin_1", vbEmpty)
With RW
MoveWindow hWnd, .Left, .Top, .Right - .Left, .Bottom - .Top, True
End With
BringWindowToTop hWnd
'------------------------------------------------------------------------
'Select Invoice Number in Serch By box
obj.FindElementById("ContentPlaceHolder1_ddlSearch").SendKeys ("Inv Number")
Range("A1").Select
'REST OF THE CODE CONTINUES FROM HERE
I have figured out the solution. Thanks to this thread link . I used winlister (by nirsoft) to find the window title of that website that the macro was opening. Then replaced that with vbEmpty in hWnd = FindWindow("Chrome_WidgetWin_1", vbEmpty) so the final line of code is like hWnd = FindWindow("Chrome_WidgetWin_1", "https://csa.xyz.com/Collector_view.aspx/Default.aspx/ - Google Chrome") .
Now the code is able to arrange both excel and chrome window side by side.
Related
I'm trying to add ControlTipText's to all MSForms.Control in all Userforms, that can be displayed.
Once all of them are Added, I want to Show all ControlTipText's on pressing 'Alt', so I can easily edit the Controltips on the Excel-Sheet.
Taking Baby-Steps, I first 'tried' to instantly make the ControlTip Visible when adding the Value to it.
What I have now is:
Dim tips As Worksheet
Set tips = Worksheets("CONTROLTIPS")
Dim i As Integer
Dim ctrl As MSForms.Control
i = 0
For Each ctrl In uf.Controls
ctrl.ControlTipText = tips.Cells(i + 3, 2).Value
' ctrl .... ("TIPTEXT").Visible = True ?!?
i = i + 1
Next ctrl
There is no direct way to show the tooltip of a control. The only way is to simulate the mouse hover using APIs. Here is a very basic example. Feel free to amend it to suit your needs.
Prep:
Create a blank userform
Place a commandbutton on the userform and set it's control tip text to whatever you want.
Logic:
When the ALT key is pressed, move the mouse over the relevant control thereby triggering the control tip text
Code
Paste this code in the userform
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "Gdi32" _
(ByVal hDC As Long, ByVal nIndex As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
(ByVal hwnd As Long, ByVal hDC As Long) As Long
Private Declare Function ClientToScreen Lib "user32" _
(ByVal hwnd As Long, lpPoint As POINTAPI) As Long
Private Declare Function SetCursorPos Lib "user32" _
(ByVal X As Long, ByVal Y As Long) As Long
Private Const Xindex = 88
Private Const Yindex = 90
Private Type POINTAPI
X As Long
Y As Long
End Type
'~~> Trap the Alt key in the keydown eveent
Private Sub CommandButton1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 18 Then MoveMouseOnTopOf Me, CommandButton1
End Sub
'~~> Simulate mouse hover
Public Sub MoveMouseOnTopOf(frm As Object, ctl As Object)
Dim P As POINTAPI
Dim usrfrmHwnd As Long
Dim hDC As Long
Dim X As Double, Y As Double
hDC = GetDC(0)
X = 72 / GetDeviceCaps(hDC, Xindex)
Y = 72 / GetDeviceCaps(hDC, Yindex)
ReleaseDC 0, hDC
P.X = (ctl.Left + (ctl.Width \ 2)) / X
P.Y = (ctl.Top + (ctl.Height \ 2)) / Y
usrfrmHwnd = FindWindow(vbNullString, frm.Caption)
ClientToScreen usrfrmHwnd, P
SetCursorPos P.X, P.Y
End Sub
You can read and understand about the APIs used above in the AllAPI site.
I want to Show all ControlTipText's on pressing 'Alt'
As far as I can tell, this seems to be the reason for you starting this thread.
The values from control tips are stored in the .ControlTipText function. AFAIK the ALT button will not show all control tips, nor is there a similar alternative. What you CAN do, is show all control tips together with their respective controls in a message box:
Private Sub UserForm_Initialize
Dim ctrl As Control
For Each ctrl In Me.Controls
txt = txt & ctrl.Name & ": " & ctrl.ControlTipText & vbNewLine
Next ctrl
MsgBox txt
End Sub
Currently we have some reports in Excel that we use as dashboards for TV screens in various departments. We set these to full screen mode to hide ribbons etc, but the title bar at the very top still shows. I have some code I can use to hide this, but it only works for 32 bit Excel. I need this to work for 64 bit as well (or instead).
The code I have been using for 32 bit is as below.
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long
Private Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SetFocus Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function LockWindowUpdate Lib "user32" (ByVal hWndLock As Long) As Long
Private Const GWL_STYLE As Long = (-16) '// The offset of a window's style
Private Const GWL_EXSTYLE As Long = (-20) '// The offset of a window's extended style
Private Const WS_CAPTION As Long = &HC00000 '// Title bar bit
Private Const WS_SYSMENU As Long = &H80000 '// System menu bit
Private Const WS_THICKFRAME As Long = &H40000 '// Sizable frame bit
Private Const WS_MINIMIZEBOX As Long = &H20000 '// Minimize box bit
Private Const WS_MAXIMIZEBOX As Long = &H10000 '// Maximize box bit
Private Const WS_EX_TOOLWINDOW As Long = &H80 '// Tool Window: small titlebar bit
Private Const SC_CLOSE As Long = &HF060 'Constant to identify the Close menu item
'// Set or clear a bit from a style flag
Private Sub SetBit(ByRef lStyle As Long, ByVal lBit As Long, ByVal bOn As Boolean)
If bOn Then
lStyle = lStyle Or lBit
Else
lStyle = lStyle And Not lBit
End If
End Sub
Public Sub SetStyleHide()
Dim lStyle As Long, hMenu As Long
'Get the basic window style
lStyle = GetWindowLong(Application.hwnd, GWL_STYLE)
If lStyle = 0 Then
MsgBox "Unable to determine application window handle...", vbExclamation, "Error"
Exit Sub
End If
'// Build up the basic window style flags for the form adapted to the application window not UF's
SetBit lStyle, WS_CAPTION, False
SetBit lStyle, WS_SYSMENU, False
SetBit lStyle, WS_THICKFRAME, False
SetBit lStyle, WS_MINIMIZEBOX, False
SetBit lStyle, WS_MAXIMIZEBOX, False
'Set the basic window styles
SetWindowLong Application.hwnd, GWL_STYLE, lStyle
'Get the extended window style
lStyle = GetWindowLong(Application.hwnd, GWL_EXSTYLE)
'// Handle the close button
'// hMenu = GetSystemMenu(Application.hWnd, 1)
'// Not wanted - delete it from the control menu
hMenu = GetSystemMenu(Application.hwnd, 0)
DeleteMenu hMenu, SC_CLOSE, 0&
'Update the window with the changes
DrawMenuBar Application.hwnd
SetFocus Application.hwnd
End Sub
Public Sub SetStyleShow()
Dim lStyle As Long, hMenu As Long
'Get the basic window style
lStyle = GetWindowLong(Application.hwnd, GWL_STYLE)
If lStyle = 0 Then
MsgBox "Unable to determine application window handle...", vbExclamation, "Error"
Exit Sub
End If
'// Build up the basic window style flags for the form adapted to the application window not UF's
SetBit lStyle, WS_CAPTION, True
SetBit lStyle, WS_SYSMENU, True
SetBit lStyle, WS_THICKFRAME, True
SetBit lStyle, WS_MINIMIZEBOX, True
SetBit lStyle, WS_MAXIMIZEBOX, True
'Set the basic window styles
SetWindowLong Application.hwnd, GWL_STYLE, lStyle
'Get the extended window style
lStyle = GetWindowLong(Application.hwnd, GWL_EXSTYLE)
'// Handle the close button
'// hMenu = GetSystemMenu(Application.hWnd, 1)
'// Not wanted - delete it from the control menu
'hMenu = GetSystemMenu(Application.hwnd, 0)
'DeleteMenu hMenu, SC_CLOSE, 0&
'Update the window with the changes
DrawMenuBar Application.hwnd
SetFocus Application.hwnd
End Sub
This works fine for 32 bit, but errors if I run it on a 64 bit version. Is there any way around this?
I have searched a lot for a way to minimize the window of the driver in selenium for excel vba. I have found ways for Java and python and tried to adopt them but all my tries failed
I just found a way to maximize the window using
bot.Window.Maximize
But when trying to use Minimize I got an error
Again I am searching for excel vba as for selenium ...
Thanks advanced for help
AFAIK there is no method for this in VBA implementation (there is in Python for example). There are a number of ways to manipulate size and position e.g.
bot.Window.SetSize 0, 0
Or you can run headless
bot.AddArgument "--headless"
You might also try to:
1) Emulate Windows Key + Down
2) Write a javscript function that performs window.minimize() and async execute off the parent window
3) Capture your target co-ordinates by generating a GetWindowPlacement call along with implementing your own WINDOWPLACEMENT struct. Looks like gets ugly fast.
See also:
Getting the size of a minimized window
Driver.Window.SetSize 0, 0
just made the window smaller, without minimizing the browser to the taskbar.
How to use GetWindowPlacement in selenium vba?
'for vb6
Private Type POINTAPI
x As Long
y As Long
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type WINDOWPLACEMENT
Length As Long
flags As Long
showCmd As Long
ptMinPosition As POINTAPI
ptMaxPosition As POINTAPI
rcNormalPosition As RECT
End Type
Private Declare Function GetWindowPlacement Lib "user32" (ByVal hwnd As Long, lpwndpl As WINDOWPLACEMENT) As Long
Private Sub Command1_Click()
Dim wp As WINDOWPLACEMENT
wp.Length = Len(wp)
GetWindowPlacement targetHandle, wp
End Sub
Minimize window by windows API
This is a workaround for Selenium VBA not having a working minimize window option.
''compiler constants
#If VBA7 Then
Public Declare PtrSafe Function ShowWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal nCmdShow As Long) As Boolean
Public Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
Public Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
#Else
Public Declare Function ShowWindow Lib "USER32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Boolean
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Public 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
#End If
Dim hwnd As Long
Dim Botwindowtitle As String
bot.Start
Botwindowtitle = bot.Window.Title
hwnd = GetAllWindowHandles(Botwindowtitle)
Call ShowWindow(hwnd, 7) 'Show the window minimized (SW_SHOWMINNOACTIVE = 7) http://www.jasinskionline.com/windowsapi/ref/s/showwindow.html
bot.Get "https://www.google.com/"
Private Function GetAllWindowHandles(partialName As String) As Long
Dim hwnd As Long, lngRet As Long
Dim strText As String
Dim hWndTemp As Long
hwnd = FindWindowEx(0&, 0&, vbNullString, vbNullString)
Do While hwnd <> 0
strText = String$(100, Chr$(0))
lngRet = GetWindowText(hwnd, strText, 100)
If InStr(1, strText, partialName, vbTextCompare) > 0 Then
Debug.Print "Window Handle:" & hwnd & vbNewLine & _
"Window title:" & Left$(strText, lngRet) & vbNewLine & _
"----------------------"
hWndTemp = hwnd
GetAllWindowHandles = hWndTemp
End If
'~~> Find next window
hwnd = FindWindowEx(0&, hwnd, vbNullString, vbNullString)
Loop
End Function
I need to place a userform next to a selected cell. Here's my code. Excel 2013.
In the userform module:
Private rangePosition As Range 'Property passed to form to set position based on range
'Set userform position to right of range
Property Let PositionToRange(rangeInput As Range)
Set rangePosition = rangeInput
Me.Left = rangePosition.Left + rangePosition.Width + 30
Me.Top = rangePosition.Top + Application.CommandBars("Ribbon").Height + 27
End Property
In a standard module:
userform.PositionToRange = Selection '(or some specified range)
userform.Show
Okay, great. So at first this seemed to do the trick. However, it only seems to work in the standard view when Excel first loads, with the first 30 rows or so. However, if you try to use it on, say, row 4000, or even 40, it places the userform WAY off the screen. Excel doesn't seem to take the position of the screen into account. To see what I mean, try using the code above to place a userform next to cell A1. Then scroll down so A1 is no longer on the screen and run the code again. It puts the userform in exactly the same place, as if you were still scrolled up in the original position.
Is there an attribute I can use other than range.Left, etc to place the userform relative to where the range is on the screen? Or do I need to do some weird voodoo crap where I figure out the position of the scroll bar and find the position of the cell relative to that, after factoring in the rotational force of the earth and relative distance from the sun, of course?
Oh, Microsoft...
You can adjust the position of the form when it is scrolled by using the
ActiveWindow.VisibleRange.Top &
ActiveWindow.VisibleRange.Left
Use this it will work in all cases
Me.Left = ActiveCell.Left + ActiveCell.Width - ActiveWindow.VisibleRange.Left
Me.Top = ActiveCell.Top - ActiveWindow.VisibleRange.Top
By declaring the GetDeviceCaps , GetDC , ReleaseDC
functions , I repositioned the userform next to each the clicked
activecell .(The template is checked in 32-bit and 64-bit Excel versions)
Type POINTAPI
X As Long
Y As Long
End Type
#If VBA7 Then
Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDc As LongPtr, ByVal nIndex As Long) As Long
Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDc As LongPtr) As Long
Dim hDc As LongPtr
#Else
Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDc As Long, ByVal nIndex As Long) As Long
Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDc As Long) As Long
Dim hDc As Long
#End If
...
Source codes , sample file link
I have a UserForm I've created in Excel 2010 using VBA. Controls are added to the form programmatically based on data from a particular sheet. My code adds all the controls and then determines if the form is excessively long. If it is, then the form gets set to a maximum height of 500px and scrolling is enabled.
The scrollbars appear and work as expected when clicking on the scrollbars, but the mouse scrollwheel has no effect on the scrollbars on the form.
I haven't seen any properties for enabling mouse wheel scrolling. Every article I've found on Google points to scrolling controls within a UserForm (ListBox, ComboBox, etc.) and not the UserForm itself. Other articles I've found are dated back to Excel 2003 which did not support mouse wheel scrolling out of the box.
Does anyone have any idea what's going on here?
Here is the code where I enable scrolling:
If Me.height > 500 Then
Me.ScrollHeight = Me.height
Me.ScrollBars = fmScrollBarsVertical
Me.KeepScrollBarsVisible = fmScrollBarsVertical
Me.height = 500
Me.Width = Me.Width + 12
End If
I am using Excel 2010 (32bit) on a Windows 7 64bit laptop. The same issue has appeared on other computers as well also running the same setup. I don't have access to another configuration to test this.
You can get it to work only on 32-bit Excel. The code won't compile and run at all under 64-bit Excel. Though I made (little bit more complicated) version that is compatible with both 32-bit and 64-bit, but it just don't scrolls on 64-bit, but at least compiles (please let me know if somebody needs that 64-bit compatible code).
So, you create a new module and paste there code for WinAPI calls:
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Const GWL_STYLE As Long = (-16) 'The offset of a window's style
Private Const WS_SYSMENU As Long = &H80000 'Style to add a system menu
Private Const WS_MINIMIZEBOX As Long = &H20000 'Style to add a Minimize box on the title bar
Private Const WS_MAXIMIZEBOX As Long = &H10000 'Style to add a Maximize box to the title bar
'To be able to scroll with mouse wheel within Userform
Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" ( _
ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
Private Const GWL_WNDPROC = -4
Private Const WM_MOUSEWHEEL = &H20A
Dim LocalHwnd As Long
Dim LocalPrevWndProc As Long
Dim myForm As UserForm
Private Function WindowProc(ByVal Lwnd As Long, ByVal Lmsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'To handle mouse events
Dim MouseKeys As Long
Dim Rotation As Long
If Lmsg = WM_MOUSEWHEEL Then
MouseKeys = wParam And 65535
Rotation = wParam / 65536
'My Form s MouseWheel function
'=================================================================
YOUR_USERFORM_NAME_HERE.MouseWheel Rotation
'=================================================================
End If
WindowProc = CallWindowProc(LocalPrevWndProc, Lwnd, Lmsg, wParam, lParam)
End Function
Public Sub WheelHook(PassedForm As UserForm)
'To get mouse events in userform
On Error Resume Next
Set myForm = PassedForm
LocalHwnd = FindWindow("ThunderDFrame", myForm.Caption)
LocalPrevWndProc = SetWindowLong(LocalHwnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub
Public Sub WheelUnHook()
'To Release Mouse events handling
Dim WorkFlag As Long
On Error Resume Next
WorkFlag = SetWindowLong(LocalHwnd, GWL_WNDPROC, LocalPrevWndProc)
Set myForm = Nothing
End Sub
And then you add a simple code to your userform... (don't forget to replace "frames_(mouseOverFrame_)") with name of your UI control you want to scroll.
Public Sub MouseWheel(ByVal Rotation As Long)
'************************************************
' To respond from MouseWheel event
' Scroll accordingly to direction
'
' Made by: Mathieu Plante
' Date: July 2004
'************************************************
Select Case frames_(mouseOverFrame_).ScrollTop - Sgn(Rotation) * 18
Case Is < 0
frames_(mouseOverFrame_).ScrollTop = 0
Case Is > frames_(mouseOverFrame_).ScrollHeight
frames_(mouseOverFrame_).ScrollTop = frames_(mouseOverFrame_).ScrollHeight
Case Else
frames_(mouseOverFrame_).ScrollTop = frames_(mouseOverFrame_).ScrollTop - Sgn(Rotation) * 18
End Select
End Sub
Because I wanted to scroll three different frames (depending on which frame is currently under mouse cursor) - I made a collection of three frames and used "MouseMove" event on each frame to assign frame number to "mouseOverFrame_" variable. So when mouse moved e.g. over 1st frame, the scroller will know which frame to scroll by having "1" inside "mouseOverFrame_" variable...