avogelba / WinDirStats

WinDirStats - Windows Directory Statistics, private clone from:
https://bitbucket.org/windirstat/windirstat
GNU General Public License v2.0
5 stars 0 forks source link

Linker error caused by COwnerDrawnListControl::OnEraseBkgnd #76

Closed avogelba closed 7 years ago

avogelba commented 10 years ago

Originally reported by: Oliver (Bitbucket: assarbad, GitHub: assarbad)


The following error occurs with VS 2005 and the x64 target.

1>ownerdrawnlistcontrol.obj : error LNK2019: unresolved external symbol "public: int __cdecl CListCtrl::GetColumnOrderArray(int *,__int64)" (?GetColumnOrderArray@CListCtrl@@QEAAHPEAH_J@Z) referenced in function "protected: int __cdecl COwnerDrawnListControl::OnEraseBkgnd(class CDC *)" (?OnEraseBkgnd@COwnerDrawnListControl@@IEAAHPEAVCDC@@@Z)

avogelba commented 10 years ago

Original comment by Oliver (Bitbucket: assarbad, GitHub: assarbad):


From the updated Wiki contents:

If you encounter a LNK2019: unresolved external symbol "public: int __cdecl CListCtrl::GetColumnOrderArray(int *,__int64)"

This is a very very annoying bug. And it's inside the MFC that comes with VS2005. I'll see whether and when I can check other versions (such as specifically VS2008). VS2010 doesn't appear to have the issue.

So we get LNK2019: unresolved external symbol "public: int __cdecl CListCtrl::GetColumnOrderArray(int *,__int64)" with a decorated name of ?GetColumnOrderArray@CListCtrl@@QEAAHPEAH_J@Z. If we have a quick look into the .def files for amd64 in VS2005 we find no such function.

Here are all the closest matches I get to see:

#!text

C:\Program Files (x86)\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\amd64\mfc80.def
    2325   ?GetColumnOrderArray@CListCtrl@@QEAAHPEAHH@Z @ 2566 NONAME
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\amd64\mfc80d.def
    3304   ?GetColumnOrderArray@CListCtrl@@QEAAHPEAHH@Z @ 3545 NONAME
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\amd64\mfc80u.def
    2316   ?GetColumnOrderArray@CListCtrl@@QEAAHPEAHH@Z @ 2557 NONAME
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\amd64\mfc80ud.def
    3293   ?GetColumnOrderArray@CListCtrl@@QEAAHPEAHH@Z @ 3534 NONAME

Microsoft provides a tool named undname that can be used o undecorate the names. Let's compare ?GetColumnOrderArray@CListCtrl@@QEAAHPEAHH@Z with ?GetColumnOrderArray@CListCtrl@@QEAAHPEAH_J@Z then:

#!text

C:\>undname ?GetColumnOrderArray@CListCtrl@@QEAAHPEAHH@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?GetColumnOrderArray@CListCtrl@@QEAAHPEAHH@Z"
is :- "public: int __cdecl CListCtrl::GetColumnOrderArray(int * __ptr64,int) __ptr64"

C:\>undname ?GetColumnOrderArray@CListCtrl@@QEAAHPEAH_J@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?GetColumnOrderArray@CListCtrl@@QEAAHPEAH_J@Z"
is :- "public: int __cdecl CListCtrl::GetColumnOrderArray(int * __ptr64,__int64) __ptr64"

Oh brilliant. So the issue is the second parameter. Let's dig further.

Looking for GetColumnOrderArray in the atlmfc subfolder underneath the VS2005 installation we find:

#!text

C:\Program Files (x86)\Microsoft Visual Studio 8\VC\atlmfc\include\afxcmn.h
     396    BOOL GetColumnOrderArray(LPINT piArray, int iCount = -1);
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\winctrl6.cpp
     192  BOOL CListCtrl::GetColumnOrderArray(LPINT piArray, int iCount /* = -1 */)

See the problem already? Hint as can be seen on this Microsoft documentation page of "Windows Data Types" INT_PTR is equivalent to __int64 on 64bit Windows.

#!c++

#if defined(_WIN64) 
 typedef __int64 INT_PTR; 
#else 
 typedef int INT_PTR;
#endif

Now, that was probably introduced with the Windows 7 SP1 SDK and I found no other way than to actually fix the declaration in afxcmn.h to match the definition from which the libs were built.

That means we change the occurrence at line 396 in afxcmn.h to read:

#!text

     396    BOOL GetColumnOrderArray(LPINT piArray, int iCount = -1);

And that's that.

Note that there is a second part to this bugfix which is included in windirstat.h, but which you don't have to care about. If you are curious, though, it reads:

#!c++

#if (_MFC_VER <=0x0800)
#define GetColumnOrderArrayX(arr,ncol) GetColumnOrderArray((arr), (int)(ncol))
#else
#define GetColumnOrderArrayX GetColumnOrderArray
#endif
avogelba commented 10 years ago

Original comment by Oliver (Bitbucket: assarbad, GitHub: assarbad):


Not an issue on VS 2012, it appears.