Yuljup

Get folder owners full name - Network path to share

5 posts in this topic

Hi,

 

Is there a way to make a variaton of the following scripts to retreive the full name of the owner of a Windows share?

Lets say I would like to know who the owner of this folder is: ServerHiddenShare$User

Example script one works with local folders, but it's not able to look for a network share.

 

Example 1:

Dim $objSD
$varFolderName = "C:\temp\test"
$oWMIService = ObjGet("winmgmts:")
$oFolderSecuritySettings = $oWMIService.Get("Win32_LogicalFileSecuritySetting='" & $varFolderName & "'")
$intRetVal = $oFolderSecuritySettings.GetSecurityDescriptor($objSD)

If $intRetVal = 0 Then
   MsgBox (0, "", "Owner: " & $objSD.Owner.Domain & "\" & $objSD.Owner.Name)
Else
   MsgBox (0, "", "Couldn't retrieve security descriptor.")
EndIf

Example 2:

MsgBox(0,"User Full Name",GetFullName(@UserName))

Func GetFullName($sUserName)
    $colItems = ""
    $strComputer = "localhost"

    $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_UserAccount WHERE Name = '" & $sUserName &  "'", "WQL", 0x10 + 0x20)

    If IsObj($colItems) then
       For $objItem In $colItems
          Return $objItem.FullName
       Next
    Else
       Return SetError(1,0,"")
    Endif
EndFunc

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

See in Set Acl permissions UDF '?do=embed' frameborder='0' data-embedContent>> or

#include-once
#RequireAdmin
Opt("MustDeclareVars",1)

;;Global $aOle32 = DllCall("ole32.dll", "long", "OleInitialize", "PTR", 0)
If Not IsDeclared("arDllCall") Then Global Static $arDllCall

#Region ;**** Token Privileges ****
Global Const $hKernel32DLL = DllOpen("Kernel32.dll")
Global Const $hAdvapi32Dll = DllOpen("AdvApi32.dll")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                    ;;
;;               NT Defined Privileges                                ;;
;;                                                                    ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Global Const $SE_RESTORE_NAME                = "SeRestorePrivilege"
Global Const $SE_BACKUP_NAME                 = "SeBackupPrivilege"
Global Const $SE_SECURITY_NAME               = "SeSecurityPrivilege"
Global Const $SE_TAKE_OWNERSHIP_NAME         = "SeTakeOwnershipPrivilege"
Global Const $SE_DEBUG_NAME                  = "SeDebugPrivilege"
Global Const $SE_CREATE_SYMBOLIC_LINK_NAME   = "SeCreateSymbolicLinkPrivilege"
Global Static $aTokenPrivilegesNewState[6][2] = [[$SE_RESTORE_NAME,2],[$SE_BACKUP_NAME,2],[$SE_SECURITY_NAME,2],[$SE_TAKE_OWNERSHIP_NAME,2],[$SE_DEBUG_NAME,2],[$SE_CREATE_SYMBOLIC_LINK_NAME,2]]
Global Static $iTokenPrivilegesState
Global Static $aTokenPrivilegesPreviousState = _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)

Global Static $BA_SIDS
Global Static $US_SIDS
Global Const $PSIDADMIN = _GetUserSid("BA")

; #FUNCTION# ====================================================================================================================================
; Name...........: _WinAPI_SetPrivilegeEx
; Description ...: Enables or disables special privileges as required by some DllCalls
; Syntax.........: _WinAPI_SetPrivilegeEx($avPrivilege)
; Parameters ....: $avPrivilege - An array of privileges and respective attributes
;                                 $SE_PRIVILEGE_ENABLED - The function enables the privilege
;                                 $SE_PRIVILEGE_REMOVED - The privilege is removed from the list of privileges in the token
;                                 0 - The function disables the privilege
; Requirement(s).: None
; Return values .: Success - An array of modified privileges and their respective previous attribute state
;                  Failure - An empty array
;                            Sets @Error
; Author ........: engine
; Modified.......: FredAI, DXRW4E
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......;
; ===============================================================================================================================================
Func _WinAPI_SetPrivilegeEx($avPrivilege)
    $iTokenPrivilegesState = $iTokenPrivilegesState ? 0 : 1
    If Not UBound($avPrivilege) Then Return SetError(1, 0, 0)
    Local $tagTP = "DWORD", $iTokens = UBound($avPrivilege), $iError = 0, $iCount
    For $i = 1 To $iTokens
        $tagTP &= ";DWORD;LONG;DWORD"
    Next
    Local $tCurrState = DLLStructCreate($tagTP), $tPrevState = DllStructCreate($tagTP), $tLUID = DllStructCreate("DWORD;LONG")
    DLLStructSetData($tCurrState, 1, $iTokens)
    For $i = 0 To $iTokens - 1
        DllCall($hAdvapi32Dll, "BOOL", "LookupPrivilegeValueW", "WSTR", Null, "WSTR", $avPrivilege[$i][0], "STRUCT*", $tLUID)
        DLLStructSetData($tCurrState, 3 * $i + 2, DllStructGetData($tLUID, 1))
        DLLStructSetData($tCurrState, 3 * $i + 3, DllStructGetData($tLUID, 2))
        DLLStructSetData($tCurrState, 3 * $i + 4, $avPrivilege[$i][1])
    Next
    Local $hToken = DllCall($hAdvapi32Dll, "BOOL", "OpenProcessToken", "HANDLE", DllCall($hKernel32DLL, "HANDLE", "GetCurrentProcess")[0], "DWORD", 40, "HANDLE*", 0)[3] ;; TOKEN_ADJUST_PRIVILEGES + TOKEN_QUERY = 40
    DllCall($hAdvapi32Dll, "BOOL", "AdjustTokenPrivileges", "HANDLE", $hToken, "BOOL", False, "STRUCT*", $tCurrState, "DWORD", DllStructGetSize($tCurrState), "STRUCT*", $tPrevState, "DWORD*", 0)
    $iError = DllCall($hKernel32DLL, "DWORD", "GetLastError")[0]
    DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hToken)
    $iCount = DllStructGetData($tPrevState, 1)
    If $iCount < 1 Then Return SetError($iError, 0, 0)
    Local $pLUID, $tName, $avPrevState[$iCount][2], $pPrevState = DllStructGetPtr($tPrevState)
    For $i = 0 To $iCount - 1
        $pLUID = $pPrevState + 12 * $i + 4
        $tName = DllStructCreate("WCHAR[" & DllCall($hAdvapi32Dll, "BOOL", "LookupPrivilegeNameW", "WSTR", Null, "PTR", $pLUID, "PTR", 0, "DWORD*", 0)[4] & "]")
        DllCall($hAdvapi32Dll, "BOOL", "LookupPrivilegeNameW", "WSTR", Null, "PTR", $pLUID, "STRUCT*", $tName, "DWORD*", DllStructGetSize($tName))
        $avPrevState[$i][0] = DllStructGetData($tName, 1)
        $avPrevState[$i][1] = DllStructGetData($tPrevState, 3 * $i + 4)
    Next
    Return SetError($iError, 1, $avPrevState)
EndFunc ;==> _WinAPI_SetPrivilegeEx

; #FUNCTION# ====================================================================================================================
; Name...........: _GetUserSid
; Description ...: Get BUILTIN ADMINISTRATORS a binary SID
; Syntax.........: _GetUserSid()
; Parameters ....: $SDDLUser - SDDL User
; Return values .: Success - BUILTIN ADMINISTRATORS SID in a byte structure
; Author ........: Paul Campbell (PaulIA) & trancexx
; Modified.......: DXRW4E
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _GetUserSid($SDDLUser = "BA")
    Local $SIDS, $SIDSB, $PSID = DllCall($hAdvapi32Dll, "BOOL", "ConvertStringSidToSidW", "WSTR", $SDDLUser, "PTR*", 0)
    If @Error Or Not $PSID[0] Then
        $SIDS = DllStructCreate("byte Data[16]")
        DllStructSetData($SIDS, "Data", "0x01020000000000052000000020020000")
    Else
        $SIDSB = DllCall($hAdvapi32Dll, "DWORD", "GetLengthSid", "PTR", $PSID[2])
        $SIDS = DllStructCreate("byte Data[" & $SIDSB[0] & "]")
        DllStructSetData($SIDS, "Data", DllStructGetData(DllStructCreate("byte Data[" & $SIDSB[0] & "]", $PSID[2]), "Data"))
        DllCall($hKernel32DLL, "PTR", "LocalFree", "PTR", $PSID[2])
    EndIf
    If $SDDLUser = "BA" Then
        $BA_SIDS = $SIDS
    Else
        $US_SIDS = $SIDS
    EndIf
    Return DllStructGetPtr($SIDS)
EndFunc

Func _WinAPI_GetLastErrorEx()
    $arDllCall = DllCall($hKernel32DLL, "LONG", "GetLastError")
    Return (@Error ? @Error : $arDllCall[0])
EndFunc ;==>_WinAPI_GetLastErrorEx

#Endregion ;**** Token Privileges ****

#Region ;**** String Security Descriptor ****

Global Const $SE_INVALID_HANDLE_VALUE = Ptr(-1)
Global Const $SDDL_REVISION_1     = 1
Global Const $OWNER_SECURITY_INFORMATION              = 0x00000001
Global Const $GROUP_SECURITY_INFORMATION              = 0x00000002
Global Const $DACL_SECURITY_INFORMATION               = 0x00000004
Global Const $OWNER_DACL_SECURITY_INFORMATION         = 0x00000005
Global Const $SACL_SECURITY_INFORMATION               = 0x00000008
Global Const $SE_DACL_PROTECTED                = 0x1000
Global Const $SE_SACL_PROTECTED                = 0x2000
Global Const $PROTECTED_DACL_SECURITY_INFORMATION     = 0x80000000
Global Const $PROTECTED_SACL_SECURITY_INFORMATION     = 0x40000000
Global Const $UNPROTECTED_DACL_SECURITY_INFORMATION   = 0x20000000
Global Const $UNPROTECTED_SACL_SECURITY_INFORMATION   = 0x10000000
Global Const $DACL_SECURITY_INFORMATION_PROTECTED     = BitOR($DACL_SECURITY_INFORMATION, $PROTECTED_DACL_SECURITY_INFORMATION)
Global Const $DACL_SECURITY_INFORMATION_UNPROTECTED   = BitOR($DACL_SECURITY_INFORMATION, $UNPROTECTED_DACL_SECURITY_INFORMATION)
Global Const $SACL_SECURITY_INFORMATION_PROTECTED     = BitOR($SACL_SECURITY_INFORMATION, $PROTECTED_SACL_SECURITY_INFORMATION)
Global Const $SACL_SECURITY_INFORMATION_UNPROTECTED   = BitOR($SACL_SECURITY_INFORMATION, $UnPROTECTED_SACL_SECURITY_INFORMATION)


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_GetFileSecurity
; Description ...: The _WinAPI_GetFileSecurity function retrieves a copy of the String-Format Security Descriptor for File or Directry.
;                   The caller identifies the object by a Name.
; Syntax.........: _WinAPI_GetFileSecurity($sObjectName[, $dwSecurityInfo])
; Parameters ....: $sObjectName    - Indicates a file or directory. The name string that identifies a file or directory object can be in one of the following formats:
;                                      A relative path, such as FileName.dat or ..\FileName
;                                      An absolute path, such as FileName.dat, C:\DirectoryName\FileName.dat, or G:\RemoteDirectoryName\FileName.dat.
;                                      A UNC name, such as \\ComputerName\ShareName\FileName.dat.
;                                    However this parameter can also be a Kernel ObjectName, example
;                                      \DosDevices\C:\DirectoryName\FileName.dat
;                                      \Device\HarddiskVolume2\DirectoryName\FileName.dat
;                  $dwSecurityInfo - Optional, A set of bit flags that indicate the type of security information to retrieve.
;                  | This parameter can be a combination of the SECURITY_INFORMATION bit flags.
;                  | Defaut = BitOr($OWNER_SECURITY_INFORMATION, $DACL_SECURITY_INFORMATION)
;                  |$OWNER_SECURITY_INFORMATION (1) - The owner identifier of the object is being referenced.
;                  |$GROUP_SECURITY_INFORMATION (2) - The primary group identifier of the object is being referenced.
;                  |$DACL_SECURITY_INFORMATION (4)  - The DACL of the object is being referenced.
;                  |$SACL_SECURITY_INFORMATION (8)  - The SACL of the object is being referenced.
;                  |$ALL_SECURITY_INFORMATION (15)  - The Owner & Primary Group & DACL & SACL of the object is being referenced.
; Return values .: Success      - If the function succeeds, the return A string security descriptor and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is None ''. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If any of the ppsidOwner, ppsidGroup, ppDacl, or ppSacl parameters are non-NULL, and the SecurityInfo parameter
;                    specifies that they be retrieved from the object, those parameters will point to the corresponding parameters
;                    in the security descriptor returned in ppSecurityDescriptor. If the security descriptor does not contain the
;                    requested information, the corresponding parameter will be set to NULL.
;                  To read the owner, group, or DACL from the object's security descriptor, the object's DACL must
;                    grant READ_CONTROL access to the caller, or the caller must be the owner of the object.
;                  To read the system access control list of the object, the $SE_SECURITY_NAME privilege must be enabled for the calling process.
;                    For information about the security implications of enabling privileges, see Running with Special Privileges.
;                  This function does not handle race conditions. If your thread calls this function at the approximate time that
;                    another thread changes the object's security descriptor, then this function could fail.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless
;                    signing has been turned off for the system, but no encryption is performed.
;                  For more information about controlling access to objects through user accounts, group accounts, or logon sessions,
;                    see How DACLs Control Access to an Object http://msdn.microsoft.com/en-us/library/windows/desktop/aa446683(v=vs.85).aspx
;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is set in the input security descriptor, the function fails.;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is not set in the input security descriptor, the resulting
;                    security descriptor string does not have a D: component. For more information, see Security Descriptor String Format.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_GetFileSecurity("C:\DirectoryName\FileName.dat")
;                  _WinAPI_GetFileSecurity("\DosDevices\C:\DirectoryName\FileName.dat")
;                  _WinAPI_GetFileSecurity("\Device\HarddiskVolume2\DirectoryName\FileName.dat")
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_GetFileSecurity(Const ByRef $sObjectName, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
    If @Error Then Return SetError(1, -@Error, "")
    If $arDllCall[0] Then ;; $ERROR_ACCESS_DENIED = 5 - $ERROR_FILE_NOT_FOUND = 2 - $ERROR_INVALID_NAME = 123
        If $arDllCall[0] <> 5 And _WinAPI_GetFilePathByObjectName($sObjectName, $arDllCall[1]) Then $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
        If $arDllCall[0] = 5 Then  ;; will not have to ever happen
            ;; $dwDesiredAccess = $MAXIMUM_ALLOWED - 0x02000000 OR BitOr($READ_CONTROL, $ACCESS_SYSTEM_SECURITY) - 0x1020000
            ;; $dwCreationDisposition = $OPEN_EXISTING - 3, $dwFlagsAndAttributes = $FILE_FLAG_BACKUP_SEMANTICS - 0x2000000
            $arDllCall = DllCall($hKernel32DLL, "HANDLE", "CreateFileW", "WSTR", $arDllCall[1], "DWORD", 0x02000000, "DWORD", 0, "PTR", Null, "DWORD", 3, "DWORD", 0x2000000, "PTR", Null)
            If @Error Or $arDllCall[0] = $SE_INVALID_HANDLE_VALUE Then Return SetError(3, (@Error ? -@Error : _WinAPI_GetLastErrorEx()), "")
            Local $hFile = $arDllCall[0]
            $pSecurityDescriptor = _WinAPI_GetFileSecurityEx($hFile, $dwSecurityInfo)
            Return SetError(@Error, @Extended + DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hFile), $pSecurityDescriptor)
        EndIf
        If $arDllCall[0] Then Return SetError(1, $arDllCall[0], "")
    EndIf
    $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertSecurityDescriptorToStringSecurityDescriptorW", "PTR", $pSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "DWORD", $dwSecurityInfo, "WSTR*", 0, "PTR", Null)
    If @Error Or Not $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : _WinAPI_GetLastErrorEx()) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), "")
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return $arDllCall[4]
EndFunc ;==>_WinAPI_GetFileSecurity


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_GetFileSecurityEx
; Description ...: The _WinAPI_GetFileSecurityEx function retrieves a copy of the String-Format Security Descriptor for File or Directry.
;                   The caller identifies the object by a Handle.
; Syntax.........: _WinAPI_GetFileSecurityEx($hFile[, $dwSecurityInfo])
; Parameters ....: $hFile          - A handle to the file from which to retrieve security information.
;                  $dwSecurityInfo - Optional, A set of bit flags that indicate the type of security information to retrieve.
;                  | This parameter can be a combination of the SECURITY_INFORMATION bit flags.
;                  | Defaut = BitOr($OWNER_SECURITY_INFORMATION, $DACL_SECURITY_INFORMATION)
;                  |$OWNER_SECURITY_INFORMATION (1) - The owner identifier of the object is being referenced.
;                  |$GROUP_SECURITY_INFORMATION (2) - The primary group identifier of the object is being referenced.
;                  |$DACL_SECURITY_INFORMATION (4)  - The DACL of the object is being referenced.
;                  |$SACL_SECURITY_INFORMATION (8)  - The SACL of the object is being referenced.
;                  |$ALL_SECURITY_INFORMATION (15)  - The Owner & Primary Group & DACL & SACL of the object is being referenced.
; Return values .: Success      - If the function succeeds, the return A string security descriptor and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is None ''. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If any of the ppsidOwner, ppsidGroup, ppDacl, or ppSacl parameters are non-NULL, and the SecurityInfo parameter
;                    specifies that they be retrieved from the object, those parameters will point to the corresponding parameters
;                    in the security descriptor returned in ppSecurityDescriptor. If the security descriptor does not contain the
;                    requested information, the corresponding parameter will be set to NULL.
;                  To read the owner, group, or DACL from the object's security descriptor, the object's DACL must
;                    grant READ_CONTROL access to the caller, or the caller must be the owner of the object.
;                  To read the system access control list of the object, the $SE_SECURITY_NAME privilege must be enabled for the calling process.
;                    For information about the security implications of enabling privileges, see Running with Special Privileges.
;                  This function does not handle race conditions. If your thread calls this function at the approximate time that
;                    another thread changes the object's security descriptor, then this function could fail.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless
;                    signing has been turned off for the system, but no encryption is performed.
;                  For more information about controlling access to objects through user accounts, group accounts, or logon sessions,
;                    see How DACLs Control Access to an Object http://msdn.microsoft.com/en-us/library/windows/desktop/aa446683(v=vs.85).aspx
;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is set in the input security descriptor, the function fails.;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is not set in the input security descriptor, the resulting
;                    security descriptor string does not have a D: component. For more information, see Security Descriptor String Format.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_GetFileSecurityEx($hFile)
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_GetFileSecurityEx(Const ByRef $hFile, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $hFile, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
    If @Error Then Return SetError(1, -@Error, "")
    If $arDllCall[0] Then
        If $arDllCall[0] <> 5 Then Return SetError(1, $arDllCall[0], "")
        ;; $dwDesiredAccess = $MAXIMUM_ALLOWED - 0x02000000 OR BitOr($READ_CONTROL, $ACCESS_SYSTEM_SECURITY) - 0x1020000
        ;; $dwFlags = $FILE_FLAG_BACKUP_SEMANTICS - 0x2000000
        $arDllCall = DllCall($hKernel32DLL, "HANDLE", "ReOpenFile", "HANDLE", $hFile, "DWORD", 0x02000000, "DWORD", 0, "DWORD", 0x2000000)
        If @Error Or $arDllCall[0] = $SE_INVALID_HANDLE_VALUE Then Return SetError(3, (@Error ? -@Error : _WinAPI_GetLastErrorEx()), "")
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $arDllCall[0], "INT", 1, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
        DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $arDllCall[1])
        If $arDllCall[0] Then Return SetError(1, $arDllCall[0], "")
    EndIf
    $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertSecurityDescriptorToStringSecurityDescriptorW", "PTR", $pSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "DWORD", $dwSecurityInfo, "WSTR*", 0, "PTR", Null)
    If @Error Or Not $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : _WinAPI_GetLastErrorEx()) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), "")
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return $arDllCall[4]
EndFunc ;==>_WinAPI_GetFileSecurityEx


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_SetFileSecurity
; Description ...: The _WinAPI_SetFileSecurity function sets specified security information in the Security Descriptor of a File or Directry.
;                   The caller identifies the object by a Name.
; Syntax.........: _WinAPI_SetFileSecurity($sObjectName[, $sSecurityDescriptor])
; Parameters ....: $sObjectName         - Indicates a file or directory. The name string that identifies a file or directory object can be in
;                                          one of the following formats:
;                                           A relative path, such as FileName.dat or ..\FileName
;                                           An absolute path, such as FileName.dat, C:\DirectoryName\FileName.dat, or G:\RemoteDirectoryName\FileName.dat.
;                                           A UNC name, such as \\ComputerName\ShareName\FileName.dat.
;                                         However this parameter can also be a Kernel ObjectName, example
;                                           \DosDevices\C:\DirectoryName\FileName.dat
;                                           \Device\HarddiskVolume2\DirectoryName\FileName.dat
;                  $sSecurityDescriptor - String containing the string-format security descriptor, see _WinAPI_GetFileSecurity()
; Return values .: Success      - If the function succeeds, the return ERROR_SUCCESS and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is non-zero. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If you are setting the discretionary access control list (DACL) or any elements in the system access control list (SACL)
;                    of an object, the system automatically propagates any inheritable access control entries (ACEs) to existing child objects,
;                    according to the rules of inheritance.
;                  The _WinAPI_SetFileSecurity function does not reorder access-allowed or access-denied ACEs based on the preferred order.
;                    When propagating inheritable ACEs to existing child objects, _WinAPI_SetFileSecurity puts inherited ACEs in order after
;                    all of the noninherited ACEs in the DACLs of the child objects.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless signing
;                    has been turned off for the system, but no encryption is performed.
;                  When you update access rights of a folder indicated by an UNC path, for example \\Test\TestFolder, the original inherited
;                    ACE is removed and the full volume path is not included.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_SetFileSecurity("C:\DirectoryName\FileName.dat", "O:BAD:PAI(A;CI;GA;;;SY)(A;CI;GA;;;BA)(A;CI;GR;;;BU)")
;                  _WinAPI_SetFileSecurity("\DosDevices\C:\DirectoryName\FileName.dat", "D:PAI(A;CI;GA;;;SY)(A;CI;GA;;;BA)(A;CI;GR;;;BU)")
;                  _WinAPI_SetFileSecurity("\Device\HarddiskVolume2\DirectoryName\FileName.dat", "O:BA")
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_SetFileSecurity(Const ByRef $sObjectName, Const ByRef $sSecurityDescriptor)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl, $pSecDes;, $iControl
    $pSecurityDescriptor = _WinAPI_LookupStringSecurityDescriptorParts($sSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    If @Error Then Return SetError(2, @Extended, 2)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    If @Error Then Return SetError(1, -@Error + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
    If $arDllCall[0] Then ;; $ERROR_ACCESS_DENIED = 5 - $ERROR_FILE_NOT_FOUND = 2 - $ERROR_INVALID_NAME = 123
        If $arDllCall[0] <> 5 And _WinAPI_GetFilePathByObjectName($sObjectName, $arDllCall[1]) Then $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        If $arDllCall[0] = 5 Then  ;; will not have to ever happen
            If Not $psidOwner Then
                $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR*", 0, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
                If @Error Or $arDllCall[0] Then
                    ;; $dwDesiredAccess = $MAXIMUM_ALLOWED - 0x02000000 OR BitOr($READ_CONTROL, $WRITE_DAC, $WRITE_OWNER, $SYNCHRONIZE, $ACCESS_SYSTEM_SECURITY) - 0x011E0000
                    ;; $dwCreationDisposition = $OPEN_EXISTING - 3, $dwFlagsAndAttributes = $FILE_FLAG_BACKUP_SEMANTICS - 0x2000000
                    $arDllCall = DllCall($hKernel32DLL, "HANDLE", "CreateFileW", "WSTR", (@Error ? $sObjectName : $arDllCall[1]), "DWORD", 0x02000000, "DWORD", 0, "PTR", Null, "DWORD", 3, "DWORD", 0x2000000, "PTR", Null)
                    If @Error Or $arDllCall[0] = $SE_INVALID_HANDLE_VALUE Then Return SetError(3, (@Error ? -@Error : $arDllCall[0]) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 3)
                    Local $hFile = $arDllCall[0]
                    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hFile, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
                    SetError((@Error ? -@Error : $arDllCall[0]) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor) + DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hFile))
                    Return SetError(@Error, @Error, @Error)
                EndIf
                $psidOwner = $arDllCall[4]
                $pSecDes = $arDllCall[8]
            EndIf
            DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR", $PSIDADMIN, "PTR", Null, "PTR", Null, "PTR", Null)
            $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", BitOR($dwSecurityInfo, $OWNER_SECURITY_INFORMATION), "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
            If $pSecDes Then $pSecDes = 0 + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecDes)
        EndIf
    EndIf
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_SetFileSecurity


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_SetFileSecurityEx
; Description ...: The _WinAPI_SetFileSecurityEx function sets specified security information in the Security Descriptor of a File or Directry.
;                   The caller identifies the object by a Handle.
; Syntax.........: _WinAPI_SetFileSecurityEx($hFile[, $sSecurityDescriptor])
; Parameters ....: $hFile               - A handle to a file for which to set security information.
;                  $sSecurityDescriptor - String containing the string-format security descriptor, see _WinAPI_GetFileSecurity()
; Return values .: Success      - If the function succeeds, the return ERROR_SUCCESS and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is non-zero. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If you are setting the discretionary access control list (DACL) or any elements in the system access control
;                    list (SACL) of an object, the system automatically propagates any inheritable access control entries (ACEs)
;                    to existing child objects, according to the ACE inheritance rules.
;                  The _WinAPI_SetFileSecurityEx function does not reorder access-allowed or access-denied ACEs based on the preferred order.
;                    When propagating inheritable ACEs to existing child objects, _WinAPI_SetFileSecurityEx puts inherited ACEs in order after
;                    all of the noninherited ACEs in the DACLs of the child objects.
;                  Note  If share access to the children of the object is not available, this function will not propagate unprotected ACEs
;                    to the children. For example, if a directory is opened with exclusive access, the operating system will not propagate
;                    unprotected ACEs to the subdirectories or files of that directory when the security on the directory is changed.
;                  Warning  If the supplied handle was opened with an ACCESS_MASK value of MAXIMUM_ALLOWED, then the _WinAPI_SetFileSecurityEx
;                    function will not propagate ACEs to children.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_SetFileSecurityEx($hFile, "O:BAD:PAI(A;CI;GA;;;SY)(A;CI;GA;;;BA)(A;CI;GR;;;BU)")
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_SetFileSecurityEx(Const ByRef $hFile, Const ByRef $sSecurityDescriptor)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl;, $iControl
    $pSecurityDescriptor = _WinAPI_LookupStringSecurityDescriptorParts($sSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    If @Error Then Return SetError(2, @Extended, 2)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hFile, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    If @Error Then Return SetError(1, -@Error + DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hFile) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
    If $arDllCall[0] = 5 Then
        ;; $dwDesiredAccess = $MAXIMUM_ALLOWED - 0x02000000 OR BitOr($READ_CONTROL, $WRITE_DAC, $WRITE_OWNER, $SYNCHRONIZE, $ACCESS_SYSTEM_SECURITY) - 0x011E0000
        ;; $dwFlags = $FILE_FLAG_BACKUP_SEMANTICS - 0x2000000
        $arDllCall = DllCall($hKernel32DLL, "HANDLE", "ReOpenFile", "HANDLE", $hFile, "DWORD", 0x02000000, "DWORD", 0, "DWORD", 0x2000000)
        If @Error Or $arDllCall[0] = $SE_INVALID_HANDLE_VALUE Then Return SetError(3, (@Error ? -@Error : _WinAPI_GetLastErrorEx() + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)), "")
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $arDllCall[0], "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $arDllCall[1])
    EndIf
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_SetFileSecurityEx

