gpt4 book ai didi

perl - 处理 Win32::API 返回的宽字符值

转载 作者:行者123 更新时间:2023-12-02 04:59:25 29 4
gpt4 key购买 nike

wide char and win32::api中提供的答案适用于将 utf-16 传递给 Win API。但是如何转换 Win API 返回的 utf16 字符串呢? (我正在尝试使用GetCommandLineW)。

我尝试了 Unicode::StringEncode::decode 但没有成功。我猜想也许需要先打包或解包数据,但是如何打包或解包呢?

之后,下一个问题是如何处理像 CommandLineToArgvW 返回的指针到 utf16 的指针。

感谢您的帮助。

最佳答案

当您指定返回值是字符串时,Win32::API 假定它以值为 0 的字节终止,但具有该值的字节在 UTF-16le 文本中很常见。

正如 Win32::API 所建议的,您应该使用 N 类型(或在 64 位版本上使用 Q)来获取数字形式的指针,然后读取自己指出内存。 Win32::API 提供了ReadMemory 来读取内存,但它需要知道要读取多少内存。这对于 NUL 终止字符串和宽 NUL 终止字符串没有用。

对于以 NUL 结尾的宽字符串,Win32::API 提供了SafeReadWideCString。但 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 lstrlenW {
my ($ptr) = @_;

state $lstrlenW = Win32::API->new('kernel32', 'lstrlenW', PTR_WIN32API_TYPE, 'i')
or die($^E);

return $lstrlenW->Call($ptr);
}


sub decode_LPCWSTR {
my ($ptr) = @_;
return undef if !$ptr;

my $num_chars = lstrlenW($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>";
}
}

关于perl - 处理 Win32::API 返回的宽字符值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44488898/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com