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.
Related
I've been reading multiple examples from here and other sources on how to accomplish this. Recently I followed this specific example which had been linked to in multiple other similar questions.
https://dorodnic.com/blog/2014/12/10/calling-cpp-by-example/
However even when directly importing this project from github it still presents an error in the C# project where it cannot reference the the C++ CLI code. "The type or namespace could not be found(are you missing a using directive or an assembly reference)". This is the same error I find while following other examples myself. Could anyone please explain to me why this fails and/or suggest steps to fix it?
Edit: adding code here to save time.
//Logic.h
#pragma once
namespace MeaningOfLife
{
namespace Cpp
{
// This is our native implementation
// It's marked with __declspec(dllexport)
// to be visible from outside the DLL boundaries
class __declspec(dllexport) Logic
{
public:
int Get() const; // That's where our code goes
};
}
}
//Logic.cpp
#include "Logic.h"
int MeaningOfLife::Cpp::Logic::Get() const
{
return 42; // Really, what else did you expect?
}
//Logic.h CLI
#pragma once
namespace MeaningOfLife
{
namespace Cpp
{
// First a Forward Declaration to Cpp::Logic class:
class Logic; // This allows us to mention it in this header file
// without actually including the native version of Logic.h
namespace CLI
{
// Next is the managed wrapper of Logic:
public ref class Logic
{
public:
// Managed wrappers are generally less concerned
// with copy constructors and operators, since .NET will
// not call them most of the time.
// The methods that do actually matter are:
// The constructor, the "destructor" and the finalizer
Logic();
~Logic();
!Logic();
int Get();
void Destroy();
static void InitializeLibrary(System::String^ path);
private:
// Pointer to our implementation
Cpp::Logic* _impl;
};
}
}
}
//Logic.cpp CLI
#include "Logic.h"
#include "..\MeaningOfLife.Cpp\Logic.h"
#include <string>
#include <Windows.h>
using namespace std;
MeaningOfLife::Cpp::CLI::Logic::Logic()
: _impl(new Cpp::Logic())
// Allocate some memory for the native implementation
{
}
int MeaningOfLife::Cpp::CLI::Logic::Get()
{
return _impl->Get(); // Call native Get
}
void MeaningOfLife::Cpp::CLI::Logic::Destroy()
{
if (_impl != nullptr)
{
delete _impl;
_impl = nullptr;
}
}
MeaningOfLife::Cpp::CLI::Logic::~Logic()
{
// C++ CLI compiler will automaticly make all ref classes implement IDisposable.
// The default implementation will invoke this method + call GC.SuspendFinalize.
Destroy(); // Clean-up any native resources
}
MeaningOfLife::Cpp::CLI::Logic::!Logic()
{
// This is the finalizer
// It's essentially a fail-safe, and will get called
// in case Logic was not used inside a using block.
Destroy(); // Clean-up any native resources
}
string ManagedStringToStdString(System::String^ str)
{
cli::array<unsigned char>^ bytes = System::Text::Encoding::ASCII->GetBytes(str);
pin_ptr<unsigned char> pinned = &bytes[0];
std::string nativeString((char*)pinned, bytes->Length);
return nativeString;
}
void MeaningOfLife::Cpp::CLI::Logic::InitializeLibrary(System::String^ path)
{
string nativePath = ManagedStringToStdString(path);
LoadLibrary(nativePath.c_str()); // Actually load the delayed library from specific location
}
//C#
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MeaningOfLife.WPF
{
using Cpp.CLI;
using Microsoft.Win32;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var fileOpenDialog = new OpenFileDialog
{
CheckFileExists = true,
Filter = "Native Library|MeaningOfLife.Cpp.dll",
InitialDirectory = Environment.CurrentDirectory
};
var result = fileOpenDialog.ShowDialog(this);
if (result.HasValue && result.Value)
{
Logic.InitializeLibrary(fileOpenDialog.FileName);
using (var wrapper = new Logic())
{
MessageBox.Show("The answer is " + wrapper.Get());
}
}
}
}
}
The error occurs at the using Cpp.CLI and then at the calls to Logic because of that.
Just as a follow up I also tried this example and received the same error in the comparable place in the code.
https://www.red-gate.com/simple-talk/dotnet/net-development/creating-ccli-wrapper/
This was solved by:
A)removing and adding back the WPF portion of the application
B)setting the "Copy Local" property of the CLI reference to true.
The reason I'm following these examples is to learn more about this process due to lack of knowledge. I do not think this is the real answer but it did solve my immediate issue.
Just wanted to ask generic question about Namespaces. If class A inherits class B and doesn't explicitly reference (using) B's namespace, do I have to explicitly using B namespace in my calling code to call B's methods from an instance of A? Is this language dependent (C#, C++)?
Ex in C#:
// Namespace X
class A : B
{
public void methodA(){...}
}
// Namespace Y
class B
{
public void methodB(){...}
}
In other code using A:
using X;
// do I need using Y?
...
A obj = new A();
obj.methodB(); // calls methodB() using instance of A
...
if A is in namespace X and B in Y, you can't do
// Namespace X
class A : B
{
...
};
you need to do:
class A : Y::B
{
...
};
So you see you had to inherit B using the qualification and there's nothing special going on there. This is in C++ btw.
If A needs anything more from Y it'll need to similarly qualify it.
Anybody using A needs to qualify it with X::A or import everything or just A, depending, to use it - using X::A; or using namespace X;. That has no effect on what happens to the visibility of things inside Y though.
The only thing that might surprise you is Koenig Lookup, so maybe read that.
No namespaces are not inherited by classes in C++ (and in C#). However due to the ADL (Argument Dependent Lookup) you can "inherit" some names from the namespace of a base class.
Here is a demonstrative program
#include <iostream>
namespace N1
{
struct A {};
void f( const A & )
{
std::cout << "N1::f( const A & )\n" << '\n';
}
}
namespace N2
{
struct B : N1::A
{
B() { f( *this ); }
};
}
int main()
{
N2::B b;
return 0;
}
Its output is
N1::f( const A & )
To "inherit" a namespace you can use the using directive in a namespace or in a block scope. For example
namespace N1
{
struct A {};
}
namespace N2
{
using namespace N1;
struct B : A
{
};
}
Take into account that you may not use the using directive in a class scope.
Or you can introduce only some names by means of a using declaration.
Classes do not inherit namespaces. using only imports the symbols in a namespace into the current source file. It has no effect on your classes themselves.
This C# code:
using System;
public class A {
public void Run() {
Console.WriteLine("Foobar");
}
}
Is completely equivalent in its effects, both in the CIL emitted as well as how users of A will use the class or derive it, to this code:
public class A {
public void Run() {
System.Console.WriteLine("Foobar");
}
}
Let's say that we import a type that we return from a method:
using System.IO;
public class A {
public Stream createStream() {
// implementation irrelevant
}
}
If we then declare class B : A in another source file, the createStream() method is inherited, and it still returns System.IO.Stream, even if the source file B is declared in doesn't have using System.IO, and users of class B do not need to import System.IO in order to use the stream returned by createStream(); the system knows the fully-qualified type is System.IO.Stream.
public class B : A {
public void doSomethingWithStream() {
// We can use a System.IO.Stream object without importing System.IO
using (var s = createStream()) {
}
}
}
public class C {
public static void doSomethingElseWithStream(B b) {
// As can other stuff that uses B.
using (var s = b.createStream()) {
}
}
}
No, there is no such thing as a inherited namespace.
Namespace does not have anything that can be derived/inherited.
If you want to inherit a class A that is in different namespace, you need to add "using namespace ..."
simple code here and the answers I find don't seem to work.
I'm using
SharpDevelop Version : 3.2.1.6466
.NET Version : 2.0.50727.5485
The problem is the error code
Expected class, delegate, enum, interface, or struct (CS1518).
Any ideas?
Program.cs codes:
using System;
using System.Threading;
namespace Threshold
{
public class Class1
{
public Class1()
{
Heritage YOLO = new Heritage();
YOLO.Fractal();
}
}
static void Main()
{
//do nothing
}
}
The cs file it calls is:
using System;
using System.Threading;
namespace Threshold
{
public class Heritage
{
int Fractal()
{
//Do stuff.
}
}
internal partial class DefineConstants
{
public const string DRIVERPATH = "d:\\tc\\bgi";
}
}
Please help with a fix.
Thanks.
Your main method is outside the class. Put it inside.
I am having a DLL file. With the use of DLL, I have to call the methods and add some more methods in my project. Now, I need to migrate the older DLL to Make that project as a new DLL. I done this But the problem is The C# code is converted to net module it shows two errors. I am not clear about that. kindly help me over it.
DLL Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace mcMath
{
public class mcMathComp
{
private bool bTest = false;
public mcMathComp()
{
// TODO: Add constructor logic here
}
/// <summary>
/// //This is a test method
/// </summary>
public void mcTestMethod()
{ }
public long Add(long val1, long val2)
{
return val1 - val2;
}
/// <summary>
/// //This is a test property
/// </summary>
public bool Extra
{
get
{
return bTest;
}
set
{
bTest = Extra;
}
}
}
}
CS Project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using mcMath;
namespace mcClient
{
class Program
{
static void Main(string[] args)
{
mcMathComp cls = new mcMathComp();
long lRes = cls.Add(23, 40);
cls.Extra = false;
Console.WriteLine(lRes.ToString());
Console.ReadKey();
}
}
}
Errors:
Program.cs(5,7): error CS0246: The type or namespace name 'mcMath' could >not be found (are you missing a using directive or an assembly reference?)
Tried Methods:
I will add the reference via Project-> Add Reference.
The using Reference also used.
Put the DLL into the current project debug/release folder
I'm guessing you used to have the code side by side, i.e.
public int Add(int a, int b)
{
return a + b;
}
public void SomeMethod()
{
var result = Add(2,3);
}
This works because the scope (this.) is applied implicitly, and takes you to the Add method on the current instance. However, if you move the method out, the scope is no longer implicit.
You will need one of:
the type name if it is a static method
or a static using if using C# 6
a reference to the instance if it is an instance method
Then you would use one of (respectively):
var result = YourType.Add(2,3); (plus using YourNamespace; at the top)
using static YourNamespace.YourType; at the top
var result = someObj.Add(2,3);
Checking the compiler message, it sounds like you've done something like (line 7):
using YourNamespace.YourType.Add;
which is simply wrong; you don't use using to bring methods into scope - only namespaces and (in C# 6) types.
Likewise, I suspect you have (line 22):
var result = YourNamespace.YourType.Add(x,y);
which is not valid as this is not a static method.
Create and Using DLL in same Project in c#
DLL or Class Library is a separate project that can be part of same solution.
As you already know, adding a reference to that dll/project will make it available in your app project.
However if function Add in dll is in different namespace (which would be normal) u would need to add using clause at the beginning of your class
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;