Add PE extended dialog templates

This commit is contained in:
Matt Nadareski
2022-11-11 14:22:53 -08:00
parent 554374b710
commit 5b974260cc
5 changed files with 305 additions and 57 deletions

View File

@@ -607,13 +607,105 @@ namespace BurnOutSharp.Builder
#endregion
dialogBoxResource.DialogTemplateExtended = dialogTemplateExtended;
dialogBoxResource.ExtendedDialogTemplate = dialogTemplateExtended;
#endregion
#region Extended dialog item templates
// TODO: Implement extended dialog item templates
var dialogItemExtendedTemplates = new List<Models.PortableExecutable.DialogItemTemplateExtended>();
for (int i = 0; i < dialogTemplateExtended.DialogItems; i++)
{
var dialogItemTemplate = new Models.PortableExecutable.DialogItemTemplateExtended();
dialogItemTemplate.HelpID = entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.ExtendedStyle = (Models.PortableExecutable.ExtendedWindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.Style = (Models.PortableExecutable.WindowStyles)entry.Data.ReadUInt32(ref offset);
dialogItemTemplate.PositionX = entry.Data.ReadInt16(ref offset);
dialogItemTemplate.PositionY = entry.Data.ReadInt16(ref offset);
dialogItemTemplate.WidthX = entry.Data.ReadInt16(ref offset);
dialogItemTemplate.HeightY = entry.Data.ReadInt16(ref offset);
dialogItemTemplate.ID = entry.Data.ReadUInt16(ref offset);
#region Class resource
currentOffset = offset;
ushort itemClassResourceIdentifier = entry.Data.ReadUInt16(ref offset);
offset = currentOffset;
// 0xFFFF means ordinal only
if (itemClassResourceIdentifier == 0xFFFF)
{
// Increment the pointer
_ = entry.Data.ReadUInt16(ref offset);
// Read the ordinal
dialogItemTemplate.ClassResourceOrdinal = (Models.PortableExecutable.DialogItemTemplateOrdinal)entry.Data.ReadUInt16(ref offset);
}
else
{
// Flag if there's an ordinal at the end
bool classResourcehasOrdinal = itemClassResourceIdentifier == 0xFFFF;
if (classResourcehasOrdinal)
offset += sizeof(ushort);
// Read the class resource as a string
dialogItemTemplate.ClassResource = entry.Data.ReadString(ref offset, Encoding.Unicode);
// Align to the WORD boundary
while ((offset % 2) != 0)
_ = entry.Data.ReadByte(ref offset);
}
#endregion
#region Title resource
currentOffset = offset;
ushort itemTitleResourceIdentifier = entry.Data.ReadUInt16(ref offset);
offset = currentOffset;
// 0xFFFF means ordinal only
if (itemTitleResourceIdentifier == 0xFFFF)
{
// Increment the pointer
_ = entry.Data.ReadUInt16(ref offset);
// Read the ordinal
dialogItemTemplate.TitleResourceOrdinal = entry.Data.ReadUInt16(ref offset);
}
else
{
// Read the title resource as a string
dialogItemTemplate.TitleResource = entry.Data.ReadString(ref offset, Encoding.Unicode);
// Align to the WORD boundary
while ((offset % 2) != 0)
_ = entry.Data.ReadByte(ref offset);
}
#endregion
#region Creation data
dialogItemTemplate.CreationDataSize = entry.Data.ReadUInt16(ref offset);
if (dialogItemTemplate.CreationDataSize != 0)
dialogItemTemplate.CreationData = entry.Data.ReadBytes(ref offset, dialogItemTemplate.CreationDataSize);
#endregion
// Align to the DWORD boundary if we're not at the end
if (offset != entry.Data.Length)
{
while ((offset % 4) != 0)
_ = entry.Data.ReadByte(ref offset);
}
dialogItemExtendedTemplates.Add(dialogItemTemplate);
}
dialogBoxResource.ExtendedDialogItemTemplates = dialogItemExtendedTemplates.ToArray();
#endregion
}
@@ -742,7 +834,7 @@ namespace BurnOutSharp.Builder
#endregion
#region Dialog Item Templates
#region Dialog item templates
var dialogItemTemplates = new List<Models.PortableExecutable.DialogItemTemplate>();

View File

