# Probleme mit Methodenaufruf von Klasse in dll (jni)



## dan72 (11. Sep 2006)

Hallo !

Ich glaub, ich habe ein Verständnisproblem zu jni.
Ich habe jetzt schon einige Beispiele ergoogeld aber nichts hat geholfen.
Folgendes Problem:
Ich habe eine DLL zur Verfügung gestellt bekommen.
In dieser DLL ist die Java Klasse JobInterface.
Von JobInterface wurde eine Headerdatei erstellt.
Diese Headerdatei ist in einer C++ Klasse eingebunden, die die Methoden enthält, die in
der JobInterface Klasse als native deklariert sind. Außerdem wird 
Beispiel:

```
public class cSiqJobInterface
{



//------ Definition der nativen Funktionen für diese Klasse ------

   
  public static native int ErledigeJob( int l, int l2 );
```
Hieraus wurde die DLL binder.dll erstellt.
Ich habe nun eine Java Klasse erstellt, in der ich die dll einbinden möchte, um 
die Funktionen der Klasse JobInterface in der dll zu nutzen.
Diese Klasse liegt im gleichen Verzeichnis wie die dll.

Codeauschnitt von aufrufender Klasse:

```
public class TryDLL {
	
	
	public static void main(String[] args) {
		
		
		//dll einbinden mit pfad
		//System.load("C:\\workspace\\dllprojekt\\binder.dll");
		
		
}
```
Beim einbinden der dll bekomme ich keine Fehlermeldung.
Ich weiß nur nicht, wie ich nun an die Funktionen rankomme.
Ich habe schon versucht ein Objekt von JobInterface zu erstellen oder die Methoden direkt aufzurufen
oder statisch.es wird aber nichts erkannt z.B.:
JobInterface cannot be resolved to a type

Ich denke, daß ich Grundsätzlich etwas falsch mache.
Bin für jede Anregung und Hilfe dankbar.


Gruß dan


----------



## Gast (11. Sep 2006)

> In dieser DLL ist die Java Klasse JobInterface.


in einer DLL ist keine Java Klasse, das ist eine native Library

du musst die methoden in cSiqJobInterface benutzen


----------



## Guest (11. Sep 2006)