Func _WinAPI_LookupStringSecurityDescriptorParts(Const ByRef $sSecurityDescriptor, ByRef $dwSecurityInfo, ByRef $psidOwner, ByRef $psidGroup, ByRef $pDacl, ByRef $pSacl)
    Static $iControl, $pSecurityDescriptor
    $dwSecurityInfo = 0
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertStringSecurityDescriptorToSecurityDescriptorW", "WSTR", $sSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "PTR*", 0, "ULONG*", 0)
    If @Error Or Not $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : _WinAPI_GetLastErrorEx()), 0)
    $pSecurityDescriptor = $arDllCall[3]
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorControl", "PTR", $pSecurityDescriptor, "WORD*", 0, "DWORD*", 0)
    $iControl = @Error ? 0 : $arDllCall[2]
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorOwner", "PTR", $pSecurityDescriptor, "PTR*", 0, "BOOL*", 0)
    $psidOwner = @Error ? Null : $arDllCall[2]
    If $psidOwner Then $dwSecurityInfo += $OWNER_SECURITY_INFORMATION
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorGroup", "PTR", $pSecurityDescriptor, "PTR*", 0, "BOOL*", 0)
    $psidGroup = @Error ? Null : $arDllCall[2]
    If $psidGroup Then $dwSecurityInfo += $GROUP_SECURITY_INFORMATION
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorDacl", "PTR", $pSecurityDescriptor, "BOOL*", 0, "PTR*", 0, "BOOL*", 0)
    $pDacl = @Error ? Null : $arDllCall[3]
    If $pDacl Then $dwSecurityInfo += (BitAND($iControl, $SE_DACL_PROTECTED) ? $DACL_SECURITY_INFORMATION_PROTECTED : $DACL_SECURITY_INFORMATION_UNPROTECTED)
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorSacl", "PTR", $pSecurityDescriptor, "BOOL*", 0, "PTR*", 0, "BOOL*", 0)
    $pSacl = @Error ? Null : $arDllCall[3]
    If $pSacl Then $dwSecurityInfo += (BitAND($iControl, $SE_SACL_PROTECTED) ? $SACL_SECURITY_INFORMATION_PROTECTED : $SACL_SECURITY_INFORMATION_UNPROTECTED)
    If Not $dwSecurityInfo Then Return SetError(87, 87, 0)
    Return $pSecurityDescriptor
EndFunc

Func _WinAPI_GetFilePathByObjectName(Const ByRef $sObjectName, ByRef $sFilePath)
    Static $sDosDevice, $aObjectName, $aRoot
    If Not $sDosDevice Then
        $aRoot = DriveGetDrive('ALL')
        If @Error Then Return SetError(1, 0, "")
        For $i = 1 To $aRoot[0]
            $arDllCall = DllCall($hKernel32DLL, "DWORD", "QueryDosDeviceW", "WSTR", $aRoot[$i], "WSTR", "", "DWORD", 0x8000)
            If @Error Or Not $arDllCall[2] Then ContinueLoop
            $sDosDevice &= @LF & $arDllCall[2] & @CR & $aRoot[$i]
            ;$sDosDevice &= @LF & $aRoot[$i] & @CR & $arDllCall[2]
        Next
    EndIf
    $sFilePath = StringRegExpReplace($sObjectName, "(?i)^\h*\\+DosDevices\\+(?=[a-z]\:)", "")
    If @Extended Then Return $sFilePath
    $aObjectName = StringRegExp($sObjectName, "(?i)^\h*\\+Device\\+(\w+\d+)(.*)", 1)
    If @Error Then Return SetError(2, 0, "")
    $aRoot = StringRegExp($sDosDevice, "(?i)\n\\Device\\\Q" & $aObjectName[0] & "\E\r([^\r\n]+)", 1)
    If @Error Then Return SetError(3, 0, "")
    $sFilePath = $aRoot[0] & $aObjectName[1]
    Return $sFilePath
EndFunc   ;==>_WinAPI_GetFileRootByObjectName


#Endregion ;**** String Security Descriptor ****
MsgBox(0, 1,_WinAPI_GetFileSecurity(@DesktopDir & "\FileName.xxx"))
MsgBox(0, 1,_WinAPI_GetFileSecurity(@DesktopDir & "\ForlderName"))

Full SecurityEx.au3

#include-once
#RequireAdmin
;;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
Opt("MustDeclareVars",1)

;;Global $aOle32 = DllCall("ole32.dll", "long", "OleInitialize", "PTR", 0)
If Not IsDeclared("arDllCall") Then Global Static $arDllCall
Global Const $_WIN32_WINNT5 = StringRegExp(@OSVersion, "(?i)WIN_(?:XP|XPe|2000|2003)")
Global Const $_WIN32_WINNT =  $_WIN32_WINNT5 ? 5 : 6
;;Global Const $WINVER = StringRegExp(@OSVersion, "(?i)WIN_(?:XP|XPe|2000|2003)") ? 5 : 6

#Region ;**** Token Privileges ****
Global Const $hKernel32DLL = DllOpen("Kernel32.dll")
Global Const $hAdvapi32Dll = DllOpen("AdvApi32.dll")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                    ;;
;;               NT Defined Privileges                                ;;
;;                                                                    ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Global Const $SE_CREATE_TOKEN_NAME           = "SeCreateTokenPrivilege"
Global Const $SE_ASSIGNPRIMARYTOKEN_NAME     = "SeAssignPrimaryTokenPrivilege"
Global Const $SE_LOCK_MEMORY_NAME            = "SeLockMemoryPrivilege"
Global Const $SE_INCREASE_QUOTA_NAME         = "SeIncreaseQuotaPrivilege"
Global Const $SE_UNSOLICITED_INPUT_NAME      = "SeUnsolicitedInputPrivilege"
Global Const $SE_MACHINE_ACCOUNT_NAME        = "SeMachineAccountPrivilege"
Global Const $SE_TCB_NAME                    = "SeTcbPrivilege"
Global Const $SE_SECURITY_NAME               = "SeSecurityPrivilege"
Global Const $SE_TAKE_OWNERSHIP_NAME         = "SeTakeOwnershipPrivilege"
Global Const $SE_LOAD_DRIVER_NAME            = "SeLoadDriverPrivilege"
Global Const $SE_SYSTEM_PROFILE_NAME         = "SeSystemProfilePrivilege"
Global Const $SE_SYSTEMTIME_NAME             = "SeSystemtimePrivilege"
Global Const $SE_PROF_SINGLE_PROCESS_NAME    = "SeProfileSingleProcessPrivilege"
Global Const $SE_INC_BASE_PRIORITY_NAME      = "SeIncreaseBasePriorityPrivilege"
Global Const $SE_CREATE_PAGEFILE_NAME        = "SeCreatePagefilePrivilege"
Global Const $SE_CREATE_PERMANENT_NAME       = "SeCreatePermanentPrivilege"
Global Const $SE_BACKUP_NAME                 = "SeBackupPrivilege"
Global Const $SE_RESTORE_NAME                = "SeRestorePrivilege"
Global Const $SE_SHUTDOWN_NAME               = "SeShutdownPrivilege"
Global Const $SE_DEBUG_NAME                  = "SeDebugPrivilege"
Global Const $SE_AUDIT_NAME                  = "SeAuditPrivilege"
Global Const $SE_SYSTEM_ENVIRONMENT_NAME     = "SeSystemEnvironmentPrivilege"
Global Const $SE_CHANGE_NOTIFY_NAME          = "SeChangeNotifyPrivilege"
Global Const $SE_REMOTE_SHUTDOWN_NAME        = "SeRemoteShutdownPrivilege"
Global Const $SE_UNDOCK_NAME                 = "SeUndockPrivilege"
Global Const $SE_SYNC_AGENT_NAME             = "SeSyncAgentPrivilege"
Global Const $SE_ENABLE_DELEGATION_NAME      = "SeEnableDelegationPrivilege"
Global Const $SE_MANAGE_VOLUME_NAME          = "SeManageVolumePrivilege"
Global Const $SE_IMPERSONATE_NAME            = "SeImpersonatePrivilege"
Global Const $SE_CREATE_GLOBAL_NAME          = "SeCreateGlobalPrivilege"
Global Const $SE_TRUSTED_CREDMAN_ACCESS_NAME = "SeTrustedCredManAccessPrivilege"
Global Const $SE_RELABEL_NAME                = "SeRelabelPrivilege"
Global Const $SE_INC_WORKING_SET_NAME        = "SeIncreaseWorkingSetPrivilege"
Global Const $SE_TIME_ZONE_NAME              = "SeTimeZonePrivilege"
Global Const $SE_CREATE_SYMBOLIC_LINK_NAME   = "SeCreateSymbolicLinkPrivilege"
;Global Const $SE_ASSIGNPRIMARYTOKEN_NAME     = "SeAssignPrimaryTokenPrivilege"
;;    Required to assign the primary token of a process.
;;    User Right: Replace a process-level token.
;Global Const $SE_AUDIT_NAME                  = "SeAuditPrivilege"
;;    Required to generate audit-log entries. Give this privilege to secure servers.
;;    User Right: Generate security audits.
;Global Const $SE_BACKUP_NAME                 = "SeBackupPrivilege"
;;    Required to perform backup operations. This privilege causes the system to grant all read access control to any file, regardless
;;     of the access control list (ACL) specified for the file. Any access request other than read is still evaluated with  the ACL.
;;     This privilege is required by the RegSaveKey and RegSaveKeyExfunctions.
;;     The following access rights are granted if this privilege is held:
;;        READ_CONTROL
;;        ACCESS_SYSTEM_SECURITY
;;        FILE_GENERIC_READ
;;        FILE_TRAVERSE
;;    User Right: Back up files and directories.
;Global Const $SE_CHANGE_NOTIFY_NAME          = "SeChangeNotifyPrivilege"
;;    Required to receive notifications of changes to files or directories. This privilege also causes the system to skip all
;;     traversal access checks. It is enabled by default for all users.
;;    User Right: Bypass traverse checking.
;Global Const $SE_CREATE_GLOBAL_NAME          = "SeCreateGlobalPrivilege"
;;    Required to create named file mapping objects in the global namespace during Terminal Services sessions. This privilege
;;     is enabled by default for administrators, services, and the local system account.
;;    User Right: Create global objects.
;Global Const $SE_CREATE_PAGEFILE_NAME        = "SeCreatePagefilePrivilege"
;;    Required to create a paging file.
;;    User Right: Create a pagefile.
;Global Const $SE_CREATE_PERMANENT_NAME       = "SeCreatePermanentPrivilege"      ;;    Required to create a permanent object.
;;    User Right: Create permanent shared objects.
;Global Const $SE_CREATE_SYMBOLIC_LINK_NAME   = "SeCreateSymbolicLinkPrivilege"
;;    Required to create a symbolic link.
;;    User Right: Create symbolic links.
;Global Const $SE_CREATE_TOKEN_NAME           = "SeCreateTokenPrivilege"
;;    Required to create a primary token.
;;    User Right: Create a token object.
;;     You cannot add this privilege to a user account with the "Create a token object"  policy. Additionally, you cannot
;;     add this privilege to an owned process using Windows APIs.Windows Server 2003 and Windows XP with SP1 and earlier:
;;     Windows APIs can add this privilege to an owned process.
;Global Const $SE_DEBUG_NAME                  = "SeDebugPrivilege"
;;    Required to debug and adjust the memory of a process owned by another account.
;;    User Right: Debug programs.
;Global Const $SE_ENABLE_DELEGATION_NAME      = "SeEnableDelegationPrivilege"
;;    Required to mark user and computer accounts as trusted for delegation.
;;    User Right: Enable computer and user accounts to be trusted for delegation.
;Global Const $SE_IMPERSONATE_NAME            = "SeImpersonatePrivilege"
;;    Required to impersonate.
;;    User Right: Impersonate a client after authentication.
;Global Const $SE_INC_BASE_PRIORITY_NAME      = "SeIncreaseBasePriorityPrivilege"
;;    Required to increase the base priority of a process.
;;    User Right: Increase scheduling priority.
;Global Const $SE_INCREASE_QUOTA_NAME         = "SeIncreaseQuotaPrivilege"
;;    Required to increase the quota assigned to a process.
;;    User Right: Adjust memory quotas for a process.
;Global Const $SE_INC_WORKING_SET_NAME        = "SeIncreaseWorkingSetPrivilege"
;;    Required to allocate more memory for applications that run in the context of users.
;;    User Right: Increase a process working set.
;Global Const $SE_LOAD_DRIVER_NAME            = "SeLoadDriverPrivilege"
;;    Required to load or unload a device driver.
;;    User Right: Load and unload device drivers.
;Global Const $SE_LOCK_MEMORY_NAME            = "SeLockMemoryPrivilege"
;;    Required to lock physical pages in memory.
;;    User Right: Lock pages in memory.
;Global Const $SE_MACHINE_ACCOUNT_NAME        = "SeMachineAccountPrivilege"
;;    Required to create a computer account.
;;    User Right: Add workstations to domain.
;Global Const $SE_MANAGE_VOLUME_NAME          = "SeManageVolumePrivilege"
;;    Required to enable volume management privileges.
;;    User Right: Manage the files on a volume.
;Global Const $SE_PROF_SINGLE_PROCESS_NAME    = "SeProfileSingleProcessPrivilege"
;;    Required to gather profiling information for a single process.
;;    User Right: Profile single process.
;Global Const $SE_RELABEL_NAME                = "SeRelabelPrivilege"
;;    Required to modify the mandatory integrity level of an object.
;;    User Right: Modify an object label.
;Global Const $SE_REMOTE_SHUTDOWN_NAME        = "SeRemoteShutdownPrivilege"
;;    Required to shut down a system using a network request.
;;    User Right: Force shutdown from a remote system.
;Global Const $SE_RESTORE_NAME                = "SeRestorePrivilege"
;;    Required to perform restore operations. This privilege causes the system to grant all write access control to any file,
;;     regardless of the ACL specified for the file. Any access request other than write is still evaluated with the ACL. Additionally,
;;     this privilege enables you to set any valid user or group SID as the owner of a rights are granted if this privilege is held:
;;         WRITE_DAC
;;         WRITE_OWNER
;;         ACCESS_SYSTEM_SECURITY
;;         FILE_GENERIC_WRITE
;;         FILE_ADD_FILE
;;         FILE_ADD_SUBDIRECTORY
;;         DELETE
;;    User Right: Restore files and directories.
;Global Const $SE_SECURITY_NAME               = "SeSecurityPrivilege"
;;    Required to perform a number of security-related functions, such as controlling and
;;     viewing audit messages. This privilege identifies its holder as a security operator.
;;    User Right: Manage auditing and security log.
;Global Const $SE_SHUTDOWN_NAME               = "SeShutdownPrivilege"
;;    Required to shut down a local system.
;;    User Right: Shut down the system.
;Global Const $SE_SYNC_AGENT_NAME             = "SeSyncAgentPrivilege"
;;    Required for a domain controller to use the Lightweight Directory Access Protocol directory synchronization services.
;;     This privilege enables the holder to read all objects and properties in the directory, regardless of the protection on
;;     and properties. By default, it is assigned to the Administrator and LocalSystem
;;     the objects accounts on domain controllers.
;;    User Right: Synchronize directory service data.
;Global Const $SE_SYSTEM_ENVIRONMENT_NAME     = "SeSystemEnvironmentPrivilege"
;;    Required to modify the nonvolatile RAM of systems that use this type of memory to store configuration information.
;;    User Right: Modify firmware environment values.
;Global Const $SE_SYSTEM_PROFILE_NAME         = "SeSystemProfilePrivilege"
;;    Required to gather profiling information for the entire system.
;;    User Right: Profile system performance.
;Global Const $SE_SYSTEMTIME_NAME             = "SeSystemtimePrivilege"
;;    Required to modify the system time.
;;    User Right: Change the system time.
;Global Const $SE_TAKE_OWNERSHIP_NAME         = "SeTakeOwnershipPrivilege"
;;    Required to take ownership of an object without being granted discretionary access. This privilege allows the owner
;;     value to be set only to those values that the holder may legitimately assign as the owner of an object.
;;    User Right: Take ownership of files or other objects.
;Global Const $SE_TCB_NAME                    = "SeTcbPrivilege"
;;    This privilege identifies its holder as part of the trusted computer base. Some trusted protected subsystems are granted this privilege.
;;    User Right: Act as part of the operating system.
;Global Const $SE_TIME_ZONE_NAME              = "SeTimeZonePrivilege"
;;    Required to adjust the time zone associated with the computer's internal clock.
;;    User Right: Change the time zone.
;Global Const $SE_TRUSTED_CREDMAN_ACCESS_NAME = "SeTrustedCredManAccessPrivilege"
;;    Required to access Credential Manager as a trusted caller.
;;    User Right: Access Credential Manager as a trusted caller.
;Global Const $SE_UNDOCK_NAME                 = "SeUndockPrivilege"
;;    Required to undock a laptop.
;;    User Right: Remove computer from docking station.
;Global Const $SE_UNSOLICITED_INPUT_NAME      = "SeUnsolicitedInputPrivilege"
;;    Required to read unsolicited input from a terminal device.
;;    User Right: Not applicable.
;
;;;;Global Static $aTokenPrivilegesNewState[35][2] = [[$SE_CREATE_TOKEN_NAME,2], [$SE_ASSIGNPRIMARYTOKEN_NAME,2], [$SE_LOCK_MEMORY_NAME,2], [$SE_INCREASE_QUOTA_NAME,2], [$SE_UNSOLICITED_INPUT_NAME,2], [$SE_MACHINE_ACCOUNT_NAME,2], [$SE_TCB_NAME,2], [$SE_SECURITY_NAME,2], [$SE_TAKE_OWNERSHIP_NAME,2], [$SE_LOAD_DRIVER_NAME,2], [$SE_SYSTEM_PROFILE_NAME,2], [$SE_SYSTEMTIME_NAME,2], [$SE_PROF_SINGLE_PROCESS_NAME,2], [$SE_INC_BASE_PRIORITY_NAME,2], [$SE_CREATE_PAGEFILE_NAME,2], [$SE_CREATE_PERMANENT_NAME,2], [$SE_BACKUP_NAME,2], [$SE_RESTORE_NAME,2], [$SE_SHUTDOWN_NAME,2], [$SE_DEBUG_NAME,2], [$SE_AUDIT_NAME,2], [$SE_SYSTEM_ENVIRONMENT_NAME,2], [$SE_CHANGE_NOTIFY_NAME,2], [$SE_REMOTE_SHUTDOWN_NAME,2], [$SE_UNDOCK_NAME,2], [$SE_SYNC_AGENT_NAME,2], [$SE_ENABLE_DELEGATION_NAME,2], [$SE_MANAGE_VOLUME_NAME,2], [$SE_IMPERSONATE_NAME,2], [$SE_CREATE_GLOBAL_NAME,2], [$SE_TRUSTED_CREDMAN_ACCESS_NAME,2], [$SE_RELABEL_NAME,2], [$SE_INC_WORKING_SET_NAME,2], [$SE_TIME_ZONE_NAME,2], [$SE_CREATE_SYMBOLIC_LINK_NAME,2]]
Global Static $aTokenPrivilegesNewState[6][2] = [[$SE_RESTORE_NAME,2],[$SE_BACKUP_NAME,2],[$SE_SECURITY_NAME,2],[$SE_TAKE_OWNERSHIP_NAME,2],[$SE_DEBUG_NAME,2],[$SE_CREATE_SYMBOLIC_LINK_NAME,2]]
Global Static $iTokenPrivilegesState
Global Static $aTokenPrivilegesPreviousState = _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)

