[英]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.