来自 JNA 的 WTSEnumerateSession
WTSEnumerateSessions from 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();
}
WTSEnumerateSessions()
returns:
- 一个指针指向
WTS_SESSION_INFO
个结构 的数组
- 一个指向
DWORD
数组中元素数的指针。
所以你需要为ppSessionInfo
参数传递一个PointerByReference
,为pCount
参数传递一个IntByReference
。然后,您可以使用这些指针指向的值来根据需要访问数组元素。这里有一个例子:
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
(这是 WTS_CURRENT_SERVER_HANDLE
在 C 中的定义)以枚举本地服务器的会话。 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();
}
}
我正在尝试从基于 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();
}
WTSEnumerateSessions()
returns:
- 一个指针指向
WTS_SESSION_INFO
个结构 的数组
- 一个指向
DWORD
数组中元素数的指针。
所以你需要为ppSessionInfo
参数传递一个PointerByReference
,为pCount
参数传递一个IntByReference
。然后,您可以使用这些指针指向的值来根据需要访问数组元素。这里有一个例子:
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
(这是 WTS_CURRENT_SERVER_HANDLE
在 C 中的定义)以枚举本地服务器的会话。 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();
}
}