www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Top-Down Structs

reply "Bob W" <nospam aol.com> writes:
After using some Win32 declarations, wich are
obviously not part of "std.c.windows.windows",
I have noticed that a resulting program crashes with

    "Error: Win32 Exception" .

This happens if the main structure ("INPUT_RECORD")
is declared before the other structures contained in
the main structure. The problem will not arise if
sub-structs [B] are declared earlier than the main
struct [A].

Before that incident I was convinced that the
D compiler would handle "top-down" declarations
correctly.



----- "Problematic" declaration sequence: -----


// INPUT_RECORD [A]

struct INPUT_RECORD {
  WORD EventType;
  union {
    KEY_EVENT_RECORD KeyEvent;
    MOUSE_EVENT_RECORD MouseEvent;
    WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
    MENU_EVENT_RECORD MenuEvent;
    FOCUS_EVENT_RECORD FocusEvent;
} }


// Structs contained in INPUT_RECORD [B]

struct KEY_EVENT_RECORD {
  BOOL bKeyDown;
  WORD wRepeatCount;
  WORD wVirtualKeyCode;
  WORD wVirtualScanCode;
  union  {  WCHAR UnicodeChar;  CHAR AsciiChar;  }
  DWORD dwControlKeyState;
}

struct MOUSE_EVENT_RECORD {
  COORD dwMousePosition;
  DWORD dwButtonState;
  DWORD dwControlKeyState;
  DWORD dwEventFlags;
}

struct WINDOW_BUFFER_SIZE_RECORD { COORD dwSize; }
struct MENU_EVENT_RECORD { UINT dwCommandId; }
struct FOCUS_EVENT_RECORD { BOOL bSetFocus; }
Mar 10 2006
next sibling parent reply AgentOrange <AgentOrange_member pathlink.com> writes:
In article <duropj$o85$1 digitaldaemon.com>, Bob W says...
After using some Win32 declarations, wich are
obviously not part of "std.c.windows.windows",
I have noticed that a resulting program crashes with

    "Error: Win32 Exception" .

This happens if the main structure ("INPUT_RECORD")
is declared before the other structures contained in
the main structure. The problem will not arise if
sub-structs [B] are declared earlier than the main
struct [A].

Before that incident I was convinced that the
D compiler would handle "top-down" declarations
correctly.



----- "Problematic" declaration sequence: -----


// INPUT_RECORD [A]

struct INPUT_RECORD {
  WORD EventType;
  union {
    KEY_EVENT_RECORD KeyEvent;
    MOUSE_EVENT_RECORD MouseEvent;
    WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
    MENU_EVENT_RECORD MenuEvent;
    FOCUS_EVENT_RECORD FocusEvent;
} }


// Structs contained in INPUT_RECORD [B]

struct KEY_EVENT_RECORD {
  BOOL bKeyDown;
  WORD wRepeatCount;
  WORD wVirtualKeyCode;
  WORD wVirtualScanCode;
  union  {  WCHAR UnicodeChar;  CHAR AsciiChar;  }
  DWORD dwControlKeyState;
}

struct MOUSE_EVENT_RECORD {
  COORD dwMousePosition;
  DWORD dwButtonState;
  DWORD dwControlKeyState;
  DWORD dwEventFlags;
}

struct WINDOW_BUFFER_SIZE_RECORD { COORD dwSize; }
struct MENU_EVENT_RECORD { UINT dwCommandId; }
struct FOCUS_EVENT_RECORD { BOOL bSetFocus; }

align(1) ?
Mar 10 2006
parent "Bob W" <nospam aol.com> writes:
"AgentOrange" <AgentOrange_member pathlink.com> wrote in message 
news:dusnj5$2bh1$1 digitaldaemon.com...
 align(1) ?

