Changing windows settings with a script - c#

I have a problem that every once in a while the amount of lines or w\e that moves when I turn the mouse wheel goes from 3 to 30 and my brother sometimes sees it changes to 100.
What I'm talking about is when you go to "Control Panel" -> "Mouse" -> and then the mouse-wheel tab, it has 2 number-scrollers, and I need to change the value of the first one with a script or .exe or whatever way you know how to change it with.
For whoever might encounter that problem and wants the solution, here's the code:
[DllImport("user32.dll", SetLastError = true)]
static extern bool SystemParametersInfo(int uiAction, int uiParam, IntPtr pvParam, int fWinIni);
static void Main(string[] args)
{
const int SPI_SETWHEELSCROLLLINES = 0x0069;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDCHANGE = 0x02;
SystemParametersInfo(SPI_SETWHEELSCROLLLINES, 3, IntPtr.Zero,
SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
}
Thanks for helping!

System parameters are not to be changed via registry keys, because (1) that's an implementation detail, that may change in future versions of Windows or even depending on other user profile settings and (2) because you are updating just the saved value, not the one that is currently active.
The correct way to go is to use the SystemParametersInfo API specifying the correct parameter constant (in your case, SPI_SETWHEELSCROLLLINES) and SPIF_UPDATEINIFILE | SPIF_SENDCHANGE as last parameter to both activate it right now and save it for the next sessions.

With regedit you can setup a script that sets the mouse wheeel scrolling speed, property is here:
HKEY_CURRENT_USER\Control Panel\Desktop\WheelScrollLines
just browse regedit (win+R regedit) look at the WeelScrollLines value, then create a reg file as specified by microsoft : https://support.microsoft.com/en-us/kb/310516#bookmark-syntax

Related

Change system default language programmatically with c#

We have a virtual keyboard (for touch screen) which its language layout is configured via the windows default language.
I have seen numerous answers which involves InputLanguageManager and CultureInfo.
They're not useful to me, didn't do the job.
There is this one method - SystemParametersInfo function with the SPI_SETDEFAULTINPUTLANG flag that i'm trying to check.
So far, didn't find any useful usage examples besides this one here, but it changes the keyboard layout from Dvorak to Marshal.
Can you give me an example (hopefully with the SystemParametersInfo) that converts the default system language to en-US?
Edit
A brief clarification.
This program replaces the explorer as windows shell, hence all keyboard settings such as setting default keyboard layout should be handled from my program.
Moreover, my wish is to replace between different installed languages such as English, Swedish, Portuguese and so on..
I don't want to change between Dvorak and Qwerty layout of the keyboard.
The purpose of this post is to ask for examples for changing between different languages and not for layout of English symbols on keyboard.
Thanks!
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref uint pvParam, uint fWinIni);
public void Foo()
{
uint localeUS = 0x00000409;
uint localeNL = 0x00000403;
SetSystemDefaultInputLanguage(localeUS);
}
public bool SetSystemDefaultInputLanguage(uint locale)
{
return SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref locale, 0);
}
public uint GetSystemDefaultInputLanguage()
{
uint result = uint.MinValue;
bool retVal = SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, ref result, 0);
return result;
}
This seems to work fine for me.
Sources:
SystemParametersInfo API
SystemParametersInfo Parameter Definition
Input Locales List MSDN

"No Disk" error using GDAL from C#/.NET

