[llvm] 8b356f4 - [llvm-rc] add support for MENUEX (#67464)

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 6 00:51:01 PDT 2023


Author: oltolm
Date: 2023-10-06T10:50:57+03:00
New Revision: 8b356f496b18d89d58820494b0f806b38822ebb9

URL: https://github.com/llvm/llvm-project/commit/8b356f496b18d89d58820494b0f806b38822ebb9
DIFF: https://github.com/llvm/llvm-project/commit/8b356f496b18d89d58820494b0f806b38822ebb9.diff

LOG: [llvm-rc] add support for MENUEX (#67464)

Fixes #39455.

Added: 
    llvm/test/tools/llvm-rc/Inputs/menuex.rc
    llvm/test/tools/llvm-rc/menuex.test

Modified: 
    llvm/tools/llvm-rc/ResourceFileWriter.cpp
    llvm/tools/llvm-rc/ResourceFileWriter.h
    llvm/tools/llvm-rc/ResourceScriptParser.cpp
    llvm/tools/llvm-rc/ResourceScriptParser.h
    llvm/tools/llvm-rc/ResourceScriptStmt.cpp
    llvm/tools/llvm-rc/ResourceScriptStmt.h
    llvm/tools/llvm-rc/ResourceVisitor.h

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-rc/Inputs/menuex.rc b/llvm/test/tools/llvm-rc/Inputs/menuex.rc
new file mode 100644
index 000000000000000..766fffe03b87d9b
--- /dev/null
+++ b/llvm/test/tools/llvm-rc/Inputs/menuex.rc
@@ -0,0 +1,14 @@
+101 MENUEX
+BEGIN
+    POPUP "File",                                           40182
+    BEGIN
+        MENUITEM "Load",                                    40011
+        MENUITEM "", 0, 0x00000800L
+
+        POPUP "Savestate Slot",                             40187
+        BEGIN
+            MENUITEM "&1",                                  40099
+            MENUITEM "&2",                                  40100
+        END
+    END
+END

diff  --git a/llvm/test/tools/llvm-rc/menuex.test b/llvm/test/tools/llvm-rc/menuex.test
new file mode 100644
index 000000000000000..2a51ffd110419c7
--- /dev/null
+++ b/llvm/test/tools/llvm-rc/menuex.test
@@ -0,0 +1,25 @@
+; RUN: llvm-rc -no-preprocess /FO %t -- %p/Inputs/menuex.rc
+; RUN: llvm-readobj %t | FileCheck %s
+
+CHECK:      Resource type (int): MENU (ID 4)
+CHECK-NEXT: Resource name (int): 101
+CHECK-NEXT: Data version: 0
+CHECK-NEXT: Memory flags: 0x1030
+CHECK-NEXT: Language ID: 1033
+CHECK-NEXT: Version (major): 0
+CHECK-NEXT: Version (minor): 0
+CHECK-NEXT: Characteristics: 0
+CHECK-NEXT: Data size: 164
+CHECK-NEXT: Data: (
+CHECK-NEXT:   0000: 01000400 00000000 00000000 00000000  |................|
+CHECK-NEXT:   0010: F69C0000 81004600 69006C00 65000000  |......F.i.l.e...|
+CHECK-NEXT:   0020: 00000000 00000000 00000000 4B9C0000  |............K...|
+CHECK-NEXT:   0030: 00004C00 6F006100 64000000 00080000  |..L.o.a.d.......|
+CHECK-NEXT:   0040: 00000000 00000000 00000000 00000000  |................|
+CHECK-NEXT:   0050: 00000000 FB9C0000 81005300 61007600  |..........S.a.v.|
+CHECK-NEXT:   0060: 65007300 74006100 74006500 20005300  |e.s.t.a.t.e. .S.|
+CHECK-NEXT:   0070: 6C006F00 74000000 00000000 00000000  |l.o.t...........|
+CHECK-NEXT:   0080: 00000000 A39C0000 00002600 31000000  |..........&.1...|
+CHECK-NEXT:   0090: 00000000 00000000 A49C0000 80002600  |..............&.|
+CHECK-NEXT:   00A0: 32000000                             |2...|
+CHECK-NEXT: )

diff  --git a/llvm/tools/llvm-rc/ResourceFileWriter.cpp b/llvm/tools/llvm-rc/ResourceFileWriter.cpp
index 62eed50976d90a0..dd9db338ece255b 100644
--- a/llvm/tools/llvm-rc/ResourceFileWriter.cpp
+++ b/llvm/tools/llvm-rc/ResourceFileWriter.cpp
@@ -471,6 +471,10 @@ Error ResourceFileWriter::visitMenuResource(const RCResource *Res) {
   return writeResource(Res, &ResourceFileWriter::writeMenuBody);
 }
 
+Error ResourceFileWriter::visitMenuExResource(const RCResource *Res) {
+  return writeResource(Res, &ResourceFileWriter::writeMenuExBody);
+}
+
 Error ResourceFileWriter::visitStringTableResource(const RCResource *Base) {
   const auto *Res = cast<StringTableResource>(Base);
 
@@ -1176,6 +1180,7 @@ Error ResourceFileWriter::writeHTMLBody(const RCResource *Base) {
 
 Error ResourceFileWriter::writeMenuDefinition(
     const std::unique_ptr<MenuDefinition> &Def, uint16_t Flags) {
+  // https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-menuitemtemplate
   assert(Def);
   const MenuDefinition *DefPtr = Def.get();
 
@@ -1202,6 +1207,34 @@ Error ResourceFileWriter::writeMenuDefinition(
   return writeMenuDefinitionList(PopupPtr->SubItems);
 }
 
+Error ResourceFileWriter::writeMenuExDefinition(
+    const std::unique_ptr<MenuDefinition> &Def, uint16_t Flags) {
+  // https://learn.microsoft.com/en-us/windows/win32/menurc/menuex-template-item
+  assert(Def);
+  const MenuDefinition *DefPtr = Def.get();
+
+  padStream(sizeof(uint32_t));
+  if (auto *MenuItemPtr = dyn_cast<MenuExItem>(DefPtr)) {
+    writeInt<uint32_t>(MenuItemPtr->Type);
+    writeInt<uint32_t>(MenuItemPtr->State);
+    writeInt<uint32_t>(MenuItemPtr->Id);
+    writeInt<uint16_t>(Flags);
+    padStream(sizeof(uint16_t));
+    RETURN_IF_ERROR(writeCString(MenuItemPtr->Name));
+    return Error::success();
+  }
+
+  auto *PopupPtr = cast<PopupExItem>(DefPtr);
+  writeInt<uint32_t>(PopupPtr->Type);
+  writeInt<uint32_t>(PopupPtr->State);
+  writeInt<uint32_t>(PopupPtr->Id);
+  writeInt<uint16_t>(Flags);
+  padStream(sizeof(uint16_t));
+  RETURN_IF_ERROR(writeCString(PopupPtr->Name));
+  writeInt<uint32_t>(PopupPtr->HelpId);
+  return writeMenuExDefinitionList(PopupPtr->SubItems);
+}
+
 Error ResourceFileWriter::writeMenuDefinitionList(
     const MenuDefinitionList &List) {
   for (auto &Def : List.Definitions) {
@@ -1216,6 +1249,20 @@ Error ResourceFileWriter::writeMenuDefinitionList(
   return Error::success();
 }
 
+Error ResourceFileWriter::writeMenuExDefinitionList(
+    const MenuDefinitionList &List) {
+  for (auto &Def : List.Definitions) {
+    uint16_t Flags = Def->getResFlags();
+    // Last element receives an additional 0x80 flag.
+    const uint16_t LastElementFlag = 0x0080;
+    if (&Def == &List.Definitions.back())
+      Flags |= LastElementFlag;
+
+    RETURN_IF_ERROR(writeMenuExDefinition(Def, Flags));
+  }
+  return Error::success();
+}
+
 Error ResourceFileWriter::writeMenuBody(const RCResource *Base) {
   // At first, MENUHEADER structure. In fact, these are two WORDs equal to 0.
   // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648018.aspx
@@ -1224,6 +1271,17 @@ Error ResourceFileWriter::writeMenuBody(const RCResource *Base) {
   return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
 }
 
+Error ResourceFileWriter::writeMenuExBody(const RCResource *Base) {
+  // At first, MENUEX_TEMPLATE_HEADER structure.
+  // Ref:
+  // https://learn.microsoft.com/en-us/windows/win32/menurc/menuex-template-header
+  writeInt<uint16_t>(1);
+  writeInt<uint16_t>(4);
+  writeInt<uint32_t>(0);
+
+  return writeMenuExDefinitionList(cast<MenuExResource>(Base)->Elements);
+}
+
 // --- StringTableResource helpers. --- //
 
 class BundleResource : public RCResource {

diff  --git a/llvm/tools/llvm-rc/ResourceFileWriter.h b/llvm/tools/llvm-rc/ResourceFileWriter.h
index 7a92f84d5d84f29..d809890ee8e8201 100644
--- a/llvm/tools/llvm-rc/ResourceFileWriter.h
+++ b/llvm/tools/llvm-rc/ResourceFileWriter.h
@@ -55,6 +55,7 @@ class ResourceFileWriter : public Visitor {
   Error visitHTMLResource(const RCResource *) override;
   Error visitIconResource(const RCResource *) override;
   Error visitMenuResource(const RCResource *) override;
+  Error visitMenuExResource(const RCResource *) override;
   Error visitVersionInfoResource(const RCResource *) override;
   Error visitStringTableResource(const RCResource *) override;
   Error visitUserDefinedResource(const RCResource *) override;
@@ -150,8 +151,12 @@ class ResourceFileWriter : public Visitor {
   // MenuResource
   Error writeMenuDefinition(const std::unique_ptr<MenuDefinition> &,
                             uint16_t Flags);
+  Error writeMenuExDefinition(const std::unique_ptr<MenuDefinition> &,
+                              uint16_t Flags);
   Error writeMenuDefinitionList(const MenuDefinitionList &List);
+  Error writeMenuExDefinitionList(const MenuDefinitionList &List);
   Error writeMenuBody(const RCResource *);
+  Error writeMenuExBody(const RCResource *);
 
   // StringTableResource
   Error visitStringTableBundle(const RCResource *);

diff  --git a/llvm/tools/llvm-rc/ResourceScriptParser.cpp b/llvm/tools/llvm-rc/ResourceScriptParser.cpp
index 0037fec4c0247d7..9e1047448831b37 100644
--- a/llvm/tools/llvm-rc/ResourceScriptParser.cpp
+++ b/llvm/tools/llvm-rc/ResourceScriptParser.cpp
@@ -80,6 +80,8 @@ RCParser::ParseType RCParser::parseSingleResource() {
     Result = parseIconResource();
   else if (TypeToken->equalsLower("MENU"))
     Result = parseMenuResource();
+  else if (TypeToken->equalsLower("MENUEX"))
+    Result = parseMenuExResource();
   else if (TypeToken->equalsLower("RCDATA"))
     Result = parseUserDefinedResource(RkRcData);
   else if (TypeToken->equalsLower("VERSIONINFO"))
@@ -499,7 +501,7 @@ RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
   case Kind::String:
   case Kind::Identifier:
     return std::make_unique<UserDefinedResource>(Type, read().value(),
-                                                  MemoryFlags);
+                                                 MemoryFlags);
   default:
     break;
   }
@@ -518,7 +520,7 @@ RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
   }
 
   return std::make_unique<UserDefinedResource>(Type, std::move(Data),
-                                                MemoryFlags);
+                                               MemoryFlags);
 }
 
 RCParser::ParseType RCParser::parseVersionInfoResource() {
@@ -557,7 +559,8 @@ Expected<Control> RCParser::parseControl() {
   IntOrString Class;
   std::optional<IntWithNotMask> Style;
   if (ClassUpper == "CONTROL") {
-    // CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
+    // CONTROL text, id, class, style, x, y, width, height [, exstyle] [,
+    // helpID]
     ASSIGN_OR_RETURN(ClassStr, readString());
     RETURN_IF_ERROR(consumeType(Kind::Comma));
     Class = *ClassStr;
@@ -589,8 +592,8 @@ Expected<Control> RCParser::parseControl() {
     HelpID = *Val;
   }
 
-  return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1],
-                 (*Args)[2], (*Args)[3], Style, ExStyle, HelpID, Class);
+  return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1], (*Args)[2],
+                 (*Args)[3], Style, ExStyle, HelpID, Class);
 }
 
 RCParser::ParseType RCParser::parseBitmapResource() {
@@ -620,7 +623,14 @@ RCParser::ParseType RCParser::parseMenuResource() {
   ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
   ASSIGN_OR_RETURN(Items, parseMenuItemsList());
   return std::make_unique<MenuResource>(std::move(*OptStatements),
-                                         std::move(*Items), MemoryFlags);
+                                        std::move(*Items), MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseMenuExResource() {
+  uint16_t MemoryFlags =
+      parseMemoryFlags(MenuExResource::getDefaultMemoryFlags());
+  ASSIGN_OR_RETURN(Items, parseMenuExItemsList());
+  return std::make_unique<MenuExResource>(std::move(*Items), MemoryFlags);
 }
 
 Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
@@ -682,6 +692,95 @@ Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
   return std::move(List);
 }
 
+Expected<MenuDefinitionList> RCParser::parseMenuExItemsList() {
+  RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+  MenuDefinitionList List;
+
+  // Read a set of items. Each item is of one of two kinds:
+  //   MENUITEM caption:String [,[id][, [type][, state]]]]
+  //   POPUP caption:String [,[id][, [type][, [state][, helpID]]]] { popupBody }
+  while (!consumeOptionalType(Kind::BlockEnd)) {
+    ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier());
+
+    bool IsMenuItem = ItemTypeResult->equals_insensitive("MENUITEM");
+    bool IsPopup = ItemTypeResult->equals_insensitive("POPUP");
+    if (!IsMenuItem && !IsPopup)
+      return getExpectedError("MENUITEM, POPUP, END or '}'", true);
+
+    // Not a separator. Read the caption.
+    ASSIGN_OR_RETURN(CaptionResult, readString());
+
+    // If MENUITEM, expect [,[id][, [type][, state]]]]
+    if (IsMenuItem) {
+      uint32_t MenuId = 0;
+      uint32_t MenuType = 0;
+      uint32_t MenuState = 0;
+
+      if (consumeOptionalType(Kind::Comma)) {
+        auto IntId = readInt();
+        if (IntId) {
+          MenuId = *IntId;
+        }
+        if (consumeOptionalType(Kind::Comma)) {
+          auto IntType = readInt();
+          if (IntType) {
+            MenuType = *IntType;
+          }
+          if (consumeOptionalType(Kind::Comma)) {
+            auto IntState = readInt();
+            if (IntState) {
+              MenuState = *IntState;
+            }
+          }
+        }
+      }
+      List.addDefinition(std::make_unique<MenuExItem>(*CaptionResult, MenuId,
+                                                      MenuType, MenuState));
+      continue;
+    }
+
+    assert(IsPopup);
+
+    uint32_t PopupId = 0;
+    uint32_t PopupType = 0;
+    uint32_t PopupState = 0;
+    uint32_t PopupHelpID = 0;
+
+    if (consumeOptionalType(Kind::Comma)) {
+      auto IntId = readInt();
+      if (IntId) {
+        PopupId = *IntId;
+      }
+      if (consumeOptionalType(Kind::Comma)) {
+        auto IntType = readInt();
+        if (IntType) {
+          PopupType = *IntType;
+        }
+        if (consumeOptionalType(Kind::Comma)) {
+          auto IntState = readInt();
+          if (IntState) {
+            PopupState = *IntState;
+          }
+          if (consumeOptionalType(Kind::Comma)) {
+            auto IntHelpID = readInt();
+            if (IntHelpID) {
+              PopupHelpID = *IntHelpID;
+            }
+          }
+        }
+      }
+    }
+    // If POPUP, read submenu items recursively.
+    ASSIGN_OR_RETURN(SubMenuResult, parseMenuExItemsList());
+    List.addDefinition(std::make_unique<PopupExItem>(
+        *CaptionResult, PopupId, PopupType, PopupState, PopupHelpID,
+        std::move(*SubMenuResult)));
+  }
+
+  return std::move(List);
+}
+
 RCParser::ParseType RCParser::parseStringTableResource() {
   uint16_t MemoryFlags =
       parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
@@ -689,7 +788,7 @@ RCParser::ParseType RCParser::parseStringTableResource() {
   RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
 
   auto Table = std::make_unique<StringTableResource>(std::move(*OptStatements),
-                                                      MemoryFlags);
+                                                     MemoryFlags);
 
   // Read strings until we reach the end of the block.
   while (!consumeOptionalType(Kind::BlockEnd)) {
@@ -753,7 +852,7 @@ Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt() {
       PrecedingCommas.push_back(HadComma);
     }
     return std::make_unique<VersionInfoValue>(*KeyResult, std::move(Values),
-                                               std::move(PrecedingCommas));
+                                              std::move(PrecedingCommas));
   }
 
   return getExpectedError("BLOCK or VALUE", true);
@@ -835,7 +934,7 @@ RCParser::ParseOptionType RCParser::parseFontStmt(OptStmtType DialogType) {
     }
   }
   return std::make_unique<FontStmt>(*SizeResult, *NameResult, FontWeight,
-                                     FontItalic, FontCharset);
+                                    FontItalic, FontCharset);
 }
 
 RCParser::ParseOptionType RCParser::parseStyleStmt() {

diff  --git a/llvm/tools/llvm-rc/ResourceScriptParser.h b/llvm/tools/llvm-rc/ResourceScriptParser.h
index a7d3b595f794377..5c01cec0f151e8b 100644
--- a/llvm/tools/llvm-rc/ResourceScriptParser.h
+++ b/llvm/tools/llvm-rc/ResourceScriptParser.h
@@ -143,6 +143,7 @@ class RCParser {
   ParseType parseIconResource();
   ParseType parseHTMLResource();
   ParseType parseMenuResource();
+  ParseType parseMenuExResource();
   ParseType parseStringTableResource();
   ParseType parseUserDefinedResource(IntOrString Type);
   ParseType parseVersionInfoResource();
@@ -153,6 +154,9 @@ class RCParser {
   // Helper MENU parser.
   Expected<MenuDefinitionList> parseMenuItemsList();
 
+  // Helper MENUEX parser.
+  Expected<MenuDefinitionList> parseMenuExItemsList();
+
   // Helper VERSIONINFO parser - read the contents of a single BLOCK statement,
   // from BEGIN to END.
   Expected<std::unique_ptr<VersionInfoBlock>>

diff  --git a/llvm/tools/llvm-rc/ResourceScriptStmt.cpp b/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
index ef8c34541881ac8..62df7999252fe19 100644
--- a/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
+++ b/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
@@ -102,6 +102,12 @@ raw_ostream &MenuSeparator::log(raw_ostream &OS) const {
   return OS << "  Menu separator\n";
 }
 
+raw_ostream &MenuExItem::log(raw_ostream &OS) const {
+  OS << "  MenuExItem (" << Name << "), ID = " << Id;
+  OS << ", type: " << Type << ", state: " << State;
+  return OS << "\n";
+}
+
 raw_ostream &PopupItem::log(raw_ostream &OS) const {
   OS << "  Popup (" << Name << ")";
   logFlags(OS, Flags);
@@ -109,12 +115,25 @@ raw_ostream &PopupItem::log(raw_ostream &OS) const {
   return SubItems.log(OS);
 }
 
+raw_ostream &PopupExItem::log(raw_ostream &OS) const {
+  OS << "  Popup (" << Name << ")";
+  OS << ", type: " << Type << ", state: " << State << ", help ID: " << HelpId;
+  OS << ":\n";
+  return SubItems.log(OS);
+}
+
 raw_ostream &MenuResource::log(raw_ostream &OS) const {
   OS << "Menu (" << ResName << "):\n";
   OptStatements->log(OS);
   return Elements.log(OS);
 }
 
+raw_ostream &MenuExResource::log(raw_ostream &OS) const {
+  OS << "MenuEx (" << ResName << "):\n";
+  OptStatements->log(OS);
+  return Elements.log(OS);
+}
+
 raw_ostream &StringTableResource::log(raw_ostream &OS) const {
   OS << "StringTable:\n";
   OptStatements->log(OS);

diff  --git a/llvm/tools/llvm-rc/ResourceScriptStmt.h b/llvm/tools/llvm-rc/ResourceScriptStmt.h
index 71f6a9d212e46cf..09853da6c500aaf 100644
--- a/llvm/tools/llvm-rc/ResourceScriptStmt.h
+++ b/llvm/tools/llvm-rc/ResourceScriptStmt.h
@@ -536,6 +536,23 @@ class MenuItem : public MenuDefinition {
   }
 };
 
+class MenuExItem : public MenuDefinition {
+public:
+  StringRef Name;
+  uint32_t Id;
+  uint32_t Type;
+  uint32_t State;
+
+  MenuExItem(StringRef Caption, uint32_t ItemId, uint32_t Type, uint32_t State)
+      : Name(Caption), Id(ItemId), Type(Type), State(State) {}
+  raw_ostream &log(raw_ostream &) const override;
+
+  MenuDefKind getKind() const override { return MkMenuItem; }
+  static bool classof(const MenuDefinition *D) {
+    return D->getKind() == MkMenuItem;
+  }
+};
+
 // POPUP statement definition.
 //
 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
@@ -550,8 +567,7 @@ class PopupItem : public MenuDefinition {
       : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
   raw_ostream &log(raw_ostream &) const override;
 
-  // This has an additional (0x10) flag. It doesn't match with documented
-  // 0x01 flag, though.
+  // This has an additional MF_POPUP (0x10) flag.
   uint16_t getResFlags() const override { return Flags | 0x10; }
   MenuDefKind getKind() const override { return MkPopup; }
   static bool classof(const MenuDefinition *D) {
@@ -559,6 +575,28 @@ class PopupItem : public MenuDefinition {
   }
 };
 
+class PopupExItem : public MenuDefinition {
+public:
+  StringRef Name;
+  uint32_t Id;
+  uint32_t Type;
+  uint32_t State;
+  uint32_t HelpId;
+  MenuDefinitionList SubItems;
+
+  PopupExItem(StringRef Caption, uint32_t Id, uint32_t Type, uint32_t State,
+              uint32_t HelpId, MenuDefinitionList &&SubItemsList)
+      : Name(Caption), Id(Id), Type(Type), State(State), HelpId(HelpId),
+        SubItems(std::move(SubItemsList)) {}
+  raw_ostream &log(raw_ostream &) const override;
+
+  uint16_t getResFlags() const override { return 0x01; }
+  MenuDefKind getKind() const override { return MkPopup; }
+  static bool classof(const MenuDefinition *D) {
+    return D->getKind() == MkPopup;
+  }
+};
+
 // Menu resource definition.
 class MenuResource : public OptStatementsRCResource {
 public:
@@ -579,6 +617,25 @@ class MenuResource : public OptStatementsRCResource {
   }
 };
 
+class MenuExResource : public OptStatementsRCResource {
+public:
+  MenuDefinitionList Elements;
+
+  MenuExResource(MenuDefinitionList &&Items, uint16_t Flags)
+      : OptStatementsRCResource({}, Flags), Elements(std::move(Items)) {}
+  raw_ostream &log(raw_ostream &) const override;
+
+  IntOrString getResourceType() const override { return RkMenu; }
+  Twine getResourceTypeName() const override { return "MENUEX"; }
+  Error visit(Visitor *V) const override {
+    return V->visitMenuExResource(this);
+  }
+  ResourceKind getKind() const override { return RkMenu; }
+  static bool classof(const RCResource *Res) {
+    return Res->getKind() == RkMenu;
+  }
+};
+
 // STRINGTABLE resource. Contains a list of strings, each having its unique ID.
 //
 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx

diff  --git a/llvm/tools/llvm-rc/ResourceVisitor.h b/llvm/tools/llvm-rc/ResourceVisitor.h
index 843c8d898a21122..a950cd7555ecdf1 100644
--- a/llvm/tools/llvm-rc/ResourceVisitor.h
+++ b/llvm/tools/llvm-rc/ResourceVisitor.h
@@ -39,6 +39,7 @@ class Visitor {
   virtual Error visitHTMLResource(const RCResource *) = 0;
   virtual Error visitIconResource(const RCResource *) = 0;
   virtual Error visitMenuResource(const RCResource *) = 0;
+  virtual Error visitMenuExResource(const RCResource *) = 0;
   virtual Error visitStringTableResource(const RCResource *) = 0;
   virtual Error visitUserDefinedResource(const RCResource *) = 0;
   virtual Error visitVersionInfoResource(const RCResource *) = 0;


        


More information about the llvm-commits mailing list