April 30, 2024, 05:53:54 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Understanding / translating imports and include files

Started by Andy, September 12, 2016, 11:36:49 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

I'm now trying to enumerate windows services.

There are several functions I need which are in the Windows.inc file,
and several in the Winsvc.inc file.

When I look at windows.inc, I see imports like this:
DECLARE IMPORT, _ChangeServiceConfig ALIAS ChangeServiceConfigA(hService AS INT,dwServiceType AS INT,dwStartType AS INT,dwErrorControl AS INT,lpBinaryPathName AS STRING,lpLoadOrderGroup AS STRING,lpdwTagId AS POINTER,lpDependencies AS STRING,lpServiceStartName AS STRING,lpPassword AS STRING,lpDisplayName AS STRING),INT
DECLARE IMPORT, _CloseServiceHandle ALIAS CloseServiceHandle(hSCObject AS INT),INT
DECLARE IMPORT, _ControlService ALIAS ControlService(hService AS INT,dwControl AS INT,lpServiceStatus AS SERVICE_STATUS),INT
DECLARE IMPORT, _CreateService ALIAS CreateServiceA(hSCManager AS INT,lpServiceName AS STRING,lpDisplayName AS STRING,dwDesiredAccess AS INT,dwServiceType AS INT,dwStartType AS INT,dwErrorControl AS INT,lpBinaryPathName AS STRING,lpLoadOrderGroup AS STRING,lpdwTagId AS POINTER,lpDependencies AS STRING,lp AS STRING,lpPassword AS STRING),INT
DECLARE IMPORT, _DeleteService ALIAS DeleteService(hService AS INT),INT
DECLARE IMPORT, _EnumDependentServices ALIAS EnumDependentServicesA(hService AS INT,dwServiceState AS INT,lpServices AS ENUM_SERVICE_STATUS,cbBufSize AS INT,pcbBytesNeeded AS POINTER,lpServicesReturned AS POINTER),INT


I.e. Pointers, strings, ints defined, and yet, when I look at winsvc.inc I see things like this:

declare import, OpenSCManager alias OpenSCManagerW(LPCWSTR lpMachineName,LPCWSTR lpDatabaseName,DWORD dwDesiredAccess),SC_HANDLE

type ENUM_SERVICE_STATUS
LPTSTR lpServiceName
LPTSTR lpDisplayName
SERVICE_STATUS ServiceStatus
endtype


So I have to try and translate this to IWB, and I'm never sure I've got it right...

DECLARE IMPORT, OpenSCManager ALIAS OpenSCManagerA(lpMachineName AS POINTER,lpDatabaseName AS POINTER,dwDesiredAccess AS INT),INT

There are many examples in VB and c++ to enumerate services, but they seem to use the format of the winsvc.inc file:

BOOL WINAPI EnumServicesStatus(
  _In_        SC_HANDLE             hSCManager,
  _In_        DWORD                 dwServiceType,
  _In_        DWORD                 dwServiceState,
  _Out_opt_   LPENUM_SERVICE_STATUS lpServices,
  _In_        DWORD                 cbBufSize,
  _Out_       LPDWORD               pcbBytesNeeded,
  _Out_       LPDWORD               lpServicesReturned,
  _Inout_opt_ LPDWORD               lpResumeHandle
);


The next problem is then re-coding these examples into IWB.

Questions:
1. Why are the two include files different - e.g. with / without pointers/strings/int's?
2. Which route do I go down to enum services as I need the winsvc.inc functions, i.e. do I translate them?
3. If I have to translate them, how do I know what should be a pointer, int, uint, string etc?

That said, I did translate the functions so I could start and delete a service, but enumerating services is more complicated. 

Thanks,
Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

TYPE ENUM_SERVICE_STATUS
DEF lpServiceName:STRING
DEF lpDisplayName:STRING
DEF ServiceStatus:SERVICE_STATUS

ENDTYPE

DECLARE IMPORT, EnumServicesStatus Alias EnumServicesStatusA(hSCManager:INT, dwServiceType:INT, dwServiceState:INT, lpServices:ENUM_SERVICE_STATUS, cbBufSize:INT, pcbBytesNeeded:INT, lpServicesReturned:INT, lpResumeHandle:INT),INT

DECLARE IMPORT, OpenSCManager Alias OpenSCManagerA (lpMachineName:STRING, lpDatabaseName:STRING, dwDesiredAccess:INT),INT




I get the definitions from the APIVIEWER 2004 utility



LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

LarryMc

Quote from: Andy on September 12, 2016, 11:36:49 PM


Questions:
1. Why are the two include files different - e.g. with / without pointers/strings/int's?
2. Which route do I go down to enum services as I need the winsvc.inc functions, i.e. do I translate them?
3. If I have to translate them, how do I know what should be a pointer, int, uint, string etc?

1.the windows.inc file was created way back to support the original language and had always been part of the base distribution. I was created so that the core windows declarations would be available to support the language.
I always suggest that instead of using "windows.inc" in your apps you use "windowssdk.inc".  A lot more definitions are taken care of for you and it doesn't make your programs any bigger.
If you use windowssdk.inc  a lot of item 2  and 3 take care of themselves.

But, as I mentioned above, if you install the APIViewer 2004 you will have most of the Definitions and Constants to look at to see what they are in terms of IWBasic.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Larry,

The ApiViewer is very very helpful, I remember now you told me about this a long time ago.

I had a look then, but frankly, I didn't understand at the time what it was telling me!  :'( (but I do now).  :)

So as far as I can work out (providing I've got this right):

The defines -
Long = Int64
Char = Char
String = String
Bool = Int

But what about ByVal and ByRef and Pointers - what is the IWB equivalent for these please?

Where something is defined as ByRef, it looks like in IWB it should be a pointer, is that correct?

ByVal x AS Long = x as INT64
ByVal y AS String = x as String
ByRef z AS Long = z as Pointer?

Thanks,
Andy.

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Quote from: Andy on September 13, 2016, 06:57:51 AM

So as far as I can work out (providing I've got this right):

The defines -
Long = Int64
Char = Char
String = String
Bool = Int

But what about ByVal and ByRef and Pointers - what is the IWB equivalent for these please?

Where something is defined as ByRef, it looks like in IWB it should be a pointer, is that correct?

ByVal x AS Long = x as INT64
ByVal y AS String = x as String
ByRef z AS Long = z as Pointer?

Thanks,
Andy.

On 32-bit compilers INT and LONG are usually the same (4 bytes) and INT64 is twice as long (8 bytes). On procedure declaration ByRef means variable is passed by using memory address (a reference to original object) and ByVal means variable is passed by using value (a copy). Some variable types in IWB are reference types and some are value types.

jalih

Quote from: Andy on September 12, 2016, 11:36:49 PM

So I have to try and translate this to IWB, and I'm never sure I've got it right...

DECLARE IMPORT, OpenSCManager ALIAS OpenSCManagerA(lpMachineName AS POINTER,lpDatabaseName AS POINTER,dwDesiredAccess AS INT),INT


I would simply translate function declaration for IWB as:

DECLARE IMPORT, OpenSCManager ALIAS OpenSCManagerA(lpMachineName AS STRING,lpDatabaseName AS STRING,dwDesiredAccess AS INT),INT

Andy

Jalih, thanks for the input.

I decided to re-translate the CreateService function (based on the APIViewer information) to:

CreateService ALIAS CreateServiceA(hSCManager AS INT,lpServiceName AS string,lpDisplayName AS string,dwDesiredAccess AS INT,dwServiceType AS INT,dwStartType AS INT,dwErrorControl AS INT,lpBinaryPathName AS string,lpLoadOrderGroup AS string,lpdwTagId AS POINTER,lpDependencies AS string,lp AS pointer,lpPassword AS string),INT

with one exception, the next to the last parameter
(lp AS pointer), the viewer states this is a string, but when I make it a string CreateService gives a logon error when run.

Defined as a pointer and passing a zero for this value works.

Parameters lp and lpPassword are optional parameters.

This could just be MS making things difficult, but it still leaves me with a problem / question...
where a string is stated, is it better to declare it as a pointer?
and what should you pass if the parameter can be optional (NULL, 0, "")?
how can a parameter that should be a string accept a zero?

Obviously the API Viewer is the way to go, but it still leaves me with some doubts as to what should be what, (string or pointer etc).

The CreateService import was using pointers in place of strings and worked.

Every parameter type MS states as LPCTSTR, is shown as a string in the API viewer.

Confused!
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Quote from: Andy on September 13, 2016, 10:17:17 PM

I decided to re-translate the CreateService function (based on the APIViewer information) to:

CreateService ALIAS CreateServiceA(hSCManager AS INT,lpServiceName AS string,lpDisplayName AS string,dwDesiredAccess AS INT,dwServiceType AS INT,dwStartType AS INT,dwErrorControl AS INT,lpBinaryPathName AS string,lpLoadOrderGroup AS string,lpdwTagId AS POINTER,lpDependencies AS string,lp AS pointer,lpPassword AS string),INT

with one exception, the next to the last parameter
(lp AS pointer), the viewer states this is a string, but when I make it a string CreateService gives a logon error when run.

Defined as a pointer and passing a zero for this value works.

It should also work, if you define it as a string and pass NULL or 0 for it

C uses NULL terminated strings and string are passed by reference (address), so using pointer  or int with address works also.

I you pass NULL as this parameter CreateService uses LocalSystem account, if you pass string then it must match with service type.

Quote from: Andy
and what should you pass if the parameter can be optional (NULL, 0, "")?

Using NULL or 0 is usually a safe bet.

Andy

Thanks Jalih for all your help - just trying to work through it as we speak.

Andy,
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

QuoteUsing NULL or 0 is usually a safe bet.
To get get it to compile but not to get it to work.
You're still going to to have to look up the function in the sdk and sort it out there (but you already know that). ;)
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Larry,

Funny you should say that, that's what I'm trying to do now with some functions.

I'm now trying to do two things:

1. Stop a service
2. Enumerate services.

At the moment I'm trying to stop the example service that I can create and start.

The process begins with OpenSCManager, secondly OpenService, I can do both, but the next part is
QueryServiceStatusEx.

I'm struggling with the last three parameters:

Here is a link from MSDN (c++ example).
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686335(v=vs.85).aspx

This is where I got up to so far...

'NOTE
'Compile and run the exe as Admin.

$Include "Windowssdk.inc"

DECLARE IMPORT, _CloseServiceHandle ALIAS CloseServiceHandle(hSCObject AS INT),INT
DECLARE IMPORT, _GetLastError ALIAS GetLastError(),INT
DECLARE IMPORT, _FormatMessage ALIAS FormatMessageA(dwFlags AS INT,lpSource AS POINTER,dwMessageId AS INT,dwLanguageId AS INT,lpBuffer AS STRING,nSize AS INT,Arguments AS POINTER),INT

'CONST SERVICE_ERROR_NORMAL = 0x1
'CONST SERVICE_DEMAND_START = 0x3
'CONST SERVICE_WIN32_OWN_PROCESS = 0x10
'const SC_MANAGER_CREATE_SERVICE = 0x2
'const SC_MANAGER_ALL_ACCESS = 0xF003F

DEF MyService,XB,ErMes,Display AS String
DEF TagId,nSize,Arguments AS Uint

nSize = 255
MyService ="IWBrules"     ' A name for the service.
Display ="IWBDisplayName" ' A display name for the service.

OPENCONSOLE 'So we can see if there are any errors.
print
print


'==========================================================
'Step 1 - open a connection to the service control manager.
'==========================================================

hSCManager = OpenSCManager("",0,SC_MANAGER_ALL_ACCESS)
IF hSCManager = 0 THEN
   Error1 = _GetLastError ()
   _FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,Error1,0,ErMes,nSize,Arguments)
   Print "  Error by OSCM: ",ErMes

_CloseServiceHandle(hSCManager)

print
print
print "  Press any key to close..."
print
DO:UNTIL INKEY$<>""
   end

else
print
print "  Service manager opened..."
print
ENDIF


'==========================
'Step 2 - open the service.
'==========================

hService = OpenService(hSCManager,MyService,SC_MANAGER_ALL_ACCESS)
IF hService = 0 THEN
   Error2 = _GetLastError ()
   _FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,Error2,0,ErMes,nSize,Arguments)
   Print "  Error by Open Service: ",ErMes

_CloseServiceHandle(hSCManager)

print
print
print "  Press any key to close..."
print
DO:UNTIL INKEY$<>""
   end

else
print
print "  Service was found..."
print
ENDIF


Next comes the query stage - and how to pass / get the last three parameters,
for QueryServiceStatusEx - (pointer lpBuffer,DWORD cbBufSize,pointer pcbBytesNeeded).

And this has me scratching my head... ??

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy


I have now managed to get the QueryServiceStatusEx function working!

It's not perfect yet, and It's designed to stop my example service
MyService ="IWBrules" - so if you want to try this you will need the example service I posted in User offerings first.

It doesn't check yet if there are any dependent services, and does give some array warnings, but it does stop the service.

I was able to change the MyService string to try and stop Adobe update service ("AdobeARMservice") - which it did!

Attached is the code.

Andy,
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Quote from: Andy on September 16, 2016, 12:00:13 AM

... and does give some array warnings, but it does stop the service.


Array warnings are due to you trying to use use ServiceStatus structure as an array of structures when printing QueryServiceStatusEx results. Your results are not correct either as QueryServiceStatusEx don't get ServiceStatus structure at all as parameter.

You should define your xbuffer as pointer and reserve space for it with NEW. To read results from buffer, just cast the pointer as SERVICE_STATUS_PROCESS to get access to the structure members.

