Ma question est différente avec celui identifié . J'ai évidemment appelé la méthode "BeginErrorReadLine" (je la marque dans le code ci-dessous).
Je veux analyser le résultat produit par Handle
Ligne de commande
Lorsqu'il est exécuté dans un environnement de ligne de commande, le résultat obtenu est le suivant:
> handle64 -p [PID]
Nthandle v4.11 - Visionneuse de poignées
Droits d'auteur (C) 1997-2017 Mark Russinovich
Sysinternals - www.sysinternals.com
10: fichier C:\Windows
1C: fichier C:\Windows\SysWOW64
[PID] est un identifiant de processus en cours d'exécution
La sortie est séparée.
Les 5 premières lignes (y compris les lignes vides) vont à l'erreur standard, les 2 dernières lignes vont à la sortie standard.
Je peux donc enlever l'en-tête en redirigeant:
> handle64 -p [PID] 2> nul
10: fichier C:\Windows
1C: fichier C:\Windows\SysWOW64
Application Winform
J'essaie ensuite d'implémenter cette commande dans une application winform C #:
Stream streamOut, streamErr;
var p = Process.Start(new ProcessStartInfo
{
FileName = "handle64.exe",
Arguments = "-p [PID]",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
});
p.OutputDataReceived += (sender, e) =>
{
streamOut.Write("Output => " + e.Data);
};
p.ErrorDataReceived += (sender, e) =>
{
streamErr.Write("Error => " + e.Data);
};
p.BeginOutputReadLine();
p.BeginErrorReadLine(); // !!!
p.WaitForExit();
Ensuite, je trouve que tout va à la sortie standard.
Question
Ok, je peux séparer l'en-tête et le corps par code.
La question est de savoir pourquoi la sortie de le programme } _ se comporte différemment entre les 2 environnements.
Est-ce que je peux faire en sorte que le résultat dans l'application Winform se comporte de la même manière en ligne de commande?
Mettre à jour
Pour le commentaire de Damien, j'essaye de lancer le programme } via 'cmd', malheureusement le résultat est le même
var p = Process.Start(new ProcessStartInfo
{
FileName = "cmd",
Arguments = "/C handle64.exe -p [PID]",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
});
...
Dans la fenêtre de sortie:
Sortie =>
Sortie => Nthandle v4.11 - Visualiseur de poignées
Sortie => Copyright (C) 1997-2017 Mark Russinovich
Sortie => Sysinternals - www.sysinternals.com
Sortie =>
Sortie => 10: fichier C:\Windows
Sortie => 1C: fichier C:\Windows\SysWOW64
Erreur =>
Ce n’est pas la réponse à votre question, mais une suggestion pour réaliser ce que vous tentez de faire (c’est-à-dire obtenir uniquement les informations de descripteur dans une application Winform):
handle tool a -nobanner
switch, vous pouvez l'utiliser pour ignorer les informations du message de copyright.
handle64.exe -pid 11624 -nobanner
Ceci est juste un exemple pour illustrer le problème auquel j'ai fait allusion dans mes commentaires. Ce n'est pas une solution, car je ne crois pas qu'il existe un moyen trivial de résoudre ce problème. J'ai créé Main
dans mon programme de travail (appelé PlayAreaCSCon
). S'il est appelé sans paramètre, il agit d'une manière similaire à ce que je soupçonne que Handle64.exe
est en train de faire. Lorsqu'il est appelé avec un paramètre, il contient un code similaire au vôtre, mais il lance ensuite une copie de lui-même sans paramètre:
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace PlayAreaCSCon
{
class Program
{
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.Out.WriteLine("Hello");
if (GetConsoleWindow() == IntPtr.Zero)
{
Console.Out.WriteLine("No Console window");
}
else
{
Console.Error.WriteLine("We have a console window");
}
}
else
{
Process p = Process.Start(new ProcessStartInfo
{
FileName = "PlayAreaCSCon.exe",
Arguments = "",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
});
TextWriter streamOut = Console.Out;
TextWriter streamErr = Console.Error;
p.OutputDataReceived += (sender, e) =>
{
streamOut.WriteLine("Output => " + e.Data);
};
p.ErrorDataReceived += (sender, e) =>
{
streamErr.WriteLine("Error => " + e.Data);
};
p.BeginOutputReadLine();
p.BeginErrorReadLine(); // !!!
p.WaitForExit();
}
}
}
}
Dans une invite de commande, j'ai la session suivante:
C:\Dev\PlayAreaCSCon\PlayAreaCSCon\bin\Debug>PlayAreaCSCon.exe
Hello
We have a console window
C:\Dev\PlayAreaCSCon\PlayAreaCSCon\bin\Debug>PlayAreaCSCon.exe a
Error =>
Output => Hello
Output => No Console window
Output =>
Ainsi, même ici, si Handle64.exe
appelle GetConsoleWindow
ou toute autre fonction moralement équivalente, il peut détecter qu’il n’est pas connecté à une console et présenter un comportement différent. La seule façon pour vous de laisser une fenêtre de console consisterait à définir CreateNoWindow
sur false, ce que je suppose que vous ne voudriez probablement pas faire.
Étant donné que Handle64
est une source fermée, il est difficile de confirmer qu'il s'agit bien de la vérification spécifique effectuée. Il n'y a pas de solution non triviale à cela de la part du appelant .
Comme l'a déclaré Damien: CreateNoWindow = false ,
Laissez-le créer la fenêtre le cacher immédiatement. Nous pourrions le créer hors écran, mais il serait toujours affiché dans la barre des tâches.
Remarque: ce code ne vaut peut-être pas mieux que de laisser la fenêtre apparaître et disparaître naturellement.
En haut de la classe, ajoutez:
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
Alors votre code devient:
var p = Process.Start(new ProcessStartInfo
{
FileName = "cmd",
Arguments = "/C handle64.exe -p [PID]",
CreateNoWindow = false,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
});
p.WaitForInputIdle();
IntPtr windowHandle = p.MainWindowHandle;
if(windowHandle == 0) throw new Exception("This did not work");
// use win32 API's to hide window (May still flicker)
ShowWindow(windowHandle,0);
// ...
Je suis incapable de tester cela, car je ne travaille que sous Linux pour le moment.
Si l'exception ne se déclenche pas, vous pouvez voir le scintillement d'une fenêtre, mais vous devriez avoir le bon résultat.
L’autre méthode que je connaisse consiste à insérer des gestionnaires dans la pompe de messages Win32 et à répondre au processus spécifique en lui indiquant ce qu’il doit savoir pour penser qu’elle a une fenêtre appropriée alors que ce n’est pas le cas. Je ne publierai aucun code lié à cette technique. Toute erreur entraînerait l’instabilité de Windows.
J'ai apporté quelques modifications à votre code:
Stream streamOut, streamErr;
var p = Process.Start(new ProcessStartInfo
{
FileName = "handle64.exe",
Arguments = "-p [PID]",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true, // even if no writing to std::in, still need this
RedirectStandardError = true,
});
p.OutputDataReceived += (sender, e) =>
{
streamOut.Write("Output => " + e.Data);
};
p.BeginOutputReadLine();
p.ErrorDataReceived += (sender, e) =>
{
streamErr.Write("Error => " + e.Data);
};
p.BeginErrorReadLine();
p.WaitForExit();
p.StandardInput.Close(); // call this before WaitForExit
p.WaitForExit();