How to pack/unpack nested structures?

I am accessing the Win32 API from Ruby, and am having trouble dealing with
structures that nest structures. How should I pack/unpack these objects?
Ruby/DL looks like it would give me a hand but I'm not sure how to use it.

Here is an example of what I'm doing. I'm calling a function,
InitializeSecurityContext, which as one of its arguments takes a pointer to
a SecBufferDesc structure. This structure contains a pointer to a SecBuffer
structure. The structures look mostly like this:

struct SecBufferDesc {
  long version;
  long numBuffers;
  SecurityBuffer * buffers;
}

struct SecurityBuffer {
  long bufferSize;
  long bufferType;
  void * buffer;
}

I am unclear on how to pack a string to contain such a structure. This sort
of works, but I am unable to access the inner structure:

  version = 1
  numBuffers = 1

  bufferSize = 100
  bufferType = 2
  buffer = "\0" * bufferSize

  struct = [version, numBuffers, [bufferSize, bufferType,
buffer].pack("LLP")].pack("LLP")

After calling the method with 'struct', I can unpack the outer structure

  struct.unpack("LLP12") # gives SecBufferDesc structure

But when I try to access the inner SecBuffer structure, I get an errror:

  secBuffPtr = struct.unpack("LLP12")[2]
  secBuffPtr.unpack("LLP12") # gives 'no associated pointer' error

What's interesting is the packing process seems to work, because the
function called correctly writes to the structures in memory. However, I
cannot then unpack the string to get access to the structures!

How can I pack the structure correctly to get to the inner structure? Thanks
for any help in advance!

Justin

p.s. Here is a short file that demonstrates the problem, without any need
for API calls:

version = 1
count = 1

size = 100
type = 2
buffer = "\0" * size

struct = [version, count, [size, type, buffer].pack("LLP")].pack("LLP")

outerStruct = struct.unpack("LLP12")
puts "structure is: #{outerStruct.inspect}"

begin
  innerStruct = outerStruct[2].unpack("LLP12")
  puts "innerStruct is #{innerStruct.inspect}"
rescue ArgumentError
  puts "unable to unpack inner structure"
end

Hi,

At Thu, 13 Jul 2006 00:31:37 +0900,
Justin Bailey wrote in [ruby-talk:201532]:

  version = 1
  numBuffers = 1

  bufferSize = 100
  bufferType = 2
  buffer = "\0" * bufferSize

I guess this buffer is the answer, unless the function returns
another pointer.

  struct = [version, numBuffers, [bufferSize, bufferType,
buffer].pack("LLP")].pack("LLP")

or:

  nested_struct = [bufferSize, bufferType, buffer].pack("LLP")
  struct = [version, numBuffers, inner_struct].pack("LLP")

  nested_struct.unpack("LLP12")

If the function alters buffer of struct SecurityBuffer, says it
allocates new buffer and returns it, unpack can't deal with it.
You need DL instead.

···

--
Nobu Nakada

Would you mind demonstrating how I can use DL to do it? I'd love to use that
library but I wasn't able to figure it out ... Thanks for your time and
attention!

Justin

···

On 7/14/06, nobu@ruby-lang.org <nobu@ruby-lang.org> wrote:

  nested_struct = [bufferSize, bufferType, buffer].pack("LLP")
  struct = [version, numBuffers, inner_struct].pack("LLP")

  nested_struct.unpack("LLP12")

If the function alters buffer of struct SecurityBuffer, says it
allocates new buffer and returns it, unpack can't deal with it.
You need DL instead.