PDA

Click to See Complete Forum and Search --> : [RESOLVED] loading C dlls in C#


nci
Oct 28th, 2007, 11:39 AM
hello,
i'm working on a way to load a dll i made in C into C#. I made a simple function that returns a string "hello" and C# calls this function and gets the string just fine. I then tried to pass a structure to C#, but this causes errors.

my C code structure
typedef struct _MY_STRUCT
{
int sName;
int sPhone;
}MY_STRUCT, *LPMY_STRUCT;


my C# structure

public struct MY_STRUCT
{
public int sName;
public int sPhone;
}



whenever I call

MY_STRUCT MyStruct = new MY_STRUCT();

//MessageBox.Show(Marshal.SizeOf(MyStruct).ToString());

//compiler doesnt like this line...
Marshal.PtrToStructure(GetString(), MyStruct);

MessageBox.Show(MyStruct.sName.ToString());
MessageBox.Show(MyStruct.sPhone.ToString());


I get a runtime error: "The structure must not be a value class.
Parameter name: structure"

I've also just tried doing this:

MyStruct = GetString(); //GetString is just the name of the function

but all i get is a runtime error saying type signiture is not compatible
by using sizeof, I know that both the C structure and the C# structure are 8 bytes long, but I dont know what else to do (and ive tried everything I could think of)

Please, could someone help me?

jmcilhinney
Oct 28th, 2007, 06:27 PM
I'm not sure why a method named "GetString" would return a structure with two int fields but, that aside, can we see the C definition of the function and also the C# declaration?

nci
Oct 29th, 2007, 12:10 AM
ok, i tried it with integers and still no luck, here is the code:


typedef struct _MY_STRUCT
{
int iName;
int iPhone;
}MY_STRUCT, *LPMY_STRUCT;


C_EXPORT LPMY_STRUCT __cdecl GetInterface (void)
{
static struct _MY_STRUCT XMPTagInterface;
memset(&XMPTagInterface,0,sizeof(XMPTagInterface));

XMPTagInterface.iName=1234;
XMPTagInterface.iPhone=5678;

return &XMPTagInterface;
}



thats how it is in the dll



in C#

public struct MY_STRUCT
{
public int iName;
public int iPhone:
}

[DllImport("tag_interface.dll")]
public static extern IntPtr GetInterface();
|--------------------i dunno if this is the right type
I also tried MY_STRUCT


//in some private meothod
MY_STRUCT MyStruct = new MY_STRUCT();

//compiler hates this line-----------------|
Marshal.PtrToStructure(GetInterface(), MyStruct);



says it cant be a value type structure :( I don;t event know what that means...lol
this code works fine when i load my test dll in my C app, but C# chokes on it
I dunno what to do. and sorry for the sadly written example

jmcilhinney
Oct 29th, 2007, 12:35 AM
There are two overloads of PtrToStructure. The one you are using cannot be used with value types, as the error message says. That means that the second parameter must be an instance of a class or other reference type, NOT a structure. If you want to marshal to a value type then you must use the other overload. In that case you specify the type and the method returns a boxed instance, which you must unbox by casting:MyStruct s = (MyStruct)Marshal.PtrToStructure(GetInterface(), typeof(MyStruct));

nci
Oct 29th, 2007, 01:47 AM
oh... :)
thanks!

wossname
Oct 29th, 2007, 07:42 AM
This would be easier to do with unsafe code but since you've got a working solution I won't bother going into detail unless you want me to.

nci
Oct 29th, 2007, 09:21 AM
yeah, i was trying to do it without unsafe code. but the whole reason i'm doing this in the first place, is becuase writing a plugin system in C# is a nightmare. So, i'm doing my plugins in C and my main app in C# (at least until I master C# dlls )

jmcilhinney
Oct 29th, 2007, 05:28 PM
writing a plugin system in C# is a nightmare.Since when? I've never done it myself but I've read about it and it seems pretty simple to me. What exactly is so nightmarish about it?

nci
Oct 29th, 2007, 06:19 PM
well, i viewed a few exaples and tutorials for it, but I'm soo lost. I just dont know enough about inheritence and interfaces yet. It just looks sooo complicated. eventually i'll understand it, but right now, its easier for me to manage plugins in C code