I am using Tamas Szekeres builds of GDAL including the C# bindings in a desktop GIS application using C# and .net 4.0
I am including the entire GDAL distribution in a sub-directory of my executable with the following folder structure:
\Plugins\GDAL
\Plugins\GDAL\gdal
\Plugins\GDAL\gdal-data
\Plugins\GDAL\proj
We are using EPSG:4326, and the software is built using 32-bit target since the GDAL C# API is using p/invoke to the 32-bit libraries (could try 64 bit since Tamas provides these, haven't gotten around to it yet).
When I run my application I get the following error
This error typically happens when software tries to access a device that is no longer attached, such as a removable drive. It is not possible to "catch" this exception because it pops up a system dialog.
After dismissing the dialog using any of the buttons, the software continues to execute as designed.
The error occurs the first time I call the following method
OSGeo.OSR.CoordinateTransformation.TransformPoint(double[] inout);
The strange stuff:
The error occurs on one, and only one computer (so far)
I've run this software in several other computers both 32 and 64 bit without problems
The error does not ocurr on the first run after compiling the GDAL shim library I am using, it only occurrs on each subsequent run
it happens regardless of release, or debug builds
it happens regardless of whether the debugger is attached or not
it happens regardless of whether I turn on or off Gdal.UseExceptions or Osr.UseExceptions();
disabling removable drives causes the bug to disappear. This is not what I consider a real solution as I will not be able to ask a customer to do this.
I have tried the following:
catching the error
changing GDAL directories and environment settings
changing computers and operating systems: this worked
used SysInternals ProcMon to trace what files are being opened with no luck, they all appear to be files that exist
I re-built the computer in question when the hard drive failed, to no avail.
"cleaning" the registry using CCleaner
files in GDAL Directory are unchanged on execution
Assumptions
Error is happening in unmanaged code
During GDAL initialization, some path is referring to a drive on the computer that is no longer attached.
I am also working on the assumption this is limited to a computer configuration error
Configuration
Windows 7 Pro
Intel Core i7 920 # 2,67GHz
12.0 GB RAM
64-bit OS
Drive C: 120 GB SSD with OS, development (Visual Studio 10), etc
Drive D: 1 TB WD 10,000k with data, not being accessed for data.
The Question
I either need a direction to trap the error, or a tool or technique that will allow me to figure out what is causing it. I don't want to release the software with the possibility that some systems will have this behaviour.
I have no experience with this library, but perhaps some fresh eyes might give you a brainwave...
Firstly, WELL WRITTEN QUESTION! Obviously this problem really has you stumped...
Your note about the error not occurring after a rebuild screams out: Does this library generate some kind of state file, in its binary directory, after it runs?
If so, it is possible that it is saving incorrect path information into that 'configuration' file, in a misguided attempt to accelerate its next start-up.
Perhaps scan this directory for changes between a 'fresh build' and 'first run'?
At very least you might find a file you can clean up on shut-down to avoid this alert...
HTH
Maybe you can try this:
Run diskmgmt.msc
Change the driveletter for Disk 2 (right click) if my assumption that Disk 2 is a Removable Disk is true
Run your application
If this removes the error, something in the application is referring to the old driveletter
It could be in the p/invoked libs
Maybe see: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46501 It talks about gcc somehow compiling a driveletter into a binary
+1 Great question, but It is not possible to "catch"
Its one of these awful solutions that will turn up on DailyWTF in 5 years. But for now it is stored here http://www.pinvoke.net/default.aspx/user32.senddlgitemmessage
using Microsoft.VisualBasic; //this reference is for the Constants.vbNo;
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern IntPtr SendDlgItemMessage(IntPtr hDlg, int nIDDlgItem, uint Msg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetActiveWindow(IntPtr hWnd);
// For Windows Mobile, replace user32.dll with coredll.dll
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
// Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetDlgItemText(IntPtr hDlg, int nIDDlgItem,[Out] StringBuilder lpString, int nMaxCount);
public void ClickSaveBoxNoButton()
{
//In this example, we've opened a Notepad instance, entered some text, and clicked the 'X' to close Notepad.
//Of course we received the 'Do you want to save...' message, and we left it sitting there. Now on to the code...
//
//Note: this example also uses API calls to FindWindow, GetDlgItemText, and SetActiveWindow.
// You'll have to find those separately.
//Find the dialog box (no need to find a "parent" first)
//classname is #32770 (dialog box), dialog box title is Notepad
IntPtr theDialogBoxHandle; // = null;
string theDialogBoxClassName = "#32770";
string theDialogBoxTitle = "Notepad";
int theDialogItemId = Convert.ToInt32("0xFFFF", 16);
StringBuilder theDialogTextHolder = new StringBuilder(1000);
//hardcoding capacity - represents maximum text length
string theDialogText = string.Empty;
string textToLookFor = "Do you want to save changes to Untitled?";
bool isChangeMessage = false;
IntPtr theNoButtonHandle; // = null;
int theNoButtonItemId = (int)Constants.vbNo;
//actual Item ID = 7
uint theClickMessage = Convert.ToUInt32("0x00F5", 16);
//= BM_CLICK value
uint wParam = 0;
uint lParam = 0;
//Get a dialog box described by the specified info
theDialogBoxHandle = FindWindow(theDialogBoxClassName, theDialogBoxTitle);
//a matching dialog box was found, so continue
if (theDialogBoxHandle != IntPtr.Zero)
{
//then get the text
GetDlgItemText(theDialogBoxHandle, theDialogItemId, theDialogTextHolder, theDialogTextHolder.Capacity);
theDialogText = theDialogTextHolder.ToString();
}
//Make sure it's the right dialog box, based on the text we got.
isChangeMessage = Regex.IsMatch(theDialogText, textToLookFor);
if ((isChangeMessage))
{
//Set the dialog box as the active window
SetActiveWindow(theDialogBoxHandle);
//And, click the No button
SendDlgItemMessage(theDialogBoxHandle, theNoButtonItemId, theClickMessage, (System.UIntPtr)wParam, (System.IntPtr)lParam);
}
}
It turns out there was no way to definitely answer this question.
I ended up "solving" the problem by figuring out that there was some hardware registered on the system that wasn't present. It is still a mystery to me why, after several years, only GDAL managed to provoke this bug.
I will put the inability to catch this exception down to the idiosyncrasies involved with p/invoke and the hardware error thrown at a very low level on the system.
You could add custom error handlers to gdal. This may help:
Link
http://trac.osgeo.org/gdal/ticket/2895

How to 'Refresh' the Vista start menu programmatically

I am working on a piece of code that removes an extra folder we have in the user's start menu. I start by removing all of the shortcuts it contains, and then remove the folder itself.
After this is done, I can confirm that the shortcuts have been removed from the start menu, but their containing folder remains listed in the start menu. So, I checked the file system for such a folder and found none. Suspecting that this is some sort of refresh problem, I logged my user out and back into Vista and found that the folder was now removed from the start menu list.
How utterly annoying... Does anyone know how to programmatically force a 'refresh' of the Vista start menu, so that the user doesn't see this empty folder before they log out?
Thanks,
-Ben
I tried to implement this myself but it did not work as expected using SendMessageTimeout.
Instead, it worked when I used
SHGetSpecialFolderLocation(CSIDL_STARTMENU)
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, NULL);
See this article for sample c++ code:
http://support.microsoft.com/kb/q193293/
Tested on Windows Server 2008 Enterprise (x86) with SP1.
This article seems to have the answer you're looking for:
http://social.msdn.microsoft.com/forums/en-US/winforms/thread/ce540c7d-a113-4f39-956e-0af6bc91abd3/
The answer given is:
class Program
{
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SendMessageTimeout ( IntPtr hWnd, int Msg, IntPtr wParam, string lParam, uint fuFlags, uint uTimeout, IntPtr lpdwResult );
private static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff);
private const int WM_SETTINGCHANGE = 0x1a;
private const int SMTO_ABORTIFHUNG = 0x0002;
static void Main ( string[] args )
{
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, null, SMTO_ABORTIFHUNG, 100, IntPtr.Zero);
}
}

