• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1211
  • Last Modified:

C++ Sizeof(struct) Reporting the Wrong Size!

I am trying to create a dialog template in memory to be passed to the CreateDialogIndirect() Win32 API call per this MSDN article:
http://msdn.microsoft.com/en-us/library/ms644996%28v=VS.85%29.aspx#template_in_memory

I'm also using the DLGTEMPLATEEX structure as described in this article instead of the DLGTEMPLATE example MSDN uses:
http://msdn.microsoft.com/en-us/library/ms645398%28VS.85%29.aspx

In my application I won't know at compile time how big the dialog box is or how long the title string will be, so I can't simply hard-code it.  Since the title string is in the middle of the DLGTEMPLATEEX struct, I have created two structs; one for the data that comes before the title, and one for the data that comes after.  I then create an array that squishes the title in between the two (which is waaaay more elegant than the example MSDN provides IMHO).

Anyway, here's the problem I am running into:  The first struct is two bytes too big and I can't figure out why!  I created a sample app and posted the code below to demonstrate what's going on.  The DlgInfo struct is only supposed to be 30 bytes long, but sizeof(DlgInfo) is reporting 32.  It's inserting two garbage bytes into the array, and CreateDialogIndirect() doesn't understand it.  It either displays no title at all, or displays a strange character before it depending on what the garbage is.

Where are these two extra bytes coming from??

I'm using Visual C++ 2008, BTW
#include <windows.h>

BOOL CALLBACK DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    //Handle the only two messages we care about at this point
	switch(msg)
	{
	case WM_CLOSE:
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    //Define the two structs and instantiate them with default values
	struct DlgInfo  //Create and initialize struct w/ default values
	{
		WORD dlgVer;
		WORD signature;
		DWORD helpID;
		DWORD exStyle;
		DWORD style;
		WORD dlgItems;
		short xPos;
		short yPos;
		short width;
		short height;
		WORD menuID;
		WORD windowClass;
	} dlgInfo = {1,0xFFFF,NULL,NULL,WS_POPUP|WS_CAPTION|WS_SYSMENU|DS_SETFONT,0,0,0,0,0,NULL,0};

	struct DlgFontInfo
	{
		WORD  pointsize;
		WORD  weight;
		BYTE  italic;
		BYTE  charset;
		wchar_t typeface[13];
	} dlgFontInfo = {NULL,NULL,NULL,NULL,L"MS Shell Dlg"};

    //Set some customized values
	const wchar_t *title = L"Test";
	short xPos = 64;
	short yPos = 64;
	short width = 230;
	short height = 180;

    //Get the sizes of everything so we know how much space we need
	unsigned char dlgInfoSize = sizeof(DlgInfo);	// <<== This returns 32.  Should be 30!  Why?
	unsigned char dlgFontInfoSize = sizeof(DlgFontInfo);
	unsigned long titleSize = wcslen(title) + 1;
	unsigned long dlgTemplateSize = dlgInfoSize + (titleSize * 2) + dlgFontInfoSize;

    //Allocate the memory
	unsigned char *dlgTemplate = new unsigned char[dlgTemplateSize];

    //Copy the 1st struct over and set the custom values
	DlgInfo *dlgInfoCpy = (DlgInfo*)dlgTemplate;
	memcpy(dlgInfoCpy, &dlgInfo, dlgInfoSize);
	dlgInfoCpy->xPos = xPos;
	dlgInfoCpy->yPos = yPos;
	dlgInfoCpy->width = width;
	dlgInfoCpy->height = height;

    //Copy the title over at the next element
	wchar_t *titleCpy = (wchar_t*)(dlgInfoCpy + 1);
	wcsncpy(titleCpy, title, titleSize);

    //Copy the 2nd struct over after the title
	DlgFontInfo *dlgFontInfoCpy = (DlgFontInfo*)(titleCpy + titleSize);
	memcpy(dlgFontInfoCpy, &dlgFontInfo, dlgFontInfoSize);

    //Create the dialog w/ a bit of error checking
        HWND hWnd;
	if( (hWnd = CreateDialogIndirect(hInstance,(LPDLGTEMPLATE)dlgTemplate,NULL,DlgProc)))
		ShowWindow(hWnd, SW_SHOW);
	else
	{
		LPTSTR errMsg = 0;
		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),NULL,(LPTSTR)&errMsg,NULL,NULL);
		MessageBox(NULL,errMsg,L"Error",MB_OK);
		delete[] errMsg;
	}

    //Begin our message loop
	MSG msg;
	while(GetMessage(&msg, NULL, NULL, NULL) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}

Open in new window

0
cuziyq
Asked:
cuziyq
  • 6
  • 4
  • 3
  • +3
2 Solutions
 
evilrixSenior Software Engineer (Avast)Commented:
Why do you think it should be 30 bytes? What about struct padding for data alignment?
http://en.wikipedia.org/wiki/Data_structure_alignment
0
 
phoffricCommented:
Your struct DlgInfo looks like 30 bytes long of content. But suppose you had an array of struct DlgInfo. Then you would want your DWORD to be properly aligned on a DWORD boundary. So, my bet is that if you print the offset of each struct DlgInfo  attribute, you will find them with the expected offset; but you will find that there are two bytes of internal padding at the end of the struct so that all elements of an array (whether you need one or not) will land on a DWORD boundary.
0
 