jmcilhinney
Oct 29th, 2007, 07:06 PM
It's actually not very complicated at all, but if you want to stick to C plugins for the moment then fair enough.

As for interfaces, they're pretty much like a C header file, with a list of methods but no implementation for any of them. Classes can then implement that interface by providing an implementation for each of the members it defines. You can then have various disparate types all able to be acst as the same type and therefore used in the same way.

For a real-life example, consider your computer and how many varied peripherals are attached to it, or could be attached to it. It's likely that many of those peripherals would have a USB interface. It doesn't matter what the peripherals do or how they do it, as long as they implement the USB interface your computer can talk to them.

Your app would be the same. You define the interface a plugin must implement. You can then load any and all plugins no matter what they do or how they do it. All your app cares about is that they implement your interface. The interface is just a bunch or method and property signatures. How each method and property is implemented is completely up to the discretion of the plugin author.

jmcilhinney
Oct 29th, 2007, 07:27 PM
Here's a quick code example:public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
Plugin1 p1 = new Plugin1();
Plugin2 p2 = new Plugin2();

this.AboutPlugin(p1);
this.AboutPlugin(p2);
}

private void AboutPlugin(IPlugin plugin)
{
plugin.About();
}
}


public interface IPlugin
{
void About();
}


public class Plugin1 : IPlugin
{
#region IPlugin Members

void IPlugin.About()
{
MessageBox.Show("All about Plugin1");
}

#endregion
}


public class Plugin2 : IPlugin
{
#region IPlugin Members

void IPlugin.About()
{
MessageBox.Show("All about Plugin2");
}

#endregion
}Note that the IPlugin interface declares a method named About that takes no parameters and returns no value. It provides no implementation, leaving that up to the classes that will implement the interface. The Plugin1 and Plugin2 classes both implement the IPlugin interface, and therefore implement the IPlugin.About method. Each class implements the method as it sees fit.

Withing the application the objects are treated as IPlugin objects, not there actual type. Because the IPlugin type has an About method we know we can call that method on any and all plugins.

In a real situation each of the plugin classes would be declared in its own DLL and you would load those DLLs at run time and access the class using reflection. That adds some complexity but it's still just a few lines of code to do that.

Paul M
Oct 30th, 2007, 03:59 AM
You could also abstract it a little and create a new instance by doing it like so...

IPlugin plgIn = new Plugin1();

jmcilhinney
Oct 30th, 2007, 04:20 AM
You could also abstract it a little and create a new instance by doing it like so...

IPlugin plgIn = new Plugin1();In a real situation you couldn't because you won't have compile-time references to the DLLs containing the plugins, so you won't know the Plugin1 type. You have to load the DLLs at run time and interrogate them using reflection.

Paul M
Oct 30th, 2007, 04:29 AM
Inside the DLL can't you do...

[assmebly: Plugin(typeof(myplugin))]

nci
Oct 30th, 2007, 09:30 AM
that was the first real example that made sense. See, normally for my C programs, i create a type structure that has all of the plugin details, like name, author, description, and a bunch of function pointers that are required (pretty much the interface) then I just pass the structure off to the app, and the app would call the plugin functions like


MyPlugin[2]->DoMath(2, 4); //what it does with 2 and 4 is up to the plugin


i like your example, jmcilhinney, it makes it look really simple. I've looked at all kinds of tutorials and my head was spinning. So, i may give this a shot.
All of the examples i've seen had an interface dll and also plugin dlls. Is this the way it has to be? or can an app just look at a directory and load all of the dlls in it?

currently, my C# app uses a dll that controls the other plugins, simply becuase I do not quiet no how to load dlls at runtime. I suppose i could import a LoadLibrary api, but, I didnt think of that till just now :)

anyway, i'm still learning C# and it is quickly becoming my favorite language.

jmcilhinney
Oct 30th, 2007, 06:31 PM
The general idea would be that you would have a folder dedicated to plugins, into which each author would install their DLL. An alternative could be that you have a registry key dedicated to storing the locations of plugin libraries, where each athor would add the path to their library and you'd read it from there.

You should take a look at the Assembly class, which is used to load assemblies at run time. I've never actually done this stuff myself so I don't know all the details, but basically you load the assembly and then interrogate it to find types that implement your plugin interface. The interrogation is done using reflection, which you can read about in the documentation for the System.Reflection namespace and the System.Type class.