;;;;Global Const $OWNER_SECURITY_INFORMATION       = 0x00000001
;;;;Global Const $SE_REGISTRY_WOW64_32KEY          = 12 ;Indicates an object for a registry entry under WOW64.
Global Const $PSIDADMIN = _WinAPI_GetWellKnownSidEx("BA")
Global Const $PSIDUSER  = _WinAPI_GetWellKnownSidEx(@UserName)
Global Const $SZSIDUSER = _WinAPI_GetWellKnownSidEx(@UserName, 2)

;;;;Local $asSDDL = StringSplit("DA|DG|DU|ED|DD|DC|BA|BG|BU|LA|LG|AO|BO|PO|SO|AU|PS|CO|CG|SY|PU|WD|RE|IU|NU|SU|RC|WR|AN|SA|CA|RS|EA|PA|RU|LS|NS|RD|NO|MU|LU|IS|CY|OW|ER|RO|CD|AC|RA|ES|MS|UD|HA|CN|AA|RM|AS|SS|AP|LW|ME|MP|HI|SI", "|")
;;;;Local $aWKS = StringSplit("$WinNullSid|$WinWorldSid|$WinLocalSid|$WinCreatorOwnerSid|$WinCreatorGroupSid|$WinCreatorOwnerServerSid|$WinCreatorGroupServerSid|$WinNtAuthoritySid|$WinDialupSid|$WinNetworkSid|$WinBatchSid|$WinInteractiveSid|$WinServiceSid|$WinAnonymousSid|$WinProxySid|$WinEnterpriseControllersSid|$WinSelfSid|$WinAuthenticatedUserSid|$WinRestrictedCodeSid|$WinTerminalServerSid|$WinRemoteLogonIdSid|$WinLogonIdsSid|$WinLocalSystemSid|$WinLocalServiceSid|$WinNetworkServiceSid|$WinBuiltinDomainSid|$WinBuiltinAdministratorsSid|$WinBuiltinUsersSid|$WinBuiltinGuestsSid|$WinBuiltinPowerUsersSid|$WinBuiltinAccountOperatorsSid|$WinBuiltinSystemOperatorsSid|$WinBuiltinPrintOperatorsSid|$WinBuiltinBackupOperatorsSid|$WinBuiltinReplicatorSid|$WinBuiltinPreWindows2000CompatibleAccessSid|$WinBuiltinRemoteDesktopUsersSid|$WinBuiltinNetworkConfigurationOperatorsSid|$WinAccountAdministratorSid|$WinAccountGuestSid|$WinAccountKrbtgtSid|$WinAccountDomainAdminsSid|$WinAccountDomainUsersSid|$WinAccountDomainGuestsSid|$WinAccountComputersSid|$WinAccountControllersSid|$WinAccountCertAdminsSid|$WinAccountSchemaAdminsSid|$WinAccountEnterpriseAdminsSid|$WinAccountPolicyAdminsSid|$WinAccountRasAndIasServersSid|$WinNTLMAuthenticationSid|$WinDigestAuthenticationSid|$WinSChannelAuthenticationSid|$WinThisOrganizationSid|$WinOtherOrganizationSid|$WinBuiltinIncomingForestTrustBuildersSid|$WinBuiltinPerfMonitoringUsersSid|$WinBuiltinPerfLoggingUsersSid|$WinBuiltinAuthorizationAccessSid|$WinBuiltinTerminalServerLicenseServersSid|$WinBuiltinDCOMUsersSid|$WinBuiltinIUsersSid|$WinIUserSid|$WinBuiltinCryptoOperatorsSid|$WinUntrustedLabelSid|$WinLowLabelSid|$WinMediumLabelSid|$WinHighLabelSid|$WinSystemLabelSid|$WinWriteRestrictedCodeSid|$WinCreatorOwnerRightsSid|$WinCacheablePrincipalsGroupSid|$WinNonCacheablePrincipalsGroupSid|$WinEnterpriseReadonlyControllersSid|$WinAccountReadonlyControllersSid|$WinBuiltinEventLogReadersGroup|$WinNewEnterpriseReadonlyControllersSid|$WinBuiltinCertSvcDComAccessGroup|$WinMediumPlusLabelSid|$WinLocalLogonSid|$WinConsoleLogonSid|$WinThisOrganizationCertificateSid|$WinApplicationPackageAuthoritySid|$WinBuiltinAnyPackageSid|$WinCapabilityInternetClientSid|$WinCapabilityInternetClientServerSid|$WinCapabilityPrivateNetworkClientServerSid|$WinCapabilityPicturesLibrarySid|$WinCapabilityVideosLibrarySid|$WinCapabilityMusicLibrarySid|$WinCapabilityDocumentsLibrarySid|$WinCapabilitySharedUserCertificatesSid|$WinCapabilityEnterpriseAuthenticationSid|$WinCapabilityRemovableStorageSid|$WinBuiltinRDSRemoteAccessServersSid|$WinBuiltinRDSEndpointServersSid|$WinBuiltinRDSManagementServersSid|$WinUserModeDriversSid|$WinBuiltinHyperVAdminsSid|$WinAccountCloneableControllersSid|$WinBuiltinAccessControlAssistanceOperatorsSid|$WinBuiltinRemoteManagementUsersSid|$WinAuthenticationAuthorityAssertedSid|$WinAuthenticationServiceAssertedSid|$WinLocalAccountSid|$WinLocalAccountAndAdministratorSid|$WinAccountProtectedUsersSid", "|", 2)

;;
;; Well known SID definitions for lookup.
;;
Global Enum _ ;; $WELL_KNOWN_SID_TYPE
    $WinNullSid                                    = 0, _    ;; Indicates a null SID.
    $WinWorldSid                                   = 1, _    ;; "WD" - $SDDL_EVERYONE - Indicates a SID that matches everyone.
    $WinLocalSid                                   = 2, _    ;; Indicates a local SID.
    $WinCreatorOwnerSid                            = 3, _    ;; "CO" - $SDDL_CREATOR_OWNER - Indicates a SID that matches the owner or creator of an object.
    $WinCreatorGroupSid                            = 4, _    ;; "CG" - $SDDL_CREATOR_GROUP - Indicates a SID that matches the creator group of an object.
    $WinCreatorOwnerServerSid                      = 5, _    ;; Indicates a creator owner server SID.
    $WinCreatorGroupServerSid                      = 6, _    ;; Indicates a creator group server SID.
    $WinNtAuthoritySid                             = 7, _    ;; Indicates a SID for the Windows NT authority account.
    $WinDialupSid                                  = 8, _    ;; Indicates a SID for a dial-up account.
    $WinNetworkSid                                 = 9, _    ;; "NU" - $SDDL_NETWORK - Indicates a SID for a network account. This SID is added to the process of a token when it logs on across a network. The corresponding logon type is LOGON32_LOGON_NETWORK.
    $WinBatchSid                                   = 10, _   ;; Indicates a SID for a batch process. This SID is added to the process of a token when it logs on as a batch job. The corresponding logon type is LOGON32_LOGON_BATCH.
    $WinInteractiveSid                             = 11, _   ;; "IU" - $SDDL_INTERACTIVE - Indicates a SID for an interactive account. This SID is added to the process of a token when it logs on interactively. The corresponding logon type is LOGON32_LOGON_INTERACTIVE.
    $WinServiceSid                                 = 12, _   ;; "SU" - $SDDL_SERVICE - Indicates a SID for a service. This SID is added to the process of a token when it logs on as a service. The corresponding logon type is LOGON32_LOGON_SERVICE.
    $WinAnonymousSid                               = 13, _   ;; "AN" - $SDDL_ANONYMOUS - Indicates a SID for the anonymous account.
    $WinProxySid                                   = 14, _   ;; Indicates a proxy SID.
    $WinEnterpriseControllersSid                   = 15, _   ;; "ED" - $SDDL_ENTERPRISE_DOMAIN_CONTROLLERS - Indicates a SID for an enterprise controller.
    $WinSelfSid                                    = 16, _   ;; "PS" - $SDDL_PERSONAL_SELF - Indicates a SID for self.
    $WinAuthenticatedUserSid                       = 17, _   ;; "AU" - $SDDL_AUTHENTICATED_USERS - Indicates a SID that matches any authenticated user.
    $WinRestrictedCodeSid                          = 18, _   ;; "RC" - $SDDL_RESTRICTED_CODE - Indicates a SID for restricted code.
    $WinTerminalServerSid                          = 19, _   ;; Indicates a SID that matches a terminal server account.
    $WinRemoteLogonIdSid                           = 20, _   ;; Indicates a SID that matches remote logons.
    $WinLogonIdsSid                                = 21, _   ;; Indicates a SID that matches logon IDs.
    $WinLocalSystemSid                             = 22, _   ;; "SY" - $SDDL_LOCAL_SYSTEM - Indicates a SID that matches the local system.
    $WinLocalServiceSid                            = 23, _   ;; "LS" - $SDDL_LOCAL_SERVICE - Indicates a SID that matches a local service.
    $WinNetworkServiceSid                          = 24, _   ;; "NS" - $SDDL_NETWORK_SERVICE - Indicates a SID that matches a network service.
    $WinBuiltinDomainSid                           = 25, _   ;; Indicates a SID that matches the domain account.
    $WinBuiltinAdministratorsSid                   = 26, _   ;; "BA" - $SDDL_BUILTIN_ADMINISTRATORS - Indicates a SID that matches the administrator group.
    $WinBuiltinUsersSid                            = 27, _   ;; "BU" - $SDDL_BUILTIN_USERS - Indicates a SID that matches built-in user accounts.
    $WinBuiltinGuestsSid                           = 28, _   ;; "BG" - $SDDL_BUILTIN_GUESTS - Indicates a SID that matches the guest account.
    $WinBuiltinPowerUsersSid                       = 29, _   ;; "PU" - $SDDL_POWER_USERS - Indicates a SID that matches the power users group.
    $WinBuiltinAccountOperatorsSid                 = 30, _   ;; "AO" - $SDDL_ACCOUNT_OPERATORS - Indicates a SID that matches the account operators account.
    $WinBuiltinSystemOperatorsSid                  = 31, _   ;; "SO" - $SDDL_SERVER_OPERATORS - Indicates a SID that matches the system operators group.
    $WinBuiltinPrintOperatorsSid                   = 32, _   ;; "PO" - $SDDL_PRINTER_OPERATORS - Indicates a SID that matches the print operators group.
    $WinBuiltinBackupOperatorsSid                  = 33, _   ;; "BO" - $SDDL_BACKUP_OPERATORS - Indicates a SID that matches the backup operators group.
    $WinBuiltinReplicatorSid                       = 34, _   ;; "RE" - $SDDL_REPLICATOR - Indicates a SID that matches the replicator account.
    $WinBuiltinPreWindows2000CompatibleAccessSid   = 35, _   ;; "RU" - $SDDL_ALIAS_PREW2KCOMPACC - Indicates a SID that matches pre-Windows 2000 compatible accounts.
    $WinBuiltinRemoteDesktopUsersSid               = 36, _   ;; "RD" - $SDDL_REMOTE_DESKTOP - Indicates a SID that matches remote desktop users.
    $WinBuiltinNetworkConfigurationOperatorsSid    = 37, _   ;; "NO" - $SDDL_NETWORK_CONFIGURATION_OPS - Indicates a SID that matches the network operators group.
    $WinAccountAdministratorSid                    = 38, _   ;; Indicates a SID that matches the account administrator's account.
    $WinAccountGuestSid                            = 39, _   ;; Indicates a SID that matches the account guest group.
    $WinAccountKrbtgtSid                           = 40, _   ;; Indicates a SID that matches account Kerberos target group.
    $WinAccountDomainAdminsSid                     = 41, _   ;; Indicates a SID that matches the account domain administrator group.
    $WinAccountDomainUsersSid                      = 42, _   ;; Indicates a SID that matches the account domain users group.
    $WinAccountDomainGuestsSid                     = 43, _   ;; Indicates a SID that matches the account domain guests group.
    $WinAccountComputersSid                        = 44, _   ;; Indicates a SID that matches the account computer group.
    $WinAccountControllersSid                      = 45, _   ;; Indicates a SID that matches the account controller group.
    $WinAccountCertAdminsSid                       = 46, _   ;; Indicates a SID that matches the certificate administrators group.
    $WinAccountSchemaAdminsSid                     = 47, _   ;; Indicates a SID that matches the schema administrators group.
    $WinAccountEnterpriseAdminsSid                 = 48, _   ;; Indicates a SID that matches the enterprise administrators group.
    $WinAccountPolicyAdminsSid                     = 49, _   ;; Indicates a SID that matches the policy administrators group.
    $WinAccountRasAndIasServersSid                 = 50, _   ;; Indicates a SID that matches the RAS and IAS server account.
    $WinNTLMAuthenticationSid                      = 51, _   ;; Indicates a SID present when the Microsoft NTLM authentication package authenticated the client.
    $WinDigestAuthenticationSid                    = 52, _   ;; Indicates a SID present when the Microsoft Digest authentication package authenticated the client.
    $WinSChannelAuthenticationSid                  = 53, _   ;; Indicates a SID present when the Secure Channel (SSL/TLS) authentication package authenticated the client.
    $WinThisOrganizationSid                        = 54, _   ;; Indicates a SID present when the user authenticated from within the forest or across a trust that does not have the selective authentication option enabled. If this SID is present, then WinOtherOrganizationSid cannot be present.
    $WinOtherOrganizationSid                       = 55, _   ;; Indicates a SID present when the user authenticated across a forest with the selective authentication option enabled. If this SID is present, then WinThisOrganizationSid cannot be present.
    $WinBuiltinIncomingForestTrustBuildersSid      = 56, _   ;; Indicates a SID that allows a user to create incoming forest trusts. It is added to the token of users who are a member of the Incoming Forest Trust Builders built-in group in the root domain of the forest.
    $WinBuiltinPerfMonitoringUsersSid              = 57, _   ;; "MU" - $SDDL_PERFMON_USERS - Indicates a SID that matches the performance monitor user group.
    $WinBuiltinPerfLoggingUsersSid                 = 58, _   ;; "LU" - $SDDL_PERFLOG_USERS - Indicates a SID that matches the performance log user group.
    $WinBuiltinAuthorizationAccessSid              = 59, _   ;; Indicates a SID that matches the Windows Authorization Access group.
    $WinBuiltinTerminalServerLicenseServersSid     = 60, _   ;; Indicates a SID is present in a server that can issue terminal server licenses.
    $WinBuiltinDCOMUsersSid                        = 61, _   ;; Indicates a SID that matches the distributed COM user group.
    $WinBuiltinIUsersSid                           = 62, _   ;; "IS" - $SDDL_IIS_USERS - Indicates a SID that matches the Internet built-in user group.
    $WinIUserSid                                   = 63, _   ;; Indicates a SID that matches the Internet user group.
    $WinBuiltinCryptoOperatorsSid                  = 64, _   ;; "CY" - $SDDL_CRYPTO_OPERATORS - Indicates a SID that allows a user to use cryptographic operations. It is added to the token of users who are a member of the CryptoOperators built-in group.
    $WinUntrustedLabelSid                          = 65, _   ;; Indicates a SID that matches an untrusted label.
    $WinLowLabelSid                                = 66, _   ;; "LW" - $SDDL_ML_LOW - Indicates a SID that matches an low level of trust label.
    $WinMediumLabelSid                             = 67, _   ;; "ME" - $SDDL_ML_MEDIUM - Indicates a SID that matches an medium level of trust label.
    $WinHighLabelSid                               = 68, _   ;; "HI" - $SDDL_ML_HIGH - Indicates a SID that matches a high level of trust label.
    $WinSystemLabelSid                             = 69, _   ;; "SI" - $SDDL_ML_SYSTEM - Indicates a SID that matches a system label.
    $WinWriteRestrictedCodeSid                     = 70, _   ;; "WR" - $SDDL_WRITE_RESTRICTED_CODE - Indicates a SID that matches a write restricted code group.
    $WinCreatorOwnerRightsSid                      = 71, _   ;; "OW" - $SDDL_OWNER_RIGHTS - Indicates a SID that matches a creator and owner rights group.
    $WinCacheablePrincipalsGroupSid                = 72, _   ;; Indicates a SID that matches a cacheable principals group.
    $WinNonCacheablePrincipalsGroupSid             = 73, _   ;; Indicates a SID that matches a non-cacheable principals group.
    $WinEnterpriseReadonlyControllersSid           = 74, _   ;; Indicates a SID that matches an enterprise wide read-only controllers group.
    $WinAccountReadonlyControllersSid              = 75, _   ;; Indicates a SID that matches an account read-only controllers group.
    $WinBuiltinEventLogReadersGroup                = 76, _   ;; "ER" - $SDDL_EVENT_LOG_READERS - Indicates a SID that matches an event log readers group.
    $WinNewEnterpriseReadonlyControllersSid        = 77, _   ;; Indicates a SID that matches a read-only enterprise domain controller.
    $WinBuiltinCertSvcDComAccessGroup              = 78      ;; "CD" - $SDDL_CERTSVC_DCOM_ACCESS - Indicates a SID that matches the built-in DCOM certification services access group.
Global Enum _ ;; $WELL_KNOWN_SID_TYPE - Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP:  This value is not available.
    $WinMediumPlusLabelSid                         = 79, _   ;; "MP" - $SDDL_ML_MEDIUM_PLUS - Indicates a SID that matches the medium plus integrity label.
    $WinLocalLogonSid                              = 80, _   ;; Indicates a SID that matches a local logon group.
    $WinConsoleLogonSid                            = 81, _   ;; Indicates a SID that matches a console logon group.
    $WinThisOrganizationCertificateSid             = 82, _   ;; Indicates a SID that matches a certificate for the given organization.
    $WinApplicationPackageAuthoritySid             = 83, _   ;; Indicates a SID that matches the application package authority.
    $WinBuiltinAnyPackageSid                       = 84, _   ;; "AC" - $SDDL_ALL_APP_PACKAGES - Indicates a SID that applies to all app containers.
    $WinCapabilityInternetClientSid                = 85, _   ;; Indicates a SID of Internet client capability for app containers.
    $WinCapabilityInternetClientServerSid          = 86, _   ;; Indicates a SID of Internet client and server capability for app containers.
    $WinCapabilityPrivateNetworkClientServerSid    = 87, _   ;; Indicates a SID of private network client and server capability for app containers.
    $WinCapabilityPicturesLibrarySid               = 88, _   ;; Indicates a SID for pictures library capability for app containers.
    $WinCapabilityVideosLibrarySid                 = 89, _   ;; Indicates a SID for videos library capability for app containers.
    $WinCapabilityMusicLibrarySid                  = 90, _   ;; Indicates a SID for music library capability for app containers.
    $WinCapabilityDocumentsLibrarySid              = 91, _   ;; Indicates a SID for documents library capability for app containers.
    $WinCapabilitySharedUserCertificatesSid        = 92, _   ;; Indicates a SID for shared user certificates capability for app containers.
    $WinCapabilityEnterpriseAuthenticationSid      = 93, _   ;; Indicates a SID for Windows credentials capability for app containers.
    $WinCapabilityRemovableStorageSid              = 94, _   ;; Indicates a SID for removable storage capability for app containers.
    $WinBuiltinRDSRemoteAccessServersSid           = 95, _   ;; "RA" - $SDDL_RDS_REMOTE_ACCESS_SERVERS
    $WinBuiltinRDSEndpointServersSid               = 96, _   ;; "ES" - $SDDL_RDS_ENDPOINT_SERVERS
    $WinBuiltinRDSManagementServersSid             = 97, _   ;; "MS" - $SDDL_RDS_MANAGEMENT_SERVERS
    $WinUserModeDriversSid                         = 98, _   ;; "UD" - $SDDL_USER_MODE_DRIVERS
    $WinBuiltinHyperVAdminsSid                     = 99, _   ;; "HA" - $SDDL_HYPER_V_ADMINS
    $WinAccountCloneableControllersSid             = 100, _  ;;
    $WinBuiltinAccessControlAssistanceOperatorsSid = 101, _  ;; "AA" - $SDDL_ACCESS_CONTROL_ASSISTANCE_OPS
    $WinBuiltinRemoteManagementUsersSid            = 102, _  ;; "RM" - $SDDL_REMOTE_MANAGEMENT_USERS
    $WinAuthenticationAuthorityAssertedSid         = 103, _  ;; "AS" - $SDDL_AUTHORITY_ASSERTED
    $WinAuthenticationServiceAssertedSid           = 104, _  ;; "SS" - $SDDL_SERVICE_ASSERTED
    $WinLocalAccountSid                            = 105, _  ;;
    $WinLocalAccountAndAdministratorSid            = 106, _  ;;
    $WinAccountProtectedUsersSid                   = 107     ;;
