Laden...

C++ DLL Aufruf in C#

Erstellt von SmokingFish vor 19 Jahren Letzter Beitrag vor 19 Jahren 5.309 Views
S
SmokingFish Themenstarter:in
4 Beiträge seit 2005
vor 19 Jahren
C++ DLL Aufruf in C#

Hi,

Also es geht darum :


#include <windows.h>

#define ST_BYREF   0x00000001L
#define ST_MATRIX  0x00000010L
#define ST_CLASS   0x00000100L

#define DLL_API __declspec(dllimport)

typedef void tvar;
typedef void app;
typedef void tbytecode;

typedef void (*_InitPPL) ();
[...]
typedef tvar *(*_SetVariable)(app *a, char *name, char *s, double d, char *ptr, int size);
[...]

HINSTANCE ppllib;
_InitPPL InitPPL;
[...]
_VSetVariable VSetVariable;
[...]

bool InitializePPL ()
{
	HINSTANCE h = LoadLibrary(TEXT("ppl.dll"));
	ppllib = h;
	if (h != NULL)
	{
		InitPPL = (_InitPPL)GetProcAddress(h, TEXT("InitPPL"));
                [...]
		VSetVariable = (_VSetVariable)GetProcAddress(h, TEXT("VSetVariable"));
                [...]
                InitPPL();
                return true;
        }
return false;
}

halt n normaler c++ header für funktionen einer dll die ich gerne benutzen würde.
mein versuch das in c# zu schreiben sieht so aus :


protected delegate void tvar();
protected delegate void app();
protected delegate void tbytecode();
		
[DllImport("ppl.dll")]
protected static extern uint InitPPL();

[...]

[DllImport("ppl.dll")]
protected static unsafe extern tvar SetVariable(app *a, char *name, char *s, double d, char *ptr, int size);

[...]

public void Initialise()
{
	InitPPL();
}


das endet beim compilen damit : "cannot take the address or size of a variable of a managed type (...app)"

ich hab erst vor kurzem mit c# begonnen und weiss eigentlich gar nicht wie ich das richtig angehn soll. ich bin mir sicher das lässt sich ganz anders viel besser - und vor allem mit funktion lösen^^

also i wär jedem sehr verbunden der mir da weiterhelfen kann.

mfg

95 Beiträge seit 2005
vor 19 Jahren

Versuchs mal so:


[DllImport("ppl.dll")]
protected static extern tvar SetVariable(app a, char name, char s, double d, char ptr, int size);

Normalerweise musst du in C# nicht angeben, dass es sich um ein Pointer hadelt. Da eine Referenz übergeben wird und die C++ Funkion auf die Speicherstellen zugreift.

Also zumindest hat das bei mir bisher immer funktioniert.

Falls es sich bei Char s um eine Zeichenkette handeln kannst du ein C# String verwenden.

Ich hoffe ich konnte dir ein bissi weiterhelfen.

Gruß

LordK

Programmieren in C# hält die grauen Zellen am Leben.
Es schärft alle fünf Sinne: den Schwachsinn, den Blödsinn, den Wahnsinn, den Unsinn und den Stumpfsinn.

S
SmokingFish Themenstarter:in
4 Beiträge seit 2005
vor 19 Jahren

danke dir, es lässt sich zumindest jetzt compilen =) ob es denn letztendlich funktioniert finde ich auch noch raus^^

noch eine kleinigkeit :

typedef void (*_NewFunction) (char *name, void *pointer, int in, int out);
protected static extern uint NewFunction(char name, void pointer, int _in, int _out);

das void pointer, es soll an der stelle wohl der pointer auf eine c++ funktion übergeben werden , void is in c# allerdings nicht erlaubt , gibt es da eine alternative?

95 Beiträge seit 2005
vor 19 Jahren

Original von SmokingFish
danke dir, es lässt sich zumindest jetzt compilen =) ob es denn letztendlich funktioniert finde ich auch noch raus^^

noch eine kleinigkeit :

typedef void (*_NewFunction) (char *name, void *pointer, int in, int out);  
protected static extern uint NewFunction(char name, void pointer, int _in, int _out);  

