问题
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);
}

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.

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

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:

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
回答1:
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.
回答2:
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!");
}
来源:https://stackoverflow.com/questions/20871514/how-to-launch-sfc-programatically-on-windows-vista-7-8