Need help with iOS objc_msgSend_stret declare/call

I’m trying to use objc_msgSend_stret in an iOS app to call a method returning a struct but I can’t get the setup right.

Structure, Name = CGPoint32
x as single
y as single
EndStructure

Protected Function getLocationInView(objPtr as Ptr, viewPtr as Ptr) As xojo.Core.Point
// assume objPtr and viewPtr are non-nil, valid, and objPtr responds to “locationInView:”
// 64-bit support using CGPoint64 edited out for clarity

// this declare works on 2014 R3.2 but crashes on 2015 R1
// (probably bug #38291 - Objective-C declares are miscompiled on 32-bit iOS for some structure return types)
// Declare Function getLocationInView lib "UIKit.Framework" selector "locationInView:" (objRef As Ptr, viewPtr as Ptr) As CoreGraphics.CGPoint32
// Dim cgp1 as CoreGraphics.CGPoint32 = getLocationInView(objPtr, viewPtr)

// per Joe Ranieri - workaround is to call directly with objc_msgSend_stret

Dim locInViewSelector as ptr = Foundation.NSSelectorFromString("locationInView:")
// locInViewSelector is now a non-nil value

Declare Sub objc_msgSend_stret lib "Foundation.Framework" selector "objc_msgSend_stret" (ByRef theStruct32Ptr as CoreGraphics.CGPoint32, objPtr as Ptr, selectorRef as Ptr, viewPtr as Ptr )

dim cgp2 as CoreGraphics.CGPoint32 
objc_msgSend_stret( cgp2, objPtr, locInViewSelector, viewPtr )
// app crashes before returning in both 2014 R3.2 and 2015 R1 so I'm doing something wrong
// "backboardd[24424] <Warning>: Application 'UIKitApplication:com.stephenbeardslee.exampleone_2014_R32[0xf1e2]' 
// "exited abnormally with signal 11: Segmentation fault: 11"
// which is normally a too many releases warning 

I’m guessing the declare is setup wrong with either the selectorPtr or the pointer to the structure being incorrect but I’m stuck.

Any help would be very much appreciated.

Yeah, you’re declare is not quite right. The lib should be:

"/usr/lib/libobjc.A.dylib"

And you don’t need the selector keyword because it is a flat c function and not an objective c selector. I’m sorry I can’t write up the correct declare since I’m on my phone, but hopefully this points you in be right direction.

Thanks @Jason King I’ll take another pass at it when I get time tonight.

objc_msgSend_stret is a C function not an Objective C message, so the declare would be:

Const ObjRuntime = "/usr/lib/libobjc.A.dylib" Declare Function objc_msgSend_stret Lib ObjRuntime (id As Ptr, SEL As Ptr, view As Ptr) As Ptr Dim p As Ptr = objc_msgSend_stret(objPtr, viewPt) Dim point As CGPoint32 = p.CGPoint32

[quote=174998:@Eli Ott]objc_msgSend_stret is a C function not an Objective C message, so the declare would be:

Const ObjRuntime = "/usr/lib/libobjc.A.dylib" Declare Function objc_msgSend_stret Lib ObjRuntime (id As Ptr, SEL As Ptr, view As Ptr) As Ptr Dim p As Ptr = objc_msgSend_stret(objPtr, viewPt) Dim point As CGPoint32 = p.CGPoint32 [/quote]

objc_msgSend_stret takes the address of a local structure variable as its first argument and does not return a value.

Thanks @Joe Ranieri, more like this?

Declare Sub objc_msgSend_stret Lib “/usr/lib/libobjc.A.dylib” (ByRef resultPtr as CGPoint32, objPtr As Ptr, selPtr As Ptr, viewPtr As Ptr)

Dim cgp32 as CGPoint32
Dim selPtr as Ptr = Foundation.NSSelectorFromString(“locationInView:”)

objc_msgSend_stret( cgp32, objPtr, selPtr, viewPtr )

[quote=175010:@Stephen J. Beardslee]Thanks @Joe Ranieri, more like this?

Declare Sub objc_msgSend_stret Lib “/usr/lib/libobjc.A.dylib” (ByRef resultPtr as CGPoint32, objPtr As Ptr, selPtr As Ptr, viewPtr As Ptr)

Dim cgp32 as CGPoint32
Dim selPtr as Ptr = Foundation.NSSelectorFromString(“locationInView:”)

objc_msgSend_stret( cgp32, objPtr, selPtr, viewPtr )[/quote]

That looks more or less correct.

Thanks for the hints, I’ll try working through a simpler case to see what my problem is.

Sorry, made a mistake, what I meant was, that since a CGPoint32 fits as return value (when C sizeof returns 1, 2, 4 or 8) it should work, but the function called should be objc_msgSend, not objc_msgSend_stret.

Declare Function objc_msgSend Lib ObjRuntime (id As Ptr, SEL As Ptr, view As Ptr) As Ptr

objc_msgSend_stret is designed to return structures. stret is Struct Return. I believe Stephen is right in trying to using objc_msgSend_stret, although I have never personally used it…

Which objc_msgSend variant to call is dependent on the architecture. On 32-bit ARM, objc_msgSend_stret is used for message sends returning structures larger than four bytes or those that contain a Single.

Progress: I can call objc_msgSend_stret with no extra parameters viewPtr and to get the viewPtr’s frame.
(I know I don’t need to, the “frame” call can be made safely with declares I just wanted a different test case)

  • Of course, when run on 2015 R1 the frame declare crashes to due to #38291, as one would expect if they didn’t forget they were testing on 2014 R3.2. So I can use objc_msgSend_stret to work around the crash for the UIView frame call.

Declare Sub objc_msgSend_stret Lib “/usr/lib/libobjc.A.dylib” (ByRef resultPtr as CGRect32, objPtr As Ptr, selPtr As Ptr )

Dim cgRect32 as CGRect32
Dim selPtr as Ptr = Foundation.NSSelectorFromString(“frame”)
objc_msgSend_stret( cgRect32, objPtr, selPtr )

I called NSStringFromClass to check the class names for the objPtr (UITapGestureRecognizer) and the viewPtr (XOJCanvasView) so those pointers look valid. As shown above, the viewPtr correctly responds to “frame”.

So it could be the selector but that same selector (“locationInView:”) works with the normal declare. Further the objPtr passes an objRespondsTo:selector test which uses the same NSSelectorFromString declare to turn the string into a selector id.

====

I need to create a clean simple test for objc_msgSend_stret with at least one additional parameter to use on something stabler than a UIGestureRecognizer in the middle of responding to a touch event.