我正在尝试通过Win32的Win32::API模块来利用Perl函数DsGetSiteName()。根据Windows SDK,DsGetSiteName的函数原型是:
DWORD DsGetSiteName(LPCTSTR ComputerName, LPTSTR *SiteName)我使用这个接口成功地编写了一个小的C++函数,以便更好地理解它的实际工作方式(我正在自学C++,但我离题了)。
无论如何,根据我对API文档的理解,第二个参数应该是一个指向变量的指针,该变量接收一个指向字符串的指针。在我的C++代码中,我将其写为:
LPSTR site;
LPTSTR *psite = &site;并且已经使用psite指针成功地调用了API。
现在我的问题是,有没有办法使用Perl的Win32::API来做同样的事情呢?我尝试了下面的Perl代码:
my $site = " " x 256;
my $computer = "devwin7";
my $DsFunc = Win32::API->new("netapi32","DWORD DsGetSiteNameA(LPCTSTR computer, LPTSTR site)");
my $DsResult = $DsFunc->Call($computer, $site);
print $site;在$DsResult中调用的结果是0(表示成功),但是$site中的数据不是我想要的,它看起来是ASCII码和不可打印字符的混合。
$site变量可能保存已分配字符串的指针地址吗?如果是这样的话,有没有办法使用Win32::API来取消对该地址的引用以获取该字符串?
提前谢谢。
发布于 2011-04-04 02:04:51
Win32::API不能处理char**。您需要自己提取字符串。
use strict;
use warnings;
use feature qw( say state );
use Encode qw( encode decode );
use Win32::API qw( );
use constant {
NO_ERROR => 0,
ERROR_NO_SITENAME => 1919,
ERROR_NOT_ENOUGH_MEMORY => 8,
};
use constant PTR_SIZE => $Config{ptrsize};
use constant PTR_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");
# Inefficient. Needs a C implementation.
sub decode_LPCWSTR {
my ($ptr) = @_;
return undef if !$ptr;
my $sW = '';
for (;;) {
my $chW = unpack('P2', pack(PTR_FORMAT, $ptr));
last if $chW eq "\0\0";
$sW .= $chW;
$ptr += 2;
}
return decode('UTF-16le', $sW);
}
sub NetApiBufferFree {
my ($Buffer) = @_;
state $NetApiBufferFree = Win32::API->new('netapi32.dll', 'NetApiBufferFree', PTR_WIN32API_TYPE, 'N')
or die($^E);
$NetApiBufferFree->Call($Buffer);
}
sub DsGetSiteName {
my ($ComputerName) = @_;
state $DsGetSiteName = Win32::API->new('netapi32.dll', 'DsGetSiteNameW', 'PP', 'N')
or die($^E);
my $packed_ComputerName = encode('UTF-16le', $ComputerName."\0");
my $packed_SiteName_buf_ptr = pack(PTR_FORMAT, 0);
$^E = $DsGetSiteName->Call($packed_ComputerName, $packed_SiteName_buf_ptr)
and return undef;
my $SiteName_buf_ptr = unpack(PTR_FORMAT, $packed_SiteName_buf_ptr);
my $SiteName = decode_LPCWSTR($SiteName_buf_ptr);
NetApiBufferFree($SiteName_buf_ptr);
return $SiteName;
}
{
my $computer_name = 'devwin7';
my ($site_name) = DsGetSiteName($computer_name)
or die("DsGetSiteName: $^E\n");
say $site_name;
}除了decode_LPCWSTR之外,其他都是未经测试的。
我使用宽接口而不是ANSI接口。使用ANSI接口是不必要的限制。
PS -我写了John Zwinck链接到的代码。
发布于 2011-04-03 22:12:29
我认为您关于$site持有字符串地址的说法是对的。下面的代码演示了如何在Perl的Win32模块中使用输出参数:http://www.perlmonks.org/?displaytype=displaycode;node_id=890698
https://stackoverflow.com/questions/5529928
复制相似问题