I have a C# library (DLL)
// ProgramLib.cs //
using System;
namespace ProgramLibrary
{
public class Lib
{
public Lib()
{
Console.WriteLine("Lib Created");
}
}
}
And I have the following console program
// Program.cs //
using System;
using ProgramLibrary;
class MainClass
{
public static void Main (string[] args)
{
ProgramLibrary.Lib lib = new ProgramLibrary.Lib();
}
}
In a linux environment, if both files reside in the same directory
What is the Mono compiler (mcs) command that compiles Program.cs with reference to ProgramLib.cs?
Thanks all!!
First compile ProgramLib to ProgramLib.dll, then reference it:
$ gmcs -t:library ProgramLib.cs
$ gmcs -r:ProgramLib.dll Program.cs
Related
I have a .NET core project that uses a .so file. I use [DllImport()] to import it. My problem is that this .so has a dependency libtomcrypt.so so it can not locate some symbols(undefined symbol: cipher_descriptor).
I tried importing my .so in C and it works fine if I specify the linker variable -ltomcrypt.
Adding a reference to libtomcrypt.so in the .NET core project did not help because it is a native .so.
Is there any way to link libtomcrypt.so to dotnet?
Try to load your library with NativeLibrary first.
static class Library
{
const string MyLibrary = "mylibrary";
static Library()
{
NativeLibrary.SetDllImportResolver(typeof(Library).Assembly, ImportResolver);
}
private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
IntPtr libHandle = IntPtr.Zero;
if (libraryName == MyLibrary)
{
// Try using the system library 'libmylibrary.so.5'
NativeLibrary.TryLoad("libmylibrary.so.5", assembly, DllImportSearchPath.System32, out libHandle);
}
return libHandle;
}
[DllImport(MyLibrary)]
public static extern int foo();
}
Interacting with native libraries in .NET Core 3.0
I am working on mixed application, using both managed & native codes
I want to call a function deployed in a native class from Main() function located in Program.cpp which is managed class.
i tried using std::thread but failed with /cli
i tried to use Managed System::Threading::Thread but failed because i need to call a native function in a native class.
So how i can handle thing without using any third-party?
If you start from a native project you need to do the following steps:
Select project properties and change the option "No Common Language Runtime Support" to "Common Language Runtime Support /clr".
Open the "Property Manager" from "View" menu / "Other Windows" and add the property sheet "C++ Common Language Runtime Support" to the needed configuration (eg.: Debug | Win32) on my system this sheet is under "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140". I use the "Microsoft.Cpp.ManagedExtensions.props" file.
You need to remove std::thread completely.
headerish:
#pragma once
#include<stddef.h>
using namespace System;
using namespace System::Threading;
namespace FooSpace
{
// Native stuff
public class Native
{
public:
static void Foo() { }
void Bar() {
}
};
// Managed stuff
public ref class Managed
{
private:
Native* m_Native;
public:
Managed()
{
m_Native = new Native();
}
~Managed()
{
if (NULL != m_Native)
{
delete m_Native;
m_Native = NULL;
}
}
void Bar()
{
m_Native->Bar();
}
static void ThreadCall(Object^ o)
{
auto me = (Managed^)o;
me->Bar(); // Call a method of an instance of the native class
Native::Foo(); // Call a static method of the Native class
}
void StartThread()
{
auto t = gcnew Thread(gcnew ParameterizedThreadStart(ThreadCall));
t->Start(this);
t->Join();
}
};
}
soure file:
#include "stdafx.h"
#include "CppCli_Native.h"
using namespace FooSpace;
int main()
{
Native::Foo(); // call native static method
auto native = new Native(); // create native instance
native->Bar(); // call native method
auto managed = gcnew Managed();
managed->Bar(); // This will call bar
managed->StartThread(); // This will start a thread
delete managed;
Console::ReadLine();
return 0;
}
Edit: It turns out that you don't need to use IntPtr to store native class.
I find this answer also useful, it also gives us a fast introduction to c++-cli syntax.
I try to call a java function from my c++ code, but the app keeps 'crashing'.
At first, I start the c++ code through JNI call, which works without any problem. Then I let the function which is called executing the callback:
#include <jni.h>
extern "C"
JNIEXPORT jstring JNICALL
Java_net_example_folder_Service_startSomething(JNIEnv *env, jobject obj) {
invoke_class(env);
return env->NewStringUTF("The End.\n"); //works if I only use this line
}
Trying to follow http://www.inonit.com/cygwin/jni/invocationApi/c.html (and a lot of other guides/tips etc.), I use this to call the java function:
void invoke_class(JNIEnv* env) {
jclass helloWorldClass;
jmethodID mainMethod;
helloWorldClass = env->FindClass("Java/net/example/folder/helloWorldClass");
mainMethod = env->GetStaticMethodID(helloWorldClass, "helloWorld", "()V");
env->CallStaticVoidMethod(helloWorldClass, mainMethod);
}
To call the java code:
package net.example.folder;
import android.util.Log;
public class helloWorldClass {
public static void helloWorld() {
Log.e("helloWorldCLass", "Hello World!");
}
}
The c++ code is called by a background service. Here is the function of the Activity that starts it:
public void startService() {
Intent i = new Intent(this, Service.class);
startService(i);
}
And this is a part of the Service:
public class SimService extends IntentService {
...
#Override
protected void onHandleIntent(Intent intent) {
System.loadLibrary("native-lib");
startSomething();
}
}
That all works, but when I now change the function 'invoke_class' to:
void invoke_class(JNIEnv* env) {
jclass helloWorldClass;
jmethodID mainMethod;
helloWorldClass = env->FindClass("net/example/folder/helloWorldClass");
mainMethod = env->GetStaticMethodID(helloWorldClass, "helloWorld", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(helloWorldClass, mainMethod, env->NewStringUTF("some text"));
}
and of course the java part to:
package net.example.folder;
import android.util.Log;
public class helloWorldClass {
public static void helloWorld(String msg) {
Log.e("helloWorldCLass", msg);
}
}
With that, I'll get the earlier mentioned crash.
Why is that? How do I pass arguments correctly?
Symbol [ is used to represent arrays (as if you had String[] msg), remove that from your GetStaticMethodID method.
You can see more information about JNI Types and Data Structures here
Also as Michael said - you should check for java exceptions in your native code, because otherwise your app will crash. You can do it using Exception jni functions. For example:
jclass exClass = env->FindClass("some/random/class");
if (exClass == nullptr || env->ExceptionOccurred()) {
env->ExceptionClear();
// do smth in case of failure
}
I am developing an extension to VS2013. Since it will be installed through MSI, I am changing the base directory to installation folder using ProvideBindingPath attribute to package class. But the 3rd party dll reference which will be loaded in runtime is not picking dll from the probed path. Its always looking into Visual studio devenv.exe folder. Is there any way to force the dll to look into my installation folder.
using MD=Microsoft.VisualStudio.Modeling.Shell;
MD.ProvideBindingPath(SubPath = #"")]
public sealed class AutomationCommandPanePackage : Package
{
public AutomationCommandPanePackage()
{
string installationPath = HelperMethods.GetInstallationPath();
if (string.IsNullOrEmpty(HelperMethods.GetInstallationPath())) return;
// Change default config file at runtime.
using (AutomationConfigurationManager.Change(installationPath, "AutomationPro.config"))
{
// Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
}
Assembly a = Assembly.GetExecutingAssembly();
Type type = a.GetType("AutomationCommandPanePackage", true);
System.Reflection.MemberInfo info = type;
var attributes = info.GetCustomAttributes(true);
foreach (var attrib in attributes)
{
if (attrib is MD.ProvideBindingPathAttribute)
{
((MD.ProvideBindingPathAttribute)attrib).SubPath = installationPath;
break;
}
}
I have been able to successfully load third party (telerik) assemblies in my extension using below code.
Register to AssemblyResolve event in your Package class constructor
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
Then in handler load packages as below:
string path = Assembly.GetExecutingAssembly().Location;
path = Path.GetDirectoryName(path);
if (args.Name.ToLower().Contains("telerik.windows.controls.gridview"))
{
path = Path.Combine(path, "telerik.windows.controls.gridview.dll");
Assembly ret = Assembly.LoadFrom(path);
return ret;
}
I have not had any issues with the above approach.
I resolved issue using
LoadLibrary() from
System.Runtime.InteropServices;
since my dll to be loaded is a COM iterop dll.
public static class win32
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); [DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
in package.cs I loaded assembly like this
win32.LoadLibrary(Path.Combine(installationPath, "apidsp_windows.dll"));
I have a C++ library that I have to use in an existing Android implementation. I'm using Android NDK and using the C++ classes via JNI.
However, I am not able to find how to subclass a C++ abstract class in Java using JNI.
Problems I face:
My aim is to provide Java implementation for the virtual methods in C++ by subclassing the abstract C++ class.
I have loaded the native library and I'm trying to declare the native methods.
The C++ methods have keyword 'virtual'. When I declare the native functions in Java after loading the C++ library, 'virtual' is not recognized. What is wrong here?
Any help is appreciated. I'm a newbie to JNI. Thanks in advance.
Let's consider we have a C++ class:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
We want to create a class Bot in Java that extends class iVehicle in the sense that calls to super invoke the C++ code from iVehicle::GetSize() and, from the C++ point of view, we can use the instances of Bot as iVehicle* variables. That's tough since C++ provides no good built-in functionality for reflection.
Here is one possible solution.
To use C++ class in Java we need to generate a Java wrapper, i.e:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
The usage in Java is simple:
class Bot extends iVehicle
{
public int GetSize()
{
if ( condition ) return 0;
// call C++ code
return super.GetSize();
}
}
However, there is a C++ part to this code:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
The similar code is for GetSize().
Then creating an instance of Java's Bot you have to call CreateNativeObject() and assign the returned value to the NativeObjectHolder field.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
So, this is the scheme. To make this work you will need to add the destruction code and to parse C++ classes to generate all this glue code.
Added:
In case where iVehicle is actually abstract you will have to generate a non-abstract wrapper that you are able to instantiate:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
And instantiate iVehicle_Wrapper in CreateNativeObject(). Vuala! You have inherited an abstract C++ class in Java.