Also you can get the required buffer size by calling QueryServiceStatusEx with lpBuffer as NULL and cbBufSize as 0. Function then returns ERROR_INSUFFICIENT_BUFFER error and the pcbBytesNeeded parameter will receive the required size. After that you can reserve space for the buffer and call QueryServiceStatusEx function again with correct parameter values.

Andy

Jalih,

QuoteYou should define your xbuffer as pointer and reserve space for it with NEW. To read results from buffer, just cast the pointer as SERVICE_STATUS_PROCESS to get access to the structure members.

I appreciate you are trying to help (and many thanks) but you've lost me now.

Are you saying something like this:

def Xbuffer as pointer
Xbuffer = new SERVICE_STATUS_PROCESS


or

def Xbuffer as pointer
Xbuffer = new (SERVICE_STATUS_PROCESS,1000) etc??

And do I now need to change the QueryServiceStatusEx parameters, if so to what?


Also with:
QueryServiceStatusEx(hService,SC_STATUS_PROCESS_INFO,&Xbuffer,8192,&Bneeded)

how do I display the details of the service as Xbuffer is now a pointer so I cannot use:
PRINT   "  Type     ",ServiceStatus[0].dwServiceType

I do understand about letting QueryServiceStatusEx fail to get the bytes needed, it was just quicker at this stage to put in 8192.

When I try NULL and 0 the message I get is
"The data area passed to a system call is too small" and not ERROR_INSUFFICIENT_BUFFER??

Windows 10 32 bit O/S.

Thanks.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

September 17, 2016, 12:09:49 AM #14 Last Edit: September 17, 2016, 06:53:14 AM by jalih
Quote from: Andy on September 16, 2016, 09:34:40 PM

Are you saying something like this:

def Xbuffer as pointer
Xbuffer = new SERVICE_STATUS_PROCESS


or

def Xbuffer as pointer
Xbuffer = new (SERVICE_STATUS_PROCESS,1000) etc??

And do I now need to change the QueryServiceStatusEx parameters, if so to what?


Also with:
QueryServiceStatusEx(hService,SC_STATUS_PROCESS_INFO,&Xbuffer,8192,&Bneeded)

how do I display the details of the service as Xbuffer is now a pointer so I cannot use:
PRINT   "  Type     ",ServiceStatus[0].dwServiceType

I do understand about letting QueryServiceStatusEx fail to get the bytes needed, it was just quicker at this stage to put in 8192.

This is not tested but something like:


qs = QueryServiceStatusEx(hService,SC_STATUS_PROCESS_INFO,NULL,0,&Bneeded)
if  !qs then
if _GetLastError() = ERROR_INSUFFICIENT_BUFFER then
Xbuffer = new(char, Bneeded)
qs = QueryServiceStatusEx(hService,SC_STATUS_PROCESS_INFO,Xbuffer,Bneeded,&Bneeded)
' Now get and display the results using type cast
print #<SERVICE_STATUS_PROCESS>Xbuffer.dwCurrentState
'Free the buffer
delete Xbuffer
endif
endif


As I look for WinAPI definition, it seems currently QueryServiceStatusEx returns just one information level, so the required buffer size should always be the same.

try correcting your declaration of  ServiceStatus variable to:


def ServiceStatus as SERVICE_STATUS_PROCESS


and try calling  QueryServiceStatusEx as:


qs = QueryServiceStatusEx(hService,SC_STATUS_PROCESS_INFO,&ServiceStatus, sizeof(SERVICE_STATUS_PROCESS), &Bneeded)


Next correct print statements: remove array indexes  after ServiceStatus.


Andy

Jalih,

Thank you so much - I was able to correct the code with your help and now it runs correctly.

Attached is a copy of the new code (stop2.iwb).

I am also looking an enumerating services with EnumServicesStatusEx, in the mean time I have written some code to list all services (which are listed in the registry).

The output is a text file "AsreviceList.txt" stored in the same path as the program (regservices).

Anyone who wants to try this needs to first download my Registry.inc file and save it in the IWBDev Includes folder before compiling regservices.iwb.

regservices.exe needs to be run as an Administrator.


The text output file should mirror what you see under "Services" in Task Manager.

Attached are the files.

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

September 17, 2016, 03:57:50 AM #16 Last Edit: September 17, 2016, 05:44:28 AM by jalih
Quote from: Andy on September 17, 2016, 01:12:38 AM

I am also looking an enumerating services with EnumServicesStatusEx...


Here is a HotBasic version of EnumServicesStatus sample program:


$APPTYPE CONSOLE: $TYPECHECK ON

$define SERVICE_WIN32 &h30 'SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS
$define SERVICE_DRIVER 11 'SERVICE_DRIVER = SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER or SERVICE_RECOGNIZER_DRIVER
$define SC_MANAGER_ALL_ACCESS &hF003F 'SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SC_MANAGER_CONNECT or SC_MANAGER_CREATE_SERVICE or SC_MANAGER_ENUMERATE_SERVICE or SC_MANAGER_LOCK or SC_MANAGER_QUERY_LOCK_STATUS or SC_MANAGER_MODIFY_BOOT_CONFIG
$define SERVICE_STATE_ALL 3 'SERVICE_STATE_ALL = SERVICE_ACTIVE or SERVICE_INACTIVE
$define ERROR_MORE_DATA 234 'ERROR_MORE_DATA
$define SC_ENUM_PROCESS_INFO 0 'SC_ENUM_PROCESS_INFO


type SERVICE_STATUS
dwServiceType as long
dwCurrentState as long
dwControlsAccepted as long
dwWin32ExitCode as long
dwServiceSpecificExitCode as long
dwCheckPoint as long
dwWaitHint as long
end type


type ENUM_SERVICE_STATUS
lpServiceName as long 'string pointer
lpDisplayName as long 'string pointer
ServiceStatus as SERVICE_STATUS
end type


declare function OpenSCManager lib "advapi32" alias "OpenSCManagerA" (lpMachineName as long, lpDatabaseName as long, dwDesiredAccess as long) as long
declare function CloseServiceHandle lib "advapi32" (hSCObject as long) as long
declare function EnumServicesStatus lib "advapi32" alias "EnumServicesStatusA" (hSCManager as long, dwServiceType_ as dword, dwServiceState as dword, lpServices as long, cbBufSize as long, pcbBytesNeeded as long, lpServicesReturned as long, lpResumeHandle as long) as long


dim service as ENUM_SERVICE_STATUS

defdword dwBytesNeeded = 0;
defdword dwServicesReturned = 0;
defdword dwResumedHandle = 0;
defdword dwServiceType = SERVICE_WIN32 or SERVICE_DRIVER

deflng hHandle = OpenSCManager(0,0, SC_MANAGER_ALL_ACCESS)
if not hHandle then
print "Unable to open SCM, error: "
print getlasterror
Application.Terminate
else
print "SCM opened sucessfully"
print " "
end if

deflng retVal = EnumServicesStatus(hHandle, dwServiceType, SERVICE_STATE_ALL, @service, sizeof(ENUM_SERVICE_STATUS), @dwBytesNeeded,@dwServicesReturned,@dwResumedHandle)

if not retVal then
if getlasterror = ERROR_MORE_DATA then
deflng dwBytes = sizeof(ENUM_SERVICE_STATUS) + dwBytesNeeded
dim pServices as memory
pServices.initialize  dwBytes
retVal = EnumServicesStatus(hHandle, dwServiceType, SERVICE_STATE_ALL, pServices.pointer,dwBytes, @dwBytesNeeded, @dwServicesReturned,@dwResumedHandle)
defint  i
for i = 1 to dwServicesReturned
pServices.readUDT(service)
print byref$(service.lpServiceName)
next i
pServices.close
end if
end if

if not CloseServiceHandle(hHandle) then
print "Unable to close SCM, error:"
print getlasterror
else
print " "
print "SCM closed succesfully!"
end if

pause
end


HotBasic type checking doesn't allow passing 0 as string, so I declare all optional string parameters as long. Also, I use MEMORY object to handle required buffer operations instead of NEW/DELETE + pointer stuff. Note that, HotBasic uses @ instead of  C-style & to get address of a variable.

IWB is a lot faster to work with than HotBasic but for some perverse reason I still like working with HotBasic, also it's compiled executable size 
is hard to beat (8K for this sample).

Andy

Thanks Jalih as always,

I will look into that code as soon as I can.

I can get most of the information out of the registry (don't worry, this really is an area I'm very very good at), and I will try to combine it with QueryServicesStaus to produce a list of services and their current states.

I will try to post this alternative as soon as I can.

Thanks again,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Quote from: Andy on September 17, 2016, 06:30:45 AM
I will try to post this alternative as soon as I can.

Here is a IWB version, using winapi declarations from windowssdk.inc.


$Include "Windowssdk.inc"

dim service as ENUM_SERVICE_STATUS

uint dwBytesNeeded = 0
uint dwServicesReturned = 0
uint dwResumedHandle = 0
uint dwServiceType = SERVICE_WIN32 | SERVICE_DRIVER

int hHandle = OpenSCManager(0,0, SC_MANAGER_ALL_ACCESS)
if !hHandle then
print "Unable to open SCM, error: "
print GetLastError()
else
print "SCM opened sucessfully"
end if

int retVal = EnumServicesStatus(hHandle, dwServiceType, SERVICE_STATE_ALL, &service, sizeof(ENUM_SERVICE_STATUS), &dwBytesNeeded,&dwServicesReturned,&dwResumedHandle)

if not retVal then
if GetLastError() = ERROR_MORE_DATA then
UINT dwBytes = sizeof(ENUM_SERVICE_STATUS) + dwBytesNeeded
pointer p
p = NEW(char, dwBytes)
retVal = EnumServicesStatus(hHandle, dwServiceType, SERVICE_STATE_ALL, p, dwBytes, &dwBytesNeeded, &dwServicesReturned, &dwResumedHandle)
int  i
for i = 0 to dwServicesReturned-1
print #<ENUM_SERVICE_STATUS>p[i].lpServiceName
next i
DELETE p
end if
end if

if !CloseServiceHandle(hHandle) then
print "Unable to close SCM, error:"
print GetLastError()
else
print "SCM closed succesfully!"
end if

do:until inkey$ <> ""
end


Just noticed and fixed: my previous samples had ! operator mixed with NOT keyword. I mainly program in PL/I and HotBasic, so it sometimes happens.

Andy

Jalih,

That's more great work - thank you!

I've amended the code to query each service and display the details.

Attached is the amended code.

One more question, the name of the service is stored here:
#<ENUM_SERVICE_STATUS>p.lpServiceName - which is a pointer.

How can I pass this service name to a string?

Thanks,
Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Quote from: Andy on September 17, 2016, 10:36:08 PM

One more question, the name of the service is stored here:
#<ENUM_SERVICE_STATUS>p.lpServiceName - which is a pointer.

How can I pass this service name to a string?


You use a pointer:  IWB's type checking requires the use of type casting:


pointer p = #<ENUM_SERVICE_STATUS>p[i].lpServiceName
string s =  #<string>p


Andy

Jalih,

Thanks, that works.

I have also found that this works too:

int hh
char bufferz [500]
for hh = 0 to 499
     bufferz[hh] = ""
next hh

string Sname = ""
sprintf(bufferz, *<ENUM_SERVICE_STATUS>p[i].lpServiceName)

for hh = 0 to 499
     Sname = Sname + bufferz[hh]
next hh

print "  Service name as a string ",Sname


and requires $include "stdio.inc" at the start of the source code.

I can now get extra information about each service from the registry as the service names can be stored as strings for cross referencing.

Thanks again!
Andy.

Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

Now, all this gives me an idea.

I wrote an alternative task manager program, but services were not included.

So, I think I will update my task manager with a services window.

See attached screenshot.

One thing though, some services I cannot access due to access rights, so I cannot determine if they are running or not - It's a shame, and I don't know why!

Thanks,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.