Тип запуска службы JNA Windows - PullRequest
2 голосов
/ 16 марта 2012

Я играл с 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 ]

3 голосов
/ 17 марта 2012

Проблема здесь в том, что, хотя специфичный для платформы JNA код обеспечивает обработку запросов о состоянии службы, он не обеспечивает поддержку запросов о конфигурации службы.Это означает, что для этого вам необходимо предоставить сопоставление JNA для рассматриваемой функции.

Функция, которую вы хотели бы в этом случае определить QueryServiceConfig()в Advapi32.Эта функция заполняет структуру 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
    )
}

(я получил это, используяопределение для QueryServiceStatusEx() в источнике JNA, параметры которого близко соответствуют параметрам для 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)
2 голосов
/ 31 августа 2016

Использование 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;
            }
        }

    }

Я действительно заботился только о «FromNativeConverter» (DoubleNullString - просто маркер типа с полем String []):

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 и, если необходимо, может возвращать блок памяти со строкой [], преобразованной в дважды байтовый массив байтов. Ради JNA, ему просто нужно знать "тип" и значение по умолчанию "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);
0 голосов
/ 06 апреля 2013

Вот программа из предыдущего ответа в виде класса 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;

    }



}
...