[Openmcl-devel] Handle/Pointer-to-Pointer FFI Question

Brent Fulgham bfulg at pacbell.net
Fri Dec 29 05:17:27 UTC 2006

Thanks, Gary.  As usual, this solved the problem.

Thanks also for the _CFURLCreateWithFileSystemPath stuff made it  
possible to use normal Unix pathing, which was a huge help for  
loading the textures.



On Dec 28, 2006, at 5:59 PM, Gary Byers wrote:

> A handle (in the Classic MacOS memory manager) is basically a pointer
> to a pointer.  If H is a handle, then:
> (rlet ((p (%get-ptr h)))
>   ;; "p" probably points to something interesting ...
>  )
> It wasn't always that simple: the address obtained by indirecting
> through a handle could change over time (though the "master pointer" -
> the handle itself - remained at a constant address).  It was possible
> to lock and unlock a handle (via #_HLock/#_HUnLock; I hope that I'm
> capitalizing those names correctly) to keep things from moving while
> you were accessing.
> Some handles denoted the in-core contents of "resources", which
> were loaded from files.  When memory got really tight, resource-based
> handles could be "purged" from memory, so dereferencing such a handle
> without first un-purging it (I forget how ...) yielded a null pointer.
> Having purgeable/relocatable blocks of memory helped early Mac
> applications to run in small address spaces, but didn't scale
> particularly well.  The only reasons that I can think of for
> handles to continue to exist involve backward-compatibility; #_HLock
> and #_HUnLock are no-ops on OSX, and a "handle" is just something
> that involves an extra level of indirection for no obvious reason.
> If a function returns a handle by reference, that means that the
> caller reserves space for a handle somewhere and passes a pointer
> to that space to that function.  RLET ((<var> <type>)) reserves some
> space for (generally uninitialized) instance of <type>, and binds
> <var> to a pointer to that reserved space.  So:
> (rlet (....
>        (&ImageDescriptor :<I>mage<D>escription))
> allocates an (uninitialized) ImageDescription handle and binds
> &ImageDescriptor to a pointer to that 4 or 8 bytes of garbage.
> (If we were to do (PREF &ImageDescriptor :<I>mage<D>escription)
> at this point, we'd get some random bits instead of a real handle;
> if we'd said RLETZ instead of RLET, those bits would be 0.)
> If we then do :
>     (let ((err (#_GraphicsImportGetImageDescription &gi  
> &ImageDescriptor)))
>         (unless (= err #$noErr)
>             (error "GraphicsImportGetImageDescription ~a" err)))
> and don't get an error, we'd be able to say:
>   (let* ((descriptor-handle (PREF  
> &ImageDescriptor :<I>mage<D>escription)))
> and the value accessed by PREF should be a "real" handle.
>     (let* ((descriptor-pointer (%get-ptr descriptor-handle)))
> If we cared about Classic MacOS compatibility, we would have locked
> the handle before dereferencing it.
>  (let ((Width (pref descriptor-pointer :<I>mage<D>escription.width))
>        (Height (pref descriptor-pointer :<I>mage<D>escription.height))
>        (Depth (pref descriptor-pointer :<I>mage<D>escription.depth))
> should give meaningful values.
> The documentation for #_GraphicsImportGetImageDescription should
> probably tell you whether or not it's necessary to dispose of the
> handle when you're done with it.  Disposing of the handle will
> make the memory that it (indirecly) pointed to free as well as
> freeing the handle itself.
> On Thu, 28 Dec 2006, Brent Fulgham wrote:
>> I'm attempting to call a QuickTime API function, which expects to  
>> be passed a
>> First call is to a function to get the graphics importer.
>> OSErr GetGraphicsImporterForFile (
>>   const FSSpec         *theFile,
>>   ComponentInstance    *gi );
>> This call is done in Lisp as:
>> (rlet ((&gi :<G>raphics<I>mport<C>omponent)
>>        (Fsspec :<FSS>pec)
>>        (Fsref    :<FSR>ef)
>>        (&ImageDescriptor :<I>mage<D>escription)
>> ... Get a FSRef from a CURL-based path (per Gary's earlier  
>> instructions)....
>>      (let ((err (#_GetGraphicsImporterForFile Fsspec &gi)))
>>         (unless (= err #$noErr)
>>                 (error "GetGraphicsImporterForFile ~a" err)))
>> This works great, returns no error, and produces a &gi value that  
>> can be used further in the routine.
>> Later (with the enclosing rlet above) I wish to get the graphics  
>> description of my image file, using the API call:
>> ComponentResult GraphicsImportGetImageDescription (
>>   GraphicsImportComponent    ci,
>>   ImageDescriptionHandle     *desc );
>> In this case, the component instance is supposed to be the actual  
>> GraphicsImportComponent object
>> (whereas the earlier call used a pointer to a  
>> <C>omponent<I>nstance).  The FFI seems to handle this
>> properly, or at least returns a <G>raphics<I>mport<C>omponent  
>> object that I can pass to the above
>> function without API complaints.
>> However, I wish to get an <I>mage<D>escription from the  
>> ImageDescriptionHandle*, which is effectively
>> a "ImageDescriptionHandle**".
>> This looks like the following (still inside the above rlet, so the  
>> stuff is in scope):
>>    (let ((err (#_GraphicsImportGetImageDescription &gi  
>> &ImageDescriptor)))
>>        (unless (= err #$noErr)
>>            (error "GraphicsImportGetImageDescription ~a" err)))
>> This seems to work, but produces incorrect results.  If I attempt  
>> to extract values from the ImageDescriptor:
>> (let ((Width (rref &ImageDescriptor :<I>mage<D>escription.width))
>>       (Height (rref &ImageDescriptor :<I>mage<D>escription.height))
>>       (Depth (rref &ImageDescriptor :<I>mage<D>escription.depth))
>> ...
>> I get very strange values.
>> I think my problem has to do with the pointer-to-pointer  
>> dereferencing, but I'm not sure how to express this using the  
>> OpenMCL FFI.
>> I could do something like:
>>  (let ((id-ptr (%get-ptr &ImageDescriptor)))
>>    (let ((err (#_GraphicsImportGetImageDescription &gi id-ptr)))
>>        (unless (= err #$noErr)
>>            (error "GraphicsImportGetImageDescription ~a" err)))
>> ... But trying this also gives me weird values.
>> Can anyone help me figure out how to pass these FFI values?
>> Thanks,
>> -Brent

More information about the Openmcl-devel mailing list