JNA传递引用到字节数组的操作无法正常工作

huangapple go评论136阅读模式
英文:

JNA passing Reference to Byte Array does not work correctly

问题

我的本地代码是:

int xlSetApplConfig(
    char *appName,
    unsigned int appChannel,
    unsigned int hwType,
    unsigned int hwIndex,
    unsigned int hwChannel,
    unsigned int busType)

我尝试在Java中使用指针来表示appName,就像这样:

// 整数..
byte[] appnamebyte = new String("JEdit").getBytes();
Pointer appname = new Memory(appnamebyte.length);
appname.write(0, appnamebyte, 0, appnamebyte.length);
int status = dll.INSTANCE.xlOpenPort(portHandle, appname, channelMask, permissionMask, 
    rxQueueSize,
    xlInterfaceVersion, busType);

该函数将字节数组写入注册表或其他地方,通过另一个给定的工具,我可以读取该值。
如果我启动我的代码,没有错误,但appname并不总是正确的。有时候会有比我想要的更多的字符("JEdit ?78ê")。
也许分配了比我想要的更多的内存。
我还尝试过传递一个普通的byte[],但问题仍然存在。

英文:

my native code is:

int xlSetApplConfig(
char *appName,
unsigned int appChannel,
unsigned int hwType,
unsigned int hwIndex,
unsigned int hwChannel,
unsigned int busType)

I tried to express appName with a Pointer in Java like this:

    //integers..
    byte[] appnamebyte = new String("JEdit").getBytes();
    Pointer appname = new Memory(appnamebyte.length);
	appname.write(0, appnamebyte, 0, appnamebyte.length);
	int status = dll.INSTANCE.xlOpenPort(portHandle, appname, channelMask, permissionMask, 
    rxQueueSize,
	xlInterfaceVersion, busType);

the function is writing the byte array to the registry or somewhere and with a other Tool(given one) I can read the value.
If I start my code there is no error but the appname is not allways correct. Sometimes there are more charcacters than i want("JEdit ?78ê").
Maybe somehow more memory than I want is allocated.
I also tried to pass an normal byte[] but with the same problem

答案1

得分: 1

遇到的问题是 C 字符串必须以 null 结尾。仅从 String 中获取字节只会得到字符 J、E、d、i 和 t。你的数组需要有第六个字节,其值为 0,以使其正常工作。

一种方法是保持你目前拥有的 Pointer 映射,并且自己分配额外的字节,然后使用 Pointer.setString() 将字节写入该本地内存:

Memory buffer = new Memory(6);
// 确保最后一个字节为 0
memory.clear(); // 也可以只设置最后一个字节
buffer.setString(0, "JEdit");

(注意,这依赖于默认的平台编码,通常不是一个好主意。你应该指定编码;在这种情况下,US-ASCII 应该可以工作。)

除了使用 setString(),你还可以像现在使用 write() 一样继续保留,并使用以 0 结尾的 byte[] 参数。

或者,如果你想在函数中使用数组映射而不是 Pointer,只需声明一个新的数组:

// 将所有元素初始化为 0
byte[] appnameNullTerminated = new byte[appname.length+1];
System.arraycopy(appname, 0, appnameNullTerminated, 0, appname.length);

或者,使用上述方法,像现在一样将以 null 结尾的 byte[] 数组写入。

同样,请确保控制字符到字节的编码。在不指定编码的情况下使用 getBytes() 通常不是一个好主意。

英文:

The problem you're encountering is that C strings must be null terminated. Simply grabbing the bytes from the String only gives you the characters J, E, d, i, and t. Your array needs to have a sixth byte with a value of 0 to work properly.

One way to do this is to keep the Pointer mapping you have and allocate the extra byte yourself and then write the bytes to that native memory using Pointer.setString():

Memory buffer = new Memory(6);
// make sure the last byte is 0
memory.clear(); // could also just set the last byte
buffer.setString(0, "JEdit");

(Note that this relies on the default platform encoding, which is generally a bad idea. You should specify the encoding; in this case US-ASCII should work.

Instead of setString() you could also keep write() as you do, with the 0-terminated byte[] argument.

Alternately if you want to use an array mapping in the function instead of a Pointer, just declare a new array:

// initializes all elements to 0
byte[] appnameNullTerminated = new byte[appname.length+1];
System.arraycopy(appname, 0, appnameNullTerminated, 0, appname.length);

Or, use the above and write that terminated byte[] array as you do now.

Again, make sure you control the encoding of the characters to bytes. Using getBytes() without specifying an encoding is generally a bad idea.

huangapple
  • 本文由 发表于 2020年10月1日 22:53:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/64157929.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定