Current Entries | Archives   RSS

 


A tale of two add-ins

Friday 10th December, 2004


Over the last couple of months we've been concentrating our efforts on the development of Visual Lint. Unfortunately there are only a limited number of hours in the day and as a result we've had to delay the release of the forthcoming version (1.6.1) of ResOrg slightly.

That's a shame, as the new version has some features (for example the ability to exclude symbols such as IDR_MAINFRAME from automated renumbering) which have been on the wish list for quite some time. Although we really want to get it out soon, the delay is priving to be worthwhile as some of the lessons learnt during the development of Visual Lint are feeding back into ResOrg.

It's interesting to compare the code behind the two products. Although both products are written in unmanaged C++, ResOrg is fundamentally an MFC MDI application packaged as an add-in while Visual Lint is a more conventional style of add-in which has much simpler UI needs. That difference in emphasis shows itself in the frameworks used by the two products - while ResOrg relies heavily on MFC for its user interface needs, Visual Lint uses the rather more lightweight WTL instead.

Not surprisingly, the style of code in the two products reflects the four year difference in their inception (that's right, ResOrg is four years old now!). This is particularly noticeable in the style of the COM interface code of the two products. ResOrg uses raw COM interfaces to access the Visual Studio extensibility model:

Project* CVc7AutomationHelper::GetProject(const CString& sName) const
{
    USES_CONVERSION;

    _Solution* pSolution  = NULL;
    Projects* pProjects   = NULL;
    Project* pProject     = NULL;

    if ( SUCCEEDED( m_pDTE->get_Solution(&pSolution) ) )
    {
        if ( SUCCEEDED( pSolution->get_Projects(&pProjects) ) )
        {
            long lProjects = 0;
            pProjects->get_Count(&lProjects);

            // This bit me the first time. The index is 1 based. BLOODY VB PROGRAMMERS!
            for (int n = 1; n <= (int)lProjects; n++)
            {
                _variant_t Index( (long)n);
                pProjects->Item(Index, &amp;pProject);

                if (NULL != pProject)
                {
                    if (0 == sName.CompareNoCase( GetName(pProject) ) )
                    {
                        break;
                    }
                    else
                    {
                        pProject->Release();
                        pProject = NULL;
                    }
                }
            }
            pProjects->Release();
        }
        pSolution->Release();
    }
    return pProject;
}

By contrast, Visual Lint makes use of the easier and more concise code yielded by COM smart pointers:

    EnvDTE::ProjectsPtr ptrProjects = m_ptrSolution->GetProjects();
    IfNullIssueError(ptrProjects);

    for (int n = 1; n <= ptrProjects->GetCount(); n++)
    {
        EnvDTE::ProjectPtr ptrProject = ptrProjects->Item(n);

        if (ptrProject != NULL)
        {
            CString sProjectFilePathName = ptrProject->GetFullName();
            if (!sProjectFilePathName.IsEmpty() )
            {
                .
                .
                .
            }
        }
    }

This difference in approach shows itself throughout both products and is a natural result of the learning process. ResOrg was the first add-in I'd worked on, and almost my first foray into COM. By contrast, Visual Lint was designed with the full capabilities of the Visual Studio IDE and it's extensibility interfaces in mind, and it shows!

Despite their different aims and approaches, the two add-ins have a surprising amount in common, and it should be no surprise that our recent experience with the development of Visual Lint is starting to feed back into ResOrg.

That can only be to the benefit of both, of course.

Posted by Anna at 8:58am | Get Permalink