Global Const $WELL_KNOWN_SID_TYPE                  = "INT"

; #FUNCTION# ====================================================================================================================================
; Name...........: _WinAPI_SetPrivilegeEx
; Description ...: Enables or disables special privileges as required by some DllCalls
; Syntax.........: _WinAPI_SetPrivilegeEx($avPrivilege)
; Parameters ....: $avPrivilege - An array of privileges and respective attributes
;                                 $SE_PRIVILEGE_ENABLED - The function enables the privilege
;                                 $SE_PRIVILEGE_REMOVED - The privilege is removed from the list of privileges in the token
;                                 0 - The function disables the privilege
; Requirement(s).: None
; Return values .: Success - An array of modified privileges and their respective previous attribute state
;                  Failure - An empty array
;                            Sets @Error
; Author ........: engine
; Modified.......: FredAI, DXRW4E
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......;
; ===============================================================================================================================================
Func _WinAPI_SetPrivilegeEx($avPrivilege)
    $iTokenPrivilegesState = $iTokenPrivilegesState ? 0 : 1
    If Not UBound($avPrivilege) Then Return SetError(1, 0, 0)
    Local $tagTP = "DWORD", $iTokens = UBound($avPrivilege), $iError = 0, $iCount
    For $i = 1 To $iTokens
        $tagTP &= ";DWORD;LONG;DWORD"
    Next
    Local $tCurrState = DLLStructCreate($tagTP), $tPrevState = DllStructCreate($tagTP), $tLUID = DllStructCreate("DWORD;LONG")
    DLLStructSetData($tCurrState, 1, $iTokens)
    For $i = 0 To $iTokens - 1
        DllCall($hAdvapi32Dll, "BOOL", "LookupPrivilegeValueW", "WSTR", Null, "WSTR", $avPrivilege[$i][0], "STRUCT*", $tLUID)
        DLLStructSetData($tCurrState, 3 * $i + 2, DllStructGetData($tLUID, 1))
        DLLStructSetData($tCurrState, 3 * $i + 3, DllStructGetData($tLUID, 2))
        DLLStructSetData($tCurrState, 3 * $i + 4, $avPrivilege[$i][1])
    Next
    Local $hToken = DllCall($hAdvapi32Dll, "BOOL", "OpenProcessToken", "HANDLE", DllCall($hKernel32DLL, "HANDLE", "GetCurrentProcess")[0], "DWORD", 40, "HANDLE*", 0)[3] ;; TOKEN_ADJUST_PRIVILEGES + TOKEN_QUERY = 40
    DllCall($hAdvapi32Dll, "BOOL", "AdjustTokenPrivileges", "HANDLE", $hToken, "BOOL", False, "STRUCT*", $tCurrState, "DWORD", DllStructGetSize($tCurrState), "STRUCT*", $tPrevState, "DWORD*", 0)
    $iError = DllCall($hKernel32DLL, "DWORD", "GetLastError")[0]
    DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hToken)
    $iCount = DllStructGetData($tPrevState, 1)
    If $iCount < 1 Then Return SetError($iError, 0, 0)
    Local $pLUID, $tName, $avPrevState[$iCount][2], $pPrevState = DllStructGetPtr($tPrevState)
    For $i = 0 To $iCount - 1
        $pLUID = $pPrevState + 12 * $i + 4
        $tName = DllStructCreate("WCHAR[" & DllCall($hAdvapi32Dll, "BOOL", "LookupPrivilegeNameW", "WSTR", Null, "PTR", $pLUID, "PTR", 0, "DWORD*", 0)[4] & "]")
        DllCall($hAdvapi32Dll, "BOOL", "LookupPrivilegeNameW", "WSTR", Null, "PTR", $pLUID, "STRUCT*", $tName, "DWORD*", DllStructGetSize($tName))
        $avPrevState[$i][0] = DllStructGetData($tName, 1)
        $avPrevState[$i][1] = DllStructGetData($tPrevState, 3 * $i + 4)
    Next
    Return SetError($iError, 1, $avPrevState)
EndFunc ;==> _WinAPI_SetPrivilegeEx

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_GetWellKnownSidEx
; Description ...: Get\Create SID
; Syntax.........: _WinAPI_GetWellKnownSidEx($sWellKnownSid)
; Parameters ....: $sWellKnownSid - A member of the WELL_KNOWN_SID_TYPE enumeration that specifies what the SID will identify
;                                   Or a string containing the string-format SID. The SID string can use either the standard
;                                     S-R-I-S-S… format for SID strings, or the SID string constant format, such as "BA" for built-in
;                                     administrators. For more information about SID string notation, see SDDL User aliases ($SDDL_*) and
;                                     SID Components http://msdn.microsoft.com/en-us/library/windows/desktop/aa379597%28v=vs.85%29.aspx
;                                   Or set NULL thi parameter to clean everything, to delete all SID Structure\pointer in $aWellKnownSid
;                  $iFlags - Optional
;                  |0 - (Default) Return pointer of the SID Structure
;                  |1 - Return SID Structure (the SID in a byte structure)
;                  |2 - Return the standard S-R-I-S-S… format for SID strings
;                  |3 - Return SID SDDL User aliases (example BA or BU etc etc)
;                  |4 - Return SID WELL_KNOWN_SID_TYPE (0 to 107)
;                  |8 - Return Array2D ($aWellKnownSid) of SID
; Return values .: Success - A pointer to a SID structure that identifies the object Or see $iFlags option
; Author ........: DXRW4E
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _WinAPI_GetWellKnownSidEx($sWellKnownSid, $iFlags = 0)
    Local Static $aWellKnownSid[5][5] = [[0,4,@LF, @CR & "0" & @LF]]
    If BitAND($iFlags, 8) Then Return $aWellKnownSid
    If $sWellKnownSid == Null Then
        Local $_aWellKnownSid[5][5] = [[0,4,@LF, @CR & "0" & @LF]]
        $aWellKnownSid = $_aWellKnownSid
        Return
    EndIf
    Local $iType = BitAND($iFlags, ($iFlags > 4 ? 3 : 7)), $iSid = Int(StringRegExp($aWellKnownSid[0][2] & $sWellKnownSid & $aWellKnownSid[0][3], "(?i)\n\K\Q" & $sWellKnownSid & "\E\r(\d+)\n", 1)[0])
    If $iSid Then Return SetError(0, $aWellKnownSid[$iSid][0], $aWellKnownSid[$iSid][$iType])
    If $aWellKnownSid[0][0] = $aWellKnownSid[0][1] Then
        $aWellKnownSid[0][1] *= 2
        ReDim $aWellKnownSid[$aWellKnownSid[0][1] + 1][5]
    EndIf
    $iSid = $aWellKnownSid[0][0] + 1
    If String($sWellKnownSid) = @UserName Then
        $sWellKnownSid = DllStructCreate("Byte SID[256]")
        $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "LookupAccountNameW", "WSTR", Null, "WSTR", @UserName, "STRUCT*", $sWellKnownSid, "DWORD*", DllStructGetSize($sWellKnownSid), "WSTR", "", "DWORD*", DllStructGetSize($sWellKnownSid), "INT*", 0)
        If @Error Or Not $arDllCall[0] Then Return SetError((@Error ? @Error : _WinAPI_GetLastErrorEx()), 1, 0)
        $arDllCall = DllCall($hAdvapi32Dll, "INT", "ConvertSidToStringSidW", "STRUCT*", $sWellKnownSid, "PTR*", 0)
        If @Error Or Not $arDllCall[0] Then Return SetError((@Error ? @Error : _WinAPI_GetLastErrorEx()), 2, 0)
        $sWellKnownSid = DllStructGetData(DllStructCreate("WCHAR[256]", $arDllCall[2]), 1)
        DllCall($hKernel32DLL, "PTR", "LocalFree", "PTR", $arDllCall[2])
        $aWellKnownSid[0][2] &= @UserName & @CR & $iSid & @LF
    EndIf
    If StringIsDigit($sWellKnownSid) Then
        $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "CreateWellKnownSid", "INT", Int($sWellKnownSid), "PTR", Null, "PTR", Null, "DWORD*", 0)
        If @Error Or Not $arDllCall[4] Then Return SetError((@Error ? @Error : _WinAPI_GetLastErrorEx()), 3, 0)
        $aWellKnownSid[$iSid][1] = DllStructCreate("Byte SID[" & $arDllCall[4] & "]")
        $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "CreateWellKnownSid", "INT", $arDllCall[1], "PTR", Null, "STRUCT*", $aWellKnownSid[$iSid][1], "DWORD*", $arDllCall[4])
        If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), 4, 0)
        $aWellKnownSid[$iSid][4] = $arDllCall[1]
    Else
        $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertStringSidToSidW", "WSTR", $sWellKnownSid, "PTR*", 0)
        If @Error Or Not $arDllCall[0] Then
            If $sWellKnownSid <> "BA" Then Return SetError((@Error ? @Error : _WinAPI_GetLastErrorEx()), 5, 0)
            $aWellKnownSid[$iSid][1] = DllStructCreate("Byte Data[16]")
            DllStructSetData($aWellKnownSid[$iSid][1], "Data", "0x01020000000000052000000020020000")
        Else
            $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetLengthSid", "PTR", $arDllCall[2])
            $aWellKnownSid[$iSid][1] = DllStructCreate("Byte Data[" & $arDllCall[0] & "]")
            DllStructSetData($aWellKnownSid[$iSid][1], "Data", DllStructGetData(DllStructCreate("Byte Data[" & $arDllCall[0] & "]", $arDllCall[1]), "Data"))
            DllCall($hKernel32DLL, "PTR", "LocalFree", "PTR", $arDllCall[1])
        EndIf
        $aWellKnownSid[$iSid][3] = $sWellKnownSid
    EndIf
    $aWellKnownSid[$iSid][2] = DllCall($hAdvapi32Dll, "BOOL", "ConvertSidToStringSidW", "STRUCT*", $aWellKnownSid[$iSid][1], "WSTR*", 0)[2]
    If Not $aWellKnownSid[$iSid][3] Then $aWellKnownSid[$iSid][3] = $aWellKnownSid[$iSid][2]
    If StringRegExp($aWellKnownSid[0][2], "(?i)\n\K\Q" & $aWellKnownSid[$iSid][2] & "\E\r\d+\n") Then
        $iSid = StringRegExp($aWellKnownSid[0][2], "(?i)\n\K\Q" & $aWellKnownSid[$iSid][2] & "\E\r(\d+)\n", 1)[0]
        $aWellKnownSid[0][2] &= $sWellKnownSid & @CR & $iSid & @LF
        $aWellKnownSid[$iSid][(StringIsDigit($sWellKnownSid) ? 4 : 3)] = $sWellKnownSid
        Return SetError(0, $aWellKnownSid[$iSid][0], $aWellKnownSid[$iSid][$iType])
    EndIf
    $aWellKnownSid[0][0] = $iSid
    $aWellKnownSid[$iSid][0] = DllStructGetPtr($aWellKnownSid[$iSid][1])
    $aWellKnownSid[0][2] &= $sWellKnownSid & @CR & $iSid & @LF & $aWellKnownSid[$iSid][2] & @CR & $iSid & @LF
    Return SetError(0, $aWellKnownSid[$iSid][0], $aWellKnownSid[$iSid][$iType])
EndFunc

Func _WinAPI_GetLastErrorEx()
    $arDllCall = DllCall($hKernel32DLL, "LONG", "GetLastError")
    Return (@Error ? @Error : $arDllCall[0])
EndFunc ;==>_WinAPI_GetLastErrorEx

;~ Func _WinAPI_CreateWellKnownSid($iWellKnownSidType = 26, $iFlags = 0)
;~  $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "CreateWellKnownSid", "INT", $iWellKnownSidType, "PTR", Null, "PTR", Null, "DWORD*", 0)
;~  If @Error Or Not $arDllCall[4] Then Return SetError((@Error ? @Error : _WinAPI_GetLastErrorEx()), 1, 0)
;~  Local $TheSID = DllStructCreate("Byte SID[" & $arDllCall[4] & "]")
;~  $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "CreateWellKnownSid", "INT", $iWellKnownSidType, "PTR", Null, "STRUCT*", $TheSID, "DWORD*", $arDllCall[4])
;~  If Not $arDllCall[0] Then Return SetError(_WinAPI_GetLastErrorEx(), 2, 0)
;~  If $iFlags Then Return DllCall($hAdvapi32Dll, "BOOL", "ConvertSidToStringSidW", "STRUCT*", $TheSID, "WSTR*", 0)[2]
;~  Return $TheSID
;~ EndFunc

#Endregion ;**** Token Privileges ****

