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 <[email protected]> wrote: > On 24 February 2012 12:10, Jan van de Sandt <[email protected]> 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. > >
