Winapi 来自JNA的WTSEnumerateSessions

Winapi 来自JNA的WTSEnumerateSessions,winapi,jna,Winapi,Jna,我正在尝试从基于java的Windows服务启动UI应用程序。如果到目前为止已经弄清楚了,那么实现此功能的唯一方法就是获取会话列表,找到当前活动的会话,获取该会话的用户句柄,最后为给定用户创建一个新进程 我从使用实现会话枚举开始,但我很难让它正常工作。问题似乎是我对“_Out_PWTS_SESSION_INFO*ppSessionInfo”参数的映射。我编写了以下代码: public interface Wtsapi32 extends StdCallLibrary { Wtsapi32

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

我从使用实现会话枚举开始,但我很难让它正常工作。问题似乎是我对“_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();
        }

    }
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();
    }    
}
我得到一个错误代码1784-错误\无效\用户\缓冲区。来自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);
        }
    }
}
主要内容:

wtsenumeratessions()
返回:

  • 指向
    WTS\u SESSION\u INFO
    结构数组的指针
  • 指向数组中元素数量的DWORD的指针
因此,您需要为
ppSessionInfo
参数传递
PointerByReference
,为
pCount
参数传递
IntByReference
。然后,您可以根据需要使用这些指针指向的值来访问数组元素。这里有一个这样的例子:

此外,您的代码正在对
hServer
参数使用
IntByReference
。它需要是一个指针,或者至少是一个
指针。在C语言中,Win32
句柄
只是一个
void*
指针。您需要将第一个参数设置为
Pointer.NULL
(这是
WTS\u CURRENT\u SERVER\u HANDLE
在C中定义的)以枚举本地服务器的会话
IntByReference(0)
Pointer.NULL
不同

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

试着这样做:

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();
        }

    }
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();
    }    
}
公共接口Wtsapi32扩展StdCallLibrary{
Wtsapi32 INSTANCE=(Wtsapi32)Native.loadLibrary(“Wtsapi32”,Wtsapi32.class,w32apipoptions.DEFAULT_OPTIONS);
布尔WTSEnumerateSessions(指针hServer,int Reserved,int Version,PointerByReference ppSessionInfo,IntByReference pCount)抛出LastErrorException;
无效WTSFreeMemory(指针pMemory);
类WTS_会话_信息扩展结构{
公共静态类ByReference扩展WTS_会话_信息实现结构。ByReference{}
公共会议d;
公共字符串pInstallationName;
公共国家;
公共WTS_会话_信息(){}
公共WTS_会话_信息(指针p){
超级(p);
}
@凌驾
受保护列表getFieldOrder(){
返回Arrays.asList(“sessionId”、“pwstationname”、“state”);
}
}
}
公共静态void main(字符串[]argv){
PointerByReference sessionInfo=新的PointerByReference();
IntByReference sessionCount=新的IntByReference();
试一试{
if(Wtsapi32.INSTANCE.WTSEnumerateSessions(Pointer.NULL、0、1、sessionInfo、sessionCount)){
指针sessionInfo=sessionInfo.getValue();
int count=sessionCount.getValue();
Wtsapi32.INSTANCE.WTS_SESSION_INFO arrRef=新的Wtsapi32.INSTANCE.WTS_SESSION_INFO(sessionInfo);

arrRef.read();//WTSEnumerateSessions()的输出
是指向结构数组的指针。因此,您需要传递对此类指针的引用,然后才能使用该指针访问该数组。我尝试了您的方法,但这导致了无效的内存异常,请参阅我尝试的代码的更新问题。为什么要对第一个参数使用
IntByReference
在C中,Win32
HANDLE
s基本上只是
void*
指针。无论哪种方式,您都需要将第一个参数设置为
Pointer.NULL
(这就是
WTS\u CURRENT\u SERVER\u HANDLE
的定义),以枚举本地服务器的会话。
IntByReference(0)
不是一回事。你是个天才!我有IntByReference,因为C样本代码我使用了IntPtr 0,这似乎是正确的选择!你想回答这个问题,我接受它,还是我自己回答它?
IntPtr(0)C#中的
相当于JNA中的
指针.NULL
,而不是
IntByReference(0)