Search code examples
winapinode-ffi

How to use EnumProcesses in node-ffi


I was trying to use EnumProcesses with node-ffi. I got code below:

import ffi from 'ffi'

export const psapi = ffi.Library('psapi', {
  EnumProcesses: ['bool', ['ulong', 'ulong', 'uint16*']]
})

export class Win32ProcessManager {
  public async getProcessList () {

    let lpidProcess = ref.alloc('ulong*')
    const cb = 1024
    const lpcbNeeded = ref.alloc('uint16*')

    const res = psapi.EnumProcesses(lpidProcess, cb, lpcbNeeded)

    const ulongSize = (ref as any).sizeof.ulong
    const totalBytesReturned = lpcbNeeded.readInt16LE()
    const processCount = totalBytesReturned / ulongSize
    console.log(`processCount: ${processCount}`)

    // ??? How to get the value from the lpidProcess?
    return lpidProcess
  }
}

I tried with ref.get but I encountered errors:

    let processId = ref.get(array, 0, ref.types.ulong)
    console.log(processId)
    const pointerSize = (ref as any).sizeof.pointer
    console.log(pointerSize)
    let processId2 = ref.get(array, (ref as any).sizeof.pointer, ref.types.ulong)
    console.log(processId2)

Errors:

RangeError [ERR_BUFFER_OUT_OF_BOUNDS]: Attempt to write outside buffer bounds

Anyone knows how to use node-ffi read the array data from dll?


Solution

  • Thanks @DrakeWu-MSFT, I finally got my code works, here are how they looks finally:

    import ffi from 'ffi';
    import ref from 'ref';
    import ArrayType from "ref-array";
    
    export const psapi = ffi.Library('psapi', {
      EnumProcesses: ['bool', ['ulong*', 'ulong', 'uint16*']],
    });
    
    export class Win32ProcessManager {
    
      public getProcessIdList (): number[] {
        const processIdLength = 1024;
        const ulongSize = (ref as any).sizeof.ulong;
        const cb = processIdLength * ulongSize;
        let processIdArray = ArrayType('ulong', processIdLength);
        let lpidProcess = ref.alloc(processIdArray);
        const lpcbNeeded = ref.alloc('uint16*');
    
        const res = psapi.EnumProcesses(lpidProcess, cb, lpcbNeeded);
    
        if (res) {
          const totalBytesReturned = lpcbNeeded.readInt16LE();
          const processCount = totalBytesReturned / ulongSize;
      
          const processArray = (lpidProcess as any).deref();
          let resultProcessArray: number[] = [];
          for (let i = 0; i < processCount; i++) {
            resultProcessArray.push(processArray[i]);
          }
      
          return resultProcessArray;
        } else {
          console.error(`Get process list failed with result from EnumProcess: ${res}`);
          return [];
        }
      }
    }
    
    

    I was struggled with getting array data from the pointer, and that was wrong, as @DrakeWu-MSFT said in the comment, because I didn't allocate enough spaces for the buffer, no data can be write into that. With ref-array and a pointer to the array, it works like a charm.