JNA Windows服务启动类型

时间:2012-03-16 18:26:54

标签: java windows service jna

我一直在玩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();

     }
}

3 个答案:

答案 0 :(得分:3)

这里的问题是,虽然JNA平台特定代码提供了查询服务状态的处理,但它不支持查询服务的配置。这意味着要执行此操作,您需要为相关函数提供JNA映射。

在这种情况下,您需要的功能是在Advapi32中定义的QueryServiceConfig()。此函数填充QUERY_SERVICE_CONFIG结构,其dwStartType属性对应于各种启动类型值。

幸运的是,使用JNA映射本机函数非常简单:您只需声明一个类似的接口(我提供的代码示例是用Groovy编写的;转换为Java应该非常直接):< / p>

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源中的definition for QueryServiceStatusEx()来推导它,其参数与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)

答案 1 :(得分:2)

使用JNA 4.2.2:

我在这个结构中遇到的问题是lpDependencies被定义为一个双重终止的字符串数组:

  

lpDependencies

     

指向必须在此服务之前启动的服务或加载排序组的以空值分隔的名称数组的指针。 数组是双重终止

所以我通过自定义类型映射解决了这个问题:

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;
            }
        }

    }

我真的只关心&#34; FromNativeConverter&#34; (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类型,如果需要,可以返回一个Memory块,并将String []转换为双字节终止的字节数组。为了JNA的缘故,它只需要知道&#34;类型&#34;和默认&#34; null&#34;值(只是它可以初始化结构)。

我的方法签名变为:

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);

答案 2 :(得分:0)

这是上一个答案中作为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;

    }



}