【问题标题】:How to pass an array of structures using JNA如何使用 JNA 传递结构数组
【发布时间】:2012-10-10 15:55:55
【问题描述】:

我参考了另一篇 stackoverflow 文章“如何将指针映射到 JNA 中的结构数组”,提出以下代码来枚举 Windows 服务依赖项。

结构和函数声明:

static class SERVICE_STATUS extends Structure {
    public int dwServiceType;
    public int dwCurrentState;
    public int dwControlsAccepted;
    public int dwWin32ExitCode;
    public int dwServiceSpecificExitCode;
    public int dwCheckPoint;
    public int dwWaitHint;
    public SERVICE_STATUS(){}
}

static class ENUM_SERVICE_STATUS extends Structure {
    public ENUM_SERVICE_STATUS(){ }

    public WString lpServiceName;
    public WString lpDisplayName;
    SERVICE_STATUS serviceStatus;
}

boolean EnumDependentServicesW(Pointer hService, int serviceState, ENUM_SERVICE_STATUS serviceStatuses, int size, IntByReference bytesNeeded, IntByReference servicesReturned);

如果只有一个服务依赖,下面的代码可以工作:

IntByReference bytesNeeded = new IntByReference();
IntByReference numberOfServices = new IntByReference();
Advapi32.ENUM_SERVICE_STATUS serviceStatus = new Advapi32.ENUM_SERVICE_STATUS();
Advapi32.ENUM_SERVICE_STATUS[] serviceStatuses = (Advapi32.ENUM_SERVICE_STATUS[]) serviceStatus.toArray(1);

if (!advapi32.EnumDependentServicesW(serviceHandle, Advapi32.SERVICE_ACTIVE, null, 0, bytesNeeded, numberOfServices)) {
    if (advapi32.EnumDependentServicesW (serviceHandle, Advapi32.SERVICE_ACTIVE, serviceStatuses[0], bytesNeeded.getValue(), bytesNeeded, numberOfServices)) {
        for(int i = numberOfServices.getValue() - 1; i >= 0; i--){
            logger.debug("Service Name: " + serviceStatuses[i].lpServiceName.toString());
    }
}

如果有 2 个服务依赖项,我会在 logger.debug 调用中获得 lpServiceName 的 NullPointerException:

IntByReference bytesNeeded = new IntByReference();
IntByReference numberOfServices = new IntByReference();
Advapi32.ENUM_SERVICE_STATUS serviceStatus = new Advapi32.ENUM_SERVICE_STATUS();
Advapi32.ENUM_SERVICE_STATUS[] serviceStatuses = (Advapi32.ENUM_SERVICE_STATUS[]) serviceStatus.toArray(2);

if (!advapi32.EnumDependentServicesW(serviceHandle, Advapi32.SERVICE_ACTIVE, null, 0, bytesNeeded, numberOfServices)) { 
    if (advapi32.EnumDependentServicesW (serviceHandle, Advapi32.SERVICE_ACTIVE, serviceStatuses[0], bytesNeeded.getValue(), bytesNeeded, numberOfServices)) {
        for(int i = numberOfServices.getValue() - 1; i >= 0; i--){
            logger.debug("Service Name: " + serviceStatuses[i].lpServiceName.toString());
    }
}

如预期的那样,上面代码的 numberOfServices 值为 2。我试图传递结构数组而不是指针,因为我希望 JNA 进行内存同步。我应该如何传递/使用结构数组?

【问题讨论】:

    标签: java arrays winapi jna structure


    【解决方案1】:

    根据docsEnumDependentServices

    lpServices [out, optional]

    指向数组的指针 接收名称和服务的 ENUM_SERVICE_STATUS 结构 数据库中每个依赖服务的状态信息。 缓冲区必须足够大以容纳结构以及字符串 他们的成员指向的地方。

    您几乎忽略了bytesNeeded 报告的所需缓冲区大小。您应该使用bytesNeeded 值来创建所需大小的Memory 实例,然后使用该Memory 实例来创建新的ENUM_SERVICE_STATUS 实例,而不是独立于所需缓冲区大小来创建结构。

    【讨论】:

    • 感谢@technomage,您的意见。我可以将内存分配给 ENUM_SERVICE_STATUS 实例,但我不太明白这是如何工作的。 BytesNeeded 是数组中所有结构的总大小加上结构指向的字符串。那么,如果我手动将所有内存分配给单个 ENUM_SERVICE_STATUS 实例,如何填充 ENUM_SERVICE_STATUS 结构数组(以及从 EnumDependentServices 返回后我将如何访问数组元素)?
    • 一旦你知道所需的内存,创建一个该大小的Memory 实例,用它来初始化一个ENUM_SERVICE_STATUS 实例,然后调用toArrayStructure 有一个带有 Pointer 值的构造函数;用它来覆盖你新分配的Memory 上的结构。一旦您在基础 Structure 上调用了 toArray,JNA 就知道如何跟踪它并在本机方法调用中同步所有数组成员。
    • 我终于通过更新到 JNA 3.3.0、创建内存实例并使用它来创建 ENUM_SERVICE_STATUS 来返回所有依赖项。谢谢@technomage!我仍在试图弄清楚如何确定用于 toArray 的大小,因为直到第二次调用 EnumDependentServices 之后我们才知道有多少服务依赖项,但是我们需要在第二次调用之前执行 toArray...
    猜你喜欢
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 2012-12-30
    相关资源
    最近更新 更多