From: DSXC on
Hi!

I've been working on some interface DLL's recently that pass a CWnd back to
a main EXE. Everything works fine in DEBUG mode. As soon as I go over to a
RELEASE version I get:
- error LNK2019: unresolved external symbol "class CHandleMap * __stdcall
afxMapHWND(int)" (?afxMapHWND@@YGPAVCHandleMap@@H@Z)

Now this is rather interesting as I did a search on the net and found that
this function is not in the MFC71.lib but is in the MFC71D.lib. If I
comment out the code like:

#ifdef _DEBUG
afxMapHWND(TRUE);
#endif
m_lpParent = new CWnd();
m_lpParent->Attach(lpParent->GetSafeHwnd());;
return CreateDlgIndirect(lpDialogTemplate, m_lpParent, hInstance);

It will build fine but will assert the application on close:
//within CWnd::DestroyWindow()
CHandleMap *pMap;
pMap = afxMapHWND();
ASSERT(pMap != NULL);

Also I can STATICALLY link the MFC DLL to the program... but this increases
my DLL's size from 96Kb to 600Kb. When I'm trying to keep sizes to a
minimum this is too much. My DEBUG DLL is only 160Kb itself.

Now my question is how I can link into the library file to have this
afxMapHWND function dynamically linked to my DLL? I found a post stating it
is in nafxcw.lib and uafxcw.lib but when I add this (one or the other, not
both) into my additional dependencies I get:
- error LNK2005: _RawDllMain(a)12 already defined in nafxcw.lib(dllmodul.obj)
- error LNK2005: _DllMain(a)12 already defined in nafxcw.lib(dllmodul.obj)
- error LNK2005: __pRawDllMain already defined in nafxcw.lib(dllmodul.obj)
- error LNK2005: __afxForceUSRDLL already defined in
nafxcw.lib(dllmodul.obj)
- warning LNK4006: _RawDllMain(a)12 already defined in
nafxcw.lib(dllmodul.obj); second definition ignored
- warning LNK4006: _DllMain(a)12 already defined in nafxcw.lib(dllmodul.obj);
second definition ignored
- warning LNK4006: __pRawDllMain already defined in
nafxcw.lib(dllmodul.obj); second definition ignored
- warning LNK4006: __afxForceUSRDLL already defined in
nafxcw.lib(dllmodul.obj); second definition ignored
- warning LNK4098: defaultlib 'mfc71.lib' conflicts with use of other libs;
use /NODEFAULTLIB:library
- warning LNK4098: defaultlib 'mfcs71.lib' conflicts with use of other
libs; use /NODEFAULTLIB:library
- error LNK2001: unresolved external symbol ___argv
- error LNK2001: unresolved external symbol ___argc
- error LNK2001: unresolved external symbol __mbctype
- error LNK2019: unresolved external symbol __mbctype referenced in
function "void __stdcall _AfxAbbreviateName(char *,int,int)"
(?_AfxAbbreviateName@@YGXPADHH@Z)
- error LNK2001: unresolved external symbol __mbctype
- fatal error LNK1120: 3 unresolved externals

Is there a way around this? The code sample below shows what it is doing:

int LoadGUI(CWnd *lpParent, CDialog **lpChild)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HINSTANCE hInst;
HRSRC hResource;
HGLOBAL hTemplate;
LPCDLGTEMPLATE lpDialogTemplate;

hInst = AfxFindResourceHandle(MAKEINTRESOURCE(IDD_MAIN_DIALOG),
RT_DIALOG);
hResource = ::FindResource(hInst, MAKEINTRESOURCE(IDD_MAIN_DIALOG),
RT_DIALOG);
hTemplate = LoadResource(hInst, hResource);
lpDialogTemplate = (LPCDLGTEMPLATE) LockResource(hTemplate);

theApp.m_lpMainDialog = new CMyDlg(lpParent, theApp.m_clrBackground);
theApp.m_lpMainDialog->AttachControlSite(lpParent);
theApp.m_lpMainDialog->Create(lpDialogTemplate, lpParent, hInst);

(*lpChild) = theApp.m_lpMainDialog;

if ((*lpChild) != NULL)
{
return 1;
}
else
{
return 0;
}
}

and

BOOL CMyDlg::Create(LPCDLGTEMPLATE lpDialogTemplate, CWnd *lpParent,
HINSTANCE hInstance)
{
#ifdef _DEBUG
afxMapHWND(TRUE);
#endif
m_lpParent = new CWnd();
m_lpParent->Attach(lpParent->GetSafeHwnd());;
return CreateDlgIndirect(lpDialogTemplate, m_lpParent, hInstance);
}

The LoadGUI is passed called from the parent EXE inside the GUI DLL. Hope
this makes sense :).

Thanks in advance.

DSXC


From: MrAsm on
On Tue, 12 Jun 2007 13:57:40 +1000, "DSXC" <dsxc80(a)gmail.com> wrote:

>Everything works fine in DEBUG mode. As soon as I go over to a
>RELEASE version I get:
> - error LNK2019: unresolved external symbol "class CHandleMap * __stdcall
>afxMapHWND(int)" (?afxMapHWND@@YGPAVCHandleMap@@H@Z)
>
>Now this is rather interesting as I did a search on the net and found that
>this function is not in the MFC71.lib but is in the MFC71D.lib. If I
>comment out the code like:

I think that the 'afxMapHWND' function is *very* important for the MFC
framework. It may not be *exported* in the release build of MFC, but I
believe it is *implemented* (defined) also in the release build.
(Note that a function can be defined but not exported by a library.)

You can see its implementation in 'wincore.cpp' file (and note that
there is no #ifdef _DEBUG ... to exclude that function from release
builds).

I don't know why you need to *explicitly* call afxMapHWND (it should
be called by the MFC framework, when it needs that). I think that you
could avoid calling that function explicitly.

