VS2005 Include Folder configuration madness

Hiya,

We're in the process of testing one of our add-ins against VS2005 Pro RTM, and along the way we are encountering some very, very odd behaviour. The latest to surface relates to the Visual C++ include folder configuration.

In VS2002 and VS2003 you can simply grab a VCPlatform object directly from EnvDTE::Properties:Item(L"Platforms") and use it irrespective of whether a solution is open. Unfortunately, the Platforms property has gone in VS2005, to be replaced by "IncludeDirectories", which contains the raw (i.e. including macros) include folder configuration.

So far, so good...except that we still need a VCPlatform object (or something related to it; VCProject or VCProjectEngine should do just as well) to expand the macros (each has an Evaluate() method which does just that).

Given that we need to read this irrespective of whether a solution is actually open, the only documented way we can find to do this is to create an inproc VCProjectEngine object ourselves. As a result, we've modified the helper function we use to read the include folder config to do this (see below). At first it seemed to work fine...BUT we have just discovered some very nasty behaviour which we're at a loss to work around.

First of all, instantiating a VCProjectEngine object directly during a build causes an access violation within VCProjectEngineLibrary when the object is released.

Our first workaround was to instead create an instance of it during OnConnection(), but then the IDE reports that it cannot load the file because "it is in a zombie state", and the "Build" menu dissappears!

After undoing the changes we then realised that if the include folder config was read before a solution was loaded, the solution would fail to load...the solution explorer would remain empty, and the progress bar on the status bar would show that it was still loading.

