3

I've been trying to solve the problem that Chris Iverson was having in this other Stackoverflow question.

I want to launch SFC (the System File Checker tool) programatically.

It works on Windows XP:

private void RunSfc()
{
    ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/K sfc.exe /scannow");
    System.Diagnostics.Process.Start(startInfo);
}

enter image description here

Other variants that do work under Windows XP:

//Launch SFC directly
ProcessStartInfo startInfo = new ProcessStartInfo("sfc.exe", "/scannow"); 
System.Diagnostics.Process.Start(startInfo);

//Use full path to SFC
String sfcPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "sfc.exe");
ProcessStartInfo startInfo = new ProcessStartInfo(sfcPath, "/scannow"); 

The same code fails on Windows 7 (with the launching program running as an administrator). The console window appears, but SFC gives the error:

Windows Resource Protection could not start the repair service.

enter image description here

But if i manually run sfc /scannow from a separate elevated command prompt, it works:

enter image description here

So there is obviously something strange happening with Windows Vista/7/8. i don't know what, exactly. But it's likely related to UAC, UIPI, session 0 isoloation, or the fact that console windows were run by CSRSS

But still, i don't understand the issue.

It would have been nice to solve Chris's issue, in the off chance that i want to do what he did.

And remember: My code already is running as an administrator. I right-click and Launch as administrator:

enter image description here

That doesn't mean the issue is not some other subtle issue related to UAC, but it's not due to the fact that i'm running as a standard user.

Code in WinForms application

private void button1_Click(object sender, EventArgs e)
{
    RunSfc(); 
}

32-bit fails

Turns out there is a 32-bit version of cmd.exe and a 32-bit version of sfc.exe:

  • C:\Windows\SysWOW64\cmd.exe
  • C:\Windows\SysWOW64\sfc.exe

If you run an elevated 32-bit cmd, neither the 32-bit nor 64-bit version of sfc will work.

So the conundrum becomes how to launch the 64-bit cmd.exe from a 32-bit process. Which probably means the conundrum becomes how to find the the 64-bit version of cmd.exe from a 32-bit process, given:

  • you may not be on a 64-bit machine
  • you might already be running a 64-bit process
  • Windows likes to fake the names of the System32 folder based on the bit-ness of your process
Community
  • 1
  • 1
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • Can you turn UAC completely off, just as a test scenario to determine if it is involved in the problem? – vcsjones Jan 01 '14 at 18:01
  • Awwww, i don't wanna have to rebooooooot. *Le sigh*. Fine. – Ian Boyd Jan 01 '14 at 18:20
  • 1
    @vcsjones No effect. The console window still says **Windows Resource Protection could not start the repair service**. – Ian Boyd Jan 01 '14 at 18:22
  • Actually, this is kinda funny. All of your code samples work just fine for me on Windows 8.1. I *verbatim* copied your code into a Command Line project, right clicked on the resulting executable, and ran as admin. Scan kicked off just fine. – vcsjones Jan 01 '14 at 18:31
  • @vcsjones Try a WinForms project (i.e. with a UI) – Ian Boyd Jan 01 '14 at 18:32
  • Is there maybe a service which is disabled or takes to long to start up in that scenario? Just guessing... – PMF Jan 01 '14 at 18:32
  • @IanBoyd. Yes. Now I can reproduce your issue. This is kinda really weird. – vcsjones Jan 01 '14 at 18:35
  • I think you can find the 32-bit cmd by looking for `C:\WINDOWS\SysNative\cmd.exe`. If that directory exists, you are on a 64-bit machine running as a 32-bit process. If that directory doesn't exist, you are either on a 32-bit machine, or a 64-bit machine running as a 64-bit process. So, launcher `SysNative\cmd.exe` if it exists, otherwise launch `System32\cmd.exe`. – vcsjones Jan 10 '14 at 14:40

2 Answers2

3

My experiments suggest that the issue is related to the WOW64 emulator. I have this code in a non-elevated WinForms app:

...
using System.Diagnostics;
...

ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/K sfc.exe /scannow");
  startInfo.UseShellExecute = true;
  startInfo.Verb = "runas";
Process.Start(startInfo);

From a 32 bit WOW64 process this fails with this message in the console window:

Windows Resource Protection could not start the repair service.

From a 64 bit process, the above code succeeds.

Indeed, I don't think .net or WinForms are relevant here at all. If I run 32 bit cmd.exe from the SysWOW64 folder, and then call sfc, I experience failure. But I am successful with the 64 bit cmd.exe.

And there's not even any need to bring cmd.exe into this at all. From a 64 bit process, running without elevation, the following succeeds:

...
using System.Diagnostics;
...

ProcessStartInfo startInfo = new ProcessStartInfo("sfc.exe", "/scannow");
startInfo.UseShellExecute = true;
startInfo.Verb = "runas";
Process.Start(startInfo);

So I guess the solution to your problem will involve either switching your main program to 64 bit (probably a little drastic), or splicing a 64 bit process into the chain so that the 64 bit sfc can be run.

umlcat
  • 4,091
  • 3
  • 19
  • 29
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • @Ian I answered the question you originally asked. I also answered the second question that you asked in your question edit. Fire up a 64 bit executable dedicated to running sfc. But only do that if you are on 64 but OS. You cannot use cmd.exe as your launcher because it is confounded by file system redirector. But your 64 bit exe that is outside system dir is fine. – David Heffernan Jan 06 '14 at 05:33
  • i don't get to dictate the bit-ness of the jitted executable; nor would i want to; nor would i want to ship a separate thunking executable. i'd like the 32 or 64 bit code to know how to launch the 32 or 64 bit version of cmd, in order to launch the 32 or 64 bit sfc image. – Ian Boyd Jan 22 '14 at 16:26
  • So start the 64 bit cmd then. From a 32 bit process you can find it in C:/windows/sysnative. – David Heffernan Jan 22 '14 at 16:29
  • Anyway, I think that is your problem. I believe I answered the question that you asked. – David Heffernan Jan 22 '14 at 16:36
  • Or forget about cmd and go straight to the 64 bit sfc. It's a shame you are getting confused between the solution to your problem, and the answer to the question that you asked. – David Heffernan Jan 22 '14 at 16:46
  • Why don't you ask a question? Or, to put it another way, what other questions are you going to ask after this one? – David Heffernan Jan 24 '14 at 15:33
  • The code i put in the original question does not work on a 64-bit platform, if the executable was jitted to 32-bit. The code in the answer does not work if the application was jitted to 32-bit. Shipping a 64-bit thunker application is not going to happen (a. i don't know if the user is running 64-bit OS, b. i only ship single executable applications, c) someone calling the helper function will fail when they didn't ship a thunker app). The question is: "How to launch SFC programatically on Windows Vista/7/8?" – Ian Boyd Jan 24 '14 at 15:40
  • You changed the question. I answered the original one. You have got confused between the solution to your problem, and the answer to the question that you asked. – David Heffernan Jan 24 '14 at 15:43
  • Looking at my edit history; i added a summary of your excellent insights about the 32-64 bit barrier; and a second edit with a word and grammer. i don't think it changed the meaning of the question. – Ian Boyd Jan 24 '14 at 15:45
  • The edit history is quite clear. At the time I wrote this answer, no mention was ever made of a requirement that no 64 bit stub could be used. I spent my time working on this, and you now expect me to answer a different question too. You've asked two completely different questions. Even worse, the second question was added as an edit to the first question. – David Heffernan Jan 24 '14 at 15:51
  • i would thought it would go without saying that a 64-bit stub could not be used. i also didn't specify that any solution couldn't involve automatically downloading BartsPE, altering the boot sector of the drive, triggering a restart, where it will use a version of SFC and...forget it. have an accept. i'll solve it later. – Ian Boyd Jan 24 '14 at 16:16
  • I believe that a 64 bit stub is the solution anyway. That's where I think you will end up. Attempting to use sysnative will fail. And disabling file system redirection is a risky business. There are simply some problems that cannot be solved inside the emulator. – David Heffernan Jan 24 '14 at 16:17
1

With all the help here I ended up with this and it worked fine on 8.1 x64. Thank you all very much!

    ...
    using System.Diagnostics;
    ...

    private void button4_Click(object sender, EventArgs e)
    {
        string docs = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        string snat = Environment.GetEnvironmentVariable("windir") + @"\sysnative\sfc.exe";

        Process a = new Process();
          a.StartInfo.FileName = snat;
          a.StartInfo.Arguments = "/SCANNOW";
          a.StartInfo.UseShellExecute = false;
          a.StartInfo.RedirectStandardOutput = true;
          a.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
          a.StartInfo.CreateNoWindow = true;
        a.Start();

        string output = a.StandardOutput.ReadToEnd();
        a.WaitForExit();

        using (StreamWriter outfile = new StreamWriter(docs + @"\Testoutput.txt"))
        {
            outfile.Write(output);
        }

        MessageBox.Show("DONE!");
    }
umlcat
  • 4,091
  • 3
  • 19
  • 29
AGnoob
  • 11
  • 1