繁体   English   中英

JNA Windows服务启动类型

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM