On AFX_MODULE_STATE, or – Avoiding afxCurrentInstanceHandle Asserts, Part 1

All too often I see one of these asserts fire:

ASSERT(afxCurrentInstanceHandle != NULL)
ASSERT(afxCurrentResourceHandle != NULL);
ASSERT(afxCurrentAppName != NULL);

These are coded in afxwin1.inl, and are part of the MFC high level accessors:

AfxGetInstanceHandle()
AfxGetResourceHandle()
AfxGetAppName()

If these asserts fire for you too, there’s a good chance you’re missing some afx module state management code.

Module States – Purpose

Most Win32 GUI functionality accesses resources in one way or another, and thus requires a resource handle. For example, MFC’s CDialog::DoModal() includes essentially the following calls:

…
hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
hDialogTemplate = LoadResource(hInst, hResource);
…

Where hInst is an HINSTANCE obtained from either the currently running exe or the currently running dll.

Which poses the problem: which one?

I.e., any binary in the address space can contain resources. Should the dialog-creation code search the dialog resource at the executable, or one of the dll’s? How would the code know?

A user of native Win32 API is on his own here, and must explicitly create resource handles from loaded binaries, manage their lifetime and choose the proper one when actual resources are required. MFC pioneers had the noble intention of masking this madness from their users, and thus the AFX_MODULE_STATE apparatus was born: a module state is – roughly put – a wrapper around all binary-specific-data (e.g. resource handle) that is to be switched upon any call from one binary into another.

Note that module states include much more than resource handles (check afxstate_.h and see), but resource management does seem to be the canonical usage – actually the only usage for me personally.

Module States – Basic Usage

Module-data management wasn’t thoroughly hidden away from the developer, but the coding involved was indeed reduced to a minimum. The most succinct description I know is part of the wizard-generated code for an MFC dll:

//TODO: If this DLL is dynamically linked against the MFC DLLs,
// any functions exported from this DLL which call into
// MFC
must have the AFX_MANAGE_STATE macro added at the
// very beginning of the function.
//
// For example:
//
// extern “C” BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.

So it boils down to a single declaration at the start of a function:

AFX_MANAGE_STATE(AfxGetStaticModuleState());

This is classical RAII usage: the macro generates an object, whose ctor and dtor perform substitution of the module state into a specified slot (more on this slot in later posts). The resulting code is not only compact – albeit admittedly cryptic – but also exception safe.

‘Functions which call into MFC’ is a bit of a broad phrasing (surely CString usage isn’t considered ‘calling into MFC’). I understand this wording as ‘functions which make GUI calls’.

This single line of code is the only documented way of managing state, which makes one wonder why AfxGetStaticModuleState wasn’t baked into the AFX_MANAGE_STATE macro in the first place. More on this – in the next post.

About these ads
This entry was posted in MFC.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s