I found a piece of code that enables my User form list boxes to resize in height based on the number of inputs, but the declaration is for win32 and i do not know how to change it to win 64 correctly, please help. Here it is:
Option Explicit
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 Const LB_GETITEMHEIGHT = &H1A1
Public Function AutoSizeLBHeight(LB As Object) As Boolean
If Not TypeOf LB Is ListBox Then Exit Function
On Error GoTo ErrHandler
Dim lItemHeight As Long
Dim lRet As Long
Dim lItems As Long
Dim sngTwips As Single
Dim sngLBHeight As Single
If LB.ListCount = 0 Then
LB.Height = 125
AutoSizeLBHeight = True
Else
lItems = LB.ListCount
lItemHeight = SendMessage(LB.hwnd, LB_GETITEMHEIGHT, 0&, 0&)
If lItemHeight > 0 Then
sngTwips = lItemHeight * Screen.TwipsPerPixelY
sngLBHeight = (sngTwips * lItems) + 125
LB.Height = sngLBHeight
AutoSizeLBHeight = True
End If
End If
ErrHandler:
End Function
http://www.jkp-ads.com/articles/apideclarations.asp has everything you need.
The SendMessage API is a good example because it uses both types:
32-bit:
Public Declare Function SendMessageA Lib "user32" ( _
ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
64 bit:
Public Declare PtrSafe Function SendMessageA Lib "user32" ( _
ByVal hWnd As LongPtr, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As LongPtr
The first argument -hWnd- is a window handle, which is an address in memory. The return value is a pointer to a function, which is also an address in memory. Both of these must be declared LongPtr in 64-bit VBA. The arguments wMsg and wParam are used to pass data, so they can be Long in both 32-bit and 64-bit.
But you are aware that you only need this for 64bit-Excel, not for 64bit-Windows?
Using Compiler Directives will allow the code to run properly on either platform.
#If Win64 Then
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As LongPtr, ByVal wMsg As Long, _
ByVal wParam As LongPtr, lParam As Any) As LongPtr
#ElseIf Win32 Then
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
#End If
Related
I'd like to convert VBA macro to Google Apps script but I think this particular one is impossible to convert as I am totally lost where to begin with this. I couldn't find anyway to do what "findwindow" does on APP script. Does anyone have any idea how to tackle this or should I give up on this?
Plus, is there anyone played with the phone companion? As they don't provide any API, the only way to use the mobile companion to send messages with google spread would be using findwindow, which shows the same problem. Any insight on this would be highly appreciated. Thanks.
Option Explicit
#If VBA7 Then
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowa
Private Declare PtrSafe Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowexa
Public Declare PtrSafe Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
(ByVal hwndParent As Long, _
ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, _
ByVal lpszWindow As String) As Long
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessagea
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByRef lParam As Any) As Long
'https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagea
Private Declare PtrSafe Function PostMessage Lib "user32" Alias "PostMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByRef lParam As Any) As Long
Private Declare PtrSafe Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wFlag As Long) As Long
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal Milliseconds As LongPtr)
#Else
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowa
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-findwindowexa
Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
(ByVal hwndParent As Long, _
ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, _
ByVal lpszWindow As String) As Long
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessagea
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByRef lParam As Any) As Long
'https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagea
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByRef lParam As Any) As Long
>Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wFlag As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal Milliseconds As LongPtr)
#End If
Dim Handle, HandleEx As Long
Private Const WM_SETTEXT = &HC: Private Const WM_KEYDOWN = &H100
Private Const VK_RETURN = &HD: Private Const VK_ESCAPE = &H1B
Private Const WM_CLOSE = &H10: Private Const GW_HWNDNEXT = &H2
Sub Send_Kakao(Target As Range, Msg As Range)
Dim SendTo$: SendTo = Target.Value
Dim Message$: Message = Msg.Value
Dim hwnd_KakaoTalk As Long: Dim hwnd_RichEdit As Long
Call Call_ChatRoom(Target)
DoEvents
Sleep 1000
hwnd_KakaoTalk = FindWindow(vbNullString, SendTo)
hwnd_RichEdit = FindWindowEx(hwnd_KakaoTalk, 0, "RichEdit50W", vbNullString)
If hwnd_RichEdit = 0 Then MsgBox SendTo & "This chatroom is not opened.": Exit Sub
Call SendMessage(hwnd_RichEdit, WM_SETTEXT, 0, ByVal Message)
Call PostMessage(hwnd_RichEdit, WM_KEYDOWN, VK_RETURN, 0)
End Sub
Private Sub Call_ChatRoom(Target As Range)
Dim ChatRoom$: ChatRoom = Target.Value
Dim rtnV As Long
Handle = FindWindow("EVA_Window_Dblclk", vbNullString) 'Saave Window Handle info of Kakao on Handle
'//Print error when cannot be located
If Handle = 0 Then
MsgBox "Open kakao first.", 16, "Error"
Else
HandleEx = FindWindowEx(Handle, 0, "EVA_ChildWindow", vbNullString) 'children Window1
HandleEx = FindWindowEx(HandleEx, 0, "EVA_Window", vbNullString) 'children Window2
HandleEx = FindWindowEx(HandleEx, 0, "Edit", vbNullString) 'children Window3
Call SendMessage(HandleEx, WM_SETTEXT, 0, ByVal ChatRoom)
DoEvents
Sleep 1000
Call PostMessage(HandleEx, WM_KEYDOWN, VK_RETURN, 0)
End If
End Sub
I want to locate an recently opened pdf file and save it in a target folder, right now i can able to locate the pdf file using its name and close it but i want to use Save As function.
Code tried to Locate and close the PDF
Option Explicit
Private Declare Function FindWindow Lib "user32" _
Alias "FindWindowA" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Declare Function PostMessage Lib "user32" _
Alias "PostMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Declare Function GetWindowThreadProcessId _
Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Declare Function GetParent Lib "user32" (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
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, _
ByVal wCmd As Long) As Long
Const GW_HWNDNEXT = 2
Const WM_CLOSE = &H10
Const SYNCHRONIZE = &H100000
Public Sub Test()
Dim hWindow As Long
Dim hProcess As Long
Dim lProcessId As Long
Dim lngReturnValue As Long
hWindow = SearchHndByWndName_Parent("vieworder.pdf.php")
hProcess = OpenProcess(SYNCHRONIZE, 0&, lProcessId)
lngReturnValue = PostMessage(hWindow, WM_CLOSE, 0&, 0&)
End Sub
Private Function SearchHndByWndName_Parent(strSearch As String) As Long
Dim strTMP As String * 100
Dim nhWnd As Long
nhWnd = FindWindow(vbNullString, vbNullString)
Do While Not nhWnd = 0
If GetParent(nhWnd) = 0 Then
GetWindowText nhWnd, strTMP, 100
If InStr(strTMP, strSearch) > 0 Then
SearchHndByWndName_Parent = nhWnd
Exit Do
End If
End If
nhWnd = GetWindow(nhWnd, GW_HWNDNEXT)
Loop
End Function
I am working in a restricted environment so I cant add any Adobe dll as reference, also the file which i am looking for is not yet saved in any folder.
Please share your suggestions.
Thank You
i write this code to change default printer in windows and work fine but in reload the INI file have a error
this is a code :
Private Sub SetDefaultPrinter(ByVal PrinterName As String, ByVal DriverName As String, ByVal PrinterPort As String)
Dim DeviceLine As String
'rebuild a valid device line string
DeviceLine = PrinterName & "," & DriverName & "," & PrinterPort
'Store the new printer information in the
'[WINDOWS] section of the WIN.INI file for
'the DEVICE= item
Call WriteProfileString("windows", "Device", DeviceLine)
'Cause all applications to reload the INI file
Call SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, "windows")
End Sub
Private Declare Function WriteProfileString Lib "kernel32" Alias "WriteProfileStringA" (ByVal lpszSection As String, ByVal lpszKeyName As String, ByVal lpszString 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 String) As Long
Private Const HWND_BROADCAST As Long = &HFFFF&
Private Const WM_WININICHANGE As Long = &H1A
and this is a error :
A call to PInvoke function 'Test!Test.Form2::SendMessage' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Does anyone have an idea to solve this problem?
Thankful
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lparam As String) As Long
Your data types are wrong. The hwnd parameter is pointer sized, wMsg is a 32 bit value, and wParam, lParam and the return value are pointer sized. Note that Long is a 64 bit type.
Instead it should be
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, _
ByVal lparam As String) As IntPtr
Note that I recommend that, in the modern day, you use pinvoke declarations rather than Declare. This offer much more flexibility.
Hi I want to ask if is it possible to have MsgBox without any buttons only with my message? Maybe is another way to display messages to user without using MsgBox?
I usually do not answer question which do not show enough research but this is way beyond a normal user.
Is it possible to have MsgBox without any buttons only with my message?
Msgbox doesn't give you an option to hide it. But we can bypass by subclassing the Excel Application and the Message Box.
Is another way to display messages to user without using MsgBox?
Yes you have two alternatives
Use a customized userform OR
Subclassing as I have shown below
ScreenShot
Code
Paste this code in a module and run the procedure Sample
Option Explicit
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
Private Declare Function CallNextHookEx Lib "user32" _
(ByVal hHook As Long, ByVal ncode As Long, _
ByVal WParam As Long, lparam As Any) As Long
Private Declare Function FindWindow Lib "user32" _
Alias "FindWindowA" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _
ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszCaption As String) As Long
Private Declare Function ShowWindow Lib "user32" _
(ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function EnableWindow Lib "user32" _
(ByVal hwnd As Long, ByVal fEnable 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 SetWindowLong Lib "user32" _
Alias "SetWindowLongA" (ByVal hwnd As Long, _
ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" _
Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare Function CallWindowProc Lib "user32" _
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 Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private hwndXLApp As Long
Private hwndMsgBox As Long
Private hwndMsgBoxBtn As Long
Private HookIt As Long
Private OldAppWinProc As Long
Private OldMBoxWinProc As Long
Private Const WH_CBT As Long = 5
Private Const HCBT_CREATEWND As Long = 3
Private Const GWL_STYLE As Long = -16
Private Const DS_NOIDLEMSG As Long = &H100&
Private Const GWL_WNDPROC As Long = (-4)
Private Const WM_ENTERIDLE As Long = &H121
Private Const WM_COMMAND As Long = &H111
Private Const WM_NCDESTROY As Long = &H82
Sub Sample()
hwndXLApp = FindWindow("XLMAIN", Application.Caption)
'~> Setup the hook to catch creation of messagebox
HookIt = SetWindowsHookEx(WH_CBT, AddressOf HookProc, 0, GetCurrentThreadId)
MsgBox ("Look Mommy, My button is missing!!!")
End Sub
Private Function HookProc(ByVal idHook As Long, ByVal WParam As Long, ByVal lparam As Long) As Long
Dim strBuffer As String
Dim RetVal As Long, curStyle As Long, NewStyle As Long
'~~> Check if a window is being created
If idHook = HCBT_CREATEWND Then
strBuffer = Space(256)
'~~> Check if it is a MSGBOX
RetVal = GetClassName(WParam, strBuffer, 256)
If Left(strBuffer, RetVal) = "#32770" Then
'~~> Handle of Msgbox
hwndMsgBox = WParam
'~~> We make the Msgbox Modeless so that we can use
'~~> ShowWindow API to hide the button
curStyle = GetWindowLong(WParam, GWL_STYLE)
NewStyle = curStyle And Not DS_NOIDLEMSG
SetWindowLong WParam, GWL_STYLE, NewStyle
'~~> Subclass Excel app to catch the WM_ENTERIDLE message and
OldAppWinProc = SetWindowLong(hwndXLApp, GWL_WNDPROC, AddressOf NewAppWindowProc)
'~~> Sub class the msgbox to catch the WM_NCDESTROY message to cleanup
OldMBoxWinProc = SetWindowLong(WParam, GWL_WNDPROC, AddressOf NewMsgBxWindowProc)
'~~> UnHook
UnhookWindowsHookEx HookIt
End If
End If
'~~> Call next hook
HookProc = CallNextHookEx(HookIt, idHook, ByVal WParam, ByVal lparam)
End Function
Private Function NewAppWindowProc(ByVal hwnd As Long, ByVal MSG _
As Long, ByVal WParam As Long, ByVal lparam As Long) As Long
On Error Resume Next
Select Case MSG
Case WM_ENTERIDLE
EnableWindow hwnd, 1
hwndMsgBoxBtn = FindWindowEx(hwndMsgBox, ByVal 0&, "Button", vbNullString)
ShowWindow hwndMsgBoxBtn, 0
'~~> Un SubClass Excel
SetWindowLong hwnd, GWL_WNDPROC, OldAppWinProc
End Select
'~~> Pass Intercepted Messages To The Original WinProc
NewAppWindowProc = CallWindowProc(OldAppWinProc, hwnd, MSG, WParam, lparam)
End Function
Private Function NewMsgBxWindowProc(ByVal hwnd As Long, ByVal MSG _
As Long, ByVal WParam As Long, ByVal lparam As Long) As Long
On Error Resume Next
Select Case MSG
Case WM_NCDESTROY, WM_COMMAND
SetWindowLong hwnd, GWL_WNDPROC, OldMBoxWinProc
End Select
NewMsgBxWindowProc = CallWindowProc(OldMBoxWinProc, hwnd, MSG, WParam, lparam)
End Function
I am working on converting some very old VBA code to run on AutoCAD 2014. I have so far converted everything but there is an issue with the forms (they are modeless and require an activation callback to modify the window propertis). The following is the VBA6 source code:
IN THE FORM:
Private Sub UserForm_Activate()
#If ACAD2000 = 0 Then
If Not bPopup Then
Call EnumWindows(AddressOf EnumWindowsProc, vbNull)
Call SubClass
bPopup = True
End If
#End If
End Sub
MODULE (named modModeLessFormFocus):
Option Explicit
Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private ThisHwnd As Long
Public Const GWL_STYLE = -16
Public Const WS_POPUP = &H80000000
Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Integer
Dim title As String * 32
Call GetWindowText(hwnd, ByVal title, 32)
If InStr(title, "About") Then
ThisHwnd = hwnd
EnumWindowsProc = False
ElseIf InStr(title, "Preferences") Then
ThisHwnd = hwnd
EnumWindowsProc = False
ElseIf InStr(title, "Display Block Attributes") Then
ThisHwnd = hwnd
EnumWindowsProc = False
Else
EnumWindowsProc = True
End If
End Function
Public Function SubClass() As Long
Dim Flags As Long
Flags = GetWindowLong(ThisHwnd, GWL_STYLE)
Flags = Flags Xor WS_POPUP
SetWindowLong ThisHwnd, GWL_STYLE, Flags
End Function
The error I get when running is a "Type Mismatch" in UserForm_Activate on 'AddressOf EnumWindowsProc.' I have tried to convert it to 64bit using PtrSafe and PtrLong but inevitably it fails and the program crashes.
If anyone is smart enough to convert this or point me in the right direction I would be very appreciative.
Thanks
I found the API for 64-bit VBA7 in http://www.jkp-ads.com/articles/apideclarations.asp
#If VBA7 Then
#If Win64 Then
Private Declare PtrSafe Function GetWindowLongPtr Lib "USER32" Alias "GetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
#Else
Private Declare PtrSafe Function GetWindowLongPtr Lib "USER32" Alias "GetWindowLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
#End If
Private Declare PtrSafe Function GetWindowText Lib "USER32" Alias "GetWindowTextA" _
(ByVal hWnd As LongPtr, ByVal lpString As String, _
ByVal cch As LongPtr) As Long
#Else
Private Declare Function GetWindowLongPtr Lib "USER32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex 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
#End If
You can also look at http://msdn.microsoft.com/en-us/library/aa383663(VS.85).aspx for the updated API