Я пытаюсь изменить режим консоли Windows для вывода (CONOUT$
) с помощью Windows API и SetConsoleMode вызовов.Поэтому я изменил сценарий PowerShell, основанный на ConinMode.ps1 (и который работает для input ), чтобы сделать это. Чтение прекрасно работает как с ConoutMode.exe , так и с моим сценарием и возвращает:
# .\ConoutMode.exe
mode: 0x3
ENABLE_PROCESSED_OUTPUT 0x0001 ON
ENABLE_WRAP_AT_EOL_OUTPUT 0x0002 ON
ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 off <====
DISABLE_NEWLINE_AUTO_RETURN 0x0008 off
ENABLE_LVB_GRID_WORLDWIDE 0x0010 off
# .\ConoutMode.ps1
OK! GetConsoleWindow handle : 0x1F06D6
Console Input Mode (CONIN) : 0x21f
Console Output Mode (CONOUT) : 0x3
Однако и мой сценарий, и исполняемый файл не могут записать режим,(Возможно, потому что он думает, что мой дескриптор вывода не указывает на консоль ?)
В PowerShell:
# .\ConoutMode.exe set 0x000f
error: SetConsoleMode failed (is stdout a console?)
# .\ConoutMode.ps1 -Mode 7
OK! GetConsoleWindow handle : 0x1F06D6
old (out) mode: 0x3
SetConsoleMode (out) failed (is stdout a console?)
At C:\cygwin64\home\emix\win_esc_test\ConoutMode.ps1:112 char:9
+ throw "SetConsoleMode (out) failed (is stdout a console?)"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (SetConsoleMode ...out a console?):String) [], RuntimeException
+ FullyQualifiedErrorId : SetConsoleMode (out) failed (is stdout a console?)
Вот мой скрипт ConoutMode.ps1
вв целом:
param (
[int] $Mode
)
$signature = @'
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
public const int STD_INPUT_HANDLE = -10;
public const int STD_OUTPUT_HANDLE = -11;
public const int ENABLE_PROCESSED_OUTPUT = 0x0001;
public const int ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002;
public const int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
public const int DISABLE_NEWLINE_AUTO_RETURN = 0x0008;
public const int ENABLE_LVB_GRID_WORLDWIDE = 0x0010;
'@
#----------------------------------------------------------
$WinAPI = Add-Type -MemberDefinition $signature -Name WinAPI -Namespace ConoutMode -PassThru
#$WinAPI = Add-Type -MemberDefinition $signature -Name WinAPI -Namespace IdentifyConsoleWindow -PassThru
$hwnd = $WinAPI::GetConsoleWindow()
if ($hwnd -eq 0) {
throw "Error: GetConsoleWindow returned NULL."
}
echo "OK! GetConsoleWindow handle : 0x$($hwnd.ToString("X"))"
function GetConIn {
$ret = $WinAPI::GetStdHandle($WinAPI::STD_INPUT_HANDLE)
if ($ret -eq -1) {
throw "Error: cannot get stdin handle"
}
return $ret
}
function GetConOut {
$ret = $WinAPI::GetStdHandle($WinAPI::STD_OUTPUT_HANDLE)
if ($ret -eq -1) {
throw "Error: cannot get stdout handle"
}
return $ret
}
function GetConInMode { #GetCOnsoleMode
$conin = GetConIn
$mode = 0
$ret = $WinAPI::GetConsoleMode($conin, [ref]$mode)
if ($ret -eq 0) {
throw "GetConsoleMode (in) failed (is stdin a console?)"
}
return $mode
}
function GetConOutMode {
$conout = GetConOut
$mode = 0
$ret = $WinAPI::GetConsoleMode($conout, [ref]$mode)
if ($ret -eq 0) {
throw "GetConsoleMode (out) failed (is stdout a console?)"
}
return $mode
}
function SetConInMode($mode) {
$conin = GetConIn
$ret = $WinAPI::SetConsoleMode($conin, $mode)
if ($ret -eq 0) {
throw "SetConsoleMode (in) failed (is stdin a console?)"
}
}
function SetConOutMode($mode) {
#$conout = GetConOut
# Different tack:
$conout = $hwnd
$ret = $WinAPI::SetConsoleMode($conout, $mode)
if ($ret -eq 0) {
throw "SetConsoleMode (out) failed (is stdout a console?)"
}
}
#----------------------------------------------------------
# MAIN
#----------------------------------------------------------
$oldInMode = GetConInMode
$oldOutMode = GetConOutMode
$newMode = $oldOutMode
$doit = $false
if ($PSBoundParameters.ContainsKey("Mode")) {
$newMode = $Mode
$doit = $true
}
if ($doit) {
echo "old (out) mode: 0x$($oldOutMode.ToString("x"))"
SetConOutMode $newMode
$newMode = GetConOutMode
echo "new (out) mode: 0x$($newMode.ToString("x"))"
} else {
echo "Console Input Mode (CONIN) : 0x$($oldInMode.ToString("x"))"
echo "Console Output Mode (CONOUT) : 0x$($oldOutMode.ToString("x"))"
}
Итак, в конце дня я хочу включить ENABLE_VIRTUAL_TERMINAL_PROCESSING
для консоли.
Система, которую я использую для этого:
---------------------------------------------------------
PowerShell Version : 6.1.1
OS Name : Microsoft Windows 8.1 (64-bit)
OS Version : 6.3.9600 [2018-11-16 00:50:01]
OS BuildLabEx : 9600.19179
OS HAL : 6.3.9600.18969
OS Kernel : 6.3.9600.18217
OS UBR : 19182
-------------------------------------------------------
with Privilege : Administrator
-------------------------------------------------------
ExecutionPolicy :
MachinePolicy : Undefined
UserPolicy : Undefined
Process : Undefined
CurrentUser : Undefined
LocalMachine : Bypass
Console Settings:
Type : ConsoleHost
OutputEncoding : Unicode (UTF-8)
Color Capability : 23
Registry VT Level : 1
CodePage (input) : 437
CodePage (output) : 437
Я также включил элемент реестра: HKCU:\Console\VirtualTerminalLevel
, как указано в другом месте.
Q: Как включить этот бит / флаг с помощью PowerShell?
Некоторые вещи, которые я могу придумать, могут быть неправильными:
- У меня наверняка неверное пониманиекак это работает ...
- У меня могут быть неправильные разрешения для записи на консоль?(Как установить?)
Я не могу записать в правильный выходной буфер?(Как найти?)
Обратите внимание, что установка режима вывода одного экранного буфера не влияет на режим вывода других экранных буферов.
Возможно, при выполнении скрипта создается новый буфер вывода?(Что делать?)
- Возможно, мне придется создать новый буфер?
- Мне, возможно, придется создать новую Консоль?
Вопросы и ссылки по теме: