Does anybody use kernel32::FormatMessage?

To add comments, please log in or register
Amy Liu
956
Amy Liu  

Ref: https://docs.microsoft.com/en-us/windows/desktop/api/WinBase/nf-winbase-formatmessage

Below code is the syntax:

DWORD FormatMessage(
  DWORD   dwFlags,
  LPCVOID lpSource,
  DWORD   dwMessageId,
  DWORD   dwLanguageId,
  LPTSTR  lpBuffer,
  DWORD   nSize,
  va_list *Arguments
);

In my MQL4 code, I import it first like this:

#import "kernel32.dll" 
uint GetLastError(void);
uint FormatMessage(
  uint         dwFlags,
  uint/ulong   lpSource,
  uint         dwMessageId,
  uint         dwLanguageId,
  ushort       &lpBuffer[],
  uint         nSize,
  ulong        Arguments
);
#import

DWORD is 32 bit unsigned, so use uint to replace DWORD.

LPCVOID lpSource has the follow description in ms article:

lpSource

The location of the message definition. The type of this parameter depends upon the settings in the dwFlagsparameter.

dwFlags SettingMeaning
FORMAT_MESSAGE_FROM_HMODULE0x00000800A handle to the module that contains the message table to search.
FORMAT_MESSAGE_FROM_STRING0x00000400Pointer to a string that consists of unformatted message text. It will be scanned for inserts and formatted accordingly.
 

If neither of these flags is set in dwFlags, then lpSource is ignored.


This means lpsource is a handle or pointer, so we can try uint or ulong.

LPTSTR  lpBuffer is a pointer to a 16 bit UNICODE character buffer, so we can pass ushort array to get the string.

va_list *Arguments is a little complicated but the key information is here:

If you do not have a pointer of type va_list*, then specify the FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array of DWORD_PTR values; those values are input to the message formatted as the insert values. Each insert must have a corresponding element in the array.

and combine the upper information with below:

Security Remarks

If this function is called without FORMAT_MESSAGE_IGNORE_INSERTS, the Arguments parameter must contain enough parameters to satisfy all insertion sequences in the message string, and they must be of the correct type. Therefore, do not use untrusted or unknown message strings with inserts enabled because they can contain more insertion sequences than Arguments provides, or those that may be of the wrong type. In particular, it is unsafe to take an arbitrary system error code returned from an API and use FORMAT_MESSAGE_FROM_SYSTEM withoutFORMAT_MESSAGE_IGNORE_INSERTS.

So va_list *Arguments can be a 64 bit pointer when ulong can be used.

and ref to an example of use FormatMessage to get system error description: https://docs.microsoft.com/zh-cn/windows/desktop/Debug/retrieving-the-last-error-code

FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

I then use the imported function like this:

uint dwFlags=FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM;
ulong/uint lpSource=NULL;   //Try both ulong and uint
uint dwLastError=kernel32::GetLastError();
uint dwLanguageId=0;
ushort usMessage[100];
uint nSize=100;
ulong Arguments=NULL;
FormatMessage(dwFlags,lpSource,dwLastError,dwLanguageId,usMessage,nSize,Arguments);

But when my code run to FormatMessage line, it generates errors of "Cannot find 'FormatMessage' in 'kernel32.dll'" and "unresolved import function call". Can anybody help? Thank you very much!


FormatMessage function (winbase.h)
FormatMessage function (winbase.h)
  • 2018.12.05
  • windows-sdk-content
  • docs.microsoft.com
Formats a message string. Use this kernel 32 function to get system error descriptions.
alphatrading
95
alphatrading  
 LPTSTR  lpBuffer

is a pointer to a non-constant TCHAR. TCHAR being either a simple char or a wide char depending on whether UNICODE is defined in your project.

Means from MQL you either have to use FormatMessageA() or  FormatMessageW(). As you use MQL5, in your case you have to use the wide char version.

Use the context help of Visual Studio, or PE Explorer from HeavenTools to quickly find out how a specific function is exported by a DLL.

William Roeder
18310
William Roeder  
  1. alphatrading: have to use FormatMessageA() or  FormatMessageW().
    Strings are all wide since Build 600 and Higher (17.02.2014)

  2. Amy Liu: Ref: https://docs.microsoft.com/en-us/windows/desktop/api/WinBase/nf-winbase-formatmessage
    Please use the link button Use the link button See the difference? https://docs.microsoft.com/en-us/windows/desktop/api/WinBase/nf-winbase-formatmessage
              Messages Editor

Amy Liu
956
Amy Liu  
whroeder1:
  1. Strings are all wide since Build 600 and Higher (17.02.2014)

  2. Please use the link button See the difference? https://docs.microsoft.com/en-us/windows/desktop/api/WinBase/nf-winbase-formatmessage
              Messages Editor

Thank you. I have edited the original post to use link button.

To add comments, please log in or register