我如何使用更具体的结构类型来代替更通用的结构类型?

How do I use a more specific struct type in place of a more general one?

我正在开发 windows 设备管理器,它将与 java 一起使用。 我坚持尝试无错误地通过 SetupDiSetClassInstallParams 函数。 (我正在尝试禁用设备。)

我在 C++ 中 运行 完全相同的结构(必要方式),我没有任何问题。

我收到 ERROR_INVALID_USER_BUFFER 错误。当我尝试在 C++ 中得到这个错误时,我需要用错误的值更改 SP_PROPCHANGE_PARAMS 结构值。

我的结构减量:

    public static class SP_CLASSINSTALL_HEADER extends Structure {

    public static class ByReference extends SP_CLASSINSTALL_HEADER implements Structure.ByReference {
        public ByReference() {
        }

        public ByReference(Pointer memory) {
            super(memory);
        }
    }

    public SP_CLASSINSTALL_HEADER() {
        cbSize = size();
    }

    public SP_CLASSINSTALL_HEADER(Pointer memory) {
        super(memory);
        read();
    }

    public int cbSize;
    public long InstallFunction; **/* <-- this should be int or else buffer size changes, dll cannot place variables on right places. */**

    protected List getFieldOrder() {
        return Arrays.asList(new String[] { "cbSize", "InstallFunction" });
    }
}

public static class SP_PROPCHANGE_PARAMS extends Structure {

    public static class ByReference extends SP_PROPCHANGE_PARAMS implements Structure.ByReference {
        public ByReference() {
        }

        public ByReference(Pointer memory) {
            super(memory);
        }
    }

    public SP_PROPCHANGE_PARAMS() {
    }

    public SP_PROPCHANGE_PARAMS(Pointer memory) {
        super(memory);
        read();
    }

    public SP_CLASSINSTALL_HEADER ClassInstallHeader = new SP_CLASSINSTALL_HEADER();
    public int StateChange;
    public int Scope;
    public int HwProfile;

    protected List getFieldOrder() {
        return Arrays.asList(new String[] { "ClassInstallHeader", "StateChange", "Scope", "HwProfile" });
    }
}

我的函数减速:

boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, Pointer deviceInfoData, Pointer classInstallHeader, int size);

如何调用这个函数:

    SP_PROPCHANGE_PARAMS spPropChangeParams = new SP_PROPCHANGE_PARAMS(); 
    spPropChangeParams.ClassInstallHeader.InstallFunction = DISetupApi.DIF_PROPERTYCHANGE;
    spPropChangeParams.Scope = DISetupApi.DICS_FLAG_GLOBAL;
    spPropChangeParams.HwProfile = 0;
    spPropChangeParams.StateChange = DISetupApi.DICS_DISABLE;
    int spPropChangeParamsSize = spPropChangeParams.size();
    SP_CLASSINSTALL_HEADER classInstallHeaderReference = new SP_CLASSINSTALL_HEADER(spPropChangeParams.getPointer());

    setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData().getPointer(), classInstallHeaderReference.getPointer(),
            spPropChangeParamsSize);

它在 C++ 中的工作原理:

SP_PROPCHANGE_PARAMS spPropChangeParams;    
spPropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
spPropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0; 
spPropChangeParams.StateChange = DICS_DISABLE;

SetupDiSetClassInstallParams(hDeviceInfo, &device.getDeviceInfoData(), (SP_CLASSINSTALL_HEADER*)&spPropChangeParams, sizeof(spPropChangeParams));

实际上我混合和匹配了太多的方式,这些结构和函数我改变了结构的变量类型和函数的参数类型,最后除了错误我什么也得不到。我找不到我的错误。你能帮我解决这个问题吗?

提前致谢!

传递 Structure 时,除非万不得已,否则不要使用 Structure.getPointer()。当您这样做时,JNA 无法自动同步本机数据和 Java 数据,而且很容易出错,您需要自己记住在哪里做这件事。在您的情况下, Java 字段中的任何内容都不会在您调用 setupApi.SetupDiSetClassInstallParams.

时复制到本机内存中

将您的函数映射更改为此:

boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_CLASSINSTALL_HEADER classInstallHeader, int size);

并将调用更改为:

setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData(), classInstallHeaderReference,             spPropChangeParamsSize);

编辑

如果你坚持你原来的结构定义(其中SP_CLASSINSTALL_HEADER是一个字段),你需要添加一个函数映射到接口(扩展接口并创建你自己的本地库实例):

public interface MySetupApi extends SetupApi {
    MySetupApi INSTANCE = (MySetupApi)Native.loadLibrary(MySetupApi.class, W32APIOptions.DEFAULT_OPTIONS);
    boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_PROPCHANGE_PARAMS propChangeParams, int size);
}