Compare commits
26 Commits
master
...
libwinpty-
Author | SHA1 | Date | |
---|---|---|---|
|
9675a911a1 | ||
|
41762f3851 | ||
|
b844635158 | ||
|
9b69f67f56 | ||
|
e3c669ae56 | ||
|
7f1045972c | ||
|
cfb5f81de3 | ||
|
6deb5e2c26 | ||
|
873733faa4 | ||
|
3da3381859 | ||
|
80d4faa72c | ||
|
834195074a | ||
|
413f17a81e | ||
|
ede3244c26 | ||
|
cf76665cfe | ||
|
ba0e3a49fd | ||
|
f2c4f6a59b | ||
|
f04774eb06 | ||
|
840847624d | ||
|
f6c6f0558e | ||
|
a532a7ce3b | ||
|
1ec380ad61 | ||
|
1fafbc2ef5 | ||
|
95be1c291f | ||
|
fe60984ce4 | ||
|
6b31bd9d8c |
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -1,11 +1,9 @@
|
||||
* text=auto
|
||||
*.bat text eol=crlf
|
||||
*.c text
|
||||
*.cc text
|
||||
*.gyp text
|
||||
*.gypi text
|
||||
*.h text
|
||||
*.ps1 text eol=crlf
|
||||
*.rst text
|
||||
*.sh text
|
||||
*.txt text
|
||||
@ -17,3 +15,4 @@ configure text
|
||||
*.sh eol=lf
|
||||
configure eol=lf
|
||||
VERSION.txt eol=lf
|
||||
shared/GetCommitHash.cmd text eol=crlf
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -2,15 +2,10 @@
|
||||
*.suo
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
*.pyc
|
||||
winpty.sdf
|
||||
winpty.opensdf
|
||||
/config.mk
|
||||
/build
|
||||
/build-gyp
|
||||
/build-libpty
|
||||
/ship/packages
|
||||
/ship/tmp
|
||||
/src/Default
|
||||
/src/Release
|
||||
/src/gen
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2016 Ryan Prichard
|
||||
Copyright (c) 2011-2015 Ryan Prichard
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
|
142
Makefile
142
Makefile
@ -20,42 +20,35 @@
|
||||
|
||||
# Use make -n to see the actual command-lines make would run.
|
||||
|
||||
# The default "make install" prefix is /usr/local. Pass PREFIX=<path> on the
|
||||
# command-line to override the default.
|
||||
|
||||
.SECONDEXPANSION :
|
||||
|
||||
.PHONY : default
|
||||
default : all
|
||||
|
||||
PREFIX := /usr/local
|
||||
UNIX_ADAPTER_EXE := winpty.exe
|
||||
MINGW_ENABLE_CXX11_FLAG := -std=c++11
|
||||
USE_PCH := 1
|
||||
|
||||
COMMON_CXXFLAGS :=
|
||||
UNIX_CXXFLAGS :=
|
||||
MINGW_CXXFLAGS :=
|
||||
MINGW_LDFLAGS :=
|
||||
UNIX_LDFLAGS :=
|
||||
USE_PCH ?= 1
|
||||
PREFIX ?= /usr/local
|
||||
UNIX_ADAPTER_EXE ?= console.exe
|
||||
|
||||
# Include config.mk but complain if it hasn't been created yet.
|
||||
ifeq "$(wildcard config.mk)" ""
|
||||
$(error config.mk does not exist. Please run ./configure)
|
||||
endif
|
||||
|
||||
MINGW_ENABLE_CXX11_FLAG ?= -std=c++11
|
||||
|
||||
include config.mk
|
||||
|
||||
COMMON_CXXFLAGS += \
|
||||
COMMON_CXXFLAGS := $(COMMON_CXXFLAGS) \
|
||||
-DWINPTY_VERSION=$(shell cat VERSION.txt | tr -d '\r\n') \
|
||||
-DWINPTY_VERSION_SUFFIX=$(VERSION_SUFFIX) \
|
||||
-DWINPTY_COMMIT_HASH=$(COMMIT_HASH) \
|
||||
-MMD -Wall \
|
||||
-DUNICODE \
|
||||
-D_UNICODE \
|
||||
-D_WIN32_WINNT=0x0501 \
|
||||
-Ibuild/gen
|
||||
-DWINVER=0x0501 \
|
||||
-D_WIN32_WINNT=0x0501
|
||||
|
||||
UNIX_CXXFLAGS += \
|
||||
UNIX_CXXFLAGS := $(UNIX_CXXFLAGS) \
|
||||
$(COMMON_CXXFLAGS)
|
||||
|
||||
MINGW_CXXFLAGS += \
|
||||
MINGW_CXXFLAGS := $(MINGW_CXXFLAGS) \
|
||||
$(COMMON_CXXFLAGS) \
|
||||
-O2 \
|
||||
$(MINGW_ENABLE_CXX11_FLAG)
|
||||
@ -63,104 +56,67 @@ MINGW_CXXFLAGS += \
|
||||
MINGW_LDFLAGS += -static -static-libgcc -static-libstdc++
|
||||
UNIX_LDFLAGS += $(UNIX_LDFLAGS_STATIC)
|
||||
|
||||
ifeq "$(USE_PCH)" "1"
|
||||
MINGW_CXXFLAGS += -include build/mingw/PrecompiledHeader.h
|
||||
PCH_DEP := build/mingw/PrecompiledHeader.h.gch
|
||||
else
|
||||
PCH_DEP :=
|
||||
endif
|
||||
|
||||
build/gen/GenVersion.h : VERSION.txt $(COMMIT_HASH_DEP) | $$(@D)/.mkdir
|
||||
$(info Updating build/gen/GenVersion.h)
|
||||
@echo "const char GenVersion_Version[] = \"$(shell cat VERSION.txt | tr -d '\r\n')\";" > build/gen/GenVersion.h
|
||||
@echo "const char GenVersion_Commit[] = \"$(COMMIT_HASH)\";" >> build/gen/GenVersion.h
|
||||
|
||||
build/mingw/PrecompiledHeader.h : src/shared/PrecompiledHeader.h | $$(@D)/.mkdir
|
||||
$(info Copying $< to $@)
|
||||
@cp $< $@
|
||||
|
||||
build/mingw/PrecompiledHeader.h.gch : build/mingw/PrecompiledHeader.h | $$(@D)/.mkdir
|
||||
$(info Compiling $<)
|
||||
@$(MINGW_CXX) $(MINGW_CXXFLAGS) -c -o $@ $<
|
||||
|
||||
-include build/mingw/PrecompiledHeader.h.d
|
||||
|
||||
define def_unix_target
|
||||
build/$1/%.o : src/%.cc | $$$$(@D)/.mkdir
|
||||
$$(info Compiling $$<)
|
||||
build/$1/%.o : src/%.cc VERSION.txt
|
||||
@echo Compiling $$<
|
||||
@mkdir -p $$(dir $$@)
|
||||
@$$(UNIX_CXX) $$(UNIX_CXXFLAGS) $2 -I src/include -c -o $$@ $$<
|
||||
endef
|
||||
|
||||
ifeq "$(USE_PCH)" "1"
|
||||
PCH_INCLUDE := -include
|
||||
else
|
||||
PCH_INCLUDE :=
|
||||
endif
|
||||
|
||||
define def_mingw_target
|
||||
build/$1/%.o : src/%.cc $$(PCH_DEP) | $$$$(@D)/.mkdir
|
||||
$$(info Compiling $$<)
|
||||
@$$(MINGW_CXX) $$(MINGW_CXXFLAGS) $2 -I src/include -c -o $$@ $$<
|
||||
ifeq "$$(USE_PCH)" "1"
|
||||
H_$(1) := build/$1/PrecompiledHeader.h
|
||||
H_GCH_$(1) := build/$1/PrecompiledHeader.h.gch
|
||||
|
||||
$$(H_$(1)) : src/shared/PrecompiledHeader.h
|
||||
@echo Copying $$< to $$@
|
||||
@mkdir -p $$(dir $$@)
|
||||
@cp $$< $$@
|
||||
|
||||
$$(H_GCH_$(1)) : $$(H_$(1))
|
||||
@echo Compiling $$<
|
||||
@mkdir -p $$(dir $$@)
|
||||
@$$(MINGW_CXX) $$(MINGW_CXXFLAGS) $2 -c -o $$@ $$<
|
||||
endif
|
||||
|
||||
build/$1/%.o : src/%.cc VERSION.txt $$(H_GCH_$(1))
|
||||
@echo Compiling $$<
|
||||
@mkdir -p $$(dir $$@)
|
||||
@$$(MINGW_CXX) $$(MINGW_CXXFLAGS) $2 $$(PCH_INCLUDE) $$(H_$(1)) -I src/include -c -o $$@ $$<
|
||||
endef
|
||||
|
||||
include src/subdir.mk
|
||||
|
||||
.PHONY : all
|
||||
all : $(ALL_TARGETS)
|
||||
|
||||
.PHONY : tests
|
||||
tests : $(TEST_PROGRAMS)
|
||||
|
||||
.PHONY : install-bin
|
||||
install-bin : all
|
||||
install : all
|
||||
mkdir -p $(PREFIX)/bin
|
||||
install -m 755 -p -s build/$(UNIX_ADAPTER_EXE) $(PREFIX)/bin
|
||||
install -m 755 -p -s build/winpty.dll $(PREFIX)/bin
|
||||
install -m 755 -p -s build/winpty-agent.exe $(PREFIX)/bin
|
||||
|
||||
.PHONY : install-debugserver
|
||||
install-debugserver : all
|
||||
mkdir -p $(PREFIX)/bin
|
||||
install -m 755 -p -s build/winpty-debugserver.exe $(PREFIX)/bin
|
||||
|
||||
.PHONY : install-lib
|
||||
install-lib : all
|
||||
mkdir -p $(PREFIX)/lib
|
||||
install -m 644 -p build/winpty.lib $(PREFIX)/lib
|
||||
|
||||
.PHONY : install-doc
|
||||
install-doc :
|
||||
mkdir -p $(PREFIX)/share/doc/winpty
|
||||
install -m 644 -p LICENSE $(PREFIX)/share/doc/winpty
|
||||
install -m 644 -p README.md $(PREFIX)/share/doc/winpty
|
||||
install -m 644 -p RELEASES.md $(PREFIX)/share/doc/winpty
|
||||
|
||||
.PHONY : install-include
|
||||
install-include :
|
||||
mkdir -p $(PREFIX)/include/winpty
|
||||
install -m 644 -p src/include/winpty.h $(PREFIX)/include/winpty
|
||||
install -m 644 -p src/include/winpty_constants.h $(PREFIX)/include/winpty
|
||||
|
||||
.PHONY : install
|
||||
install : \
|
||||
install-bin \
|
||||
install-debugserver \
|
||||
install-lib \
|
||||
install-doc \
|
||||
install-include
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
rm -fr build
|
||||
|
||||
.PHONY : clean-msvc
|
||||
clean-msvc :
|
||||
rm -fr src/Default src/Release src/.vs src/gen
|
||||
rm -f src/*.vcxproj src/*.vcxproj.filters src/*.sln src/*.sdf
|
||||
clean-msvs :
|
||||
rm -fr src/Default
|
||||
rm -f src/*.vcxproj
|
||||
rm -f src/*.vcxproj.filters
|
||||
rm -f src/*.sln
|
||||
|
||||
.PHONY : distclean
|
||||
distclean : clean
|
||||
rm -f config.mk
|
||||
|
||||
.PRECIOUS : %.mkdir
|
||||
%.mkdir :
|
||||
$(info Creating directory $(dir $@))
|
||||
@mkdir -p $(dir $@)
|
||||
@touch $@
|
||||
.PHONY : default all tests install clean clean-msvs distclean
|
||||
|
||||
src/%.h :
|
||||
@echo "Missing header file $@ (stale dependency file?)"
|
||||
|
151
README.md
151
README.md
@ -1,151 +0,0 @@
|
||||
# winpty
|
||||
|
||||
[![Build Status](https://ci.appveyor.com/api/projects/status/69tb9gylsph1ee1x/branch/master?svg=true)](https://ci.appveyor.com/project/rprichard/winpty/branch/master)
|
||||
|
||||
winpty is a Windows software package providing an interface similar to a Unix
|
||||
pty-master for communicating with Windows console programs. The package
|
||||
consists of a library (libwinpty) and a tool for Cygwin and MSYS for running
|
||||
Windows console programs in a Cygwin/MSYS pty.
|
||||
|
||||
The software works by starting the `winpty-agent.exe` process with a new,
|
||||
hidden console window, which bridges between the console API and terminal
|
||||
input/output escape codes. It polls the hidden console's screen buffer for
|
||||
changes and generates a corresponding stream of output.
|
||||
|
||||
The Unix adapter allows running Windows console programs (e.g. CMD, PowerShell,
|
||||
IronPython, etc.) under `mintty` or Cygwin's `sshd` with
|
||||
properly-functioning input (e.g. arrow and function keys) and output (e.g. line
|
||||
buffering). The library could be also useful for writing a non-Cygwin SSH
|
||||
server.
|
||||
|
||||
## Supported Windows versions
|
||||
|
||||
winpty runs on Windows XP through Windows 10, including server versions. It
|
||||
can be compiled into either 32-bit or 64-bit binaries.
|
||||
|
||||
## Cygwin/MSYS adapter (`winpty.exe`)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
You need the following to build winpty:
|
||||
|
||||
* A Cygwin or MSYS installation
|
||||
* GNU make
|
||||
* A MinGW g++ toolchain capable of compiling C++11 code to build `winpty.dll`
|
||||
and `winpty-agent.exe`
|
||||
* A g++ toolchain targeting Cygwin or MSYS to build `winpty.exe`
|
||||
|
||||
Winpty requires two g++ toolchains as it is split into two parts. The
|
||||
`winpty.dll` and `winpty-agent.exe` binaries interface with the native
|
||||
Windows command prompt window so they are compiled with the native MinGW
|
||||
toolchain. The `winpty.exe` binary interfaces with the MSYS/Cygwin terminal so
|
||||
it is compiled with the MSYS/Cygwin toolchain.
|
||||
|
||||
MinGW appears to be split into two distributions -- MinGW (creates 32-bit
|
||||
binaries) and MinGW-w64 (creates both 32-bit and 64-bit binaries). Either
|
||||
one is generally acceptable.
|
||||
|
||||
#### Cygwin packages
|
||||
|
||||
The default g++ compiler for Cygwin targets Cygwin itself, but Cygwin also
|
||||
packages MinGW-w64 compilers. As of this writing, the necessary packages are:
|
||||
|
||||
* Either `mingw64-i686-gcc-g++` or `mingw64-x86_64-gcc-g++`. Select the
|
||||
appropriate compiler for your CPU architecture.
|
||||
* `gcc-g++`
|
||||
* `make`
|
||||
|
||||
As of this writing (2016-01-23), only the MinGW-w64 compiler is acceptable.
|
||||
The MinGW compiler (e.g. from the `mingw-gcc-g++` package) is no longer
|
||||
maintained and is too buggy.
|
||||
|
||||
#### MSYS packages
|
||||
|
||||
For the original MSYS, use the `mingw-get` tool (MinGW Installation Manager),
|
||||
and select at least these components:
|
||||
|
||||
* `mingw-developer-toolkit`
|
||||
* `mingw32-base`
|
||||
* `mingw32-gcc-g++`
|
||||
* `msys-base`
|
||||
* `msys-system-builder`
|
||||
|
||||
When running `./configure`, make sure that `mingw32-g++` is in your
|
||||
`PATH`. It will be in the `C:\MinGW\bin` directory.
|
||||
|
||||
#### MSYS2 packages
|
||||
|
||||
For MSYS2, use `pacman` and install at least these packages:
|
||||
|
||||
* `msys/gcc`
|
||||
* `mingw32/mingw-w64-i686-gcc` or `mingw64/mingw-w64-x86_64-gcc`. Select
|
||||
the appropriate compiler for your CPU architecture.
|
||||
* `make`
|
||||
|
||||
MSYS2 provides three start menu shortcuts for starting MSYS2:
|
||||
|
||||
* MinGW-w64 Win32 Shell
|
||||
* MinGW-w64 Win64 Shell
|
||||
* MSYS2 Shell
|
||||
|
||||
To build winpty, use the MinGW-w64 {Win32,Win64} shortcut of the architecture
|
||||
matching MSYS2. These shortcuts will put the g++ compiler from the
|
||||
`{mingw32,mingw64}/mingw-w64-{i686,x86_64}-gcc` packages into the `PATH`.
|
||||
|
||||
Alternatively, instead of installing `mingw32/mingw-w64-i686-gcc` or
|
||||
`mingw64/mingw-w64-x86_64-gcc`, install the `mingw-w64-cross-gcc` and
|
||||
`mingw-w64-cross-crt-git` packages. These packages install cross-compilers
|
||||
into `/opt/bin`, and then any of the three shortcuts will work.
|
||||
|
||||
### Building the Unix adapter
|
||||
|
||||
In the project directory, run `./configure`, then `make`, then `make install`.
|
||||
By default, winpty is installed into `/usr/local`. Pass `PREFIX=<path>` to
|
||||
`make install` to override this default.
|
||||
|
||||
### Using the Unix adapter
|
||||
|
||||
To run a Windows console program in `mintty` or Cygwin `sshd`, prepend
|
||||
`winpty` to the command-line:
|
||||
|
||||
$ winpty powershell
|
||||
Windows PowerShell
|
||||
Copyright (C) 2009 Microsoft Corporation. All rights reserved.
|
||||
|
||||
PS C:\rprichard\proj\winpty> 10 + 20
|
||||
30
|
||||
PS C:\rprichard\proj\winpty> exit
|
||||
|
||||
## Embedding winpty / MSVC compilation
|
||||
|
||||
See `src/include/winpty.h` for the prototypes of functions exported by
|
||||
`winpty.dll`.
|
||||
|
||||
Only the `winpty.exe` binary uses Cygwin; all the other binaries work without
|
||||
it and can be compiled with either MinGW or MSVC. To compile using MSVC,
|
||||
download gyp and run `gyp -I configurations.gypi` in the `src` subdirectory.
|
||||
This will generate a `winpty.sln` and associated project files. See the
|
||||
`src/winpty.gyp` and `src/configurations.gypi` files for notes on dealing with
|
||||
MSVC versions and different architectures.
|
||||
|
||||
Compiling winpty with MSVC currently requires MSVC 2013 or newer.
|
||||
|
||||
## Debugging winpty
|
||||
|
||||
winpty comes with a tool for collecting timestamped debugging output. To use
|
||||
it:
|
||||
|
||||
1. Run `winpty-debugserver.exe` on the same computer as winpty.
|
||||
2. Set the `WINPTY_DEBUG` environment variable to `trace` for the
|
||||
`winpty.exe` process and/or the process using `libwinpty.dll`.
|
||||
|
||||
winpty also recognizes a `WINPTY_SHOW_CONSOLE` environment variable. Set it
|
||||
to 1 to prevent winpty from hiding the console window.
|
||||
|
||||
## Copyright
|
||||
|
||||
This project is distributed under the MIT license (see the `LICENSE` file in
|
||||
the project root).
|
||||
|
||||
By submitting a pull request for this project, you agree to license your
|
||||
contribution under the MIT license to this project.
|
127
README.rst
Normal file
127
README.rst
Normal file
@ -0,0 +1,127 @@
|
||||
======
|
||||
winpty
|
||||
======
|
||||
|
||||
winpty is a Windows software package providing an interface similar to a Unix
|
||||
pty-master for communicating with Windows console programs. The package
|
||||
consists of a library (libwinpty) and a tool for Cygwin and MSYS for running
|
||||
Windows console programs in a Cygwin/MSYS pty.
|
||||
|
||||
The software works by starting the ``winpty-agent.exe`` process with a new,
|
||||
hidden console window, which bridges between the console API and terminal
|
||||
input/output escape codes. It polls the hidden console's screen buffer for
|
||||
changes and generates a corresponding stream of output.
|
||||
|
||||
The Unix adapter allows running Windows console programs (e.g. CMD, PowerShell,
|
||||
IronPython, etc.) under ``mintty`` or Cygwin's ``sshd`` with
|
||||
properly-functioning input (e.g. arrow and function keys) and output (e.g. line
|
||||
buffering). The library could be also useful for writing a non-Cygwin SSH
|
||||
server.
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
You need the following to build winpty:
|
||||
|
||||
* A Cygwin or MSYS installation
|
||||
* GNU make
|
||||
* A MinGW g++ toolchain capable of compiling C++11 code to build ``winpty.dll``
|
||||
and ``winpty-agent.exe``
|
||||
* A g++ toolchain targeting Cygwin or MSYS to build ``console.exe``
|
||||
|
||||
Winpty requires two g++ toolchains as it is split into two parts. The
|
||||
``winpty.dll`` and ``winpty-agent.exe`` binaries interface with the native
|
||||
Windows command prompt window so they are compiled with the native MinGW
|
||||
toolchain. The console.exe binary interfaces with the MSYS/Cygwin terminal so
|
||||
it is compiled with the MSYS/Cygwin toolchain.
|
||||
|
||||
MinGW appears to be split into two distributions -- MinGW (creates 32-bit
|
||||
binaries) and MinGW-w64 (creates both 32-bit and 64-bit binaries). Either
|
||||
one is generally acceptable.
|
||||
|
||||
Cygwin packages
|
||||
---------------
|
||||
|
||||
The default g++ compiler for Cygwin targets Cygwin itself, but Cygwin also
|
||||
packages MinGW-w64 compilers. As of this writing, the necessary packages are:
|
||||
|
||||
* Either ``mingw64-i686-gcc-g++`` or ``mingw64-x86_64-gcc-g++``. Select the
|
||||
appropriate compiler for your CPU architecture.
|
||||
* ``gcc-g++``
|
||||
* ``make``
|
||||
|
||||
As of this writing (2016-01-23), only the MinGW-w64 compiler is acceptable.
|
||||
The MinGW compiler (e.g. from the ``mingw-gcc-g++`` package) is no longer
|
||||
maintained and is too buggy.
|
||||
|
||||
MSYS packages
|
||||
-------------
|
||||
|
||||
For the original MSYS, use the ``mingw-get`` tool (MinGW Installation Manager),
|
||||
and select at least these components:
|
||||
|
||||
* ``mingw-developer-toolkit``
|
||||
* ``mingw32-base``
|
||||
* ``mingw32-gcc-g++``
|
||||
* ``msys-base``
|
||||
* ``msys-system-builder``
|
||||
|
||||
When running ``./configure``, make sure that ``mingw32-g++`` is in your
|
||||
``PATH``. It will be in the ``C:\MinGW\bin`` directory.
|
||||
|
||||
MSYS2 packages
|
||||
--------------
|
||||
|
||||
For MSYS2, use ``pacman`` and install at least these packages:
|
||||
|
||||
* ``msys/gcc``
|
||||
* ``mingw32/mingw-w64-i686-gcc`` or ``mingw64/mingw-w64-x86_64-gcc``. Select
|
||||
the appropriate compiler for your CPU architecture.
|
||||
* ``make``
|
||||
|
||||
Build
|
||||
=====
|
||||
|
||||
In the project directory, run ``./configure``, then ``make``.
|
||||
|
||||
This will produce three binaries:
|
||||
|
||||
* ``build/winpty.dll``
|
||||
* ``build/winpty-agent.exe``
|
||||
* ``build/console.exe``
|
||||
|
||||
Using the Unix adapter
|
||||
======================
|
||||
|
||||
To run a Windows console program in ``mintty`` or Cygwin ``sshd``, prepend
|
||||
``console.exe`` to the command-line::
|
||||
|
||||
$ build/console.exe c:/Python27/python.exe
|
||||
Python 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win32
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> 10 + 20
|
||||
30
|
||||
>>> exit()
|
||||
$
|
||||
|
||||
Debugging winpty
|
||||
================
|
||||
|
||||
winpty comes with a tool for collecting timestamped debugging output. To use
|
||||
it:
|
||||
|
||||
1. Run ``winpty-debugserver.exe`` on the same computer as winpty.
|
||||
2. Set the ``WINPTY_DEBUG`` environment variable to ``trace`` for the
|
||||
``console.exe`` process and/or the process using ``libwinpty.dll``.
|
||||
|
||||
winpty also recognizes a ``WINPTY_SHOW_CONSOLE`` environment variable. Set it
|
||||
to 1 to prevent winpty from hiding the console window.
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This project is distributed under the MIT license (see the ``LICENSE`` file in
|
||||
the project root).
|
||||
|
||||
By submitting a pull request for this project, you agree to license your
|
||||
contribution under the MIT license to this project.
|
173
RELEASES.md
Normal file → Executable file
173
RELEASES.md
Normal file → Executable file
@ -1,174 +1,7 @@
|
||||
# Next Version
|
||||
# Next version
|
||||
|
||||
Input handling changes:
|
||||
|
||||
* Improve Ctrl-C handling with programs that use unprocessed input. (e.g.
|
||||
Ctrl-C now cancels input with PowerShell on Windows 10.)
|
||||
[#116](https://github.com/rprichard/winpty/issues/116)
|
||||
* Fix a theoretical issue with input event ordering.
|
||||
[#117](https://github.com/rprichard/winpty/issues/117)
|
||||
* Ctrl/Shift+{Arrow,Home,End} keys now work with IntelliJ.
|
||||
[#118](https://github.com/rprichard/winpty/issues/118)
|
||||
|
||||
# Version 0.4.3 (2017-05-17)
|
||||
|
||||
Input handling changes:
|
||||
|
||||
* winpty sets `ENHANCED_KEY` for arrow and navigation keys. This fixes an
|
||||
issue with the Ruby REPL.
|
||||
[#99](https://github.com/rprichard/winpty/issues/99)
|
||||
* AltGr keys are handled better now.
|
||||
[#109](https://github.com/rprichard/winpty/issues/109)
|
||||
* In `ENABLE_VIRTUAL_TERMINAL_INPUT` mode, when typing Home/End with a
|
||||
modifier (e.g. Ctrl), winpty now generates an H/F escape sequence like
|
||||
`^[[1;5F` rather than a 1/4 escape like `^[[4;5~`.
|
||||
[#114](https://github.com/rprichard/winpty/issues/114)
|
||||
|
||||
Resizing and scraping fixes:
|
||||
|
||||
* winpty now synthesizes a `WINDOW_BUFFER_SIZE_EVENT` event after resizing
|
||||
the console to better propagate window size changes to console programs.
|
||||
In particular, this affects WSL and Cygwin.
|
||||
[#110](https://github.com/rprichard/winpty/issues/110)
|
||||
* Better handling of resizing for certain full-screen programs, like
|
||||
WSL less.
|
||||
[#112](https://github.com/rprichard/winpty/issues/112)
|
||||
* Hide the cursor if it's currently outside the console window. This change
|
||||
fixes an issue with Far Manager.
|
||||
[#113](https://github.com/rprichard/winpty/issues/113)
|
||||
* winpty now avoids using console fonts smaller than 5px high to improve
|
||||
half-vs-full-width character handling. See
|
||||
https://github.com/Microsoft/vscode/issues/19665.
|
||||
[b4db322010](https://github.com/rprichard/winpty/commit/b4db322010d2d897e6c496fefc4f0ecc9b84c2f3)
|
||||
|
||||
Cygwin/MSYS adapter fix:
|
||||
|
||||
* The way the `winpty` Cygwin/MSYS2 adapter searches for the program to
|
||||
launch changed. It now resolves symlinks and searches the PATH explicitly.
|
||||
[#81](https://github.com/rprichard/winpty/issues/81)
|
||||
[#98](https://github.com/rprichard/winpty/issues/98)
|
||||
|
||||
This release does not include binaries for the old MSYS1 project anymore.
|
||||
MSYS2 will continue to be supported. See
|
||||
https://github.com/rprichard/winpty/issues/97.
|
||||
|
||||
# Version 0.4.2 (2017-01-18)
|
||||
|
||||
This release improves WSL support (i.e. Bash-on-Windows):
|
||||
|
||||
* winpty generates more correct input escape sequences for WSL programs that
|
||||
enable an alternate input mode using DECCKM. This bug affected arrow keys
|
||||
and Home/End in WSL programs such as `vim`, `mc`, and `less`.
|
||||
[#90](https://github.com/rprichard/winpty/issues/90)
|
||||
* winpty now recognizes the `COMMON_LVB_REVERSE_VIDEO` and
|
||||
`COMMON_LVB_UNDERSCORE` text attributes. The Windows console uses these
|
||||
attributes to implement the SGR.4(Underline) and SGR.7(Negative) modes in
|
||||
its VT handling. This change affects WSL pager status bars, man pages, etc.
|
||||
|
||||
The build system no longer has a "version suffix" mechanism, so passing
|
||||
`VERSION_SUFFIX=<suffix>` to make or `-D VERSION_SUFFIX=<suffix>` to gyp now
|
||||
has no effect. AFAIK, the mechanism was never used publicly.
|
||||
[67a34b6c03](https://github.com/rprichard/winpty/commit/67a34b6c03557a5c2e0a2bdd502c2210921d8f3e)
|
||||
|
||||
# Version 0.4.1 (2017-01-03)
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* This version fixes a bug where the `winpty-agent.exe` process could read
|
||||
past the end of a buffer.
|
||||
[#94](https://github.com/rprichard/winpty/issues/94)
|
||||
|
||||
# Version 0.4.0 (2016-06-28)
|
||||
|
||||
The winpty library has a new API that should be easier for embedding.
|
||||
[880c00c69e](https://github.com/rprichard/winpty/commit/880c00c69eeca73643ddb576f02c5badbec81f56)
|
||||
|
||||
User-visible changes:
|
||||
|
||||
* winpty now automatically puts the terminal into mouse mode when it detects
|
||||
that the console has left QuickEdit mode. The `--mouse` option still forces
|
||||
the terminal into mouse mode. In principle, an option could be added to
|
||||
suppress terminal mode, but hopefully it won't be necessary. There is a
|
||||
script in the `misc` subdirectory, `misc/ConinMode.ps1`, that can change
|
||||
the QuickEdit mode from the command-line.
|
||||
* winpty now passes keyboard escapes to `bash.exe` in the Windows Subsystem
|
||||
for Linux.
|
||||
[#82](https://github.com/rprichard/winpty/issues/82)
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* By default, `winpty.dll` avoids calling `SetProcessWindowStation` within
|
||||
the calling process.
|
||||
[#58](https://github.com/rprichard/winpty/issues/58)
|
||||
* Fixed an uninitialized memory bug that could have crashed winpty.
|
||||
[#80](https://github.com/rprichard/winpty/issues/80)
|
||||
* winpty now works better with very large and very small terminal windows.
|
||||
It resizes the console font according to the number of columns.
|
||||
[#61](https://github.com/rprichard/winpty/issues/61)
|
||||
* winpty no longer uses Mark to freeze the console on Windows 10. The Mark
|
||||
command could interfere with the cursor position, corrupting the data in
|
||||
the screen buffer.
|
||||
[#79](https://github.com/rprichard/winpty/issues/79)
|
||||
|
||||
# Version 0.3.0 (2016-05-20)
|
||||
|
||||
User-visible changes:
|
||||
|
||||
* The UNIX adapter is renamed from `console.exe` to `winpty.exe` to be
|
||||
consistent with MSYS2. The name `winpty.exe` is less likely to conflict
|
||||
with another program and is easier to search for online (e.g. for someone
|
||||
unfamiliar with winpty).
|
||||
* The UNIX adapter now clears the `TERM` variable.
|
||||
[#43](https://github.com/rprichard/winpty/issues/43)
|
||||
* An escape character appearing in a console screen buffer cell is converted
|
||||
to a '?'.
|
||||
[#47](https://github.com/rprichard/winpty/issues/47)
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* A major bug affecting XP users was fixed.
|
||||
[#67](https://github.com/rprichard/winpty/issues/67)
|
||||
* Fixed an incompatibility with ConEmu where winpty hung if ConEmu's
|
||||
"Process 'start'" feature was enabled.
|
||||
[#70](https://github.com/rprichard/winpty/issues/70)
|
||||
* Fixed a bug where `cmd.exe` sometimes printed the message,
|
||||
`Not enough storage is available to process this command.`.
|
||||
[#74](https://github.com/rprichard/winpty/issues/74)
|
||||
|
||||
Many changes internally:
|
||||
|
||||
* The codebase is switched from C++03 to C++11 and uses exceptions internally.
|
||||
No exceptions are thrown across the C APIs defined in `winpty.h`.
|
||||
* This version drops support for the original MinGW compiler packaged with
|
||||
Cygwin (`i686-pc-mingw32-g++`). The MinGW-w64 compiler is still supported,
|
||||
as is the MinGW distributed at mingw.org. Compiling with MSVC now requires
|
||||
MSVC 2013 or newer. Windows XP is still supported.
|
||||
[ec3eae8df5](https://github.com/rprichard/winpty/commit/ec3eae8df5bbbb36d7628d168b0815638d122f37)
|
||||
* Pipe security is improved. winpty works harder to produce unique pipe names
|
||||
and includes a random component in the name. winpty secures pipes with a
|
||||
DACL that prevents arbitrary users from connecting to its pipes. winpty now
|
||||
passes `PIPE_REJECT_REMOTE_CLIENTS` on Vista and up, and it verifies that
|
||||
the pipe client PID is correct, again on Vista and up. When connecting to a
|
||||
named pipe, winpty uses the `SECURITY_IDENTIFICATION` flag to restrict
|
||||
impersonation. Previous versions *should* still be secure.
|
||||
* `winpty-debugserver.exe` now has an `--everyone` flag that allows capturing
|
||||
debug output from other users.
|
||||
* The code now compiles cleanly with MSVC's "Security Development Lifecycle"
|
||||
(`/SDL`) checks enabled.
|
||||
|
||||
# Version 0.2.2 (2016-02-25)
|
||||
|
||||
Minor bug fixes and enhancements:
|
||||
|
||||
* Fix a bug that generated spurious mouse input records when an incomplete
|
||||
mouse escape sequence was seen.
|
||||
* Fix a buffer overflow bug in `winpty-debugserver.exe` affecting messages of
|
||||
exactly 4096 bytes.
|
||||
* For MSVC builds, add a `src/configurations.gypi` file that can be included
|
||||
on the gyp command-line to enable 32-bit and 64-bit builds.
|
||||
* `winpty-agent --show-input` mode: Flush stdout after each line.
|
||||
* Makefile builds: generate a `build/winpty.lib` import library to accompany
|
||||
`build/winpty.dll`.
|
||||
* Fix a bug that could have generated spurious mouse input records when an
|
||||
incomplete mouse escape sequence was seen.
|
||||
|
||||
# Version 0.2.1 (2015-12-19)
|
||||
|
||||
|
2
VERSION.txt
Normal file → Executable file
2
VERSION.txt
Normal file → Executable file
@ -1 +1 @@
|
||||
0.4.4-dev
|
||||
0.2.2
|
||||
|
16
appveyor.yml
16
appveyor.yml
@ -1,16 +0,0 @@
|
||||
image: Visual Studio 2015
|
||||
|
||||
init:
|
||||
- C:\msys64\usr\bin\bash --login -c "pacman -S --needed --noconfirm --noprogressbar msys/make msys/tar msys/gcc mingw-w64-cross-toolchain"
|
||||
- C:\cygwin\setup-x86 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make
|
||||
- C:\cygwin64\setup-x86_64 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make
|
||||
|
||||
build_script:
|
||||
- C:\Python27-x64\python.exe ship\ship.py --kind msys2 --arch x64 --syspath C:\msys64
|
||||
- C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch ia32 --syspath C:\cygwin
|
||||
- C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch x64 --syspath C:\cygwin64
|
||||
- C:\Python27-x64\python.exe ship\make_msvc_package.py
|
||||
|
||||
artifacts:
|
||||
- path: ship\packages\*.tar.gz
|
||||
- path: ship\packages\*.zip
|
30
configure
vendored
30
configure
vendored
@ -149,19 +149,29 @@ echo MINGW_CXX=$MINGW_CXX >> config.mk
|
||||
if test $IS_MSYS1 = 1; then
|
||||
echo UNIX_CXXFLAGS += -DWINPTY_TARGET_MSYS1 >> config.mk
|
||||
# The MSYS1 MinGW compiler has a bug that prevents inclusion of algorithm
|
||||
# and math.h in normal C++11 mode. The workaround is to enable the gnu++11
|
||||
# mode instead. The bug was fixed on 2015-07-31, but as of 2016-02-26, the
|
||||
# and math.h in normal C++11 mode. The workaround is to enable the g++11
|
||||
# mode instead. The bug was fixed on 2015-07-31, but as of 2016-01-05, the
|
||||
# fix apparently hasn't been released. See
|
||||
# http://ehc.ac/p/mingw/bugs/2250/.
|
||||
echo MINGW_ENABLE_CXX11_FLAG := -std=gnu++11 >> config.mk
|
||||
echo MINGW_ENABLE_CXX11_FLAG = -std=gnu++11 >> config.mk
|
||||
fi
|
||||
|
||||
if test -d .git -a -f .git/HEAD -a -f .git/index && git rev-parse HEAD >&/dev/null; then
|
||||
echo "Commit info: git"
|
||||
echo 'COMMIT_HASH = $(shell git rev-parse HEAD)' >> config.mk
|
||||
echo 'COMMIT_HASH_DEP := config.mk .git/HEAD .git/index' >> config.mk
|
||||
# Figure out how to embed build info (e.g. git commit) into the binary.
|
||||
if test -f BUILD_INFO.txt; then
|
||||
echo "Build info: source package"
|
||||
eval $(grep '^VERSION_SUFFIX=' BUILD_INFO.txt | tr -d '\r')
|
||||
eval $(grep '^COMMIT_HASH=' BUILD_INFO.txt | tr -d '\r')
|
||||
echo "VERSION_SUFFIX ?= ${VERSION_SUFFIX}" >> config.mk
|
||||
echo "COMMIT_HASH ?= ${COMMIT_HASH}" >> config.mk
|
||||
echo "BUILD_INFO_DEP = config.mk" >> config.mk
|
||||
elif test -d .git && git rev-parse HEAD >&/dev/null; then
|
||||
echo "Build info: git"
|
||||
echo 'VERSION_SUFFIX ?= -dev' >> config.mk
|
||||
echo 'COMMIT_HASH ?= $$(git rev-parse HEAD)' >> config.mk
|
||||
echo 'BUILD_INFO_DEP = config.mk .git/HEAD' >> config.mk
|
||||
else
|
||||
echo "Commit info: none"
|
||||
echo 'COMMIT_HASH := none' >> config.mk
|
||||
echo 'COMMIT_HASH_DEP := config.mk' >> config.mk
|
||||
echo "Build info: none"
|
||||
echo 'VERSION_SUFFIX ?= -dev' >> config.mk
|
||||
echo 'COMMIT_HASH ?= none' >> config.mk
|
||||
echo 'BUILD_INFO_DEP = config.mk' >> config.mk
|
||||
fi
|
||||
|
1
misc/BufferResizeTests.cc
Normal file → Executable file
1
misc/BufferResizeTests.cc
Normal file → Executable file
@ -1,6 +1,7 @@
|
||||
#include <windows.h>
|
||||
#include <cassert>
|
||||
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
#include "TestUtil.cc"
|
||||
|
||||
void dumpInfoToTrace() {
|
||||
|
1
misc/ChangeScreenBuffer.cc
Normal file → Executable file
1
misc/ChangeScreenBuffer.cc
Normal file → Executable file
@ -7,6 +7,7 @@
|
||||
#include <io.h>
|
||||
#include <cassert>
|
||||
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main()
|
||||
|
1
misc/ClearConsole.cc
Normal file → Executable file
1
misc/ClearConsole.cc
Normal file → Executable file
@ -15,6 +15,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
@ -1,117 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static HANDLE getConin() {
|
||||
HANDLE conin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (conin == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "error: cannot get stdin\n");
|
||||
exit(1);
|
||||
}
|
||||
return conin;
|
||||
}
|
||||
|
||||
static DWORD getConsoleMode() {
|
||||
DWORD mode = 0;
|
||||
if (!GetConsoleMode(getConin(), &mode)) {
|
||||
fprintf(stderr, "error: GetConsoleMode failed (is stdin a console?)\n");
|
||||
exit(1);
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
static void setConsoleMode(DWORD mode) {
|
||||
if (!SetConsoleMode(getConin(), mode)) {
|
||||
fprintf(stderr, "error: SetConsoleMode failed (is stdin a console?)\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static long parseInt(const std::string &s) {
|
||||
errno = 0;
|
||||
char *endptr = nullptr;
|
||||
long result = strtol(s.c_str(), &endptr, 0);
|
||||
if (errno != 0 || !endptr || *endptr != '\0') {
|
||||
fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str());
|
||||
exit(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
printf("Usage: ConinMode [verb] [options]\n");
|
||||
printf("Verbs:\n");
|
||||
printf(" [info] Dumps info about mode flags.\n");
|
||||
printf(" get Prints the mode DWORD.\n");
|
||||
printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n");
|
||||
printf(" set VALUE MASK\n");
|
||||
printf(" Same as `set VALUE`, but only alters the bits in MASK.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct {
|
||||
const char *name;
|
||||
DWORD value;
|
||||
} kInputFlags[] = {
|
||||
"ENABLE_PROCESSED_INPUT", ENABLE_PROCESSED_INPUT, // 0x0001
|
||||
"ENABLE_LINE_INPUT", ENABLE_LINE_INPUT, // 0x0002
|
||||
"ENABLE_ECHO_INPUT", ENABLE_ECHO_INPUT, // 0x0004
|
||||
"ENABLE_WINDOW_INPUT", ENABLE_WINDOW_INPUT, // 0x0008
|
||||
"ENABLE_MOUSE_INPUT", ENABLE_MOUSE_INPUT, // 0x0010
|
||||
"ENABLE_INSERT_MODE", ENABLE_INSERT_MODE, // 0x0020
|
||||
"ENABLE_QUICK_EDIT_MODE", ENABLE_QUICK_EDIT_MODE, // 0x0040
|
||||
"ENABLE_EXTENDED_FLAGS", ENABLE_EXTENDED_FLAGS, // 0x0080
|
||||
"ENABLE_VIRTUAL_TERMINAL_INPUT", 0x0200/*ENABLE_VIRTUAL_TERMINAL_INPUT*/, // 0x0200
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::vector<std::string> args;
|
||||
for (size_t i = 1; i < argc; ++i) {
|
||||
args.push_back(argv[i]);
|
||||
}
|
||||
|
||||
if (args.empty() || args.size() == 1 && args[0] == "info") {
|
||||
DWORD mode = getConsoleMode();
|
||||
printf("mode: 0x%lx\n", mode);
|
||||
for (const auto &flag : kInputFlags) {
|
||||
printf("%-29s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off");
|
||||
mode &= ~flag.value;
|
||||
}
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if (mode & (1u << i)) {
|
||||
printf("Unrecognized flag: %04x\n", (1u << i));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto verb = args[0];
|
||||
|
||||
if (verb == "set") {
|
||||
if (args.size() == 2) {
|
||||
const DWORD newMode = parseInt(args[1]);
|
||||
setConsoleMode(newMode);
|
||||
} else if (args.size() == 3) {
|
||||
const DWORD mode = parseInt(args[1]);
|
||||
const DWORD mask = parseInt(args[2]);
|
||||
const int newMode = (getConsoleMode() & ~mask) | (mode & mask);
|
||||
setConsoleMode(newMode);
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
} else if (verb == "get") {
|
||||
if (args.size() != 1) {
|
||||
usage();
|
||||
}
|
||||
printf("0x%lx\n", getConsoleMode());
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
#
|
||||
# PowerShell script for controlling the console QuickEdit and InsertMode flags.
|
||||
#
|
||||
# Turn QuickEdit off to interact with mouse-driven console programs.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# powershell .\ConinMode.ps1 [Options]
|
||||
#
|
||||
# Options:
|
||||
# -QuickEdit [on/off]
|
||||
# -InsertMode [on/off]
|
||||
# -Mode [integer]
|
||||
#
|
||||
|
||||
param (
|
||||
[ValidateSet("on", "off")][string] $QuickEdit,
|
||||
[ValidateSet("on", "off")][string] $InsertMode,
|
||||
[int] $Mode
|
||||
)
|
||||
|
||||
$signature = @'
|
||||
[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 ENABLE_INSERT_MODE = 0x0020;
|
||||
public const int ENABLE_QUICK_EDIT_MODE = 0x0040;
|
||||
public const int ENABLE_EXTENDED_FLAGS = 0x0080;
|
||||
'@
|
||||
|
||||
$WinAPI = Add-Type -MemberDefinition $signature `
|
||||
-Name WinAPI -Namespace ConinModeScript `
|
||||
-PassThru
|
||||
|
||||
function GetConIn {
|
||||
$ret = $WinAPI::GetStdHandle($WinAPI::STD_INPUT_HANDLE)
|
||||
if ($ret -eq -1) {
|
||||
throw "error: cannot get stdin"
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
|
||||
function GetConsoleMode {
|
||||
$conin = GetConIn
|
||||
$mode = 0
|
||||
$ret = $WinAPI::GetConsoleMode($conin, [ref]$mode)
|
||||
if ($ret -eq 0) {
|
||||
throw "GetConsoleMode failed (is stdin a console?)"
|
||||
}
|
||||
return $mode
|
||||
}
|
||||
|
||||
function SetConsoleMode($mode) {
|
||||
$conin = GetConIn
|
||||
$ret = $WinAPI::SetConsoleMode($conin, $mode)
|
||||
if ($ret -eq 0) {
|
||||
throw "SetConsoleMode failed (is stdin a console?)"
|
||||
}
|
||||
}
|
||||
|
||||
$oldMode = GetConsoleMode
|
||||
$newMode = $oldMode
|
||||
$doingSomething = $false
|
||||
|
||||
if ($PSBoundParameters.ContainsKey("Mode")) {
|
||||
$newMode = $Mode
|
||||
$doingSomething = $true
|
||||
}
|
||||
|
||||
if ($QuickEdit + $InsertMode -ne "") {
|
||||
if (!($newMode -band $WinAPI::ENABLE_EXTENDED_FLAGS)) {
|
||||
# We can't enable an extended flag without overwriting the existing
|
||||
# QuickEdit/InsertMode flags. AFAICT, there is no way to query their
|
||||
# existing values, so at least we can choose sensible defaults.
|
||||
$newMode = $newMode -bor $WinAPI::ENABLE_EXTENDED_FLAGS
|
||||
$newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE
|
||||
$newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE
|
||||
$doingSomething = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($QuickEdit -eq "on") {
|
||||
$newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE
|
||||
$doingSomething = $true
|
||||
} elseif ($QuickEdit -eq "off") {
|
||||
$newMode = $newMode -band (-bnot $WinAPI::ENABLE_QUICK_EDIT_MODE)
|
||||
$doingSomething = $true
|
||||
}
|
||||
|
||||
if ($InsertMode -eq "on") {
|
||||
$newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE
|
||||
$doingSomething = $true
|
||||
} elseif ($InsertMode -eq "off") {
|
||||
$newMode = $newMode -band (-bnot $WinAPI::ENABLE_INSERT_MODE)
|
||||
$doingSomething = $true
|
||||
}
|
||||
|
||||
if ($doingSomething) {
|
||||
echo "old mode: $oldMode"
|
||||
SetConsoleMode $newMode
|
||||
$newMode = GetConsoleMode
|
||||
echo "new mode: $newMode"
|
||||
} else {
|
||||
echo "mode: $oldMode"
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static HANDLE getConout() {
|
||||
HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (conout == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "error: cannot get stdout\n");
|
||||
exit(1);
|
||||
}
|
||||
return conout;
|
||||
}
|
||||
|
||||
static DWORD getConsoleMode() {
|
||||
DWORD mode = 0;
|
||||
if (!GetConsoleMode(getConout(), &mode)) {
|
||||
fprintf(stderr, "error: GetConsoleMode failed (is stdout a console?)\n");
|
||||
exit(1);
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
static void setConsoleMode(DWORD mode) {
|
||||
if (!SetConsoleMode(getConout(), mode)) {
|
||||
fprintf(stderr, "error: SetConsoleMode failed (is stdout a console?)\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static long parseInt(const std::string &s) {
|
||||
errno = 0;
|
||||
char *endptr = nullptr;
|
||||
long result = strtol(s.c_str(), &endptr, 0);
|
||||
if (errno != 0 || !endptr || *endptr != '\0') {
|
||||
fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str());
|
||||
exit(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
printf("Usage: ConoutMode [verb] [options]\n");
|
||||
printf("Verbs:\n");
|
||||
printf(" [info] Dumps info about mode flags.\n");
|
||||
printf(" get Prints the mode DWORD.\n");
|
||||
printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n");
|
||||
printf(" set VALUE MASK\n");
|
||||
printf(" Same as `set VALUE`, but only alters the bits in MASK.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct {
|
||||
const char *name;
|
||||
DWORD value;
|
||||
} kOutputFlags[] = {
|
||||
"ENABLE_PROCESSED_OUTPUT", ENABLE_PROCESSED_OUTPUT, // 0x0001
|
||||
"ENABLE_WRAP_AT_EOL_OUTPUT", ENABLE_WRAP_AT_EOL_OUTPUT, // 0x0002
|
||||
"ENABLE_VIRTUAL_TERMINAL_PROCESSING", 0x0004/*ENABLE_VIRTUAL_TERMINAL_PROCESSING*/, // 0x0004
|
||||
"DISABLE_NEWLINE_AUTO_RETURN", 0x0008/*DISABLE_NEWLINE_AUTO_RETURN*/, // 0x0008
|
||||
"ENABLE_LVB_GRID_WORLDWIDE", 0x0010/*ENABLE_LVB_GRID_WORLDWIDE*/, //0x0010
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::vector<std::string> args;
|
||||
for (size_t i = 1; i < argc; ++i) {
|
||||
args.push_back(argv[i]);
|
||||
}
|
||||
|
||||
if (args.empty() || args.size() == 1 && args[0] == "info") {
|
||||
DWORD mode = getConsoleMode();
|
||||
printf("mode: 0x%lx\n", mode);
|
||||
for (const auto &flag : kOutputFlags) {
|
||||
printf("%-34s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off");
|
||||
mode &= ~flag.value;
|
||||
}
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if (mode & (1u << i)) {
|
||||
printf("Unrecognized flag: %04x\n", (1u << i));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto verb = args[0];
|
||||
|
||||
if (verb == "set") {
|
||||
if (args.size() == 2) {
|
||||
const DWORD newMode = parseInt(args[1]);
|
||||
setConsoleMode(newMode);
|
||||
} else if (args.size() == 3) {
|
||||
const DWORD mode = parseInt(args[1]);
|
||||
const DWORD mask = parseInt(args[2]);
|
||||
const int newMode = (getConsoleMode() & ~mask) | (mode & mask);
|
||||
setConsoleMode(newMode);
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
} else if (verb == "get") {
|
||||
if (args.size() != 1) {
|
||||
usage();
|
||||
}
|
||||
printf("0x%lx\n", getConsoleMode());
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
0
misc/DebugClient.py
Executable file → Normal file
0
misc/DebugClient.py
Executable file → Normal file
0
misc/DebugServer.py
Executable file → Normal file
0
misc/DebugServer.py
Executable file → Normal file
@ -1,46 +0,0 @@
|
||||
Note regarding ENABLE_EXTENDED_FLAGS (2016-05-30)
|
||||
|
||||
There is a complicated interaction between the ENABLE_EXTENDED_FLAGS flag
|
||||
and the ENABLE_QUICK_EDIT_MODE and ENABLE_INSERT_MODE flags (presumably for
|
||||
backwards compatibility?). I studied the behavior on Windows 7 and Windows
|
||||
10, with both the old and new consoles, and I didn't see any differences
|
||||
between versions. Here's what I seemed to observe:
|
||||
|
||||
- The console has three flags internally:
|
||||
- QuickEdit
|
||||
- InsertMode
|
||||
- ExtendedFlags
|
||||
|
||||
- SetConsoleMode psuedocode:
|
||||
void SetConsoleMode(..., DWORD mode) {
|
||||
ExtendedFlags = (mode & (ENABLE_EXTENDED_FLAGS
|
||||
| ENABLE_QUICK_EDIT_MODE
|
||||
| ENABLE_INSERT_MODE )) != 0;
|
||||
if (ExtendedFlags) {
|
||||
QuickEdit = (mode & ENABLE_QUICK_EDIT_MODE) != 0;
|
||||
InsertMode = (mode & ENABLE_INSERT_MODE) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
- Setting QuickEdit or InsertMode from the properties dialog GUI does not
|
||||
affect the ExtendedFlags setting -- it simply toggles the one flag.
|
||||
|
||||
- GetConsoleMode psuedocode:
|
||||
GetConsoleMode(..., DWORD *result) {
|
||||
if (ExtendedFlags) {
|
||||
*result |= ENABLE_EXTENDED_FLAGS;
|
||||
if (QuickEdit) { *result |= ENABLE_QUICK_EDIT_MODE; }
|
||||
if (InsertMode) { *result |= ENABLE_INSERT_MODE; }
|
||||
}
|
||||
}
|
||||
|
||||
Effectively, the ExtendedFlags flags controls whether the other two flags
|
||||
are visible/controlled by the user application. If they aren't visible,
|
||||
though, there is no way for the user application to make them visible,
|
||||
except by overwriting their values! Calling SetConsoleMode with just
|
||||
ENABLE_EXTENDED_FLAGS would clear the extended flags we want to read.
|
||||
|
||||
Consequently, if a program temporarily alters the QuickEdit flag (e.g. to
|
||||
enable mouse input), it cannot restore the original values of the QuickEdit
|
||||
and InsertMode flags, UNLESS every other console program cooperates by
|
||||
keeping the ExtendedFlags flag set.
|
@ -1,528 +0,0 @@
|
||||
==================================
|
||||
Code Page 437, Consolas font
|
||||
==================================
|
||||
|
||||
Options: -face "Consolas" -family 0x36
|
||||
Chars: A2 A3 2014 3044 30FC 4000
|
||||
|
||||
FontSurvey "-face \"Consolas\" -family 0x36"
|
||||
|
||||
Windows 7
|
||||
---------
|
||||
|
||||
Size 1: 1,3 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 1,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 2,5 BAD (HHHHHH)
|
||||
Size 6: 3,6 BAD (HHHHHH)
|
||||
Size 7: 3,6 BAD (HHHHHH)
|
||||
Size 8: 4,8 BAD (HHHHHH)
|
||||
Size 9: 4,9 BAD (HHHHHH)
|
||||
Size 10: 5,10 BAD (HHHHHH)
|
||||
Size 11: 5,11 BAD (HHHHHH)
|
||||
Size 12: 6,12 BAD (HHHHHH)
|
||||
Size 13: 6,13 BAD (HHHHHH)
|
||||
Size 14: 7,14 BAD (HHHHHH)
|
||||
Size 15: 7,15 BAD (HHHHHH)
|
||||
Size 16: 8,16 BAD (HHHHHH)
|
||||
Size 17: 8,17 BAD (HHHHHH)
|
||||
Size 18: 8,18 BAD (HHHHHH)
|
||||
Size 19: 9,19 BAD (HHHHHH)
|
||||
Size 20: 9,20 BAD (HHHHHH)
|
||||
Size 21: 10,22 BAD (HHHHHH)
|
||||
Size 22: 10,22 BAD (HHHHHH)
|
||||
Size 23: 11,23 BAD (HHHHHH)
|
||||
Size 24: 11,24 BAD (HHHHHH)
|
||||
Size 25: 12,25 BAD (HHHHHH)
|
||||
Size 26: 12,26 BAD (HHHHHH)
|
||||
Size 27: 13,27 BAD (HHHHHH)
|
||||
Size 28: 13,28 BAD (HHHHHH)
|
||||
Size 29: 14,29 BAD (HHHHHH)
|
||||
Size 30: 14,30 BAD (HHHHHH)
|
||||
Size 31: 15,31 BAD (HHHHHH)
|
||||
Size 32: 15,32 BAD (HHHHHH)
|
||||
Size 33: 15,33 BAD (HHHHHH)
|
||||
Size 34: 16,34 BAD (HHHHHH)
|
||||
Size 35: 16,36 BAD (HHHHHH)
|
||||
Size 36: 17,36 BAD (HHHHHH)
|
||||
Size 37: 17,37 BAD (HHHHHH)
|
||||
Size 38: 18,38 BAD (HHHHHH)
|
||||
Size 39: 18,39 BAD (HHHHHH)
|
||||
Size 40: 19,40 BAD (HHHHHH)
|
||||
Size 41: 19,41 BAD (HHHHHH)
|
||||
Size 42: 20,42 BAD (HHHHHH)
|
||||
Size 43: 20,43 BAD (HHHHHH)
|
||||
Size 44: 21,44 BAD (HHHHHH)
|
||||
Size 45: 21,45 BAD (HHHHHH)
|
||||
Size 46: 22,46 BAD (HHHHHH)
|
||||
Size 47: 22,47 BAD (HHHHHH)
|
||||
Size 48: 23,48 BAD (HHHHHH)
|
||||
Size 49: 23,49 BAD (HHHHHH)
|
||||
Size 50: 23,50 BAD (HHHHHH)
|
||||
Size 51: 24,51 BAD (HHHHHH)
|
||||
Size 52: 24,52 BAD (HHHHHH)
|
||||
Size 53: 25,53 BAD (HHHHHH)
|
||||
Size 54: 25,54 BAD (HHHHHH)
|
||||
Size 55: 26,55 BAD (HHHHHH)
|
||||
Size 56: 26,56 BAD (HHHHHH)
|
||||
Size 57: 27,57 BAD (HHHHHH)
|
||||
Size 58: 27,58 BAD (HHHHHH)
|
||||
Size 59: 28,59 BAD (HHHHHH)
|
||||
Size 60: 28,60 BAD (HHHHHH)
|
||||
Size 61: 29,61 BAD (HHHHHH)
|
||||
Size 62: 29,62 BAD (HHHHHH)
|
||||
Size 63: 30,64 BAD (HHHHHH)
|
||||
Size 64: 30,64 BAD (HHHHHH)
|
||||
Size 65: 31,65 BAD (HHHHHH)
|
||||
Size 66: 31,66 BAD (HHHHHH)
|
||||
Size 67: 31,67 BAD (HHHHHH)
|
||||
Size 68: 32,68 BAD (HHHHHH)
|
||||
Size 69: 32,69 BAD (HHHHHH)
|
||||
Size 70: 33,70 BAD (HHHHHH)
|
||||
Size 71: 33,71 BAD (HHHHHH)
|
||||
Size 72: 34,72 BAD (HHHHHH)
|
||||
Size 73: 34,73 BAD (HHHHHH)
|
||||
Size 74: 35,74 BAD (HHHHHH)
|
||||
Size 75: 35,75 BAD (HHHHHH)
|
||||
Size 76: 36,76 BAD (HHHHHH)
|
||||
Size 77: 36,77 BAD (HHHHHH)
|
||||
Size 78: 37,78 BAD (HHHHHH)
|
||||
Size 79: 37,79 BAD (HHHHHH)
|
||||
Size 80: 38,80 BAD (HHHHHH)
|
||||
Size 81: 38,81 BAD (HHHHHH)
|
||||
Size 82: 39,82 BAD (HHHHHH)
|
||||
Size 83: 39,83 BAD (HHHHHH)
|
||||
Size 84: 39,84 BAD (HHHHHH)
|
||||
Size 85: 40,85 BAD (HHHHHH)
|
||||
Size 86: 40,86 BAD (HHHHHH)
|
||||
Size 87: 41,87 BAD (HHHHHH)
|
||||
Size 88: 41,88 BAD (HHHHHH)
|
||||
Size 89: 42,89 BAD (HHHHHH)
|
||||
Size 90: 42,90 BAD (HHHHHH)
|
||||
Size 91: 43,91 BAD (HHHHHH)
|
||||
Size 92: 43,92 BAD (HHHHHH)
|
||||
Size 93: 44,93 BAD (HHHHHH)
|
||||
Size 94: 44,94 BAD (HHHHHH)
|
||||
Size 95: 45,95 BAD (HHHHHH)
|
||||
Size 96: 45,96 BAD (HHHHHH)
|
||||
Size 97: 46,97 BAD (HHHHHH)
|
||||
Size 98: 46,98 BAD (HHHHHH)
|
||||
Size 99: 46,99 BAD (HHHHHH)
|
||||
Size 100: 47,100 BAD (HHHHHH)
|
||||
|
||||
Windows 8
|
||||
---------
|
||||
|
||||
Size 1: 1,3 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 1,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 2,5 BAD (HHHHHH)
|
||||
Size 6: 3,6 BAD (HHHHHH)
|
||||
Size 7: 3,6 BAD (HHHHHH)
|
||||
Size 8: 4,8 BAD (HHHHHH)
|
||||
Size 9: 4,9 BAD (HHHHHH)
|
||||
Size 10: 5,10 BAD (HHHHHH)
|
||||
Size 11: 5,11 BAD (HHHHHH)
|
||||
Size 12: 6,12 BAD (HHHHHH)
|
||||
Size 13: 6,13 BAD (HHHHHH)
|
||||
Size 14: 7,14 BAD (HHHHHH)
|
||||
Size 15: 7,15 BAD (HHHHHH)
|
||||
Size 16: 8,16 BAD (HHHHHH)
|
||||
Size 17: 8,17 BAD (HHHHHH)
|
||||
Size 18: 8,18 BAD (HHHHHH)
|
||||
Size 19: 9,19 BAD (HHHHHH)
|
||||
Size 20: 9,20 BAD (HHHHHH)
|
||||
Size 21: 10,22 BAD (HHHHHH)
|
||||
Size 22: 10,22 BAD (HHHHHH)
|
||||
Size 23: 11,23 BAD (HHHHHH)
|
||||
Size 24: 11,24 BAD (HHHHHH)
|
||||
Size 25: 12,25 BAD (HHHHHH)
|
||||
Size 26: 12,26 BAD (HHHHHH)
|
||||
Size 27: 13,27 BAD (HHHHHH)
|
||||
Size 28: 13,28 BAD (HHHHHH)
|
||||
Size 29: 14,29 BAD (HHHHHH)
|
||||
Size 30: 14,30 BAD (HHHHHH)
|
||||
Size 31: 15,31 BAD (HHHHHH)
|
||||
Size 32: 15,32 BAD (HHHHHH)
|
||||
Size 33: 15,33 BAD (HHHHHH)
|
||||
Size 34: 16,34 BAD (HHHHHH)
|
||||
Size 35: 16,36 BAD (HHHHHH)
|
||||
Size 36: 17,36 BAD (HHHHHH)
|
||||
Size 37: 17,37 BAD (HHHHHH)
|
||||
Size 38: 18,38 BAD (HHHHHH)
|
||||
Size 39: 18,39 BAD (HHHHHH)
|
||||
Size 40: 19,40 BAD (HHHHHH)
|
||||
Size 41: 19,41 BAD (HHHHHH)
|
||||
Size 42: 20,42 BAD (HHHHHH)
|
||||
Size 43: 20,43 BAD (HHHHHH)
|
||||
Size 44: 21,44 BAD (HHHHHH)
|
||||
Size 45: 21,45 BAD (HHHHHH)
|
||||
Size 46: 22,46 BAD (HHHHHH)
|
||||
Size 47: 22,47 BAD (HHHHHH)
|
||||
Size 48: 23,48 BAD (HHHHHH)
|
||||
Size 49: 23,49 BAD (HHHHHH)
|
||||
Size 50: 23,50 BAD (HHHHHH)
|
||||
Size 51: 24,51 BAD (HHHHHH)
|
||||
Size 52: 24,52 BAD (HHHHHH)
|
||||
Size 53: 25,53 BAD (HHHHHH)
|
||||
Size 54: 25,54 BAD (HHHHHH)
|
||||
Size 55: 26,55 BAD (HHHHHH)
|
||||
Size 56: 26,56 BAD (HHHHHH)
|
||||
Size 57: 27,57 BAD (HHHHHH)
|
||||
Size 58: 27,58 BAD (HHHHHH)
|
||||
Size 59: 28,59 BAD (HHHHHH)
|
||||
Size 60: 28,60 BAD (HHHHHH)
|
||||
Size 61: 29,61 BAD (HHHHHH)
|
||||
Size 62: 29,62 BAD (HHHHHH)
|
||||
Size 63: 30,64 BAD (HHHHHH)
|
||||
Size 64: 30,64 BAD (HHHHHH)
|
||||
Size 65: 31,65 BAD (HHHHHH)
|
||||
Size 66: 31,66 BAD (HHHHHH)
|
||||
Size 67: 31,67 BAD (HHHHHH)
|
||||
Size 68: 32,68 BAD (HHHHHH)
|
||||
Size 69: 32,69 BAD (HHHHHH)
|
||||
Size 70: 33,70 BAD (HHHHHH)
|
||||
Size 71: 33,71 BAD (HHHHHH)
|
||||
Size 72: 34,72 BAD (HHHHHH)
|
||||
Size 73: 34,73 BAD (HHHHHH)
|
||||
Size 74: 35,74 BAD (HHHHHH)
|
||||
Size 75: 35,75 BAD (HHHHHH)
|
||||
Size 76: 36,76 BAD (HHHHHH)
|
||||
Size 77: 36,77 BAD (HHHHHH)
|
||||
Size 78: 37,78 BAD (HHHHHH)
|
||||
Size 79: 37,79 BAD (HHHHHH)
|
||||
Size 80: 38,80 BAD (HHHHHH)
|
||||
Size 81: 38,81 BAD (HHHHHH)
|
||||
Size 82: 39,82 BAD (HHHHHH)
|
||||
Size 83: 39,83 BAD (HHHHHH)
|
||||
Size 84: 39,84 BAD (HHHHHH)
|
||||
Size 85: 40,85 BAD (HHHHHH)
|
||||
Size 86: 40,86 BAD (HHHHHH)
|
||||
Size 87: 41,87 BAD (HHHHHH)
|
||||
Size 88: 41,88 BAD (HHHHHH)
|
||||
Size 89: 42,89 BAD (HHHHHH)
|
||||
Size 90: 42,90 BAD (HHHHHH)
|
||||
Size 91: 43,91 BAD (HHHHHH)
|
||||
Size 92: 43,92 BAD (HHHHHH)
|
||||
Size 93: 44,93 BAD (HHHHHH)
|
||||
Size 94: 44,94 BAD (HHHHHH)
|
||||
Size 95: 45,95 BAD (HHHHHH)
|
||||
Size 96: 45,96 BAD (HHHHHH)
|
||||
Size 97: 46,97 BAD (HHHHHH)
|
||||
Size 98: 46,98 BAD (HHHHHH)
|
||||
Size 99: 46,99 BAD (HHHHHH)
|
||||
Size 100: 47,100 BAD (HHHHHH)
|
||||
|
||||
Windows 8.1
|
||||
-----------
|
||||
|
||||
Size 1: 1,3 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 1,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 2,5 BAD (HHHHHH)
|
||||
Size 6: 3,6 BAD (HHHHHH)
|
||||
Size 7: 3,6 BAD (HHHHHH)
|
||||
Size 8: 4,8 BAD (HHHHHH)
|
||||
Size 9: 4,9 BAD (HHHHHH)
|
||||
Size 10: 5,10 BAD (HHHHHH)
|
||||
Size 11: 5,11 BAD (HHHHHH)
|
||||
Size 12: 6,12 BAD (HHHHHH)
|
||||
Size 13: 6,13 BAD (HHHHHH)
|
||||
Size 14: 7,14 BAD (HHHHHH)
|
||||
Size 15: 7,15 BAD (HHHHHH)
|
||||
Size 16: 8,16 BAD (HHHHHH)
|
||||
Size 17: 8,17 BAD (HHHHHH)
|
||||
Size 18: 8,18 BAD (HHHHHH)
|
||||
Size 19: 9,19 BAD (HHHHHH)
|
||||
Size 20: 9,20 BAD (HHHHHH)
|
||||
Size 21: 10,22 BAD (HHHHHH)
|
||||
Size 22: 10,22 BAD (HHHHHH)
|
||||
Size 23: 11,23 BAD (HHHHHH)
|
||||
Size 24: 11,24 BAD (HHHHHH)
|
||||
Size 25: 12,25 BAD (HHHHHH)
|
||||
Size 26: 12,26 BAD (HHHHHH)
|
||||
Size 27: 13,27 BAD (HHHHHH)
|
||||
Size 28: 13,28 BAD (HHHHHH)
|
||||
Size 29: 14,29 BAD (HHHHHH)
|
||||
Size 30: 14,30 BAD (HHHHHH)
|
||||
Size 31: 15,31 BAD (HHHHHH)
|
||||
Size 32: 15,32 BAD (HHHHHH)
|
||||
Size 33: 15,33 BAD (HHHHHH)
|
||||
Size 34: 16,34 BAD (HHHHHH)
|
||||
Size 35: 16,36 BAD (HHHHHH)
|
||||
Size 36: 17,36 BAD (HHHHHH)
|
||||
Size 37: 17,37 BAD (HHHHHH)
|
||||
Size 38: 18,38 BAD (HHHHHH)
|
||||
Size 39: 18,39 BAD (HHHHHH)
|
||||
Size 40: 19,40 BAD (HHHHHH)
|
||||
Size 41: 19,41 BAD (HHHHHH)
|
||||
Size 42: 20,42 BAD (HHHHHH)
|
||||
Size 43: 20,43 BAD (HHHHHH)
|
||||
Size 44: 21,44 BAD (HHHHHH)
|
||||
Size 45: 21,45 BAD (HHHHHH)
|
||||
Size 46: 22,46 BAD (HHHHHH)
|
||||
Size 47: 22,47 BAD (HHHHHH)
|
||||
Size 48: 23,48 BAD (HHHHHH)
|
||||
Size 49: 23,49 BAD (HHHHHH)
|
||||
Size 50: 23,50 BAD (HHHHHH)
|
||||
Size 51: 24,51 BAD (HHHHHH)
|
||||
Size 52: 24,52 BAD (HHHHHH)
|
||||
Size 53: 25,53 BAD (HHHHHH)
|
||||
Size 54: 25,54 BAD (HHHHHH)
|
||||
Size 55: 26,55 BAD (HHHHHH)
|
||||
Size 56: 26,56 BAD (HHHHHH)
|
||||
Size 57: 27,57 BAD (HHHHHH)
|
||||
Size 58: 27,58 BAD (HHHHHH)
|
||||
Size 59: 28,59 BAD (HHHHHH)
|
||||
Size 60: 28,60 BAD (HHHHHH)
|
||||
Size 61: 29,61 BAD (HHHHHH)
|
||||
Size 62: 29,62 BAD (HHHHHH)
|
||||
Size 63: 30,64 BAD (HHHHHH)
|
||||
Size 64: 30,64 BAD (HHHHHH)
|
||||
Size 65: 31,65 BAD (HHHHHH)
|
||||
Size 66: 31,66 BAD (HHHHHH)
|
||||
Size 67: 31,67 BAD (HHHHHH)
|
||||
Size 68: 32,68 BAD (HHHHHH)
|
||||
Size 69: 32,69 BAD (HHHHHH)
|
||||
Size 70: 33,70 BAD (HHHHHH)
|
||||
Size 71: 33,71 BAD (HHHHHH)
|
||||
Size 72: 34,72 BAD (HHHHHH)
|
||||
Size 73: 34,73 BAD (HHHHHH)
|
||||
Size 74: 35,74 BAD (HHHHHH)
|
||||
Size 75: 35,75 BAD (HHHHHH)
|
||||
Size 76: 36,76 BAD (HHHHHH)
|
||||
Size 77: 36,77 BAD (HHHHHH)
|
||||
Size 78: 37,78 BAD (HHHHHH)
|
||||
Size 79: 37,79 BAD (HHHHHH)
|
||||
Size 80: 38,80 BAD (HHHHHH)
|
||||
Size 81: 38,81 BAD (HHHHHH)
|
||||
Size 82: 39,82 BAD (HHHHHH)
|
||||
Size 83: 39,83 BAD (HHHHHH)
|
||||
Size 84: 39,84 BAD (HHHHHH)
|
||||
Size 85: 40,85 BAD (HHHHHH)
|
||||
Size 86: 40,86 BAD (HHHHHH)
|
||||
Size 87: 41,87 BAD (HHHHHH)
|
||||
Size 88: 41,88 BAD (HHHHHH)
|
||||
Size 89: 42,89 BAD (HHHHHH)
|
||||
Size 90: 42,90 BAD (HHHHHH)
|
||||
Size 91: 43,91 BAD (HHHHHH)
|
||||
Size 92: 43,92 BAD (HHHHHH)
|
||||
Size 93: 44,93 BAD (HHHHHH)
|
||||
Size 94: 44,94 BAD (HHHHHH)
|
||||
Size 95: 45,95 BAD (HHHHHH)
|
||||
Size 96: 45,96 BAD (HHHHHH)
|
||||
Size 97: 46,97 BAD (HHHHHH)
|
||||
Size 98: 46,98 BAD (HHHHHH)
|
||||
Size 99: 46,99 BAD (HHHHHH)
|
||||
Size 100: 47,100 BAD (HHHHHH)
|
||||
|
||||
Windows 10 14342 Old Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,3 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 1,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 2,5 BAD (HHHHHH)
|
||||
Size 6: 3,6 BAD (HHHHHH)
|
||||
Size 7: 3,6 BAD (HHHHHH)
|
||||
Size 8: 4,8 BAD (HHHHHH)
|
||||
Size 9: 4,9 BAD (HHHHHH)
|
||||
Size 10: 5,10 BAD (HHHHHH)
|
||||
Size 11: 5,11 BAD (HHHHHH)
|
||||
Size 12: 6,12 BAD (HHHHHH)
|
||||
Size 13: 6,13 BAD (HHHHHH)
|
||||
Size 14: 7,14 BAD (HHHHHH)
|
||||
Size 15: 7,15 BAD (HHHHHH)
|
||||
Size 16: 8,16 BAD (HHHHHH)
|
||||
Size 17: 8,17 BAD (HHHHHH)
|
||||
Size 18: 8,18 BAD (HHHHHH)
|
||||
Size 19: 9,19 BAD (HHHHHH)
|
||||
Size 20: 9,20 BAD (HHHHHH)
|
||||
Size 21: 10,22 BAD (HHHHHH)
|
||||
Size 22: 10,22 BAD (HHHHHH)
|
||||
Size 23: 11,23 BAD (HHHHHH)
|
||||
Size 24: 11,24 BAD (HHHHHH)
|
||||
Size 25: 12,25 BAD (HHHHHH)
|
||||
Size 26: 12,26 BAD (HHHHHH)
|
||||
Size 27: 13,27 BAD (HHHHHH)
|
||||
Size 28: 13,28 BAD (HHHHHH)
|
||||
Size 29: 14,29 BAD (HHHHHH)
|
||||
Size 30: 14,30 BAD (HHHHHH)
|
||||
Size 31: 15,31 BAD (HHHHHH)
|
||||
Size 32: 15,32 BAD (HHHHHH)
|
||||
Size 33: 15,33 BAD (HHHHHH)
|
||||
Size 34: 16,34 BAD (HHHHHH)
|
||||
Size 35: 16,36 BAD (HHHHHH)
|
||||
Size 36: 17,36 BAD (HHHHHH)
|
||||
Size 37: 17,37 BAD (HHHHHH)
|
||||
Size 38: 18,38 BAD (HHHHHH)
|
||||
Size 39: 18,39 BAD (HHHHHH)
|
||||
Size 40: 19,40 BAD (HHHHHH)
|
||||
Size 41: 19,41 BAD (HHHHHH)
|
||||
Size 42: 20,42 BAD (HHHHHH)
|
||||
Size 43: 20,43 BAD (HHHHHH)
|
||||
Size 44: 21,44 BAD (HHHHHH)
|
||||
Size 45: 21,45 BAD (HHHHHH)
|
||||
Size 46: 22,46 BAD (HHHHHH)
|
||||
Size 47: 22,47 BAD (HHHHHH)
|
||||
Size 48: 23,48 BAD (HHHHHH)
|
||||
Size 49: 23,49 BAD (HHHHHH)
|
||||
Size 50: 23,50 BAD (HHHHHH)
|
||||
Size 51: 24,51 BAD (HHHHHH)
|
||||
Size 52: 24,52 BAD (HHHHHH)
|
||||
Size 53: 25,53 BAD (HHHHHH)
|
||||
Size 54: 25,54 BAD (HHHHHH)
|
||||
Size 55: 26,55 BAD (HHHHHH)
|
||||
Size 56: 26,56 BAD (HHHHHH)
|
||||
Size 57: 27,57 BAD (HHHHHH)
|
||||
Size 58: 27,58 BAD (HHHHHH)
|
||||
Size 59: 28,59 BAD (HHHHHH)
|
||||
Size 60: 28,60 BAD (HHHHHH)
|
||||
Size 61: 29,61 BAD (HHHHHH)
|
||||
Size 62: 29,62 BAD (HHHHHH)
|
||||
Size 63: 30,64 BAD (HHHHHH)
|
||||
Size 64: 30,64 BAD (HHHHHH)
|
||||
Size 65: 31,65 BAD (HHHHHH)
|
||||
Size 66: 31,66 BAD (HHHHHH)
|
||||
Size 67: 31,67 BAD (HHHHHH)
|
||||
Size 68: 32,68 BAD (HHHHHH)
|
||||
Size 69: 32,69 BAD (HHHHHH)
|
||||
Size 70: 33,70 BAD (HHHHHH)
|
||||
Size 71: 33,71 BAD (HHHHHH)
|
||||
Size 72: 34,72 BAD (HHHHHH)
|
||||
Size 73: 34,73 BAD (HHHHHH)
|
||||
Size 74: 35,74 BAD (HHHHHH)
|
||||
Size 75: 35,75 BAD (HHHHHH)
|
||||
Size 76: 36,76 BAD (HHHHHH)
|
||||
Size 77: 36,77 BAD (HHHHHH)
|
||||
Size 78: 37,78 BAD (HHHHHH)
|
||||
Size 79: 37,79 BAD (HHHHHH)
|
||||
Size 80: 38,80 BAD (HHHHHH)
|
||||
Size 81: 38,81 BAD (HHHHHH)
|
||||
Size 82: 39,82 BAD (HHHHHH)
|
||||
Size 83: 39,83 BAD (HHHHHH)
|
||||
Size 84: 39,84 BAD (HHHHHH)
|
||||
Size 85: 40,85 BAD (HHHHHH)
|
||||
Size 86: 40,86 BAD (HHHHHH)
|
||||
Size 87: 41,87 BAD (HHHHHH)
|
||||
Size 88: 41,88 BAD (HHHHHH)
|
||||
Size 89: 42,89 BAD (HHHHHH)
|
||||
Size 90: 42,90 BAD (HHHHHH)
|
||||
Size 91: 43,91 BAD (HHHHHH)
|
||||
Size 92: 43,92 BAD (HHHHHH)
|
||||
Size 93: 44,93 BAD (HHHHHH)
|
||||
Size 94: 44,94 BAD (HHHHHH)
|
||||
Size 95: 45,95 BAD (HHHHHH)
|
||||
Size 96: 45,96 BAD (HHHHHH)
|
||||
Size 97: 46,97 BAD (HHHHHH)
|
||||
Size 98: 46,98 BAD (HHHHHH)
|
||||
Size 99: 46,99 BAD (HHHHHH)
|
||||
Size 100: 47,100 BAD (HHHHHH)
|
||||
|
||||
Windows 10 14342 New Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,1 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 1,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 2,5 BAD (HHHHHH)
|
||||
Size 6: 3,6 BAD (HHHHHH)
|
||||
Size 7: 3,7 BAD (HHHHHH)
|
||||
Size 8: 4,8 BAD (HHHHHH)
|
||||
Size 9: 4,9 BAD (HHHHHH)
|
||||
Size 10: 5,10 BAD (HHHHHH)
|
||||
Size 11: 5,11 BAD (HHHHHH)
|
||||
Size 12: 6,12 BAD (HHHHHH)
|
||||
Size 13: 6,13 BAD (HHHHHH)
|
||||
Size 14: 7,14 BAD (HHHHHH)
|
||||
Size 15: 7,15 BAD (HHHHHH)
|
||||
Size 16: 8,16 BAD (HHHHHH)
|
||||
Size 17: 8,17 BAD (HHHHHH)
|
||||
Size 18: 8,18 BAD (HHHHHH)
|
||||
Size 19: 9,19 BAD (HHHHHH)
|
||||
Size 20: 9,20 BAD (HHHHHH)
|
||||
Size 21: 10,21 BAD (HHHHHH)
|
||||
Size 22: 10,22 BAD (HHHHHH)
|
||||
Size 23: 11,23 BAD (HHHHHH)
|
||||
Size 24: 11,24 BAD (HHHHHH)
|
||||
Size 25: 12,25 BAD (HHHHHH)
|
||||
Size 26: 12,26 BAD (HHHHHH)
|
||||
Size 27: 13,27 BAD (HHHHHH)
|
||||
Size 28: 13,28 BAD (HHHHHH)
|
||||
Size 29: 14,29 BAD (HHHHHH)
|
||||
Size 30: 14,30 BAD (HHHHHH)
|
||||
Size 31: 15,31 BAD (HHHHHH)
|
||||
Size 32: 15,32 BAD (HHHHHH)
|
||||
Size 33: 15,33 BAD (HHHHHH)
|
||||
Size 34: 16,34 BAD (HHHHHH)
|
||||
Size 35: 16,35 BAD (HHHHHH)
|
||||
Size 36: 17,36 BAD (HHHHHH)
|
||||
Size 37: 17,37 BAD (HHHHHH)
|
||||
Size 38: 18,38 BAD (HHHHHH)
|
||||
Size 39: 18,39 BAD (HHHHHH)
|
||||
Size 40: 19,40 BAD (HHHHHH)
|
||||
Size 41: 19,41 BAD (HHHHHH)
|
||||
Size 42: 20,42 BAD (HHHHHH)
|
||||
Size 43: 20,43 BAD (HHHHHH)
|
||||
Size 44: 21,44 BAD (HHHHHH)
|
||||
Size 45: 21,45 BAD (HHHHHH)
|
||||
Size 46: 22,46 BAD (HHHHHH)
|
||||
Size 47: 22,47 BAD (HHHHHH)
|
||||
Size 48: 23,48 BAD (HHHHHH)
|
||||
Size 49: 23,49 BAD (HHHHHH)
|
||||
Size 50: 23,50 BAD (HHHHHH)
|
||||
Size 51: 24,51 BAD (HHHHHH)
|
||||
Size 52: 24,52 BAD (HHHHHH)
|
||||
Size 53: 25,53 BAD (HHHHHH)
|
||||
Size 54: 25,54 BAD (HHHHHH)
|
||||
Size 55: 26,55 BAD (HHHHHH)
|
||||
Size 56: 26,56 BAD (HHHHHH)
|
||||
Size 57: 27,57 BAD (HHHHHH)
|
||||
Size 58: 27,58 BAD (HHHHHH)
|
||||
Size 59: 28,59 BAD (HHHHHH)
|
||||
Size 60: 28,60 BAD (HHHHHH)
|
||||
Size 61: 29,61 BAD (HHHHHH)
|
||||
Size 62: 29,62 BAD (HHHHHH)
|
||||
Size 63: 30,63 BAD (HHHHHH)
|
||||
Size 64: 30,64 BAD (HHHHHH)
|
||||
Size 65: 31,65 BAD (HHHHHH)
|
||||
Size 66: 31,66 BAD (HHHHHH)
|
||||
Size 67: 31,67 BAD (HHHHHH)
|
||||
Size 68: 32,68 BAD (HHHHHH)
|
||||
Size 69: 32,69 BAD (HHHHHH)
|
||||
Size 70: 33,70 BAD (HHHHHH)
|
||||
Size 71: 33,71 BAD (HHHHHH)
|
||||
Size 72: 34,72 BAD (HHHHHH)
|
||||
Size 73: 34,73 BAD (HHHHHH)
|
||||
Size 74: 35,74 BAD (HHHHHH)
|
||||
Size 75: 35,75 BAD (HHHHHH)
|
||||
Size 76: 36,76 BAD (HHHHHH)
|
||||
Size 77: 36,77 BAD (HHHHHH)
|
||||
Size 78: 37,78 BAD (HHHHHH)
|
||||
Size 79: 37,79 BAD (HHHHHH)
|
||||
Size 80: 38,80 BAD (HHHHHH)
|
||||
Size 81: 38,81 BAD (HHHHHH)
|
||||
Size 82: 39,82 BAD (HHHHHH)
|
||||
Size 83: 39,83 BAD (HHHHHH)
|
||||
Size 84: 39,84 BAD (HHHHHH)
|
||||
Size 85: 40,85 BAD (HHHHHH)
|
||||
Size 86: 40,86 BAD (HHHHHH)
|
||||
Size 87: 41,87 BAD (HHHHHH)
|
||||
Size 88: 41,88 BAD (HHHHHH)
|
||||
Size 89: 42,89 BAD (HHHHHH)
|
||||
Size 90: 42,90 BAD (HHHHHH)
|
||||
Size 91: 43,91 BAD (HHHHHH)
|
||||
Size 92: 43,92 BAD (HHHHHH)
|
||||
Size 93: 44,93 BAD (HHHHHH)
|
||||
Size 94: 44,94 BAD (HHHHHH)
|
||||
Size 95: 45,95 BAD (HHHHHH)
|
||||
Size 96: 45,96 BAD (HHHHHH)
|
||||
Size 97: 46,97 BAD (HHHHHH)
|
||||
Size 98: 46,98 BAD (HHHHHH)
|
||||
Size 99: 46,99 BAD (HHHHHH)
|
||||
Size 100: 47,100 BAD (HHHHHH)
|
@ -1,633 +0,0 @@
|
||||
==================================
|
||||
Code Page 437, Lucida Console font
|
||||
==================================
|
||||
|
||||
Options: -face "Lucida Console" -family 0x36
|
||||
Chars: A2 A3 2014 3044 30FC 4000
|
||||
|
||||
FontSurvey "-face \"Lucida Console\" -family 0x36"
|
||||
|
||||
Vista
|
||||
-----
|
||||
|
||||
Size 1: 1,2 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 2,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 3,5 BAD (HHHHHH)
|
||||
Size 6: 4,6 BAD (HHHHHH)
|
||||
Size 7: 4,7 BAD (HHHHHH)
|
||||
Size 8: 5,8 BAD (HHHHHH)
|
||||
Size 9: 5,9 BAD (HHHHHH)
|
||||
Size 10: 6,10 BAD (HHHHHH)
|
||||
Size 11: 7,11 BAD (HHHHHH)
|
||||
Size 12: 7,12 BAD (HHHHHH)
|
||||
Size 13: 8,13 BAD (HHHHHH)
|
||||
Size 14: 8,14 BAD (HHHHHH)
|
||||
Size 15: 9,15 BAD (HHHHHH)
|
||||
Size 16: 10,16 BAD (HHHHHH)
|
||||
Size 17: 10,17 BAD (HHHHHH)
|
||||
Size 18: 11,18 BAD (HHHHHH)
|
||||
Size 19: 11,19 BAD (HHHHHH)
|
||||
Size 20: 12,20 BAD (HHHHHH)
|
||||
Size 21: 13,21 BAD (HHHHHH)
|
||||
Size 22: 13,22 BAD (HHHHHH)
|
||||
Size 23: 14,23 BAD (HHHHHH)
|
||||
Size 24: 14,24 BAD (HHHHHH)
|
||||
Size 25: 15,25 BAD (HHHHHH)
|
||||
Size 26: 16,26 BAD (HHHHHH)
|
||||
Size 27: 16,27 BAD (HHHHHH)
|
||||
Size 28: 17,28 BAD (HHHHHH)
|
||||
Size 29: 17,29 BAD (HHHHHH)
|
||||
Size 30: 18,30 BAD (HHHHHH)
|
||||
Size 31: 19,31 BAD (HHHHHH)
|
||||
Size 32: 19,32 BAD (HHHHHH)
|
||||
Size 33: 20,33 BAD (HHHHHH)
|
||||
Size 34: 20,34 BAD (HHHHHH)
|
||||
Size 35: 21,35 BAD (HHHHHH)
|
||||
Size 36: 22,36 BAD (HHHHHH)
|
||||
Size 37: 22,37 BAD (HHHHHH)
|
||||
Size 38: 23,38 BAD (HHHHHH)
|
||||
Size 39: 23,39 BAD (HHHHHH)
|
||||
Size 40: 24,40 BAD (HHHHHH)
|
||||
Size 41: 25,41 BAD (HHHHHH)
|
||||
Size 42: 25,42 BAD (HHHHHH)
|
||||
Size 43: 26,43 BAD (HHHHHH)
|
||||
Size 44: 27,44 BAD (HHHHHH)
|
||||
Size 45: 27,45 BAD (HHHHHH)
|
||||
Size 46: 28,46 BAD (HHHHHH)
|
||||
Size 47: 28,47 BAD (HHHHHH)
|
||||
Size 48: 29,48 BAD (HHHHHH)
|
||||
Size 49: 30,49 BAD (HHHHHH)
|
||||
Size 50: 30,50 BAD (HHHHHH)
|
||||
Size 51: 31,51 BAD (HHHHHH)
|
||||
Size 52: 31,52 BAD (HHHHHH)
|
||||
Size 53: 32,53 BAD (HHHHHH)
|
||||
Size 54: 33,54 BAD (HHHHHH)
|
||||
Size 55: 33,55 BAD (HHHHHH)
|
||||
Size 56: 34,56 BAD (HHHHHH)
|
||||
Size 57: 34,57 BAD (HHHHHH)
|
||||
Size 58: 35,58 BAD (HHHHHH)
|
||||
Size 59: 36,59 BAD (HHHHHH)
|
||||
Size 60: 36,60 BAD (HHHHHH)
|
||||
Size 61: 37,61 BAD (HHHHHH)
|
||||
Size 62: 37,62 BAD (HHHHHH)
|
||||
Size 63: 38,63 BAD (HHHHHH)
|
||||
Size 64: 39,65 BAD (HHHHHH)
|
||||
Size 65: 39,65 BAD (HHHHHH)
|
||||
Size 66: 40,66 BAD (HHHHHH)
|
||||
Size 67: 40,67 BAD (HHHHHH)
|
||||
Size 68: 41,68 BAD (HHHHHH)
|
||||
Size 69: 42,69 BAD (HHHHHH)
|
||||
Size 70: 42,70 BAD (HHHHHH)
|
||||
Size 71: 43,71 BAD (HHHHHH)
|
||||
Size 72: 43,72 BAD (HHHHHH)
|
||||
Size 73: 44,73 BAD (HHHHHH)
|
||||
Size 74: 45,74 BAD (HHHHHH)
|
||||
Size 75: 45,75 BAD (HHHHHH)
|
||||
Size 76: 46,76 BAD (HHHHHH)
|
||||
Size 77: 46,77 BAD (HHHHHH)
|
||||
Size 78: 47,78 BAD (HHHHHH)
|
||||
Size 79: 48,79 BAD (HHHHHH)
|
||||
Size 80: 48,80 BAD (HHHHHH)
|
||||
Size 81: 49,81 BAD (HHHHHH)
|
||||
Size 82: 49,82 BAD (HHHHHH)
|
||||
Size 83: 50,83 BAD (HHHHHH)
|
||||
Size 84: 51,84 BAD (HHHHHH)
|
||||
Size 85: 51,85 BAD (HHHHHH)
|
||||
Size 86: 52,86 BAD (HHHHHH)
|
||||
Size 87: 52,87 BAD (HHHHHH)
|
||||
Size 88: 53,88 BAD (HHHHHH)
|
||||
Size 89: 54,89 BAD (HHHHHH)
|
||||
Size 90: 54,90 BAD (HHHHHH)
|
||||
Size 91: 55,91 BAD (HHHHHH)
|
||||
Size 92: 55,92 BAD (HHHHHH)
|
||||
Size 93: 56,93 BAD (HHHHHH)
|
||||
Size 94: 57,94 BAD (HHHHHH)
|
||||
Size 95: 57,95 BAD (HHHHHH)
|
||||
Size 96: 58,96 BAD (HHHHHH)
|
||||
Size 97: 58,97 BAD (HHHHHH)
|
||||
Size 98: 59,98 BAD (HHHHHH)
|
||||
Size 99: 60,99 BAD (HHHHHH)
|
||||
Size 100: 60,100 BAD (HHHHHH)
|
||||
|
||||
|
||||
Windows 7
|
||||
---------
|
||||
|
||||
Size 1: 1,2 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 2,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 3,5 BAD (HHHHHH)
|
||||
Size 6: 4,6 BAD (HHHHHH)
|
||||
Size 7: 4,7 BAD (HHHHHH)
|
||||
Size 8: 5,8 BAD (HHHHHH)
|
||||
Size 9: 5,9 BAD (HHHHHH)
|
||||
Size 10: 6,10 BAD (HHHHHH)
|
||||
Size 11: 7,11 BAD (HHHHHH)
|
||||
Size 12: 7,12 BAD (HHHHHH)
|
||||
Size 13: 8,13 BAD (HHHHHH)
|
||||
Size 14: 8,14 BAD (HHHHHH)
|
||||
Size 15: 9,15 BAD (HHHHHH)
|
||||
Size 16: 10,16 BAD (HHHHHH)
|
||||
Size 17: 10,17 BAD (HHHHHH)
|
||||
Size 18: 11,18 BAD (HHHHHH)
|
||||
Size 19: 11,19 BAD (HHHHHH)
|
||||
Size 20: 12,20 BAD (HHHHHH)
|
||||
Size 21: 13,21 BAD (HHHHHH)
|
||||
Size 22: 13,22 BAD (HHHHHH)
|
||||
Size 23: 14,23 BAD (HHHHHH)
|
||||
Size 24: 14,24 BAD (HHHHHH)
|
||||
Size 25: 15,25 BAD (HHHHHH)
|
||||
Size 26: 16,26 BAD (HHHHHH)
|
||||
Size 27: 16,27 BAD (HHHHHH)
|
||||
Size 28: 17,28 BAD (HHHHHH)
|
||||
Size 29: 17,29 BAD (HHHHHH)
|
||||
Size 30: 18,30 BAD (HHHHHH)
|
||||
Size 31: 19,31 BAD (HHHHHH)
|
||||
Size 32: 19,32 BAD (HHHHHH)
|
||||
Size 33: 20,33 BAD (HHHHHH)
|
||||
Size 34: 20,34 BAD (HHHHHH)
|
||||
Size 35: 21,35 BAD (HHHHHH)
|
||||
Size 36: 22,36 BAD (HHHHHH)
|
||||
Size 37: 22,37 BAD (HHHHHH)
|
||||
Size 38: 23,38 BAD (HHHHHH)
|
||||
Size 39: 23,39 BAD (HHHHHH)
|
||||
Size 40: 24,40 BAD (HHHHHH)
|
||||
Size 41: 25,41 BAD (HHHHHH)
|
||||
Size 42: 25,42 BAD (HHHHHH)
|
||||
Size 43: 26,43 BAD (HHHHHH)
|
||||
Size 44: 27,44 BAD (HHHHHH)
|
||||
Size 45: 27,45 BAD (HHHHHH)
|
||||
Size 46: 28,46 BAD (HHHHHH)
|
||||
Size 47: 28,47 BAD (HHHHHH)
|
||||
Size 48: 29,48 BAD (HHHHHH)
|
||||
Size 49: 30,49 BAD (HHHHHH)
|
||||
Size 50: 30,50 BAD (HHHHHH)
|
||||
Size 51: 31,51 BAD (HHHHHH)
|
||||
Size 52: 31,52 BAD (HHHHHH)
|
||||
Size 53: 32,53 BAD (HHHHHH)
|
||||
Size 54: 33,54 BAD (HHHHHH)
|
||||
Size 55: 33,55 BAD (HHHHHH)
|
||||
Size 56: 34,56 BAD (HHHHHH)
|
||||
Size 57: 34,57 BAD (HHHHHH)
|
||||
Size 58: 35,58 BAD (HHHHHH)
|
||||
Size 59: 36,59 BAD (HHHHHH)
|
||||
Size 60: 36,60 BAD (HHHHHH)
|
||||
Size 61: 37,61 BAD (HHHHHH)
|
||||
Size 62: 37,62 BAD (HHHHHH)
|
||||
Size 63: 38,63 BAD (HHHHHH)
|
||||
Size 64: 39,65 BAD (HHHHHH)
|
||||
Size 65: 39,65 BAD (HHHHHH)
|
||||
Size 66: 40,66 BAD (HHHHHH)
|
||||
Size 67: 40,67 BAD (HHHHHH)
|
||||
Size 68: 41,68 BAD (HHHHHH)
|
||||
Size 69: 42,69 BAD (HHHHHH)
|
||||
Size 70: 42,70 BAD (HHHHHH)
|
||||
Size 71: 43,71 BAD (HHHHHH)
|
||||
Size 72: 43,72 BAD (HHHHHH)
|
||||
Size 73: 44,73 BAD (HHHHHH)
|
||||
Size 74: 45,74 BAD (HHHHHH)
|
||||
Size 75: 45,75 BAD (HHHHHH)
|
||||
Size 76: 46,76 BAD (HHHHHH)
|
||||
Size 77: 46,77 BAD (HHHHHH)
|
||||
Size 78: 47,78 BAD (HHHHHH)
|
||||
Size 79: 48,79 BAD (HHHHHH)
|
||||
Size 80: 48,80 BAD (HHHHHH)
|
||||
Size 81: 49,81 BAD (HHHHHH)
|
||||
Size 82: 49,82 BAD (HHHHHH)
|
||||
Size 83: 50,83 BAD (HHHHHH)
|
||||
Size 84: 51,84 BAD (HHHHHH)
|
||||
Size 85: 51,85 BAD (HHHHHH)
|
||||
Size 86: 52,86 BAD (HHHHHH)
|
||||
Size 87: 52,87 BAD (HHHHHH)
|
||||
Size 88: 53,88 BAD (HHHHHH)
|
||||
Size 89: 54,89 BAD (HHHHHH)
|
||||
Size 90: 54,90 BAD (HHHHHH)
|
||||
Size 91: 55,91 BAD (HHHHHH)
|
||||
Size 92: 55,92 BAD (HHHHHH)
|
||||
Size 93: 56,93 BAD (HHHHHH)
|
||||
Size 94: 57,94 BAD (HHHHHH)
|
||||
Size 95: 57,95 BAD (HHHHHH)
|
||||
Size 96: 58,96 BAD (HHHHHH)
|
||||
Size 97: 58,97 BAD (HHHHHH)
|
||||
Size 98: 59,98 BAD (HHHHHH)
|
||||
Size 99: 60,99 BAD (HHHHHH)
|
||||
Size 100: 60,100 BAD (HHHHHH)
|
||||
|
||||
Windows 8
|
||||
---------
|
||||
|
||||
Size 1: 1,2 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 2,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 3,5 BAD (HHHHHH)
|
||||
Size 6: 4,6 BAD (HHHHHH)
|
||||
Size 7: 4,7 BAD (HHHHHH)
|
||||
Size 8: 5,8 BAD (HHHHHH)
|
||||
Size 9: 5,9 BAD (HHHHHH)
|
||||
Size 10: 6,10 BAD (HHHHHH)
|
||||
Size 11: 7,11 BAD (HHHHHH)
|
||||
Size 12: 7,12 BAD (HHHHHH)
|
||||
Size 13: 8,13 BAD (HHHHHH)
|
||||
Size 14: 8,14 BAD (HHHHHH)
|
||||
Size 15: 9,15 BAD (HHHHHH)
|
||||
Size 16: 10,16 BAD (HHHHHH)
|
||||
Size 17: 10,17 BAD (HHHHHH)
|
||||
Size 18: 11,18 BAD (HHHHHH)
|
||||
Size 19: 11,19 BAD (HHHHHH)
|
||||
Size 20: 12,20 BAD (HHHHHH)
|
||||
Size 21: 13,21 BAD (HHHHHH)
|
||||
Size 22: 13,22 BAD (HHHHHH)
|
||||
Size 23: 14,23 BAD (HHHHHH)
|
||||
Size 24: 14,24 BAD (HHHHHH)
|
||||
Size 25: 15,25 BAD (HHHHHH)
|
||||
Size 26: 16,26 BAD (HHHHHH)
|
||||
Size 27: 16,27 BAD (HHHHHH)
|
||||
Size 28: 17,28 BAD (HHHHHH)
|
||||
Size 29: 17,29 BAD (HHHHHH)
|
||||
Size 30: 18,30 BAD (HHHHHH)
|
||||
Size 31: 19,31 BAD (HHHHHH)
|
||||
Size 32: 19,32 BAD (HHHHHH)
|
||||
Size 33: 20,33 BAD (HHHHHH)
|
||||
Size 34: 20,34 BAD (HHHHHH)
|
||||
Size 35: 21,35 BAD (HHHHHH)
|
||||
Size 36: 22,36 BAD (HHHHHH)
|
||||
Size 37: 22,37 BAD (HHHHHH)
|
||||
Size 38: 23,38 BAD (HHHHHH)
|
||||
Size 39: 23,39 BAD (HHHHHH)
|
||||
Size 40: 24,40 BAD (HHHHHH)
|
||||
Size 41: 25,41 BAD (HHHHHH)
|
||||
Size 42: 25,42 BAD (HHHHHH)
|
||||
Size 43: 26,43 BAD (HHHHHH)
|
||||
Size 44: 27,44 BAD (HHHHHH)
|
||||
Size 45: 27,45 BAD (HHHHHH)
|
||||
Size 46: 28,46 BAD (HHHHHH)
|
||||
Size 47: 28,47 BAD (HHHHHH)
|
||||
Size 48: 29,48 BAD (HHHHHH)
|
||||
Size 49: 30,49 BAD (HHHHHH)
|
||||
Size 50: 30,50 BAD (HHHHHH)
|
||||
Size 51: 31,51 BAD (HHHHHH)
|
||||
Size 52: 31,52 BAD (HHHHHH)
|
||||
Size 53: 32,53 BAD (HHHHHH)
|
||||
Size 54: 33,54 BAD (HHHHHH)
|
||||
Size 55: 33,55 BAD (HHHHHH)
|
||||
Size 56: 34,56 BAD (HHHHHH)
|
||||
Size 57: 34,57 BAD (HHHHHH)
|
||||
Size 58: 35,58 BAD (HHHHHH)
|
||||
Size 59: 36,59 BAD (HHHHHH)
|
||||
Size 60: 36,60 BAD (HHHHHH)
|
||||
Size 61: 37,61 BAD (HHHHHH)
|
||||
Size 62: 37,62 BAD (HHHHHH)
|
||||
Size 63: 38,63 BAD (HHHHHH)
|
||||
Size 64: 39,65 BAD (HHHHHH)
|
||||
Size 65: 39,65 BAD (HHHHHH)
|
||||
Size 66: 40,66 BAD (HHHHHH)
|
||||
Size 67: 40,67 BAD (HHHHHH)
|
||||
Size 68: 41,68 BAD (HHHHHH)
|
||||
Size 69: 42,69 BAD (HHHHHH)
|
||||
Size 70: 42,70 BAD (HHHHHH)
|
||||
Size 71: 43,71 BAD (HHHHHH)
|
||||
Size 72: 43,72 BAD (HHHHHH)
|
||||
Size 73: 44,73 BAD (HHHHHH)
|
||||
Size 74: 45,74 BAD (HHHHHH)
|
||||
Size 75: 45,75 BAD (HHHHHH)
|
||||
Size 76: 46,76 BAD (HHHHHH)
|
||||
Size 77: 46,77 BAD (HHHHHH)
|
||||
Size 78: 47,78 BAD (HHHHHH)
|
||||
Size 79: 48,79 BAD (HHHHHH)
|
||||
Size 80: 48,80 BAD (HHHHHH)
|
||||
Size 81: 49,81 BAD (HHHHHH)
|
||||
Size 82: 49,82 BAD (HHHHHH)
|
||||
Size 83: 50,83 BAD (HHHHHH)
|
||||
Size 84: 51,84 BAD (HHHHHH)
|
||||
Size 85: 51,85 BAD (HHHHHH)
|
||||
Size 86: 52,86 BAD (HHHHHH)
|
||||
Size 87: 52,87 BAD (HHHHHH)
|
||||
Size 88: 53,88 BAD (HHHHHH)
|
||||
Size 89: 54,89 BAD (HHHHHH)
|
||||
Size 90: 54,90 BAD (HHHHHH)
|
||||
Size 91: 55,91 BAD (HHHHHH)
|
||||
Size 92: 55,92 BAD (HHHHHH)
|
||||
Size 93: 56,93 BAD (HHHHHH)
|
||||
Size 94: 57,94 BAD (HHHHHH)
|
||||
Size 95: 57,95 BAD (HHHHHH)
|
||||
Size 96: 58,96 BAD (HHHHHH)
|
||||
Size 97: 58,97 BAD (HHHHHH)
|
||||
Size 98: 59,98 BAD (HHHHHH)
|
||||
Size 99: 60,99 BAD (HHHHHH)
|
||||
Size 100: 60,100 BAD (HHHHHH)
|
||||
|
||||
Windows 8.1
|
||||
-----------
|
||||
|
||||
Size 1: 1,2 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 2,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 3,5 BAD (HHHHHH)
|
||||
Size 6: 4,6 BAD (HHHHHH)
|
||||
Size 7: 4,7 BAD (HHHHHH)
|
||||
Size 8: 5,8 BAD (HHHHHH)
|
||||
Size 9: 5,9 BAD (HHHHHH)
|
||||
Size 10: 6,10 BAD (HHHHHH)
|
||||
Size 11: 7,11 BAD (HHHHHH)
|
||||
Size 12: 7,12 BAD (HHHHHH)
|
||||
Size 13: 8,13 BAD (HHHHHH)
|
||||
Size 14: 8,14 BAD (HHHHHH)
|
||||
Size 15: 9,15 BAD (HHHHHH)
|
||||
Size 16: 10,16 BAD (HHHHHH)
|
||||
Size 17: 10,17 BAD (HHHHHH)
|
||||
Size 18: 11,18 BAD (HHHHHH)
|
||||
Size 19: 11,19 BAD (HHHHHH)
|
||||
Size 20: 12,20 BAD (HHHHHH)
|
||||
Size 21: 13,21 BAD (HHHHHH)
|
||||
Size 22: 13,22 BAD (HHHHHH)
|
||||
Size 23: 14,23 BAD (HHHHHH)
|
||||
Size 24: 14,24 BAD (HHHHHH)
|
||||
Size 25: 15,25 BAD (HHHHHH)
|
||||
Size 26: 16,26 BAD (HHHHHH)
|
||||
Size 27: 16,27 BAD (HHHHHH)
|
||||
Size 28: 17,28 BAD (HHHHHH)
|
||||
Size 29: 17,29 BAD (HHHHHH)
|
||||
Size 30: 18,30 BAD (HHHHHH)
|
||||
Size 31: 19,31 BAD (HHHHHH)
|
||||
Size 32: 19,32 BAD (HHHHHH)
|
||||
Size 33: 20,33 BAD (HHHHHH)
|
||||
Size 34: 20,34 BAD (HHHHHH)
|
||||
Size 35: 21,35 BAD (HHHHHH)
|
||||
Size 36: 22,36 BAD (HHHHHH)
|
||||
Size 37: 22,37 BAD (HHHHHH)
|
||||
Size 38: 23,38 BAD (HHHHHH)
|
||||
Size 39: 23,39 BAD (HHHHHH)
|
||||
Size 40: 24,40 BAD (HHHHHH)
|
||||
Size 41: 25,41 BAD (HHHHHH)
|
||||
Size 42: 25,42 BAD (HHHHHH)
|
||||
Size 43: 26,43 BAD (HHHHHH)
|
||||
Size 44: 27,44 BAD (HHHHHH)
|
||||
Size 45: 27,45 BAD (HHHHHH)
|
||||
Size 46: 28,46 BAD (HHHHHH)
|
||||
Size 47: 28,47 BAD (HHHHHH)
|
||||
Size 48: 29,48 BAD (HHHHHH)
|
||||
Size 49: 30,49 BAD (HHHHHH)
|
||||
Size 50: 30,50 BAD (HHHHHH)
|
||||
Size 51: 31,51 BAD (HHHHHH)
|
||||
Size 52: 31,52 BAD (HHHHHH)
|
||||
Size 53: 32,53 BAD (HHHHHH)
|
||||
Size 54: 33,54 BAD (HHHHHH)
|
||||
Size 55: 33,55 BAD (HHHHHH)
|
||||
Size 56: 34,56 BAD (HHHHHH)
|
||||
Size 57: 34,57 BAD (HHHHHH)
|
||||
Size 58: 35,58 BAD (HHHHHH)
|
||||
Size 59: 36,59 BAD (HHHHHH)
|
||||
Size 60: 36,60 BAD (HHHHHH)
|
||||
Size 61: 37,61 BAD (HHHHHH)
|
||||
Size 62: 37,62 BAD (HHHHHH)
|
||||
Size 63: 38,63 BAD (HHHHHH)
|
||||
Size 64: 39,65 BAD (HHHHHH)
|
||||
Size 65: 39,65 BAD (HHHHHH)
|
||||
Size 66: 40,66 BAD (HHHHHH)
|
||||
Size 67: 40,67 BAD (HHHHHH)
|
||||
Size 68: 41,68 BAD (HHHHHH)
|
||||
Size 69: 42,69 BAD (HHHHHH)
|
||||
Size 70: 42,70 BAD (HHHHHH)
|
||||
Size 71: 43,71 BAD (HHHHHH)
|
||||
Size 72: 43,72 BAD (HHHHHH)
|
||||
Size 73: 44,73 BAD (HHHHHH)
|
||||
Size 74: 45,74 BAD (HHHHHH)
|
||||
Size 75: 45,75 BAD (HHHHHH)
|
||||
Size 76: 46,76 BAD (HHHHHH)
|
||||
Size 77: 46,77 BAD (HHHHHH)
|
||||
Size 78: 47,78 BAD (HHHHHH)
|
||||
Size 79: 48,79 BAD (HHHHHH)
|
||||
Size 80: 48,80 BAD (HHHHHH)
|
||||
Size 81: 49,81 BAD (HHHHHH)
|
||||
Size 82: 49,82 BAD (HHHHHH)
|
||||
Size 83: 50,83 BAD (HHHHHH)
|
||||
Size 84: 51,84 BAD (HHHHHH)
|
||||
Size 85: 51,85 BAD (HHHHHH)
|
||||
Size 86: 52,86 BAD (HHHHHH)
|
||||
Size 87: 52,87 BAD (HHHHHH)
|
||||
Size 88: 53,88 BAD (HHHHHH)
|
||||
Size 89: 54,89 BAD (HHHHHH)
|
||||
Size 90: 54,90 BAD (HHHHHH)
|
||||
Size 91: 55,91 BAD (HHHHHH)
|
||||
Size 92: 55,92 BAD (HHHHHH)
|
||||
Size 93: 56,93 BAD (HHHHHH)
|
||||
Size 94: 57,94 BAD (HHHHHH)
|
||||
Size 95: 57,95 BAD (HHHHHH)
|
||||
Size 96: 58,96 BAD (HHHHHH)
|
||||
Size 97: 58,97 BAD (HHHHHH)
|
||||
Size 98: 59,98 BAD (HHHHHH)
|
||||
Size 99: 60,99 BAD (HHHHHH)
|
||||
Size 100: 60,100 BAD (HHHHHH)
|
||||
|
||||
Windows 10 14342 Old Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,2 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 2,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 3,5 BAD (HHHHHH)
|
||||
Size 6: 4,6 BAD (HHHHHH)
|
||||
Size 7: 4,7 BAD (HHHHHH)
|
||||
Size 8: 5,8 BAD (HHHHHH)
|
||||
Size 9: 5,9 BAD (HHHHHH)
|
||||
Size 10: 6,10 BAD (HHHHHH)
|
||||
Size 11: 7,11 BAD (HHHHHH)
|
||||
Size 12: 7,12 BAD (HHHHHH)
|
||||
Size 13: 8,13 BAD (HHHHHH)
|
||||
Size 14: 8,14 BAD (HHHHHH)
|
||||
Size 15: 9,15 BAD (HHHHHH)
|
||||
Size 16: 10,16 BAD (HHHHHH)
|
||||
Size 17: 10,17 BAD (HHHHHH)
|
||||
Size 18: 11,18 BAD (HHHHHH)
|
||||
Size 19: 11,19 BAD (HHHHHH)
|
||||
Size 20: 12,20 BAD (HHHHHH)
|
||||
Size 21: 13,21 BAD (HHHHHH)
|
||||
Size 22: 13,22 BAD (HHHHHH)
|
||||
Size 23: 14,23 BAD (HHHHHH)
|
||||
Size 24: 14,24 BAD (HHHHHH)
|
||||
Size 25: 15,25 BAD (HHHHHH)
|
||||
Size 26: 16,26 BAD (HHHHHH)
|
||||
Size 27: 16,27 BAD (HHHHHH)
|
||||
Size 28: 17,28 BAD (HHHHHH)
|
||||
Size 29: 17,29 BAD (HHHHHH)
|
||||
Size 30: 18,30 BAD (HHHHHH)
|
||||
Size 31: 19,31 BAD (HHHHHH)
|
||||
Size 32: 19,32 BAD (HHHHHH)
|
||||
Size 33: 20,33 BAD (HHHHHH)
|
||||
Size 34: 20,34 BAD (HHHHHH)
|
||||
Size 35: 21,35 BAD (HHHHHH)
|
||||
Size 36: 22,36 BAD (HHHHHH)
|
||||
Size 37: 22,37 BAD (HHHHHH)
|
||||
Size 38: 23,38 BAD (HHHHHH)
|
||||
Size 39: 23,39 BAD (HHHHHH)
|
||||
Size 40: 24,40 BAD (HHHHHH)
|
||||
Size 41: 25,41 BAD (HHHHHH)
|
||||
Size 42: 25,42 BAD (HHHHHH)
|
||||
Size 43: 26,43 BAD (HHHHHH)
|
||||
Size 44: 27,44 BAD (HHHHHH)
|
||||
Size 45: 27,45 BAD (HHHHHH)
|
||||
Size 46: 28,46 BAD (HHHHHH)
|
||||
Size 47: 28,47 BAD (HHHHHH)
|
||||
Size 48: 29,48 BAD (HHHHHH)
|
||||
Size 49: 30,49 BAD (HHHHHH)
|
||||
Size 50: 30,50 BAD (HHHHHH)
|
||||
Size 51: 31,51 BAD (HHHHHH)
|
||||
Size 52: 31,52 BAD (HHHHHH)
|
||||
Size 53: 32,53 BAD (HHHHHH)
|
||||
Size 54: 33,54 BAD (HHHHHH)
|
||||
Size 55: 33,55 BAD (HHHHHH)
|
||||
Size 56: 34,56 BAD (HHHHHH)
|
||||
Size 57: 34,57 BAD (HHHHHH)
|
||||
Size 58: 35,58 BAD (HHHHHH)
|
||||
Size 59: 36,59 BAD (HHHHHH)
|
||||
Size 60: 36,60 BAD (HHHHHH)
|
||||
Size 61: 37,61 BAD (HHHHHH)
|
||||
Size 62: 37,62 BAD (HHHHHH)
|
||||
Size 63: 38,63 BAD (HHHHHH)
|
||||
Size 64: 39,65 BAD (HHHHHH)
|
||||
Size 65: 39,65 BAD (HHHHHH)
|
||||
Size 66: 40,66 BAD (HHHHHH)
|
||||
Size 67: 40,67 BAD (HHHHHH)
|
||||
Size 68: 41,68 BAD (HHHHHH)
|
||||
Size 69: 42,69 BAD (HHHHHH)
|
||||
Size 70: 42,70 BAD (HHHHHH)
|
||||
Size 71: 43,71 BAD (HHHHHH)
|
||||
Size 72: 43,72 BAD (HHHHHH)
|
||||
Size 73: 44,73 BAD (HHHHHH)
|
||||
Size 74: 45,74 BAD (HHHHHH)
|
||||
Size 75: 45,75 BAD (HHHHHH)
|
||||
Size 76: 46,76 BAD (HHHHHH)
|
||||
Size 77: 46,77 BAD (HHHHHH)
|
||||
Size 78: 47,78 BAD (HHHHHH)
|
||||
Size 79: 48,79 BAD (HHHHHH)
|
||||
Size 80: 48,80 BAD (HHHHHH)
|
||||
Size 81: 49,81 BAD (HHHHHH)
|
||||
Size 82: 49,82 BAD (HHHHHH)
|
||||
Size 83: 50,83 BAD (HHHHHH)
|
||||
Size 84: 51,84 BAD (HHHHHH)
|
||||
Size 85: 51,85 BAD (HHHHHH)
|
||||
Size 86: 52,86 BAD (HHHHHH)
|
||||
Size 87: 52,87 BAD (HHHHHH)
|
||||
Size 88: 53,88 BAD (HHHHHH)
|
||||
Size 89: 54,89 BAD (HHHHHH)
|
||||
Size 90: 54,90 BAD (HHHHHH)
|
||||
Size 91: 55,91 BAD (HHHHHH)
|
||||
Size 92: 55,92 BAD (HHHHHH)
|
||||
Size 93: 56,93 BAD (HHHHHH)
|
||||
Size 94: 57,94 BAD (HHHHHH)
|
||||
Size 95: 57,95 BAD (HHHHHH)
|
||||
Size 96: 58,96 BAD (HHHHHH)
|
||||
Size 97: 58,97 BAD (HHHHHH)
|
||||
Size 98: 59,98 BAD (HHHHHH)
|
||||
Size 99: 60,99 BAD (HHHHHH)
|
||||
Size 100: 60,100 BAD (HHHHHH)
|
||||
|
||||
Windows 10 14342 New Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,1 BAD (HHHHHH)
|
||||
Size 2: 1,2 BAD (HHHHHH)
|
||||
Size 3: 2,3 BAD (HHHHHH)
|
||||
Size 4: 2,4 BAD (HHHHHH)
|
||||
Size 5: 3,5 BAD (HHHHHH)
|
||||
Size 6: 4,6 BAD (HHHHHH)
|
||||
Size 7: 4,7 BAD (HHHHHH)
|
||||
Size 8: 5,8 BAD (HHHHHH)
|
||||
Size 9: 5,9 BAD (HHHHHH)
|
||||
Size 10: 6,10 BAD (HHHHHH)
|
||||
Size 11: 7,11 BAD (HHHHHH)
|
||||
Size 12: 7,12 BAD (HHHHHH)
|
||||
Size 13: 8,13 BAD (HHHHHH)
|
||||
Size 14: 8,14 BAD (HHHHHH)
|
||||
Size 15: 9,15 BAD (HHHHHH)
|
||||
Size 16: 10,16 BAD (HHHHHH)
|
||||
Size 17: 10,17 BAD (HHHHHH)
|
||||
Size 18: 11,18 BAD (HHHHHH)
|
||||
Size 19: 11,19 BAD (HHHHHH)
|
||||
Size 20: 12,20 BAD (HHHHHH)
|
||||
Size 21: 13,21 BAD (HHHHHH)
|
||||
Size 22: 13,22 BAD (HHHHHH)
|
||||
Size 23: 14,23 BAD (HHHHHH)
|
||||
Size 24: 14,24 BAD (HHHHHH)
|
||||
Size 25: 15,25 BAD (HHHHHH)
|
||||
Size 26: 16,26 BAD (HHHHHH)
|
||||
Size 27: 16,27 BAD (HHHHHH)
|
||||
Size 28: 17,28 BAD (HHHHHH)
|
||||
Size 29: 17,29 BAD (HHHHHH)
|
||||
Size 30: 18,30 BAD (HHHHHH)
|
||||
Size 31: 19,31 BAD (HHHHHH)
|
||||
Size 32: 19,32 BAD (HHHHHH)
|
||||
Size 33: 20,33 BAD (HHHHHH)
|
||||
Size 34: 20,34 BAD (HHHHHH)
|
||||
Size 35: 21,35 BAD (HHHHHH)
|
||||
Size 36: 22,36 BAD (HHHHHH)
|
||||
Size 37: 22,37 BAD (HHHHHH)
|
||||
Size 38: 23,38 BAD (HHHHHH)
|
||||
Size 39: 23,39 BAD (HHHHHH)
|
||||
Size 40: 24,40 BAD (HHHHHH)
|
||||
Size 41: 25,41 BAD (HHHHHH)
|
||||
Size 42: 25,42 BAD (HHHHHH)
|
||||
Size 43: 26,43 BAD (HHHHHH)
|
||||
Size 44: 27,44 BAD (HHHHHH)
|
||||
Size 45: 27,45 BAD (HHHHHH)
|
||||
Size 46: 28,46 BAD (HHHHHH)
|
||||
Size 47: 28,47 BAD (HHHHHH)
|
||||
Size 48: 29,48 BAD (HHHHHH)
|
||||
Size 49: 30,49 BAD (HHHHHH)
|
||||
Size 50: 30,50 BAD (HHHHHH)
|
||||
Size 51: 31,51 BAD (HHHHHH)
|
||||
Size 52: 31,52 BAD (HHHHHH)
|
||||
Size 53: 32,53 BAD (HHHHHH)
|
||||
Size 54: 33,54 BAD (HHHHHH)
|
||||
Size 55: 33,55 BAD (HHHHHH)
|
||||
Size 56: 34,56 BAD (HHHHHH)
|
||||
Size 57: 34,57 BAD (HHHHHH)
|
||||
Size 58: 35,58 BAD (HHHHHH)
|
||||
Size 59: 36,59 BAD (HHHHHH)
|
||||
Size 60: 36,60 BAD (HHHHHH)
|
||||
Size 61: 37,61 BAD (HHHHHH)
|
||||
Size 62: 37,62 BAD (HHHHHH)
|
||||
Size 63: 38,63 BAD (HHHHHH)
|
||||
Size 64: 39,64 BAD (HHHHHH)
|
||||
Size 65: 39,65 BAD (HHHHHH)
|
||||
Size 66: 40,66 BAD (HHHHHH)
|
||||
Size 67: 40,67 BAD (HHHHHH)
|
||||
Size 68: 41,68 BAD (HHHHHH)
|
||||
Size 69: 42,69 BAD (HHHHHH)
|
||||
Size 70: 42,70 BAD (HHHHHH)
|
||||
Size 71: 43,71 BAD (HHHHHH)
|
||||
Size 72: 43,72 BAD (HHHHHH)
|
||||
Size 73: 44,73 BAD (HHHHHH)
|
||||
Size 74: 45,74 BAD (HHHHHH)
|
||||
Size 75: 45,75 BAD (HHHHHH)
|
||||
Size 76: 46,76 BAD (HHHHHH)
|
||||
Size 77: 46,77 BAD (HHHHHH)
|
||||
Size 78: 47,78 BAD (HHHHHH)
|
||||
Size 79: 48,79 BAD (HHHHHH)
|
||||
Size 80: 48,80 BAD (HHHHHH)
|
||||
Size 81: 49,81 BAD (HHHHHH)
|
||||
Size 82: 49,82 BAD (HHHHHH)
|
||||
Size 83: 50,83 BAD (HHHHHH)
|
||||
Size 84: 51,84 BAD (HHHHHH)
|
||||
Size 85: 51,85 BAD (HHHHHH)
|
||||
Size 86: 52,86 BAD (HHHHHH)
|
||||
Size 87: 52,87 BAD (HHHHHH)
|
||||
Size 88: 53,88 BAD (HHHHHH)
|
||||
Size 89: 54,89 BAD (HHHHHH)
|
||||
Size 90: 54,90 BAD (HHHHHH)
|
||||
Size 91: 55,91 BAD (HHHHHH)
|
||||
Size 92: 55,92 BAD (HHHHHH)
|
||||
Size 93: 56,93 BAD (HHHHHH)
|
||||
Size 94: 57,94 BAD (HHHHHH)
|
||||
Size 95: 57,95 BAD (HHHHHH)
|
||||
Size 96: 58,96 BAD (HHHHHH)
|
||||
Size 97: 58,97 BAD (HHHHHH)
|
||||
Size 98: 59,98 BAD (HHHHHH)
|
||||
Size 99: 60,99 BAD (HHHHHH)
|
||||
Size 100: 60,100 BAD (HHHHHH)
|
@ -1,630 +0,0 @@
|
||||
=======================================
|
||||
Code Page 932, Japanese, MS Gothic font
|
||||
=======================================
|
||||
|
||||
Options: -face-gothic -family 0x36
|
||||
Chars: A2 A3 2014 3044 30FC 4000
|
||||
|
||||
Vista
|
||||
-----
|
||||
|
||||
Size 1: 1,2 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 BAD (FFFFHH)
|
||||
Size 4: 2,4 OK (HHHFFF)
|
||||
Size 5: 3,5 OK (HHHFFF)
|
||||
Size 6: 3,6 OK (HHHFFF)
|
||||
Size 7: 4,7 OK (HHHFFF)
|
||||
Size 8: 4,8 OK (HHHFFF)
|
||||
Size 9: 5,9 OK (HHHFFF)
|
||||
Size 10: 5,10 OK (HHHFFF)
|
||||
Size 11: 6,11 OK (HHHFFF)
|
||||
Size 12: 6,12 OK (HHHFFF)
|
||||
Size 13: 7,13 OK (HHHFFF)
|
||||
Size 14: 7,14 BAD (HHHFHH)
|
||||
Size 15: 8,15 OK (HHHFFF)
|
||||
Size 16: 8,16 BAD (HHHFHH)
|
||||
Size 17: 9,17 OK (HHHFFF)
|
||||
Size 18: 9,18 BAD (HHHFHH)
|
||||
Size 19: 10,19 OK (HHHFFF)
|
||||
Size 20: 10,20 BAD (HHHFHH)
|
||||
Size 21: 11,21 OK (HHHFFF)
|
||||
Size 22: 11,22 BAD (HHHFHH)
|
||||
Size 23: 12,23 BAD (HHHFHH)
|
||||
Size 24: 12,24 BAD (HHHFHH)
|
||||
Size 25: 13,25 BAD (HHHFHH)
|
||||
Size 26: 13,26 BAD (HHHFHH)
|
||||
Size 27: 14,27 BAD (HHHFHH)
|
||||
Size 28: 14,28 BAD (HHHFHH)
|
||||
Size 29: 15,29 BAD (HHHFHH)
|
||||
Size 30: 15,30 BAD (HHHFHH)
|
||||
Size 31: 16,31 BAD (HHHFHH)
|
||||
Size 32: 16,33 BAD (HHHFHH)
|
||||
Size 33: 17,33 BAD (HHHFHH)
|
||||
Size 34: 17,34 BAD (HHHFHH)
|
||||
Size 35: 18,35 BAD (HHHFHH)
|
||||
Size 36: 18,36 BAD (HHHFHH)
|
||||
Size 37: 19,37 BAD (HHHFHH)
|
||||
Size 38: 19,38 BAD (HHHFHH)
|
||||
Size 39: 20,39 BAD (HHHFHH)
|
||||
Size 40: 20,40 BAD (HHHFHH)
|
||||
Size 41: 21,41 BAD (HHHFHH)
|
||||
Size 42: 21,42 BAD (HHHFHH)
|
||||
Size 43: 22,43 BAD (HHHFHH)
|
||||
Size 44: 22,44 BAD (HHHFHH)
|
||||
Size 45: 23,45 BAD (HHHFHH)
|
||||
Size 46: 23,46 BAD (HHHFHH)
|
||||
Size 47: 24,47 BAD (HHHFHH)
|
||||
Size 48: 24,48 BAD (HHHFHH)
|
||||
Size 49: 25,49 BAD (HHHFHH)
|
||||
Size 50: 25,50 BAD (HHHFHH)
|
||||
Size 51: 26,51 BAD (HHHFHH)
|
||||
Size 52: 26,52 BAD (HHHFHH)
|
||||
Size 53: 27,53 BAD (HHHFHH)
|
||||
Size 54: 27,54 BAD (HHHFHH)
|
||||
Size 55: 28,55 BAD (HHHFHH)
|
||||
Size 56: 28,56 BAD (HHHFHH)
|
||||
Size 57: 29,57 BAD (HHHFHH)
|
||||
Size 58: 29,58 BAD (HHHFHH)
|
||||
Size 59: 30,59 BAD (HHHFHH)
|
||||
Size 60: 30,60 BAD (HHHFHH)
|
||||
Size 61: 31,61 BAD (HHHFHH)
|
||||
Size 62: 31,62 BAD (HHHFHH)
|
||||
Size 63: 32,63 BAD (HHHFHH)
|
||||
Size 64: 32,64 BAD (HHHFHH)
|
||||
Size 65: 33,65 BAD (HHHFHH)
|
||||
Size 66: 33,66 BAD (HHHFHH)
|
||||
Size 67: 34,67 BAD (HHHFHH)
|
||||
Size 68: 34,68 BAD (HHHFHH)
|
||||
Size 69: 35,69 BAD (HHHFHH)
|
||||
Size 70: 35,70 BAD (HHHFHH)
|
||||
Size 71: 36,71 BAD (HHHFHH)
|
||||
Size 72: 36,72 BAD (HHHFHH)
|
||||
Size 73: 37,73 BAD (HHHFHH)
|
||||
Size 74: 37,74 BAD (HHHFHH)
|
||||
Size 75: 38,75 BAD (HHHFHH)
|
||||
Size 76: 38,76 BAD (HHHFHH)
|
||||
Size 77: 39,77 BAD (HHHFHH)
|
||||
Size 78: 39,78 BAD (HHHFHH)
|
||||
Size 79: 40,79 BAD (HHHFHH)
|
||||
Size 80: 40,80 BAD (HHHFHH)
|
||||
Size 81: 41,81 BAD (HHHFHH)
|
||||
Size 82: 41,82 BAD (HHHFHH)
|
||||
Size 83: 42,83 BAD (HHHFHH)
|
||||
Size 84: 42,84 BAD (HHHFHH)
|
||||
Size 85: 43,85 BAD (HHHFHH)
|
||||
Size 86: 43,86 BAD (HHHFHH)
|
||||
Size 87: 44,87 BAD (HHHFHH)
|
||||
Size 88: 44,88 BAD (HHHFHH)
|
||||
Size 89: 45,89 BAD (HHHFHH)
|
||||
Size 90: 45,90 BAD (HHHFHH)
|
||||
Size 91: 46,91 BAD (HHHFHH)
|
||||
Size 92: 46,92 BAD (HHHFHH)
|
||||
Size 93: 47,93 BAD (HHHFHH)
|
||||
Size 94: 47,94 BAD (HHHFHH)
|
||||
Size 95: 48,95 BAD (HHHFHH)
|
||||
Size 96: 48,97 BAD (HHHFHH)
|
||||
Size 97: 49,97 BAD (HHHFHH)
|
||||
Size 98: 49,98 BAD (HHHFHH)
|
||||
Size 99: 50,99 BAD (HHHFHH)
|
||||
Size 100: 50,100 BAD (HHHFHH)
|
||||
|
||||
Windows 7
|
||||
---------
|
||||
|
||||
Size 1: 1,2 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 BAD (FFFFHH)
|
||||
Size 4: 2,4 OK (HHHFFF)
|
||||
Size 5: 3,5 OK (HHHFFF)
|
||||
Size 6: 3,6 OK (HHHFFF)
|
||||
Size 7: 4,7 OK (HHHFFF)
|
||||
Size 8: 4,8 OK (HHHFFF)
|
||||
Size 9: 5,9 OK (HHHFFF)
|
||||
Size 10: 5,10 OK (HHHFFF)
|
||||
Size 11: 6,11 OK (HHHFFF)
|
||||
Size 12: 6,12 OK (HHHFFF)
|
||||
Size 13: 7,13 OK (HHHFFF)
|
||||
Size 14: 7,14 BAD (FFFFFF)
|
||||
Size 15: 8,15 OK (HHHFFF)
|
||||
Size 16: 8,16 BAD (FFFFFF)
|
||||
Size 17: 9,17 OK (HHHFFF)
|
||||
Size 18: 9,18 BAD (FFFFFF)
|
||||
Size 19: 10,19 OK (HHHFFF)
|
||||
Size 20: 10,20 BAD (FFFFFF)
|
||||
Size 21: 11,21 OK (HHHFFF)
|
||||
Size 22: 11,22 BAD (FFFFFF)
|
||||
Size 23: 12,23 BAD (FFFFFF)
|
||||
Size 24: 12,24 BAD (FFFFFF)
|
||||
Size 25: 13,25 BAD (FFFFFF)
|
||||
Size 26: 13,26 BAD (FFFFFF)
|
||||
Size 27: 14,27 BAD (FFFFFF)
|
||||
Size 28: 14,28 BAD (FFFFFF)
|
||||
Size 29: 15,29 BAD (FFFFFF)
|
||||
Size 30: 15,30 BAD (FFFFFF)
|
||||
Size 31: 16,31 BAD (FFFFFF)
|
||||
Size 32: 16,33 BAD (FFFFFF)
|
||||
Size 33: 17,33 BAD (FFFFFF)
|
||||
Size 34: 17,34 BAD (FFFFFF)
|
||||
Size 35: 18,35 BAD (FFFFFF)
|
||||
Size 36: 18,36 BAD (FFFFFF)
|
||||
Size 37: 19,37 BAD (FFFFFF)
|
||||
Size 38: 19,38 BAD (FFFFFF)
|
||||
Size 39: 20,39 BAD (FFFFFF)
|
||||
Size 40: 20,40 BAD (FFFFFF)
|
||||
Size 41: 21,41 BAD (FFFFFF)
|
||||
Size 42: 21,42 BAD (FFFFFF)
|
||||
Size 43: 22,43 BAD (FFFFFF)
|
||||
Size 44: 22,44 BAD (FFFFFF)
|
||||
Size 45: 23,45 BAD (FFFFFF)
|
||||
Size 46: 23,46 BAD (FFFFFF)
|
||||
Size 47: 24,47 BAD (FFFFFF)
|
||||
Size 48: 24,48 BAD (FFFFFF)
|
||||
Size 49: 25,49 BAD (FFFFFF)
|
||||
Size 50: 25,50 BAD (FFFFFF)
|
||||
Size 51: 26,51 BAD (FFFFFF)
|
||||
Size 52: 26,52 BAD (FFFFFF)
|
||||
Size 53: 27,53 BAD (FFFFFF)
|
||||
Size 54: 27,54 BAD (FFFFFF)
|
||||
Size 55: 28,55 BAD (FFFFFF)
|
||||
Size 56: 28,56 BAD (FFFFFF)
|
||||
Size 57: 29,57 BAD (FFFFFF)
|
||||
Size 58: 29,58 BAD (FFFFFF)
|
||||
Size 59: 30,59 BAD (FFFFFF)
|
||||
Size 60: 30,60 BAD (FFFFFF)
|
||||
Size 61: 31,61 BAD (FFFFFF)
|
||||
Size 62: 31,62 BAD (FFFFFF)
|
||||
Size 63: 32,63 BAD (FFFFFF)
|
||||
Size 64: 32,64 BAD (FFFFFF)
|
||||
Size 65: 33,65 BAD (FFFFFF)
|
||||
Size 66: 33,66 BAD (FFFFFF)
|
||||
Size 67: 34,67 BAD (FFFFFF)
|
||||
Size 68: 34,68 BAD (FFFFFF)
|
||||
Size 69: 35,69 BAD (FFFFFF)
|
||||
Size 70: 35,70 BAD (FFFFFF)
|
||||
Size 71: 36,71 BAD (FFFFFF)
|
||||
Size 72: 36,72 BAD (FFFFFF)
|
||||
Size 73: 37,73 BAD (FFFFFF)
|
||||
Size 74: 37,74 BAD (FFFFFF)
|
||||
Size 75: 38,75 BAD (FFFFFF)
|
||||
Size 76: 38,76 BAD (FFFFFF)
|
||||
Size 77: 39,77 BAD (FFFFFF)
|
||||
Size 78: 39,78 BAD (FFFFFF)
|
||||
Size 79: 40,79 BAD (FFFFFF)
|
||||
Size 80: 40,80 BAD (FFFFFF)
|
||||
Size 81: 41,81 BAD (FFFFFF)
|
||||
Size 82: 41,82 BAD (FFFFFF)
|
||||
Size 83: 42,83 BAD (FFFFFF)
|
||||
Size 84: 42,84 BAD (FFFFFF)
|
||||
Size 85: 43,85 BAD (FFFFFF)
|
||||
Size 86: 43,86 BAD (FFFFFF)
|
||||
Size 87: 44,87 BAD (FFFFFF)
|
||||
Size 88: 44,88 BAD (FFFFFF)
|
||||
Size 89: 45,89 BAD (FFFFFF)
|
||||
Size 90: 45,90 BAD (FFFFFF)
|
||||
Size 91: 46,91 BAD (FFFFFF)
|
||||
Size 92: 46,92 BAD (FFFFFF)
|
||||
Size 93: 47,93 BAD (FFFFFF)
|
||||
Size 94: 47,94 BAD (FFFFFF)
|
||||
Size 95: 48,95 BAD (FFFFFF)
|
||||
Size 96: 48,97 BAD (FFFFFF)
|
||||
Size 97: 49,97 BAD (FFFFFF)
|
||||
Size 98: 49,98 BAD (FFFFFF)
|
||||
Size 99: 50,99 BAD (FFFFFF)
|
||||
Size 100: 50,100 BAD (FFFFFF)
|
||||
|
||||
Windows 8
|
||||
---------
|
||||
|
||||
Size 1: 1,2 BAD (FFFFHH)
|
||||
Size 2: 1,2 BAD (FFFFHH)
|
||||
Size 3: 2,3 BAD (FFFFFF)
|
||||
Size 4: 2,4 BAD (FFFFHH)
|
||||
Size 5: 3,5 BAD (FFFFFF)
|
||||
Size 6: 3,6 BAD (FFFFHH)
|
||||
Size 7: 4,7 BAD (FFFFFF)
|
||||
Size 8: 4,8 BAD (FFFFHH)
|
||||
Size 9: 5,9 BAD (FFFFFF)
|
||||
Size 10: 5,10 BAD (FFFFHH)
|
||||
Size 11: 6,11 BAD (FFFFFF)
|
||||
Size 12: 6,12 BAD (FFFFHH)
|
||||
Size 13: 7,13 BAD (FFFFFF)
|
||||
Size 14: 7,14 BAD (FFFFHH)
|
||||
Size 15: 8,15 BAD (FFFFFF)
|
||||
Size 16: 8,16 BAD (FFFFHH)
|
||||
Size 17: 9,17 BAD (FFFFFF)
|
||||
Size 18: 9,18 BAD (FFFFHH)
|
||||
Size 19: 10,19 BAD (FFFFFF)
|
||||
Size 20: 10,20 BAD (FFFFFF)
|
||||
Size 21: 11,21 BAD (FFFFFF)
|
||||
Size 22: 11,22 BAD (FFFFFF)
|
||||
Size 23: 12,23 BAD (FFFFFF)
|
||||
Size 24: 12,24 BAD (FFFFFF)
|
||||
Size 25: 13,25 BAD (FFFFFF)
|
||||
Size 26: 13,26 BAD (FFFFFF)
|
||||
Size 27: 14,27 BAD (FFFFFF)
|
||||
Size 28: 14,28 BAD (FFFFFF)
|
||||
Size 29: 15,29 BAD (FFFFFF)
|
||||
Size 30: 15,30 BAD (FFFFFF)
|
||||
Size 31: 16,31 BAD (FFFFFF)
|
||||
Size 32: 16,33 BAD (FFFFFF)
|
||||
Size 33: 17,33 BAD (FFFFFF)
|
||||
Size 34: 17,34 BAD (FFFFFF)
|
||||
Size 35: 18,35 BAD (FFFFFF)
|
||||
Size 36: 18,36 BAD (FFFFFF)
|
||||
Size 37: 19,37 BAD (FFFFFF)
|
||||
Size 38: 19,38 BAD (FFFFFF)
|
||||
Size 39: 20,39 BAD (FFFFFF)
|
||||
Size 40: 20,40 BAD (FFFFFF)
|
||||
Size 41: 21,41 BAD (FFFFFF)
|
||||
Size 42: 21,42 BAD (FFFFFF)
|
||||
Size 43: 22,43 BAD (FFFFFF)
|
||||
Size 44: 22,44 BAD (FFFFFF)
|
||||
Size 45: 23,45 BAD (FFFFFF)
|
||||
Size 46: 23,46 BAD (FFFFFF)
|
||||
Size 47: 24,47 BAD (FFFFFF)
|
||||
Size 48: 24,48 BAD (FFFFFF)
|
||||
Size 49: 25,49 BAD (FFFFFF)
|
||||
Size 50: 25,50 BAD (FFFFFF)
|
||||
Size 51: 26,51 BAD (FFFFFF)
|
||||
Size 52: 26,52 BAD (FFFFFF)
|
||||
Size 53: 27,53 BAD (FFFFFF)
|
||||
Size 54: 27,54 BAD (FFFFFF)
|
||||
Size 55: 28,55 BAD (FFFFFF)
|
||||
Size 56: 28,56 BAD (FFFFFF)
|
||||
Size 57: 29,57 BAD (FFFFFF)
|
||||
Size 58: 29,58 BAD (FFFFFF)
|
||||
Size 59: 30,59 BAD (FFFFFF)
|
||||
Size 60: 30,60 BAD (FFFFFF)
|
||||
Size 61: 31,61 BAD (FFFFFF)
|
||||
Size 62: 31,62 BAD (FFFFFF)
|
||||
Size 63: 32,63 BAD (FFFFFF)
|
||||
Size 64: 32,64 BAD (FFFFFF)
|
||||
Size 65: 33,65 BAD (FFFFFF)
|
||||
Size 66: 33,66 BAD (FFFFFF)
|
||||
Size 67: 34,67 BAD (FFFFFF)
|
||||
Size 68: 34,68 BAD (FFFFFF)
|
||||
Size 69: 35,69 BAD (FFFFFF)
|
||||
Size 70: 35,70 BAD (FFFFFF)
|
||||
Size 71: 36,71 BAD (FFFFFF)
|
||||
Size 72: 36,72 BAD (FFFFFF)
|
||||
Size 73: 37,73 BAD (FFFFFF)
|
||||
Size 74: 37,74 BAD (FFFFFF)
|
||||
Size 75: 38,75 BAD (FFFFFF)
|
||||
Size 76: 38,76 BAD (FFFFFF)
|
||||
Size 77: 39,77 BAD (FFFFFF)
|
||||
Size 78: 39,78 BAD (FFFFFF)
|
||||
Size 79: 40,79 BAD (FFFFFF)
|
||||
Size 80: 40,80 BAD (FFFFFF)
|
||||
Size 81: 41,81 BAD (FFFFFF)
|
||||
Size 82: 41,82 BAD (FFFFFF)
|
||||
Size 83: 42,83 BAD (FFFFFF)
|
||||
Size 84: 42,84 BAD (FFFFFF)
|
||||
Size 85: 43,85 BAD (FFFFFF)
|
||||
Size 86: 43,86 BAD (FFFFFF)
|
||||
Size 87: 44,87 BAD (FFFFFF)
|
||||
Size 88: 44,88 BAD (FFFFFF)
|
||||
Size 89: 45,89 BAD (FFFFFF)
|
||||
Size 90: 45,90 BAD (FFFFFF)
|
||||
Size 91: 46,91 BAD (FFFFFF)
|
||||
Size 92: 46,92 BAD (FFFFFF)
|
||||
Size 93: 47,93 BAD (FFFFFF)
|
||||
Size 94: 47,94 BAD (FFFFFF)
|
||||
Size 95: 48,95 BAD (FFFFFF)
|
||||
Size 96: 48,97 BAD (FFFFFF)
|
||||
Size 97: 49,97 BAD (FFFFFF)
|
||||
Size 98: 49,98 BAD (FFFFFF)
|
||||
Size 99: 50,99 BAD (FFFFFF)
|
||||
Size 100: 50,100 BAD (FFFFFF)
|
||||
|
||||
Windows 8.1
|
||||
-----------
|
||||
|
||||
Size 1: 1,2 BAD (FFFFHH)
|
||||
Size 2: 1,2 BAD (FFFFHH)
|
||||
Size 3: 2,3 BAD (FFFFFF)
|
||||
Size 4: 2,4 BAD (FFFFHH)
|
||||
Size 5: 3,5 BAD (FFFFFF)
|
||||
Size 6: 3,6 BAD (FFFFHH)
|
||||
Size 7: 4,7 BAD (FFFFFF)
|
||||
Size 8: 4,8 BAD (FFFFHH)
|
||||
Size 9: 5,9 BAD (FFFFFF)
|
||||
Size 10: 5,10 BAD (FFFFHH)
|
||||
Size 11: 6,11 BAD (FFFFFF)
|
||||
Size 12: 6,12 BAD (FFFFHH)
|
||||
Size 13: 7,13 BAD (FFFFFF)
|
||||
Size 14: 7,14 BAD (FFFFHH)
|
||||
Size 15: 8,15 BAD (FFFFFF)
|
||||
Size 16: 8,16 BAD (FFFFHH)
|
||||
Size 17: 9,17 BAD (FFFFFF)
|
||||
Size 18: 9,18 BAD (FFFFHH)
|
||||
Size 19: 10,19 BAD (FFFFFF)
|
||||
Size 20: 10,20 BAD (FFFFFF)
|
||||
Size 21: 11,21 BAD (FFFFFF)
|
||||
Size 22: 11,22 BAD (FFFFFF)
|
||||
Size 23: 12,23 BAD (FFFFFF)
|
||||
Size 24: 12,24 BAD (FFFFFF)
|
||||
Size 25: 13,25 BAD (FFFFFF)
|
||||
Size 26: 13,26 BAD (FFFFFF)
|
||||
Size 27: 14,27 BAD (FFFFFF)
|
||||
Size 28: 14,28 BAD (FFFFFF)
|
||||
Size 29: 15,29 BAD (FFFFFF)
|
||||
Size 30: 15,30 BAD (FFFFFF)
|
||||
Size 31: 16,31 BAD (FFFFFF)
|
||||
Size 32: 16,33 BAD (FFFFFF)
|
||||
Size 33: 17,33 BAD (FFFFFF)
|
||||
Size 34: 17,34 BAD (FFFFFF)
|
||||
Size 35: 18,35 BAD (FFFFFF)
|
||||
Size 36: 18,36 BAD (FFFFFF)
|
||||
Size 37: 19,37 BAD (FFFFFF)
|
||||
Size 38: 19,38 BAD (FFFFFF)
|
||||
Size 39: 20,39 BAD (FFFFFF)
|
||||
Size 40: 20,40 BAD (FFFFFF)
|
||||
Size 41: 21,41 BAD (FFFFFF)
|
||||
Size 42: 21,42 BAD (FFFFFF)
|
||||
Size 43: 22,43 BAD (FFFFFF)
|
||||
Size 44: 22,44 BAD (FFFFFF)
|
||||
Size 45: 23,45 BAD (FFFFFF)
|
||||
Size 46: 23,46 BAD (FFFFFF)
|
||||
Size 47: 24,47 BAD (FFFFFF)
|
||||
Size 48: 24,48 BAD (FFFFFF)
|
||||
Size 49: 25,49 BAD (FFFFFF)
|
||||
Size 50: 25,50 BAD (FFFFFF)
|
||||
Size 51: 26,51 BAD (FFFFFF)
|
||||
Size 52: 26,52 BAD (FFFFFF)
|
||||
Size 53: 27,53 BAD (FFFFFF)
|
||||
Size 54: 27,54 BAD (FFFFFF)
|
||||
Size 55: 28,55 BAD (FFFFFF)
|
||||
Size 56: 28,56 BAD (FFFFFF)
|
||||
Size 57: 29,57 BAD (FFFFFF)
|
||||
Size 58: 29,58 BAD (FFFFFF)
|
||||
Size 59: 30,59 BAD (FFFFFF)
|
||||
Size 60: 30,60 BAD (FFFFFF)
|
||||
Size 61: 31,61 BAD (FFFFFF)
|
||||
Size 62: 31,62 BAD (FFFFFF)
|
||||
Size 63: 32,63 BAD (FFFFFF)
|
||||
Size 64: 32,64 BAD (FFFFFF)
|
||||
Size 65: 33,65 BAD (FFFFFF)
|
||||
Size 66: 33,66 BAD (FFFFFF)
|
||||
Size 67: 34,67 BAD (FFFFFF)
|
||||
Size 68: 34,68 BAD (FFFFFF)
|
||||
Size 69: 35,69 BAD (FFFFFF)
|
||||
Size 70: 35,70 BAD (FFFFFF)
|
||||
Size 71: 36,71 BAD (FFFFFF)
|
||||
Size 72: 36,72 BAD (FFFFFF)
|
||||
Size 73: 37,73 BAD (FFFFFF)
|
||||
Size 74: 37,74 BAD (FFFFFF)
|
||||
Size 75: 38,75 BAD (FFFFFF)
|
||||
Size 76: 38,76 BAD (FFFFFF)
|
||||
Size 77: 39,77 BAD (FFFFFF)
|
||||
Size 78: 39,78 BAD (FFFFFF)
|
||||
Size 79: 40,79 BAD (FFFFFF)
|
||||
Size 80: 40,80 BAD (FFFFFF)
|
||||
Size 81: 41,81 BAD (FFFFFF)
|
||||
Size 82: 41,82 BAD (FFFFFF)
|
||||
Size 83: 42,83 BAD (FFFFFF)
|
||||
Size 84: 42,84 BAD (FFFFFF)
|
||||
Size 85: 43,85 BAD (FFFFFF)
|
||||
Size 86: 43,86 BAD (FFFFFF)
|
||||
Size 87: 44,87 BAD (FFFFFF)
|
||||
Size 88: 44,88 BAD (FFFFFF)
|
||||
Size 89: 45,89 BAD (FFFFFF)
|
||||
Size 90: 45,90 BAD (FFFFFF)
|
||||
Size 91: 46,91 BAD (FFFFFF)
|
||||
Size 92: 46,92 BAD (FFFFFF)
|
||||
Size 93: 47,93 BAD (FFFFFF)
|
||||
Size 94: 47,94 BAD (FFFFFF)
|
||||
Size 95: 48,95 BAD (FFFFFF)
|
||||
Size 96: 48,97 BAD (FFFFFF)
|
||||
Size 97: 49,97 BAD (FFFFFF)
|
||||
Size 98: 49,98 BAD (FFFFFF)
|
||||
Size 99: 50,99 BAD (FFFFFF)
|
||||
Size 100: 50,100 BAD (FFFFFF)
|
||||
|
||||
Windows 10 14342 Old Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,2 BAD (FFFFHH)
|
||||
Size 2: 1,2 BAD (FFFFHH)
|
||||
Size 3: 2,3 BAD (FFFFFF)
|
||||
Size 4: 2,4 BAD (FFFFHH)
|
||||
Size 5: 3,5 BAD (FFFFFF)
|
||||
Size 6: 3,6 BAD (FFFFHH)
|
||||
Size 7: 4,7 BAD (FFFFFF)
|
||||
Size 8: 4,8 BAD (FFFFHH)
|
||||
Size 9: 5,9 BAD (FFFFFF)
|
||||
Size 10: 5,10 BAD (FFFFHH)
|
||||
Size 11: 6,11 BAD (FFFFFF)
|
||||
Size 12: 6,12 BAD (FFFFHH)
|
||||
Size 13: 7,13 BAD (FFFFFF)
|
||||
Size 14: 7,14 BAD (FFFFHH)
|
||||
Size 15: 8,15 BAD (FFFFFF)
|
||||
Size 16: 8,16 BAD (FFFFHH)
|
||||
Size 17: 9,17 BAD (FFFFFF)
|
||||
Size 18: 9,18 BAD (FFFFHH)
|
||||
Size 19: 10,19 BAD (FFFFFF)
|
||||
Size 20: 10,20 BAD (FFFFFF)
|
||||
Size 21: 11,21 BAD (FFFFFF)
|
||||
Size 22: 11,22 BAD (FFFFFF)
|
||||
Size 23: 12,23 BAD (FFFFFF)
|
||||
Size 24: 12,24 BAD (FFFFFF)
|
||||
Size 25: 13,25 BAD (FFFFFF)
|
||||
Size 26: 13,26 BAD (FFFFFF)
|
||||
Size 27: 14,27 BAD (FFFFFF)
|
||||
Size 28: 14,28 BAD (FFFFFF)
|
||||
Size 29: 15,29 BAD (FFFFFF)
|
||||
Size 30: 15,30 BAD (FFFFFF)
|
||||
Size 31: 16,31 BAD (FFFFFF)
|
||||
Size 32: 16,33 BAD (FFFFFF)
|
||||
Size 33: 17,33 BAD (FFFFFF)
|
||||
Size 34: 17,34 BAD (FFFFFF)
|
||||
Size 35: 18,35 BAD (FFFFFF)
|
||||
Size 36: 18,36 BAD (FFFFFF)
|
||||
Size 37: 19,37 BAD (FFFFFF)
|
||||
Size 38: 19,38 BAD (FFFFFF)
|
||||
Size 39: 20,39 BAD (FFFFFF)
|
||||
Size 40: 20,40 BAD (FFFFFF)
|
||||
Size 41: 21,41 BAD (FFFFFF)
|
||||
Size 42: 21,42 BAD (FFFFFF)
|
||||
Size 43: 22,43 BAD (FFFFFF)
|
||||
Size 44: 22,44 BAD (FFFFFF)
|
||||
Size 45: 23,45 BAD (FFFFFF)
|
||||
Size 46: 23,46 BAD (FFFFFF)
|
||||
Size 47: 24,47 BAD (FFFFFF)
|
||||
Size 48: 24,48 BAD (FFFFFF)
|
||||
Size 49: 25,49 BAD (FFFFFF)
|
||||
Size 50: 25,50 BAD (FFFFFF)
|
||||
Size 51: 26,51 BAD (FFFFFF)
|
||||
Size 52: 26,52 BAD (FFFFFF)
|
||||
Size 53: 27,53 BAD (FFFFFF)
|
||||
Size 54: 27,54 BAD (FFFFFF)
|
||||
Size 55: 28,55 BAD (FFFFFF)
|
||||
Size 56: 28,56 BAD (FFFFFF)
|
||||
Size 57: 29,57 BAD (FFFFFF)
|
||||
Size 58: 29,58 BAD (FFFFFF)
|
||||
Size 59: 30,59 BAD (FFFFFF)
|
||||
Size 60: 30,60 BAD (FFFFFF)
|
||||
Size 61: 31,61 BAD (FFFFFF)
|
||||
Size 62: 31,62 BAD (FFFFFF)
|
||||
Size 63: 32,63 BAD (FFFFFF)
|
||||
Size 64: 32,64 BAD (FFFFFF)
|
||||
Size 65: 33,65 BAD (FFFFFF)
|
||||
Size 66: 33,66 BAD (FFFFFF)
|
||||
Size 67: 34,67 BAD (FFFFFF)
|
||||
Size 68: 34,68 BAD (FFFFFF)
|
||||
Size 69: 35,69 BAD (FFFFFF)
|
||||
Size 70: 35,70 BAD (FFFFFF)
|
||||
Size 71: 36,71 BAD (FFFFFF)
|
||||
Size 72: 36,72 BAD (FFFFFF)
|
||||
Size 73: 37,73 BAD (FFFFFF)
|
||||
Size 74: 37,74 BAD (FFFFFF)
|
||||
Size 75: 38,75 BAD (FFFFFF)
|
||||
Size 76: 38,76 BAD (FFFFFF)
|
||||
Size 77: 39,77 BAD (FFFFFF)
|
||||
Size 78: 39,78 BAD (FFFFFF)
|
||||
Size 79: 40,79 BAD (FFFFFF)
|
||||
Size 80: 40,80 BAD (FFFFFF)
|
||||
Size 81: 41,81 BAD (FFFFFF)
|
||||
Size 82: 41,82 BAD (FFFFFF)
|
||||
Size 83: 42,83 BAD (FFFFFF)
|
||||
Size 84: 42,84 BAD (FFFFFF)
|
||||
Size 85: 43,85 BAD (FFFFFF)
|
||||
Size 86: 43,86 BAD (FFFFFF)
|
||||
Size 87: 44,87 BAD (FFFFFF)
|
||||
Size 88: 44,88 BAD (FFFFFF)
|
||||
Size 89: 45,89 BAD (FFFFFF)
|
||||
Size 90: 45,90 BAD (FFFFFF)
|
||||
Size 91: 46,91 BAD (FFFFFF)
|
||||
Size 92: 46,92 BAD (FFFFFF)
|
||||
Size 93: 47,93 BAD (FFFFFF)
|
||||
Size 94: 47,94 BAD (FFFFFF)
|
||||
Size 95: 48,95 BAD (FFFFFF)
|
||||
Size 96: 48,97 BAD (FFFFFF)
|
||||
Size 97: 49,97 BAD (FFFFFF)
|
||||
Size 98: 49,98 BAD (FFFFFF)
|
||||
Size 99: 50,99 BAD (FFFFFF)
|
||||
Size 100: 50,100 BAD (FFFFFF)
|
||||
|
||||
Windows 10 14342 New Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,1 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 OK (HHHFFF)
|
||||
Size 4: 2,4 OK (HHHFFF)
|
||||
Size 5: 3,5 OK (HHHFFF)
|
||||
Size 6: 3,6 OK (HHHFFF)
|
||||
Size 7: 4,7 OK (HHHFFF)
|
||||
Size 8: 4,8 OK (HHHFFF)
|
||||
Size 9: 5,9 OK (HHHFFF)
|
||||
Size 10: 5,10 OK (HHHFFF)
|
||||
Size 11: 6,11 OK (HHHFFF)
|
||||
Size 12: 6,12 OK (HHHFFF)
|
||||
Size 13: 7,13 OK (HHHFFF)
|
||||
Size 14: 7,14 OK (HHHFFF)
|
||||
Size 15: 8,15 OK (HHHFFF)
|
||||
Size 16: 8,16 OK (HHHFFF)
|
||||
Size 17: 9,17 OK (HHHFFF)
|
||||
Size 18: 9,18 OK (HHHFFF)
|
||||
Size 19: 10,19 OK (HHHFFF)
|
||||
Size 20: 10,20 OK (HHHFFF)
|
||||
Size 21: 11,21 OK (HHHFFF)
|
||||
Size 22: 11,22 OK (HHHFFF)
|
||||
Size 23: 12,23 OK (HHHFFF)
|
||||
Size 24: 12,24 OK (HHHFFF)
|
||||
Size 25: 13,25 OK (HHHFFF)
|
||||
Size 26: 13,26 OK (HHHFFF)
|
||||
Size 27: 14,27 OK (HHHFFF)
|
||||
Size 28: 14,28 OK (HHHFFF)
|
||||
Size 29: 15,29 OK (HHHFFF)
|
||||
Size 30: 15,30 OK (HHHFFF)
|
||||
Size 31: 16,31 OK (HHHFFF)
|
||||
Size 32: 16,32 OK (HHHFFF)
|
||||
Size 33: 17,33 OK (HHHFFF)
|
||||
Size 34: 17,34 OK (HHHFFF)
|
||||
Size 35: 18,35 OK (HHHFFF)
|
||||
Size 36: 18,36 OK (HHHFFF)
|
||||
Size 37: 19,37 OK (HHHFFF)
|
||||
Size 38: 19,38 OK (HHHFFF)
|
||||
Size 39: 20,39 OK (HHHFFF)
|
||||
Size 40: 20,40 OK (HHHFFF)
|
||||
Size 41: 21,41 OK (HHHFFF)
|
||||
Size 42: 21,42 OK (HHHFFF)
|
||||
Size 43: 22,43 OK (HHHFFF)
|
||||
Size 44: 22,44 OK (HHHFFF)
|
||||
Size 45: 23,45 OK (HHHFFF)
|
||||
Size 46: 23,46 OK (HHHFFF)
|
||||
Size 47: 24,47 OK (HHHFFF)
|
||||
Size 48: 24,48 OK (HHHFFF)
|
||||
Size 49: 25,49 OK (HHHFFF)
|
||||
Size 50: 25,50 OK (HHHFFF)
|
||||
Size 51: 26,51 OK (HHHFFF)
|
||||
Size 52: 26,52 OK (HHHFFF)
|
||||
Size 53: 27,53 OK (HHHFFF)
|
||||
Size 54: 27,54 OK (HHHFFF)
|
||||
Size 55: 28,55 OK (HHHFFF)
|
||||
Size 56: 28,56 OK (HHHFFF)
|
||||
Size 57: 29,57 OK (HHHFFF)
|
||||
Size 58: 29,58 OK (HHHFFF)
|
||||
Size 59: 30,59 OK (HHHFFF)
|
||||
Size 60: 30,60 OK (HHHFFF)
|
||||
Size 61: 31,61 OK (HHHFFF)
|
||||
Size 62: 31,62 OK (HHHFFF)
|
||||
Size 63: 32,63 OK (HHHFFF)
|
||||
Size 64: 32,64 OK (HHHFFF)
|
||||
Size 65: 33,65 OK (HHHFFF)
|
||||
Size 66: 33,66 OK (HHHFFF)
|
||||
Size 67: 34,67 OK (HHHFFF)
|
||||
Size 68: 34,68 OK (HHHFFF)
|
||||
Size 69: 35,69 OK (HHHFFF)
|
||||
Size 70: 35,70 OK (HHHFFF)
|
||||
Size 71: 36,71 OK (HHHFFF)
|
||||
Size 72: 36,72 OK (HHHFFF)
|
||||
Size 73: 37,73 OK (HHHFFF)
|
||||
Size 74: 37,74 OK (HHHFFF)
|
||||
Size 75: 38,75 OK (HHHFFF)
|
||||
Size 76: 38,76 OK (HHHFFF)
|
||||
Size 77: 39,77 OK (HHHFFF)
|
||||
Size 78: 39,78 OK (HHHFFF)
|
||||
Size 79: 40,79 OK (HHHFFF)
|
||||
Size 80: 40,80 OK (HHHFFF)
|
||||
Size 81: 41,81 OK (HHHFFF)
|
||||
Size 82: 41,82 OK (HHHFFF)
|
||||
Size 83: 42,83 OK (HHHFFF)
|
||||
Size 84: 42,84 OK (HHHFFF)
|
||||
Size 85: 43,85 OK (HHHFFF)
|
||||
Size 86: 43,86 OK (HHHFFF)
|
||||
Size 87: 44,87 OK (HHHFFF)
|
||||
Size 88: 44,88 OK (HHHFFF)
|
||||
Size 89: 45,89 OK (HHHFFF)
|
||||
Size 90: 45,90 OK (HHHFFF)
|
||||
Size 91: 46,91 OK (HHHFFF)
|
||||
Size 92: 46,92 OK (HHHFFF)
|
||||
Size 93: 47,93 OK (HHHFFF)
|
||||
Size 94: 47,94 OK (HHHFFF)
|
||||
Size 95: 48,95 OK (HHHFFF)
|
||||
Size 96: 48,96 OK (HHHFFF)
|
||||
Size 97: 49,97 OK (HHHFFF)
|
||||
Size 98: 49,98 OK (HHHFFF)
|
||||
Size 99: 50,99 OK (HHHFFF)
|
||||
Size 100: 50,100 OK (HHHFFF)
|
@ -1,630 +0,0 @@
|
||||
==========================================================
|
||||
Code Page 936, Chinese Simplified (China/PRC), SimSun font
|
||||
==========================================================
|
||||
|
||||
Options: -face-simsun -family 0x36
|
||||
Chars: A2 A3 2014 3044 30FC 4000
|
||||
|
||||
Vista
|
||||
-----
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,3 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (HHHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (HHHFHH)
|
||||
Size 8: 4,9 GOOD (HHFFFF)
|
||||
Size 9: 5,10 BAD (HHHFHH)
|
||||
Size 10: 5,11 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (HHHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,15 BAD (HHHFHH)
|
||||
Size 14: 7,16 GOOD (HHFFFF)
|
||||
Size 15: 8,17 BAD (HHHFHH)
|
||||
Size 16: 8,18 GOOD (HHFFFF)
|
||||
Size 17: 9,19 BAD (HHHFHH)
|
||||
Size 18: 9,21 GOOD (HHFFFF)
|
||||
Size 19: 10,22 BAD (HHHFHH)
|
||||
Size 20: 10,23 GOOD (HHFFFF)
|
||||
Size 21: 11,24 BAD (HHHFHH)
|
||||
Size 22: 11,25 GOOD (HHFFFF)
|
||||
Size 23: 12,26 BAD (HHHFHH)
|
||||
Size 24: 12,27 GOOD (HHFFFF)
|
||||
Size 25: 13,29 BAD (HHHFHH)
|
||||
Size 26: 13,30 GOOD (HHFFFF)
|
||||
Size 27: 14,31 BAD (HHHFHH)
|
||||
Size 28: 14,32 GOOD (HHFFFF)
|
||||
Size 29: 15,33 BAD (HHHFHH)
|
||||
Size 30: 15,34 GOOD (HHFFFF)
|
||||
Size 31: 16,35 BAD (HHHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,38 BAD (HHHFHH)
|
||||
Size 34: 17,39 GOOD (HHFFFF)
|
||||
Size 35: 18,40 BAD (HHHFHH)
|
||||
Size 36: 18,41 GOOD (HHFFFF)
|
||||
Size 37: 19,42 BAD (HHHFHH)
|
||||
Size 38: 19,43 GOOD (HHFFFF)
|
||||
Size 39: 20,44 BAD (HHHFHH)
|
||||
Size 40: 20,46 GOOD (HHFFFF)
|
||||
Size 41: 21,47 BAD (HHHFHH)
|
||||
Size 42: 21,48 GOOD (HHFFFF)
|
||||
Size 43: 22,49 BAD (HHHFHH)
|
||||
Size 44: 22,50 GOOD (HHFFFF)
|
||||
Size 45: 23,51 BAD (HHHFHH)
|
||||
Size 46: 23,52 GOOD (HHFFFF)
|
||||
Size 47: 24,54 BAD (HHHFHH)
|
||||
Size 48: 24,55 GOOD (HHFFFF)
|
||||
Size 49: 25,56 BAD (HHHFHH)
|
||||
Size 50: 25,57 GOOD (HHFFFF)
|
||||
Size 51: 26,58 BAD (HHHFHH)
|
||||
Size 52: 26,59 GOOD (HHFFFF)
|
||||
Size 53: 27,60 BAD (HHHFHH)
|
||||
Size 54: 27,62 GOOD (HHFFFF)
|
||||
Size 55: 28,63 BAD (HHHFHH)
|
||||
Size 56: 28,64 GOOD (HHFFFF)
|
||||
Size 57: 29,65 BAD (HHHFHH)
|
||||
Size 58: 29,66 GOOD (HHFFFF)
|
||||
Size 59: 30,67 BAD (HHHFHH)
|
||||
Size 60: 30,68 GOOD (HHFFFF)
|
||||
Size 61: 31,70 BAD (HHHFHH)
|
||||
Size 62: 31,71 GOOD (HHFFFF)
|
||||
Size 63: 32,72 BAD (HHHFHH)
|
||||
Size 64: 32,73 GOOD (HHFFFF)
|
||||
Size 65: 33,74 GOOD (HHFFFF)
|
||||
Size 66: 33,75 GOOD (HHFFFF)
|
||||
Size 67: 34,76 GOOD (HHFFFF)
|
||||
Size 68: 34,78 GOOD (HHFFFF)
|
||||
Size 69: 35,79 GOOD (HHFFFF)
|
||||
Size 70: 35,80 GOOD (HHFFFF)
|
||||
Size 71: 36,81 GOOD (HHFFFF)
|
||||
Size 72: 36,82 GOOD (HHFFFF)
|
||||
Size 73: 37,83 GOOD (HHFFFF)
|
||||
Size 74: 37,84 GOOD (HHFFFF)
|
||||
Size 75: 38,86 GOOD (HHFFFF)
|
||||
Size 76: 38,87 GOOD (HHFFFF)
|
||||
Size 77: 39,88 GOOD (HHFFFF)
|
||||
Size 78: 39,89 GOOD (HHFFFF)
|
||||
Size 79: 40,90 GOOD (HHFFFF)
|
||||
Size 80: 40,91 GOOD (HHFFFF)
|
||||
Size 81: 41,92 GOOD (HHFFFF)
|
||||
Size 82: 41,94 GOOD (HHFFFF)
|
||||
Size 83: 42,95 GOOD (HHFFFF)
|
||||
Size 84: 42,96 GOOD (HHFFFF)
|
||||
Size 85: 43,97 GOOD (HHFFFF)
|
||||
Size 86: 43,98 GOOD (HHFFFF)
|
||||
Size 87: 44,99 GOOD (HHFFFF)
|
||||
Size 88: 44,100 GOOD (HHFFFF)
|
||||
Size 89: 45,102 GOOD (HHFFFF)
|
||||
Size 90: 45,103 GOOD (HHFFFF)
|
||||
Size 91: 46,104 GOOD (HHFFFF)
|
||||
Size 92: 46,105 GOOD (HHFFFF)
|
||||
Size 93: 47,106 GOOD (HHFFFF)
|
||||
Size 94: 47,107 GOOD (HHFFFF)
|
||||
Size 95: 48,108 GOOD (HHFFFF)
|
||||
Size 96: 48,111 GOOD (HHFFFF)
|
||||
Size 97: 49,111 GOOD (HHFFFF)
|
||||
Size 98: 49,112 GOOD (HHFFFF)
|
||||
Size 99: 50,113 GOOD (HHFFFF)
|
||||
Size 100: 50,114 GOOD (HHFFFF)
|
||||
|
||||
Windows 7
|
||||
---------
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,3 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (FFHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (FFHFHH)
|
||||
Size 8: 4,9 GOOD (HHFFFF)
|
||||
Size 9: 5,10 BAD (FFHFHH)
|
||||
Size 10: 5,11 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (FFHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,15 BAD (FFHFHH)
|
||||
Size 14: 7,16 GOOD (HHFFFF)
|
||||
Size 15: 8,17 BAD (FFHFHH)
|
||||
Size 16: 8,18 GOOD (HHFFFF)
|
||||
Size 17: 9,19 BAD (FFHFHH)
|
||||
Size 18: 9,21 GOOD (HHFFFF)
|
||||
Size 19: 10,22 BAD (FFHFHH)
|
||||
Size 20: 10,23 GOOD (HHFFFF)
|
||||
Size 21: 11,24 BAD (FFHFHH)
|
||||
Size 22: 11,25 GOOD (HHFFFF)
|
||||
Size 23: 12,26 BAD (FFHFHH)
|
||||
Size 24: 12,27 GOOD (HHFFFF)
|
||||
Size 25: 13,29 BAD (FFHFHH)
|
||||
Size 26: 13,30 GOOD (HHFFFF)
|
||||
Size 27: 14,31 BAD (FFHFHH)
|
||||
Size 28: 14,32 GOOD (HHFFFF)
|
||||
Size 29: 15,33 BAD (FFHFHH)
|
||||
Size 30: 15,34 GOOD (HHFFFF)
|
||||
Size 31: 16,35 BAD (FFHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,38 BAD (FFHFHH)
|
||||
Size 34: 17,39 GOOD (HHFFFF)
|
||||
Size 35: 18,40 BAD (FFHFHH)
|
||||
Size 36: 18,41 GOOD (HHFFFF)
|
||||
Size 37: 19,42 BAD (FFHFHH)
|
||||
Size 38: 19,43 GOOD (HHFFFF)
|
||||
Size 39: 20,44 BAD (FFHFHH)
|
||||
Size 40: 20,46 GOOD (HHFFFF)
|
||||
Size 41: 21,47 BAD (FFHFHH)
|
||||
Size 42: 21,48 GOOD (HHFFFF)
|
||||
Size 43: 22,49 BAD (FFHFHH)
|
||||
Size 44: 22,50 GOOD (HHFFFF)
|
||||
Size 45: 23,51 BAD (FFHFHH)
|
||||
Size 46: 23,52 GOOD (HHFFFF)
|
||||
Size 47: 24,54 BAD (FFHFHH)
|
||||
Size 48: 24,55 GOOD (HHFFFF)
|
||||
Size 49: 25,56 BAD (FFHFHH)
|
||||
Size 50: 25,57 GOOD (HHFFFF)
|
||||
Size 51: 26,58 BAD (FFHFHH)
|
||||
Size 52: 26,59 GOOD (HHFFFF)
|
||||
Size 53: 27,60 BAD (FFHFHH)
|
||||
Size 54: 27,62 GOOD (HHFFFF)
|
||||
Size 55: 28,63 BAD (FFHFHH)
|
||||
Size 56: 28,64 GOOD (HHFFFF)
|
||||
Size 57: 29,65 BAD (FFHFHH)
|
||||
Size 58: 29,66 GOOD (HHFFFF)
|
||||
Size 59: 30,67 BAD (FFHFHH)
|
||||
Size 60: 30,68 GOOD (HHFFFF)
|
||||
Size 61: 31,70 BAD (FFHFHH)
|
||||
Size 62: 31,71 GOOD (HHFFFF)
|
||||
Size 63: 32,72 BAD (FFHFHH)
|
||||
Size 64: 32,73 GOOD (HHFFFF)
|
||||
Size 65: 33,74 GOOD (HHFFFF)
|
||||
Size 66: 33,75 GOOD (HHFFFF)
|
||||
Size 67: 34,76 GOOD (HHFFFF)
|
||||
Size 68: 34,78 GOOD (HHFFFF)
|
||||
Size 69: 35,79 GOOD (HHFFFF)
|
||||
Size 70: 35,80 GOOD (HHFFFF)
|
||||
Size 71: 36,81 GOOD (HHFFFF)
|
||||
Size 72: 36,82 GOOD (HHFFFF)
|
||||
Size 73: 37,83 GOOD (HHFFFF)
|
||||
Size 74: 37,84 GOOD (HHFFFF)
|
||||
Size 75: 38,86 GOOD (HHFFFF)
|
||||
Size 76: 38,87 GOOD (HHFFFF)
|
||||
Size 77: 39,88 GOOD (HHFFFF)
|
||||
Size 78: 39,89 GOOD (HHFFFF)
|
||||
Size 79: 40,90 GOOD (HHFFFF)
|
||||
Size 80: 40,91 GOOD (HHFFFF)
|
||||
Size 81: 41,92 GOOD (HHFFFF)
|
||||
Size 82: 41,94 GOOD (HHFFFF)
|
||||
Size 83: 42,95 GOOD (HHFFFF)
|
||||
Size 84: 42,96 GOOD (HHFFFF)
|
||||
Size 85: 43,97 GOOD (HHFFFF)
|
||||
Size 86: 43,98 GOOD (HHFFFF)
|
||||
Size 87: 44,99 GOOD (HHFFFF)
|
||||
Size 88: 44,100 GOOD (HHFFFF)
|
||||
Size 89: 45,102 GOOD (HHFFFF)
|
||||
Size 90: 45,103 GOOD (HHFFFF)
|
||||
Size 91: 46,104 GOOD (HHFFFF)
|
||||
Size 92: 46,105 GOOD (HHFFFF)
|
||||
Size 93: 47,106 GOOD (HHFFFF)
|
||||
Size 94: 47,107 GOOD (HHFFFF)
|
||||
Size 95: 48,108 GOOD (HHFFFF)
|
||||
Size 96: 48,111 GOOD (HHFFFF)
|
||||
Size 97: 49,111 GOOD (HHFFFF)
|
||||
Size 98: 49,112 GOOD (HHFFFF)
|
||||
Size 99: 50,113 GOOD (HHFFFF)
|
||||
Size 100: 50,114 GOOD (HHFFFF)
|
||||
|
||||
Windows 8
|
||||
---------
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,3 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (FFHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (FFHFHH)
|
||||
Size 8: 4,9 GOOD (HHFFFF)
|
||||
Size 9: 5,10 BAD (FFHFHH)
|
||||
Size 10: 5,11 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (FFHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,15 BAD (FFHFHH)
|
||||
Size 14: 7,16 GOOD (HHFFFF)
|
||||
Size 15: 8,17 BAD (FFHFHH)
|
||||
Size 16: 8,18 GOOD (HHFFFF)
|
||||
Size 17: 9,19 BAD (FFHFHH)
|
||||
Size 18: 9,21 GOOD (HHFFFF)
|
||||
Size 19: 10,22 BAD (FFHFHH)
|
||||
Size 20: 10,23 GOOD (HHFFFF)
|
||||
Size 21: 11,24 BAD (FFHFHH)
|
||||
Size 22: 11,25 GOOD (HHFFFF)
|
||||
Size 23: 12,26 BAD (FFHFHH)
|
||||
Size 24: 12,27 GOOD (HHFFFF)
|
||||
Size 25: 13,29 BAD (FFHFHH)
|
||||
Size 26: 13,30 GOOD (HHFFFF)
|
||||
Size 27: 14,31 BAD (FFHFHH)
|
||||
Size 28: 14,32 GOOD (HHFFFF)
|
||||
Size 29: 15,33 BAD (FFHFHH)
|
||||
Size 30: 15,34 GOOD (HHFFFF)
|
||||
Size 31: 16,35 BAD (FFHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,38 BAD (FFHFHH)
|
||||
Size 34: 17,39 GOOD (HHFFFF)
|
||||
Size 35: 18,40 BAD (FFHFHH)
|
||||
Size 36: 18,41 GOOD (HHFFFF)
|
||||
Size 37: 19,42 BAD (FFHFHH)
|
||||
Size 38: 19,43 GOOD (HHFFFF)
|
||||
Size 39: 20,44 BAD (FFHFHH)
|
||||
Size 40: 20,46 GOOD (HHFFFF)
|
||||
Size 41: 21,47 BAD (FFHFHH)
|
||||
Size 42: 21,48 GOOD (HHFFFF)
|
||||
Size 43: 22,49 BAD (FFHFHH)
|
||||
Size 44: 22,50 GOOD (HHFFFF)
|
||||
Size 45: 23,51 BAD (FFHFHH)
|
||||
Size 46: 23,52 GOOD (HHFFFF)
|
||||
Size 47: 24,54 BAD (FFHFHH)
|
||||
Size 48: 24,55 GOOD (HHFFFF)
|
||||
Size 49: 25,56 BAD (FFHFHH)
|
||||
Size 50: 25,57 GOOD (HHFFFF)
|
||||
Size 51: 26,58 BAD (FFHFHH)
|
||||
Size 52: 26,59 GOOD (HHFFFF)
|
||||
Size 53: 27,60 BAD (FFHFHH)
|
||||
Size 54: 27,62 GOOD (HHFFFF)
|
||||
Size 55: 28,63 BAD (FFHFHH)
|
||||
Size 56: 28,64 GOOD (HHFFFF)
|
||||
Size 57: 29,65 BAD (FFHFHH)
|
||||
Size 58: 29,66 GOOD (HHFFFF)
|
||||
Size 59: 30,67 BAD (FFHFHH)
|
||||
Size 60: 30,68 GOOD (HHFFFF)
|
||||
Size 61: 31,70 BAD (FFHFHH)
|
||||
Size 62: 31,71 GOOD (HHFFFF)
|
||||
Size 63: 32,72 BAD (FFHFHH)
|
||||
Size 64: 32,73 GOOD (HHFFFF)
|
||||
Size 65: 33,74 GOOD (HHFFFF)
|
||||
Size 66: 33,75 GOOD (HHFFFF)
|
||||
Size 67: 34,76 GOOD (HHFFFF)
|
||||
Size 68: 34,78 GOOD (HHFFFF)
|
||||
Size 69: 35,79 GOOD (HHFFFF)
|
||||
Size 70: 35,80 GOOD (HHFFFF)
|
||||
Size 71: 36,81 GOOD (HHFFFF)
|
||||
Size 72: 36,82 GOOD (HHFFFF)
|
||||
Size 73: 37,83 GOOD (HHFFFF)
|
||||
Size 74: 37,84 GOOD (HHFFFF)
|
||||
Size 75: 38,86 GOOD (HHFFFF)
|
||||
Size 76: 38,87 GOOD (HHFFFF)
|
||||
Size 77: 39,88 GOOD (HHFFFF)
|
||||
Size 78: 39,89 GOOD (HHFFFF)
|
||||
Size 79: 40,90 GOOD (HHFFFF)
|
||||
Size 80: 40,91 GOOD (HHFFFF)
|
||||
Size 81: 41,92 GOOD (HHFFFF)
|
||||
Size 82: 41,94 GOOD (HHFFFF)
|
||||
Size 83: 42,95 GOOD (HHFFFF)
|
||||
Size 84: 42,96 GOOD (HHFFFF)
|
||||
Size 85: 43,97 GOOD (HHFFFF)
|
||||
Size 86: 43,98 GOOD (HHFFFF)
|
||||
Size 87: 44,99 GOOD (HHFFFF)
|
||||
Size 88: 44,100 GOOD (HHFFFF)
|
||||
Size 89: 45,102 GOOD (HHFFFF)
|
||||
Size 90: 45,103 GOOD (HHFFFF)
|
||||
Size 91: 46,104 GOOD (HHFFFF)
|
||||
Size 92: 46,105 GOOD (HHFFFF)
|
||||
Size 93: 47,106 GOOD (HHFFFF)
|
||||
Size 94: 47,107 GOOD (HHFFFF)
|
||||
Size 95: 48,108 GOOD (HHFFFF)
|
||||
Size 96: 48,111 GOOD (HHFFFF)
|
||||
Size 97: 49,111 GOOD (HHFFFF)
|
||||
Size 98: 49,112 GOOD (HHFFFF)
|
||||
Size 99: 50,113 GOOD (HHFFFF)
|
||||
Size 100: 50,114 GOOD (HHFFFF)
|
||||
|
||||
Windows 8.1
|
||||
-----------
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,3 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (FFHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (FFHFHH)
|
||||
Size 8: 4,9 GOOD (HHFFFF)
|
||||
Size 9: 5,10 BAD (FFHFHH)
|
||||
Size 10: 5,11 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (FFHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,15 BAD (FFHFHH)
|
||||
Size 14: 7,16 GOOD (HHFFFF)
|
||||
Size 15: 8,17 BAD (FFHFHH)
|
||||
Size 16: 8,18 GOOD (HHFFFF)
|
||||
Size 17: 9,19 BAD (FFHFHH)
|
||||
Size 18: 9,21 GOOD (HHFFFF)
|
||||
Size 19: 10,22 BAD (FFHFHH)
|
||||
Size 20: 10,23 GOOD (HHFFFF)
|
||||
Size 21: 11,24 BAD (FFHFHH)
|
||||
Size 22: 11,25 GOOD (HHFFFF)
|
||||
Size 23: 12,26 BAD (FFHFHH)
|
||||
Size 24: 12,27 GOOD (HHFFFF)
|
||||
Size 25: 13,29 BAD (FFHFHH)
|
||||
Size 26: 13,30 GOOD (HHFFFF)
|
||||
Size 27: 14,31 BAD (FFHFHH)
|
||||
Size 28: 14,32 GOOD (HHFFFF)
|
||||
Size 29: 15,33 BAD (FFHFHH)
|
||||
Size 30: 15,34 GOOD (HHFFFF)
|
||||
Size 31: 16,35 BAD (FFHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,38 BAD (FFHFHH)
|
||||
Size 34: 17,39 GOOD (HHFFFF)
|
||||
Size 35: 18,40 BAD (FFHFHH)
|
||||
Size 36: 18,41 GOOD (HHFFFF)
|
||||
Size 37: 19,42 BAD (FFHFHH)
|
||||
Size 38: 19,43 GOOD (HHFFFF)
|
||||
Size 39: 20,44 BAD (FFHFHH)
|
||||
Size 40: 20,46 GOOD (HHFFFF)
|
||||
Size 41: 21,47 BAD (FFHFHH)
|
||||
Size 42: 21,48 GOOD (HHFFFF)
|
||||
Size 43: 22,49 BAD (FFHFHH)
|
||||
Size 44: 22,50 GOOD (HHFFFF)
|
||||
Size 45: 23,51 BAD (FFHFHH)
|
||||
Size 46: 23,52 GOOD (HHFFFF)
|
||||
Size 47: 24,54 BAD (FFHFHH)
|
||||
Size 48: 24,55 GOOD (HHFFFF)
|
||||
Size 49: 25,56 BAD (FFHFHH)
|
||||
Size 50: 25,57 GOOD (HHFFFF)
|
||||
Size 51: 26,58 BAD (FFHFHH)
|
||||
Size 52: 26,59 GOOD (HHFFFF)
|
||||
Size 53: 27,60 BAD (FFHFHH)
|
||||
Size 54: 27,62 GOOD (HHFFFF)
|
||||
Size 55: 28,63 BAD (FFHFHH)
|
||||
Size 56: 28,64 GOOD (HHFFFF)
|
||||
Size 57: 29,65 BAD (FFHFHH)
|
||||
Size 58: 29,66 GOOD (HHFFFF)
|
||||
Size 59: 30,67 BAD (FFHFHH)
|
||||
Size 60: 30,68 GOOD (HHFFFF)
|
||||
Size 61: 31,70 BAD (FFHFHH)
|
||||
Size 62: 31,71 GOOD (HHFFFF)
|
||||
Size 63: 32,72 BAD (FFHFHH)
|
||||
Size 64: 32,73 GOOD (HHFFFF)
|
||||
Size 65: 33,74 GOOD (HHFFFF)
|
||||
Size 66: 33,75 GOOD (HHFFFF)
|
||||
Size 67: 34,76 GOOD (HHFFFF)
|
||||
Size 68: 34,78 GOOD (HHFFFF)
|
||||
Size 69: 35,79 GOOD (HHFFFF)
|
||||
Size 70: 35,80 GOOD (HHFFFF)
|
||||
Size 71: 36,81 GOOD (HHFFFF)
|
||||
Size 72: 36,82 GOOD (HHFFFF)
|
||||
Size 73: 37,83 GOOD (HHFFFF)
|
||||
Size 74: 37,84 GOOD (HHFFFF)
|
||||
Size 75: 38,86 GOOD (HHFFFF)
|
||||
Size 76: 38,87 GOOD (HHFFFF)
|
||||
Size 77: 39,88 GOOD (HHFFFF)
|
||||
Size 78: 39,89 GOOD (HHFFFF)
|
||||
Size 79: 40,90 GOOD (HHFFFF)
|
||||
Size 80: 40,91 GOOD (HHFFFF)
|
||||
Size 81: 41,92 GOOD (HHFFFF)
|
||||
Size 82: 41,94 GOOD (HHFFFF)
|
||||
Size 83: 42,95 GOOD (HHFFFF)
|
||||
Size 84: 42,96 GOOD (HHFFFF)
|
||||
Size 85: 43,97 GOOD (HHFFFF)
|
||||
Size 86: 43,98 GOOD (HHFFFF)
|
||||
Size 87: 44,99 GOOD (HHFFFF)
|
||||
Size 88: 44,100 GOOD (HHFFFF)
|
||||
Size 89: 45,102 GOOD (HHFFFF)
|
||||
Size 90: 45,103 GOOD (HHFFFF)
|
||||
Size 91: 46,104 GOOD (HHFFFF)
|
||||
Size 92: 46,105 GOOD (HHFFFF)
|
||||
Size 93: 47,106 GOOD (HHFFFF)
|
||||
Size 94: 47,107 GOOD (HHFFFF)
|
||||
Size 95: 48,108 GOOD (HHFFFF)
|
||||
Size 96: 48,111 GOOD (HHFFFF)
|
||||
Size 97: 49,111 GOOD (HHFFFF)
|
||||
Size 98: 49,112 GOOD (HHFFFF)
|
||||
Size 99: 50,113 GOOD (HHFFFF)
|
||||
Size 100: 50,114 GOOD (HHFFFF)
|
||||
|
||||
Windows 10 14342 Old Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,3 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (FFHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (FFHFHH)
|
||||
Size 8: 4,9 GOOD (HHFFFF)
|
||||
Size 9: 5,10 BAD (FFHFHH)
|
||||
Size 10: 5,11 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (FFHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,15 BAD (FFHFHH)
|
||||
Size 14: 7,16 GOOD (HHFFFF)
|
||||
Size 15: 8,17 BAD (FFHFHH)
|
||||
Size 16: 8,18 GOOD (HHFFFF)
|
||||
Size 17: 9,19 BAD (FFHFHH)
|
||||
Size 18: 9,21 GOOD (HHFFFF)
|
||||
Size 19: 10,22 BAD (FFHFHH)
|
||||
Size 20: 10,23 GOOD (HHFFFF)
|
||||
Size 21: 11,24 BAD (FFHFHH)
|
||||
Size 22: 11,25 GOOD (HHFFFF)
|
||||
Size 23: 12,26 BAD (FFHFHH)
|
||||
Size 24: 12,27 GOOD (HHFFFF)
|
||||
Size 25: 13,29 BAD (FFHFHH)
|
||||
Size 26: 13,30 GOOD (HHFFFF)
|
||||
Size 27: 14,31 BAD (FFHFHH)
|
||||
Size 28: 14,32 GOOD (HHFFFF)
|
||||
Size 29: 15,33 BAD (FFHFHH)
|
||||
Size 30: 15,34 GOOD (HHFFFF)
|
||||
Size 31: 16,35 BAD (FFHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,38 BAD (FFHFHH)
|
||||
Size 34: 17,39 GOOD (HHFFFF)
|
||||
Size 35: 18,40 BAD (FFHFHH)
|
||||
Size 36: 18,41 GOOD (HHFFFF)
|
||||
Size 37: 19,42 BAD (FFHFHH)
|
||||
Size 38: 19,43 GOOD (HHFFFF)
|
||||
Size 39: 20,44 BAD (FFHFHH)
|
||||
Size 40: 20,46 GOOD (HHFFFF)
|
||||
Size 41: 21,47 BAD (FFHFHH)
|
||||
Size 42: 21,48 GOOD (HHFFFF)
|
||||
Size 43: 22,49 BAD (FFHFHH)
|
||||
Size 44: 22,50 GOOD (HHFFFF)
|
||||
Size 45: 23,51 BAD (FFHFHH)
|
||||
Size 46: 23,52 GOOD (HHFFFF)
|
||||
Size 47: 24,54 BAD (FFHFHH)
|
||||
Size 48: 24,55 GOOD (HHFFFF)
|
||||
Size 49: 25,56 BAD (FFHFHH)
|
||||
Size 50: 25,57 GOOD (HHFFFF)
|
||||
Size 51: 26,58 BAD (FFHFHH)
|
||||
Size 52: 26,59 GOOD (HHFFFF)
|
||||
Size 53: 27,60 BAD (FFHFHH)
|
||||
Size 54: 27,62 GOOD (HHFFFF)
|
||||
Size 55: 28,63 BAD (FFHFHH)
|
||||
Size 56: 28,64 GOOD (HHFFFF)
|
||||
Size 57: 29,65 BAD (FFHFHH)
|
||||
Size 58: 29,66 GOOD (HHFFFF)
|
||||
Size 59: 30,67 BAD (FFHFHH)
|
||||
Size 60: 30,68 GOOD (HHFFFF)
|
||||
Size 61: 31,70 BAD (FFHFHH)
|
||||
Size 62: 31,71 GOOD (HHFFFF)
|
||||
Size 63: 32,72 BAD (FFHFHH)
|
||||
Size 64: 32,73 GOOD (HHFFFF)
|
||||
Size 65: 33,74 GOOD (HHFFFF)
|
||||
Size 66: 33,75 GOOD (HHFFFF)
|
||||
Size 67: 34,76 GOOD (HHFFFF)
|
||||
Size 68: 34,78 GOOD (HHFFFF)
|
||||
Size 69: 35,79 GOOD (HHFFFF)
|
||||
Size 70: 35,80 GOOD (HHFFFF)
|
||||
Size 71: 36,81 GOOD (HHFFFF)
|
||||
Size 72: 36,82 GOOD (HHFFFF)
|
||||
Size 73: 37,83 GOOD (HHFFFF)
|
||||
Size 74: 37,84 GOOD (HHFFFF)
|
||||
Size 75: 38,86 GOOD (HHFFFF)
|
||||
Size 76: 38,87 GOOD (HHFFFF)
|
||||
Size 77: 39,88 GOOD (HHFFFF)
|
||||
Size 78: 39,89 GOOD (HHFFFF)
|
||||
Size 79: 40,90 GOOD (HHFFFF)
|
||||
Size 80: 40,91 GOOD (HHFFFF)
|
||||
Size 81: 41,92 GOOD (HHFFFF)
|
||||
Size 82: 41,94 GOOD (HHFFFF)
|
||||
Size 83: 42,95 GOOD (HHFFFF)
|
||||
Size 84: 42,96 GOOD (HHFFFF)
|
||||
Size 85: 43,97 GOOD (HHFFFF)
|
||||
Size 86: 43,98 GOOD (HHFFFF)
|
||||
Size 87: 44,99 GOOD (HHFFFF)
|
||||
Size 88: 44,100 GOOD (HHFFFF)
|
||||
Size 89: 45,102 GOOD (HHFFFF)
|
||||
Size 90: 45,103 GOOD (HHFFFF)
|
||||
Size 91: 46,104 GOOD (HHFFFF)
|
||||
Size 92: 46,105 GOOD (HHFFFF)
|
||||
Size 93: 47,106 GOOD (HHFFFF)
|
||||
Size 94: 47,107 GOOD (HHFFFF)
|
||||
Size 95: 48,108 GOOD (HHFFFF)
|
||||
Size 96: 48,111 GOOD (HHFFFF)
|
||||
Size 97: 49,111 GOOD (HHFFFF)
|
||||
Size 98: 49,112 GOOD (HHFFFF)
|
||||
Size 99: 50,113 GOOD (HHFFFF)
|
||||
Size 100: 50,114 GOOD (HHFFFF)
|
||||
|
||||
Windows 10 14342 New Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,1 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,3 GOOD (HHFFFF)
|
||||
Size 4: 2,4 GOOD (HHFFFF)
|
||||
Size 5: 3,5 GOOD (HHFFFF)
|
||||
Size 6: 3,6 GOOD (HHFFFF)
|
||||
Size 7: 4,7 GOOD (HHFFFF)
|
||||
Size 8: 4,8 GOOD (HHFFFF)
|
||||
Size 9: 5,9 GOOD (HHFFFF)
|
||||
Size 10: 5,10 GOOD (HHFFFF)
|
||||
Size 11: 6,11 GOOD (HHFFFF)
|
||||
Size 12: 6,12 GOOD (HHFFFF)
|
||||
Size 13: 7,13 GOOD (HHFFFF)
|
||||
Size 14: 7,14 GOOD (HHFFFF)
|
||||
Size 15: 8,15 GOOD (HHFFFF)
|
||||
Size 16: 8,16 GOOD (HHFFFF)
|
||||
Size 17: 9,17 GOOD (HHFFFF)
|
||||
Size 18: 9,18 GOOD (HHFFFF)
|
||||
Size 19: 10,19 GOOD (HHFFFF)
|
||||
Size 20: 10,20 GOOD (HHFFFF)
|
||||
Size 21: 11,21 GOOD (HHFFFF)
|
||||
Size 22: 11,22 GOOD (HHFFFF)
|
||||
Size 23: 12,23 GOOD (HHFFFF)
|
||||
Size 24: 12,24 GOOD (HHFFFF)
|
||||
Size 25: 13,25 GOOD (HHFFFF)
|
||||
Size 26: 13,26 GOOD (HHFFFF)
|
||||
Size 27: 14,27 GOOD (HHFFFF)
|
||||
Size 28: 14,28 GOOD (HHFFFF)
|
||||
Size 29: 15,29 GOOD (HHFFFF)
|
||||
Size 30: 15,30 GOOD (HHFFFF)
|
||||
Size 31: 16,31 GOOD (HHFFFF)
|
||||
Size 32: 16,32 GOOD (HHFFFF)
|
||||
Size 33: 17,33 GOOD (HHFFFF)
|
||||
Size 34: 17,34 GOOD (HHFFFF)
|
||||
Size 35: 18,35 GOOD (HHFFFF)
|
||||
Size 36: 18,36 GOOD (HHFFFF)
|
||||
Size 37: 19,37 GOOD (HHFFFF)
|
||||
Size 38: 19,38 GOOD (HHFFFF)
|
||||
Size 39: 20,39 GOOD (HHFFFF)
|
||||
Size 40: 20,40 GOOD (HHFFFF)
|
||||
Size 41: 21,41 GOOD (HHFFFF)
|
||||
Size 42: 21,42 GOOD (HHFFFF)
|
||||
Size 43: 22,43 GOOD (HHFFFF)
|
||||
Size 44: 22,44 GOOD (HHFFFF)
|
||||
Size 45: 23,45 GOOD (HHFFFF)
|
||||
Size 46: 23,46 GOOD (HHFFFF)
|
||||
Size 47: 24,47 GOOD (HHFFFF)
|
||||
Size 48: 24,48 GOOD (HHFFFF)
|
||||
Size 49: 25,49 GOOD (HHFFFF)
|
||||
Size 50: 25,50 GOOD (HHFFFF)
|
||||
Size 51: 26,51 GOOD (HHFFFF)
|
||||
Size 52: 26,52 GOOD (HHFFFF)
|
||||
Size 53: 27,53 GOOD (HHFFFF)
|
||||
Size 54: 27,54 GOOD (HHFFFF)
|
||||
Size 55: 28,55 GOOD (HHFFFF)
|
||||
Size 56: 28,56 GOOD (HHFFFF)
|
||||
Size 57: 29,57 GOOD (HHFFFF)
|
||||
Size 58: 29,58 GOOD (HHFFFF)
|
||||
Size 59: 30,59 GOOD (HHFFFF)
|
||||
Size 60: 30,60 GOOD (HHFFFF)
|
||||
Size 61: 31,61 GOOD (HHFFFF)
|
||||
Size 62: 31,62 GOOD (HHFFFF)
|
||||
Size 63: 32,63 GOOD (HHFFFF)
|
||||
Size 64: 32,64 GOOD (HHFFFF)
|
||||
Size 65: 33,65 GOOD (HHFFFF)
|
||||
Size 66: 33,66 GOOD (HHFFFF)
|
||||
Size 67: 34,67 GOOD (HHFFFF)
|
||||
Size 68: 34,68 GOOD (HHFFFF)
|
||||
Size 69: 35,69 GOOD (HHFFFF)
|
||||
Size 70: 35,70 GOOD (HHFFFF)
|
||||
Size 71: 36,71 GOOD (HHFFFF)
|
||||
Size 72: 36,72 GOOD (HHFFFF)
|
||||
Size 73: 37,73 GOOD (HHFFFF)
|
||||
Size 74: 37,74 GOOD (HHFFFF)
|
||||
Size 75: 38,75 GOOD (HHFFFF)
|
||||
Size 76: 38,76 GOOD (HHFFFF)
|
||||
Size 77: 39,77 GOOD (HHFFFF)
|
||||
Size 78: 39,78 GOOD (HHFFFF)
|
||||
Size 79: 40,79 GOOD (HHFFFF)
|
||||
Size 80: 40,80 GOOD (HHFFFF)
|
||||
Size 81: 41,81 GOOD (HHFFFF)
|
||||
Size 82: 41,82 GOOD (HHFFFF)
|
||||
Size 83: 42,83 GOOD (HHFFFF)
|
||||
Size 84: 42,84 GOOD (HHFFFF)
|
||||
Size 85: 43,85 GOOD (HHFFFF)
|
||||
Size 86: 43,86 GOOD (HHFFFF)
|
||||
Size 87: 44,87 GOOD (HHFFFF)
|
||||
Size 88: 44,88 GOOD (HHFFFF)
|
||||
Size 89: 45,89 GOOD (HHFFFF)
|
||||
Size 90: 45,90 GOOD (HHFFFF)
|
||||
Size 91: 46,91 GOOD (HHFFFF)
|
||||
Size 92: 46,92 GOOD (HHFFFF)
|
||||
Size 93: 47,93 GOOD (HHFFFF)
|
||||
Size 94: 47,94 GOOD (HHFFFF)
|
||||
Size 95: 48,95 GOOD (HHFFFF)
|
||||
Size 96: 48,96 GOOD (HHFFFF)
|
||||
Size 97: 49,97 GOOD (HHFFFF)
|
||||
Size 98: 49,98 GOOD (HHFFFF)
|
||||
Size 99: 50,99 GOOD (HHFFFF)
|
||||
Size 100: 50,100 GOOD (HHFFFF)
|
@ -1,630 +0,0 @@
|
||||
=====================================
|
||||
Code Page 949, Korean, GulimChe font
|
||||
=====================================
|
||||
|
||||
Options: -face-gulimche -family 0x36
|
||||
Chars: A2 A3 2014 3044 30FC 4000
|
||||
|
||||
Vista
|
||||
-----
|
||||
|
||||
Size 1: 1,2 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 BAD (FFFFHH)
|
||||
Size 4: 2,5 OK (HHHFFF)
|
||||
Size 5: 3,6 BAD (HHHFHH)
|
||||
Size 6: 3,7 OK (HHHFFF)
|
||||
Size 7: 4,8 BAD (HHHFHH)
|
||||
Size 8: 4,9 OK (HHHFFF)
|
||||
Size 9: 5,10 BAD (HHHFHH)
|
||||
Size 10: 5,11 OK (HHHFFF)
|
||||
Size 11: 6,13 BAD (HHHFHH)
|
||||
Size 12: 6,14 OK (HHHFFF)
|
||||
Size 13: 7,15 BAD (HHHFHH)
|
||||
Size 14: 7,16 OK (HHHFFF)
|
||||
Size 15: 8,17 BAD (HHHFHH)
|
||||
Size 16: 8,18 OK (HHHFFF)
|
||||
Size 17: 9,20 BAD (HHHFHH)
|
||||
Size 18: 9,21 OK (HHHFFF)
|
||||
Size 19: 10,22 BAD (HHHFHH)
|
||||
Size 20: 10,23 OK (HHHFFF)
|
||||
Size 21: 11,24 BAD (HHHFHH)
|
||||
Size 22: 11,25 OK (HHHFFF)
|
||||
Size 23: 12,26 BAD (HHHFHH)
|
||||
Size 24: 12,28 OK (HHHFFF)
|
||||
Size 25: 13,29 BAD (HHHFHH)
|
||||
Size 26: 13,30 OK (HHHFFF)
|
||||
Size 27: 14,31 BAD (HHHFHH)
|
||||
Size 28: 14,32 OK (HHHFFF)
|
||||
Size 29: 15,33 BAD (HHHFHH)
|
||||
Size 30: 15,34 OK (HHHFFF)
|
||||
Size 31: 16,36 BAD (HHHFHH)
|
||||
Size 32: 16,37 OK (HHHFFF)
|
||||
Size 33: 17,38 BAD (HHHFHH)
|
||||
Size 34: 17,39 OK (HHHFFF)
|
||||
Size 35: 18,40 BAD (HHHFHH)
|
||||
Size 36: 18,41 OK (HHHFFF)
|
||||
Size 37: 19,42 BAD (HHHFHH)
|
||||
Size 38: 19,44 OK (HHHFFF)
|
||||
Size 39: 20,45 BAD (HHHFHH)
|
||||
Size 40: 20,46 OK (HHHFFF)
|
||||
Size 41: 21,47 BAD (HHHFHH)
|
||||
Size 42: 21,48 OK (HHHFFF)
|
||||
Size 43: 22,49 BAD (HHHFHH)
|
||||
Size 44: 22,51 OK (HHHFFF)
|
||||
Size 45: 23,52 BAD (HHHFHH)
|
||||
Size 46: 23,53 OK (HHHFFF)
|
||||
Size 47: 24,54 BAD (HHHFHH)
|
||||
Size 48: 24,55 OK (HHHFFF)
|
||||
Size 49: 25,56 BAD (HHHFHH)
|
||||
Size 50: 25,57 OK (HHHFFF)
|
||||
Size 51: 26,59 BAD (HHHFHH)
|
||||
Size 52: 26,60 OK (HHHFFF)
|
||||
Size 53: 27,61 BAD (HHHFHH)
|
||||
Size 54: 27,62 OK (HHHFFF)
|
||||
Size 55: 28,63 BAD (HHHFHH)
|
||||
Size 56: 28,64 OK (HHHFFF)
|
||||
Size 57: 29,65 BAD (HHHFHH)
|
||||
Size 58: 29,67 OK (HHHFFF)
|
||||
Size 59: 30,68 BAD (HHHFHH)
|
||||
Size 60: 30,69 OK (HHHFFF)
|
||||
Size 61: 31,70 BAD (HHHFHH)
|
||||
Size 62: 31,71 OK (HHHFFF)
|
||||
Size 63: 32,72 BAD (HHHFHH)
|
||||
Size 64: 32,74 OK (HHHFFF)
|
||||
Size 65: 33,75 BAD (HHHFHH)
|
||||
Size 66: 33,76 OK (HHHFFF)
|
||||
Size 67: 34,77 BAD (HHHFHH)
|
||||
Size 68: 34,78 OK (HHHFFF)
|
||||
Size 69: 35,79 BAD (HHHFHH)
|
||||
Size 70: 35,80 OK (HHHFFF)
|
||||
Size 71: 36,82 BAD (HHHFHH)
|
||||
Size 72: 36,83 OK (HHHFFF)
|
||||
Size 73: 37,84 BAD (HHHFHH)
|
||||
Size 74: 37,85 OK (HHHFFF)
|
||||
Size 75: 38,86 BAD (HHHFHH)
|
||||
Size 76: 38,87 OK (HHHFFF)
|
||||
Size 77: 39,88 BAD (HHHFHH)
|
||||
Size 78: 39,90 OK (HHHFFF)
|
||||
Size 79: 40,91 BAD (HHHFHH)
|
||||
Size 80: 40,92 OK (HHHFFF)
|
||||
Size 81: 41,93 BAD (HHHFHH)
|
||||
Size 82: 41,94 OK (HHHFFF)
|
||||
Size 83: 42,95 BAD (HHHFHH)
|
||||
Size 84: 42,96 OK (HHHFFF)
|
||||
Size 85: 43,98 BAD (HHHFHH)
|
||||
Size 86: 43,99 OK (HHHFFF)
|
||||
Size 87: 44,100 BAD (HHHFHH)
|
||||
Size 88: 44,101 OK (HHHFFF)
|
||||
Size 89: 45,102 BAD (HHHFHH)
|
||||
Size 90: 45,103 OK (HHHFFF)
|
||||
Size 91: 46,105 BAD (HHHFHH)
|
||||
Size 92: 46,106 OK (HHHFFF)
|
||||
Size 93: 47,107 BAD (HHHFHH)
|
||||
Size 94: 47,108 OK (HHHFFF)
|
||||
Size 95: 48,109 BAD (HHHFHH)
|
||||
Size 96: 48,110 OK (HHHFFF)
|
||||
Size 97: 49,111 BAD (HHHFHH)
|
||||
Size 98: 49,113 OK (HHHFFF)
|
||||
Size 99: 50,114 BAD (HHHFHH)
|
||||
Size 100: 50,115 OK (HHHFFF)
|
||||
|
||||
Windows 7
|
||||
---------
|
||||
|
||||
Size 1: 1,2 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 BAD (FFFFHH)
|
||||
Size 4: 2,5 OK (HHHFFF)
|
||||
Size 5: 3,6 BAD (FFFFHH)
|
||||
Size 6: 3,7 OK (HHHFFF)
|
||||
Size 7: 4,8 BAD (FFFFHH)
|
||||
Size 8: 4,9 OK (HHHFFF)
|
||||
Size 9: 5,10 BAD (FFFFHH)
|
||||
Size 10: 5,11 OK (HHHFFF)
|
||||
Size 11: 6,13 BAD (FFFFHH)
|
||||
Size 12: 6,14 OK (HHHFFF)
|
||||
Size 13: 7,15 BAD (FFFFHH)
|
||||
Size 14: 7,16 OK (HHHFFF)
|
||||
Size 15: 8,17 BAD (FFFFHH)
|
||||
Size 16: 8,18 OK (HHHFFF)
|
||||
Size 17: 9,20 BAD (FFFFHH)
|
||||
Size 18: 9,21 OK (HHHFFF)
|
||||
Size 19: 10,22 BAD (FFFFHH)
|
||||
Size 20: 10,23 OK (HHHFFF)
|
||||
Size 21: 11,24 BAD (FFFFHH)
|
||||
Size 22: 11,25 OK (HHHFFF)
|
||||
Size 23: 12,26 BAD (FFFFHH)
|
||||
Size 24: 12,28 OK (HHHFFF)
|
||||
Size 25: 13,29 BAD (FFFFHH)
|
||||
Size 26: 13,30 OK (HHHFFF)
|
||||
Size 27: 14,31 BAD (FFFFHH)
|
||||
Size 28: 14,32 OK (HHHFFF)
|
||||
Size 29: 15,33 BAD (FFFFHH)
|
||||
Size 30: 15,34 OK (HHHFFF)
|
||||
Size 31: 16,36 BAD (FFFFHH)
|
||||
Size 32: 16,37 OK (HHHFFF)
|
||||
Size 33: 17,38 BAD (FFFFHH)
|
||||
Size 34: 17,39 OK (HHHFFF)
|
||||
Size 35: 18,40 BAD (FFFFHH)
|
||||
Size 36: 18,41 OK (HHHFFF)
|
||||
Size 37: 19,42 BAD (FFFFHH)
|
||||
Size 38: 19,44 OK (HHHFFF)
|
||||
Size 39: 20,45 BAD (FFFFHH)
|
||||
Size 40: 20,46 OK (HHHFFF)
|
||||
Size 41: 21,47 BAD (FFFFHH)
|
||||
Size 42: 21,48 OK (HHHFFF)
|
||||
Size 43: 22,49 BAD (FFFFHH)
|
||||
Size 44: 22,51 OK (HHHFFF)
|
||||
Size 45: 23,52 BAD (FFFFHH)
|
||||
Size 46: 23,53 OK (HHHFFF)
|
||||
Size 47: 24,54 BAD (FFFFHH)
|
||||
Size 48: 24,55 OK (HHHFFF)
|
||||
Size 49: 25,56 BAD (FFFFHH)
|
||||
Size 50: 25,57 OK (HHHFFF)
|
||||
Size 51: 26,59 BAD (FFFFHH)
|
||||
Size 52: 26,60 OK (HHHFFF)
|
||||
Size 53: 27,61 BAD (FFFFHH)
|
||||
Size 54: 27,62 OK (HHHFFF)
|
||||
Size 55: 28,63 BAD (FFFFHH)
|
||||
Size 56: 28,64 OK (HHHFFF)
|
||||
Size 57: 29,65 BAD (FFFFHH)
|
||||
Size 58: 29,67 OK (HHHFFF)
|
||||
Size 59: 30,68 BAD (FFFFHH)
|
||||
Size 60: 30,69 OK (HHHFFF)
|
||||
Size 61: 31,70 BAD (FFFFHH)
|
||||
Size 62: 31,71 OK (HHHFFF)
|
||||
Size 63: 32,72 BAD (FFFFHH)
|
||||
Size 64: 32,74 OK (HHHFFF)
|
||||
Size 65: 33,75 BAD (FFFFHH)
|
||||
Size 66: 33,76 OK (HHHFFF)
|
||||
Size 67: 34,77 BAD (FFFFHH)
|
||||
Size 68: 34,78 OK (HHHFFF)
|
||||
Size 69: 35,79 BAD (FFFFHH)
|
||||
Size 70: 35,80 OK (HHHFFF)
|
||||
Size 71: 36,82 BAD (FFFFHH)
|
||||
Size 72: 36,83 OK (HHHFFF)
|
||||
Size 73: 37,84 BAD (FFFFHH)
|
||||
Size 74: 37,85 OK (HHHFFF)
|
||||
Size 75: 38,86 BAD (FFFFHH)
|
||||
Size 76: 38,87 OK (HHHFFF)
|
||||
Size 77: 39,88 BAD (FFFFHH)
|
||||
Size 78: 39,90 OK (HHHFFF)
|
||||
Size 79: 40,91 BAD (FFFFHH)
|
||||
Size 80: 40,92 OK (HHHFFF)
|
||||
Size 81: 41,93 BAD (FFFFHH)
|
||||
Size 82: 41,94 OK (HHHFFF)
|
||||
Size 83: 42,95 BAD (FFFFHH)
|
||||
Size 84: 42,96 OK (HHHFFF)
|
||||
Size 85: 43,98 BAD (FFFFHH)
|
||||
Size 86: 43,99 OK (HHHFFF)
|
||||
Size 87: 44,100 BAD (FFFFHH)
|
||||
Size 88: 44,101 OK (HHHFFF)
|
||||
Size 89: 45,102 BAD (FFFFHH)
|
||||
Size 90: 45,103 OK (HHHFFF)
|
||||
Size 91: 46,105 BAD (FFFFHH)
|
||||
Size 92: 46,106 OK (HHHFFF)
|
||||
Size 93: 47,107 BAD (FFFFHH)
|
||||
Size 94: 47,108 OK (HHHFFF)
|
||||
Size 95: 48,109 BAD (FFFFHH)
|
||||
Size 96: 48,110 OK (HHHFFF)
|
||||
Size 97: 49,111 BAD (FFFFHH)
|
||||
Size 98: 49,113 OK (HHHFFF)
|
||||
Size 99: 50,114 BAD (FFFFHH)
|
||||
Size 100: 50,115 OK (HHHFFF)
|
||||
|
||||
Windows 8
|
||||
---------
|
||||
|
||||
Size 1: 1,2 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 BAD (FFFFHH)
|
||||
Size 4: 2,5 OK (HHHFFF)
|
||||
Size 5: 3,6 BAD (FFFFHH)
|
||||
Size 6: 3,7 OK (HHHFFF)
|
||||
Size 7: 4,8 BAD (FFFFHH)
|
||||
Size 8: 4,9 OK (HHHFFF)
|
||||
Size 9: 5,10 BAD (FFFFHH)
|
||||
Size 10: 5,11 OK (HHHFFF)
|
||||
Size 11: 6,13 BAD (FFFFHH)
|
||||
Size 12: 6,14 OK (HHHFFF)
|
||||
Size 13: 7,15 BAD (FFFFHH)
|
||||
Size 14: 7,16 OK (HHHFFF)
|
||||
Size 15: 8,17 BAD (FFFFHH)
|
||||
Size 16: 8,18 OK (HHHFFF)
|
||||
Size 17: 9,20 BAD (FFFFHH)
|
||||
Size 18: 9,21 OK (HHHFFF)
|
||||
Size 19: 10,22 BAD (FFFFHH)
|
||||
Size 20: 10,23 OK (HHHFFF)
|
||||
Size 21: 11,24 BAD (FFFFHH)
|
||||
Size 22: 11,25 OK (HHHFFF)
|
||||
Size 23: 12,26 BAD (FFFFHH)
|
||||
Size 24: 12,28 OK (HHHFFF)
|
||||
Size 25: 13,29 BAD (FFFFHH)
|
||||
Size 26: 13,30 OK (HHHFFF)
|
||||
Size 27: 14,31 BAD (FFFFHH)
|
||||
Size 28: 14,32 OK (HHHFFF)
|
||||
Size 29: 15,33 BAD (FFFFHH)
|
||||
Size 30: 15,34 OK (HHHFFF)
|
||||
Size 31: 16,36 BAD (FFFFHH)
|
||||
Size 32: 16,37 OK (HHHFFF)
|
||||
Size 33: 17,38 BAD (FFFFHH)
|
||||
Size 34: 17,39 OK (HHHFFF)
|
||||
Size 35: 18,40 BAD (FFFFHH)
|
||||
Size 36: 18,41 OK (HHHFFF)
|
||||
Size 37: 19,42 BAD (FFFFHH)
|
||||
Size 38: 19,44 OK (HHHFFF)
|
||||
Size 39: 20,45 BAD (FFFFHH)
|
||||
Size 40: 20,46 OK (HHHFFF)
|
||||
Size 41: 21,47 BAD (FFFFHH)
|
||||
Size 42: 21,48 OK (HHHFFF)
|
||||
Size 43: 22,49 BAD (FFFFHH)
|
||||
Size 44: 22,51 OK (HHHFFF)
|
||||
Size 45: 23,52 BAD (FFFFHH)
|
||||
Size 46: 23,53 OK (HHHFFF)
|
||||
Size 47: 24,54 BAD (FFFFHH)
|
||||
Size 48: 24,55 OK (HHHFFF)
|
||||
Size 49: 25,56 BAD (FFFFHH)
|
||||
Size 50: 25,57 OK (HHHFFF)
|
||||
Size 51: 26,59 BAD (FFFFHH)
|
||||
Size 52: 26,60 OK (HHHFFF)
|
||||
Size 53: 27,61 BAD (FFFFHH)
|
||||
Size 54: 27,62 OK (HHHFFF)
|
||||
Size 55: 28,63 BAD (FFFFHH)
|
||||
Size 56: 28,64 OK (HHHFFF)
|
||||
Size 57: 29,65 BAD (FFFFHH)
|
||||
Size 58: 29,67 OK (HHHFFF)
|
||||
Size 59: 30,68 BAD (FFFFHH)
|
||||
Size 60: 30,69 OK (HHHFFF)
|
||||
Size 61: 31,70 BAD (FFFFHH)
|
||||
Size 62: 31,71 OK (HHHFFF)
|
||||
Size 63: 32,72 BAD (FFFFHH)
|
||||
Size 64: 32,74 OK (HHHFFF)
|
||||
Size 65: 33,75 BAD (FFFFHH)
|
||||
Size 66: 33,76 OK (HHHFFF)
|
||||
Size 67: 34,77 BAD (FFFFHH)
|
||||
Size 68: 34,78 OK (HHHFFF)
|
||||
Size 69: 35,79 BAD (FFFFHH)
|
||||
Size 70: 35,80 OK (HHHFFF)
|
||||
Size 71: 36,82 BAD (FFFFHH)
|
||||
Size 72: 36,83 OK (HHHFFF)
|
||||
Size 73: 37,84 BAD (FFFFHH)
|
||||
Size 74: 37,85 OK (HHHFFF)
|
||||
Size 75: 38,86 BAD (FFFFHH)
|
||||
Size 76: 38,87 OK (HHHFFF)
|
||||
Size 77: 39,88 BAD (FFFFHH)
|
||||
Size 78: 39,90 OK (HHHFFF)
|
||||
Size 79: 40,91 BAD (FFFFHH)
|
||||
Size 80: 40,92 OK (HHHFFF)
|
||||
Size 81: 41,93 BAD (FFFFHH)
|
||||
Size 82: 41,94 OK (HHHFFF)
|
||||
Size 83: 42,95 BAD (FFFFHH)
|
||||
Size 84: 42,96 OK (HHHFFF)
|
||||
Size 85: 43,98 BAD (FFFFHH)
|
||||
Size 86: 43,99 OK (HHHFFF)
|
||||
Size 87: 44,100 BAD (FFFFHH)
|
||||
Size 88: 44,101 OK (HHHFFF)
|
||||
Size 89: 45,102 BAD (FFFFHH)
|
||||
Size 90: 45,103 OK (HHHFFF)
|
||||
Size 91: 46,105 BAD (FFFFHH)
|
||||
Size 92: 46,106 OK (HHHFFF)
|
||||
Size 93: 47,107 BAD (FFFFHH)
|
||||
Size 94: 47,108 OK (HHHFFF)
|
||||
Size 95: 48,109 BAD (FFFFHH)
|
||||
Size 96: 48,110 OK (HHHFFF)
|
||||
Size 97: 49,111 BAD (FFFFHH)
|
||||
Size 98: 49,113 OK (HHHFFF)
|
||||
Size 99: 50,114 BAD (FFFFHH)
|
||||
Size 100: 50,115 OK (HHHFFF)
|
||||
|
||||
Windows 8.1
|
||||
-----------
|
||||
|
||||
Size 1: 1,2 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 BAD (FFFFHH)
|
||||
Size 4: 2,5 OK (HHHFFF)
|
||||
Size 5: 3,6 BAD (FFFFHH)
|
||||
Size 6: 3,7 OK (HHHFFF)
|
||||
Size 7: 4,8 BAD (FFFFHH)
|
||||
Size 8: 4,9 OK (HHHFFF)
|
||||
Size 9: 5,10 BAD (FFFFHH)
|
||||
Size 10: 5,11 OK (HHHFFF)
|
||||
Size 11: 6,13 BAD (FFFFHH)
|
||||
Size 12: 6,14 OK (HHHFFF)
|
||||
Size 13: 7,15 BAD (FFFFHH)
|
||||
Size 14: 7,16 OK (HHHFFF)
|
||||
Size 15: 8,17 BAD (FFFFHH)
|
||||
Size 16: 8,18 OK (HHHFFF)
|
||||
Size 17: 9,20 BAD (FFFFHH)
|
||||
Size 18: 9,21 OK (HHHFFF)
|
||||
Size 19: 10,22 BAD (FFFFHH)
|
||||
Size 20: 10,23 OK (HHHFFF)
|
||||
Size 21: 11,24 BAD (FFFFHH)
|
||||
Size 22: 11,25 OK (HHHFFF)
|
||||
Size 23: 12,26 BAD (FFFFHH)
|
||||
Size 24: 12,28 OK (HHHFFF)
|
||||
Size 25: 13,29 BAD (FFFFHH)
|
||||
Size 26: 13,30 OK (HHHFFF)
|
||||
Size 27: 14,31 BAD (FFFFHH)
|
||||
Size 28: 14,32 OK (HHHFFF)
|
||||
Size 29: 15,33 BAD (FFFFHH)
|
||||
Size 30: 15,34 OK (HHHFFF)
|
||||
Size 31: 16,36 BAD (FFFFHH)
|
||||
Size 32: 16,37 OK (HHHFFF)
|
||||
Size 33: 17,38 BAD (FFFFHH)
|
||||
Size 34: 17,39 OK (HHHFFF)
|
||||
Size 35: 18,40 BAD (FFFFHH)
|
||||
Size 36: 18,41 OK (HHHFFF)
|
||||
Size 37: 19,42 BAD (FFFFHH)
|
||||
Size 38: 19,44 OK (HHHFFF)
|
||||
Size 39: 20,45 BAD (FFFFHH)
|
||||
Size 40: 20,46 OK (HHHFFF)
|
||||
Size 41: 21,47 BAD (FFFFHH)
|
||||
Size 42: 21,48 OK (HHHFFF)
|
||||
Size 43: 22,49 BAD (FFFFHH)
|
||||
Size 44: 22,51 OK (HHHFFF)
|
||||
Size 45: 23,52 BAD (FFFFHH)
|
||||
Size 46: 23,53 OK (HHHFFF)
|
||||
Size 47: 24,54 BAD (FFFFHH)
|
||||
Size 48: 24,55 OK (HHHFFF)
|
||||
Size 49: 25,56 BAD (FFFFHH)
|
||||
Size 50: 25,57 OK (HHHFFF)
|
||||
Size 51: 26,59 BAD (FFFFHH)
|
||||
Size 52: 26,60 OK (HHHFFF)
|
||||
Size 53: 27,61 BAD (FFFFHH)
|
||||
Size 54: 27,62 OK (HHHFFF)
|
||||
Size 55: 28,63 BAD (FFFFHH)
|
||||
Size 56: 28,64 OK (HHHFFF)
|
||||
Size 57: 29,65 BAD (FFFFHH)
|
||||
Size 58: 29,67 OK (HHHFFF)
|
||||
Size 59: 30,68 BAD (FFFFHH)
|
||||
Size 60: 30,69 OK (HHHFFF)
|
||||
Size 61: 31,70 BAD (FFFFHH)
|
||||
Size 62: 31,71 OK (HHHFFF)
|
||||
Size 63: 32,72 BAD (FFFFHH)
|
||||
Size 64: 32,74 OK (HHHFFF)
|
||||
Size 65: 33,75 BAD (FFFFHH)
|
||||
Size 66: 33,76 OK (HHHFFF)
|
||||
Size 67: 34,77 BAD (FFFFHH)
|
||||
Size 68: 34,78 OK (HHHFFF)
|
||||
Size 69: 35,79 BAD (FFFFHH)
|
||||
Size 70: 35,80 OK (HHHFFF)
|
||||
Size 71: 36,82 BAD (FFFFHH)
|
||||
Size 72: 36,83 OK (HHHFFF)
|
||||
Size 73: 37,84 BAD (FFFFHH)
|
||||
Size 74: 37,85 OK (HHHFFF)
|
||||
Size 75: 38,86 BAD (FFFFHH)
|
||||
Size 76: 38,87 OK (HHHFFF)
|
||||
Size 77: 39,88 BAD (FFFFHH)
|
||||
Size 78: 39,90 OK (HHHFFF)
|
||||
Size 79: 40,91 BAD (FFFFHH)
|
||||
Size 80: 40,92 OK (HHHFFF)
|
||||
Size 81: 41,93 BAD (FFFFHH)
|
||||
Size 82: 41,94 OK (HHHFFF)
|
||||
Size 83: 42,95 BAD (FFFFHH)
|
||||
Size 84: 42,96 OK (HHHFFF)
|
||||
Size 85: 43,98 BAD (FFFFHH)
|
||||
Size 86: 43,99 OK (HHHFFF)
|
||||
Size 87: 44,100 BAD (FFFFHH)
|
||||
Size 88: 44,101 OK (HHHFFF)
|
||||
Size 89: 45,102 BAD (FFFFHH)
|
||||
Size 90: 45,103 OK (HHHFFF)
|
||||
Size 91: 46,105 BAD (FFFFHH)
|
||||
Size 92: 46,106 OK (HHHFFF)
|
||||
Size 93: 47,107 BAD (FFFFHH)
|
||||
Size 94: 47,108 OK (HHHFFF)
|
||||
Size 95: 48,109 BAD (FFFFHH)
|
||||
Size 96: 48,110 OK (HHHFFF)
|
||||
Size 97: 49,111 BAD (FFFFHH)
|
||||
Size 98: 49,113 OK (HHHFFF)
|
||||
Size 99: 50,114 BAD (FFFFHH)
|
||||
Size 100: 50,115 OK (HHHFFF)
|
||||
|
||||
Windows 10 14342 Old Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,2 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 BAD (FFFFHH)
|
||||
Size 4: 2,5 OK (HHHFFF)
|
||||
Size 5: 3,6 BAD (FFFFHH)
|
||||
Size 6: 3,7 OK (HHHFFF)
|
||||
Size 7: 4,8 BAD (FFFFHH)
|
||||
Size 8: 4,9 OK (HHHFFF)
|
||||
Size 9: 5,10 BAD (FFFFHH)
|
||||
Size 10: 5,11 OK (HHHFFF)
|
||||
Size 11: 6,13 BAD (FFFFHH)
|
||||
Size 12: 6,14 OK (HHHFFF)
|
||||
Size 13: 7,15 BAD (FFFFHH)
|
||||
Size 14: 7,16 OK (HHHFFF)
|
||||
Size 15: 8,17 BAD (FFFFHH)
|
||||
Size 16: 8,18 OK (HHHFFF)
|
||||
Size 17: 9,20 BAD (FFFFHH)
|
||||
Size 18: 9,21 OK (HHHFFF)
|
||||
Size 19: 10,22 BAD (FFFFHH)
|
||||
Size 20: 10,23 OK (HHHFFF)
|
||||
Size 21: 11,24 BAD (FFFFHH)
|
||||
Size 22: 11,25 OK (HHHFFF)
|
||||
Size 23: 12,26 BAD (FFFFHH)
|
||||
Size 24: 12,28 OK (HHHFFF)
|
||||
Size 25: 13,29 BAD (FFFFHH)
|
||||
Size 26: 13,30 OK (HHHFFF)
|
||||
Size 27: 14,31 BAD (FFFFHH)
|
||||
Size 28: 14,32 OK (HHHFFF)
|
||||
Size 29: 15,33 BAD (FFFFHH)
|
||||
Size 30: 15,34 OK (HHHFFF)
|
||||
Size 31: 16,36 BAD (FFFFHH)
|
||||
Size 32: 16,37 OK (HHHFFF)
|
||||
Size 33: 17,38 BAD (FFFFHH)
|
||||
Size 34: 17,39 OK (HHHFFF)
|
||||
Size 35: 18,40 BAD (FFFFHH)
|
||||
Size 36: 18,41 OK (HHHFFF)
|
||||
Size 37: 19,42 BAD (FFFFHH)
|
||||
Size 38: 19,44 OK (HHHFFF)
|
||||
Size 39: 20,45 BAD (FFFFHH)
|
||||
Size 40: 20,46 OK (HHHFFF)
|
||||
Size 41: 21,47 BAD (FFFFHH)
|
||||
Size 42: 21,48 OK (HHHFFF)
|
||||
Size 43: 22,49 BAD (FFFFHH)
|
||||
Size 44: 22,51 OK (HHHFFF)
|
||||
Size 45: 23,52 BAD (FFFFHH)
|
||||
Size 46: 23,53 OK (HHHFFF)
|
||||
Size 47: 24,54 BAD (FFFFHH)
|
||||
Size 48: 24,55 OK (HHHFFF)
|
||||
Size 49: 25,56 BAD (FFFFHH)
|
||||
Size 50: 25,57 OK (HHHFFF)
|
||||
Size 51: 26,59 BAD (FFFFHH)
|
||||
Size 52: 26,60 OK (HHHFFF)
|
||||
Size 53: 27,61 BAD (FFFFHH)
|
||||
Size 54: 27,62 OK (HHHFFF)
|
||||
Size 55: 28,63 BAD (FFFFHH)
|
||||
Size 56: 28,64 OK (HHHFFF)
|
||||
Size 57: 29,65 BAD (FFFFHH)
|
||||
Size 58: 29,67 OK (HHHFFF)
|
||||
Size 59: 30,68 BAD (FFFFHH)
|
||||
Size 60: 30,69 OK (HHHFFF)
|
||||
Size 61: 31,70 BAD (FFFFHH)
|
||||
Size 62: 31,71 OK (HHHFFF)
|
||||
Size 63: 32,72 BAD (FFFFHH)
|
||||
Size 64: 32,74 OK (HHHFFF)
|
||||
Size 65: 33,75 BAD (FFFFHH)
|
||||
Size 66: 33,76 OK (HHHFFF)
|
||||
Size 67: 34,77 BAD (FFFFHH)
|
||||
Size 68: 34,78 OK (HHHFFF)
|
||||
Size 69: 35,79 BAD (FFFFHH)
|
||||
Size 70: 35,80 OK (HHHFFF)
|
||||
Size 71: 36,82 BAD (FFFFHH)
|
||||
Size 72: 36,83 OK (HHHFFF)
|
||||
Size 73: 37,84 BAD (FFFFHH)
|
||||
Size 74: 37,85 OK (HHHFFF)
|
||||
Size 75: 38,86 BAD (FFFFHH)
|
||||
Size 76: 38,87 OK (HHHFFF)
|
||||
Size 77: 39,88 BAD (FFFFHH)
|
||||
Size 78: 39,90 OK (HHHFFF)
|
||||
Size 79: 40,91 BAD (FFFFHH)
|
||||
Size 80: 40,92 OK (HHHFFF)
|
||||
Size 81: 41,93 BAD (FFFFHH)
|
||||
Size 82: 41,94 OK (HHHFFF)
|
||||
Size 83: 42,95 BAD (FFFFHH)
|
||||
Size 84: 42,96 OK (HHHFFF)
|
||||
Size 85: 43,98 BAD (FFFFHH)
|
||||
Size 86: 43,99 OK (HHHFFF)
|
||||
Size 87: 44,100 BAD (FFFFHH)
|
||||
Size 88: 44,101 OK (HHHFFF)
|
||||
Size 89: 45,102 BAD (FFFFHH)
|
||||
Size 90: 45,103 OK (HHHFFF)
|
||||
Size 91: 46,105 BAD (FFFFHH)
|
||||
Size 92: 46,106 OK (HHHFFF)
|
||||
Size 93: 47,107 BAD (FFFFHH)
|
||||
Size 94: 47,108 OK (HHHFFF)
|
||||
Size 95: 48,109 BAD (FFFFHH)
|
||||
Size 96: 48,110 OK (HHHFFF)
|
||||
Size 97: 49,111 BAD (FFFFHH)
|
||||
Size 98: 49,113 OK (HHHFFF)
|
||||
Size 99: 50,114 BAD (FFFFHH)
|
||||
Size 100: 50,115 OK (HHHFFF)
|
||||
|
||||
Windows 10 14342 New Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,1 OK (HHHFFF)
|
||||
Size 2: 1,2 OK (HHHFFF)
|
||||
Size 3: 2,3 OK (HHHFFF)
|
||||
Size 4: 2,4 OK (HHHFFF)
|
||||
Size 5: 3,5 OK (HHHFFF)
|
||||
Size 6: 3,6 OK (HHHFFF)
|
||||
Size 7: 4,7 OK (HHHFFF)
|
||||
Size 8: 4,8 OK (HHHFFF)
|
||||
Size 9: 5,9 OK (HHHFFF)
|
||||
Size 10: 5,10 OK (HHHFFF)
|
||||
Size 11: 6,11 OK (HHHFFF)
|
||||
Size 12: 6,12 OK (HHHFFF)
|
||||
Size 13: 7,13 OK (HHHFFF)
|
||||
Size 14: 7,14 OK (HHHFFF)
|
||||
Size 15: 8,15 OK (HHHFFF)
|
||||
Size 16: 8,16 OK (HHHFFF)
|
||||
Size 17: 9,17 OK (HHHFFF)
|
||||
Size 18: 9,18 OK (HHHFFF)
|
||||
Size 19: 10,19 OK (HHHFFF)
|
||||
Size 20: 10,20 OK (HHHFFF)
|
||||
Size 21: 11,21 OK (HHHFFF)
|
||||
Size 22: 11,22 OK (HHHFFF)
|
||||
Size 23: 12,23 OK (HHHFFF)
|
||||
Size 24: 12,24 OK (HHHFFF)
|
||||
Size 25: 13,25 OK (HHHFFF)
|
||||
Size 26: 13,26 OK (HHHFFF)
|
||||
Size 27: 14,27 OK (HHHFFF)
|
||||
Size 28: 14,28 OK (HHHFFF)
|
||||
Size 29: 15,29 OK (HHHFFF)
|
||||
Size 30: 15,30 OK (HHHFFF)
|
||||
Size 31: 16,31 OK (HHHFFF)
|
||||
Size 32: 16,32 OK (HHHFFF)
|
||||
Size 33: 17,33 OK (HHHFFF)
|
||||
Size 34: 17,34 OK (HHHFFF)
|
||||
Size 35: 18,35 OK (HHHFFF)
|
||||
Size 36: 18,36 OK (HHHFFF)
|
||||
Size 37: 19,37 OK (HHHFFF)
|
||||
Size 38: 19,38 OK (HHHFFF)
|
||||
Size 39: 20,39 OK (HHHFFF)
|
||||
Size 40: 20,40 OK (HHHFFF)
|
||||
Size 41: 21,41 OK (HHHFFF)
|
||||
Size 42: 21,42 OK (HHHFFF)
|
||||
Size 43: 22,43 OK (HHHFFF)
|
||||
Size 44: 22,44 OK (HHHFFF)
|
||||
Size 45: 23,45 OK (HHHFFF)
|
||||
Size 46: 23,46 OK (HHHFFF)
|
||||
Size 47: 24,47 OK (HHHFFF)
|
||||
Size 48: 24,48 OK (HHHFFF)
|
||||
Size 49: 25,49 OK (HHHFFF)
|
||||
Size 50: 25,50 OK (HHHFFF)
|
||||
Size 51: 26,51 OK (HHHFFF)
|
||||
Size 52: 26,52 OK (HHHFFF)
|
||||
Size 53: 27,53 OK (HHHFFF)
|
||||
Size 54: 27,54 OK (HHHFFF)
|
||||
Size 55: 28,55 OK (HHHFFF)
|
||||
Size 56: 28,56 OK (HHHFFF)
|
||||
Size 57: 29,57 OK (HHHFFF)
|
||||
Size 58: 29,58 OK (HHHFFF)
|
||||
Size 59: 30,59 OK (HHHFFF)
|
||||
Size 60: 30,60 OK (HHHFFF)
|
||||
Size 61: 31,61 OK (HHHFFF)
|
||||
Size 62: 31,62 OK (HHHFFF)
|
||||
Size 63: 32,63 OK (HHHFFF)
|
||||
Size 64: 32,64 OK (HHHFFF)
|
||||
Size 65: 33,65 OK (HHHFFF)
|
||||
Size 66: 33,66 OK (HHHFFF)
|
||||
Size 67: 34,67 OK (HHHFFF)
|
||||
Size 68: 34,68 OK (HHHFFF)
|
||||
Size 69: 35,69 OK (HHHFFF)
|
||||
Size 70: 35,70 OK (HHHFFF)
|
||||
Size 71: 36,71 OK (HHHFFF)
|
||||
Size 72: 36,72 OK (HHHFFF)
|
||||
Size 73: 37,73 OK (HHHFFF)
|
||||
Size 74: 37,74 OK (HHHFFF)
|
||||
Size 75: 38,75 OK (HHHFFF)
|
||||
Size 76: 38,76 OK (HHHFFF)
|
||||
Size 77: 39,77 OK (HHHFFF)
|
||||
Size 78: 39,78 OK (HHHFFF)
|
||||
Size 79: 40,79 OK (HHHFFF)
|
||||
Size 80: 40,80 OK (HHHFFF)
|
||||
Size 81: 41,81 OK (HHHFFF)
|
||||
Size 82: 41,82 OK (HHHFFF)
|
||||
Size 83: 42,83 OK (HHHFFF)
|
||||
Size 84: 42,84 OK (HHHFFF)
|
||||
Size 85: 43,85 OK (HHHFFF)
|
||||
Size 86: 43,86 OK (HHHFFF)
|
||||
Size 87: 44,87 OK (HHHFFF)
|
||||
Size 88: 44,88 OK (HHHFFF)
|
||||
Size 89: 45,89 OK (HHHFFF)
|
||||
Size 90: 45,90 OK (HHHFFF)
|
||||
Size 91: 46,91 OK (HHHFFF)
|
||||
Size 92: 46,92 OK (HHHFFF)
|
||||
Size 93: 47,93 OK (HHHFFF)
|
||||
Size 94: 47,94 OK (HHHFFF)
|
||||
Size 95: 48,95 OK (HHHFFF)
|
||||
Size 96: 48,96 OK (HHHFFF)
|
||||
Size 97: 49,97 OK (HHHFFF)
|
||||
Size 98: 49,98 OK (HHHFFF)
|
||||
Size 99: 50,99 OK (HHHFFF)
|
||||
Size 100: 50,100 OK (HHHFFF)
|
@ -1,630 +0,0 @@
|
||||
===========================================================
|
||||
Code Page 950, Chinese Traditional (Taiwan), MingLight font
|
||||
===========================================================
|
||||
|
||||
Options: -face-minglight -family 0x36
|
||||
Chars: A2 A3 2014 3044 30FC 4000
|
||||
|
||||
Vista
|
||||
-----
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,4 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (HHHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (HHHFHH)
|
||||
Size 8: 4,10 GOOD (HHFFFF)
|
||||
Size 9: 5,11 BAD (HHHFHH)
|
||||
Size 10: 5,12 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (HHHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,16 BAD (HHHFHH)
|
||||
Size 14: 7,17 GOOD (HHFFFF)
|
||||
Size 15: 8,18 BAD (HHHFHH)
|
||||
Size 16: 8,19 GOOD (HHFFFF)
|
||||
Size 17: 9,20 BAD (HHHFHH)
|
||||
Size 18: 9,22 GOOD (HHFFFF)
|
||||
Size 19: 10,23 BAD (HHHFHH)
|
||||
Size 20: 10,24 GOOD (HHFFFF)
|
||||
Size 21: 11,25 BAD (HHHFHH)
|
||||
Size 22: 11,26 GOOD (HHFFFF)
|
||||
Size 23: 12,28 BAD (HHHFHH)
|
||||
Size 24: 12,29 GOOD (HHFFFF)
|
||||
Size 25: 13,30 BAD (HHHFHH)
|
||||
Size 26: 13,31 GOOD (HHFFFF)
|
||||
Size 27: 14,32 BAD (HHHFHH)
|
||||
Size 28: 14,34 GOOD (HHFFFF)
|
||||
Size 29: 15,35 BAD (HHHFHH)
|
||||
Size 30: 15,36 GOOD (HHFFFF)
|
||||
Size 31: 16,37 BAD (HHHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,40 BAD (HHHFHH)
|
||||
Size 34: 17,41 GOOD (HHFFFF)
|
||||
Size 35: 18,42 BAD (HHHFHH)
|
||||
Size 36: 18,43 GOOD (HHFFFF)
|
||||
Size 37: 19,44 BAD (HHHFHH)
|
||||
Size 38: 19,46 GOOD (HHFFFF)
|
||||
Size 39: 20,47 BAD (HHHFHH)
|
||||
Size 40: 20,48 GOOD (HHFFFF)
|
||||
Size 41: 21,49 BAD (HHHFHH)
|
||||
Size 42: 21,50 GOOD (HHFFFF)
|
||||
Size 43: 22,52 BAD (HHHFHH)
|
||||
Size 44: 22,53 GOOD (HHFFFF)
|
||||
Size 45: 23,54 BAD (HHHFHH)
|
||||
Size 46: 23,55 GOOD (HHFFFF)
|
||||
Size 47: 24,56 BAD (HHHFHH)
|
||||
Size 48: 24,58 GOOD (HHFFFF)
|
||||
Size 49: 25,59 BAD (HHHFHH)
|
||||
Size 50: 25,60 GOOD (HHFFFF)
|
||||
Size 51: 26,61 BAD (HHHFHH)
|
||||
Size 52: 26,62 GOOD (HHFFFF)
|
||||
Size 53: 27,64 BAD (HHHFHH)
|
||||
Size 54: 27,65 GOOD (HHFFFF)
|
||||
Size 55: 28,66 BAD (HHHFHH)
|
||||
Size 56: 28,67 GOOD (HHFFFF)
|
||||
Size 57: 29,68 BAD (HHHFHH)
|
||||
Size 58: 29,70 GOOD (HHFFFF)
|
||||
Size 59: 30,71 BAD (HHHFHH)
|
||||
Size 60: 30,72 GOOD (HHFFFF)
|
||||
Size 61: 31,73 BAD (HHHFHH)
|
||||
Size 62: 31,74 GOOD (HHFFFF)
|
||||
Size 63: 32,76 BAD (HHHFHH)
|
||||
Size 64: 32,77 GOOD (HHFFFF)
|
||||
Size 65: 33,78 BAD (HHHFHH)
|
||||
Size 66: 33,79 GOOD (HHFFFF)
|
||||
Size 67: 34,80 BAD (HHHFHH)
|
||||
Size 68: 34,82 GOOD (HHFFFF)
|
||||
Size 69: 35,83 BAD (HHHFHH)
|
||||
Size 70: 35,84 GOOD (HHFFFF)
|
||||
Size 71: 36,85 BAD (HHHFHH)
|
||||
Size 72: 36,86 GOOD (HHFFFF)
|
||||
Size 73: 37,88 BAD (HHHFHH)
|
||||
Size 74: 37,89 GOOD (HHFFFF)
|
||||
Size 75: 38,90 BAD (HHHFHH)
|
||||
Size 76: 38,91 GOOD (HHFFFF)
|
||||
Size 77: 39,92 BAD (HHHFHH)
|
||||
Size 78: 39,94 GOOD (HHFFFF)
|
||||
Size 79: 40,95 BAD (HHHFHH)
|
||||
Size 80: 40,96 GOOD (HHFFFF)
|
||||
Size 81: 41,97 BAD (HHHFHH)
|
||||
Size 82: 41,98 GOOD (HHFFFF)
|
||||
Size 83: 42,100 BAD (HHHFHH)
|
||||
Size 84: 42,101 GOOD (HHFFFF)
|
||||
Size 85: 43,102 BAD (HHHFHH)
|
||||
Size 86: 43,103 GOOD (HHFFFF)
|
||||
Size 87: 44,104 BAD (HHHFHH)
|
||||
Size 88: 44,106 GOOD (HHFFFF)
|
||||
Size 89: 45,107 BAD (HHHFHH)
|
||||
Size 90: 45,108 GOOD (HHFFFF)
|
||||
Size 91: 46,109 BAD (HHHFHH)
|
||||
Size 92: 46,110 GOOD (HHFFFF)
|
||||
Size 93: 47,112 BAD (HHHFHH)
|
||||
Size 94: 47,113 GOOD (HHFFFF)
|
||||
Size 95: 48,114 BAD (HHHFHH)
|
||||
Size 96: 48,115 GOOD (HHFFFF)
|
||||
Size 97: 49,116 BAD (HHHFHH)
|
||||
Size 98: 49,118 GOOD (HHFFFF)
|
||||
Size 99: 50,119 BAD (HHHFHH)
|
||||
Size 100: 50,120 GOOD (HHFFFF)
|
||||
|
||||
Windows 7
|
||||
---------
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,4 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (FFHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (FFHFHH)
|
||||
Size 8: 4,10 GOOD (HHFFFF)
|
||||
Size 9: 5,11 BAD (FFHFHH)
|
||||
Size 10: 5,12 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (FFHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,16 BAD (FFHFHH)
|
||||
Size 14: 7,17 GOOD (HHFFFF)
|
||||
Size 15: 8,18 BAD (FFHFHH)
|
||||
Size 16: 8,19 GOOD (HHFFFF)
|
||||
Size 17: 9,20 BAD (FFHFHH)
|
||||
Size 18: 9,22 GOOD (HHFFFF)
|
||||
Size 19: 10,23 BAD (FFHFHH)
|
||||
Size 20: 10,24 GOOD (HHFFFF)
|
||||
Size 21: 11,25 BAD (FFHFHH)
|
||||
Size 22: 11,26 GOOD (HHFFFF)
|
||||
Size 23: 12,28 BAD (FFHFHH)
|
||||
Size 24: 12,29 GOOD (HHFFFF)
|
||||
Size 25: 13,30 BAD (FFHFHH)
|
||||
Size 26: 13,31 GOOD (HHFFFF)
|
||||
Size 27: 14,32 BAD (FFHFHH)
|
||||
Size 28: 14,34 GOOD (HHFFFF)
|
||||
Size 29: 15,35 BAD (FFHFHH)
|
||||
Size 30: 15,36 GOOD (HHFFFF)
|
||||
Size 31: 16,37 BAD (FFHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,40 BAD (FFHFHH)
|
||||
Size 34: 17,41 GOOD (HHFFFF)
|
||||
Size 35: 18,42 BAD (FFHFHH)
|
||||
Size 36: 18,43 GOOD (HHFFFF)
|
||||
Size 37: 19,44 BAD (FFHFHH)
|
||||
Size 38: 19,46 GOOD (HHFFFF)
|
||||
Size 39: 20,47 BAD (FFHFHH)
|
||||
Size 40: 20,48 GOOD (HHFFFF)
|
||||
Size 41: 21,49 BAD (FFHFHH)
|
||||
Size 42: 21,50 GOOD (HHFFFF)
|
||||
Size 43: 22,52 BAD (FFHFHH)
|
||||
Size 44: 22,53 GOOD (HHFFFF)
|
||||
Size 45: 23,54 BAD (FFHFHH)
|
||||
Size 46: 23,55 GOOD (HHFFFF)
|
||||
Size 47: 24,56 BAD (FFHFHH)
|
||||
Size 48: 24,58 GOOD (HHFFFF)
|
||||
Size 49: 25,59 BAD (FFHFHH)
|
||||
Size 50: 25,60 GOOD (HHFFFF)
|
||||
Size 51: 26,61 BAD (FFHFHH)
|
||||
Size 52: 26,62 GOOD (HHFFFF)
|
||||
Size 53: 27,64 BAD (FFHFHH)
|
||||
Size 54: 27,65 GOOD (HHFFFF)
|
||||
Size 55: 28,66 BAD (FFHFHH)
|
||||
Size 56: 28,67 GOOD (HHFFFF)
|
||||
Size 57: 29,68 BAD (FFHFHH)
|
||||
Size 58: 29,70 GOOD (HHFFFF)
|
||||
Size 59: 30,71 BAD (FFHFHH)
|
||||
Size 60: 30,72 GOOD (HHFFFF)
|
||||
Size 61: 31,73 BAD (FFHFHH)
|
||||
Size 62: 31,74 GOOD (HHFFFF)
|
||||
Size 63: 32,76 BAD (FFHFHH)
|
||||
Size 64: 32,77 GOOD (HHFFFF)
|
||||
Size 65: 33,78 BAD (FFHFHH)
|
||||
Size 66: 33,79 GOOD (HHFFFF)
|
||||
Size 67: 34,80 BAD (FFHFHH)
|
||||
Size 68: 34,82 GOOD (HHFFFF)
|
||||
Size 69: 35,83 BAD (FFHFHH)
|
||||
Size 70: 35,84 GOOD (HHFFFF)
|
||||
Size 71: 36,85 BAD (FFHFHH)
|
||||
Size 72: 36,86 GOOD (HHFFFF)
|
||||
Size 73: 37,88 BAD (FFHFHH)
|
||||
Size 74: 37,89 GOOD (HHFFFF)
|
||||
Size 75: 38,90 BAD (FFHFHH)
|
||||
Size 76: 38,91 GOOD (HHFFFF)
|
||||
Size 77: 39,92 BAD (FFHFHH)
|
||||
Size 78: 39,94 GOOD (HHFFFF)
|
||||
Size 79: 40,95 BAD (FFHFHH)
|
||||
Size 80: 40,96 GOOD (HHFFFF)
|
||||
Size 81: 41,97 BAD (FFHFHH)
|
||||
Size 82: 41,98 GOOD (HHFFFF)
|
||||
Size 83: 42,100 BAD (FFHFHH)
|
||||
Size 84: 42,101 GOOD (HHFFFF)
|
||||
Size 85: 43,102 BAD (FFHFHH)
|
||||
Size 86: 43,103 GOOD (HHFFFF)
|
||||
Size 87: 44,104 BAD (FFHFHH)
|
||||
Size 88: 44,106 GOOD (HHFFFF)
|
||||
Size 89: 45,107 BAD (FFHFHH)
|
||||
Size 90: 45,108 GOOD (HHFFFF)
|
||||
Size 91: 46,109 BAD (FFHFHH)
|
||||
Size 92: 46,110 GOOD (HHFFFF)
|
||||
Size 93: 47,112 BAD (FFHFHH)
|
||||
Size 94: 47,113 GOOD (HHFFFF)
|
||||
Size 95: 48,114 BAD (FFHFHH)
|
||||
Size 96: 48,115 GOOD (HHFFFF)
|
||||
Size 97: 49,116 BAD (FFHFHH)
|
||||
Size 98: 49,118 GOOD (HHFFFF)
|
||||
Size 99: 50,119 BAD (FFHFHH)
|
||||
Size 100: 50,120 GOOD (HHFFFF)
|
||||
|
||||
Windows 8
|
||||
---------
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,4 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (FFHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (FFHFHH)
|
||||
Size 8: 4,10 GOOD (HHFFFF)
|
||||
Size 9: 5,11 BAD (FFHFHH)
|
||||
Size 10: 5,12 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (FFHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,16 BAD (FFHFHH)
|
||||
Size 14: 7,17 GOOD (HHFFFF)
|
||||
Size 15: 8,18 BAD (FFHFHH)
|
||||
Size 16: 8,19 GOOD (HHFFFF)
|
||||
Size 17: 9,20 BAD (FFHFHH)
|
||||
Size 18: 9,22 GOOD (HHFFFF)
|
||||
Size 19: 10,23 BAD (FFHFHH)
|
||||
Size 20: 10,24 GOOD (HHFFFF)
|
||||
Size 21: 11,25 BAD (FFHFHH)
|
||||
Size 22: 11,26 GOOD (HHFFFF)
|
||||
Size 23: 12,28 BAD (FFHFHH)
|
||||
Size 24: 12,29 GOOD (HHFFFF)
|
||||
Size 25: 13,30 BAD (FFHFHH)
|
||||
Size 26: 13,31 GOOD (HHFFFF)
|
||||
Size 27: 14,32 BAD (FFHFHH)
|
||||
Size 28: 14,34 GOOD (HHFFFF)
|
||||
Size 29: 15,35 BAD (FFHFHH)
|
||||
Size 30: 15,36 GOOD (HHFFFF)
|
||||
Size 31: 16,37 BAD (FFHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,40 BAD (FFHFHH)
|
||||
Size 34: 17,41 GOOD (HHFFFF)
|
||||
Size 35: 18,42 BAD (FFHFHH)
|
||||
Size 36: 18,43 GOOD (HHFFFF)
|
||||
Size 37: 19,44 BAD (FFHFHH)
|
||||
Size 38: 19,46 GOOD (HHFFFF)
|
||||
Size 39: 20,47 BAD (FFHFHH)
|
||||
Size 40: 20,48 GOOD (HHFFFF)
|
||||
Size 41: 21,49 BAD (FFHFHH)
|
||||
Size 42: 21,50 GOOD (HHFFFF)
|
||||
Size 43: 22,52 BAD (FFHFHH)
|
||||
Size 44: 22,53 GOOD (HHFFFF)
|
||||
Size 45: 23,54 BAD (FFHFHH)
|
||||
Size 46: 23,55 GOOD (HHFFFF)
|
||||
Size 47: 24,56 BAD (FFHFHH)
|
||||
Size 48: 24,58 GOOD (HHFFFF)
|
||||
Size 49: 25,59 BAD (FFHFHH)
|
||||
Size 50: 25,60 GOOD (HHFFFF)
|
||||
Size 51: 26,61 BAD (FFHFHH)
|
||||
Size 52: 26,62 GOOD (HHFFFF)
|
||||
Size 53: 27,64 BAD (FFHFHH)
|
||||
Size 54: 27,65 GOOD (HHFFFF)
|
||||
Size 55: 28,66 BAD (FFHFHH)
|
||||
Size 56: 28,67 GOOD (HHFFFF)
|
||||
Size 57: 29,68 BAD (FFHFHH)
|
||||
Size 58: 29,70 GOOD (HHFFFF)
|
||||
Size 59: 30,71 BAD (FFHFHH)
|
||||
Size 60: 30,72 GOOD (HHFFFF)
|
||||
Size 61: 31,73 BAD (FFHFHH)
|
||||
Size 62: 31,74 GOOD (HHFFFF)
|
||||
Size 63: 32,76 BAD (FFHFHH)
|
||||
Size 64: 32,77 GOOD (HHFFFF)
|
||||
Size 65: 33,78 BAD (FFHFHH)
|
||||
Size 66: 33,79 GOOD (HHFFFF)
|
||||
Size 67: 34,80 BAD (FFHFHH)
|
||||
Size 68: 34,82 GOOD (HHFFFF)
|
||||
Size 69: 35,83 BAD (FFHFHH)
|
||||
Size 70: 35,84 GOOD (HHFFFF)
|
||||
Size 71: 36,85 BAD (FFHFHH)
|
||||
Size 72: 36,86 GOOD (HHFFFF)
|
||||
Size 73: 37,88 BAD (FFHFHH)
|
||||
Size 74: 37,89 GOOD (HHFFFF)
|
||||
Size 75: 38,90 BAD (FFHFHH)
|
||||
Size 76: 38,91 GOOD (HHFFFF)
|
||||
Size 77: 39,92 BAD (FFHFHH)
|
||||
Size 78: 39,94 GOOD (HHFFFF)
|
||||
Size 79: 40,95 BAD (FFHFHH)
|
||||
Size 80: 40,96 GOOD (HHFFFF)
|
||||
Size 81: 41,97 BAD (FFHFHH)
|
||||
Size 82: 41,98 GOOD (HHFFFF)
|
||||
Size 83: 42,100 BAD (FFHFHH)
|
||||
Size 84: 42,101 GOOD (HHFFFF)
|
||||
Size 85: 43,102 BAD (FFHFHH)
|
||||
Size 86: 43,103 GOOD (HHFFFF)
|
||||
Size 87: 44,104 BAD (FFHFHH)
|
||||
Size 88: 44,106 GOOD (HHFFFF)
|
||||
Size 89: 45,107 BAD (FFHFHH)
|
||||
Size 90: 45,108 GOOD (HHFFFF)
|
||||
Size 91: 46,109 BAD (FFHFHH)
|
||||
Size 92: 46,110 GOOD (HHFFFF)
|
||||
Size 93: 47,112 BAD (FFHFHH)
|
||||
Size 94: 47,113 GOOD (HHFFFF)
|
||||
Size 95: 48,114 BAD (FFHFHH)
|
||||
Size 96: 48,115 GOOD (HHFFFF)
|
||||
Size 97: 49,116 BAD (FFHFHH)
|
||||
Size 98: 49,118 GOOD (HHFFFF)
|
||||
Size 99: 50,119 BAD (FFHFHH)
|
||||
Size 100: 50,120 GOOD (HHFFFF)
|
||||
|
||||
Windows 8.1
|
||||
-----------
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,4 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (FFHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (FFHFHH)
|
||||
Size 8: 4,10 GOOD (HHFFFF)
|
||||
Size 9: 5,11 BAD (FFHFHH)
|
||||
Size 10: 5,12 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (FFHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,16 BAD (FFHFHH)
|
||||
Size 14: 7,17 GOOD (HHFFFF)
|
||||
Size 15: 8,18 BAD (FFHFHH)
|
||||
Size 16: 8,19 GOOD (HHFFFF)
|
||||
Size 17: 9,20 BAD (FFHFHH)
|
||||
Size 18: 9,22 GOOD (HHFFFF)
|
||||
Size 19: 10,23 BAD (FFHFHH)
|
||||
Size 20: 10,24 GOOD (HHFFFF)
|
||||
Size 21: 11,25 BAD (FFHFHH)
|
||||
Size 22: 11,26 GOOD (HHFFFF)
|
||||
Size 23: 12,28 BAD (FFHFHH)
|
||||
Size 24: 12,29 GOOD (HHFFFF)
|
||||
Size 25: 13,30 BAD (FFHFHH)
|
||||
Size 26: 13,31 GOOD (HHFFFF)
|
||||
Size 27: 14,32 BAD (FFHFHH)
|
||||
Size 28: 14,34 GOOD (HHFFFF)
|
||||
Size 29: 15,35 BAD (FFHFHH)
|
||||
Size 30: 15,36 GOOD (HHFFFF)
|
||||
Size 31: 16,37 BAD (FFHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,40 BAD (FFHFHH)
|
||||
Size 34: 17,41 GOOD (HHFFFF)
|
||||
Size 35: 18,42 BAD (FFHFHH)
|
||||
Size 36: 18,43 GOOD (HHFFFF)
|
||||
Size 37: 19,44 BAD (FFHFHH)
|
||||
Size 38: 19,46 GOOD (HHFFFF)
|
||||
Size 39: 20,47 BAD (FFHFHH)
|
||||
Size 40: 20,48 GOOD (HHFFFF)
|
||||
Size 41: 21,49 BAD (FFHFHH)
|
||||
Size 42: 21,50 GOOD (HHFFFF)
|
||||
Size 43: 22,52 BAD (FFHFHH)
|
||||
Size 44: 22,53 GOOD (HHFFFF)
|
||||
Size 45: 23,54 BAD (FFHFHH)
|
||||
Size 46: 23,55 GOOD (HHFFFF)
|
||||
Size 47: 24,56 BAD (FFHFHH)
|
||||
Size 48: 24,58 GOOD (HHFFFF)
|
||||
Size 49: 25,59 BAD (FFHFHH)
|
||||
Size 50: 25,60 GOOD (HHFFFF)
|
||||
Size 51: 26,61 BAD (FFHFHH)
|
||||
Size 52: 26,62 GOOD (HHFFFF)
|
||||
Size 53: 27,64 BAD (FFHFHH)
|
||||
Size 54: 27,65 GOOD (HHFFFF)
|
||||
Size 55: 28,66 BAD (FFHFHH)
|
||||
Size 56: 28,67 GOOD (HHFFFF)
|
||||
Size 57: 29,68 BAD (FFHFHH)
|
||||
Size 58: 29,70 GOOD (HHFFFF)
|
||||
Size 59: 30,71 BAD (FFHFHH)
|
||||
Size 60: 30,72 GOOD (HHFFFF)
|
||||
Size 61: 31,73 BAD (FFHFHH)
|
||||
Size 62: 31,74 GOOD (HHFFFF)
|
||||
Size 63: 32,76 BAD (FFHFHH)
|
||||
Size 64: 32,77 GOOD (HHFFFF)
|
||||
Size 65: 33,78 BAD (FFHFHH)
|
||||
Size 66: 33,79 GOOD (HHFFFF)
|
||||
Size 67: 34,80 BAD (FFHFHH)
|
||||
Size 68: 34,82 GOOD (HHFFFF)
|
||||
Size 69: 35,83 BAD (FFHFHH)
|
||||
Size 70: 35,84 GOOD (HHFFFF)
|
||||
Size 71: 36,85 BAD (FFHFHH)
|
||||
Size 72: 36,86 GOOD (HHFFFF)
|
||||
Size 73: 37,88 BAD (FFHFHH)
|
||||
Size 74: 37,89 GOOD (HHFFFF)
|
||||
Size 75: 38,90 BAD (FFHFHH)
|
||||
Size 76: 38,91 GOOD (HHFFFF)
|
||||
Size 77: 39,92 BAD (FFHFHH)
|
||||
Size 78: 39,94 GOOD (HHFFFF)
|
||||
Size 79: 40,95 BAD (FFHFHH)
|
||||
Size 80: 40,96 GOOD (HHFFFF)
|
||||
Size 81: 41,97 BAD (FFHFHH)
|
||||
Size 82: 41,98 GOOD (HHFFFF)
|
||||
Size 83: 42,100 BAD (FFHFHH)
|
||||
Size 84: 42,101 GOOD (HHFFFF)
|
||||
Size 85: 43,102 BAD (FFHFHH)
|
||||
Size 86: 43,103 GOOD (HHFFFF)
|
||||
Size 87: 44,104 BAD (FFHFHH)
|
||||
Size 88: 44,106 GOOD (HHFFFF)
|
||||
Size 89: 45,107 BAD (FFHFHH)
|
||||
Size 90: 45,108 GOOD (HHFFFF)
|
||||
Size 91: 46,109 BAD (FFHFHH)
|
||||
Size 92: 46,110 GOOD (HHFFFF)
|
||||
Size 93: 47,112 BAD (FFHFHH)
|
||||
Size 94: 47,113 GOOD (HHFFFF)
|
||||
Size 95: 48,114 BAD (FFHFHH)
|
||||
Size 96: 48,115 GOOD (HHFFFF)
|
||||
Size 97: 49,116 BAD (FFHFHH)
|
||||
Size 98: 49,118 GOOD (HHFFFF)
|
||||
Size 99: 50,119 BAD (FFHFHH)
|
||||
Size 100: 50,120 GOOD (HHFFFF)
|
||||
|
||||
Windows 10 14342 Old Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,2 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,4 BAD (FFHFHH)
|
||||
Size 4: 2,5 GOOD (HHFFFF)
|
||||
Size 5: 3,6 BAD (FFHFHH)
|
||||
Size 6: 3,7 GOOD (HHFFFF)
|
||||
Size 7: 4,8 BAD (FFHFHH)
|
||||
Size 8: 4,10 GOOD (HHFFFF)
|
||||
Size 9: 5,11 BAD (FFHFHH)
|
||||
Size 10: 5,12 GOOD (HHFFFF)
|
||||
Size 11: 6,13 BAD (FFHFHH)
|
||||
Size 12: 6,14 GOOD (HHFFFF)
|
||||
Size 13: 7,16 BAD (FFHFHH)
|
||||
Size 14: 7,17 GOOD (HHFFFF)
|
||||
Size 15: 8,18 BAD (FFHFHH)
|
||||
Size 16: 8,19 GOOD (HHFFFF)
|
||||
Size 17: 9,20 BAD (FFHFHH)
|
||||
Size 18: 9,22 GOOD (HHFFFF)
|
||||
Size 19: 10,23 BAD (FFHFHH)
|
||||
Size 20: 10,24 GOOD (HHFFFF)
|
||||
Size 21: 11,25 BAD (FFHFHH)
|
||||
Size 22: 11,26 GOOD (HHFFFF)
|
||||
Size 23: 12,28 BAD (FFHFHH)
|
||||
Size 24: 12,29 GOOD (HHFFFF)
|
||||
Size 25: 13,30 BAD (FFHFHH)
|
||||
Size 26: 13,31 GOOD (HHFFFF)
|
||||
Size 27: 14,32 BAD (FFHFHH)
|
||||
Size 28: 14,34 GOOD (HHFFFF)
|
||||
Size 29: 15,35 BAD (FFHFHH)
|
||||
Size 30: 15,36 GOOD (HHFFFF)
|
||||
Size 31: 16,37 BAD (FFHFHH)
|
||||
Size 32: 16,38 GOOD (HHFFFF)
|
||||
Size 33: 17,40 BAD (FFHFHH)
|
||||
Size 34: 17,41 GOOD (HHFFFF)
|
||||
Size 35: 18,42 BAD (FFHFHH)
|
||||
Size 36: 18,43 GOOD (HHFFFF)
|
||||
Size 37: 19,44 BAD (FFHFHH)
|
||||
Size 38: 19,46 GOOD (HHFFFF)
|
||||
Size 39: 20,47 BAD (FFHFHH)
|
||||
Size 40: 20,48 GOOD (HHFFFF)
|
||||
Size 41: 21,49 BAD (FFHFHH)
|
||||
Size 42: 21,50 GOOD (HHFFFF)
|
||||
Size 43: 22,52 BAD (FFHFHH)
|
||||
Size 44: 22,53 GOOD (HHFFFF)
|
||||
Size 45: 23,54 BAD (FFHFHH)
|
||||
Size 46: 23,55 GOOD (HHFFFF)
|
||||
Size 47: 24,56 BAD (FFHFHH)
|
||||
Size 48: 24,58 GOOD (HHFFFF)
|
||||
Size 49: 25,59 BAD (FFHFHH)
|
||||
Size 50: 25,60 GOOD (HHFFFF)
|
||||
Size 51: 26,61 BAD (FFHFHH)
|
||||
Size 52: 26,62 GOOD (HHFFFF)
|
||||
Size 53: 27,64 BAD (FFHFHH)
|
||||
Size 54: 27,65 GOOD (HHFFFF)
|
||||
Size 55: 28,66 BAD (FFHFHH)
|
||||
Size 56: 28,67 GOOD (HHFFFF)
|
||||
Size 57: 29,68 BAD (FFHFHH)
|
||||
Size 58: 29,70 GOOD (HHFFFF)
|
||||
Size 59: 30,71 BAD (FFHFHH)
|
||||
Size 60: 30,72 GOOD (HHFFFF)
|
||||
Size 61: 31,73 BAD (FFHFHH)
|
||||
Size 62: 31,74 GOOD (HHFFFF)
|
||||
Size 63: 32,76 BAD (FFHFHH)
|
||||
Size 64: 32,77 GOOD (HHFFFF)
|
||||
Size 65: 33,78 BAD (FFHFHH)
|
||||
Size 66: 33,79 GOOD (HHFFFF)
|
||||
Size 67: 34,80 BAD (FFHFHH)
|
||||
Size 68: 34,82 GOOD (HHFFFF)
|
||||
Size 69: 35,83 BAD (FFHFHH)
|
||||
Size 70: 35,84 GOOD (HHFFFF)
|
||||
Size 71: 36,85 BAD (FFHFHH)
|
||||
Size 72: 36,86 GOOD (HHFFFF)
|
||||
Size 73: 37,88 BAD (FFHFHH)
|
||||
Size 74: 37,89 GOOD (HHFFFF)
|
||||
Size 75: 38,90 BAD (FFHFHH)
|
||||
Size 76: 38,91 GOOD (HHFFFF)
|
||||
Size 77: 39,92 BAD (FFHFHH)
|
||||
Size 78: 39,94 GOOD (HHFFFF)
|
||||
Size 79: 40,95 BAD (FFHFHH)
|
||||
Size 80: 40,96 GOOD (HHFFFF)
|
||||
Size 81: 41,97 BAD (FFHFHH)
|
||||
Size 82: 41,98 GOOD (HHFFFF)
|
||||
Size 83: 42,100 BAD (FFHFHH)
|
||||
Size 84: 42,101 GOOD (HHFFFF)
|
||||
Size 85: 43,102 BAD (FFHFHH)
|
||||
Size 86: 43,103 GOOD (HHFFFF)
|
||||
Size 87: 44,104 BAD (FFHFHH)
|
||||
Size 88: 44,106 GOOD (HHFFFF)
|
||||
Size 89: 45,107 BAD (FFHFHH)
|
||||
Size 90: 45,108 GOOD (HHFFFF)
|
||||
Size 91: 46,109 BAD (FFHFHH)
|
||||
Size 92: 46,110 GOOD (HHFFFF)
|
||||
Size 93: 47,112 BAD (FFHFHH)
|
||||
Size 94: 47,113 GOOD (HHFFFF)
|
||||
Size 95: 48,114 BAD (FFHFHH)
|
||||
Size 96: 48,115 GOOD (HHFFFF)
|
||||
Size 97: 49,116 BAD (FFHFHH)
|
||||
Size 98: 49,118 GOOD (HHFFFF)
|
||||
Size 99: 50,119 BAD (FFHFHH)
|
||||
Size 100: 50,120 GOOD (HHFFFF)
|
||||
|
||||
Windows 10 14342 New Console
|
||||
----------------------------
|
||||
|
||||
Size 1: 1,1 GOOD (HHFFFF)
|
||||
Size 2: 1,2 GOOD (HHFFFF)
|
||||
Size 3: 2,3 GOOD (HHFFFF)
|
||||
Size 4: 2,4 GOOD (HHFFFF)
|
||||
Size 5: 3,5 GOOD (HHFFFF)
|
||||
Size 6: 3,6 GOOD (HHFFFF)
|
||||
Size 7: 4,7 GOOD (HHFFFF)
|
||||
Size 8: 4,8 GOOD (HHFFFF)
|
||||
Size 9: 5,9 GOOD (HHFFFF)
|
||||
Size 10: 5,10 GOOD (HHFFFF)
|
||||
Size 11: 6,11 GOOD (HHFFFF)
|
||||
Size 12: 6,12 GOOD (HHFFFF)
|
||||
Size 13: 7,13 GOOD (HHFFFF)
|
||||
Size 14: 7,14 GOOD (HHFFFF)
|
||||
Size 15: 8,15 GOOD (HHFFFF)
|
||||
Size 16: 8,16 GOOD (HHFFFF)
|
||||
Size 17: 9,17 GOOD (HHFFFF)
|
||||
Size 18: 9,18 GOOD (HHFFFF)
|
||||
Size 19: 10,19 GOOD (HHFFFF)
|
||||
Size 20: 10,20 GOOD (HHFFFF)
|
||||
Size 21: 11,21 GOOD (HHFFFF)
|
||||
Size 22: 11,22 GOOD (HHFFFF)
|
||||
Size 23: 12,23 GOOD (HHFFFF)
|
||||
Size 24: 12,24 GOOD (HHFFFF)
|
||||
Size 25: 13,25 GOOD (HHFFFF)
|
||||
Size 26: 13,26 GOOD (HHFFFF)
|
||||
Size 27: 14,27 GOOD (HHFFFF)
|
||||
Size 28: 14,28 GOOD (HHFFFF)
|
||||
Size 29: 15,29 GOOD (HHFFFF)
|
||||
Size 30: 15,30 GOOD (HHFFFF)
|
||||
Size 31: 16,31 GOOD (HHFFFF)
|
||||
Size 32: 16,32 GOOD (HHFFFF)
|
||||
Size 33: 17,33 GOOD (HHFFFF)
|
||||
Size 34: 17,34 GOOD (HHFFFF)
|
||||
Size 35: 18,35 GOOD (HHFFFF)
|
||||
Size 36: 18,36 GOOD (HHFFFF)
|
||||
Size 37: 19,37 GOOD (HHFFFF)
|
||||
Size 38: 19,38 GOOD (HHFFFF)
|
||||
Size 39: 20,39 GOOD (HHFFFF)
|
||||
Size 40: 20,40 GOOD (HHFFFF)
|
||||
Size 41: 21,41 GOOD (HHFFFF)
|
||||
Size 42: 21,42 GOOD (HHFFFF)
|
||||
Size 43: 22,43 GOOD (HHFFFF)
|
||||
Size 44: 22,44 GOOD (HHFFFF)
|
||||
Size 45: 23,45 GOOD (HHFFFF)
|
||||
Size 46: 23,46 GOOD (HHFFFF)
|
||||
Size 47: 24,47 GOOD (HHFFFF)
|
||||
Size 48: 24,48 GOOD (HHFFFF)
|
||||
Size 49: 25,49 GOOD (HHFFFF)
|
||||
Size 50: 25,50 GOOD (HHFFFF)
|
||||
Size 51: 26,51 GOOD (HHFFFF)
|
||||
Size 52: 26,52 GOOD (HHFFFF)
|
||||
Size 53: 27,53 GOOD (HHFFFF)
|
||||
Size 54: 27,54 GOOD (HHFFFF)
|
||||
Size 55: 28,55 GOOD (HHFFFF)
|
||||
Size 56: 28,56 GOOD (HHFFFF)
|
||||
Size 57: 29,57 GOOD (HHFFFF)
|
||||
Size 58: 29,58 GOOD (HHFFFF)
|
||||
Size 59: 30,59 GOOD (HHFFFF)
|
||||
Size 60: 30,60 GOOD (HHFFFF)
|
||||
Size 61: 31,61 GOOD (HHFFFF)
|
||||
Size 62: 31,62 GOOD (HHFFFF)
|
||||
Size 63: 32,63 GOOD (HHFFFF)
|
||||
Size 64: 32,64 GOOD (HHFFFF)
|
||||
Size 65: 33,65 GOOD (HHFFFF)
|
||||
Size 66: 33,66 GOOD (HHFFFF)
|
||||
Size 67: 34,67 GOOD (HHFFFF)
|
||||
Size 68: 34,68 GOOD (HHFFFF)
|
||||
Size 69: 35,69 GOOD (HHFFFF)
|
||||
Size 70: 35,70 GOOD (HHFFFF)
|
||||
Size 71: 36,71 GOOD (HHFFFF)
|
||||
Size 72: 36,72 GOOD (HHFFFF)
|
||||
Size 73: 37,73 GOOD (HHFFFF)
|
||||
Size 74: 37,74 GOOD (HHFFFF)
|
||||
Size 75: 38,75 GOOD (HHFFFF)
|
||||
Size 76: 38,76 GOOD (HHFFFF)
|
||||
Size 77: 39,77 GOOD (HHFFFF)
|
||||
Size 78: 39,78 GOOD (HHFFFF)
|
||||
Size 79: 40,79 GOOD (HHFFFF)
|
||||
Size 80: 40,80 GOOD (HHFFFF)
|
||||
Size 81: 41,81 GOOD (HHFFFF)
|
||||
Size 82: 41,82 GOOD (HHFFFF)
|
||||
Size 83: 42,83 GOOD (HHFFFF)
|
||||
Size 84: 42,84 GOOD (HHFFFF)
|
||||
Size 85: 43,85 GOOD (HHFFFF)
|
||||
Size 86: 43,86 GOOD (HHFFFF)
|
||||
Size 87: 44,87 GOOD (HHFFFF)
|
||||
Size 88: 44,88 GOOD (HHFFFF)
|
||||
Size 89: 45,89 GOOD (HHFFFF)
|
||||
Size 90: 45,90 GOOD (HHFFFF)
|
||||
Size 91: 46,91 GOOD (HHFFFF)
|
||||
Size 92: 46,92 GOOD (HHFFFF)
|
||||
Size 93: 47,93 GOOD (HHFFFF)
|
||||
Size 94: 47,94 GOOD (HHFFFF)
|
||||
Size 95: 48,95 GOOD (HHFFFF)
|
||||
Size 96: 48,96 GOOD (HHFFFF)
|
||||
Size 97: 49,97 GOOD (HHFFFF)
|
||||
Size 98: 49,98 GOOD (HHFFFF)
|
||||
Size 99: 50,99 GOOD (HHFFFF)
|
||||
Size 100: 50,100 GOOD (HHFFFF)
|
@ -1,16 +0,0 @@
|
||||
The narrowest allowed console window, in pixels, on a conventional (~96dpi)
|
||||
monitor:
|
||||
|
||||
(mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 1 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12
|
||||
|
||||
(mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 16 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12
|
||||
|
||||
sz1:px sz1:col sz16:px sz16:col
|
||||
Vista: 124 104 137 10
|
||||
Windows 7: 132 112 147 11
|
||||
Windows 8: 140 120 147 11
|
||||
Windows 8.1: 140 120 147 11
|
||||
Windows 10 OLD: 136 116 147 11
|
||||
Windows 10 NEW: 136 103 136 10
|
||||
|
||||
I used build 14342 to test Windows 10.
|
@ -1,4 +0,0 @@
|
||||
As before, avoid odd sizes in favor of even sizes.
|
||||
|
||||
It's curious that the Japanese font is handled so poorly, especially with
|
||||
Windows 8 and later.
|
@ -1,144 +0,0 @@
|
||||
Issues:
|
||||
|
||||
- Starting with the 14342 build, changing the font using
|
||||
SetCurrentConsoleFontEx does not affect the window size. e.g. The content
|
||||
itself will resize/redraw, but the window neither shrinks nor expands.
|
||||
Presumably this is an oversight? It's almost a convenience; if a program
|
||||
is going to resize the window anyway, then it's nice that the window size
|
||||
contraints don't get in the way. Ordinarily, changing the font doesn't just
|
||||
change the window size in pixels--it can also change the size as measured in
|
||||
rows and columns.
|
||||
|
||||
- (Aside: in the 14342 build, there is also a bug with wmic.exe. Open a console
|
||||
with more than 300 lines of screen buffer, then fill those lines with, e.g.,
|
||||
dir /s. Then run wmic.exe. You won't be able to see the wmic.exe prompt.
|
||||
If you query the screen buffer info somehow, you'll notice that the srWindow
|
||||
is not contained within the dwSize. This breaks winpty's scraping, because
|
||||
it's invalid.)
|
||||
|
||||
- In build 14316, with the Japanese locale, with the 437 code page, attempting
|
||||
to set the Consolas font instead sets the Terminal (raster) font. It seems
|
||||
to pick an appropriate vertical size.
|
||||
|
||||
- It seems necessary to specify "-family 0x36" for maximum reliability.
|
||||
Setting the family to 0 almost always works, and specifying just -tt rarely
|
||||
works.
|
||||
|
||||
Win7
|
||||
English locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
Japanese locale / 932 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
Japanese locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt unreliable
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
|
||||
Win10 Build 10586
|
||||
New console
|
||||
Japanese locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
|
||||
Win10 Build 14316
|
||||
Old console
|
||||
English locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
Japanese locale / 932 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
Japanese locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selected very small Consolas font
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
New console
|
||||
English locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt works
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
Japanese locale / 932 code page:
|
||||
SetFont.exe -face Consolas -h 16 selects gothic instead
|
||||
SetFont.exe -face Consolas -h 16 -tt selects gothic instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 selects gothic instead
|
||||
Japanese locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36(*) selects Terminal font instead
|
||||
|
||||
Win10 Build 14342
|
||||
Old Console
|
||||
English locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
Japanese locale / 932 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
Japanese locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
New console
|
||||
English locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 works
|
||||
SetFont.exe -face Consolas -h 16 -tt works
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
Japanese locale / 932 code page:
|
||||
SetFont.exe -face Consolas -h 16 selects gothic instead
|
||||
SetFont.exe -face Consolas -h 16 -tt selects gothic instead
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 selects gothic instead
|
||||
Japanese locale / 437 code page:
|
||||
SetFont.exe -face Consolas -h 16 selects Terminal font instead
|
||||
SetFont.exe -face Consolas -h 16 -tt works
|
||||
SetFont.exe -face Consolas -h 16 -family 0x36 works
|
||||
|
||||
(*) I was trying to figure out whether the inconsistency was at when I stumbled
|
||||
onto this completely unexpected bug. Here's more detail:
|
||||
|
||||
F:\>SetFont.exe -face Consolas -h 16 -family 0x36 -weight normal -w 8
|
||||
Setting to: nFont=0 dwFontSize=(8,16) FontFamily=0x36 FontWeight=400 FaceName="Consolas"
|
||||
SetCurrentConsoleFontEx returned 1
|
||||
|
||||
F:\>GetFont.exe
|
||||
largestConsoleWindowSize=(96,50)
|
||||
maxWnd=0: nFont=0 dwFontSize=(12,16) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
|
||||
maxWnd=1: nFont=0 dwFontSize=(96,25) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
|
||||
00-00: 12x16
|
||||
GetNumberOfConsoleFonts returned 0
|
||||
CP=437 OutputCP=437
|
||||
|
||||
F:\>SetFont.exe -face "Lucida Console" -h 16 -family 0x36 -weight normal
|
||||
Setting to: nFont=0 dwFontSize=(0,16) FontFamily=0x36 FontWeight=400 FaceName="Lucida Console"
|
||||
SetCurrentConsoleFontEx returned 1
|
||||
|
||||
F:\>GetFont.exe
|
||||
largestConsoleWindowSize=(96,50)
|
||||
maxWnd=0: nFont=0 dwFontSize=(12,16) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
|
||||
maxWnd=1: nFont=0 dwFontSize=(96,25) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
|
||||
00-00: 12x16
|
||||
GetNumberOfConsoleFonts returned 0
|
||||
CP=437 OutputCP=437
|
||||
|
||||
F:\>SetFont.exe -face "Lucida Console" -h 12 -family 0x36 -weight normal
|
||||
Setting to: nFont=0 dwFontSize=(0,12) FontFamily=0x36 FontWeight=400 FaceName="Lucida Console"
|
||||
SetCurrentConsoleFontEx returned 1
|
||||
|
||||
F:\>GetFont.exe
|
||||
largestConsoleWindowSize=(230,66)
|
||||
maxWnd=0: nFont=0 dwFontSize=(5,12) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
|
||||
maxWnd=1: nFont=0 dwFontSize=(116,36) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
|
||||
00-00: 5x12
|
||||
GetNumberOfConsoleFonts returned 0
|
||||
CP=437 OutputCP=437
|
||||
|
||||
Even attempting to set to a Lucida Console / Consolas font from the Console
|
||||
properties dialog fails.
|
@ -1,100 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
|
||||
|
||||
// See https://en.wikipedia.org/wiki/List_of_CJK_fonts
|
||||
const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese
|
||||
const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese
|
||||
const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese
|
||||
const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean
|
||||
|
||||
std::vector<bool> condense(const std::vector<CHAR_INFO> &buf) {
|
||||
std::vector<bool> ret;
|
||||
size_t i = 0;
|
||||
while (i < buf.size()) {
|
||||
if (buf[i].Char.UnicodeChar == L' ' &&
|
||||
((buf[i].Attributes & 0x300) == 0)) {
|
||||
// end of line
|
||||
break;
|
||||
} else if (i + 1 < buf.size() &&
|
||||
((buf[i].Attributes & 0x300) == 0x100) &&
|
||||
((buf[i + 1].Attributes & 0x300) == 0x200) &&
|
||||
buf[i].Char.UnicodeChar != L' ' &&
|
||||
buf[i].Char.UnicodeChar == buf[i + 1].Char.UnicodeChar) {
|
||||
// double-width
|
||||
ret.push_back(true);
|
||||
i += 2;
|
||||
} else if ((buf[i].Attributes & 0x300) == 0) {
|
||||
// single-width
|
||||
ret.push_back(false);
|
||||
i++;
|
||||
} else {
|
||||
ASSERT(false && "unexpected output");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s \"arguments for SetFont.exe\"\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *setFontArgs = argv[1];
|
||||
|
||||
const wchar_t testLine[] = { 0xA2, 0xA3, 0x2014, 0x3044, 0x30FC, 0x4000, 0 };
|
||||
const HANDLE conout = openConout();
|
||||
|
||||
char setFontCmd[1024];
|
||||
for (int h = 1; h <= 100; ++h) {
|
||||
sprintf(setFontCmd, ".\\SetFont.exe %s -h %d && cls", setFontArgs, h);
|
||||
system(setFontCmd);
|
||||
|
||||
CONSOLE_FONT_INFOEX infoex = {};
|
||||
infoex.cbSize = sizeof(infoex);
|
||||
BOOL success = GetCurrentConsoleFontEx(conout, FALSE, &infoex);
|
||||
ASSERT(success && "GetCurrentConsoleFontEx failed");
|
||||
|
||||
DWORD actual = 0;
|
||||
success = WriteConsoleW(conout, testLine, wcslen(testLine), &actual, nullptr);
|
||||
ASSERT(success && actual == wcslen(testLine));
|
||||
|
||||
std::vector<CHAR_INFO> readBuf(14);
|
||||
const SMALL_RECT readRegion = {0, 0, static_cast<short>(readBuf.size() - 1), 0};
|
||||
SMALL_RECT readRegion2 = readRegion;
|
||||
success = ReadConsoleOutputW(
|
||||
conout, readBuf.data(),
|
||||
{static_cast<short>(readBuf.size()), 1},
|
||||
{0, 0},
|
||||
&readRegion2);
|
||||
ASSERT(success && !memcmp(&readRegion, &readRegion2, sizeof(readRegion)));
|
||||
|
||||
const auto widths = condense(readBuf);
|
||||
std::string widthsStr;
|
||||
for (bool width : widths) {
|
||||
widthsStr.append(width ? "F" : "H");
|
||||
}
|
||||
char size[16];
|
||||
sprintf(size, "%d,%d", infoex.dwFontSize.X, infoex.dwFontSize.Y);
|
||||
const char *status = "";
|
||||
if (widthsStr == "HHFFFF") {
|
||||
status = "GOOD";
|
||||
} else if (widthsStr == "HHHFFF") {
|
||||
status = "OK";
|
||||
} else {
|
||||
status = "BAD";
|
||||
}
|
||||
trace("Size %3d: %-7s %-4s (%s)", h, size, status, widthsStr.c_str());
|
||||
}
|
||||
sprintf(setFontCmd, ".\\SetFont.exe %s -h 14", setFontArgs);
|
||||
system(setFontCmd);
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
const int SC_CONSOLE_MARK = 0xFFF2;
|
||||
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
|
||||
|
||||
int main(int argc, char *argv[0]) {
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s (mark|selectall|read)\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum class Test { Mark, SelectAll, Read } test;
|
||||
if (!strcmp(argv[1], "mark")) {
|
||||
test = Test::Mark;
|
||||
} else if (!strcmp(argv[1], "selectall")) {
|
||||
test = Test::SelectAll;
|
||||
} else if (!strcmp(argv[1], "read")) {
|
||||
test = Test::Read;
|
||||
} else {
|
||||
printf("Invalid test: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
TimeMeasurement tm;
|
||||
HWND hwnd = GetConsoleWindow();
|
||||
|
||||
setWindowPos(0, 0, 1, 1);
|
||||
setBufferSize(100, 3000);
|
||||
system("cls");
|
||||
setWindowPos(0, 2975, 100, 25);
|
||||
setCursorPos(0, 2999);
|
||||
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
// CONSOLE_SCREEN_BUFFER_INFO info = {};
|
||||
// GetConsoleScreenBufferInfo(conout, &info);
|
||||
|
||||
if (test == Test::Mark) {
|
||||
SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0);
|
||||
SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
|
||||
} else if (test == Test::SelectAll) {
|
||||
SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
|
||||
SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
|
||||
} else if (test == Test::Read) {
|
||||
static CHAR_INFO buffer[100 * 3000];
|
||||
const SMALL_RECT readRegion = {0, 0, 99, 2999};
|
||||
SMALL_RECT tmp = readRegion;
|
||||
BOOL ret = ReadConsoleOutput(conout, buffer, {100, 3000}, {0, 0}, &tmp);
|
||||
ASSERT(ret && !memcmp(&tmp, &readRegion, sizeof(tmp)));
|
||||
}
|
||||
}
|
||||
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
|
||||
printf("elapsed: %f\n", tm.elapsed());
|
||||
return 0;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#include <conio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("\nPress any keys -- Ctrl-D exits\n\n");
|
||||
|
||||
while (true) {
|
||||
const int ch = getch();
|
||||
printf("0x%x", ch);
|
||||
if (isgraph(ch)) {
|
||||
printf(" '%c'", ch);
|
||||
}
|
||||
printf("\n");
|
||||
if (ch == 0x4) { // Ctrl-D
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main() {
|
||||
const HANDLE conout = openConout();
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO info = {};
|
||||
BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
|
||||
ASSERT(ret && "GetConsoleScreenBufferInfo failed");
|
||||
|
||||
trace("cursor=%d,%d", info.dwCursorPosition.X, info.dwCursorPosition.Y);
|
||||
printf("cursor=%d,%d\n", info.dwCursorPosition.X, info.dwCursorPosition.Y);
|
||||
|
||||
trace("srWindow={L=%d,T=%d,R=%d,B=%d}", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom);
|
||||
printf("srWindow={L=%d,T=%d,R=%d,B=%d}\n", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom);
|
||||
|
||||
trace("dwSize=%d,%d", info.dwSize.X, info.dwSize.Y);
|
||||
printf("dwSize=%d,%d\n", info.dwSize.X, info.dwSize.Y);
|
||||
|
||||
const HWND hwnd = GetConsoleWindow();
|
||||
if (hwnd != NULL) {
|
||||
RECT r = {};
|
||||
if (GetWindowRect(hwnd, &r)) {
|
||||
const int w = r.right - r.left;
|
||||
const int h = r.bottom - r.top;
|
||||
trace("hwnd: pos=(%d,%d) size=(%d,%d)", r.left, r.top, w, h);
|
||||
printf("hwnd: pos=(%d,%d) size=(%d,%d)\n", r.left, r.top, w, h);
|
||||
} else {
|
||||
trace("GetWindowRect failed");
|
||||
printf("GetWindowRect failed\n");
|
||||
}
|
||||
} else {
|
||||
trace("GetConsoleWindow returned NULL");
|
||||
printf("GetConsoleWindow returned NULL\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
261
misc/GetFont.cc
261
misc/GetFont.cc
@ -1,261 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "../src/shared/OsModule.h"
|
||||
#include "../src/shared/StringUtil.h"
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/StringUtil.cc"
|
||||
|
||||
#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
// Some of these types and functions are missing from the MinGW headers.
|
||||
// Others are undocumented.
|
||||
|
||||
struct AGENT_CONSOLE_FONT_INFO {
|
||||
DWORD nFont;
|
||||
COORD dwFontSize;
|
||||
};
|
||||
|
||||
struct AGENT_CONSOLE_FONT_INFOEX {
|
||||
ULONG cbSize;
|
||||
DWORD nFont;
|
||||
COORD dwFontSize;
|
||||
UINT FontFamily;
|
||||
UINT FontWeight;
|
||||
WCHAR FaceName[LF_FACESIZE];
|
||||
};
|
||||
|
||||
// undocumented XP API
|
||||
typedef BOOL WINAPI SetConsoleFont_t(
|
||||
HANDLE hOutput,
|
||||
DWORD dwFontIndex);
|
||||
|
||||
// undocumented XP API
|
||||
typedef DWORD WINAPI GetNumberOfConsoleFonts_t();
|
||||
|
||||
// XP and up
|
||||
typedef BOOL WINAPI GetCurrentConsoleFont_t(
|
||||
HANDLE hOutput,
|
||||
BOOL bMaximumWindow,
|
||||
AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont);
|
||||
|
||||
// XP and up
|
||||
typedef COORD WINAPI GetConsoleFontSize_t(
|
||||
HANDLE hConsoleOutput,
|
||||
DWORD nFont);
|
||||
|
||||
// Vista and up
|
||||
typedef BOOL WINAPI GetCurrentConsoleFontEx_t(
|
||||
HANDLE hConsoleOutput,
|
||||
BOOL bMaximumWindow,
|
||||
AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
|
||||
|
||||
// Vista and up
|
||||
typedef BOOL WINAPI SetCurrentConsoleFontEx_t(
|
||||
HANDLE hConsoleOutput,
|
||||
BOOL bMaximumWindow,
|
||||
AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
|
||||
|
||||
#define GET_MODULE_PROC(mod, funcName) \
|
||||
m_##funcName = reinterpret_cast<funcName##_t*>((mod).proc(#funcName)); \
|
||||
|
||||
#define DEFINE_ACCESSOR(funcName) \
|
||||
funcName##_t &funcName() const { \
|
||||
ASSERT(valid()); \
|
||||
return *m_##funcName; \
|
||||
}
|
||||
|
||||
class XPFontAPI {
|
||||
public:
|
||||
XPFontAPI() : m_kernel32(L"kernel32.dll") {
|
||||
GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont);
|
||||
GET_MODULE_PROC(m_kernel32, GetConsoleFontSize);
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return m_GetCurrentConsoleFont != NULL &&
|
||||
m_GetConsoleFontSize != NULL;
|
||||
}
|
||||
|
||||
DEFINE_ACCESSOR(GetCurrentConsoleFont)
|
||||
DEFINE_ACCESSOR(GetConsoleFontSize)
|
||||
|
||||
private:
|
||||
OsModule m_kernel32;
|
||||
GetCurrentConsoleFont_t *m_GetCurrentConsoleFont;
|
||||
GetConsoleFontSize_t *m_GetConsoleFontSize;
|
||||
};
|
||||
|
||||
class UndocumentedXPFontAPI : public XPFontAPI {
|
||||
public:
|
||||
UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") {
|
||||
GET_MODULE_PROC(m_kernel32, SetConsoleFont);
|
||||
GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts);
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return this->XPFontAPI::valid() &&
|
||||
m_SetConsoleFont != NULL &&
|
||||
m_GetNumberOfConsoleFonts != NULL;
|
||||
}
|
||||
|
||||
DEFINE_ACCESSOR(SetConsoleFont)
|
||||
DEFINE_ACCESSOR(GetNumberOfConsoleFonts)
|
||||
|
||||
private:
|
||||
OsModule m_kernel32;
|
||||
SetConsoleFont_t *m_SetConsoleFont;
|
||||
GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts;
|
||||
};
|
||||
|
||||
class VistaFontAPI : public XPFontAPI {
|
||||
public:
|
||||
VistaFontAPI() : m_kernel32(L"kernel32.dll") {
|
||||
GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx);
|
||||
GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx);
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return this->XPFontAPI::valid() &&
|
||||
m_GetCurrentConsoleFontEx != NULL &&
|
||||
m_SetCurrentConsoleFontEx != NULL;
|
||||
}
|
||||
|
||||
DEFINE_ACCESSOR(GetCurrentConsoleFontEx)
|
||||
DEFINE_ACCESSOR(SetCurrentConsoleFontEx)
|
||||
|
||||
private:
|
||||
OsModule m_kernel32;
|
||||
GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx;
|
||||
SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx;
|
||||
};
|
||||
|
||||
static std::vector<std::pair<DWORD, COORD> > readFontTable(
|
||||
XPFontAPI &api, HANDLE conout, DWORD maxCount) {
|
||||
std::vector<std::pair<DWORD, COORD> > ret;
|
||||
for (DWORD i = 0; i < maxCount; ++i) {
|
||||
COORD size = api.GetConsoleFontSize()(conout, i);
|
||||
if (size.X == 0 && size.Y == 0) {
|
||||
break;
|
||||
}
|
||||
ret.push_back(std::make_pair(i, size));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dumpFontTable(HANDLE conout) {
|
||||
const int kMaxCount = 1000;
|
||||
XPFontAPI api;
|
||||
if (!api.valid()) {
|
||||
printf("dumpFontTable: cannot dump font table -- missing APIs\n");
|
||||
return;
|
||||
}
|
||||
std::vector<std::pair<DWORD, COORD> > table =
|
||||
readFontTable(api, conout, kMaxCount);
|
||||
std::string line;
|
||||
char tmp[128];
|
||||
size_t first = 0;
|
||||
while (first < table.size()) {
|
||||
size_t last = std::min(table.size() - 1, first + 10 - 1);
|
||||
winpty_snprintf(tmp, "%02u-%02u:",
|
||||
static_cast<unsigned>(first), static_cast<unsigned>(last));
|
||||
line = tmp;
|
||||
for (size_t i = first; i <= last; ++i) {
|
||||
if (i % 10 == 5) {
|
||||
line += " - ";
|
||||
}
|
||||
winpty_snprintf(tmp, " %2dx%-2d",
|
||||
table[i].second.X, table[i].second.Y);
|
||||
line += tmp;
|
||||
}
|
||||
printf("%s\n", line.c_str());
|
||||
first = last + 1;
|
||||
}
|
||||
if (table.size() == kMaxCount) {
|
||||
printf("... stopped reading at %d fonts ...\n", kMaxCount);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string stringToCodePoints(const std::wstring &str) {
|
||||
std::string ret = "(";
|
||||
for (size_t i = 0; i < str.size(); ++i) {
|
||||
char tmp[32];
|
||||
winpty_snprintf(tmp, "%X", str[i]);
|
||||
if (ret.size() > 1) {
|
||||
ret.push_back(' ');
|
||||
}
|
||||
ret += tmp;
|
||||
}
|
||||
ret.push_back(')');
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dumpFontInfoEx(
|
||||
const AGENT_CONSOLE_FONT_INFOEX &infoex) {
|
||||
std::wstring faceName(infoex.FaceName,
|
||||
winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName)));
|
||||
cprintf(L"nFont=%u dwFontSize=(%d,%d) "
|
||||
"FontFamily=0x%x FontWeight=%u FaceName=%ls %hs\n",
|
||||
static_cast<unsigned>(infoex.nFont),
|
||||
infoex.dwFontSize.X, infoex.dwFontSize.Y,
|
||||
infoex.FontFamily, infoex.FontWeight, faceName.c_str(),
|
||||
stringToCodePoints(faceName).c_str());
|
||||
}
|
||||
|
||||
static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, BOOL maxWindow) {
|
||||
AGENT_CONSOLE_FONT_INFOEX infoex = {0};
|
||||
infoex.cbSize = sizeof(infoex);
|
||||
if (!api.GetCurrentConsoleFontEx()(conout, maxWindow, &infoex)) {
|
||||
printf("GetCurrentConsoleFontEx call failed\n");
|
||||
return;
|
||||
}
|
||||
dumpFontInfoEx(infoex);
|
||||
}
|
||||
|
||||
static void dumpXPFont(XPFontAPI &api, HANDLE conout, BOOL maxWindow) {
|
||||
AGENT_CONSOLE_FONT_INFO info = {0};
|
||||
if (!api.GetCurrentConsoleFont()(conout, maxWindow, &info)) {
|
||||
printf("GetCurrentConsoleFont call failed\n");
|
||||
return;
|
||||
}
|
||||
printf("nFont=%u dwFontSize=(%d,%d)\n",
|
||||
static_cast<unsigned>(info.nFont),
|
||||
info.dwFontSize.X, info.dwFontSize.Y);
|
||||
}
|
||||
|
||||
static void dumpFontAndTable(HANDLE conout) {
|
||||
VistaFontAPI vista;
|
||||
if (vista.valid()) {
|
||||
printf("maxWnd=0: "); dumpVistaFont(vista, conout, FALSE);
|
||||
printf("maxWnd=1: "); dumpVistaFont(vista, conout, TRUE);
|
||||
dumpFontTable(conout);
|
||||
return;
|
||||
}
|
||||
UndocumentedXPFontAPI xp;
|
||||
if (xp.valid()) {
|
||||
printf("maxWnd=0: "); dumpXPFont(xp, conout, FALSE);
|
||||
printf("maxWnd=1: "); dumpXPFont(xp, conout, TRUE);
|
||||
dumpFontTable(conout);
|
||||
return;
|
||||
}
|
||||
printf("setSmallFont: neither Vista nor XP APIs detected -- giving up\n");
|
||||
dumpFontTable(conout);
|
||||
}
|
||||
|
||||
int main() {
|
||||
const HANDLE conout = openConout();
|
||||
const COORD largest = GetLargestConsoleWindowSize(conout);
|
||||
printf("largestConsoleWindowSize=(%d,%d)\n", largest.X, largest.Y);
|
||||
dumpFontAndTable(conout);
|
||||
UndocumentedXPFontAPI xp;
|
||||
if (xp.valid()) {
|
||||
printf("GetNumberOfConsoleFonts returned %u\n", xp.GetNumberOfConsoleFonts()());
|
||||
} else {
|
||||
printf("The GetNumberOfConsoleFonts API was missing\n");
|
||||
}
|
||||
printf("CP=%u OutputCP=%u\n", GetConsoleCP(), GetConsoleOutputCP());
|
||||
return 0;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
#
|
||||
# Usage: powershell <path>\IdentifyConsoleWindow.ps1
|
||||
#
|
||||
# This script determines whether the process has a console attached, whether
|
||||
# that console has a non-NULL window (e.g. HWND), and whether the window is on
|
||||
# the current window station.
|
||||
#
|
||||
|
||||
$signature = @'
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern IntPtr GetConsoleWindow();
|
||||
|
||||
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
|
||||
public static extern bool SetConsoleTitle(String title);
|
||||
|
||||
[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
|
||||
public static extern int GetWindowText(IntPtr hWnd,
|
||||
System.Text.StringBuilder lpString,
|
||||
int nMaxCount);
|
||||
'@
|
||||
|
||||
$WinAPI = Add-Type -MemberDefinition $signature `
|
||||
-Name WinAPI -Namespace IdentifyConsoleWindow -PassThru
|
||||
|
||||
if (!$WinAPI::SetConsoleTitle("ConsoleWindowScript")) {
|
||||
echo "error: could not change console title -- is a console attached?"
|
||||
exit 1
|
||||
} else {
|
||||
echo "note: successfully set console title to ""ConsoleWindowScript""."
|
||||
}
|
||||
|
||||
$hwnd = $WinAPI::GetConsoleWindow()
|
||||
if ($hwnd -eq 0) {
|
||||
echo "note: GetConsoleWindow returned NULL."
|
||||
} else {
|
||||
echo "note: GetConsoleWindow returned 0x$($hwnd.ToString("X"))."
|
||||
$sb = New-Object System.Text.StringBuilder -ArgumentList 4096
|
||||
if ($WinAPI::GetWindowText($hwnd, $sb, $sb.Capacity)) {
|
||||
$title = $sb.ToString()
|
||||
echo "note: GetWindowText returned ""${title}""."
|
||||
if ($title -eq "ConsoleWindowScript") {
|
||||
echo "success!"
|
||||
} else {
|
||||
echo "error: expected to see ""ConsoleWindowScript""."
|
||||
echo " (Perhaps the console window is on a different window station?)"
|
||||
}
|
||||
} else {
|
||||
echo "error: GetWindowText could not read the window title."
|
||||
echo " (Perhaps the console window is on a different window station?)"
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
// Determines whether this is a new console by testing whether MARK moves the
|
||||
// cursor.
|
||||
//
|
||||
// WARNING: This test program may behave erratically if run under winpty.
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
const int SC_CONSOLE_MARK = 0xFFF2;
|
||||
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
|
||||
|
||||
static COORD getWindowPos(HANDLE conout) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info = {};
|
||||
BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
|
||||
ASSERT(ret && "GetConsoleScreenBufferInfo failed");
|
||||
return { info.srWindow.Left, info.srWindow.Top };
|
||||
}
|
||||
|
||||
static COORD getWindowSize(HANDLE conout) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info = {};
|
||||
BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
|
||||
ASSERT(ret && "GetConsoleScreenBufferInfo failed");
|
||||
return {
|
||||
static_cast<short>(info.srWindow.Right - info.srWindow.Left + 1),
|
||||
static_cast<short>(info.srWindow.Bottom - info.srWindow.Top + 1)
|
||||
};
|
||||
}
|
||||
|
||||
static COORD getCursorPos(HANDLE conout) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info = {};
|
||||
BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
|
||||
ASSERT(ret && "GetConsoleScreenBufferInfo failed");
|
||||
return info.dwCursorPosition;
|
||||
}
|
||||
|
||||
static void setCursorPos(HANDLE conout, COORD pos) {
|
||||
BOOL ret = SetConsoleCursorPosition(conout, pos);
|
||||
ASSERT(ret && "SetConsoleCursorPosition failed");
|
||||
}
|
||||
|
||||
int main() {
|
||||
const HANDLE conout = openConout();
|
||||
const HWND hwnd = GetConsoleWindow();
|
||||
ASSERT(hwnd != NULL && "GetConsoleWindow() returned NULL");
|
||||
|
||||
// With the legacy console, the Mark command moves the the cursor to the
|
||||
// top-left cell of the visible console window. Determine whether this
|
||||
// is the new console by seeing if the cursor moves.
|
||||
|
||||
const auto windowSize = getWindowSize(conout);
|
||||
if (windowSize.X <= 1) {
|
||||
printf("Error: console window must be at least 2 columns wide\n");
|
||||
trace("Error: console window must be at least 2 columns wide");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool cursorMoved = false;
|
||||
const auto initialPos = getCursorPos(conout);
|
||||
|
||||
const auto windowPos = getWindowPos(conout);
|
||||
setCursorPos(conout, { static_cast<short>(windowPos.X + 1), windowPos.Y });
|
||||
|
||||
{
|
||||
const auto posA = getCursorPos(conout);
|
||||
SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0);
|
||||
const auto posB = getCursorPos(conout);
|
||||
cursorMoved = memcmp(&posA, &posB, sizeof(posA)) != 0;
|
||||
SendMessage(hwnd, WM_CHAR, 27, 0x00010001); // Send ESCAPE
|
||||
}
|
||||
|
||||
setCursorPos(conout, initialPos);
|
||||
|
||||
if (cursorMoved) {
|
||||
printf("Legacy console (i.e. MARK moved cursor)\n");
|
||||
trace("Legacy console (i.e. MARK moved cursor)");
|
||||
} else {
|
||||
printf("Windows 10 new console (i.e MARK did not move cursor)\n");
|
||||
trace("Windows 10 new console (i.e MARK did not move cursor)");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
0
misc/MouseInputNotes.txt
Normal file → Executable file
0
misc/MouseInputNotes.txt
Normal file → Executable file
@ -1,34 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3 && argc != 5) {
|
||||
printf("Usage: %s x y\n", argv[0]);
|
||||
printf("Usage: %s x y width height\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
HWND hwnd = GetConsoleWindow();
|
||||
|
||||
const int x = atoi(argv[1]);
|
||||
const int y = atoi(argv[2]);
|
||||
|
||||
int w = 0, h = 0;
|
||||
if (argc == 3) {
|
||||
RECT r = {};
|
||||
BOOL ret = GetWindowRect(hwnd, &r);
|
||||
ASSERT(ret && "GetWindowRect failed on console window");
|
||||
w = r.right - r.left;
|
||||
h = r.bottom - r.top;
|
||||
} else {
|
||||
w = atoi(argv[3]);
|
||||
h = atoi(argv[4]);
|
||||
}
|
||||
|
||||
BOOL ret = MoveWindow(hwnd, x, y, w, h, TRUE);
|
||||
trace("MoveWindow: ret=%d", ret);
|
||||
printf("MoveWindow: ret=%d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
75
misc/QueryFont.cc
Normal file
75
misc/QueryFont.cc
Normal file
@ -0,0 +1,75 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
static void queryCurrentConsoleFont(HANDLE conout, BOOL max) {
|
||||
CONSOLE_FONT_INFO info = {0};
|
||||
if (!GetCurrentConsoleFont(conout, max, &info)) {
|
||||
cprintf(L"GetCurrentConsoleFont call failed\n");
|
||||
} else {
|
||||
cprintf(L"info(max=%d): nFont=%u dwFontSize=(%d,%d)\n",
|
||||
max, static_cast<unsigned>(info.nFont),
|
||||
info.dwFontSize.X, info.dwFontSize.Y);
|
||||
}
|
||||
}
|
||||
|
||||
static void queryCurrentConsoleFontEx(HANDLE conout, BOOL max) {
|
||||
CONSOLE_FONT_INFOEX infoex = {0};
|
||||
infoex.cbSize = sizeof(infoex);
|
||||
if (!GetCurrentConsoleFontEx(conout, max, &infoex)) {
|
||||
cprintf(L"GetCurrentConsoleFontEx call failed\n");
|
||||
} else {
|
||||
wchar_t faceName[LF_FACESIZE + 1];
|
||||
memcpy(faceName, infoex.FaceName, sizeof(faceName));
|
||||
faceName[LF_FACESIZE] = L'\0';
|
||||
cprintf(L"infoex(max=%d): nFont=%u dwFontSize=(%d,%d) "
|
||||
L"FontFamily=0x%x FontWeight=%u "
|
||||
L"FaceName=\"%ls\"",
|
||||
max, static_cast<unsigned>(infoex.nFont),
|
||||
infoex.dwFontSize.X, infoex.dwFontSize.Y,
|
||||
infoex.FontFamily, infoex.FontWeight,
|
||||
faceName);
|
||||
cprintf(L" (");
|
||||
for (int i = 0; i < LF_FACESIZE; ++i) {
|
||||
if (i > 0) {
|
||||
cprintf(L" ");
|
||||
}
|
||||
cprintf(L"%X", infoex.FaceName[i]);
|
||||
if (infoex.FaceName[i] == L'\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cprintf(L")\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
queryCurrentConsoleFont(conout, FALSE);
|
||||
queryCurrentConsoleFont(conout, TRUE);
|
||||
queryCurrentConsoleFontEx(conout, FALSE);
|
||||
queryCurrentConsoleFontEx(conout, TRUE);
|
||||
const COORD largest = GetLargestConsoleWindowSize(conout);
|
||||
cprintf(L"largestConsoleWindowSize=(%d,%d)\n", largest.X, largest.Y);
|
||||
for (int i = 0;; ++i) {
|
||||
const COORD size = GetConsoleFontSize(conout, i);
|
||||
if (size.X == 0 && size.Y == 0) {
|
||||
break;
|
||||
}
|
||||
cprintf(L"font %d: %dx%d\n", i, size.X, size.Y);
|
||||
}
|
||||
HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
|
||||
FARPROC proc = GetProcAddress(kernel32, "GetNumberOfConsoleFonts");
|
||||
if (proc == NULL) {
|
||||
cprintf(L"Could not get address of GetNumberOfConsoleFonts\n");
|
||||
} else {
|
||||
cprintf(L"GetNumberOfConsoleFonts returned %d\n",
|
||||
reinterpret_cast<int WINAPI(*)(HANDLE)>(proc)(conout));
|
||||
}
|
||||
cprintf(L"InputCP=%u OutputCP=%u", GetConsoleCP(), GetConsoleOutputCP());
|
||||
return 0;
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
//
|
||||
// Verify that console selection blocks writes to an inactive console screen
|
||||
// buffer. Writes TEST PASSED or TEST FAILED to the popup console window.
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
const int SC_CONSOLE_MARK = 0xFFF2;
|
||||
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
|
||||
|
||||
bool g_useMark = false;
|
||||
|
||||
CALLBACK DWORD pausingThread(LPVOID dummy)
|
||||
{
|
||||
HWND hwnd = GetConsoleWindow();
|
||||
trace("Sending selection to freeze");
|
||||
SendMessage(hwnd, WM_SYSCOMMAND,
|
||||
g_useMark ? SC_CONSOLE_MARK :
|
||||
SC_CONSOLE_SELECT_ALL,
|
||||
0);
|
||||
Sleep(1000);
|
||||
trace("Sending escape WM_CHAR to unfreeze");
|
||||
SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
|
||||
Sleep(1000);
|
||||
}
|
||||
|
||||
static HANDLE createBuffer() {
|
||||
HANDLE buf = CreateConsoleScreenBuffer(
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
CONSOLE_TEXTMODE_BUFFER,
|
||||
NULL);
|
||||
ASSERT(buf != INVALID_HANDLE_VALUE);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void runTest(bool useMark, bool createEarly) {
|
||||
trace("=======================================");
|
||||
trace("useMark=%d createEarly=%d", useMark, createEarly);
|
||||
g_useMark = useMark;
|
||||
HANDLE buf = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (createEarly) {
|
||||
buf = createBuffer();
|
||||
}
|
||||
|
||||
CreateThread(NULL, 0,
|
||||
pausingThread, NULL,
|
||||
0, NULL);
|
||||
Sleep(500);
|
||||
|
||||
if (!createEarly) {
|
||||
trace("Creating buffer");
|
||||
TimeMeasurement tm1;
|
||||
buf = createBuffer();
|
||||
const double elapsed1 = tm1.elapsed();
|
||||
if (elapsed1 >= 0.250) {
|
||||
printf("!!! TEST FAILED !!!\n");
|
||||
Sleep(2000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
trace("Writing to aux buffer");
|
||||
TimeMeasurement tm2;
|
||||
DWORD actual = 0;
|
||||
BOOL ret = WriteConsoleW(buf, L"HI", 2, &actual, NULL);
|
||||
const double elapsed2 = tm2.elapsed();
|
||||
trace("Writing to aux buffer: finished: ret=%d actual=%d (elapsed=%1.3f)", ret, actual, elapsed2);
|
||||
if (elapsed2 < 0.250) {
|
||||
printf("!!! TEST FAILED !!!\n");
|
||||
} else {
|
||||
printf("TEST PASSED\n");
|
||||
}
|
||||
Sleep(2000);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
startChildProcess(L"child");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string arg = argv[1];
|
||||
if (arg == "child") {
|
||||
for (int useMark = 0; useMark <= 1; useMark++) {
|
||||
for (int createEarly = 0; createEarly <= 1; createEarly++) {
|
||||
runTest(useMark, createEarly);
|
||||
}
|
||||
}
|
||||
printf("done...\n");
|
||||
Sleep(1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
1
misc/ScreenBufferTest.cc
Normal file → Executable file
1
misc/ScreenBufferTest.cc
Normal file → Executable file
@ -52,6 +52,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
const char *g_prefix = "";
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
const char *g_prefix = "";
|
||||
|
||||
|
@ -1,90 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
static void usage() {
|
||||
printf("usage: SetBufInfo [-set] [-buf W H] [-win W H] [-pos X Y]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const HANDLE conout = CreateFileW(L"CONOUT$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
ASSERT(conout != INVALID_HANDLE_VALUE);
|
||||
|
||||
bool change = false;
|
||||
BOOL success;
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX info = {};
|
||||
info.cbSize = sizeof(info);
|
||||
|
||||
success = GetConsoleScreenBufferInfoEx(conout, &info);
|
||||
ASSERT(success && "GetConsoleScreenBufferInfoEx failed");
|
||||
|
||||
for (int i = 1; i < argc; ) {
|
||||
std::string arg = argv[i];
|
||||
if (arg == "-buf" && (i + 2) < argc) {
|
||||
info.dwSize.X = atoi(argv[i + 1]);
|
||||
info.dwSize.Y = atoi(argv[i + 2]);
|
||||
i += 3;
|
||||
change = true;
|
||||
} else if (arg == "-pos" && (i + 2) < argc) {
|
||||
int dx = info.srWindow.Right - info.srWindow.Left;
|
||||
int dy = info.srWindow.Bottom - info.srWindow.Top;
|
||||
info.srWindow.Left = atoi(argv[i + 1]);
|
||||
info.srWindow.Top = atoi(argv[i + 2]);
|
||||
i += 3;
|
||||
info.srWindow.Right = info.srWindow.Left + dx;
|
||||
info.srWindow.Bottom = info.srWindow.Top + dy;
|
||||
change = true;
|
||||
} else if (arg == "-win" && (i + 2) < argc) {
|
||||
info.srWindow.Right = info.srWindow.Left + atoi(argv[i + 1]) - 1;
|
||||
info.srWindow.Bottom = info.srWindow.Top + atoi(argv[i + 2]) - 1;
|
||||
i += 3;
|
||||
change = true;
|
||||
} else if (arg == "-set") {
|
||||
change = true;
|
||||
++i;
|
||||
} else if (arg == "--help" || arg == "-help") {
|
||||
usage();
|
||||
exit(0);
|
||||
} else {
|
||||
fprintf(stderr, "error: unrecognized argument: %s\n", arg.c_str());
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (change) {
|
||||
success = SetConsoleScreenBufferInfoEx(conout, &info);
|
||||
if (success) {
|
||||
printf("success\n");
|
||||
} else {
|
||||
printf("SetConsoleScreenBufferInfoEx call failed\n");
|
||||
}
|
||||
success = GetConsoleScreenBufferInfoEx(conout, &info);
|
||||
ASSERT(success && "GetConsoleScreenBufferInfoEx failed");
|
||||
}
|
||||
|
||||
auto dump = [](const char *fmt, ...) {
|
||||
char msg[256];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(msg, fmt, ap);
|
||||
va_end(ap);
|
||||
trace("%s", msg);
|
||||
printf("%s\n", msg);
|
||||
};
|
||||
|
||||
dump("buffer-size: %d x %d", info.dwSize.X, info.dwSize.Y);
|
||||
dump("window-size: %d x %d",
|
||||
info.srWindow.Right - info.srWindow.Left + 1,
|
||||
info.srWindow.Bottom - info.srWindow.Top + 1);
|
||||
dump("window-pos: %d, %d", info.srWindow.Left, info.srWindow.Top);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
printf("Usage: %s x y width height\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const HANDLE conout = CreateFileW(L"CONOUT$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
ASSERT(conout != INVALID_HANDLE_VALUE);
|
||||
|
||||
COORD size = {
|
||||
(short)atoi(argv[1]),
|
||||
(short)atoi(argv[2]),
|
||||
};
|
||||
|
||||
BOOL ret = SetConsoleScreenBufferSize(conout, size);
|
||||
const unsigned lastError = GetLastError();
|
||||
const char *const retStr = ret ? "OK" : "failed";
|
||||
trace("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)", retStr, lastError);
|
||||
printf("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)\n", retStr, lastError);
|
||||
|
||||
return 0;
|
||||
}
|
1
misc/SetCursorPos.cc
Normal file → Executable file
1
misc/SetCursorPos.cc
Normal file → Executable file
@ -1,6 +1,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int col = atoi(argv[1]);
|
||||
|
@ -5,21 +5,32 @@
|
||||
#include <string>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
|
||||
|
||||
// See https://en.wikipedia.org/wiki/List_of_CJK_fonts
|
||||
const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese
|
||||
const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese
|
||||
const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese
|
||||
const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean
|
||||
// Attempt to set the console font to the given facename and pixel size.
|
||||
// These APIs should exist on Vista and up.
|
||||
static void setConsoleFont(const wchar_t *faceName, int pixelSize)
|
||||
{
|
||||
CONSOLE_FONT_INFOEX fontex = {0};
|
||||
fontex.cbSize = sizeof(fontex);
|
||||
fontex.FontWeight = 400;
|
||||
fontex.dwFontSize.Y = pixelSize;
|
||||
wcsncpy(fontex.FaceName, faceName, COUNT_OF(fontex.FaceName));
|
||||
fontex.nFont = 34;
|
||||
BOOL ret = SetCurrentConsoleFontEx(
|
||||
GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
FALSE,
|
||||
&fontex);
|
||||
cprintf(L"SetCurrentConsoleFontEx returned %d\n", ret);
|
||||
}
|
||||
|
||||
int main() {
|
||||
setlocale(LC_ALL, "");
|
||||
wchar_t *cmdline = GetCommandLineW();
|
||||
int argc = 0;
|
||||
wchar_t **argv = CommandLineToArgvW(cmdline, &argc);
|
||||
const HANDLE conout = openConout();
|
||||
|
||||
if (argc == 1) {
|
||||
cprintf(L"Usage:\n");
|
||||
@ -30,10 +41,8 @@ int main() {
|
||||
cprintf(L" -idx INDEX\n");
|
||||
cprintf(L" -w WIDTH\n");
|
||||
cprintf(L" -h HEIGHT\n");
|
||||
cprintf(L" -family (0xNN|NN)\n");
|
||||
cprintf(L" -weight (normal|bold|NNN)\n");
|
||||
cprintf(L" -face FACENAME\n");
|
||||
cprintf(L" -face-{gothic|simsun|minglight|gulimche) [JP,CN-sim,CN-tra,KR]\n");
|
||||
cprintf(L" -tt\n");
|
||||
cprintf(L" -vec\n");
|
||||
cprintf(L" -vp\n");
|
||||
@ -53,6 +62,7 @@ int main() {
|
||||
if (proc == NULL) {
|
||||
cprintf(L"Couldn't get address of SetConsoleFont\n");
|
||||
} else {
|
||||
const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
BOOL ret = reinterpret_cast<BOOL WINAPI(*)(HANDLE, DWORD)>(proc)(
|
||||
conout, index);
|
||||
cprintf(L"SetFont returned %d\n", ret);
|
||||
@ -88,9 +98,6 @@ int main() {
|
||||
} else if (arg == L"-face") {
|
||||
wcsncpy(fontex.FaceName, next.c_str(), COUNT_OF(fontex.FaceName));
|
||||
++i; continue;
|
||||
} else if (arg == L"-family") {
|
||||
fontex.FontFamily = strtol(narrowString(next).c_str(), nullptr, 0);
|
||||
++i; continue;
|
||||
}
|
||||
}
|
||||
if (arg == L"-tt") {
|
||||
@ -114,13 +121,11 @@ int main() {
|
||||
} else if (arg == L"-decorative") {
|
||||
fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_DECORATIVE;
|
||||
} else if (arg == L"-face-gothic") {
|
||||
wcsncpy(fontex.FaceName, kMSGothic, COUNT_OF(fontex.FaceName));
|
||||
} else if (arg == L"-face-simsun") {
|
||||
wcsncpy(fontex.FaceName, kNSimSun, COUNT_OF(fontex.FaceName));
|
||||
} else if (arg == L"-face-minglight") {
|
||||
wcsncpy(fontex.FaceName, kMingLight, COUNT_OF(fontex.FaceName));
|
||||
} else if (arg == L"-face-gulimche") {
|
||||
wcsncpy(fontex.FaceName, kGulimChe, COUNT_OF(fontex.FaceName));
|
||||
// MS ゴシック
|
||||
const wchar_t gothicFace[] = {
|
||||
0xFF2D, 0xFF33, 0x20, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0x0
|
||||
};
|
||||
wcsncpy(fontex.FaceName, gothicFace, COUNT_OF(fontex.FaceName));
|
||||
} else {
|
||||
cprintf(L"Unrecognized argument: %ls\n", arg.c_str());
|
||||
exit(1);
|
||||
@ -136,7 +141,7 @@ int main() {
|
||||
fontex.FaceName);
|
||||
|
||||
BOOL ret = SetCurrentConsoleFontEx(
|
||||
conout,
|
||||
GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
FALSE,
|
||||
&fontex);
|
||||
cprintf(L"SetCurrentConsoleFontEx returned %d\n", ret);
|
||||
|
@ -1,36 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 5) {
|
||||
printf("Usage: %s x y width height\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const HANDLE conout = CreateFileW(L"CONOUT$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
ASSERT(conout != INVALID_HANDLE_VALUE);
|
||||
|
||||
SMALL_RECT sr = {
|
||||
(short)atoi(argv[1]),
|
||||
(short)atoi(argv[2]),
|
||||
(short)(atoi(argv[1]) + atoi(argv[3]) - 1),
|
||||
(short)(atoi(argv[2]) + atoi(argv[4]) - 1),
|
||||
};
|
||||
|
||||
trace("Calling SetConsoleWindowInfo with {L=%d,T=%d,R=%d,B=%d}",
|
||||
sr.Left, sr.Top, sr.Right, sr.Bottom);
|
||||
BOOL ret = SetConsoleWindowInfo(conout, TRUE, &sr);
|
||||
const unsigned lastError = GetLastError();
|
||||
const char *const retStr = ret ? "OK" : "failed";
|
||||
trace("SetConsoleWindowInfo ret: %s (LastError=0x%x)", retStr, lastError);
|
||||
printf("SetConsoleWindowInfo ret: %s (LastError=0x%x)\n", retStr, lastError);
|
||||
|
||||
return 0;
|
||||
}
|
0
misc/Spew.py
Executable file → Normal file
0
misc/Spew.py
Executable file → Normal file
14
misc/TestUtil.cc
Normal file → Executable file
14
misc/TestUtil.cc
Normal file → Executable file
@ -9,11 +9,6 @@
|
||||
#include <string>
|
||||
|
||||
#include "../src/shared/DebugClient.h"
|
||||
#include "../src/shared/TimeMeasurement.h"
|
||||
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
#include "../src/shared/WinptyAssert.cc"
|
||||
#include "../src/shared/WinptyException.cc"
|
||||
|
||||
// Launch this test program again, in a new console that we will destroy.
|
||||
static void startChildProcess(const wchar_t *args) {
|
||||
@ -161,12 +156,3 @@ static std::string narrowString(const std::wstring &input)
|
||||
assert(mblen2 == mblen);
|
||||
return std::string(tmp.data(), tmp.size());
|
||||
}
|
||||
|
||||
HANDLE openConout() {
|
||||
const HANDLE conout = CreateFileW(L"CONOUT$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
ASSERT(conout != INVALID_HANDLE_VALUE);
|
||||
return conout;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
|
1
misc/UnicodeWideTest1.cc
Normal file → Executable file
1
misc/UnicodeWideTest1.cc
Normal file → Executable file
@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
|
1
misc/UnicodeWideTest2.cc
Normal file → Executable file
1
misc/UnicodeWideTest2.cc
Normal file → Executable file
@ -8,6 +8,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
static void writeChars(const wchar_t *text) {
|
||||
wcslen(text);
|
||||
|
@ -28,9 +28,9 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// Read it back.
|
||||
std::vector<CHAR_INFO> readBuffer(dataToWrite.size() * 2);
|
||||
COORD bufSize = {static_cast<short>(readBuffer.size()), 1};
|
||||
COORD bufSize = {readBuffer.size(), 1};
|
||||
COORD bufCoord = {0, 0};
|
||||
SMALL_RECT topLeft = {0, 0, static_cast<short>(readBuffer.size() - 1), 0};
|
||||
SMALL_RECT topLeft = {0, 0, readBuffer.size() - 1, 0};
|
||||
ret = ReadConsoleOutputW(
|
||||
GetStdHandle(STD_OUTPUT_HANDLE), readBuffer.data(),
|
||||
bufSize, bufCoord, &topLeft);
|
||||
|
1
misc/VeryLargeRead.cc
Normal file → Executable file
1
misc/VeryLargeRead.cc
Normal file → Executable file
@ -63,6 +63,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
long long width = 9000;
|
||||
|
2
misc/Win10ResizeWhileFrozen.cc
Normal file → Executable file
2
misc/Win10ResizeWhileFrozen.cc
Normal file → Executable file
@ -14,7 +14,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
#include "TestUtil.cc"
|
||||
|
||||
const int SC_CONSOLE_MARK = 0xFFF2;
|
||||
|
1
misc/Win10WrapTest1.cc
Normal file → Executable file
1
misc/Win10WrapTest1.cc
Normal file → Executable file
@ -6,6 +6,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
1
misc/Win10WrapTest2.cc
Normal file → Executable file
1
misc/Win10WrapTest2.cc
Normal file → Executable file
@ -1,6 +1,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc == 1) {
|
||||
|
@ -1,27 +0,0 @@
|
||||
// I noticed this on the ConEmu web site:
|
||||
//
|
||||
// https://social.msdn.microsoft.com/Forums/en-US/40c8e395-cca9-45c8-b9b8-2fbe6782ac2b/readconsoleoutput-cause-access-violation-writing-location-exception
|
||||
// https://conemu.github.io/en/MicrosoftBugs.html
|
||||
//
|
||||
// In Windows 7, 8, and 8.1, a ReadConsoleOutputW with an out-of-bounds read
|
||||
// region crashes the application. I have reproduced the problem on Windows 8
|
||||
// and 8.1, but not on Windows 7.
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main() {
|
||||
setWindowPos(0, 0, 1, 1);
|
||||
setBufferSize(80, 25);
|
||||
setWindowPos(0, 0, 80, 25);
|
||||
|
||||
const HANDLE conout = openConout();
|
||||
static CHAR_INFO lineBuf[80];
|
||||
SMALL_RECT readRegion = { 0, 999, 79, 999 };
|
||||
const BOOL ret = ReadConsoleOutputW(conout, lineBuf, {80, 1}, {0, 0}, &readRegion);
|
||||
ASSERT(!ret && "ReadConsoleOutputW should have failed");
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static std::wstring mbsToWcs(const std::string &s) {
|
||||
const size_t len = mbstowcs(nullptr, s.c_str(), 0);
|
||||
if (len == static_cast<size_t>(-1)) {
|
||||
assert(false && "mbsToWcs: invalid string");
|
||||
}
|
||||
std::wstring ret;
|
||||
ret.resize(len);
|
||||
const size_t len2 = mbstowcs(&ret[0], s.c_str(), len);
|
||||
assert(len == len2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t parseHex(wchar_t ch, bool &invalid) {
|
||||
if (ch >= L'0' && ch <= L'9') {
|
||||
return ch - L'0';
|
||||
} else if (ch >= L'a' && ch <= L'f') {
|
||||
return ch - L'a' + 10;
|
||||
} else if (ch >= L'A' && ch <= L'F') {
|
||||
return ch - L'A' + 10;
|
||||
} else {
|
||||
invalid = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::vector<std::wstring> args;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
args.push_back(mbsToWcs(argv[i]));
|
||||
}
|
||||
|
||||
std::wstring out;
|
||||
for (const auto &arg : args) {
|
||||
if (!out.empty()) {
|
||||
out.push_back(L' ');
|
||||
}
|
||||
for (size_t i = 0; i < arg.size(); ++i) {
|
||||
wchar_t ch = arg[i];
|
||||
wchar_t nch = i + 1 < arg.size() ? arg[i + 1] : L'\0';
|
||||
if (ch == L'\\') {
|
||||
switch (nch) {
|
||||
case L'a': ch = L'\a'; ++i; break;
|
||||
case L'b': ch = L'\b'; ++i; break;
|
||||
case L'e': ch = L'\x1b'; ++i; break;
|
||||
case L'f': ch = L'\f'; ++i; break;
|
||||
case L'n': ch = L'\n'; ++i; break;
|
||||
case L'r': ch = L'\r'; ++i; break;
|
||||
case L't': ch = L'\t'; ++i; break;
|
||||
case L'v': ch = L'\v'; ++i; break;
|
||||
case L'\\': ch = L'\\'; ++i; break;
|
||||
case L'\'': ch = L'\''; ++i; break;
|
||||
case L'\"': ch = L'\"'; ++i; break;
|
||||
case L'\?': ch = L'\?'; ++i; break;
|
||||
case L'x':
|
||||
if (i + 3 < arg.size()) {
|
||||
bool invalid = false;
|
||||
uint32_t d1 = parseHex(arg[i + 2], invalid);
|
||||
uint32_t d2 = parseHex(arg[i + 3], invalid);
|
||||
if (!invalid) {
|
||||
i += 3;
|
||||
ch = (d1 << 4) | d2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L'u':
|
||||
if (i + 5 < arg.size()) {
|
||||
bool invalid = false;
|
||||
uint32_t d1 = parseHex(arg[i + 2], invalid);
|
||||
uint32_t d2 = parseHex(arg[i + 3], invalid);
|
||||
uint32_t d3 = parseHex(arg[i + 4], invalid);
|
||||
uint32_t d4 = parseHex(arg[i + 5], invalid);
|
||||
if (!invalid) {
|
||||
i += 5;
|
||||
ch = (d1 << 24) | (d2 << 16) | (d3 << 8) | d4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
out.push_back(ch);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD actual = 0;
|
||||
if (!WriteConsoleW(
|
||||
GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
out.c_str(),
|
||||
out.size(),
|
||||
&actual,
|
||||
nullptr)) {
|
||||
fprintf(stderr, "WriteConsole failed (is stdout a console?)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
1
misc/buffer-tests/.gitignore
vendored
Executable file
1
misc/buffer-tests/.gitignore
vendored
Executable file
@ -0,0 +1 @@
|
||||
/build
|
101
misc/buffer-tests/HandleTests/CreateProcess.cc
Executable file
101
misc/buffer-tests/HandleTests/CreateProcess.cc
Executable file
@ -0,0 +1,101 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
REGISTER(Test_CreateProcess_ModeCombos, always);
|
||||
static void Test_CreateProcess_ModeCombos() {
|
||||
// It is often unclear how (or whether) various combinations of
|
||||
// CreateProcess parameters work when combined. Try to test the ambiguous
|
||||
// combinations.
|
||||
|
||||
SpawnFailure failure;
|
||||
|
||||
{
|
||||
// CREATE_NEW_CONSOLE | DETACHED_PROCESS ==> call fails
|
||||
Worker p;
|
||||
auto c = p.tryChild({ false, CREATE_NEW_CONSOLE | DETACHED_PROCESS }, &failure);
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
{
|
||||
// CREATE_NO_WINDOW | CREATE_NEW_CONSOLE ==> CREATE_NEW_CONSOLE dominates
|
||||
Worker p;
|
||||
auto c = p.tryChild({ false, CREATE_NO_WINDOW | CREATE_NEW_CONSOLE }, &failure);
|
||||
CHECK(c.valid());
|
||||
CHECK(c.consoleWindow() != nullptr);
|
||||
CHECK(IsWindowVisible(c.consoleWindow()));
|
||||
}
|
||||
{
|
||||
// CREATE_NO_WINDOW | DETACHED_PROCESS ==> DETACHED_PROCESS dominates
|
||||
Worker p;
|
||||
auto c = p.tryChild({ false, CREATE_NO_WINDOW | DETACHED_PROCESS }, &failure);
|
||||
CHECK(c.valid());
|
||||
CHECK_EQ(c.newBuffer().value(), INVALID_HANDLE_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateProcess_STARTUPINFOEX, isAtLeastVista);
|
||||
static void Test_CreateProcess_STARTUPINFOEX() {
|
||||
// STARTUPINFOEX tests.
|
||||
|
||||
Worker p;
|
||||
SpawnFailure failure;
|
||||
auto pipe1 = newPipe(p, true);
|
||||
auto ph1 = std::get<0>(pipe1);
|
||||
auto ph2 = std::get<1>(pipe1);
|
||||
|
||||
auto testSetup = [&](SpawnParams sp, size_t cb, HANDLE inherit) {
|
||||
sp.sui.cb = cb;
|
||||
sp.inheritCount = 1;
|
||||
sp.inheritList = { inherit };
|
||||
return p.tryChild(sp, &failure);
|
||||
};
|
||||
|
||||
{
|
||||
// The STARTUPINFOEX parameter is ignored if
|
||||
// EXTENDED_STARTUPINFO_PRESENT isn't present.
|
||||
auto c = testSetup({true}, sizeof(STARTUPINFOEXW), ph1.value());
|
||||
CHECK(c.valid());
|
||||
auto ch2 = Handle::invent(ph2.value(), c);
|
||||
// i.e. ph2 was inherited, because ch2 identifies the same thing.
|
||||
CHECK(compareObjectHandles(ph2, ch2));
|
||||
}
|
||||
{
|
||||
// If EXTENDED_STARTUPINFO_PRESENT is specified, but the cb value
|
||||
// is wrong, the API call fails.
|
||||
auto c = testSetup({true, EXTENDED_STARTUPINFO_PRESENT},
|
||||
sizeof(STARTUPINFOW), ph1.value());
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateNoWindow_HiddenVsNothing, always);
|
||||
static void Test_CreateNoWindow_HiddenVsNothing() {
|
||||
|
||||
Worker p;
|
||||
auto c = p.child({ false, CREATE_NO_WINDOW });
|
||||
|
||||
if (isAtLeastWin7()) {
|
||||
// As of Windows 7, GetConsoleWindow returns NULL.
|
||||
CHECK(c.consoleWindow() == nullptr);
|
||||
} else {
|
||||
// On earlier operating systems, GetConsoleWindow returns a handle
|
||||
// to an invisible window.
|
||||
CHECK(c.consoleWindow() != nullptr);
|
||||
CHECK(!IsWindowVisible(c.consoleWindow()));
|
||||
}
|
||||
}
|
||||
|
||||
// MSDN's CreateProcess page currently has this note in it:
|
||||
//
|
||||
// Important The caller is responsible for ensuring that the standard
|
||||
// handle fields in STARTUPINFO contain valid handle values. These fields
|
||||
// are copied unchanged to the child process without validation, even when
|
||||
// the dwFlags member specifies STARTF_USESTDHANDLES. Incorrect values can
|
||||
// cause the child process to misbehave or crash. Use the Application
|
||||
// Verifier runtime verification tool to detect invalid handles.
|
||||
//
|
||||
// XXX: The word "even" here sticks out. Verify that the standard handle
|
||||
// fields in STARTUPINFO are ignored when STARTF_USESTDHANDLES is not
|
||||
// specified.
|
66
misc/buffer-tests/HandleTests/CreateProcess_Detached.cc
Executable file
66
misc/buffer-tests/HandleTests/CreateProcess_Detached.cc
Executable file
@ -0,0 +1,66 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
// Test CreateProcess called with dwCreationFlags containing DETACHED_PROCESS.
|
||||
|
||||
// This macro will output nicer line information than a function if it fails.
|
||||
#define CHECK_NULL(proc) \
|
||||
do { \
|
||||
CHECK(handleInts(stdHandles(proc)) == \
|
||||
(std::vector<uint64_t> {0,0,0})); \
|
||||
} while(0)
|
||||
|
||||
REGISTER(Test_CreateProcess_Detached, always);
|
||||
static void Test_CreateProcess_Detached() {
|
||||
{
|
||||
Worker p;
|
||||
auto c1 = p.child({ true, DETACHED_PROCESS });
|
||||
CHECK_NULL(c1);
|
||||
auto c2 = p.child({ false, DETACHED_PROCESS });
|
||||
CHECK_NULL(c2);
|
||||
}
|
||||
{
|
||||
Worker p;
|
||||
auto c = p.child({ true, DETACHED_PROCESS, {
|
||||
p.getStdin(),
|
||||
p.getStdout(),
|
||||
p.getStderr(),
|
||||
}});
|
||||
CHECK(handleValues(stdHandles(c)) == handleValues(stdHandles(p)));
|
||||
}
|
||||
{
|
||||
Worker p;
|
||||
auto c = p.child({ false, DETACHED_PROCESS, {
|
||||
p.getStdin(),
|
||||
p.getStdout(),
|
||||
p.getStderr(),
|
||||
}});
|
||||
if (isTraditionalConio()) {
|
||||
CHECK(handleValues(stdHandles(c)) == handleValues(stdHandles(p)));
|
||||
} else{
|
||||
CHECK_NULL(c);
|
||||
}
|
||||
}
|
||||
{
|
||||
Worker p({ false, DETACHED_PROCESS });
|
||||
auto pipe = newPipe(p, true);
|
||||
std::get<0>(pipe).setStdin();
|
||||
std::get<1>(pipe).setStdout().setStderr();
|
||||
|
||||
{
|
||||
auto c1 = p.child({ true, DETACHED_PROCESS });
|
||||
CHECK_NULL(c1);
|
||||
auto c2 = p.child({ false, DETACHED_PROCESS });
|
||||
CHECK_NULL(c2);
|
||||
}
|
||||
{
|
||||
// The worker p2 was started with STARTF_USESTDHANDLES and with
|
||||
// standard handles referring to a pipe. Nevertheless, its
|
||||
// children's standard handles are NULL.
|
||||
auto p2 = p.child({ true, DETACHED_PROCESS, stdHandles(p) });
|
||||
auto c1 = p2.child({ true, DETACHED_PROCESS });
|
||||
CHECK_NULL(c1);
|
||||
auto c2 = p2.child({ false, DETACHED_PROCESS });
|
||||
CHECK_NULL(c2);
|
||||
}
|
||||
}
|
||||
}
|
212
misc/buffer-tests/HandleTests/CreateProcess_Duplicate.cc
Executable file
212
misc/buffer-tests/HandleTests/CreateProcess_Duplicate.cc
Executable file
@ -0,0 +1,212 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
// If CreateProcess is called with these parameters:
|
||||
// - bInheritHandles=FALSE
|
||||
// - STARTF_USESTDHANDLES is not specified
|
||||
// - the "CreationConsoleMode" is Inherit (see console-handles.md)
|
||||
// then Windows duplicates each of STDIN/STDOUT/STDERR to the child.
|
||||
//
|
||||
// There are variations between OS releases, especially with regards to
|
||||
// how console handles work.
|
||||
|
||||
// This handle duplication seems to be broken in WOW64 mode. It affects
|
||||
// at least:
|
||||
// - Windows 7 SP1
|
||||
// For some reason, the problem apparently only affects the client operating
|
||||
// system, not the server OS.
|
||||
//
|
||||
// Export this function to the other duplicate tests.
|
||||
bool brokenDuplicationInWow64() {
|
||||
return isWin7() && isWorkstation() && isWow64();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
static bool handlesAreNull(Worker &p) {
|
||||
return handleInts(stdHandles(p)) == std::vector<uint64_t> {0, 0, 0};
|
||||
}
|
||||
|
||||
static std::string testMessage(bool isNull) {
|
||||
return isNull ? "BUG(dup->NULL)" : "OK(dup)";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Test_CreateProcess_Duplicate_Impl(T makeChild) {
|
||||
printTestName(__FUNCTION__);
|
||||
|
||||
{
|
||||
// An inheritable pipe is still inherited.
|
||||
Worker p;
|
||||
auto pipe = newPipe(p, true);
|
||||
auto wh = std::get<1>(pipe).setStdin().setStdout().setStderr();
|
||||
CHECK(wh.inheritable());
|
||||
auto c = makeChild(p, { false });
|
||||
|
||||
const auto expect = testMessage(brokenDuplicationInWow64());
|
||||
const auto actual = testMessage(handlesAreNull(c));
|
||||
std::cout << __FUNCTION__ << ": expect: " << expect << std::endl;
|
||||
std::cout << __FUNCTION__ << ": actual: " << actual << std::endl;
|
||||
CHECK_EQ(actual, expect);
|
||||
|
||||
if (c.getStdout().value() != nullptr) {
|
||||
{
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({ c.getStdin(), c.getStdout(), c.getStderr(), wh }));
|
||||
}
|
||||
for (auto h : stdHandles(c)) {
|
||||
CHECK(h.tryFlags());
|
||||
if (!h.tryFlags()) {
|
||||
continue;
|
||||
}
|
||||
auto inheritMessage = [](bool inheritable) {
|
||||
return inheritable
|
||||
? "OK(inherit)"
|
||||
: "BAD(dup->non-inheritable)";
|
||||
};
|
||||
const std::string expect = inheritMessage(isAtLeastVista());
|
||||
const std::string actual = inheritMessage(h.inheritable());
|
||||
if (expect == actual && isAtLeastVista()) {
|
||||
continue; // We'll just stay silent in this case.
|
||||
}
|
||||
std::cout << __FUNCTION__ << ": expect: " << expect << std::endl;
|
||||
std::cout << __FUNCTION__ << ": actual: " << actual << std::endl;
|
||||
CHECK_EQ(actual, expect);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// A non-inheritable pipe is still inherited.
|
||||
Worker p;
|
||||
auto pipe = newPipe(p, false);
|
||||
auto wh = std::get<1>(pipe).setStdin().setStdout().setStderr();
|
||||
auto c = makeChild(p, { false });
|
||||
|
||||
const auto expect = testMessage(brokenDuplicationInWow64());
|
||||
const auto actual = testMessage(handlesAreNull(c));
|
||||
std::cout << __FUNCTION__ << ": expect: " << expect << std::endl;
|
||||
std::cout << __FUNCTION__ << ": actual: " << actual << std::endl;
|
||||
CHECK_EQ(actual, expect);
|
||||
|
||||
if (c.getStdout().value() != nullptr) {
|
||||
{
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({ c.getStdin(), c.getStdout(), c.getStderr(), wh }));
|
||||
}
|
||||
// CreateProcess makes separate handles for stdin/stdout/stderr,
|
||||
// even though the parent has the same handle for each of them.
|
||||
CHECK(c.getStdin().value() != c.getStdout().value());
|
||||
CHECK(c.getStdout().value() != c.getStderr().value());
|
||||
CHECK(c.getStdin().value() != c.getStderr().value());
|
||||
for (auto h : stdHandles(c)) {
|
||||
CHECK(h.tryFlags() && !h.inheritable());
|
||||
}
|
||||
// Calling FreeConsole in the child does not free the duplicated
|
||||
// handles.
|
||||
c.detach();
|
||||
{
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({ c.getStdin(), c.getStdout(), c.getStderr(), wh }));
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// Bogus values are transformed into zero.
|
||||
Worker p;
|
||||
Handle::invent(0x10000ull, p).setStdin().setStdout();
|
||||
Handle::invent(0x0ull, p).setStderr();
|
||||
auto c = makeChild(p, { false });
|
||||
CHECK(handleInts(stdHandles(c)) == (std::vector<uint64_t> {0,0,0}));
|
||||
}
|
||||
|
||||
if (isAtLeastWin8()) {
|
||||
// On Windows 8 and up, if a standard handle we duplicate just happens
|
||||
// to be a console handle, that isn't sufficient reason for FreeConsole
|
||||
// to close it.
|
||||
Worker p;
|
||||
auto c = makeChild(p, { false });
|
||||
auto ph = stdHandles(p);
|
||||
auto ch = stdHandles(c);
|
||||
auto check = [&]() {
|
||||
ObjectSnap snap;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
CHECK(snap.eq(ph[i], ch[i]));
|
||||
CHECK(ph[i].tryFlags() && ch[i].tryFlags());
|
||||
CHECK_EQ(ph[i].tryFlags() && ph[i].inheritable(),
|
||||
ch[i].tryFlags() && ch[i].inheritable());
|
||||
}
|
||||
};
|
||||
check();
|
||||
c.detach();
|
||||
check();
|
||||
}
|
||||
|
||||
{
|
||||
// Traditional console-like values are passed through as-is,
|
||||
// up to 0x0FFFFFFFull.
|
||||
Worker p;
|
||||
Handle::invent(0x0FFFFFFFull, p).setStdin();
|
||||
Handle::invent(0x10000003ull, p).setStdout();
|
||||
Handle::invent(0x00000003ull, p).setStderr();
|
||||
auto c = makeChild(p, { false });
|
||||
if (isAtLeastWin8()) {
|
||||
// These values are invalid on Windows 8 and turned into NULL.
|
||||
CHECK(handleInts(stdHandles(c)) ==
|
||||
(std::vector<uint64_t> { 0, 0, 0 }));
|
||||
} else {
|
||||
CHECK(handleInts(stdHandles(c)) ==
|
||||
(std::vector<uint64_t> { 0x0FFFFFFFull, 0, 3 }));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Test setting STDIN/STDOUT/STDERR to non-inheritable console handles.
|
||||
//
|
||||
// Handle duplication does not apply to traditional console handles,
|
||||
// and a console handle is inherited if and only if it is inheritable.
|
||||
//
|
||||
// On new releases, this will Just Work.
|
||||
//
|
||||
Worker p;
|
||||
p.getStdout().setFirstChar('A');
|
||||
p.openConin(false).setStdin();
|
||||
p.newBuffer(false, 'B').setStdout().setStderr();
|
||||
auto c = makeChild(p, { false });
|
||||
|
||||
if (!isAtLeastWin8()) {
|
||||
CHECK(handleValues(stdHandles(p)) == handleValues(stdHandles(c)));
|
||||
CHECK(!c.getStdin().tryFlags());
|
||||
CHECK(!c.getStdout().tryFlags());
|
||||
CHECK(!c.getStderr().tryFlags());
|
||||
} else {
|
||||
// In Win8, a console handle works like all other handles.
|
||||
CHECK_EQ(c.getStdout().firstChar(), 'B');
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({ p.getStdout(), p.getStderr(),
|
||||
c.getStdout(), c.getStderr() }));
|
||||
CHECK(!c.getStdout().inheritable());
|
||||
CHECK(!c.getStderr().inheritable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
REGISTER(Test_CreateProcess_Duplicate, always);
|
||||
static void Test_CreateProcess_Duplicate() {
|
||||
Test_CreateProcess_Duplicate_Impl([](Worker &p, SpawnParams sp) {
|
||||
return p.child(sp);
|
||||
});
|
||||
if (isModernConio()) {
|
||||
// With modern console I/O, calling CreateProcess with these
|
||||
// parameters also duplicates standard handles:
|
||||
// - bInheritHandles=TRUE
|
||||
// - STARTF_USESTDHANDLES not specified
|
||||
// - an inherit list (PROC_THREAD_ATTRIBUTE_HANDLE_LIST) is specified
|
||||
Test_CreateProcess_Duplicate_Impl([](Worker &p, SpawnParams sp) {
|
||||
return childWithDummyInheritList(p, sp, false);
|
||||
});
|
||||
Test_CreateProcess_Duplicate_Impl([](Worker &p, SpawnParams sp) {
|
||||
return childWithDummyInheritList(p, sp, true);
|
||||
});
|
||||
}
|
||||
}
|
81
misc/buffer-tests/HandleTests/CreateProcess_Duplicate_PseudoHandleBug.cc
Executable file
81
misc/buffer-tests/HandleTests/CreateProcess_Duplicate_PseudoHandleBug.cc
Executable file
@ -0,0 +1,81 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
// With CreateProcess's default handle duplication behavior, the
|
||||
// GetCurrentProcess() psuedo-handle (i.e. INVALID_HANDLE_VALUE) is translated
|
||||
// to a real handle value for the child process. It is a handle to the parent
|
||||
// process. Naturally, this was unintended behavior, and as of Windows 8.1,
|
||||
// the handle is instead translated to NULL. On some older operating systems,
|
||||
// the WOW64 mode also translates it to NULL.
|
||||
|
||||
const std::string bugParentProc = "BUG(parent-proc)";
|
||||
const std::string okInvalid = "OK(INVALID)";
|
||||
const std::string okNull = "OK(NULL)";
|
||||
|
||||
static std::string determineChildStdout(Worker &c, Worker &p) {
|
||||
if (c.getStdout().value() == nullptr) {
|
||||
return okNull;
|
||||
} else if (c.getStdout().value() == INVALID_HANDLE_VALUE) {
|
||||
return okInvalid;
|
||||
} else {
|
||||
auto handleToPInP = Handle::dup(p.processHandle(), p);
|
||||
CHECK(compareObjectHandles(c.getStdout(), handleToPInP));
|
||||
return bugParentProc;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateProcess_Duplicate_PseudoHandleBug, always);
|
||||
static void Test_CreateProcess_Duplicate_PseudoHandleBug() {
|
||||
Worker p;
|
||||
Handle::invent(GetCurrentProcess(), p).setStdout();
|
||||
auto c = p.child({ false });
|
||||
|
||||
const std::string expect =
|
||||
(isAtLeastWin8_1() || (isAtLeastVista() && isWow64()))
|
||||
? okNull
|
||||
: bugParentProc;
|
||||
|
||||
const std::string actual = determineChildStdout(c, p);
|
||||
|
||||
trace("%s: actual: %s", __FUNCTION__, actual.c_str());
|
||||
std::cout << __FUNCTION__ << ": expect: " << expect << std::endl;
|
||||
std::cout << __FUNCTION__ << ": actual: " << actual << std::endl;
|
||||
CHECK_EQ(actual, expect);
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateProcess_Duplicate_PseudoHandleBug_IL, isAtLeastVista);
|
||||
static void Test_CreateProcess_Duplicate_PseudoHandleBug_IL() {
|
||||
// As above, but use an inherit list. With an inherit list, standard
|
||||
// handles are duplicated, but only with Windows 8 and up.
|
||||
for (int useDummyPipe = 0; useDummyPipe <= 1; ++useDummyPipe) {
|
||||
Worker p;
|
||||
Handle::invent(INVALID_HANDLE_VALUE, p).setStdout();
|
||||
auto c = childWithDummyInheritList(p, {}, useDummyPipe != 0);
|
||||
|
||||
// Figure out what we expect to see.
|
||||
std::string expect;
|
||||
if (isAtLeastWin8_1()) {
|
||||
// Windows 8.1 turns INVALID_HANDLE_VALUE into NULL.
|
||||
expect = okNull;
|
||||
} else if (isAtLeastWin8()) {
|
||||
// Windows 8 tries to duplicate the handle. WOW64 seems to be
|
||||
// OK, though.
|
||||
if (isWow64()) {
|
||||
expect = okNull;
|
||||
} else {
|
||||
expect = bugParentProc;
|
||||
}
|
||||
} else {
|
||||
// Prior to Windows 8, duplication doesn't occur in this case, so
|
||||
// the bug isn't relevant. We run the test anyway, but it's less
|
||||
// interesting.
|
||||
expect = okInvalid;
|
||||
}
|
||||
|
||||
const std::string actual = determineChildStdout(c, p);
|
||||
|
||||
trace("%s: actual: %s", __FUNCTION__, actual.c_str());
|
||||
std::cout << __FUNCTION__ << ": expect: " << expect << std::endl;
|
||||
std::cout << __FUNCTION__ << ": actual: " << actual << std::endl;
|
||||
CHECK_EQ(actual, expect);
|
||||
}
|
||||
}
|
47
misc/buffer-tests/HandleTests/CreateProcess_Duplicate_XPPipeBug.cc
Executable file
47
misc/buffer-tests/HandleTests/CreateProcess_Duplicate_XPPipeBug.cc
Executable file
@ -0,0 +1,47 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
// Windows XP bug: default inheritance doesn't work with the read end
|
||||
// of a pipe, even if it's inheritable. It works with the write end.
|
||||
|
||||
bool brokenDuplicationInWow64();
|
||||
|
||||
REGISTER(Test_CreateProcess_Duplicate_XPPipeBug, always);
|
||||
static void Test_CreateProcess_Duplicate_XPPipeBug() {
|
||||
auto check = [](Worker &proc, Handle correct, bool expectNull) {
|
||||
CHECK_EQ((proc.getStdin().value() == nullptr), expectNull);
|
||||
CHECK_EQ((proc.getStdout().value() == nullptr), expectNull);
|
||||
CHECK_EQ((proc.getStderr().value() == nullptr), expectNull);
|
||||
if (proc.getStdout().value() != nullptr) {
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({
|
||||
proc.getStdin(), proc.getStdout(), proc.getStderr(), correct
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
Worker p;
|
||||
|
||||
auto pipe = newPipe(p, false);
|
||||
auto rh = std::get<0>(pipe).setStdin().setStdout().setStderr();
|
||||
auto c1 = p.child({ false });
|
||||
check(c1, rh, !isAtLeastVista() || brokenDuplicationInWow64());
|
||||
|
||||
// Marking the handle itself inheritable makes no difference.
|
||||
rh.setInheritable(true);
|
||||
auto c2 = p.child({ false });
|
||||
check(c2, rh, !isAtLeastVista() || brokenDuplicationInWow64());
|
||||
|
||||
// If we enter bInheritHandles=TRUE mode, it works.
|
||||
auto c3 = p.child({ true });
|
||||
check(c3, rh, false);
|
||||
|
||||
// Using STARTF_USESTDHANDLES works too.
|
||||
Handle::invent(nullptr, p).setStdin().setStdout().setStderr();
|
||||
auto c4 = p.child({ true, 0, { rh, rh, rh }});
|
||||
check(c4, rh, false);
|
||||
|
||||
// Also test the write end of the pipe.
|
||||
auto wh = std::get<1>(pipe).setStdin().setStdout().setStderr();
|
||||
auto c5 = p.child({ false });
|
||||
check(c5, wh, brokenDuplicationInWow64());
|
||||
}
|
53
misc/buffer-tests/HandleTests/CreateProcess_InheritAllHandles.cc
Executable file
53
misc/buffer-tests/HandleTests/CreateProcess_InheritAllHandles.cc
Executable file
@ -0,0 +1,53 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
//
|
||||
// Test CreateProcess when called with these parameters:
|
||||
// - STARTF_USESTDHANDLES is not specified
|
||||
// - bInheritHandles=TRUE
|
||||
// - CreationConsoleMode=Inherit
|
||||
//
|
||||
|
||||
REGISTER(Test_CreateProcess_InheritAllHandles, always);
|
||||
static void Test_CreateProcess_InheritAllHandles() {
|
||||
auto &hv = handleValues;
|
||||
|
||||
{
|
||||
// Simple case: the standard handles are left as-is.
|
||||
Worker p;
|
||||
auto pipe = newPipe(p, true);
|
||||
std::get<0>(pipe).setStdin();
|
||||
std::get<1>(pipe).setStdout().setStderr();
|
||||
auto c = p.child({ true });
|
||||
CHECK(hv(stdHandles(c)) == hv(stdHandles(p)));
|
||||
}
|
||||
|
||||
{
|
||||
// We can pass arbitrary values through.
|
||||
Worker p;
|
||||
Handle::invent(0x0ull, p).setStdin();
|
||||
Handle::invent(0x10000ull, p).setStdout();
|
||||
Handle::invent(INVALID_HANDLE_VALUE, p).setStderr();
|
||||
auto c = p.child({ true });
|
||||
CHECK(hv(stdHandles(c)) == hv(stdHandles(p)));
|
||||
}
|
||||
|
||||
{
|
||||
// Passing through a non-inheritable handle produces an invalid child
|
||||
// handle.
|
||||
Worker p;
|
||||
p.openConin(false).setStdin();
|
||||
p.openConout(false).setStdout().setStderr();
|
||||
auto c = p.child({ true });
|
||||
CHECK(hv(stdHandles(c)) == hv(stdHandles(p)));
|
||||
if (isTraditionalConio()) {
|
||||
CHECK(!c.getStdin().tryFlags());
|
||||
CHECK(!c.getStdout().tryFlags());
|
||||
CHECK(!c.getStderr().tryFlags());
|
||||
} else {
|
||||
ObjectSnap snap;
|
||||
CHECK(!snap.eq(p.getStdin(), c.getStdin()));
|
||||
CHECK(!snap.eq(p.getStdout(), c.getStdout()));
|
||||
CHECK(!snap.eq(p.getStderr(), c.getStderr()));
|
||||
}
|
||||
}
|
||||
}
|
388
misc/buffer-tests/HandleTests/CreateProcess_InheritList.cc
Executable file
388
misc/buffer-tests/HandleTests/CreateProcess_InheritList.cc
Executable file
@ -0,0 +1,388 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
//
|
||||
// Test CreateProcess, using PROC_THREAD_ATTRIBUTE_HANDLE_LIST to restrict the
|
||||
// inherited handles.
|
||||
//
|
||||
// Ordinarily, standard handles are copied as-is.
|
||||
//
|
||||
// On Windows 8 and later, if a PROC_THREAD_ATTRIBUTE_HANDLE_LIST list is used,
|
||||
// then the standard handles are duplicated instead.
|
||||
//
|
||||
|
||||
REGISTER(Test_CreateProcess_InheritList, isAtLeastVista);
|
||||
static void Test_CreateProcess_InheritList() {
|
||||
// Specifically test inherit lists.
|
||||
|
||||
SpawnFailure failure;
|
||||
|
||||
auto testSetup = [&](Worker &proc,
|
||||
SpawnParams sp,
|
||||
std::initializer_list<HANDLE> inheritList) {
|
||||
sp.dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
|
||||
sp.sui.cb = sizeof(STARTUPINFOEXW);
|
||||
sp.inheritCount = inheritList.size();
|
||||
std::copy(inheritList.begin(), inheritList.end(),
|
||||
sp.inheritList.begin());
|
||||
return proc.tryChild(sp, &failure);
|
||||
};
|
||||
|
||||
Worker p;
|
||||
auto pipe1 = newPipe(p, true);
|
||||
auto ph1 = std::get<0>(pipe1);
|
||||
auto ph2 = std::get<1>(pipe1);
|
||||
|
||||
auto pipe2 = newPipe(p, true);
|
||||
auto ph3 = std::get<0>(pipe2);
|
||||
auto ph4 = std::get<1>(pipe2);
|
||||
|
||||
auto phNI = ph1.dup(false);
|
||||
|
||||
// Add an extra console handle so we can verify that a child's console
|
||||
// handles didn't revert to the original default, but were inherited.
|
||||
p.openConout(true);
|
||||
|
||||
auto testSetupStdHandles = [&](SpawnParams sp) {
|
||||
const auto in = sp.sui.hStdInput;
|
||||
const auto out = sp.sui.hStdOutput;
|
||||
const auto err = sp.sui.hStdError;
|
||||
sp.dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
|
||||
sp.sui.cb = sizeof(STARTUPINFOEXW);
|
||||
// This test case isn't interested in what
|
||||
// PROC_THREAD_ATTRIBUTE_HANDLE_LIST does when there are duplicate
|
||||
// handles in its list.
|
||||
ASSERT(in != out && out != err && in != err);
|
||||
sp.inheritCount = 3;
|
||||
sp.inheritList = { in, out, err };
|
||||
return p.tryChild(sp, &failure);
|
||||
};
|
||||
|
||||
auto ch1 = [&](RemoteWorker &c) { return Handle::invent(ph1.value(), c); };
|
||||
auto ch2 = [&](RemoteWorker &c) { return Handle::invent(ph2.value(), c); };
|
||||
auto ch3 = [&](RemoteWorker &c) { return Handle::invent(ph3.value(), c); };
|
||||
auto ch4 = [&](RemoteWorker &c) { return Handle::invent(ph4.value(), c); };
|
||||
|
||||
{
|
||||
// Use PROC_THREAD_ATTRIBUTE_HANDLE_LIST correctly.
|
||||
auto c = testSetup(p, {true}, {ph1.value()});
|
||||
CHECK(c.valid());
|
||||
// i.e. ph1 was inherited, because ch1 identifies the same thing.
|
||||
// ph2 was not inherited, because it wasn't listed.
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq(ph1, ch1(c)));
|
||||
CHECK(!snap.eq(ph2, ch2(c)));
|
||||
|
||||
if (!isAtLeastWin8()) {
|
||||
// The traditional console handles were all inherited, but they're
|
||||
// also the standard handles, so maybe that's an exception. We'll
|
||||
// test more aggressively below.
|
||||
CHECK(handleValues(c.scanForConsoleHandles()) ==
|
||||
handleValues(p.scanForConsoleHandles()));
|
||||
}
|
||||
}
|
||||
{
|
||||
// UpdateProcThreadAttribute fails if the buffer size is zero.
|
||||
auto c = testSetup(p, {true}, {});
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::UpdateProcThreadAttribute);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_BAD_LENGTH);
|
||||
}
|
||||
{
|
||||
// Attempting to inherit the GetCurrentProcess pseudo-handle also
|
||||
// fails. (The MSDN docs point out that using GetCurrentProcess here
|
||||
// will fail.)
|
||||
auto c = testSetup(p, {true}, {GetCurrentProcess()});
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
{
|
||||
// CreateProcess fails if the inherit list has a non-inheritable handle
|
||||
// in it. (STARTF_USESTDHANDLES not set.)
|
||||
auto c1 = testSetup(p, {true}, {phNI.value()});
|
||||
CHECK(!c1.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
{
|
||||
// CreateProcess fails if the inherit list has a non-inheritable handle
|
||||
// in it. (STARTF_USESTDHANDLES set.)
|
||||
auto c = testSetup(p, {true, 0, {phNI, phNI, phNI}}, {phNI.value()});
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
{
|
||||
// If bInheritHandles=FALSE and PROC_THREAD_ATTRIBUTE_HANDLE_LIST are
|
||||
// combined, the API call fails. (STARTF_USESTDHANDLES not set.)
|
||||
auto c = testSetup(p, {false}, {ph1.value()});
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
{
|
||||
// If bInheritHandles=FALSE and PROC_THREAD_ATTRIBUTE_HANDLE_LIST are
|
||||
// combined, the API call fails. (STARTF_USESTDHANDLES set.)
|
||||
auto c = testSetupStdHandles({false, 0, {ph1, ph2, ph4}});
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
if (!isAtLeastWin8()) {
|
||||
// Attempt to restrict inheritance to just one of the three open
|
||||
// traditional console handles.
|
||||
auto c = testSetupStdHandles({true, 0, {ph1, ph2, p.getStderr()}});
|
||||
if (isWin7()) {
|
||||
// On Windows 7, the CreateProcess call fails with a strange
|
||||
// error.
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_NO_SYSTEM_RESOURCES);
|
||||
} else {
|
||||
// On Vista, the CreateProcess call succeeds, but handle
|
||||
// inheritance is broken. All of the console handles are
|
||||
// inherited, not just the error screen buffer that was listed.
|
||||
// None of the pipe handles were inherited, even though two were
|
||||
// listed.
|
||||
c.dumpConsoleHandles();
|
||||
CHECK(handleValues(c.scanForConsoleHandles()) ==
|
||||
handleValues(p.scanForConsoleHandles()));
|
||||
{
|
||||
ObjectSnap snap;
|
||||
CHECK(!snap.eq(ph1, ch1(c)));
|
||||
CHECK(!snap.eq(ph2, ch2(c)));
|
||||
CHECK(!snap.eq(ph3, ch3(c)));
|
||||
CHECK(!snap.eq(ph4, ch4(c)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAtLeastWin8()) {
|
||||
// Make a final valiant effort to find a
|
||||
// PROC_THREAD_ATTRIBUTE_HANDLE_LIST and console handle interaction.
|
||||
// We'll set all the standard handles to pipes. Nevertheless, all
|
||||
// console handles are inherited.
|
||||
auto c = testSetupStdHandles({true, 0, {ph1, ph2, ph4}});
|
||||
CHECK(c.valid());
|
||||
CHECK(handleValues(c.scanForConsoleHandles()) ==
|
||||
handleValues(p.scanForConsoleHandles()));
|
||||
}
|
||||
|
||||
//
|
||||
// What does it mean if the inherit list has a NULL handle in it?
|
||||
//
|
||||
|
||||
{
|
||||
// CreateProcess apparently succeeds if the inherit list has a single
|
||||
// NULL in it. Inheritable handles unrelated to standard handles are
|
||||
// not inherited.
|
||||
auto c = testSetup(p, {true}, {NULL});
|
||||
CHECK(c.valid());
|
||||
// None of the inheritable handles were inherited.
|
||||
ObjectSnap snap;
|
||||
CHECK(!snap.eq(ph1, ch1(c)));
|
||||
CHECK(!snap.eq(ph2, ch2(c)));
|
||||
}
|
||||
{
|
||||
// {NULL, a handle} ==> nothing is inherited.
|
||||
auto c = testSetup(p, {true}, {NULL, ph2.value()});
|
||||
CHECK(c.valid());
|
||||
ObjectSnap snap;
|
||||
CHECK(!snap.eq(ph1, ch1(c)));
|
||||
CHECK(!snap.eq(ph2, ch2(c)));
|
||||
}
|
||||
{
|
||||
// {a handle, NULL} ==> nothing is inherited. (Apparently a NULL
|
||||
// anywhere in the list means "inherit nothing"? The attribute is not
|
||||
// ignored.)
|
||||
auto c = testSetup(p, {true}, {ph1.value(), NULL});
|
||||
CHECK(c.valid());
|
||||
ObjectSnap snap;
|
||||
CHECK(!snap.eq(ph1, ch1(c)));
|
||||
CHECK(!snap.eq(ph2, ch2(c)));
|
||||
}
|
||||
{
|
||||
// bInheritHandles=FALSE still fails.
|
||||
auto c = testSetup(p, {false}, {NULL});
|
||||
CHECK(!c.valid());
|
||||
CHECK_EQ(failure.kind, SpawnFailure::CreateProcess);
|
||||
CHECK_EQ(failure.errCode, (DWORD)ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
{
|
||||
// Test whether inheritList={NULL} has an unexpected effect on the
|
||||
// standard handles. Everything seems consistent.
|
||||
auto q = testSetup(p, {true}, {ph1.value(), ph2.value()});
|
||||
ch1(q).setStdin();
|
||||
ch2(q).setStdout().setStderr();
|
||||
auto c = testSetup(q, {true}, {NULL});
|
||||
ObjectSnap snap;
|
||||
if (isAtLeastWin8()) {
|
||||
// In Windows 8, standard handles are duplicated if an inherit
|
||||
// list is specified.
|
||||
CHECK(snap.eq({c.getStdin(), q.getStdin(), ch1(q)}));
|
||||
CHECK(snap.eq({c.getStdout(), q.getStdout(), ch2(q)}));
|
||||
CHECK(snap.eq({c.getStderr(), q.getStderr(), ch2(q)}));
|
||||
CHECK(c.getStdout().value() != c.getStderr().value());
|
||||
CHECK(c.getStdin().tryFlags() && c.getStdin().inheritable());
|
||||
CHECK(c.getStdout().tryFlags() && c.getStdout().inheritable());
|
||||
CHECK(c.getStderr().tryFlags() && c.getStderr().inheritable());
|
||||
} else {
|
||||
// The standard handles were not successfully inherited.
|
||||
CHECK(handleValues(stdHandles(c)) == handleValues(stdHandles(q)));
|
||||
CHECK(!snap.eq(ch1(c), ch1(q)));
|
||||
CHECK(!snap.eq(ch2(c), ch2(q)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateProcess_InheritList_StdHandles, isAtLeastVista);
|
||||
static void Test_CreateProcess_InheritList_StdHandles() {
|
||||
// List one of the standard handles in the inherit list, and see what
|
||||
// happens to the standard list.
|
||||
|
||||
auto check = [](Worker &p, RemoteHandle rh, RemoteHandle wh) {
|
||||
ASSERT(!rh.isTraditionalConsole());
|
||||
ASSERT(!wh.isTraditionalConsole());
|
||||
{
|
||||
// Test bInheritHandles=TRUE, STARTF_USESTDHANDLES, and the
|
||||
// PROC_THREAD_ATTRIBUTE_HANDLE_LIST attribute. Verify that the
|
||||
// standard handles are set to handles whose inheritability was
|
||||
// suppressed.
|
||||
SpawnParams sp { true, EXTENDED_STARTUPINFO_PRESENT, {rh, wh, wh} };
|
||||
sp.sui.cb = sizeof(STARTUPINFOEXW);
|
||||
sp.inheritCount = 1;
|
||||
sp.inheritList = { wh.value() };
|
||||
auto c = p.child(sp);
|
||||
ObjectSnap snap;
|
||||
CHECK(handleValues(stdHandles(c)) ==
|
||||
handleValues(std::vector<RemoteHandle> {rh, wh, wh}));
|
||||
CHECK(!snap.eq(rh, c.getStdin()));
|
||||
CHECK(snap.eq(wh, c.getStdout()));
|
||||
CHECK(snap.eq(wh, c.getStderr()));
|
||||
}
|
||||
|
||||
{
|
||||
// Same as above, but use a single NULL in the inherit list. Now
|
||||
// none of the handles are inherited, but the standard values are
|
||||
// unchanged.
|
||||
SpawnParams sp { true, EXTENDED_STARTUPINFO_PRESENT, {rh, wh, wh} };
|
||||
sp.sui.cb = sizeof(STARTUPINFOEXW);
|
||||
sp.inheritCount = 1;
|
||||
sp.inheritList = { NULL };
|
||||
auto c = p.child(sp);
|
||||
ObjectSnap snap;
|
||||
CHECK(handleValues(stdHandles(c)) ==
|
||||
handleValues(std::vector<RemoteHandle> {rh, wh, wh}));
|
||||
CHECK(!snap.eq(rh, c.getStdin()));
|
||||
CHECK(!snap.eq(wh, c.getStdout()));
|
||||
CHECK(!snap.eq(wh, c.getStderr()));
|
||||
}
|
||||
|
||||
if (!isAtLeastWin8()) {
|
||||
// Same as above, but avoid STARTF_USESTDHANDLES this time. The
|
||||
// behavior changed with Windows 8, which now appears to duplicate
|
||||
// handles in this case.
|
||||
rh.setStdin();
|
||||
wh.setStdout().setStderr();
|
||||
SpawnParams sp { true, EXTENDED_STARTUPINFO_PRESENT };
|
||||
sp.sui.cb = sizeof(STARTUPINFOEXW);
|
||||
sp.inheritCount = 1;
|
||||
sp.inheritList = { wh.value() };
|
||||
auto c = p.child(sp);
|
||||
ObjectSnap snap;
|
||||
CHECK(handleValues(stdHandles(p)) == handleValues(stdHandles(c)));
|
||||
CHECK(!snap.eq(p.getStdin(), c.getStdin()));
|
||||
CHECK(snap.eq(p.getStdout(), c.getStdout()));
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
Worker p;
|
||||
auto pipe = newPipe(p, true);
|
||||
check(p, std::get<0>(pipe), std::get<1>(pipe));
|
||||
}
|
||||
|
||||
if (isModernConio()) {
|
||||
Worker p;
|
||||
check(p, p.openConin(true), p.openConout(true));
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateProcess_InheritList_ModernDuplication, isAtLeastVista);
|
||||
static void Test_CreateProcess_InheritList_ModernDuplication() {
|
||||
auto &hv = handleValues;
|
||||
|
||||
for (int useDummyPipe = 0; useDummyPipe <= 1; ++useDummyPipe) {
|
||||
// Once we've specified an inherit list, non-inheritable standard
|
||||
// handles are duplicated.
|
||||
Worker p;
|
||||
auto pipe = newPipe(p);
|
||||
auto rh = std::get<0>(pipe).setStdin();
|
||||
auto wh = std::get<1>(pipe).setStdout().setStderr();
|
||||
auto c = childWithDummyInheritList(p, {}, useDummyPipe != 0);
|
||||
if (isModernConio()) {
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq(rh, c.getStdin()));
|
||||
CHECK(snap.eq(wh, c.getStdout()));
|
||||
CHECK(snap.eq(wh, c.getStderr()));
|
||||
CHECK(c.getStdout().value() != c.getStderr().value());
|
||||
for (auto h : stdHandles(c)) {
|
||||
CHECK(!h.inheritable());
|
||||
}
|
||||
} else {
|
||||
CHECK(hv(stdHandles(c)) == hv(stdHandles(p)));
|
||||
CHECK(!c.getStdin().tryFlags());
|
||||
CHECK(!c.getStdout().tryFlags());
|
||||
CHECK(!c.getStderr().tryFlags());
|
||||
}
|
||||
}
|
||||
|
||||
for (int useDummyPipe = 0; useDummyPipe <= 1; ++useDummyPipe) {
|
||||
// Invalid handles are translated to 0x0. (For full details, see the
|
||||
// "duplicate" CreateProcess tests.)
|
||||
Worker p;
|
||||
Handle::invent(0x0ull, p).setStdin();
|
||||
Handle::invent(0xdeadbeefull, p).setStdout();
|
||||
auto c = childWithDummyInheritList(p, {}, useDummyPipe != 0);
|
||||
if (isModernConio()) {
|
||||
CHECK(c.getStdin().uvalue() == 0ull);
|
||||
CHECK(c.getStdout().uvalue() == 0ull);
|
||||
} else {
|
||||
CHECK(c.getStdin().uvalue() == 0ull);
|
||||
CHECK(c.getStdout().value() ==
|
||||
Handle::invent(0xdeadbeefull, c).value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateProcess_Duplicate_StdHandles, isModernConio);
|
||||
static void Test_CreateProcess_Duplicate_StdHandles() {
|
||||
// The default Unbound console handles should be inheritable, so with
|
||||
// bInheritHandles=TRUE and standard handles listed in the inherit list,
|
||||
// the child process should have six console handles, all usable.
|
||||
Worker p;
|
||||
|
||||
SpawnParams sp { true, EXTENDED_STARTUPINFO_PRESENT };
|
||||
sp.sui.cb = sizeof(STARTUPINFOEXW);
|
||||
sp.inheritCount = 3;
|
||||
sp.inheritList = {
|
||||
p.getStdin().value(),
|
||||
p.getStdout().value(),
|
||||
p.getStderr().value(),
|
||||
};
|
||||
auto c = p.child(sp);
|
||||
|
||||
std::vector<uint64_t> expected;
|
||||
extendVector(expected, handleInts(stdHandles(p)));
|
||||
extendVector(expected, handleInts(stdHandles(c)));
|
||||
std::sort(expected.begin(), expected.end());
|
||||
|
||||
auto correct = handleInts(c.scanForConsoleHandles());
|
||||
std::sort(correct.begin(), correct.end());
|
||||
|
||||
p.dumpConsoleHandles();
|
||||
c.dumpConsoleHandles();
|
||||
|
||||
CHECK(expected == correct);
|
||||
}
|
53
misc/buffer-tests/HandleTests/CreateProcess_NewConsole.cc
Executable file
53
misc/buffer-tests/HandleTests/CreateProcess_NewConsole.cc
Executable file
@ -0,0 +1,53 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
//
|
||||
// Test CreateProcess when called with these parameters:
|
||||
// - STARTF_USESTDHANDLES is not specified
|
||||
// - bInheritHandles=FALSE or bInheritHandles=TRUE
|
||||
// - CreationConsoleMode=NewConsole
|
||||
//
|
||||
|
||||
REGISTER(Test_CreateProcess_NewConsole, always);
|
||||
static void Test_CreateProcess_NewConsole() {
|
||||
auto check = [](Worker &p, bool inheritHandles) {
|
||||
auto c = p.child({ inheritHandles, Worker::defaultCreationFlags() });
|
||||
if (isTraditionalConio()) {
|
||||
checkInitConsoleHandleSet(c);
|
||||
CHECK(handleInts(stdHandles(c)) ==
|
||||
(std::vector<uint64_t> {0x3, 0x7, 0xb}));
|
||||
} else {
|
||||
checkModernConsoleHandleInit(c, true, true, true);
|
||||
}
|
||||
return c;
|
||||
};
|
||||
{
|
||||
Worker p;
|
||||
check(p, true);
|
||||
check(p, false);
|
||||
}
|
||||
{
|
||||
Worker p;
|
||||
p.openConin(false).setStdin();
|
||||
p.newBuffer(false).setStdout().dup(true).setStderr();
|
||||
check(p, true);
|
||||
check(p, false);
|
||||
}
|
||||
|
||||
if (isModernConio()) {
|
||||
// The default Unbound console handles should be inheritable, so with
|
||||
// bInheritHandles=TRUE, the child process should have six console
|
||||
// handles, all usable.
|
||||
Worker p;
|
||||
auto c = check(p, true);
|
||||
|
||||
std::vector<uint64_t> expected;
|
||||
extendVector(expected, handleInts(stdHandles(p)));
|
||||
extendVector(expected, handleInts(stdHandles(c)));
|
||||
std::sort(expected.begin(), expected.end());
|
||||
|
||||
auto correct = handleInts(c.scanForConsoleHandles());
|
||||
std::sort(correct.begin(), correct.end());
|
||||
|
||||
CHECK(expected == correct);
|
||||
}
|
||||
}
|
190
misc/buffer-tests/HandleTests/CreateProcess_UseStdHandles.cc
Executable file
190
misc/buffer-tests/HandleTests/CreateProcess_UseStdHandles.cc
Executable file
@ -0,0 +1,190 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
//
|
||||
// Test CreateProcess when called with these parameters:
|
||||
// - STARTF_USESTDHANDLES is specified
|
||||
// - bInheritHandles=FALSE or bInheritHandles=TRUE
|
||||
// - CreationConsoleMode=NewConsole or CreationConsoleMode=Inherit
|
||||
//
|
||||
// Verify:
|
||||
// - The resulting traditional ConsoleHandleSet is correct.
|
||||
// - Windows 8 creates Unbound handles when appropriate.
|
||||
// - Standard handles are set correctly.
|
||||
//
|
||||
// Before Windows 8, the child process has the standard handles specified
|
||||
// in STARTUPINFO, without exception. Starting with Windows 8, the STARTUPINFO
|
||||
// handles are ignored with bInheritHandles=FALSE, and even with
|
||||
// bInheritHandles=TRUE, a NULL hStd{Input,Output,Error} field is translated to
|
||||
// a new open handle if a new console is being created.
|
||||
|
||||
template <typename T>
|
||||
void checkVariousInputs(T check) {
|
||||
{
|
||||
// Specify the original std values. With CreationConsoleMode==Inherit
|
||||
// and bInheritHandles=FALSE, this code used to work (i.e. produce
|
||||
// valid standard handles in the child). As of Windows 8, the standard
|
||||
// handles are now NULL instead.
|
||||
Worker p;
|
||||
check(p, stdHandles(p));
|
||||
}
|
||||
{
|
||||
Worker p;
|
||||
check(p, {
|
||||
p.getStdin().dup(),
|
||||
p.getStdout().dup(),
|
||||
p.getStderr().dup(),
|
||||
});
|
||||
}
|
||||
{
|
||||
Worker p;
|
||||
check(p, {
|
||||
p.getStdin().dup(true),
|
||||
p.getStdout().dup(true),
|
||||
p.getStderr().dup(true),
|
||||
});
|
||||
}
|
||||
{
|
||||
Worker p;
|
||||
check(p, {
|
||||
p.openConin(),
|
||||
p.openConout(),
|
||||
p.openConout(),
|
||||
});
|
||||
}
|
||||
{
|
||||
Worker p;
|
||||
check(p, {
|
||||
p.openConin(true),
|
||||
p.openConout(true),
|
||||
p.openConout(true),
|
||||
});
|
||||
}
|
||||
{
|
||||
// Invalid handles.
|
||||
Worker p;
|
||||
check(p, {
|
||||
Handle::invent(nullptr, p),
|
||||
Handle::invent(0x10000ull, p),
|
||||
Handle::invent(0xdeadbeecull, p),
|
||||
});
|
||||
check(p, {
|
||||
Handle::invent(INVALID_HANDLE_VALUE, p),
|
||||
Handle::invent(nullptr, p),
|
||||
Handle::invent(nullptr, p),
|
||||
});
|
||||
check(p, {
|
||||
Handle::invent(nullptr, p),
|
||||
Handle::invent(nullptr, p),
|
||||
Handle::invent(nullptr, p),
|
||||
});
|
||||
}
|
||||
{
|
||||
// Try a non-inheritable pipe.
|
||||
Worker p;
|
||||
auto pipe = newPipe(p, false);
|
||||
check(p, {
|
||||
std::get<0>(pipe),
|
||||
std::get<1>(pipe),
|
||||
std::get<1>(pipe),
|
||||
});
|
||||
}
|
||||
{
|
||||
// Try an inheritable pipe.
|
||||
Worker p;
|
||||
auto pipe = newPipe(p, true);
|
||||
check(p, {
|
||||
std::get<0>(pipe),
|
||||
std::get<1>(pipe),
|
||||
std::get<1>(pipe),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateProcess_UseStdHandles, always);
|
||||
static void Test_CreateProcess_UseStdHandles() {
|
||||
checkVariousInputs([](Worker &p, std::vector<Handle> newHandles) {
|
||||
ASSERT(newHandles.size() == 3);
|
||||
auto check = [&](Worker &c, bool inheritHandles, bool newConsole) {
|
||||
trace("Test_CreateProcess_UseStdHandles: "
|
||||
"inheritHandles=%d newConsole=%d",
|
||||
inheritHandles, newConsole);
|
||||
auto childHandles = stdHandles(c);
|
||||
if (isTraditionalConio()) {
|
||||
CHECK(handleValues(stdHandles(c)) == handleValues(newHandles));
|
||||
if (newConsole) {
|
||||
checkInitConsoleHandleSet(c);
|
||||
} else {
|
||||
checkInitConsoleHandleSet(c, p);
|
||||
}
|
||||
// The child handles have the same values as the parent.
|
||||
// Verify that the child standard handles point to the right
|
||||
// kernel objects.
|
||||
ObjectSnap snap;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (newHandles[i].value() == nullptr ||
|
||||
newHandles[i].value() == INVALID_HANDLE_VALUE) {
|
||||
// Nothing to check.
|
||||
} else if (newHandles[i].isTraditionalConsole()) {
|
||||
// Everything interesting was already checked in
|
||||
// checkInitConsoleHandleSet.
|
||||
} else if (newHandles[i].tryFlags()) {
|
||||
// A handle is not inherited simply because it is
|
||||
// listed in STARTUPINFO. The new child standard
|
||||
// handle is valid iff:
|
||||
// - the parent handle was valid, AND
|
||||
// - the parent handle was inheritable, AND
|
||||
// - bInheritHandles is TRUE
|
||||
//
|
||||
// The logic below is not obviously true for all
|
||||
// possible handle values, but it will work for all
|
||||
// values we test for. (i.e. There could be some
|
||||
// handle H to object O that isn't inherited, but by
|
||||
// sheer conincidence, the child gets a handle H that
|
||||
// also refers to O. (e.g. Windows internal objects.)
|
||||
// This test case works because we know that Windows
|
||||
// won't create a reference to our test objects.)
|
||||
CHECK(snap.eq(newHandles[i], childHandles[i]) ==
|
||||
(inheritHandles && newHandles[i].inheritable()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ObjectSnap snap;
|
||||
bool consoleOpened[3] = {false, false, false};
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (inheritHandles && newHandles[i].value() != nullptr) {
|
||||
// The parent's standard handle is used, without
|
||||
// validation or duplication. It is not inherited
|
||||
// simply because it is listed in STARTUPINFO.
|
||||
CHECK(childHandles[i].value() ==
|
||||
newHandles[i].value());
|
||||
if (newHandles[i].value() == INVALID_HANDLE_VALUE) {
|
||||
// The test below does not work on the current
|
||||
// process pseudo-handle (aka
|
||||
// INVALID_HANDLE_VALUE).
|
||||
} else if (newHandles[i].tryFlags()) {
|
||||
CHECK(snap.eq(newHandles[i], childHandles[i]) ==
|
||||
newHandles[i].inheritable());
|
||||
}
|
||||
} else if (newConsole) {
|
||||
consoleOpened[i] = true;
|
||||
} else {
|
||||
CHECK(childHandles[i].value() == nullptr);
|
||||
}
|
||||
}
|
||||
checkModernConsoleHandleInit(c,
|
||||
consoleOpened[0],
|
||||
consoleOpened[1],
|
||||
consoleOpened[2]);
|
||||
}
|
||||
};
|
||||
|
||||
for (int inheritInt = 0; inheritInt <= 1; ++inheritInt) {
|
||||
const bool inherit = inheritInt != 0;
|
||||
auto c1 = p.child({inherit, 0, newHandles});
|
||||
check(c1, inherit, false);
|
||||
auto c2 = p.child(
|
||||
{inherit, Worker::defaultCreationFlags(), newHandles});
|
||||
check(c2, inherit, true);
|
||||
}
|
||||
});
|
||||
}
|
223
misc/buffer-tests/HandleTests/MiscTests.cc
Executable file
223
misc/buffer-tests/HandleTests/MiscTests.cc
Executable file
@ -0,0 +1,223 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
REGISTER(Test_CompareObjectHandles, always);
|
||||
static void Test_CompareObjectHandles() {
|
||||
// Verify that compareObjectHandles and ObjectSnap are working.
|
||||
|
||||
Worker p;
|
||||
Worker other;
|
||||
auto pipe1 = newPipe(p, true);
|
||||
auto ph1 = std::get<0>(pipe1);
|
||||
auto ph2 = std::get<1>(pipe1);
|
||||
auto ph1dup = ph1.dup();
|
||||
auto ph1other = ph1.dup(other);
|
||||
|
||||
ObjectSnap snap;
|
||||
|
||||
CHECK(!compareObjectHandles(ph1, ph2));
|
||||
CHECK(compareObjectHandles(ph1, ph1dup));
|
||||
CHECK(compareObjectHandles(ph1, ph1other));
|
||||
|
||||
CHECK(!snap.eq(ph1, ph2));
|
||||
CHECK(snap.eq(ph1, ph1dup));
|
||||
CHECK(snap.eq(ph1, ph1other));
|
||||
CHECK(snap.eq({ ph1, ph1other, ph1dup }));
|
||||
|
||||
CHECK(!snap.eq({ ph2, ph1, ph1other, ph1dup }));
|
||||
CHECK(!snap.eq({ ph1, ph2, ph1other, ph1dup }));
|
||||
CHECK(!snap.eq({ ph1, ph1other, ph2, ph1dup }));
|
||||
CHECK(!snap.eq({ ph1, ph1other, ph1dup, ph2 }));
|
||||
}
|
||||
|
||||
REGISTER(Test_IntrinsicInheritFlags, always);
|
||||
static void Test_IntrinsicInheritFlags() {
|
||||
// Console handles have an inherit flag, just as kernel handles do.
|
||||
//
|
||||
// In Windows 7, there is a bug where DuplicateHandle(h, FALSE) makes the
|
||||
// new handle inheritable if the old handle was inheritable.
|
||||
|
||||
Worker p;
|
||||
auto n = p.newBuffer(FALSE);
|
||||
auto y = p.newBuffer(TRUE);
|
||||
auto nn = n.dup(FALSE);
|
||||
auto yn = y.dup(FALSE);
|
||||
auto ny = n.dup(TRUE);
|
||||
auto yy = y.dup(TRUE);
|
||||
p.dumpConsoleHandles();
|
||||
|
||||
CHECK(n.inheritable() == false);
|
||||
CHECK(nn.inheritable() == false);
|
||||
CHECK(yn.inheritable() == isWin7());
|
||||
CHECK(y.inheritable() == true);
|
||||
CHECK(ny.inheritable() == true);
|
||||
CHECK(yy.inheritable() == true);
|
||||
|
||||
for (auto &h : (Handle[]){ n, y, nn, ny, yn, yy }) {
|
||||
const bool v = h.inheritable();
|
||||
if (isWin7()) {
|
||||
// In Windows 7, the console handle inherit flags could not be
|
||||
// changed.
|
||||
CHECK(h.trySetInheritable(v) == false);
|
||||
CHECK(h.trySetInheritable(!v) == false);
|
||||
CHECK(h.inheritable() == v);
|
||||
} else {
|
||||
// With older and newer operating systems, the inheritability can
|
||||
// be changed. (In newer operating systems, i.e. Windows 8 and up,
|
||||
// the console handles are just normal kernel handles.)
|
||||
CHECK(h.trySetInheritable(!v) == true);
|
||||
CHECK(h.inheritable() == !v);
|
||||
}
|
||||
}
|
||||
p.dumpConsoleHandles();
|
||||
|
||||
// For sanity's sake, check that DuplicateHandle(h, FALSE) does the right
|
||||
// thing with an inheritable pipe handle, even on Windows 7.
|
||||
auto pipeY = std::get<0>(newPipe(p, TRUE));
|
||||
auto pipeN = pipeY.dup(FALSE);
|
||||
CHECK(pipeY.inheritable() == true);
|
||||
CHECK(pipeN.inheritable() == false);
|
||||
}
|
||||
|
||||
REGISTER(Test_Input_Vs_Output, always);
|
||||
static void Test_Input_Vs_Output() {
|
||||
// Ensure that APIs meant for the other kind of handle fail.
|
||||
Worker p;
|
||||
CHECK(!p.getStdin().tryScreenBufferInfo());
|
||||
CHECK(!p.getStdout().tryNumberOfConsoleInputEvents());
|
||||
}
|
||||
|
||||
REGISTER(Test_Detach_Does_Not_Change_Standard_Handles, always);
|
||||
static void Test_Detach_Does_Not_Change_Standard_Handles() {
|
||||
// Detaching the current console does not affect the standard handles.
|
||||
auto check = [](Worker &p) {
|
||||
auto handles1 = handleValues(stdHandles(p));
|
||||
p.detach();
|
||||
auto handles2 = handleValues(stdHandles(p));
|
||||
CHECK(handles1 == handles2);
|
||||
};
|
||||
// Simplest form of the test.
|
||||
{
|
||||
Worker p1;
|
||||
check(p1);
|
||||
}
|
||||
// Also do a test with duplicated handles, just in case detaching resets
|
||||
// the handles to their defaults.
|
||||
{
|
||||
Worker p2;
|
||||
p2.getStdin().dup(TRUE).setStdin();
|
||||
p2.getStdout().dup(TRUE).setStdout();
|
||||
p2.getStderr().dup(TRUE).setStderr();
|
||||
check(p2);
|
||||
}
|
||||
// Do another test with STARTF_USESTDHANDLES, just in case detaching resets
|
||||
// to the hStd{Input,Output,Error} values.
|
||||
{
|
||||
Worker p3;
|
||||
auto pipe = newPipe(p3, true);
|
||||
auto rh = std::get<0>(pipe);
|
||||
auto wh = std::get<1>(pipe);
|
||||
auto p3c = p3.child({true, 0, {rh, wh, wh.dup(true)}});
|
||||
check(p3c);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_Activate_Does_Not_Change_Standard_Handles, always);
|
||||
static void Test_Activate_Does_Not_Change_Standard_Handles() {
|
||||
// SetConsoleActiveScreenBuffer does not change the standard handles.
|
||||
// MSDN documents this fact on "Console Handles"[1]
|
||||
//
|
||||
// "Note that changing the active screen buffer does not affect the
|
||||
// handle returned by GetStdHandle. Similarly, using SetStdHandle to
|
||||
// change the STDOUT handle does not affect the active screen buffer."
|
||||
//
|
||||
// [1] https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075.aspx
|
||||
Worker p;
|
||||
auto handles1 = handleValues(stdHandles(p));
|
||||
p.newBuffer(TRUE).activate();
|
||||
auto handles2 = handleValues(stdHandles(p));
|
||||
CHECK(handles1 == handles2);
|
||||
}
|
||||
|
||||
REGISTER(Test_Active_ScreenBuffer_Order, always);
|
||||
static void Test_Active_ScreenBuffer_Order() {
|
||||
// SetActiveConsoleScreenBuffer does not increase a refcount on the
|
||||
// screen buffer. Instead, when the active screen buffer's refcount hits
|
||||
// zero, Windows activates the most-recently-activated buffer.
|
||||
|
||||
auto firstChar = [](Worker &p) {
|
||||
auto h = p.openConout();
|
||||
auto ret = h.firstChar();
|
||||
h.close();
|
||||
return ret;
|
||||
};
|
||||
|
||||
{
|
||||
// Simplest test
|
||||
Worker p;
|
||||
p.getStdout().setFirstChar('a');
|
||||
auto h = p.newBuffer(false, 'b').activate();
|
||||
h.close();
|
||||
CHECK_EQ(firstChar(p), 'a');
|
||||
}
|
||||
{
|
||||
// a -> b -> c -> b -> a
|
||||
Worker p;
|
||||
p.getStdout().setFirstChar('a');
|
||||
auto b = p.newBuffer(false, 'b').activate();
|
||||
auto c = p.newBuffer(false, 'c').activate();
|
||||
c.close();
|
||||
CHECK_EQ(firstChar(p), 'b');
|
||||
b.close();
|
||||
CHECK_EQ(firstChar(p), 'a');
|
||||
}
|
||||
{
|
||||
// a -> b -> c -> b -> c -> a
|
||||
Worker p;
|
||||
p.getStdout().setFirstChar('a');
|
||||
auto b = p.newBuffer(false, 'b').activate();
|
||||
auto c = p.newBuffer(false, 'c').activate();
|
||||
b.activate();
|
||||
b.close();
|
||||
CHECK_EQ(firstChar(p), 'c');
|
||||
c.close();
|
||||
CHECK_EQ(firstChar(p), 'a');
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_GetStdHandle_SetStdHandle, always);
|
||||
static void Test_GetStdHandle_SetStdHandle() {
|
||||
// A commenter on the Old New Thing blog suggested that
|
||||
// GetStdHandle/SetStdHandle could have internally used CloseHandle and/or
|
||||
// DuplicateHandle, which would have changed the resource management
|
||||
// obligations of the callers to those APIs. In fact, the APIs are just
|
||||
// simple wrappers around global variables. Try to write tests for this
|
||||
// fact.
|
||||
//
|
||||
// http://blogs.msdn.com/b/oldnewthing/archive/2013/03/07/10399690.aspx#10400489
|
||||
auto &hv = handleValues;
|
||||
{
|
||||
// Set values and read them back. We get the same handles.
|
||||
Worker p;
|
||||
auto pipe = newPipe(p);
|
||||
auto rh = std::get<0>(pipe);
|
||||
auto wh1 = std::get<1>(pipe);
|
||||
auto wh2 = std::get<1>(pipe).dup();
|
||||
setStdHandles({ rh, wh1, wh2 });
|
||||
CHECK(hv(stdHandles(p)) == hv({ rh, wh1, wh2}));
|
||||
|
||||
// Call again, and we still get the same handles.
|
||||
CHECK(hv(stdHandles(p)) == hv({ rh, wh1, wh2}));
|
||||
}
|
||||
{
|
||||
Worker p;
|
||||
p.getStdout().setFirstChar('a');
|
||||
p.newBuffer(false, 'b').activate().setStdout().dup().setStderr();
|
||||
std::get<1>(newPipe(p)).setStdout().dup().setStderr();
|
||||
|
||||
// SetStdHandle doesn't close its previous handle when it's given a new
|
||||
// handle. Therefore, the two handles given to SetStdHandle for STDOUT
|
||||
// and STDERR are still open, and the new screen buffer is still
|
||||
// active.
|
||||
CHECK_EQ(p.openConout().firstChar(), 'b');
|
||||
}
|
||||
}
|
240
misc/buffer-tests/HandleTests/Modern.cc
Executable file
240
misc/buffer-tests/HandleTests/Modern.cc
Executable file
@ -0,0 +1,240 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
REGISTER(Test_AttachConsole_AllocConsole_StdHandles, isModernConio);
|
||||
static void Test_AttachConsole_AllocConsole_StdHandles() {
|
||||
// Verify that AttachConsole does the right thing w.r.t. console handle
|
||||
// sets and standard handles.
|
||||
|
||||
auto check = [](bool newConsole, bool useStdHandles, int nullIndex) {
|
||||
trace("checking: newConsole=%d useStdHandles=%d nullIndex=%d",
|
||||
newConsole, useStdHandles, nullIndex);
|
||||
Worker p;
|
||||
SpawnParams sp = useStdHandles
|
||||
? SpawnParams { true, 0, stdHandles(p) }
|
||||
: SpawnParams { false, 0 };
|
||||
|
||||
auto c = p.child(sp);
|
||||
auto pipe = newPipe(c, true);
|
||||
std::get<0>(pipe).setStdin();
|
||||
std::get<1>(pipe).setStdout().setStdout();
|
||||
|
||||
if (nullIndex == 0) {
|
||||
Handle::invent(nullptr, c).setStdin();
|
||||
} else if (nullIndex == 1) {
|
||||
Handle::invent(nullptr, c).setStdout();
|
||||
} else if (nullIndex == 2) {
|
||||
Handle::invent(nullptr, c).setStderr();
|
||||
}
|
||||
|
||||
auto origStdHandles = stdHandles(c);
|
||||
c.detach();
|
||||
CHECK(handleValues(stdHandles(c)) == handleValues(origStdHandles));
|
||||
|
||||
if (newConsole) {
|
||||
c.alloc();
|
||||
} else {
|
||||
Worker other;
|
||||
c.attach(other);
|
||||
}
|
||||
|
||||
if (useStdHandles) {
|
||||
auto curHandles = stdHandles(c);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (i != nullIndex) {
|
||||
CHECK(curHandles[i].value() == origStdHandles[i].value());
|
||||
}
|
||||
}
|
||||
checkModernConsoleHandleInit(c,
|
||||
nullIndex == 0,
|
||||
nullIndex == 1,
|
||||
nullIndex == 2);
|
||||
} else {
|
||||
checkModernConsoleHandleInit(c, true, true, true);
|
||||
}
|
||||
};
|
||||
|
||||
for (int i = -1; i < 3; ++i) {
|
||||
check(false, false, i);
|
||||
check(false, true, i);
|
||||
check(true, false, i);
|
||||
check(true, true, i);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_Unbound_vs_Bound, isModernConio);
|
||||
static void Test_Unbound_vs_Bound() {
|
||||
{
|
||||
// An Unbound output handle refers to the initial buffer.
|
||||
Worker p;
|
||||
auto ob = p.getStdout().setFirstChar('O');
|
||||
p.newBuffer(true, 'N').activate().setStdout().setStderr();
|
||||
CHECK_EQ(ob.firstChar(), 'O');
|
||||
|
||||
// The handle can come from another process.
|
||||
Worker p2;
|
||||
CHECK_EQ(p2.getStdout().dup(p).firstChar(), 'O');
|
||||
|
||||
// CONOUT$ will use the new buffer, though.
|
||||
CHECK_EQ(p.openConout().firstChar(), 'N');
|
||||
}
|
||||
{
|
||||
// A Bound handle from another process does not work.
|
||||
Worker wa;
|
||||
Worker wb;
|
||||
wa.getStdout().setFirstChar('a');
|
||||
wb.getStdout().setFirstChar('b');
|
||||
auto a_b = wb.openConout().dup(wa);
|
||||
auto a_c = wb.newBuffer(false, 'c').dup(wa);
|
||||
CHECK(a_b.tryFlags());
|
||||
CHECK(a_c.tryFlags());
|
||||
CHECK(!a_b.tryScreenBufferInfo());
|
||||
CHECK(!a_c.tryScreenBufferInfo());
|
||||
|
||||
// We can *make* them work, though, if we reattach p to p2's console.
|
||||
wa.detach();
|
||||
CHECK(a_b.tryFlags() && a_c.tryFlags());
|
||||
wa.attach(wb);
|
||||
CHECK(a_b.tryScreenBufferInfo() && a_b.firstChar() == 'b');
|
||||
CHECK(a_c.tryScreenBufferInfo() && a_c.firstChar() == 'c');
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_Console_Without_Processes, isModernConio);
|
||||
static void Test_Console_Without_Processes() {
|
||||
auto waitForTitle = [](HWND hwnd, const std::string &title) {
|
||||
for (int i = 0; i < 100 && (windowText(hwnd) != title); ++i) {
|
||||
Sleep(20);
|
||||
}
|
||||
};
|
||||
auto waitForNotTitle = [](HWND hwnd, const std::string &title) {
|
||||
for (int i = 0; i < 100 && (windowText(hwnd) == title); ++i) {
|
||||
Sleep(20);
|
||||
}
|
||||
};
|
||||
{
|
||||
// It is possible to have a console with no attached process. Verify
|
||||
// that the console window has the expected title even after its only
|
||||
// process detaches. The window dies once the duplicated Bound handle
|
||||
// is closed.
|
||||
Worker p({ false, CREATE_NEW_CONSOLE });
|
||||
auto bound = p.openConout();
|
||||
auto hwnd = p.consoleWindow();
|
||||
auto title = makeTempName(__FUNCTION__);
|
||||
p.setTitle(title);
|
||||
waitForTitle(hwnd, title);
|
||||
p.detach();
|
||||
Sleep(200);
|
||||
CHECK_EQ(windowText(hwnd), title);
|
||||
bound.close();
|
||||
waitForNotTitle(hwnd, title);
|
||||
CHECK(windowText(hwnd) != title);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_Implicit_Buffer_Reference, isModernConio);
|
||||
static void Test_Implicit_Buffer_Reference() {
|
||||
// Test that a process attached to a console holds an implicit reference
|
||||
// to the screen buffer that was active at attachment.
|
||||
auto activeFirstChar = [](Worker &proc) {
|
||||
auto b = proc.openConout();
|
||||
auto ret = b.firstChar();
|
||||
b.close();
|
||||
return ret;
|
||||
};
|
||||
{
|
||||
Worker p;
|
||||
Worker p2({ false, DETACHED_PROCESS });
|
||||
p.getStdout().setFirstChar('A');
|
||||
auto b = p.newBuffer(false, 'B').activate();
|
||||
auto pipe = newPipe(p, true);
|
||||
|
||||
// Spawn a child process that has no console handles open.
|
||||
SpawnParams sp({ true, EXTENDED_STARTUPINFO_PRESENT, {
|
||||
std::get<0>(pipe),
|
||||
std::get<1>(pipe),
|
||||
std::get<1>(pipe),
|
||||
}});
|
||||
sp.sui.cb = sizeof(STARTUPINFOEXW);
|
||||
sp.inheritCount = 2;
|
||||
sp.inheritList = {
|
||||
std::get<0>(pipe).value(),
|
||||
std::get<1>(pipe).value(),
|
||||
};
|
||||
auto c = p.child(sp);
|
||||
CHECK_EQ(c.scanForConsoleHandles().size(), 0u);
|
||||
|
||||
// Now close the only open handle to the B buffer. The active
|
||||
// buffer remains A, because the child implicitly references B.
|
||||
b.close();
|
||||
CHECK_EQ(activeFirstChar(p), 'B');
|
||||
c.detach();
|
||||
|
||||
// Once the child detaches, B is freed, and A activates.
|
||||
CHECK_EQ(activeFirstChar(p), 'A');
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_FreeConsole_Closes_Handles, isModernConio);
|
||||
static void Test_FreeConsole_Closes_Handles() {
|
||||
auto check = [](Worker &proc, bool ineq, bool outeq, bool erreq) {
|
||||
auto dupin = proc.getStdin().dup();
|
||||
auto dupout = proc.getStdout().dup();
|
||||
auto duperr = proc.getStderr().dup();
|
||||
proc.detach();
|
||||
ObjectSnap snap;
|
||||
CHECK_EQ(snap.eq(proc.getStdin(), dupin), ineq);
|
||||
CHECK_EQ(snap.eq(proc.getStdout(), dupout), outeq);
|
||||
CHECK_EQ(snap.eq(proc.getStderr(), duperr), erreq);
|
||||
dupin.close();
|
||||
dupout.close();
|
||||
duperr.close();
|
||||
};
|
||||
{
|
||||
// The child opened three console handles, so FreeConsole closes all of
|
||||
// them.
|
||||
Worker p;
|
||||
check(p, false, false, false);
|
||||
}
|
||||
{
|
||||
// The child inherited the handles, so FreeConsole closes none of them.
|
||||
Worker p;
|
||||
auto c = p.child({ true });
|
||||
check(c, true, true, true);
|
||||
}
|
||||
{
|
||||
// Duplicated console handles: still none of them are closed.
|
||||
Worker p;
|
||||
auto c = p.child({ false });
|
||||
check(c, true, true, true);
|
||||
}
|
||||
{
|
||||
// FreeConsole doesn't close the current stdhandles; it closes the
|
||||
// handles it opened at attach-time.
|
||||
Worker p;
|
||||
p.openConout().setStderr();
|
||||
check(p, false, false, true);
|
||||
}
|
||||
{
|
||||
// With UseStdHandles, handles aren't closed.
|
||||
Worker p;
|
||||
auto c = p.child({ true, 0, stdHandles(p) });
|
||||
check(c, true, true, true);
|
||||
}
|
||||
{
|
||||
// Using StdHandles, AllocConsole sometimes only opens a few handles.
|
||||
// Only the handles it opens are closed.
|
||||
Worker p({ false, DETACHED_PROCESS });
|
||||
auto pipe = newPipe(p, true);
|
||||
auto c = p.child({ true, DETACHED_PROCESS, {
|
||||
std::get<0>(pipe),
|
||||
std::get<1>(pipe),
|
||||
std::get<1>(pipe),
|
||||
}});
|
||||
Handle::invent(0ull, c).setStderr();
|
||||
c.alloc();
|
||||
CHECK(c.getStdin().value() == std::get<0>(pipe).value());
|
||||
CHECK(c.getStdout().value() == std::get<1>(pipe).value());
|
||||
CHECK(c.getStderr().tryScreenBufferInfo());
|
||||
check(c, true, true, false);
|
||||
}
|
||||
}
|
307
misc/buffer-tests/HandleTests/Traditional.cc
Executable file
307
misc/buffer-tests/HandleTests/Traditional.cc
Executable file
@ -0,0 +1,307 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
REGISTER(Test_HandleDuplication, isTraditionalConio);
|
||||
static void Test_HandleDuplication() {
|
||||
// A traditional console handle cannot be duplicated to another process,
|
||||
// and it must be duplicated using the GetConsoleProcess() pseudo-value.
|
||||
// (This tests targetProcess != psuedo-value, but it doesn't test
|
||||
// sourceProcess != pseudo-value. Not worth the trouble.)
|
||||
Worker p, other;
|
||||
p.getStdout().setFirstChar('x');
|
||||
CHECK_EQ(p.getStdout().dup().firstChar(), 'x');
|
||||
CHECK_EQ(p.getStdout().dup(p).value(), INVALID_HANDLE_VALUE);
|
||||
CHECK_EQ(p.getStdout().dup(other).value(), INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
REGISTER(Test_NewConsole_Resets_ConsoleHandleSet, isTraditionalConio);
|
||||
static void Test_NewConsole_Resets_ConsoleHandleSet() {
|
||||
// Test that creating a new console properly resets everything.
|
||||
Worker p;
|
||||
|
||||
// Open some handles to demonstrate the "clean slate" outcome.
|
||||
auto orig = stdHandles(p);
|
||||
p.getStdin().dup(true).setStdin();
|
||||
p.newBuffer(true).setStderr().dup(true).setStdout().activate();
|
||||
for (auto &h : orig) {
|
||||
h.close();
|
||||
}
|
||||
|
||||
auto checkClean = [](Worker &proc) {
|
||||
proc.dumpConsoleHandles();
|
||||
CHECK_EQ(proc.getStdin().uvalue(), 0x3u);
|
||||
CHECK_EQ(proc.getStdout().uvalue(), 0x7u);
|
||||
CHECK_EQ(proc.getStderr().uvalue(), 0xbu);
|
||||
auto handles = proc.scanForConsoleHandles();
|
||||
CHECK(handleValues(handles) == (std::vector<HANDLE> {
|
||||
proc.getStdin().value(),
|
||||
proc.getStdout().value(),
|
||||
proc.getStderr().value(),
|
||||
}));
|
||||
CHECK(allInheritable(handles));
|
||||
};
|
||||
|
||||
// A child with a new console is reset to a blank slate.
|
||||
for (int inherit = 0; inherit <= 1; ++inherit) {
|
||||
auto c1 = p.child({ inherit != 0, CREATE_NEW_CONSOLE });
|
||||
checkClean(c1);
|
||||
auto c2 = p.child({ inherit != 0, CREATE_NO_WINDOW });
|
||||
checkClean(c2);
|
||||
|
||||
// Starting a child from a DETACHED_PROCESS also produces a clean
|
||||
// configuration.
|
||||
Worker detachedParent({ false, DETACHED_PROCESS });
|
||||
auto pipe = newPipe(detachedParent, true);
|
||||
std::get<0>(pipe).setStdin();
|
||||
std::get<1>(pipe).setStdout().dup(true).setStdout();
|
||||
Worker c3 = detachedParent.child({ inherit != 0, 0 });
|
||||
checkClean(c3);
|
||||
}
|
||||
|
||||
// Similarly, detaching and allocating a new console resets the
|
||||
// ConsoleHandleSet.
|
||||
p.detach();
|
||||
p.alloc();
|
||||
checkClean(p);
|
||||
}
|
||||
|
||||
REGISTER(Test_CreateProcess_DetachedProcess, isTraditionalConio);
|
||||
static void Test_CreateProcess_DetachedProcess() {
|
||||
// A child with DETACHED_PROCESS has no console, and its standard handles
|
||||
// are set to 0 by default.
|
||||
Worker p;
|
||||
|
||||
p.getStdin().dup(TRUE).setStdin();
|
||||
p.getStdout().dup(TRUE).setStdout();
|
||||
p.getStderr().dup(TRUE).setStderr();
|
||||
|
||||
auto c = p.child({ true, DETACHED_PROCESS });
|
||||
|
||||
CHECK(c.getStdin().uvalue() == 0);
|
||||
CHECK(c.getStdout().uvalue() == 0);
|
||||
CHECK(c.getStderr().uvalue() == 0);
|
||||
CHECK(c.scanForConsoleHandles().empty());
|
||||
CHECK(c.consoleWindow() == NULL);
|
||||
|
||||
// XXX: What do GetConsoleCP and GetConsoleOutputCP do when no console is attached?
|
||||
|
||||
// Verify that we have a blank slate even with an implicit console
|
||||
// creation.
|
||||
auto c2 = c.child({ true });
|
||||
auto c2h = c2.scanForConsoleHandles();
|
||||
CHECK(handleValues(c2h) == (std::vector<HANDLE> {
|
||||
c2.getStdin().value(),
|
||||
c2.getStdout().value(),
|
||||
c2.getStderr().value(),
|
||||
}));
|
||||
}
|
||||
|
||||
REGISTER(Test_Creation_bInheritHandles_Flag, isTraditionalConio);
|
||||
static void Test_Creation_bInheritHandles_Flag() {
|
||||
// The bInheritHandles flags to CreateProcess has no effect on console
|
||||
// handles.
|
||||
Worker p;
|
||||
for (auto &h : (Handle[]){
|
||||
p.getStdin(),
|
||||
p.getStdout(),
|
||||
p.getStderr(),
|
||||
p.newBuffer(false),
|
||||
p.newBuffer(true),
|
||||
}) {
|
||||
h.dup(false);
|
||||
h.dup(true);
|
||||
}
|
||||
auto cY = p.child({ true });
|
||||
auto cN = p.child({ false });
|
||||
auto &hv = handleValues;
|
||||
CHECK(hv(cY.scanForConsoleHandles()) == hv(inheritableHandles(p.scanForConsoleHandles())));
|
||||
CHECK(hv(cN.scanForConsoleHandles()) == hv(inheritableHandles(p.scanForConsoleHandles())));
|
||||
}
|
||||
|
||||
REGISTER(Test_HandleAllocationOrder, isTraditionalConio);
|
||||
static void Test_HandleAllocationOrder() {
|
||||
// When a new handle is created, it always assumes the lowest unused value.
|
||||
Worker p;
|
||||
|
||||
auto h3 = p.getStdin();
|
||||
auto h7 = p.getStdout();
|
||||
auto hb = p.getStderr();
|
||||
auto hf = h7.dup(true);
|
||||
auto h13 = h3.dup(true);
|
||||
auto h17 = hb.dup(true);
|
||||
|
||||
CHECK(h3.uvalue() == 0x3);
|
||||
CHECK(h7.uvalue() == 0x7);
|
||||
CHECK(hb.uvalue() == 0xb);
|
||||
CHECK(hf.uvalue() == 0xf);
|
||||
CHECK(h13.uvalue() == 0x13);
|
||||
CHECK(h17.uvalue() == 0x17);
|
||||
|
||||
hf.close();
|
||||
h13.close();
|
||||
h7.close();
|
||||
|
||||
h7 = h3.dup(true);
|
||||
hf = h3.dup(true);
|
||||
h13 = h3.dup(true);
|
||||
auto h1b = h3.dup(true);
|
||||
|
||||
CHECK(h7.uvalue() == 0x7);
|
||||
CHECK(hf.uvalue() == 0xf);
|
||||
CHECK(h13.uvalue() == 0x13);
|
||||
CHECK(h1b.uvalue() == 0x1b);
|
||||
}
|
||||
|
||||
REGISTER(Test_InheritNothing, isTraditionalConio);
|
||||
static void Test_InheritNothing() {
|
||||
// It's possible for the standard handles to be non-inheritable.
|
||||
//
|
||||
// Avoid calling DuplicateHandle(h, FALSE), because it produces inheritable
|
||||
// console handles on Windows 7.
|
||||
Worker p;
|
||||
auto conin = p.openConin();
|
||||
auto conout = p.openConout();
|
||||
p.getStdin().close();
|
||||
p.getStdout().close();
|
||||
p.getStderr().close();
|
||||
conin.setStdin();
|
||||
conout.setStdout().dup().setStderr();
|
||||
p.dumpConsoleHandles();
|
||||
|
||||
auto c = p.child({ true });
|
||||
// The child has no open console handles.
|
||||
CHECK(c.scanForConsoleHandles().empty());
|
||||
c.dumpConsoleHandles();
|
||||
// The standard handle values are inherited, even though they're invalid.
|
||||
CHECK(c.getStdin().value() == p.getStdin().value());
|
||||
CHECK(c.getStdout().value() == p.getStdout().value());
|
||||
CHECK(c.getStderr().value() == p.getStderr().value());
|
||||
// Verify a console is attached.
|
||||
CHECK(c.openConin().value() != INVALID_HANDLE_VALUE);
|
||||
CHECK(c.openConout().value() != INVALID_HANDLE_VALUE);
|
||||
CHECK(c.newBuffer().value() != INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
REGISTER(Test_AttachConsole_And_CreateProcess_Inheritance, isTraditionalConio);
|
||||
static void Test_AttachConsole_And_CreateProcess_Inheritance() {
|
||||
Worker p;
|
||||
Worker unrelated({ false, DETACHED_PROCESS });
|
||||
|
||||
auto conin = p.getStdin().dup(true);
|
||||
auto conout1 = p.getStdout().dup(true);
|
||||
auto conout2 = p.getStderr().dup(true);
|
||||
p.openConout(false); // an extra handle for checkInitConsoleHandleSet testing
|
||||
p.openConout(true); // an extra handle for checkInitConsoleHandleSet testing
|
||||
p.getStdin().close();
|
||||
p.getStdout().close();
|
||||
p.getStderr().close();
|
||||
conin.setStdin();
|
||||
conout1.setStdout();
|
||||
conout2.setStderr();
|
||||
|
||||
auto c = p.child({ true });
|
||||
|
||||
auto c2 = c.child({ true });
|
||||
c2.detach();
|
||||
c2.attach(c);
|
||||
|
||||
unrelated.attach(p);
|
||||
|
||||
// The first child will have the same standard handles as the parent.
|
||||
CHECK(c.getStdin().value() == p.getStdin().value());
|
||||
CHECK(c.getStdout().value() == p.getStdout().value());
|
||||
CHECK(c.getStderr().value() == p.getStderr().value());
|
||||
|
||||
// AttachConsole sets the handles to (0x3, 0x7, 0xb) regardless of handle
|
||||
// validity. In this case, c2 initially had non-default handles, and it
|
||||
// attached to a process that has and also initially had non-default
|
||||
// handles. Nevertheless, the new standard handles are the defaults.
|
||||
for (auto proc : {&c2, &unrelated}) {
|
||||
CHECK(proc->getStdin().uvalue() == 0x3);
|
||||
CHECK(proc->getStdout().uvalue() == 0x7);
|
||||
CHECK(proc->getStderr().uvalue() == 0xb);
|
||||
}
|
||||
|
||||
// The set of inheritable console handles in these processes exactly match
|
||||
// that of the parent.
|
||||
checkInitConsoleHandleSet(c, p);
|
||||
checkInitConsoleHandleSet(c2, p);
|
||||
checkInitConsoleHandleSet(unrelated, p);
|
||||
}
|
||||
|
||||
REGISTER(Test_Detach_Implicitly_Closes_Handles, isTraditionalConio);
|
||||
static void Test_Detach_Implicitly_Closes_Handles() {
|
||||
// After detaching, calling GetHandleInformation fails on previous console
|
||||
// handles.
|
||||
|
||||
Worker p;
|
||||
Handle orig[] = {
|
||||
p.getStdin(),
|
||||
p.getStdout(),
|
||||
p.getStderr(),
|
||||
p.getStdin().dup(TRUE),
|
||||
p.getStdout().dup(TRUE),
|
||||
p.getStderr().dup(TRUE),
|
||||
p.openConin(TRUE),
|
||||
p.openConout(TRUE),
|
||||
};
|
||||
|
||||
p.detach();
|
||||
for (auto h : orig) {
|
||||
CHECK(!h.tryFlags());
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER(Test_AttachConsole_AllocConsole_StdHandles, isTraditionalConio);
|
||||
static void Test_AttachConsole_AllocConsole_StdHandles() {
|
||||
// Verify that AttachConsole does the right thing w.r.t. console handle
|
||||
// sets and standard handles.
|
||||
|
||||
auto check = [](bool newConsole, bool useStdHandles) {
|
||||
trace("checking: newConsole=%d useStdHandles=%d",
|
||||
newConsole, useStdHandles);
|
||||
Worker p;
|
||||
SpawnParams sp = useStdHandles
|
||||
? SpawnParams { true, 0, stdHandles(p) }
|
||||
: SpawnParams { false, 0 };
|
||||
p.openConout(false); // 0x0f
|
||||
p.openConout(true); // 0x13
|
||||
|
||||
auto c = p.child(sp);
|
||||
auto pipe = newPipe(c, true);
|
||||
std::get<0>(pipe).setStdin();
|
||||
std::get<1>(pipe).setStdout().setStdout();
|
||||
auto origStdHandles = stdHandles(c);
|
||||
c.detach();
|
||||
CHECK(handleValues(stdHandles(c)) == handleValues(origStdHandles));
|
||||
|
||||
if (newConsole) {
|
||||
c.alloc();
|
||||
checkInitConsoleHandleSet(c);
|
||||
} else {
|
||||
Worker other;
|
||||
auto out = other.newBuffer(true, 'N'); // 0x0f
|
||||
other.openConin(false); // 0x13
|
||||
auto in = other.openConin(true); // 0x17
|
||||
out.activate(); // activate new buffer
|
||||
other.getStdin().close(); // close 0x03
|
||||
other.getStdout().close(); // close 0x07
|
||||
other.getStderr().close(); // close 0x0b
|
||||
in.setStdin(); // 0x17
|
||||
out.setStdout().dup(true).setStderr(); // 0x0f and 0x1b
|
||||
c.attach(other);
|
||||
checkInitConsoleHandleSet(c, other);
|
||||
}
|
||||
|
||||
if (useStdHandles) {
|
||||
CHECK(handleValues(stdHandles(c)) == handleValues(origStdHandles));
|
||||
} else {
|
||||
CHECK(handleInts(stdHandles(c)) ==
|
||||
(std::vector<uint64_t> { 0x3, 0x7, 0xb }));
|
||||
}
|
||||
};
|
||||
|
||||
check(false, false);
|
||||
check(false, true);
|
||||
check(true, false);
|
||||
check(true, true);
|
||||
}
|
117
misc/buffer-tests/HandleTests/Win7_Conout_Crash.cc
Executable file
117
misc/buffer-tests/HandleTests/Win7_Conout_Crash.cc
Executable file
@ -0,0 +1,117 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
// Test for the Windows 7 win7_conout_crash bug.
|
||||
//
|
||||
// See console-handle.md, #win7_conout_crash, for theory. Basically, if a
|
||||
// process does not have a handle for a screen buffer, and it opens and closes
|
||||
// CONOUT$, then the buffer is destroyed, even though another process is still
|
||||
// using it. Closing the *other* handles crashes conhost.exe.
|
||||
//
|
||||
// The bug affects Windows 7 SP1, but does not affect
|
||||
// Windows Server 2008 R2 SP1, the server version of the OS.
|
||||
//
|
||||
|
||||
REGISTER(Win7_RefCount_Bug, always);
|
||||
static void Win7_RefCount_Bug() {
|
||||
{
|
||||
// Simplest demonstration:
|
||||
//
|
||||
// We will have two screen buffers in this test, O and N. The parent opens
|
||||
// CONOUT$ to access N, but when it closes its handle, N is freed,
|
||||
// restoring O as the active buffer.
|
||||
//
|
||||
Worker p;
|
||||
p.getStdout().setFirstChar('O');
|
||||
auto c = p.child();
|
||||
c.newBuffer(false, 'N').activate();
|
||||
auto conout = p.openConout();
|
||||
CHECK_EQ(conout.firstChar(), 'N');
|
||||
conout.close();
|
||||
// At this point, Win7 is broken. Test for it and hope we don't crash.
|
||||
conout = p.openConout();
|
||||
if (isWin7() && isWorkstation()) {
|
||||
CHECK_EQ(conout.firstChar(), 'O');
|
||||
} else {
|
||||
CHECK_EQ(conout.firstChar(), 'N');
|
||||
}
|
||||
}
|
||||
{
|
||||
// We can still "close" the handle by first importing it to another
|
||||
// process, then detaching that process from its console.
|
||||
Worker p;
|
||||
Worker assistant({ false, DETACHED_PROCESS });
|
||||
p.getStdout().setFirstChar('O');
|
||||
auto c = p.child();
|
||||
c.newBuffer(false, 'N').activate();
|
||||
|
||||
// Do the read a few times for good measure.
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
auto conout = p.openConout(true); // Must be inheritable!
|
||||
CHECK_EQ(conout.firstChar(), 'N');
|
||||
assistant.attach(p); // The attach imports the CONOUT$ handle
|
||||
conout.close();
|
||||
assistant.detach(); // Exiting would also work.
|
||||
}
|
||||
}
|
||||
{
|
||||
// If the child detaches, the screen buffer is still allocated. This
|
||||
// demonstrates that the CONOUT$ handle *did* increment a refcount on
|
||||
// the buffer.
|
||||
Worker p;
|
||||
p.getStdout().setFirstChar('O');
|
||||
Worker c = p.child();
|
||||
c.newBuffer(false, 'N').activate();
|
||||
auto conout = p.openConout();
|
||||
c.detach(); // The child must exit/detach *without* closing the handle.
|
||||
CHECK_EQ(conout.firstChar(), 'N');
|
||||
auto conout2 = p.openConout();
|
||||
CHECK_EQ(conout2.firstChar(), 'N');
|
||||
// It is now safe to close the handles. There is no other "console
|
||||
// object" referencing the screen buffer.
|
||||
conout.close();
|
||||
conout2.close();
|
||||
}
|
||||
{
|
||||
// If there are multiple console objects, closing any of them frees
|
||||
// the screen buffer.
|
||||
Worker p;
|
||||
auto c1 = p.child();
|
||||
auto c2 = p.child();
|
||||
p.getStdout().setFirstChar('O');
|
||||
p.newBuffer(false, 'N').activate();
|
||||
auto ch1 = c1.openConout();
|
||||
auto ch2 = c2.openConout();
|
||||
CHECK_EQ(ch1.firstChar(), 'N');
|
||||
CHECK_EQ(ch2.firstChar(), 'N');
|
||||
ch1.close();
|
||||
// At this point, Win7 is broken. Test for it and hope we don't crash.
|
||||
auto testHandle = c1.openConout();
|
||||
if (isWin7() && isWorkstation()) {
|
||||
CHECK_EQ(testHandle.firstChar(), 'O');
|
||||
} else {
|
||||
CHECK_EQ(testHandle.firstChar(), 'N');
|
||||
}
|
||||
}
|
||||
|
||||
if (isTraditionalConio()) {
|
||||
// Two processes can share a console object; in that case, CloseHandle
|
||||
// does not immediately fail.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
Worker p1;
|
||||
Worker p2 = p1.child();
|
||||
Worker p3({false, DETACHED_PROCESS});
|
||||
p1.getStdout().setFirstChar('O');
|
||||
Worker observer = p1.child();
|
||||
p1.newBuffer(false, 'N').activate();
|
||||
auto objref1 = p2.openConout(true);
|
||||
p3.attach(p2);
|
||||
auto objref2 = Handle::invent(objref1.value(), p3);
|
||||
if (i == 0) {
|
||||
objref1.close();
|
||||
} else {
|
||||
objref2.close();
|
||||
}
|
||||
CHECK_EQ(observer.openConout().firstChar(), 'N');
|
||||
}
|
||||
}
|
||||
}
|
33
misc/buffer-tests/HandleTests/main.cc
Executable file
33
misc/buffer-tests/HandleTests/main.cc
Executable file
@ -0,0 +1,33 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
int main() {
|
||||
for (DWORD flags : {CREATE_NEW_CONSOLE, CREATE_NO_WINDOW}) {
|
||||
if (flags == CREATE_NEW_CONSOLE) {
|
||||
printTestName("Using CREATE_NEW_CONSOLE as default creation mode");
|
||||
} else {
|
||||
printTestName("Using CREATE_NO_WINDOW as default creation mode");
|
||||
}
|
||||
Worker::setDefaultCreationFlags(flags);
|
||||
for (auto &test : registeredTests()) {
|
||||
std::string name;
|
||||
bool (*cond)();
|
||||
void (*func)();
|
||||
std::tie(name, cond, func) = test;
|
||||
if (cond()) {
|
||||
printTestName(name);
|
||||
func();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
const auto failures = failedTests();
|
||||
if (failures.empty()) {
|
||||
std::cout << "All tests passed!" << std::endl;
|
||||
} else {
|
||||
std::cout << "Failed tests:" << std::endl;
|
||||
for (auto name : failures) {
|
||||
std::cout << " " << name << std::endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
112
misc/buffer-tests/Makefile
Normal file
112
misc/buffer-tests/Makefile
Normal file
@ -0,0 +1,112 @@
|
||||
include ../../config.mk
|
||||
CXX = $(MINGW_CXX)
|
||||
|
||||
# Pass -Wno-format to disable format checking because gcc complains about
|
||||
# %I64x. I can't use %lld because it's broken on MinGW-on-WinXP, though it
|
||||
# works on later OSs. %I64x works everywhere with MinGW, at runtime. I
|
||||
# need to find a better way to do this int-to-string conversion.
|
||||
CXXFLAGS += \
|
||||
-MMD \
|
||||
-Wall \
|
||||
-Wno-format \
|
||||
-Iharness -I../../src/shared \
|
||||
-std=c++11 \
|
||||
-DUNICODE \
|
||||
-D_UNICODE \
|
||||
-D_WIN32_WINNT=0x0600
|
||||
LDFLAGS += -static -static-libgcc -static-libstdc++
|
||||
|
||||
# To disable PCH, just comment out these two lines.
|
||||
PCHFLAGS = -include build/obj/pch.h
|
||||
PCHDEPS = build/obj/pch.h.gch
|
||||
|
||||
# Use gmake -n to see the command-lines gmake would run.
|
||||
|
||||
COMMON_OBJECTS = \
|
||||
build/obj/harness/Event.o \
|
||||
build/obj/harness/NtHandleQuery.o \
|
||||
build/obj/harness/ShmemParcel.o \
|
||||
build/obj/harness/Spawn.o \
|
||||
build/obj/harness/UnicodeConversions.o \
|
||||
build/obj/harness/Util.o \
|
||||
build/obj/shared/DebugClient.o \
|
||||
build/obj/shared/WinptyAssert.o \
|
||||
build/obj/shared/winpty_wcsnlen.o
|
||||
|
||||
WORKER_OBJECTS = \
|
||||
build/obj/harness/WorkerProgram.o
|
||||
|
||||
TEST_OBJECTS = \
|
||||
build/obj/harness/RemoteHandle.o \
|
||||
build/obj/harness/RemoteWorker.o \
|
||||
build/obj/harness/TestUtil.o \
|
||||
|
||||
HANDLETESTS_OBJECTS = \
|
||||
build/obj/HandleTests/CreateProcess.o \
|
||||
build/obj/HandleTests/CreateProcess_Detached.o \
|
||||
build/obj/HandleTests/CreateProcess_Duplicate.o \
|
||||
build/obj/HandleTests/CreateProcess_Duplicate_PseudoHandleBug.o \
|
||||
build/obj/HandleTests/CreateProcess_Duplicate_XPPipeBug.o \
|
||||
build/obj/HandleTests/CreateProcess_InheritAllHandles.o \
|
||||
build/obj/HandleTests/CreateProcess_InheritList.o \
|
||||
build/obj/HandleTests/CreateProcess_NewConsole.o \
|
||||
build/obj/HandleTests/CreateProcess_UseStdHandles.o \
|
||||
build/obj/HandleTests/MiscTests.o \
|
||||
build/obj/HandleTests/Modern.o \
|
||||
build/obj/HandleTests/Traditional.o \
|
||||
build/obj/HandleTests/Win7_Conout_Crash.o \
|
||||
build/obj/HandleTests/main.o
|
||||
|
||||
include tests.mk
|
||||
|
||||
.PHONY : all
|
||||
all : \
|
||||
$(TESTS) \
|
||||
build/Worker.exe \
|
||||
build/HandleTests.exe \
|
||||
build/HandleTests.exe.manifest
|
||||
|
||||
.PHONY : clean
|
||||
clean:
|
||||
rm -fr build
|
||||
|
||||
build/obj/pch.h.gch : harness/pch.h
|
||||
@echo Compiling PCH $<
|
||||
@mkdir -p $$(dirname $@)
|
||||
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
build/obj/%.o : %.cc $(PCHDEPS)
|
||||
@echo Compiling $<
|
||||
@mkdir -p $$(dirname $@)
|
||||
@$(CXX) $(PCHFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
build/obj/shared/%.o : ../../src/shared/%.cc $(PCHDEPS)
|
||||
@echo Compiling $<
|
||||
@mkdir -p $$(dirname $@)
|
||||
@$(CXX) $(PCHFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
.PRECIOUS : build/obj/%.o
|
||||
.PRECIOUS : build/obj/shared/%.o
|
||||
|
||||
build/Worker.exe : $(WORKER_OBJECTS) $(COMMON_OBJECTS)
|
||||
@echo Linking $@
|
||||
@$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
build/HandleTests.exe : $(HANDLETESTS_OBJECTS) $(TEST_OBJECTS) $(COMMON_OBJECTS)
|
||||
@echo Linking $@
|
||||
@$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
build/HandleTests.exe.manifest : manifest.xml
|
||||
@Echo Copying $< to $@
|
||||
@mkdir -p $$(dirname $@)
|
||||
@cp $< $@
|
||||
|
||||
build/%.exe : build/obj/%.o $(TEST_OBJECTS) $(COMMON_OBJECTS)
|
||||
@echo Linking $@
|
||||
@$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
-include $(COMMON_OBJECTS:.o=.d)
|
||||
-include $(WORKER_OBJECTS:.o=.d)
|
||||
-include $(TEST_OBJECTS:.o=.d)
|
||||
-include $(HANDLETESTS_OBJECTS:.o=.d)
|
||||
-include build/obj/*.d
|
119
misc/buffer-tests/Test_GetConsoleTitleW.cc
Normal file
119
misc/buffer-tests/Test_GetConsoleTitleW.cc
Normal file
@ -0,0 +1,119 @@
|
||||
// Test GetConsoleTitleW.
|
||||
//
|
||||
// Each of these OS sets implements different semantics for the system call:
|
||||
// * Windows XP
|
||||
// * Vista and Windows 7
|
||||
// * Windows 8 and up (at least to Windows 10)
|
||||
//
|
||||
|
||||
#include <TestCommon.h>
|
||||
|
||||
static void checkBuf(const std::array<wchar_t, 1024> &actual,
|
||||
const std::array<wchar_t, 1024> &expected,
|
||||
const char *filename,
|
||||
int line) {
|
||||
if (actual != expected) {
|
||||
for (size_t i = 0; i < actual.size(); ++i) {
|
||||
if (actual[i] != expected[i]) {
|
||||
std::cout << filename << ":" << line << ": "
|
||||
<< "char mismatch: [" << i << "]: "
|
||||
<< actual[i] << " != " << expected[i]
|
||||
<< " ('" << static_cast<char>(actual[i]) << "' != '"
|
||||
<< static_cast<char>(expected[i]) << "')"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_BUF(actual, ...) (checkBuf((actual), __VA_ARGS__, __FILE__, __LINE__))
|
||||
|
||||
int main() {
|
||||
Worker w;
|
||||
|
||||
std::array<wchar_t, 1024> readBuf;
|
||||
const std::wstring kNul = std::wstring(L"", 1);
|
||||
const std::array<wchar_t, 1024> kJunk = {
|
||||
'1', '2', '3', '4', '5', '6', '7', '8',
|
||||
'9', '0', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
};
|
||||
|
||||
for (auto inputStr : {
|
||||
std::wstring(L""),
|
||||
std::wstring(L"a"),
|
||||
std::wstring(L"ab"),
|
||||
std::wstring(L"abc"),
|
||||
std::wstring(L"abcd"),
|
||||
std::wstring(L"abcde"),
|
||||
}) {
|
||||
for (size_t readLen = 0; readLen < 12; ++readLen) {
|
||||
std::cout << "Testing \"" << narrowString(inputStr) << "\", "
|
||||
<< "reading " << readLen << " chars" << std::endl;
|
||||
|
||||
// Set the title and read it back.
|
||||
w.setTitle(narrowString(inputStr));
|
||||
readBuf = kJunk;
|
||||
const DWORD retVal = w.titleInternal(readBuf, readLen);
|
||||
|
||||
if (readLen == 0) {
|
||||
// When passing a buffer size 0, the API returns 0 and leaves
|
||||
// the buffer untouched. Every OS version does the same thing.
|
||||
CHECK_EQ(retVal, 0u);
|
||||
CHECK_BUF(readBuf, kJunk);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::wstring expectedWrite;
|
||||
|
||||
if (isAtLeastWin8()) {
|
||||
expectedWrite = inputStr.substr(0, readLen - 1) + kNul;
|
||||
|
||||
// The call returns the untruncated length.
|
||||
CHECK_EQ(retVal, inputStr.size());
|
||||
}
|
||||
else if (isAtLeastVista()) {
|
||||
// Vista and Windows 7 have a bug where the title is instead
|
||||
// truncated to half the correct number of characters. (i.e.
|
||||
// The `readlen` is seemingly interpreted as a byte count
|
||||
// rather than a character count.) The bug isn't present on XP
|
||||
// or Windows 8.
|
||||
if (readLen == 1) {
|
||||
// There is not even room for a NUL terminator, so it's
|
||||
// just left off. The call still succeeds, though.
|
||||
expectedWrite = std::wstring();
|
||||
} else {
|
||||
expectedWrite =
|
||||
inputStr.substr(0, (readLen / 2) - 1) + kNul;
|
||||
}
|
||||
|
||||
// The call returns the untruncated length.
|
||||
CHECK_EQ(retVal, inputStr.size());
|
||||
}
|
||||
else {
|
||||
// Unlike later OSs, XP returns a truncated title length.
|
||||
// Moreover, whenever it would return 0, either because:
|
||||
// * the title is blank, and/or
|
||||
// * the read length is 1
|
||||
// then XP does not NUL-terminate the buffer.
|
||||
const size_t truncatedLen = std::min(inputStr.size(), readLen - 1);
|
||||
if (truncatedLen == 0) {
|
||||
expectedWrite = std::wstring();
|
||||
} else {
|
||||
expectedWrite = inputStr.substr(0, truncatedLen) + kNul;
|
||||
}
|
||||
CHECK_EQ(retVal, truncatedLen);
|
||||
}
|
||||
|
||||
// I will assume that remaining characters have undefined values,
|
||||
// but I suspect they're actually unchanged. On the other hand,
|
||||
// the API must never modify the bytes beyond `readLen`.
|
||||
auto expected = kJunk;
|
||||
std::copy(&readBuf[0], &readBuf[readLen], expected.begin());
|
||||
std::copy(expectedWrite.begin(), expectedWrite.end(), expected.begin());
|
||||
|
||||
CHECK_BUF(readBuf, expected);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
32
misc/buffer-tests/Win7Bug_InheritHandles.cc
Normal file
32
misc/buffer-tests/Win7Bug_InheritHandles.cc
Normal file
@ -0,0 +1,32 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
int main() {
|
||||
trace("----------------------------------");
|
||||
Worker p;
|
||||
p.getStdout().write("<-- origBuffer -->");
|
||||
|
||||
auto c = p.child();
|
||||
auto cb = c.newBuffer(FALSE);
|
||||
cb.activate();
|
||||
cb.write("<-- cb -->");
|
||||
c.dumpConsoleHandles(TRUE);
|
||||
|
||||
// Proposed fix: the agent somehow decides it should attach to this
|
||||
// particular child process. Does that fix the problem?
|
||||
//
|
||||
// No, because the child's new buffer was not marked inheritable. If it
|
||||
// were inheritable, then the parent would "inherit" the handle during
|
||||
// attach, and both processes would use the same refcount for
|
||||
// `CloseHandle`.
|
||||
p.detach();
|
||||
p.attach(c);
|
||||
p.dumpConsoleHandles(TRUE);
|
||||
auto pb = p.openConout();
|
||||
|
||||
cb.close();
|
||||
|
||||
// Demonstrate that pb is an invalid handle.
|
||||
pb.close();
|
||||
|
||||
Sleep(300000);
|
||||
}
|
56
misc/buffer-tests/Win7Bug_RaceCondition.cc
Normal file
56
misc/buffer-tests/Win7Bug_RaceCondition.cc
Normal file
@ -0,0 +1,56 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
const int SC_CONSOLE_MARK = 0xFFF2;
|
||||
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
|
||||
|
||||
int main() {
|
||||
SpawnParams sp;
|
||||
sp.bInheritHandles = TRUE;
|
||||
|
||||
trace("----------------------------------");
|
||||
Worker p;
|
||||
p.getStdout().write("<-- origBuffer -->");
|
||||
|
||||
auto c = p.child();
|
||||
auto cb = c.newBuffer();
|
||||
cb.activate();
|
||||
cb.write("<-- cb -->");
|
||||
|
||||
// This is what the winpty-agent would want to do:
|
||||
// - It tries to "freeze" the console with "Select All", which blocks
|
||||
// WriteConsole but little else. Closing a screen buffer is not
|
||||
// blocked.
|
||||
// - Then, winpty wants to get the buffer info, then read screen content.
|
||||
// - If the child process closes its special screen buffer during the
|
||||
// scraping, then on Windows 7, conhost can start reading freed memory
|
||||
// and crash. In this test case, `info2` is frequently garbage.
|
||||
// Somehow winpty-agent needs to avoid this situation, but options seem
|
||||
// scarce:
|
||||
// - The Windows 7 bug only happens with `CloseHandle` AFAICT. If a
|
||||
// buffer handle goes away implicitly from `FreeConsole` or process
|
||||
// exit, then the buffer is reference counted properly. If app
|
||||
// developers avoid closing their buffer handle, winpty can work.
|
||||
// - Be really careful about when to scrape. Pay close attention to
|
||||
// the kinds of WinEvents a full-screen app generates just before it
|
||||
// exits, and try to fast-path everything such that no scraping is
|
||||
// necessary.
|
||||
// - Start interfering with the user processes attached to the console.
|
||||
// - e.g. inject a DLL inside the processes and open CONOUT$, or
|
||||
// override APIs, etc.
|
||||
// - Attach to the right console process before opening CONOUT$. If
|
||||
// that console's buffer handle is inheritable, then opening CONOUT$
|
||||
// will then produce a safe handle.
|
||||
// - Accept a certain amount of unreliability.
|
||||
SendMessage(p.consoleWindow(), WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
|
||||
auto scrape = p.openConout();
|
||||
auto info1 = scrape.screenBufferInfo();
|
||||
cb.close();
|
||||
Sleep(200); // Helps the test fail more often.
|
||||
auto info2 = scrape.screenBufferInfo();
|
||||
SendMessage(p.consoleWindow(), WM_CHAR, 27, 0x00010001);
|
||||
|
||||
trace("%d %d %d %d", info1.srWindow.Left, info1.srWindow.Top, info1.srWindow.Right, info1.srWindow.Bottom);
|
||||
trace("%d %d %d %d", info2.srWindow.Left, info2.srWindow.Top, info2.srWindow.Right, info2.srWindow.Bottom);
|
||||
|
||||
Sleep(300000);
|
||||
}
|
94
misc/buffer-tests/harness/Command.h
Normal file
94
misc/buffer-tests/harness/Command.h
Normal file
@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include "FixedSizeString.h"
|
||||
#include "Spawn.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
struct Command {
|
||||
enum Kind {
|
||||
AllocConsole,
|
||||
AttachConsole,
|
||||
Close,
|
||||
CloseQuietly,
|
||||
DumpConsoleHandles,
|
||||
DumpStandardHandles,
|
||||
Duplicate,
|
||||
Exit,
|
||||
FreeConsole,
|
||||
GetConsoleProcessList,
|
||||
GetConsoleScreenBufferInfo,
|
||||
GetConsoleSelectionInfo,
|
||||
GetConsoleTitle,
|
||||
GetConsoleWindow,
|
||||
GetHandleInformation,
|
||||
GetNumberOfConsoleInputEvents,
|
||||
GetStdin,
|
||||
GetStderr,
|
||||
GetStdout,
|
||||
Hello,
|
||||
LookupKernelObject,
|
||||
NewBuffer,
|
||||
OpenConin,
|
||||
OpenConout,
|
||||
ReadConsoleOutput,
|
||||
ScanForConsoleHandles,
|
||||
SetConsoleTitle,
|
||||
SetHandleInformation,
|
||||
SetStdin,
|
||||
SetStderr,
|
||||
SetStdout,
|
||||
SetActiveBuffer,
|
||||
SpawnChild,
|
||||
System,
|
||||
WriteConsoleOutput,
|
||||
WriteText,
|
||||
};
|
||||
|
||||
// These fields must appear first so that the LookupKernelObject RPC will
|
||||
// work. This RPC occurs from 32-bit test programs to a 64-bit worker.
|
||||
// In that case, most of this struct's fields do not have the same
|
||||
// addresses or sizes.
|
||||
Kind kind;
|
||||
struct {
|
||||
uint32_t pid;
|
||||
uint32_t handle[2];
|
||||
uint32_t kernelObject[2];
|
||||
} lookupKernelObject;
|
||||
|
||||
HANDLE handle;
|
||||
HANDLE targetProcess;
|
||||
DWORD dword;
|
||||
BOOL success;
|
||||
BOOL bInheritHandle;
|
||||
BOOL writeToEach;
|
||||
HWND hwnd;
|
||||
union {
|
||||
CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo;
|
||||
CONSOLE_SELECTION_INFO consoleSelectionInfo;
|
||||
struct {
|
||||
FixedSizeString<128> spawnName;
|
||||
SpawnParams spawnParams;
|
||||
SpawnFailure spawnFailure;
|
||||
} spawn;
|
||||
FixedSizeString<1024> writeText;
|
||||
FixedSizeString<1024> systemText;
|
||||
std::array<wchar_t, 1024> consoleTitle;
|
||||
std::array<DWORD, 1024> processList;
|
||||
struct {
|
||||
DWORD mask;
|
||||
DWORD flags;
|
||||
} setFlags;
|
||||
struct {
|
||||
int count;
|
||||
std::array<HANDLE, 1024> table;
|
||||
} scanForConsoleHandles;
|
||||
struct {
|
||||
std::array<CHAR_INFO, 1024> buffer;
|
||||
COORD bufferSize;
|
||||
COORD bufferCoord;
|
||||
SMALL_RECT ioRegion;
|
||||
} consoleIo;
|
||||
} u;
|
||||
};
|
31
misc/buffer-tests/harness/Event.cc
Normal file
31
misc/buffer-tests/harness/Event.cc
Normal file
@ -0,0 +1,31 @@
|
||||
#include "Event.h"
|
||||
|
||||
#include "UnicodeConversions.h"
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
Event::Event(const std::string &name) {
|
||||
// Create manual-reset, not signaled initially.
|
||||
m_handle = CreateEventW(NULL, TRUE, FALSE, widenString(name).c_str());
|
||||
ASSERT(m_handle != NULL);
|
||||
}
|
||||
|
||||
Event::~Event() {
|
||||
if (m_handle != NULL) {
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void Event::set() {
|
||||
BOOL ret = SetEvent(m_handle);
|
||||
ASSERT(ret && "SetEvent failed");
|
||||
}
|
||||
|
||||
void Event::reset() {
|
||||
BOOL ret = ResetEvent(m_handle);
|
||||
ASSERT(ret && "ResetEvent failed");
|
||||
}
|
||||
|
||||
void Event::wait() {
|
||||
DWORD ret = WaitForSingleObject(m_handle, INFINITE);
|
||||
ASSERT(ret == WAIT_OBJECT_0 && "WaitForSingleObject failed");
|
||||
}
|
30
misc/buffer-tests/harness/Event.h
Normal file
30
misc/buffer-tests/harness/Event.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
class Event {
|
||||
public:
|
||||
explicit Event(const std::string &name);
|
||||
~Event();
|
||||
void set();
|
||||
void reset();
|
||||
void wait();
|
||||
|
||||
// no copying
|
||||
Event(const Event &other) = delete;
|
||||
Event &operator=(const Event &other) = delete;
|
||||
|
||||
// moving is okay
|
||||
Event(Event &&other) { *this = std::move(other); }
|
||||
Event &operator=(Event &&other) {
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
};
|
37
misc/buffer-tests/harness/FixedSizeString.h
Normal file
37
misc/buffer-tests/harness/FixedSizeString.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
template <size_t N>
|
||||
struct FixedSizeString {
|
||||
public:
|
||||
std::string str() const {
|
||||
ASSERT(strnlen(data, N) < N);
|
||||
return std::string(data);
|
||||
}
|
||||
|
||||
const char *c_str() const {
|
||||
ASSERT(strnlen(data, N) < N);
|
||||
return data;
|
||||
}
|
||||
|
||||
FixedSizeString &operator=(const char *from) {
|
||||
ASSERT(strlen(from) < N);
|
||||
strcpy(data, from);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedSizeString &operator=(const std::string &from) {
|
||||
ASSERT(from.size() < N);
|
||||
ASSERT(from.size() == strlen(from.c_str()));
|
||||
strcpy(data, from.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
char data[N];
|
||||
};
|
74
misc/buffer-tests/harness/NtHandleQuery.cc
Executable file
74
misc/buffer-tests/harness/NtHandleQuery.cc
Executable file
@ -0,0 +1,74 @@
|
||||
#include "NtHandleQuery.h"
|
||||
|
||||
#include <DebugClient.h>
|
||||
#include <OsModule.h>
|
||||
|
||||
// internal definitions copied from mingw-w64's winternl.h and ntstatus.h.
|
||||
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
|
||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004)
|
||||
|
||||
typedef enum _SYSTEM_INFORMATION_CLASS {
|
||||
SystemBasicInformation = 0,
|
||||
SystemProcessorInformation = 1,
|
||||
SystemPerformanceInformation = 2,
|
||||
SystemTimeOfDayInformation = 3,
|
||||
SystemProcessInformation = 5,
|
||||
SystemProcessorPerformanceInformation = 8,
|
||||
SystemHandleInformation = 16,
|
||||
SystemPagefileInformation = 18,
|
||||
SystemInterruptInformation = 23,
|
||||
SystemExceptionInformation = 33,
|
||||
SystemRegistryQuotaInformation = 37,
|
||||
SystemLookasideInformation = 45
|
||||
} SYSTEM_INFORMATION_CLASS;
|
||||
|
||||
typedef NTSTATUS NTAPI NtQuerySystemInformation_Type(
|
||||
SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
PVOID SystemInformation,
|
||||
ULONG SystemInformationLength,
|
||||
PULONG ReturnLength);
|
||||
|
||||
std::vector<SYSTEM_HANDLE_ENTRY> queryNtHandles() {
|
||||
OsModule ntdll(L"ntdll.dll");
|
||||
auto funcPtr = ntdll.proc("NtQuerySystemInformation");
|
||||
ASSERT(funcPtr != NULL && "NtQuerySystemInformation API is missing");
|
||||
auto func = reinterpret_cast<NtQuerySystemInformation_Type*>(funcPtr);
|
||||
static std::vector<char> buf(1024);
|
||||
while (true) {
|
||||
ULONG returnLength = 0;
|
||||
auto ret = func(
|
||||
SystemHandleInformation,
|
||||
buf.data(),
|
||||
buf.size(),
|
||||
&returnLength);
|
||||
if (ret == STATUS_INFO_LENGTH_MISMATCH) {
|
||||
buf.resize(buf.size() * 2);
|
||||
continue;
|
||||
} else if (ret == STATUS_SUCCESS) {
|
||||
break;
|
||||
} else {
|
||||
trace("Could not query NT handles, status was 0x%x",
|
||||
static_cast<unsigned>(ret));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
auto &info = *reinterpret_cast<SYSTEM_HANDLE_INFORMATION*>(buf.data());
|
||||
std::vector<SYSTEM_HANDLE_ENTRY> ret(info.Count);
|
||||
std::copy(info.Handle, info.Handle + info.Count, ret.begin());
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the ObjectPointer (underlying NT object) for the NT handle.
|
||||
void *ntHandlePointer(const std::vector<SYSTEM_HANDLE_ENTRY> &table,
|
||||
DWORD pid, HANDLE h) {
|
||||
HANDLE ret = nullptr;
|
||||
for (auto &entry : table) {
|
||||
if (entry.OwnerPid == pid &&
|
||||
entry.HandleValue == reinterpret_cast<uint64_t>(h)) {
|
||||
ASSERT(ret == nullptr);
|
||||
ret = entry.ObjectPointer;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
23
misc/buffer-tests/harness/NtHandleQuery.h
Executable file
23
misc/buffer-tests/harness/NtHandleQuery.h
Executable file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_ENTRY {
|
||||
ULONG OwnerPid;
|
||||
BYTE ObjectType;
|
||||
BYTE HandleFlags;
|
||||
USHORT HandleValue;
|
||||
PVOID ObjectPointer;
|
||||
ULONG AccessMask;
|
||||
} SYSTEM_HANDLE_ENTRY, *PSYSTEM_HANDLE_ENTRY;
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_INFORMATION {
|
||||
ULONG Count;
|
||||
SYSTEM_HANDLE_ENTRY Handle[1];
|
||||
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
|
||||
|
||||
std::vector<SYSTEM_HANDLE_ENTRY> queryNtHandles();
|
||||
void *ntHandlePointer(const std::vector<SYSTEM_HANDLE_ENTRY> &table,
|
||||
DWORD pid, HANDLE h);
|
47
misc/buffer-tests/harness/OsVersion.h
Normal file
47
misc/buffer-tests/harness/OsVersion.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
inline std::tuple<int, int> osversion() {
|
||||
OSVERSIONINFOW info = { sizeof(info) };
|
||||
ASSERT(GetVersionExW(&info));
|
||||
return std::make_tuple(info.dwMajorVersion, info.dwMinorVersion);
|
||||
}
|
||||
|
||||
inline bool isWorkstation() {
|
||||
OSVERSIONINFOEXW info = { sizeof(info) };
|
||||
ASSERT(GetVersionExW(reinterpret_cast<OSVERSIONINFO*>(&info)));
|
||||
return info.wProductType == VER_NT_WORKSTATION;
|
||||
}
|
||||
|
||||
inline bool isWin7() {
|
||||
return osversion() == std::make_tuple(6, 1);
|
||||
}
|
||||
|
||||
inline bool isAtLeastVista() {
|
||||
return osversion() >= std::make_tuple(6, 0);
|
||||
}
|
||||
|
||||
inline bool isAtLeastWin7() {
|
||||
return osversion() >= std::make_tuple(6, 1);
|
||||
}
|
||||
|
||||
inline bool isAtLeastWin8() {
|
||||
return osversion() >= std::make_tuple(6, 2);
|
||||
}
|
||||
|
||||
inline bool isAtLeastWin8_1() {
|
||||
return osversion() >= std::make_tuple(6, 3);
|
||||
}
|
||||
|
||||
inline bool isTraditionalConio() {
|
||||
return !isAtLeastWin8();
|
||||
}
|
||||
|
||||
inline bool isModernConio() {
|
||||
return isAtLeastWin8();
|
||||
}
|
226
misc/buffer-tests/harness/RemoteHandle.cc
Executable file
226
misc/buffer-tests/harness/RemoteHandle.cc
Executable file
@ -0,0 +1,226 @@
|
||||
#include "RemoteHandle.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "RemoteWorker.h"
|
||||
|
||||
#include <DebugClient.h>
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
RemoteHandle RemoteHandle::dup(HANDLE h, RemoteWorker &target,
|
||||
BOOL bInheritHandle) {
|
||||
HANDLE targetHandle;
|
||||
BOOL success = DuplicateHandle(
|
||||
GetCurrentProcess(),
|
||||
h,
|
||||
target.m_process,
|
||||
&targetHandle,
|
||||
0, bInheritHandle, DUPLICATE_SAME_ACCESS);
|
||||
ASSERT(success && "DuplicateHandle failed");
|
||||
return RemoteHandle(targetHandle, target);
|
||||
}
|
||||
|
||||
RemoteHandle &RemoteHandle::activate() {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().rpc(Command::SetActiveBuffer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RemoteHandle::write(const std::string &msg) {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().cmd().u.writeText = msg;
|
||||
worker().rpc(Command::WriteText);
|
||||
}
|
||||
|
||||
void RemoteHandle::close() {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().rpc(Command::Close);
|
||||
}
|
||||
|
||||
RemoteHandle &RemoteHandle::setStdin() {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().rpc(Command::SetStdin);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RemoteHandle &RemoteHandle::setStdout() {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().rpc(Command::SetStdout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RemoteHandle &RemoteHandle::setStderr() {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().rpc(Command::SetStderr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RemoteHandle RemoteHandle::dupImpl(RemoteWorker *target, BOOL bInheritHandle) {
|
||||
HANDLE targetProcessFromSource;
|
||||
|
||||
if (target == nullptr) {
|
||||
targetProcessFromSource = GetCurrentProcess();
|
||||
} else {
|
||||
// Allow the source worker to see the target worker.
|
||||
targetProcessFromSource = INVALID_HANDLE_VALUE;
|
||||
BOOL success = DuplicateHandle(
|
||||
GetCurrentProcess(),
|
||||
target->m_process,
|
||||
worker().m_process,
|
||||
&targetProcessFromSource,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
ASSERT(success && "Process handle duplication failed");
|
||||
}
|
||||
|
||||
// Do the user-level duplication in the source process.
|
||||
worker().cmd().handle = m_value;
|
||||
worker().cmd().targetProcess = targetProcessFromSource;
|
||||
worker().cmd().bInheritHandle = bInheritHandle;
|
||||
worker().rpc(Command::Duplicate);
|
||||
HANDLE retHandle = worker().cmd().handle;
|
||||
|
||||
if (target != nullptr) {
|
||||
// Cleanup targetProcessFromSource.
|
||||
worker().cmd().handle = targetProcessFromSource;
|
||||
worker().rpc(Command::CloseQuietly);
|
||||
ASSERT(worker().cmd().success &&
|
||||
"Error closing remote process handle");
|
||||
}
|
||||
|
||||
return RemoteHandle(retHandle, target != nullptr ? *target : worker());
|
||||
}
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO RemoteHandle::screenBufferInfo() {
|
||||
CONSOLE_SCREEN_BUFFER_INFO ret;
|
||||
bool success = tryScreenBufferInfo(&ret);
|
||||
ASSERT(success && "GetConsoleScreenBufferInfo failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RemoteHandle::tryScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO *info) {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().rpc(Command::GetConsoleScreenBufferInfo);
|
||||
if (worker().cmd().success && info != nullptr) {
|
||||
*info = worker().cmd().u.consoleScreenBufferInfo;
|
||||
}
|
||||
return worker().cmd().success;
|
||||
}
|
||||
|
||||
DWORD RemoteHandle::flags() {
|
||||
DWORD ret;
|
||||
bool success = tryFlags(&ret);
|
||||
ASSERT(success && "GetHandleInformation failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RemoteHandle::tryFlags(DWORD *flags) {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().rpc(Command::GetHandleInformation);
|
||||
if (worker().cmd().success && flags != nullptr) {
|
||||
*flags = worker().cmd().dword;
|
||||
}
|
||||
return worker().cmd().success;
|
||||
}
|
||||
|
||||
void RemoteHandle::setFlags(DWORD mask, DWORD flags) {
|
||||
bool success = trySetFlags(mask, flags);
|
||||
ASSERT(success && "SetHandleInformation failed");
|
||||
}
|
||||
|
||||
bool RemoteHandle::trySetFlags(DWORD mask, DWORD flags) {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().cmd().u.setFlags.mask = mask;
|
||||
worker().cmd().u.setFlags.flags = flags;
|
||||
worker().rpc(Command::SetHandleInformation);
|
||||
return worker().cmd().success;
|
||||
}
|
||||
|
||||
wchar_t RemoteHandle::firstChar() {
|
||||
// The "first char" is useful for identifying which output buffer a handle
|
||||
// refers to.
|
||||
worker().cmd().handle = m_value;
|
||||
const SMALL_RECT region = {};
|
||||
auto &io = worker().cmd().u.consoleIo;
|
||||
io.bufferSize = { 1, 1 };
|
||||
io.bufferCoord = {};
|
||||
io.ioRegion = region;
|
||||
worker().rpc(Command::ReadConsoleOutput);
|
||||
ASSERT(worker().cmd().success);
|
||||
ASSERT(!memcmp(&io.ioRegion, ®ion, sizeof(region)));
|
||||
return io.buffer[0].Char.UnicodeChar;
|
||||
}
|
||||
|
||||
RemoteHandle &RemoteHandle::setFirstChar(wchar_t ch) {
|
||||
// The "first char" is useful for identifying which output buffer a handle
|
||||
// refers to.
|
||||
worker().cmd().handle = m_value;
|
||||
const SMALL_RECT region = {};
|
||||
auto &io = worker().cmd().u.consoleIo;
|
||||
io.buffer[0].Char.UnicodeChar = ch;
|
||||
io.buffer[0].Attributes = 7;
|
||||
io.bufferSize = { 1, 1 };
|
||||
io.bufferCoord = {};
|
||||
io.ioRegion = region;
|
||||
worker().rpc(Command::WriteConsoleOutput);
|
||||
ASSERT(worker().cmd().success);
|
||||
ASSERT(!memcmp(&io.ioRegion, ®ion, sizeof(region)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool RemoteHandle::tryNumberOfConsoleInputEvents(DWORD *ret) {
|
||||
worker().cmd().handle = m_value;
|
||||
worker().rpc(Command::GetNumberOfConsoleInputEvents);
|
||||
if (worker().cmd().success && ret != nullptr) {
|
||||
*ret = worker().cmd().dword;
|
||||
}
|
||||
return worker().cmd().success;
|
||||
}
|
||||
|
||||
std::vector<RemoteHandle> inheritableHandles(
|
||||
const std::vector<RemoteHandle> &vec) {
|
||||
std::vector<RemoteHandle> ret;
|
||||
for (auto h : vec) {
|
||||
if (h.inheritable()) {
|
||||
ret.push_back(h);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> handleInts(const std::vector<RemoteHandle> &vec) {
|
||||
std::vector<uint64_t> ret;
|
||||
for (auto h : vec) {
|
||||
ret.push_back(reinterpret_cast<uint64_t>(h.value()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<HANDLE> handleValues(const std::vector<RemoteHandle> &vec) {
|
||||
std::vector<HANDLE> ret;
|
||||
for (auto h : vec) {
|
||||
ret.push_back(h.value());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// It would make more sense to use a std::tuple here, but it's inconvenient.
|
||||
std::vector<RemoteHandle> stdHandles(RemoteWorker &worker) {
|
||||
return {
|
||||
worker.getStdin(),
|
||||
worker.getStdout(),
|
||||
worker.getStderr(),
|
||||
};
|
||||
}
|
||||
|
||||
// It would make more sense to use a std::tuple here, but it's inconvenient.
|
||||
void setStdHandles(std::vector<RemoteHandle> handles) {
|
||||
ASSERT(handles.size() == 3);
|
||||
handles[0].setStdin();
|
||||
handles[1].setStdout();
|
||||
handles[2].setStderr();
|
||||
}
|
||||
|
||||
bool allInheritable(const std::vector<RemoteHandle> &vec) {
|
||||
return handleValues(vec) == handleValues(inheritableHandles(vec));
|
||||
}
|
82
misc/buffer-tests/harness/RemoteHandle.h
Executable file
82
misc/buffer-tests/harness/RemoteHandle.h
Executable file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
class RemoteWorker;
|
||||
|
||||
class RemoteHandle {
|
||||
friend class RemoteWorker;
|
||||
|
||||
private:
|
||||
RemoteHandle(HANDLE value, RemoteWorker &worker) :
|
||||
m_value(value), m_worker(&worker)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static RemoteHandle invent(HANDLE h, RemoteWorker &worker) {
|
||||
return RemoteHandle(h, worker);
|
||||
}
|
||||
static RemoteHandle invent(uint64_t h, RemoteWorker &worker) {
|
||||
return RemoteHandle(reinterpret_cast<HANDLE>(h), worker);
|
||||
}
|
||||
RemoteHandle &activate();
|
||||
void write(const std::string &msg);
|
||||
void close();
|
||||
RemoteHandle &setStdin();
|
||||
RemoteHandle &setStdout();
|
||||
RemoteHandle &setStderr();
|
||||
private:
|
||||
RemoteHandle dupImpl(RemoteWorker *target, BOOL bInheritHandle);
|
||||
public:
|
||||
RemoteHandle dup(RemoteWorker &target, BOOL bInheritHandle=FALSE) {
|
||||
return dupImpl(&target, bInheritHandle);
|
||||
}
|
||||
RemoteHandle dup(BOOL bInheritHandle=FALSE) {
|
||||
return dupImpl(nullptr, bInheritHandle);
|
||||
}
|
||||
static RemoteHandle dup(HANDLE h, RemoteWorker &target,
|
||||
BOOL bInheritHandle=FALSE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo();
|
||||
bool tryScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO *info=nullptr);
|
||||
DWORD flags();
|
||||
bool tryFlags(DWORD *flags=nullptr);
|
||||
void setFlags(DWORD mask, DWORD flags);
|
||||
bool trySetFlags(DWORD mask, DWORD flags);
|
||||
bool inheritable() {
|
||||
return flags() & HANDLE_FLAG_INHERIT;
|
||||
}
|
||||
void setInheritable(bool inheritable) {
|
||||
auto success = trySetInheritable(inheritable);
|
||||
ASSERT(success && "setInheritable failed");
|
||||
}
|
||||
bool trySetInheritable(bool inheritable) {
|
||||
return trySetFlags(HANDLE_FLAG_INHERIT,
|
||||
inheritable ? HANDLE_FLAG_INHERIT : 0);
|
||||
}
|
||||
wchar_t firstChar();
|
||||
RemoteHandle &setFirstChar(wchar_t ch);
|
||||
bool tryNumberOfConsoleInputEvents(DWORD *ret=nullptr);
|
||||
HANDLE value() const { return m_value; }
|
||||
uint64_t uvalue() const { return reinterpret_cast<uint64_t>(m_value); }
|
||||
bool isTraditionalConsole() const { return (uvalue() & 3) == 3; }
|
||||
RemoteWorker &worker() const { return *m_worker; }
|
||||
|
||||
private:
|
||||
HANDLE m_value;
|
||||
RemoteWorker *m_worker;
|
||||
};
|
||||
|
||||
std::vector<RemoteHandle> inheritableHandles(
|
||||
const std::vector<RemoteHandle> &vec);
|
||||
std::vector<uint64_t> handleInts(const std::vector<RemoteHandle> &vec);
|
||||
std::vector<HANDLE> handleValues(const std::vector<RemoteHandle> &vec);
|
||||
std::vector<RemoteHandle> stdHandles(RemoteWorker &worker);
|
||||
void setStdHandles(std::vector<RemoteHandle> handles);
|
||||
bool allInheritable(const std::vector<RemoteHandle> &vec);
|
156
misc/buffer-tests/harness/RemoteWorker.cc
Executable file
156
misc/buffer-tests/harness/RemoteWorker.cc
Executable file
@ -0,0 +1,156 @@
|
||||
#include "RemoteWorker.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "UnicodeConversions.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <DebugClient.h>
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
DWORD RemoteWorker::dwDefaultCreationFlags = CREATE_NEW_CONSOLE;
|
||||
|
||||
RemoteWorker::RemoteWorker(decltype(DoNotSpawn)) :
|
||||
m_name(makeTempName("WinptyBufferTests")),
|
||||
m_parcel(m_name + "-shmem", ShmemParcel::CreateNew),
|
||||
m_startEvent(m_name + "-start"),
|
||||
m_finishEvent(m_name + "-finish")
|
||||
{
|
||||
m_finishEvent.set();
|
||||
}
|
||||
|
||||
RemoteWorker::RemoteWorker(SpawnParams params) : RemoteWorker(DoNotSpawn) {
|
||||
SpawnFailure dummy;
|
||||
m_process = spawn(m_name, params, dummy);
|
||||
ASSERT(m_process != nullptr && "Could not create RemoteWorker");
|
||||
m_valid = true;
|
||||
// Perform an RPC just to ensure that the worker process is ready, and
|
||||
// the console exists, before returning.
|
||||
rpc(Command::Hello);
|
||||
}
|
||||
|
||||
RemoteWorker RemoteWorker::child(SpawnParams params) {
|
||||
auto ret = tryChild(params);
|
||||
ASSERT(ret.valid() && "Could not spawn child worker");
|
||||
return ret;
|
||||
}
|
||||
|
||||
RemoteWorker RemoteWorker::tryChild(SpawnParams params, SpawnFailure *failure) {
|
||||
RemoteWorker ret(DoNotSpawn);
|
||||
cmd().u.spawn.spawnName = ret.m_name;
|
||||
cmd().u.spawn.spawnParams = params;
|
||||
rpc(Command::SpawnChild);
|
||||
if (cmd().handle == nullptr) {
|
||||
if (failure != nullptr) {
|
||||
*failure = cmd().u.spawn.spawnFailure;
|
||||
}
|
||||
} else {
|
||||
BOOL dupSuccess = DuplicateHandle(
|
||||
m_process,
|
||||
cmd().handle,
|
||||
GetCurrentProcess(),
|
||||
&ret.m_process,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
ASSERT(dupSuccess && "RemoteWorker::child: DuplicateHandle failed");
|
||||
rpc(Command::CloseQuietly);
|
||||
ASSERT(cmd().success && "RemoteWorker::child: CloseHandle failed");
|
||||
ret.m_valid = true;
|
||||
// Perform an RPC just to ensure that the worker process is ready, and
|
||||
// the console exists, before returning.
|
||||
ret.rpc(Command::Hello);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RemoteWorker::exit() {
|
||||
cmd().dword = 0;
|
||||
rpcAsync(Command::Exit);
|
||||
DWORD result = WaitForSingleObject(m_process, INFINITE);
|
||||
ASSERT(result == WAIT_OBJECT_0 &&
|
||||
"WaitForSingleObject failed while killing worker");
|
||||
CloseHandle(m_process);
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
CONSOLE_SELECTION_INFO RemoteWorker::selectionInfo() {
|
||||
rpc(Command::GetConsoleSelectionInfo);
|
||||
ASSERT(cmd().success);
|
||||
return cmd().u.consoleSelectionInfo;
|
||||
}
|
||||
|
||||
void RemoteWorker::dumpConsoleHandles(BOOL writeToEach) {
|
||||
cmd().writeToEach = writeToEach;
|
||||
rpc(Command::DumpConsoleHandles);
|
||||
}
|
||||
|
||||
std::vector<RemoteHandle> RemoteWorker::scanForConsoleHandles() {
|
||||
rpc(Command::ScanForConsoleHandles);
|
||||
auto &rpcTable = cmd().u.scanForConsoleHandles;
|
||||
std::vector<RemoteHandle> ret;
|
||||
for (int i = 0; i < rpcTable.count; ++i) {
|
||||
ret.push_back(RemoteHandle(rpcTable.table[i], *this));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RemoteWorker::setTitleInternal(const std::wstring &wstr) {
|
||||
ASSERT(wstr.size() < cmd().u.consoleTitle.size());
|
||||
ASSERT(wstr.size() == wcslen(wstr.c_str()));
|
||||
wcscpy(cmd().u.consoleTitle.data(), wstr.c_str());
|
||||
rpc(Command::SetConsoleTitle);
|
||||
return cmd().success;
|
||||
}
|
||||
|
||||
std::string RemoteWorker::title() {
|
||||
std::array<wchar_t, 1024> buf;
|
||||
DWORD ret = titleInternal(buf, buf.size());
|
||||
ret = std::min<DWORD>(ret, buf.size() - 1);
|
||||
buf[std::min<size_t>(buf.size() - 1, ret)] = L'\0';
|
||||
return narrowString(std::wstring(buf.data()));
|
||||
}
|
||||
|
||||
// This API is more low-level than typical, because GetConsoleTitleW is buggy
|
||||
// in older versions of Windows, and this method is used to test the bugs.
|
||||
DWORD RemoteWorker::titleInternal(std::array<wchar_t, 1024> &buf, DWORD bufSize) {
|
||||
cmd().dword = bufSize;
|
||||
cmd().u.consoleTitle = buf;
|
||||
rpc(Command::GetConsoleTitle);
|
||||
buf = cmd().u.consoleTitle;
|
||||
return cmd().dword;
|
||||
}
|
||||
|
||||
std::vector<DWORD> RemoteWorker::consoleProcessList() {
|
||||
rpc(Command::GetConsoleProcessList);
|
||||
DWORD count = cmd().dword;
|
||||
ASSERT(count <= cmd().u.processList.size());
|
||||
return std::vector<DWORD>(
|
||||
&cmd().u.processList[0],
|
||||
&cmd().u.processList[count]);
|
||||
}
|
||||
|
||||
uint64_t RemoteWorker::lookupKernelObject(DWORD pid, HANDLE h) {
|
||||
const uint64_t h64 = reinterpret_cast<uint64_t>(h);
|
||||
cmd().lookupKernelObject.pid = pid;
|
||||
memcpy(&cmd().lookupKernelObject.handle, &h64, sizeof(h64));
|
||||
rpc(Command::LookupKernelObject);
|
||||
uint64_t ret;
|
||||
memcpy(&ret, &cmd().lookupKernelObject.kernelObject, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RemoteWorker::rpc(Command::Kind kind) {
|
||||
rpcImpl(kind);
|
||||
m_finishEvent.wait();
|
||||
}
|
||||
|
||||
void RemoteWorker::rpcAsync(Command::Kind kind) {
|
||||
rpcImpl(kind);
|
||||
}
|
||||
|
||||
void RemoteWorker::rpcImpl(Command::Kind kind) {
|
||||
ASSERT(m_valid && "Cannot perform an RPC on an invalid RemoteWorker");
|
||||
m_finishEvent.wait();
|
||||
m_finishEvent.reset();
|
||||
cmd().kind = kind;
|
||||
m_startEvent.set();
|
||||
}
|
138
misc/buffer-tests/harness/RemoteWorker.h
Executable file
138
misc/buffer-tests/harness/RemoteWorker.h
Executable file
@ -0,0 +1,138 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Command.h"
|
||||
#include "Event.h"
|
||||
#include "RemoteHandle.h"
|
||||
#include "ShmemParcel.h"
|
||||
#include "Spawn.h"
|
||||
#include "UnicodeConversions.h"
|
||||
|
||||
class RemoteWorker {
|
||||
friend class RemoteHandle;
|
||||
friend uint64_t wow64LookupKernelObject(DWORD pid, HANDLE handle);
|
||||
static DWORD dwDefaultCreationFlags;
|
||||
|
||||
public:
|
||||
static void setDefaultCreationFlags(DWORD flags) {
|
||||
dwDefaultCreationFlags = flags;
|
||||
}
|
||||
static DWORD defaultCreationFlags() {
|
||||
return dwDefaultCreationFlags;
|
||||
}
|
||||
|
||||
public:
|
||||
struct {} static constexpr DoNotSpawn = {};
|
||||
explicit RemoteWorker(decltype(DoNotSpawn));
|
||||
explicit RemoteWorker() : RemoteWorker({false, dwDefaultCreationFlags}) {}
|
||||
explicit RemoteWorker(SpawnParams params);
|
||||
RemoteWorker child(SpawnParams params={});
|
||||
RemoteWorker tryChild(SpawnParams params={}, SpawnFailure *failure=nullptr);
|
||||
~RemoteWorker() { cleanup(); }
|
||||
bool valid() { return m_valid; }
|
||||
void exit();
|
||||
private:
|
||||
void cleanup() { if (m_valid) { exit(); } }
|
||||
public:
|
||||
|
||||
// basic worker info
|
||||
HANDLE processHandle() { return m_process; }
|
||||
DWORD pid() { return GetProcessId(m_process); }
|
||||
|
||||
// allow moving
|
||||
RemoteWorker(RemoteWorker &&other) :
|
||||
m_valid(std::move(other.m_valid)),
|
||||
m_name(std::move(other.m_name)),
|
||||
m_parcel(std::move(other.m_parcel)),
|
||||
m_startEvent(std::move(other.m_startEvent)),
|
||||
m_finishEvent(std::move(other.m_finishEvent)),
|
||||
m_process(std::move(other.m_process))
|
||||
{
|
||||
other.m_valid = false;
|
||||
other.m_process = nullptr;
|
||||
}
|
||||
RemoteWorker &operator=(RemoteWorker &&other) {
|
||||
cleanup();
|
||||
m_valid = std::move(other.m_valid);
|
||||
m_name = std::move(other.m_name);
|
||||
m_parcel = std::move(other.m_parcel);
|
||||
m_startEvent = std::move(other.m_startEvent);
|
||||
m_finishEvent = std::move(other.m_finishEvent);
|
||||
m_process = std::move(other.m_process);
|
||||
other.m_valid = false;
|
||||
other.m_process = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Commands
|
||||
RemoteHandle getStdin() { rpc(Command::GetStdin); return RemoteHandle(cmd().handle, *this); }
|
||||
RemoteHandle getStdout() { rpc(Command::GetStdout); return RemoteHandle(cmd().handle, *this); }
|
||||
RemoteHandle getStderr() { rpc(Command::GetStderr); return RemoteHandle(cmd().handle, *this); }
|
||||
bool detach() { rpc(Command::FreeConsole); return cmd().success; }
|
||||
bool attach(RemoteWorker &worker) { cmd().dword = GetProcessId(worker.m_process); rpc(Command::AttachConsole); return cmd().success; }
|
||||
bool alloc() { rpc(Command::AllocConsole); return cmd().success; }
|
||||
void dumpStandardHandles() { rpc(Command::DumpStandardHandles); }
|
||||
int system(const std::string &arg) { cmd().u.systemText = arg; rpc(Command::System); return cmd().dword; }
|
||||
HWND consoleWindow() { rpc(Command::GetConsoleWindow); return cmd().hwnd; }
|
||||
|
||||
CONSOLE_SELECTION_INFO selectionInfo();
|
||||
void dumpConsoleHandles(BOOL writeToEach=FALSE);
|
||||
std::vector<RemoteHandle> scanForConsoleHandles();
|
||||
void setTitle(const std::string &str) { auto b = setTitleInternal(widenString(str)); ASSERT(b && "setTitle failed"); }
|
||||
bool setTitleInternal(const std::wstring &str);
|
||||
std::string title();
|
||||
DWORD titleInternal(std::array<wchar_t, 1024> &buf, DWORD bufSize);
|
||||
std::vector<DWORD> consoleProcessList();
|
||||
|
||||
RemoteHandle openConin(BOOL bInheritHandle=FALSE) {
|
||||
cmd().bInheritHandle = bInheritHandle;
|
||||
rpc(Command::OpenConin);
|
||||
return RemoteHandle(cmd().handle, *this);
|
||||
}
|
||||
|
||||
RemoteHandle openConout(BOOL bInheritHandle=FALSE) {
|
||||
cmd().bInheritHandle = bInheritHandle;
|
||||
rpc(Command::OpenConout);
|
||||
return RemoteHandle(cmd().handle, *this);
|
||||
}
|
||||
|
||||
RemoteHandle newBuffer(BOOL bInheritHandle=FALSE, wchar_t firstChar=L'\0') {
|
||||
cmd().bInheritHandle = bInheritHandle;
|
||||
rpc(Command::NewBuffer);
|
||||
auto h = RemoteHandle(cmd().handle, *this);
|
||||
if (firstChar != L'\0') {
|
||||
h.setFirstChar(firstChar);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t lookupKernelObject(DWORD pid, HANDLE h);
|
||||
|
||||
private:
|
||||
Command &cmd() { return m_parcel.value()[0]; }
|
||||
void rpc(Command::Kind kind);
|
||||
void rpcAsync(Command::Kind kind);
|
||||
void rpcImpl(Command::Kind kind);
|
||||
|
||||
private:
|
||||
bool m_valid = false;
|
||||
std::string m_name;
|
||||
|
||||
// HACK: Use Command[2] instead of Command. To accommodate WOW64, we need
|
||||
// to have a 32-bit test program communicate with a 64-bit worker to query
|
||||
// kernel handles. The sizes of the parcels will not match, but it's
|
||||
// mostly OK as long as the creation size is larger than the open size, and
|
||||
// the 32-bit program creates the parcel. In principle, a better fix might
|
||||
// be to use parcels of different sizes or make the Command struct's size
|
||||
// independent of architecture, but those changes are hard.
|
||||
ShmemParcelTyped<Command[2]> m_parcel;
|
||||
|
||||
Event m_startEvent;
|
||||
Event m_finishEvent;
|
||||
HANDLE m_process = NULL;
|
||||
};
|
42
misc/buffer-tests/harness/ShmemParcel.cc
Normal file
42
misc/buffer-tests/harness/ShmemParcel.cc
Normal file
@ -0,0 +1,42 @@
|
||||
#include "ShmemParcel.h"
|
||||
|
||||
#include "UnicodeConversions.h"
|
||||
#include <DebugClient.h>
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
ShmemParcel::ShmemParcel(
|
||||
const std::string &name,
|
||||
CreationDisposition disposition,
|
||||
size_t size)
|
||||
{
|
||||
if (disposition == CreateNew) {
|
||||
SetLastError(0);
|
||||
m_hfile = CreateFileMappingW(
|
||||
INVALID_HANDLE_VALUE,
|
||||
NULL,
|
||||
PAGE_READWRITE,
|
||||
0,
|
||||
size,
|
||||
widenString(name).c_str());
|
||||
ASSERT(m_hfile != NULL && GetLastError() == 0 &&
|
||||
"Failed to create shared memory");
|
||||
} else if (disposition == OpenExisting) {
|
||||
m_hfile = OpenFileMappingW(
|
||||
FILE_MAP_ALL_ACCESS,
|
||||
FALSE,
|
||||
widenString(name).c_str());
|
||||
ASSERT(m_hfile != NULL && "Failed to open shared memory");
|
||||
} else {
|
||||
ASSERT(false && "Invalid disposition value");
|
||||
}
|
||||
m_view = MapViewOfFile(m_hfile, FILE_MAP_ALL_ACCESS, 0, 0, size);
|
||||
ASSERT(m_view != NULL && "Failed to map view of shared memory to create it");
|
||||
}
|
||||
|
||||
ShmemParcel::~ShmemParcel()
|
||||
{
|
||||
if (m_hfile != NULL) {
|
||||
UnmapViewOfFile(m_view);
|
||||
CloseHandle(m_hfile);
|
||||
}
|
||||
}
|
61
misc/buffer-tests/harness/ShmemParcel.h
Normal file
61
misc/buffer-tests/harness/ShmemParcel.h
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
class ShmemParcel {
|
||||
public:
|
||||
enum CreationDisposition {
|
||||
CreateNew,
|
||||
OpenExisting,
|
||||
};
|
||||
|
||||
public:
|
||||
ShmemParcel(
|
||||
const std::string &name,
|
||||
CreationDisposition disposition,
|
||||
size_t size);
|
||||
|
||||
~ShmemParcel();
|
||||
|
||||
// no copying
|
||||
ShmemParcel(const ShmemParcel &other) = delete;
|
||||
ShmemParcel &operator=(const ShmemParcel &other) = delete;
|
||||
|
||||
// moving is okay
|
||||
ShmemParcel(ShmemParcel &&other) {
|
||||
*this = std::move(other);
|
||||
}
|
||||
ShmemParcel &operator=(ShmemParcel &&other) {
|
||||
m_hfile = other.m_hfile;
|
||||
m_view = other.m_view;
|
||||
other.m_hfile = NULL;
|
||||
other.m_view = NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void *view() { return m_view; }
|
||||
|
||||
private:
|
||||
HANDLE m_hfile;
|
||||
void *m_view;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ShmemParcelTyped {
|
||||
public:
|
||||
ShmemParcelTyped(
|
||||
const std::string &name,
|
||||
ShmemParcel::CreationDisposition disposition) :
|
||||
m_parcel(name, disposition, sizeof(T))
|
||||
{
|
||||
}
|
||||
|
||||
T &value() { return *static_cast<T*>(m_parcel.view()); }
|
||||
|
||||
private:
|
||||
ShmemParcel m_parcel;
|
||||
};
|
131
misc/buffer-tests/harness/Spawn.cc
Normal file
131
misc/buffer-tests/harness/Spawn.cc
Normal file
@ -0,0 +1,131 @@
|
||||
#include "Spawn.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "UnicodeConversions.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <DebugClient.h>
|
||||
#include <OsModule.h>
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
namespace {
|
||||
|
||||
static std::vector<wchar_t> wstrToWVector(const std::wstring &str) {
|
||||
std::vector<wchar_t> ret;
|
||||
ret.resize(str.size() + 1);
|
||||
wmemcpy(ret.data(), str.c_str(), str.size() + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
HANDLE spawn(const std::string &workerName,
|
||||
const SpawnParams ¶ms,
|
||||
SpawnFailure &error) {
|
||||
auto exeBaseName = (isWow64() && params.nativeWorkerBitness)
|
||||
? "Worker64.exe" // always 64-bit binary, used to escape WOW64 environ
|
||||
: "Worker.exe"; // 32 or 64-bit binary, same arch as test program
|
||||
auto workerPath =
|
||||
pathDirName(getModuleFileName(NULL)) + "\\" + exeBaseName;
|
||||
const std::wstring workerPathWStr = widenString(workerPath);
|
||||
const std::string cmdLine = "\"" + workerPath + "\" " + workerName;
|
||||
auto cmdLineWVec = wstrToWVector(widenString(cmdLine));
|
||||
|
||||
STARTUPINFOEXW suix = { params.sui };
|
||||
ASSERT(suix.StartupInfo.cb == sizeof(STARTUPINFOW) ||
|
||||
suix.StartupInfo.cb == sizeof(STARTUPINFOEXW));
|
||||
std::unique_ptr<char[]> attrListBuffer;
|
||||
auto inheritList = params.inheritList;
|
||||
|
||||
OsModule kernel32(L"kernel32.dll");
|
||||
#define DECL_API_FUNC(name) decltype(name) *p##name = nullptr;
|
||||
DECL_API_FUNC(InitializeProcThreadAttributeList);
|
||||
DECL_API_FUNC(UpdateProcThreadAttribute);
|
||||
DECL_API_FUNC(DeleteProcThreadAttributeList);
|
||||
#undef DECL_API_FUNC
|
||||
|
||||
struct AttrList {
|
||||
decltype(DeleteProcThreadAttributeList) *cleanup = nullptr;
|
||||
LPPROC_THREAD_ATTRIBUTE_LIST v = nullptr;
|
||||
~AttrList() {
|
||||
if (v != nullptr) {
|
||||
ASSERT(cleanup != nullptr);
|
||||
cleanup(v);
|
||||
}
|
||||
}
|
||||
} attrList;
|
||||
|
||||
if (params.inheritCount != SpawnParams::NoInheritList) {
|
||||
// Add PROC_THREAD_ATTRIBUTE_HANDLE_LIST to the STARTUPINFOEX. Use
|
||||
// dynamic binding, because this code must run on XP, which does not
|
||||
// have this functionality.
|
||||
ASSERT(params.inheritCount < params.inheritList.size());
|
||||
#define GET_API_FUNC(name) p##name = reinterpret_cast<decltype(name)*>(kernel32.proc(#name));
|
||||
GET_API_FUNC(InitializeProcThreadAttributeList);
|
||||
GET_API_FUNC(UpdateProcThreadAttribute);
|
||||
GET_API_FUNC(DeleteProcThreadAttributeList);
|
||||
#undef GET_API_FUNC
|
||||
if (pInitializeProcThreadAttributeList == nullptr ||
|
||||
pUpdateProcThreadAttribute == nullptr ||
|
||||
pDeleteProcThreadAttributeList == nullptr) {
|
||||
trace("Error: skipping PROC_THREAD_ATTRIBUTE_HANDLE_LIST "
|
||||
"due to missing APIs");
|
||||
} else {
|
||||
SIZE_T bufferSize = 0;
|
||||
auto success = pInitializeProcThreadAttributeList(
|
||||
NULL, 1, 0, &bufferSize);
|
||||
if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
// The InitializeProcThreadAttributeList API "fails" with
|
||||
// ERROR_INSUFFICIENT_BUFFER.
|
||||
success = TRUE;
|
||||
}
|
||||
ASSERT(success &&
|
||||
"First InitializeProcThreadAttributeList call failed");
|
||||
attrListBuffer = std::unique_ptr<char[]>(new char[bufferSize]);
|
||||
attrList.cleanup = pDeleteProcThreadAttributeList;
|
||||
suix.lpAttributeList = attrList.v =
|
||||
reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(
|
||||
attrListBuffer.get());
|
||||
success = pInitializeProcThreadAttributeList(
|
||||
suix.lpAttributeList, 1, 0, &bufferSize);
|
||||
ASSERT(success &&
|
||||
"Second InitializeProcThreadAttributeList call failed");
|
||||
success = pUpdateProcThreadAttribute(
|
||||
suix.lpAttributeList, 0,
|
||||
PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
|
||||
inheritList.data(),
|
||||
params.inheritCount * sizeof(HANDLE),
|
||||
nullptr, nullptr);
|
||||
if (!success) {
|
||||
error.kind = SpawnFailure::UpdateProcThreadAttribute;
|
||||
error.errCode = GetLastError();
|
||||
trace("UpdateProcThreadAttribute failed: %s",
|
||||
errorString(error.errCode).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION pi;
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
|
||||
auto success = CreateProcessW(workerPathWStr.c_str(), cmdLineWVec.data(),
|
||||
NULL, NULL,
|
||||
/*bInheritHandles=*/params.bInheritHandles,
|
||||
/*dwCreationFlags=*/params.dwCreationFlags,
|
||||
NULL, NULL,
|
||||
&suix.StartupInfo, &pi);
|
||||
if (!success) {
|
||||
error.kind = SpawnFailure::CreateProcess;
|
||||
error.errCode = GetLastError();
|
||||
trace("CreateProcessW failed: %s",
|
||||
errorString(error.errCode).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
error.kind = SpawnFailure::Success;
|
||||
error.errCode = 0;
|
||||
CloseHandle(pi.hThread);
|
||||
return pi.hProcess;
|
||||
}
|
45
misc/buffer-tests/harness/Spawn.h
Normal file
45
misc/buffer-tests/harness/Spawn.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "RemoteHandle.h"
|
||||
|
||||
struct SpawnParams {
|
||||
BOOL bInheritHandles = FALSE;
|
||||
DWORD dwCreationFlags = 0;
|
||||
STARTUPINFOW sui = { sizeof(STARTUPINFOW), 0 };
|
||||
static const size_t NoInheritList = static_cast<size_t>(~0);
|
||||
size_t inheritCount = NoInheritList;
|
||||
std::array<HANDLE, 1024> inheritList = {};
|
||||
bool nativeWorkerBitness = false;
|
||||
|
||||
SpawnParams(bool bInheritHandles=false, DWORD dwCreationFlags=0) :
|
||||
bInheritHandles(bInheritHandles),
|
||||
dwCreationFlags(dwCreationFlags)
|
||||
{
|
||||
}
|
||||
|
||||
SpawnParams(bool bInheritHandles, DWORD dwCreationFlags,
|
||||
std::vector<RemoteHandle> stdHandles) :
|
||||
bInheritHandles(bInheritHandles),
|
||||
dwCreationFlags(dwCreationFlags)
|
||||
{
|
||||
ASSERT(stdHandles.size() == 3);
|
||||
sui.dwFlags |= STARTF_USESTDHANDLES;
|
||||
sui.hStdInput = stdHandles[0].value();
|
||||
sui.hStdOutput = stdHandles[1].value();
|
||||
sui.hStdError = stdHandles[2].value();
|
||||
}
|
||||
};
|
||||
|
||||
struct SpawnFailure {
|
||||
enum Kind { Success, CreateProcess, UpdateProcThreadAttribute };
|
||||
Kind kind = Success;
|
||||
DWORD errCode = 0;
|
||||
};
|
||||
|
||||
HANDLE spawn(const std::string &workerName,
|
||||
const SpawnParams ¶ms,
|
||||
SpawnFailure &error);
|
31
misc/buffer-tests/harness/TestCommon.h
Normal file
31
misc/buffer-tests/harness/TestCommon.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <cwchar>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "NtHandleQuery.h"
|
||||
#include "OsVersion.h"
|
||||
#include "RemoteHandle.h"
|
||||
#include "RemoteWorker.h"
|
||||
#include "TestUtil.h"
|
||||
#include "UnicodeConversions.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <DebugClient.h>
|
||||
#include <WinptyAssert.h>
|
||||
#include <winpty_wcsnlen.h>
|
||||
|
||||
using Handle = RemoteHandle;
|
||||
using Worker = RemoteWorker;
|
327
misc/buffer-tests/harness/TestUtil.cc
Executable file
327
misc/buffer-tests/harness/TestUtil.cc
Executable file
@ -0,0 +1,327 @@
|
||||
#include "TestUtil.h"
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "OsVersion.h"
|
||||
#include "NtHandleQuery.h"
|
||||
#include "RemoteHandle.h"
|
||||
#include "RemoteWorker.h"
|
||||
#include "UnicodeConversions.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <DebugClient.h>
|
||||
#include <OsModule.h>
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
static RegistrationTable *g_testFunctions;
|
||||
static std::unordered_set<std::string> g_testFailures;
|
||||
|
||||
void printTestName(const std::string &name) {
|
||||
trace("----------------------------------------------------------");
|
||||
trace("%s", name.c_str());
|
||||
printf("%s\n", name.c_str());
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void recordFailure(const std::string &name) {
|
||||
g_testFailures.insert(name);
|
||||
}
|
||||
|
||||
std::vector<std::string> failedTests() {
|
||||
std::vector<std::string> ret(g_testFailures.begin(), g_testFailures.end());
|
||||
std::sort(ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void registerTest(const std::string &name, bool (&cond)(), void (&func)()) {
|
||||
if (g_testFunctions == nullptr) {
|
||||
g_testFunctions = new RegistrationTable {};
|
||||
}
|
||||
for (auto &entry : *g_testFunctions) {
|
||||
// I think the compiler catches duplicates already, but just in case.
|
||||
ASSERT(&cond != std::get<1>(entry) || &func != std::get<2>(entry));
|
||||
}
|
||||
g_testFunctions->push_back(std::make_tuple(name, &cond, &func));
|
||||
}
|
||||
|
||||
RegistrationTable registeredTests() {
|
||||
return *g_testFunctions;
|
||||
}
|
||||
|
||||
static bool hasBuiltinCompareObjectHandles() {
|
||||
static auto kernelbase = LoadLibraryW(L"KernelBase.dll");
|
||||
if (kernelbase != nullptr) {
|
||||
static auto proc = GetProcAddress(kernelbase, "CompareObjectHandles");
|
||||
if (proc != nullptr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool needsWow64HandleLookup() {
|
||||
// The Worker.exe and the test programs must always be the same bitness.
|
||||
// However, in WOW64 mode, prior to Windows 7 64-bit, the WOW64 version of
|
||||
// NtQuerySystemInformation returned almost no handle information. Even
|
||||
// in Windows 7, the pointers are truncated to 32-bits, so for maximum
|
||||
// reliability, use the RPC technique there too. Windows 10 has a proper
|
||||
// API.
|
||||
static bool value = isWow64();
|
||||
return value;
|
||||
}
|
||||
|
||||
static RemoteWorker makeLookupWorker() {
|
||||
SpawnParams sp(false, DETACHED_PROCESS);
|
||||
sp.nativeWorkerBitness = true;
|
||||
return RemoteWorker(sp);
|
||||
}
|
||||
|
||||
uint64_t wow64LookupKernelObject(DWORD pid, HANDLE handle) {
|
||||
static auto lookupWorker = makeLookupWorker();
|
||||
return lookupWorker.lookupKernelObject(pid, handle);
|
||||
}
|
||||
|
||||
static bool builtinCompareObjectHandles(RemoteHandle h1, RemoteHandle h2) {
|
||||
static OsModule kernelbase(L"KernelBase.dll");
|
||||
static auto comp =
|
||||
reinterpret_cast<BOOL(WINAPI*)(HANDLE,HANDLE)>(
|
||||
kernelbase.proc("CompareObjectHandles"));
|
||||
ASSERT(comp != nullptr);
|
||||
HANDLE h1local = nullptr;
|
||||
HANDLE h2local = nullptr;
|
||||
bool dup1 = DuplicateHandle(
|
||||
h1.worker().processHandle(),
|
||||
h1.value(),
|
||||
GetCurrentProcess(),
|
||||
&h1local,
|
||||
0, false, DUPLICATE_SAME_ACCESS);
|
||||
bool dup2 = DuplicateHandle(
|
||||
h2.worker().processHandle(),
|
||||
h2.value(),
|
||||
GetCurrentProcess(),
|
||||
&h2local,
|
||||
0, false, DUPLICATE_SAME_ACCESS);
|
||||
bool ret = dup1 && dup2 && comp(h1local, h2local);
|
||||
if (dup1) {
|
||||
CloseHandle(h1local);
|
||||
}
|
||||
if (dup2) {
|
||||
CloseHandle(h2local);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool compareObjectHandles(RemoteHandle h1, RemoteHandle h2) {
|
||||
ObjectSnap snap;
|
||||
return snap.eq(h1, h2);
|
||||
}
|
||||
|
||||
ObjectSnap::ObjectSnap() {
|
||||
if (!hasBuiltinCompareObjectHandles() && !needsWow64HandleLookup()) {
|
||||
m_table = queryNtHandles();
|
||||
m_hasTable = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ObjectSnap::object(RemoteHandle h) {
|
||||
if (needsWow64HandleLookup()) {
|
||||
return wow64LookupKernelObject(h.worker().pid(), h.value());
|
||||
}
|
||||
if (!m_hasTable) {
|
||||
m_table = queryNtHandles();
|
||||
}
|
||||
return reinterpret_cast<uint64_t>(ntHandlePointer(
|
||||
m_table, h.worker().pid(), h.value()));
|
||||
}
|
||||
|
||||
bool ObjectSnap::eq(std::initializer_list<RemoteHandle> handles) {
|
||||
if (handles.size() < 2) {
|
||||
return true;
|
||||
}
|
||||
if (hasBuiltinCompareObjectHandles()) {
|
||||
for (auto i = handles.begin() + 1; i < handles.end(); ++i) {
|
||||
if (!builtinCompareObjectHandles(*handles.begin(), *i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto first = object(*handles.begin());
|
||||
for (auto i = handles.begin() + 1; i < handles.end(); ++i) {
|
||||
if (first != object(*i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::tuple<RemoteHandle, RemoteHandle> newPipe(
|
||||
RemoteWorker &w, BOOL inheritable) {
|
||||
HANDLE readPipe, writePipe;
|
||||
auto ret = CreatePipe(&readPipe, &writePipe, NULL, 0);
|
||||
ASSERT(ret && "CreatePipe failed");
|
||||
auto p1 = RemoteHandle::dup(readPipe, w, inheritable);
|
||||
auto p2 = RemoteHandle::dup(writePipe, w, inheritable);
|
||||
trace("Opened pipe in pid %u: rh=0x%I64x wh=0x%I64x",
|
||||
w.pid(), p1.uvalue(), p2.uvalue());
|
||||
CloseHandle(readPipe);
|
||||
CloseHandle(writePipe);
|
||||
return std::make_tuple(p1, p2);
|
||||
}
|
||||
|
||||
std::string windowText(HWND hwnd) {
|
||||
std::array<wchar_t, 256> buf;
|
||||
DWORD ret = GetWindowTextW(hwnd, buf.data(), buf.size());
|
||||
ASSERT(ret >= 0 && ret <= buf.size() - 1);
|
||||
buf[ret] = L'\0';
|
||||
return narrowString(std::wstring(buf.data()));
|
||||
}
|
||||
|
||||
// Verify that the process' open console handle set is as expected from
|
||||
// attaching to a new console.
|
||||
// * The set of console handles is exactly (0x3, 0x7, 0xb).
|
||||
// * The console handles are inheritable.
|
||||
void checkInitConsoleHandleSet(RemoteWorker &proc) {
|
||||
CHECK(isTraditionalConio() && "checkInitConsoleHandleSet is not valid "
|
||||
"with modern conio");
|
||||
auto actualHandles = proc.scanForConsoleHandles();
|
||||
auto correctHandles = std::vector<uint64_t> { 0x3, 0x7, 0xb };
|
||||
if (handleInts(actualHandles) == correctHandles &&
|
||||
allInheritable(actualHandles)) {
|
||||
return;
|
||||
}
|
||||
proc.dumpConsoleHandles();
|
||||
CHECK(false && "checkInitConsoleHandleSet failed");
|
||||
}
|
||||
|
||||
// Verify that the child's open console handle set is as expected from having
|
||||
// just attached to or spawned from a source worker.
|
||||
// * The set of child handles should exactly match the set of inheritable
|
||||
// source handles.
|
||||
// * Every open child handle should be inheritable.
|
||||
void checkInitConsoleHandleSet(RemoteWorker &child, RemoteWorker &source) {
|
||||
ASSERT(isTraditionalConio() && "checkInitConsoleHandleSet is not valid "
|
||||
"with modern conio");
|
||||
auto cvec = child.scanForConsoleHandles();
|
||||
auto cvecInherit = inheritableHandles(cvec);
|
||||
auto svecInherit = inheritableHandles(source.scanForConsoleHandles());
|
||||
auto hv = &handleValues;
|
||||
if (hv(cvecInherit) == hv(svecInherit) && allInheritable(cvec)) {
|
||||
return;
|
||||
}
|
||||
source.dumpConsoleHandles();
|
||||
child.dumpConsoleHandles();
|
||||
CHECK(false && "checkInitConsoleHandleSet failed");
|
||||
}
|
||||
|
||||
// Returns true if the handle is a "usable console handle":
|
||||
// * The handle must be open.
|
||||
// * It must be a console handle.
|
||||
// * The process must have an attached console.
|
||||
// * With modern conio, the handle must be "unbound" or bound to the
|
||||
// currently attached console.
|
||||
bool isUsableConsoleHandle(RemoteHandle h) {
|
||||
// XXX: It would be more efficient/elegant to use GetConsoleMode instead.
|
||||
return h.tryNumberOfConsoleInputEvents() || h.tryScreenBufferInfo();
|
||||
}
|
||||
|
||||
bool isUsableConsoleInputHandle(RemoteHandle h) {
|
||||
return h.tryNumberOfConsoleInputEvents();
|
||||
}
|
||||
|
||||
bool isUsableConsoleOutputHandle(RemoteHandle h) {
|
||||
return h.tryScreenBufferInfo();
|
||||
}
|
||||
|
||||
bool isUnboundConsoleObject(RemoteHandle h) {
|
||||
// XXX: Consider what happens here with NULL, INVALID_HANDLE_OBJECT, junk,
|
||||
// etc. I *think* it should work.
|
||||
ASSERT(isModernConio() && "isUnboundConsoleObject is not valid with "
|
||||
"traditional conio");
|
||||
static RemoteWorker other{ SpawnParams {false, CREATE_NO_WINDOW} };
|
||||
auto dup = h.dup(other);
|
||||
bool ret = isUsableConsoleHandle(dup);
|
||||
dup.close();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Verify that an optional subset of the STDIN/STDOUT/STDERR standard
|
||||
// handles are new handles referring to new Unbound console objects.
|
||||
void checkModernConsoleHandleInit(RemoteWorker &proc,
|
||||
bool in, bool out, bool err) {
|
||||
// List all the usable console handles that weren't just opened.
|
||||
std::vector<RemoteHandle> preExistingHandles;
|
||||
for (auto h : proc.scanForConsoleHandles()) {
|
||||
if ((in && h.value() == proc.getStdin().value()) ||
|
||||
(out && h.value() == proc.getStdout().value()) ||
|
||||
(err && h.value() == proc.getStderr().value())) {
|
||||
continue;
|
||||
}
|
||||
preExistingHandles.push_back(h);
|
||||
}
|
||||
ObjectSnap snap;
|
||||
auto checkNonReuse = [&](RemoteHandle h) {
|
||||
// The Unbound console objects that were just opened should not be
|
||||
// inherited from anywhere else -- they should be brand new objects.
|
||||
for (auto other : preExistingHandles) {
|
||||
CHECK(!snap.eq(h, other));
|
||||
}
|
||||
};
|
||||
|
||||
if (in) {
|
||||
CHECK(isUsableConsoleInputHandle(proc.getStdin()));
|
||||
CHECK(isUnboundConsoleObject(proc.getStdin()));
|
||||
checkNonReuse(proc.getStdin());
|
||||
}
|
||||
if (out) {
|
||||
CHECK(isUsableConsoleOutputHandle(proc.getStdout()));
|
||||
CHECK(isUnboundConsoleObject(proc.getStdout()));
|
||||
checkNonReuse(proc.getStdout());
|
||||
}
|
||||
if (err) {
|
||||
CHECK(isUsableConsoleOutputHandle(proc.getStderr()));
|
||||
CHECK(isUnboundConsoleObject(proc.getStderr()));
|
||||
checkNonReuse(proc.getStderr());
|
||||
}
|
||||
if (out && err) {
|
||||
ObjectSnap snap;
|
||||
CHECK(proc.getStdout().value() != proc.getStderr().value());
|
||||
CHECK(snap.eq(proc.getStdout(), proc.getStderr()));
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper around RemoteWorker::child that does the bare minimum to use an
|
||||
// inherit list.
|
||||
//
|
||||
// If `dummyPipeInInheritList` is true, it also creates an inheritable pipe,
|
||||
// closes one end, and specifies the other end in an inherit list. It closes
|
||||
// the final pipe end in the parent and child before returning.
|
||||
//
|
||||
// This function is useful for testing the modern bInheritHandles=TRUE handle
|
||||
// duplication functionality.
|
||||
//
|
||||
RemoteWorker childWithDummyInheritList(RemoteWorker &p, SpawnParams sp,
|
||||
bool dummyPipeInInheritList) {
|
||||
sp.bInheritHandles = true;
|
||||
sp.dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
|
||||
sp.sui.cb = sizeof(STARTUPINFOEXW);
|
||||
sp.inheritCount = 1;
|
||||
|
||||
if (dummyPipeInInheritList) {
|
||||
auto pipe = newPipe(p, true);
|
||||
std::get<0>(pipe).close();
|
||||
auto dummy = std::get<1>(pipe);
|
||||
sp.inheritList = { dummy.value() };
|
||||
auto c = p.child(sp);
|
||||
RemoteHandle::invent(dummy.value(), c).close();
|
||||
dummy.close();
|
||||
return c;
|
||||
} else {
|
||||
sp.inheritList = { NULL };
|
||||
return p.child(sp);
|
||||
}
|
||||
}
|
90
misc/buffer-tests/harness/TestUtil.h
Executable file
90
misc/buffer-tests/harness/TestUtil.h
Executable file
@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "NtHandleQuery.h"
|
||||
#include "RemoteHandle.h"
|
||||
#include "Spawn.h"
|
||||
|
||||
class RemoteWorker;
|
||||
|
||||
#define CHECK(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
recordFailure(__FUNCTION__); \
|
||||
trace("%s:%d: ERROR: check failed: " #cond, __FILE__, __LINE__); \
|
||||
std::cout << __FILE__ << ":" << __LINE__ \
|
||||
<< (": ERROR: check failed: " #cond) \
|
||||
<< std::endl; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CHECK_EQ(actual, expected) \
|
||||
do { \
|
||||
auto a = (actual); \
|
||||
auto e = (expected); \
|
||||
if (a != e) { \
|
||||
recordFailure(__FUNCTION__); \
|
||||
trace("%s:%d: ERROR: check failed " \
|
||||
"(" #actual " != " #expected ")", __FILE__, __LINE__); \
|
||||
std::cout << __FILE__ << ":" << __LINE__ \
|
||||
<< ": ERROR: check failed " \
|
||||
<< ("(" #actual " != " #expected "): ") \
|
||||
<< a << " != " << e \
|
||||
<< std::endl; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define REGISTER(name, cond) \
|
||||
static void name(); \
|
||||
int g_register_ ## cond ## _ ## name = (registerTest(#name, cond, name), 0)
|
||||
|
||||
template <typename T>
|
||||
static void extendVector(std::vector<T> &base, const std::vector<T> &to_add) {
|
||||
base.insert(base.end(), to_add.begin(), to_add.end());
|
||||
}
|
||||
|
||||
// Test registration
|
||||
void printTestName(const std::string &name);
|
||||
void recordFailure(const std::string &name);
|
||||
std::vector<std::string> failedTests();
|
||||
void registerTest(const std::string &name, bool(&cond)(), void(&func)());
|
||||
using RegistrationTable = std::vector<std::tuple<std::string, bool(*)(), void(*)()>>;
|
||||
RegistrationTable registeredTests();
|
||||
inline bool always() { return true; }
|
||||
|
||||
bool compareObjectHandles(RemoteHandle h1, RemoteHandle h2);
|
||||
|
||||
// NT kernel handle->object snapshot
|
||||
class ObjectSnap {
|
||||
public:
|
||||
ObjectSnap();
|
||||
uint64_t object(RemoteHandle h);
|
||||
bool eq(std::initializer_list<RemoteHandle> handles);
|
||||
bool eq(RemoteHandle h1, RemoteHandle h2) { return eq({h1, h2}); }
|
||||
private:
|
||||
bool m_hasTable = false;
|
||||
std::vector<SYSTEM_HANDLE_ENTRY> m_table;
|
||||
};
|
||||
|
||||
// Misc
|
||||
std::tuple<RemoteHandle, RemoteHandle> newPipe(
|
||||
RemoteWorker &w, BOOL inheritable=FALSE);
|
||||
std::string windowText(HWND hwnd);
|
||||
|
||||
// "domain-specific" routines: perhaps these belong outside the harness?
|
||||
void checkInitConsoleHandleSet(RemoteWorker &child);
|
||||
void checkInitConsoleHandleSet(RemoteWorker &child, RemoteWorker &source);
|
||||
bool isUsableConsoleHandle(RemoteHandle h);
|
||||
bool isUsableConsoleInputHandle(RemoteHandle h);
|
||||
bool isUsableConsoleOutputHandle(RemoteHandle h);
|
||||
bool isUnboundConsoleObject(RemoteHandle h);
|
||||
void checkModernConsoleHandleInit(RemoteWorker &proc,
|
||||
bool in, bool out, bool err);
|
||||
RemoteWorker childWithDummyInheritList(RemoteWorker &p, SpawnParams sp,
|
||||
bool dummyPipeInInheritList);
|
44
misc/buffer-tests/harness/UnicodeConversions.cc
Normal file
44
misc/buffer-tests/harness/UnicodeConversions.cc
Normal file
@ -0,0 +1,44 @@
|
||||
#include "UnicodeConversions.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
std::string narrowString(const std::wstring &input)
|
||||
{
|
||||
int mblen = WideCharToMultiByte(
|
||||
CP_UTF8, 0,
|
||||
input.data(), input.size(),
|
||||
NULL, 0, NULL, NULL);
|
||||
if (mblen <= 0) {
|
||||
return std::string();
|
||||
}
|
||||
std::vector<char> tmp(mblen);
|
||||
int mblen2 = WideCharToMultiByte(
|
||||
CP_UTF8, 0,
|
||||
input.data(), input.size(),
|
||||
tmp.data(), tmp.size(),
|
||||
NULL, NULL);
|
||||
ASSERT(mblen2 == mblen);
|
||||
return std::string(tmp.data(), tmp.size());
|
||||
}
|
||||
|
||||
std::wstring widenString(const std::string &input)
|
||||
{
|
||||
int widelen = MultiByteToWideChar(
|
||||
CP_UTF8, 0,
|
||||
input.data(), input.size(),
|
||||
NULL, 0);
|
||||
if (widelen <= 0) {
|
||||
return std::wstring();
|
||||
}
|
||||
std::vector<wchar_t> tmp(widelen);
|
||||
int widelen2 = MultiByteToWideChar(
|
||||
CP_UTF8, 0,
|
||||
input.data(), input.size(),
|
||||
tmp.data(), tmp.size());
|
||||
ASSERT(widelen2 == widelen);
|
||||
return std::wstring(tmp.data(), tmp.size());
|
||||
}
|
6
misc/buffer-tests/harness/UnicodeConversions.h
Normal file
6
misc/buffer-tests/harness/UnicodeConversions.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string narrowString(const std::wstring &input);
|
||||
std::wstring widenString(const std::string &input);
|
126
misc/buffer-tests/harness/Util.cc
Normal file
126
misc/buffer-tests/harness/Util.cc
Normal file
@ -0,0 +1,126 @@
|
||||
#include "Util.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "UnicodeConversions.h"
|
||||
|
||||
#include <OsModule.h>
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
namespace {
|
||||
|
||||
static std::string timeString() {
|
||||
FILETIME fileTime;
|
||||
GetSystemTimeAsFileTime(&fileTime);
|
||||
auto ret = ((uint64_t)fileTime.dwHighDateTime << 32) |
|
||||
fileTime.dwLowDateTime;
|
||||
return std::to_string(ret);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::string pathDirName(const std::string &path)
|
||||
{
|
||||
std::string::size_type pos = path.find_last_of("\\/");
|
||||
if (pos == std::string::npos) {
|
||||
return std::string();
|
||||
} else {
|
||||
return path.substr(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for GetModuleFileNameW. Returns a UTF-8 string. Aborts on error.
|
||||
std::string getModuleFileName(HMODULE module)
|
||||
{
|
||||
const DWORD size = 4096;
|
||||
wchar_t filename[size];
|
||||
DWORD actual = GetModuleFileNameW(module, filename, size);
|
||||
ASSERT(actual > 0 && actual < size);
|
||||
return narrowString(filename);
|
||||
}
|
||||
|
||||
// Convert GetLastError()'s error code to a presentable message such as:
|
||||
//
|
||||
// <87:The parameter is incorrect.>
|
||||
//
|
||||
std::string errorString(DWORD errCode) {
|
||||
// MSDN has this note about "Windows 10":
|
||||
//
|
||||
// Windows 10:
|
||||
//
|
||||
// LocalFree is not in the modern SDK, so it cannot be used to free
|
||||
// the result buffer. Instead, use HeapFree (GetProcessHeap(),
|
||||
// allocatedMessage). In this case, this is the same as calling
|
||||
// LocalFree on memory.
|
||||
//
|
||||
// Important: LocalAlloc() has different options: LMEM_FIXED, and
|
||||
// LMEM_MOVABLE. FormatMessage() uses LMEM_FIXED, so HeapFree can be
|
||||
// used. If LMEM_MOVABLE is used, HeapFree cannot be used.
|
||||
//
|
||||
// My interpretation of this note is:
|
||||
// * "Windows 10" really just means, "the latest MS SDK", which supports
|
||||
// Windows 10, as well as older releases.
|
||||
// * In every NT kernel ever, HeapFree is perfectly fine to use with
|
||||
// LocalAlloc LMEM_FIXED allocations.
|
||||
// * In every NT kernel ever, the FormatMessage buffer can be freed with
|
||||
// HeapFree.
|
||||
// The note is clumsy, though. Without clarity, I can't safely use
|
||||
// HeapFree, but apparently LocalFree calls stop compiling in the newest
|
||||
// SDK.
|
||||
//
|
||||
// Instead, I'll use a fixed-size buffer.
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "<" << errCode << ":";
|
||||
std::vector<wchar_t> msgBuf(1024);
|
||||
DWORD ret = FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr,
|
||||
errCode,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
msgBuf.data(),
|
||||
msgBuf.size(),
|
||||
nullptr);
|
||||
if (ret == 0) {
|
||||
ss << "FormatMessageW failed:";
|
||||
ss << GetLastError();
|
||||
} else {
|
||||
msgBuf[msgBuf.size() - 1] = L'\0';
|
||||
std::string msg = narrowString(std::wstring(msgBuf.data()));
|
||||
if (msg.size() >= 2 && msg.substr(msg.size() - 2) == "\r\n") {
|
||||
msg.resize(msg.size() - 2);
|
||||
}
|
||||
ss << msg;
|
||||
}
|
||||
ss << ">";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool isWow64() {
|
||||
static bool valueInitialized = false;
|
||||
static bool value = false;
|
||||
if (!valueInitialized) {
|
||||
OsModule kernel32(L"kernel32.dll");
|
||||
auto proc = reinterpret_cast<decltype(IsWow64Process)*>(
|
||||
kernel32.proc("IsWow64Process"));
|
||||
BOOL isWow64 = FALSE;
|
||||
BOOL ret = proc(GetCurrentProcess(), &isWow64);
|
||||
value = ret && isWow64;
|
||||
valueInitialized = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string makeTempName(const std::string &baseName) {
|
||||
static int workerCounter = 0;
|
||||
static auto initialTimeString = timeString();
|
||||
return baseName + "-" +
|
||||
std::to_string(static_cast<int>(GetCurrentProcessId())) + "-" +
|
||||
initialTimeString + "-" +
|
||||
std::to_string(++workerCounter);
|
||||
}
|
12
misc/buffer-tests/harness/Util.h
Normal file
12
misc/buffer-tests/harness/Util.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
std::string pathDirName(const std::string &path);
|
||||
std::string getModuleFileName(HMODULE module);
|
||||
std::string errorString(DWORD errCode);
|
||||
bool isWow64();
|
||||
std::string makeTempName(const std::string &baseName);
|
355
misc/buffer-tests/harness/WorkerProgram.cc
Normal file
355
misc/buffer-tests/harness/WorkerProgram.cc
Normal file
@ -0,0 +1,355 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "Command.h"
|
||||
#include "Event.h"
|
||||
#include "NtHandleQuery.h"
|
||||
#include "OsVersion.h"
|
||||
#include "ShmemParcel.h"
|
||||
#include "Spawn.h"
|
||||
|
||||
#include <DebugClient.h>
|
||||
|
||||
static const char *g_prefix = "";
|
||||
|
||||
static const char *successOrFail(BOOL ret) {
|
||||
return ret ? "ok" : "FAILED";
|
||||
}
|
||||
|
||||
static HANDLE openConHandle(const wchar_t *name, BOOL bInheritHandle) {
|
||||
// If sa isn't provided, the handle defaults to not-inheritable.
|
||||
SECURITY_ATTRIBUTES sa = {0};
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = bInheritHandle;
|
||||
|
||||
trace("%sOpening %ls...", g_prefix, name);
|
||||
HANDLE conout = CreateFileW(name,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
&sa,
|
||||
OPEN_EXISTING, 0, NULL);
|
||||
trace("%sOpening %ls... 0x%I64x", g_prefix, name, (int64_t)conout);
|
||||
return conout;
|
||||
}
|
||||
|
||||
static HANDLE createBuffer(BOOL bInheritHandle) {
|
||||
// If sa isn't provided, the handle defaults to not-inheritable.
|
||||
SECURITY_ATTRIBUTES sa = {0};
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = bInheritHandle;
|
||||
|
||||
trace("%sCreating a new buffer...", g_prefix);
|
||||
HANDLE conout = CreateConsoleScreenBuffer(
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
&sa,
|
||||
CONSOLE_TEXTMODE_BUFFER, NULL);
|
||||
|
||||
trace("%sCreating a new buffer... 0x%I64x", g_prefix, (int64_t)conout);
|
||||
return conout;
|
||||
}
|
||||
|
||||
static void writeTest(HANDLE conout, const char *msg) {
|
||||
char writeData[256];
|
||||
sprintf(writeData, "%s%s\n", g_prefix, msg);
|
||||
|
||||
trace("%sWriting to 0x%I64x: '%s'...",
|
||||
g_prefix, (int64_t)conout, msg);
|
||||
DWORD actual = 0;
|
||||
BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL);
|
||||
trace("%sWriting to 0x%I64x: '%s'... %s",
|
||||
g_prefix, (int64_t)conout, msg,
|
||||
successOrFail(ret && actual == strlen(writeData)));
|
||||
}
|
||||
|
||||
static void setConsoleActiveScreenBuffer(HANDLE conout) {
|
||||
trace("SetConsoleActiveScreenBuffer(0x%I64x) called...",
|
||||
(int64_t)conout);
|
||||
trace("SetConsoleActiveScreenBuffer(0x%I64x) called... %s",
|
||||
(int64_t)conout,
|
||||
successOrFail(SetConsoleActiveScreenBuffer(conout)));
|
||||
}
|
||||
|
||||
static void dumpStandardHandles() {
|
||||
trace("stdin=0x%I64x stdout=0x%I64x stderr=0x%I64x",
|
||||
(int64_t)GetStdHandle(STD_INPUT_HANDLE),
|
||||
(int64_t)GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
(int64_t)GetStdHandle(STD_ERROR_HANDLE));
|
||||
}
|
||||
|
||||
static std::vector<HANDLE> scanForConsoleHandles() {
|
||||
std::vector<HANDLE> ret;
|
||||
if (isModernConio()) {
|
||||
// As of Windows 8, console handles are real kernel handles.
|
||||
for (unsigned int i = 0x4; i <= 0x1000; i += 4) {
|
||||
HANDLE h = reinterpret_cast<HANDLE>(i);
|
||||
DWORD mode;
|
||||
if (GetConsoleMode(h, &mode)) {
|
||||
ret.push_back(h);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (unsigned int i = 0x3; i < 0x3 + 100 * 4; i += 4) {
|
||||
HANDLE h = reinterpret_cast<HANDLE>(i);
|
||||
DWORD mode;
|
||||
if (GetConsoleMode(h, &mode)) {
|
||||
ret.push_back(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dumpConsoleHandles(bool writeToEach) {
|
||||
std::string dumpLine = "";
|
||||
for (HANDLE h : scanForConsoleHandles()) {
|
||||
char buf[32];
|
||||
sprintf(buf, "0x%I64x", (int64_t)h);
|
||||
dumpLine += buf;
|
||||
dumpLine.push_back('(');
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
bool is_output = false;
|
||||
DWORD count;
|
||||
if (GetNumberOfConsoleInputEvents(h, &count)) {
|
||||
dumpLine.push_back('I');
|
||||
}
|
||||
if (GetConsoleScreenBufferInfo(h, &info)) {
|
||||
is_output = true;
|
||||
dumpLine.push_back('O');
|
||||
CHAR_INFO charInfo;
|
||||
SMALL_RECT readRegion = {};
|
||||
if (ReadConsoleOutputW(h, &charInfo, {1,1}, {0,0}, &readRegion)) {
|
||||
wchar_t ch = charInfo.Char.UnicodeChar;
|
||||
if (ch != L' ') {
|
||||
dumpLine.push_back((char)ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
DWORD flags = 0;
|
||||
if (GetHandleInformation(h, &flags)) {
|
||||
dumpLine.push_back((flags & HANDLE_FLAG_INHERIT) ? '^' : '_');
|
||||
}
|
||||
}
|
||||
dumpLine += ") ";
|
||||
if (writeToEach && is_output) {
|
||||
char msg[256];
|
||||
sprintf(msg, "%d: Writing to 0x%I64x",
|
||||
(int)GetCurrentProcessId(), (int64_t)h);
|
||||
writeTest(h, msg);
|
||||
}
|
||||
}
|
||||
trace("Valid console handles:%s", dumpLine.c_str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void handleConsoleIoCommand(Command &cmd, T func) {
|
||||
const auto sz = cmd.u.consoleIo.bufferSize;
|
||||
ASSERT(static_cast<size_t>(sz.X) * sz.Y <= cmd.u.consoleIo.buffer.size());
|
||||
cmd.success = func(cmd.handle, cmd.u.consoleIo.buffer.data(),
|
||||
cmd.u.consoleIo.bufferSize, cmd.u.consoleIo.bufferCoord,
|
||||
&cmd.u.consoleIo.ioRegion);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::string workerName = argv[1];
|
||||
|
||||
ShmemParcelTyped<Command> parcel(workerName + "-shmem", ShmemParcel::OpenExisting);
|
||||
Event startEvent(workerName + "-start");
|
||||
Event finishEvent(workerName + "-finish");
|
||||
Command &cmd = parcel.value();
|
||||
|
||||
dumpStandardHandles();
|
||||
|
||||
while (true) {
|
||||
startEvent.wait();
|
||||
startEvent.reset();
|
||||
switch (cmd.kind) {
|
||||
case Command::AllocConsole:
|
||||
trace("Calling AllocConsole...");
|
||||
cmd.success = AllocConsole();
|
||||
trace("Calling AllocConsole... %s",
|
||||
successOrFail(cmd.success));
|
||||
break;
|
||||
case Command::AttachConsole:
|
||||
trace("Calling AttachConsole(%u)...",
|
||||
(unsigned int)cmd.dword);
|
||||
cmd.success = AttachConsole(cmd.dword);
|
||||
trace("Calling AttachConsole(%u)... %s",
|
||||
(unsigned int)cmd.dword, successOrFail(cmd.success));
|
||||
break;
|
||||
case Command::Close:
|
||||
trace("closing 0x%I64x...",
|
||||
(int64_t)cmd.handle);
|
||||
cmd.success = CloseHandle(cmd.handle);
|
||||
trace("closing 0x%I64x... %s",
|
||||
(int64_t)cmd.handle, successOrFail(cmd.success));
|
||||
break;
|
||||
case Command::CloseQuietly:
|
||||
cmd.success = CloseHandle(cmd.handle);
|
||||
break;
|
||||
case Command::DumpStandardHandles:
|
||||
dumpStandardHandles();
|
||||
break;
|
||||
case Command::DumpConsoleHandles:
|
||||
dumpConsoleHandles(cmd.writeToEach);
|
||||
break;
|
||||
case Command::Duplicate: {
|
||||
HANDLE sourceHandle = cmd.handle;
|
||||
cmd.success = DuplicateHandle(
|
||||
GetCurrentProcess(),
|
||||
sourceHandle,
|
||||
cmd.targetProcess,
|
||||
&cmd.handle,
|
||||
0, cmd.bInheritHandle, DUPLICATE_SAME_ACCESS);
|
||||
if (!cmd.success) {
|
||||
cmd.handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
trace("dup 0x%I64x to pid %u... %s, 0x%I64x",
|
||||
(int64_t)sourceHandle,
|
||||
(unsigned int)GetProcessId(cmd.targetProcess),
|
||||
successOrFail(cmd.success),
|
||||
(int64_t)cmd.handle);
|
||||
break;
|
||||
}
|
||||
case Command::Exit:
|
||||
trace("exiting");
|
||||
ExitProcess(cmd.dword);
|
||||
break;
|
||||
case Command::FreeConsole:
|
||||
trace("Calling FreeConsole...");
|
||||
cmd.success = FreeConsole();
|
||||
trace("Calling FreeConsole... %s", successOrFail(cmd.success));
|
||||
break;
|
||||
case Command::GetConsoleProcessList:
|
||||
cmd.dword = GetConsoleProcessList(cmd.u.processList.data(),
|
||||
cmd.u.processList.size());
|
||||
break;
|
||||
case Command::GetConsoleScreenBufferInfo:
|
||||
cmd.u.consoleScreenBufferInfo = {};
|
||||
cmd.success = GetConsoleScreenBufferInfo(
|
||||
cmd.handle, &cmd.u.consoleScreenBufferInfo);
|
||||
break;
|
||||
case Command::GetConsoleSelectionInfo:
|
||||
cmd.u.consoleSelectionInfo = {};
|
||||
cmd.success = GetConsoleSelectionInfo(&cmd.u.consoleSelectionInfo);
|
||||
break;
|
||||
case Command::GetConsoleTitle:
|
||||
// GetConsoleTitle is buggy, so make the worker API for it very
|
||||
// explicit so we can test its bugginess.
|
||||
ASSERT(cmd.dword <= cmd.u.consoleTitle.size());
|
||||
cmd.dword = GetConsoleTitleW(cmd.u.consoleTitle.data(), cmd.dword);
|
||||
break;
|
||||
case Command::GetConsoleWindow:
|
||||
cmd.hwnd = GetConsoleWindow();
|
||||
break;
|
||||
case Command::GetHandleInformation:
|
||||
cmd.success = GetHandleInformation(cmd.handle, &cmd.dword);
|
||||
break;
|
||||
case Command::GetNumberOfConsoleInputEvents:
|
||||
cmd.success = GetNumberOfConsoleInputEvents(cmd.handle, &cmd.dword);
|
||||
break;
|
||||
case Command::GetStdin:
|
||||
cmd.handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
break;
|
||||
case Command::GetStderr:
|
||||
cmd.handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
break;
|
||||
case Command::GetStdout:
|
||||
cmd.handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
break;
|
||||
case Command::Hello:
|
||||
// NOOP for Worker startup synchronization.
|
||||
break;
|
||||
case Command::LookupKernelObject: {
|
||||
uint64_t h64;
|
||||
memcpy(&h64, &cmd.lookupKernelObject.handle, sizeof(h64));
|
||||
auto handles = queryNtHandles();
|
||||
uint64_t result =
|
||||
reinterpret_cast<uint64_t>(
|
||||
ntHandlePointer(
|
||||
handles, cmd.lookupKernelObject.pid,
|
||||
reinterpret_cast<HANDLE>(h64)));
|
||||
memcpy(&cmd.lookupKernelObject.kernelObject,
|
||||
&result, sizeof(result));
|
||||
trace("LOOKUP: p%d: 0x%I64x => 0x%I64x",
|
||||
(int)cmd.lookupKernelObject.pid,
|
||||
h64,
|
||||
result);
|
||||
break;
|
||||
}
|
||||
case Command::NewBuffer:
|
||||
cmd.handle = createBuffer(cmd.bInheritHandle);
|
||||
break;
|
||||
case Command::OpenConin:
|
||||
cmd.handle = openConHandle(L"CONIN$", cmd.bInheritHandle);
|
||||
break;
|
||||
case Command::OpenConout:
|
||||
cmd.handle = openConHandle(L"CONOUT$", cmd.bInheritHandle);
|
||||
break;
|
||||
case Command::ReadConsoleOutput:
|
||||
handleConsoleIoCommand(cmd, ReadConsoleOutputW);
|
||||
break;
|
||||
case Command::ScanForConsoleHandles: {
|
||||
auto ret = scanForConsoleHandles();
|
||||
ASSERT(ret.size() <= cmd.u.scanForConsoleHandles.table.size());
|
||||
cmd.u.scanForConsoleHandles.count = ret.size();
|
||||
std::copy(ret.begin(), ret.end(),
|
||||
cmd.u.scanForConsoleHandles.table.begin());
|
||||
break;
|
||||
}
|
||||
case Command::SetConsoleTitle: {
|
||||
auto nul = std::find(cmd.u.consoleTitle.begin(),
|
||||
cmd.u.consoleTitle.end(), L'\0');
|
||||
ASSERT(nul != cmd.u.consoleTitle.end());
|
||||
cmd.success = SetConsoleTitleW(cmd.u.consoleTitle.data());
|
||||
break;
|
||||
}
|
||||
case Command::SetHandleInformation:
|
||||
cmd.success = SetHandleInformation(
|
||||
cmd.handle, cmd.u.setFlags.mask, cmd.u.setFlags.flags);
|
||||
break;
|
||||
case Command::SetStdin:
|
||||
SetStdHandle(STD_INPUT_HANDLE, cmd.handle);
|
||||
trace("setting stdin to 0x%I64x", (int64_t)cmd.handle);
|
||||
break;
|
||||
case Command::SetStderr:
|
||||
SetStdHandle(STD_ERROR_HANDLE, cmd.handle);
|
||||
trace("setting stderr to 0x%I64x", (int64_t)cmd.handle);
|
||||
break;
|
||||
case Command::SetStdout:
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, cmd.handle);
|
||||
trace("setting stdout to 0x%I64x", (int64_t)cmd.handle);
|
||||
break;
|
||||
case Command::SetActiveBuffer:
|
||||
setConsoleActiveScreenBuffer(cmd.handle);
|
||||
break;
|
||||
case Command::SpawnChild:
|
||||
trace("Spawning child...");
|
||||
cmd.handle = spawn(cmd.u.spawn.spawnName.str(),
|
||||
cmd.u.spawn.spawnParams,
|
||||
cmd.u.spawn.spawnFailure);
|
||||
if (cmd.handle != nullptr) {
|
||||
trace("Spawning child... pid %u",
|
||||
(unsigned int)GetProcessId(cmd.handle));
|
||||
}
|
||||
break;
|
||||
case Command::System:
|
||||
cmd.dword = system(cmd.u.systemText.c_str());
|
||||
break;
|
||||
case Command::WriteConsoleOutput:
|
||||
handleConsoleIoCommand(cmd, WriteConsoleOutputW);
|
||||
break;
|
||||
case Command::WriteText:
|
||||
writeTest(cmd.handle, cmd.u.writeText.c_str());
|
||||
break;
|
||||
}
|
||||
finishEvent.set();
|
||||
}
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user