Dereferencing pointers in Win32 API

Ruby/Win Gurus,

I haven’t figured out how to dereference pointers passed in as arguments
to Win32 API. For example, in the following call (in C) to NetStatisticsGet
API (which may be broken on NT, but that is not the point here).

LPBYTE lpBuffer;
int ret;
ret = NetStatisticsGet (
NULL,
(char *)is_workstation ? L"LanmanWorkstation" : L"LanmanServer"),
0,
0,
&lpBuffer);

The last parameter lpBuffer is a pointer to a pointer.
The API call internally allocates memory and sets the value of the pointer
to the
variable whose pointer you have passed in. It is your responsibility to free
the
memory using NetApiBufferFree function.

When I call this in Ruby, I do the following:

···

#----------------

netStatisticsGet = Win32API.new(‘netapi32’,‘NetStatisticsGet’,‘PPNNP’,‘I’)

lpBuffer = ’ ’ * 4 # area to store the pointer value

assume that the variable ‘service’ contains “LanmanWorkstation” in Unicode

ret = netStatisticsGet.call(0,service,0,0,lpBuffer)

#-----------------

This call succeeds (because I get ret == 0) which means lpBuffer now points
to the
buffer in memory. My questions is how do I de-reference this variable in
Ruby?

TIA,
– shanko

Please unsubscribe

Shashank Date sdate@everestkc.net wrote:Ruby/Win Gurus,

I haven’t figured out how to dereference pointers passed in as arguments
to Win32 API. For example, in the following call (in C) to NetStatisticsGet
API (which may be broken on NT, but that is not the point here).

LPBYTE lpBuffer;
int ret;
ret = NetStatisticsGet (
NULL,
(char *)is_workstation ? L"LanmanWorkstation" : L"LanmanServer"),
0,
0,
&lpBuffer);

The last parameter lpBuffer is a pointer to a pointer.
The API call internally allocates memory and sets the value of the pointer
to the
variable whose pointer you have passed in. It is your responsibility to free
the
memory using NetApiBufferFree function.

When I call this in Ruby, I do the following:

···

#----------------

netStatisticsGet = Win32API.new(‘netapi32’,‘NetStatisticsGet’,‘PPNNP’,‘I’)

lpBuffer = ’ ’ * 4 # area to store the pointer value

assume that the variable ‘service’ contains “LanmanWorkstation” in Unicode

ret = netStatisticsGet.call(0,service,0,0,lpBuffer)

#-----------------

This call succeeds (because I get ret == 0) which means lpBuffer now points
to the
buffer in memory. My questions is how do I de-reference this variable in
Ruby?

TIA,
– shanko

If I’m not completely wrong, you should be able to dereference it using
lpBuffer.unpack(‘P’) where is the size of the buffer in
bytes. Just remember that unpack returns an array, the first element of
which will be the dereferenced buffer as a string.

···

On Sat, 10 Jan 2004 11:26:59 -0600, Shashank Date sdate@everestkc.net wrote:

When I call this in Ruby, I do the following:
#----------------

netStatisticsGet =
Win32API.new(‘netapi32’,‘NetStatisticsGet’,‘PPNNP’,‘I’)

lpBuffer = ’ ’ * 4 # area to store the pointer value

assume that the variable ‘service’ contains “LanmanWorkstation” in

Unicode
ret = netStatisticsGet.call(0,service,0,0,lpBuffer)

#-----------------

This call succeeds (because I get ret == 0) which means lpBuffer now
points
to the
buffer in memory. My questions is how do I de-reference this variable in
Ruby?


Dennis Ranke

Thanks for looking.

“Dennis Ranke” exoticorn@epost.de wrote in message

If I’m not completely wrong, you should be able to dereference it using
lpBuffer.unpack(‘P’) where is the size of the buffer in
bytes. Just remember that unpack returns an array, the first element of
which will be the dereferenced buffer as a string.

I tried that and i get:

