ターゲットファイルがcon
ないので、コマンドtype con > file.txt
は、CMDシェルで^Z
のための特別な処理を持っていないとtype
コマンドはUnicodeで実行されませんでした(UTF-16LE)出力モードです。この場合、^Z
処理だけがReadFile
呼び出し自体にあります。コンソール入力バッファの場合、行が^Z
で始まる場合は0バイトを返すように文書化されていません。
読み込みバイト数(lpNumberOfBytesRead
)が出力パラメータとして参照によって返される4番目の引数(x64のレジスタr9)であることに注目して、デバッガをアタッチして調べてみましょう。
C:\Temp>type con > file.txt
Breakpoint 1 hit
KERNELBASE!ReadFile:
00007ffc`fb573cc0 48895c2410 mov qword ptr [rsp+10h],rbx
ss:00000068`c5d1dfa8=000001e3000001e7
0:000> r r9
r9=00000068c5d1dfd0
0:000> pt
line1
KERNELBASE!ReadFile+0xa9:
00007ffc`fb573d69 c3 ret
0:000> dd 68c5d1dfd0 l1
00000068`c5d1dfd0 00000007
上記のように、"line1\r\n"
は7文字です。次のは"\x1aline2\r\n"
を入力して、何バイトReadFile
見てみましょうと伝え読み:
0:000> g
Breakpoint 1 hit
KERNELBASE!ReadFile:
00007ffc`fb573cc0 48895c2410 mov qword ptr [rsp+10h],rbx
ss:00000068`c5d1dfa8=0000000000000000
0:000> r r9
r9=00000068c5d1dfd0
0:000> pt
^Zline2
KERNELBASE!ReadFile+0xa9:
00007ffc`fb573d69 c3 ret
0:000> dd 68c5d1dfd0 l1
00000068`c5d1dfd0 00000000
あなたは上記を参照したように、この時間は、それはすなわちEOF、0バイトを読み取ります。 ^Z
の後に入力されたものはすべて無視されました。
ただし、入力バッファに^Z
が表示されている場合は、この動作を一般的に行うことをお勧めします。 type
がこれを行いますが、Unicodeモードで実行された場合、つまりcmd /u /c type con > file.txt
になります。この場合、cmdには^Z
の入力をスキャンする特別な処理があります。しかし、私はあなたがUTF-16LEファイルを望んでいないと思っています。特に、cmdはBOMを書いていないので、エディタがUTFエンコーディングを検出できるようになっています。
copy con file.txt
があなたの望むものとまったく同じことが起こるので、運が良かったです。内部的にはcmd!ZScanA
を呼び出して各行をスキャンして^Z
文字を探します。これをデバッガで実際に確認できますが、今回は完全に文書化されていません。調べると、この関数の3番目のパラメータ(x64のレジスタr8)は、in-out引数として読み取られたバイト数です。
のは、7文字列"line1\r\n"
入力することにより、再び始めましょう:出力で
C:\Temp>copy con file.txt
line1
Breakpoint 0 hit
cmd!ZScanA:
00007ff7`cf4c26d0 48895c2408 mov qword ptr [rsp+8],rbx
ss:00000068`c5d1e9d0=0000000000000000
0:000> r r8; dd @r8 l1
r8=00000068c5d1ea64
00000068`c5d1ea64 00000007
を、スキャンした長さは7つの文字のまま:
0:000> pt
cmd!ZScanA+0x4f:
00007ff7`cf4c271f c3 ret
0:000> dd 68c5d1ea64 l1
00000068`c5d1ea64 00000007
0:000> g
次は23(0x17の)文字列"line2\x1a Ignore this...\r\n"
を入力します。
line2^Z Ignore this...
Breakpoint 0 hit
cmd!ZScanA:
00007ff7`cf4c26d0 48895c2408 mov qword ptr [rsp+8],rbx
ss:00000068`c5d1e9d0=0000000000000000
0:000> r r8; dd @r8 l1
r8=00000068c5d1ea64
00000068`c5d1ea64 00000017
今回は、スキャンされたlen
0:000> pt
cmd!ZScanA+0x4f:
00007ff7`cf4c271f c3 ret
0:000> dd 68c5d1ea64 l1
00000068`c5d1ea64 00000005
我々はfile.txtをはそれが12バイトで、あることを期待:GTHは^Z
が先行している唯一の5つの文字である
C:\Temp>for %a in (file.txt) do @echo %~za
12
より一般的には、Windowsのコンソールプログラムの場合Unix端末の動作を近似するCtrl + D処理を実装したい場合は、ワイド文字コンソール機能ReadConsoleW
を使用して、CONSOLE_READCONSOLE_CONTROL
構造体をpInputControl
として渡すことができます。この構造体のdwCtrlWakeupMask
フィールドは、どの制御文字が読み込みを直ちに終了するかを設定するビットマスクです。たとえば、ビット4はCtrl + Dを有効にします。あなたは上記の例でこれを見ることはできませんが、この読み出しはすぐにでもEnterを押しせずに、Ctrlキー+ Dを押して終了した
C:\Temp>.\test
Enter some text: line1
You entered: line1\x04
:私はこのケースを示して簡単なテストプログラムを書きました。制御文字('\x04'
)の^D
は入力バッファに残ります。これは、複数の制御文字に対して異なる動作が必要な場合に便利です。
'copy con file.txt'も必要なように動作するはずです。 – eryksun