Как избавиться от кнопки закрытия окна консоли? - PullRequest
0 голосов
/ 30 мая 2020

У меня есть клиент, который использует какое-то старое, но все еще необходимое 32-битное программное обеспечение, работающее в окне консоли. Необходимо отключить кнопку «Закрыть», поскольку закрытие консоли с помощью этой кнопки вызывает серьезные проблемы в этом программном обеспечении.

Я думал о следующем способе:

1) Найти дескриптор активной консоли
2) Отключить кнопку закрытия с помощью функции GetSystemMenu

Может быть, я Совершенно неправ, но мне пока не удалось найти способ сделать это.

Редактировать:

Проблема только в кнопке закрытия. Конечно, пользователи также могут выйти из программы с помощью Alt + F4 или диспетчера задач, но они этого не делают. Они используют кнопку закрытия, поэтому я хочу ее отключить.

Конечно, лучшим решением было бы отключить все способы отмены программы, но отключение кнопки «Закрыть» будет работать.

Чтобы запустить программу внутри формы Windows, тоже можно было бы использовать одно из возможных решений.

1 Ответ

0 голосов
/ 30 мая 2020

Чтобы взаимодействовать с внешним окном, вам нужно сначала найти его / проверить, что оно существует.

У нас есть разные методы поиска окна. Здесь я рассматриваю FindWindowEx и Process.GetProcessesByName () . UI Automation и Enum Windows в конечном итоге предоставляют другие варианты.

Сохраните заголовок окна CMD где-нибудь, например, в поле экземпляра (это могут быть настройки проекта или что-то еще, к чему вы можете получить доступ во время выполнения).

Private cmdWindowTitle As String = "The Window Title"

FindWindowEx более полезен, если вы точно знаете, что такое заголовок окна, и он не меняется со временем.
Process.GetProcessesByName() можно использовать для поиска окна с помощью Имя процесса, а затем проверьте, является ли Process.MainWindowTitle.Contains() хотя бы частично известной строкой.

Если вместо этого окно консоли принадлежит текущему процессу, вам просто нужно:

Process.GetCurrentProcess().MainWindowHandle

' -- If the Console Window belongs to the current Process: --
Dim cmdWindowHandle = Process.GetCurrentProcess().MainWindowHandle
' -----------------------------------------------------------

' -- Find it when the exact Window title is known: --
Dim cmdWindowHandle As IntPtr = NativeMethods.GetCmdWindowByCaption(cmdWindowTitle)
' -----------------------------------------------------------

' -- Find it when only a partial caption is available: --
Dim cmdWindowHandle As IntPtr = IntPtr.Zero
Dim cmdProc = Process.GetProcessesByName("cmd").
    FirstOrDefault(Function(p) p.MainWindowTitle.Contains(cmdWindowTitle))
If cmdProc IsNot Nothing Then
    cmdWindowHandle = cmdProc.MainWindowHandle
End If
' -----------------------------------------------------------

' Choose one of the above, then, in any case:
If cmdWindowHanle <> IntPtr.Zero Then
    NativeMethods.WindowDisableSysMenu(cmdWindowHandle)
End If

Примечание : Здесь я предполагая, что имя процесса - cmd, а имя класса Window - ConsoleWindowClass. А может и не быть. При необходимости измените их.

Поскольку теперь в окне нет кнопок SystemMenu или Close (мы просто скрыли их все), его нельзя закрыть с помощью ALT + F4 или любым другим способом, кроме использования диспетчера задач (или подождите для его закрытия естественно ).
Чтобы закрыть его из вашего приложения, отправьте сообщение WM_CLOSE:

' -- find the Window as described before --
Dim cmdWindowHandle As IntPtr = NativeMethods.GetCmdWindowByCaption(cmdWindowTitle)
If Not cmdWindowHandle.Equals(IntPtr.Zero) Then
    NativeMethods.SendCloseMessage(cmdWindowHandle)
End If

Объявления NativeMethods:

Public Class NativeMethods

    Private Const WM_CLOSE As Integer = &H10

    Public Enum WinStyles As UInteger
        WS_MAXIMIZE = &H1000000
        WS_MAXIMIZEBOX = &H10000
        WS_MINIMIZE = &H20000000
        WS_MINIMIZEBOX = &H20000
        WS_SYSMENU = &H80000
    End Enum

    Public Enum GWL_Flags As Integer
        GWL_STYLE = -16
        GWL_EXSTYLE = -20
    End Enum

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function SendMessage(hWnd As IntPtr, uMsg As WinMessage, wParam As Integer, lParam As Integer) As Integer
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function FindWindowEx(hwndParent As IntPtr, hwndChildAfter As IntPtr, lpszClass As String, lpszWindow As String) As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function GetWindowLong(hWnd As IntPtr, nIndex As GWL_Flags) As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function SetWindowLong(hWnd As IntPtr, nIndex As GWL_Flags, dwNewLong As IntPtr) As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function GetWindowLongPtr(hWnd As IntPtr, nIndex As GWL_Flags) As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function SetWindowLongPtr(hWnd As IntPtr, nIndex As GWL_Flags, dwNewLong As IntPtr) As IntPtr
    End Function

    ' Public wrappers
    Public Shared Function GetWindowLongUni(hWnd As IntPtr, nIndex As GWL_Flags) As Integer
        If IntPtr.Size = 8 Then
            Return GetWindowLongPtr(hWnd, nIndex).ToInt32()
        Else
            Return GetWindowLong(hWnd, nIndex).ToInt32()
        End If
    End Function

    Public Shared Function SetWindowLongUni(hWnd As IntPtr, nIndex As GWL_Flags, dwNewLong As Integer) As Integer
        If IntPtr.Size = 8 Then
            Return SetWindowLongPtr(hWnd, nIndex, New IntPtr(dwNewLong)).ToInt32()
        Else
            Return SetWindowLong(hWnd, nIndex, New IntPtr(dwNewLong)).ToInt32()
        End If
    End Function

    Public Shared Function GetCmdWindowByCaption(cmdCaption As String) As IntPtr
        Return FindWindowEx(IntPtr.Zero, IntPtr.Zero, "ConsoleWindowClass", cmdCaption)
    End Function

    Public Shared Sub WindowDisableSysMenu(windowHandle As IntPtr)
        Dim styles As Integer = GetWindowLongUni(windowHandle, GWL_Flags.GWL_STYLE)
        styles = styles And Not CInt(WinStyles.WS_SYSMENU)
        SetWindowLongUni(windowHandle, GWL_Flags.GWL_STYLE, styles)
    End Sub

    Public Shared Sub SendCloseMessage(windowHandle As IntPtr)
        SendMessage(windowHandle, WM_CLOSE, 0, 0)
    End Sub
End Class
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...