However, if you are doing some 'hack' or really advanced thing (if I
recall correctly, I've never called afxMapHWND explicitly), and you
really need to call it, you might want to copy-and-paste its source
code locally in your module; but I believe it is not very good
programming style and architecture, IMHO...
I would prefer to refactor your code and architecture, to avoid
explicit call to afxMapHWND, if possible.


>Also I can STATICALLY link the MFC DLL to the program... but this increases
>my DLL's size from 96Kb to 600Kb. When I'm trying to keep sizes to a
>minimum this is too much. My DEBUG DLL is only 160Kb itself.

If your purpose is to have very lean thin binaries and you don't want
dependency from external MFC DLL, you might consider using ATL, and
WTL (which is based on ATL) as a foundation for the GUI.

MrAsm
From: DSXC on
Thanks for your response.

Well the reason behind calling the afxMapHWND is because I'm passing a HWND
which is not in the map down as a parent window. Without passing this the
parent window asserts on creation (CWnd::AssertValid function) at the point
where it is checking if the CHandleMap is valid. If there is a way to pass
a parent CWnd from an EXE into a child CWnd inside a DLL I'd like to know -
all of the DLL's are loaded via LoadLibrary. The parent CWnd is to a tab
control within our container application, the DLL's pass CDialog back to the
parent via a create method. The CDialog is then shown on the tab control
using ShowWindow(SW_SHOW) when it is the selected tab (and SW_HIDE when it
is not). It works fine when the CDialogs are created within the container
application, but not within the DLL.

At the moment I'm sticking with MFC from an ease of use point of view
(haven't used ATL for probably 3 years, so it means remembering stuff I
haven't used for a while), but if there is no way of doing this I may have
to go back to ATL.

DSXC

"MrAsm" <mrasm(a)usa.com> wrote in message
news:5sav631ki2quotk12kkjj70lvuup08qihm(a)4ax.com...
> On Tue, 12 Jun 2007 13:57:40 +1000, "DSXC" <dsxc80(a)gmail.com> wrote:
>
>>Everything works fine in DEBUG mode. As soon as I go over to a
>>RELEASE version I get:
>> - error LNK2019: unresolved external symbol "class CHandleMap * __stdcall
>>afxMapHWND(int)" (?afxMapHWND@@YGPAVCHandleMap@@H@Z)
>>
>>Now this is rather interesting as I did a search on the net and found that
>>this function is not in the MFC71.lib but is in the MFC71D.lib. If I
>>comment out the code like:
>
> I think that the 'afxMapHWND' function is *very* important for the MFC
> framework. It may not be *exported* in the release build of MFC, but I
> believe it is *implemented* (defined) also in the release build.
> (Note that a function can be defined but not exported by a library.)
>
> You can see its implementation in 'wincore.cpp' file (and note that
> there is no #ifdef _DEBUG ... to exclude that function from release
> builds).
>
> I don't know why you need to *explicitly* call afxMapHWND (it should
> be called by the MFC framework, when it needs that). I think that you
> could avoid calling that function explicitly.
>
> However, if you are doing some 'hack' or really advanced thing (if I
> recall correctly, I've never called afxMapHWND explicitly), and you
> really need to call it, you might want to copy-and-paste its source
> code locally in your module; but I believe it is not very good
> programming style and architecture, IMHO...
> I would prefer to refactor your code and architecture, to avoid
> explicit call to afxMapHWND, if possible.
>
>
>>Also I can STATICALLY link the MFC DLL to the program... but this
>>increases
>>my DLL's size from 96Kb to 600Kb. When I'm trying to keep sizes to a
>>minimum this is too much. My DEBUG DLL is only 160Kb itself.
>
> If your purpose is to have very lean thin binaries and you don't want
> dependency from external MFC DLL, you might consider using ATL, and
> WTL (which is based on ATL) as a foundation for the GUI.
>
> MrAsm


From: MrAsm on
On Thu, 14 Jun 2007 12:56:26 +1000, "DSXC" <dsxc80(a)gmail.com> wrote:

>Thanks for your response.

You're welcome.


>Well the reason behind calling the afxMapHWND is because I'm passing a HWND
>which is not in the map down as a parent window. Without passing this the
>parent window asserts on creation (CWnd::AssertValid function) at the point
>where it is checking if the CHandleMap is valid. If there is a way to pass
>a parent CWnd from an EXE into a child CWnd inside a DLL I'd like to know -
>all of the DLL's are loaded via LoadLibrary.

Are you using MFC Extension DLLs, or just Win32 DLLs?
(Maybe the problems occurr because you are exposing MFC classes from a
Win32 DLL, not an MFC Extension DLL?)

However, I would consider using ATL/WTL, also because ATL CWindow is
just a thin C++ wrapper around HWND, and - for what I know - in ATL
there are no HWND-CWnd maps typical of MFC.
So, using ATL/WTL, you could avoid the HWND-CWnd map problem.

MrAsm
From: David Ching on
"DSXC" <dsxc80(a)gmail.com> wrote in message
news:1371b54ciduefc9(a)corp.supernews.com...
> Well the reason behind calling the afxMapHWND is because I'm passing a
> HWND which is not in the map down as a parent window. Without passing
> this the parent window asserts on creation (CWnd::AssertValid function) at
> the point where it is checking if the CHandleMap is valid. If there is a
> way to pass a parent CWnd from an EXE into a child CWnd inside a DLL I'd
> like to know - all of the DLL's are loaded via LoadLibrary. The parent
> CWnd is to a tab control within our container application, the DLL's pass
> CDialog back to the parent via a create method. The CDialog is then shown
> on the tab control using ShowWindow(SW_SHOW) when it is the selected tab
> (and SW_HIDE when it is not). It works fine when the CDialogs are created
> within the container application, but not within the DLL.
>
> At the moment I'm sticking with MFC from an ease of use point of view
> (haven't used ATL for probably 3 years, so it means remembering stuff I
> haven't used for a while), but if there is no way of doing this I may have
> to go back to ATL.
>

I would try to resolve this in MFC, as it is the easier route than dumping
it and going to ATL.

As Asm hints, if you pass CWnd * between your .exe and .dll, you need to
make sure both are NOT statically linking MFC. This is because both .exe
and .dll need to be using same copy of MFC so that both have the CWnd in the
map. (If you statically link MFC, there is a separate copy running in .exe
and another in .dll, and these don't know about CWnd's in the other.)

If you did want to statically link MFC (like I love to do), then what you
would do is pass HWND between .exe/.dll and when the receiver gets it, it
can do a CWnd::Attach() on it to associate the HWND to a CWnd in that
module's MFC HWND map.

-- David