Package com.sun.jna.platform.win32

Source Code of com.sun.jna.platform.win32.Advapi32Util

/* Copyright (c) 2010 Daniel Doubrovkine, All Rights Reserved
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details. 
*/
package com.sun.jna.platform.win32;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinNT.EVENTLOGRECORD;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
import com.sun.jna.platform.win32.WinNT.PSID;
import com.sun.jna.platform.win32.WinNT.PSIDByReference;
import com.sun.jna.platform.win32.WinNT.SID_AND_ATTRIBUTES;
import com.sun.jna.platform.win32.WinNT.SID_NAME_USE;
import com.sun.jna.platform.win32.WinReg.HKEY;
import com.sun.jna.platform.win32.WinReg.HKEYByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;

/**
* Advapi32 utility API.
* @author dblock[at]dblock.org
*/
public abstract class Advapi32Util {
 
  /**
   * An account.
   */
  public static class Account {
    /**
     * Account name.
     */
    public String name;
    /**
     * Account domain.
     */
    public String domain;
    /**
     * Account SID.
     */
    public byte[] sid;
    /**
     * String representation of the account SID.
     */
    public String sidString;
    /**
     * Account type, one of SID_NAME_USE.
     */
    public int accountType;
    /**
     * Fully qualified account name.
     */
    public String fqn;
  }
 
  /**
   * Retrieves the name of the user associated with the current thread.
   * @return A user name.
   */
  public static String getUserName() {
    char[] buffer = new char[128];
    IntByReference len = new IntByReference(buffer.length);
    boolean result = Advapi32.INSTANCE.GetUserNameW(buffer, len);
   
    if (! result) {
     
      int rc = Kernel32.INSTANCE.GetLastError();

      switch(rc) {
      case W32Errors.ERROR_INSUFFICIENT_BUFFER:
        buffer = new char[len.getValue()];
        break;
      default:
        throw new Win32Exception(Native.getLastError());
      }
     
      result = Advapi32.INSTANCE.GetUserNameW(buffer, len);
    }
   
    if (! result) {
      throw new Win32Exception(Native.getLastError());
    }
   
    return Native.toString(buffer);
  }

  /**
   * Retrieves a security identifier (SID) for the account on the current system.
   * @param accountName Specifies the account name.
   * @return A structure containing the account SID;
   */
  public static Account getAccountByName(String accountName) {
    return getAccountByName(null, accountName);
  }
     
  /**
   * Retrieves a security identifier (SID) for a given account.
   * @param systemName Name of the system.
   * @param accountName Account name.
   * @return A structure containing the account SID.
   */
  public static Account getAccountByName(String systemName, String accountName) {
    IntByReference pSid = new IntByReference(0);
    IntByReference cchDomainName = new IntByReference(0);
    PointerByReference peUse = new PointerByReference();
   
    if (Advapi32.INSTANCE.LookupAccountName(systemName, accountName, null, pSid, null, cchDomainName, peUse)) {
      throw new RuntimeException("LookupAccountNameW was expected to fail with ERROR_INSUFFICIENT_BUFFER");
    }
   
    int rc = Kernel32.INSTANCE.GetLastError();
    if (pSid.getValue() == 0 || rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
      throw new Win32Exception(rc);
    }

    Memory sidMemory = new Memory(pSid.getValue());
    PSID result = new PSID(sidMemory);
    char[] referencedDomainName = new char[cchDomainName.getValue() + 1];

    if (! Advapi32.INSTANCE.LookupAccountName(systemName, accountName, result, pSid, referencedDomainName, cchDomainName, peUse)) {
      throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
    }
   
    Account account = new Account();
    account.accountType = peUse.getPointer().getInt(0);
    account.name = accountName;

        String[] accountNamePartsBs = accountName.split("\\\\", 2);
        String[] accountNamePartsAt = accountName.split("@", 2);

        if (accountNamePartsBs.length == 2) {
          account.name = accountNamePartsBs[1];
        } else if (accountNamePartsAt.length == 2) {
          account.name = accountNamePartsAt[0];
        } else {
            account.name = accountName;
        }
   
    if (cchDomainName.getValue() > 0) {
      account.domain = Native.toString(referencedDomainName);
      account.fqn = account.domain + "\\" + account.name;
    } else {
      account.fqn = account.name;
    }
   
    account.sid = result.getBytes();
    account.sidString = convertSidToStringSid(new PSID(account.sid));
    return account;
  }

  /**
   * Get the account by SID on the local system.
   *
   * @param sid SID.
   * @return Account.
   */
  public static Account getAccountBySid(PSID sid) {
    return getAccountBySid(null, sid);
  }
 
