[英]JNA Windows Service Startup Type
我一直在使用JNA,并且能够使用以下代码返回Windows服务的状态(即启动或停止)。 我不确定如何返回服务的启动类型。 我确定JNA之外还有其他方法,但我想尽可能继续使用JNA。
import com.sun.jna.*;
import com.sun.jna.Library.Handler;
import com.sun.jna.platform.win32.*;
import com.sun.jna.platform.win32.Advapi32Util.*;
import com.sun.jna.platform.win32.WinNT.*;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.*;
public class WindowsService {
public static void main(String[] args) {
W32ServiceManager serviceManager = new W32ServiceManager();
serviceManager.open(Winsvc.SC_MANAGER_ALL_ACCESS);
W32Service service = serviceManager.openService("W32Time", Winsvc.SC_MANAGER_ALL_ACCESS);
System.out.println(service.queryStatus().dwCurrentState);
service.close();
}
}
这里的问题是,尽管特定于JNA平台的代码提供了查询服务状态的处理,但它不提供查询服务配置的支持。 这意味着,您需要为所涉及的功能提供JNA映射。
在这种情况下,您想要的功能是Advapi32中定义的QueryServiceConfig()
。 此函数填充QUERY_SERVICE_CONFIG
结构,该结构具有dwStartType
属性,该属性对应于各种启动类型值。
幸运的是,使用JNA映射本机函数确实很简单:您只需声明一个接口即可(我提供的代码示例是用Groovy编写的;到Java的转换应该很简单):
interface MyAdvapi32 extends StdCallLibrary {
MyAdvapi32 INSTANCE = (Advapi32) Native.loadLibrary("Advapi32", MyAdvapi32.class, W32APIOptions.UNICODE_OPTIONS);
boolean QueryServiceConfig(
SC_HANDLE hService,
QUERY_SERVICE_CONFIG lpServiceConfig,
int cbBufSize,
IntByReference pcbBytesNeeded
)
}
(我使用JNA源代码中QueryServiceStatusEx()
的定义派生了该参数,其参数与QueryServiceConfig()
的参数非常QueryServiceConfig()
。请注意, QueryServiceStatusEx()
最终是W32Service#queryStatus()
调用的函数)。
但是,我们的函数需要QUERY_SERVICE_CONFIG
结构,该结构未在JNA中定义。 从JNA的SERVICE_STATUS_PROCESS
定义模型开始,我们最终得到如下结果:
class QUERY_SERVICE_CONFIG extends Structure {
public DWORD dwServiceType
public DWORD dwStartType
public DWORD dwErrorControl
public char[] lpBinaryPathName
public char[] lpLoadOrderGroup
public DWORD dwTagId
public char[] lpDependencies
public char[] lpServiceStartName
public char[] lpDisplayName
QUERY_SERVICE_CONFIG() {}
QUERY_SERVICE_CONFIG(int size) {
lpBinaryPathName = new char[256]
lpLoadOrderGroup = new char[256]
lpDependencies = new char[256]
lpServiceStartName = new char[256]
lpDisplayName = new char[256]
allocateMemory(size)
}
}
(请注意,此结构比SERVICE_STATUS_PROCESS
涉及得多,因为SERVICE_STATUS_PROCESS
仅具有DWORD
参数。我在第二个构造函数中提供的分配大小(对于JNA是必需的)可能不是正确的大小。)
有了我们的结构和新接口,我们可以创建一个方法来调用QueryServiceConfig:
QUERY_SERVICE_CONFIG queryServiceConfig(W32Service service) {
IntByReference size = new IntByReference()
MyAdvapi32.INSTANCE.QueryServiceConfig(
service.handle,
null,
0,
size
)
QUERY_SERVICE_CONFIG config = new QUERY_SERVICE_CONFIG(size.value)
if (!MyAdvapi32.INSTANCE.QueryServiceConfig(
service.handle,
config,
config.size(),
size
)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return config
}
一旦有了所有这些,使用它就非常简单:
QUERY_SERVICE_CONFIG config = queryServiceConfig(service)
System.out.println(config.dwStartType)
使用JNA 4.2.2:
我在这种结构上遇到的问题是lpDependencies定义为以双终止符终止的字符串数组:
lpDependencies
指向必须以空分隔的服务或负载排序组名称的数组的指针,该名称必须在此服务之前开始。 该数组是双重以null结尾的 。
所以我通过自定义类型映射解决了这个问题:
public class QUERY_SERVICE_CONFIG extends Structure
{
public QUERY_SERVICE_CONFIG(Pointer p)
{
super(p, ALIGN_DEFAULT, new MyTypeMapper());
}
public int dwServiceType;
public int dwStartType;
public int dwErrorControl;
public String lpBinaryPathName;
public String lpLoadOrderGroup;
public int dwTagId;
public TypeMappers.DoubleNullString lpDependencies;
public String lpServiceStartName;
public String lpDisplayName;
@Override
protected List<String> getFieldOrder()
{
return Arrays
.asList("dwServiceType", "dwStartType", "dwErrorControl", "lpBinaryPathName", "lpLoadOrderGroup",
"dwTagId", "lpDependencies", "lpServiceStartName", "lpDisplayName");
}
public static class MyTypeMapper implements TypeMapper
{
@Override
public FromNativeConverter getFromNativeConverter(Class javaType)
{
FromNativeConverter result = null;
if (javaType.equals(TypeMappers.DoubleNullString.class))
{
result = TypeMappers.DoubleNullString.FROM_NATIVE_CONVERTER;
}
return result;
}
@Override
public ToNativeConverter getToNativeConverter(Class javaType)
{
ToNativeConverter result = null;
if (javaType.equals(TypeMappers.DoubleNullString.class))
{
result = TypeMappers.DoubleNullString.TO_NATIVE_CONVERTER;
}
return result;
}
}
}
我真的只关心“ FromNativeConverter”(DoubleNullString只是具有String []字段的Type标记):
public class MyFromNativeConverter implements FromNativeConverter
{
@Override
public Object fromNative(Object nativeValue, FromNativeContext context)
{
DoubleNullString result = new DoubleNullString();
Pointer p = (Pointer) nativeValue;
int offset = 0;
List<String> doubleNullList = new ArrayList<>();
while (!(p.getByte(offset) == 0))
{
String s = p.getString(offset);
doubleNullList.add(s);
offset += s.length() + 1;
}
result.lpDependencies = doubleNullList.toArray(new String[doubleNullList.size()]);
return result;
}
@Override
public Class nativeType()
{
return Pointer.class;
}
}
作为参考, ToNativeConverter应该只返回Pointer.class类型,并且如果需要,可以返回将String []转换为双倍终止的字节数组的Memory块。 为了JNA的缘故,它只需要知道“ type”和默认的“ null”值(恰好可以初始化结构)。
然后,我的方法签名变为:
Memory memory = new Memory(required.getValue());
Advapi32Ex.QUERY_SERVICE_CONFIG query = new Advapi32Ex.QUERY_SERVICE_CONFIG(memory);
Advapi32Ex.INSTANCE.QueryServiceConfigA(session.getHandle(), query, (int) memory.size(), required);
这是来自上一个答案的程序作为Java类。 重要-完全需要JNA 3.3.0
import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.*;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import java.util.Arrays;
import java.util.List;
public class ServiceUtil {
interface MyAdvapi32 extends StdCallLibrary {
public MyAdvapi32 INSTANCE = (MyAdvapi32) Native.loadLibrary("Advapi32", MyAdvapi32.class, W32APIOptions.UNICODE_OPTIONS);
public boolean QueryServiceConfig(
Winsvc.SC_HANDLE hService,
QUERY_SERVICE_CONFIG lpServiceConfig,
int cbBufSize,
IntByReference pcbBytesNeeded
);
}
public static class QUERY_SERVICE_CONFIG extends Structure {
public WinDef.DWORD dwServiceType;
public WinDef.DWORD dwStartType;
public WinDef.DWORD dwErrorControl;
public char[] lpBinaryPathName;
public char[] lpLoadOrderGroup;
public WinDef.DWORD dwTagId;
public char[] lpDependencies;
public char[] lpServiceStartName;
public char[] lpDisplayName;
public QUERY_SERVICE_CONFIG() {}
public QUERY_SERVICE_CONFIG(int size) {
lpBinaryPathName = new char[256];
lpLoadOrderGroup = new char[256];
lpDependencies = new char[256];
lpServiceStartName = new char[256];
lpDisplayName = new char[256];
allocateMemory(size);
}
@Override
protected List getFieldOrder() {
return Arrays.asList("lpBinaryPathName","lpLoadOrderGroup","lpDependencies","lpServiceStartName","lpDisplayName");
}
}
public static QUERY_SERVICE_CONFIG queryServiceConfig(W32Service service) {
IntByReference size = new IntByReference();
MyAdvapi32.INSTANCE.QueryServiceConfig(
service.getHandle(),
null,
0,
size
);
QUERY_SERVICE_CONFIG config = new QUERY_SERVICE_CONFIG(size.getValue());
if (!MyAdvapi32.INSTANCE.QueryServiceConfig(
service.getHandle(),
config,
config.size(),
size
)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return config;
}
public static String checkService(String serviceToCheck) {
W32ServiceManager serviceManager = new W32ServiceManager();
serviceManager.open(Winsvc.SC_MANAGER_ALL_ACCESS);
W32Service service = serviceManager.openService(serviceToCheck, Winsvc.SC_MANAGER_ALL_ACCESS);
IntByReference size = new IntByReference();
MyAdvapi32.INSTANCE.QueryServiceConfig(
service.getHandle(),
null,
0,
size
);
QUERY_SERVICE_CONFIG config = queryServiceConfig(service);
String result = config.dwStartType.toString();
service.close();
return result;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.