MonoTouch 绑定无法使用字段

Posted

技术标签:

【中文标题】MonoTouch 绑定无法使用字段【英文标题】:MonoTouch Binding cannot use fields 【发布时间】:2012-05-09 22:32:16 【问题描述】:

您好,我正在尝试将 google admboads 更新到 V6,但在绑定以下内容并将其公开给托管世界时遇到了一些麻烦

我有以下结构

typedef struct GADAdSize 
  CGSize size;
  NSUInteger flags;
 GADAdSize;

我在单点触控方面做了这个

[StructLayout(LayoutKind.Sequential)]
public struct GADAdSize

    public SizeF size;
    public uint flags;

我有以下代码

extern GADAdSize const kGADAdSizeBanner;
extern GADAdSize const kGADAdSizeMediumRectangle;

我无法使用 [Field] 属性绑定它,因为文档指定 Field 属性只能用于

NSString 引用 NSArray 引用 32 位整数 (System.Int32) 32 位浮点数(System.Single) 64 位浮点数 (System.Double)

所以我尝试了以下两种我能想到的方法

[DllImport ("__Internal")]
    extern static IntPtr kGADAdSizeMediumRectangle ();

public static GADAdSize MediumRectangle 

    get 
    
        object obj = Marshal.PtrToStructure(kGADAdSizeMediumRectangle(), typeof(GADAdSize));
        return (GADAdSize) obj;
    

public static GADAdSize Banner 

    get 
    
        var handle = Dlfcn.dlopen ("libGoogleAdMobAds", 0);
        IntPtr ptr = Dlfcn.GetIntPtr(handle, "kGADAdSizeBanner");   
        Dlfcn.dlclose (handle);     
        object obj = Marshal.PtrToStructure(ptr, typeof(GADAdSize));
        return (GADAdSize) obj;
    

在这两种情况下都会崩溃

使用 DLLImport 我在调用 Marshal.PtrToStructure() 时得到一个 nullargument 异常,第二个引发 DLLNotFoundException System.ArgumentNullException

提前感谢您的帮助

亚历克斯


编辑:

对不起@Poupou 我的错,它抛出一个 System.ArgumentNullException 句柄值它的 0 以及 ptr 值它的 0

堆栈跟踪是:

System.ArgumentNullException: Argument cannot be null.
Parameter name: src
  at (wrapper managed-to-native) System.Runtime.InteropServices.Marshal:PtrToStructure (intptr,System.Type)
  at AlexTouch.GoogleAdMobAds.GADAdSizeConstants.get_Banner () [0x00000] in <filename unknown>:0
  at MobclixText.MobclixTextViewController.ViewDidLoad () [0x00006] in /Users/Alex/Projects/MobclixText/MobclixText/MobclixTextViewController.cs:33
  at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging:void_objc_msgSend (intptr,intptr)
  at MonoTouch.UIKit.UIWindow.MakeKeyAndVisible () [0x00010] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIWindow.g.cs:98
  at MobclixText.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication app, MonoTouch.Foundation.NSDictionary options) [0x00031] in /Users/Alex/Projects/MobclixText/MobclixText/AppDelegate.cs:44
  at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
  at MobclixText.Application.Main (System.String[] args) [0x00000] in /Users/Alex/Projects/MobclixText/MobclixText/Main.cs:17

我猜这是由于句柄为 0。

关于你的评论

将 dlsym 与特殊标志之一 (man dlsym) 一起使用可能会有所帮助。

你能给我一个如何使用它的例子吗=) ??

亚历克斯


编辑 2:

你好@Poupou,感谢你的回答,但是

IntPtr RTLD_MAIN_ONLY = (IntPtr) (-5);
IntPtr ptr = Dlfcn.GetIntPtr (RTLD_MAIN_ONLY, "kGADAdSizeBanner");

我仍然得到 ptr 等于 0 任何其他想法?

亚历克斯


编辑 3:

好的,我现在试试下面的

IntPtr RTLD_MAIN_ONLY = Dlfcn.dlopen (null, 0);
IntPtr ptr = Dlfcn.dlsym (RTLD_MAIN_ONLY, "kGADAdSizeBanner");              
Console.WriteLine("RTLD_MAIN_ONLY: " + RTLD_MAIN_ONLY);
Console.WriteLine("ptr: " + ptr);