Global Const $SE_INVALID_HANDLE_VALUE = Ptr(-1)
Global Const $SDDL_REVISION_1     = 1
Global Const $OWNER_SECURITY_INFORMATION              = 0x00000001
Global Const $GROUP_SECURITY_INFORMATION              = 0x00000002
Global Const $DACL_SECURITY_INFORMATION               = 0x00000004
Global Const $OWNER_DACL_SECURITY_INFORMATION         = 0x00000005
Global Const $SACL_SECURITY_INFORMATION               = 0x00000008
Global Const $SE_DACL_PROTECTED                = 0x1000
Global Const $SE_SACL_PROTECTED                = 0x2000
Global Const $PROTECTED_DACL_SECURITY_INFORMATION     = 0x80000000
Global Const $PROTECTED_SACL_SECURITY_INFORMATION     = 0x40000000
Global Const $UNPROTECTED_DACL_SECURITY_INFORMATION   = 0x20000000
Global Const $UNPROTECTED_SACL_SECURITY_INFORMATION   = 0x10000000
Global Const $DACL_SECURITY_INFORMATION_PROTECTED     = BitOR($DACL_SECURITY_INFORMATION, $PROTECTED_DACL_SECURITY_INFORMATION)
Global Const $DACL_SECURITY_INFORMATION_UNPROTECTED   = BitOR($DACL_SECURITY_INFORMATION, $UNPROTECTED_DACL_SECURITY_INFORMATION)
Global Const $SACL_SECURITY_INFORMATION_PROTECTED     = BitOR($SACL_SECURITY_INFORMATION, $PROTECTED_SACL_SECURITY_INFORMATION)
Global Const $SACL_SECURITY_INFORMATION_UNPROTECTED   = BitOR($SACL_SECURITY_INFORMATION, $UnPROTECTED_SACL_SECURITY_INFORMATION)
Global Const $SE_REGISTRY_KEY                  = 4  ;; Indicates a registry key. A registry key object can be in the local registry, such as CLASSES_ROOT\SomePath or in a remote registry, such as \\ComputerName\CLASSES_ROOT\SomePath. The names of registry keys must use the following literal strings to identify the predefined registry keys: "CLASSES_ROOT", "CURRENT_USER", "MACHINE", and "USERS".
Global Const $SE_REGISTRY_WOW64_32KEY          = 12 ;; Indicates an object for a registry entry under WOW64.
Global Const $KEY_WOW64_64KEY                  = 0x0100 ;; Indicates that an application on 64-bit Windows should operate on the 64-bit registry view. This flag is ignored by 32-bit Windows. For more information, see Accessing an Alternate Registry View. This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
Global Const $KEY_WOW64_32KEY                  = 0x0200 ;; Indicates that an application on 64-bit Windows should operate on the 32-bit registry view. This flag is ignored by 32-bit Windows. For more information, see Accessing an Alternate Registry View. This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
Global Const $KEY_WOW64_RES                    = 0x0300
Global Const $HKEY_PREDEFINED[11][6]           = [[0x80000000,"HKCR","CLASSES_ROOT","\Registry\Machine\SOFTWARE\Classes","HKEY_CLASSES_ROOT","HKCR"],[0x80000001,"HKCU","CURRENT_USER","\Registry\User\CurrentUser","HKEY_CURRENT_USER","HKCU"],[0x80000002,"HKLM","MACHINE","\Registry\Machine","HKEY_LOCAL_MACHINE","HKLM"],[0x80000003,"HKU","USERS","\Registry\User","HKEY_USERS","HKU"],[0x80000005,"HKLM","MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current","\Registry\Machine\SYSTEM\CurrentControlSet\Hardware Profiles\Current","HKEY_CURRENT_CONFIG","HKCC"],[0x80000007,"HKCU","CURRENT_USER\Software\Classes\Local Settings","\Registry\User\CurrentUser\Software\Classes\Local Settings","HKEY_CURRENT_USER_LOCAL_SETTINGS","HKLS"],[0x80000004,"HKPD","PERFORMANCE_DATA\","","HKEY_PERFORMANCE_DATA","HKPD"],[0x80000006,"HKDD","DYN_DATA\","","HKEY_DYN_DATA","HKDD"],[0x80000050,"HKPT","PERFORMANCE_TEXT\","","HKEY_PERFORMANCE_TEXT","HKPT"],[0x80000060,"HKPN","PERFORMANCE_NLSTEXT\","","HKEY_PERFORMANCE_NLSTEXT","HKPN"],[0,";",0,""]]

#Region ;**** String Security Descriptor ****

; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_GetFileSecurity
; Description ...: The _WinAPI_GetFileSecurity function retrieves a copy of the String-Format Security Descriptor for File or Directry.
;                   The caller identifies the object by a Name.
; Syntax.........: _WinAPI_GetFileSecurity($sObjectName[, $dwSecurityInfo])
; Parameters ....: $sObjectName    - Indicates a file or directory. The name string that identifies a file or directory object can be in one of the following formats:
;                                      A relative path, such as FileName.dat or ..\FileName
;                                      An absolute path, such as FileName.dat, C:\DirectoryName\FileName.dat, or G:\RemoteDirectoryName\FileName.dat.
;                                      A UNC name, such as \\ComputerName\ShareName\FileName.dat.
;                                    However this parameter can also be a Kernel ObjectName, example
;                                      \DosDevices\C:\DirectoryName\FileName.dat
;                                      \Device\HarddiskVolume2\DirectoryName\FileName.dat
;                  $dwSecurityInfo - Optional, A set of bit flags that indicate the type of security information to retrieve.
;                  | This parameter can be a combination of the SECURITY_INFORMATION bit flags.
;                  | Defaut = BitOr($OWNER_SECURITY_INFORMATION, $DACL_SECURITY_INFORMATION)
;                  |$OWNER_SECURITY_INFORMATION (1) - The owner identifier of the object is being referenced.
;                  |$GROUP_SECURITY_INFORMATION (2) - The primary group identifier of the object is being referenced.
;                  |$DACL_SECURITY_INFORMATION (4)  - The DACL of the object is being referenced.
;                  |$SACL_SECURITY_INFORMATION (8)  - The SACL of the object is being referenced.
;                  |$ALL_SECURITY_INFORMATION (15)  - The Owner & Primary Group & DACL & SACL of the object is being referenced.
; Return values .: Success      - If the function succeeds, the return A string security descriptor and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is None ''. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If any of the ppsidOwner, ppsidGroup, ppDacl, or ppSacl parameters are non-NULL, and the SecurityInfo parameter
;                    specifies that they be retrieved from the object, those parameters will point to the corresponding parameters
;                    in the security descriptor returned in ppSecurityDescriptor. If the security descriptor does not contain the
;                    requested information, the corresponding parameter will be set to NULL.
;                  To read the owner, group, or DACL from the object's security descriptor, the object's DACL must
;                    grant READ_CONTROL access to the caller, or the caller must be the owner of the object.
;                  To read the system access control list of the object, the $SE_SECURITY_NAME privilege must be enabled for the calling process.
;                    For information about the security implications of enabling privileges, see Running with Special Privileges.
;                  This function does not handle race conditions. If your thread calls this function at the approximate time that
;                    another thread changes the object's security descriptor, then this function could fail.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless
;                    signing has been turned off for the system, but no encryption is performed.
;                  For more information about controlling access to objects through user accounts, group accounts, or logon sessions,
;                    see How DACLs Control Access to an Object http://msdn.microsoft.com/en-us/library/windows/desktop/aa446683(v=vs.85).aspx
;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is set in the input security descriptor, the function fails.;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is not set in the input security descriptor, the resulting
;                    security descriptor string does not have a D: component. For more information, see Security Descriptor String Format.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_GetFileSecurity("C:\DirectoryName\FileName.dat")
;                  _WinAPI_GetFileSecurity("\DosDevices\C:\DirectoryName\FileName.dat")
;                  _WinAPI_GetFileSecurity("\Device\HarddiskVolume2\DirectoryName\FileName.dat")
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_GetFileSecurity(Const ByRef $sObjectName, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
    If @Error Then Return SetError(1, -@Error, "")
    If $arDllCall[0] Then ;; $ERROR_ACCESS_DENIED = 5 - $ERROR_FILE_NOT_FOUND = 2 - $ERROR_INVALID_NAME = 123
        If $arDllCall[0] <> 5 And _WinAPI_GetFilePathByObjectName($sObjectName, $arDllCall[1]) Then $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
        If $arDllCall[0] = 5 Then  ;; will not have to ever happen
            ;; $dwDesiredAccess = $MAXIMUM_ALLOWED - 0x02000000 OR BitOr($READ_CONTROL, $ACCESS_SYSTEM_SECURITY) - 0x1020000
            ;; $dwCreationDisposition = $OPEN_EXISTING - 3, $dwFlagsAndAttributes = $FILE_FLAG_BACKUP_SEMANTICS - 0x2000000
            $arDllCall = DllCall($hKernel32DLL, "HANDLE", "CreateFileW", "WSTR", $arDllCall[1], "DWORD", 0x02000000, "DWORD", 0, "PTR", Null, "DWORD", 3, "DWORD", 0x2000000, "PTR", Null)
            If @Error Or $arDllCall[0] = $SE_INVALID_HANDLE_VALUE Then Return SetError(3, (@Error ? -@Error : _WinAPI_GetLastErrorEx()), "")
            Local $hFile = $arDllCall[0]
            $pSecurityDescriptor = _WinAPI_GetFileSecurityEx($hFile, $dwSecurityInfo)
            Return SetError(@Error, @Extended + DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hFile), $pSecurityDescriptor)
        EndIf
        If $arDllCall[0] Then Return SetError(1, $arDllCall[0], "")
    EndIf
    $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertSecurityDescriptorToStringSecurityDescriptorW", "PTR", $pSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "DWORD", $dwSecurityInfo, "WSTR*", 0, "PTR", Null)
    If @Error Or Not $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : _WinAPI_GetLastErrorEx()) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), "")
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return $arDllCall[4]
EndFunc ;==>_WinAPI_GetFileSecurity


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_GetFileSecurityEx
; Description ...: The _WinAPI_GetFileSecurityEx function retrieves a copy of the String-Format Security Descriptor for File or Directry.
;                   The caller identifies the object by a Handle.
; Syntax.........: _WinAPI_GetFileSecurityEx($hFile[, $dwSecurityInfo])
; Parameters ....: $hFile          - A handle to the file from which to retrieve security information.
;                  $dwSecurityInfo - Optional, A set of bit flags that indicate the type of security information to retrieve.
;                  | This parameter can be a combination of the SECURITY_INFORMATION bit flags.
;                  | Defaut = BitOr($OWNER_SECURITY_INFORMATION, $DACL_SECURITY_INFORMATION)
;                  |$OWNER_SECURITY_INFORMATION (1) - The owner identifier of the object is being referenced.
;                  |$GROUP_SECURITY_INFORMATION (2) - The primary group identifier of the object is being referenced.
;                  |$DACL_SECURITY_INFORMATION (4)  - The DACL of the object is being referenced.
;                  |$SACL_SECURITY_INFORMATION (8)  - The SACL of the object is being referenced.
;                  |$ALL_SECURITY_INFORMATION (15)  - The Owner & Primary Group & DACL & SACL of the object is being referenced.
; Return values .: Success      - If the function succeeds, the return A string security descriptor and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is None ''. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If any of the ppsidOwner, ppsidGroup, ppDacl, or ppSacl parameters are non-NULL, and the SecurityInfo parameter
;                    specifies that they be retrieved from the object, those parameters will point to the corresponding parameters
;                    in the security descriptor returned in ppSecurityDescriptor. If the security descriptor does not contain the
;                    requested information, the corresponding parameter will be set to NULL.
;                  To read the owner, group, or DACL from the object's security descriptor, the object's DACL must
;                    grant READ_CONTROL access to the caller, or the caller must be the owner of the object.
;                  To read the system access control list of the object, the $SE_SECURITY_NAME privilege must be enabled for the calling process.
;                    For information about the security implications of enabling privileges, see Running with Special Privileges.
;                  This function does not handle race conditions. If your thread calls this function at the approximate time that
;                    another thread changes the object's security descriptor, then this function could fail.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless
;                    signing has been turned off for the system, but no encryption is performed.
;                  For more information about controlling access to objects through user accounts, group accounts, or logon sessions,
;                    see How DACLs Control Access to an Object http://msdn.microsoft.com/en-us/library/windows/desktop/aa446683(v=vs.85).aspx
;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is set in the input security descriptor, the function fails.;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is not set in the input security descriptor, the resulting
;                    security descriptor string does not have a D: component. For more information, see Security Descriptor String Format.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_GetFileSecurityEx($hFile)
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_GetFileSecurityEx(Const ByRef $hFile, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $hFile, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
    If @Error Then Return SetError(1, -@Error, "")
    If $arDllCall[0] Then
        If $arDllCall[0] <> 5 Then Return SetError(1, $arDllCall[0], "")
        ;; $dwDesiredAccess = $MAXIMUM_ALLOWED - 0x02000000 OR BitOr($READ_CONTROL, $ACCESS_SYSTEM_SECURITY) - 0x1020000
        ;; $dwFlags = $FILE_FLAG_BACKUP_SEMANTICS - 0x2000000
        $arDllCall = DllCall($hKernel32DLL, "HANDLE", "ReOpenFile", "HANDLE", $hFile, "DWORD", 0x02000000, "DWORD", 0, "DWORD", 0x2000000)
        If @Error Or $arDllCall[0] = $SE_INVALID_HANDLE_VALUE Then Return SetError(3, (@Error ? -@Error : _WinAPI_GetLastErrorEx()), "")
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $arDllCall[0], "INT", 1, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
        DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $arDllCall[1])
        If $arDllCall[0] Then Return SetError(1, $arDllCall[0], "")
    EndIf
    $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertSecurityDescriptorToStringSecurityDescriptorW", "PTR", $pSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "DWORD", $dwSecurityInfo, "WSTR*", 0, "PTR", Null)
    If @Error Or Not $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : _WinAPI_GetLastErrorEx()) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), "")
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return $arDllCall[4]
EndFunc ;==>_WinAPI_GetFileSecurityEx


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_SetFileSecurity
; Description ...: The _WinAPI_SetFileSecurity function sets specified security information in the Security Descriptor of a File or Directry.
;                   The caller identifies the object by a Name.
; Syntax.........: _WinAPI_SetFileSecurity($sObjectName[, $sSecurityDescriptor])
; Parameters ....: $sObjectName         - Indicates a file or directory. The name string that identifies a file or directory object can be in
;                                          one of the following formats:
;                                           A relative path, such as FileName.dat or ..\FileName
;                                           An absolute path, such as FileName.dat, C:\DirectoryName\FileName.dat, or G:\RemoteDirectoryName\FileName.dat.
;                                           A UNC name, such as \\ComputerName\ShareName\FileName.dat.
;                                         However this parameter can also be a Kernel ObjectName, example
;                                           \DosDevices\C:\DirectoryName\FileName.dat
;                                           \Device\HarddiskVolume2\DirectoryName\FileName.dat
;                  $sSecurityDescriptor - String containing the string-format security descriptor, see _WinAPI_GetFileSecurity()
; Return values .: Success      - If the function succeeds, the return ERROR_SUCCESS and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is non-zero. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If you are setting the discretionary access control list (DACL) or any elements in the system access control list (SACL)
;                    of an object, the system automatically propagates any inheritable access control entries (ACEs) to existing child objects,
;                    according to the rules of inheritance.
;                  The _WinAPI_SetFileSecurity function does not reorder access-allowed or access-denied ACEs based on the preferred order.
;                    When propagating inheritable ACEs to existing child objects, _WinAPI_SetFileSecurity puts inherited ACEs in order after
;                    all of the noninherited ACEs in the DACLs of the child objects.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless signing
;                    has been turned off for the system, but no encryption is performed.
;                  When you update access rights of a folder indicated by an UNC path, for example \\Test\TestFolder, the original inherited
;                    ACE is removed and the full volume path is not included.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_SetFileSecurity("C:\DirectoryName\FileName.dat", "O:BAD:PAI(A;CI;GA;;;SY)(A;CI;GA;;;BA)(A;CI;GR;;;BU)")
;                  _WinAPI_SetFileSecurity("\DosDevices\C:\DirectoryName\FileName.dat", "D:PAI(A;CI;GA;;;SY)(A;CI;GA;;;BA)(A;CI;GR;;;BU)")
;                  _WinAPI_SetFileSecurity("\Device\HarddiskVolume2\DirectoryName\FileName.dat", "O:BA")
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_SetFileSecurity(Const ByRef $sObjectName, Const ByRef $sSecurityDescriptor)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl, $pSecDes;, $iControl
    $pSecurityDescriptor = _WinAPI_LookupStringSecurityDescriptorParts($sSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    If @Error Then Return SetError(2, @Extended, 2)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    If @Error Then Return SetError(1, -@Error + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
    If $arDllCall[0] Then ;; $ERROR_ACCESS_DENIED = 5 - $ERROR_FILE_NOT_FOUND = 2 - $ERROR_INVALID_NAME = 123
        If $arDllCall[0] <> 5 And _WinAPI_GetFilePathByObjectName($sObjectName, $arDllCall[1]) Then $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        If $arDllCall[0] = 5 Then  ;; will not have to ever happen
            If Not $psidOwner Then
                $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR*", 0, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
                If @Error Or $arDllCall[0] Then
                    ;; $dwDesiredAccess = $MAXIMUM_ALLOWED - 0x02000000 OR BitOr($READ_CONTROL, $WRITE_DAC, $WRITE_OWNER, $SYNCHRONIZE, $ACCESS_SYSTEM_SECURITY) - 0x011E0000
                    ;; $dwCreationDisposition = $OPEN_EXISTING - 3, $dwFlagsAndAttributes = $FILE_FLAG_BACKUP_SEMANTICS - 0x2000000
                    $arDllCall = DllCall($hKernel32DLL, "HANDLE", "CreateFileW", "WSTR", (@Error ? $sObjectName : $arDllCall[1]), "DWORD", 0x02000000, "DWORD", 0, "PTR", Null, "DWORD", 3, "DWORD", 0x2000000, "PTR", Null)
                    If @Error Or $arDllCall[0] = $SE_INVALID_HANDLE_VALUE Then Return SetError(3, (@Error ? -@Error : $arDllCall[0]) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 3)
                    Local $hFile = $arDllCall[0]
                    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hFile, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
                    SetError((@Error ? -@Error : $arDllCall[0]) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor) + DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hFile))
                    Return SetError(@Error, @Error, @Error)
                EndIf
                $psidOwner = $arDllCall[4]
                $pSecDes = $arDllCall[8]
            EndIf
            DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR", $PSIDADMIN, "PTR", Null, "PTR", Null, "PTR", Null)
            $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", BitOR($dwSecurityInfo, $OWNER_SECURITY_INFORMATION), "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
            If $pSecDes Then $pSecDes = 0 + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecDes)
        EndIf
    EndIf
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_SetFileSecurity


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_SetFileSecurityEx
; Description ...: The _WinAPI_SetFileSecurityEx function sets specified security information in the Security Descriptor of a File or Directry.
;                   The caller identifies the object by a Handle.
; Syntax.........: _WinAPI_SetFileSecurityEx($hFile[, $sSecurityDescriptor])
; Parameters ....: $hFile               - A handle to a file for which to set security information.
;                  $sSecurityDescriptor - String containing the string-format security descriptor, see _WinAPI_GetFileSecurity()
; Return values .: Success      - If the function succeeds, the return ERROR_SUCCESS and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is non-zero. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If you are setting the discretionary access control list (DACL) or any elements in the system access control
;                    list (SACL) of an object, the system automatically propagates any inheritable access control entries (ACEs)
;                    to existing child objects, according to the ACE inheritance rules.
;                  The _WinAPI_SetFileSecurityEx function does not reorder access-allowed or access-denied ACEs based on the preferred order.
;                    When propagating inheritable ACEs to existing child objects, _WinAPI_SetFileSecurityEx puts inherited ACEs in order after
;                    all of the noninherited ACEs in the DACLs of the child objects.
;                  Note  If share access to the children of the object is not available, this function will not propagate unprotected ACEs
;                    to the children. For example, if a directory is opened with exclusive access, the operating system will not propagate
;                    unprotected ACEs to the subdirectories or files of that directory when the security on the directory is changed.
;                  Warning  If the supplied handle was opened with an ACCESS_MASK value of MAXIMUM_ALLOWED, then the _WinAPI_SetFileSecurityEx
;                    function will not propagate ACEs to children.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_SetFileSecurityEx($hFile, "O:BAD:PAI(A;CI;GA;;;SY)(A;CI;GA;;;BA)(A;CI;GR;;;BU)")
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_SetFileSecurityEx(Const ByRef $hFile, Const ByRef $sSecurityDescriptor)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl;, $iControl
    $pSecurityDescriptor = _WinAPI_LookupStringSecurityDescriptorParts($sSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    If @Error Then Return SetError(2, @Extended, 2)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hFile, "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    If @Error Then Return SetError(1, -@Error + DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hFile) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
    If $arDllCall[0] = 5 Then
        ;; $dwDesiredAccess = $MAXIMUM_ALLOWED - 0x02000000 OR BitOr($READ_CONTROL, $WRITE_DAC, $WRITE_OWNER, $SYNCHRONIZE, $ACCESS_SYSTEM_SECURITY) - 0x011E0000
        ;; $dwFlags = $FILE_FLAG_BACKUP_SEMANTICS - 0x2000000
        $arDllCall = DllCall($hKernel32DLL, "HANDLE", "ReOpenFile", "HANDLE", $hFile, "DWORD", 0x02000000, "DWORD", 0, "DWORD", 0x2000000)
        If @Error Or $arDllCall[0] = $SE_INVALID_HANDLE_VALUE Then Return SetError(3, (@Error ? -@Error : _WinAPI_GetLastErrorEx() + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)), "")
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $arDllCall[0], "INT", 1, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $arDllCall[1])
    EndIf
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_SetFileSecurityEx


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_RegGetKeySecurity
; Description ...: The _WinAPI_RegGetKeySecurity function retrieves a copy of the String-Format Security Descriptor for registry key.
;                   The caller identifies the object by a Name.
; Syntax.........: _WinAPI_RegGetKeySecurity($sObjectName[, $dwSecurityInfo[, $iObjectType]])
; Parameters ....: $sObjectName    - Indicates a registry key. The name string that identifies a registry key object can be in
;                                     "HKLM\SOFTWARE\Example" or "HKEY_USERS" or "HKEY_CURRENT_USER\Software"
;                                     "\Registry\Machine\SOFTWARE\Example" or "\Registry\User" or "\Registry\User\CurrentUser"
;                                     "MACHINE\Software\Example" or "USERS" or "CURRENT_USER\Software"
;                                     "CLASSES_ROOT\Example" or in a remote registry such as \\ComputerName\CLASSES_ROOT\Example.
;                  $dwSecurityInfo - Optional, A set of bit flags that indicate the type of security information to retrieve.
;                  | This parameter can be a combination of the SECURITY_INFORMATION bit flags.
;                  | Defaut $OWNER_SECURITY_INFORMATION + $DACL_SECURITY_INFORMATION
;                  |$OWNER_SECURITY_INFORMATION (1) - The owner identifier of the object is being referenced.
;                  |$GROUP_SECURITY_INFORMATION (2) - The primary group identifier of the object is being referenced.
;                  |$DACL_SECURITY_INFORMATION (4)  - The DACL of the object is being referenced.
;                  |$SACL_SECURITY_INFORMATION (8)  - The SACL of the object is being referenced.
;                  |$ALL_SECURITY_INFORMATION (15)  - The Owner & Primary Group & DACL & SACL of the object is being referenced.
;                  $iObjectType    - Optional, Default = 4
;                  |$SE_REGISTRY_KEY (4)          - Indicates a registry key.
;                  |$SE_REGISTRY_WOW64_32KEY (12) - Indicates an object for a registry entry under WOW64.
; Return values .: Success      - If the function succeeds, the return A string security descriptor and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is None ''. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If any of the ppsidOwner, ppsidGroup, ppDacl, or ppSacl parameters are non-NULL, and the SecurityInfo parameter
;                    specifies that they be retrieved from the object, those parameters will point to the corresponding parameters
;                    in the security descriptor returned in ppSecurityDescriptor. If the security descriptor does not contain the
;                    requested information, the corresponding parameter will be set to NULL.
;                  To read the owner, group, or DACL from the object's security descriptor, the object's DACL must
;                    grant READ_CONTROL access to the caller, or the caller must be the owner of the object.
;                  To read the system access control list of the object, the $SE_SECURITY_NAME privilege must be enabled for the calling process.
;                    For information about the security implications of enabling privileges, see Running with Special Privileges.
;                  This function does not handle race conditions. If your thread calls this function at the approximate time that
;                    another thread changes the object's security descriptor, then this function could fail.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless
;                    signing has been turned off for the system, but no encryption is performed.
;                  For more information about controlling access to objects through user accounts, group accounts, or logon sessions,
;                    see How DACLs Control Access to an Object http://msdn.microsoft.com/en-us/library/windows/desktop/aa446683(v=vs.85).aspx
;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is set in the input security descriptor, the function fails.;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is not set in the input security descriptor, the resulting
;                    security descriptor string does not have a D: component. For more information, see Security Descriptor String Format.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_RegGetKeySecurity(0, "HKLM\Software\KeyName")
;                  _WinAPI_RegGetKeySecurity(0, "HKEY_CURRENT_USER\Software", $DACL_SECURITY_INFORMATION)
;                  _WinAPI_RegGetKeySecurity(0, "MACHINE\Software\Example", $OWNER_SECURITY_INFORMATION)
;                  _WinAPI_RegGetKeySecurity(0, "\Registry\Machine\SOFTWARE\Example", $ALL_SECURITY_INFORMATION, $SE_REGISTRY_WOW64_32KEY)
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_RegGetKeySecurity($sObjectName, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION, $iObjectType = 4)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", _RegGetPredefinedKeyEx($sObjectName, $iObjectType, 2), "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
    If @Error Then Return SetError(1, -@Error, "")
    If $arDllCall[0] Then ;; $ERROR_ACCESS_DENIED = 5
        If $arDllCall[0] <> 5 Then Return SetError(1, $arDllCall[0], "")
        $pSecurityDescriptor = _WinAPI_RegGetKeySecurityEx(Null, $sObjectName, ($iObjectType = 12 ? $KEY_WOW64_32KEY : 0), $dwSecurityInfo)
        Return SetError(@Error, @Extended, $pSecurityDescriptor)
    EndIf
    $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertSecurityDescriptorToStringSecurityDescriptorW", "PTR", $pSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "DWORD", $dwSecurityInfo, "WSTR*", 0, "PTR", Null)
    If @Error Or Not $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : _WinAPI_GetLastErrorEx()) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), "")
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return $arDllCall[4]
EndFunc ;==>_WinAPI_RegGetKeySecurity


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_RegGetKeySecurityEx
; Description ...: The _WinAPI_RegGetKeySecurityEx function retrieves a copy of the String-Format Security Descriptor for registry key.
;                   The caller identifies the object by a handle.
; Syntax.........: _WinAPI_RegGetKeySecurityEx($hKey[, $sSubKey[,$samDesired[, $dwSecurityInfo]]])
; Parameters ....: $hKey           - A handle to the object from which to retrieve security information, handle to an open registry key
;                                     returned by the RegOpenKey or RegCreateKey or RegOpenKeyEx or RegCreateKeyEx function,
;                                     or it can be one of the following predefined keys:
;                                        $HKEY_CLASSES_ROOT
;                                        $HKEY_CURRENT_CONFIG
;                                        $HKEY_CURRENT_USER
;                                        $HKEY_LOCAL_MACHINE
;                                        $HKEY_USERS
;                                     This parameter can be NULL (use the NULL or 0 to set NULL this parameter, If $hKey is NULL,
;                                      $sSubKey must be contain Full String KeyName, example
;                                          "HKLM\SOFTWARE\Example" or "HKEY_USERS" or "HKEY_CURRENT_USER\Software"
;                                          "\Registry\Machine\SOFTWARE\Example" or "\Registry\User" or "\Registry\User\CurrentUser"
;                                          "MACHINE\Software\Example" or "USERS" or "CURRENT_USER\Software"
;                                          "CLASSES_ROOT\Example" or in a remote registry such as \\ComputerName\CLASSES_ROOT\Example.
;                  $sSubKey        - Optional, The name of the registry subkey to be opened, Key names are not case sensitive. This parameter can be NULL
;                  $samDesired     - Optional, An access mask the specifies the platform-specific view of the registry.
;                  |  These flags are ignored by 32-bit Windows
;                  |$KEY_WOW64_64KEY (256) - operate on the 64-bit registry view
;                  |$KEY_WOW64_32KEY (512) - operate on the 32-bit registry view
;                  $dwSecurityInfo - Optional, A set of bit flags that indicate the type of security information to retrieve.
;                  | This parameter can be a combination of the SECURITY_INFORMATION bit flags.
;                  | Defaut $OWNER_SECURITY_INFORMATION + $DACL_SECURITY_INFORMATION
;                  |$OWNER_SECURITY_INFORMATION (1) - The owner identifier of the object is being referenced.
;                  |$GROUP_SECURITY_INFORMATION (2) - The primary group identifier of the object is being referenced.
;                  |$DACL_SECURITY_INFORMATION (4)  - The DACL of the object is being referenced.
;                  |$SACL_SECURITY_INFORMATION (8)  - The SACL of the object is being referenced.
;                  |$ALL_SECURITY_INFORMATION (15)  - The Owner & Primary Group & DACL & SACL of the object is being referenced.
; Return values .: Success      - If the function succeeds, the return A string security descriptor and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is None ''. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If any of the ppsidOwner, ppsidGroup, ppDacl, or ppSacl parameters are non-NULL, and the SecurityInfo parameter
;                    specifies that they be retrieved from the object, those parameters will point to the corresponding parameters
;                    in the security descriptor returned in ppSecurityDescriptor. If the security descriptor does not contain the
;                    requested information, the corresponding parameter will be set to NULL.
;                  To read the owner, group, or DACL from the object's security descriptor, the object's DACL must
;                    grant READ_CONTROL access to the caller, or the caller must be the owner of the object.
;                  To read the system access control list of the object, the $SE_SECURITY_NAME privilege must be enabled for the calling process.
;                    For information about the security implications of enabling privileges, see Running with Special Privileges.
;                  This function does not handle race conditions. If your thread calls this function at the approximate time that
;                    another thread changes the object's security descriptor, then this function could fail.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless
;                    signing has been turned off for the system, but no encryption is performed.
;                  For more information about controlling access to objects through user accounts, group accounts, or logon sessions,
;                    see How DACLs Control Access to an Object http://msdn.microsoft.com/en-us/library/windows/desktop/aa446683(v=vs.85).aspx
;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is set in the input security descriptor, the function fails.;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is not set in the input security descriptor, the resulting
;                    security descriptor string does not have a D: component. For more information, see Security Descriptor String Format.
; Link ..........:
; Example .......: _WinAPI_RegGetKeySecurityEx(0, "HKLM\Software\KeyName")
;                  _WinAPI_RegGetKeySecurityEx(0, "HKLM\Software\KeyName", 0, $DACL_SECURITY_INFORMATION)
;                  _WinAPI_RegGetKeySecurityEx(0, "HKLM\Software\KeyName", $KEY_WOW64_64KEY, $ALL_SECURITY_INFORMATION)
;                  _WinAPI_RegGetKeySecurityEx(_WinAPI_RegOpenKey("HKLM\Software\KeyName2"))
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_RegGetKeySecurityEx($hKey, $sSubKey = Null, $samDesired = 0, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor
    ;; $REG_OPTION_BACKUP_RESTORE = 4 - $SE_KERNEL_OBJECT = 6
    If $sSubKey Then
        $arDllCall = DllCall($hAdvapi32Dll, "LONG", "RegOpenKeyExW", "ULONG_PTR", ($hKey ? $hKey : _RegGetPredefinedKeyEx($sSubKey, $samDesired)), "WSTR", $sSubKey, "DWORD", 4, "DWORD", $samDesired, "ULONG_PTR*", 0)
        If @Error Or $arDllCall[0] Then Return SetError(3, (@Error ? -@Error : $arDllCall[0]), "")
        $hKey = $arDllCall[5]
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $hKey, "INT", 6, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
        If @Error Or $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : $arDllCall[0]) + DllCall($hAdvapi32Dll, "LONG", "RegCloseKey", "ULONG_PTR", $hKey), "")
        DllCall($hAdvapi32Dll, "LONG", "RegCloseKey", "ULONG_PTR", $hKey)
    Else
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $hKey, "INT", 6, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
        If @Error Then Return SetError(1, -@Error, "")
        If $arDllCall[0] Then ;; $ERROR_ACCESS_DENIED = 5
            If $arDllCall[0] <> 5 Then Return SetError(1, $arDllCall[0], "")
            $arDllCall = DllCall($hAdvapi32Dll, "LONG", "RegOpenKeyExW", "ULONG_PTR", $hKey, "WSTR", Null, "DWORD", 4, "DWORD", $samDesired, "ULONG_PTR*", 0)
            If @Error Or $arDllCall[0] Then Return SetError(3, (@Error ? -@Error : $arDllCall[0]), "")
            $hKey = $arDllCall[5]
            $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $hKey, "INT", 6, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
            DllCall($hAdvapi32Dll, "LONG", "RegCloseKey", "ULONG_PTR", $hKey)
            If $arDllCall[0] Then Return SetError(1, $arDllCall[0], "")
        EndIf
    EndIf
    $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertSecurityDescriptorToStringSecurityDescriptorW", "PTR", $pSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "DWORD", $dwSecurityInfo, "WSTR*", 0, "PTR", Null)
    If @Error Or Not $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : _WinAPI_GetLastErrorEx()) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), "")
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return $arDllCall[4]
EndFunc ;==>_WinAPI_RegGetKeySecurityEx


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_RegSetKeySecurity
; Description ...: Sets specified security information in the security descriptor of a registry key, based on String-Format Security Descriptor
;                   The caller identifies the object by a Name.
; Syntax.........: _WinAPI_RegSetKeySecurity($sObjectName, $sSecurityDescriptor[, $iObjectType])
; Parameters ....: $sObjectName         - Name to the object for which to set security information, example
;                                          "HKLM\SOFTWARE\Example" or "HKEY_USERS" or "HKEY_CURRENT_USER\Software"
;                                          "\Registry\Machine\SOFTWARE\Example" or "\Registry\User" or "\Registry\User\CurrentUser"
;                                          "MACHINE\Software\Example" or "USERS" or "CURRENT_USER\Software"
;                                          "CLASSES_ROOT\Example" or in a remote registry such as \\ComputerName\CLASSES_ROOT\Example.
;                  $sSecurityDescriptor - String containing the string-format security descriptor, see _WinAPI_RegGetKeySecurity
;                  $iObjectType         - Optional
;                  |$SE_REGISTRY_KEY (4)          - Indicates a registry key.
;                  |$SE_REGISTRY_WOW64_32KEY (12) - Indicates an object for a registry entry under WOW64.
; Return values .: Success      - If the function succeeds, the return ERROR_SUCCESS and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is non-zero. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If you are setting the discretionary access control list (DACL) or any elements in the system access control list (SACL)
;                    of an object, the system automatically propagates any inheritable access control entries (ACEs) to existing child objects,
;                    according to the rules of inheritance.
;                  The _WinAPI_RegSetKeySecurity function does not reorder access-allowed or access-denied ACEs based on the preferred order.
;                    When propagating inheritable ACEs to existing child objects, _WinAPI_RegSetKeySecurity puts inherited ACEs in order after
;                    all of the noninherited ACEs in the DACLs of the child objects.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless signing
;                    has been turned off for the system, but no encryption is performed.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_RegSetKeySecurity("HKLM\Software\KeyName", "O:BAD:PAI(A;CI;KR;;;AC)(A;CIIO;KA;;;BA)(A;CI;KA;;;SY)(A;CI;KR;;;BU)")
;                  _WinAPI_RegSetKeySecurity("HKEY_CURRENT_USER\Software", "D:PAI(A;CIIO;KA;;;BA)(A;CI;KA;;;SY)(A;CI;KR;;;BU)", $SE_REGISTRY_WOW64_32KEY)
;                  _WinAPI_RegSetKeySecurity("MACHINE\Software\Example", "D:PAI(A;CIIO;KA;;;BA)(A;CI;KA;;;SY)(A;CI;KR;;;BU)")
;                  _WinAPI_RegSetKeySecurity("\Registry\Machine\SOFTWARE\Example", "D:PAI(A;CIIO;KA;;;BA)(A;CI;KA;;;SY)(A;CI;KR;;;BU)")
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_RegSetKeySecurity($sObjectName, $sSecurityDescriptor, $iObjectType = 6)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl, $pSecDes;, $iControl
    $pSecurityDescriptor = _WinAPI_LookupStringSecurityDescriptorParts($sSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    If @Error Then Return SetError(2, @Extended, 2)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", _RegGetPredefinedKeyEx($sObjectName, $iObjectType, 2), "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    If @Error Then Return SetError(1, @Error + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
    If $arDllCall[0] = 5 Then  ;; $ERROR_ACCESS_DENIED = 5
        If Not $psidOwner Then
            $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", $iObjectType, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR*", 0, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
            If @Error Or $arDllCall[0] Then
                DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
                $pSecurityDescriptor = _WinAPI_RegSetKeySecurityEx(Null, $sObjectName, $sSecurityDescriptor, ($iObjectType = 12 ? $KEY_WOW64_32KEY : 0))
                Return SetError(@Error, @Extended, $pSecurityDescriptor)
            EndIf
            $psidOwner = $arDllCall[4]
            $pSecDes = $arDllCall[8]
        EndIf
        DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR", $PSIDADMIN, "PTR", Null, "PTR", Null, "PTR", Null)
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $arDllCall[1], "INT", 1, "DWORD", BitOR($dwSecurityInfo,$OWNER_SECURITY_INFORMATION), "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        If $pSecDes Then $pSecDes = 0 + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecDes)
    EndIf
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_SetFileSecurity


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_RegSetKeySecurityEx
; Description ...: Sets specified security information in the security descriptor of a registry key, based on String-Format Security Descriptor
;                   The caller identifies the object by a handle.
; Syntax.........: _WinAPI_RegSetKeySecurityEx($hKey, $sSubKey, $sSecurityDescriptor[, $samDesired])
; Parameters ....: $hKey                - A handle to the object for which to set security information, handle to an open registry key returned
;                                          by the RegCreateKeyEx or RegOpenKeyEx function, or it can be one of the following predefined keys:
;                                             HKEY_CLASSES_ROOT
;                                             HKEY_CURRENT_CONFIG
;                                             HKEY_CURRENT_USER
;                                             HKEY_LOCAL_MACHINE
;                                             HKEY_USERS
;                                          This parameter can be NULL (use the NULL or 0 to set NULL this parameter, If $hKey is NULL,
;                                           $sSubKey must be contain Full String KeyName, example
;                                               "HKLM\SOFTWARE\Example" or "HKEY_USERS" or "HKEY_CURRENT_USER\Software"
;                                               "\Registry\Machine\SOFTWARE\Example" or "\Registry\User" or "\Registry\User\CurrentUser"
;                                               "MACHINE\Software\Example" or "USERS" or "CURRENT_USER\Software"
;                                               "CLASSES_ROOT\Example" or in a remote registry such as \\ComputerName\CLASSES_ROOT\Example.
;                  $sSubKey             - Optional, The name of the registry subkey to be opened, Key names are not case sensitive. This parameter can be NULL
;                  $sSecurityDescriptor - String containing the string-format security descriptor, see _WinAPI_RegGetKeySecurity
;                  $samDesired - Optional, An access mask the specifies the platform-specific view of the registry.
;                  |  These flags are ignored by 32-bit Windows
;                  |$KEY_WOW64_64KEY (256) - operate on the 64-bit registry view
;                  |$KEY_WOW64_32KEY (512) - operate on the 32-bit registry view
; Return values .: Success      - If the function succeeds, the return ERROR_SUCCESS and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is non-zero. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If you are setting the discretionary access control list (DACL) or any elements in the system access control
;                    list (SACL) of an object, the system automatically propagates any inheritable access control entries (ACEs)
;                    to existing child objects, according to the ACE inheritance rules.
;                  The _WinAPI_RegSetKeySecurityEx function does not reorder access-allowed or access-denied ACEs based on the preferred order.
;                    When propagating inheritable ACEs to existing child objects, _WinAPI_RegSetKeySecurityEx puts inherited ACEs in order after
;                    all of the noninherited ACEs in the DACLs of the child objects.
;                  Note  If share access to the children of the object is not available, this function will not propagate unprotected ACEs
;                    to the children. For example, if a directory is opened with exclusive access, the operating system will not propagate
;                    unprotected ACEs to the subdirectories or files of that directory when the security on the directory is changed.
;                  Warning  If the supplied handle was opened with an ACCESS_MASK value of MAXIMUM_ALLOWED, then the _WinAPI_RegSetKeySecurityEx
;                    function will not propagate ACEs to children.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_RegSetKeySecurityEx(0, "HKLM\Software\KeyName", "O:BAD:PAI(A;CI;KR;;;AC)(A;CIIO;KA;;;BA)(A;CI;KA;;;SY)(A;CI;KR;;;BU)")
;                  _WinAPI_RegSetKeySecurityEx(0, "HKCUSoftware\KeyName", "D:PAI(A;CIIO;KA;;;BA)(A;CI;KA;;;SY)(A;CI;KR;;;BU)", $KEY_WOW64_64KEY)
;                  _WinAPI_RegSetKeySecurityEx(_WinAPI_RegOpenKeyEx("HKLM\Software\KeyName2"), Null, "D:PAI(A;CIIO;KA;;;BA)(A;CI;KA;;;SY)(A;CI;KR;;;BU)")
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_RegSetKeySecurityEx($hKey, $sSubKey, $sSecurityDescriptor, $samDesired = 0)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl;, $iControl
    $pSecurityDescriptor = _WinAPI_LookupStringSecurityDescriptorParts($sSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    If @Error Then Return SetError(2, @Extended, 2)
    ;; $REG_OPTION_BACKUP_RESTORE = 4 - $SE_KERNEL_OBJECT = 6
    If $sSubKey Then
        $arDllCall = DllCall($hAdvapi32Dll, "LONG", "RegOpenKeyExW", "ULONG_PTR", ($hKey ? $hKey : _RegGetPredefinedKeyEx($sSubKey, $samDesired)), "WSTR", $sSubKey, "DWORD", 4, "DWORD", $samDesired, "ULONG_PTR*", 0)
        If @Error Or $arDllCall[0] Then Return SetError(3, (@Error ? -@Error : $arDllCall[0]) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 3)
        $hKey = $arDllCall[5]
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hKey, "INT", 6, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        If @Error Or $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : $arDllCall[0]) + DllCall($hAdvapi32Dll, "LONG", "RegCloseKey", "ULONG_PTR", $hKey) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
    Else
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hKey, "INT", 6, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        If @Error Then Return SetError(1, -@Error + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
        If $arDllCall[0] <> 5 Then Return SetError($arDllCall[0], $arDllCall[0] + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), $arDllCall[0])
        $arDllCall = DllCall($hAdvapi32Dll, "LONG", "RegOpenKeyExW", "ULONG_PTR", $hKey, "WSTR", Null, "DWORD", 4, "DWORD", $samDesired, "ULONG_PTR*", 0)
        If @Error Or $arDllCall[0] Then Return SetError(3, (@Error ? -@Error : $arDllCall[0]) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 3)
        $hKey = $arDllCall[5]
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hKey, "INT", 6, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    EndIf
    DllCall($hAdvapi32Dll, "LONG", "RegCloseKey", "ULONG_PTR", $hKey)
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_RegSetKeySecurityEx


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_GetStringSecurityDescriptor
; Description ...: The _WinAPI_GetStringSecurityDescriptor function retrieves a copy of the String-Format Security Descriptor for an object specified by Name or Handle.
; Syntax.........: _WinAPI_GetStringSecurityDescriptor($ObjectName, $iObjectType[, $dwSecurityInfo])
; Parameters ....: $ObjectName     - Name or Handle to the object from which to retrieve security information
;                                    For descriptions of the string formats for the different object types, see $iObjectType.
;                  $iObjectType    - Specifies a value from the SE_OBJECT_TYPE enumeration that indicates the type of object Name or Handle by the $ObjectName parameter.
;                  |$SE_UNKNOWN_OBJECT_TYPE (0)      - Unknown object type.
;                  |$SE_FILE_OBJECT (1)              - Indicates a file or directory. The name string that identifies a file or directory object
;                  |                                    can be in one of the following formats:
;                  |                                       A relative path, such as FileName.dat or ..\FileName
;                  |                                       An absolute path, such as FileName.dat, C:\DirectoryName\FileName.dat, or G:\RemoteDirectoryName\FileName.dat.
;                  |                                       A UNC name, such as \\ComputerName\ShareName\FileName.dat.
;                  |$SE_SERVICE (2)                  - Indicates a Windows service. A service object can be a local service, such as ServiceName, or a remote service,
;                  |                                    such as \\ComputerName\ServiceName.
;                  |$SE_PRINTER (3)                  - Indicates a printer. A printer object can be a local printer, such as PrinterName, or a remote printer,
;                  |                                    such as \\ComputerName\PrinterName.
;                  |$SE_REGISTRY_KEY (4)             - Indicates a registry key. an Object Handle (Handle Key) or Object Name (KeyPath)
;                  |                                    A handle to an open registry key. This handle is returned by the _WinAPI_RegCreateKeyEx or _WinAPI_RegOpenKeyEx function
;                  |                                    A registry key object (KeyPath) can be in the local registry, such as CLASSES_ROOT\SomePath
;                  |                                     or in a remote registry, such as \\ComputerName\CLASSES_ROOT\SomePath.
;                  |                                    The names of registry keys must use the following literal strings to identify the predefined registry keys:
;                  |                                     "CLASSES_ROOT", "CURRENT_USER", "MACHINE", and "USERS".
;                  |                                    However _WinAPI_GetStringSecurityDescriptor also supports KeyPath and Key Object Name (Registry Key Object Routines)
;                  |                                     "HKLM\SOFTWARE\Example" or "HKEY_USERS" or "HKEY_CURRENT_USER\Software"
;                  |                                     "\Registry\Machine\SOFTWARE\Example" or "\Registry\User" or "\Registry\User\CurrentUser"
;                  |$SE_LMSHARE (5)                  - Indicates a network share. A share object can be local, such as ShareName, or remote, such as \\ComputerName\ShareName.
;                  |$SE_KERNEL_OBJECT (6)            - Indicates a local kernel object. Object Handle support all types of kernel objects, Object Name support
;                  |                                    only the following kernel objects: semaphore, event, mutex, waitable timer, and file mapping
;                  |$SE_WINDOW_OBJECT (7)            - Indicates a window station or desktop object on the local computer. You cannot use Object Name with these
;                  |                                    objects because the names of window stations or desktops are not unique.
;                  |$SE_DS_OBJECT (8)                - Indicates a directory service object or a property set or property of a directory service object. The name
;                  |                                    string for a directory service object must be in X.500 form, for example:
;                  |                                       CN=SomeObject,OU=ou2,OU=ou1,DC=DomainName,DC=CompanyName,DC=com,O=internet
;                  |$SE_DS_OBJECT_ALL (9)            - Indicates a directory service object and all of its property sets and properties.
;                  |$SE_PROVIDER_DEFINED_OBJECT (10) - Indicates a provider-defined object.
;                  |$SE_WMIGUID_OBJECT (11)          - Indicates a WMI object.
;                  |$SE_REGISTRY_WOW64_32KEY (12)    - Indicates an object for a registry entry under WOW64.
;                  $dwSecurityInfo - Optional, A set of bit flags that indicate the type of security information to retrieve.
;                  | This parameter can be a combination of the SECURITY_INFORMATION bit flags.
;                  |  Defaut $OWNER_SECURITY_INFORMATION + $DACL_SECURITY_INFORMATION
;                  |$OWNER_SECURITY_INFORMATION (1) - The owner identifier of the object is being referenced.
;                  |$GROUP_SECURITY_INFORMATION (2) - The primary group identifier of the object is being referenced.
;                  |$DACL_SECURITY_INFORMATION (4)  - The DACL of the object is being referenced.
;                  |$SACL_SECURITY_INFORMATION (8)  - The SACL of the object is being referenced.
;                  |$ALL_SECURITY_INFORMATION (15)  - The Owner & Primary Group & DACL & SACL of the object is being referenced.
; Return values .: Success      - If the function succeeds, the return A string security descriptor and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is None ''. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If any of the ppsidOwner, ppsidGroup, ppDacl, or ppSacl parameters are non-NULL, and the SecurityInfo parameter
;                    specifies that they be retrieved from the object, those parameters will point to the corresponding parameters
;                    in the security descriptor returned in ppSecurityDescriptor. If the security descriptor does not contain the
;                    requested information, the corresponding parameter will be set to NULL.
;                  If object is specified by Name
;                      To read the owner, group, or DACL from the object's security descriptor, the object's DACL must
;                        grant READ_CONTROL access to the caller, or the caller must be the owner of the object.
;                      To read the system access control list of the object, the $SE_SECURITY_NAME privilege must be enabled for the calling process.
;                        For information about the security implications of enabling privileges, see Running with Special Privileges.
;                      You can use the _WinAPI_GetStringSecurityDescriptor function with the following types of objects:
;                          Local or remote files or directories on an NTFS file system
;                          Local or remote printers
;                          Local or remote Windows services
;                          Network shares
;                          Registry keys
;                          Semaphores, events, mutexes, and waitable timers
;                          File-mapping objects
;                          Directory service objects
;                  If object is specified by Handle
;                      To read the owner, group, or DACL from the object's security descriptor, the calling process must
;                        have been granted READ_CONTROL access when the handle was opened. To get READ_CONTROL access, the
;                        caller must be the owner of the object or the object's DACL must grant the access.
;                      To read the SACL from the security descriptor, the calling process must have been granted $ACCESS_SYSTEM_SECURITY
;                        access when the handle was opened. The proper way to get this access is to enable the $SE_SECURITY_NAME privilege
;                        in the caller's current token, open the handle for ACCESS_SYSTEM_SECURITY access, and then disable the privilege.
;                        For information about the security implications of enabling privileges, see Running with Special Privileges
;                      You can use the _WinAPI_GetStringSecurityDescriptor function with the following types of objects:
;                          Local or remote files or directories on an NTFS file system
;                          Named pipes
;                          Local or remote printers
;                          Local or remote Windows services
;                          Network shares
;                          Registry keys
;                          Semaphores, events, mutexes, and waitable timers
;                          Processes, threads, jobs, and file-mapping objects
;                          Interactive service window stations and desktops
;                          Directory service objects
;                     If Object is registry handle, you need\have\recommended to use $SE_KERNEL_OBJECT (6)
;                       in this case $SE_KERNEL_OBJECT is much safer instead of $SE_REGISTRY_KEY or $SE_REGISTRY_WOW64_32KEY
;                  This function does not handle race conditions. If your thread calls this function at the approximate time that
;                    another thread changes the object's security descriptor, then this function could fail.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless
;                    signing has been turned off for the system, but no encryption is performed.
;                  For more information about controlling access to objects through user accounts, group accounts, or logon sessions,
;                    see How DACLs Control Access to an Object http://msdn.microsoft.com/en-us/library/windows/desktop/aa446683(v=vs.85).aspx
;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is set in the input security descriptor, the function fails.;
;                  If the DACL is NULL, and the SE_DACL_PRESENT control bit is not set in the input security descriptor, the resulting
;                    security descriptor string does not have a D: component. For more information, see Security Descriptor String Format.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_GetStringSecurityDescriptor(@DesktoDir & "\example.txt")
;                  _WinAPI_GetStringSecurityDescriptor($hOpenFile)
;                  _WinAPI_GetStringSecurityDescriptor("HKLM\SOFTWARE\KeyName", 4)
;                  _WinAPI_GetStringSecurityDescriptor($hKey, 4)
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_GetStringSecurityDescriptor($ObjectName, $iObjectType, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    If IsString($ObjectName) Then
        If $iObjectType = 4 Or $iObjectType = 12 Then _RegGetPredefinedKeyEx($ObjectName, $iObjectType, 2)  ;; $SE_REGISTRY_KEY = 4 - $SE_REGISTRY_WOW64_32KEY = 12
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $ObjectName, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
    Else
        ;;If $iObjectType = 4 Or $iObjectType = 12 Then $iObjectType = 6
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $ObjectName, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR", Null, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
    EndIf
    If @Error Or $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : $arDllCall[0]), "")
    Local $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertSecurityDescriptorToStringSecurityDescriptorW", "PTR", $pSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "DWORD", $dwSecurityInfo, "WSTR*", 0, "PTR", Null)
    If @Error Or Not $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : _WinAPI_GetLastErrorEx()) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), "")
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    Return $arDllCall[4]
EndFunc ;==>_WinAPI_GetStringSecurityDescriptor


; #FUNCTION# ========================================================================================================================
; Name...........: _WinAPI_SetStringSecurityDescriptor
; Description ...: Sets specified security information in the security descriptor of a specified object. The caller identifies the object by a Handle or by Name.
; Syntax.........: _WinAPI_SetStringSecurityDescriptor($ObjectName, $iObjectType, $sSecurityDescriptor)
; Parameters ....: $ObjectName          - Name or Handle to the object for which to set security information.
;                                          For descriptions of the string formats for the different object types, see $iObjectType.
;                  $iObjectType         - Specifies a value from the SE_OBJECT_TYPE enumeration that indicates the type of object Name or Handle by the $ObjectName parameter.
;                  |$SE_UNKNOWN_OBJECT_TYPE (0)      - Unknown object type.
;                  |$SE_FILE_OBJECT (1)              - Indicates a file or directory. The name string that identifies a file or directory object
;                  |                                    can be in one of the following formats:
;                  |                                       A relative path, such as FileName.dat or ..\FileName
;                  |                                       An absolute path, such as FileName.dat, C:\DirectoryName\FileName.dat, or G:\RemoteDirectoryName\FileName.dat.
;                  |                                       A UNC name, such as \\ComputerName\ShareName\FileName.dat.
;                  |$SE_SERVICE (2)                  - Indicates a Windows service. A service object can be a local service, such as ServiceName, or a remote service,
;                  |                                    such as \\ComputerName\ServiceName.
;                  |$SE_PRINTER (3)                  - Indicates a printer. A printer object can be a local printer, such as PrinterName, or a remote printer,
;                  |                                    such as \\ComputerName\PrinterName.
;                  |$SE_REGISTRY_KEY (4)             - Indicates a registry key. an Object Handle (Handle Key) or Object Name (KeyPath)
;                  |                                    A handle to an open registry key. This handle is returned by the _WinAPI_RegCreateKeyEx or _WinAPI_RegOpenKeyEx function
;                  |                                    A registry key object (KeyPath) can be in the local registry, such as CLASSES_ROOT\SomePath
;                  |                                     or in a remote registry, such as \\ComputerName\CLASSES_ROOT\SomePath.
;                  |                                    The names of registry keys must use the following literal strings to identify the predefined registry keys:
;                  |                                     "CLASSES_ROOT", "CURRENT_USER", "MACHINE", and "USERS".
;                  |                                    However _WinAPI_SetStringSecurityDescriptor also supports KeyPath and Key Object Name (Registry Key Object Routines)
;                  |                                     "HKLM\SOFTWARE\Example" or "HKEY_USERS" or "HKEY_CURRENT_USER\Software"
;                  |                                     "\Registry\Machine\SOFTWARE\Example" or "\Registry\User" or "\Registry\User\CurrentUser"
;                  |$SE_LMSHARE (5)                  - Indicates a network share. A share object can be local, such as ShareName, or remote, such as \\ComputerName\ShareName.
;                  |$SE_KERNEL_OBJECT (6)            - Indicates a local kernel object. Object Handle support all types of kernel objects, Object Name support
;                  |                                    only the following kernel objects: semaphore, event, mutex, waitable timer, and file mapping
;                  |$SE_WINDOW_OBJECT (7)            - Indicates a window station or desktop object on the local computer. You cannot use Object Name with these
;                  |                                    objects because the names of window stations or desktops are not unique.
;                  |$SE_DS_OBJECT (8)                - Indicates a directory service object or a property set or property of a directory service object. The name
;                  |                                    string for a directory service object must be in X.500 form, for example:
;                  |                                       CN=SomeObject,OU=ou2,OU=ou1,DC=DomainName,DC=CompanyName,DC=com,O=internet
;                  |$SE_DS_OBJECT_ALL (9)            - Indicates a directory service object and all of its property sets and properties.
;                  |$SE_PROVIDER_DEFINED_OBJECT (10) - Indicates a provider-defined object.
;                  |$SE_WMIGUID_OBJECT (11)          - Indicates a WMI object.
;                  |$SE_REGISTRY_WOW64_32KEY (12)    - Indicates an object for a registry entry under WOW64.
;                  $sSecurityDescriptor - String containing the string-format security descriptor, see _WinAPI_GetStringSecurityDescriptor
; Return values .: Success      - If the function succeeds, the return ERROR_SUCCESS and set @Error = ERROR_SUCCESS.
;                  Failure      - If the function fails, the return value is non-zero. and sets the @error flag to non-zero, and set extended error information
;                    @Extended: -1 = unable to use the DLL file,
;                               -2 = unknown "return type",
;                               -3 = "function" not found in the DLL file,
;                               -4 = bad number of parameters,
;                               -5 = bad parameter.
;                               0+ = error code defined in WinError.h
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: If you are setting the discretionary access control list (DACL) or any elements in the system access control list (SACL)
;                    of an object, the system automatically propagates any inheritable access control entries (ACEs) to existing child objects,
;                    according to the rules of inheritance.
;                  If object is specified by Name
;                      You can use the SetNamedSecurityInfo function with the following types of objects:
;                          Local or remote files or directories on an NTFS
;                          Local or remote printers
;                          Local or remote Windows services
;                          Network shares
;                          Registry keys
;                          Semaphores, events, mutexes, and waitable timers
;                          File-mapping objects
;                          Directory service objects
;                  If object is specified by Handle
;                      You can use the SetSecurityInfo function with the following types of objects:
;                          Local or remote files or directories on an NTFS
;                          Named pipes
;                          Local or remote printers
;                          Local or remote Windows services
;                          Network shares
;                          Registry keys
;                          Semaphores, events, mutexes, and waitable timers
;                          Processes, threads, jobs, and file-mapping objects
;                          Window stations and desktops
;                          Directory service objects
;                     If Object is registry handle, is recommended to use $SE_KERNEL_OBJECT (6), in some cases it seems
;                        that the $SE_KERNEL_OBJECT is more secure instead of $SE_REGISTRY_KEY or $SE_REGISTRY_WOW64_32KEY
;                  This function does not reorder access-allowed or access-denied ACEs based on the preferred order. When propagating
;                    inheritable ACEs to existing child objects, _WinAPI_SetStringSecurityDescriptor puts inherited ACEs in order after all
;                    of the noninherited ACEs in the DACLs of the child objects.
;                  This function transfers information in plaintext. The information transferred by this function is signed unless signing has
;                    been turned off for the system, but no encryption is performed.
;                  When you update access rights of a folder indicated by an UNC path, for example \\Test\TestFolder, the original inherited ACE
;                    is removed and the full volume path is not included.
;                  Note: If share access to the children of the object is not available, this function will not propagate unprotected ACEs to the children.
;                    For example, if a directory is opened with exclusive access, the operating system will not propagate unprotected ACEs to the
;                    subdirectories or files of that directory when the security on the directory is changed.
;                  Warning: If the supplied handle was opened with an ACCESS_MASK value of MAXIMUM_ALLOWED, then the _WinAPI_SetStringSecurityDescriptor function
;                    will not propagate ACEs to children.
; Related .......:
; Link ..........:
; Example .......: _WinAPI_SetStringSecurityDescriptor(@DesktoDir & "\example.txt", "O:BAD:PAI(A;CI;GA;;;SY)(A;CI;GA;;;BA)(A;CI;GR;;;BU)")
;                  _WinAPI_SetStringSecurityDescriptor("HKLM\Software\KeyName", "O:BAD:PAI(A;CI;GA;;;SY)(A;CI;GA;;;BA)(A;CI;GR;;;BU)", 4)
; Note ..........:
; ===================================================================================================================================
Func _WinAPI_SetStringSecurityDescriptor($ObjectName, $iObjectType, $sSecurityDescriptor)
    ;;If Not $iTokenPrivilegesState Then _WinAPI_SetPrivilegeEx($aTokenPrivilegesNewState)
    Static $pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl, $pSecDes, $iSI, $atSecurityInfo[2][3] = [["GetSecurityInfo","SetSecurityInfo","HANDLE"],["GetNamedSecurityInfoW","SetNamedSecurityInfoW","WSTR"]]
    $pSecurityDescriptor = _WinAPI_LookupStringSecurityDescriptorParts($sSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    If @Error Then Return SetError(2, @Extended, 2)
    $iSI = IsString($ObjectName)
    If $iSI And $iObjectType = 4 Or $iObjectType = 12 Then _RegGetPredefinedKeyEx($ObjectName, $iObjectType, 2)  ;; $SE_REGISTRY_KEY = 4 - $SE_REGISTRY_WOW64_32KEY = 12
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", $atSecurityInfo[$iSI][1], $atSecurityInfo[$iSI][2], $ObjectName, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    If @Error Then Return SetError(1, -@Error + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
    If $arDllCall[0] <> 5 Then Return SetError($arDllCall[0], DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), $arDllCall[0])
    If Not $psidOwner Then
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", $atSecurityInfo[$iSI][0], $atSecurityInfo[$iSI][2], $ObjectName, "INT", $iObjectType, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR*", 0, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
        If @Error Or $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : $arDllCall[0]) + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor), 1)
        $psidOwner = $arDllCall[4]
        $pSecDes = $arDllCall[8]
    EndIf
    DllCall($hAdvapi32Dll, "DWORD", $atSecurityInfo[$iSI][1], $atSecurityInfo[$iSI][2], $ObjectName, "INT", $iObjectType, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR", $PSIDADMIN, "PTR", Null, "PTR", Null, "PTR", Null)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", $atSecurityInfo[$iSI][1], $atSecurityInfo[$iSI][2], $ObjectName, "INT", $iObjectType, "DWORD", BitOR($dwSecurityInfo, $OWNER_SECURITY_INFORMATION), "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    If $pSecDes Then $pSecDes = 0 + DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecDes)
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_SetStringSecurityDescriptor


Func _WinAPI_GetSecurityInfo(Const ByRef $hObject, Const ByRef $iObjectType, Const ByRef $dwSecurityInfo, ByRef $psidOwner, ByRef $psidGroup, ByRef $pDacl, ByRef $pSacl, ByRef $pSecurityDescriptor)
    Static $iControl, $dwSecurityInfoEx
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $hObject, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR*", 0, "PTR*", 0, "PTR*", 0, "PTR*", 0, "PTR*", 0)
    If @Error Or $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : $arDllCall[0]), 1)
    $psidOwner = $arDllCall[4]
    $psidGroup = $arDllCall[5]
    $pDacl = $arDllCall[6]
    $pSacl = $arDllCall[7]
    $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorControl", "PTR", $pSecurityDescriptor, "WORD*", 0, "DWORD*", 0)
    $iControl = @Error ? 0 : $arDllCall[2]
    $dwSecurityInfoEx = $dwSecurityInfo
    If $pDacl Then $dwSecurityInfoEx = BitOR($dwSecurityInfoEx, (BitAND($iControl, $SE_DACL_PROTECTED) ? $DACL_SECURITY_INFORMATION_PROTECTED : $DACL_SECURITY_INFORMATION_UNPROTECTED))
    If $pSacl Then $dwSecurityInfoEx = BitOR($dwSecurityInfoEx, (BitAND($iControl, $SE_SACL_PROTECTED) ? $SACL_SECURITY_INFORMATION_PROTECTED : $SACL_SECURITY_INFORMATION_UNPROTECTED))
    Return $dwSecurityInfoEx
EndFunc ;==>_WinAPI_GetSecurityInfo


Func _WinAPI_GetSecurityInfoEx(Const ByRef $hObject, Const ByRef $iObjectType, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $hObject, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR*", 0, "PTR*", 0, "PTR*", 0, "PTR*", 0, "PTR*", 0)
    If @Error Or $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : $arDllCall[0]), 1)
    Return $arDllCall[8]
EndFunc ;==>_WinAPI_GetSecurityInfoEx


Func _WinAPI_GetNamedSecurityInfo(Const ByRef $sObjectName, Const ByRef $iObjectType, Const ByRef $dwSecurityInfo, ByRef $psidOwner, ByRef $psidGroup, ByRef $pDacl, ByRef $pSacl, ByRef $pSecurityDescriptor)
    Static $iControl, $dwSecurityInfoEx
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR*", 0, "PTR*", 0, "PTR*", 0, "PTR*", 0, "PTR*", 0)
    If @Error Or $arDllCall[0] Then Return SetError(1, (@Error ? -@error : $arDllCall[0]), 1)
    $psidOwner = $arDllCall[4]
    $psidGroup = $arDllCall[5]
    $pDacl = $arDllCall[6]
    $pSacl = $arDllCall[7]
    $pSecurityDescriptor = $arDllCall[8]
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorControl", "PTR", $pSecurityDescriptor, "WORD*", 0, "DWORD*", 0)
    $iControl = @Error ? 0 : $arDllCall[2]
    $dwSecurityInfoEx = $dwSecurityInfo
    If $pDacl Then $dwSecurityInfoEx = BitOR($dwSecurityInfoEx, (BitAND($iControl, $SE_DACL_PROTECTED) ? $DACL_SECURITY_INFORMATION_PROTECTED : $DACL_SECURITY_INFORMATION_UNPROTECTED))
    If $pSacl Then $dwSecurityInfoEx = BitOR($dwSecurityInfoEx, (BitAND($iControl, $SE_SACL_PROTECTED) ? $SACL_SECURITY_INFORMATION_PROTECTED : $SACL_SECURITY_INFORMATION_UNPROTECTED))
    Return $dwSecurityInfoEx
EndFunc ;==>_WinAPI_GetNamedSecurityInfo


Func _WinAPI_GetNamedSecurityInfoEx(Const ByRef $sObjectName, Const ByRef $iObjectType, $dwSecurityInfo = $OWNER_DACL_SECURITY_INFORMATION)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR*", 0, "PTR*", 0, "PTR*", 0, "PTR*", 0, "PTR*", 0)
    If @Error Or $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : $arDllCall[0]), 1)
    Return $arDllCall[8]
EndFunc ;==>_WinAPI_GetNamedSecurityInfoEx


Func _WinAPI_SetSecurityInfo(Const ByRef $hObject, Const ByRef $iObjectType, Const ByRef $dwSecurityInfo, Const ByRef $psidOwner, Const ByRef $psidGroup, Const ByRef $pDacl, Const ByRef $pSacl)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hObject, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    If @Error Then Return SetError(1, -@Error, 1)
    If $arDllCall[0] = 5 Then
        Local $pSecurityDescriptor, $_psidOwner = $psidOwner
        If Not $_psidOwner Then
            $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetSecurityInfo", "HANDLE", $hObject, "INT", $iObjectType, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR*", 0, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
            If @Error Or $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : $arDllCall[0]), 2)
            $_psidOwner = $arDllCall[4]
            $pSecurityDescriptor = $arDllCall[8]
        EndIf
        DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hObject, "INT", $iObjectType, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR", $PSIDADMIN, "PTR", Null, "PTR", Null, "PTR", Null)
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetSecurityInfo", "HANDLE", $hObject, "INT", $iObjectType, "DWORD", BitOR($dwSecurityInfo, $OWNER_SECURITY_INFORMATION), "PTR", $_psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        If $pSecurityDescriptor Then DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    EndIf
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_SetSecurityInfo


Func _WinAPI_SetSecurityInfoEx(Const ByRef $hObject, Const ByRef $iObjectType, Const ByRef $pSecurityDescriptor)
    Static $iSecurityInfo, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl
    If Not _WinAPI_LookupSecurityDescriptorPartsEx($pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl) Then Return SetError(@Error, @Extended, 2)
    $iSecurityInfo = _WinAPI_SetSecurityInfo($hObject, $iObjectType, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    Return SetError(@Error, @Extended, $iSecurityInfo)
EndFunc ;==>_WinAPI_SetSecurityInfoEx


Func _WinAPI_SetNamedSecurityInfo(Const ByRef $sObjectName, Const ByRef $iObjectType, Const ByRef $dwSecurityInfo, Const ByRef $psidOwner, Const ByRef $psidGroup, Const ByRef $pDacl, Const ByRef $pSacl)
    $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", $iObjectType, "DWORD", $dwSecurityInfo, "PTR", $psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
    If @Error Then Return SetError(1, -@Error, 1)
    If $arDllCall[0] = 5 Then
        Local $pSecurityDescriptor, $_psidOwner = $psidOwner
        If Not $_psidOwner Then
            $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "GetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", $iObjectType, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR*", 0, "PTR", Null, "PTR", Null, "PTR", Null, "PTR*", 0)
            If @Error Or $arDllCall[0] Then Return SetError(2, (@Error ? -@Error : $arDllCall[0]), 2)
            $_psidOwner = $arDllCall[4]
            $pSecurityDescriptor = $arDllCall[8]
        EndIf
        DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", $iObjectType, "DWORD", $OWNER_SECURITY_INFORMATION, "PTR", $PSIDADMIN, "PTR", Null, "PTR", Null, "PTR", Null)
        $arDllCall = DllCall($hAdvapi32Dll, "DWORD", "SetNamedSecurityInfoW", "WSTR", $sObjectName, "INT", $iObjectType, "DWORD", BitOR($dwSecurityInfo, $OWNER_SECURITY_INFORMATION), "PTR", $_psidOwner, "PTR", $psidGroup, "PTR", $pDacl, "PTR", $pSacl)
        If $pSecurityDescriptor Then DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $pSecurityDescriptor)
    EndIf
    Return SetError($arDllCall[0], $arDllCall[0], $arDllCall[0])
EndFunc ;==>_WinAPI_SetNamedSecurityInfo


Func _WinAPI_SetNamedSecurityInfoEx(Const ByRef $sObjectName, Const ByRef $iObjectType, Const ByRef $pSecurityDescriptor)
    Static $iNamedSecurityInfo, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl
    If Not _WinAPI_LookupSecurityDescriptorPartsEx($pSecurityDescriptor, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl) Then Return SetError(@Error, @Extended, 2)
    $iNamedSecurityInfo = _WinAPI_SetNamedSecurityInfo($sObjectName, $iObjectType, $dwSecurityInfo, $psidOwner, $psidGroup, $pDacl, $pSacl)
    Return SetError(@Error, @Extended, $iNamedSecurityInfo)
EndFunc ;==>_WinAPI_SetNamedSecurityInfoEx


Func _WinAPI_LookupStringSecurityDescriptorParts(Const ByRef $sSecurityDescriptor, ByRef $dwSecurityInfo, ByRef $psidOwner, ByRef $psidGroup, ByRef $pDacl, ByRef $pSacl)
    Static $iControl, $pSecurityDescriptor
    $dwSecurityInfo = 0
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "ConvertStringSecurityDescriptorToSecurityDescriptorW", "WSTR", $sSecurityDescriptor, "DWORD", $SDDL_REVISION_1, "PTR*", 0, "ULONG*", 0)
    If @Error Or Not $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : _WinAPI_GetLastErrorEx()), 0)
    $pSecurityDescriptor = $arDllCall[3]
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorControl", "PTR", $pSecurityDescriptor, "WORD*", 0, "DWORD*", 0)
    $iControl = @Error ? 0 : $arDllCall[2]
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorOwner", "PTR", $pSecurityDescriptor, "PTR*", 0, "BOOL*", 0)
    $psidOwner = @Error ? Null : $arDllCall[2]
    If $psidOwner Then $dwSecurityInfo += $OWNER_SECURITY_INFORMATION
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorGroup", "PTR", $pSecurityDescriptor, "PTR*", 0, "BOOL*", 0)
    $psidGroup = @Error ? Null : $arDllCall[2]
    If $psidGroup Then $dwSecurityInfo += $GROUP_SECURITY_INFORMATION
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorDacl", "PTR", $pSecurityDescriptor, "BOOL*", 0, "PTR*", 0, "BOOL*", 0)
    $pDacl = @Error ? Null : $arDllCall[3]
    If $pDacl Then $dwSecurityInfo += (BitAND($iControl, $SE_DACL_PROTECTED) ? $DACL_SECURITY_INFORMATION_PROTECTED : $DACL_SECURITY_INFORMATION_UNPROTECTED)
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorSacl", "PTR", $pSecurityDescriptor, "BOOL*", 0, "PTR*", 0, "BOOL*", 0)
    $pSacl = @Error ? Null : $arDllCall[3]
    If $pSacl Then $dwSecurityInfo += (BitAND($iControl, $SE_SACL_PROTECTED) ? $SACL_SECURITY_INFORMATION_PROTECTED : $SACL_SECURITY_INFORMATION_UNPROTECTED)
    If Not $dwSecurityInfo Then Return SetError(87, 87, 0)
    Return $pSecurityDescriptor
EndFunc


Func _WinAPI_LookupSecurityDescriptorPartsEx(Const ByRef $pSecurityDescriptor, ByRef $dwSecurityInfo, ByRef $psidOwner, ByRef $psidGroup, ByRef $pDacl, ByRef $pSacl)
    Static $iControl
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "IsValidSecurityDescriptor", "PTR", $pSecurityDescriptor)
    If @Error Or Not $arDllCall[0] Then Return SetError(1, (@Error ? -@Error : _WinAPI_GetLastErrorEx()), 0)
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorControl", "PTR", $pSecurityDescriptor, "WORD*", 0, "DWORD*", 0)
    $iControl = @Error ? 0 : $arDllCall[2]  ;; $iControl = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorControl", "PTR", $pSecurityDescriptor, "WORD*", 0, "DWORD*", 0)[2]
    $arDllCall = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorOwner", "PTR", $pSecurityDescriptor, "PTR*", 0, "BOOL*", 0)
    $psidOwner = @Error ? Null : $arDllCall[2]  ;; $psidOwner = DllCall($hAdvapi32Dll,"BOOL", "GetSecurityDescriptorOwner", "PTR", $pSecurityDescriptor, "PTR*", 0, "BOOL*", 0)[2]
    $dwSecurityInfo = $psidOwner ? $OWNER_SECURITY_INFORMATION : 0
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorGroup", "PTR", $pSecurityDescriptor, "PTR*", 0, "BOOL*", 0)
    $psidGroup = @Error ? Null : $arDllCall[2]  ;; $psidGroup = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorGroup", "PTR", $pSecurityDescriptor, "PTR*", 0, "BOOL*", 0)[2]
    If $psidGroup Then $dwSecurityInfo += $GROUP_SECURITY_INFORMATION
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorDacl", "PTR", $pSecurityDescriptor, "BOOL*", 0, "PTR*", 0, "BOOL*", 0)
    $pDacl = @Error ? Null : $arDllCall[3]  ;; $pDacl = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorDacl", "PTR", $pSecurityDescriptor, "BOOL*", 0, "PTR*", 0, "BOOL*", 0)[3]
    If $pDacl Then $dwSecurityInfo += (BitAND($iControl, $SE_DACL_PROTECTED) ? $DACL_SECURITY_INFORMATION_PROTECTED : $DACL_SECURITY_INFORMATION_UNPROTECTED)
    $arDllCall = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorSacl", "PTR", $pSecurityDescriptor, "BOOL*", 0, "PTR*", 0, "BOOL*", 0)
    $pSacl = @Error ? Null : $arDllCall[3]  ;; $pSacl = DllCall($hAdvapi32Dll, "BOOL", "GetSecurityDescriptorSacl", "PTR", $pSecurityDescriptor, "BOOL*", 0, "PTR*", 0, "BOOL*", 0)[3]
    If $pSacl Then $dwSecurityInfo += (BitAND($iControl, $SE_SACL_PROTECTED) ? $SACL_SECURITY_INFORMATION_PROTECTED : $SACL_SECURITY_INFORMATION_UNPROTECTED)
    If Not $dwSecurityInfo Then SetError(87, 87, 0)
    Return $dwSecurityInfo
EndFunc


Func _WinAPI_SfcIsKeyProtected($szKey, $samDesired = 0)
    $arDllCall = DllCall("Sfc.dll", "BOOL", "SfcIsKeyProtected", "ULONG_PTR", _RegGetPredefinedKeyEx($szKey, $samDesired), "WSTR", $szKey, "DWORD", $samDesired)
    If @Error Then Return SetError(@Error, @Extended, 0)
    Return $arDllCall[0]
EndFunc


Func _WinAPI_SfcIsFileProtected($sProtFileName)
    $arDllCall = DllCall("Sfc.dll", "BOOL", "SfcIsFileProtected", "HANDLE", Null, "WSTR", $sProtFileName)
    If @Error Then Return SetError(@Error, @Extended, 0)
    Return $arDllCall[0]
EndFunc


Func _WinAPI_LocalFreeEx(Const ByRef $hMem)
    $arDllCall = DllCall($hKernel32DLL, "HANDLE", "LocalFree", "HANDLE", $hMem)
    If @Error Or $arDllCall[0] Then Return SetError((@Error ? -@Error : _WinAPI_GetLastErrorEx()), 0, 0)
    Return 0
EndFunc


Func _WinAPI_CloseHandleEx(Const ByRef $hObject)
    $arDllCall = DllCall($hKernel32DLL, "BOOL", "CloseHandle", "HANDLE", $hObject)
    If @Error Or Not $arDllCall[0] Then Return SetError((@Error ? -@Error : _WinAPI_GetLastErrorEx()), 0, 0)
    Return 0
EndFunc


Func _WinAPI_GetFilePathByObjectName(Const ByRef $sObjectName, ByRef $sFilePath)
    Static $sDosDevice, $aObjectName, $aRoot
    If Not $sDosDevice Then
        $aRoot = DriveGetDrive('ALL')
        If @Error Then Return SetError(1, 0, "")
        For $i = 1 To $aRoot[0]
            $arDllCall = DllCall($hKernel32DLL, "DWORD", "QueryDosDeviceW", "WSTR", $aRoot[$i], "WSTR", "", "DWORD", 0x8000)
            If @Error Or Not $arDllCall[2] Then ContinueLoop
            $sDosDevice &= @LF & $arDllCall[2] & @CR & $aRoot[$i]
            ;$sDosDevice &= @LF & $aRoot[$i] & @CR & $arDllCall[2]
        Next
    EndIf
    $sFilePath = StringRegExpReplace($sObjectName, "(?i)^\h*\\+DosDevices\\+(?=[a-z]\:)", "")
    If @Extended Then Return $sFilePath
    $aObjectName = StringRegExp($sObjectName, "(?i)^\h*\\+Device\\+(\w+\d+)(.*)", 1)
    If @Error Then Return SetError(2, 0, "")
    $aRoot = StringRegExp($sDosDevice, "(?i)\n\\Device\\\Q" & $aObjectName[0] & "\E\r([^\r\n]+)", 1)
    If @Error Then Return SetError(3, 0, "")
    $sFilePath = $aRoot[0] & $aObjectName[1]
    Return $sFilePath
EndFunc   ;==>_WinAPI_GetFileRootByObjectName


Func _WinAPI_GetFilePathByObjectNameEx(ByRef $sObjectName, $iFlags = 0)
    Static $sDosDevice, $aObjectName, $aRoot
    If Not $sDosDevice Then
        $aRoot = DriveGetDrive('ALL')
        If @Error Then Return SetError(1, 0, ($iFlags ? $sObjectName : ""))
        For $i = 1 To $aRoot[0]
            $arDllCall = DllCall($hKernel32DLL, "DWORD", "QueryDosDeviceW", "WSTR", $aRoot[$i], "WSTR", "", "DWORD", 0x8000)
            If @Error Or Not $arDllCall[2] Then ContinueLoop
            $sDosDevice &= @LF & $arDllCall[2] & @CR & $aRoot[$i]
            ;$sDosDevice &= @LF & $aRoot[$i] & @CR & $arDllCall[2]
        Next
    EndIf
    $sObjectName = StringRegExpReplace($sObjectName, "(?i)^\h*\\+DosDevices\\+(?=[a-z]\:)", "")
    If @Extended Then Return $sObjectName
    $aObjectName = StringRegExp($sObjectName, "(?i)^\h*\\+Device\\+(\w+\d+)(.*)", 1)
    If @Error Then Return SetError(2, 0, ($iFlags ? $sObjectName : ""))
    $aRoot = StringRegExp($sDosDevice, "(?i)\n\\Device\\\Q" & $aObjectName[0] & "\E\r([^\r\n]+)", 1)
    If @Error Then Return SetError(3, 0, ($iFlags ? $sObjectName : ""))
    $sObjectName = $aRoot[0] & $aObjectName[1]
    Return $sObjectName
    ;;Static $oDosDevice, $aObjectName, $sRoot
    ;;If Not IsObj($oDosDevice) Then
    ;;  $sRoot = DriveGetDrive('ALL')
    ;;  If @Error Then Return SetError(1, 0, $sObjectName)
    ;;  $oDosDevice = ObjCreate("Scripting.Dictionary")
    ;;  If Not IsObj($oDosDevice) Then Return SetError(2, 0, $sObjectName)
    ;;  $oDosDevice.CompareMode = Int(1)
    ;;  For $i = 1 To $sRoot[0]
    ;;      $arDllCall = DllCall($hKernel32DLL, "DWORD", "QueryDosDeviceW", "WSTR", $sRoot[$i], "WSTR", "", "DWORD", 0x8000)
    ;;      If @Error Or Not $arDllCall[2] Then ContinueLoop
    ;;      $oDosDevice.Item($arDllCall[2]) = $sRoot[$i]
    ;;      ;$oDosDevice.Item($sRoot[$i]) = $arDllCall[2]
    ;;  Next
    ;;EndIf
    ;;$sObjectName = StringRegExpReplace($sObjectName, "(?i)^\h*\\+DosDevices\\+(?=[a-z]\:)", "")
    ;;If @Extended Then Return $sObjectName
    ;;$aObjectName = StringRegExp($sObjectName, "(?i)^\h*\\+Device\\+(\w+\d+)(.*)", 1)
    ;;If @Error Then Return SetError(2, 0, "")
    ;;$sRoot = $oDosDevice.Item("\Device\" & $aObjectName[0])
    ;;If Not $sRoot Then Return SetError(3, 0, "")
    ;;$sObjectName = $sRoot & $aObjectName[1]
    ;;Return $sObjectName
EndFunc   ;==>_WinAPI_GetFileRootByObjectName


Func _WinAPI_GetFileObjectNameByPath($sFilePath, $iFlags = 0)
    Static $aRoot
    $aRoot = StringRegExp($sFilePath, "(?i)^\h*(?:\\+DosDevices\\+)?([a-z]\:)(.*)", 1)
    If @Error Then Return SetError(1, 0, "")
    $arDllCall = DllCall($hKernel32DLL, "DWORD", "QueryDosDeviceW", "WSTR", $aRoot[0], "WSTR", "", "DWORD", 0x8000)
    If @Error Or Not $arDllCall[2] Then Return SetError(2, 0, ($iFlags ? $sFilePath : ""))
    $sFilePath = $arDllCall[2] & $aRoot[1]
    Return $sFilePath
EndFunc   ;==>_WinAPI_GetFileRootByObjectName


; #FUNCTION# ====================================================================================================================
; Name...........: _RegGetPredefinedKey
; Description ...: Get HKEY Handle\KeyName\ObjectName
; Syntax.........: _RegGetPredefinedKey(ByRef $szKey, ByRef $iType[, $iFlags])
; Parameters ....: $szKey  - HKEY Name
;                  $iType  - A mask that specifies the access rights for the key
;                  $iFlags - Optional
;                  |0 - (Default) Return $iPredefinedKey
;                  |1 - Return HKEY String for Inf File (AddReg\DelReg Directive)
;                  |2 - Return SE_REGISTRY_KEY String for SDDL (StringSecurityDescriptorEx)
;                  |3 - Return KEY ObjectName String (Registry Key Object Routines)
; Return values .: HKEY Handle\KeyName\ObjectName
; Author ........: DXRW4E
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _RegGetPredefinedKey(ByRef $szKey, ByRef $iType, $iFlags = 0)
    ;;Static Local $HKEY_PREDEFINED[11][6] = [[0x80000000,"HKCR","CLASSES_ROOT","\Registry\Machine\SOFTWARE\Classes","HKEY_CLASSES_ROOT","HKCR"],[0x80000001,"HKCU","CURRENT_USER","\Registry\User\CurrentUser","HKEY_CURRENT_USER","HKCU"],[0x80000002,"HKLM","MACHINE","\Registry\Machine","HKEY_LOCAL_MACHINE","HKLM"],[0x80000003,"HKU","USERS","\Registry\User","HKEY_USERS","HKU"],[0x80000005,"HKLM","MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current","\Registry\Machine\SYSTEM\CurrentControlSet\Hardware Profiles\Current","HKEY_CURRENT_CONFIG","HKCC"],[0x80000007,"HKCU","CURRENT_USER\Software\Classes\Local Settings","\Registry\User\CurrentUser\Software\Classes\Local Settings","HKEY_CURRENT_USER_LOCAL_SETTINGS","HKLS"],[0x80000004,"HKPD","PERFORMANCE_DATA\","","HKEY_PERFORMANCE_DATA","HKPD"],[0x80000006,"HKDD","DYN_DATA\","","HKEY_DYN_DATA","HKDD"],[0x80000050,"HKPT","PERFORMANCE_TEXT\","","HKEY_PERFORMANCE_TEXT","HKPT"],[0x80000060,"HKPN","PERFORMANCE_NLSTEXT\","","HKEY_PERFORMANCE_NLSTEXT","HKPN"],[0,";",0,""]]
    $iFlags = BitAND($iFlags, 3)
    Local $ahKey = StringRegExp($szKey, "^\h*([^\W\d]*+)((?:32|64)?+(?!\w))\\*(.*)", 1)
    Switch $ahKey[0]    ;;  ;StringRegExp($szKey, "^\w*+", 1)[0] ;
        Case "HKCR","HKEY_CLASSES_ROOT", "CLASSES_ROOT";, "MACHINE\SOFTWARE\Classes"
            $ahKey[0] = 0
        Case "HKCU", "HKEY_CURRENT_USER", "CURRENT_USER"
            $ahKey[0] = 1
        Case "HKLM", "HKEY_LOCAL_MACHINE", "MACHINE"
            $ahKey[0] = 2
        Case "HKU", "HKEY_USERS", "USERS"
            $ahKey[0] = 3
        Case "HKCC", "HKEY_CURRENT_CONFIG";, "MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current"
            $ahKey[0] = 4
            If $iFlags = 1 Then $ahKey[2] = "SYSTEM\CurrentControlSet\Hardware Profiles\Current" & StringRegExpReplace($ahKey[2], "^.", "\\$0")
        Case "HKLS", "HKEY_CURRENT_USER_LOCAL_SETTINGS";, "CURRENT_USER\Software\Classes\Local Settings"
            $ahKey[0] = 5
            If $iFlags = 1 Then $ahKey[2] = "Software\Classes\Local Settings" & StringRegExpReplace($ahKey[2], "^.", "\\$0")
        Case "HKPD", "HKEY_PERFORMANCE_DATA"
            $ahKey[0] = 6
        Case "HKDD", "HKEY_DYN_DATA"
            $ahKey[0] = 7
        Case "HKPT", "HKEY_PERFORMANCE_TEXT"
            $ahKey[0] = 8
        Case "HKPN", "HKEY_PERFORMANCE_NLSTEXT"
            $ahKey[0] = 9
        Case Else
            If $iFlags = 2 Then $iType = ($iType = 12) ? $SE_REGISTRY_WOW64_32KEY : $SE_REGISTRY_KEY
            Return SetError(1, 0, $HKEY_PREDEFINED[10][$iFlags])
    EndSwitch
    If $iFlags = 2 Then
        $iType = ($ahKey[1] == "32") ? $SE_REGISTRY_WOW64_32KEY : $SE_REGISTRY_KEY
        $szKey = $HKEY_PREDEFINED[$ahKey[0]][$iFlags] & StringRegExpReplace($ahKey[2], "^.", "\\$0")
        Return $szKey
    ElseIf $iFlags = 3 Then
        If $ahKey[0] > 5 Then Return SetError(1, 0, "")
        Return $HKEY_PREDEFINED[$ahKey[0]][$iFlags] & StringRegExpReplace($ahKey[2], "^.", "\\$0")
    Else
        ;;If $ahKey[1] Then $iType = BitOR($iType, ($ahKey[1] == "32" ? $KEY_WOW64_32KEY : $KEY_WOW64_64KEY))
        If $ahKey[1] Then $iType = BitXOR(BitOR($iType, $KEY_WOW64_RES), ($ahKey[1] == "32" ? $KEY_WOW64_64KEY : $KEY_WOW64_32KEY))
        $szKey = $ahKey[2] ? $ahKey[2] : Null
        Return $HKEY_PREDEFINED[$ahKey[0]][$iFlags]
    EndIf
EndFunc


; #FUNCTION# ====================================================================================================================
; Name...........: _RegGetPredefinedKeyEx
; Description ...: Get HKEY Handle\KeyName\ObjectName
; Syntax.........: _RegGetPredefinedKeyEx(ByRef $szKey, ByRef $iType[, $iFlags])
; Parameters ....: $szKey  - HKEY Name
;                  $iType  - A mask that specifies the access rights for the key
;                  $iFlags - Optional
;                  |0 - (Default) Return $iPredefinedKey
;                  |1 - Return HKEY String for Inf File (AddReg\DelReg Directive)
;                  |2 - Return SE_REGISTRY_KEY String for SDDL (StringSecurityDescriptorEx)
;                  |3 - Return KEY ObjectName String (Registry Key Object Routines)
; Return values .: HKEY Handle\KeyName\ObjectName
; Author ........: DXRW4E
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _RegGetPredefinedKeyEx(ByRef $szKey, ByRef $iType, $iFlags = 0)
    ;;Static Local $HKEY_PREDEFINED[11][6] = [[0x80000000,"HKCR","CLASSES_ROOT","\Registry\Machine\SOFTWARE\Classes","HKEY_CLASSES_ROOT","HKCR"],[0x80000001,"HKCU","CURRENT_USER","\Registry\User\CurrentUser","HKEY_CURRENT_USER","HKCU"],[0x80000002,"HKLM","MACHINE","\Registry\Machine","HKEY_LOCAL_MACHINE","HKLM"],[0x80000003,"HKU","USERS","\Registry\User","HKEY_USERS","HKU"],[0x80000005,"HKLM","MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current","\Registry\Machine\SYSTEM\CurrentControlSet\Hardware Profiles\Current","HKEY_CURRENT_CONFIG","HKCC"],[0x80000007,"HKCU","CURRENT_USER\Software\Classes\Local Settings","\Registry\User\CurrentUser\Software\Classes\Local Settings","HKEY_CURRENT_USER_LOCAL_SETTINGS","HKLS"],[0x80000004,"HKPD","PERFORMANCE_DATA\","","HKEY_PERFORMANCE_DATA","HKPD"],[0x80000006,"HKDD","DYN_DATA\","","HKEY_DYN_DATA","HKDD"],[0x80000050,"HKPT","PERFORMANCE_TEXT\","","HKEY_PERFORMANCE_TEXT","HKPT"],[0x80000060,"HKPN","PERFORMANCE_NLSTEXT\","","HKEY_PERFORMANCE_NLSTEXT","HKPN"],[0,";",0,""]]
    $iFlags = BitAND($iFlags, 3)
    Local $ahKey = StringRegExp($szKey, "^[\h\\]*+([^\W\d]*+)((?:32|64)?+(?!\w))\\*+(.*)", 1)
    If @Error Then Return SetError(1, 0, $HKEY_PREDEFINED[10][$iFlags])
    Switch $ahKey[0]
        Case "HKCR","HKEY_CLASSES_ROOT", "CLASSES_ROOT";, "MACHINE\SOFTWARE\Classes"
            $ahKey[0] = 0
        Case "HKCU", "HKEY_CURRENT_USER", "CURRENT_USER"
            $ahKey[0] = 1
        Case "HKLM", "HKEY_LOCAL_MACHINE", "MACHINE"
            $ahKey[0] = 2
        Case "HKU", "HKEY_USERS", "USERS"
            $ahKey[0] = 3
        Case "HKCC", "HKEY_CURRENT_CONFIG";, "MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current"
            $ahKey[0] = 4
            If $iFlags = 1 Then $ahKey[2] = "SYSTEM\CurrentControlSet\Hardware Profiles\Current" & StringRegExpReplace($ahKey[2], "^.", "\\$0")
        Case "HKLS", "HKEY_CURRENT_USER_LOCAL_SETTINGS";, "CURRENT_USER\Software\Classes\Local Settings"
            $ahKey[0] = 5
            If $iFlags = 1 Then $ahKey[2] = "Software\Classes\Local Settings" & StringRegExpReplace($ahKey[2], "^.", "\\$0")
        Case "HKPD", "HKEY_PERFORMANCE_DATA"
            $ahKey[0] = 6
        Case "HKDD", "HKEY_DYN_DATA"
            $ahKey[0] = 7
        Case "HKPT", "HKEY_PERFORMANCE_TEXT"
            $ahKey[0] = 8
        Case "HKPN", "HKEY_PERFORMANCE_NLSTEXT"
            $ahKey[0] = 9
        Case "Registry"
            $ahKey = StringRegExp($ahKey[2], "(?i)^(?|(Machine)((?:\\+SYSTEM\\+CurrentControlSet\\+Hardware Profiles\\+Current(?!\w)|\\+SOFTWARE\\+Classes(?!\w))?+)|User((?:\\+CurrentUser(?!\w)|\\+S-1-5-\d+-\d+-\d+-\d+-\d+)?+)((?:\\+Software\\+Classes\\+Local Settings(?!\w)|\\+_CLASSES\\+Local Settings(?!\w)|\\+_CLASSES(?!\w))?+))\\*(.*)", 1)
            If @Error Then Return SetError(1, 0, $HKEY_PREDEFINED[10][$iFlags])
            If $ahKey[0] = "Machine" Then
                $ahKey[0] = Not $ahKey[1] ? 2 : (StringRegExp($ahKey[1], "(?i)^\\+SO") ? 0 : 4)
                If $ahKey[0] = 4 And $iFlags = 1  Then $ahKey[2] = "SYSTEM\CurrentControlSet\Hardware Profiles\Current" & StringRegExpReplace($ahKey[2], "^.", "\\$0")
            Else
                $ahKey[0] = Not $ahKey[0] ? 3 : (StringRight($ahKey[1], 2) = "gs" ? 5 : 1)
                If ($ahKey[0] = 5 And $iFlags = 1) Or ($ahKey[1] And $ahKey[0] = 3) Then $ahKey[2] = "Software\Classes" & ($ahKey[0] = 5 ? "\Local Settings" : "") & StringRegExpReplace($ahKey[2], "^.", "\\$0")
            EndIf
        Case Else
            If $iFlags = 2 Then $iType = ($iType = 12) ? $SE_REGISTRY_WOW64_32KEY : $SE_REGISTRY_KEY
            If $iFlags = 2 Or Not StringRegExp($szKey, "^\h*\\+[^\\]+\\+") Then Return SetError(1, 0, $HKEY_PREDEFINED[10][$iFlags])
            $ahKey[0] = StringRegExpReplace($szKey, "^\h*\\+[^\\]+\\+", "")
            $ahKey[1] = _RegGetPredefinedKeyEx($ahKey[0], $iType, $iFlags)
            If Not @Error Then $szKey = $ahKey[0]
            Return SetError(@Error, 0, $ahKey[1])
    EndSwitch
    If $iFlags = 2 Then
        $iType = ($ahKey[1] == "32") ? $SE_REGISTRY_WOW64_32KEY : $SE_REGISTRY_KEY
        $szKey = $HKEY_PREDEFINED[$ahKey[0]][$iFlags] & StringRegExpReplace($ahKey[2], "^.", "\\$0")
        Return $szKey
    ElseIf $iFlags = 3 Then
        If $ahKey[0] > 5 Then Return SetError(1, 0, "")
        Return $HKEY_PREDEFINED[$ahKey[0]][$iFlags] & StringRegExpReplace($ahKey[2], "^.", "\\$0")
    Else
        ;;If $ahKey[1] Then $iType = BitOR($iType, ($ahKey[1] == "32" ? $KEY_WOW64_32KEY : $KEY_WOW64_64KEY))
        If $ahKey[1] Then $iType = BitXOR(BitOR($iType, $KEY_WOW64_RES), ($ahKey[1] == "32" ? $KEY_WOW64_64KEY : $KEY_WOW64_32KEY))
        $szKey = $ahKey[2] ? $ahKey[2] : Null
        Return $HKEY_PREDEFINED[$ahKey[0]][$iFlags]
    EndIf
EndFunc


#Endregion ;**** String Security Descriptor ****
 

Ciao.

SecurityEx.au3

Edited by DXRW4E

apps-odrive.pngdrive_app_badge.png box-logo.png new_logo.png MEGA_Logo.png

Share this post


Link to post
Share on other sites

Thanks for trying to help, DXRW4E.

I couldn't find what I was looking for, but I found another solution.

Instead of looking for the owner I just found a file that contains the users full name, which is all I wanted.

I will post my solution once I finish it.

Share this post


Link to post
Share on other sites

Hi,

This became the solution to my problem.

Keep in mind, I created a cmd script that retreives the full name of the user by using a "net user" command, then saving it to a log file with the full name in the filename.

I then clean all of the text in the filename that I don't want, to get the finished product.

This code is useless without the rest, but I just wanted to post some of it here in case anyone would be interested. I could clean the rest of the code and post that aswel.. Just ask if you're interested :)

I know there may be better solutions out there, but I'm just not good enough with AutoIt to make it, yet..

Please feel free to offer better solutions to finding a domain users full name with AutoIt.

Func FindFullName()
    While 1     
        Local $hSearch = FileFindFirstFile($srcDir1 & $input & $FullNamePath & "\FullName_*.log")
        ; Check if the search was successful, if not display a message and return False.
            If $hSearch = -1 Then
                MsgBox(48, "Error", "Full name cannot be found for: " & $input)
            EndIf
        ; Assign a Local variable the empty string which will contain the files names found.
        Local $sFileName = "", $iResult = 0
        $sFileName = FileFindNextFile($hSearch)
        ; If there is no more file matching the search.
            If @error Then ExitLoop
        $string = $sFileName
        Local $a_rep[2][2] = [["FullName_", ""], [".log", ""]]
        For $i = 0 To Ubound($a_rep, 1) - 1
        $string = StringRegExpReplace($string, "\Q" & $a_rep[$i][0] & "\E", $a_rep[$i][1])
    Next
        ; Display user's full name
        $iResult = MsgBox(BitOR($MB_SYSTEMMODAL, $MB_OKCANCEL), "", "User's full name: " & $string)
        If $iResult <> $IDOK Then ExitLoop  ; If the user clicks on the cancel/close button.
        Local $iFileExists1 = FileExists($srcDir1 & $input & "_CPR")
        If $iFileExists1 = 1 Then
            Call("CheckPrev1")
        EndIf
        ; Close the search handle.
        FileClose($hSearch)
    WEnd
EndFunc

Share this post


Link to post
Share on other sites

Have you tried Waters AD UDF? It is very awesome, I started recently using autoit and his UDF has been a godsend for me. I use it to validate a user and to adjust permissions based on distribution lists. Just 2 of MANY options that he has configured. :D Give it a whirl you might be surprised!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now