gto250 发表于 2010-8-31 19:46:00

关于P版的纯au3编写服务程序的实际应用求帮助(已解决)

本帖最后由 gto250 于 2010-8-31 20:34 编辑

Const $hAdvApi32Dll = DllOpen("AdvApi32.dll")
Const $hKernel32Dll = DllOpen("Kernel32.dll")

Const $tagSERVICE_TABLE_ENTRY = "ptr ServiceName;ptr ServiceMain"
Const $tagSERVICE_STATUS = "dword ServiceType;dword CurrentState;dword ControlsAccepted;dword Win32ExitCode;dword ServiceSpecificExitCode;dword CheckPoint;dword WaitHint"

Global $hServiceStatus, $tServiceStatus, $pServiceStatus
Global $hServiceMain, $pServiceMain, $tServiceTable, $pServiceTable
Global $hServiceHandlerEx, $pServiceHandlerEx

$hServiceMain = DllCallbackRegister("_ServiceMain", "none", "dword;ptr")
$pServiceMain = DllCallbackGetPtr($hServiceMain)

$hServiceHandlerEx = DllCallbackRegister("_ServiceHandlerEx", "dword", "dword;dword;ptr;ptr")
$pServiceHandlerEx = DllCallbackGetPtr($hServiceHandlerEx)

$pServiceTable = _ServiceHeapAlloc(32)
$tServiceTable = DllStructCreate($tagSERVICE_TABLE_ENTRY, $pServiceTable)
DllStructSetData($tServiceTable, "ServiceName", $pServiceTable + 16)
DllStructSetData($tServiceTable, "ServiceMain", $pServiceMain)

$tServiceName = DllStructCreate("char ServiceName", $pServiceTable + 16)
DllStructSetData($tServiceName, "ServiceName", "AutoIt3Service")

$tServiceStatus = DllStructCreate($tagSERVICE_STATUS)
$pServiceStatus = DllStructGetPtr($tServiceStatus)
DllStructSetData($tServiceStatus, "ServiceType", 16)
DllStructSetData($tServiceStatus, "ControlsAccepted", 3)

_StartServiceCtrlDispatcher($pServiceTable)


Func _StartServiceCtrlDispatcher($pServiceTable)
      Local $iResult
      $iResult = DllCall($hAdvApi32Dll, "int", "StartServiceCtrlDispatcher", "ptr", $pServiceTable)
      Return SetError(_ServiceLastError(), 0, $iResult)
EndFunc      ;==>_StartServiceCtrlDispatcher

Func _SetServiceStatus($hServiceStatus, $pServiceStatus)
      Local $iResult
      $iResult = DllCall($hAdvApi32Dll, "int", "SetServiceStatus", "hWnd", $hServiceStatus, _
                        "ptr", $pServiceStatus)
      Return SetError(_ServiceLastError(), 0, $iResult)
EndFunc      ;==>_SerServiceStatus

Func _RegisterServiceCtrlHandlerEx($sServiceName, $pHandlerEx, $pContext = 0)
      Local $iResult
      $iResult = DllCall($hAdvApi32Dll, "hWnd", "RegisterServiceCtrlHandlerEx", _
                        "str", $sServiceName, "ptr", $pHandlerEx, "ptr", $pContext)
      Return SetError(_ServiceLastError(), 0, $iResult)
EndFunc      ;==>_RegisterServiceCtrlHandlerEx

Func _ServiceHandlerEx($iRequest, $iEventType, $pEventData, $pContext)
      Switch $iRequest
      Case 1
                DllStructSetData($tServiceStatus, "CurrentState", 1)
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Return 0
      Case 2
                DllStructSetData($tServiceStatus, "CurrentState", 7)
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Return 0
      Case 3
                DllStructSetData($tServiceStatus, "CurrentState", 5)
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Sleep(5000)
                DllStructSetData($tServiceStatus, "CurrentState", 4)
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Return 0
      Case 4
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Return 0
      EndSwitch
EndFunc      ;==>_ServiceHandlerEx

Func _ServiceHeapAlloc($iSize, $iFlags = 8)
      If $iSize < 1 Then Return SetError(87, 0, 0)

      Local $hHeap, $iResult

      $hHeap = DllCall($hKernel32Dll, "hWnd", "GetProcessHeap")
      $iResult = DllCall($hKernel32Dll, "ptr", "HeapAlloc", "hWnd", $hHeap, _
                        "dword", $iFlags, "dword", $iSize)
      Return $iResult
EndFunc      ;==>_ServiceHeapAlloc

Func _ServiceHeapFree(ByRef $pBuffer)
      If $pBuffer = 0 Then Return SetError(87, 0, 0)

      Local $iResult, $hHeap
      $hHeap = DllCall($hKernel32Dll, "hWnd", "GetProcessHeap")
      $iResult = DllCall($hKernel32Dll, "int", "HeapFree", "hWnd", $hHeap, _
                        "dword", 0, "ptr", $pBuffer)
      If $iResult Then $pBuffer = 0
      Return $iResult
EndFunc      ;==>_ServiceHeapFree

Func _ServiceHeapSize(ByRef $pBuffer)
      If $pBuffer = 0 Then Return SetError(87, 0, 0)

      Local $iResult, $hHeap
      $hHeap = DllCall($hKernel32Dll, "hWnd", "GetProcessHeap")
      $iResult = DllCall($hKernel32Dll, "int", "HeapSize", "hWnd", $hHeap, _
                        "dword", 0, "ptr", $pBuffer)
      Return $iResult
EndFunc      ;==>_ServiceHeapFree

Func _ServiceLastError()
      Local $iResult
      $iResult = DllCall($hKernel32Dll, "dword", "GetLastError")
      Return $iResult
EndFunc      ;==>_ServiceLastError

Func _ServiceMain($iNumberofArgs, $pArgs)
      $hServiceStatus = _RegisterServiceCtrlHandlerEx("AutoIt3Service", $pServiceHandlerEx)

      DllStructSetData($tServiceStatus, "CurrentState", 4)
      _SetServiceStatus($hServiceStatus, $pServiceStatus)
EndFunc      ;==>_ServiceMain以上是P版的纯au3编写服务程序的代码,但是不知道怎么应用于实际,自己想要实现的代码应该加在何处?
请已经用这个代码实现实际应用的兄弟给个帮助!

pusofalse 发表于 2010-8-31 19:57:11

#NoTrayIcon
#include <LocalSecurityAuthority.au3>

Const $SERVICE_WIN32_OWN_PROCESS = 0x0010
Const $SERVICE_WIN32_SHARE_PROCESS = 0x0020
Const $SERVICE_INTERACTIVE_PROCESS = 0x0100

Const $SERVICE_STOPPED = 1
Const $SERVICE_RUNNING = 4
Const $SERVICE_CONTINUE_PENDING = 5
Const $SERVICE_PAUSED = 7

Const $SERVICE_ACCEPT_STOP = 1
Const $SERVICE_ACCEPT_PAUSE_CONTINUE = 2

Const $SERVICE_CONTROL_STOP = 1
Const $SERVICE_CONTROL_PAUSE = 2
Const $SERVICE_CONTROL_CONTINUE = 3
Const $SERVICE_CONTROL_INTERROGATE = 4

Const $tagSERVICE_STATUS = "dword ServiceType;dword CurrentState;dword ControlsAccepted;dword Win32ExitCode;dword ServiceSpecificExitCode;dword CheckPoint;dword WaitHint"

If Not @Compiled Then Exit(Msgbox(48, "Error", "Compile first."))

; SCM - 服务控制器 (Service Control Manager)。

; 此服务程序的名称。
Global $sServiceName = "Au3MemCleaner"

; 判断此服务程序是否由SCM启动。
Local $tProcessBasic = DllStructCreate("dword;ptr;ulong_ptr;ulong")
_NtQueryInformationProcess(-1, 0, DllStructGetPtr($tProcessBasic), 24)

If DllStructGetData($tProcessBasic, 4, 3) <> ProcessExists("Services.exe") Then
      $hService = _LsaOpenService($sServiceName, 0xF01FF)
      If ($hService = 0) Then $hService = _CreateService($sServiceName, $sServiceName, _
                        bitOr($SERVICE_WIN32_OWN_PROCESS, $SERVICE_INTERACTIVE_PROCESS), _
                              2, 0, @ScriptFullPath, "", 0)
      _StartService($hService)
      _LsaCloseServiceHandle($hService)
      exit
EndIf

; 定义几个全局变量,以便在多个函数中共享它们的值。
Global $hServiceMain, $hHandlerEx, $tServiceTable
Global $tServiceStatus, $pServiceStatus, $hServiceStatus

; 注册服务入口点函数,用于在SCM启动服务时,向SCM报告自己的状态。
$hServiceMain = DllCallbackRegister("_ServiceMain", "none", "dword;ptr")
; 子控制请求函数,用于接收SCM发来的请求,并报告自己的状态。
$hHandlerEx = DllCallbackRegister("_HandlerEx", "dword", "dword;dword;ptr;ptr")

$tServiceTable = DllStructCreate("ptr;ptr;ptr;ptr;char")
DllStructSetData($tServiceTable, 1, DllStructGetPtr($tServiceTable, 5)) ; 服务名称。
DllStructSetData($tServiceTable, 2, DllCallbackGetPtr($hServiceMain)) ; 入口点函数地址。
DllStructSetData($tServiceTable, 5, $sServiceName)

$tServiceStatus = DllStructCreate($tagSERVICE_STATUS)
$pServiceStatus = DllStructGetPtr($tServiceStatus)
DllStructSetData($tServiceStatus, "ServiceType", _ ; 服务类型
                        bitOr($SERVICE_WIN32_OWN_PROCESS, _ ; 独享进程。
                        $SERVICE_INTERACTIVE_PROCESS)) ; 允许与桌面交互。

DllStructSetData($tServiceStatus, "ControlsAccepted", _ ; 指定允许接收的后续控制请求。
                        bitOr($SERVICE_ACCEPT_STOP, _ ; 服务可以停止。
                        $SERVICE_ACCEPT_PAUSE_CONTINUE)) ; 服务可以暂停和继续。

; 启动服务的控制调度分派线程。
; 当SCM启动某个服务时,服务进程的主线程必须在30秒内调用此函数。
; SCM将分派表传递给StartServiceCtrlDispatcher,这将把调用进程的主线程转换为控制分派器,
; 该分派器启动一个新线程,该线程运行分派表中每个服务的 ServiceMain 入口点函数。
; 如果 StartServiceCtrlDispatcher 函数30秒没有被调用, 便会出现1053的错误(服务没有及时响应控制请求)。
_StartServiceCtrlDispatcher(DllStructGetPtr($tServiceTable))

Func _ServiceMain($iNumberofArgs, $pArguments)
      Local $aProcess, $hProcess, $hToken, $aPriv = [[$SE_DEBUG_NAME, 2]]

      ; 注册服务的“控制处理器”,以用于接收停止、暂停等请求操作,应在ServiceMain函数中尽早调用。
      $hServiceStatus = _RegisterServiceCtrlHandlerEx($sServiceName, DllCallbackGetPtr($hHandlerEx))

      ; 向SCM报告自己的状态。
      DllStructSetData($tServiceStatus, "CurrentState", $SERVICE_RUNNING)
      _SetServiceStatus($hServiceStatus, $pServiceStatus)

      Msgbox(4, "Bingo~!!", "I am running as a service~~")

      $hToken = _OpenProcessToken(-1)
      If Not _IsPrivilegeEnabled($hToken, $SE_DEBUG_NAME) Then
                _AdjustTokenPrivileges($hToken, $aPriv)
      EndIf
      _LsaCloseHandle($hToken)

      ; 在服务的主函数中循环清理内存。
      While 1
                $aProcess = ProcessList()
                For $i = 1 To $aProcess
                        $hProcess = _OpenProcess($aProcess[$i])
                        _EmptyWorkingSet($hProcess)
                        _LsaCloseHandle($hProcess)
                        Sleep(50)
                Next
      WEnd
EndFunc      ;==>_ServiceMain

; 服务的“控制处理器”,用于处理SCM发出的各种请求。
Func _HandlerEx($iRequest, $iEventType, $pEventData, $pContext)
      Switch $iRequest
      Case $SERVICE_CONTROL_STOP ; 服务需停止。
                ; 如果30秒内没有向SCM报告自己的状态,将会出现1053的错误。
                DllStructSetData($tServiceStatus, "CurrentState", $SERVICE_STOPPED)
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Return 0
      Case $SERVICE_CONTROL_PAUSE ; 服务需暂停。
                ; 同上,必须在30秒调用,否则出错。
                DllStructSetData($tServiceStatus, "CurrentState", $SERVICE_PAUSED)
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Return 0
      Case $SERVICE_CONTROL_CONTINUE ; 服务需要继续。
                ; 同上。
                DllStructSetData($tServiceStatus, "CurrentState", $SERVICE_RUNNING)
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Return 0
      Case $SERVICE_CONTROL_INTERROGATE ; 服务需要向SCM报告自己的状态。
                _SetServiceStatus($hServiceStatus, $pServiceStatus)
                Return 0
      EndSwitch
EndFunc      ;==>_HandlerEx

Func _SetServiceStatus($hServiceStatus, $pServiceStatus)
      Local $iResult
      $iResult = DllCall("AdvApi32.dll", "int", "SetServiceStatus", _
                        "hWnd", $hServiceStatus, "ptr", $pServiceStatus)
      Return SetError(_GetLastError(), 0, $iResult)
EndFunc      ;==>_SetServiceStatus



Func _StartService($hService, $iNumberofArgs = 0, $pArguments = 0)
      Local $iResult
      $iResult = DllCall("AdvApi32.dll", "int", "StartService", "hWnd", $hService, _
                        "dword", $iNumberofArgs, "ptr", $pArguments)
      Return SetError(_GetLastError(), 0, $iResult)
EndFunc      ;==>_StartService

Func _RegisterServiceCtrlHandlerEx($sServiceName, $pHandlerEx, $pContext = 0)
      Local $iResult
      $iResult = DllCall("AdvApi32.dll", "hWnd", "RegisterServiceCtrlHandlerEx", _
                        "str", $sServiceName, "ptr", $pHandlerEx, "ptr", $pContext)
      Return SetError(_GetLastError(), 0, $iResult)
EndFunc      ;==>_RegisterServiceCtrlHandlerEx

Func _StartServiceCtrlDispatcher($pServiceTable)
      Local $iResult
      $iResult = DllCall("AdvApi32.dll", "int", "StartServiceCtrlDispatcher", _
                        "ptr", $pServiceTable)
      Return SetError(_GetLastError(), 0, $iResult)
EndFunc      ;==>_StartServiceCtrlDispatcher

Func _CreateService($sServiceName, $sDisplayName, $iServiceType, $iStartType, _
                $iErrorControl, $sBinaryPath, $sLoadOrderGroup, $aDependencies, _
                $sStartName = "", $sPassword = "", $iDesiredAccess = 0xF01FF)

      Local $iResult, $tServiceName, $tDisplayName, $tBinaryPath, $hSC
      Local $tLoadOrder, $tDependencies, $tStartName, $tPassword, $sBuffer

      $tServiceName = DllStructCreate("wchar ServiceName[" & StringLen($sServiceName) + 1 & "]")
      DllStructSetData($tServiceName, "ServiceName", $sServiceName)
      If $sDisplayName <> "" Then
                $tDisplayName = DllStructCreate("wchar DisplayName[" & StringLen($sDisplayName) + 1 & "]")
                DllStructSetData($tDisplayName, "DisplayName", $sDisplayName)
      EndIf
      If $sBinaryPath <> "" Then
                $tBinaryPath = DllStructCreate("wchar BinaryPath[" & StringLen($sBinaryPath) + 1 & "]")
                DllStructSetData($tBinaryPath, "BinaryPath", $sBinaryPath)
      EndIf
      If $sLoadOrderGroup <> "" Then
                $tLoadOrder = DllStructCreate("wchar LoadOrder[" & StringLen($sLoadOrderGroup) + 1 & "]")
                DllStructSetData($tLoadOrder, "LoadOrder", $sLoadOrderGroup)
      EndIf
      If $sStartName <> "" Then
                $tStartName = DllStructCreate("wchar StartName[" & StringLen($sStartName) + 1 & "]")
                DllStructSetData($tStartName, "StartName", $sStartName)
      EndIf
      If $sPassword <> "" Then
                $tPassword = DllStructCreate("wchar Password[" & StringLen($sPassword) + 1 & "]")
                DllStructSetData($tPassword, "Password", $sPassword)
      EndIf
      If IsArray($aDependencies) And UBound($aDependencies, 0) = 1 Then
                For $i = 0 To UBound($aDependencies) - 1
                        $sBuffer &= "wchar[" & StringLen($aDependencies[$i]) + 1 & "];")
                Next
                $tDependencies = DllStructCreate($sBuffer & ";wchar")
                For $i =0 To UBound($aDependencies) - 1
                        DllStructSetData($tDependencies, ($i + 1), $aDependencies[$i])
                Next
      EndIf
      $hSC = _LsaOpenSCManager("", 2)
      $iResult = DllCall("AdvApi32.dll", "hWnd", "CreateServiceW", _
                        "hWnd", $hSC, _
                        "ptr", DllStructGetPtr($tServiceName), _
                        "ptr", DllStructGetPtr($tDisplayName), _
                        "dword", $iDesiredAccess, _
                        "dword", $iServiceType, _
                        "dword", $iStartType, _
                        "dword", $iErrorControl, _
                        "ptr", DllStructGetPtr($tBinaryPath), _
                        "ptr", DllStructGetPtr($tLoadOrder), _
                        "ptr", 0, _
                        "ptr", DllStructGetPtr($tDependencies), _
                        "ptr", DllStructGetPtr($tStartName), _
                        "ptr", DllStructGetPtr($tPassword))
      Return SetError(_GetLastError(), _LsaCloseServiceHandle($hSC), $iResult)
EndFunc      ;==>_CreateService

