I want to bind an objective c library (For using a cable) in xamarin. I am new to xamarin platform, Can anyone help me to convert the below .h file to "ApiDefinition.cs" in Xamarin binding project.
#import <UIKit/UIKit.h>
#ifndef CABLE_
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#protocol CableManagerDelegate;
/*
This protocol), describes the main interface to the Cable Socket Manager layer.
To use, call factory method below [CableManager sharedInstance]
*/
#protocol CableManagerProtocol <NSObject>
// set delegate for cable connect callbacks
-(void)setDelegate:(id < CableManagerDelegate >) delegate;
-(BOOL)isCableConnected;
-(NSString *)getAccessoryFirmwareVersion;
#end
#protocol CableManagerDelegate <NSObject>
//Cable was connected
- (void) cableConnected:(NSString *)protocol;
// Cable was disconnected and/or application moved to background
- (void) cableDisconnected;
#end
#interface CableManager : NSObject
+ (id < CableManagerProtocol >)sharedInstance;
#end
Can't write it for you, but the sample below is the general pattern which you can learn more about in the guide linked below. One of your key challenges is going to be making sure the callback on the delegate fires. To Map this, check out the "Binding Protocols" section.
http://developer.xamarin.com/guides/ios/advanced_topics/binding_objective-c/binding_objc_libs/
ApiDefinition.cs
using MonoTouch.ObjCRuntime;
using MonoTouch.Foundation;
using System;
namespace MyNamespace
{
[BaseType (typeof (NSObject))]
interface MyObjCWrapper
{
[Export("initWithArg1:arg2:arg3:")]
void Constructor(string first, string second, string third);
[Export("mySelectorTaking1arg:")] // note colon, takes 1 arg
void DoSomethingWith1Arg(string filePath);
[Export("getSomething")] // note no colon, takes 0 args
int GetSomething();
}
To complete this binding, you should add the native library to the
project. You can do this by adding the native library to your project,
either by dragging and dropping the native library from Finder onto
the project in the solution explorer, or by right-clicking the project
and choosing Add > Add Files to select the native library. Native
libraries by convention start with the word "lib" and end with the
extension ".a". When you do this, Xamarin Studio will add two files:
the .a file and an automatically populated C# file that contains
information about what the native library contains:
You will end up with a file like this (libLibraryName.linkwith.cs):
using System;
using MonoTouch.ObjCRuntime;
[assembly: LinkWith ("libLibraryName.a", SmartLink = true, ForceLoad = true)]
Use Objective-Sharpie. It will do the initial bulk of work for you and you just need to fill in the gaps...
Related
I only have a lib file and its header file (static library?) I want to use this in C#. From googling I have come to the conclusion I need to write a wrapper dll that C# will be able to use.
I have tried writing this both in C++ and C++/CLI but when I run my program I get a error stating that
Unable to load DLL 'foo.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
I have already used a dependency checker and my dependencies are fine so I'm assuming my dll setup is incorrect.
I am only trying to use functions from the lib not classes.
Here is an example of my cs file
using System;
using System.Runtime.InteropServices;
using System.Text;
public class FooWrapper
{
[DllImport("FooWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern short DoSomething(ushort var);
}
// More functions like the one above
I have added FooWrapper.dll to my project by going into VS and doing Solution Explorer > Add > Existing Item > Directory that my dll is in > FooWrapper.dll
For my DLL I just created a new DLL C++ project, added a class named FooWrapper. This resulted in having a project that has
Project
|
-Refrences
|
-External Dependencies
|
-Header Files
-- FooWrapper.h
-- framework.h
-- pch.h
|
-Resource Files
|
- Source Files
--FooWrapper.cpp
--dllmain.cpp
--pch.cpp
FooWrapper.h looks something like this
#pragma once
#ifndef FOOWRAPPER_H
#define FOOWRAPPER_H
#include <string>
#include "Foolib.h" // header file that comes with lib file i originally had
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
#ifdef FOOWRAPPER_EXPORTS
#define FOOWRAPPER_API __declspec(dllexport)
#else
#define FOOWRAPPER_API __declspec(dllimport)
#endif
FOOWRAPPER_API I16 DoSomething(const I16 var) // I16 is defined (typedef) as a short
#ifdef __cplusplus
}
#endif
#endif
I have also linked the lib and header by adding the include directory under Properties>C/C++> Additional Include Directories
and Linker > Additional Library Directories > *Directory that FooLib.lib is in *
and Linker > Input > Additional Dependencies > *Directory that FooLib.lib is in * > FooLib.lib
So lastly when I call DoSomething the code stops and gives me the Exception from HRESULT: 0x8007007E error message.
Can someone maybe tell me if I skipped a step? Or am I supposed to use C++/CLI to create the library? If so I can try that again. Or is this not possible without seeing the implementation of the FooLib.lib code?
castro's comment solved the issue:
Try creating your C++ project as a CLR project. So long as you follow the rules (only include native code in the cpp) it should then be as simple as adding your project as a reference to your C# project. Going from memory so I can't say for sure, but this might help you get started: learn.microsoft.com/en-us/cpp/dotnet/…
I need to import a dll made in c# from c++
All the examples I found import a single function from a dll, but as far as I know, you cannot export a single function from c# without exporting the whole class (I'm a bit of a c# newbie though)
I am using node gyp to compile it (I'm building a node module for my web app using v8)
Here is my c# code:
using System;
using System.IO;
using System.Runtime.InteropServices;
[ComVisible(true)]
public class Hello
{
public static void Main()
{
Console.WriteLine("Hello World!");
string createText = "Hello World" + Environment.NewLine;
File.WriteAllText(".\\asd.txt", createText);
}
}
And this is my c++ header file:
#ifndef ASDLIB_H
#define ASDLIB_H
#define ASD_IMPORT __declspec(dllimport)
#define STDCALL __stdcall
class ASD_IMPORT Hello{
public:
STDCALL static void ASD_IMPORT Main();
};
#endif // ASDLIB_H
I normally do this kind of stuff by creating a static C++ CLR Wrapper Lib.
These are the steps I'm normally using (although I don't use it very often):
Here minimal example with using Visual Studio:
1. Create managed C# .NET library Project
Let name it HelloLibManaged
with one file Hello.cs and following content:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloLibManaged
{
public class Hello
{
public void Print()
{
System.Console.WriteLine("Hello from Managed Lib");
}
}
}
Build this lib with x86 or x64 , just dont Any CPU
2. Create a new C++ CLR static lib project within same solution.
Let's name it HelloLibCpp
Add a reference to HelloLibManaged project via Project->Add Reference
Remove automatic created existing .h/.cpp files from Project, and create these 2 files:
HelloUnmanaged.h
#pragma once
namespace hello_managed {
class Hello
{
public:
void Print();
};
}
and
HelloUnmanaged.cpp:
#include "HelloUnmanaged.h"
namespace hello_managed
{
void Hello::Print()
{
HelloLibManaged::Hello^ hello = gcnew HelloLibManaged::Hello();
hello->Print();
}
}
Und Project Properties -> General specify static lib.
In the Build settings specify x86 / x64 - use the same build type as building Managed lib from Step 1.
Now you can build the dll and use it in your other unmanaged C++ projects.
For more advanced stuff, like return types and methods with parameters you have to do Type-Marshalling between managed/unmanaged code. There are many resources online with more information about Type-Conversion between managed/unmanaged code. Keyword: Marshaling.
I'm trying to create a DLL exposing some static functions to use then in C.
Recently I read an article of Microsoft named "An Overview of Managed/Unmanaged Code Interoperability" and in this there is no a clear explanation on how to "Exposing a Managed API as a Flat API".
I installed this plugin to Visual Studio (https://www.nuget.org/packages/UnmanagedExports) but I still can't compile a project in C.
My C# project exposes a function like this:
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace libcallcstest
{
public class Class1
{
[DllExport("add", CallingConvention = CallingConvention.Cdecl)]
public static int add(int a, int b)
{
return a + b;
}
}
}
After building project, result these three files:
libcallcstest.dll
libcallcstest.pdb
libcallcstest.tlb
My C code is:
#include <stdio.h>
#include <stdlib.h>
int add(int, int);
int main(int argc, char** argv) {
int z = add(2,5);
printf("%d\n", z);
return (EXIT_SUCCESS);
}
And finally when I try to compile this file with:
gcc -o main.exe main.c -lcallcstest
Not work properly, files created by building the C# project are in the same folder as the main.c file.
Pleas any help!!!
One way to go: you may want to host CLR in your process. I would recommend against it though, because hosting is not the easiest procedure out there.
Also it's often not really needed or you can use some slower methods to communicate with .Net code from unmanaged environment (for example, present your library as a local server and access it through network interfaces. As I see it that way you'll have ten times less work to do).
Or you could go with your original variant using utilities to help you like mentioned here.
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!
How does an unmanaged c++ .dll know where the location of a managed c# .dll is?
Some context:
I have a c++ .dll that imports a type library (.tlb) and inside one of the c++ functions, I instantiate a pointer to the functions inside the c# .dll. Then, using that pointer, I can call the c# functions in c++. I would like to know how c++ .dll know where the c# .dll is? Further, is there a better way to do this type of coding?
Does the .tlb need to be in the same directory as the c# .dll?
One way to accomplishing the above is to register the C# dll file with the Microsoft Windows Registry using the regasm command. This command EXE is included with distributions of Visual Studios. An example use of the command follows:
regasm NameofC#DLL.dll /tlb:NameofC#DLL.tlb
Once you have registered it in the registry you will need to install it to the global assembly cache (GAC) using the gacutil command. This is also included with distributions of Visual Studios. An example use of the command follows:
gacutil /i NameofC#DLL.dll
Once these steps are completed your C++ code will be able to find the C# dll assuming your DLL files are constructed similar to the following:
[C#]
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace MyNameSpace
{
/// <summary>
/// Interface for C++ DLL. This exposes the functions used inside the dll
/// Make sure the return types, function names, and argument types match the class
/// </summary>
[ComVisible(true)]
[Guid("CBA208F2-E43B-4958-97C7-C24EA5A213DE")]
public interface IMyClass
{
int Function1();
int Function2();
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("579091E6-83A1-4aa5-89A7-F432AB2A57E3")]
[ComVisible(true)]
public class MyClass : IMyClass
{
public MyClass()
{
//Constructor
}
public int Function1()
{
//Do something in C#
return an integer;
}
public int Function2()
{
//Do something else in C#
return an integer;
}
}//End Class MyClass
}//End namespace MyNameSpace
Everywhere you see a GUID being used, that is a randomly generated global identifier used to identify your C# code. This number can be randomly generated using the GUID creation tool provided with Visual Studios under the "Tool menu" and the "Create GUID" option. Select Registry format and press "New GUID". Then just press copy and paste it where the GUID needs to be (Remove the brackets!)
[C++]
#include <windows.h>
#include "stdafx.h"
#include <cstdlib>
#pragma warning (disable: 4278)
#import <mscorlib.tlb> raw_interfaces_only
#include <stdio.h>
//This path needs to be valid at compile time. The file does not need to be there in runtime when using the DLL after compile.
#import "C:\\...\\NameofC#DLL.tlb" no_namespace named_guids
extern "C" _declspec(dllexport) int _Function1()
{
int result = 0;
IMyClass *CSharpInterface = NULL;
//Open interface to C#
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_MyClass, NULL, CLSCTX_INPROC_SERVER,
IID_IMyClass, reinterpret_cast<void**>(&CSharpInterface));
//Call Function1 C# method
result = CSharpInterface->Function1();
//Close interface
CoUninitialize();
//Return result
return result;
}
The required TLB file at compile time can be generated using the tlbexp command also included with visual studios.An example use of the command follows:
tlbexp NameofC#DLL.dll
If you do not specify a path it will default to the following path:
C:\Program Files\Microsoft Visual Studio 9.0\VC
There a several places you can mess this up and the C# DLL call will fail.
Regards,
SeaMossDesign
Maybe I'm missing something, but you can create a custom CLR host and invoke a method from C# without pointer. Check ICLRRuntimeHost::ExecuteInDefaultAppDomain out.