Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using winapi with winim #37

Closed
mprkins opened this issue Apr 9, 2019 · 1 comment
Closed

Using winapi with winim #37

mprkins opened this issue Apr 9, 2019 · 1 comment

Comments

@mprkins
Copy link

mprkins commented Apr 9, 2019

Hello I am just trying to get some help as I am trying to use winim to use winapi in my program. So I am basically trying to port the following code in Nim.

#include <stdio.h>
#include <Windows.h>
int main()
{

//Open the Service Control Manager
SC_HANDLE sc = ::OpenSCManager (NULL,NULL,SC_MANAGER_ENUMERATE_SERVICE);
//Check if OpenSCManager returns NULL. Otherwise proceed
if (sc != NULL)
{
printf("Opened SCM using OpenSCManager n");
ENUM_SERVICE_STATUS service_data, *lpservice;
BOOL retVal;
DWORD bytesNeeded,srvCount,resumeHandle = 0,srvType, srvState;
srvType = SERVICE_WIN32;
srvState = SERVICE_STATE_ALL;
//Call EnumServicesStatus using the handle returned by OpenSCManager
retVal = ::EnumServicesStatus (sc,srvType,srvState,&service_data,sizeof(service_data),
&bytesNeeded,&srvCount,&resumeHandle);
DWORD err = GetLastError();
//Check if EnumServicesStatus needs more memory space
if ((retVal == FALSE) || err == ERROR_MORE_DATA)
{
DWORD dwBytes = bytesNeeded + sizeof(ENUM_SERVICE_STATUS);
lpservice = new ENUM_SERVICE_STATUS [dwBytes];
EnumServicesStatus (sc,srvType,srvState,lpservice,dwBytes,
&bytesNeeded,&srvCount,&resumeHandle);
}
printf("Count of NT Services using EnumServicesStatus : %dnn",srvCount);
for(int i=0;i<srvCount;i++)
{
printf("%sn",lpservice[i].lpDisplayName);
}
}

//Close the SC_HANLDE returned by OpenSCManager
CloseServiceHandle(sc);
}

Can you help me understand how the types/casting the types work with winim and how should I do it ?

import winim/lean,strformat

proc main =
    var hSCManager = OpenSCManagerW(
        nil,
        nil,
        SC_MANAGER_ENUMERATE_SERVICE
        )
        
    let errSCManager = GetLastError()
    echo fmt"OpenSCManager err: {errSCManager}"

    var
        dwServiceType: DWORD = SERVICE_WIN32
        dwServiceState: DWORD = SERVICE_STATE_ALL
        cbBufSize: DWORD = 256
        lpServices = addr cbBufSize 
        pcbBytesNeeded: DWORD
        lpServicesReturned: DWORD
        resumeHandle: DWORD


    let retVal = EnumServicesStatusW(
    hSCManager,
    dwServiceType,
    dwServiceState,
    cast [LPENUM_SERVICE_STATUSW](&lpServices),
    cbBufSize,   
    cast [ptr DWORD](&pcbBytesNeeded),
    cast [ptr DWORD](&lpServicesReturned),
    cast [ptr DWORD](&resumeHandle)
    )
    let errEnumServicesStatus = GetLastError()
    echo fmt"EnumServicesStatus: {errEnumServicesStatus} {pcbBytesNeeded}"

    if retVal == FALSE or errEnumServicesStatus == ERROR_MORE_DATA:
        var dwBytes: DWORD = cbBufSize + int32(sizeof(ENUM_SERVICE_STATUS))
        cbBufSize = cast[DWORD](&pcbBytesNeeded)
        # ???????
        # var lpServices = newSeq[ENUM_SERVICE_STATUS](dwBytes)
        EnumServicesStatusW(
            hSCManager,
            dwServiceType,
            dwServiceState,
            cast [LPENUM_SERVICE_STATUSW](&lpServices),
            cbBufSize,   
            cast [LPDWORD](&pcbBytesNeeded),
            cast [LPDWORD](&lpServicesReturned),
            cast [LPDWORD](&resumeHandle)
        )

        let errEnumServicesStatus = GetLastError()
        echo fmt"EnumServicesStatus: {errEnumServicesStatus} {pcbBytesNeeded}"
    # ?????
    # for i in 0..<cast[DWORD](lpServicesReturned):
    #     echo lpServices[i].lpDisplayName

when isMainModule:
    main()
@khchen
Copy link
Owner

khchen commented Apr 9, 2019

import winim/lean
import strformat except `&`

proc main =
  var sc = OpenSCManager(nil, nil, SC_MANAGER_ENUMERATE_SERVICE)

  if sc != 0:
    defer: CloseServiceHandle(sc)

    const
      srvType = SERVICE_WIN32
      srvState = SERVICE_STATE_ALL

    var bytesNeeded, srvCount, resumeHandle: DWORD

    # Use nil pointer in first call to avoid realloc the buffer later
    EnumServicesStatus(sc, srvType, srvState, nil, 0, &bytesNeeded, &srvCount,
      &resumeHandle)

    # Use string for the buffer, or you can use alloc() and then dealloc() later.
    var buffer = newString(bytesNeeded)

    # Cast the pointer to what EnumServicesStatus want.
    # Here &buffer = addr buffer[0]
    let lpService = cast[LPENUM_SERVICE_STATUS](&buffer)

    # We can access the low level c array easily by using Nim's UncheckedArray.
    let services = cast[ptr UncheckedArray[ENUM_SERVICE_STATUS]](lpService)

    EnumServicesStatus(sc, srvType, srvState, lpService, bytesNeeded,
      &bytesNeeded, &srvCount, &resumeHandle)

    echo fmt"Count of NT Services using EnumServicesStatus: {srvCount}"
    for i in 0..<srvCount:
      echo fmt"{services[i].lpServiceName}: {services[i].lpDisplayName}"

when isMainModule:
  main()

@khchen khchen closed this as completed Apr 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants