Win32 api format message with node-ffi

0

I am trying to use node-ffi to interface with the win32 api FormatMessageA however I cannot seem to get the out lpBuffer parameter, here is a snippet of code to show what I have tried

   'use strict';

   const ref = require('ref');
   const ffi = require('ffi');

   const Kernel32 = ffi.Library('Kernel32.dll', {
       FormatMessageA: ['ulong', [
           'ulong', //flags 
           'void *', 
           'ulong', //status number
           'ulong', //language 
           'uchar *',
           'ulong',
           'void *'
       ]]
   });


   const FORMAT_MESSAGE_FROM_SYSTEM = 0x1000;
   const FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100;
   const FORMAT_MESSAGE_IGNORE_INSERTS = 0x200;

   const lpBuffer = ref.alloc('uchar *'); 

   const result = Kernel32.FormatMessageA(
       FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
       null, 
       0x80090300, //error code
       0,
       lpBuffer,
       0, 
       null
   );

   console.log(result); //prints 57 bytes

I know function is successful as it returns 57 however I cannot get lpBuffer value which contains the error string I require.

winapi
kernel32
node-ffi
asked on Stack Overflow Mar 23, 2017 by simon-p-r • edited Mar 24, 2017 by simon-p-r

1 Answer

1

As I stated in my 1st comment, according to [MSDN] FormatMessage function:

  • FORMAT_MESSAGE_ALLOCATE_BUFFER description:

    The lpBuffer parameter is a pointer to an LPTSTR; you must cast the pointer to an LPTSTR (for example, (LPTSTR)&lpBuffer).

  • The (2nd) example at the bottom of the page:

    // Some code (not relevant for this problem)
    LPWSTR pBuffer = NULL;
    // Some more code (still not relevant)
    FormatMessage(FORMAT_MESSAGE_FROM_STRING |
                  FORMAT_MESSAGE_ALLOCATE_BUFFER,
                  pMessage, 
                  0,
                  0,
                  (LPWSTR)&pBuffer,
    // The rest of the code (not relevant)
    

when the dwFlags argument is composed of FORMAT_MESSAGE_ALLOCATE_BUFFER, the function expects that the lpBuffer argument which is a LPTSTR (pointer to TCHAR), to actually be a pointer to LPTSTR (double pointer to TCHAR) cast ed to LPTSTR.

That, translated in JS (that I have no experience with), would mean:

const lpBuffer = ref.alloc('uchar **');

Note: according to the same page, the buffer should be freed using LocalFree when it's no longer needed (makes sense, since FormatMessage allocates memory for it - that's why it requires to be a double pointer). Again, don't know how this would translate in JS (what I do know is that LocalFree should be called on an uchar *(dereferenced) buffer, not directly on lpBuffer).

answered on Stack Overflow Mar 24, 2017 by CristiFati

User contributions licensed under CC BY-SA 3.0