I want to get the current mouse pointer speed, and I want to set it.
To get it, I use
Public Declare Function SystemParametersInfo Lib "user32.dll" Alias "SystemParametersInfoA" (ByVal uAction As Int32, ByVal uParam As Int32, ByRef lpvParam As Int32, ByVal fuWinIni As Int32) As Int32
Dim Result As Int32 = 0
Dim iSuccess As Integer = SystemParametersInfo(SPI_GETMOUSESPEED, 0, Result, 0)
To set it, I use
Public Declare Function SystemParametersInfo Lib "user32.dll" Alias "SystemParametersInfoA" (ByVal uAction As Int32, ByVal uParam As Int32, ByVal lpvParam As Int32, ByVal fuWinIni As Int32) As Int32
Dim iVal As Integer = 10
Dim iSuccess As Integer = SystemParametersInfo(SPI_SETMOUSESPEED, 0, iVal, 0)
Please note the different declarations of the same function.
If I change the ByRef to ByVal or vice versa, one of the functions does not work.
Do I really have to declare the same function differently? Or did I make any mistakes? If I did, can somebody please tell me how to do it correctly?
The core problem is that you cannot declare an overload in VB this way because as the error message says, they cannot overload each other because there differ only by parameters declared ByRef and ByVal
(you didnt mention the error). This would not happen in C# because you'd use in
and out
which would change the signature.
You have several options, one is to use the Alias
:
' declaration for all ByVal args:
Declare Function SetSysParam Lib "user32.dll" Alias "SystemParametersInfoA"...
' one parm ByRef for getting the speed:
Declare Function GetSysParam Lib "user32.dll" Alias "SystemParametersInfoA"...
In case it is not obvious, you'd invoke them as SetSysParam
and GetSysParam.
Code Analysis/FxCop will likely complain about the way you are using these, so here is how to implement API calls so it doesnt. Start with a class named NativeMethods
:
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function SystemParametersInfo(uiAction As SPI,
uiParam As UInteger,
pvParam As IntPtr,
fWinIni As SPIF) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
' alias a ByRef version for GETting the speed, but this is not
' needed since NET offers a cleaner way
<DllImport("user32.dll", EntryPoint:="SystemParametersInfo", SetLastError:=True)>
Private Shared Function SystemParametersInfoPVByRef(uiAction As SPI,
uiParam As UInteger,
ByRef pvParam As IntPtr,
fWinIni As SPIF) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
' other stuff for the last param
<Flags>
Enum SPIF
None = &H0
SPIF_UPDATEINIFILE = &H1
SPIF_SENDCHANGE = &H2
SPIF_SENDWININICHANGE = &H2
End Enum
' there are lots and lots of Sys Params, so use an Enum to group them
Enum SPI
SETMOUSESPEED = &H71
GETMOUSESPEED = &H70
End Enum
' exposed "wrapper" for setting the value to allow a more
' meaningful name and hiding gory details of Msg values etc
Friend Shared Function SetMouseSpeed(speed As Integer) As Boolean
' somewhat optional error checking
If speed < 1 Then speed = 1
If speed > 20 Then speed = 20
Return SystemParametersInfo(SPI.SETMOUSESPEED, 0, New IntPtr(speed), SPIF.None)
End Function
Friend Shared Function GetMouseSpeed() As Integer
Dim speed As New IntPtr(0)
' the caller will have to evaluate the return to see if this
' succeeded
If SystemParametersInfoPVByRef(SPI.GETMOUSESPEED, 0, speed, SPIF.None) Then
Return speed.ToInt32
Else
Return -1 ' magic number that API call failed
End If
End Function
One advantage to the NET format is in the return. Nearly all API calls return 0 or 1 to indicate success or failure. The MarshalAs... Boolean
converts that to an Net Boolean. You can add to the class over time collecting the correct magic numbers, declarations, Enums and structures for the various Win32 API calls. It is a shared/static procedure, so it would be called as:
NativeMethods.SetMouseSpeed(myNewSpeed)
The "wrappers" not only hides the untidy details of the API from your code, it can also also work out what to do if the API call fails. In the case of getting the speed, it works out what value to return instead of the current speed if/when the call fails, something not likely be misread as a speed value (like maybe -1). As noted in the code, there is nice clean way to get the mouse speed in .NET making the overload unneeded:
mySpeed = System.Windows.Forms.SystemInformation.MouseSpeed
Finally, I should mention that it is not a good idea to unilaterally change the user's setting for the user's mouse on their system. They picked that value for a reason. If there is some good reason to do so, the original value should be restored when the app exits.
Technical note: I ran this thru CA to make sure of the size of everything