We would of course be very keen to find out if there is another way to read the include folder configuration on VS2005, irrespective of whether a solution is loaded (ideally we'd like to find a way to the VCPlatform interface we need as before rather than having to create a VCProjectEngine object ourselves).

Some input from the Visual C++ extensibility team would be most welcome.

 

Kind Regards,

    Anna-Jayne Metcalfe

    Software/Product Development Consultant,
    Riverblade Limited.
   
http://www.riverblade.co.uk

 


CString VsAutomationHelper::GetVcIncludeFolders(EnvDTE::_DTE* pDTE, const _bstr_t& bsPlatform)
{
    CString sIncludeFolders;
    if (pDTE != NULL)
    {
        try
        {
            EnvDTE::_DTEPtr ptrDTE;
            pDTE->QueryInterface(&ptrDTE);
 
            EnvDTE::PropertiesPtr ptrProperties = ptrDTE->GetProperties(L"Projects", L"VCDirectories");
            try
            {
                VC2003ProjectEngineLibrary::IVCCollectionPtr ptrVc2003Platforms = ptrProperties->Item(L"Platforms")->GetObject();
                VC2002ProjectEngineLibrary::IVCCollectionPtr ptrVc2002Platforms = ptrProperties->Item(L"Platforms")->GetObject();
                if (ptrVc2003Platforms != NULL)
                {
                    // VS.NET 2003
                    VC2003ProjectEngineLibrary::VCPlatformPtr ptrPlatform = ptrVc2003Platforms->Item(bsPlatform);
 
                    _bstr_t bsFolders = ptrPlatform->GetIncludeDirectories();
                    sIncludeFolders = COLE2CT( ptrPlatform->Evaluate(bsFolders) );
                }
                else if (ptrVc2002Platforms != NULL)
                {
                    // VS.NET 2002
                    VC2002ProjectEngineLibrary::VCPlatformPtr ptrPlatform = ptrVc2002Platforms->Item(bsPlatform);
 
                    _bstr_t bsFolders = ptrPlatform->GetIncludeDirectories();
                    sIncludeFolders = COLE2CT( ptrPlatform->Evaluate(bsFolders) );
                }
            }
            catch (const _com_error& e)
            {
                // VS2005 will end up here
                UNREFERENCED_PARAMETER(e);
            }
 
            if (sIncludeFolders.IsEmpty() )
            {
                // VS2005 doesn't have the "Platforms" property, so we have to do it a different way
                // Use a temporary VCProjectEngine object to evaluate the macro expressions
                // Note that we can't get this from DTE::Projects::Item(x) as documented since
                // there may not be a solution open at this point.
                VC2005ProjectEngineLibrary::VCProjectEnginePtr ptrEngine;
                ptrEngine.CreateInstance( __uuidof(VC2005ProjectEngineLibrary::VCProjectEngineObject), NULL, CLSCTX_INPROC_SERVER);
 
                EnvDTE::PropertyPtr ptrProperty = ptrProperties->Item(L"IncludeDirectories");
                _bstr_t bsRawIncludeFolders = ptrProperty->GetValue();
 
                sIncludeFolders = COLE2CT(ptrEngine->Evaluate(bsRawIncludeFolders) );
 
                sIncludeFolders = ::GetVs2005IncludeConfiguration(sIncludeFolders, bsPlatform);
 
                ptrEngine.Release();
            }
        }
        catch (const _com_error& e)
        {
            ATLASSERT(false);
        }
    }
    ATLASSERT(!sIncludeFolders.IsEmpty() );
 
    return sIncludeFolders;
}



Answer this question

VS2005 Include Folder configuration madness

  • Sathyashankar

    Thank you so much for that piece of code, I was using the old way to access the IncludeDirectory via Platforms but ran into a problem with vs2005, only to discover they changed the api, what kind of developer would do that

    IMHO, you don't change an api if its breaks the client code. Even if you want to change the api, you keep it backward compatible!

    Anyway, thanks, this saved me a lot of head banging against the wall.


  • drizzed

    Hi Kallex,

    The following code will grab you the available platforms even if no solution is open:

    EnvDTE::_DTEPtr ptrDTE = GetDTE();
    ATLASSERT(ptrDTE != NULL);

    EnvDTE::ProjectsPtr ptrProjects = ptrDTE->GetObject(L"VCProjects");
    VCProjectEngineLibrary::VCProjectEnginePtr ptrVCProjectEngine = ptrProjects->GetProperties()->Item(L"VCProjectEngine")->GetObject();

    if (NULL != ptrVCProjectEngine)
    {
    VCProjectEngineLibrary::IVCCollectionPtr ptrPlatforms = ptrVCProjectEngine->GetPlatforms();

    long nCount = ptrPlatforms->GetCount();

    for (long n = 1; n <= nCount; n++)
    {
    VCProjectEngineLibrary::VCPlatformPtr ptrPlatform = ptrPlatforms->Item( _variant_t(n) );
    .
    .
    .
    }
    }

    Apologies for the delayed reply; I've only just seen your post.

    HTH,

    Anna



  • jfkennedy5

    We have indeed, but I'm still curious why these properties were removed in the first place. Incidentally you can see some screenshots of the property changes at http://www.riverblade.co.uk/blog.php archive=2006_01_01_archive.xml#113594239745415143

    Is there any info from the Visual C++ entensibility team on the detail of the changes that have been made, and why I'm also concerned that the MSDN docs now recommend a way of doing this that no longer works...

    Cheers,

    Anna



  • Stephen J.Vanterpool

    Hello!

    Thanks a lot for getting back to the subject. The post was not late at all, we didn't yet dwell into that much deeper (other than recognised the issue needing to be solved).

    So really great news and thanks so much for coming back to reply!

    Br,

    Kalle


  • Jehan Badshah

    Anytime Kalle. :)

  • VidyaSagarCh

    Anytime :)

  • fibonacci1123

    I believe that you have found a solution to this problem (based upon posts you made on the Yahoo! mailing list).

    Craig



  • Handra

    Hi!

    Did some (extensive enough) Googling about the matter and seems that too few people require the Platforms information. We however do, as we have to automatically read and modify the VC++ directories of certain platform.

    One thing to get into the stuff is supposedly VCProjectEngine, however what is the proper way of doing the thing when there is no particular project involved, ie when starting up Visual Studio (while loading an add-in that's supposed to set up its directory paths)

    Br,

    Kalle


  • VS2005 Include Folder configuration madness