API函数GetVolumePathNamesForVolume

API函数GetVolumePathNamesForVolume

本文介绍了JNA for Windows API函数GetVolumePathNamesForVolumeName的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已成功使用JNA来调用几个Windows API函数,但是我遇到了这个问题

I've successfully used JNA to call a couple of Windows API functions but I get stuck at this one

完整C声明是:

BOOL WINAPI GetVolumePathNamesForVolumeName(
  __in   LPCTSTR lpszVolumeName,
  __out  LPTSTR lpszVolumePathNames,
  __in   DWORD cchBufferLength,
  __out  PDWORD lpcchReturnLength
);

我的Kernel32接口方法原型是:

My Kernel32 interface method prototype for this is:

boolean GetVolumePathNamesForVolumeName(String lpszVolumeName, Pointer lpszVolumePathNames, int cchBufferLength, Pointer lpcchReturnLength);

我使用以下内容加载界面

and I use the below to load the interface

Native.loadLibrary('kernel32', Kernel32.class, W32APIOptions.UNICODE_OPTIONS)

我试过:

public String[] getPathNames() {
    Memory pathNames = new Memory(100);
    Memory len = new Memory(4);
    if (!kernel32.GetVolumePathNamesForVolumeName(this.getGuidPath(), pathNames, 100, len)) {
        if (kernel32.GetLastError() == WindowsConstants.ERROR_MORE_DATA) {
            pathNames = new Memory(len.getInt(0));
            if (!kernel32.GetVolumePathNamesForVolumeName(this.getGuidPath(), pathNames, len.getInt(0), len)) {
                throw new WinApiException(kernel32.GetLastError());
            }
        }
        else
            throw new WinApiException(kernel32.GetLastError());
    }
    int count = len.getInt(0);
    return pathNames.getStringArray(0, true);
}

根本不起作用。尚未确定异常,但我的代码却爆炸了。

which does not work at all. Not sure about the exception yet but my code bombs out.

以下类似作品:

public String[] getPathNames() {
    Memory pathNames = new Memory(100);
    Memory len = new Memory(4);
    if (!kernel32.GetVolumePathNamesForVolumeName(this.getGuidPath(), pathNames, 100, len)) {
        if (kernel32.GetLastError() == WindowsConstants.ERROR_MORE_DATA) {
            pathNames = new Memory(len.getInt(0));
            if (!kernel32.GetVolumePathNamesForVolumeName(this.getGuidPath(), pathNames, len.getInt(0), len)) {
                throw new WinApiException(kernel32.GetLastError());
            }
        }
        else
            throw new WinApiException(kernel32.GetLastError());
    }
    int count = len.getInt(0);
    String[] result = new String[count];
    int offset = 0;
    for (int i = 0; i < count; i++) {
        result[i] = pathNames.getString(offset, true);
        offset += result[i].length() * Native.WCHAR_SIZE + Native.WCHAR_SIZE;
    }
    return result;
}

这个的结果是第一个值很好但是之后我可以看到有编码问题表明我的错误是错误的。

What happens with this one is that the first value come out fine but after that one can see that there is encoding problems which indicate that I've got the offset wrong.

推荐答案

我的版本 \\?\ Volume {5b57f944-8d60-11de-8b2a-806d6172696f} \ 应该获得 C:\

Kernel32接口:

Kernel32 Interface:

import com.sun.jna.WString;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;

public interface Kernel32 extends StdCallLibrary {

    public boolean GetVolumePathNamesForVolumeNameW(
              WString lpszVolumeName,
              char[] lpszVolumePathNames,
              DWORD cchBufferLength,
              IntByReference lpcchReturnLength
            );

    public int GetLastError();
}

测试申​​请:

import java.util.Arrays;

import com.sun.jna.Native;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.ptr.IntByReference;

public class TestJNA {

    static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32.dll", Kernel32.class);