@@ -19,7 +19,7 @@
/// <summary>
/// Dialog box extended header structure
/// </summary>
public DialogTemplateExtended DialogTemplateExtended;
public DialogTemplateExtended ExtendedDialogTemplate;
#endregion
@@ -33,6 +33,14 @@
/// </summary>
public DialogItemTemplate[] DialogItemTemplates;
/// <summary>
/// Following the DLGTEMPLATEEX header in an extended dialog box template is one or more
/// DLGITEMTEMPLATEEX structures that describe the controls of the dialog box. The cDlgItems
/// member of the DLGITEMTEMPLATEEX structure specifies the number of DLGITEMTEMPLATEEX
/// structures that follow in the template.
/// </summary>
public DialogItemTemplateExtended[] ExtendedDialogItemTemplates;
#endregion
}
}

View File

@@ -0,0 +1,131 @@
using System.Runtime.InteropServices;
namespace BurnOutSharp.Models.PortableExecutable
{
/// <summary>
/// A block of text used by an extended dialog box template to describe the extended dialog box.
/// For a description of the format of an extended dialog box template, see DLGTEMPLATEEX.
/// </summary>
/// <see href="https://learn.microsoft.com/en-us/windows/win32/dlgbox/dlgitemtemplateex"/>
[StructLayout(LayoutKind.Sequential)]
public class DialogItemTemplateExtended
{
/// <summary>
/// The help context identifier for the control. When the system sends a WM_HELP message,
/// it passes the helpID value in the dwContextId member of the HELPINFO structure.
/// </summary>
public uint HelpID;
/// <summary>
/// The extended styles for a window. This member is not used to create controls in dialog
/// boxes, but applications that use dialog box templates can use it to create other types
/// of windows.
/// </summary>
public ExtendedWindowStyles ExtendedStyle;
/// <summary>
/// The style of the control. This member can be a combination of window style values
/// (such as WS_BORDER) and one or more of the control style values (such as
/// BS_PUSHBUTTON and ES_LEFT).
/// </summary>
public WindowStyles Style;
/// <summary>
/// The x-coordinate, in dialog box units, of the upper-left corner of the control.
/// This coordinate is always relative to the upper-left corner of the dialog box's
/// client area.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public short PositionX;
/// <summary>
/// The y-coordinate, in dialog box units, of the upper-left corner of the control.
/// This coordinate is always relative to the upper-left corner of the dialog box's
/// client area.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public short PositionY;
/// <summary>
/// The width, in dialog box units, of the control.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public short WidthX;
/// <summary>
/// The height, in dialog box units, of the control.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public short HeightY;
/// <summary>
/// The control identifier.
/// </summary>
public ushort ID;
/// <summary>
/// A variable-length array of 16-bit elements that specifies the window class of the control. If
/// the first element of this array is any value other than 0xFFFF, the system treats the array as
/// a null-terminated Unicode string that specifies the name of a registered window class.
///
/// If the first element is 0xFFFF, the array has one additional element that specifies the ordinal
/// value of a predefined system class.
/// </summary>
/// <remarks>
/// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
/// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
/// </remarks>
public string ClassResource;
/// <summary>
/// The ordinal value of a predefined system class.
/// </summary>
public DialogItemTemplateOrdinal ClassResourceOrdinal;
/// <summary>
/// A variable-length array of 16-bit elements that contains the initial text or resource identifier of the
/// control. If the first element of this array is 0xFFFF, the array has one additional element that
/// specifies the ordinal value of a resource, such as an icon, in an executable file. You can use a
/// resource identifier for controls, such as static icon controls, that load and display an icon or other
/// resource rather than text. If the first element is any value other than 0xFFFF, the system treats the
/// array as a null-terminated Unicode string that specifies the initial text.
/// </summary>
/// <remarks>
/// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
/// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
/// </remarks>
public string TitleResource;
/// <summary>
/// An ordinal value of a resource, such as an icon, in an executable file
/// </summary>
public ushort TitleResourceOrdinal;
/// <summary>
/// The creation data array begins at the next WORD boundary after the title array. This creation data
/// can be of any size and format. If the first word of the creation data array is nonzero, it indicates
/// the size, in bytes, of the creation data (including the size word).
/// </summary>
public ushort CreationDataSize;
/// <summary>
/// The creation data array begins at the next WORD boundary after the title array. This creation data
/// can be of any size and format. The control's window procedure must be able to interpret the data.
/// When the system creates the control, it passes a pointer to this data in the lParam parameter of the
/// WM_CREATE message that it sends to the control.
/// </summary>
public byte[] CreationData;
}
}

View File