  /**
   * Get the account by SID.
   *
   * @param systemName Name of the system.
   * @param sid SID.
   * @return Account.
   */
  public static Account getAccountBySid(String systemName, PSID sid) {
      IntByReference cchName = new IntByReference();
      IntByReference cchDomainName = new IntByReference();
      PointerByReference peUse = new PointerByReference();

      if (Advapi32.INSTANCE.LookupAccountSid(null, sid,
          null, cchName, null, cchDomainName, peUse)) {
      throw new RuntimeException("LookupAccountSidW was expected to fail with ERROR_INSUFFICIENT_BUFFER");
      }
     
      int rc = Kernel32.INSTANCE.GetLastError();
    if (cchName.getValue() == 0 || rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
      throw new Win32Exception(rc);
    }     
   
    char[] domainName = new char[cchDomainName.getValue()];
    char[] name = new char[cchName.getValue()];
     
    if (! Advapi32.INSTANCE.LookupAccountSid(null, sid,
          name, cchName, domainName, cchDomainName, peUse)) {
        throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
      }
   
    Account account = new Account();
    account.accountType = peUse.getPointer().getInt(0);
    account.name = Native.toString(name);
   
    if (cchDomainName.getValue() > 0) {
      account.domain = Native.toString(domainName);
      account.fqn = account.domain + "\\" + account.name;
    } else {
      account.fqn = account.name;
    }
   
    account.sid = sid.getBytes();
    account.sidString = convertSidToStringSid(sid);
    return account;
  }
 
  /**
   * Convert a security identifier (SID) to a string format suitable for display,
   * storage, or transmission.
   * @param sid SID bytes.
   * @return String SID.
   */
  public static String convertSidToStringSid(PSID sid) {
    PointerByReference stringSid = new PointerByReference();
    if (! Advapi32.INSTANCE.ConvertSidToStringSid(sid, stringSid)) {
      throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
    }
    String result = stringSid.getValue().getString(0, true);
    Kernel32.INSTANCE.LocalFree(stringSid.getValue());
    return result;
  }
 
  /**
   * Convert a string representation of a security identifier (SID) to
   * a binary format.
   * @param sidString
   *   String SID.
   * @return SID bytes.
   */
  public static byte[] convertStringSidToSid(String sidString) {
    PSIDByReference pSID = new PSIDByReference();
    if (! Advapi32.INSTANCE.ConvertStringSidToSid(sidString, pSID)) {
      throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
    }
    return pSID.getValue().getBytes();
  }
 
  /**
   * Compares a SID to a well known SID and returns TRUE if they match.
   * @param sidString
   *  String representation of a SID.
   * @param wellKnownSidType
   *  Member of the WELL_KNOWN_SID_TYPE enumeration to compare with the SID at pSid.
   * @return
   *  True if the SID is of the well-known type, false otherwise.
   */
  public static boolean isWellKnownSid(String sidString, int wellKnownSidType) {
    PSIDByReference pSID = new PSIDByReference();
    if (! Advapi32.INSTANCE.ConvertStringSidToSid(sidString, pSID)) {
      throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
    }
    return Advapi32.INSTANCE.IsWellKnownSid(pSID.getValue(), wellKnownSidType);
  }

  /**
   * Compares a SID to a well known SID and returns TRUE if they match.
   * @param sidBytes
   *  Byte representation of a SID.
   * @param wellKnownSidType
   *  Member of the WELL_KNOWN_SID_TYPE enumeration to compare with the SID at pSid.
   * @return
   *  True if the SID is of the well-known type, false otherwise.
   */
  public static boolean isWellKnownSid(byte[] sidBytes, int wellKnownSidType) {
    PSID pSID = new PSID(sidBytes);
    return Advapi32.INSTANCE.IsWellKnownSid(pSID, wellKnownSidType);   
  }
 
  /**
   * Get an account name from a string SID on the local machine.
   *
   * @param sidString SID.
   * @return Account.
   */
  public static Account getAccountBySid(String sidString) {
    return getAccountBySid(null, sidString);
  }
 
  /**
   * Get an account name from a string SID.
   *
   * @param systemName System name.
   * @param sidString SID.
   * @return Account.
   */
  public static Account getAccountBySid(String systemName, String sidString) {
    return getAccountBySid(systemName, new PSID(convertStringSidToSid(sidString)));
  }
 
  /**
   * This function returns the groups associated with a security token,
   * such as a user token.
   *
   * @param hToken Token.
   * @return Token groups.
   */
  public static Account[] getTokenGroups(HANDLE hToken) {
      // get token group information size
        IntByReference tokenInformationLength = new IntByReference();
        if (Advapi32.INSTANCE.GetTokenInformation(hToken,
            WinNT.TOKEN_INFORMATION_CLASS.TokenGroups, null, 0, tokenInformationLength)) {
          throw new RuntimeException("Expected GetTokenInformation to fail with ERROR_INSUFFICIENT_BUFFER");
        }
        int rc = Kernel32.INSTANCE.GetLastError();
        if (rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
          throw new Win32Exception(rc);
        }
        // get token group information
    WinNT.TOKEN_GROUPS groups = new WinNT.TOKEN_GROUPS(tokenInformationLength.getValue());
        if (! Advapi32.INSTANCE.GetTokenInformation(hToken,
            WinNT.TOKEN_INFORMATION_CLASS.TokenGroups, groups,
            tokenInformationLength.getValue(), tokenInformationLength)) {
          throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
        ArrayList<Account> userGroups = new ArrayList<Account>();
        // make array of names
      for (SID_AND_ATTRIBUTES sidAndAttribute : groups.getGroups()) {
        Account group = null;
        try {
          group = Advapi32Util.getAccountBySid(sidAndAttribute.Sid);
        } catch(Exception e) {
          group = new Account();
            group.sid = sidAndAttribute.Sid.getBytes();
            group.sidString = Advapi32Util.convertSidToStringSid(sidAndAttribute.Sid);
          group.name = group.sidString;
          group.fqn = group.sidString;
            group.accountType = SID_NAME_USE.SidTypeGroup;
        }
        userGroups.add(group);
      }
        return userGroups.toArray(new Account[0]);
  }

  /**
   * This function returns the information about the user who owns a security token,
   *
   * @param hToken Token.
   * @return Token user.
   */
  public static Account getTokenAccount(HANDLE hToken) {
      // get token group information size
        IntByReference tokenInformationLength = new IntByReference();
        if (Advapi32.INSTANCE.GetTokenInformation(hToken,
            WinNT.TOKEN_INFORMATION_CLASS.TokenUser, null, 0, tokenInformationLength)) {
          throw new RuntimeException("Expected GetTokenInformation to fail with ERROR_INSUFFICIENT_BUFFER");
        }
        int rc = Kernel32.INSTANCE.GetLastError();
        if (rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
          throw new Win32Exception(rc);
        }
        // get token user information
    WinNT.TOKEN_USER user = new WinNT.TOKEN_USER(tokenInformationLength.getValue());
        if (! Advapi32.INSTANCE.GetTokenInformation(hToken,
            WinNT.TOKEN_INFORMATION_CLASS.TokenUser, user,
            tokenInformationLength.getValue(), tokenInformationLength)) {
          throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }       
        return getAccountBySid(user.User.Sid);
  }
 
  /**
   * Return the group memberships of the currently logged on user.
   * @return An array of groups.
   */
  public static Account[] getCurrentUserGroups() {   
      HANDLEByReference phToken = new HANDLEByReference();     
      try {
        // open thread or process token
          HANDLE threadHandle = Kernel32.INSTANCE.GetCurrentThread();
          if (! Advapi32.INSTANCE.OpenThreadToken(threadHandle,
              WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY, true, phToken)) {
              if (W32Errors.ERROR_NO_TOKEN != Kernel32.INSTANCE.GetLastError()) {
                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
              }         
              HANDLE processHandle = Kernel32.INSTANCE.GetCurrentProcess();
              if (! Advapi32.INSTANCE.OpenProcessToken(processHandle,
                  WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY, phToken)) {
                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
              }
          }
          return getTokenGroups(phToken.getValue());
      } finally {
        if (phToken.getValue() != WinBase.INVALID_HANDLE_VALUE) {
          if (! Kernel32.INSTANCE.CloseHandle(phToken.getValue())) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
          }
        }
      }   
  }

  /**
   * Checks whether a registry key exists.
   * @param root
   *  HKEY_LOCAL_MACHINE, etc.
   * @param key
   *  Path to the registry key.
   * @return
   *  True if the key exists.
   */
  public static boolean registryKeyExists(HKEY root, String key) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, key, 0, WinNT.KEY_READ, phkKey);
    switch(rc) {
    case W32Errors.ERROR_SUCCESS:
      Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      return true;
    case W32Errors.ERROR_FILE_NOT_FOUND:
      return false;
    default:
      throw new Win32Exception(rc);
    }
  }
 
  /**
   * Checks whether a registry value exists.
   * @param root
   *  HKEY_LOCAL_MACHINE, etc.
   * @param key
   *  Registry key path.
   * @param value
   *  Value name.
   * @return
   *  True if the value exists.
   */
  public static boolean registryValueExists(HKEY root, String key, String value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, key, 0, WinNT.KEY_READ, phkKey);
    try {
      switch(rc) {
      case W32Errors.ERROR_SUCCESS:
        break;
      case W32Errors.ERROR_FILE_NOT_FOUND:
        return false;
      default:
        throw new Win32Exception(rc);
      }
      IntByReference lpcbData = new IntByReference();
      IntByReference lpType = new IntByReference();
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, (char[]) null, lpcbData);
      switch(rc) {
      case W32Errors.ERROR_SUCCESS:
      case W32Errors.ERROR_INSUFFICIENT_BUFFER:
        return true;
      case W32Errors.ERROR_FILE_NOT_FOUND:
        return false;
      default:
        throw new Win32Exception(rc);
      }
    } finally {
      if (phkKey.getValue() != WinBase.INVALID_HANDLE_VALUE) {
        rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
        if (rc != W32Errors.ERROR_SUCCESS) {
          throw new Win32Exception(rc);
        }
      }
    }
  } 

  /**
   * Get a registry REG_SZ value.
   * @param root
   *  Root key.
   * @param key
   *  Registry path.
   * @param value
   *  Name of the value to retrieve.
   * @return
   *  String value.
   */
  public static String registryGetStringValue(HKEY root, String key, String value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, key, 0, WinNT.KEY_READ, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      IntByReference lpcbData = new IntByReference();
      IntByReference lpType = new IntByReference();
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, (char[]) null, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      if (lpType.getValue() != WinNT.REG_SZ) {
        throw new RuntimeException("Unexpected registry type " + lpType.getValue() + ", expected REG_SZ");
      }
      char[] data = new char[lpcbData.getValue()];
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, data, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      return Native.toString(data);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }

  /**
   * Get a registry REG_EXPAND_SZ value.
   * @param root
   *  Root key.
   * @param key
   *  Registry path.
   * @param value
   *  Name of the value to retrieve.
   * @return
   *  String value.
   */
  public static String registryGetExpandableStringValue(HKEY root, String key, String value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, key, 0, WinNT.KEY_READ, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      IntByReference lpcbData = new IntByReference();
      IntByReference lpType = new IntByReference();
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, (char[]) null, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      if (lpType.getValue() != WinNT.REG_EXPAND_SZ) {
        throw new RuntimeException("Unexpected registry type " + lpType.getValue() + ", expected REG_SZ");
      }
      char[] data = new char[lpcbData.getValue()];
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, data, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      return Native.toString(data);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Get a registry REG_MULTI_SZ value.
   * @param root
   *  Root key.
   * @param key
   *  Registry path.
   * @param value
   *  Name of the value to retrieve.
   * @return
   *  String value.
   */
  public static String[] registryGetStringArray(HKEY root, String key, String value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, key, 0, WinNT.KEY_READ, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      IntByReference lpcbData = new IntByReference();
      IntByReference lpType = new IntByReference();
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, (char[]) null, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      if (lpType.getValue() != WinNT.REG_MULTI_SZ) {
        throw new RuntimeException("Unexpected registry type " + lpType.getValue() + ", expected REG_SZ");
      }
      Memory data = new Memory(lpcbData.getValue());
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, data, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      ArrayList<String> result = new ArrayList<String>();
      int offset = 0;
      while(offset < data.size()) {
        String s = data.getString(offset, true);
        offset += s.length() * Native.WCHAR_SIZE;
        offset += Native.WCHAR_SIZE;
        result.add(s);
      }
      return result.toArray(new String[0]);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Get a registry REG_BINARY value.
   * @param root
   *  Root key.
   * @param key
   *  Registry path.
   * @param value
   *  Name of the value to retrieve.
   * @return
   *  String value.
   */
  public static byte[] registryGetBinaryValue(HKEY root, String key, String value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, key, 0, WinNT.KEY_READ, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      IntByReference lpcbData = new IntByReference();
      IntByReference lpType = new IntByReference();
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, (char[]) null, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      if (lpType.getValue() != WinNT.REG_BINARY) {
        throw new RuntimeException("Unexpected registry type " + lpType.getValue() + ", expected REG_BINARY");
      }
      byte[] data = new byte[lpcbData.getValue()];
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, data, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      return data;
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Get a registry DWORD value.
   * @param root
   *  Root key.
   * @param key
   *  Registry key path.
   * @param value
   *  Name of the value to retrieve.
   * @return
   *  Integer value.
   */
  public static int registryGetIntValue(HKEY root, String key, String value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, key, 0, WinNT.KEY_READ, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      IntByReference lpcbData = new IntByReference();
      IntByReference lpType = new IntByReference();
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, (char[]) null, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      if (lpType.getValue() != WinNT.REG_DWORD) {
        throw new RuntimeException("Unexpected registry type " + lpType.getValue() + ", expected REG_SZ");
      }
      IntByReference data = new IntByReference();
      rc = Advapi32.INSTANCE.RegQueryValueEx(
          phkKey.getValue(), value, 0, lpType, data, lpcbData);
      if (rc != W32Errors.ERROR_SUCCESS && rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
        throw new Win32Exception(rc);
      }
      return data.getValue();
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Create a registry key.
   * @param hKey
   *  Parent key.
   * @param keyName
   *  Key name.
   * @return
   *  True if the key was created, false otherwise.
   */
  public static boolean registryCreateKey(HKEY hKey, String keyName) {
    HKEYByReference phkResult = new HKEYByReference();
    IntByReference lpdwDisposition = new IntByReference();
      int rc = Advapi32.INSTANCE.RegCreateKeyEx(hKey, keyName, 0, null, WinNT.REG_OPTION_NON_VOLATILE,
          WinNT.KEY_READ, null, phkResult, lpdwDisposition);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    rc = Advapi32.INSTANCE.RegCloseKey(phkResult.getValue());
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    return WinNT.REG_CREATED_NEW_KEY == lpdwDisposition.getValue();
  }

  /**
   * Create a registry key.
   * @param root
   *  Root key.
   * @param parentPath
   *  Path to an existing registry key.
   * @param keyName
   *  Key name.
   * @return
   *  True if the key was created, false otherwise.
   */
  public static boolean registryCreateKey(HKEY root, String parentPath, String keyName) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, parentPath, 0, WinNT.KEY_CREATE_SUB_KEY, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      return registryCreateKey(phkKey.getValue(), keyName);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }   
  }
 
  /**
   * Set an integer value in registry.
   * @param hKey
   *  Parent key.
   * @param name
   *  Value name.
   * @param value
   *  Value to write to registry.
   */
  public static void registrySetIntValue(HKEY hKey, String name, int value) {
        byte[] data = new byte[4];
        data[0] = (byte)(value & 0xff);
        data[1] = (byte)((value >> 8) & 0xff);
        data[2] = (byte)((value >> 16) & 0xff);
        data[3] = (byte)((value >> 24) & 0xff);
    int rc = Advapi32.INSTANCE.RegSetValueEx(hKey, name, 0, WinNT.REG_DWORD, data, 4);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
  }
 
  /**
   * Set an integer value in registry.
   * @param root
   *  Root key.
   * @param keyPath
   *  Path to an existing registry key.
   * @param name
   *  Value name.
   * @param value
   *  Value to write to registry.
   */
  public static void registrySetIntValue(HKEY root, String keyPath, String name, int value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ | WinNT.KEY_WRITE, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      registrySetIntValue(phkKey.getValue(), name, value);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }   
  }

  /**
   * Set a string value in registry.
   * @param hKey
   *  Parent key.
   * @param name
   *  Value name.
   * @param value
   *  Value to write to registry.
   */
  public static void registrySetStringValue(HKEY hKey, String name, String value) {
      char[] data = Native.toCharArray(value);
    int rc = Advapi32.INSTANCE.RegSetValueEx(hKey, name, 0, WinNT.REG_SZ,
        data, data.length * Native.WCHAR_SIZE);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
   
  }

  /**
   * Set a string value in registry.
   * @param root
   *  Root key.
   * @param keyPath
   *  Path to an existing registry key.
   * @param name
   *  Value name.
   * @param value
   *  Value to write to registry.
   */
  public static void registrySetStringValue(HKEY root, String keyPath, String name, String value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ | WinNT.KEY_WRITE, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      registrySetStringValue(phkKey.getValue(), name, value);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Set an expandable string value in registry.
   * @param hKey
   *  Parent key.
   * @param name
   *  Value name.
   * @param value
   *  Value to write to registry.
   */
  public static void registrySetExpandableStringValue(HKEY hKey, String name, String value) {
      char[] data = Native.toCharArray(value);
    int rc = Advapi32.INSTANCE.RegSetValueEx(hKey, name, 0, WinNT.REG_EXPAND_SZ,
        data, data.length * Native.WCHAR_SIZE);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
   
  }

  /**
   * Set a string value in registry.
   * @param root
   *  Root key.
   * @param keyPath
   *  Path to an existing registry key.
   * @param name
   *  Value name.
   * @param value
   *  Value to write to registry.
   */
  public static void registrySetExpandableStringValue(HKEY root, String keyPath, String name, String value) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ | WinNT.KEY_WRITE, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      registrySetExpandableStringValue(phkKey.getValue(), name, value);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }

  /**
   * Set a string array value in registry.
   * @param hKey
   *  Parent key.
   * @param name
   *  Name.
   * @param arr
   *  Array of strings to write to registry.
   */
  public static void registrySetStringArray(HKEY hKey, String name, String[] arr) {
    int size = 0;
    for(String s : arr) {
      size += s.length() * Native.WCHAR_SIZE;
      size += Native.WCHAR_SIZE;
    }
   
    int offset = 0;
    Memory data = new Memory(size);
    for(String s : arr) {
      data.setString(offset, s, true);
      offset += s.length() * Native.WCHAR_SIZE;
      offset += Native.WCHAR_SIZE;
    }
   
    int rc = Advapi32.INSTANCE.RegSetValueEx(hKey, name, 0, WinNT.REG_MULTI_SZ,
        data.getByteArray(0, size), size);
   
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
   
  }

  /**
   * Set a string array value in registry.
   * @param root
   *  Root key.
   * @param keyPath
   *  Path to an existing registry key.
   * @param name
   *  Value name.
   * @param arr
   *  Array of strings to write to registry.
   */
  public static void registrySetStringArray(HKEY root, String keyPath, String name, String[] arr) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ | WinNT.KEY_WRITE, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      registrySetStringArray(phkKey.getValue(), name, arr);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Set a binary value in registry.
   * @param hKey
   *  Parent key.
   * @param name
   *  Value name.
   * @param data
   *  Data to write to registry.
   */
  public static void registrySetBinaryValue(HKEY hKey, String name, byte[] data) {
    int rc = Advapi32.INSTANCE.RegSetValueEx(hKey, name, 0, WinNT.REG_BINARY, data, data.length);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
   
  }

  /**
   * Set a binary value in registry.
   * @param root
   *  Root key.
   * @param keyPath
   *  Path to an existing registry key.
   * @param name
   *  Value name.
   * @param data
   *  Data to write to registry.
   */
  public static void registrySetBinaryValue(HKEY root, String keyPath, String name, byte[] data) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ | WinNT.KEY_WRITE, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      registrySetBinaryValue(phkKey.getValue(), name, data);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Delete a registry key.
   * @param hKey
   *  Parent key.
   * @param keyName
   *  Name of the key to delete.
   */
  public static void registryDeleteKey(HKEY hKey, String keyName) {
    int rc = Advapi32.INSTANCE.RegDeleteKey(hKey, keyName);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }   
  }
 
  /**
   * Delete a registry key.
   * @param root
   *  Root key.
   * @param keyPath
   *  Path to an existing registry key.
   * @param keyName
   *  Name of the key to delete.
   */
  public static void registryDeleteKey(HKEY root, String keyPath, String keyName) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ | WinNT.KEY_WRITE, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      registryDeleteKey(phkKey.getValue(), keyName);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Delete a registry value.
   * @param hKey
   *  Parent key.
   * @param valueName
   *  Name of the value to delete.
   */
  public static void registryDeleteValue(HKEY hKey, String valueName) {
    int rc = Advapi32.INSTANCE.RegDeleteValue(hKey, valueName);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }   
  }
 
  /**
   * Delete a registry value.
   * @param root
   *  Root key.
   * @param keyPath
   *  Path to an existing registry key.
   * @param valueName
   *  Name of the value to delete.
   */
  public static void registryDeleteValue(HKEY root, String keyPath, String valueName) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ | WinNT.KEY_WRITE, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      registryDeleteValue(phkKey.getValue(), valueName);
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }
 
  /**
   * Get names of the registry key's sub-keys.
   * @param hKey
   *  Registry key.
   * @return
   *  Array of registry key names.
   */
  public static String[] registryGetKeys(HKEY hKey) {
      IntByReference lpcSubKeys = new IntByReference();
      IntByReference lpcMaxSubKeyLen = new IntByReference();
      int rc = Advapi32.INSTANCE.RegQueryInfoKey(hKey, null, null, null,
          lpcSubKeys, lpcMaxSubKeyLen, null, null, null, null, null, null);
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
      ArrayList<String> keys = new ArrayList<String>(lpcSubKeys.getValue());
      char[] name = new char[lpcMaxSubKeyLen.getValue() + 1];
      for (int i = 0; i < lpcSubKeys.getValue(); i++) {
        IntByReference lpcchValueName = new IntByReference(lpcMaxSubKeyLen.getValue() + 1);
          rc = Advapi32.INSTANCE.RegEnumKeyEx(hKey, i, name, lpcchValueName,
              null, null, null, null);
          if (rc != W32Errors.ERROR_SUCCESS) {
            throw new Win32Exception(rc);
          }
          keys.add(Native.toString(name));
      }
      return keys.toArray(new String[0]);
  }

  /**
   * Get names of the registry key's sub-keys.
   * @param root
   *  Root key.
   * @param keyPath
   *  Path to a registry key.
   * @return
   *  Array of registry key names.
   */
  public static String[] registryGetKeys(HKEY root, String keyPath) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {
      throw new Win32Exception(rc);
    }
    try {
      return registryGetKeys(phkKey.getValue());
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }
  }

  /**
   * Get a table of registry values.
   * @param hKey
   *  Registry key.
   * @return
   *  Table of values.
   */
  public static TreeMap<String, Object> registryGetValues(HKEY hKey) {
      IntByReference lpcValues = new IntByReference();
      IntByReference lpcMaxValueNameLen = new IntByReference();
      IntByReference lpcMaxValueLen = new IntByReference();
      int rc = Advapi32.INSTANCE.RegQueryInfoKey(hKey, null, null, null, null,
          null, null, lpcValues, lpcMaxValueNameLen, lpcMaxValueLen, null, null);
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    TreeMap<String, Object> keyValues = new TreeMap<String, Object>();   
      char[] name = new char[lpcMaxValueNameLen.getValue() + 1];
      byte[] data = new byte[lpcMaxValueLen.getValue()];
      for (int i = 0; i < lpcValues.getValue(); i++) {
        IntByReference lpcchValueName = new IntByReference(lpcMaxValueNameLen.getValue() + 1);
        IntByReference lpcbData = new IntByReference(lpcMaxValueLen.getValue());
        IntByReference lpType = new IntByReference();
          rc = Advapi32.INSTANCE.RegEnumValue(hKey, i, name, lpcchValueName, null,
              lpType, data, lpcbData);
          if (rc != W32Errors.ERROR_SUCCESS) {
            throw new Win32Exception(rc);
          }
         
          String nameString = Native.toString(name);
         
      Memory byteData = new Memory(lpcbData.getValue());
      byteData.write(0, data, 0, lpcbData.getValue());
         
          switch(lpType.getValue()) {
          case WinNT.REG_DWORD:
          {
              keyValues.put(nameString, byteData.getInt(0));
            break;
          }
          case WinNT.REG_SZ:
          case WinNT.REG_EXPAND_SZ:
          {
        keyValues.put(nameString, byteData.getString(0, true));
            break;
          }
          case WinNT.REG_BINARY:
          {
            keyValues.put(nameString, byteData.getByteArray(0, lpcbData.getValue()));
            break;
          }
          case WinNT.REG_MULTI_SZ:
          {
          Memory stringData = new Memory(lpcbData.getValue());
          stringData.write(0, data, 0, lpcbData.getValue());
          ArrayList<String> result = new ArrayList<String>();
          int offset = 0;
          while(offset < stringData.size()) {
            String s = stringData.getString(offset, true);
            offset += s.length() * Native.WCHAR_SIZE;
            offset += Native.WCHAR_SIZE;
            result.add(s);
          }
          keyValues.put(nameString, result.toArray(new String[0]));
          break;
          }
          default:
            throw new RuntimeException("Unsupported type: " + lpType.getValue());
          }
      }
      return keyValues;
  }
 
  /**
   * Get a table of registry values.
   * @param root
   *  Registry root.
   * @param keyPath
   *  Regitry key path.
   * @return
   *  Table of values.
   */
  public static TreeMap<String, Object> registryGetValues(HKEY root, String keyPath) {
    HKEYByReference phkKey = new HKEYByReference();
    int rc = Advapi32.INSTANCE.RegOpenKeyEx(root, keyPath, 0, WinNT.KEY_READ, phkKey);
    if (rc != W32Errors.ERROR_SUCCESS) {      throw new Win32Exception(rc);
    }
    try {
      return registryGetValues(phkKey.getValue());
    } finally {
      rc = Advapi32.INSTANCE.RegCloseKey(phkKey.getValue());
      if (rc != W32Errors.ERROR_SUCCESS) {
        throw new Win32Exception(rc);
      }
    }   
  }
 
  /**
   * Converts a map of environment variables to an environment block suitable
   * for {@link Advapi32#CreateProcessAsUser}. This environment block consists
   * of null-terminated blocks of null-terminated strings. Each string is in the
   * following form: name=value\0
   * @param environment Environment variables
   * @return A environment block
   */
  public static String getEnvironmentBlock(Map<String, String> environment) {
    StringBuffer out = new StringBuffer();
    for (Entry<String, String> entry: environment.entrySet()) {
      if (entry.getValue() != null) {
        out.append(entry.getKey() + "=" + entry.getValue() + "\0");
      }
    }
    return out.toString() + "\0";
  }
 
  /**
   * Event log types.
   */
  public static enum EventLogType {
    Error,
    Warning,
    Informational,
    AuditSuccess,
    AuditFailure
  }
 
  /**
   * An event log record.
   */
  public static class EventLogRecord {
    private EVENTLOGRECORD _record = null;
    private String _source;
    private byte[] _data;
    private String[] _strings;
   
    /**
     * Raw record data.
     * @return
     *  EVENTLOGRECORD.
     */
    public EVENTLOGRECORD getRecord() {
      return _record;
    }
   
    /**
     * Event Id.
     * @return
     *  Integer.
     */
    public int getEventId() {
      return _record.EventID.intValue();
    }
   
    /**
     * Event source.
     * @return
     *  String.
     */
    public String getSource() {
      return _source;
    }
   
    /**
     * Status code for the facility, part of the Event ID.
     * @return
     *  Status code.
     */
    public int getStatusCode() {
      return _record.EventID.intValue() & 0xFFFF;
    }
   
    /**
     * Record number of the record. This value can be used with the EVENTLOG_SEEK_READ flag in
     * the ReadEventLog function to begin reading at a specified record.
     * @return
     *  Integer.
     */
    public int getRecordNumber() {
      return _record.RecordNumber.intValue();
    }
   
    /**
     * Record length, with data.
     * @return
     *  Number of bytes in the record including data.
     */
    public int getLength() {
      return _record.Length.intValue();
    }
   
    /**
     * Strings associated with this event.
     * @return
     *  Array of strings or null.
     */
    public String[] getStrings() {
      return _strings;
    }
   
    /**
     * Event log type.
     * @return
     *  Event log type.
     */
    public EventLogType getType() {
      switch(_record.EventType.intValue()) {
      case WinNT.EVENTLOG_SUCCESS:
      case WinNT.EVENTLOG_INFORMATION_TYPE:
        return EventLogType.Informational;
      case WinNT.EVENTLOG_AUDIT_FAILURE:
        return EventLogType.AuditFailure;
      case WinNT.EVENTLOG_AUDIT_SUCCESS:
        return EventLogType.AuditSuccess;
      case WinNT.EVENTLOG_ERROR_TYPE:
        return EventLogType.Error;
      case WinNT.EVENTLOG_WARNING_TYPE:
        return EventLogType.Warning;
      default:
        throw new RuntimeException("Invalid type: " + _record.EventType.intValue());
      }
    }
   
    /**
     * Raw data associated with the record.
     * @return
     *  Array of bytes or null.
     */
    public byte[] getData() {
      return _data;
    }
   
    public EventLogRecord(Pointer pevlr) {
      _record = new EVENTLOGRECORD(pevlr);
      _source = pevlr.getString(_record.size(), true);
      // data
      if (_record.DataLength.intValue() > 0) {
        _data = pevlr.getByteArray(_record.DataOffset.intValue(),
            _record.DataLength.intValue());
      }
      // strings
      if (_record.NumStrings.intValue() > 0) {
        ArrayList<String> strings = new ArrayList<String>();
        int count = _record.NumStrings.intValue();
        long offset = _record.StringOffset.intValue();
        while(count > 0) {
          String s = pevlr.getString(offset, true);
          strings.add(s);
          offset += s.length() * Native.WCHAR_SIZE;
          offset += Native.WCHAR_SIZE;
          count--;
        }
        _strings = strings.toArray(new String[0]);
      }
    }
  }
 
  /**
   * An iterator for Event Log entries.
   */
  public static class EventLogIterator
    implements Iterable<EventLogRecord>, Iterator<EventLogRecord> {
   
      private HANDLE _h = null;
      private Memory _buffer = new Memory(1024 * 64); // memory buffer to store events
      private boolean _done = false; // no more events
      private int _dwRead = 0; // number of bytes remaining in the current buffer
      private Pointer _pevlr = null; // pointer to the current record
      private int _flags = WinNT.EVENTLOG_FORWARDS_READ;

    public EventLogIterator(String sourceName) {
      this(null, sourceName, WinNT.EVENTLOG_FORWARDS_READ);
    }
   
    public EventLogIterator(String serverName, String sourceName, int flags) {
      _flags = flags;
        _h = Advapi32.INSTANCE.OpenEventLog(serverName, sourceName);
        if (_h == null) {
          throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
    }
   
    private boolean read() {
      // finished or bytes remain, don't read any new data
      if (_done || _dwRead > 0) {
        return false;
      }
     
        IntByReference pnBytesRead = new IntByReference();
        IntByReference pnMinNumberOfBytesNeeded = new IntByReference();
     
      if (! Advapi32.INSTANCE.ReadEventLog(_h,
            WinNT.EVENTLOG_SEQUENTIAL_READ | _flags,
            0, _buffer, (int) _buffer.size(), pnBytesRead, pnMinNumberOfBytesNeeded)) {

        int rc = Kernel32.INSTANCE.GetLastError();
       
        // not enough bytes in the buffer, resize
        if (rc == W32Errors.ERROR_INSUFFICIENT_BUFFER) {
          _buffer = new Memory(pnMinNumberOfBytesNeeded.getValue());
         
          if (! Advapi32.INSTANCE.ReadEventLog(_h,
                WinNT.EVENTLOG_SEQUENTIAL_READ | _flags,
                0, _buffer, (int) _buffer.size(), pnBytesRead, pnMinNumberOfBytesNeeded)) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
          }         
        } else {
          // read failed, no more entries or error
          close();
          if (rc != W32Errors.ERROR_HANDLE_EOF) {
            throw new Win32Exception(rc);
          }
          return false;
        }
      }
     
        _dwRead = pnBytesRead.getValue();
        _pevlr = _buffer;
        return true;
    }
   
    /**
     * Call close() in the case when the caller needs to abandon the iterator before
     * the iteration completes.
     */
    public void close() {
      _done = true;
      if (_h != null) {
        if (! Advapi32.INSTANCE.CloseEventLog(_h)) {
          throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
        _h = null;
      }
    }
   
    @Override
    public Iterator<EventLogRecord> iterator() {
      return this;
    }

    @Override
    public boolean hasNext() {
      read();
      return ! _done;
    }

    @Override
    public EventLogRecord next() {
      read();
      EventLogRecord record = new EventLogRecord(_pevlr);
        _dwRead -= record.getLength();
        _pevlr = _pevlr.share(record.getLength());
      return record;
    }

    @Override
    public void remove() {
     
    }
  }
}
TOP

Related Classes of com.sun.jna.platform.win32.Advapi32Util

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.