我正在尝试从基于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();
}
答案 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();
}
}