Set global hotkey with Windows modifier - vb6

I want to set up a global hotkey* in VB6 that listens to the keyboard shortcut Win + O.
I have found heaps of messy examples, but nothing which involves the Windows key.
What's the ideal way to setup hotkeys and how does one include the Windows key as a modifier?
* I'm after a global shortcut. That means I don't have to have the application in focus for it to work.

RegisterHotKey in the Windows API will allow you to register a global hot key. You will also need to use GlobalAddAtom to obtain a unique hot key identifier. See this link for details.
Private Declare Function RegisterHotKey Lib "user32" (ByVal hwnd As Long, ByVal id As Long, ByVal fsModifiers As Long, ByVal vk As Long) As Long
Private Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer
Private Const WM_HOTKEY As Long = &H312
Private Const MOD_WIN As Long = &H8
m_lHotkey = GlobalAddAtom("MyHotkey")
Call RegisterHotKey(Me.hwnd, m_lHotkey, MOD_WIN, vbKeyO)
Then you just need to listen for the WM_HOTKEY message on your window.

Related

Numeric values of WinHTTP constants (eg. WINHTTP_NO_CLIENT_CERT_CONTEXT)

I need to set this property for a WinHttp request...
BOOL fRet = WinHttpSetOption(hRequest,
WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
WINHTTP_NO_CLIENT_CERT_CONTEXT,
0);
But from within an old VB application. I can access the method but can't use the constants.
I can use this to access the method from VB...
Declare Function WinHttpSetOption Lib "winhttp.dll" _
(ByVal hInternet As Variant, ByVal dwOption As Integer, ByVal lpBuffer As Byte, ByVal dwBufferLength As Integer) _
As Boolean
And then call it like so...
Call WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0);
But have to replace the constants WINHTTP_OPTION_CLIENT_CERT_CONTEXT and WINHTTP_NO_CLIENT_CERT_CONTEXT with the correct numbers, or figure out how to import them.
After I long google search, I think WINHTTP_OPTION_CLIENT_CERT_CONTEXT is 47 but can't find WINHTTP_NO_CLIENT_CERT_CONTEXT anywhere.
Many thanks

How to find correct values for HWND window handles?

WinRestore,% hwnd([1])
i have found in many programming language the use of hwnd. after searching on google it comes out to be handle. I didnt got more information on this. how programmer knows the value to put in, eg.
Const LB_GETTEXTLEN = &H18A
Const LB_GETTEXT = &H189
Const LB_GETCOUNT = &H18B
&h18a how he known, how will he use this?
this is the example program
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
Const LB_GETTEXTLEN = &H18A
Const LB_GETTEXT = &H189
Const LB_GETCOUNT = &H18B
Private Function GetListItems(ByVal hList As Long) As Variant
Dim i As Long, nCount As Long, lItemLength As Long
Dim sItem() As String
nCount = SendMessage(hList, LB_GETCOUNT, 0, ByVal 0&)
For i = 0 To nCount - 1
lItemLength = SendMessage(hList, LB_GETTEXTLEN, i, ByVal 0&)
ReDim Preserve sItem(i)
sItem(i) = String(lItemLength, 0)
Call SendMessage(hList, LB_GETTEXT, i, ByVal sItem(i))
Next i
GetListItems = sItem
End Function
there are many such examples in all different languages but concept will be the same. so i want to learn it. what does it mean and how to use it.
another example from ahk
Gui,2:+hwndhwnd
hwnd(2,hwnd)
Those are all window messages that you can find information about on the MSDN Documentation by googling them. See below links:
LB_GETTEXTLEN
LB_GETTEXT
LB_GETCOUNT
You can find them and other related messages by checking the documentation for the native List Box control.
As for the numbers they're hexadecimal numbers which are (usually) mentioned in the documentation. But since these aren't you'll have to google them and check other websites/forums, or find their values on your own by experimenting with them in C or C++ .
In VB hexadecimal numbers are represented by prepending the number with &H, whereas in C, C++, C# or alike they're prepended with 0x.
In a forms editor each window/control has a hwnd property. For windows not created by your forms package you use the API calls FindWindow (easiest but not reliable) or EnumWindows. Also GetForegroundWindow and GetDesktopWindow.
To find out the value of constants you download the C header files as part of the Windows SDK https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk. It also has the documentation for all these API calls. This is online documentation listing all the windows' functions https://msdn.microsoft.com/en-us/library/windows/desktop/ms633505(v=vs.85).aspx.

VB6 sidebar app

