これは良い質問です。戻り値が文字列であると指定すると、Win32 :: APIは値0のバイトで終了するとみなしますが、その値を持つバイトはUTF-16leのテキストで共通です。
Win32 :: APIの示唆しているように、N
タイプ(または、64ビットビルドではQ
)を使用してポインタを数値として取得し、次にポイントメモリを読んでください。 Win32 :: APIはメモリを読み取るのにReadMemory
を提供しますが、読み取るメモリの量を知る必要があります。これは、NUL終了文字列とNUL終了文字列には役に立ちません。
この後者の場合、Win32 :: APIはSafeReadWideCString
を提供しますが、返される内容が一貫していないため、代わりにdecode_LPCWSTR
を使用します。
use strict;
use warnings;
use feature qw(say state);
use open ':std', ':encoding('.do { require Win32; "cp".Win32::GetConsoleOutputCP() }.')';
use Config qw(%Config);
use Encode qw(decode encode);
use Win32::API qw(ReadMemory);
use constant PTR_SIZE => $Config{ptrsize};
use constant PTR_PACK_FORMAT =>
PTR_SIZE == 8 ? 'Q'
: PTR_SIZE == 4 ? 'L'
: die("Unrecognized ptrsize\n");
use constant PTR_WIN32API_TYPE =>
PTR_SIZE == 8 ? 'Q'
: PTR_SIZE == 4 ? 'N'
: die("Unrecognized ptrsize\n");
sub decode_LPCWSTR {
my ($ptr) = @_;
state $lstrlenW = Win32::API->new('kernel32', 'lstrlenW', PTR_WIN32API_TYPE, 'i')
or die($^E);
return undef if !$ptr;
my $num_chars = $lstrlenW->Call($ptr)
or return '';
return decode('UTF-16le', ReadMemory($ptr, $num_chars * 2));
}
# Returns true on success. Returns false and sets $^E on error.
sub LocalFree {
my ($ptr) = @_;
state $LocalFree = Win32::API->new('kernel32', 'LocalFree', PTR_WIN32API_TYPE, PTR_WIN32API_TYPE)
or die($^E);
return $LocalFree->Call($ptr) == 0;
}
sub GetCommandLine {
state $GetCommandLine = Win32::API->new('kernel32', 'GetCommandLineW', '', PTR_WIN32API_TYPE)
or die($^E);
return decode_LPCWSTR($GetCommandLine->Call());
}
# Returns a reference to an array on success. Returns undef and sets $^E on error.
sub CommandLineToArgv {
my ($cmd_line) = @_;
state $CommandLineToArgv = Win32::API->new('shell32', 'CommandLineToArgvW', 'PP', PTR_WIN32API_TYPE)
or die($^E);
my $cmd_line_encoded = encode('UTF-16le', $cmd_line."\0");
my $num_args_buf = pack('i', 0); # Allocate space for an "int".
my $arg_ptrs_ptr = $CommandLineToArgv->Call($cmd_line_encoded, $num_args_buf)
or return undef;
my $num_args = unpack('i', $num_args_buf);
my @args =
map { decode_LPCWSTR($_) }
unpack PTR_PACK_FORMAT.'*',
ReadMemory($arg_ptrs_ptr, PTR_SIZE * $num_args);
LocalFree($arg_ptrs_ptr);
return \@args;
}
{
my $cmd_line = GetCommandLine();
say $cmd_line;
my $args = CommandLineToArgv($cmd_line)
or die("CommandLineToArgv: $^E\n");
for my $arg (@$args) {
say "<$arg>";
}
}
あなたが試したもの、予想したもの、そしてあなたが得たもののコードを投稿してください。 – andlabs
@andlabs、私はその質問を理解していますが、私はOPが提供できることはそれほど多くないことを知っています。私は答えを書いている途中です。 – ikegami
は*あなたがしようとしたまさに表示され、あなたが持っていた問題を記述するためのコードを記載してください*「私は 'はUnicode :: STRING'と'エンコード:: decode'の両方を試してみました」。それは私たちがより正確な答えを書くのに役立ちます。あなたの質問の主な価値は、同様の問題の解決策を探している多くの人々にとってです。 「成功しなければ」というのは問題の声明ではなく、あなたの状況がそれと一致するかどうかを判断することは不可能です。 – Borodin