CToolBar::_GetButton link error for ARMV4

I'm porting code developed for the PPC ARMV4 platform from eVC++4.0 to Visual Studio 2005.  While trying to port a class that derives from CToolBar, I ran into a link problem involving the CToolBar::_GetButton function.  The problem I'm having can be demonstrated using the simple class defined below:< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

class __declspec(dllexport) CToolBarDummy : public CToolBar

{

public:

       void GetButtonTest()

       {

              TBBUTTON button;

              _GetButton(0, &button);

       }

};

 

When I try to build my project (ok, SOLUTION) using VS 2005, this code compiles but I get the following link error:

 

error LNK2019: unresolved external symbol "protected: void __cdecl CToolBar::_GetButton(int,struct _TBBUTTON *)const " ( _GetButton@CToolBar@@IBAXHPAU_TBBUTTON@@@Z) referenced in function "public: void __cdecl CToolBarDummy::GetButtonTest(void)" ( GetButtonTest@CToolBarDummy@@QAAXXZ)

 

The _GetButton function is defined in the CToolBar declaration, which is why it compiles.  Has _GetButton been dropped for PPC / WinCE   Or, could this link error be caused because of a problem with the current version of the MFC library



Answer this question

CToolBar::_GetButton link error for ARMV4

  • C Dickson

    Cool, sounds like you're knocking on wood in your MFC porting project!

    Youe comment about the const cast workaround intrigued me: if it were in fact an issue with const, the compiler diagnostic would seem wrong.  But the diagnostic is correct, and the actual explanation is a bit more nuanced:

    It is true that the cast is there to remove the const-ness so that CWnd::DefWindowProcW() can be called, but it's also casting away the type CToolBarDummy--information needed by the compiler to grant access to that base method.  In other words, when "this" is no longer the invoking object, the access rules behave as if this code were residing in some other arbitary location.
     
    Your workaround works because, after the cast, the compiler uses the relationship between containing class type (CToolBarDummy) and the object used to invoke DefWindowProcW (the local variable pBar).  Since they're the same type, access is granted as if is were through "this."  Pretty subtle, and I'm sure someone more versed in the C++ language could offer a more precise explanation.

    Brian

  • throsturi

    Did some digging around and being an outsider I can't be 100% conclusive. 

    This function is exported from the static lib (uafxcw.lib) but not from the dynamic lib (mfc80U.lib).  Furthermore, it is also used by MFC internally by bartool.cpp and barcmd.cpp.  And since it is marked as protected, your code is *expected* to compile. 

    Since this seems to be issue with how the DLL was built by Microsoft (its def file didn't include this function symbol), you should open a bug on this.

    The workaround might be to copy the implementation of this method from bartool.cpp and paste it into your app.



  • ueqt

    Hi Brian,< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

     

    Actually, I'd already tried your suggested workaround, but I got a compile error that didn't make any sense to me, so I decided to first try to find out why _GetButton wasn't linking.  However, after your response to my post I revisited the option of adding the _GetButton code to my class.  Listed below is my previous example, but now with the CWnd::_GetButton function lifted from CWnd and renamed my_GetButton:

     

    class __declspec(dllexport) CToolBarDummy : public CToolBar

    {

    public:

           void GetButtonTest()

           {

                  TBBUTTON button;

                  my_GetButton(0, &button);

           }

     

           void my_GetButton(int nIndex, TBBUTTON* pButton) const

           {

                  CToolBar* pBar = (CToolBar*)this;

                  VERIFY(pBar->DefWindowProcW(TB_GETBUTTON, nIndex,

        (LPARAM)pButton));

                  // TBSTATE_ENABLED == TBBS_DISABLED so invert it

                  pButton->fsState ^= TBSTATE_ENABLED;

           }

    };

     

    When I tried to compile this code, I got the following error:

     

    error C2248: 'CWnd::DefWindowProcW' : cannot access protected member declared in class 'CWnd'

     

    At the time this error struck me as odd because CToolBarDummy publicly derives from CToolBar, which in turn publicly derives from CControlBar, and CControlBar publicly derives from CWnd.  Thus, it seemed to me that protected members of CWnd should be accessable from CToolBarDummy member functions.  However, after reading your response I went back to this code and realized that the seemingly redundant cast of the "this" pointer to CToolBar* in the original code was in fact there to cast away the const-ness of the function.  So, I modified the code to cast the "this" pointer to CToolBarDummy* as per the following:

     

           CToolBarDummy* pBar = (CToolBarDummy*)this;

     

    After this change, the code compiled and linked.

     

    Sorry for being so long-winded about what may be an obvious solution, but I've included this detail to hopefully help others who may run into similar issues with ported code.  The problem with _GetButton and the Microsoft libraries still exists, but at least there is a workaround.  As always, Brian, thanks for your help.

     

    Art

     

     


  • CToolBar::_GetButton link error for ARMV4