我目前正在做一个项目,需要开发一个原生DLL(用C++)来访问Java应用程序。我选择了JNA来做桥接工作,我面临着从Java向C++函数传递正确的int值的问题。
简单地说,我有一个函数在C++中接受一个int值作为参数:(代码被剥离,方法被重命名以保持机密性)
JAVALINK_EXPORT SomeStructure WINAPI GetSomeStructureFromIndex(int index) {
std::string debugMsg("Received index of ");
debugMsg.append(toString(index));
OutputDebugString(debugMsg.c_str());
SomeStructure result = defaultStructure;
if (index >= 0 && index < structListSize)
result = structList[index];
return result;
}
ToString
是一种简单的方法,它使用std::StringStream
将任何数据类型的值转换为std::String
。执行情况如下:
template <class T>
inline std::string toString (const T& t) {
std::stringstream ss;
ss << t;
return ss.str();
}
somestructure
是从我在代码中使用的实际结构重命名的。structlist
是somestructure
的数组。structlistsize
和structlist
都是共享内存中的全局变量。
这是DLL的Java接口中的方法签名:
SomeStructure.ByValue GetSomeStructureFromIndex(int index);
这就是我对测试用例使用Java中的方法的方式:
SomeStructure.ByValue received = library.GetSomeStructureFromIndex(1);
Library
是使用Native.LoadLibrary
生成的DLL文件(StdCallLibrary
的子类)的接口实例。当上述代码在Java执行时,我在我的Windows调试输出中得到类似以下的输出:
Received index of 86701080
(如果在从数组中获取结构之前忽略了使用if(index>=0&&index
index
的检查,则程序将继续遇到访问冲突错误)
86701080
可以是任意值。我意识到它会根据导出函数的签名而改变。我是不是漏了什么?如果函数签名为void PrintIndex(int index)
,则函数正确地接收到1
的期望值
EDIT(0):我修改了示例代码,使其与实际代码更加匹配。
编辑(1):根据@Technomage的指针,我已经开始对所有方法签名和变量使用
byvalue
来收集返回的结构。
编辑(2):与C++中的
someStructure
结构相比,Java类someStructure
有一个额外的变量和一个Java方法。我正在测试这是否是造成差异的原因。
问题已解决
@Technomage解释说,要让C++函数按照预期解释其参数和返回值,用作返回类型的结构(以及用作函数参数的结构)的大小不应与Java对应的结构不同。在
SomeStructure
的情况下,在C++中使用sizeof(SomeStructure)
以及在Java中使用SomeStructure.size()
可以检查这一点。
基本上,
someStructure
结构的大小与其Java表示形式不同。SomeStructure
包含一个固定长度的数组,如下面的代码所示:
#define MAX_LIST_SIZE 256
typedef struct {
int list[MAX_LIST_SIZE];
int length;
} SomeStructure;
但是,Java表示没有指定定长数组的大小。
列表
已初始化为包含一个0
值。
package model;
import com.sun.jna.Structure;
public class SomeStructure extends Structure {
public static class ByValue extends SomeStructure implements Structure.ByValue { }
public int[] list = {0};
public int length = 0;
}
我通过用以下语句替换错误的初始化语句来解决问题:
private static final int MAX_LIST_SIZE = 256;
public int[] list = new int[MAX_LIST_SIZE];
注意:整数常量
max_list_size
声明为private
以使其仅适用于Java。
在做了所有这些修改之后,我的代码运行良好,不再遇到访问违规。
“winapi”意味着stdcall调用约定,但您必须查看宏的本地定义才能确定。如果是,则需要stdcalllibrary
而不是library
。这可能会影响传入的index
参数。
您还复制了您的结构(通过值语义),而不是指向它的指针。当您按值传递结构或按值返回结构时,您需要告诉JNA您正在这样做。
编辑
确保SomeStructure.Size()
与本机SizeOf(SomeStructure)
匹配。通常,由值返回的结构是这样实现的,即调用方在堆栈上分配内存,并将一个隐式指针传递给被调用方,然后被调用方写入该内存。如果调用方和被调用方在该内存的大小上存在分歧,则会影响堆栈上的其他东西(如参数和返回值)。您还可以向函数添加更多的参数,并打印它们的值(十六进制),以获得堆栈上的近似值。如果传入可识别的参数(例如0x12345678),就会很清楚是什么在向错误的方向推动或拉动堆栈。
问题内容: 在Java中,如何将一个函数作为另一个函数的参数传递? 问题答案: Java 8及以上 如果你的类或接口只有一个抽象方法(有时称为SAM type),则使用Java 8+ lambda表达式,例如: 然后可以在使用MyInterface的任何地方替换lambda表达式: 例如,你可以非常快速地创建一个新线程: 并使用方法引用语法使其更加清晰: 如果没有 lambda表达式,则最后两个示
我有一个Kotlin代码: 现在我想从Java类调用这个方法。我不知道该怎么称呼这个。这是我试过的 但它显示了以下错误。
问题内容: 我已经熟悉Android框架和Java,并希望创建一个通用的“ NetworkHelper”类,该类可以处理大多数联网代码,使我能够从中调用网页。 我遵循了来自developer.android.com的这篇文章来创建我的网络类:http : //developer.android.com/training/basics/network- ops/connecting.html 码:
假设我们有python中的函数: 虽然我可能会将传递给A,但我正在寻找一种优雅的方法来传递类似于的东西来执行。 我现在看到的唯一方法是发送一个函数列表并按顺序应用它们。有没有更好的办法?
最近我在使用c语言时遇到了一些问题,基本上是这样的: 在一个函数(比如intmain)中,我声明了一个变量Y=5,我有一个lambda函数,它接收一个值并将Y相加; 我的问题是:我需要将这个lambda函数传递给一个已经存在的函数,这样它就可以在另一个函数内部调用。 我尝试了几件事,但没有一个像我预期的那样工作(有些甚至不起作用): 另一个问题是我不能改变我的receives函数签名,因为代码的剩
在Python中,我可以很容易地将函数作为参数传递,并在另一个函数内部执行。