das void pointer, es soll an der stelle wohl der pointer auf eine c++ funktion übergeben werden , void is in c# allerdings nicht erlaubt , gibt es da eine alternative?

Hm is mir jetzt nichts bekannt. Vielleicht könntest du mal probieren das Void einfach weg zu lassen. Falls da auch nichts übergeben werden soll, könntest du "null" verwenden. Damit würdest du aber nur die Parameterliste füllen und nichts übergeben.

Aber das man irgendetwas in c++ void übergeben kann wusste ich auch nicht.

Gruß

LordK

Programmieren in C# hält die grauen Zellen am Leben.
Es schärft alle fünf Sinne: den Schwachsinn, den Blödsinn, den Wahnsinn, den Unsinn und den Stumpfsinn.

S
SmokingFish Themenstarter:in
4 Beiträge seit 2005
vor 19 Jahren

leider doch..allerdings hab i noch ganz andere probleme ^^

i fang ma an :



[DllImport("ppl.dll")]
protected static extern tvar GetVariable(app a, string name,ref string s,ref double d, string ptr);

public string GetVariable(string Variable)
{
	string s = "";
	double d = 0;
		
	tvar v = GetVariable(null,Variable,ref s,ref d, null);

	return s;
}


erstma das , eigentlich sollte das doch jetzt stimmen (der aufruf), allerdings bekomm i für die zeile "tvar v = .." den fehler "function pointer was not created by a delegate" (also compiliert , beim testen der funktion)

problem 2 :


void testfunc ()
{

}

NewFunction("testfunc", &testfunc, 1, 0);

also i muss irgentwie die testfunc als parameter übergeben, nur wie is mir ein rätsel wenn es "void" als typ in c# nicht gibt.

95 Beiträge seit 2005
vor 19 Jahren

Du solltest die Variablen nicht mit ref übergeben. Der C-Code geht automatisch auf die Speicherstelle der Variablen.

Programmieren in C# hält die grauen Zellen am Leben.
Es schärft alle fünf Sinne: den Schwachsinn, den Blödsinn, den Wahnsinn, den Unsinn und den Stumpfsinn.

M
456 Beiträge seit 2004
vor 19 Jahren

Für void* schreibt man IntPtr wenn es safe Code sein soll.
Wenn du deinen Code als unsafe markierst, kannst du auch ganz normal Pointer nehmen.

Wichtig ist nur, dass die Funktionen wenn sie mit nem C++ Compiler kompiliert wurden, als extern "C" deklariert werden. (Stichwort: Name Mangling)

tvar, app und Andere kannst du natürlich nicht nutzen. Du musst schon die Datentypen des CTS nehmen 😉

Außerdem solltest du auch auf den richtigen Namen für die Funktion achten. In deinem Code unten heißt die Funktion die du lädst "VSetVariable". In deinem C#-Code schreibst du aber nur "SetVariable". (EntryPoint benutzen)

DllImport noch mal kurz erklärt:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcwlkSysimportAttributeTutorial.asp

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.

S
SmokingFish Themenstarter:in
4 Beiträge seit 2005
vor 19 Jahren

das ich void* nutzen kann wenn ich unsafe benutze hab i auch rausgefunden. app usw scheine ich wirklich nicht nutzen zu können ohne die typen wirklich zu kennen (im orginal c++ code hat das funktioniert). aber die sind für die funktionen die ich brauche nicht notwendig. und das Get/Set Variable, das sind 2 funktion je, VSet/VGet gibt es auch noch. ne letzte frage noch (hoffe es is die letzte^^) : wenn ich nun void* als parameter habe, wie kann ich ich eine normale funktion als parameter übergeben? (void*) zum umwandeln funzt net, da wird bestimmt ne funktion geben^^

M
456 Beiträge seit 2004
vor 19 Jahren

Wenn du einen Funktionszeiger als Paramter für eine andere Funktion übergeben willst (Callback-Funktion), dann musst du einen Delegaten nutzen.
Wie sowas aussieht kannst du hier sehen:
http://www.dotnet247.com/247reference/msgs/55/276613.aspx

Im 2.0 Framework gibt es sogar die Möglichkeit einen nativen Function-Pointer direkt in einen Delegaten umzuwandeln.

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.