Comment obtenir la poignée de la fenêtre d'une application console

Quelqu'un peut-il me dire comment obtenir la poignée D'une application Windows console en C#? Dans une application Windows Forms, j'essaierais normalement this.Handle .

33
demandé sur stakx 2009-08-14 16:23:28

6 réponses

Pas sûr que ça marche, mais vous pouvez essayer :

IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
49
répondu Thomas Levesque 2009-08-14 12:33:36

Voici une manière robuste de le faire:

les fonctions connexes de la Console Win32 API sont:

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)]
static extern bool FreeConsole();
  • pour la console le processus actuel est attaché, juste GetConsoleWindow() est suffisant
  • pour la console un autre processus est attaché à, y attacher aussi avec AttachConsole , appeler GetConsoleWindow , les détacher immédiatement avec FreeConsole .

pour les plus prudents, enregistrez un gestionnaire d'événements de la console avant de l'attacher (et désinscrivez-le après l'avoir désactivé) afin de ne pas vous arrêter accidentellement si un l'événement de la console se produit dans le petit laps de temps que vous êtes attaché à la console:

[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine,
   bool Add);
delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
enum CtrlTypes : uint {
    CTRL_C_EVENT = 0,
    CTRL_BREAK_EVENT,
    CTRL_CLOSE_EVENT,  
    CTRL_LOGOFF_EVENT = 5,
    CTRL_SHUTDOWN_EVENT
}

bool is_attached=false;    
ConsoleCtrlDelegate ConsoleCtrlDelegateDetach = delegate(CtrlType) {
     if (is_attached = !FreeConsole())
         Trace.Error('FreeConsole on ' + CtrlType + ': ' + new Win32Exception());
     return true;
};

apporter des modifications au processus actuel juste pour lire quelque chose est assez laid (quand il s'agit d'un processus de la console, cela devient vraiment laid car il nécessite un processus d'aide pour éviter de terminer la console actuelle). Néanmoins, une enquête plus approfondie montre qu'il n'y a pas d'autre moyen que de s'injecter dans le processus csrss ou le processus cible.

les informations de correspondance de la Console sont localisées et gérées par csrss.exe (ou une multitude de ceux-ci, un pour chaque session, depuis Vista), de sorte qu'elles ne peuvent pas être récupérées avec les goûts de ReadProcessMemory . Tout ce que csrss expose est le CSRSS LPC API . Il n'y a qu'une seule fonction pertinente dans la liste complète des API, SrvGetConsoleWindow . Et il n'accepte pas un PID mais détermine celui de l'appelant comme vu dans une alternative mise en œuvre ou démontage de la fonction dans winsrv.dll .

17
répondu ivan_pozdeev 2017-05-23 12:32:17

essayez ceci:

[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
public static extern IntPtr FindWindowByCaption(IntPtr zeroOnly, string lpWindowName);
…

Console.Title = "Test";
…

IntPtr handle = FindWindowByCaption(IntPtr.Zero, Console.Title);
10
répondu Humble Coder 2012-06-17 21:16:55

je viens de résoudre ce problème pour moi-même (malheureusement avant de voir la réponse de Thomas qui est beaucoup plus rapide). Eh bien, voici une autre façon pour ceux qui ne sont pas satisfaits de sa réponse. J'écris cette réponse parce que je veux fournir une autre réponse + une meilleure façon de concevoir la classe Program si vous traitez votre console comme une fenêtre. Commençons par ce dessin:

j'ai en quelque sorte changé le style par défaut du Program de la classe. En fait, j'ai fait une classe qui a un programme, et pas seulement une méthode qui la représentent et utilise d'autres classes pour le contenu. (Si vous ne savez pas ce que je veux dire, pas d'importance).

la raison pour laquelle j'ai dû le faire est que je voulais écrire le gestionnaire d'événements suivant:

private void CatchUnhandled(Object sender, UnhandledExceptionEventArgs e)
{
    var exception = e.ExceptionObject as Exception;
    MessageBox.Show(this, exception.Message, "Error"); // Check out 1st arg.
}

il surcharge cette méthode MessageBox.Show(IWin32Window, String, String) .

parce que la Console n'implémente pas IWin32Window , j'ai dû le mettre en œuvre moi-même, bien sûr, afin de simplement appeler this dans le 1 st argument.

Voici la mise en œuvre et tout le reste:

Note: ce code est copié-collé de mon application, vous pouvez vous sentir libre de changer les modificateurs d'accès

Program Déclaration De Classe:

internal class Program : IWin32Window
{
    ...
}

IWin32Window mise en œuvre:

public IntPtr Handle
{
    get { return NativeMethods.GetConsoleWindow(); }
}

il utilise la classe suivante:

internal static class NativeMethods
{
    [DllImport("kernel32.dll")]
    internal static extern IntPtr GetConsoleWindow();
}

maintenant, le problème est que vous ne pouvez pas réellement appeler this dans Main , étant une méthode statique, donc ce qui était dans Main j'ai déménagé à une nouvelle méthode appelée Start et tout Main fait est de créer un nouveau Program et appelant Start .

private static void Main()
{
    new Program().Start();
}

private void Start()
{
    AppDomain.CurrentDomain.UnhandledException += CatchUnhandled;

    throw new Exception();
}

le résultat était, bien sûr, une boîte à messages avec la fenêtre de ma console comme propriétaire.

L'utilisation de cette méthode pour une boîte de message, n'est bien sûr qu'une application de cette méthode.

7
répondu MasterMastic 2017-05-23 12:10:21

Je ne pense pas qu'il y ait une telle chose. La fenêtre console n'est pas accessible à l'application. Vous pouvez essayer d'itérer la liste des processus en cherchant votre propre nom de processus. La classe IIRC Process contient une propriété pour la poignée de fenêtre principale du programme, qui pourrait être la fenêtre de console pour les applications de console - dont je ne suis pas sûr.

1
répondu Thorsten Dittmar 2009-08-14 12:29:42

dans une application de console qui a strié diagostics à la console, et pour lequel je voulais désactiver l'entrée de souris, j'ai essayé GetConsoleWindow(), Process.GetCurrentProcess().MainWindowHandle, and FindWindowByCaption(IntPtr.Zero, Console.Title) . Chacun d'eux a retourné la même poignée non-zéro, mais quand j'ai essayé d'utiliser cette poignée dans le code SetConsoleMode il a lancé une exception "poignée invalide". Finalement j'ai essayé SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode | ENABLE_EXTENDED_FLAGS)) avec STD_INPUT_HANDLE défini comme -10, et ça a fonctionné. La documentation de MS suggère que les poignées vers les consoles peuvent être réassignées, et je ne suis pas à l'aise ou heureux avec ceci solution, mais jusqu'à présent, c'est la seule chose que j'ai trouvé qui me permet de désactiver le mode édition rapide par programmation. GetStdHandle(STD_INPUT_HANDLE) retourne '3', les autres appels renvoient une valeur à 7 chiffres qui varie chaque fois que le programme est lancé.

0
répondu mickeyf 2017-06-21 20:08:48