web-dev-qa-db-fra.com

Lorsqu’un programme est exécuté en C #, tous les messages sont envoyés à la sortie standard, mais l’erreur standard ne contient rien.

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 =>

13
shingo

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
3
Dipen Shah

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 .

2

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.

2
Strom

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();
0
Gauravsa