Discussion:
PRINTDLG causing offset
(too old to reply)
Scoots
2009-08-14 21:44:09 UTC
Permalink
Hello,

Sorry for the rather indescript subject, but I have a problem that's
rather difficult to state. I have an application where my main class
is declared globally. I've inherited this code, and it's quite large,
so I don't question why, I've just left it that way.

It looks something like the following:

CSimApp theApp;

in the header, the definition for CSimApp looks like:

class CSimApp
{
.
. Bunch of stuff
.

PRINTDLG m_PageSetupDlg;
PRINTDLG m_PrintDlg;

.
. More Stuff
.


CPointDatabase m_PointDB;
}

Where CPointDatabase was a class I wrote and the details of which
should not matter. If they do, I'll see what I can do to post it.
It's a few lists, etc. Not a real database. Anyway, this structure
causes thApp instance to be initialized at startup (as it is globally
defined), and, as m_PointDB is a member variable and not a pointer, it
gets initialized at the very beginning of the CSimApp constructor.

None of this should be surprising, but I discovered that the address
of &theApp.m_PointDB (in the CSimApp constructor) and "this" (inside
the CPointDatabase constructor) were 4 bytes different. So after some
debugging, I went "aha! I have two different class definitions for
something in CSimApp, " as I had just spent a fair bit of time
removing old code that was no longer used in the new app, I thought it
was highly possible for me to have introduced two definitions.

But it turns out that it is PRINTDLG. Each PRINTDLG causes 2 bytes of
offset to appear between the two pointers, which should be the same.
As soon as I remove the PRINTDLG member variables, the issue
disappeared.


Now, PRINTDLG is a defined in Windows.h, I think (or at least, you get
access by including it), and I ran a search and I do NOT have any
other definition for PRINTDLG. What's going on here? How is the size
showing up as different? And it's not just a debug mode "oops," my
object fails a afx mem check with a null pointer, caused by the
offset.

Thanks, and this isn't urgent, as I don't need printing yet. Just a
"what's going on?"
~Scoots
Tamas Demjen
2009-08-15 00:44:56 UTC
Permalink
Post by Scoots
class CSimApp
{
.
. Bunch of stuff
.
PRINTDLG m_PageSetupDlg;
PRINTDLG m_PrintDlg;
.
. More Stuff
.
CPointDatabase m_PointDB;
}
[...]
Post by Scoots
I discovered that the address
of &theApp.m_PointDB (in the CSimApp constructor) and "this" (inside
the CPointDatabase constructor) were 4 bytes different. So after some
debugging, I went "aha! I have two different class definitions for
something in CSimApp
A number of things can cause such a problem. All of the following have
happened to me before.

1. Alignment, and most likely that's the problem in your case. If you
include your class from two units, and one of them uses a different
alignment, you're in a big trouble:

// One.cpp:
#pragma pack(1)
#include "SimApp.h"

// Two.cpp:
#pragma pack(16)
#include "SimApp.h"

The easiest way to verify this is to specify the alignment explicitly
for your class definition:

#pragma pack(push, 4)
class CSimApp
{
...
};
#pragma pack(pop)


2. Conditionals
2.a. Explicit, such as

class CSimApp
{
...
#ifdef SOME_CONDITION
int value;
#endif
...
};

2.b. Implicit, such as
class CSimApp
{
...
TCHAR title[TITLE_SIZE];
...
};

Hint: If you include this file from an ANSI DLL and a UNICODE DLL,
sizeof(CSimApp) will be different. Pass a pointer back and forth, and
the alignment will be incorrect.


3. Your include path can be incorrectly set up, and you may be including
two different versions of the SimApp.h in two different places. Or your
precompiled header database might be corrupt.


4. Two DLLs compiled with different compiler options, or different
compilers altogether. For example, in Borland the default size of an
enum is 1, in Visual Studio it's 4. Two modules are not necessarily
binary compatible.


5. Although it's extremely unlikely that windows.h itself is buggy, it
happened to me. Back in the day, Borland accidentally shipped the wrong
declarations with a new compiler, which made sizeof(BITMAPINFOHEADER)
incorrect, which made all of my .bmp files invalid. It was a missing
#pragma pack or something like that in the Win32 headers. I don't think
the current Visual Studio has such a problem with something so common as
PRINTDLG.

Tom
Scoots
2009-08-26 05:13:35 UTC
Permalink
I am still not sure of the exact cause, as I do not have a single pack
statement in my project, but wrapping my headers in pragma packs works.
Tamas Demjen
2009-08-28 00:47:24 UTC
Permalink
Post by Scoots
I am still not sure of the exact cause, as I do not have a single pack
statement in my project, but wrapping my headers in pragma packs works.
It is possible that you included a header file that issued a #pragma
pack change without properly restoring it using "pop". It could be a 3rd
party (or even a Microsoft) header.

Also the default packing is a compiler option, which can be changed on a
unit basis. So if one of your .cpp files has an override, that can
explain it. That would be under Configuration Properties -> C/C++ ->
Code Generation -> Struct Member Alignment (/Zp[num] switch).

Tom

Loading...