    /**
     * @param args
     */
    public static void main(String[] args) {

        try {
            System.out.println(getPathNames());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public static String getPathNames() throws Win32Exception {
        DWORD value = new DWORD(100);
        char[] pathNames = new char[100];
        IntByReference len = new IntByReference();
        if (kernel32.GetVolumePathNamesForVolumeNameW(getGuidPath(), pathNames, value, len)) {
            if (kernel32.GetLastError() == WindowsConstants.ERROR_MORE_DATA) {
                pathNames = new char[len.getValue()];
                DWORD sz = new DWORD(len.getValue());
                if (!kernel32.GetVolumePathNamesForVolumeNameW(getGuidPath(), pathNames, sz, len)) {
                    throw new Win32Exception(kernel32.GetLastError());
                }
            }
            else
                throw new Win32Exception(kernel32.GetLastError());
        }

        return Arrays.toString(pathNames);
    }

    private static WString getGuidPath() {

        final WString str  = new WString("\\\\?\\Volume{5b57f944-8d60-11de-8b2a-806d6172696f}\\");

        return str;
    }
}

结果:

[C, :, \, , ]

要仔细检查,我在DOS命令提示符处键入: mountvol

To double-check it, I type at DOS command prompt: mountvol

已编辑:改善结果值......

Edited: To improve of the result value...

更改的返回值getPathNames()方法,来自:

return Arrays.toString(pathNames);

return new String(pathNames);

在我的测试应用程序中,您可以:

In my test application, you can just:

String[] points = getPathNames().split("\u0000"); //split by Unicode NULL

for(String s: points) System.out.println("mount: " + s);

我唯一关心的是JNA如何处理来自 lpszVolumePathNames的以NULL结尾的Unicode字符串 Kernel32中的参数 GetVolumePathNamesForVolumeNameW()方法自:

My only concern is how JNA handles NULL-terminated Unicode strings from lpszVolumePathNames parameter in Kernel32 GetVolumePathNamesForVolumeNameW() method since:

指向缓冲区的指针,该缓冲区接收
驱动器号和卷
GUID路径列表。该列表是一个由
终止的
以null结尾的字符串数组,另外还有一个NULL字符。如果
缓冲区不足以容纳
完整列表,则缓冲区尽可能保留在
列表中。

A pointer to a buffer that receives the list of drive letters and volume GUID paths. The list is an array of null-terminated strings terminated by an additional NULL character. If the buffer is not large enough to hold the complete list, the buffer holds as much of the list as possible.

虽然,JNI规范说(我不确定JNA方面的事情):

Though, JNI specification says (I am not sure on JNA side of thing):


获取的Unicode字符串GetStringChars或GetStringCritical
不以NULL结尾。调用
GetStringLength来查找
字符串中16位Unicode字符的数字
。某些操作系统,例如Windows NT
,预计有两个尾随
的零字节值来终止Unicode
字符串。您不能将
GetStringChars的结果传递给
期望Unicode字符串的Windows NT API。你必须使
另一个字符串副本并插入
两个尾随零字节值。

Unicode strings obtained from GetStringChars or GetStringCritical are not NULL-terminated. Call GetStringLength to find out the number of 16-bit Unicode characters in a string. Some operating systems, such as Windows NT, expect two trailing zero byte values to terminate Unicode strings. You cannot pass the result of GetStringChars to Windows NT APIs that expect a Unicode string. You must make another copy of the string and insert the two trailing zero byte values.

编辑:

似乎我的代码没错,因为 lpszVolumePathNames 参数通过验证其中是否存在\ u0000字符串,正确地返回Unicode中以NULL结尾的字符串:

It seems that my code is OK as the lpszVolumePathNames parameter returns NULL-terminated strings in Unicode correctly by verifying the presence of "\u0000" strings within it:

String point = getPathNames().replaceAll("\u0000", "-");

这篇关于JNA for Windows API函数GetVolumePathNamesForVolumeName的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 03:02