cuziyqAuthor Commented:
Padding should be zero.  The title needs to start at the very next WORD offset after the window class.  This is why the garbage in those extra two bytes gives me a strange (usually Asian) character before the title when the dialog displays on the screen -- unless the garbage is 0000, in which case no title displays at all.
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

 
evilrixSenior Software Engineer (Avast)Commented:
>> Padding should be zero.
Why should it? The compiler is free to put padding where ever it chooses to facilitate data alignment.
0
 
cuziyqAuthor Commented:
Sorry . . . I meant to say that the title needs to start at the very next WORD offset of the WndClass element of the DlgInfo struct.
0
 
phoffricCommented:
You can force no padding, and since you do not have an array, that would be OK. Or, what we have done is to explicitly put in the padding and initialize to 0, if that would help. I am not familiar enough with your program to understand why your program doesn't use just the attribute values rather than go beyond the size of the last attribute.
0
 
cuziyqAuthor Commented:
How do I get it to force no padding?
0
 
phoffricCommented:
>> WORD windowClass;
>> WndClass element of the DlgInfo struct
You have windowClass as WORD not WndClass - is that a problem?
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> How do I get it to force no padding?
http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx
0
 
phoffricCommented:
>> It's inserting two garbage bytes into the array, and CreateDialogIndirect() doesn't understand it.
I would expect that if you pack and you get your size down to 30, that you will still experience problems. Packing the struct should not affect the functionality of the program unless directed to do so by your documentation.
0
 
cuziyqAuthor Commented:
The windowClass member accepts a class atom (which is a WORD value), or a null-terminated string with the class's name.  In this case, 0000 indicates Windows' built-in default dialog class.

The CreateDialogIndirect() API call simply takes a pointer to the start of a glob of memory describing the dialog box to be created.  It has very specifiic byte alignment requirements imposed by Microsoft.  The only way to do it at run time is with dynamic allocation, so if the compiler is giving me "courtesy padding", I need to turn it off.

I could solve it by subtracting 2 manually, but that would be a hack.
0
 
phoffricCommented:
I gather that you believe that your program is reading the garbage in the two padded bytes. The question is why is this happening? This should not be the case normally. I don't know the Windows API well enough to comment. I tried to build a program from you code, but I didn't get good results - just a stuck window (but that's my lack of knowing Windows api).

When you talk about a windowClass member, are you talking about the WNDCLASS Structure:
    http://msdn.microsoft.com/en-us/library/ms633576%28VS.85%29.aspx

Well, back to your pack.. Did it work and now you get a size of 30? And did that get your title correct?
0
 
phoffricCommented:
I'm sorry - I left in some words in previous post that I figured out.

Revision:
I tried to build a program from you code, but I didn't get good results - just a stuck window (but that's my lack of knowing Windows api).

When you talk about a windowClass member, are you talking about the WNDCLASS Structure:
    http://msdn.microsoft.com/en-us/library/ms633576%28VS.85%29.aspx

Well, back to your pack.. Did it work and now you get a size of 30? And did that get your title correct?
0
 
pgnatyukCommented:
Actually it does not matter if you set a title or a style in the dialog template or not - all these things can be changed later by calling SetWindowText, SetWindowLong, etc API. So find the hard-coded values that will allow you to create the dialog fast.

You can make aside an MFC dialog application and debug DoModal - you'll how Microsoft implemented all this things.

I did the same few years ago, in 2003, - on a slow Windows Mobile/CE devices this trick improved the app performance dramatically.


0
 
OrcbighterCommented:
if you set you compiler to be byte-aligned, the sizeof function will return 30 bytes for the dlgInfo struct.

Open the Properties of your project, then select the path Configuration Properties \ C/C++ \ Code Generation

In the right-hand pane click on the item named 'Struct Member Alignment'
select '1 Byte' from ther drop down
recompile all
test the sizeof again

0
 
itsmeandnobodyelseCommented:
>>>> Padding should be zero.  
>>>> The title needs to start at the very next WORD offset after the window class.

>>>> The CreateDialogIndirect() API call simply takes a pointer to the start of a glob of memory
>>>> describing the dialog box to be created.  It has very specifiic byte alignment requirements
>>>>  imposed by Microsoft.  The only way to do it at run time is with dynamic allocation, so if the
>>>> compiler is giving me "courtesy padding", I need to turn it off.

Hmm. The struct you should use is

typedef struct {
WORD dlgVer;
WORD signature;
DWORD helpID;
DWORD exStyle;
DWORD style;
WORD cDlgItems;
short x;
short y;
short cx;
short cy;
sz_Or_Ord menu;
sz_Or_Ord windowClass;
WCHAR title[titleLen];
short pointsize;
short weight;
short bItalic;
WCHAR font[fontLen];
} DLGTEMPLATEEX;

You see the title is an array of WCHAR where a single element is also word-size. That's probably why there is no padding between windowClass and title. If you would use the above structure instead of concatenating two (hand-made) structures you wouldn't have an alignment issue what is only a problem cause you were using two structures.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

  • 6
  • 4
  • 3
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now