嚴格意義上說,您不得不使用命令提示符以重定向輸出啓動程序。否則,你需要自己解析命令行,GUI外殼可能不會那樣做。
如果您只是想要在輸出Start Debugging
時重定向輸出,請取消選中Enable the Visual Studio hosting process
複選框即可。
如果你沒有,和"output.txt"
你見過沒有,其實是不應用程序生成的,但"YourApplication.vshost.exe"
你開始調試之前,由Visual Studio IDE被催生。內容總是空的,不能寫;因爲它被Hosting Process鎖定。
不過,如果你希望應用程序表現爲無論什麼模式,你啓動它一樣,事情更復雜。
當你開始調試應用程序,它的開始:
「YourApplication.exe」 ARG1 ARG2
因爲輸出已由IDE重定向。
當你Start Without Debugging
,它的開始:
「%COMSPEC%」/ C 「」 YourApplication.exe 「ARG1 ARG2 ^> output.txt的&暫停」
這是正確的方式讓你的應用程序獲取你指定的所有參數。
你可能想看看我以前的回答How can I detect if "Press any key to continue . . ." will be displayed?。
在這裏,我在下面的代碼中使用的方法類似atavistic throwback:
應用程序的代碼
using System.Diagnostics;
using System.Linq;
using System;
class Test {
public static void Main(string[] args) {
foreach(var arg in args)
Console.WriteLine(arg);
}
static Test() {
var current=Process.GetCurrentProcess();
var parent=current.GetParentProcess();
var grand=parent.GetParentProcess();
if(null==grand
||grand.MainModule.FileName!=current.MainModule.FileName)
using(var child=Process.Start(
new ProcessStartInfo {
FileName=Environment.GetEnvironmentVariable("comspec"),
Arguments="/c\x20"+Environment.CommandLine,
RedirectStandardOutput=true,
UseShellExecute=false
})) {
Console.Write(child.StandardOutput.ReadToEnd());
child.WaitForExit();
Environment.Exit(child.ExitCode);
}
#if false // change to true if child process debugging is needed
else {
if(!Debugger.IsAttached)
Debugger.Launch();
Main(Environment.GetCommandLineArgs().Skip(1).ToArray());
current.Kill(); // or Environment.Exit(0);
}
#endif
}
}
我們還需要下面的代碼,以便它可以工作:
的擴展方法的代碼
using System.Management; // add reference is required
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System;
public static partial class NativeMethods {
[DllImport("kernel32.dll")]
public static extern bool TerminateThread(
IntPtr hThread, uint dwExitCode);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenThread(
uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
}
public static partial class ProcessThreadExtensions /* public methods */ {
public static void Abort(this ProcessThread t) {
NativeMethods.TerminateThread(
NativeMethods.OpenThread(1, false, (uint)t.Id), 1);
}
public static IEnumerable<Process> GetChildProcesses(this Process p) {
return p.GetProcesses(1);
}
public static Process GetParentProcess(this Process p) {
return p.GetProcesses(-1).SingleOrDefault();
}
}
partial class ProcessThreadExtensions /* non-public methods */ {
static IEnumerable<Process> GetProcesses(
this Process p, int direction) {
return
from format in new[] {
"select {0} from Win32_Process where {1}" }
let selectName=direction<0?"ParentProcessId":"ProcessId"
let filterName=direction<0?"ProcessId":"ParentProcessId"
let filter=String.Format("{0} = {1}", p.Id, filterName)
let query=String.Format(format, selectName, filter)
let searcher=new ManagementObjectSearcher("root\\CIMV2", query)
from ManagementObject x in searcher.Get()
let process=
ProcessThreadExtensions.GetProcessById(x[selectName])
where null!=process
select process;
}
// not a good practice to use generics like this;
// but for the convenience ..
static Process GetProcessById<T>(T processId) {
try {
var id=(int)Convert.ChangeType(processId, typeof(int));
return Process.GetProcessById(id);
}
catch(ArgumentException) {
return default(Process);
}
}
}
由於家長會的Visual Studio IDE(目前名爲"devenv"
),當我們正在調試。事實上,父母和祖父母的過程是多種多樣的,我們需要一個規則來執行一些檢查。
棘手的部分是孫子是真正遇到Main
。代碼檢查每次運行時的祖父進程。如果祖父母是null
那麼它會產生,但產生的過程將是%comspec%
,這也是新過程的父母,它將以相同的可執行文件開始。因此,如果祖父母和自己一樣,那麼它就不會繼續產卵,只會碰到Main
。
Static Constructor用於代碼中,該代碼在Main
之前啓動。有關於SO的回答問題:How does a static constructor work?。
當我們開始調試時,我們正在調試祖父進程(產生)。對於使用孫子進程進行調試,我使用條件編譯Debugger.Launch
來調用Main
,以保持清除Main
。
有關調試器的回答問題也將有所幫助:Attach debugger in C# to another process。
這不能爲C#項目完成,但是(正如您可能知道的那樣)完成此操作對於C++項目來說可行。我不知道VS爲什麼不一致。我想這只是微軟普遍缺乏團隊之間的波蘭和協調。 – bames53 2014-08-26 19:00:12