Ja Genau!
Das mit dem Objekt erzeugen war auch nur aus Verzweiflung 
Ich habe auch versucht die Methoden direkt in meiner aufrufenden Klasse TryDLL aufzurufen.
Aber wenn ich z.B. ErledigeJob( 1, 1 ) aufrufe, wird diese Funktion dann als Funktion der Klasse TryDLL erkannt - und die gibt es ja nicht :-(
Wie rufe ich diese Methoden also auf?
Genau das ist mein Problem.

Gruß Dan


----------



## Lord BenneX (11. Sep 2006)

Funktioniert es so nicht?


```
cSiqJobInterface.ErledigeJob(1,1);
```

Gruß

Lordy


----------



## thE_29 (12. Sep 2006)

Ein Dll kann man nicht mit Pfad laden!

Der muss schon in einem library Pfad sein oder im aktuellen Verzeichnis!


----------



## Anmeldeboykottierer (12. Sep 2006)

Hi,
ich glaube du machst da noch ein paar Kleinigkeiten falsch.
Die Bibliothek wird mit System.LoadLibrary geladen. 
Zudem gehört das Laden der Bibliothek in die Klasse, die die Methoden anbietet. Die nativen Methoden sollen letztlich gegen die dyn. Bibliothek gelinkt werden.
Du hättest also Code der Form:

```
public class cSiqJobInterface 
{ 
//------ Definition der nativen Funktionen für diese Klasse ------ 
 public static native int ErledigeJob( int l, int l2 );

  static {
    System.loadLibrary(DLL/SO);
  }
}

public class TestDll {
  public static void main(String[]  args)  {
    cSiqJobInterface.ErledigeJob(1,1);
  }
}
```

Wobei die Bennenung hier vollkommen gegen die Konventionen ist. Klassen und Interfaces beginnen mit einem Großbuchstaben, Methoden mit einem Kleinen.
Du schreibst diese .java Datei, erzeugst dir dazu den Header und dann implementierst mit diesem die dyn. Bibliothek. 
Diese wird mittels static dort gelinkt, wo sie auch benötigt wird (in der klasse, die native Methoden anbietet).

Gruß Der Anmeldeboykottierer


----------



## Guest (12. Sep 2006)

Hi Lord BenneX!

Dachte ich auch. So sieht meine aufrufende Klasse aus.


```
class TryDLL {
	
	public static void main(String[] args) {
		
		new cSiqJobInterface().ErledigeJob(1,1);
		
	}

}
```

Wie gesagt ist cSiqJobInterface die Klasse, wo die nativen Methodendeklarationen sind und von der die Headerdatei für die c++ Klasse mit den Methodenimplementationen erstellt wurde. Die DLL wird auch in dieser Klasse geladen.
Die Klasse und Methode sollte doch erst erkannt werden, wenn das Programm läuft, da es ja dynamisch eingebunden wird. 
Es wird aber immer gesagt, daß die Klasse oder der Typ nicht aufgelöst werden kann, wenn ich die TryDLL kompiliere:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	cSiqJobInterface cannot be resolved to a type

	at TryDLL.main(TryDLL.java:7)


Hi thE_29
Die DLL binder.dll ist im aktuellem Verzeichnis.
Und ist es nicht so?(aus der javadoc):

public static void load(String filename)
Loads a code file with the specified filename from the local file system as a dynamic library. 
The filename argument must be a complete path name. 

und mit LoadLibrary wird kein  path mitgegeben?

Gruß Dan


----------



## dan72 (12. Sep 2006)

Hallo Anmeldeboykottierer!

Hab' doch tatsächlich deinen Eintrag übersehen   
Genau so geschieht es auch.
Die dll wird mit loadLibrary in der Klasse mit den nativen Methoden aufgerufen.
Hatte Sie nur nochmal in meiner aufrufenden Klasse geladen, da es nicht geklappt hat aber wieder rausgeschmissen.
Meine aufrufenden Klasse sieht folgendermaßen aus:

```
class TryDLL {
	
	public static void main(String[] args) {
		
		new cSiqJobInterface().ErledigeJob(1,1);
		//cSiqJobInterface.ErledigeJob(1,1);
               

		
		
	}

}
```
Habe die beiden Aufrufe der Methode probiert aber funzt net.
Fehlermeldung:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	cSiqJobInterface cannot be resolved

	at TryDLL.main(TryDLL.java:8)

Die Klasse ist unbekannt :-(

Für die Konventionsverletzung kann ich nichts.
Ich habe die dll zur Verfügung gestellt bekommen, zusammen mit der Headerdatei von cSiqJobInterface.
Ich habe also keinen Einblick in die Codeimplementierung.

Gruß Dan


----------



## Anmeldeboykottierer (12. Sep 2006)

Äh, wieso seh ich das erst jetzt?! Lass mal das static weg. Dann stimmt einerseits dein new Operator wieder, andererseits glaube ich kann das so auch nicht funktionieren. 
Static bindet eine Methode statisch ein, der Aufruf erfolgt aber durch das Linken gegen eine dynamische Bibliothek, ich denke hier kann es leicht zu einem Fehler kommen (wie will man etwas dyn. und statisch linken?). 
Da die Adresse der Methode erst zur Laufzeit ermittelt wird, kannst du hier nicht statisch linken (behaupte ich mal), wahrscheinlich kracht es einfach an der Stelle.

Gruß Der Anmeldeboykottierer


----------



## Anmeldeboykottierer (12. Sep 2006)

Um Missverständnissen vor zu beugen, ich nochmal:
Ich meinte das static vor dem native!


----------



## thE_29 (12. Sep 2006)

static vor native geht ganz normal!

Poste mal die gesamte Exception!


----------



## Guest (12. Sep 2006)

Erst einmal danke für eure Hilfe.

Folgendes ist schon alles, was eclipse ausschmeißt:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
cSiqJobInterface cannot be resolved

at TryDLL.main(TryDLL.java:8)

Der Entwickler, von dem ich die dll habe, hat die dll erfolgreich in seiner Umgebung am Laufen gehabt.
Deswegen muss das mit dem static, wie the_29 schon sagte, auch stimmen.
Die dll ist ja im gleichen Verzeichnis wie die aufrufende Klasse.
Aufgerufen habe ich die Methoden schon auf unterschiedlichste Weise, da ich in Tutorials jeweils unterschiedlich Möglichkeiten gesehen habe.
Wenn es wirklich so ist, das es reicht die dll im gleichen Verzeichnis zu haben (braucht den Pfad der dll also nicht bekannt machen) und es reicht die native Funktion in ein Java Klasse mit z.B. cSiqJobInterface.ErledigeJob(1,1);  aufzurufen, dann kann ja eigentlich nur was an der dll nicht stimmen... denke ich.
Es ist doch so, das der Compiler nach der Klasse in der dll sucht(im aktuellen Verzeichnis) wenn er keine anderen Informationen über die Klasse hat?
Ich habe auch schon ein Tutorial gesehen, in dem die native Methode direkt aufgerfuen wird.
In meiner aufrufenden Klasse würde dann einfach stehen:


```
public class TryDLL 
{
	public static void main(String[] args) 
	{
		ErledigeJob(1,1); 
	}
}
```

aber da habe ich die Exception:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	The method ErledigeJob(int, int) is undefined for the type TryDLL

	at TryDLL.main(TryDLL.java:5)

Wird also gar nicht als native Methode erkannt.
Ich habe nicht mehr die geringste Ahnung, was ich noch versuchen kann.
Vielleicht habt ihr ja noch eine letzte Idee.

Gruß Dan


----------



## thE_29 (13. Sep 2006)

Wie hast du die dll gelinkt?

Wenn du es mit GCC gemacht hast, nimm den MS Compiler (Visual Studio express ist gratis)

Ich habe noch nie ne DLL mit gcc zum Laufen gebracht!


----------



## Anmeldeboykottierer (13. Sep 2006)

Hi,
was du hier machst ist ja auch falsch. Die native Methode liegt nicht in der Klasse TryDll. Also musst du die schon aus der Klasse heraus aufrufen, zu der die native Methode gehört.
Für diese ist wichtig, dass die im gleichen Package liegt, wie beim Ersteller der dll (sonst gibt es auch hier wieder probleme).


----------



## Guest (13. Sep 2006)

Hallo!

@the_29
Laut Entwickler ist es mit Visual Studio gelinkt.
Ich habe da auch keine Möglichkeit etwas zu machen, da ich nur die dll habe, die ich nutzen möchte.

@Anmeldeboykottierer
Den Aufruf nur mit der Methode ist auch nur eine Beschreibung gewesen.
Ich habe auch versucht mit der Klasse aufzurufen. Ich habe das mit dem Direktaufruf einer Methode in einem Tutorial gesehen. Wollte damit nur sagen, daß ich in der Hinsicht schon einiges probiert habe.
Das mit dem Package hört sich aber interessant an.
Ich habe Die Aufrufende Klasse und die dll im gleichen Verzeichnis. Muss ich noch irgendwas mit packages machen damit die dll und damit die Klasse mit den nativen Methoden angesprochen werden kann???

Gruß dan


----------



## thE_29 (13. Sep 2006)

Die packages dürfen NIEMALS nach dem linken der DLL geändert werden!

Siehe hier: http://www.java-forum.org/de/viewtopic.php?t=36236

Also wenn der Entwickler das package bla.hubert; hatte wie er die dll erstellt hat, so muss du dieses Package auch haben und die Klasse auch!


----------



## Guest (13. Sep 2006)

Ich schick jetzt ers einmal die dll mit meinem Aufruf zurück.
Mal sehen was sich ergibt. werde ich dann posten.

Vielen Danke erst einmal.


----------



## dan72 (17. Sep 2006)

Hallo an Alle !

Jetzt habe ich mal alle Informationen zusammengestellt, die ich zur Verfügung stellen kann.
Vielleicht habe ich ja bisher Informationen nicht richtig dargestellt. 
Ich habe die Dll siqCnn.dll. Diese habe ich mal mit dem Programm Dependency Walker untersucht.
Dort konnte ich auch durch die Einträge erkennen, daß die Klasse cSiqJobInterface und die Funktion 
SetJob in der DLL vorhanden sind.
Hier mal die Darstellung im Dependency Walker: 

_Java_siq_cSiqJobInterface_SetJob@16

Hier ist auch zu sehen, das alles im Verzeichnis ( package) siq vorhanden ist oder war.
Ich habe mir auf meinem Rechner nun das Verzeichnis dllloader erstellt.
Hier habe ich die Java Klasse, die die Klasse cSiqJobInterface in meiner dll aufrufen soll.
Aufrufende Klasse TestFile.java im Ordner dllloader lautet wie folgt:


```
import siq.*;

public class TestFile 
{
	public static void main(String[] args) {
		
		
		 //new siq_cSiqJobInterface().SetJob(0,1);//so hab ich's auch probiert
		 cSiqJobInterface c = new cSiqJobInterface();
		 c.SetJob(0,1);
		System.out.println(System.getProperty("java.library.path"));//mal die LD_LIBRARY_PATH ausgeben
	}
}
```
Nun habe ich das Unterverzeichnis siq erstellt. Hier befindet sich nun meine siqCnn.dll.
Wenn ich nun die TestFile kompiliere und ausführe, bekomme ich folgende Meldung:

TestFile.java:15: cannot find symbol
symbol  : class cSiqJobInterface
location: class TestFile
					 cSiqJobInterface c = new cSiqJobInterface();

2 errors

Ich denke, ich habe alles aufgeführt. Ich kommentiere alles bis auf den java.library.path aus.
Dann kann man noch die Einträge in der LD_LIBRARY_PATH sehen.
Ein kleiner Auschnitt:

C:\WINDOWS\system32;.;C:\WINDOWS\system32;C:\WINDOWS; usw. 

Die dll habe ich auch mal im Ordner system32 gepackt.

@thE_29 ________________________________________________

Ich mache irgendwie immer den gleichen Fehler.
Ich habe mal versucht deine DLL anzusprechen, die du mir als link gesetzt hast.
Ich habe im Verzeichnis dlltest wieder eine aufrufende Klasse für die dll:


```
import at.jta.process.*;


public class TestFile 
{
	public static void main(String[] args) {
		Win32Killer w = new Win32Killer();
	}
}
```

Einfach nur um ein Objekt einer deiner Klassen zu erzeugen.
Dann habe ich die Unterverzeichnisse für das package erzeugt.
Erst das Verzeichnis at, darin jta und darin das Verzeichnis process.
Dort habe ich dann deine dll.
Wenn ich die Klasse TestFile ausführe, habe ich fast genau die gleiche Ausgabe wie mit meiner siqCnn.dll:

TestFile.java:7: cannot find symbol
symbol : class Win32Killer
location: class TestFile
					 Win32Killer w = new Win32Killer();

Es wird vorher auch noch gemeckert, daß es das package net gibt.
TestFile.java:1: package at.jta.process does not exist
import at.jta.process.*;

Ich weiß wirklich nicht, wo ich einen Fehler mache.
Hoffe Jemand kann mir weiterhelfen.

Gruß Dan[/code]


----------



## thE_29 (18. Sep 2006)

Du musst schon alle Klassen von http://www.java-forum.org/de/viewtopic.php?t=36236 hier übernehmen dass das ganze auch klappt (mit packages)

Nur die dll alleine beinhaltet doch keine Java Klassen!


----------



## dan72 (18. Sep 2006)

Hi thE_29!

Der letzte Satz hat's gebracht. Ich glaube ich hab's jetzt.
Ich bin ganz falsh rangegangen, weil ich am Anfang nur die DLL bekommen habe und damit habe ich dann angefangen zu arbeiten. Vielen Dank nochmal. Ich probier gleich nochmal die "Funktionen" in der dll anzusprechen.


Gruß Dan


----------

