I'm attempting to create a VB6 executable (not sure of the proper syntax) that will toggle the X-Mouse option in Tweak UI under Windows 98SE. Ideally, I would like to have two scripts - one that turns it off (regardless of its state) and one that turns it on (again, regardless of its state).
I have been able to open the TweakUI control panel with the code below.
Private Sub Form_Load()
Call Shell("rundll32.exe shell32.dll,Control_RunDLL tweakui.cpl", vbNormalFocus)
End Sub
If possible, I would like it to do it without opening the TweakUI control panel.
As far as I can tell, changing the registry setting doesn't work as I would have to reboot the computer for that to take effect.
I have Registry Monitor 7.04 running. It captures the following:
Path: C:\WINDOWS\RUNDLL32.EXE
Command Line: "C:\WINDOWS\RUNDLL32.EXE" "C:\WINDOWS\SYSTEM\TWEAKUI.CPL", Tweak UI
Other: hKey: 0xC2A066F0
Honestly, I'm not sure how to move forward.
Not sure the best way to show progress on this, I'll just edit.
This code is very close.
Private Declare Function SystemParametersInfo Lib "user32" Alias _
"SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, _
ByRef lpvParam As Any, ByVal fuWinIni As Long) As Long
Const SPI_SETACTIVEWINDOWTRACKING = 4097
'Click on this button to Activate XMouse
Private Sub Command1_Click()
SystemParametersInfo SPI_SETACTIVEWINDOWTRACKING, 0, True, 0
End Sub
'Click on this button to Deactivate XMouse
Private Sub Command2_Click()
SystemParametersInfo SPI_SETACTIVEWINDOWTRACKING, 0, False, 0
End Sub
Button 1 works correctly and Activates XMouse. But button two does not deactivate it.
SPI_SETACTIVEWINDOWTRACKING is the parameter that does this.
systemparametersinfo is the function call that gets or sets settings like this. See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
There is sample code using systemparametersinfo that changes the wallpaper. https://winsourcecode.blogspot.com/2019/06/changewallpaper.html
Thank you to all of the input. I was able to solve this problem.
Private Declare Function SystemParametersInfo Lib "user32" Alias _
"SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, _
ByVal lpvParam As Boolean, ByVal fuWinIni As Long) As Long
Const SPI_SETACTIVEWINDOWTRACKING = 4097
Private Sub Command1_Click()
retVal = SystemParametersInfo(SPI_SETACTIVEWINDOWTRACKING, 0, True, 0)
End Sub
Private Sub Command2_Click()
retVal = SystemParametersInfo(SPI_SETACTIVEWINDOWTRACKING, 0, False, 0)
End Sub
In addition to the help here, I stumbled upon a few gems that gave me what I needed.
Control the mouse speed under Windows 98 / 2000
and
Controling Active Window Tracking
A couple things of note. I had to include this or else nothing happened:
Const SPI_SETACTIVEWINDOWTRACKING = 4097
Also, the 3rd parameter was
ByRef lpvParam As Boolean
Instead of
ByVal lpvParam As Boolean
I was passing a pointer to a pointer instead of a pointer to a value
Related
The Problem
Call a procedure whenever the Main Excel Window is resized.
First attempt:
Sub Workbook_WindowResize(ByVal Wn As Window)
Debug.Print Wn.Width & "x" & Wn.Height
End Sub
Results:
The sub routine is called whenever the 'inner' workbook window is resized but not when the application window is resized. I.E. occcurs on resize of the Multiple Document Interface child containing the application instance.
Second attempt
Dim WithEvents App As Application
Private Sub App_WindowResize(ByVal Wb As Workbook, ByVal Wn As Window)
Debug.Print Wn.Width & "x" & Wn.Height
End Sub
Results:
Oddly, the same thing that happened before occurs, which definitely surprised me. The event only occurs when the workbook window is resized instead of the application window.
For this reason I started looking into using the windows API.
There are many examples of setting SystemWide keyboard and mouse hooks using the windows APIs. This is along the same lines:
Public Enum enHookTypes
WH_CALLWNDPROC = 4
WH_CALLWNDPROCRET = 12
WH_CBT = 5
WH_DEBUG = 9
WH_FOREGROUNDIDLE = 11
WH_GETMESSAGE = 3
WH_HARDWARE = 8
WH_JOURNALPLAYBACK = 1
WH_JOURNALRECORD = 0
WH_MOUSE = 7
WH_MSGFILTER = (-1)
WH_SHELL = 10
WH_SYSMSGFILTER = 6
WH_KEYBOARD_LL = 13
WH_MOUSE_LL = 14
WH_KEYBOARD = 2
End Enum
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As LongPtr, ByVal lpfn As Long, ByVal hMod As Long, ByVal dwThreadId As Long) As LongPtr
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function GetLastError Lib "kernel32" () As Long
'Ensure that your hook procedure does not interfere with the normal operation of other hook procedures
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Public hndl As Long
Sub HookWindow()
hndl = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf measureWindow, Application.Hinstance, 0&)
Debug.Print hndl & "~~" & GetLastError()
End Sub
Sub unhookWindow()
ret = UnhookWindowsHookEx(hndl)
Debug.Print ret
End Sub
Public Sub measureWindow(code As Long, wParam As Long, lParam As Long)
If code > 0 Then
Debug.Print ThisWorkbook.Windows(1).Width & "x" & ThisWorkbook.Windows(1).Height
Else
ret = CallNextHookEx(measureWindow, code, wParam, lParam)
End If
End Sub
Results:
If I replace the WH_CALLWNDPROC in:
hndl = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf measureWindow, Application.Hinstance, 0&)
with WH_KEYBOARD_LL the sub-routine is called whenever a key is pressed. Similarly, if I replace it with WH_MOUSE_LL the sub-routine is called whenever the mouse is moved or a mouse button pressed.
The problem is that when I try to hook the sub-routine to WH_CALLWNDPROC nothing happens?
Why?
I'm still not sure, but the same is true for all ENUMS in enHookTypes except WH_MOUSE_LL and WH_KEYBOARD_LL. Looking through the WinAPI documentation I read that you can use GetLastError from Kernel32.dll do get some indication of why the operation failed.
The error numbers I have got so far are (in decimal) error 5 (for JOURNAL hooks) and error 1428 for the rest.
Ultimately this also failed.
Application.Windows is a collection of window objects of Worbooks opened within the Application. The WindowResize event is raised when a non-maximized window changes size. The Workbook_WindowResize(ByVal Wn As Window) is exposed within the workbook object itself. The Application_WindowResize(ByVal Wb as Workbook, ByVal Wn As Window) event has to do with ANY/ALL of the workbooks within the Application when a non-maximized workbook's window changes size. Hence the difference in references passed in by the events. It is just a Window in the first case, of the workbook that raised the event, within the workbook object, and there is no question here which window it is (it's the "Me" workbook's window). It is both the Workbook and that workbook's window when it is raised at the Application level since the workbook the event relates to needs identification :) And no, Excel does not have a "Resize" event for the App window itself and you would need to go to APIs for that.
With the later Excel versions (past the 2010), there is ONE workbook per Excel Application window, the workbook's window is always maximized in the old sense, and both Workbook and Application events refer to the same workbook and would work just as you would want them to.
Solution , create a timer event that checks and compares the width every few seconds...
Sub my_ONTIME()
application.OnTime Now + TimeValue("00:00:2"), "my_TIMEREVENT"
End Sub
Sub my_TIMEREVENT()
If application.Width <> EWIDTHR Then ESCREENRESIZE
my_ONTIME
End Sub
Sub ESCREENRESIZE()
Dim EWIDTH As Single
Dim ESIDE As Single
Dim EMID As Single
EWIDTH = application.Width
EWIDTHR = EWIDTH
If EWIDTH < 500 Then
EWIDTH = 500
application.Width = 500
End If
EMID = 80 * 5.41
ESIDE = ((EWIDTH - EMID) / 2) / 5.41
Sheet1.Columns("A:A").ColumnWidth = ESIDE
Sheet1.Columns("C:C").ColumnWidth = ESIDE
End Sub
I have a Rich Text Box control. It has no scroll bars, cause I am using Mouse Wheel module to capture Mouse Wheel events.
When the rich text box is selected and mouse wheel is rotated up/down it sends keys {UP} and {DOWN} to they rich text box to "mimic" the scroll effect.
However, when you are at the beginning or at the ending of the text box content (e.g there's nothing to scroll anymore), there's annoying beep system sound playing. I need to disable this, any ideas how to do that ?
Already tried adding this code in the rich text box's keypress event:
If KeyAscii = 38 Or KeyAscii = 40 Then
KeyAscii = 0
End If
Doesn't work. Don't know why it just doesn't work when it is supposed to be working.
Use the KeyDown event instead of KeyPress, and disable the KeyCode only if the cursor is located at the first/last line to prevent disabling the arrow keys (up/down) completely.
First you need to add the following to the declarations:
Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long
Private Const EM_LINEFROMCHAR = &HC9
Private Const EM_GETLINECOUNT = &HBA
Private Function GetCurrentLine(Txt As RichTextBox) As Long
GetCurrentLine = SendMessage(Txt.hWnd, EM_LINEFROMCHAR, Txt.SelStart, 0&) + 1
End Function
Private Function GetLineCount(Txt As RichTextBox) As Long
GetLineCount = SendMessage(Txt.hWnd, EM_GETLINECOUNT, 0&, 0&)
End Function
Then use the KeyDown event as described:
Private Sub RichTextBox1_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyUp Then
If GetCurrentLine(RichTextBox1) = 1 Then KeyCode = 0
ElseIf KeyCode = vbKeyDown Then
If GetCurrentLine(RichTextBox1) = GetLineCount(RichTextBox1) Then KeyCode = 0
End If
End Sub
Of course you'll need to replace RichTextBox1 with the name of your RichTextBox.
Hope that helps :)
Outside of a function/sub
Public Declare Function SendMessageByVal Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
In your sub/function
Ret = SendMessageByVal(gRtfHwnd, EM_SETEDITSTYLE, SES_ALLOWBEEPS + SES_USECRLF, SES_ALLOWBEEPS + SES_USECRLF)
To see more see http://ambracode.com/index/show/1405175 which is some copy of an old post I made at SO.
I have a webform displayed in a WebBrowser control in a Visual Basic application to allow users to upload files to my webserver. Unusually for this type of thing, I know in advance the folder they need to browse to (I want them to upload a file which the VB application has generated) and I would like the Browse dialog box to default to that folder but it seems to default to whichever folder was last used by any application for File / Open.
I've tried using ChDir in VB to set the current folder but that doesn't work.
Is there any way I can persuade the Browse box to default to my desired folder?
First of all, I ought to state that there is no reliable way of doing this. The reason why it is so hard is for security reasons. There is a defaultValue and value property for the INPUT TYPE=FILE element, but if programmers had access to this, this could be used to suck files from the client machine - definitely not a good idea.
In Internet Explorer, the browse file dialogue is actually implemented by a Windows Common Dialog component. However, you have no direct access to this component.
There is no reliable browser-independent way of doing this. And I certainly don't recommend you reverse-engineer the "Last Recently Used" file list for the Common Dialog control (see jac's link). Doing that is very dangerous, since it is an internal-algorithm likely to change. And worse, you are hacking global state to solve a local problem (see Old New Thing blog, ad nauseam).
A solution that doesn't violate global state, but still hacky is to take advantage of the fact we know what the text is on the file upload dialogue. After your document has loaded, you can use a Timer to wait for the dialogue to appear, and at that point, paste the correct directory into the dialogue.
In my sample, I have code where the web browser control sits, and the BrowserHack.bas module.
Form code:
Option Explicit
Private Sub cmdLoadPage_Click()
' Store the default path into the .Tag property.
tmrWaitForDialogue.Tag = "C:\Windows\System32"
' Load URL.
wbMain.Navigate "<URL>"
End Sub
Private Sub Form_Load()
tmrWaitForDialogue.Enabled = False
tmrWaitForDialogue.Interval = 100 ' 10th of a second delay.
End Sub
Private Sub tmrWaitForDialogue_Timer()
If BrowserHack.IsBrowserFileDialogueVisible Then
' We don't want the Timer to fire again.
tmrWaitForDialogue.Enabled = False
' Copy the directory onto the clipboard.
Clipboard.Clear
Clipboard.SetText tmrWaitForDialogue.Tag
' The focus will be on the file path text box in the Open dialogue.
' Use CTL-V to paste the text, and then followed by an Enter character to
' dismiss the dropdown, and another to Open the folder.
SendKeys "^V"
SendKeys "{ENTER}"
SendKeys "{ENTER}"
End If
End Sub
Private Sub wbMain_DocumentComplete(ByVal pDisp As Object, URL As Variant)
tmrWaitForDialogue.Enabled = True
End Sub
BrowserHack:
' Purpose: Code to look for the WebBrowser (Internet Explorer) dialogue which appears when a File Upload control is clicked.
' Notes: Internet Explorer version dependent.
Option Explicit
Private Declare Function EnumThreadWindows Lib "User32.dll" ( _
ByVal dwThreadId As Long, _
ByVal lpfn As Long, _
ByVal lParam As Long _
) As Long
Private Declare Function GetClassName Lib "User32.dll" Alias "GetClassNameW" (ByVal hWnd As Long, ByVal lpClassName As Long, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowText Lib "User32.dll" Alias "GetWindowTextW" (ByVal hWnd As Long, ByVal lpString As Long, ByVal nMaxCount As Long) As Long
Private Declare Function IsWindowVisible Lib "User32.dll" (ByVal hWnd As Long) As Long
Private Const APITRUE As Long = 1 ' Win32 API TRUE value
Private Const APIFALSE As Long = 0 ' Win32 API FALSE value
' This dialogue class is pretty universal.
Private Const m_ksDialogueClass As String = "#32770"
Private Const m_knDialogueClassLen As Long = 6
' This text may well change every time the browser is updated.
Private Const m_ksDialogueText As String = "Choose File to Upload"
Private Const m_knDialogueTextLen As Long = 21
' Buffers to be used for these strings.
Private m_sClassNameBuffer As String
Private m_sWindowNameBuffer As String
' Callback from the EnumThreadWindow() function.
Private Function EnumThreadWndProc( _
ByVal hWnd As Long, _
ByVal lParam As Long _
) As Long
Dim nRet As Long
' Filter out hidden windows.
If IsWindowVisible(hWnd) = APITRUE Then
' Retrieve the class name of the window.
' Note that this function requires you to allocate a buffer *including* the terminating null character.
' Since VB strings *always* are null terminated, we can add one to the string length.
nRet = GetClassName(hWnd, StrPtr(m_sClassNameBuffer), (m_knDialogueClassLen + 1))
' If the classes match, then try for a match on the window's text.
If m_sClassNameBuffer = m_ksDialogueClass Then
' Ditto GetClassName().
nRet = GetWindowText(hWnd, StrPtr(m_sWindowNameBuffer), (m_knDialogueTextLen + 1))
If m_sWindowNameBuffer = m_ksDialogueText Then
' This return value says "stop the enumeration".
' In this case EnumThreadWindow() with also return APIFALSE.
EnumThreadWndProc = APIFALSE
Exit Function
End If
End If
End If
EnumThreadWndProc = APITRUE
End Function
' Purpose: If the browser window is detected
Public Function IsBrowserFileDialogueVisible() As Boolean
' If this is the first time this function has been called, the buffers will not be allocated.
' Do this now.
If LenB(m_sClassNameBuffer) = 0 Then
m_sClassNameBuffer = Space$(m_knDialogueClassLen)
m_sWindowNameBuffer = Space$(m_knDialogueTextLen)
End If
' Enumerate through all windows on this thread. VB apps are single-threaded, and all GUI elements are forced to be on this thread, so this is ok.
If EnumThreadWindows(App.ThreadID, AddressOf EnumThreadWndProc, 0&) = APIFALSE Then
IsBrowserFileDialogueVisible = True
Else
IsBrowserFileDialogueVisible = False
End If
End Function
i want achieve when shortcut link runs ... the form closes automatically, btw im new to vb coding so any help will be much appreciated, here's my code so far
Private Sub Form_Load()
Set ss = CreateObject("WScript.Shell")
ss.Run Chr(34) & ss.specialfolders("Desktop") & "\app\SOMEGAME.lnk" & Chr(34)
End Sub
Assuming you're using VB6 (which is what your code looks like) you can close your form by calling
Unload Me
at the end of the Form_Load event handler.
However, you don't need to use a form to launch a shortcut - you can add a module to your project (right-click your project, select Add -> Module) and then just call the ShellExecute() function to launch your shortcut like so:
'Declare the ShellExecute() API function
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
Private Const SW_SHOWNORMAL As Long = 1
'Entry point of your program
Public Sub Main()
Dim sPath As String
sPath = "C:\app\SOMEGAME.lnk"
ShellExecute 0, vbNullString, sPath, vbNullString, "C:\", SW_SHOWNORMAL
End Sub
To make this work, set the Startup Object under Project Properties to Sub Main.
Using this approach, you don't have a form - your program just runs from the command-line (or from its own shortcut). It's generally better not to create / show a form if your program doesn't need it since forms use extra resources.
With that said, you should try using VB.Net or C# to write programs for Windows - VB6 is old technology without support and it can't handle a number of new technologies. If you don't already know VB6 there's little point in learning it now - your time could be put to much better use by learning VB.Net / C#.
I'm putting together a small program in Visual Basic Express 2010, and part of it is to take a delayed screen shot.
I've got the main code working, I've got Visual Basic delaying taking the screen shot with System.Threading.Thread.CurrentThread.Sleep(5000), but what I'm looking for is a way to draw directly to the screen the number of seconds remaining.
You know how in Windows, in the Display Properties under Settings, when you click on Identify you get a huge number displayed on each monitor?
I'm trying to recreate that, with the number counting down until the screen shot is taken, giving the user plenty of notification to get their required applications in focus for the screen shot.
Is it possible to do this? Or is it something that will take a heck of a lot of coding?
Many thanks for any help you can offer
Create a Label control in a Form and use something like the following to make it transparent:
Me.TransparencyKey = Color.Gray ' or any other color.
Me.BackColor = TransparencyKey
Me.FormBorderStyle = FormBorderStyle.None
will make something like this:
To make your window transparent to mouse, PInvoke GetWindowLong and SetWindowLong:
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowLong( _
ByVal hWnd As IntPtr, _
ByVal nIndex As Integer) As Integer
End Function
<DllImport("user32.dll")> _
Private Shared Function SetWindowLong( _
ByVal hWnd As IntPtr, _
ByVal nIndex As Integer, _
ByVal dwNewLong As IntPtr) As Integer
End Function
Then in your Form_Load() add the following:
Dim hwnd As IntPtr = Me.Handle
Dim extendedStyle As Integer = GetWindowLong(hwnd, GWL_EXSTYLE)
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle Or WS_EX_TRANSPARENT)
Constants:
Const WS_EX_TRANSPARENT As Integer = &H20
Const GWL_EXSTYLE As Integer = -20