Winapi 来自JNA的WTSEnumerateSessions
我正在尝试从基于java的Windows服务启动UI应用程序。如果到目前为止已经弄清楚了,那么实现此功能的唯一方法就是获取会话列表,找到当前活动的会话,获取该会话的用户句柄,最后为给定用户创建一个新进程 我从使用实现会话枚举开始,但我很难让它正常工作。问题似乎是我对“_Out_PWTS_SESSION_INFO*ppSessionInfo”参数的映射。我编写了以下代码:Winapi 来自JNA的WTSEnumerateSessions,winapi,jna,Winapi,Jna,我正在尝试从基于java的Windows服务启动UI应用程序。如果到目前为止已经弄清楚了,那么实现此功能的唯一方法就是获取会话列表,找到当前活动的会话,获取该会话的用户句柄,最后为给定用户创建一个新进程 我从使用实现会话枚举开始,但我很难让它正常工作。问题似乎是我对“_Out_PWTS_SESSION_INFO*ppSessionInfo”参数的映射。我编写了以下代码: public interface Wtsapi32 extends StdCallLibrary { Wtsapi32
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中,Win32HANDLE
s基本上只是void*
指针。无论哪种方式,您都需要将第一个参数设置为Pointer.NULL
(这就是WTS\u CURRENT\u SERVER\u HANDLE
的定义),以枚举本地服务器的会话。IntByReference(0)
不是一回事。你是个天才!我有IntByReference,因为C样本代码我使用了IntPtr 0,这似乎是正确的选择!你想回答这个问题,我接受它,还是我自己回答它?IntPtr(0)C#中的相当于JNA中的指针.NULL
,而不是IntByReference(0)
。