Surviving the Release Version

Linkage Errors

Linkage Types

Certain functions require a specific linkage type, such as __stdcall. Other functions require correct parameter matching. Perhaps the most common errors are in using incorrect linkage types. When a function specifies a __stdcall linkage you must specify the __stdcall for the function you declare. If it does not specify __stdcall, you must not use the __stdcall linkage. Note that you rarely if ever see a "bare" __stdcall linkage declared as such. Instead, there are many linkage type macros, such as WINAPI, CALLBACK, IMAGEAPI, and even the hoary old (and distinctly obsolete) PASCAL which are macros which are all defined as __stdcall. For example, the top-level thread function for an AfxBeginThread function is defined as a function whose prototype uses the AFX_THREADPROC linkage type. 

UINT (AFX_CDECL * AFX_THREADPROC)(LPVOID);

which you might guess as being a CDECL (that is, non-__stdcall) linkage. If you declared your thread function as

UINT CALLBACK MyThreadFunc(LPVOID value)

and started the thread as

AfxBeginThread((AFX_THREAD_PROC)MyThreadFunc, this);

then the explicit cast (often added to make a compiler warning go away!) would fool the compiler into generating code. This often results in the query "My thread function crashes the app when the thread completes, but only in release mode". Exactly why it doesn't do this in debug mode escapes me, but most of the time when we look at the problem it was a bad linkage type on the thread function. So when you see a crash like this, make sure that you have all the right linkages in place. Beware of using casts of function types; instead. write the function as

AfxBeginThread(MyThreadFunc, (LPVOID)this);

which will allow the compiler to check the linkage types and parameter counts.

Parameter counts

Using casts will also result in problems with parameter counts. Most of these should be fatal in debug mode, but for some reason some of them don't show up until the release build. In particular, any function with a __stdcall linkage in any of its guises must have the correct number of arguments. Usually this shows up instantly at compile time unless you have used a function-prototype cast (like the (AFX_THREADPROC) cast in the previous section) to override the compiler's judgment. This almost always results in a fatal error when the function returns. 

The most common place this shows up is when user-defined messages are used. You have a message which doesn't use the WPARAM and LPARAM values, so you write

wnd->PostMessage(UWM_MY_MESSAGE);

to simply send the message. You then write a handler that looks like

afx_msg void OnMyMessage(); // incorrect!

and the program crashes in release mode. Again, I've not investigated why this doesn't cause a problem in debug mode, but we've seen it happen all the time when the release build is created. The correct signature for a user-defined message is always, without exception

afx_msg LRESULT OnMyMessage(WPARAM, LPARAM);

You must return a value, and you must have the parameters as specified (and you must use the types WPARAM and LPARAM if you want compatibility into the 64-bit world; the number of people who "knew" that WPARAM meant WORD and simply wrote (WORD, LONG) in their Win16 code paid the penalty when they went to Win32 where it is actually (UNSIGNED LONG, LONG), and it will be different again in Win64, so why do it wrong by trying to be cute?)

Note that if you don't use the parameter values, you don't provide a name for the parameters. So your handler for OnMyMessage is coded as

LRESULT CMyClass::OnMyMessage(WPARAM, LPARAM)
    {
     ...do something here...
     return 0; // logically void, 0, always
    }

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Brevity is the soul of wit” - Shakespeare