Ich versuche gerade in Java auf eine DLL zuzugreifen, die wiederum auf eine fertige DLL zugreift.
Dazu habe ich die üblichen Schritte getan: Java-Klasse mit nativen Methoden schreiben, kompilieren, JNI-Headerdatei erstellen, DLL mit VC++ 2005 erstellen. Alles ließ sich fein kompilieren, und jetzt beim Testen gibts ein Problem:
ZitatException in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: DMX.DMXController.startDevice()V
at DMX.DMXController.startDevice(Native Method)
Ich rufe zuerst init() auf, da passt noch alles. Erst beim aufrufen von startDevice() kommt die Fehlermeldung.
Die Java-Klasse:
public class DMXController
{
public static native void startDevice();
public static native void setData(long Channel, long Data);
public static native void setChannelCount(long Count);
public static native void stopDevice();
public static void init()
{
System.load(System.getProperty("user.dir")+"/light.dll");
}
}
Alles anzeigen
Die Header-Datei aus der JNI Kompilierung:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class DMXController */
#ifndef _Included_DMXController
#define _Included_DMXController
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: DMXController
* Method: startDevice
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_DMXController_startDevice
(JNIEnv *, jclass);
/*
* Class: DMXController
* Method: setData
* Signature: (JJ)V
*/
JNIEXPORT void JNICALL Java_DMXController_setData
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: DMXController
* Method: setChannelCount
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_DMXController_setChannelCount
(JNIEnv *, jclass, jlong);
/*
* Class: DMXController
* Method: stopDevice
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_DMXController_stopDevice
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
Alles anzeigen
Die Header-Datei light.h:
// light.h : Hauptheaderdatei für die light-DLL
//
#pragma once
#ifndef __AFXWIN_H__
#error "'stdafx.h' vor dieser Datei für PCH einschließen"
#endif
#include "resource.h" // Hauptsymbole
#include <windows.h>
#include <tchar.h>
#include "DMXController.h"
// ClightApp
// Siehe light.cpp für die Implementierung dieser Klasse
//
class ClightApp : public CWinApp
{
typedef void (__stdcall *PFNSTARTDEVICE)();
typedef void (__stdcall *PFNSETDATA)(DWORD dwChannel, DWORD dwData);
typedef void (__stdcall *PFNSETCHANNEL)(DWORD dwCount);
typedef void (__stdcall *PFNSTOPDEVICE)();
public:
ClightApp();
~ClightApp();
PFNSTARTDEVICE StartDevice;
PFNSETDATA SetData;
PFNSETCHANNEL SetChannelCount;
PFNSTOPDEVICE StopDevice;
// Überschreibungen
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
JNIEXPORT void JNICALL Java_DMXController_startDevice(JNIEnv *env, jclass c);
JNIEXPORT void JNICALL Java_DMXController_setData(JNIEnv *env, jclass c, jlong channel, jlong data);
JNIEXPORT void JNICALL Java_DMXController_setChannelCount(JNIEnv *env, jclass c, jlong count);
JNIEXPORT void JNICALL Java_DMXController_stopDevice(JNIEnv *env, jclass c);
private:
HMODULE hLib;
};
Alles anzeigen
und die light.cpp-Datei:
// light.cpp : Definiert die Initialisierungsroutinen für die DLL.
//
#include "stdafx.h"
#include "light.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//
//TODO: Wenn diese DLL dynamisch mit MFC-DLLs verknüpft ist,
// muss für alle aus dieser DLL exportierten Funktionen, die in
// MFC aufgerufen werden, das AFX_MANAGE_STATE-Makro
// am Anfang der Funktion hinzugefügt werden.
//
// Beispiel:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // Hier normaler Funktionsrumpf
// }
//
// Es ist sehr wichtig, dass dieses Makro in jeder Funktion
// vor allen MFC-Aufrufen angezeigt wird. Dies bedeutet,
// dass es als erste Anweisung innerhalb der
// Funktion angezeigt werden muss, sogar vor jeglichen Deklarationen von Objektvariablen,
// da ihre Konstruktoren Aufrufe in die MFC-DLL generieren
// könnten.
//
// Siehe Technische Hinweise für MFC 33 und 58 für weitere
// Details.
//
// ClightApp
BEGIN_MESSAGE_MAP(ClightApp, CWinApp)
END_MESSAGE_MAP()
// ClightApp-Erstellung
ClightApp::ClightApp()
{
hLib = LoadLibrary(_T("K8062d.dll"));
StartDevice = (PFNSTARTDEVICE)GetProcAddress(hLib, "StartDevice");
SetData = (PFNSETDATA)GetProcAddress(hLib, "SetData");
SetChannelCount = (PFNSETCHANNEL)GetProcAddress(hLib, "SetChannelCount");
StopDevice = (PFNSTOPDEVICE)GetProcAddress(hLib, "StopDevice");
}
ClightApp::~ClightApp()
{
FreeLibrary(hLib);
}
// Das einzige ClightApp-Objekt
ClightApp theApp;
// ClightApp-Initialisierung
BOOL ClightApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
JNIEXPORT void JNICALL Java_DMXController_startDevice(JNIEnv *env, jclass c)
{
ClightApp app;
app.StartDevice();
}
JNIEXPORT void JNICALL Java_DMXController_setData(JNIEnv *env, jclass c, jlong channel, jlong data)
{
ClightApp app;
app.SetData(channel, data);
}
JNIEXPORT void JNICALL Java_DMXController_setChannelCount(JNIEnv *env, jclass c, jlong count)
{
ClightApp app;
app.SetChannelCount(count);
}
JNIEXPORT void JNICALL Java_DMXController_stopDevice(JNIEnv *env, jclass c)
{
ClightApp app;
app.StopDevice();
}
Alles anzeigen
Die DLL wird gefunden, denn wenn ich für System.load() einen anderen Parameter angeb, schreit er. Auch wenn ich statt .load() .loadLibrary() verwend und die DLL ins system32-Verzeichnis kopier, kommt dasselbe raus.
Was kann da nicht stimmen?