Running an invisible form on the foreground - vb6

I'm wondering how I would be able to run an invisible form in the foreground (meaning it runs wherever the heck you might be in your computer). I've tried playing around with formless applications using modules but unfortunately nothing happens. I've also tried doing
Form1.Visible = False
Form1.WindowState = 2 (Maximized)
But it WILL NOT run in the foreground (It will if it's focused on) and also the Windows "warning error" sort of sound (the "ehh." sort of sound in monotone) keeps playing when you hit a key. The coding I tried out is this in case you want to know:
Private Sub Form1_KeyPress(KeyAscii As Integer, Shift As Integer)
If KeyAscii <> 0 Then PlaySound App.Path & "\sounds\ding.wav", ByVal 0&, SND_FILENAME Or SND_ASYNC
End Sub
And of course using the Windows APIs for playing wav files (winnm.dll or something I believe)
My main question would be (which means THIS is what I want answered) is how I could possibly make it run ANYWHERE on the computer and not make "ehh." monotone sounds. Because That is obviously not what I wanted to achieve.
Oh, and quick update, I've made it play the proper sound (HOORAY!). Just disregard the latter part of the question.

Please tell us why you want to do this?
What are you trying to accomplish?
Have a look at the following API:
'api for keeping form on top
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
For example call it as follows:
'put form always on top
With Screen
SetWindowPos Me.hwnd, -1, 0, 0, .Width, .Height, 3
End With 'screen

Related

How can it be possible to steal focus so easily?

Using Outlook 2013 on Windows 7, I created this Macro, just to test it:
Private Sub Application_Reminder(ByVal Item As Object)
Activeexplorer.Activate
End Sub
Whenever I am working on a different application and an Outlook reminder fires, Outlook becomes the active window stealing focus from the application I am working at.
How can it be possible??
I mean, I think that the “Activeexplorer.Activate” method uses some Windows api like “SetForegroundWindow” or maybe “SetActiveWindow” or some other api.
All these apis forbid to steal focus, so my question is how the Outlook vba method can so easily and horrifyingly able to steal focus?
The alarm is partially disarmed, as stated at https://msdn.microsoft.com/it-it/library/windows/desktop/ms633539(v=vs.85).aspx, SetForegroundWindow can be used by other processes not in the foreground if “The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).”
I changed the value of the registry key 'ForegroundLockTimeout' at 'HKCU:\Control Panel\Desktop' from zero to 20000 and now, in my specific case, Outlook won’t steal the focus.
I wonder which is the maximum value for the 'ForegroundLockTimeout' registry key, or, in other words, if it is possible to permanently disable any other process not in the foreground stealing focus from the active application.
Here's the reason Windows was not behaving as expected:
I changed the value of the registry key 'ForegroundLockTimeout' at 'HKCU:\Control Panel\Desktop' from zero to 20000
The value shouldn't have been zero in the first place. Something on your system, possibly a long time ago, must have explicitly changed this setting in order to disable the foreground lock. This has nothing to do with Outlook per se.
I recommend you set it back to the default, which is 200,000, i.e., 200 seconds.
As for the maximum, well, it has to fit into a DWORD, so probably about 49 days. If it is treated as a signed value internally, about 24 days. There's probably little point in setting it longer than a day.
Yes, SetForegroundWindow is supposed to respect the foreground window and just flash the taskbar for background applications but there are various hacks people use to trick Windows and steal the focus.
My preferred method of notifying the user about something important is to bring the window to the top without stealing the keyboard focus. The tricky bit would be to figure out which HWND to pass, I could not really find the HWND property of the ActiveExplorer form just by looking on MSDN.
Const HWND_TOP = 0
Const SWP_NOSIZE = &H1
Const SWP_NOMOVE = &H2
Const SWP_NOACTIVATE = &H10
Const SWP_SHOWWINDOW = &H40
Private Declare Sub 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)
...
SetWindowPos ??.hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE Or SWP_SHOWWINDOW Or SWP_NOMOVE Or SWP_NOSIZE
Another alternative is to call FlashWindow to flash the taskbar button which is what SetForegroundWindow would do if you don't have the right to grab focus.

I can't subclass MS Access form if the window of IDE has been opened

