启动远程桌面客户端。无法控制PID杀死。启动后PID更改... WTF?

时间:2010-06-23 12:05:24

标签: c# process c#-4.0 remote-desktop

我正在编写一个程序(C#Windows窗体中的Visual Studio 2010),它跟踪远程桌面客户端的多个实例(mstsc.exe - 使用Windows 7版本测试)。我一直试图启动这个程序并使用以下代码获取其PID:

Process mstsc = Process.Start(mstscLocation, mstscConString);
int mstscProcessId = mstsc.Id;
DataRow row = openConn.NewRow();
row["RDP ID"] = mstscID;
openConn.Rows.Add(row);

这会启动客户端并返回一个ID。问题是,如果我尝试使用以下代码终止PID,则无法执行此操作:

int rdpID = Convert.ToInt32(dgvOpenConnections.Rows[selectedIndex].Cells["RDP ID"].Value.ToString());

try
{
    // kill off mstsc
    Process mstsc = Process.GetProcessById(rdpID);
    mstsc.Kill();
}

我已经验证从Process.Start记录的PID与从DataGridView(dgvOpenConnections)检索到的PID相同并放入rpdID(尝试失败并因原始PID不再存在而命中catch)。此外,我在启动MSTSC.EXE的一个实例后在命令提示符下发出了“任务列表”,并且可以验证它是否更改了PID(在此测试中,C#记录了4288但是任务列表显示它运行为8172)。

我无法杀死所有MSTSC进程,因为我试图控制多个进程。有没有办法追查第二个PID MSTSC似乎使用?我的猜测是要么启动第二个进程并取消第一个进程,要么这可能是一个子进程(尽管启动后返回的PID不再存在)。

如何在C#中确保我拥有正确的进程ID以便以后监视或终止远程桌面客户端的特定实例?

2 个答案:

答案 0 :(得分:4)

如果您尝试在64位Windows中从32位应用程序运行mstsc,则会发生这种情况。

(资料来源:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/22c10140-a502-4aa1-98d3-3607b8b573e8/

在64位Windows上有两个版本的mstsc

  1. c:\windows\system32\mstsc.exe 64位版本
  2. c:\windows\syswow64\mstsc.exe或多或少是一个“重定向”,它将从与您的应用程序不同的进程中打开c:\windows\system32\mstsc.exe
  3. 我遇到了同样的问题。我的应用程序启动了mstsc,该进程立即退出,并且mstsc重新出现,具有不同的父进程和不同的PID。

    这是因为64位Windows使用文件系统重定向将对64位c:\windows\system32可执行文件的调用重定向到c:\windows\syswow64

    有两种解决方案:

    1. 将您的应用程序重新编译为64位。然后您的应用程序也将使用64位mstsc。
    2. 禁用文件系统重定向(请参阅http://blog.tonycamilli.com/2005/07/disabling-wow64-file-system.html)并从32位应用程序访问64位mstsc。
    3. 我只尝试过重新编译,但它确实有效。 : - )

      修改 如果您不希望您的用户使用正确的版本(我们正在使用ClickOnce部署,所以我们宁愿向所有人发送一个链接),这是一个解决方法:

      如果您正在为.sts文件使用.RDP文件,只需在文件名中添加一个唯一标记即可。 mstsc将使用mstsc host_user_token.rdp之类的命令行启动。

      现在,在您致电Process.Start后,请执行Process.WaitForExit超时(5秒)。如果进程没有退出,则表示您拥有正确的对象。

      如果进程 退出,请执行一个小轮询循环(100毫秒间隔,5秒超时),用您的令牌检查进程:

      var timeout = AppSettings.GetIntValue(
                  Constants.SettingsKeyProcessFinderTimeout, Constants.ProcessFinderTimeoutDefault);
      int elapsedTime = 0;
      Process process = null;
      while (elapsedTime <= timeout)
      {
          process =
              Process.GetProcessesByName("mstsc").FirstOrDefault(p => p.StartInfo.Arguments.Contains(guid));
          Logger.TraceVerbose(
              string.Format(
                  "Elapsed time: {0}; Found process with PID {1}", elapsedTime, process == null ? -1 : process.Id));
          if (process != null)
          {
              break;
          }
      
          Thread.Sleep(SleepInterval);
          elapsedTime += SleepInterval;
      }
      

      在该循环之后,如果您仍然有process == null,则会出现一些错误(未找到进程或从未执行过程)。如果你有一个Process引用,那就是“new”mstsc进程。

答案 1 :(得分:0)

我使用Process Explorer尝试了您的示例,但我看不到正在创建的第二个或子进程。从头到尾远程桌面进程是同一个,并且在创建之后我能够使用我在开始时看到的相同PID来终止进程。