Page 1 of 1

Shutdown Local/Remote Computers (Windows only)

Posted: Sat Nov 17, 2007 9:51 pm
by ABBKlaus
Hi,

this code send a Shutdownmessage to a local or remote computer running Windows NT.

Code: Select all

#SE_SHUTDOWN_NAME                         = "SeShutdownPrivilege"
#SE_REMOTE_SHUTDOWN_NAME                  = "SeRemoteShutdownPrivilege"

InitNetwork()

Procedure.s GetLastError(Err.l)
  Protected buffer.l=0,ferr.l,errormsg$=""
  
  ferr=FormatMessage_(#FORMAT_MESSAGE_ALLOCATE_BUFFER|#FORMAT_MESSAGE_FROM_SYSTEM,0,Err,GetUserDefaultLangID_(),@buffer,0,0)
  If buffer<>0
    errormsg$=PeekS(buffer)
    LocalFree_(buffer)
    errormsg$=RemoveString(errormsg$,Chr(13)+Chr(10))
  EndIf
  
  ProcedureReturn errormsg$
 EndProcedure

Procedure.l IPF_EnablePrivilege(Privilege.s,Enable.l=1)
  Protected Res.l
  Protected hToken.l, hProcess.l
  Protected tTP.TOKEN_PRIVILEGES, tTPOld.TOKEN_PRIVILEGES, lTpOld.l
  Protected Success.l
  
  Res = LookupPrivilegeValue_(0, Privilege, @tLUID.LUID) 
  If Res
    hProcess = GetCurrentProcess_()
    If hProcess
      Res = OpenProcessToken_(hProcess, #TOKEN_ADJUST_PRIVILEGES | #TOKEN_QUERY, @hToken)
      If Res
        With tTP
          \PrivilegeCount = 1
          If Enable
            \Privileges[0]\Attributes = #SE_PRIVILEGE_ENABLED
          Else
            \Privileges[0]\Attributes = 0
          EndIf
          \Privileges[0]\Luid\LowPart = tLUID\LowPart
          \Privileges[0]\Luid\HighPart = tLUID\HighPart
        EndWith
        Res = AdjustTokenPrivileges_(hToken, 0, @tTP, SizeOf(tTP), @tTPOld, @lTpOld)
        If Res
          Success=1
        EndIf
        CloseHandle_(hToken)
      EndIf
    EndIf
  EndIf
  
  If Success
    If Enable
      Debug Privilege+" enabled"
    Else
      Debug Privilege+" disabled"
    EndIf
  Else
    Err=GetLastError_()
    If Enable
      Debug Privilege+" not enabled ("+GetLastError(Err)+")"
    Else
      Debug Privilege+" not disabled ("+GetLastError(Err)+")"
    EndIf
  EndIf
  
  ProcedureReturn Success
EndProcedure

Procedure.l InitiateSystemShutdown(MachineName$="",Message$="",Timeout.l=10,ForceAppsClosed.b=0,RebootAfterShutdown.b=0)
  ;InitiateSystemShutdown Function
  ;http://msdn2.microsoft.com/en-us/library/aa376873.aspx
  
  ;ABBKlaus on 17.11.2007
  ;
  ;Usage :
  ;
  ;Err.l=InitiateSystemShutdown([MachineName$,[Message$,[Timeout,[ForceAppsClosed,[RebootAfterShutdown]]]]])
  ;
  ;Parameters :
  ;
  ;MachineName$
  ;  The network name of the computer to be shut down.
  ;  If MachineName$ is an empty string, the function shuts down the local computer.
  ;Message$
  ;  The message to be displayed in the shutdown dialog box.
  ;  This parameter can be an empty string if no message is required.
  ;Timeout
  ;  The length of time that the shutdown dialog box should be displayed, in seconds.
  ;ForceAppsClosed
  ;  If this parameter is TRUE, forces all open applications to close.
  ;RebootAfterShutdown
  ;  If this parameter is TRUE, the computer is to restart immediately after shutting down.
  ;
  ;Return value :
  ;  If the function succeeds, the return value is zero.
  ;  If the wrong OS is used the function returns -1.
  ;  If the function fails, the return value is an system error code.
  
  Protected AdvapiDLL,*Msg,Privilege.s,Res.l=0
  
  ;Test OK on WinNT4 - SP6 / WinXP - SP2
  If OSVersion()=#PB_OS_Windows_95 Or OSVersion()=#PB_OS_Windows_98 Or OSVersion()=#PB_OS_Windows_ME
    ProcedureReturn -1
  EndIf
  
  If UCase(MachineName$)=UCase(Hostname()) Or MachineName$=""
    Privilege = #SE_SHUTDOWN_NAME
  Else
    Privilege = #SE_REMOTE_SHUTDOWN_NAME
  EndIf
  
  If IPF_EnablePrivilege(Privilege)
    AdvapiDLL=OpenLibrary(#PB_Any,"Advapi32.dll")
    If AdvapiDLL
      *Machine=0
      If MachineName$<>""
        *Machine=@MachineName$
      EndIf
      *Msg=0
      If Message$<>""
        *Msg=@Message$
      EndIf
      
      CompilerIf #PB_Compiler_Unicode
        Res=CallFunction(AdvapiDLL,"InitiateSystemShutdownW",*Machine,*Msg,Timeout,ForceAppsClosed,RebootAfterShutdown)
      CompilerElse
        Res=CallFunction(AdvapiDLL,"InitiateSystemShutdownA",*Machine,*Msg,Timeout,ForceAppsClosed,RebootAfterShutdown)
      CompilerEndIf
      
      If Res
        Res=0
      Else
        Res=GetLastError_()
      EndIf
      
      CloseLibrary(AdvapiDLL)
    EndIf
    IPF_EnablePrivilege(Privilege,0)
  Else
    Res=GetLastError_()
  EndIf
  
  ProcedureReturn Res
EndProcedure

Procedure.l AbortSystemShutdown(MachineName$="")
  ;AbortSystemShutdown Function
  ;http://msdn2.microsoft.com/en-us/library/aa376630.aspx
  
  ;ABBKlaus on 17.11.2007
  ;
  ;Usage :
  ;
  ;Err.l=AbortSystemShutdown([MachineName$])
  ;
  ;Parameters :
  ;
  ;MachineName$
  ;  The network name of the computer where the shutdown is to be stopped.
  ;  If lpMachineName is an empty string, the function stops the shutdown on the local computer.
  ;
  ;Return value :
  ;  If the function succeeds, the return value is zero.
  ;  If the wrong OS is used the function returns -1.
  ;  If the function fails, the return value is an system error code.
   
  Protected AdvapiDLL,Privilege.s,Res.l=0
  
  ;Test OK on WinNT4 - SP6 / WinXP - SP2
  If OSVersion()=#PB_OS_Windows_95 Or OSVersion()=#PB_OS_Windows_98 Or OSVersion()=#PB_OS_Windows_ME
    ProcedureReturn -1
  EndIf
  
  If UCase(MachineName$)=UCase(Hostname()) Or MachineName$=""
    Privilege = #SE_SHUTDOWN_NAME
  Else
    Privilege = #SE_REMOTE_SHUTDOWN_NAME
  EndIf
  
  If IPF_EnablePrivilege(Privilege)
    AdvapiDLL=OpenLibrary(#PB_Any,"Advapi32.dll")
    If AdvapiDLL
      *Machine=0
      If MachineName$<>""
        *Machine=@MachineName$
      EndIf
      
      CompilerIf #PB_Compiler_Unicode
        Res=CallFunction(AdvapiDLL,"AbortSystemShutdownW",*Machine)
      CompilerElse
        Res=CallFunction(AdvapiDLL,"AbortSystemShutdownA",*Machine)
      CompilerEndIf
      
      If Res
        Res=0
      Else
        Res=GetLastError_()
      EndIf
      
      CloseLibrary(AdvapiDLL)
    EndIf
    IPF_EnablePrivilege(Privilege,0)
  Else
    Res=GetLastError_()
  EndIf
  
  ProcedureReturn Res
EndProcedure

; Demo code
MachineName$=""
Message$="PureBasic shutdown test"
Timeout.l=10
ForceAppsClosed.b=1
RebootAfterShutdown.b=1
Res=InitiateSystemShutdown(MachineName$,Message$,Timeout,ForceAppsClosed,RebootAfterShutdown)
If Res=0
  Delay(1000)
  If AbortSystemShutdown(MachineName$)
    Debug GetLastError(Res)
  EndIf
Else
  Debug GetLastError(Res)
EndIf
[Edit]
- added descriptions of the routines
- added debug output when an error occurs

Posted: Sat Nov 17, 2007 11:11 pm
by Kwai chang caine
Hello AbbKlaus

Great code 8)
It's work fine under my computer, but i try to work it under a computer of my network and he don't works :cry:
Perhaps a problem of authorization :roll:
The two computer is in XP sp2

Posted: Sun Nov 18, 2007 2:10 pm
by ABBKlaus
Kwaï chang caïne wrote:Hello AbbKlaus

Great code 8)
It's work fine under my computer, but i try to work it under a computer of my network and he don't works :cry:
Perhaps a problem of authorization :roll:
The two computer is in XP sp2
Hello Kwaï chang caïne,

i changed my above code to be more precise when an error occurs.

Maybe that helps you find out why its not working on one of your computers :wink:

Regards Klaus

Posted: Mon Nov 19, 2007 10:13 am
by Kwai chang caine
Thanks a lot 8)

Let me test your new code tomorrow.
And I give you news

Posted: Thu Nov 22, 2007 12:43 pm
by Kwai chang caine
Hello

I try your code to a network of my job.
It don't works :cry:
The message debugger is "The network path was not found" in french
Perhaps a problem of proxy or server. :?

The code is just work if i give the name of my computer.
It is a pity, but it's not serious. :wink:

Thanks 8)