As the title suggests I am trying to move my mouse cursor to an element in a HTML document, some details I think I should share first:
Browser: Internet Explorer 11
IDE: Ms Excel VBA
Monitor resolution: Single monitor and dual monitor (extended), both resolution 1920x1080
I am using getBoundingClientRect to get the HTML element position and ClientToScreen to map that location to screen location and finally SetCursorPos to set the mouse position. The problem I am facing is that it looks like there is always a non-fixed offset somewhere moving my cursor to the wrong location. Even when trying on a website such as Google's homepage.
From troubleshooting, placing my mouse at the tip of the IE content area (presumable location 0,0 for getBoundingClientRect) the results show that after running ClientToScreen the location of Y is off but quite a few pixels.
Set to (0,0) position X: 0 ; Y:0 'Manually set variables to 0,0 position
GetCursorPos X: 2400 ; Y:161 'Placed my mouse at the presumed 0,0 position for reference
ClientToScreen position X: 2400 ; Y:-10 'After ClientToScreen position Y position is not as expected, at least to me
Below is the code I used, you can simply open an IE window and navigate to http://www.google.com then run the macro.
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function SetCursorPos Lib "user32" (ByVal X As Long, ByVal Y As Long) As Long
Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare PtrSafe Function ClientToScreen Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
Private Declare PtrSafe 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)
Private Const MOUSEEVENTF_RIGHTDOWN As Long = &H8
Private Const MOUSEEVENTF_RIGHTUP As Long = &H10
Public Type POINTAPI
X As Long
Y As Long
End Type
Sub test()
Dim testDoc As HTMLDocument
Dim testDiv As HTMLDivElement
Dim ieWindow As InternetExplorer
Dim hwnd As Long
Dim pntCursor As POINTAPI
Dim pntRet As Long
Dim curPos As POINTAPI
For Each w In CreateObject("Shell.Application").Windows
With w
If .Name = "Internet Explorer" Then
Set ieWindow = w
Exit For
End If
End With
Next w
Set testDoc = ieWindow.document
Set testDiv = testDoc.getElementById("hplogo")
hwnd = 0
hwnd = FindWindow("IEFrame", vbNullString)
pntCursor.X = testDiv.getBoundingClientRect().Left
pntCursor.Y = testDiv.getBoundingClientRect().Top
pntRet = ClientToScreen(hwnd, pntCursor)
pntRet = SetCursorPos(pntCursor.X, pntCursor.Y)
SetCursorPosition = (pntRet <> 0)
mouse_event MOUSEEVENTF_RIGHTDOWN, 0&, 0&, 0&, 0&
mouse_event MOUSEEVENTF_RIGHTUP, 0&, 0&, 0&, 0&
End Sub
Here I am trying to move the cursor to the Google Logo but this is where my mouse ends up (top left of the right click menu).
I've already spent 3 days on just this issue and cannot find enough details online that explains this issue. Any help will be greatly appreciated.
I'm trying to position a couple of external windows from within my application but either end up with just a piece of the title bar on screen near the top left or the window goes far to the right and ends up at x = 32767
The function declarations are in a module and the Move_Notepad Sub is part of a form.
Option Explicit On
Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function MoveWindow Lib "user32.dll" Alias "MoveWindow" (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
Public Sub Move_Notepad()
'Move NotePad to 1,1 and set its Width and height to 800,720 (pixels)
Dim GoWindow As Long
hWinHand = FindWindow(vbNullString, "Untitled - Notepad")
GoWindow = MoveWindow(hWinHand, 1, 1, 800, 720, 1)
End Sub
Private Sub bMove_Notepad_Click(sender As Object, e As EventArgs) Handles bMove_Notepad.Click
Move_Notepad()
End Sub
I installed the PInvoke.net Visual Studio Extension extension and got the following code which finallyworked for me:
<DllImport("user32.dll")>
Public Function MoveWindow(ByVal hWnd As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal bRepaint As Boolean) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Public Function FindWindow(
ByVal lpClassName As String,
ByVal lpWindowName As String) As IntPtr
End Function
I have a access database with some forms and vba code behind the forms.
On Form_Open (on every form) I have this piece of code.
Dim hWindow As Long
Dim nResult As Long
Dim nCmdShow As Long
hWindow = Application.hWndAccessApp
nCmdShow = SW_HIDE
nResult = ShowWindow(ByVal hWindow, ByVal nCmdShow)
Call ShowWindow(Me.hWnd, SW_NORMAL)
This hides Access and shows only the opened form.
My problem is that Access is starting, but the form will not open.
I have to kill the Access task in task manager.
Is there any way to solve the problem?
EDIT: Every form is a PopUp
As I understand, you need to hide main form and leave popup form open. I normally use window opacity settings instead of hiding:
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 SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As Long, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
Private Const LWA_ALPHA As Long = &H2&
Private Const LWA_COLORKEY As Long = &H1&
Private Const GWL_EXSTYLE As Long = -20
Private Const WS_EX_LAYERED As Long = &H80000
Public Function SetWndOpacity(hwnd As Long, opacity As Byte, clr As Long)
DoCmd.Maximize
SetWindowLong hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) Or WS_EX_LAYERED
SetLayeredWindowAttributes hwnd, 0&, opacity, LWA_ALPHA
End Function
Then call:
SetWndOpacity Access.hWndAccessApp(), 0, 0
I am trying to use the function URLDownloadToFile in Access 2010 VBA code. When i run the code it tells me that URLDownloadToFile is not defined.
I have read that this function is in the urlmon.dll which i DO have on my computer. I tried to click the references button in the code editor and load it but it would not let me do so.
How can I fix this so I can use the function? Or is there another function that will allow me to download a url to to a file?
You'll need to declare this WinAPI function in order to call it from procedures in your code.
From HERE
Private Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Public Function DownloadFile(URL As String, LocalFilename As String) As Boolean
Dim lngRetVal As Long
lngRetVal = URLDownloadToFile(0, URL, LocalFilename, 0, 0)
If lngRetVal = 0 Then
If Dir(LocalFileName) <> vbNullString Then
DownloadFile = True
End If
End If
End Function
Private Sub Form_Load()
If Not DownloadFile("http://www.ex-designz.net", "c:\\photogallery.asp") Then
MsgBox "Unable to download the file, or the source URL doesn't exist."
End If
End Sub
We have a Visual Basic application inside of Microsoft Access and we need to make a network connection. With VB6, there was a handy little control called WinSock that made this possible, but I can't find anything similar for the stripped down VB version that exists inside of Microsoft Access. Any ideas?
Since I'm not getting any answers, I'll try to clarify what I need this for.
My application sends out an email, and we're currently using a built-in Outlook object to create a message and send it in the background. The drawback is that it prompts the user to approve an "outside program" to send an email, which is frustrating our users and seems unnecessary. All of the other emailing options I've been able to find online require us to either download or purchase a control, which would be too labor intensive for us to deploy to all of our users.
I was hoping to use a socket control to manually connect to the SMTP server and send a message (since this is trivial in other languages) but I can't find any way to make a TCP connection in VBA.
I just dealt with this very issue in the last month. For various reasons, CDO was not adequate, direct use of MAPI way too complex, and the Outlook prompt you complain about completely unacceptable.
I ended up using Outlook Redemption. It's widely used by Access developers, though I found it to be rather convoluted and not terribly well-documented. But it is doing the job quite well.
The email "security" feature added by Microsoft has frustrated many developers. I don't know of an elegant solution. I've used the freeware app ClickYes Express with success, but of course that's not the answer you seek.
For the specific problem mentioned in the OP, there is a better solution. 'save' mail to Outlook. Do not 'send' it. It gives the user explicit control over what is sent, and when, and does not generate pop-up dialogs. A triple win.
But since you ask....
Option Explicit
Public Const AF_INET = 2 'internetwork: UDP, TCP, etc.
Public Const SOCK_STREAM = 1 'Stream socket
Public Const SOCKET_ERROR = -1
Type sockaddr_in
sin_family As Integer
sin_port As Integer
sin_addr As Long
sin_zero As String * 8
End Type
#If Win32 Then
'for WSAStartup() function.
Public Const WSADESCRIPTION_LEN = 256
Public Const WSASYS_STATUS_LEN = 128
Public Const WSA_DescriptionSize = WSADESCRIPTION_LEN + 1
Public Const WSA_SysStatusSize = WSASYS_STATUS_LEN + 1
Type wsaData
wVersion As Integer
wHighVersion As Integer
szDescription As String * WSA_DescriptionSize
szSystemStatus As String * WSA_SysStatusSize
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As String * 200
End Type
#If Not VBA7 Then
'Use this section for Excel 95
Type Hostent
h_name As Long '32 bit pointer
h_aliases As Long '32 bit pointer
h_addrtype As Integer 'String * 2 (declared as short)
h_length As Integer 'String * 2 (declared as short)
h_addr_list As Long '32 bit pointer
End Type
Public Declare Function closesocket Lib "ws2_32.dll" (ByVal s As Long) As Long
Public Declare Function connect Lib "ws2_32.dll" (ByVal sID As Long, ByRef name As sockaddr_in, ByVal namelen As Long) As Long
Public Declare Function htons Lib "ws2_32.dll" (ByVal hostshort As Integer) As Integer
Public Declare Function inet_addr Lib "ws2_32.dll" (ByVal cp As String) As Long
Public Declare Function recv Lib "ws2_32.dll" (ByVal s As Long, ByRef buf As Any, ByVal buflen As Long, ByVal flags As Long) As Long
Public Declare Function recvstr Lib "ws2_32.dll" (ByVal s As Long, ByVal buf As Any, ByVal buflen As Long, ByVal flags As Long) As Long
Public Declare Function send Lib "ws2_32.dll" (ByVal s As Long, ByRef buf As Any, ByVal buflen As Long, ByVal flags As Long) As Long
Public Declare Function socket Lib "ws2_32.dll" (ByVal af As Long, ByVal s_type As Long, ByVal Protocol As Long) As Long
Public Declare Function WSAStartup Lib "ws2_32.dll" (wVersionRequested As Integer, lpWSAData As wsaData) As Long
Public Declare Function WSACleanup Lib "ws2_32.dll" () As Long
'Public Declare Function setsockopt Lib "ws2_32.dll" (ByVal s As Long, ByVal level As Long, ByVal optname As Long, optval As Any, ByVal optlen As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Public Declare Function gethostbyname Lib "ws2_32.dll" (ByVal host_name As String) As Long
#Else
'on Win64, ws2_32.dll in system32 has the file description "32-bit DLL" and uses 64bit pointers (morons)
'on Win64 as on Win32, 32-bit numbers are called int.
'on VBA7/64, as on VBA6/32, 32 bit numbers are called long.
'delete following duplicate section for Excel 95
Type Hostent
h_name As LongPtr '32/64 bit pointer
h_aliases As LongPtr '32/64 bit pointer
h_addrtype As Integer 'String * 2 (declared as short)
h_length As Integer 'String * 2 (declared as short)
h_addr_list As LongPtr '32/64 bit pointer
End Type
Public Declare PtrSafe Function closesocket Lib "ws2_32.dll" (ByVal sID As LongPtr) As Long
Public Declare PtrSafe Function connect Lib "ws2_32.dll" (ByVal sID As LongPtr, ByRef name As sockaddr_in, ByVal namelen As Long) As Long
Public Declare PtrSafe Function htons Lib "ws2_32.dll" (ByVal hostshort As Integer) As Integer
Public Declare PtrSafe Function inet_addr Lib "ws2_32.dll" (ByVal cp As String) As Long
Public Declare PtrSafe Function recv Lib "ws2_32.dll" (ByVal sID As LongPtr, ByRef buf As Any, ByVal buflen As Long, ByVal flags As Long) As Long
Public Declare PtrSafe Function recvstr Lib "ws2_32.dll" (ByVal sID As LongPtr, ByVal buf As Any, ByVal buflen As Long, ByVal flags As Long) As Long
Public Declare PtrSafe Function send Lib "ws2_32.dll" (ByVal sID As LongPtr, ByRef buf As Any, ByVal buflen As Long, ByVal flags As Long) As Long
Public Declare PtrSafe Function socket Lib "ws2_32.dll" (ByVal af As Long, ByVal s_type As Long, ByVal Protocol As Long) As Long
Public Declare PtrSafe Function WSAStartup Lib "ws2_32.dll" (wVersionRequested As Integer, lpWSAData As wsaData) As Long
Public Declare PtrSafe Function WSACleanup Lib "ws2_32.dll" () As Long
'Public Declare PtrSafe Function setsockopt Lib "ws2_32.dll" (ByVal sID As Long, ByVal level As LongPtr, ByVal optname As Long, optval As Any, ByVal optlen As Long) As Long
Public Declare PtrSafe Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As LongPtr)
Public Declare PtrSafe Function gethostbyname Lib "ws2_32.dll" (ByVal host_name As String) As LongPtr
#End If
#Else
'OSX
'delete following duplicate section for Excel 95
'No 64bit version of Excel is available yet for the OSX
Type Hostent
h_name As Long '32 bit pointer
h_aliases As Long '32 bit pointer
h_addrtype As Long '32 bit int (declared as int)
h_length As Long '32 bit int (declared as int)
h_addr_list As Long '32 bit pointer
End Type
'ssize_t is a signed type. signed version of size_t,
'used where a size may instead contain a negative error code
'size_t is the unsigned integer type of the result of the sizeof operator
'size_t is an unsigned integer type of at least 16 bit
'or libsystem.dylib ?
Public Declare Function socket Lib "libc.dylib" (ByVal af As Long, ByVal s_type As Long, ByVal Protocol As Long) As Long
Public Declare Function connect Lib "libc.dylib" (ByVal s As Long, ByRef name As sockaddr_in, ByVal namelen As Long) As Long
' or read ?
Public Declare Function recv Lib "libc.dylib" (ByVal s As Long, buf As Any, ByVal buflen As Long, ByVal flags As Long) As Long
Public Declare Function send Lib "libc.dylib" (ByVal s As Long, buf As Any, ByVal buflen As Long, ByVal flags As Long) As Long
Public Declare Function htons Lib "libc.dylib" (ByVal Host_Short As Integer) As Integer 'x x x, but seems to work !!!
Public Declare Function inet_addr Lib "libc.dylib" (ByVal cp As String) As Long
Public Declare Function closesocket Lib "libc.dylib" Alias "close" (ByVal s As Long) As Long
Public Declare Function setsockopt Lib "libc.dylib" (ByVal s As Long, ByVal level As Long, ByVal optname As Long, optval As Any, ByVal optlen As Long) As Long
Public Declare Function gethostbyname Lib "libc.dylib" (ByVal host_name As String) As Long
Public Declare Sub CopyMemory Lib "libc.dylib" Alias "memmove" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
#End If
Private Function MyData(I_SocketAddress As sockaddr_in, Register As Integer, dataword As Long, serr As String) As Long
Dim strSend As String
Dim count As Integer
Dim bArray() As Byte
Dim errCode As Integer
Dim socketID As Long
socketID = socket(AF_INET, SOCK_STREAM, 0)
errCode = connect(socketID, I_SocketAddress, Len(I_SocketAddress))
count = send(socketID, ByVal strSend, Len(strSend), 0)
If count <> Len(strSend) Then
errCode = -1
serr = "ERROR: network failure on send, " & Err.LastDllError()
Else
count = RecvB(socketID, bArray, maxLength)
dodata bArray
End If
DoEvents
Call closesocket(socketID)
MyData = errCode
End Function
Private Function RecvB(socketID As Long, bArray() As Byte, ByVal maxLength As Integer) As Integer
Dim c As String * 1
Dim b As Byte
Dim buf() As Byte
Dim Length As Integer
Dim count As Long
Dim i As Integer
Dim dStartTime As Variant
Dim nErr As Long
Const iFlags = 0
ReDim bArray(1 To maxLength)
ReDim buf(1 To maxLength)
dStartTime = Time
While (Length < maxLength) And (4 > DateDiff("s", dStartTime, Time))
DoEvents
count = recv(socketID, buf(1), maxLength, iFlags)
If count = SOCKET_ERROR Then '-1
nErr = Err.LastDllError()
If nErr = 0 Then
RecvB = -1
Else
RecvB = -nErr
End If
'Debug.Print "socket_error in RecvB. lastdllerror:", nErr
Exit Function '
End If '
For i = 1 To count
bArray(Length + i) = buf(i)
Next
Length = Length + count
Wend
RecvB = Length
End Function
This is TCP code, not email code. It's also includes OSX VBA TCP code, which I have not previously published.