i am developing a basic winform application for which i want to change wallpaper using c#, the problem the image is not stretched to fit the screen size.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace DailyWallpaper
{
class WallpaperChanger
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SystemParametersInfo(
UInt32 action, UInt32 uParam, String vParam, UInt32 winIni);
private static readonly UInt32 SPI_SETDESKWALLPAPER = 0x14;
private static readonly UInt32 SPIF_UPDATEINIFILE = 0x01;
private static readonly UInt32 SPIF_SENDWININICHANGE = 0x02;
public void SetWallpaper(String path)
{
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, path, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
}
}
can anyone tell me how can i rectify this error, thank in advance.
Try executing the following code:
public void SetWallpaper(String path)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(#"Control Panel\Desktop", true);
key.SetValue(#"WallpaperStyle", 2.ToString());
key.SetValue(#"TileWallpaper", 0.ToString());
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, path, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
EDIT:
You can also modify your function and pass a Style to it:
public void SetWallpaper(String path, Style style)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(#"Control Panel\Desktop", true);
if (style == Style.Stretched)
{
key.SetValue(#"WallpaperStyle", 2.ToString());
key.SetValue(#"TileWallpaper", 0.ToString());
}
if (style == Style.Centered)
{
key.SetValue(#"WallpaperStyle", 1.ToString());
key.SetValue(#"TileWallpaper", 0.ToString());
}
if (style == Style.Tiled)
{
key.SetValue(#"WallpaperStyle", 1.ToString());
key.SetValue(#"TileWallpaper", 1.ToString());
}
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, path, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
Related
I am trying to make use of RegenerateUserEnvironment method so that I can refresh environment variables without restarting the instance. However, it ends up with an access violation error. I am not sure but to me, a process updating its own memory should not cause an error.
Things I tried:
Passing the actual token of current process. No chance.
Duplicating current token with all possible permissions. No chance.
Running as administrator, in case it is about SeDebugPrivilege or similar, but no chance.
Any ideas?
Code:
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using Microsoft.Win32;
namespace EnvVarControl
{
internal static partial class Program
{
#region Pinvoke
public const uint STANDARD_RIGHTS_READ = 0x00020000;
public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
public const uint TOKEN_ADJUST_DEFAULT = 0x0080;
public const uint TOKEN_ADJUST_GROUPS = 0x0040;
public const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
public const uint TOKEN_ADJUST_SESSIONID = 0x0100;
public const uint TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID;
public const uint TOKEN_ASSIGN_PRIMARY = 0x0001;
public const uint TOKEN_DUPLICATE = 0x0002;
public const uint TOKEN_IMPERSONATE = 0x0004;
public const uint TOKEN_QUERY = 0x0008;
public const uint TOKEN_QUERY_SOURCE = 0x0010;
public const uint TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
public enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation = 2
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[DllImport("advapi32.dll", SetLastError = true, EntryPoint = "DuplicateTokenEx")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, TOKEN_TYPE TokenType, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
[LibraryImport("shell32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool RegenerateUserEnvironment(IntPtr hToken,
[MarshalAs(UnmanagedType.Bool)] bool bSet);
#endregion Pinvoke
public static void Main()
{
// Subscribe to the UserPreferenceChanged event
SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged;
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
private static void CheckPathBeforeAndAfterRegenerateUserEnvironment()
{
// Get the value of the PATH environment variable before calling RegenerateUserEnvironment
var pathBefore = Environment.GetEnvironmentVariable("PATH");
Console.WriteLine($"BEFORE: {pathBefore}\n");
RefreshEnvironmentVariables();
// Get the value of the PATH environment variable after calling RegenerateUserEnvironment
var pathAfter = Environment.GetEnvironmentVariable("PATH");
Console.WriteLine($"AFTER: {pathAfter}\n");
// Compare the two values of the PATH environment variable
if (pathBefore != pathAfter)
{
Console.WriteLine("Warning: The value of the PATH environment variable has changed!");
}
else
{
Console.WriteLine("No change.");
}
}
private static void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
// Check if the environment variables have changed
if (e.Category == UserPreferenceCategory.General)
{
// Check the value of the PATH environment variable before and after calling RegenerateUserEnvironment
CheckPathBeforeAndAfterRegenerateUserEnvironment();
}
}
private static void RefreshEnvironmentVariables()
{
// Open the process token and duplicate
var token = WindowsIdentity.GetCurrent().AccessToken.DangerousGetHandle();
var duplicatededToken = DuplicateToken(token);
// Call the RegenerateUserEnvironment function to update the environment variables
if (!RegenerateUserEnvironment(duplicatededToken, true))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
}
private static nint DuplicateToken(nint token)
{
var sa = new SECURITY_ATTRIBUTES
{
bInheritHandle = false
};
sa.Length = Marshal.SizeOf(sa);
sa.lpSecurityDescriptor = 0;
const TOKEN_TYPE TokenType = TOKEN_TYPE.TokenPrimary;
const SECURITY_IMPERSONATION_LEVEL SecurityImpersonation = SECURITY_IMPERSONATION_LEVEL.SecurityIdentification;
var DupedToken = new IntPtr(0);
if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, ref sa, TokenType, SecurityImpersonation, ref DupedToken))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
return DupedToken;
}
}
}
Error message:
Exception thrown at ... (shell32.dll) in EnvVarControl.exe: ...: Access violation writing location ...
Edit: Based on the very accurate answer, I paste the correct piece of code below:
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace EnvVarControl
{
internal static partial class Program
{
#region Pinvoke
[LibraryImport("shell32.dll", SetLastError = true)]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool RegenerateUserEnvironment(out IntPtr pPrevEnv, [MarshalAs(UnmanagedType.Bool)] bool bSetCurrentEnv);
#endregion Pinvoke
public static void Main()
{
// Subscribe to the UserPreferenceChanged event
SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged;
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
private static void CheckPathBeforeAndAfterRegenerateUserEnvironment()
{
// Get the value of the PATH environment variable before calling RegenerateUserEnvironment
var pathBefore = Environment.GetEnvironmentVariable("PATH");
Console.WriteLine($"BEFORE: {pathBefore}\n");
RefreshEnvironmentVariables();
// Get the value of the PATH environment variable after calling RegenerateUserEnvironment
var pathAfter = Environment.GetEnvironmentVariable("PATH");
Console.WriteLine($"AFTER: {pathAfter}\n");
// Compare the two values of the PATH environment variable
if (pathBefore != pathAfter)
{
Console.WriteLine("Warning: The value of the PATH environment variable has changed!");
}
else
{
Console.WriteLine("No change.");
}
}
private static void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
// Check if the environment variables have changed
if (e.Category == UserPreferenceCategory.General)
{
// Check the value of the PATH environment variable before and after calling RegenerateUserEnvironment
CheckPathBeforeAndAfterRegenerateUserEnvironment();
}
}
private static void RefreshEnvironmentVariables()
{
// Call the RegenerateUserEnvironment function to update the environment variables
// Reference: https://stackoverflow.com/questions/74913727/trying-to-create-a-demo-using-regenerateuserenvironment-throwing-access-violatio/74914038#74914038
if (!RegenerateUserEnvironment(out _, true))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
}
}
}
RegenerateUserEnvironment does not need a token; the first parameter is a 2-level pointer, which will be set to the previous environmet block.
define RegenerateUserEnvironment as:
[DllImport("shell32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RegenerateUserEnvironment(out IntPtr pPrevEnv, [MarshalAs(UnmanagedType.Bool)] bool bSetCurrentEnv);
and call it like follows:
RegenerateUserEnvironment(out IntPtr pPrevEnv, true)
public partial class Form1 : Form
{
public string[] allFiles = new string[10];
[DllImport("user32.dll", CharSet =CharSet.Auto)]
private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, string pvParam, uint fWinIni);
const uint SPI_SETDESKWALLPAPER = 0x14;
const uint SPIF_UPDATEINIFILE = 0x01;
const uint SPIF_SENDWININICHANGE = 0x02;
public Form1()
{
InitializeComponent();
SystemEvents.PowerModeChanged += OnPowerChange;
}
private void OnPowerChange(object sender, PowerModeChangedEventArgs e)
{
switch (e.Mode) {
case PowerModes.Resume:
var result = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, #"F:\abc", SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
Console.WriteLine(result);
string wp = GetWPPath();
Console.WriteLine(wp);
break;
case PowerModes.Suspend:
var res = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, #"F:\abc", SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
break;
}
}
private static string GetWPPath()
{
RegistryKey wallpaper = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", false);
string wp_path = wallpaper.GetValue("WallPaper").ToString();
wallpaper.Close();
return wp_path;
}
I want to change the wallpaper when i resume laptop from sleep or hibernate. I also checked the registry key, it shows the wallpaper as the path I've set but the desktop background is just black. Is there some kind of reg keys that I have to change or something?
Edit: I hardcoded the file as #"F:\abc", that's the problem. Changed it by mentioning the extension too like #"F:\abc.jpg" and it works. Anyways, I'm gonna change it to an input so shouldn't be a problem. Thanks to all of you.
I have tried to do it in console. It works for me. And later you can add your app to windows autoload.
You must add using System.Runtime.InteropServices;
class Program
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SystemParametersInfo(int uAction,
int uParam, string lpvParam, int fuWinIni);
private static readonly int MAX_PATH = 260;
private static readonly int SPI_GETDESKWALLPAPER = 0x73;
private static readonly int SPI_SETDESKWALLPAPER = 0x14;
private static readonly int SPIF_UPDATEINIFILE = 0x01;
private static readonly int SPIF_SENDWININICHANGE = 0x02;
static string GetDesktopWallpaper()
{
string wallpaper = new string('\0', MAX_PATH);
SystemParametersInfo(SPI_GETDESKWALLPAPER, (int)wallpaper.Length, wallpaper, 0);
return wallpaper.Substring(0, wallpaper.IndexOf('\0'));
}
static void SetDesktopWallpaper(string filename)
{
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, filename,
SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
static void Main()
{
Console.WriteLine("Enter name:");
//should be like - C:\img.jpg
SetDesktopWallpaper(Console.ReadLine());
}
}
I want to write text to the currently selected application but its writing junk and causing weird things to happen.
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Runtime.InteropServices;
namespace i_allbwn
{
class Program
{
static void Main(string[] args)
{
Thread.Sleep(500);
ActionWithChance.brif_allbwn();
Console.ReadKey();
}
}
class ActionWithChance
{
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //Key down flag
public const int KEYEVENTF_KEYUP = 0x0002; //Key up flag
public static void brif_allbwn()
{
argraffu(new String[] {
"line1",
"line2",
"line3",
}
);
}
public static void allbwn(Byte[] Name)
{
for (int i = 0; i < Name.Length; i++)
{
Console.WriteLine("Writing " + (Char)Name[i]);
keybd_event((Byte)Name[i], 0, KEYEVENTF_EXTENDEDKEY, 0);
Thread.Sleep(10);
keybd_event((Byte)Name[i], 0, KEYEVENTF_KEYUP, 0);
}
}
public static void argraffu(String[] text)
{
foreach (String s in text)
{
allbwn(ToByteArray(s));
keybd_event((Byte)'\r', 0, KEYEVENTF_EXTENDEDKEY, 0);
Thread.Sleep(10);
keybd_event((Byte)'\r', 0, KEYEVENTF_KEYUP, 0);
}
}
public static Byte[] ToByteArray(String StringToConvert)
{
Char[] CharArray = StringToConvert.ToCharArray();
Byte[] ByteArray = new Byte[CharArray.Length];
for (int i = 0; i < CharArray.Length; i++)
{
ByteArray[i] = Convert.ToByte(CharArray[i]);
}
return ByteArray;
}
}
}
My functions for doing it are like this:
public const Int32 WM_CHAR = 0x0102;
public void SendKeys(string message)
{
foreach (char c in message)
{
int charValue = c;
IntPtr val = new IntPtr((Int32)c);
SendMessage(WindowHandle, WM_CHAR, val, new IntPtr(0));
}
}
Basically what I'm doing is getting the handle of the application, e.g:
Process proc = Process.GetProcessesByName("Notepad")[0];
Then getting the handle with proc.MainModule.Handle()
The Autoit library makes it really easy to interact with external windows.
Install the nuget package called AutoItX.Dotnet
Then it's just a matter of:
using AutoIt;
class Program
{
static void Main(string[] args)
{
AutoItX.Run("notepad.exe", null);
AutoItX.WinWait("Untitled - Notepad");
AutoItX.ControlSend("Untitled - Notepad", "", "[CLASSNN:Edit1]", "testing");
//ControlSend is the ideal way to send text, but you can also pretend text was typed into the keyboard:
AutoItX.Send("howdy pilgrim");
}
}
How to set Windows 7 Wallpaper slideshow programmatically?
Setting a normal wallpaper
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SystemParametersInfo(UInt32 uiAction, UInt32 uiParam, String pvParam, UInt32 fWinIni);
private static UInt32 SPI_SETDESKWALLPAPER = 20;
private static UInt32 SPIF_UPDATEINIFILE = 0x1;
public void SetImage(string filename)
{
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, filename, SPIF_UPDATEINIFILE);
}
What i found until now:
There is an ini-file for the slideshow in
C:\Users\CurrentUser\AppData\Roaming\Microsoft\Windows\Themes\
The wallpaper has to be in the following folder during the slideshow:
C:\Users\CurrentUser\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg
(during a slideshow the file is changing automatically)
try this
public sealed class Wallpaper
{
Wallpaper() { }
const int SPI_SETDESKWALLPAPER = 20;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDWININICHANGE = 0x02;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
public enum Style : int
{
Tiled,
Centered,
Stretched
}
public static void Set(Uri uri, Style style)
{
System.IO.Stream s = new System.Net.WebClient().OpenRead(uri.ToString());
System.Drawing.Image img = System.Drawing.Image.FromStream(s);
string tempPath = Path.Combine(Path.GetTempPath(), "wallpaper.bmp");
img.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp);
RegistryKey key = Registry.CurrentUser.OpenSubKey(#"Control Panel\Desktop", true);
if (style == Style.Stretched)
{
key.SetValue(#"WallpaperStyle", 2.ToString());
key.SetValue(#"TileWallpaper", 0.ToString());
}
if (style == Style.Centered)
{
key.SetValue(#"WallpaperStyle", 1.ToString());
key.SetValue(#"TileWallpaper", 0.ToString());
}
if (style == Style.Tiled)
{
key.SetValue(#"WallpaperStyle", 1.ToString());
key.SetValue(#"TileWallpaper", 1.ToString());
}
SystemParametersInfo(SPI_SETDESKWALLPAPER,
0,
tempPath,
SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
}
The original question is this
I use this code to play a MIDI file for my game, but I can not hear any sound from my speakers. Would you help me? It's kind of an emergency, please...
My speakers are turned on ;)
[DllImport("winmm.dll", EntryPoint="mciSendStringA")]
private static extern long mciSendString(string lpstrCommand, string lpstrReturnString, long uReturnLength, long hwndCallback);
public static long PlayMidiFile(string MidiFile)
{
long lRet = -1;
if (File.Exists(MidiFile))
{
lRet = mciSendString("stop midi", "", 0, 0);
lRet = mciSendString("close midi", "", 0, 0);
lRet = mciSendString(("open sequencer!"
+ (MidiFile + " alias midi")), "", 0, 0);
lRet = mciSendString("play midi", "", 0, 0);
return lRet;
}
else
{
//Error Message
return lRet;
}
}
I am not really sure about your implementation of winmm.dll but I have a tested and working code for it.
I got the source code from this open source project: Tea Timer.
The implementation of the code is pretty straight forward as below. Hope it helps.
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace TeaTimer
{
/// <summary>
/// MCIPlayer is based off code by Slain.
/// Found here: http://www.sadeveloper.net/Articles_View.aspx?articleID=212
/// </summary>
public class MCIPlayer
{
private static readonly string sAlias="TeaTimerAudio";
[DllImport("winmm.dll")]
private static extern long mciSendString(string strCommand,StringBuilder strReturn,int iReturnLength, IntPtr hwndCallback);
[DllImport("Winmm.dll")]
private static extern long PlaySound(byte[] data, IntPtr hMod, UInt32 dwFlags);
public static void Play(string sFile)
{
_Open(sFile);
_Play();
}
public static void Stop()
{
_Close();
}
private static void _Open(string sFileName)
{
if(_Status()!="")
_Close();
string sCommand = "open \"" + sFileName + "\" alias "+sAlias;
mciSendString(sCommand, null, 0, IntPtr.Zero);
}
private static void _Close()
{
string sCommand = "close "+sAlias;
mciSendString(sCommand, null, 0, IntPtr.Zero);
}
private static void _Play()
{
string sCommand = "play "+sAlias;
mciSendString(sCommand, null, 0, IntPtr.Zero);
}
private static string _Status()
{
StringBuilder sBuffer = new StringBuilder(128);
mciSendString("status "+sAlias+" mode", sBuffer, sBuffer.Capacity, IntPtr.Zero);
return sBuffer.ToString();
}
}
}
EDIT: This is how you play and stop a music file:
public static void playSound(string sFile)
{
//WavPlay.WavPlayer.Play(sFile);
MCIPlayer.Play(sFile);
}
public static void stopSound()
{
//WavPlay.WavPlayer.StopPlay();
MCIPlayer.Stop();
}
I used to use the definition...
[DllImport("winmm.dll", EntryPoint = "mciSendStringA")]
public static extern void mciSendStringA(string lpstrCommand, string lpstrReturnString, long uReturnLength, long hwndCallback);
...in .Net 3.5 but in .Net 4.0 is gave me and unbalanced pinvoke exception! I fixed it by using this instead...
[DllImport("winmm.dll", EntryPoint = "mciSendStringA")]
public static extern void mciSendStringA(string lpstrCommand, string lpstrReturnString, int uReturnLength, IntPtr hwndCallback);
...and passing in IntPtr.Zero as the last param.
The only difference is the uReturnLength is an int (and not a long) and hwndCallback is a IntPtr (and not a long).
Hope this helps...