Skip to content

Instantly share code, notes, and snippets.

@cstrahan
Created June 8, 2011 23:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save cstrahan/1015672 to your computer and use it in GitHub Desktop.
Save cstrahan/1015672 to your computer and use it in GitHub Desktop.
Windows HLLAPI bindings in Ruby (via FFI)

HLLAPI: High Level Language Application Programming Interface

Links:

http://www.serengeti.com/literature/winhllapi.pdf

http://www.sdisw.com/tn3270/whllapi3270cs.htm

#define WHLLDESCRIPTION_LEN 127

int WinHLLAPIStartup(WORD wVersionRequired, LPWHLLAPIDATA lpData)

VOID WinHLLAPI(LPWORD lpwFunction,     /* Function name */
               LPBYTE lpbyString,      /* String pointer */
               LPWORD lpwLength,       /* String (data) length */
               LPWORD lpwReturnCode ); /* Return code */

typedef struct tagWHLLAPIDATA {
   WORD wVersion;
   char  szDescription[WHLLDESCRIPTION_LEN+1];
} WHLLAPIDATA, * PWHLLAPIDATA, FAR * LPWHLLAPIDATA;
require 'ffi'
module HLLAPI
extend FFI::Library
ffi_lib 'Whllapi.dll'
# use an explicit layout/alignment:
class WHLLAPIDATA < FFI::Struct
layout :wVersion, :uint16, 0,
:szDescription, [:uint8, 128], 2
end
attach_function :WinHLLAPIStartup, [ :int16, WHLLAPIDATA.by_ref ], :int
attach_function :WinHLLAPI, [ :pointer, :string, :pointer, :pointer ], :void
end
#########
# Example:
#########
version_required = 3
# Create a WHLLAPIDATA struct
data = HLLAPI::WHLLAPIDATA.new
data[:wVersion] = version_required
# This will pass the struct by-ref, because of the way we defined its signature
hold = HLLAPI::WinHLLAPIStartup(version_required, data)
# At some point, I'm assuming you'll want to call WinHLLAPI.
# Let's set up the arguments:
function = FFI::MemoryPointer.new(:uint16)
string = "some string goes here" # or nil to pass a NULL pointer
length = FFI::MemoryPointer.new(:uint16)
return_code = FFI::MemoryPointer.new(:uint16)
# write to the pointers as needed - I'm using 0 just as an example
function.write_uint16(0)
length.write_uint16(string.size + 1) # I'm assuming you need to account for the null char,
# which FFI automatically adds for you (assumes null-terminated ASCII)
HLLAPI::WinHLLAPI(function, string, length, return_code)
# Get the return_code, if you'd like:
ret = return_code.read_uint16
# The MemoryPointers will be released when GC'd, as MemoryPointer#autorelease? is true by default.
# ... but you can go ahead and be explicit:
[function, length, return_code].each { |ptr| ptr.free }
# Ideally, you would hide a lot of this gunk behind a friendlier API.
# I personally would tuck away the ffi stuff in HLLAPI::Native::Whllapi
# and all of the public, friendlier stuff would go in ::HLLAPI
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment