locked
Using ribbon control in 64 bit application RRS feed

  • Question

  • I just got through converting my 32 bit app to a 64-bit Visual Studio 2013 C++ app.

    Now I'm trying to update the user interface to use a ribbon instead of a menu.

    I downloaded and tested the sample "SimpleRibbon" and it works fine, but it is 32 bit.

    I applied all the same proinciples, created the XML file, compiled using UICC.exe, and created the same interface in my app that exists in the sample app.  Everything worked fine with compiling the XML file, but now my app won't compile, so I can't use it

    I keep getting error    error LNK2019: unresolved external symbol "public: static long __cdecl CApplication::CreateInstance(struct IUIApplication * *)" (?CreateInstance@CApplication@@SAJPEAPEAUIUIApplication@@@Z) referenced in function "bool __cdecl InitializeFramework(struct HWND__ *)" (?InitializeFramework@@YA_NPEAUHWND__@@@Z)

    and

    error LNK1120: 1 unresolved externals  

    Those are the only two errors.

    I thought COM objects were supposed to run in 64-bit apps ??  But it appears that's where the issue lies

    This is the code I copied from the sample "SimpleRibbon" that works fine in that 32-bit app but doesn't work for me:

    ----------------------------

    IUIFramework *g_pFramework = NULL;  // Reference to the Ribbon framework.
    IUIApplication *g_pApplication = NULL;  // Reference to the Application object.

    //
    //  FUNCTION: InitializeFramework(HWND)
    //
    //  PURPOSE:  Initialize the Ribbon framework and bind a Ribbon to the application.
    //
    //  COMMENTS:
    //
    //    To get a Ribbon to display, the Ribbon framework must be initialized.
    //    This involves three important steps:
    //      1) Instantiating the Ribbon framework object (CLSID_UIRibbonFramework).
    //      2) Passing the host HWND and IUIApplication object to the framework.
    //      3) Loading the binary markup compiled by UICC.exe.
    //
    bool InitializeFramework(HWND hWnd)
    {
        // Here we instantiate the Ribbon framework object.
        HRESULT hr = CoCreateInstance(CLSID_UIRibbonFramework,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&g_pFramework));

        if (FAILED(hr))
        {
            return false;
        }   

        // Next, we create the application object (IUIApplication) and call the framework Initialize method,
        // passing the application object and the host HWND that the Ribbon will attach itself to.
        hr = CApplication::CreateInstance(&g_pApplication);

        if (FAILED(hr))
        {
            return false;
        }

        hr = g_pFramework->Initialize(hWnd, g_pApplication);
        if (FAILED(hr))
        {
            return false;
        }

        // Finally, we load the binary markup.  This will initiate callbacks to the IUIApplication object
        // that was provided to the framework earlier, allowing command handlers to be bound to individual
        // commands.
        hr = g_pFramework->LoadUI(GetModuleHandle(NULL), L"SIMPLERIBBON_RIBBON");
        if (FAILED(hr))
        {
            return false;
        }

        return true;
    }

    //
    //  FUNCTION: DestroyFramework()
    //

    void DestroyFramework()
    {
        if (g_pFramework)
        {
            g_pFramework->Destroy();
            g_pFramework->Release();
            g_pFramework = NULL;
        }

        if (g_pApplication)
        {
            g_pApplication->Release();
            g_pApplication = NULL;
        }
    }

    Tuesday, January 31, 2017 7:16 PM

All replies

  • Did you also implement the CApplication class from the sample's Application.cpp file?
    Tuesday, January 31, 2017 8:51 PM
  • Yes.

    #include <UIRibbon.h>
    #include <UIRibbonPropertyHelpers.h>

    #include "Application.h"
    #include "CommandHandler.h"

    // Static method to create an instance of the object.
    HRESULT CApplication::CreateInstance(IUIApplication **ppApplication)
    {
        *ppApplication = NULL;

        HRESULT hr = S_OK;
       
        CApplication* pApplication = new CApplication();

        if (pApplication != NULL)
        {
            *ppApplication = static_cast<IUIApplication *>(pApplication);
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }

        return hr;
    }

    // IUnknown method implementations.
    STDMETHODIMP_(ULONG) CApplication::AddRef()
    {
        return InterlockedIncrement(&m_cRef);
    }

    STDMETHODIMP_(ULONG) CApplication::Release()
    {
        LONG cRef = InterlockedDecrement(&m_cRef);
        if (cRef == 0)
        {
            delete this;
        }

        return cRef;
    }

    STDMETHODIMP CApplication::QueryInterface(REFIID iid, void** ppv)
    {
        if (iid == __uuidof(IUnknown))
        {
            *ppv = static_cast<IUnknown*>(this);
        }
        else if (iid == __uuidof(IUIApplication))
        {
            *ppv = static_cast<IUIApplication*>(this);
        }
        else
        {
            *ppv = NULL;
            return E_NOINTERFACE;
        }

        AddRef();
        return S_OK;
    }

    //
    //  FUNCTION: OnCreateUICommand(UINT, UI_COMMANDTYPE, IUICommandHandler)
    //
    //  PURPOSE: Called by the Ribbon framework for each command specified in markup, to allow
    //           the host application to bind a command handler to that command.
    //
    //  COMMENTS:
    //
    //    In this SimpleRibbon sample, the same command handler is returned for all commands
    //    specified in the SimpleRibbon.xml file.
    //    
    //    To view the OnCreateUICommand callbacks, uncomment the _cwprintf call.
    //
    //
    STDMETHODIMP CApplication::OnCreateUICommand(
        UINT nCmdID,
        UI_COMMANDTYPE typeID,
        IUICommandHandler** ppCommandHandler)
    {
        UNREFERENCED_PARAMETER(typeID);
        UNREFERENCED_PARAMETER(nCmdID);

        if (NULL == m_pCommandHandler)
        {
            HRESULT hr = CCommandHandler::CreateInstance(&m_pCommandHandler);
            if (FAILED(hr))
            {
                return hr;
            }
        }

        return m_pCommandHandler->QueryInterface(IID_PPV_ARGS(ppCommandHandler));
    }

    //
    //  FUNCTION: OnViewChanged(UINT, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB, INT)
    //
    //  PURPOSE: Called when the state of a View (Ribbon is a view) changes, for example, created, destroyed, or resized.
    //
    //
    STDMETHODIMP CApplication::OnViewChanged(
        UINT viewId,
        UI_VIEWTYPE typeId,
        IUnknown* pView,
        UI_VIEWVERB verb,
        INT uReasonCode)
    {
        UNREFERENCED_PARAMETER(uReasonCode);
        UNREFERENCED_PARAMETER(viewId);

        HRESULT hr = E_NOTIMPL;

        // Checks to see if the view that was changed was a Ribbon view.
        if (UI_VIEWTYPE_RIBBON == typeId)
        {
            switch (verb)
            {           
                // The view was newly created.
            case UI_VIEWVERB_CREATE:
                hr = S_OK;
                break;

                // The view has been resized.  For the Ribbon view, the application should
                // call GetHeight to determine the height of the ribbon.
            case UI_VIEWVERB_SIZE:
                {
                    IUIRibbon* pRibbon = NULL;
                    UINT uRibbonHeight;

                    hr = pView->QueryInterface(IID_PPV_ARGS(&pRibbon));
                    if (SUCCEEDED(hr))
                    {
                        // Call to the framework to determine the desired height of the Ribbon.
                        hr = pRibbon->GetHeight(&uRibbonHeight);
                        pRibbon->Release();
                        // Use the ribbon height to position controls in the client area of the window.
                    }
                }
                break;
                // The view was destroyed.
            case UI_VIEWVERB_DESTROY:
                hr = S_OK;
                break;
            }
        }

        return hr;
    }


    //
    //  FUNCTION: OnDestroyUICommand(UINT, UI_COMMANDTYPE, IUICommandHandler*)
    //
    //  PURPOSE: Called by the Ribbon framework for each command at the time of ribbon destruction.
    //
    STDMETHODIMP CApplication::OnDestroyUICommand(
        UINT32 nCmdID,
        UI_COMMANDTYPE typeID,
        IUICommandHandler* commandHandler)
    {
        UNREFERENCED_PARAMETER(commandHandler);
        UNREFERENCED_PARAMETER(typeID);
        UNREFERENCED_PARAMETER(nCmdID);

        return E_NOTIMPL;
    }

    • Edited by TallGuy63 Tuesday, January 31, 2017 9:10 PM
    Tuesday, January 31, 2017 9:08 PM
  • I'm thinking that maybe there is a problem with CreateInstance() in a 64-bit app, although there is supposed to not be...  but I see no examples of ribbons in 64 bit and no explanations anywhere, so I can't prove it with another similar problem by someone else...
    Tuesday, January 31, 2017 9:47 PM
  • You could try to build the SimpleRibbon sample as a 64 bit app.  I was able to build it as a 64 bit app using VS 2015 Community.

    The linker error doesn't look like a COM issue to me.  Rather it seems that the module that contains the CApplication class code, including the static CreateInstance function, is not being included in the link.



    • Edited by RLWA32 Tuesday, January 31, 2017 11:34 PM added comment
    Tuesday, January 31, 2017 10:11 PM