vel*_*tis 5 c# java jna new-operator visual-c++
我试图使用JNA在C#和Java之间建立一个回调接口.
C# < - CLI - > Visual C++ 2010 < - JNA - > Java
在Java和C++之间我使用非托管结构来获得回调功能.在C++中,我试图将具有回调指针的结构包装到托管对象中.
在Java和C++之间,一切正常,直到我尝试使用gcroot在非托管代码中生成托管对象.
更新它甚至没有gcroot失败.只需使用"Logger ^ logger = gcnew Logger(logStruct);"
我目前的解决方案如下:
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"});
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
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();
};
}
Run Code Online (Sandbox Code Playgroud)
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
}
}
Run Code Online (Sandbox Code Playgroud)
我在飞行中写了这些.我希望这些也可以验证.
我究竟做错了什么?例如,如果我使用...
gcroot<System::String^> str = gcnew System::String("");
Run Code Online (Sandbox Code Playgroud)
......一切正常
是否有另一种方法将托管对象传递给C#?
记录此错误日志
UPDATE
似乎任何我自己的Class用法都会让我失败.
UPDATE
我自己管理的对象或函数的Anykind使我失败.
UPDATE
StaticCSharpClass :: STATICMETHOD(); 也失败了.看起来所有与托管对象相关的操作都会失败.
UPDATE
如果我从.NET调用相同的方法,一切正常.
只是为了让这个问题更容易找到 内部错误(0xe0434352)
应该用谷歌搜索错误“内部错误(0xe0434352)”。
http://jira.talendforge.org/browse/TDI-19427
这表明我必须为 GAC(全局程序集缓存)注册 dll,因为 Java 仅在 GAC 和应用程序基目录中搜索 dll。因为 Java.exe 路径不可配置。
使用构建后事件为 GAC 注册程序集:
gacutil /i "$(TargetPath)"
Run Code Online (Sandbox Code Playgroud)
很棒的独白!=)