Disabling Screen Saver and Power Options in C#

I am writing an application in C# that plays a movie. I need to figure out how to disable the screen saver and power options using C#.
I know the Windows SDK API has a function called SetThreadExecutionState() which can be used to do this, however, I do not know if there is a better way to do it. If not, how do I incorporate this function into C#?
Not sure if there is a better .NET solution but here is how you could use that API:
The required usings:
using System.Runtime.InteropServices;
The P/Invoke:
public const uint ES_CONTINUOUS = 0x80000000;
public const uint ES_SYSTEM_REQUIRED = 0x00000001;
public const uint ES_DISPLAY_REQUIRED = 0x00000002;
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint SetThreadExecutionState([In] uint esFlags);
And then disable screensaver by:
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
Finnaly enable screensaver by reseting the execution state back to original value:
SetThreadExecutionState(ES_CONTINUOUS);
Note that I just picked one of the flags at random in my example. You'd need to combine the correct flags to get the specific behavior you desire. You will find the description of flags on MSDN.

C#/.NET app doesn't recognize Environment Var Change (PATH)

In my C# app, I am programmatically installing an Oracle client if one is not present, which requires adding a dir to the PATH system environment variable. This all works fine, but it doesn't take effect until the user logs out/in to windows, or reboots. How can I get my app to recognize and use the new PATH var without this step? Even restarting my app would be better than requiring the user to log out/in.
Supposedly, broadcasting this change to other processes should work. Here's what I've tried, with no success:
using System.Runtime.InteropServices;
private const int HWND_BROADCAST = 0xffff;
private const int WM_WININICHANGE = 0x001a, WM_SETTINGCHANGE = WM_WININICHANGE, INI_INTL = 1;
[DllImport("user32.dll")]
private static extern int SendMessageTimeoutA(int hWnd, uint wMsg, uint wParam, string lParam, int fuFlags, int uTimeout, int lpdwResult);
int rtnVal = 0;
SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, "Environment", 2, 5000, rtnVal);
I've been told if you stop and restart the process in question, it should pick up these kinds of changes, but restarting my app doesn't do it. I suppose it could be an Oracle issue, that something about Oracle requires the login to recognize the change, I'm not sure. Thanks in advance.
Does Environment.GetEnvironmentVariable("MYVAR", EnvironmentVariableTarget.Machine) not work?
If my app is running elevated then I can
Environment.SetEnvironmentVariable("MYVAR", "cool", EnvironmentVariableTarget.Machine);
//do some other stuff...
Console.WriteLine(Environment.GetEnvironmentVariable("MYVAR", EnvironmentVariableTarget.Machine));
C:\TestApp>>TestApp.exe
cool
I don't know if this will work for other running processes but it should for your app doing the getting/setting
Your problem is only certain apps listen for that message (such as explorer) so it will not be used by your application at all. As the environment is generally inherited then restarting your app from within itself isn't going to help as it will get your current Environment block. If the user restarts from the start menu it will work (assuming the WM_SETTINGCHANGE has been broadcast).
You are best using Environment.GetEnvironmentVariable to read out the current value from the registry and merge it back into you current environment. Basically doing Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) + ";" + (Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User)));
In our project we setup Oracle Instant Client with use of "install.bat" from Instant Client archive. For example:
install.bat odp.net1x %1 name

Categories

Resources