On 24 February 2012 15:02, Jan van de Sandt <jvdsandt@gmail.com> wrote:
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?'
This happens when you putting a pointer to struct as return value in function signature, which means that you doing something wrong, or modified code in different place. What i see (in ICU-NativeBoost-Core-jvds.3) is following : nbTestprimOpenTimeZones: anErrorCode <primitive: #primitiveNativeCall module: #NativeBoostPlugin> ^ self nbCall: #( ICUEnumerationNB___>>>>_*__<<<< remove it___ ucal_openTimeZones_48( ICUErrorCodeNB* anErrorCode ) ) and once you will do that, the error you see will go away. but i cannot call the function since i don't have the corresponding library on my machine, have binaries somewhere for download?.
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.
I takes time to get used to it. I know by myself that interfacing with C is confusing, especially when dealing with pointers.
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.
-- Best regards, Igor Stasenko.