diff --git a/LICENSE b/LICENSE index d49c018..2b3c3e5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2020, 終了 +Copyright (c) 2020 TAKEMURA Kiriko All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index f144ba1..396b19b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,36 @@ -# soundrestore - Restore Logon, Logoff, and Unlock Sound Events on Windows 10 +# System Sound Player +**A small C# program that will restore the logon, logoff, and unlock sound events on Windows 10.** + +In Windows 10, Microsoft removed the ability for the operating system to play a sound when logging on, logging off, or unlocking the computer. This program will help you get these sound events back, because like everything the Windows team do, the removal of these events was only half-assed. + +What was removed in Windows 10 was the ability for the operating system to actually play back a configured sound file. This was supposedly because they had optimized startup and shutdown so much that they couldn't get the sounds to play reliably anymore. However, the ability to set a sound file via the control panel still exists and has just been hidden. + +## How to Use +1. Put `soundrestore.exe` in a central location, like your Windows directory +1. Put a shortcut to `soundrestore.exe` in your Startup folder +1. Launch the shortcut manually once (or reboot) +1. Use the `RestoreSoundEvents.reg` to unhide the program events for "Windows Logon", "Windows Logoff" and "Windows Unlock" (you need to do this once for every user if you have multiple user accounts) +1. Configure the sounds that you want to play using the Control Panel + +The All Users Startup folder is located at `C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup`, and the current user's Startup folder is located at `C:\Users\[User Name]\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup`. + +You can use the `HideSoundEvents.reg` file if you want to hide the abovementioned program events again. + +# Why? +## Windows 10 Has No Soul +![](https://i.ibb.co/Cbw576Y/W10-Laptop-Start-Mini-Start-16x9-en-US-042315.png) + +After you install Windows 10, you're greeted by a dark and cold environment along with a start menu that is basically a giant advertisement board. It feels very much like a dark and lonely subway station. It isn't welcoming at all and makes you want to leave as quickly as possible. + +My solution for this was to run some custom-made scripts that remove essentially all safely removable modern apps. I also use Windows 10 Enterprise so that I can apply a few hundred Group Policies that make the operating system largely stop spying on me. They also make it a whole lot less annoying to use. + +But it still feels dark and cold. + +## Windows Used to be Fun +![](https://i.ibb.co/D19Gr94/Annotation-2020-10-16-150202.jpg) + +Remember Windows 98? Yes, it wasn't exactly what people would consider a technological marvel. It would crash daily due to bad drivers and badly written software, and when it crashed, it showed no mercy and usually took down everything with it. + +Putting the daily crashes aside for a moment, Windows 98 did at least feel a little bit like it had a *soul*. Call me nostalgic, but I think it tried hard to be friendly and welcoming operating system that you could take seriously. It tried to help you get things done as good as it could. + +I tried to extract some Plus! 98 themes and apply them to Windows 10. If you put the effort in, you can actually still customize everything from the wallpaper and colors right down to the desktop icons, mouse pointers and sounds. That's part of what made the themes fun back in the day. But since Microsoft's Shell Team decided that Windows 10 isn't supposed to be fun, I had to resort to writing this small program to get some of the fun back. diff --git a/src/soundrestore.sln b/src/soundrestore.sln new file mode 100644 index 0000000..7e23c7d --- /dev/null +++ b/src/soundrestore.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "soundrestore", "soundrestore\soundrestore.csproj", "{C83D7D14-48EE-47B9-A07E-E9CD4F0FFA96}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C83D7D14-48EE-47B9-A07E-E9CD4F0FFA96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C83D7D14-48EE-47B9-A07E-E9CD4F0FFA96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C83D7D14-48EE-47B9-A07E-E9CD4F0FFA96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C83D7D14-48EE-47B9-A07E-E9CD4F0FFA96}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/soundrestore/AssemblyInfo.cs b/src/soundrestore/AssemblyInfo.cs new file mode 100644 index 0000000..845499d --- /dev/null +++ b/src/soundrestore/AssemblyInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("System Sound Player")] +[assembly: AssemblyDescription("System Sound Player")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("TAKEMURA Kiriko")] +[assembly: AssemblyProduct("System Sound Player")] +[assembly: AssemblyCopyright("Copyright © TAKEMURA Kiriko 2020")] +[assembly: ComVisible(false)] +[assembly: Guid("b3839d3a-3aec-4b0f-bad1-587d521bbf8e")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/soundrestore/DummyForm.Designer.cs b/src/soundrestore/DummyForm.Designer.cs new file mode 100644 index 0000000..b111264 --- /dev/null +++ b/src/soundrestore/DummyForm.Designer.cs @@ -0,0 +1,52 @@ +namespace soundrestore +{ + partial class DummyForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // DummyForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(0, 0); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Name = "DummyForm"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.WindowState = System.Windows.Forms.FormWindowState.Minimized; + this.Shown += new System.EventHandler(this.DummyForm_Shown); + this.ResumeLayout(false); + + } + + #endregion + } +} + diff --git a/src/soundrestore/DummyForm.cs b/src/soundrestore/DummyForm.cs new file mode 100644 index 0000000..18d6204 --- /dev/null +++ b/src/soundrestore/DummyForm.cs @@ -0,0 +1,142 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Media; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Microsoft.Win32; + +namespace soundrestore +{ + /* Microsoft: + * + * As part of speeding up logon, logoff, shutdown, we experiment a lot + * with what process is in control of the startup and shutdown sounds. + * In an interim build of Windows 8 we were able to speed things up + * considerably by moving the shutdown sound from Explorer.exe (which + * is running while you’re still logged on) to logonui.exe (which + * is the thing that shows the “Shutting down” circle.) + * + * However moving the shutdown sound this late started running into + * other problems. The code we use to play the sound (PlaySound) needs + * to read from the registry (to see what the preferences for this + * sound were) and from the disk (to read the .wav file), and we ran + * into issues where the sound was unable to play (or got cutoff + * halfway) because we had shut down the registry or the disk already! + * + * We could have spent time rewriting the API but we decided the safest + * and most performant thing to do was to eliminate the sound altogether. + * + * + * TLDR: We could have kept the sounds, but weren't competent enough to + * do it, so we decided to just kill the feature. + */ + + public partial class DummyForm : Form + { + [DllImport("user32.dll")] + private extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason); + + [DllImport("user32.dll")] + private extern static bool ShutdownBlockReasonDestroy(IntPtr hWnd); + + private enum Sound + { + None = 0, + Logon = 1, + Logoff = 2, + Unlock = 3 + } + + protected override bool ShowWithoutActivation + { + get { return true; } + } + + protected override CreateParams CreateParams + { + get + { + CreateParams baseParams = base.CreateParams; + + const int WS_EX_NOACTIVATE = 0x08000000; + baseParams.ExStyle |= (int)(WS_EX_NOACTIVATE); + + return baseParams; + } + } + + public DummyForm() + { + InitializeComponent(); + + SystemEvents.SessionEnded += new SessionEndedEventHandler(SystemEvents_SessionEnded); + SystemEvents.SessionSwitch += new SessionSwitchEventHandler(SystemEvents_SessionSwitch); + } + + private void DummyForm_Shown(object sender, EventArgs e) + { + Hide(); + Play(Sound.Logon); + } + + private void SystemEvents_SessionEnded(object sender, SessionEndedEventArgs e) + { + ShutdownBlockReasonCreate(this.Handle, "Playing shutdown sound"); + Play(Sound.Logoff); + ShutdownBlockReasonDestroy(this.Handle); + } + + private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) + { + if (e.Reason == SessionSwitchReason.SessionUnlock) + Play(Sound.Unlock); + } + + private void Play(Sound what) + { + const string SUBKEY_TPL = "AppEvents\\Schemes\\Apps\\.Default\\{0}\\.Current"; + string subkey = null, file = null; ; + + switch (what) + { + case Sound.Logon: + subkey = "WindowsLogon"; + break; + case Sound.Logoff: + subkey = "WindowsLogoff"; + break; + case Sound.Unlock: + subkey = "WindowsUnlock"; + break; + } + + if (string.IsNullOrEmpty(subkey)) + return; + + subkey = string.Format(CultureInfo.InvariantCulture, SUBKEY_TPL, subkey); + + using (RegistryKey key = Registry.CurrentUser.OpenSubKey(subkey)) + if (key != null) + file = (string)key.GetValue("", null); + + if (string.IsNullOrEmpty(file)) + return; + + if (!File.Exists(file)) + return; + + try + { + using (SoundPlayer sp = new SoundPlayer(file)) + sp.PlaySync(); + } + catch (Exception e) + { + EventLog.WriteEntry("Application", string.Format(CultureInfo.InvariantCulture, + "Cannot play system sound: {0}", e), EventLogEntryType.Error); + } + } + } +} \ No newline at end of file diff --git a/src/soundrestore/DummyForm.resx b/src/soundrestore/DummyForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/src/soundrestore/DummyForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/soundrestore/Program.cs b/src/soundrestore/Program.cs new file mode 100644 index 0000000..b19b11f --- /dev/null +++ b/src/soundrestore/Program.cs @@ -0,0 +1,23 @@ +using System; +using System.Windows.Forms; +using System.Threading; + +namespace soundrestore +{ + static class Program + { + [STAThread] + static void Main() + { + Mutex mutex = new Mutex(true, "sndrst_d3f9ae65"); + + if (!mutex.WaitOne(TimeSpan.Zero, true)) + return; + + Application.Run(new DummyForm()); + + mutex.ReleaseMutex(); + mutex.Dispose(); + } + } +} diff --git a/src/soundrestore/sound.ico b/src/soundrestore/sound.ico new file mode 100644 index 0000000..79432a6 Binary files /dev/null and b/src/soundrestore/sound.ico differ diff --git a/src/soundrestore/soundrestore.csproj b/src/soundrestore/soundrestore.csproj new file mode 100644 index 0000000..856872d --- /dev/null +++ b/src/soundrestore/soundrestore.csproj @@ -0,0 +1,105 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {C83D7D14-48EE-47B9-A07E-E9CD4F0FFA96} + WinExe + Properties + soundrestore + soundrestore + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + sound.ico + + + true + + + true + bin\Debug\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\soundrestore.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + false + false + + + bin\Release\ + TRACE + true + pdbonly + AnyCPU + bin\Release\soundrestore.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + false + false + false + + + + + + + + + Form + + + DummyForm.cs + + + + + + + DummyForm.cs + + + + + + + + + + + \ No newline at end of file