All.
I'm attempting to develop a 'sidebar' application with vb6, which I want to behave like windows Vista's gadget sidebar or Google Desktop sidebar, in the respect that other windows could not maximize over it.
I'm aware that chances of this happening are probably very little, but I'm asking just in case.
Currently, I've got a form that has multiple controls, and runs a function on load which makes itself the exact height of the screen, minus the taskbar, and it's 'left' location is set by a timer to be 'screen.width - me.width', so it will start at full height on the far right of the screen, and cannot be moved. Code for the height is as follows, if it is necessary.
Declare Function GetUserNameA Lib "advapi32.dll" (ByVal lpBuffer As String, nSize As Long) As Long
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" ( _
ByVal hwnd As Long, _
ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" ( _
ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
Public Declare Function SetLayeredWindowAttributes Lib "user32" ( _
ByVal hwnd As Long, _
ByVal crKey As Long, _
ByVal bAlpha As Byte, _
ByVal dwFlags As Long) As Long
Public Const GWL_STYLE = (-16)
Public Const GWL_EXSTYLE = (-20)
Public Const WS_EX_LAYERED = &H80000
Public Const LWA_COLORKEY = &H1
Public Const LWA_ALPHA = &H2
Private Const ABM_GETTASKBARPOS = &H5
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type APPBARDATA
cbSize As Long
hwnd As Long
uCallbackMessage As Long
uEdge As Long
rc As RECT
lParam As Long
End Type
Private Declare Function SHAppBarMessage Lib "shell32.dll" (ByVal dwMessage As Long, pData As APPBARDATA) As Long
Function Fixheight()
Dim ABD As APPBARDATA
SHAppBarMessage ABM_GETTASKBARPOS, ABD
Form1.Height = Screen.Height - ((ABD.rc.Bottom - ABD.rc.Top) * 12)
If Form1.Height <= 600 Then
Form1.Height = Screen.Height
End If
End Function
To be clear, I do not want an 'always on top' function. I already have that, and it's driving me insane, as the form has to me closed or minimized in order to maximize, minimize of close another program (i.e. chrome, word, etc) behind it. This form must instead not allow other programs to maximize over it, so that if for example, the user maximized Chrome, chrome would maximize minus form1.width.
I doubt that this is possible because as far as I'm concerned, that would mean taking control of chrome, and essentially making it's maximize function as
me.height = screen.height - ((ABD.rc.Bottom - ABD.rc.Top) * 12)
me.width = screen.width - form1.width
which isn't possible.
Anyway, hopefully someone out there can help. As I said, I seriously doubt the possibility of having this work, but if so, all the better.
Thanks in advance!
Thanks to Ken White, I googled SHAppBarMessage and found the following website, offering a downloadable source with the very feature I needed. I just have to implement it now!!
Very glad I asked! Thank you!
Edit: Found this spanish website, which while needed some help from Google Translate, is more suited to my needs. Just need to figure out how to make it work on the Right Hand Side! Thanks again!

vba How to control message boxes from another program?

So I want to use
pid = Shell(MyApp, 1)
with VBA to automate the use of a crappy external program. This program unfortunately has all sorts of annoying dialog boxes and popups that must be clicked. Is there any way to directly control each dialog box to ensure that the "OK" button is pressed rather than "Cancel"?
Currently I am using
AppActivate pid
Application.SendKeys ("%R")
But this command can only guarantee the "OK" of the initial pop-up dialog. Subsequent pop-ups may not be clicked, especially because I'm not sure how to guarantee focus on the new popup. Is there a way to find the child process ID's of any new popups? Is there any way to directly "click" a particularly labeled control button?
How to Interact with a Button on a Dialog
Well, there is a way of sending a WM_COMMAND message to common buttons on a dialog box effectively closing it:
Declare Function SendMessageA Lib "user32" (ByVal hWnd As Long, ByVal Msg As Integer, ByVal wParam As Long, ByVal lParam As Long) As Long
Declare Function FindWindowA Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Const WM_COMMAND As Integer = 273
Const WM_CLOSE As Integer = 16
Const IDOK As Integer = 1
Const IDCANCEL As Integer = 2
Sub ShowDialogs()
If Shell("C:\Users\myself\dialogs.exe") <> 0 Then
Dim hWnd As Long
hWnd = FindWindowA("#32770", "Info")
Debug.Print hWnd
SendMessageA hWnd, WM_COMMAND, IDOK, 0
End If
End Sub
Important Notes:
I had to use Spy++ to find out what class name Windows gives to message box dialogs.
The Windows SDK headers contained useful constants, especially the value for WM_COMMAND which was obtained from WinUser.h.
Each time a dialog is a created, you will need to obtain the handle for the window again using FindWindowA, as shown in the preceding code.

Findwindow and SendMessage

I am trying to figure out why this is not sending a ALT+F to notepad,
Private Declare Function FindWindow1 Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Const WM_KEYUP = &H101
Private Const WM_KEYDOWN = &H100
Private Const WM_SYSKEYDOWN = &H104
Private Sub Command_Click()
Dim parenthwnd As Long
Dim hwnd As Long
parenthwnd = FindWindow1(vbNullString, "Untitled - Notepad")
retvalue = SendMessage(parenthwnd, WM_SYSKEYDOWN, VK_MENU, 1&)
retvalue = SendMessage(parenthwnd, WM_KEYDOWN, VK_F, 1&)
End Sub
I get a value for parenthwnd but not for any of the retvalue values (0).
What am I missing?
You can try to send/post these messages all you want. Unfortunately they don't effect the return value of GetAsyncKeyState - which is what the system uses, while processing the VK_F message - to see if the alt is down.
As a result you can't fake keystrokes with modifiers to other applications using this mechanism.
To get around this, you need to use SendInput - but this requires that the application to receive the keystrokes is the foreground/focus window.
I think this is the problem: you're sending your message to the frame around the notepad window, and need to send it to the menu window. Use your handle with FindWindowEx and the 32768 class name (that's a menu) to get the menu window, which is a child of the one you've got the handle to. Here are two pages: http://msdn.microsoft.com/en-us/library/ms633500(v=VS.85).aspx and http://msdn.microsoft.com/en-us/library/ms633574(VS.85).aspx#class_name that should help.
Use Postmessage instead of Sendmessage
Public Const WM_SYSKEYDOWN = &H104
PostMessage hwnd, WM_SYSKEYDOWN, vbKeyF, 2 ^ 29
'Simulates Alt + F (2^29 sets the 29 bit of lParam indicating Alt is being pressed.

Resources