Trying to modify the below script to allow me to query remote machines. The first parameter to NetFileEnum needs to be a char * to the machine name. Can't seem to work out how to do that in ruby. Thanks, RC Subject: Re: win32api: how to access NetFileEnum results? From: Jos Backus <jos catnook.com> Date: Wed, 14 Jul 2004 09:28:13 +0900 References: 106163 106180 106240 106266 In-reply-to: 106266 --YiEDa0DAkWCtVeE4 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, Jul 14, 2004 at 04:57:21AM +0900, daz wrote: > Re-reading the API suggests a change of tack. > I think that memcpy isn't required. [snip] > p rbuf > #---------------------------------- > > Good or bad ? This yields 10k worth of zeroes on my screen :) I think I understand what you are trying to do (have win32api follow the pointer automagically) but I can't seem to get it to work. bufptr does have the right value in this case too, so that part works fine, but I opted to use the simpler initialization instead. So I ended up doing some memcpy's which I need anyway to access the pathname and username fields in the returned FILE_INFO_3 structs. The attached code works for me; cleanup suggestions welcomed! Thanks for your help guys. Cheers, -- Jos Backus _/ _/_/_/ Sunnyvale, CA _/ _/ _/ _/ _/_/_/ _/ _/ _/ _/ jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer' --YiEDa0DAkWCtVeE4 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="openfiles.rb" #!/usr/bin/env ruby # LMSTR = # LPBYTE* = P # DWORD = L # LPDWORD = P # PDWORD_PTR = L # NET_API_STATUS NetFileEnum( # LMSTR servername, # LMSTR basepath, # LMSTR username, # DWORD level, # LPBYTE* bufptr, # DWORD prefmaxlen, # LPDWORD entriesread, # LPDWORD totalentries, # PDWORD_PTR resume_handle #); # typedef struct _FILE_INFO_3 { # DWORD fi3_id; # DWORD fi3_permissions; # DWORD fi3_num_locks; # LMSTR fi3_pathname; # LMSTR fi3_username; # } FILE_INFO_3; require "Win32API" NetFileEnum = Win32API.new('netapi32', 'NetFileEnum', 'PPPNPNPPP','I') Memcpy = Win32API.new('msvcrt', 'memcpy', 'PPL', 'P') Pmemcpy1 = Win32API.new('msvcrt', 'memcpy', 'PLL', 'L') Pmemcpy2 = Win32API.new('msvcrt', 'memcpy', 'LPL', 'L') Wcslen = Win32API.new('msvcrt', 'wcslen', 'P', 'L') class OpenFile attr_reader :id, :permissions, :num_locks, :pathname, :username def initialize(id, permissions, num_locks, p_pathname, p_username) @id, @permissions, @num_locks = id, permissions, num_locks pathlen = Wcslen.call(p_pathname) * 2 userlen = Wcslen.call(p_username) * 2 pname = "\0" * pathlen uname = "\0" * userlen Pmemcpy1.call(pname, p_pathname, pathlen) Pmemcpy1.call(uname, p_username, userlen) @pathname = pname.delete("\0") @username = uname.delete("\0") end def inspect "File #{@pathname} opened by #{@username} (id #{@id}, #{@num_locks} lock(s))" end end MAX_PREFERRED_LENGTH = -1 FILE_INFO_3_SIZE = 20 LEVEL = 3 bufptr = "\0" * 4 entriesread = "\0" * 4 totalentries = "\0" * 4 resume_handle = "\0" * 4 ret = NetFileEnum.call(nil, nil, nil, LEVEL, bufptr, MAX_PREFERRED_LENGTH, entriesread, totalentries, resume_handle) if 0 != ret puts "Failed: #{ret}" exit end entriesread = entriesread.unpack("S")[0] totalentries = totalentries.unpack("S")[0] rbuf = "\0" * entriesread * FILE_INFO_3_SIZE # bufptr now contains a ptr to a ptr Pmemcpy1.call(rbuf, bufptr.unpack("L")[0], entriesread * FILE_INFO_3_SIZE) open_files = [] entriesread.times do |i| open_files << OpenFile.new(*rbuf[i * FILE_INFO_3_SIZE, FILE_INFO_3_SIZE].unpack("LLLLL")) end open_files.each do |file| p file end exit