RE: Common FFI declarations

  • From: William Adams <william_a_adams@xxxxxxx>
  • To: <luajit@xxxxxxxxxxxxx>
  • Date: Wed, 9 May 2012 13:19:54 +0000

that's brilliant!  When I did the Kinect interface it was "by hand", and it was 
a pain.  I want to do Direct2D, and I wasn't looking forward to having to code 
up all that gunk.  Doing this declaratively makes it much easier.  Also, bonus 
if someone writes an IDL parser to generate the declarations in your style.  
Then things can come in a lot quicker. What do you do for structures?  I have a 
declarative thing that allows me to do this sort of thing: IPv6Header_Info = {
 name = "IPv6Header";
 fields = {
  {name = "version", basetype = "uint32_t", subtype="bit", repeating = 4};
  {name = "priority", basetype = "uint32_t", subtype="bit", repeating = 4};
  {name = "flowlabel", basetype = "uint32_t", subtype="bit", repeating = 24};
  {name = "payloadlength", basetype = "uint16_t"};
  {name = "nextheader", basetype = "uint8_t"};
  {name = "hoplimit", basetype = "uint8_t"};
  {name = "source", basetype = "uint8_t", repeating = 16};
  {name = "destination", basetype = "uint8_t", repeating = 16};
 };
};
It this makes is possible to do this: header = IPv6Header(buffer, bufferlen) 
header:get_version()header:get_nextheader()header:set_destination(destbytes) 
Through the cleverness of code, these 'set_' and 'get_' can be turned into 
regular table field accessors as well. I think what you have is a nice meta 
description of an object interface.  If it also has definitions for layout, 
then I think it represents a complete meta definition for many different uses, 
besides just COM interop.  For example, if I'm going to parse CLR definitions, 
I would also represent them in this form, or close to it, and then auto 
generate CLR interop calls. -- William
===============================

- Shaping clay is easier than digging it out of the ground.


http://blog.nanotechstyles.com
http://www.thingiverse.com/WilliamAAdams
https://github.com/Wiladams
 

 > From: duncan.cross@xxxxxxxxx