What I am doing is by using SetWindowLong I change an address of an original window procedure of a window(a form in my case) to an address of my own WindowProc, then I process one of system messages and finally I pass the intercepted message to the original window procedure.
I tested intercepting messages subclassing:
A window of MS Access instance
A window of a form in an overlapping interface
Both of the tests go well only if I run the main Access window without opening an IDE window before or during the test. The trouble happens if at the time of testing not only MS Access main window is open but a window of IDE too.
The problem doesn’t arise in a first case (intercepting messages of MS Access window). While as the second case is a pain in the neck indeed (intercepting messages of a form in an overlapping interface). What happens is MS Access stops responding to user’s input. It looks like it gets looping and looping endlessly. I’d like to stress once more that such behavior takes place only when MS Access window and window of IDE are open at the same time.
I made a test file so that you can see it for yourself. I uploaded it here:
https://www.dropbox.com/s/8lnqfgb1hn3zqy8/SetWindowLong.accdb?dl=0
So, the first case(when there is no problem):
Open the file (DO NOT open IDE window till the end of the test)
Open Form1(on opening the system messages to MS Access window will start being intercepted)
Close Form1(on closing intercepting will be stopped)
Open Form 2(on opening the system messages to Form2 window will get being intercepted)
Close Form2(on closing intercepting will be stopped)
So far so good.
Now the second case (the pain in the neck):
Open the file
Open IDE window (ALT+F11)
Open Form1(on opening the system messages to MS Access window will get being intercepted)
Close Form1(on closing intercepting will be stopped)
Open Form 2(on opening the system messages to Form2 window are intended to get being intercepted, but you will witness an endless looping and no response from Access)
And now are my questions:
How come an open window of IDE can interfere in my subclassing of Form2 and does not affect the subclassing of MS Access window.
What can be done so that I was able to subclass Form2 while the window of IDE stayed open
I will be very grateful for your advice.
Edited on 2017/08/25:
Sorry for not providing my code at the beginning.
In a standard module of MS Access:
Option Compare Database
Option Explicit
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 SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public lngPrevWndProc As Long
Public Function WndProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
WndProc = CallWindowProc(lngPrevWndProc, hWnd, uMsg, wParam, lParam)
End Function
In a code module of Form2:
Option Compare Database
Option Explicit
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_WNDPROC = -4
Private Sub Form_Open(Cancel As Integer)
lngPrevWndProc = SetWindowLong(Me.hWnd, GWL_WNDPROC, AddressOf WndProc)
End Sub
Private Sub Form_Unload(Cancel As Integer)
SetWindowLong Me.hWnd, GWL_WNDPROC, lngPrevWndProc
End Sub
This sample intended to work on a 32bit Windows and in 32bit MS Access. I tested it on:
Windows XP Pro + MS Access 2000 (the file was converted to mdb); Windows 7 32bit + MS Access 2010 32bit (accdb); indows 10 32bit + MS Access 2016 32bit (accdb)
The result was the same as I described before.
Sergiy Vakshul

How can I force a vb6 control to redraw itself?

I've got a VB6 program. I'm using the Mainfest to apply "XP Themes" and give it the modern (as of 8 years ago!) look.
However, for graphical style Command buttons, I have to use some special code to redraw the button. Therein lies the problem.
When I click on one of this Graphical buttons it gets the proper "highlighting" of the background, but when another button gets the focus or mouseover, etc. that former button keeps the background highlighting.
If I move another window in front of it, the form redraws itself and this "residual" background color disappears.
I'm trying to figure out how to force that to happen.
What I've tried:
button.refresh
form.refresh
Doevents
Here is a video demo of the problem
I don't have anything like your setup to try this in, but you can try using the API call InvalidateRect. I've shown the declarations and created a Sub that uses it. It should be a simple copy and paste to try.
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function InvalidateRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT, ByVal bErase As Long) As Long
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Sub RefreshMe()
Dim udtRect As RECT
Call GetClientRect(Me.hwnd, udtRect)
InvalidateRect Me.hwnd, udtRect, 1
DoEvents 'give windows a chance to handle the event
End Sub

Access an (already opened) OpenFileDialog using VBA

I am doing some web scraping using excel vba.
At one point in my program my internet explorer instance opens an OpenFileDialog. I need to access this dialog and provide it with a filename. Is there a way to do this in vba?
My idea was to get the window handle (I've already done that) and then somehow get the object using the handle, but i cannot find a way to use the handle to access the window.
if you have the hWind of the dialag box, then the function
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
will allow you to send keys to the application with
Debug.Print PostMessage(hWind, WM_KEYDOWN, vbKeyA, 0)
more info here

vb6: how to click buttons on another running process?

using vb6 is it possible to click buttons and forms on another running process programmatically ?
Look at the SendMessage() API call. This is what Windows itself uses to notify a button it has been clicked.
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
E.g.
retval = SendMessage(hwndButton, BM_CLICK, ByVal CLng(0), ByVal CLng(0))
Tricky bit is getting the window handle of the button (hwndButton). FindWindow() and EnumChildWindows() APIs will do this. FindWindow() will return the handle of the top-level windows (e.g. Notepad). Then EnumChildWindows can be used to iterate the controls until the correct button is found.

Resources