Я пытаюсь создать интерфейс обратного вызова между C # и Java, используя JNA.
C # <- CLI -> Visual C ++ 2010 <- JNA -> Java
Между Java и C ++ я использую неуправляемые структуры для получения функций обратного вызова. В C ++ я пытаюсь обернуть структуру с указателями обратного вызова в управляемый объект.
Между Java и C ++ все работает, пока я не пытаюсь использовать gcroot для генерации управляемого объекта в неуправляемом коде.
ОБНОВЛЕНИЕ это даже не работает без gcroot. Просто с помощью «Logger ^ logger = gcnew Logger (logStruct);»
Мое текущее решение выглядит следующим образом:
Java
LoggerStruct.java
package jnatest;
import com.sun.jna.Callback;
import com.sun.jna.Structure;
import java.util.logging.Logger;
public class LoggerStruct extends Structure {
private Logger logger;
public interface GetLevelCallback extends Callback {
int callback();
}
public GetLevelCallback getLevel;
public LoggerStruct(Logger log) {
super();
this.log = log;
getLevel = new GetLevelCallback() {
public int callback() {
return logger.getLevel().intValue();
}
}
setFieldOrder(new String[] {"getLevel"});
}
}
ITestLib.java
package jnatest;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface ITestLib extends Library {
ITestLib INSTANCE = (ITestLib) Native.loadLibrary("JNATestC", ITestLib.class);
int callbackTest(LoggerStruct logStruct);
}
Main.java
package jnatest;
import com.sun.jna.NativeLibrary;
import java.util.logging.Logger;
import java.util.logging.FileHandler;
public class MainClass {
public static void main(String[] args) throws Exception {
NativeLibrary.addSearchPath("JNATestC", "C:\\JNATest");
Logger log = Logger.getLogger("Test");
FileHandler fileTxt = new FileHandler("Logging.txt");
log.addHandler(fileTxt);
LoggerStruct logStruct = new LoggerStruct(log);
ITestLib.INSTANCE.callbackTest(logStruct);
}
}
C ++
JNATestC.h
#pragma once
extern "C" {
struct LoggerStruct {
int (*getLevel)();
}
__declspec(dllexport) void callbackTest(LoggerStruct * logStruct);
}
namespace JnaWrapperTypes {
public ref class Logger { // "public ref" because I have to use it in C# as well
private:
LoggerStruct * logStruct;
public:
Logger(LoggerStruct * logStruct);
~Logger() {}
int getLevel();
};
}
JNATestC.cpp
#include "stdafx.h"
#include <vcclr.h>
#include "JNATestC.h"
namespace JnaWrapperTypes {
Logger::Logger(LoggerStruct * logStruct) {
this->logStruct = logStruct;
}
Logger::getLevel() {
return logStruct->getLevel();
}
}
using namespace JnaWrapperTypes;
using namespace StaticCSharpNamespace; // Just an example. Not existing C# lib.
extern "C" {
__declspec(dllexport) void callbackTest(LoggerStruct * logStruct) {
int level = logStruct->getLevel();
gcroot<Logger^> logger = gcnew Logger(logStruct); // IF I ADD "gcroot" FOR "Logger" THEN WHOLE INVOKE FAILS
level = logger->getLevel();
StaticCSharpClass::staticMethod(logger); // I want to pass Managed object to C# later
gcroot<System::String^> str = gcnew System::String(""); // This doesn't generate error
}
}
Я написал это на лету. Я надеюсь, что они подтверждают и.
Что я делаю не так? Например, если я использую ...
gcroot<System::String^> str = gcnew System::String("");
... все работает просто отлично.
Есть ли другой способ передать управляемый объект в C #?
Журнал этой ошибки Журнал
UPDATE
Кажется, что любое использование моего Класса приведет меня к провалу.
UPDATE
Любое использование моего управляемого объекта или функции приводит меня к неудаче.
UPDATE
StaticCSharpClass :: STATICMETHOD (); тоже не получается. Похоже, что все операции, связанные с управляемыми объектами, не выполняются.
UPDATE
Если я вызываю тот же метод из .NET, все работает нормально.
только для того, чтобы сделать эту проблему более доступной
Внутренняя ошибка (0xe0434352)