diff --git a/BurnOutSharp.Builder/Extensions.cs b/BurnOutSharp.Builder/Extensions.cs
index 0dc2dc41..f22ebae4 100644
--- a/BurnOutSharp.Builder/Extensions.cs
+++ b/BurnOutSharp.Builder/Extensions.cs
@@ -484,11 +484,130 @@ namespace BurnOutSharp.Builder
int possibleSignature = entry.Data.ReadUInt16(ref signatureOffset);
if (possibleSignature == 0xFFFF)
{
- Console.WriteLine("Extended dialog box template found, but not implemented");
-
#region Extended dialog template
- // TODO: Implement extended dialog template
+ var dialogTemplateExtended = new Models.PortableExecutable.DialogTemplateExtended();
+
+ dialogTemplateExtended.Version = entry.Data.ReadUInt16(ref offset);
+ dialogTemplateExtended.Signature = entry.Data.ReadUInt16(ref offset);
+ dialogTemplateExtended.HelpID = entry.Data.ReadUInt32(ref offset);
+ dialogTemplateExtended.ExtendedStyle = (Models.PortableExecutable.ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
+ dialogTemplateExtended.Style = (Models.PortableExecutable.WindowStyles)entry.Data.ReadUInt32(ref offset);
+ dialogTemplateExtended.DialogItems = entry.Data.ReadUInt16(ref offset);
+ dialogTemplateExtended.PositionX = entry.Data.ReadInt16(ref offset);
+ dialogTemplateExtended.PositionY = entry.Data.ReadInt16(ref offset);
+ dialogTemplateExtended.WidthX = entry.Data.ReadInt16(ref offset);
+ dialogTemplateExtended.HeightY = entry.Data.ReadInt16(ref offset);
+
+ #region Menu resource
+
+ int currentOffset = offset;
+ ushort menuResourceIdentifier = entry.Data.ReadUInt16(ref offset);
+ offset = currentOffset;
+
+ // 0x0000 means no elements
+ if (menuResourceIdentifier == 0x0000)
+ {
+ // Increment the pointer if it was empty
+ offset += sizeof(ushort);
+ }
+ else
+ {
+ // Flag if there's an ordinal at the end
+ bool menuResourceHasOrdinal = menuResourceIdentifier == 0xFFFF;
+ if (menuResourceHasOrdinal)
+ offset += sizeof(ushort);
+
+ // Read the menu resource as a string
+ dialogTemplateExtended.MenuResource = entry.Data.ReadString(ref offset, Encoding.Unicode);
+
+ // Align to the WORD boundary
+ while ((offset % 2) != 0)
+ _ = entry.Data.ReadByte(ref offset);
+
+ // Read the ordinal if we have the flag set
+ if (menuResourceHasOrdinal)
+ dialogTemplateExtended.MenuResourceOrdinal = entry.Data.ReadUInt16(ref offset);
+ }
+
+ #endregion
+
+ #region Class resource
+
+ currentOffset = offset;
+ ushort classResourceIdentifier = entry.Data.ReadUInt16(ref offset);
+ offset = currentOffset;
+
+ // 0x0000 means no elements
+ if (classResourceIdentifier == 0x0000)
+ {
+ // Increment the pointer if it was empty
+ offset += sizeof(ushort);
+ }
+ else
+ {
+ // Flag if there's an ordinal at the end
+ bool classResourcehasOrdinal = classResourceIdentifier == 0xFFFF;
+ if (classResourcehasOrdinal)
+ offset += sizeof(ushort);
+
+ // Read the class resource as a string
+ dialogTemplateExtended.ClassResource = entry.Data.ReadString(ref offset, Encoding.Unicode);
+
+ // Align to the WORD boundary
+ while ((offset % 2) != 0)
+ _ = entry.Data.ReadByte(ref offset);
+
+ // Read the ordinal if we have the flag set
+ if (classResourcehasOrdinal)
+ dialogTemplateExtended.ClassResourceOrdinal = entry.Data.ReadUInt16(ref offset);
+ }
+
+ #endregion
+
+ #region Title resource
+
+ currentOffset = offset;
+ ushort titleResourceIdentifier = entry.Data.ReadUInt16(ref offset);
+ offset = currentOffset;
+
+ // 0x0000 means no elements
+ if (titleResourceIdentifier == 0x0000)
+ {
+ // Increment the pointer if it was empty
+ offset += sizeof(ushort);
+ }
+ else
+ {
+ // Read the title resource as a string
+ dialogTemplateExtended.TitleResource = entry.Data.ReadString(ref offset, Encoding.Unicode);
+
+ // Align to the WORD boundary
+ while ((offset % 2) != 0)
+ _ = entry.Data.ReadByte(ref offset);
+ }
+
+ #endregion
+
+ #region Point size and typeface
+
+ // Only if DS_SETFONT is set are the values here used
+ if (dialogTemplateExtended.Style.HasFlag(Models.PortableExecutable.WindowStyles.DS_SETFONT))
+ {
+ dialogTemplateExtended.PointSize = entry.Data.ReadUInt16(ref offset);
+ dialogTemplateExtended.Weight = entry.Data.ReadUInt16(ref offset);
+ dialogTemplateExtended.Italic = entry.Data.ReadByte(ref offset);
+ dialogTemplateExtended.CharSet = entry.Data.ReadByte(ref offset);
+ dialogTemplateExtended.Typeface = entry.Data.ReadString(ref offset, Encoding.Unicode);
+ }
+
+ // Align to the DWORD boundary
+ while ((offset % 4) != 0)
+ _ = entry.Data.ReadByte(ref offset);
+
+ #endregion
+
+ dialogBoxResource.DialogTemplateExtended = dialogTemplateExtended;
#endregion
diff --git a/BurnOutSharp.Models/PortableExecutable/DialogBoxResource.cs b/BurnOutSharp.Models/PortableExecutable/DialogBoxResource.cs
index 1bed5211..1326d82c 100644
--- a/BurnOutSharp.Models/PortableExecutable/DialogBoxResource.cs
+++ b/BurnOutSharp.Models/PortableExecutable/DialogBoxResource.cs
@@ -9,11 +9,22 @@
///
public class DialogBoxResource
{
+ #region Dialog template
+
///
/// Dialog box header structure
///
public DialogTemplate DialogTemplate;
+ ///
+ /// Dialog box extended header structure
+ ///
+ public DialogTemplateExtended DialogTemplateExtended;
+
+ #endregion
+
+ #region Dialog item templates
+
///
/// Following the DLGTEMPLATE header in a standard dialog box template are one or more
/// DLGITEMTEMPLATE structures that define the dimensions and style of the controls in the dialog
@@ -21,5 +32,7 @@
/// These DLGITEMTEMPLATE structures must be aligned on DWORD boundaries.
///
public DialogItemTemplate[] DialogItemTemplates;
+
+ #endregion
}
}
diff --git a/BurnOutSharp.Models/PortableExecutable/DialogTemplateExtended.cs b/BurnOutSharp.Models/PortableExecutable/DialogTemplateExtended.cs
new file mode 100644
index 00000000..aac642c6
--- /dev/null
+++ b/BurnOutSharp.Models/PortableExecutable/DialogTemplateExtended.cs
@@ -0,0 +1,172 @@
+using System.Runtime.InteropServices;
+
+namespace BurnOutSharp.Models.PortableExecutable
+{
+ ///
+ /// An extended dialog box template begins with a DLGTEMPLATEEX header that describes
+ /// the dialog box and specifies the number of controls in the dialog box. For each
+ /// control in a dialog box, an extended dialog box template has a block of data that
+ /// uses the DLGITEMTEMPLATEEX format to describe the control.
+ ///
+ /// The DLGTEMPLATEEX structure is not defined in any standard header file. The
+ /// structure definition is provided here to explain the format of an extended template
+ /// for a dialog box.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public class DialogTemplateExtended
+ {
+ ///
+ /// The version number of the extended dialog box template. This member must be
+ /// set to 1.
+ ///
+ public ushort Version;
+
+ ///
+ /// Indicates whether a template is an extended dialog box template. If signature
+ /// is 0xFFFF, this is an extended dialog box template. In this case, the dlgVer
+ /// member specifies the template version number. If signature is any value other
+ /// than 0xFFFF, this is a standard dialog box template that uses the DLGTEMPLATE
+ /// and DLGITEMTEMPLATE structures.
+ ///
+ public ushort Signature;
+
+ ///
+ /// The help context identifier for the dialog box window. When the system sends a
+ /// WM_HELP message, it passes this value in the wContextId member of the HELPINFO
+ /// structure.
+ ///
+ public uint HelpID;
+
+ ///
+ /// The extended windows styles. This member is not used when creating dialog boxes,
+ /// but applications that use dialog box templates can use it to create other types
+ /// of windows.
+ ///
+ public ExtendedWindowStyles ExtendedStyle;
+
+ ///
+ /// The style of the dialog box.
+ ///
+ /// If style includes the DS_SETFONT or DS_SHELLFONT dialog box style, the DLGTEMPLATEEX
+ /// header of the extended dialog box template contains four additional members (pointsize,
+ /// weight, italic, and typeface) that describe the font to use for the text in the client
+ /// area and controls of the dialog box. If possible, the system creates a font according
+ /// to the values specified in these members. Then the system sends a WM_SETFONT message
+ /// to the dialog box and to each control to provide a handle to the font.
+ ///
+ public WindowStyles Style;
+
+ ///
+ /// The number of controls in the dialog box.
+ ///
+ public ushort DialogItems;
+
+ ///
+ /// The x-coordinate, in dialog box units, of the upper-left corner of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionX;
+
+ ///
+ /// The y-coordinate, in dialog box units, of the upper-left corner of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short PositionY;
+
+ ///
+ /// The width, in dialog box units, of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short WidthX;
+
+ ///
+ /// The height, in dialog box units, of the dialog box.
+ ///
+ ///
+ /// The x, y, cx, and cy members specify values in dialog box units. You can convert these values
+ /// to screen units (pixels) by using the MapDialogRect function.
+ ///
+ public short HeightY;
+
+ ///
+ /// A variable-length array of 16-bit elements that identifies a menu resource for the dialog box.
+ /// If the first element of this array is 0x0000, the dialog box has no menu and the array has no
+ /// other elements. If the first element is 0xFFFF, the array has one additional element that
+ /// specifies the ordinal value of a menu resource in an executable file. If the first element has
+ /// any other value, the system treats the array as a null-terminated Unicode string that specifies
+ /// the name of a menu resource in an executable file.
+ ///
+ public string MenuResource;
+
+ ///
+ /// The ordinal value of a menu resource in an executable file.
+ ///
+ public ushort MenuResourceOrdinal;
+
+ /// A variable-length array of 16-bit elements that identifies the window class of the
+ /// dialog box. If the first element of the array is 0x0000, the system uses the predefined dialog
+ /// box class for the dialog box and the array has no other elements. If the first element is 0xFFFF,
+ /// the array has one additional element that specifies the ordinal value of a predefined system
+ /// window class. If the first element has any other value, the system treats the array as a
+ /// null-terminated Unicode string that specifies the name of a registered window class.
+ ///
+ public string ClassResource;
+
+ ///
+ /// The ordinal value of a predefined system window class.
+ ///
+ public ushort ClassResourceOrdinal;
+
+ ///
+ /// The title of the dialog box. If the first element of this array is 0x0000, the dialog box has no
+ /// title and the array has no other elements.
+ ///
+ public string TitleResource;
+
+ ///
+ /// The point size of the font to use for the text in the dialog box and its controls.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public ushort PointSize;
+
+ ///
+ /// The weight of the font. Note that, although this can be any of the values listed for the lfWeight
+ /// member of the LOGFONT structure, any value that is used will be automatically changed to FW_NORMAL.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public ushort Weight;
+
+ ///
+ /// Indicates whether the font is italic. If this value is TRUE, the font is italic.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public byte Italic;
+
+ ///
+ /// The character set to be used. For more information, see the lfcharset member of LOGFONT.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public byte CharSet;
+
+ ///
+ /// The name of the typeface for the font.
+ ///
+ /// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
+ ///
+ public string Typeface;
+ }
+}
diff --git a/ExecutableTest/Program.cs b/ExecutableTest/Program.cs
index f1aaddff..4ccbce8a 100644
--- a/ExecutableTest/Program.cs
+++ b/ExecutableTest/Program.cs
@@ -1248,6 +1248,63 @@ namespace ExecutableTest
}
}
}
+ else if (dialogBox.DialogTemplateExtended != null)
+ {
+ Console.WriteLine($"{padding}Version: {dialogBox.DialogTemplateExtended.Version}");
+ Console.WriteLine($"{padding}Signature: {dialogBox.DialogTemplateExtended.Signature}");
+ Console.WriteLine($"{padding}Help ID: {dialogBox.DialogTemplateExtended.HelpID}");
+ Console.WriteLine($"{padding}Extended style: {dialogBox.DialogTemplateExtended.ExtendedStyle}");
+ Console.WriteLine($"{padding}Style: {dialogBox.DialogTemplateExtended.Style}");
+ Console.WriteLine($"{padding}Item count: {dialogBox.DialogTemplateExtended.DialogItems}");
+ Console.WriteLine($"{padding}X-coordinate of upper-left corner: {dialogBox.DialogTemplateExtended.PositionX}");
+ Console.WriteLine($"{padding}Y-coordinate of upper-left corner: {dialogBox.DialogTemplateExtended.PositionY}");
+ Console.WriteLine($"{padding}Width of the dialog box: {dialogBox.DialogTemplateExtended.WidthX}");
+ Console.WriteLine($"{padding}Height of the dialog box: {dialogBox.DialogTemplateExtended.HeightY}");
+ Console.WriteLine($"{padding}Menu resource: {dialogBox.DialogTemplateExtended.MenuResource ?? "[EMPTY]"}");
+ Console.WriteLine($"{padding}Menu resource ordinal: {dialogBox.DialogTemplateExtended.MenuResourceOrdinal}");
+ Console.WriteLine($"{padding}Class resource: {dialogBox.DialogTemplateExtended.ClassResource ?? "[EMPTY]"}");
+ Console.WriteLine($"{padding}Class resource ordinal: {dialogBox.DialogTemplateExtended.ClassResourceOrdinal}");
+ Console.WriteLine($"{padding}Title resource: {dialogBox.DialogTemplateExtended.TitleResource ?? "[EMPTY]"}");
+ Console.WriteLine($"{padding}Point size: {dialogBox.DialogTemplateExtended.PointSize}");
+ Console.WriteLine($"{padding}Weight: {dialogBox.DialogTemplateExtended.Weight}");
+ Console.WriteLine($"{padding}Italic: {dialogBox.DialogTemplateExtended.Italic}");
+ Console.WriteLine($"{padding}Character set: {dialogBox.DialogTemplateExtended.CharSet}");
+ Console.WriteLine($"{padding}Typeface: {dialogBox.DialogTemplateExtended.Typeface ?? "[EMPTY]"}");
+ Console.WriteLine();
+ //Console.WriteLine($"{padding}Dialog item templates");
+ //Console.WriteLine($"{padding}-------------------------");
+ //if (dialogBox.DialogTemplate.ItemCount == 0
+ // || dialogBox.DialogItemTemplates == null
+ // || dialogBox.DialogItemTemplates.Length == 0)
+ //{
+ // Console.WriteLine($"{padding}No dialog item templates");
+ //}
+ //else
+ //{
+ // for (int i = 0; i < dialogBox.DialogItemTemplates.Length; i++)
+ // {
+ // var dialogItemTemplate = dialogBox.DialogItemTemplates[i];
+
+ // Console.WriteLine($"{padding}Dialog item template {i}");
+ // Console.WriteLine($"{padding} Style: {dialogItemTemplate.Style}");
+ // Console.WriteLine($"{padding} Extended style: {dialogItemTemplate.ExtendedStyle}");
+ // Console.WriteLine($"{padding} X-coordinate of upper-left corner: {dialogItemTemplate.PositionX}");
+ // Console.WriteLine($"{padding} Y-coordinate of upper-left corner: {dialogItemTemplate.PositionY}");
+ // Console.WriteLine($"{padding} Width of the control: {dialogItemTemplate.WidthX}");
+ // Console.WriteLine($"{padding} Height of the control: {dialogItemTemplate.HeightY}");
+ // Console.WriteLine($"{padding} ID: {dialogItemTemplate.ID}");
+ // Console.WriteLine($"{padding} Class resource: {dialogItemTemplate.ClassResource ?? "[EMPTY]"}");
+ // Console.WriteLine($"{padding} Class resource ordinal: {dialogItemTemplate.ClassResourceOrdinal}");
+ // Console.WriteLine($"{padding} Title resource: {dialogItemTemplate.TitleResource ?? "[EMPTY]"}");
+ // Console.WriteLine($"{padding} Title resource ordinal: {dialogItemTemplate.TitleResourceOrdinal}");
+ // Console.WriteLine($"{padding} Creation data size: {dialogItemTemplate.CreationDataSize}");
+ // if (dialogItemTemplate.CreationData != null && dialogItemTemplate.CreationData.Length != 0)
+ // Console.WriteLine($"{padding} Creation data: {BitConverter.ToString(dialogItemTemplate.CreationData).Replace("-", string.Empty)}");
+ // else
+ // Console.WriteLine($"{padding} Creation data: [EMPTY]");
+ // }
+ //}
+ }
else
{
Console.WriteLine($"{padding}Dialog box resource found, but malformed");