A Windows service that start a GUI application launcher
in System Administrator mode. purebasic code.
Download (rename to .rar and use purebasic as password)
Files below: Able.exe service code - SysAdminExec.exe launcher code - .rc resource file - .xml manifest file
Able.exe service code.
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; * A Windows service that can launch a GUI application in System Administrator mode. *
; * *
; * Compiler used: PureBasic 5.62 32/64 - Tested under Windows 7 and Windows 10 *
; * *
; * The exe produced is a service named "Able.exe" that react to those parameters: *
; * /Install ; To install the service so Windows is aware of it. *
; * /Uninstall ; To uninstall the service. It must have been stopped before. *
; * /Status ; Call Service Manager to get the current service state. *
; * /Help ; Show these command line switch *
; * /? ; Show these command line switch *
; * *
; * To install, start a command window as Administrator and type "Able /Install". *
; * You can Start/Stop/Pause/Continue the service via the Service Manager, *
; * to start it click Start button, choose Execute and type "Services.msc". *
; * You can also act at the command prompt: *
; * "Net start Able" *
; * "Net stop Able" *
; * "Net pause Able" *
; * "Net continue Able" *
; * *
; * If you set #Debug to TRUE in code you will need a DebugView utility *
; * running in "Global capture" mode started as Administrator. *
; * This is great to see what the service is doing and for debugging. *
; * You can download one from Microsoft or CobaltFusion: *
; * https://docs.microsoft.com/en-us/sysinternals/downloads/debugview *
; * https://github.com/CobaltFusion/DebugViewPP/releases *
; * See in code for #DelayedStart, #RunAsSystemAdmin, and #AutoStop options. *
; * *
; * Once started, with #RunAsSystemAdmin = #True, *
; * the service, bypassing UAC, will start SysAdminExec.exe in the System Administrator mode, *
; * this is more powerfull than the Administrator mode, be carefull of what you do. *
; * Of course, you may alter the code to start some other applications. *
; * *
; * In Regedit, as System Admin, you will see subkeys like *
; * HKLM\SECURITY\Sam\* (Cache-Policy-Recovery-RXACT-SAM), you won't see this in normal Administrator mode. *
; * *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; * Update 2020-05-22 (Search code for "2020-05-22") 1.0.0.1 *
; * Added SERVICE_CONTROL_SESSIONCHANGE session change notifications, logon/logoff/sessionLock/unLock *
; * RegisterServiceCtrlHandlerEX() replace RegisterServiceCtrlHandler() *
; * Added a log file, see #Log. *
; * Also many minors enhencements and corrections. *
; * *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; * Update 2021-07-18 *
; * Minors corrections. *
; * *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Normal folder for Windows service is System32, I do not care about this in the current demo.
; In memory problem, try to start Task Manager / Process (Check All users) / Right click "Able" and stop the process.
; Calling order...
; WinMain()
; serviceInstall /install
; serviceUnInstall /uninstall
; serviceQueryServiceStatus /status
; serviceSetServiceStatus
; ServiceMain
; serviceHandlerEx
; serviceSetServiceStatus
; serviceThreadCreate() ;Start the service
; serviceThread
; RunAsSystemAdmin
; serviceTerminate
; serviceSetServiceStatus
EnableExplicit
#PB_Compiler_OS = #PB_OS_Windows
#PB_Compiler_Processor = #PB_Processor_x64
#PB_Compiler_ExecutableFormat = #PB_Compiler_Console
;#PB_Compiler_Filename = "Able.exe"
;************************************************************************************************************************************************
#Version = "2021-07-18 01:00:01" ;"" *
#AppName = "Able" ;Dictionary: able - ?^bl, adjective having enough strength, power or means (To do a thing). *
#Log = #True ;#False #True - Write to a .log file, path and name are the same as the service name. *
#Debug = #True ;#False #True - See service called procedure and progress in a DebugView utility, must be in CAPTURE GLOBAL mode. *
#DelayedStart = #False ;#False #True - To boot faster Windows will start the service after boot up is completely finished. *
#RunAsSystemAdmin = #True ;#False #True - Start the GUI application SysAdminExec.exe with the powerfull SystemAdmin privilege. *
#AutoStop = #False ;#False #True - Service stop by itself after RunAsSystemAdmin *
;************************************************************************************************************************************************
Declare.l WinMain()
Declare serviceInstall()
Declare serviceUninstall()
Declare.l serviceQueryServiceStatus(sServer.s, sService.s)
Declare.s serviceStringType(dwServiceType.l)
Declare.s serviceStringStatus(dwServiceStatus.l)
Declare.s serviceStringControlIsAccepted(dwControlAccepted.l)
Declare.s serviceStringControl(dwServiceControl.l)
Declare serviceMain(dwArgs.l, lpszArgv.i)
Declare serviceThreadCreate()
Declare.l serviceHandlerEx(ControlValue.l, dwEventType.l, lpEventData.l, lpContext.l)
Declare serviceThread(idThread.l)
Declare serviceSetServiceStatus(CurrentStatus.l, ExitCode.l, SpecificExitCode.l, Checkpoint.l, WaitHint.l)
Declare servicePause()
Declare serviceResume()
Declare serviceStop()
Declare serviceStopRaw()
Declare serviceTerminate(ErrorCode.l)
Declare.l RunAsSystemAdmin(sExeName.s)
Declare StdOut(Text.s)
Declare.l LogWrite(Text.s)
#SERVICES_ACTIVE_DATABASE = "ServicesActive"
#MAX_SERVICE_NAME_LEN = 128
#SERVICE_ADAPTER = $4
#SERVICE_RECOGNIZER_DRIVER = $8
#SERVICE_USER_OWN_PROCESS = $50
#SERVICE_USER_SHARE_PROCESS = $60
#SERVICE_INTERACTIVE_PROCESS = $100
#SERVICE_CONTROL_PARAMCHANGE = $06
#SERVICE_CONTROL_NETBINDADD = $07
#SERVICE_CONTROL_NETBINDREMOVE = $08
#SERVICE_CONTROL_NETBINDENABLE = $09
#SERVICE_CONTROL_NETBINDDISABLE = $0A
#SERVICE_CONTROL_DEVICEEVENT = $0B
#SERVICE_CONTROL_HARDWAREPROFILECHANGE = $0C
#SERVICE_CONTROL_POWEREVENT = $0D
#SERVICE_CONTROL_SESSIONCHANGE = $0E
#SERVICE_CONTROL_PRESHUTDOWN = $0F
#SERVICE_CONTROL_TIMECHANGE = $10
#SERVICE_CONTROL_TRIGGEREVENT = $20
#SERVICE_CONTROL_USERMODEREBOOT = $40
#WTS_SESSION_LOGON = $5
#WTS_SESSION_LOGOFF = $6
#WTS_SESSION_LOCK = $7
#WTS_SESSION_UNLOCK = $8
#TokenPrimary = 1
#NameSamCompatible = 2
#WTS_CONSOLE_CONNECT = $1 ;The session identified by lParam was connected to the console terminal or RemoteFX session.
#WTS_CONSOLE_DISCONNECT = $2 ;The session identified by lParam was disconnected from the console terminal or RemoteFX session.
#WTS_REMOTE_CONNECT = $3 ;The session identified by lParam was connected to the remote terminal.
#WTS_REMOTE_DISCONNECT = $4 ;The session identified by lParam was disconnected from the remote terminal.
#WTS_SESSION_LOGON = $5 ;A user has logged on to the session identified by lParam.
#WTS_SESSION_LOGOFF = $6 ;A user has logged off the session identified by lParam.
#WTS_SESSION_LOCK = $7 ;The session identified by lParam has been locked.
#WTS_SESSION_UNLOCK = $8 ;The session identified by lParam has been unlocked.
#WTS_SESSION_REMOTE_CONTROL = $9 ;The session identified by lParam has changed its remote controlled status. To determine the status, call GetSystemMetrics and check the SM_REMOTECONTROL metric.
#WTS_SESSION_CREATE = $A ;Reserved for future use.
#WTS_SESSION_TERMINATE = $B ;Reserved for future use.
Structure SERVICE_DELAYED_AUTO_START_INFO
fDelayedAutostart.l ;Delayed autostart flag
EndStructure
Structure WTSSESSION_NOTIFICATION
cbSize.l
dwSessionId.l
EndStructure
Import "Kernel32.lib"
WTSGetActiveConsoleSessionId()
ProcessIdToSessionId(ProcessEntry_th32ProcessID.l, *ProcessSessionId.LONG)
EndImport
Structure GlobalType ;All usefull variables in one place
zComputerName.s{#MAX_COMPUTERNAME_LENGTH + 1}
zServiceName.s{#MAX_SERVICE_NAME_LEN}
zServiceDisplayName.s{#MAX_SERVICE_NAME_LEN}
zExeName.s{#MAX_PATH}
hServiceStatus.i
hInstance.i
hEvent.i
hThread.i
CurrentServiceStatus.l
ServiceIsRunning.l
ServiceIsPaused.l
EndStructure
Global *pg.GlobalType ;A single global pointer to a structure of many needed variables
WinMain() ;Starting point
;_____________________________________________________________________________
Procedure.l WinMain()
Protected g.GlobalType
g\zServiceName = #AppName ;Set the service name and display name
g\zServiceDisplayName = #AppName + " service" ;Viewed in service manager, 256 char
g\hInstance = GetModuleHandle_(0)
Protected ComputerNameLen.l = SizeOf(g\zComputerName)
GetComputerName_(@g\zComputerName, @ComputerNameLen) ;Use "" for default local service
LogWrite(g\zComputerName + " : " + #AppName + " WinMain")
*pg = @g ;Set the GlobalType variable pointer
GetModuleFileName_(g\hInstance, @*pg\zExeName, #MAX_PATH) ;Get exe full name
Protected sCmdLine.s = LCase(ProgramParameter(0))
If FindString(sCmdLine, "/uninstall")
serviceUninstall()
ElseIf FindString(sCmdLine, "/install")
serviceInstall()
ElseIf FindString(sCmdLine, "/status")
serviceQueryServiceStatus(*pg\zComputerName, *pg\zServiceName)
ElseIf FindString(sCmdLine, "/help") | FindString(sCmdLine, "/?")
StdOut(#AppName)
StdOut(" /install")
StdOut(" /uninstall")
StdOut(" /status")
StdOut(" /help")
StdOut(" /?")
StdOut(" Net start " + #AppName)
StdOut(" Net stop " + #AppName)
StdOut(" Net pause " + #AppName)
StdOut(" Net continue " + #AppName)
StdOut(" Services.msc (For Service Manager)")
ElseIf Len(sCmdLine) ;Unknown command
StdOut(" Unknown command! (Try /? for help.)")
Else ;Command line is empty,
Dim ServiceTable.SERVICE_TABLE_ENTRY(1) ;Last entry must be blank
ServiceTable(0)\lpServiceName = @g\zServiceName
ServiceTable(0)\lpServiceProc = @ServiceMain()
LogWrite("WinMain:StartServiceCtrlDispatcher")
;StartServiceCtrlDispatcher_() connects the main thread of a service process to the service control manager,
;which causes the thread to be the service control dispatcher thread for the calling process.
;When Services.msc starts a service, it waits up to 30 sec for the service process to call StartServiceCtrlDispatcher,
;and does not return until all running services in the process have entered the SERVICE_STOPPED
If StartServiceCtrlDispatcher_(@ServiceTable(0))
;Service was started pointing to ServiceMain() and following code will be executed after SERVICE_STOPPED
LogWrite("WinMain:StartServiceCtrlDispatcher done : Stopped_OK")
Else
Protected LastError.l
LastError = GetLastError_() ;Might br ERROR_FAILED_SERVICE_CONTROLLER_CONNECT - ERROR_INVALID_DATA - ERROR_SERVICE_ALREADY_RUNNING
LogWrite("WinMain:StartServiceCtrlDispatcher not done : Error " + Str(LastError))
ExitProcess_(LastError)
EndIf
EndIf
EndProcedure
;_____________________________________________________________________________
#MaximumLogSize = 10240 ;10k
Procedure.l LogWrite(Text.s)
Protected FileName.s{#MAX_PATH}
Protected ByteWrittenCount.l
Protected ByteReadCount.l
Protected FileSizeLo.l
Protected FileSizeHi.l
Protected Ofset.l
Protected hFile.i
Static Writing.l
Protected *Ascii.string
Protected *Data
Protected *DataSecondHalf
If #Debug
OutputDebugString_(Text)
EndIf
If #Log
GetModuleFileName_(0, @FileName, #MAX_PATH)
FileName = Left(FileName, Len(FileName) - 3) + "log"
If Writing = #False
Writing = #True
hFile = CreateFile_(FileName, #GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ | #FILE_SHARE_WRITE | #FILE_SHARE_DELETE,
0, #OPEN_ALWAYS, #FILE_ATTRIBUTE_NORMAL, 0)
If hFile <> #INVALID_HANDLE_VALUE
FileSizeLo = SetFilePointer_(hFile, 0, 0, #FILE_END)
If FileSizeLo > #MaximumLogSize
;Limit file size
SetFilePointer_(hFile, 0, 0, #FILE_BEGIN)
*Data = LocalAlloc_(#LMEM_FIXED, FileSizeLo)
ReadFile_(hFile, *Data, FileSizeLo, @ByteReadCount, #Null)
FileSizeLo = #MaximumLogSize / 2
*DataSecondHalf = *Data + FileSizeLo
While PeekB(*DataSecondHalf - 1) <> 10 ;#LF$
*DataSecondHalf + 1
Ofset + 1 : If Ofset > 100 : Break : EndIf ;Try #LF$ for 100 characters
Wend
FileSizeLo = FileSizeLo - Ofset
SetFilePointer_(hFile, 0, 0, #FILE_BEGIN)
WriteFile_(hFile, *DataSecondHalf, FileSizeLo, @ByteWrittenCount, 0)
LocalFree_(*Data)
EndIf
*Ascii = Ascii(Text + #CRLF$)
WriteFile_(hFile, *Ascii, Len(Text) + 2, @ByteWrittenCount, 0)
FreeMemory(*Ascii)
SetEndOfFile_(hFile)
CloseHandle_(hFile)
EndIf
Writing = #False
EndIf
EndIf
ProcedureReturn(ByteWrittenCount)
EndProcedure
;_____________________________________________________________________________
Procedure.s SesionNotificationString(Notification.l)
Protected sNotification.s
Select Notification
Case #WTS_CONSOLE_CONNECT : sNotification = "WTS_CONSOLE_CONNECT" ;(0x1) The session identified by lParam was connected to the console terminal or RemoteFX session.
Case #WTS_CONSOLE_DISCONNECT : sNotification = "WTS_CONSOLE_DISCONNECT" ;(0x2) The session identified by lParam was disconnected from the console terminal or RemoteFX session.
Case #WTS_REMOTE_CONNECT : sNotification = "WTS_REMOTE_CONNECT" ;(0x3) The session identified by lParam was connected to the remote terminal.
Case #WTS_REMOTE_DISCONNECT : sNotification = "WTS_REMOTE_DISCONNECT" ;(0x4) The session identified by lParam was disconnected from the remote terminal.
Case #WTS_SESSION_LOGON : sNotification = "WTS_SESSION_LOGON" ;(0x5) A user has logged on to the session identified by lParam.
Case #WTS_SESSION_LOGOFF : sNotification = "WTS_SESSION_LOGOFF" ;(0x6) A user has logged off the session identified by lParam.
Case #WTS_SESSION_LOCK : sNotification = "WTS_SESSION_LOCK" ;(0x7) The session identified by lParam has been locked.
Case #WTS_SESSION_UNLOCK : sNotification = "WTS_SESSION_UNLOCK" ;(0x8) The session identified by lParam has been unlocked.
Case #WTS_SESSION_REMOTE_CONTROL : sNotification = "WTS_SESSION_REMOTE_CONTROL" ;(0x9) The session identified by lParam has changed its remote controlled status. To determine the status, call GetSystemMetrics and check the SM_REMOTECONTROL metric.
Case #WTS_SESSION_CREATE : sNotification = "WTS_SESSION_CREATE" ;(0xA) Reserved for future use.
Case #WTS_SESSION_TERMINATE : sNotification = "WTS_SESSION_TERMINATE" ;(0xB) Reserved for future use.
Default : sNotification = "WTS_SESSION_UNKNOWN" ;
EndSelect
ProcedureReturn(sNotification + " (0x" + Hex(Notification) + ")")
EndProcedure
;______________________________________________________________________________
Procedure.s serviceStringControlIsAccepted(dwControlAccepted.l)
Protected sCtrlAccept.s
If dwControlAccepted & #SERVICE_ACCEPT_STOP : sCtrlAccept + "SERVICE_ACCEPT_STOP, " : EndIf ;0x001
If dwControlAccepted & #SERVICE_ACCEPT_PAUSE_CONTINUE : sCtrlAccept + "SERVICE_ACCEPT_PAUSE_CONTINUE, " : EndIf ;0x002
If dwControlAccepted & #SERVICE_ACCEPT_SHUTDOWN : sCtrlAccept + "SERVICE_ACCEPT_SHUTDOWN, " : EndIf ;0x004
If dwControlAccepted & #SERVICE_ACCEPT_PARAMCHANGE : sCtrlAccept + "SERVICE_ACCEPT_PARAMCHANGE, " : EndIf ;0x008
If dwControlAccepted & #SERVICE_ACCEPT_NETBINDCHANGE : sCtrlAccept + "SERVICE_ACCEPT_NETBINDCHANGE, " : EndIf ;0x010
If dwControlAccepted & #SERVICE_ACCEPT_PRESHUTDOWN : sCtrlAccept + "SERVICE_ACCEPT_PRESHUTDOWN, " : EndIf ;0x100
If dwControlAccepted = 0 : sCtrlAccept = "Service not started, " : EndIf ;0x000
If Len(sCtrlAccept) = 0 : sCtrlAccept = "SERVICE_ACCEPT_UNKNOWN--" : EndIf ;
ProcedureReturn(Left(sCtrlAccept, Len(sCtrlAccept) - 2) + " (0x" + Hex(dwControlAccepted) + ")")
EndProcedure
;_____________________________________________________________________________
Procedure.s serviceStringType(dwServiceType.l)
Protected sServiceType.s
If dwServiceType & #SERVICE_KERNEL_DRIVER : sServiceType + "SERVICE_KERNEL_DRIVER, " : EndIf ;0x001
If dwServiceType & #SERVICE_FILE_SYSTEM_DRIVER : sServiceType + "SERVICE_FILE_SYSTEM_DRIVER, " : EndIf ;0x002
If dwServiceType & #SERVICE_ADAPTER : sServiceType + "SERVICE_ADAPTER, " : EndIf ;0x004
If dwServiceType & #SERVICE_RECOGNIZER_DRIVER : sServiceType + "SERVICE_RECOGNIZER_DRIVER, " : EndIf ;0x008
If dwServiceType & #SERVICE_WIN32_OWN_PROCESS : sServiceType + "SERVICE_WIN32_OWN_PROCESS, " : EndIf ;0x010
If dwServiceType & #SERVICE_WIN32_SHARE_PROCESS : sServiceType + "SERVICE_WIN32_SHARE_PROCESS, " : EndIf ;0x020
If dwServiceType & #SERVICE_USER_OWN_PROCESS : sServiceType + "SERVICE_USER_OWN_PROCESS, " : EndIf ;0x050
If dwServiceType & #SERVICE_USER_SHARE_PROCESS : sServiceType + "SERVICE_USER_SHARE_PROCESS, " : EndIf ;0x060
If dwServiceType & #SERVICE_INTERACTIVE_PROCESS : sServiceType + "SERVICE_INTERACTIVE_PROCESS, " : EndIf ;0x100
If Len(sServiceType) = 0 : sServiceType = "SERVICE_TYPE_UNKNOWN--" : EndIf ;
ProcedureReturn(Left(sServiceType, Len(sServiceType) - 2) + " (0x" + Hex(dwServiceType) + ")")
EndProcedure
;_____________________________________________________________________________
Procedure.s serviceStringStatus(dwServiceStatus.l)
Protected sServiceStatus.s
Select dwServiceStatus
Case #SERVICE_STOPPED : sServiceStatus = "SERVICE_STOPPED" ;1 The service is not running.
Case #SERVICE_START_PENDING : sServiceStatus = "SERVICE_START_PENDING" ;2 The service is starting.
Case #SERVICE_STOP_PENDING : sServiceStatus = "SERVICE_STOP_PENDING" ;3 The service is stopping.
Case #SERVICE_RUNNING : sServiceStatus = "SERVICE_RUNNING" ;4 The service is running.
Case #SERVICE_CONTINUE_PENDING : sServiceStatus = "SERVICE_CONTINUE_PENDING" ;5 The service continue is pending.
Case #SERVICE_PAUSE_PENDING : sServiceStatus = "SERVICE_PAUSE_PENDING" ;6 The service pause is pending.
Case #SERVICE_PAUSED : sServiceStatus = "SERVICE_PAUSED" ;7 The service is paused.
Default : sServiceStatus = "SERVICE_STATUS_UNKNOWN" ;
EndSelect
ProcedureReturn(sServiceStatus + " (" + Str(dwServiceStatus) + ")")
EndProcedure
;_____________________________________________________________________________
Procedure.s serviceStringControl(dwServiceControl.l)
Protected sServiceControl.s
Select dwServiceControl
Case #SERVICE_CONTROL_STOP : sServiceControl = "SERVICE_CONTROL_STOP" ;0x01 Notifies a service that it should stop.
Case #SERVICE_CONTROL_PAUSE : sServiceControl = "SERVICE_CONTROL_PAUSE" ;0x02 Notifies a service that it should pause.
Case #SERVICE_CONTROL_CONTINUE : sServiceControl = "SERVICE_CONTROL_CONTINUE" ;0x03 Notifies a paused service that it should resume.
Case #SERVICE_CONTROL_INTERROGATE : sServiceControl = "SERVICE_CONTROL_INTERROGATE" ;0x04 Notifies a service to report its current status
Case #SERVICE_CONTROL_SHUTDOWN : sServiceControl = "SERVICE_CONTROL_SHUTDOWN" ;0x05 Notifies a service to report its current status
Case #SERVICE_CONTROL_PARAMCHANGE : sServiceControl = "SERVICE_CONTROL_PARAMCHANGE" ;0x06 Notifies a service that service-specific startup parameters have changed.
Case #SERVICE_CONTROL_NETBINDADD : sServiceControl = "SERVICE_CONTROL_NETBINDADD" ;0x07 Notifies a network service that there is a new component for binding.
Case #SERVICE_CONTROL_NETBINDREMOVE : sServiceControl = "SERVICE_CONTROL_NETBINDREMOVE" ;0x08 Notifies a network service that a component for binding has been removed.
Case #SERVICE_CONTROL_NETBINDENABLE : sServiceControl = "SERVICE_CONTROL_NETBINDENABLE" ;0x09 Notifies a network service that a disabled binding has been enabled.
Case #SERVICE_CONTROL_NETBINDDISABLE : sServiceControl = "SERVICE_CONTROL_NETBINDDISABLE" ;0x0A Notifies a network service that one of its bindings has been disabled.
Case #SERVICE_CONTROL_DEVICEEVENT : sServiceControl = "SERVICE_CONTROL_DEVICEEVENT" ;0x0B Notifies a service of device events.
Case #SERVICE_CONTROL_HARDWAREPROFILECHANGE : sServiceControl = "SERVICE_CONTROL_HARDWAREPROFILECHANGE" ;0x0C Notifies a service that the computer's hardware profile has changed.
Case #SERVICE_CONTROL_POWEREVENT : sServiceControl = "SERVICE_CONTROL_POWEREVENT" ;0x0D Notifies a service of system power events.
Case #SERVICE_CONTROL_SESSIONCHANGE : sServiceControl = "SERVICE_CONTROL_SESSIONCHANGE" ;0x0E Notifies a service of session change events.
Case #SERVICE_CONTROL_PRESHUTDOWN : sServiceControl = "SERVICE_CONTROL_PRESHUTDOWN" ;0x0F Notifies a service that the system will be shutting down.
Case #SERVICE_CONTROL_TIMECHANGE : sServiceControl = "SERVICE_CONTROL_TIMECHANGE" ;0x10 Notifies a service that the system time has changed.
Case #SERVICE_CONTROL_TRIGGEREVENT : sServiceControl = "SERVICE_CONTROL_TRIGGEREVENT" ;0x20 Notifies a service registered for a service trigger event that the event has occurred.
Case #SERVICE_CONTROL_USERMODEREBOOT : sServiceControl = "SERVICE_CONTROL_USERMODEREBOOT" ;0x40 Notifies a service that the user has initiated a reboot.
Default : sServiceControl = "SERVICE_CONTROL_UNKNOWN" ;
EndSelect
ProcedureReturn(sServiceControl + " (0x" + Hex(dwServiceControl) + ")")
EndProcedure
;_____________________________________________________________________________
Procedure.l serviceQueryServiceStatus(sServer.s, sService.s)
Protected ServiceStat.SERVICE_STATUS
Protected hScManager.i
Protected hService.i
Protected LastError.l
LogWrite("serviceQueryServiceStatus")
hScManager = OpenSCManager_(@sServer, #SERVICES_ACTIVE_DATABASE, #SC_MANAGER_ENUMERATE_SERVICE)
If hScManager
hService = OpenService_(hScManager, @sService, #SC_MANAGER_ENUMERATE_SERVICE)
LastError = GetLastError_()
If hService
If QueryServiceStatus_(hService, @ServiceStat)
StdOut(" Server: " + sServer)
StdOut(" Service: " + sService)
StdOut(" CurrentState: " + serviceStringStatus(ServiceStat\dwCurrentState))
StdOut(" ServiceType: " + serviceStringType(ServiceStat\dwServiceType))
StdOut(" ControlsAccepted: " + serviceStringControlIsAccepted(ServiceStat\dwControlsAccepted))
StdOut(" Win32ExitCode: " + Str(ServiceStat\dwWin32ExitCode))
StdOut(" SpecificExitCode: " + Str(ServiceStat\dwServiceSpecificExitCode))
StdOut(" CheckPoint: " + Str(ServiceStat\dwCheckPoint))
StdOut(" WaitHint: " + Str(ServiceStat\dwWaitHint))
EndIf
CloseServiceHandle_(hService)
Else
Select LastError
Case #ERROR_SERVICE_DOES_NOT_EXIST : StdOut(" Service " + sService + " : ERROR_SERVICE_DOES_NOT_EXIST")
Case #ERROR_INVALID_NAME : StdOut(" Service " + sService + " : ERROR_INVALID_NAME")
Case #ERROR_ACCESS_DENIED : StdOut(" Service " + sService + " : ERROR_ACCESS_DENIED")
Case #ERROR_INVALID_HANDLE : StdOut(" Service " + sService + " : ERROR_INVALID_HANDLE")
Default : StdOut(" Service " + sService + " : ERROR 0x" + Hex(LastError))
EndSelect
EndIf
CloseServiceHandle_(hScManager)
Else
StdOut(" serviceQueryServiceStatus:OpenSCManager failed")
EndIf
ProcedureReturn(ServiceStat\dwCurrentState)
EndProcedure
;_____________________________________________________________________________
Procedure.l RunAsSystemAdmin(sExeName.s)
;Launches the given application with full system admin rights bypassing the UAC prompt
;sExeName The name of the application to launch
Static zWinSta0.s{20}
Protected ProcessInfo.PROCESS_INFORMATION
Protected ProcessEntry.PROCESSENTRY32
Protected SecurityAttributes.SECURITY_ATTRIBUTES
Protected StartupInf.STARTUPINFO
Protected ProcessSessionId.l
Protected hUserTokenDup.i
Protected hProcess.i
Protected hProcessSnapshot.i
Protected hProcessToken.i
Protected SessionId.l
Protected CreationFlags.l
Protected RetValProc.l
Protected CreateProcessResult.l
LogWrite("RunAsSystemAdmin")
;Obtain the currently active session id; every logged on user in the system has a unique session id
SessionId = WTSGetActiveConsoleSessionId() ;Get the session-id of the console session: SessionId = 1 Console Active UserName or 0 Services Disconnected ""
If SessionId <> #INVALID_HANDLE_VALUE
;Get the ProcessId of the WinLogon that have the same SessionId as the User's dwSessionId
;Obtain the process id of the winlogon process that is running within the currently active session
LogWrite("RunAsSystemAdmin:SessionId:OK")
hProcessSnapshot = CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS | #TH32CS_SNAPTHREAD, #Null)
If hProcessSnapshot <> #INVALID_HANDLE_VALUE
LogWrite("RunAsSystemAdmin:hProcessSnapshot:OK")
ProcessEntry\dwSize = SizeOf(PROCESSENTRY32)
RetValProc = Process32First_(hProcessSnapshot, @ProcessEntry)
While RetValProc
Protected *BStr
Protected *BStrData.String
*BStr = @ProcessEntry\szExeFile
*BStrData.String = @*BStr
If LCase(*BStrData\s) = "winlogon.exe" ;May be more than one
LogWrite("RunAsSystemAdmin:winlogon:OK")
ProcessIdToSessionId(ProcessEntry\th32ProcessID, @ProcessSessionId) ;Process session id RunAsAdmin for winlogon, return nonzero on success
If ProcessSessionId = SessionId ;Need WinLogOn sessionId like in TaskManager
;Obtain a handle to the winlogon process
LogWrite("RunAsSystemAdmin:ProcessSessionId:OK")
hProcess = OpenProcess_(#MAXIMUM_ALLOWED, #False, ProcessEntry\th32ProcessID)
If hProcess
LogWrite("RunAsSystemAdmin:OpenProcess_:OK")
If OpenProcessToken_(hProcess, #TOKEN_DUPLICATE, @hProcessToken)
LogWrite("RunAsSystemAdmin:OpenProcessToken_:OK")
;Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
SecurityAttributes\nLength = SizeOf(SECURITY_ATTRIBUTES)
;Copy the access token of the winlogon process, the newly created token will be a primary token
If DuplicateTokenEx_(hProcessToken, #MAXIMUM_ALLOWED, @SecurityAttributes, #SecurityIdentification,
#TokenPrimary, @hUserTokenDup)
LogWrite("RunAsSystemAdmin:DuplicateTokenEx_:OK")
;By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
;the window station has a desktop that is invisible and the process is incapable of receiving
;user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
;interaction with the new process.
zWinSta0 = "winsta0\default"
StartupInf\lpDesktop = @zWinSta0 ;Interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop
StartupInf\cb = SizeOf(STARTUPINFO)
;Flags that specify the priority and creation method of the process
CreationFlags = #NORMAL_PRIORITY_CLASS | #CREATE_NEW_CONSOLE
LogWrite("RunAsSystemAdmin:sExeName: " + sExeName)
Protected zCurDir.s{#MAX_PATH}
If FindString(sExeName, "\")
zCurDir = Left(sExeName, Len(sExeName) - FindString(ReverseString(sExeName), "\"))
Else
EndIf
LogWrite("RunAsSystemAdmin:zCurDir: " + zCurDir)
LogWrite("RunAsSystemAdmin:CreateProcessAsUser")
;Create a new process in the current user's logon session, Ok if return TRUE
;RegEdit/Admin can't see HKEY_LOCAL_MACHINE\SECURITY\* (Cache-Policy-Recovery-RXACT-SAM)
;RegEdit/SystemAdmin can see HKEY_LOCAL_MACHINE\SECURITY\* (Cache-Policy-Recovery-RXACT-SAM)
CreateProcessResult = CreateProcessAsUser_(hUserTokenDup, ;Client's access token
#Null, ;File to execute
@sExeName, ;Command line
@SecurityAttributes, ;Pointer to process SECURITY_ATTRIBUTES
@SecurityAttributes, ;Pointer to thread SECURITY_ATTRIBUTES
#False, ;Handles are not inheritable
CreationFlags, ;Creation flags
#Null, ;Pointer to new environment block
@zCurDir, ;BYVAL %NULL, _ 'Name of current directory
@StartupInf, ;Pointer to STARTUPINFO structure
@ProcessInfo) ;Receives information about new process
LogWrite("RunAsSystemAdmin:CreateProcessAsUser = " + Str(CreateProcessResult) + " (True = success)")
If CreateProcessResult = 0
LogWrite("GetLastError = " + Str(GetLastError_()))
EndIf
CloseHandle_(hUserTokenDup)
EndIf
CloseHandle_(hProcessToken)
EndIf
CloseHandle_(hProcess)
EndIf
Break ;Job done
EndIf
EndIf
RetValProc = Process32Next_(hProcessSnapshot, @ProcessEntry)
Wend
CloseHandle_(hProcessSnapshot)
EndIf
EndIf
ProcedureReturn(CreateProcessResult)
EndProcedure
;_____________________________________________________________________________
Procedure serviceInstall()
Protected ServiceDelayed.SERVICE_DELAYED_AUTO_START_INFO
Protected ServiceDesc.SERVICE_DESCRIPTION
Protected sServiceDescription.s
Protected hServiceControlManager.i
Protected hService.i
Protected JobDone.l
LogWrite("serviceInstall()")
hServiceControlManager = OpenSCManager_(@*pg\zComputerName, #Null, #SC_MANAGER_CREATE_SERVICE)
If hServiceControlManager
hService = CreateService_(hServiceControlManager, @*pg\zServiceName, @*pg\zServiceDisplayName,
#SERVICE_ALL_ACCESS, #SERVICE_WIN32_OWN_PROCESS | #SERVICE_INTERACTIVE_PROCESS,
#SERVICE_AUTO_START, #SERVICE_ERROR_NORMAL, @*pg\zExeName, #Null, #Null,
#Null, #Null, #Null) ;SERVICE_DEMAND_START SERVICE_ERROR_IGNORE
If hService
ChangeServiceConfig_(hService, #SERVICE_NO_CHANGE, #SERVICE_AUTO_START,
#SERVICE_ERROR_NORMAL, #NUL, #NUL, 0, #NUL, #NUL, #NUL, #NUL)
sServiceDescription = #AppName + " start a GUI as SYSTEM Administrator." ;1024 bytes
ServiceDesc\lpDescription = @sServiceDescription
ChangeServiceConfig2_(hService, #SERVICE_CONFIG_DESCRIPTION, @ServiceDesc)
If #DelayedStart ;Delayed service start, giving Windows time to breath on starting
ServiceDelayed\fDelayedAutostart = #True
ChangeServiceConfig2_(hService, #SERVICE_CONFIG_DELAYED_AUTO_START_INFO, @ServiceDelayed)
EndIf
StdOut("Service install successfull.")
JobDone = #True
CloseServiceHandle_(hService)
Else
StdOut("Install - CreateService : Error.")
EndIf
CloseServiceHandle_(hServiceControlManager)
Else
StdOut("Install - OpenSCManager : Error.")
StdOut("Need to be run as admin.")
EndIf
ProcedureReturn(JobDone)
EndProcedure
;_____________________________________________________________________________
Procedure serviceUnInstall()
Protected hServiceControlManager.i
Protected hService.i
Protected JobDone.l
LogWrite("serviceUnInstall()")
hServiceControlManager = OpenSCManager_(*pg\zComputerName, #Null, #SC_MANAGER_CREATE_SERVICE)
If hServiceControlManager
hService = OpenService_(hServiceControlManager, *pg\zServiceName, #SERVICE_ALL_ACCESS)
If hService
If DeleteService_(hService)
StdOut("Uninstall successfull.")
JobDone = #True
Else
StdOut("Uninstall - DeleteService : Error.")
EndIf
CloseServiceHandle_(hService)
Else
StdOut("Uninstall - OpenService : Error.")
EndIf
CloseServiceHandle_(hServiceControlManager)
Else
StdOut("Uninstall - OpenSCManager : Error.")
EndIf
ProcedureReturn(JobDone)
EndProcedure
;_____________________________________________________________________________
Procedure serviceMain(dwArgs.l, lpszArgv.i)
;dwArgc The number of arguments in the lpszArgv array.
;lpszArgv The null-terminated argument strings passed to the service by the call to the StartService function
; that started the service. If there are no arguments, this parameter can be NULL.
; Otherwise, the first argument (lpszArgv[0]) is the name of the service, followed
; by any additional arguments (lpszArgv[1] through lpszArgv[dwArgc-1]).
; If the user starts a manual service using the Services snap-in from the Control Panel,
; the strings for the lpszArgv parameter come from the properties dialog box
; for the service (from the Services snap-in, right-click the service entry, click Properties,
; and enter the parameters in Start parameters.)
;All initialization tasks are done in ServiceMain() when the service is started.
Protected SecurityAttribute.SECURITY_ATTRIBUTES
Protected RetVal.l
Protected dwContext.l ;User defined custom value
LogWrite("serviceMain()")
If OpenLibrary(123, "AdvApi32.dll")
*pg\hServiceStatus = CallCFunctionFast(GetFunction(123, "RegisterServiceCtrlHandlerExW"), @*pg\zServiceName, @ServiceHandlerEx(), dwContext)
If *pg\hServiceStatus ;Did Not work
;Startup is pending
If serviceSetServiceStatus(#SERVICE_START_PENDING, #NO_ERROR, 0, 1, 5000)
LogWrite("serviceMain : SERVICE_START_PENDING")
;Create the termination event
*pg\hEvent = CreateEvent_(@SecurityAttribute, #True, #False, "")
If *pg\hEvent
;Service startup is still pending
If serviceSetServiceStatus(#SERVICE_START_PENDING, #NO_ERROR, 0, 2, 1000)
RetVal = serviceThreadCreate() ;Start the service
If RetVal ;Service did start
If serviceSetServiceStatus(#SERVICE_RUNNING, #NO_ERROR, 0, 0, 0) ;Service is now running
;Wait for the signal to end
LogWrite("serviceMain : Service thread started : SERVICE_RUNNING : WaitForSingleObject")
WaitForSingleObject_(*pg\hEvent, #INFINITE)
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
ServiceTerminate(GetLastError_())
CloseLibrary(123)
EndProcedure
;_____________________________________________________________________________
Procedure serviceThreadCreate()
Protected SecurityAttribute.SECURITY_ATTRIBUTES
Protected idThread.l
LogWrite("serviceThreadCreate()")
*pg\hThread = CreateThread_(SecurityAttribute, 0, @ServiceThread(), 0, 0, idThread)
If *pg\hThread ;The thread start OK
*pg\ServiceIsRunning = #True ;Set the global to running
ProcedureReturn(#True)
EndIf
EndProcedure
;_____________________________________________________________________________
Procedure.l serviceHandlerEx(ControlValue.l, dwEventType.l, lpEventData.l, lpContext.l)
LogWrite("serviceHandler(Received request for " + serviceStringControl(ControlValue) + ")")
Select ControlValue
Case #SERVICE_CONTROL_STOP,
#SERVICE_CONTROL_SHUTDOWN,
#CTRL_SHUTDOWN_EVENT
If *pg\ServiceIsPaused ;Resuming before ending
serviceSetServiceStatus(#SERVICE_CONTINUE_PENDING, #NO_ERROR, 0, 1, 1000) ;Tell the SCM that we are resuming
ServiceResume() ;Resume the service
*pg\CurrentServiceStatus = #SERVICE_RUNNING ;Set the current state
EndIf
*pg\CurrentServiceStatus = #SERVICE_STOP_PENDING ;Set global status
serviceSetServiceStatus(#SERVICE_STOP_PENDING, #NO_ERROR, 0, 1, 5000)
ServiceStop()
Case #SERVICE_CONTROL_PAUSE ;0x2 Service should pause.
If (*pg\ServiceIsRunning <> #False) And (*pg\ServiceIsPaused = #False) ;Running And Not paused
serviceSetServiceStatus(#SERVICE_PAUSE_PENDING, #NO_ERROR, 0, 1, 1000) ;Tell the SCM that we are pausing
ServicePause() ;Pause it
*pg\CurrentServiceStatus = #SERVICE_PAUSED ;Set the current state
EndIf
Case #SERVICE_CONTROL_CONTINUE ;0x3 Service should resume
If (*pg\ServiceIsRunning <> #False) And (*pg\ServiceIsPaused <> #False) ;Running and paused
serviceSetServiceStatus(#SERVICE_CONTINUE_PENDING, #NO_ERROR, 0, 1, 1000) ;Tell the SCM that we are resuming
ServiceResume() ;Resume the service
*pg\CurrentServiceStatus = #SERVICE_RUNNING ;Set the current state
EndIf
Case #SERVICE_CONTROL_INTERROGATE ;0x4 Service should report its current status to the control manager
;Simply return NO_ERROR; the SCM is aware of the current state of the service.
ProcedureReturn(#NO_ERROR) ;A return value is needed else the command line "Net Start" will be erratic
Case #SERVICE_CONTROL_SESSIONCHANGE
Protected *pWtSessionNotification.WTSSESSION_NOTIFICATION
*pWtSessionNotification = lpEventData
LogWrite("SERVICE_CONTROL_SESSIONCHANGE : " + SesionNotificationString(dwEventType) + ", SessionId: " + *pWtSessionNotification\dwSessionId)
Select dwEventType
Case #WTS_SESSION_LOGON ;0x5
;LogWrite("WTS_SESSION_LOGON SessionId: " + *pWtSessionNotification\dwSessionId)
Case #WTS_SESSION_LOGOFF ;0x6
;LogWrite("WTS_SESSION_LOGOFF SessionId: " + *pWtSessionNotification\dwSessionId)
Case #WTS_SESSION_LOCK ;0x7
;LogWrite("WTS_SESSION_LOGON SessionId: " + *pWtSessionNotification\dwSessionId)
Case #WTS_SESSION_UNLOCK ;0x8
;LogWrite("WTS_SESSION_UNLOCK SessionId: " + *pWtSessionNotification\dwSessionId)
;WTS_CONSOLE_CONNECT (0x1) The session identified by lParam was connected To the console terminal Or RemoteFX session.
;WTS_CONSOLE_DISCONNECT (0x2) The session identified by lParam was disconnected from the console terminal Or RemoteFX session.
;WTS_REMOTE_CONNECT (0x3) The session identified by lParam was connected To the remote terminal.
;WTS_REMOTE_DISCONNECT (0x4) The session identified by lParam was disconnected from the remote terminal.
;WTS_SESSION_LOGON (0x5) A user has logged on To the session identified by lParam.
;WTS_SESSION_LOGOFF (0x6) A user has logged off the session identified by lParam.
;WTS_SESSION_LOCK (0x7) The session identified by lParam has been locked.
;WTS_SESSION_UNLOCK (0x8) The session identified by lParam has been unlocked.
;WTS_SESSION_REMOTE_CONTROL (0x9) The session identified by lParam has changed its remote controlled status. To determine the status, CALL GetSystemMetrics And check the SM_REMOTECONTROL metric.
;WTS_SESSION_CREATE (0xA) Reserved For future use.
;WTS_SESSION_TERMINATE (0xB) Reserved For future use.
;lParam [IN] The identifier of the session.
EndSelect
EndSelect
serviceSetServiceStatus(*pg\CurrentServiceStatus, #NO_ERROR, 0, 0, 0)
ProcedureReturn(#NO_ERROR)
EndProcedure
;_____________________________________________________________________________
Procedure serviceThread(idThread.l)
;Here goes the service's job...
If #RunAsSystemAdmin
LogWrite("-")
;Show UserNameEx and UserName
Protected zUserName.s{#UNLEN}
Protected UserNameLen.l = #UNLEN
GetUserNameEx_(#NameSamCompatible, @zUserName, @UserNameLen)
LogWrite("UserNameEx: " + zUserName)
GetUserName_(@zUserName, @UserNameLen)
LogWrite("UserName: " + zUserName + " <<<<<<<<<<<<<<<<<<< Should be 'System' (System Administrator).")
;Call SysAdminExec.exe
Protected FullNameExe.s{#MAX_PATH}
FullNameExe = GetPathPart(*pg\zExeName) + "SysAdminExec.exe" ;Set full path name
LogWrite("serviceThread(RunAsSystemAdmin(" + FullNameExe + ")")
RunAsSystemAdmin(FullNameExe)
Sleep_(2000)
EndIf
If #AutoStop
ServiceStopRaw() ;Used when a service want To End by itself after his job is done
Else
Repeat
LogWrite("serviceThread() running " + FormatDate("%hh:%ii:%ss", Date()))
Sleep_(2000)
ForEver
EndIf
EndProcedure
;_____________________________________________________________________________
Procedure serviceSetServiceStatus(CurrentStatus.l, ExitCode.l, ServiceSpecificExitCode.l, Checkpoint.l, WaitHint.l)
LogWrite("serviceSetServiceStatus(" + serviceStringStatus(CurrentStatus) + ")")
Protected ServiceStatus.SERVICE_STATUS
ServiceStatus\dwServiceType = #SERVICE_WIN32_OWN_PROCESS ;Setup the UDT.
ServiceStatus\dwCurrentState = CurrentStatus
If CurrentStatus = #SERVICE_START_PENDING
ServiceStatus\dwControlsAccepted = #SERVICE_ACCEPT_SESSIONCHANGE
Else
ServiceStatus\dwControlsAccepted = #SERVICE_ACCEPT_STOP | #SERVICE_ACCEPT_PAUSE_CONTINUE | #SERVICE_ACCEPT_SHUTDOWN | #SERVICE_ACCEPT_SESSIONCHANGE
EndIf
If ServiceSpecificExitCode = 0
ServiceStatus\dwWin32ExitCode = ExitCode
Else
ServiceStatus\dwWin32ExitCode = #ERROR_SERVICE_SPECIFIC_ERROR
EndIf
ServiceStatus\dwServiceSpecificExitCode = ServiceSpecificExitCode
ServiceStatus\dwCheckPoint = Checkpoint
ServiceStatus\dwWaitHint = WaitHint
If SetServiceStatus_(*pg\hServiceStatus, @ServiceStatus)
ProcedureReturn(#True)
Else ;Something went wrong, so stop the service
ServiceStop()
EndIf
EndProcedure
;_____________________________________________________________________________
Procedure servicePause()
LogWrite("servicePause() " + FormatDate("%hh:%ii:%ss", Date()))
*pg\ServiceIsPaused = #True ;Set the global indicating that we are paused
SuspendThread_(*pg\hThread)
EndProcedure
;_____________________________________________________________________________
Procedure serviceResume()
LogWrite("serviceResume() " + FormatDate("%hh:%ii:%ss", Date()))
*pg\ServiceIsPaused = #False ;Set the global indicating that we are not paused
ResumeThread_(*pg\hThread)
EndProcedure
;_____________________________________________________________________________
Procedure serviceStop()
LogWrite("Service thread stopping at " + FormatDate("%hh:%ii:%ss", Date()))
*pg\ServiceIsRunning = #False ;Set the global flag indicating that the service is not running
SetEvent_(*pg\hEvent) ;Set the event so the service will stop
EndProcedure
;_____________________________________________________________________________
Procedure serviceStopRaw() ;Use when a service want to end by itself
Protected ServiceStat.SERVICE_STATUS
Protected hServiceControlManager.i
Protected hService.i
LogWrite("serviceStopRaw()")
hServiceControlManager = OpenSCManager_(*pg\zComputerName, #Null, #SC_MANAGER_CREATE_SERVICE)
If hServiceControlManager
hService = OpenService_(hServiceControlManager, @*pg\zServiceName, #SERVICE_ALL_ACCESS)
If hService
ControlService_(hService, #SERVICE_CONTROL_STOP, @ServiceStat)
EndIf
CloseServiceHandle_(hServiceControlManager)
EndIf
EndProcedure
;_____________________________________________________________________________
Procedure serviceTerminate(ErrorCode.l)
LogWrite("serviceTerminate()")
If *pg\hEvent
CloseHandle_(*pg\hEvent)
EndIf
If *pg\hServiceStatus
serviceSetServiceStatus(#SERVICE_STOPPED, ErrorCode, 0, 0, 0)
EndIf
If *pg\hThread
CloseHandle_(*pg\hThread)
EndIf
EndProcedure
;_____________________________________________________________________________
Procedure StdOut(Text.s)
Protected CharDone.l
Protected Reserved.l
WriteConsole_(GetStdHandle_(#STD_OUTPUT_HANDLE), Text + #CRLF$, Len(Text) + 2, CharDone, Reserved)
EndProcedure
;_____________________________________________________________________________
;
; IDE Options = PureBasic 5.72 (Windows - x64)
; ExecutableFormat = Console
; CursorPosition = 720
; FirstLine = 841
; Markers = 645,689
; EnableAsm
; EnableThread
; EnableXP
; EnableAdmin
; UseIcon = wmploc.DLL.024.ico
; Executable = Able.exe
; DisableDebugger
; CompileSourceDirectory
; Compiler = PureBasic 5.72 (Windows - x64)
; IncludeVersionInfo
; VersionField0 = 1.0.0.1
; VersionField1 = 1.0.0.1
; VersionField2 = Able
; VersionField3 = Able
; VersionField4 = 1.0.0.1
; VersionField5 = 1.0.0.1
; VersionField6 = Service to start a GUI as SYSTEM Administrator
; VersionField7 = Able
; VersionField8 = Able
; VersionField9 = 2020
; VersionField10 = 2020
; EnableUnicode
SysAdminExec.exe launcher code.
; ********************************************************************************************
; SysAdminExec.exe - A application launcher For the Able Windows service. *
; *
; Detect if User is Administrator or System-Administrator, application icon will follow. *
; Use an .ini file for size, position, and record the last 150 exe launched. *
; Use a mutex for single instance and set self foreground. *
; *
; Enable messages reception from non elevated applications, *
; this may be done with Drag-and-Drop or via the command line. *
; *
; ********************************************************************************************
EnableExplicit
#PB_Compiler_ExecutableFormat = #PB_Compiler_Executable
#PB_Compiler_IsMainFile = 1
#WM_COPYGLOBALDATA = $0049
#ButtonExec = 101
#ComboExeNameList = 201
#StaticAdminInfo = 301
#CRYPT_STRING_HEXRAW = $C
#SECURITY_NT_AUTHORITY = 5
Macro LoWord(WordWord) : (WordWord&$ffff) : EndMacro
Macro HiWord(WordWord) : ((WordWord>>16)&$ffff) : EndMacro
;_____________________________________________________________________________
Procedure.s AsciiToUnicode(sAscii.s)
Protected CharCount.l
Protected sUnicode.s
CharCount = lstrlen_(sAscii) ;Get dual bytes character count
sUnicode = Space(CharCount * 2) ;Initialize string
MultiByteToWideChar_(#CP_ACP, #Null, sAscii, CharCount, @sUnicode, @CharCount)
ProcedureReturn(sUnicode)
EndProcedure
;_____________________________________________________________________________
Procedure.s FileDataGet(sFileName.s)
Protected hFile.l
Protected FileSizeLo.l
Protected FileSizeHi.l
Protected ReturnCount.l
Protected sFileData.s
hFile = CreateFile_(sFileName, #GENERIC_READ, #FILE_SHARE_READ, #Null,
#OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, #Null)
If hFile <> #INVALID_HANDLE_VALUE
FileSizeLo = GetFileSize_(hFile, @FileSizeHi)
sFileData = Space(FileSizeLo)
ReadFile_(hFile, @sFileData, FileSizeLo, @ReturnCount, #Null)
CloseHandle_(hFile)
ProcedureReturn(AsciiToUnicode(sFileData))
EndIf
EndProcedure
;_____________________________________________________________________________
Procedure.l FileDataSet(sFileName.s, sFileData.s)
Protected hFile.l
Protected WrittenCount.l
Protected *aFileData
hFile = CreateFile_(sFileName, #GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ,
#Null, #CREATE_ALWAYS, #FILE_ATTRIBUTE_NORMAL, #Null)
If hFile <> #INVALID_HANDLE_VALUE
*aFileData = Ascii(sFileData)
WriteFile_(hFile, *aFileData, Len(sFileData), @WrittenCount, #Null)
FreeMemory(*aFileData)
SetEndOfFile_(hFile)
CloseHandle_(hFile)
If WrittenCount = Len(sFileData)
ProcedureReturn(#True)
EndIf
EndIf
EndProcedure
;_____________________________________________________________________________
Procedure.l IsUserAdmin()
Protected NtAuthority.SID_IDENTIFIER_AUTHORITY ;6bytes
Protected *AdministratorsGroup
Protected zAutoriteNT.s{#UNLEN}
Protected zSysName.s{#UNLEN}
Protected zCurrentUser.s{#UNLEN}
Protected SidAccountType.l
Protected AutoriteNtLen.l
Protected SysNameLen.l
Protected IsMember.l
Protected AdminLevel.l
;IsUserAnAdmin api may not be there in future Windows release, so doing it following way.
NtAuthority\value[5] = #SECURITY_NT_AUTHORITY ;SECURITY_NT_AUTHORITY = 5
If AllocateAndInitializeSid_(@NtAuthority, 2, #SECURITY_BUILTIN_DOMAIN_RID,
#DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, @*AdministratorsGroup)
If OpenLibrary(125, "AdvApi32.dll")
If CallCFunctionFast(GetFunction(125, "CheckTokenMembership"), #Null, *AdministratorsGroup, @IsMember)
If IsMember
;Is Administrator + System Administrator
;Get SystemAdministatot locale name, will differ with different language
;SID: S-1-5-18 - Local System - "System" - "Syst�me" AUTORITE NT - A service account that is used by the operating system.
Dim SidArray.b(11)
SidArray.b(0) = 1 : SidArray.b(1) = 1 : SidArray.b(0) = 1 : SidArray.b(7) = 5 : SidArray.b(8) = 18 ;Chr(1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0)
SysNameLen = SizeOf(zSysName)
AutoriteNTLen = SizeOf(zAutoriteNT)
If LookupAccountSid_(#Null, @SidArray(0), @zSysName, @SysNameLen, @zAutoriteNT, @AutoriteNtLen, @SidAccountType) ;ok if true
Protected UserNameLen.l = #UNLEN
GetUserName_(@zCurrentUser, @UserNameLen) ;A SysAdm will get locale-System as name
If zCurrentUser = zSysName ;User is SystemAdmin
AdminLevel = 2 ;System-Administrator
Else
AdminLevel = 1 ;Administrator only
EndIf
EndIf
EndIf
EndIf
EndIf
CloseLibrary(125)
FreeSid_(*AdministratorsGroup)
EndIf
ProcedureReturn(AdminLevel)
EndProcedure
;_____________________________________________________________________________
Procedure.l DoShellExecuteEx(hParent.l, zVerb.s, zFile.s, zParam.s, zPath.s, dwShow.l)
Protected ShellInfo.SHELLEXECUTEINFO
If LCase(Right(zFile, 4)) <> ".lnk"
ShellInfo\lpVerb = @zVerb
Else
ShellInfo\lpVerb = #Null
EndIf
ShellInfo\cbSize = SizeOf(ShellInfo)
ShellInfo\hWnd = hParent
ShellInfo\lpFile = @zFile
ShellInfo\lpParameters = @zParam
ShellInfo\lpDirectory = @zPath
ShellInfo\nShow = dwShow
ShellInfo\hInstApp = #Null
ShellInfo\lpIdList = #Null
ShellInfo\lpClass = #Null
ShellInfo\hkeyClass = #Null
ShellInfo\dwHotKey = #Null
ShellInfo\hProcess = #Null
ShellInfo\fMask = #SEE_MASK_FLAG_DDEWAIT
ShellExecuteEx_(ShellInfo)
If ShellInfo\hInstApp > 32
ProcedureReturn(ShellInfo\hProcess)
EndIf
EndProcedure
;_____________________________________________________________________________
Procedure ComboboxDuplicateRemove(hComboBox.i)
Protected index.l
For index = 0 To SendMessage_(hComboBox, #CB_GETCOUNT, 0, 0) - 2
Protected sItem.s = Space(SendMessage_(hComboBox, #CB_GETLBTEXTLEN, index, 0))
SendMessage_(hComboBox, #CB_GETLBTEXT, index, @sItem)
Protected Found.l = SendMessage_(hComboBox, #CB_FINDSTRINGEXACT, index, @sItem) ;#CB_ERR = -1
If Found > index
SendMessage_(hComboBox, #CB_DELETESTRING, Found, 0)
index - 1 ;Since the item is deleted, all subsequent item will be shifted up, so decrement index to avoid missing one item
EndIf
Next
For index = 150 To SendMessage_(hComboBox, #CB_GETCOUNT, 0, 0) - 1 ;Limit list to 150 items
SendMessage_(hComboBox, #CB_DELETESTRING, index, 0)
Next
EndProcedure
;_____________________________________________________________________________
Procedure WndProc(hWnd, uMsg, wParam, lParam)
Protected pPaint.PAINTSTRUCT
Protected tRect.RECT
Protected *CreateStruct.CREATESTRUCT
Protected LogicalFont.LOGFONT
Protected NonClient.NONCLIENTMETRICS
Protected ClientSize.SizeL
Protected sIniFileData.s
Protected ComboboxItem.s, ComboboxItems.s
Protected index.l
Protected hDC.i
Static hInstance.i
Static hStaticAdminInfo.i
Static hComboExeNameList.i
Static hButtonExec.i
Static hFont.i
Static sIniFileName.s
Static hIcon.i
Select uMsg
Case #WM_CREATE
*CreateStruct = lParam ;Just for the fun of using pointers to get hInstance from CreateWindowEx_()
hInstance = *CreateStruct\lpCreateParams ;Or hInstance = GetModuleHandle_(0)
;Enable message reception from non elevated application
ChangeWindowMessageFilter_(#WM_DROPFILES, #MSGFLT_ADD)
ChangeWindowMessageFilter_(#WM_COPYDATA, #MSGFLT_ADD)
ChangeWindowMessageFilter_(#WM_COPYGLOBALDATA, #MSGFLT_ADD)
;Get default Windows font
NonClient\cbSize = SizeOf(NONCLIENTMETRICS)
SystemParametersInfo_(#SPI_GETNONCLIENTMETRICS, SizeOf(NONCLIENTMETRICS), @NonClient, 0)
LogicalFont = NonClient\lfMessageFont
hFont = CreateFontIndirect_(LogicalFont) ;Usually "Segoe UI", 9
;Create static
hStaticAdminInfo = CreateWindowEx_(#WS_EX_TRANSPARENT, "Static", "I am Not SystemAdministrator, nor Administrator.",
#WS_CHILD | #WS_VISIBLE | #SS_CENTER | #SS_CENTERIMAGE , 20, 5, 500, 15, hWnd, #StaticAdminInfo, hInstance, 0)
SendMessage_(hStaticAdminInfo, #WM_SETFONT, hFont, #True)
;Create ComboBox
hComboExeNameList = CreateWindowEx_(#WS_EX_CLIENTEDGE , "ComboBox", "", #WS_CHILD | #WS_VISIBLE | #WS_TABSTOP | #CBS_DROPDOWN |
#CBS_AUTOHSCROLL | #CBS_HASSTRINGS, 20, 30, 500, 225, hWnd, #ComboExeNameList, hInstance, 0)
SendMessage_(hComboExeNameList, #WM_SETFONT, hFont, #True)
SendMessage_(hComboExeNameList, #CB_SETMINVISIBLE, 25, 0)
Protected hwndEdit.i = FindWindowEx_(hComboExeNameList, 0, "Edit", #Null) ;Get Combobox Edit handle
SendMessage_(hwndEdit, #EM_SETCUEBANNER, 01, @"RunAs - Accept Drag&Drop - Accept CommandLine") ;Cue stay if control have focus, #CB_SETCUEBANNER don't
;Create execute button
hButtonExec = CreateWindowEx_(#WS_EX_LEFT, "Button", "Start this executable", #WS_CHILD | #WS_VISIBLE | #WS_TABSTOP,
20, 65, 500, 25, hWnd, #ButtonExec, hInstance, 0)
SendMessage_(hButtonExec, #WM_SETFONT, hFont, #True)
;Verify User/Admin/SysAdmin level
Protected.l AdminLevel = IsUserAdmin()
If AdminLevel = 1
SetWindowText_(hStaticAdminInfo, "I am Administrator but not SystemAdministrator.")
hIcon = LoadImage_(hInstance, "#102", #IMAGE_ICON, 32, 32, #LR_DEFAULTCOLOR)
ElseIf AdminLevel = 2
SetWindowText_(hStaticAdminInfo, "I am Administrator and SystemAdministrator.")
hIcon = LoadImage_(hInstance, "#103", #IMAGE_ICON, 32, 32, #LR_DEFAULTCOLOR)
Else
SetWindowText_(hStaticAdminInfo, "I am not Administrator, nor SystemAdministrator.")
hIcon = LoadImage_(hInstance, "#101", #IMAGE_ICON, 32, 32, #LR_DEFAULTCOLOR)
EndIf
;Set icon
SendMessage_(hWnd, #WM_SETICON, #ICON_SMALL, hIcon)
SendMessage_(hWnd, #WM_SETICON, #ICON_BIG, hIcon)
;Read ini file
sIniFileName = ProgramFilename()
sIniFileName = Left(sIniFileName, Len(sIniFileName) - 3) + "ini"
sIniFileData = FileDataGet(sIniFileName)
If Len(sIniFileData)
For index = 1 To CountString(sIniFileData, #CRLF$) + 1
ComboboxItem = StringField(sIniFileData, index, #CRLF$)
If Left(ComboboxItem, 16) = "WindowPlacement="
If OpenLibrary(0126, "Crypt32.dll")
Protected WinPla.WindowPlacement
Protected WinPlaSize.l
ComboboxItem = RTrim(Mid(ComboboxItem, 17))
WinPlaSize = SizeOf(WindowPlacement)
CallCFunctionFast(GetFunction(0126, "CryptStringToBinaryW"), @ComboboxItem, ;Convert from hexadecimal text
WinPlaSize * 2, #CRYPT_STRING_HEXRAW, @WinPla, @WinPlaSize, 0, 0)
CloseLibrary(0126)
WinPla\showCmd = #SW_RESTORE
SetWindowPlacement_(hWnd, WinPla)
EndIf
Break
Else
SendMessage_(hComboExeNameList, #CB_ADDSTRING, index - 1, ComboboxItem)
EndIf
Next
Else ;Some defaults if no ini
SendMessage_(hComboExeNameList, #CB_ADDSTRING, index - 1, @"RegEdit.exe")
SendMessage_(hComboExeNameList, #CB_ADDSTRING, index - 1, @"Explorer.exe")
SendMessage_(hComboExeNameList, #CB_ADDSTRING, index - 1, @"NotePad.exe")
EndIf
SendMessage_(hComboExeNameList, #CB_SETCURSEL, 0, 0) ;Select first item in list
;Command-line
If OpenLibrary(0127, "Shell32.dll")
Protected ArgumentCount.l
Protected *Argument.string = CallCFunction(0127, "CommandLineToArgvW", GetCommandLine_(), @ArgumentCount)
CloseLibrary(0127)
Protected pMem.i = *Argument
For index = 01 To ArgumentCount - 1 ;Bypass first *Argument and enumerate subsequents
*Argument = *Argument + SizeOf(*Argument) ;Point to the next argument
SendMessage_(hComboExeNameList, #CB_INSERTSTRING, 0, *Argument\s)
Next
LocalFree_(pMem)
ComboboxDuplicateRemove(hComboExeNameList)
SendMessage_(hComboExeNameList, #CB_SETCURSEL, 0, 0) ;Select first item in list
EndIf
ProcedureReturn(0)
Case #WM_COMMAND
Select LoWord(wParam) ;Control id
Case #ButtonExec, #IDOK ;Execute program from combobox
If (HiWord(wParam) = #BN_CLICKED) Or (HiWord(wParam) = 1)
Protected.s zFile.s{#MAX_PATH}
Protected.s zParam.s{#MAX_PATH}
Protected.s zPath.s{#MAX_PATH}
Protected.s zVerb.s{30}
Protected.s Duplicate
Protected.i hParent
Protected.l dwShow
Protected.l TextLen
TextLen = SendMessage_(hComboExeNameList, #WM_GETTEXTLENGTH, 0, 0)
If TextLen
hParent = GetDesktopWindow_()
zVerb = "open"
SendMessage_(hComboExeNameList, #WM_GETTEXT, TextLen + 1, @zFile) ;Get item
DoShellExecuteEx(hParent, zVerb, zFile, zParam, zPath, #SW_SHOWNORMAL) ;Execute it
SendMessage_(hComboExeNameList, #CB_INSERTSTRING, 0, zFile) ;Insert item in position zero
ComboboxDuplicateRemove(hComboExeNameList)
SendMessage_(hComboExeNameList, #CB_SETCURSEL, 0, 0) ;Item zero become the current selection
EndIf
EndIf
Case #IDCANCEL ;Escape key
PostMessage_(hWnd, #WM_SYSCOMMAND, #SC_CLOSE, 0)
EndSelect
Case #WM_DROPFILES ;Dropped files on self window
Protected zFileName.s{#MAX_PATH}
Protected.i hDrop
Protected.l DroppedFileCount
Protected.l Looper
hDrop = wParam
DroppedFileCount = DragQueryFile_(hDrop, $FFFFFFFF, 0, 0)
For Looper = 0 To DroppedFileCount - 1
DragQueryFile_(hDrop, Looper, @zFileName, SizeOf(zFileName))
SendMessage_(hComboExeNameList, #CB_INSERTSTRING, 0, @zFileName)
If Looper = DroppedFileCount - 1
SendMessage_(hComboExeNameList, #WM_SETTEXT, Len(zFileName), zFileName) ;Write edit part of combo
EndIf
Next
DragFinish_(hDrop) ;Releases drop memory allocated by Windows
ComboboxDuplicateRemove(hComboExeNameList)
Case #WM_CTLCOLORSTATIC
If lParam = hStaticAdminInfo
SetTextColor_(WPARAM, #Yellow)
SetBkMode_(WPARAM, #TRANSPARENT)
ProcedureReturn(GetStockObject_(#NULL_BRUSH)) ;Set background transparent
EndIf
Case #WM_ERASEBKGND ;DrawGradient, hDC in wParam
Protected rcFill.RECT
Protected rcClient.RECT
Protected Increment.f
Protected hBrush.i
Protected BandIndex
GetClientRect_(WindowFromDC_(wParam), rcClient)
Increment = rcClient\Bottom / 100
For BandIndex = 0 To 99
SetRect_(rcFill, 0, BandIndex * Increment, rcClient\Right + 1, (BandIndex + 1) * Increment)
hBrush = CreateSolidBrush_(RGB(10, 50, 192 - BandIndex))
FillRect_(wParam, rcFill, hBrush)
DeleteObject_(hBrush)
Next
Case #WM_LBUTTONDOWN ;Client area dialog drag via click down simulation on caption
If wParam = #MK_LBUTTON
SendMessage_(hComboExeNameList, #CB_SHOWDROPDOWN, #False, 0)
SendMessage_(hWnd, #WM_NCLBUTTONDOWN, #HTCAPTION, #Null)
EndIf
Case #WM_GETMINMAXINFO ;Window size limit
Protected *MinMaxInfoPtr.MINMAXINFO
*MinMaxInfoPtr = lParam
*MinMaxInfoPtr\ptMinTrackSize\x = 400 ;Limit minimum width
*MinMaxInfoPtr\ptMinTrackSize\y = 135 ;Limit minimum height
*MinMaxInfoPtr\ptMaxTrackSize\y = 135 ;Limit maximum height
Case #WM_SIZE ;Window resizing
If wParam <> #SIZE_MINIMIZED
ClientSize\cx = LoWord(lParam)
ClientSize\cy = HiWord(lParam)
MoveWindow_(hStaticAdminInfo, 5, 5, ClientSize\cx - 10, 14, #False)
MoveWindow_(hComboExeNameList, 5, 25, ClientSize\cx - 10, 14, #False)
MoveWindow_(hButtonExec, 5, 65, ClientSize\cx - 10, 24, #False)
InvalidateRect_(hWnd, #Null, #True) : UpdateWindow_(hWnd)
EndIf
Case #WM_CLOSE
PostMessage_(hWnd, #WM_QUIT, 0, 0)
Case #WM_DESTROY
;Save filename list to ini file
For index = 0 To SendMessage_(hComboExeNameList, #CB_GETCOUNT, 0, 0) - 1
ComboboxItem = Space(SendMessage_(hComboExeNameList, #CB_GETLBTEXTLEN, index, 0))
SendMessage_(hComboExeNameList, #CB_GETLBTEXT, index, @ComboboxItem)
sIniFileData = sIniFileData + ComboboxItem + #CRLF$
Next
Protected sHexText.s
If OpenLibrary(0128, "Crypt32.dll") ;Convert WinPla to hexa-decimal text
WinPla\length = SizeOf(WindowPlacement)
GetWindowPlacement_(hWnd, @WinPla)
Protected HexTextLen.l = SizeOf(WindowPlacement) * 4 + 4
sHexText = Space(HexTextLen)
CallCFunctionFast(GetFunction(0128, "CryptBinaryToStringW"), WinPla, SizeOf(WinPla), #CRYPT_STRING_HEXRAW, @sHexText, @HexTextLen)
CloseLibrary(0128)
sHexText = "WindowPlacement=" + Left(sHexText, Len(sHexText) - 02)
EndIf
FileDataSet(sIniFileName, sIniFileData + sHexText)
;Clean-up
DestroyIcon_(hIcon)
DeleteObject_(hFont)
PostQuitMessage_(0)
EndSelect
ProcedureReturn(DefWindowProc_(hWnd, uMsg, wParam, lParam))
EndProcedure
;_____________________________________________________________________________
Define wce.WndClassEx
Define WindowSize.Sizel
Define msg.msg
Define AppName.s
Define CommandLine.s
Define hWnd.i
Define hInstance.i
AppName = "SysAdminExec"
hInstance = GetModuleHandle_(0)
;Using a mutex to allow only one instance of this app
Define dwMutex.l = 2006162257 ;YYMMDDHHMM
Define sMutex.s = "2006162257" ;MaxStringLen is #MAX_PATH, no "\", case sensitive
Define hMutex.i = CreateMutex_(#Null, 0, sMutex)
If GetLastError_() = #ERROR_ALREADY_EXISTS ;App is already running
Define hTry.i = GetForegroundWindow_() ;Start search with the foreground Window
While hTry
If GetWindowLongPtr_(hTry, #GWL_USERDATA) = dwMutex ;Found it
If IsWindowVisible_(hTry) ;Ignore hidden windows
If IsIconic_(hTry)
ShowWindow_(hTry, #SW_RESTORE) ;UnMinimize if needed
Else
ShowWindow_(hTry, #SW_SHOW)
SetForegroundWindow_(hTry)
EndIf
Break ;Job done, exit loop
EndIf
EndIf
hTry = GetWindow_(hTry, #GW_HWNDNEXT)
Wend
End(#ERROR_ALREADY_EXISTS)
EndIf ;See SetWindowLongPtr_() below
wce\cbSize = SizeOf(WNDCLASSEX)
wce\STYLE = #CS_HREDRAW | #CS_VREDRAW
wce\lpfnWndProc = @WndProc()
wce\cbClsExtra = 0
wce\cbWndExtra = 0
wce\hInstance = hInstance
wce\hIcon = 0
wce\hIconSm = 0
wce\hCursor = LoadCursor_(#Null, #IDC_ARROW)
wce\hbrBackground = 0
wce\lpszMenuName = 0
wce\lpszClassName = @AppName
RegisterClassEx_(@wce)
WindowSize\cx = 540
WindowSize\cy = 140
;Create a window using the registered class
hWnd = CreateWindowEx_(#WS_EX_LEFT | #WS_EX_ACCEPTFILES,
AppName, ;Window class name
AppName, ;Window caption
#WS_OVERLAPPEDWINDOW, ;Window style
(GetSystemMetrics_(#SM_CXSCREEN) - WindowSize\cx) / 2, ;Center position x
(GetSystemMetrics_(#SM_CYSCREEN) - WindowSize\cy) / 2, ;Centr position y
WindowSize\cx, ;x size
WindowSize\cy, ;y size
#HWND_DESKTOP, ;Parent window handle
0, ;Window menu handle
hInstance, ;Program instance handle
hInstance) ;Creation parameters
SetWindowLongPtr_(hWnd, #GWL_USERDATA, dwMutex) ;This window have unique USERDATA number
ShowWindow_(hWnd, #SW_SHOWDEFAULT)
UpdateWindow_(hWnd)
While GetMessage_(Msg, 0, 0, 0) ;<> #WM_QUIT
If IsDialogMessage_(hWnd, Msg) = #False
TranslateMessage_(Msg) ;TranslateMessage translates virtual-key messages into character messages.
DispatchMessage_(Msg)
EndIf
Wend
End msg\wParam
;_____________________________________________________________________________
;
; IDE Options = PureBasic 5.72 (Windows - x64)
; CursorPosition = 50
; FirstLine = 42
; EnableAsm
; EnableXP
; UseIcon = ieframe.dll.108.ico
; Executable = SysAdminExec.exe
; DisableDebugger
; CompileSourceDirectory
; IncludeVersionInfo
; AddResource = SysAdminExec.rc
; EnableUnicode
.rc resource file.
0x65 ICON "ieframe.dll.108.ico" // 101 blue
0x66 ICON "imageres.dll.073.ico" // 102 blue yellow
0x67 ICON "wlanpref.dll.011.ico" // 103 blue yellow green red
#define IDR_MANIFEST 1 // EXE = 1, DLL = 2.
#define RT_MANIFEST 24 // Side-by-Side Assembly Manifest. MAKEINTRESOURCE(24)
IDR_MANIFEST RT_MANIFEST "SysAdminExec.xml"
.xml manifest file.
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<assemblyIdentity
version='1.0.0.0'
processorArchitecture='*'
name='Company.Product.Name'
type='win32'
/>
<description></description>
<!-- Common controls - Theme section -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type='win32'
name='Microsoft.Windows.Common-Controls'
version='6.0.0.0'
processorArchitecture='*'
publicKeyToken='6595b64144ccf1df'
language='*'
/>
</dependentAssembly>
</dependency>
<!-- Version - Compatibility section for Program Compatibility Assistant (PCA) -->
<compatibility xmlns='urn:schemas-microsoft-com:compatibility.v1'>
<application>
// Windows XP and Windows Vista ignore this manifest section
<!-- Windows Vista -->
<supportedOS Id='{e2011457-1546-43c5-a5fe-008deee3d3f0}'/>
<!-- Windows 7 -->
<supportedOS Id='{35138b9a-5d96-4fbd-8e2d-a2440225f93a}'/>
<!-- Windows 8 -->
<supportedOS Id='{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}'/>
<!-- Windows 8.1 Needed to report GetVersionEx 6.3 instead of 8.2-->
<supportedOS Id='{1f676c76-80e1-4239-95bb-83d0f6d0da78}'/>
<!-- Windows 10.0 Needed to report GetVersionEx 10.0 instead of 6.2-->
<supportedOS Id='{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}'/>
</application>
</compatibility>
<!-- DpiAware & long path section -->
<!-- <dpiAware>true</dpiAware> -->
// <asmv3:application xmlns:asmv3='urn:schemas-microsoft-com:asm.v3'>
// <asmv3:windowsSettings xmlns='http:\x2F\x2Fschemas.microsoft.com/SMI/2005/WindowsSettings'> // \x2F = 47 = '/'
// <dpiAware>false</dpiAware>
// <path:longPathAware>true</path:longPathAware>
// </asmv3:windowsSettings>
// </asmv3:application>
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns:dpi="http://schemas.microsoft.com/SMI/2005/WindowsSettings"
xmlns:path="http://schemas.microsoft.com/SMI/2016">
<dpi:dpiAware>True</dpi:dpiAware>
<path:longPathAware>true</path:longPathAware>
</asmv3:windowsSettings>
</asmv3:application>
<!-- Trustinfo section - Run as -->
<asmv3:trustInfo xmlns:asmv3='urn:schemas-microsoft-com:asm.v3'>
<asmv3:security>
<asmv3:requestedPrivileges>
<!-- level='asInvoker' level='highestAvailable' level='requireAdministrator' -->
<!-- DO not put anything betwen <asmv3:requestedExecutionLevel and </asmv3:requestedPrivileges> -->
<!-- OR you will get "The operating system denied access to the specified file." -->
<asmv3:requestedExecutionLevel
level='asInvoker'
uiAccess='false' />
</asmv3:requestedPrivileges>
</asmv3:security>
</asmv3:trustInfo>
</assembly>
hosted by awardspace
andrew sun's syntax highlighter