Func _EmptyWorkingSet($hProcess)
      Local $iResult
      $iResult = DllCall("psapi.dll", "int", "EmptyWorkingSet", "hWnd", $hProcess)
      Return SetError(_GetLastError(), 0, $iResult)
EndFunc      ;==>_EmptyWorkingSet

Func _NtQueryInformationProcess($hProcess, $iClass, $pBuffer, $iSizeofBuffer)
      Local $iResult

      $iResult = DllCall("Ntdll.dll", "dword", "NtQueryInformationProcess", "hWnd", $hProcess, _
                        "int", $iClass, "ptr", $pBuffer, "ulong", $iSizeofBuffer, "ulong*", 0)
      Return SetError($iResult, $iResult, $iResult = 0)
EndFunc      ;==>_NtQueryInformationProcess服务程序,清理内存的。

从_ServiceMain函数中的Msgbox(4, "Bingo~!!", "I am running as a service~~")那里开始,
是自己定义的服务程序代码,也就是说,自己的服务代码只能在_ServiceMain函数中执行。
当服务被停止后,程序运行的流程会退出_ServiceMain函数,并转向函数外的_StartServiceCtrlDispatcher($pServiceTable),从下一句开始执行。

itljl 发表于 2010-8-31 20:34:33

回复 2# pusofalse


    请教P版,以前我测试这段代码的时候,是成功的。
在while 1 内的代码确实可以运行,
但只要涉及到有msgbox,gui之类的就不会显示,但若是filewrite之类的就可以。

就好像程序不能和桌面交互的感觉。是为什么呢?

gto250 发表于 2010-8-31 20:35:52

谢谢p版的帮助,我先学学,遇到问题再问

xsjtxy 发表于 2010-8-31 21:04:38

本帖最后由 xsjtxy 于 2010-8-31 21:06 编辑

回复 2# pusofalse


    顺便再请教下,我想在里面加个防止进程被结束的功能为什么不成功。

用在进程上都没问题的。

58fly 发表于 2010-9-1 01:06:51

程序做成服务,太复杂了,面临很多兼容性的问题吧

lamlp 发表于 2011-2-25 10:56:46

注释太少了,上面那段不太理解

boyhong 发表于 2011-3-21 15:30:39

C:\Documents and Settings\zhanghong1\桌面\test.au3(190,88) : 错误: 表达式错误
                        $sBuffer &= "wchar[" & StringLen($aDependencies[$i]) + 1 & "];")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
C:\Documents and Settings\zhanghong1\桌面\test.au3 - 1 error(s), 0 warning(s)
   

2楼P大,我在编译时出错。

502762378 发表于 2011-12-20 21:54:49

权限不够的我顶下

凡之雪 发表于 2012-1-31 03:40:19

权限不够的我顶下

kehongpc 发表于 2012-2-3 23:34:08

注释太少了,上面那段不太理解

zldfsz 发表于 2012-3-5 14:01:30

弄不懂,先收藏,以后再研究

tttbbb999 发表于 2012-3-5 14:09:21

C:\Documents and Settings\zhanghong1\桌面\test.au3(190,88) : 错误: 表达式错误
                      ...
boyhong 发表于 2011-3-21 15:30 http://www.autoitx.com/images/common/back.gif


    缺少这个
#include <LocalSecurityAuthority.au3>

wei999 发表于 2012-3-11 23:19:43

缺少这个
#include
tttbbb999 发表于 2012-3-5 14:09 http://autoitx.com/images/common/back.gif
这个有也出现

    C:\Documents and Settings\zhanghong1\桌面\test.au3(190,88) : 错误: 表达式错误
                        $sBuffer &= "wchar[" & StringLen($aDependencies[$i]) + 1 & "];")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
C:\Documents and Settings\zhanghong1\桌面\test.au3 - 1 error(s), 0 warning(s)

872777825 发表于 2012-4-12 16:10:05

服务程序,清理内存的。

从_ServiceMain函数中的Msgbox(4, "Bingo~!!", "I am running as a service~~") ...
pusofalse 发表于 2010-8-31 19:57 http://www.autoitx.com/images/common/back.gif


    老大 我引用这个代码为什么不行呢
直接用你源代码编译提示$sBuffer &= "wchar[" & StringLen($aDependencies[$i]) + 1 & "];")这句有问题我把后面的括号去掉后可以编译但添加服务后   不弹出msgbox对话框   
但手动运行却没任何反应   进程可以看到相关进程   希望老大能解释下
页: [1] 2 3
查看完整版本: 关于P版的纯au3编写服务程序的实际应用求帮助(已解决)