You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#通过ObjCRuntime调用Objective-C函数获取结构体返回值问题

问题原因

代码拿不到正确结果是两个核心错误:

  • 错误使用IntPtr_objc_msgSend入口处理结构体返回值。Objective-C消息发送的ABI对结构体返回有专门的调用约定:x86_64架构下超过16字节的结构体返回需要调用objc_msgSend_stret而非普通objc_msgSend;arm64架构下虽然统一使用objc_msgSend,但blittable结构体是直接作为值类型返回,不会返回指向结构体的IntPtr指针。你用返回IntPtr的重载调用,栈结构不匹配,自然拿到无效的0x0结果。
  • 错误使用Dlfcn.GetCGRectAPI。这个方法是用来读取动态库导出的C语言全局CGRect变量的,第一个参数要求是dlopen拿到的动态库句柄,第二个参数是全局变量的符号名,完全不是用来处理objc_msgSend返回结果的,传空字符串加无效句柄不可能拿到正确值。
正确实现方法

优先使用ObjCRuntime内置的封装,不用手动处理架构差异和调用约定,避免踩ABI的坑:

方法1:使用内置的结构体消息发送封装(推荐)

微软iOS/macOS绑定库已经为CGRect这类常用blittable结构体内置了对应的消息发送实现,自动适配不同架构的调用规则:

// 替换成你实际要调用的selector,比如获取UIView的frame就传"frame"
Selector targetSelector = new Selector("frame");
// 直接调用内置封装,返回值就是正确的CGRect
CGRect result = Messaging.CGRect_objc_msgSend(CGRect.Empty, objectHandle, targetSelector.Handle);

如果调用的方法带参数,直接使用内置的对应参数重载即可,不需要额外处理调用逻辑。

方法2:自定义结构体场景的手动P/Invoke

如果你要返回的是自定义结构体,需要根据架构声明正确的P/Invoke签名:

// arm64架构下不需要objc_msgSend_stret,直接返回结构体即可
[DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")]
static extern CGRect CGRect_objc_msgSend(IntPtr target, IntPtr selector);

// x86_64架构下返回大于16字节结构体需要用stret入口
[DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend_stret")]
static extern void CGRect_objc_msgSend_stret(out CGRect result, IntPtr target, IntPtr selector);

// 调用时根据架构选择对应方法
CGRect result;
if (Runtime.Arch == Arch.DEVICE || Runtime.IsARM64CallingConvention)
{
    result = CGRect_objc_msgSend(objectHandle, selectorHandle);
}
else
{
    CGRect_objc_msgSend_stret(out result, objectHandle, selectorHandle);
}

方法3:避免手动调用消息发送

如果只是获取已知类型对象的属性,不需要手动写msgSend逻辑,直接用运行时绑定即可:

// 将非托管句柄转为NSObject对象
NSObject targetObj = Runtime.GetNSObject(objectHandle);
// 已知具体类型的场景直接强转访问属性即可,比如UIView直接取Frame属性
// var view = (UIView)targetObj;
// CGRect frame = view.Frame;

// 动态类型场景用KVC取值
NSValue rectValue = (NSValue)targetObj.ValueForKey(new NSString("frame"));
CGRect result = rectValue.CGRectValue;

注意:所有手动调用objc_msgSend的场景,都要保证selector存在且参数/返回值类型匹配,否则会出现内存泄露、崩溃或者返回值错误的问题。

内容的提问来源于stack exchange,提问作者Aleksandr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:18:19