Bug 5022 - MonoTouch Binding cannot use fields
Summary: MonoTouch Binding cannot use fields
Status: RESOLVED FIXED
Alias: None
Product: iOS
Classification: Xamarin
Component: Tools ()
Version: 5.3.x
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-05-11 00:45 UTC by Alex Soto
Modified: 2012-05-17 22:21 UTC (History)
4 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Binding Priject (3.60 MB, application/zip)
2012-05-11 00:45 UTC, Alex Soto
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Alex Soto 2012-05-11 00:45:35 UTC
Created attachment 1857 [details]
Binding Priject

Hello I posted this question on StackOverflow please see for more info

http://stackoverflow.com/questions/10525043/monotouch-binding-cannot-use-fields 

Im using MonoTouch 5.3.3

I added My binding project and the admob sdk as requested by Sebastien Pouliot the header file I'm having problems with is GADAdSize.h

Thanks a lot for any help

Alex
Comment 1 Alex Soto 2012-05-11 00:56:51 UTC
Also to Test the binding part I cant make to work just create a new monotouch single view application and add AlexTouch.GoogleAdmobAds.dll as reference and add the following line of code in ViewDidLoad on viewcontroller

GADAdSizeConstants.GADAdSize size = GADAdSizeConstants.Banner;

Alex
Comment 2 Sebastien Pouliot 2012-05-11 08:59:16 UTC
I think you forgot to read the instructions in the generated source, e.g.

	// The first step to creating a binding is to add your native library ("libNativeLibrary.a")
	// to the project by right-clicking (or Control-clicking) the folder containing this source
	// file and clicking "Add files..." and then simply select the native library (or libraries)
	// that you want to bind.

That means the .a is not added to your .dll and no [LinkWith] is generated to instruct how your application will be able to link with the native code. 

IOW every other thing you tried cannot work since the .a was never linked (or otherwise available) to your application (at least not by adding your .dll as a reference).

Please try those steps again and, if you still have an issue, re-attach your code *including* a test application showing the issue (in case that's where you added the extra linking parameters).
Comment 3 Alex Soto 2012-05-11 10:55:33 UTC
Hello Sorry that was my mistake, since I created that binding from scratch before sending it to you but here is the updated one with the test case

The test case tries 2 ways of trying to find the c symbol located on extras.cs

// First way
public static GADAdSize Banner 
		{
			get 
			{
				
				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);
				
				GADAdSize obj = new GADAdSize();
				
				//object obj = Marshal.PtrToStructure(ptr, typeof(GADAdSize));
				return obj;
			}
		}

// Second Way
[DllImport ("__Internal")]
		extern static IntPtr kGADAdSizeFullBanner ();

		public static GADAdSize FullBanner 
		{
			get 
			{
				object obj = Marshal.PtrToStructure(kGADAdSizeFullBanner(), typeof(GADAdSize));
				return (GADAdSize) obj;
			}
		}

In the First way I get Handle with value of -2 and ptr with value of 0

In the second way I get System.EntryPointNotFoundException: kGADAdSizeFullBanner

Thanks in advance for your time and help

Alex
Comment 4 Alex Soto 2012-05-11 11:28:36 UTC
Here is the link to the project and the test case could not upload to bugzilla due to size

http://dl.dropbox.com/u/2058130/AdmobBinding.zip

Alex
Comment 5 Sebastien Pouliot 2012-05-11 15:36:11 UTC
The symbol is there:

$ nm AdmobV6Test.app/AdmobV6Test | grep kGADAdSizeBanner
00287278 s _kGADAdSizeBanner

^ however it's a local (not external) symbol (lowercase 's') and it seems `dlsym` won't return a pointer in such case when used with RTLD_MAIN_ONLY (or any other option).

What's needed is to convince the native linker to expose them... without source changes.
Comment 6 Alex Soto 2012-05-11 23:02:42 UTC
Any Ideas on how to do that? Sorry I have no idea on how to do it :(
Comment 7 Sebastien Pouliot 2012-05-15 15:33:49 UTC
No, I started reading about the (native) linker options (there are many of them) but I got interrupted by other issues. The goal is to ensure the section symbols stays global (uppercase 'S') like the static library itself once the application is linked (instead of a local, lowercase 's') as above.

$ nm GoogleAdMobAdsSDK/libGoogleAdMobAds.a | grep kGADAdSizeBanner
         U _kGADAdSizeBanner
nm: no name list
00001ecc S _kGADAdSizeBanner
         U _kGADAdSizeBanner
nm: no name list
00002910 S _kGADAdSizeBanner
         U _kGADAdSizeBanner
nm: no name list
000026ac S _kGADAdSizeBanner
Comment 8 Rolf Bjarne Kvinge [MSFT] 2012-05-16 06:45:00 UTC
I believe there is also another way: create another native library that wraps these internal symbols into global ones.

So you'd have something like this in your .m file:

CGSize kGADAdSizeBannerGlobal = kGADAdSizeBanner;
Comment 9 Sebastien Pouliot 2012-05-17 14:47:20 UTC
So I found a way to get the values. The first part is to convince the linker to export the symbol (without hiding any existing ones). That can be done by creating an alias (which by default is global) of the (local) symbols. E.g.

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

Afterward the code:

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

will give you an instance of GADAdSize with a value of 320x50.

You'll need to re-export every symbol you need (yuck) but that should be possible to include this in the "LinkWith" attribute (iirc) so it won't be a requirement for end users.
Comment 10 Alex Soto 2012-05-17 22:21:58 UTC
Woow Sebastien you are my hero!! ;-)

Just a couple of things to finish this bug report and to finish the binding

How can I bind these 2 messages?

- (id<GADAdNetworkExtras>)adNetworkExtrasFor:(Class<GADAdNetworkExtras>)clazz;

[Export ("adNetworkExtrasFor:")]
GADAdNetworkExtras AdNetworkExtrasFor(Type clazz);
		


- (void)removeAdNetworkExtrasFor:(Class<GADAdNetworkExtras>)clazz;

[Export ("removeAdNetworkExtrasFor:")]
void RemoveAdNetworkExtrasFor(Type clazz);


I tried using Type but that didn't work


And the second and last thing

I have the following C functions but if I try to PInvoke them i get an EntryNotFoundExeption

tried the following for the first one

	[DllImport ("__Internal", EntryPoint = "GADAdSizeFromCGSize")]
	extern static IntPtr ExtSizeFromCGSize (IntPtr size);

	public static GADAdSize AdSizeFromSizeF (SizeF size)
	{
			
		IntPtr ptrSize = Marshal.AllocHGlobal(Marshal.SizeOf(size));
		Marshal.StructureToPtr(size, ptrSize, true);
		
		if (ptrSize == IntPtr.Zero)
			return GADAdSizeCons.Invalid;

		object obj = Marshal.PtrToStructure(ExtSizeFromCGSize(ptrSize), typeof(GADAdSize));
		
		return (GADAdSize) obj;
	}


// Given a CGSize, return a custom GADAdSize. Use this only if you require a
// non-standard size, otherwise, use one of the standard size constants above.
GADAdSize GADAdSizeFromCGSize(CGSize size);