dereferencing pointers in Win32 API

S

Shashank Date

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
 
D

Dennis Ranke

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?

If I'm not completely wrong, you should be able to dereference it using
lpBuffer.unpack('P<size>') where <size> 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.
 
S

Shashank Date

Thanks for looking.

Dennis Ranke said:
If I'm not completely wrong, you should be able to dereference it using
lpBuffer.unpack('P<size>') where <size> 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 = (13*8) + (28*4)
p STAT_WORKSTATION_SIZE

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

__END__
 
P

Park Heesob

Hi,
Thanks for looking.



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 = (13*8) + (28*4)

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
 
D

Dennis Ranke

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

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)?
 
S

Shashank Date

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 = (13*8) + (28*4)

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,141
Messages
2,570,817
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top