> Date: Wed, 9 May 2012 12:08:44 +0100
> Subject: Re: Common FFI declarations
> To: luajit@xxxxxxxxxxxxx
> 
> On Wed, May 9, 2012 at 2:44 AM, William Adams <william_a_adams@xxxxxxx> wrote:
> > Do you intend to tackle COM interop in any way?
> 
> I have been working on my own little system for handling COM. For
> example, declaring the interfaces for Windows 7's API for adding an
> animated progress bar to a window's task bar icon:
> 
>   --
>   local com = require 'extern.windows.com'
>   com.def {
>     {"ITaskbarList";
>       methods = {
>         {'HrInit'};
>         {'AddTab', 'void* hwnd'};
>         {'DeleteTab', 'void* hwnd'};
>         {'ActivateTab', 'void* hwnd'};
>         {'SetActiveAlt', 'void* hwnd'};
>       };
>       iid = '56FDF344-FD6D-11d0-958A006097C9A090';
>     };
>     {"ITaskbarList2", inherits='ITaskbarList';
>       methods = {
>         {'MarkFullscreenWindow', 'void* hwnd, bool32'};
>       };
>       iid = '602D4995-B13A-429b-A66E1935E44F4317';
>     };
>     {"ITaskbarList3", inherits='ITaskbarList2';
>       methods = {
>         {'SetProgressValue', 'void* hwnd, uint64_t done, uint64_t total'};
>         {'SetProgressState', 'void* hwnd, uint32_t tbpfFlags'};
>         {'RegisterTab', 'void* hwndTab, void* hwndMDI'};
>         {'UnregisterTab', 'void* hwndTab'};
>         {'SetTabOrder', 'void* hwndTab, void* hwndInsertBefore'};
>         {'SetTabActive', 'void* hwndTab, void* hwndMDI, uint32_t tbatFlags'};
>         {'ThumbBarAddButtons', 'void* hwnd, uint32_t buttons, void* button'};
>         {'ThumbBarUpdateButtons', 'void* hwnd, uint32_t buttons, void* 
> button'};
>         {'ThumbBarSetImageList', 'void* hwnd, void* himagelist'};
>         {'SetOverlayIcon', [[void* hwnd, void* hicon,
>           const wchar_t* description]]};
>         {'SetThumbnailTooltip', 'void* hwnd, const wchar_t* toolTip'};
>         {'SetThumbnailClip', 'void* hwnd, RECT* clip'};
>       };
>       iid = 'EA1AFB91-9E28-4B86-90E99E9F8A5EEFAF';
>     };
>   }
>   --
> 
> ...does the equivalent to this:
> 
>   --
>   ffi.cdef [[
>     typedef struct ITaskbarList {
>       struct {
>         int32_t (__stdcall *QueryInterface)(ITaskbarList* self, GUID* guid,
>           void** out_interface);
>         uint32_t (__stdcall *AddRef)(ITaskbarList* self);
>         uint32_t (__stdcall *Release)(ITaskbarList* self);
>         int32_t (__stdcall *HrInit)(ITaskbarList* self);
>         int32_t (__stdcall *AddTab)(ITaskbarList* self, void* hwnd);
>         int32_t (__stdcall *DeleteTab)(ITaskbarList* self, void* hwnd);
>         int32_t (__stdcall *ActivateTab)(ITaskbarList* self, void* hwnd);
>         int32_t (__stdcall *SetActiveAlt)(ITaskbarList* self, void* hwnd);
>       } *lpVtbl;
>     } ITaskbarList;
>     typedef struct ITaskbarList2 {
>       struct {
>         int32_t (__stdcall *QueryInterface)(ITaskbarList2* self, GUID* guid,
>           void** out_interface);
>         uint32_t (__stdcall *AddRef)(ITaskbarList2* self);
>         uint32_t (__stdcall *Release)(ITaskbarList2* self);
>         int32_t (__stdcall *HrInit)(ITaskbarList2* self);
>         int32_t (__stdcall *AddTab)(ITaskbarList2* self, void* hwnd);
>         int32_t (__stdcall *DeleteTab)(ITaskbarList2* self, void* hwnd);
>         int32_t (__stdcall *ActivateTab)(ITaskbarList2* self, void* hwnd);
>         int32_t (__stdcall *SetActiveAlt)(ITaskbarList2* self, void* hwnd);
>         int32_t (__stdcall *MarkFullscreenWindow)(ITaskbarList2* self,
> void* hwnd, bool32);
>       } *lpVtbl;
>     } ITaskbarList2;
>     typedef struct ITaskbarList3 {
>       struct {
>         int32_t (__stdcall *QueryInterface)(ITaskbarList3* self, GUID* guid,
>           void** out_interface);
>         uint32_t (__stdcall *AddRef)(ITaskbarList3* self);
>         uint32_t (__stdcall *Release)(ITaskbarList3* self);
>         int32_t (__stdcall *HrInit)(ITaskbarList3* self);
>         int32_t (__stdcall *AddTab)(ITaskbarList3* self, void* hwnd);
>         int32_t (__stdcall *DeleteTab)(ITaskbarList3* self, void* hwnd);
>         int32_t (__stdcall *ActivateTab)(ITaskbarList3* self, void* hwnd);
>         int32_t (__stdcall *SetActiveAlt)(ITaskbarList3* self, void* hwnd);
>         int32_t (__stdcall *MarkFullscreenWindow)(ITaskbarList3* self,
>           void* hwnd, bool32);
>         int32_t (__stdcall *SetProgressValue)(ITaskbarList3* self, void* hwnd,
>           uint64_t done, uint64_t total);
>         int32_t (__stdcall *SetProgressState)(ITaskbarList3* self, void* hwnd,
>           uint32_t tbpfFlags);
>         int32_t (__stdcall *RegisterTab)(ITaskbarList3* self, void* hwndTab,
>           void* hwndMDI);
>         int32_t (__stdcall *UnregisterTab)(ITaskbarList3* self, void* 
> hwndTab);
>         int32_t (__stdcall *SetTabOrder)(ITaskbarList3* self, void* hwndTab,
>           void* hwndInsertBefore);
>         int32_t (__stdcall *SetTabActive)(ITaskbarList3* self, void* hwndTab,
>           void* hwndMDI, uint32_t tbatFlags);
>         int32_t (__stdcall *ThumbBarAddButtons)(ITaskbarList3* self, void* 
> hwnd,
>           uint32_t buttons, void* button);
>         int32_t (__stdcall *ThumbBarUpdateButtons)(ITaskbarList3* self,
>           void* hwnd, uint32_t buttons, void* button);
>         int32_t (__stdcall *ThumbBarSetImageList)(ITaskbarList3* self,
>           void* hwnd, void* himagelist);
>         int32_t (__stdcall *SetOverlayIcon)(ITaskbarList3* self, void* hwnd,
>           void* hicon, const wchar_t* description);
>         int32_t (__stdcall *SetThumbnailTooltip)(ITaskbarList3* self,
> void* hwnd,
>           const wchar_t* toolTip);
>         int32_t (__stdcall *SetThumbnailClip)(ITaskbarList3* self, void* hwnd,
>           RECT* clip);
>       } *lpVtbl;
>     } ITaskbarList3;
>   ]]
>   ffi.metatype('ITaskbarList', {
>     __index = function(self, k)
>       return self.lpVtbl[k]
>     end;
>   })
>   ffi.metatype('ITaskbarList2', {
>     __index = function(self, k)
>       return self.lpVtbl[k]
>     end;
>   })
>   ffi.metatype('ITaskbarList3', {
>     __index = function(self, k)
>       return self.lpVtbl[k]
>     end;
>   })
>   --
> 
> Additional things:
> - com.iidof('ITaskbarList') returns a GUID struct containing the defined IID
> - com.gc(interface) sets the interface's own Release method as its
> __gc metamethod
> - com.release(interface) removes the interface's __gc metamethod and
> calls :Release() directly
> - com.cast('IOtherInterface', interface) finds the defined IID of
> IOtherInterface and uses the QueryInterface method to attempt to cast
> it
> - com.new(clsid, 'IInterfaceName') attempts to call CoCreateInstance()
> to instantiate a new object of this type. IAt the moment it only
> supports in-proc server because that's all I've been interested in
> myself so far, so this is a limitation of the system as-is.)
> - If any method names start with get_ or set_, these are assumed to be
> property getters and setters intended for JavaScript use, and custom
> __index and __newindex metamethods are provided to handle this
> - Interfaces inherit IUnknown unless specified, methods return int
> (HRESULT) unless specified (with ret="OtherType";)
> - Interface structs are predefined so that interfaces in the same
> com.def() block can all reference each other
> 
> I'm happy to share this if people are interested.
> 
> (I know it is not everyone's goal, but in my own FFI bindings I try to
> demystify these APIs so the bindings are as short and consistent as
> possible, rather than do the minimal necessary to just import the
> standard headers.)
> 
> -Duncan
> 
                                          

Other related posts: