Apple documents the structures used for Block functions here.
Basically, one creates two structures and can then pass the one’s address to an ObjC function that takes a Block parameter. Here’s the gist of the Xojo code for that:
[code]structure Block
isa_ as Ptr
flags As Integer
reserved As Integer
invoke As Ptr
descriptor As Ptr
user_id as Integer
user_data as Ptr
end
static blockCallback as Ptr = CType (AddressOf theCallbackMethod, Ptr)
static gBlockDesc as new MemoryBlock (16)
gBlockDesc.Int32Value (4) = Block.Size
declare function dlsym lib “System” (hdl as Integer, symbol as CString) as Ptr
static isaPtr as Ptr = dlsym (-2, “_NSConcreteGlobalBlock”)
Now, while this works in 32 bit builds, I cannot get it working in 64 bit. The Block structure should be working just fine in 64 bit, and I changed the gBlockDesc code to:
static gBlockDesc as new MemoryBlock (32)
gBlockDesc.Int64Value (8) = Block.Size
Yet, this always crashes when I invoke the block.
Has anyone figured this out and gotten Blocks to work this way in 64 bit builds, i.e. without using a Plugin?
Doesn’t the declare require a consistent set of arguments?
By that I mean… it requires either 32bit all the time, or 64bit all the time…
and if it worked as a 32bit compile then INTEGER was a 32bit value, but in a 64bit compile its a 64bit value
What if you used UINT32 or INT32? to force it to use 32bit values
@Dave The structs in C are using “int” for the types, and the equivalent in Xojo is Integer. Also, the constistency in the Mac APIs is in the source, not in the binary form. So, if a C header says “int”, that means 32 bit values in 32 bit builds, and 64 bit values in 64 bit builds.
Although, what puzzles me, now that you’re pointing that out, is that the first struct uses “int” whereas the other uses “long int”…
For those who want to poke at the code, I’ve made a simple demo project:
[quote=402921:@Thomas Tempelmann]“int” does translate to “Int32” in Xojo.
“long” does translate to “Integer” in Xojo.[/quote]
This is something that has puzzled me for just a short time ago too. The C definitions are sometimes really a bit unclear (at least for me), stating that long is “at least 32 Bits long” while longlong is 64 Bits
A tip for you, make sure that the blocks you’re testing with come back in on the main thread (like a NSSavePanel), many of them come back in on a different thread and this causes a StackOverFlowException. IAP & AVFoundation are the two frameworks off the top of my head which do this.
I have a feedback request for this, but I don’t have feedback on this computer.
What Sam means is that the callback function would do this, if it could be called in a thread:
[code]Private Shared Sub taskCompletionUnsafeThread(ByRef blk as Block, error_ref as Ptr) #pragma StackOverflowChecking false
declare sub dispatch_sync_f lib SysLib (q as Ptr, ByRef context as Block, f as Ptr)
declare function dispatch_get_current_queue lib SysLib () as Ptr
declare sub retain lib CocoaLib selector “retain” (id as Ptr)
declare sub release lib CocoaLib selector “release” (id as Ptr)
blk.user_data = error_ref
if gMainQueue = dispatch_get_current_queue() then
// we’re on the main thread - must not call dispatch_sync to avoid deadlock
taskCompletionOnMainThread (blk)
else
// we’re doing a sync call so that any objects remain retained until they’re handled by the callback on the main thread
dispatch_sync_f (gMainQueue, blk, gCompletionHandler)
end if
End Sub[/code]
Some globals would need setting up before:
declare function dispatch_get_current_queue lib SysLib () as Ptr
gMainQueue = dispatch_get_current_queue()
gCompletionHandler = CType (AddressOf taskCompletionOnMainThread, Ptr)
taskCompletionOnMainThread is the final callback function that would get invoked safely.
I’ll update my sample code accordingly for the sake of others who might need this.
Yes. As long as you create a structure for each different type of block, and know how to deal with the callback in case it’s called asynchronously (i.e. from a different thread) - which is discussed here, for instance.