Обвийте DLL в Java

Имам някакъв код за комуникация с хардуерно устройство на Windows, което работи на C++. Кодът прави нещо доста просто, за да реагира на натискане на бутон на устройството и имам това, компилирано в dll с наблюдател, който се извиква при натискане на бутона. Сега трябва да свържа това с голяма Java програма.

Възнамерявах да използвам JNA, но работи само със C и не мога да видя как да направя това с модел Observer в C. Разгледах използването на BridJ и SWIG (и двата от които могат да работят върху C++ DLL), за да създам интерфейс към компилираната dll (със свързания заглавен файл), но BridJ създава огромни количества файлове (в JNAeratorStudio) и след това спира с грешка и не виждам как да започна на Windows с SWIG (използвам по-скоро Visual Studio Express отколкото пълното Visual Studio).

Някой знае ли за урок за интегриране на C++ DLL с Java програма - SWIG изглежда доста обещаващо, но уроците са "блатисти".

Поставих малко прост C код за комуникация с DLL по-долу:

#include <iostream>
#include <stdio.h>

#include "DeepFocusControlDll.h"

using namespace std;
using namespace DeepFocusControl;

class MyObserver : public DeepFocusControl::DeepFocusObserver{
    void Event(){
        printf("***Button Pushed***");
    }
};

int main()
{
    DeepFocusControl::AVA6Control* dfc = new DeepFocusControl::AVA6Control();
    MyObserver* observer = new MyObserver();
    dfc->AddObserver(observer);
    bool connected = dfc->IsConnected();
    printf("Connected %s\n", (connected)?"true":"false");
    bool connectresult = dfc->Connect();
    printf("Connecting %s\n", (connectresult)?"true":"false");
    connected = dfc->IsConnected();
    printf("Connected %s\n", (connected)?"true":"false");
    dfc->SetHardwareAppLaunch(false);
    char waitChar;
    cin >> waitChar;
    dfc->SetHardwareAppLaunch(true);
    dfc->RemoveObserver(observer);
    dfc->Disconnect();
    printf("Disconnected\n");
    cin >> waitChar;
}

Ако някой знае по-прост начин за използване на модел на наблюдател за това, с радост мога да прекодирам и страната C.


person Neil Benn    schedule 21.06.2012    source източник
comment
Нещото наблюдател се нарича обратно извикване в SWIG. Потърсете го на уебсайта на SWIG. Успех за вас.   -  person J-16 SDiZ    schedule 21.06.2012
comment
Възнамерявах да използвам JNA: нарича се JNI. И вие не трябва да прекодирате C++ страната, за да го използвате. Вие трябва да създадете JNI съвместим интерфейс към вашата съществуваща функционалност - това е всичко.   -  person paulsm4    schedule 21.06.2012
comment
Генерирах класове в SWIG, които изглеждат разумни, но няма привидна връзка между класовете и моя dll!   -  person Neil Benn    schedule 21.06.2012
comment
Не, имах предвид JNA: github.com/twall/jna. За JNI ще трябва да напиша нещо, което да интерпретира JNI извикванията към моите C++ извиквания. Ако ще го направя, мога също така да напиша обвивка на C и да използвам JNA.   -  person Neil Benn    schedule 21.06.2012
comment
Обратните извиквания на JNA ви позволяват да предоставите собствен код с указател на функция, който се преобразува обратно в извикване на метод на Java. Ще трябва да предоставите функция за глобален регистър от вашия собствен код, която ще зададе указател на функция, който да бъде извикан от вашия наблюдател. След това JNA може да извика функцията за регистриране с базиран на Java обект за обратно извикване.   -  person technomage    schedule 25.06.2012


Отговори (1)


Изглежда, че търсите функцията за директори на SWIG. В най-простата му форма можете да използвате директори със SWIG, като дадете интерфейсен файл като:

%module(directors=1) MyModule
%feature("director");         

%{
#include "mydll.h"
%}

%include "mydll.h"

При даден заглавен файл "mydll.h":

class Observer {
public:
  virtual void frobination() = 0;
  virtual ~Observer() {}
};

inline void bar(Observer *o) {
  o->frobination();
}

След това можете да стартирате SWIG:

swig -Wall -java -c++ mymodule.i

Това ще генерира три Java класа: MyModule, MyModuleJNI и Observer. От тях MyModule ще съдържа всички безплатни функции от вашия заглавен файл, изложени като static членски функции, тъй като Java няма такова нещо като безплатни функции. Можете спокойно да пренебрегнете MyModuleJNI - това е лепило, генерирано от SWIG за свързване на MyModule с реалните реализации на C++. Ще трябва да компилирате mymodule_wrap.cxx за MyModuleJNI (и следователно MyModule), за да работи правилно и да заредите DLL с помощта на System.loadLibrary, преди да извикате функции от тях.

Класът Observer директно съответства на интерфейса Observer в mydll.h. Трябва да извлечете от него в Java и да замените функцията frobinate, за да му дадете своя собствена реализация:

public class Test extends Observer {
  @Override
  public void frobination() {
    System.out.println("go go gadget frobinator");
  }

  public static void main(String[] argv) {
    System.loadLibrary("mymodule");
    Test t = new Test();
    MyModule.bar(t);    
  }
}

Което мога да компилирам и стартирам, за да направя точно това, което се надявате.

Ако искате, можете да автоматизирате обаждането до System.loadLibrary, като добавите:

%pragma(java) jniclasscode=%{
  static {
    try {
        System.loadLibrary("mymodule");
    } catch (UnsatisfiedLinkError e) {
      System.err.println("Native code library failed to load. \n" + e);
      System.exit(1);
    }
  }
%}

към вашия SWIG интерфейсен файл.

Ако вашият истински заглавен файл е толкова прост, трябва да е толкова прост, за да получите същите резултати. Ако е по-сложно, можете да инструктирате SWIG да обработи част от опаковката си по различни начини.

person Flexo    schedule 22.06.2012