I have a small DLL that has 3 functions : Init, Load and run.
I'm new with c# so as I read the questions here, I've opened a console project and wanted to load the DLL and use it's functions.
unfortunately - it didn't work. can anyone advise what went wrong?
This is the error I get:
Unable to find an entry point named 'Init' in DLL
'....path to my DLL....'.
this is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("C:\\Desktop\\DLLTest.dll", CharSet = CharSet.Unicode)]
public static extern bool Init();
[DllImport("C:\\Desktop\\DLLTest.dll", CharSet = CharSet.Unicode)]
public static extern bool Load(string file);
[DllImport("C:\\Desktop\\DLLTest.dll", CharSet = CharSet.Unicode)]
public static extern bool Play();
static void Main()
{
Console.WriteLine("got till here!!!");
Init();
Load("C:\\Desktop\\the_thing_about_dogs_480x270.mp4");
Play();
}
}
}
The only thing I can suspect is maybe the fact that I'm not creating an instance?
besides that, no clue :(
* editing : *
this is the DLL :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DLLTest
{
public class DLLTestApi
{
myInfo localPlay;
public bool Init()
{
localPlay = new myInfo();
return true;
}
public bool Load(string file)
{
localPlay.Load(file);
return true;
}
public bool Play()
{
localPlay.StartNewThread();
return true;
}
public bool Stop()
{
localPlay.DxStopWMp();
return true;
}
public bool Pause()
{
localPlay.DxPause();
return true;
}
public bool Resume()
{
localPlay.DxResume();
return true;
}
public bool Close()
{
localPlay.DxClose();
return true;
}
}
}
The error message tells you clearly what the problem is. Your DLL does not export a function named Init. Possible reasons for this include:
The DLL is not an unmanaged DLL.
The DLL simply does not export a function of that name.
The DLL exports that function, but the name is decorated or mangled.
Probably the easiest way to diagnose the fault is to use a tool like Dependency Walker to inspect the DLL's exports.
Update
From the edit to the question, it is clear that item 1 is the reason. Your DLL is a managed DLL and it is incorrect to attempt to access it using p/invoke. Simply add it as a reference to your console application project.
To load a dll dynamically, not sure if it applies to a managed dll, use Assembly.LoadFrom() from System.Reflection;
To create an instance use Activator.CreateInstance() from System.Activator;
Related
mono_class_from_name_case returns nullptr and i found no way to get more information why, and the mono documentation is very basic. My question is, i think i am missing something, is there a method to "link" the two assemblys together?, is that even needed?, why is the class showing up in the metadata but not accessable via get class?
I get the name and namespace through the metadata interface and they are valid strings. The dlls are compiled without any warnings/errors.
Beetween the open of the assambly and the metadata access is no other operation.
The code is first executed for base.dll then for content.dll. Both are in the same Domain, but different Assemblys and images.
Things i noticed:
Removing the base class in Slime "fixes" it. <- maybe missing a reference to base.dll?
It still does not work, when making the base not abstract/without any virtual method
Changing from mono_class_from_name_case to mono_class_from_name has the same behavior.
C++ Code:
//metadata.getRaw returns a MonoImage* loaded with mono_domain_assembly_open & mono_assembly_get_image, the base dll is loaded first
const MonoTableInfo* table_info = mono_image_get_table_info(metadata.GetRaw(), MONO_TABLE_TYPEDEF);
int rows = mono_table_info_get_rows(table_info);
for (int i = 0; i < rows; i++)
{
MonoClass* _class = nullptr;
uint32_t cols[MONO_TYPEDEF_SIZE];
mono_metadata_decode_row(table_info, i, cols, MONO_TYPEDEF_SIZE);
const char* name = mono_metadata_string_heap(metadata.GetRaw(), cols[MONO_TYPEDEF_NAME]);
const char* name_space = mono_metadata_string_heap(metadata.GetRaw(), cols[MONO_TYPEDEF_NAMESPACE]);
//this returns nullptr for a valid class, i think the base dll is not loaded
_class = mono_class_from_name_case(metadata.GetRaw(), name_space, name);
//this does happen...
if (_class == nullptr) {
continue;
}
}
The two involved DLLs:
Base.dll
csc.exe -target:library -nologo -optimize+ -debug- -out:Base.dll Item.cs
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Base
{
public abstract class Item
{
public Item()
{
}
public abstract bool init();
public abstract void release();
}
}
Content.dll
csc.exe -target:library -nologo -optimize+ -debug- -reference:Base.dll -out:Content.dll Slime.cs
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Content{
public class Slime : Base.Item
{
public Slime()
{
}
public override bool init()
{
return true;
}
public override void release()
{
}
}
}
I found the "error" there is a difference beetween mono_assembly_load and mono_domain_assembly_open. With mono_assembly_load it works.
I have C# as my front end application and I want to call c++ dll from my c# but I am getting error.
I am posting my code here please help me out how to resolve this:
Program.cs
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestCSharp
{
class Program
{
[DllImport("C:\\Users\\xyz\\source\\repos\\Project1\\Debug\\TestCpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void DisplayHelloFromDLL(StringBuilder name, int appId);
static void Main(string[] args)
{
try
{
StringBuilder str = new StringBuilder("name");
DisplayHelloFromDLL(str, str.Length);
str.Clear();
}
catch(DllNotFoundException exception)
{
Console.WriteLine(exception.Message);
}
catch(Exception exception)
{
Console.WriteLine("General exception " + exception.Message);
}
finally
{
Console.WriteLine("Try again");
}
}
}
}
and cpp code like below:
Header: source.h
#include <string>
using namespace std;
extern "C"
{
namespace Test
{
class test
{
public:
test();
__declspec(dllexport) void DisplayHelloFromDLL(char * name, int appId);
}
}
}
c++ class: source.cpp
#include <stdio.h>
#include "source.h"
Test::test::test()
{
printf("This is default constructor");
}
void Test::test::DisplayHelloFromDLL(char * name, int appId)
{
printf("Hello from DLL !\n");
printf("Name is %s\n", name);
printf("Length is %d \n", appId);
}
Code is building successfully but when I run this I got Unable to find an entry point named 'DisplayHelloFromDLL' in DLL.
Same CPP code when I am writing without using namespace and class, it is working fine.
i.e.
Header: source.h
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL(char * name, int appId);
}
c++ class: source.cpp
#include "source.h"
void DisplayHelloFromDLL(char * name, int appId)
{
printf("Hello from DLL !\n");
printf("Name is %s\n", name);
printf("Length is %d \n", appId);
}
So how do I use DLL which has namespaces and claases in my c# application.
Thanks for the answers.
I resolved the issue by making one extra class(Wrapper class) that contains the managed code. This wrapper class is called by the c# classes in the same way as I mentioned in the question. This wrapper class than call the c++ class and return the result to the UI.
The easiest way is to create a "proxy": set of clear-C functions, these will call your c++ functions.
I think calling c++ function is not good idea: name decoration is changed from version to version of compiler.
Do you have this project hosted somewhere?
On the first view I would say that you need to build the c++ project first (only the c++!!!) and then run the C# project.
Perhaps you would like to have a look here: Testprojects
Especially the "MessageBox" stuff shows how to use C++ with C#. There are some Testprojects with UWP as well.
I wan to import a DLL and use its functions but i want to assign the dll to a value so i dont end up overiding methods
Example of how I want to do it
mydll = [DllImport("MyDll.dll")]
mydll.SayHi();
// So I don't override this:
public void SayHi() { Console.WriteLine("Hello!!!"); }
Any way to acheive this?
Import the DLL in a wrapper class.
using System;
using System.Runtime.InteropServices;
// Namespace is optional but generally recommended.
namespace MyDLLImports
{
static class MyDLLWrapper
{
// Use DllImport to import the SayHi() function.
[DllImport("mydll.dll", CharSet = CharSet.Unicode)]
public static extern void SayHi();
}
}
class Program
{
static void SayHi()
{
// whatever...
}
static void Main()
{
// Call the different SayHi() functions.
MyImports.MyDLLWrapper.SayHi();
SayHi();
}
}
See the MSDN docs on the DLLImport attribute for further details. You may also need to declare calling conventions, different character encodings, the DLL's main entry point, etc.
I have a problem with my compiler not being able to import kernel32.dll, althrough I'm using System.Runtime.InteropServices. Here is the Code:
using System;
...
using System.Runtime.InteropServices;
namespace server
{
class Debugconsole
{
public void Initialise()
{
[DllImport("kernel32.dll")]
...
}
}
}
It throws a whole bunch of syntaxerrors and "Can't find "DllImport" in current context."
Thanks for your help.
Attributes cannot be used inside a method.
You should move it out of your method:
class Debugconsole
{
[DllImport("kernel32.dll")]
... the static extern method declaration ...
public void Initialise()
{
...
}
}
I'm trying to call a method, which is in a dll I've imported, from another class. Is there any way to do that? Thank you in advance!
To clarify myself: There is a class called "TTSManager". In this class a dll was imported. There also is a class "TTSdotNET" and in THIS class I would like to call a method within a dll, but the method isn't accessible. I hope somebody will help me.
P.S. I code in C#
"TTSManager":
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
public class TTSManager : MonoBehaviour
{
[DllImport ("SpeakerLib")]
private static extern void SpeakToSpeaker(string tts);
[DllImport ("SpeakerLib")]
private static extern void SpeakToFile(string tts, string fileName, string fileFormat); [DllImport ("SpeakerLib")]
private static extern void ReleaseSpeaker();
private static TTSManager instance = null;
private TTSManager(){}
public static TTSManager getInstance
{
get
{
if(instance == null)
{
instance = new TTSManager();
}
return instance;
}
}
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
}
"TTSdotNET":
public class TTSdotNet : MonoBehaviour
{
void Update ()
{
if (Input.GetKey(KeyCode.F10))
{
SpeakToSpeaker("hello world i feel uncomfortable.");
}
}
}
I tend to create a separate static class for the DLL imports. In addition to importing the functions I mostly also create wrapper methods for each DLL function call.
Example:
internal static class NativeCalls
{
[DllImport ...]
private static extern int SomeFunctionCall(...);
public static int SomeFunction(...)
{
return SomeFunctionCall(...);
}
}
That way, any class can access the DLL and your problem is solved.