Как использовать EnumProcesses в node-ffi

#winapi #node-ffi

#winapi #узел-ffi

Вопрос:

Я пытался использовать EnumProcesses с node-ffi . Я получил код ниже:

 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
  }
}
  

Я пытался с ref.get , но столкнулся с ошибками:

     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)
  

Ошибки:

 RangeError [ERR_BUFFER_OUT_OF_BOUNDS]: Attempt to write outside buffer bounds
  

Кто-нибудь знает, как использовать node-ffi чтение данных массива из dll?

Комментарии:

1. Вам нужно использовать достаточно большой массив вместо указателя (который может содержать только 1 элемент), потому что трудно предсказать, сколько процессов будет во время вашего вызова EnumProcesses . Кстати, вы объявили тип параметра равным ulong , но передали ulong* , возможно, вы могли бы использовать ref-array , а затем передать count_of_array * sizeof_each_element в качестве 2-го параметра.

2. @DrakeWu-MSFT Спасибо за ваш комментарий! Вы спасли мне жизнь! Вчера я потратил целый день, чтобы решить эту проблему.

3. NP, и вы можете поделиться своим решением в качестве ответа и не стесняйтесь принимать его самостоятельно.

4. Опубликован окончательный код: P

Ответ №1:

Спасибо @DrakeWu-MSFT, я наконец-то получил свой код, вот как они выглядят, наконец:

 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 [];
    }
  }
}

  

Я боролся с получением данных массива из указателя, и это было неправильно, как сказал @DrakeWu-MSFT в комментарии, потому что я не выделил достаточно места для буфера, никакие данные не могут быть записаны в это. С ref-array и указателем на массив это работает как шарм.

Комментарии:

1. Небольшая проблема, cb должна быть длина массива (1024) * ulongSize , хотя 1024 достаточно для большинства случаев.

2. И вы также можете не стесняться принимать свои собственные ответы .