Sign in to follow this  
Followers 0
gil900

I don't know why _RetrieveRunningServices() started to work so slow

9 posts in this topic

#1 ·  Posted (edited)

Hello,

my script using function that get array of all the running services on the computer.

that function always worked properly until now.

for some reason, now it takes 30 seconds for the function to finish.

this is the function:

Func _RetrieveRunningServices()
    Local Const $wbemFlagReturnImmediately = 0x10
    Local Const $wbemFlagForwardOnly = 0x20
    Local $colItems = "", $even = 1, $objItem, $services[1]
    $services[0] = 0

    Local $objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\CIMV2")

    If @error Then
        MsgBox(16, "_RetrieveRunningServices", "ObjGet Error: winmgmts")
        ;ConsoleWrite("_RetrieveRunningServices -> ObjGet Error: winmgmts"&@CRLF)
        Return $services
        ;Exit
    EndIf
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_Service", "WQL", _
            $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

    If @error Then
        MsgBox(16, "_RetrieveRunningServices", "ExecQuery Error: SELECT * FROM Win32_Service")
        ;ConsoleWrite("_RetrieveRunningServices -> ExecQuery Error: SELECT * FROM Win32_Service"&@CRLF)
        Return $services
        ;Exit
    EndIf
    If IsObj($colItems) Then

        For $objItem In $colItems
            If $objItem.State = "Running" Then
                If IsArray($services) Then
                    ReDim $services[UBound($services) + 1]
                Else
                    Dim $services[2]
                EndIf
                $services[0] = UBound($services) - 1
;~             $services[UBound($services) - 1] = $objItem.Name
                $services[UBound($services) - 1] = $objItem.name ;& "[0]" & $objItem.State
            EndIf
        Next
    EndIf
    Return $services
EndFunc   ;==>_RetrieveRunningServices

I checked the performance of the function with this code:

#include <Array.au3>

$timer = TimerInit()
$Services = _RetrieveRunningServices()
ConsoleWrite("time: "&TimerDiff($timer)&@CRLF)
_ArrayDisplay($Services)

The output i got is time: 30195.6027959443

and i ran the test several times and it always took 30 seconds.

 

The first thing I decided to do after I found out that the problem is this function, I searched for an alternative function. and i found alternative function in >Computer Info UDF's

the alternative function is _ComputerGetServices()

so i tested that function and i was surprised to find that I get the exact same result. With the alternate function!

this is my test with the alternate function:

#include <Array.au3>
#include "CompInfo.au3"

Dim $Services
$timer = TimerInit()
_ComputerGetServices($Services, "Running")
If @error Then
    ConsoleWrite("error"&@CRLF)
EndIf
ConsoleWrite("time: "&TimerDiff($timer)&@CRLF)
_ArrayDisplay($Services)

the output is: time: 30459.1907821033

I so i decided to go back to the original function check what exactly is slow in that function.

at the end, i found that this loop:

.......
        For $objItem In $colItems
            ; Anything inside the loop is disabled to isolate the problem
            
;~          If $objItem.State = "Running" Then
;~              If IsArray($services) Then
;~                  ReDim $services[UBound($services) + 1]
;~              Else
;~                  Dim $services[2]
;~              EndIf
;~              $services[0] = UBound($services) - 1
;~             $services[UBound($services) - 1] = $objItem.Name
;~              $services[UBound($services) - 1] = $objItem.name ;& "[0]" & $objItem.State
;~          EndIf
        Next
        ConsoleWrite(1&@CRLF) ; only to see when it finish
.......

is the slow part that takes 30 secodns.

I do not know to go from here .. I did not write this function.
I would love if someone will help solve the problem ..

I do not know why this is happening .. maybe this giant loop?

Thanks for helpers!

Edited by gil900

Share this post


Link to post
Share on other sites



#3 ·  Posted (edited)

Changed or updated your security software?

I canceled my antivirus for the test to isolate the problem.

But even if the problem is antivirus related , I can not tell users to cancel their antivirus ..

I hope you understand. The code should work correctly under all conditions (or most conditions if all conditions is impossible).

im looking for a command for Command Prompt that will print for me list of all running services with their display names and the short services name.

that way, with this Command i can create alternate function that will do it through Command Prompt...

Edited by gil900

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Well, you can simply use the net start dos command :

#Include <Array.au3>

$iPid = Run(@ComSpec & " /c net start", @SystemDir, @SW_HIDE, 2)
ProcessWaitClose($iPid)

$sResult = _OEM2ANSI(StdoutRead($iPid)) ; needed for some languages (like french for me)

$aResult = StringRegExp($sResult, "(?m)^\h+(\N+)", 3)
_ArraySort($aResult)
_ArrayDisplay($aResult)


Func _OEM2ANSI($what)
    $ret = DllCall('user32.dll', 'Int', 'OemToChar', 'str', $what, 'str', '')
    Return $ret[2]
EndFunc   ;==>_OEM2ANSI
Edited by jguinch

Share this post


Link to post
Share on other sites

 

Well, you can simply use the net start dos command :

#Include <Array.au3>

$iPid = Run(@ComSpec & " /c net start", @SystemDir, @SW_HIDE, 2)
ProcessWaitClose($iPid)

$sResult = _OEM2ANSI(StdoutRead($iPid)) ; needed for some languages (like french for me)

$aResult = StringRegExp($sResult, "(?m)^\h+(\N+)", 3)
_ArraySort($aResult)
_ArrayDisplay($aResult)


Func _OEM2ANSI($what)
    $ret = DllCall('user32.dll', 'Int', 'OemToChar', 'str', $what, 'str', '')
    Return $ret[2]
EndFunc   ;==>_OEM2ANSI

I know. I tried it.

The problem is that it does not give the short names in the list.

I need also the short names

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

 

The problem is that it does not give the short names in the list.

In my code, _ArraySort($aResult) does the job, no ?

Did you try with sc query ?

#Include <Array.au3>

Local $iPid = Run(@ComSpec & " /c sc query", @SystemDir, @SW_HIDE, 2)
ProcessWaitClose($iPid)

Local $sResult = _OEM2ANSI(StdoutRead($iPid))

Local $aResult = StringRegExp($sResult, "(?mi)^(?:SERVICE_NAME|DISPLAY_NAME):\h*(\N+)", 3)

Local $aServices [ UBound($aResult) / 2][2], $n = 0
For $i = 0 To UBound($aResult) - 1  Step 2
    $aServices[$n][0] = $aResult[$i]
    $aServices[$n][1] = $aResult[$i + 1]
    $n += 1
Next

;_ArraySort($aServices) ; Sort by ShortName
_ArraySort($aServices, 0, 0, 0, 1) ; Sort by DisplayName
_ArrayDisplay($aServices)




Func _OEM2ANSI($what)
    $ret = DllCall('user32.dll', 'Int', 'OemToChar', 'str', $what, 'str', '')
    Return $ret[2]
EndFunc   ;==>_OEM2ANSI
Edited by jguinch

Share this post


Link to post
Share on other sites

 

In my code, _ArraySort($aResult) does the job, no ?

Did you try with sc query ?

#Include <Array.au3>

Local $iPid = Run(@ComSpec & " /c sc query", @SystemDir, @SW_HIDE, 2)
ProcessWaitClose($iPid)

Local $sResult = _OEM2ANSI(StdoutRead($iPid))

Local $aResult = StringRegExp($sResult, "(?mi)^(?:SERVICE_NAME|DISPLAY_NAME):\h*(\N+)", 3)

Local $aServices [ UBound($aResult) / 2][2], $n = 0
For $i = 0 To UBound($aResult) - 1  Step 2
    $aServices[$n][0] = $aResult[$i]
    $aServices[$n][1] = $aResult[$i + 1]
    $n += 1
Next

;_ArraySort($aServices) ; Sort by ShortName
_ArraySort($aServices, 0, 0, 0, 1) ; Sort by DisplayName
_ArrayDisplay($aServices)




Func _OEM2ANSI($what)
    $ret = DllCall('user32.dll', 'Int', 'OemToChar', 'str', $what, 'str', '')
    Return $ret[2]
EndFunc   ;==>_OEM2ANSI

Thank you!

You're an angel!

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

I did few adjustments. Please check if everything is fine

#Include <Array.au3>


;_ArraySort($aServices) ; Sort by ShortName

$aServices = _RetrieveRunningServices2(1)
_ArrayDisplay($aServices)



Func _RetrieveRunningServices2($Sort = 0)
    Local $Output[1][2] , $iPid , $sResult , $aResult
    $iPid = Run(@ComSpec & " /c sc query", @SystemDir, @SW_HIDE, 2)
    ProcessWaitClose($iPid)
    $sResult = DllCall('user32.dll', 'Int', 'OemToChar', 'str', StdoutRead($iPid), 'str', '')[2]
    $aResult = StringRegExp($sResult, "(?mi)^(?:SERVICE_NAME|DISPLAY_NAME):\h*(\N+)", 3)
    If IsArray($aResult) Then
        Local $aServices [(UBound($aResult) / 2)+1][2] , $n = 1
        For $i = 0 To UBound($aResult) - 1  Step 2
            $aServices[$n][0] = $aResult[$i]
            $aServices[$n][1] = $aResult[$i + 1]
            $n += 1
        Next
        If $Sort = 1 Then _ArraySort($aServices, 0, 0, 0, 1) ; Sort by DisplayName
        $aServices[0][0] = UBound($aServices)-1
        $Output = $aServices
    EndIf

    $Output[0][0] = UBound($Output)-1
    Return $Output
EndFunc

thanks!

Edited by gil900

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