#c# #winforms #winforms-interop
#c# #winforms #winforms-взаимодействие
Вопрос:
Я пишу приложение Windows forms, которое может запускать консоль для отладки. Я хочу отключить кнопку закрытия консоли, чтобы приложение Windows forms нельзя было закрыть с помощью кнопки закрытия консоли. Я создал скелет тестового кода, и он работает. Код приведен ниже:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace bsa_working
{
public partial class Form1 : Form
{
static bool console_on = false;
public Form1()
{
InitializeComponent();
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (ViewConsole.Checked)
{
Win32.AllocConsole();
ConsoleProperties.ConsoleMain();
// Set console flag to true
console_on = true; // will be used later
}
else
Win32.FreeConsole();
}
}
public class Win32
{
[DllImport("kernel32.dll")]
public static extern Boolean AllocConsole();
[DllImport("kernel32.dll")]
public static extern Boolean FreeConsole();
}
public class ConsoleProperties
{
[DllImport("user32.dll")]
static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern IntPtr RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);
internal const uint SC_CLOSE = 0xF060;
internal const uint MF_GRAYED = 0x00000001;
internal const uint MF_BYCOMMAND = 0x00000000;
public static void ConsoleMain()
{
IntPtr hMenu = Process.GetCurrentProcess().MainWindowHandle;
IntPtr hSystemMenu = GetSystemMenu(hMenu, false);
EnableMenuItem(hSystemMenu, SC_CLOSE, MF_GRAYED);
RemoveMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND);
// Set console title
Console.Title = "Test Console";
// Set console surface foreground and background color
Console.BackgroundColor = ConsoleColor.DarkBlue;
Console.ForegroundColor = ConsoleColor.White;
Console.Clear();
}
}
}
Код работает нормально, ЗА ИСКЛЮЧЕНИЕМ:
-
Когда код скомпилирован и запущен в первый раз, X на консоли не отображается серым цветом, но он отображается серым цветом в приложении Windows Forms. Однако, когда код закрывается и запускается снова, код работает так, как должен; то есть X на консоли становится серым, а приложение Windows Forms таким, каким оно должно быть. Есть идеи, почему и как это можно исправить?
-
Иногда консоль отображается за формой win. Есть ли способ заставить консоль всегда быть на вершине?
Кроме того, есть ли какой-либо способ привязать консоль к определенному месту в WinForm? приложение? Я могу установить его размер, поэтому, если бы я мог закрепить его в определенном месте, я мог бы создать для него место в форме.
Комментарии:
1. Почему у вас просто нет Windows forms в вашем приложении, например, другой формы или элемента управления внутри текстового поля с включенной многострочностью, тогда вы перенаправляете стандартный вывод консоли на этот элемент управления без всей этой магии, которую вы пытаетесь сделать?
2. Потому что консоль в первую очередь предназначена для отладки, и я не обязательно хочу видеть ее все время.
3. @Zeos6: Я делаю то же самое в некоторых своих приложениях. Мне действительно нравится, как это работает. Вместо вызова
Process.GetCurrentProcess().MainWindowHandle
(что может привести к конфликту между формой и окном консоли), после вызова AllocConsole() получите дескриптор окна консоли, вызвавGetConsoleWindow()
4. Я думаю, что GetConsoleWindow () работает только для XP, и я хочу, чтобы это работало даже в среде операционной системы, отличной от XP.
5. Я не могу воспроизвести свою систему (64-разрядная версия Win7). Это поддерживает совет Boo о состоянии гонки. Хотя я вообще не понимаю, почему консоль становится главным окном процесса.
Ответ №1:
Чтобы заставить это работать, вам нужно изменить, IntPtr hMenu = Process.GetCurrentProcess().MainWindowHandle;
чтобы вместо этого использовать дескриптор окна Консоли (который вы можете получить, вызвав GetConsoleWindow()
).
Чтобы отобразить его сверху, вы могли бы использовать, например, SetForegroundWindow
с дескриптором окна консоли.
Что касается закрепления, я действительно не уверен, возможно ли это вообще.
Комментарии:
1. Спасибо за совет. Я согласен с условием гонки, и я также думаю, что закрепление, вероятно, не годится. Я просто подумал спросить, если я что-то упустил. Мое единственное возражение против GetConsoleWindow () заключается в том, что оно работает только для Win 2000 и XP. Если вы попытаетесь обойти (который существует), то возникнут проблемы, если у вас несколько comsoles, поскольку обходной путь находит только nearestone в порядке z. Я надеюсь избежать использования GetConsoleWindow ().
2. @Zeos6 с вашим приложением связана максимум ОДНА консоль (см. msdn.microsoft.com/en-us/library/windows/desktop / … ) так что это не будет проблемой… И
GetConsoleWindow
работает и для более поздних версий Windows! Пожалуйста, не забудьте проголосовать за / отметить как принятый любой ответ, который помог (см. meta.stackexchange.com/questions/5234 / … )3. Спасибо Yahia. Я отмечу ответ. Я согласен с тем, что у вас есть только одна консоль с выделением. Я предполагаю, что моя путаница в том, что если у меня есть несколько приложений, и каждое приложение создает консоль, то какую консоль я получу? Насколько я понимаю, вы получите ближайшую консоль в порядке z, не обязательно ту, которая связана с нужным вам приложением. Кроме того, спасибо за SetForegroundWindow. В любом случае, мне может понадобиться использовать GetConsoleWindow(), хотя я бы предпочел этого не делать.
4. @Zeos6 Вы абсолютно точно не получите «ближайшую», но, согласно MS, именно ту консоль, которая связана с вашим приложением (см. msdn.microsoft.com/en-us/library/windows/desktop / … )… этот вызов API учитывает только контекст процесса, А НЕ какие-либо координаты экрана.