Как получить дескриптор окна консольного приложения
может кто-нибудь сказать мне, как получить дескриптор консольного приложения Windows на C#? В приложении Windows Forms я обычно пытаюсь this.Handle
.
6 ответов
Не уверен, что это работает, но вы можете попробовать это :
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
- вышеуказанного
Process.MainWindowHandle
метод работает только для процесса, который запустил консоль - на
FindWindowByCaption
метод по своей сути является ненадежным
вот надежный способ сделать это:
связанные функции из консоль Win32 API являются:
[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();
- для консоли текущий процесс подключен к, просто
GetConsoleWindow()
is достаточно - для консоли присоединен другой процесс, присоединитесь к нему также с помощью
AttachConsole
, называютGetConsoleWindow
, их немедленно отсоединить сFreeConsole
.
для дополнительной осторожности зарегистрируйте обработчик событий консоли перед подключением (и отмените его регистрацию после отсоединения), чтобы вы случайно не получили прекращение, если событие консоли происходит в крошечный промежуток времени, который вы прикреплены к консоли:
[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;
};
внесение изменений в текущий процесс просто читать что-то довольно уродливо (когда это консольный процесс, это становится действительно уродливым, так как он требует вспомогательного процесса, чтобы избежать завершения текущей консоли). Тем не менее, дальнейшее исследование показывает, что нет другого способа, кроме инъекции в csrss
процесс или целевой процесс.
информация о корреспонденции консоли находится и управляется csrss.exe
(или множество из них, по одному для каждого сеанса, начиная с Vista), поэтому это не может быть полученные с ReadProcessMemory
. Все это csrss
выставляет это CSRSS LPC API. В полном списке API есть только одна соответствующая функция,SrvGetConsoleWindow
. И он не принимает PID, но определяет, что вызывающей стороны, как видно в альтернативная реализация или разборка функции в winsrv.dll
.
попробуйте это:
[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);
Я только что решил эту проблему для себя (к сожалению, прежде чем увидеть Томас что гораздо быстрее). Ну, вот еще один способ для тех, кто не удовлетворен его ответом. Я пишу этот ответ, потому что хочу дать другой ответ + лучший способ создать Program
класс, если вы рассматриваете консоль как окно. Давайте начнем с этого дизайна:
Я вроде как изменил стиль по умолчанию Program
класса. Я действительно сделал это класс, в котором есть программа, а не только один метод, который представляет ее и использует другие классы для контента. (Если вы не знаете, что я имею в виду, не важно).
причина, по которой я должен был это сделать, заключается в том, что я хотел написать следующий обработчик событий:
private void CatchUnhandled(Object sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject as Exception;
MessageBox.Show(this, exception.Message, "Error"); // Check out 1st arg.
}
он перегружает этот метод MessageBox.Show(IWin32Window, String, String)
.
потому что консоль не реализует IWin32Window
, я должен был реализовать его сам, конечно, для того, чтобы просто позвонить this
в 1st
Я не думаю, что есть такая вещь. Окно консоли недоступно для приложения. Вы можете попытаться повторить список процессов, ища собственное имя процесса. The Process
класс IIRC содержит свойство для дескриптора главного окна программы, которое может быть консольным окном для консольных приложений , в котором я не уверен.
в консольном приложении, которое передавало диагостику на консоль и для которого я хотел отключить ввод мыши, я попытался
GetConsoleWindow(),
Process.GetCurrentProcess().MainWindowHandle, and FindWindowByCaption(IntPtr.Zero, Console.Title)
.
Каждый из них возвращал один и тот же ненулевой дескриптор, но когда я попытался использовать этот дескриптор в SetConsoleMode, он вызвал исключение "недопустимый дескриптор". Наконец я попробовал SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode | ENABLE_EXTENDED_FLAGS))
С STD_INPUT_HANDLE, определенным как -10, и это сработало. Документация MS предполагает, что дескрипторы консолей могут быть переназначены, и я не доволен этим решением, но так далеко это единственное, что я нашел, что позволяет мне отключить режим быстрого редактирования программно. GetStdHandle(STD_INPUT_HANDLE)
возвращает '3', другие вызовы возвращают 7-значное значение, которое меняется каждый раз при запуске программы.