From: DSXC on 11 Jun 2007 23:57 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 13 Jun 2007 05:03 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 13 Jun 2007 22:56 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 14 Jun 2007 07:57 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 14 Jun 2007 09:23
"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 |