Perl Win32 :: API和指针 [英] Perl Win32::API and Pointers

查看:143
本文介绍了Perl Win32 :: API和指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图利用Win32 API函数DsGetSiteName()使用Perl的Win32 :: API模块。根据Windows SDK,DsGetSiteName的函数原型是:

I'm trying to utilize the Win32 API function DsGetSiteName() using Perl's Win32::API module. According to the Windows SDK, the function prototype for DsGetSiteName is:

DWORD DsGetSiteName(LPCTSTR ComputerName, LPTSTR *SiteName)

我成功地使用这个API编写了一个小的C ++函数,以更好地理解它实际上是如何工作的(我'我自己学习C ++,但我离题。)

I successfully wrote a small C++ function using this API to get a better understanding of how it would actually work (I'm learning C++ on my own, but I digress).

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

Anyhow, from my understanding of the API documentation, the second parameter is supposed to be a pointer to a variable that receives a pointer to a string. In my C++ code, I wrote that as:

LPSTR site;
LPTSTR *psite = &site;

,并使用psite指针成功调用了API。

and have successfully called the API using the psite pointer.

现在我的问题是,有没有办法做同样使用Perl的Win32 :: API?我试过下面的Perl代码:

Now my question is, is there a way to do the same using Perl's Win32::API? I've tried the following Perl code:

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中的调用结果为零(表示成功),但$网站不是我想要的,它看起来是ASCII和不可打印字符的混合。

and the result of the call in $DsResult is zero (meaning success), but the data in $site is not what I want, it looks to be a mixture of ASCII and non-printable characters.

$ site变量可以保存分配的字符串的指针地址?如果是这样,有没有办法使用Win32 :: API解除引用该地址以获取字符串?

Could the $site variable be holding the pointer address of the allocated string? And if so, is there a way using Win32::API to dereference that address to get at the string?

提前感谢。

推荐答案

Win32 :: API无法处理 char ** 。您需要自己解压缩字符串。

Win32::API can't handle char**. You'll need to extract the string yourself.

use strict;
use warnings;

use Encode     qw( encode decode );
use Win32::API qw( );

use constant {
   NO_ERROR                => 0,
   ERROR_NO_SITENAME       => 1919,
   ERROR_NOT_ENOUGH_MEMORY => 8,
};


# Inefficient. Needs a C implementation.
sub decode_LPCWSTR {
   my ($ptr) = @_;

   return undef if !$ptr;

   my $sW = '';
   for (;;) {
      my $chW = unpack('P2', pack('L', $ptr));
      last if $chW eq "\0\0";
      $sW .= $chW;
      $ptr += 2;
   }

   return decode('UTF-16le', $sW);   
}


my $NetApiBufferFree = Win32::API->new('netapi32.dll', 'NetApiBufferFree', 'N', 'N')
   or die $^E;

sub NetApiBufferFree {
   my ($Buffer) = @_;
   $NetApiBufferFree->Call($Buffer);
}


my $DsGetSiteName = Win32::API->new('netapi32.dll', 'DsGetSiteNameW', 'PP', 'N')
   or die $^E;

sub DsGetSiteName {
   my ($ComputerName) = @_;

   my $packed_ComputerName = encode('UTF-16le', $ComputerName."\0");
   my $packed_SiteName_buf_ptr = pack('L', 0);

   $^E = $DsGetSiteName->Call($packed_ComputerName, $packed_SiteName_buf_ptr)
      and return;

   my $SiteName_buf_ptr = unpack('L', $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";

    print "$site_name\n";
}

除了 decode_LPCWSTR 未经测试。

我使用WIDE接口而不是ANSI接口。使用ANSI接口是不必要的限制。

I used the WIDE interface instead of the ANSI interface. Using the ANSI interface is needlessly limiting.

PS—我写了John Zwinck链接的代码。

PS — I wrote the code to which John Zwinck linked.

这篇关于Perl Win32 :: API和指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