I have simple static lib in xcode with the only class
test.h:
#interface TestClass : NSObject {
NSString *SomeString;
}
#property(nonatomic, readwrite, copy) NSString *SomeString;
- (NSString *) getString;
- (int) getInt;
#end
test.m:
#implementation TestClass
#synthesize SomeString;
- (id)init
{
if ((self = [super init]) == nil)
return nil;
SomeString = #"test string value";
return self;
}
- (NSString *) getString {
return #"Lorem ipsum dolor sit amet";
}
- (int) getInt {
return 123;
}
#end
I've copied TstClass from the dll generated by btouch. if i'm using original dll's implementation:
[Register ("TestClass", true)]
public class TstClass : NSObject
variables Handle, ClassHandle etc are nulls, but app runs and returns nulls as a getInt, getString and SomeString. if I change definition to
[Register ("TestClass")]
public class TstClass : NSObject
inner variables are valid (meaning not null), but app crashes with no output when I'm trying to call a TstClass's function.
During my research I've found someone has fixed this by unchecking "thumb" option in XCode build setting, but I can not find anything that looks like thumb in xcode project. (just in case: XCode 4.2 build 4C199; and I'm using latest version of Monotouch)
How do I create static lib in xcode and use it with monotouch? what's wrong with my code?
and the last question: I have a .a and its .h files. is there an easier way to generate bindings from library and header files?
The easiest path to bind your library is to use the binding generator (this is the "btouch" tool which is part of MonoTouch):
A detailed document is here:
http://docs.xamarin.com/ios/advanced_topics/binding_objective-c_types
The reason your variables are null is that you did not properly initialize the library (ClassHandle is a virtual method that should return the return value from Class.GetHandle ("ClassName") in this case).
Use the following contract file with btouch to generate a proper binding:
using MonoTouch.Foundation;
using MonoTouch.ObjCRuntime;
namespace AlexD {
[BaseType (typeof (NSObject))]
interface TestClass {
[Export ("SomeString")] string SomeString { get; set; }
[Export ("getString")] string GetString ();
[Export ("getInt")] int GetInt ();
}
}
Save that into AlexD.cs and then run:
/Developer/MonoTouch/usr/bin/mtouch AlexD.cs
This will generate AlexD.dll that contains your binding to your native library. You can use this plus the proper set of command line arguments to mtouch to access your library.
You can also bundle your native library inside the DLL, to simplify distribution (single .dll will contain both the C# binding and the native library), for details on how to do this, see:
http://docs.xamarin.com/ios/advanced_topics/binding_objective-c_types#Linking_the_Dependencies
it took some time to figure out how to make it work.
Make sure lib and app target architectures are the same. (I had armv7 for lib and armv6 for app)
Make sure build targets are the same (was iOS device for lib and iOS simulator for app. iOS simulator target sets architecture to i386, which makes lib and app build incompatible)
for some reason additional mtouch arguments requires "-cxx -gcc_flags" and not just "-gcc_flags";
for some reason .a lib was not linked without "-force_load" argument;
add "-v -v -v" to additional mtouch arguments to see full build log. That helped a lot to find this solution.
Thumb instructions set must be disabled (fixed by adding User-defined project option GCC_THUMB_SUPPORT:NO)
that's it!
Related
I've struggle several hours on that and I can't find what I'm doing wrong.
I created a new C# dll project, here is the content of the only class it contain:
using System;
using System.Runtime.InteropServices;
namespace PolygonSl {
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Config {
[ComVisible(true)]
public string GetCompany() {
return "POL";
}
}
}
I basically remove everything from it trying to make it work, the only reference is System.
I checked the Make assembly COM-Visible flag on the Assembly Information and my project is signed (seams required for codebase).
It compiling fine, after that, I called RegAsm.exe, giving it my dll, I added /codebase and /tlb, the command is successful.
When I go to my VBA project, I can add my new tlb file to the references, working fine. After, I can use it in my code, the autocomplete is working and I can compile with no errors.
Then, when I execute, I got this:
Run-time error '430':
Class does not support Automation or does not support expected interface
Here is my code sample in the VBA:
Private Sub Button1_Click()
'With CreateObject("PolygonSl.Config")
With New PolygonSl.Config
MessBox .GetCompany, MB_OK, "Test"
End With
End Sub
I tried late binding and my code is running fine with it but I'd like to be able to use the autocomplete.
Anyone have a suggestion on what I could try to make it work?
Edit (Adding some details on my environment)
I work on VS2008 for projects related to Dynamics SL (one of the Microsoft ERPs)
I'm on Windows Server 2008 R8 Standard, running from VMWare
Compiling on Framework 3.5, Release, x86, Dynamics SL client is 32 bits
I tried my dll on Dynamics but also on Excel to be sure that the problem was not Dynamics ;)
I think you need to define an interface to be able to see getcompany.
using System;
using System.Runtime.InteropServices;
namespace PolygonSl
{
[Guid("6DC1808F-81BA-4DE0-9F7C-42EA11621B7E")]
[System.Runtime.InteropServices.ComVisible(true)]
[System.Runtime.InteropServices.InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IConfig
{
string GetCompany();
}
[Guid("434C844C-9FA2-4EC6-AB75-45D3013D75BE")]
[System.Runtime.InteropServices.ComVisible(true)]
[System.Runtime.InteropServices.ClassInterface(ClassInterfaceType.None)]
public class Config : IConfig
{
public string GetCompany()
{
return "POL";
}
}
}
You can generate the interface automatically by placing the cursor in the class definition and using Edit.Refactor.ExtractInterface.
I'd have to admit that I'm at the absolute edge of my abilities here and the above is put together based on examples I've seen elsewhere.
Edit
The following test code works fine on my PC
Option Explicit
Sub polygontest()
Dim my_polygon As SOPolygon.Config
Set my_polygon = New SOPolygon.Config
Debug.Print my_polygon.GetCompany
End Sub
Where SOPolygon is the project name.
I have read the documentation from Xamarin.
And this is my test class in Objective-C:
#import "XamarinBundleLib.h"
#implementation XamarinBundleLib
+(NSString *)testBinding{
return #"Hello Binding";
}
#end
It's very easy, just one method.
And this is my C# class:
namespace ResloveName
{
[BaseType (typeof (NSObject))]
public partial interface IXamarinBundleLib {
[Static,Export ("testBinding")]
NSString TestBinding {get;}
}
}
Then this is my AppDelegate code:
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
// Override point for customization after application launch.
// If not required for your application you can safely delete this method
string testStr = ResloveName.IXamarinBundleLib.TestBinding.ToString ();
System.Console.WriteLine ("testStr="+testStr);
return true;
}
When I run the application, I get this exception:
The TestBinding attributes is null.
I must be wrong somewhere, so how can I fix it?
I wrote a very detailed blog post about creating a static library from ObjC code last year that works on Xamarin.iOS binding projects and you can find it here (just in case :wink::wink:).
That being said if you already have a fat static library in your hands and it is already added into your Xamarin.iOS Binding Project as shown here:
The issue could be that your libxyz.linkwith.cs is missing some information, if it looks like this:
using ObjCRuntime;
[assembly: LinkWith ("libFoo.a", SmartLink = true, ForceLoad = true)]
it is definitely missing some important information about the architectures supported by your fat library (it is missing the second argument target), you can use the following command to retrieve what architectures your current static library supports
xcrun -sdk iphoneos lipo -info path/to/your/libFoo.a
and you should get something like this as output
Architectures in the fat file: Foo/libFoo.a are: i386 armv7 x86_64 arm64
So we know this static library supports i386 armv7 x86_64 arm64 and we should provide our LinkWith attribute the supported archs by providing the second argument target as follows:
using ObjCRuntime;
[assembly: LinkWith ("libFoo.a", LinkTarget.ArmV7 | LinkTarget.Arm64 | LinkTarget.Simulator | LinkTarget.Simulator64, SmartLink = true, ForceLoad = true)]
Also make sure that the first parameter of the LinkWith attribute matches your static library file name ("libFoo.a" in my case).
The other thing I would suggest double checking is that the Build Action of your static library (libFoo.a in my case) is correctly set to ObjcBindingNativeLibrary as show here:
Hope this helps!
Here are the steps what I have done.
I have created a .dll file using C# with the content as
public static int MyFunction(int dummy)
{
MessageBox.Show("I am in dll");
return 0;
}
I have also created an MFC application (exe) with content as
int main()
{
int a = MyFunction(0);
return 0;
}
Is this right way to do the call ?
Note:
i. I have changed my MFC application to /cl (common language run time support)
ii. I have also added C# file in the MFC's Reference.
Problems I faced:
Error 1 error C3861: 'MyFunction': identifier not found
Warning 2 warning C4793: 'MyDialog::`vcall'{132}'' : function compiled as native :
I have used the following command in the MyDialog.cpp file as a last line, the warning is solved.
#pragma unmanaged
Now how to solve the Error?
The C# code is placed inside a class, say MyClass. If you want to call a static member of this class in C++/CLI, you need to use MyClass::MyFunction(0).
Finally, you would need to add the namespace: MyNamespace::MyClass::MyFunction(0).
You can compile your C++ program with the /clr flag and use C++/CLI to simply call any .NET code (as long as you include a reference to it).
You could also use a COM callable wrapper for your C# code (compiled in a DLL) -> check this article
I have successfully created an updated ZBar MonoTouch binding dll, following up on this answer here from a while ago, using the updated [Field] bindings to bind static NSStrings (previously I was just duplicating the value of the NSString in my binding dll).
The binding dll compiles fine (Compiled in Release mode).
And using the binding ZBar.dll from my app works fine in Debug builds, returning the correct NSString value from the native lib. However in Release builds it always returns null.
Note that I have the linker behaviour set to strip all assemblies for both Debug and Release builds, so it's nothing to do with the linker stripping anything out.
I tried turning off the LLVM compiler for Release, and it still returns null in Release builds. However enabling debugging in Release builds fixes it (obviously not a solution though).
Heres the binding code:
[Static]
interface ZBarSDK
{
// extern NSString* const ZBarReaderControllerResults;
[Field ("ZBarReaderControllerResults", "__Internal")]
NSString BarcodeResultsKey { get; }
}
And here's the decompiled IL (According to MonoDevelop):
namespace ZBar
{
public static class ZBarSDK
{
[CompilerGenerated]
private static NSString _BarcodeResultsKey;
[CompilerGenerated]
private static readonly IntPtr __Internal_libraryHandle = Dlfcn.dlopen(null, 0);
public static NSString BarcodeResultsKey
{
get
{
if (ZBarSDK._BarcodeResultsKey == null)
{
ZBarSDK._BarcodeResultsKey = Dlfcn.GetStringConstant(ZBarSDK.__Internal_libraryHandle, "ZBarReaderControllerResults");
}
return ZBarSDK._BarcodeResultsKey;
}
}
}
}
Monotouch: 6.0.10
Add this to the additional mtouch arguments in the project's iOS Build options page:
--nosymbolstrip=ZBarReaderControllerResults
The difference between Debug and Release builds is that Release builds are stripped, thus removing the symbol for the field, so Xamarin.iOS can't find it at runtime. This option will make Xamarin.iOS tell the linker that it should keep that symbol, even if the symbol is not used (note that the binding to the field is a dynamic binding which happens at runtime, so the native strip tool is not able to see that the field is actually used).
F# declared namespace is not available in the c# project or visible through the object browser.
I have built a normal F# library project, but even after i build the project and reference it to my C# project, I am unable to access the desired namespace.
I am also unable to see it in the object browser, i get an error telling me that it has not been built. I am running on the september release can someone point out my error ?
F# Version 1.9.6.0
(6) Edit : Referencing the dll directly has fixed my problem, referencing the project allows me to compile but the intellisence does not work. When the dll is directly referenced the intellisence works perfectly.
This is the code found in the .fs file
#light
namespace Soilsiu.Core
module public Process =
open System.Xml.Linq
let private xname (tag:string) = XName.Get(tag)
let private tagUrl (tag:XElement) = let attribute = tag.Attribute(xname "href")
attribute.Value
let Bookmarks(xmlFile:string) =
let xml = XDocument.Load(xmlFile)
xml.Elements <| xname "A" |> Seq.map(tagUrl)
let PrintBookmarks (xmlFile:string) =
let list = Bookmarks(xmlFile)
list |> Seq.iter(fun u -> printfn "%s" u)
(5) Edit : Could ReSharper 4.0 be the problem?
(4) Edit : When i say the Object browser is unable to read the resulting assembly, i mean that when I try to open the assembly in the object browser i get an error telling me the project has not yet been built. yet again i can read the assembly using reflector.
(3) Edit : Reflector can Disassemble the dll but the Object Browser is unable to read it.
(2) Edit : I have Upgraded my F# version to 1.9.6.2 and still the same consequence
(1) Edit : I was able to Disassemble the dll to C# I get : (Everything seems to be fine here)
namespace Soilsiu.Core
{
[CompilationMapping(7)]
public static class Crawler
[CompilationMapping(7)]
public static class Process
}
[CompilationMapping(7)]
public static class Process
{
// Methods
static Process();
public static IEnumerable<string> Bookmarks(string xmlFile);
public static void PrintBookmarks(string xmlFile);
internal static string tagUrl(XElement tag);
internal static XName xname(string tag);
// Nested Types
[Serializable]
internal class clo#13 : FastFunc<XElement, string>
{
// Methods
public clo#13();
public override string Invoke(XElement tag#9);
}
[Serializable]
internal class clo#17 : FastFunc<string, Unit>
{
// Methods
public clo#17();
public override Unit Invoke(string u);
}
}
What if you reference the produced DLL directly (i.e., not via a project reference, but via a file reference)?
Maybe IntelliSense is just messed up? What compiler error do you get when you try to use it in C#? When you say "the object browser is unable to read it" what does that mean?
For what it's worth, I added this to a F# library project, referenced it (project) from a C# console app, and was able to use it. IntelliSense did not work at first though. (Had to rebuild.)
If you can make a solid repro, I'd suggest emailing it to F# bugs alias (fsbugs).
I tried the same thing. It looks as if Visual Studio and Resharper 4.0 doesn't understand F# for some reason. If you ignore the sea of red text and the lack of intellisense, it will compile fine.
Try
Make sure that C# project is targeted FULL .NET (NOT Client Profile).
Add references to assemblies into C# project which are used by F# project.