C:/atest/tst_netapi32.rb:28:in `unpack’: no associated pointer
(ArgumentError)
from C:/atest/tst_netapi32.rb:28

Here is the program, and I am on Win XP (Home)
ruby 1.8.0 (2003-08-04) [i386-mswin32]:

···

#---------------------------------------------------------------------------
require “Win32API”

SERVICE_WORKSTATION = [
76,0,97,0,110,0,109,0,97,0,110,0,87,0,111,0,114,0,
107,0,115,0,116,0,97,0,116,0,105,0,111,0,110,0,0,0]

SERVICE_WORKSTATION.each{|e| print “%c” % e if e > 0}
puts

service = SERVICE_WORKSTATION.pack(“U*”) # Unicode

NetStatisticsGet = Win32API.new(‘netapi32’,‘NetStatisticsGet’,‘PPNNP’,‘I’)

bufptr = " " * 4
ret = NetStatisticsGet.call(0,service,0,0,bufptr)

if 0 != ret
puts “Failed:#{ret}”
exit
end

Here’s where I’m confused…

#packstring = “I” * 13
#packstring += “L” * 27
#struct = bufptr.unpack(packstring)

STAT_WORKSTATION_SIZE = (138) + (284)
p STAT_WORKSTATION_SIZE

struct = bufptr.unpack(“P#{STAT_WORKSTATION_SIZE}”)
p struct

END

Hi,

Thanks for looking.

“Dennis Ranke” exoticorn@epost.de wrote in message

If I’m not completely wrong, you should be able to dereference it using
lpBuffer.unpack(‘P’) where is the size of the buffer in
bytes. Just remember that unpack returns an array, the first element of
which will be the dereferenced buffer as a string.

I tried that and i get:

C:/atest/tst_netapi32.rb:28:in `unpack’: no associated pointer
(ArgumentError)
from C:/atest/tst_netapi32.rb:28

Just use memcpy.
Try this code.

require “Win32API”

SERVICE_WORKSTATION = [
76,0,97,0,110,0,109,0,97,0,110,0,87,0,111,0,114,0,
107,0,115,0,116,0,97,0,116,0,105,0,111,0,110,0,0,0]

SERVICE_WORKSTATION.each{|e| print “%c” % e if e > 0}
puts

service = SERVICE_WORKSTATION.pack(“U*”) # Unicode

NetStatisticsGet = Win32API.new(‘netapi32’,‘NetStatisticsGet’,‘PPNNP’,‘I’)

bufptr = “\0” * 4
ret = NetStatisticsGet.call(0,service,0,0,bufptr)

if 0 != ret
puts “Failed:#{ret}”
exit
end

STAT_WORKSTATION_SIZE = (138) + (284)

rbuf = “\0” * STAT_WORKSTATION_SIZE
memcpy = Win32API.new(‘msvcrt’,‘memcpy’,‘PPL’,‘P’)
memcpy.Call(rbuf,bufptr,STAT_WORKSTATION_SIZE)

struct = rbuf.unpack(“L*”)
p struct

END

Regards,

Park Heesob

You are right, after reading the relevant ruby source, it seems that you
can only dereference pointers that you have written into the string
yourself using Array#pack(‘P’). So the suggestion of Park to use memcpy
might be your best bet.

As a sidenote to matz:

Is it intentional that String#unpack(‘P’) can raise both
“no associated pointer” (when the string doesn’t have any associates)
and
“non associated pointer” (then the string does have associates, but this
pointer isn’t among them)?

···

On Sat, 10 Jan 2004 14:43:19 -0600, Shashank Date sdate@everestkc.net wrote:

If I’m not completely wrong, you should be able to dereference it using
lpBuffer.unpack(‘P’) where is the size of the buffer in
bytes. Just remember that unpack returns an array, the first element of
which will be the dereferenced buffer as a string.

I tried that and i get:

C:/atest/tst_netapi32.rb:28:in `unpack’: no associated pointer
(ArgumentError)
from C:/atest/tst_netapi32.rb:28


Dennis Ranke

This worked :

Just use memcpy.
Try this code.

require “Win32API”

SERVICE_WORKSTATION = [
76,0,97,0,110,0,109,0,97,0,110,0,87,0,111,0,114,0,
107,0,115,0,116,0,97,0,116,0,105,0,111,0,110,0,0,0]

SERVICE_WORKSTATION.each{|e| print “%c” % e if e > 0}
puts

service = SERVICE_WORKSTATION.pack(“U*”) # Unicode

NetStatisticsGet = Win32API.new(‘netapi32’,‘NetStatisticsGet’,‘PPNNP’,‘I’)

bufptr = “\0” * 4
ret = NetStatisticsGet.call(0,service,0,0,bufptr)

if 0 != ret
puts “Failed:#{ret}”
exit
end

STAT_WORKSTATION_SIZE = (138) + (284)

rbuf = “\0” * STAT_WORKSTATION_SIZE
memcpy = Win32API.new(‘msvcrt’,‘memcpy’,‘PPL’,‘P’)
memcpy.Call(rbuf,bufptr,STAT_WORKSTATION_SIZE)

struct = rbuf.unpack(“L*”)
p struct

END

Regards,

Park Heesob

Thanks, Park.
– shanko