首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Perl Win32::API和指针

Perl Win32::API和指针
EN

Stack Overflow用户
提问于 2011-04-03 21:42:05
回答 2查看 1.3K关注 0票数 3

我正在尝试通过Win32的Win32::API模块来利用Perl函数DsGetSiteName()。根据Windows SDK,DsGetSiteName的函数原型是:

代码语言:javascript
复制
DWORD DsGetSiteName(LPCTSTR ComputerName, LPTSTR *SiteName)

我使用这个接口成功地编写了一个小的C++函数,以便更好地理解它的实际工作方式(我正在自学C++,但我离题了)。

无论如何,根据我对API文档的理解,第二个参数应该是一个指向变量的指针,该变量接收一个指向字符串的指针。在我的C++代码中,我将其写为:

代码语言:javascript
复制
LPSTR site;
LPTSTR *psite = &site;

并且已经使用psite指针成功地调用了API。

现在我的问题是,有没有办法使用Perl的Win32::API来做同样的事情呢?我尝试了下面的Perl代码:

代码语言:javascript
复制
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来取消对该地址的引用以获取该字符串?

提前谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-04-04 02:04:51

Win32::API不能处理char**。您需要自己提取字符串。

代码语言:javascript
复制
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链接到的代码。

票数 6
EN

Stack Overflow用户

发布于 2011-04-03 22:12:29

我认为您关于$site持有字符串地址的说法是对的。下面的代码演示了如何在Perl的Win32模块中使用输出参数:http://www.perlmonks.org/?displaytype=displaycode;node_id=890698

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5529928

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档