Skip to content

MESSAGETABLE resource issues

Paul McArrow edited this page Feb 13, 2023 · 4 revisions

Problem

  • No rule to compile messages.mc (or another *.mc file).
  • FormatMessage doesn't work as expected. The return code is 1813 (0x715) ERROR_RESOURCE_TYPE_NOT_FOUND "The specified resource type cannot be found in the image file". (String and other resources work as expected — the application, for instance, displays the provided icon.)
  • Events posted to the Application event log are displayed as errors, with a roughly similar diagnostic notice ("Message table cannot be found in the image file").

Analysis

The "official" steps to compile Windows resources are:

  1. [optional] *.mc to *.rc and **.bin with mc.exe (symbolic definitions of messages to binary);
  2. *.rc to *.res with rc.exe (symbolic definitions of everything else to binary);
  3. *.res to *.obj with cvtres.exe (proprietary binary *.res format to COFF object file)

windres implements steps 2 and 3, but there is no tool equivalent to the Message Compiler (MC) in the LLVM suite. One way around is to use the message compiler provided in Wine. However, while binary resources (e.g. MSG00409.bin where 0409 stands for English) produced by wmc are bit-exact matches of mc outputs, llvm-windres doesn't seem to compile them into object files correctly. Look at the following figure:

MESSAGETABLE-Screenshot 2023-02-12 114316

Top left is the llvm-windres-compiled and linked resource view by Visual Studio. Bottom right is a view of the same resources by Resource Hacker (a tool slightly newer than XN Resource Editor, albeit occasionally crashing when browsing large folders). Center is a view of a Message Table resource in one of the system binaries that exposes it in order to be an event source (i.e. event definition supplier for the Event Log).

Due to some parser omission or macro definition mismatch that we refrained from troubleshooting further, llvm-windres posts the message table as a user-defined binary resource under a literal type name "MESSAGETABLE", rather than a well-known resource of enumerated type 11 MESSAGETABLE.

Solution

Using both wmc and wrc fixes the issue. wrc only compiles to *.res, not to *.obj. Assuming that messages.rc are included into nssm.rc (that also contains other application resources, such as menues and dialogs), the command line arguments are as follows:

'$(wine_TOOLDIR)/wmc' -u -U messages.mc
iconv -f utf-16 -t utf-8 nssm.rc > nssm8.rc
'$(wine_TOOLDIR)/wrc' nssm8.rc --verbose '--include-dir=$(PREFIX)/$(TARGET)/include' -D_INC_VADEFS -o nssmwrc.res -O res
'llvm-cvtres' nssmwrc.res /VERBOSE /MACHINE:ARM /OUT:nssmwrc.o

Then add nssmwrc.o to the linker command line. Since it's a solitary object file, no command line switches are needed.

You may need to add (-D) other macro definitions, such as those from VS_FIXEDFILEINFO structure (verrsrc.h) which wrc does not provide by default. E.g. if your RC file contains the following section:

    FILEVERSION NSSM_VERSIONINFO
    PRODUCTVERSION NSSM_VERSIONINFO
    FILEFLAGSMASK VS_FF_DEBUG | VS_FF_PRERELEASE
#ifdef _DEBUG
    FILEFLAGS NSSM_FILEFLAGS | VS_FF_DEBUG
#else
    FILEFLAGS NSSM_FILEFLAGS
#endif
    FILEOS VOS__WINDOWS32
    FILETYPE VFT_APP
    FILESUBTYPE 0x0L

— set flags that apply (e.g. VOS_WINDOWS32) to their documented values and flags that don't apply (e.g. VS_FF_DEBUG) to 0.

Implementation notes

Depend on the wine-tools component (itself host-only).

The Wine build has to run a full project-wide ./configure pass; it's long, but not unbearably long. After that, only the tools are compiled and linked.

Validity

Wine tools are introduced by PR #29 (commit f094dac8f4fb0756324111f74cb3e6a24b7eba66).