来自JNA的WTSEnumerateSessions

时间:2015-05-26 17:58:24

标签: winapi jna

我正在尝试从基于java的Windows服务启动UI应用程序。如果到目前为止已经找到了,那么实现这项工作的唯一方法是获取会话列表,找到当前活动的会话,获取该会话的用户句柄,最后为给定用户创建新流程。

我开始使用WTSEnumerateSessions实现会话枚举,但我很难让这个工作。问题似乎是我的“_Out_PWTS_SESSION_INFO * ppSessionInfo”参数的映射。我写了以下代码:

public interface Wtsapi32 extends StdCallLibrary {
   Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
   boolean WTSEnumerateSessions(IntByReference hServer, int Reserved, int Version, WTS_SESSION_INFO.ByReference[] ppSessionInfo, IntByReference pCount) throws LastErrorException;

   class WTS_SESSION_INFO extends Structure {
       public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}
       public int sessionId;
       public String pWinStationName;
       public int state;

       @Override
       protected List getFieldOrder() {
           return Arrays.asList("sessionId", "pWinStationName", "state");
       }
   }

}

尝试使用类似的东西调用代码时:

public static void main(String[] argv) {
        Wtsapi32.WTS_SESSION_INFO.ByReference[] sessionInfo = null;
        IntByReference sessionCount = new IntByReference();
        try {
            if (Wtsapi32.INSTANCE.WTSEnumerateSessions(new IntByReference(0), 0, 1, sessionInfo, sessionCount)) {
                System.out.println("success :-)");
            }
        } catch (LastErrorException ex) {
            ex.printStackTrace();
        }

    }

我收到错误代码1784 - ERROR_INVALID_USER_BUFFER。来自JNA的所谓API调用的正确映射是什么?

更新 我尝试了一个建议的Remy Lebeau版本,但这给了我一个无效的内存访问异常:

public interface Wtsapi32 extends StdCallLibrary {
    Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
    boolean WTSEnumerateSessions(IntByReference hServer, int Reserved, int Version, PointerByReference ppSessionInfo, IntByReference pCount) throws LastErrorException;

    class WTS_SESSION_INFO extends Structure {
        public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}

        public int sessionId;
        public String pWinStationName;
        public int state;

        @Override
        protected List getFieldOrder() {
            return Arrays.asList("sessionId", "pWinStationName", "state");
        }

        public WTS_SESSION_INFO() {}
        public WTS_SESSION_INFO(Pointer p) {
            super(p);
        }
    }
}

主:

    PointerByReference sessionInfoPtr = new PointerByReference();
    IntByReference sessionCount = new IntByReference();
    try {
        if (Wtsapi32.INSTANCE.WTSEnumerateSessions(new IntByReference(0), 0, 1, sessionInfoPtr, sessionCount)) {
            System.out.println("success :-)");
        }
    } catch (LastErrorException ex) {
        ex.printStackTrace();
    }

1 个答案:

答案 0 :(得分:2)

WTSEnumerateSessions()返回:

  • 指针 WTS_SESSION_INFO结构的数组
  • 指针 指向数组中元素数量的DWORD

因此,您需要为PointerByReference参数传递ppSessionInfo,为IntByReference参数传递pCount。然后,您可以使用这些指针指向的值来根据需要访问数组元素。这里记录了一个例子:

JNA Example #7: Retrieve an Array of Structs from C

此外,您的代码使用IntByReference作为hServer参数。它必须是com.sun.jna.platform.win32.WinNT.HANDLE,或者至少是Pointer。在C中,Win32 HANDLE只是一个void*指针。您需要将第一个参数设置为Pointer.NULL(这是C中定义的WTS_CURRENT_SERVER_HANDLE)以枚举本地服务器的会话。 IntByReference(0)Pointer.NULL不同。

完成使用后,不要忘记调用WTSFreeMemory()释放数组数据。

尝试这样的事情:

public interface Wtsapi32 extends StdCallLibrary {
   Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);

   boolean WTSEnumerateSessions(Pointer hServer, int Reserved, int Version, PointerByReference ppSessionInfo, IntByReference pCount) throws LastErrorException;
   void WTSFreeMemory(Pointer pMemory);

   class WTS_SESSION_INFO extends Structure {
       public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}

       public int sessionId;
       public String pWinStationName;
       public int state;

       public WTS_SESSION_INFO() {}
       public WTS_SESSION_INFO(Pointer p) {
           super(p);
       }

       @Override
       protected List getFieldOrder() {
           return Arrays.asList("sessionId", "pWinStationName", "state");
       }
    }
}

public static void main(String[] argv) {
    PointerByReference sessionInfoPtr = new PointerByReference();
    IntByReference sessionCount = new IntByReference();
    try {
        if (Wtsapi32.INSTANCE.WTSEnumerateSessions(Pointer.NULL, 0, 1, sessionInfoPtr, sessionCount)) {
            Pointer sessionInfo = sessionInfoPtr.getValue();
            int count = sessionCount.getValue();
            Wtsapi32.INSTANCE.WTS_SESSION_INFO arrRef = new Wtsapi32.INSTANCE.WTS_SESSION_INFO(sessionInfo);
            arrRef.read(); // <-- not sure why this is here
            Wtsapi32.INSTANCE.WTS_SESSION_INFO[] sessions = (Wtsapi32.INSTANCE.WTS_SESSION_INFO[])arrRef.toArray(count);
            for (Wtsapi32.INSTANCE.WTS_SESSION_INFO session : sessions) {
                // use session as needed...
            }
            WTSFreeMemory(sessionInfo);
        }
    } catch (LastErrorException ex) {
        ex.printStackTrace();
    }    
}