@@ -106,6 +106,10 @@ namespace BurnOutSharp.Models.PortableExecutable
/// 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.
/// </summary>
/// <remarks>
/// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
/// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
/// </remarks>
public string MenuResource;
/// <summary>
@@ -120,6 +124,10 @@ namespace BurnOutSharp.Models.PortableExecutable
/// 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.
/// </summary>
/// <remarks>
/// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
/// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
/// </remarks>
public string ClassResource;
/// <summary>
@@ -131,6 +139,10 @@ namespace BurnOutSharp.Models.PortableExecutable
/// 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.
/// </summary>
/// <remarks>
/// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
/// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
/// </remarks>
public string TitleResource;
/// <summary>
@@ -167,6 +179,10 @@ namespace BurnOutSharp.Models.PortableExecutable
///
/// This member is present only if the style member specifies DS_SETFONT or DS_SHELLFONT.
/// </summary>
/// <remarks>
/// If you specify character strings in the class and title arrays, you must use Unicode strings. Use the
/// MultiByteToWideChar function to generate Unicode strings from ANSI strings.
/// </remarks>
public string Typeface;
}
}

View File

@@ -1248,62 +1248,63 @@ namespace ExecutableTest
}
}
}
else if (dialogBox.DialogTemplateExtended != null)
else if (dialogBox.ExtendedDialogTemplate != 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($"{padding}Version: {dialogBox.ExtendedDialogTemplate.Version}");
Console.WriteLine($"{padding}Signature: {dialogBox.ExtendedDialogTemplate.Signature}");
Console.WriteLine($"{padding}Help ID: {dialogBox.ExtendedDialogTemplate.HelpID}");
Console.WriteLine($"{padding}Extended style: {dialogBox.ExtendedDialogTemplate.ExtendedStyle}");
Console.WriteLine($"{padding}Style: {dialogBox.ExtendedDialogTemplate.Style}");
Console.WriteLine($"{padding}Item count: {dialogBox.ExtendedDialogTemplate.DialogItems}");
Console.WriteLine($"{padding}X-coordinate of upper-left corner: {dialogBox.ExtendedDialogTemplate.PositionX}");
Console.WriteLine($"{padding}Y-coordinate of upper-left corner: {dialogBox.ExtendedDialogTemplate.PositionY}");
Console.WriteLine($"{padding}Width of the dialog box: {dialogBox.ExtendedDialogTemplate.WidthX}");
Console.WriteLine($"{padding}Height of the dialog box: {dialogBox.ExtendedDialogTemplate.HeightY}");
Console.WriteLine($"{padding}Menu resource: {dialogBox.ExtendedDialogTemplate.MenuResource ?? "[EMPTY]"}");
Console.WriteLine($"{padding}Menu resource ordinal: {dialogBox.ExtendedDialogTemplate.MenuResourceOrdinal}");
Console.WriteLine($"{padding}Class resource: {dialogBox.ExtendedDialogTemplate.ClassResource ?? "[EMPTY]"}");
Console.WriteLine($"{padding}Class resource ordinal: {dialogBox.ExtendedDialogTemplate.ClassResourceOrdinal}");
Console.WriteLine($"{padding}Title resource: {dialogBox.ExtendedDialogTemplate.TitleResource ?? "[EMPTY]"}");
Console.WriteLine($"{padding}Point size: {dialogBox.ExtendedDialogTemplate.PointSize}");
Console.WriteLine($"{padding}Weight: {dialogBox.ExtendedDialogTemplate.Weight}");
Console.WriteLine($"{padding}Italic: {dialogBox.ExtendedDialogTemplate.Italic}");
Console.WriteLine($"{padding}Character set: {dialogBox.ExtendedDialogTemplate.CharSet}");
Console.WriteLine($"{padding}Typeface: {dialogBox.ExtendedDialogTemplate.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 templates");
Console.WriteLine($"{padding}-------------------------");
if (dialogBox.ExtendedDialogTemplate.DialogItems == 0
|| dialogBox.ExtendedDialogItemTemplates == null
|| dialogBox.ExtendedDialogItemTemplates.Length == 0)
{
Console.WriteLine($"{padding}No dialog item templates");
}
else
{
for (int i = 0; i < dialogBox.ExtendedDialogItemTemplates.Length; i++)
{
var dialogItemTemplate = dialogBox.ExtendedDialogItemTemplates[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]");
// }
//}
Console.WriteLine($"{padding}Dialog item template {i}");
Console.WriteLine($"{padding} Help ID: {dialogItemTemplate.HelpID}");
Console.WriteLine($"{padding} Extended style: {dialogItemTemplate.ExtendedStyle}");
Console.WriteLine($"{padding} Style: {dialogItemTemplate.Style}");
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
{