Nope.
Mar 10 2006
prev sibling parent reply John C <johnch_atms hotmail.com> writes:
Bob W wrote:
 After using some Win32 declarations, wich are
 obviously not part of "std.c.windows.windows",
 I have noticed that a resulting program crashes with
 
     "Error: Win32 Exception" .
 
 This happens if the main structure ("INPUT_RECORD")
 is declared before the other structures contained in
 the main structure. The problem will not arise if
 sub-structs [B] are declared earlier than the main
 struct [A].
 
 Before that incident I was convinced that the
 D compiler would handle "top-down" declarations
 correctly.
 
 
 
 ----- "Problematic" declaration sequence: -----
 
 
 // INPUT_RECORD [A]
 
 struct INPUT_RECORD {
   WORD EventType;
   union {
     KEY_EVENT_RECORD KeyEvent;
     MOUSE_EVENT_RECORD MouseEvent;
     WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
     MENU_EVENT_RECORD MenuEvent;
     FOCUS_EVENT_RECORD FocusEvent;
 } }
 
 
 // Structs contained in INPUT_RECORD [B]
 
 struct KEY_EVENT_RECORD {
   BOOL bKeyDown;
   WORD wRepeatCount;
   WORD wVirtualKeyCode;
   WORD wVirtualScanCode;
   union  {  WCHAR UnicodeChar;  CHAR AsciiChar;  }
   DWORD dwControlKeyState;
 }
 
 struct MOUSE_EVENT_RECORD {
   COORD dwMousePosition;
   DWORD dwButtonState;
   DWORD dwControlKeyState;
   DWORD dwEventFlags;
 }
 
 struct WINDOW_BUFFER_SIZE_RECORD { COORD dwSize; }
 struct MENU_EVENT_RECORD { UINT dwCommandId; }
 struct FOCUS_EVENT_RECORD { BOOL bSetFocus; }
 
 
 

Couldn't repro on my Windows XP machine. Runs without throwing exceptions here.
Mar 11 2006
next sibling parent "Bob W" <nospam aol.com> writes:
"John C" <johnch_atms hotmail.com> wrote in message 
news:duuj4n$2ui9$1 digitaldaemon.com...


 Couldn't repro on my Windows XP machine. Runs without throwing exceptions 
 here.

It all depends what you were doing with the structs. Just declaring them won't cause any trouble. In my case I was calling the Win32 functions PeekConsoleInputA() and/or ReadConsoleInputA(), which was sufficient to upset Win XP. Both functions expect a pointer to an INPUT_RECORD structure.
Mar 11 2006
prev sibling next sibling parent reply "Bob W" <nospam aol.com> writes:
I just wanted to add this info:

Check INPUT_RECORD.sizeof if it is declared before
and after its related sub-structs. In the first case
the size of INPUT_RECORD will be 4, otherwise the
size is 20.
Mar 11 2006
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Sun, 12 Mar 2006 02:02:48 +0100, Bob W <nospam aol.com> wrote:
 I just wanted to add this info:

 Check INPUT_RECORD.sizeof if it is declared before
 and after its related sub-structs. In the first case
 the size of INPUT_RECORD will be 4, otherwise the
 size is 20.

Interestingly naming the union fixes the problem. eg. struct INPUT_RECORD { WORD EventType; union bob { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; } bob a; } (rest of wrong declaration order as given by OP) results in an INPUT_RECORD.sizeof of 20. I think the bug lies in the handling of anonymous unions. Regan
Mar 12 2006
next sibling parent "Regan Heath" <regan netwin.co.nz> writes:
Here is the code I used to test this, to save someone else the trouble.

Regan

-----------

import std.c.windows.windows;
import std.stdio;

// INPUT_RECORD [A]

struct INPUT_RECORD {
	WORD EventType;
	union bob {
		KEY_EVENT_RECORD KeyEvent;
		MOUSE_EVENT_RECORD MouseEvent;
		WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
		MENU_EVENT_RECORD MenuEvent;
		FOCUS_EVENT_RECORD FocusEvent;
	}
	bob a;
}

alias INPUT_RECORD* PINPUT_RECORD;

// Structs contained in INPUT_RECORD [B]

struct KEY_EVENT_RECORD {
   BOOL bKeyDown;
   WORD wRepeatCount;
   WORD wVirtualKeyCode;
   WORD wVirtualScanCode;
   union  {  WCHAR UnicodeChar;  CHAR AsciiChar;  }
   DWORD dwControlKeyState;
}

struct MOUSE_EVENT_RECORD {
   COORD dwMousePosition;
   DWORD dwButtonState;
   DWORD dwControlKeyState;
   DWORD dwEventFlags;
}

struct COORD {
     SHORT X;
     SHORT Y;
}

struct WINDOW_BUFFER_SIZE_RECORD { COORD dwSize; }
struct MENU_EVENT_RECORD { UINT dwCommandId; }
struct FOCUS_EVENT_RECORD { BOOL bSetFocus; }

extern(Windows) {
	BOOL ReadConsoleInputA(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer,  
DWORD nLength, LPDWORD lpNumberOfEventsRead);
	BOOL ReadConsoleInputW(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer,  
DWORD nLength, LPDWORD lpNumberOfEventsRead);
	
	HANDLE GetStdHandle(DWORD nStdHandle);
	
	DWORD STD_INPUT_HANDLE    = cast(DWORD)-10;
	DWORD STD_OUTPUT_HANDLE   = cast(DWORD)-11;
	DWORD STD_ERROR_HANDLE    = cast(DWORD)-12;

	WORD KEY_EVENT					= 0x0001; // Event contains key event record
	WORD MOUSE_EVENT				= 0x0002; // Event contains mouse event record
	WORD WINDOW_BUFFER_SIZE_EVENT	= 0x0004; // Event contains window change  
event record
	WORD MENU_EVENT					= 0x0008; // Event contains menu event record
	WORD FOCUS_EVENT				= 0x0010; // event contains focus change
}

char[][WORD] types;

static this()
{
	types[KEY_EVENT] = "Key Event";
	types[MOUSE_EVENT] = "Mouse Event";
	types[WINDOW_BUFFER_SIZE_EVENT] = "Window Buffer Size Event";
	types[MENU_EVENT] = "Menu Event";
	types[FOCUS_EVENT] = "Focus Event";
}

void main()
{
	HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
	INPUT_RECORD rec;
	DWORD rd;

	writefln("INPUT_RECORD.sizeof = ",INPUT_RECORD.sizeof);
	
	if (ReadConsoleInputA(hIn,&rec,cast(DWORD)1,&rd) == 0) {
		writefln("ReadConsoleInputA failed");
		return ;
	}
	
	writefln(rd," records read:");
	writefln("Type: ",types[rec.EventType]);
}
Mar 12 2006
prev sibling parent reply "Bob W" <nospam aol.com> writes:
"Regan Heath" <regan netwin.co.nz> wrote in message 
news:ops6amc90r23k2f5 nrage.netwin.co.nz...
 On Sun, 12 Mar 2006 02:02:48 +0100, Bob W <nospam aol.com> wrote:
 I just wanted to add this info:

 Check INPUT_RECORD.sizeof if it is declared before
 and after its related sub-structs. In the first case
 the size of INPUT_RECORD will be 4, otherwise the
 size is 20.

Interestingly naming the union fixes the problem. eg. struct INPUT_RECORD { WORD EventType; union bob { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; } bob a; } (rest of wrong declaration order as given by OP) results in an INPUT_RECORD.sizeof of 20. I think the bug lies in the handling of anonymous unions. Regan

Good job! Looks like a usable workaround. But in the long term I would rather like to see the D compiler to stick to its promises: "anonymous structs/unions are allowed as members of other structs/unions"
Mar 12 2006
parent "Regan Heath" <regan netwin.co.nz> writes:
On Sun, 12 Mar 2006 10:49:36 -0800, Brad Roberts <braddr puremagic.com>  
wrote:
 Would one of you finish minimizing the test case and file it in bugzilla?

Done. Regan
Mar 12 2006
prev sibling parent Brad Roberts <braddr puremagic.com> writes:
On Sun, 12 Mar 2006, Bob W wrote:

 "Regan Heath" <regan netwin.co.nz> wrote in message 
 news:ops6amc90r23k2f5 nrage.netwin.co.nz...
 On Sun, 12 Mar 2006 02:02:48 +0100, Bob W <nospam aol.com> wrote:
 I just wanted to add this info:

 Check INPUT_RECORD.sizeof if it is declared before
 and after its related sub-structs. In the first case
 the size of INPUT_RECORD will be 4, otherwise the
 size is 20.

Interestingly naming the union fixes the problem. eg. struct INPUT_RECORD { WORD EventType; union bob { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; } bob a; } (rest of wrong declaration order as given by OP) results in an INPUT_RECORD.sizeof of 20. I think the bug lies in the handling of anonymous unions. Regan

Good job! Looks like a usable workaround. But in the long term I would rather like to see the D compiler to stick to its promises: "anonymous structs/unions are allowed as members of other structs/unions"

Would one of you finish minimizing the test case and file it in bugzilla? Thanks, Brad
Mar 12 2006