Search code examples
c#command-line-argumentsscreensaver

Process.Start(ProcessStartInfo) doesn't send command line to screensavers (.scr files)


I am currently writing an app to start the screensaver on Windows 10 and show the screen instead of a black background. So that Bubbles and relatives can act like in older OS version.

Here is my full code:

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;

public class DrawOverMyScreen {
  public static void Main(string[] CommandLine) {
    switch (CommandLine[0]) {
      case "/c":
        DialogResult Answer = MessageBox.Show("What do you want to do?\n\n - Press \"Yes\" to configure the screensaver\n - Press \"No\" to change the screensaver\n - Press \"Cancel\" to do nothing", "DrawOverMyScreen Configuration", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3);
        switch (Answer) {
          case DialogResult.Yes:
            Screensaver("/c");
            break;

          case DialogResult.No:
            throw new NotImplementedException();
            break;

          default:
            break;
        }
        break;

      default:
        Screensaver("/s");
        break;
    }
  }

  public static void Screensaver(string CommandLine) {
    RegistryKey Settings = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\DrawOverMyScreen");
    if (Settings != null) {
      string ScreensaverLocation = Settings.GetValue("Screensaver", string.Empty).ToString();
      if (!string.IsNullOrEmpty(ScreensaverLocation) && File.Exists(ScreensaverLocation)) {
        Process Screensaver = Process.Start(new ProcessStartInfo(ScreensaverLocation, CommandLine));
        Screensaver.WaitForExit();
      }
    }
  }
}

Notice the Screensaver method. It uses Process.Start(new ProcessStartInfo(ScreensaverLocation, CommandLine)); to start the screensaver. But whenever I do Screensaver("/c"); to run the screensaver's config utility, I only get the normal screensaver view (The one you get when idle after a certain time). Using the run prompt like this: C:\Windows\SysWOW64\SCREEN~1.SCR /c also gives the same result, but command line prompt actually opens the config utility.

Why won't it work, and how can I make it so it works?


Solution

  • Just from what you have provided, I can't tell you why it won't work. I do not have a screensaver to test that with (that I know of). But I'm able to do all four of these with Notepad opening a text file:

    Separate ProcessStartInfo

         ProcessStartInfo procInfo = new ProcessStartInfo("notepad.exe", "c:\\test.txt");
         Process proc = Process.Start(procInfo);
         proc.WaitForExit();
    

    Separate ProcessStartInfo with Properties

         ProcessStartInfo procInfo = new ProcessStartInfo();
         procInfo.Arguments = "c:\\test.txt";
         procInfo.FileName = "notepad.exe";
         Process proc = Process.Start(procInfo);
         proc.WaitForExit();
    

    Inline ProcessStartInfo

         Process proc = Process.Start(new ProcessStartInfo("notepad.exe", "c:\\test.txt"));
         proc.WaitForExit();
    

    No PSI, Just Process

         Process proc = Process.Start("notepad.exe", "c:\\test.txt");
         proc.WaitForExit();
    

    You may want to go with the first one so that you can breakpoint on the "Process proc..." line and examine the properties of procInfo. The Arguments property should show the 2nd value (in my case, c:\\test.txt), and the FileName property should be the path to what you are executing (mine is notepad.exe).

    EDIT: I added the separate one with properties so you can really see explicit setting.

    CONFIGURE A SCREENSAVER

    I have worked out an example using the 3D Text screensaver:

         string scrPath = @"C:\Windows\System32\ssText3d.scr";
         ProcessStartInfo procInfo = new ProcessStartInfo();
         procInfo.FileName = scrPath;
         procInfo.Verb = "config";
         procInfo.UseShellExecute = false;
         Process proc = Process.Start(procInfo);
         proc.WaitForExit();
    

    I didn't use the Arguments. Instead, I used the Verb. This requires UseShellExecute to be set to false. I got the expected configuration dialog instead of the screensaver running.

    More About Verbs

    This is where the verbs are for screen savers. enter image description here

    You can also define custom verbs: Register an Application to Handle Arbitrary File Types