Thanks for the explanation, it starts to make sense to me now. But when I change the return type of the first call from "void*" to�ICUEnumerationNB I end up here:

NBExternalStructureType>>coerceReturn: gen

" ... should we support handling return of external structures? "
self error: 'returning pointer to structure?'

The problem is not so urgent for me anymore because I can work around it using just�NBExternalAddress instances. But off course I'm still curious to know what's the best way to handle these kind of native calls.

Jan.

PS: The code is in�http://www.squeaksource.com/ICU.html��ICUCalendarNB>>#nbTestAllTimeZones




On Fri, Feb 24, 2012 at 2:35 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 24 February 2012 12:10, Jan van de Sandt <jvdsandt@gmail.com> wrote:
> Hi,
>
> Well, it works if I don't use the ICUEnumeration class. The first call
> returns an NBExternalAddress instance. If I pass this instance to the second
> call than it works fine. The native call looks like this:
>
> self nbCall: #( char* uenum_next_48(void* aHandle, nil, ICUErrorCodeNB*
> anErrorCode ) )
>
> My idea was to use a subclass of�NBExternalHandle where I can put all the
> functions related to this handle. But it�stops working when I copy the value
> from the ExternalAddress to my handle subclass�ICUEnumerationNB and use one
> of these calls:
>
> self nbCall: #( char* uenum_next_48(ICUEnumerationNB* aHandle, nil,
> ICUErrorCodeNB* anErrorCode ) )
>
> or
>
> self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil,
> ICUErrorCodeNB* anErrorCode ) )
>

Since NBExternalHandle is variable byte class,
if you pass a pointer to it, like
ICUEnumerationNB* then FFI will push a pointer to the first indexable
byte in ICUEnumerationNB instance,
but not the value of handle stored in this instance.
In your case, you stored UEnumeration*, but then you pushing
UEnumeration**, while function expects UEnumeration*.

It is hard to say, why "ICUEnumerationNB aHandle" doesn't works for
you without looking at code, especially
that NBExternalAddress is a subclass of NBExternalHandle.

You can try the following:

Since both functions working with same type (UEnumeration*) , �you can
actually treat it as if you would have

typedef UEnumeration* ICUEnumerationNB;
in C.

So, then just remove '*' everywhere (in function which returns it, and
in functions where you passing it as argument):

self nbCall: #( ICUEnumerationNB ucal_openTimeZones_48(
ICUErrorCodeNB* anErrorCode ) )

and:
self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil,
ICUErrorCodeNB* anErrorCode ) )

that should work fine, unless that library doing something strange
(which also might be the case ;).

P.S. originally, i intentionally raising an error when you passing a
pointer to NBExternalAddress or Handle types
(so is allows to pass a just a value, but not a pointer to the value)
to prevent mistakes like that.
But some functions actually wanting to get a pointer to the pointer
(like int** etc), so then they can store a pointer at that pointer,
and i was added that, because it is convenient.

P.P.S Yo dawg, i put a pointer to that pointer so you can point to
what it points ;)

--
Best regards,
Igor Stasenko.