Dlfcn.dlopen (null, 0); 已完成 here 现在我得到了一个句柄值 -2 但我猜本机链接器现在正在删除符号,我怎样才能防止这种情况发生??

非常感谢您抽出宝贵时间@Poupou

亚历克斯

【问题讨论】:

DLLNotFoundException ?我很惊讶,handle 的值是多少?和堆栈跟踪?由于该库已被静态链接,因此将找不到它。将 dlsym 与特殊标志之一 (man dlsym) 一起使用可能会有所帮助。 @poupou 请看我的更新,希望你能帮助我也感谢你的信息。 【参考方案1】:

所以我找到了一种获取值的方法。第一部分是说服链接器导出符号(不隐藏任何现有符号)。这可以通过创建(本地)符号的别名(默认为全局)来完成。例如

-gcc_flags="-Xlinker -alias -Xlinker _kGADAdSizeBanner -Xlinker _MTAdSizeBanner"

后面的代码:

IntPtr RTLD_MAIN_ONLY = Dlfcn.dlopen (null, 0);
IntPtr ptr = Dlfcn.dlsym (RTLD_MAIN_ONLY, "MTAdSizeBanner");
object obj2 = Marshal.PtrToStructure(ptr, typeof(GADAdSize));

将为您提供一个 GADAdSize 的实例,其值为 320x50。

您需要重新导出所需的每个符号(糟糕),但这应该可以将其包含在 [LinkWith] 属性 (iirc) 中,这样最终用户就不需要这样做了。

【讨论】:

今晚会试一试,让你知道它是否有效;-) 非常感谢塞巴斯蒂安 谢谢谢谢 非常感谢 Sebastien 的工作,你是我的英雄 ;-) 刚刚在错误报告中问了另一件事,希望你能帮助我。再次感谢 @poupou 我有同样的问题,但动态库。任何建议【参考方案2】:

您的第二个解决方案是通常使用的。它从指定的动态加载符号。 OTOH 这适用于 ios 上的系统库。

为什么?因为您自己提供的库将与您的主要可执行文件静态链接。这与 [DllImport("__Internal") 必须用于正常 p/invoke 的原因相同。

回到符号,dldym 有一些选项可以处理主可执行文件(或所有加载的代码)。在终端窗口上执行man dlsym 以查看它们。这可能(没有尝试过)使用:

 IntPtr RTLD_MAIN_ONLY = (IntPtr) -5;
 IntPtr ptr = Dlfcn.GetIntPtr (RTLD_MAIN_ONLY, "kGADAdSizeBanner"); 

注1:Dlfcn.GetIntPtr是一个实用方法,基本上包裹了dlsym

注意 2:也请查看其他选项 :-) 如果您得到一个非空(不是 IntPtr.Zero)指针,那么您可以尝试将其编组为 SizeF 结构。

【讨论】:

首先确保该符号包含在您的主(本机)可执行文件中(即本机链接器没有删除它,否则将无法正常工作),然后读取man dlsym 以获取其他特殊值。 好的,为了获得我的主要可执行文件的句柄,我应该使用var handle = Dlfcn.dlopen ("__Internal", 0); 吗?抱歉,我是这个工具的新手 好的,尝试Dlfcn.dlopen (null, 0); 在这里完成https://github.com/mono/maccore/blob/master/src/generator.cs#L2733 现在我得到一个句柄值-2 但我猜本机链接器正在删除符号,我怎样才能防止这种情况发生? ? 项目设置。它会更快(如果您可以填写错误报告并且我们可以查看您的项目,那么它会更简单。

以上是关于MonoTouch 绑定无法使用字段的主要内容,如果未能解决你的问题,请参考以下文章

应用程序委托问题,MonoTouch

Monotouch - UIActionSheet 无法在 iPad 上正确显示

MonoTouch <--> 静态库异常:无法在包中加载 NIB

我无法在 Monotouch UITableViewController 中禁用页眉或页脚

无法在 SplitView MonoTouch 上显示 NavigationBar

MonoTouch 是不是有任何数据绑定支持?