Hi all,
I have a C struct as follows:
(defcstruct MyPrivateData (notification io_object_t) (deviceInterface :pointer) ;; void pointer (deviceName CFStringRef) (locationID UInt32))
of which the deviceInterface slot is the one I'm interested in. I need to pass the address of the deviceInterface pointer to a function that sets the pointer to valid device interface struct.
So...
In the sample code from Apple the C function is called like this:
typedef struct MyPrivateData { io_object_t notification; IOUSBDeviceInterface **deviceInterface; CFStringRef deviceName; UInt32 locationID; } MyPrivateData;
IOCFPlugInInterface **plugInInterface = NULL; SInt32 score; HRESULT res;
res = (*plugInInterface)->QueryInterface( plugInInterface, CFUUIDGetUUIDBytes( kIOUSBDeviceInterfaceID ), (LPVOID*) &privateDataRef->deviceInterface );
How would I translate this call into a valid CFFI equivalent ?
I have so far:
(let ((query-interface-ptr (foreign-slot-value plugInInterface 'IOCFPlugInInterface 'ccag.osx.iokit::QueryInterface)))
(format *debug-io* "~%DEVICE-ADDED: query-interface-ptr = ~s." query-interface-ptr)
(setq res (foreign-funcall-pointer query-interface-ptr () :pointer plugInInterface CFUUIDBytes (cf-uuid-get-uuid-bytes kIOUSBDeviceInterfaceID) :pointer (foreign-slot-pointer privateDataRef 'MyPrivateData 'deviceInterface)))
(format *debug-io* "~%DEVICE-ADDED: deviceInterface = ~s." (foreign-slot-value privateDataRef 'MyPrivateData 'deviceInterface))
...
This code "crashes" with signal 100 as reported by AllegroCL in the call to foreign-funcall-pointer ...
Any hints or advice really appreciated!
TIA!
Best wishes Frank
Hello Frank,
On Thu, Aug 25, 2011 at 6:19 PM, Frank Goenninger frgo@me.com wrote:
In the sample code from Apple the C function is called like this:
typedef struct MyPrivateData { io_object_t notification; IOUSBDeviceInterface **deviceInterface; CFStringRef deviceName; UInt32 locationID; } MyPrivateData;
Why is deviceInterface a pointer to a pointer?
IOCFPlugInInterface **plugInInterface = NULL; SInt32 score; HRESULT res;
res = (*plugInInterface)->QueryInterface( plugInInterface, CFUUIDGetUUIDBytes( kIOUSBDeviceInterfaceID ), (LPVOID*) &privateDataRef->deviceInterface );
Hello Luís,
Am 26.08.2011 um 01:20 schrieb Luís Oliveira:
Hello Frank,
On Thu, Aug 25, 2011 at 6:19 PM, Frank Goenninger frgo@me.com wrote:
In the sample code from Apple the C function is called like this:
typedef struct MyPrivateData { io_object_t notification; IOUSBDeviceInterface **deviceInterface; CFStringRef deviceName; UInt32 locationID; } MyPrivateData;
Why is deviceInterface a pointer to a pointer?
Because Apple designed the interface to calls like GetLocationID in IOKit like this:
kr = (*privateDataRef->deviceInterface)->GetLocationID(privateDataRef->deviceInterface, &locationID);
Here I need to pass the address of a pointer to IOUSBDeviceInterface struct ...
This:
IOReturn (*GetLocationID)(void *self, UInt32 *locationID);
is part of
typedef struct IOUSBDeviceStruct { ... } IOUSBDeviceInterface;
So, it's actually the address of a pointer to a IOUSBDeviceInterface struct.
I have defined this as:
(defcstruct IOUSBDeviceStruct
(_reserved :pointer) (QueryInterface :pointer) (AddRef :pointer) (Release :pointer)
;; Function Pointers
(CreateDeviceAsyncEventSource :pointer) (GetDeviceAsyncEventSource :pointer)
(CreateDeviceAsyncPort :pointer) (GetDeviceAsyncPort :pointer)
(USBDeviceOpen :pointer) (USBDeviceClose :pointer)
(GetDeviceClass :pointer) (GetDeviceSubClass :pointer) (GetDeviceProtocol :pointer) (GetDeviceVendor :pointer) (GetDeviceProduct :pointer) (GetDeviceReleaseNumber :pointer) (GetDeviceAddress :pointer) (GetDeviceBusPowerAvailable :pointer) (GetDeviceSpeed :pointer) (GetNumberOfConfigurations :pointer) (GetLocationID :pointer) (GetConfigurationDescriptionPtr :pointer) (GetConfiguration :pointer) (SetConfiguration :pointer) (GetBusFrameNumber :pointer) (ResetDevice :pointer) (DeviceRequest :pointer) (DeviceRequestAsync :pointer) (CreateInterfaceIterator :pointer))
(defctype IOUSBDeviceInterface IOUSBDeviceStruct)
So, IOKit lib allocates the memory for this struct and the pointer passed in via the pointer address is then pointing to this memory block. Or that's at least how I understood it ...
Thanks!
Frank
On Fri, Aug 26, 2011 at 10:08 AM, Frank Goenninger frgo@me.com wrote:
kr = (*privateDataRef->deviceInterface)->GetLocationID(privateDataRef->deviceInterface, &locationID);
Here I need to pass the address of a pointer to IOUSBDeviceInterface struct ...
Couldn't you call it like this?
IOUSBDeviceInterface *foo; GetLocationID(&foo, ...);
If you can, I'd try reducing your test case to allocate a pointer using WITH-FOREIGN-OBJECT and pass that to GetLocationID instead of using a struct.
Cheers,
Am 26.08.2011 um 12:52 schrieb Luís Oliveira:
On Fri, Aug 26, 2011 at 10:08 AM, Frank Goenninger frgo@me.com wrote:
kr = (*privateDataRef->deviceInterface)->GetLocationID(privateDataRef->deviceInterface, &locationID);
Here I need to pass the address of a pointer to IOUSBDeviceInterface struct ...
Couldn't you call it like this?
IOUSBDeviceInterface *foo; GetLocationID(&foo, ...);
If you can, I'd try reducing your test case to allocate a pointer using WITH-FOREIGN-OBJECT and pass that to GetLocationID instead of using a struct.
Cheers,
And how would the CFFI equivalent to
GetLocationID(&foo, ...);
look like?
I still need the address of a variable that holds a pointer (and not the struct)...
(with-foreign-object (ptr :pointer) ...
?
Cheers Frank
On Thu, 25 Aug 2011 19:19:41 +0200, Frank Goenninger said:
(setq res (foreign-funcall-pointer query-interface-ptr () :pointer plugInInterface CFUUIDBytes (cf-uuid-get-uuid-bytes kIOUSBDeviceInterfaceID) :pointer (foreign-slot-pointer privateDataRef 'MyPrivateData 'deviceInterface))) ...
This code "crashes" with signal 100 as reported by AllegroCL in the call to foreign-funcall-pointer ...
I suspect the problem is the UUID argument, not the pointer.
CFUUIDBytes is a struct type, i.e. you need to pass the aggregate by value. IIRC, CFFI doesn't support that.
__Martin
On Fri, Aug 26, 2011 at 12:13 PM, Martin Simmons martin@lispworks.com wrote:
I suspect the problem is the UUID argument, not the pointer.
CFUUIDBytes is a struct type, i.e. you need to pass the aggregate by value. IIRC, CFFI doesn't support that.
Correct. There's a work-in-progress integration of FSBV[1] into CFFI[2] that adds such support via libffi. [1] might be the most useful to Frank if he's in a hurry.
Cheers,
[1] http://repo.or.cz/w/fsbv.git [2] https://github.com/cffi/cffi/tree/fsbv
On Fri, Aug 26, 2011 at 7:41 AM, Luís Oliveira luismbo@gmail.com wrote:
On Fri, Aug 26, 2011 at 12:13 PM, Martin Simmons martin@lispworks.com wrote:
I suspect the problem is the UUID argument, not the pointer.
CFUUIDBytes is a struct type, i.e. you need to pass the aggregate by
value.
IIRC, CFFI doesn't support that.
Correct. There's a work-in-progress integration of FSBV[1] into CFFI[2] that adds such support via libffi. [1] might be the most useful to Frank if he's in a hurry.
Cheers,
[1] http://repo.or.cz/w/fsbv.git [2] https://github.com/cffi/cffi/tree/fsbv
-- Luís Oliveira http://r42.eu/~luis/
Just to emphasize, the standalone FSBV works, the integration project is very early and probably doesn't even compile. The syntax will likely change somewhat when the integration is ready. I just noticed that the repo.or.czgitweb page is giving an error so I sent an email to the admins. There's a mirror at http://common-lisp.net/gitweb?p=projects/gsll/fsbv.git;a=summary;js=1 but it seems to be lagging by one commit.
Liam
On Fri, Aug 26, 2011 at 5:19 PM, Liam Healy lnp@healy.washington.dc.us wrote:
Just to emphasize, the standalone FSBV works, the integration project is very early and probably doesn't even compile.
BTW, a random unstructured thought: it might be interesting to allow for different "backends" in the integrated FSBV, such that the structs-by-value functionality could be supported without libffi in recent Allegro versions or Lispworks.
Cheers,
Am 26.08.2011 um 18:19 schrieb Liam Healy:
On Fri, Aug 26, 2011 at 7:41 AM, Luís Oliveira luismbo@gmail.com wrote: On Fri, Aug 26, 2011 at 12:13 PM, Martin Simmons martin@lispworks.com wrote:
I suspect the problem is the UUID argument, not the pointer.
CFUUIDBytes is a struct type, i.e. you need to pass the aggregate by value. IIRC, CFFI doesn't support that.
Correct. There's a work-in-progress integration of FSBV[1] into CFFI[2] that adds such support via libffi. [1] might be the most useful to Frank if he's in a hurry.
He is. ;-) But: I need both, CFFI and FSBV. So, how to do that ?
TIA!
Best wishes -
Frank
On Wed, Sep 7, 2011 at 8:09 PM, Frank Goenninger frgo@me.com wrote:
He is. ;-) But: I need both, CFFI and FSBV. So, how to do that ?
Load FSBV and use it for the definitions where you need to pass structures by value. I.e., use FSBV:DEFCSTRUCT and FSBV:DEFCFUN where necessary. (You probably don't wan't to use it for all of your definitions since it changes the default semantics of structure types from pass-by-reference to pass-by-value.)