Я пытаюсь изменить режим консоли Windows для вывода (CONOUT$
) с помощью Windows API и SetConsoleMode вызывает. Поэтому я изменил сценарий PowerShell на основе ConinMode.ps1 ( и который работает для ввода), чтобы сделать это. Чтение прекрасно работает с обоими 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
, как указано в другом месте.
Вопрос: Как включить этот бит/флаг с помощью PowerShell?
Некоторые вещи, о которых я могу думать, могут быть неправильными:
- Я, конечно, неправильно понимаю, как это работает...
- У меня могут быть неправильные разрешения писать в консоль? (Как установить?)
- #P10# <блочная цитата> #P11# блочная цитата>
Возможно, при выполнении скрипта создается новый выходной буфер? (Что делать?)
- Возможно, мне придется создать новый буфер?
- Возможно, мне придется создать новую консоль?
Похожие вопросы и ссылки: