Sign in to follow this  
Followers 0
yaroslavp

ERROR_PRIVILEGE_NOT_HELD returned by _Date_Time_SetTimeZoneInformation

4 posts in this topic

Hi all,

A script that uses "_Date_Time_SetTimeZoneInformation" works very well in Windows XP. In Windows 7, however, it fails. The precise point of failure (in _Date_Time_SetTimeZoneInformation()) is this call:

Local $aResult = DllCall("kernel32.dll", "bool", "SetTimeZoneInformation", "ptr", DllStructGetPtr($tZoneInfo))

which sets the ERROR_PRIVILEGE_NOT_HELD flag.

Note that all the previous calls succeed, including the call that enables the required privilege! So I have no idea why the function returns this error.

I tried to enable the "SeTimeZonePrivilege" as well, but still failed.

AutoIt is executed with local administrator rights.

Thanks for any hints or suggestions.

Yaroslav

Share this post


Link to post
Share on other sites



You didn't say what privilege you set or how you set it. Note there are two, depending on your version: MSDN: SetTimeZoneInformation Function

Remarks

An application must have the SE_TIME_ZONE_NAME privilege for this function to succeed. This privilege is disabled by default. Use the AdjustTokenPrivileges function to enable the privilege before calling SetTimeZoneInformation, and then to disable the privilege after the SetTimeZoneInformation call. For more information, see Running with Special Privileges.

Windows Server 2003 and Windows XP/2000: The application must have the SE_SYSTEMTIME_NAME privilege.

To inform Explorer that the time zone has changed, send the WM_SETTINGCHANGE message.

;)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

I resolved the problem. Both _Date_Time_SetTimeZoneInformation() and _Security__SetPrivilege() needed modifications to work correctly in Windows 7 (the changes were made according to some code I found elsewhere in these forums). However, after these modifications they cease to work in WinXP!

In a nutshell, a different privilege needs to be enabled for changing timezones in Windows 7, and different code is needed to successfully enable a privilege.

I didn't quite have time to make a platform-independent version of these functions, so I just switch them based on the current OS. The code of both functions for Windows 7 is attached.

tmp.au3

Share this post


Link to post
Share on other sites

Thanks for posting your resolution. yaroslavp's posted code mirrored below:

Func _tagTOKEN_PRIVILEGES($iPrivilegeCount)
    If Not ( IsInt($iPrivilegeCount) And $iPrivilegeCount > 0 ) Then Return SetError(-1, 0, "")
    Local $tagTOKEN_PRIVILEGES = "dword PrivilegeCount;"
    For $i = 0 To $iPrivilegeCount - 1
        $tagTOKEN_PRIVILEGES &= "dword LowPart" & $i & ";long HighPart" & $i & ";dword Attributes" & $i & ";"
    Next
    Return StringTrimRight($tagTOKEN_PRIVILEGES, 1)
EndFunc




Func SetTimeZoneInformation($iBias, $sStdName, $tStdDate, $iStdBias, $sDayName, $tDayDate, $iDayBias)
    _DebugOut("SetTimeZoneInformation")
    Local $tStdName = _WinAPI_MultiByteToWideChar($sStdName)
    Local $tDayName = _WinAPI_MultiByteToWideChar($sDayName)
    Local $tZoneInfo = DllStructCreate($tagTIME_ZONE_INFORMATION)
    DllStructSetData($tZoneInfo, "Bias", $iBias)
    DllStructSetData($tZoneInfo, "StdName", DllStructGetData($tStdName, 1))
    _MemMoveMemory(DllStructGetPtr($tStdDate), DllStructGetPtr($tZoneInfo, "StdDate"), DllStructGetSize($tStdDate))
    DllStructSetData($tZoneInfo, "StdBias", $iStdBias)
    DllStructSetData($tZoneInfo, "DayName", DllStructGetData($tDayName, 1))
    _MemMoveMemory(DllStructGetPtr($tDayDate), DllStructGetPtr($tZoneInfo, "DayDate"), DllStructGetSize($tDayDate))
    DllStructSetData($tZoneInfo, "DayBias", $iDayBias)

    Local $aResult = DllCall("kernel32.dll", "handle", "GetCurrentProcess")
    If @error Then 
        _DebugOut("error 1")
        Return SetError(@error, @extended, False)
    EndIf
    Local $proc = $aResult[0]

    Local $aResult2 = DllCall("advapi32.dll", "int", "OpenProcessToken", "handle", $proc, "dword", BitOR($TOKEN_ADJUST_PRIVILEGES, $TOKEN_QUERY), "ptr*", 0)
    If @error Then 
        _DebugOut("error 2")
        Return SetError(@error, @extended, False)
    ENdIf
    Local $hToken = $aResult2[3]

    Local $res = SetPrivilege($hToken, "SeTimeZonePrivilege", True)
    $res = BitAnd($res, SetPrivilege($hToken, "SeSystemTimePrivilege", True))

    Local $iError = @error
    Local $iLastError = @extended
    Local $iRet = False
    If Not @error Then
        ; Set time zone information
        Local $aResult = DllCall("kernel32.dll", "bool", "SetTimeZoneInformation", "ptr", DllStructGetPtr($tZoneInfo))
        If @error Then
            $iError = @error
            $iLastError = @extended
            _DebugOut("error 3 " & $iLastError)
        ElseIf $aResult[0] Then
            $iLastError = 0
            $iRet = True
        Else
            $iError = 1
            $iLastError = _WinAPI_GetLastError()
            _DebugOut("error 4 " & $iLastError)
        EndIf

        ; Disable system time privileged mode
        SetPrivilege($hToken, "SeSystemTimePrivilege", False)
        SetPrivilege($hToken, "SeTimeZonePrivilege", False)
        If @error Then 
            $iError = 2
            _DebugOut("error 6 " & $iLastError)    
        EndIf            
    Else
            _DebugOut("error 5 " & $iLastError)    
    EndIf
    
    _WinAPI_CloseHandle($hToken)

    _DebugOut("Errors: " & $iError & ", " & $iLastError & ", " & $iRet)
    Return SetError($iError,  $iLastError, $iRet)
EndFunc   ;==>_Date_Time_SetTimeZoneInformation




Func SetPrivilege($hToken, $sPrivilege, $fEnable)
    _DebugOut("SetPrivilege")

    Local $pRequired, $tRequired, $iLUID, $iAttributes, $iCurrState, $pCurrState, $tCurrState, $iPrevState, $pPrevState, $tPrevState

    $iLUID = _Security__LookupPrivilegeValue("", $sPrivilege)
    If $iLUID = 0 Then Return SetError(-1, 0, False)

    $tCurrState = DllStructCreate( _tagTOKEN_PRIVILEGES(1) )
    $pCurrState = DllStructGetPtr($tCurrState)
    $iCurrState = DllStructGetSize($tCurrState)
    $tPrevState = DllStructCreate( _tagTOKEN_PRIVILEGES(1) )
    $pPrevState = DllStructGetPtr($tPrevState)
    $iPrevState = DllStructGetSize($tPrevState)
    $tRequired = DllStructCreate("int Data")
    $pRequired = DllStructGetPtr($tRequired)
    ; Get current privilege setting
    DllStructSetData($tCurrState, "PrivilegeCount", 1)
    DllStructSetData($tCurrState, "LowPart0", $iLUID)
    If Not _Security__AdjustTokenPrivileges($hToken, False, $pCurrState, $iCurrState, $pPrevState, $pRequired) Then
        Return SetError(-2, @error, False)
    EndIf
    ; Set privilege based on prior setting
    DllStructSetData($tPrevState, "PrivilegeCount", 1)
    DllStructSetData($tPrevState, "LowPart0", $iLUID)
    $iAttributes = DllStructGetData($tPrevState, "Attributes0")
    If $fEnable Then
        $iAttributes = BitOR($iAttributes, $SE_PRIVILEGE_ENABLED)
    Else
        $iAttributes = BitAND($iAttributes, BitNOT($SE_PRIVILEGE_ENABLED))
    EndIf
    DllStructSetData($tPrevState, "Attributes0", $iAttributes)
    If Not _Security__AdjustTokenPrivileges($hToken, False, $pPrevState, $iPrevState, $pCurrState, $pRequired) Then
        Return SetError(-3, @error, False)
    EndIf
    Return SetError(0, 0, True)
EndFunc   ;==>_Security__SetPrivilege


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

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
Sign in to follow this  
Followers 0