I'm using the EnvDTE COM objects to automate Visual Studio. I'm still looking through the documentation, however, I figured I'd drop the question here to see if someone already knows how to do this.
我正在使用EnvDTE COM对象来自动化Visual Studio。我仍在查看文档,但是,我想我会在这里删除问题,看看是否有人已经知道如何做到这一点。
So, the problem is that when I get the DTE object and look at what Solution is open, I need to open another instance of Visual Studio if the solution is not the one I'm expecting. I don't necessarily want to load another solution over an existing instance of VS.
所以,问题在于,当我获得DTE对象并查看解决方案是否打开时,如果解决方案不是我期望的解决方案,我需要打开另一个Visual Studio实例。我不一定想在现有的VS实例上加载另一个解决方案。
1 个解决方案
#1
So, I figured this out on my own. It turns out that the RunningObjectTable is the way to iterate over all VS instances and look for one with the solution open that I am expecting. If I don't find an instance that I can use, then I call CoCreateInstance() to launch a new VS IDE:
所以,我自己想出来了。事实证明,RunningObjectTable是迭代所有VS实例并查找解决方案打开的方法,我希望如此。如果我找不到可以使用的实例,那么我调用CoCreateInstance()来启动一个新的VS IDE:
#define RETURN_ON_FAIL( expression ) \
result = ( expression ); \
if ( FAILED( result ) ) \
return false; \
else // To prevent danging else condition
...
HRESULT result;
CLSID clsid;
CComPtr<IUnknown> punk;
CComPtr<EnvDTE::_DTE> dte;
RETURN_ON_FAIL( ::CLSIDFromProgID(L"VisualStudio.DTE", &clsid) );
...
// Search through the Running Object Table for an instance of Visual Studio
// to use that either has the correct solution already open or does not have
// any solution open.
CComPtr<IRunningObjectTable> ROT;
RETURN_ON_FAIL( GetRunningObjectTable( 0, &ROT ) );
CComPtr<IBindCtx> bindCtx;
RETURN_ON_FAIL( CreateBindCtx( 0, &bindCtx ) );
CComPtr<IEnumMoniker> enumMoniker;
RETURN_ON_FAIL( ROT->EnumRunning( &enumMoniker ) );
CComPtr<IMoniker> dteMoniker;
RETURN_ON_FAIL( CreateClassMoniker( clsid, &dteMoniker ) );
CComBSTR bstrSolution( solutionPath );
CComPtr<IMoniker> moniker;
ULONG monikersFetched = 0;
while ( enumMoniker->Next( 1, &moniker, &monikersFetched ) == S_OK)
{
if ( moniker->IsEqual( dteMoniker ) )
{
result = ROT->GetObject( moniker, &punk );
if ( result == S_OK )
{
dte = punk;
if ( dte )
{
CComPtr<EnvDTE::_Solution> solution;
RETURN_ON_FAIL( dte->get_Solution( &solution ) );
VARIANT_BOOL isOpen = FALSE;
RETURN_ON_FAIL( solution->get_IsOpen( &isOpen ) );
if ( !isOpen )
{
RETURN_ON_FAIL( solution->Open( bstrSolution ) );
break;
}
else
{
CComBSTR fullName;
RETURN_ON_FAIL( solution->get_FullName( &fullName ) );
if ( fullName == bstrSolution )
break;
}
}
}
punk = NULL;
}
moniker = NULL;
}
if ( !dte )
{
RETURN_ON_FAIL( ::CoCreateInstance( clsid, NULL, CLSCTX_LOCAL_SERVER, EnvDTE::IID__DTE, (LPVOID*)&punk ) );
dte = punk;
if ( !dte )
return false;
if ( solutionPath )
{
CComPtr<EnvDTE::_Solution> solution;
RETURN_ON_FAIL( dte->get_Solution( &solution ) );
CComBSTR bstrSolution( solutionPath );
RETURN_ON_FAIL( solution->Open( bstrSolution ) );
}
}
#1
So, I figured this out on my own. It turns out that the RunningObjectTable is the way to iterate over all VS instances and look for one with the solution open that I am expecting. If I don't find an instance that I can use, then I call CoCreateInstance() to launch a new VS IDE:
所以,我自己想出来了。事实证明,RunningObjectTable是迭代所有VS实例并查找解决方案打开的方法,我希望如此。如果我找不到可以使用的实例,那么我调用CoCreateInstance()来启动一个新的VS IDE:
#define RETURN_ON_FAIL( expression ) \
result = ( expression ); \
if ( FAILED( result ) ) \
return false; \
else // To prevent danging else condition
...
HRESULT result;
CLSID clsid;
CComPtr<IUnknown> punk;
CComPtr<EnvDTE::_DTE> dte;
RETURN_ON_FAIL( ::CLSIDFromProgID(L"VisualStudio.DTE", &clsid) );
...
// Search through the Running Object Table for an instance of Visual Studio
// to use that either has the correct solution already open or does not have
// any solution open.
CComPtr<IRunningObjectTable> ROT;
RETURN_ON_FAIL( GetRunningObjectTable( 0, &ROT ) );
CComPtr<IBindCtx> bindCtx;
RETURN_ON_FAIL( CreateBindCtx( 0, &bindCtx ) );
CComPtr<IEnumMoniker> enumMoniker;
RETURN_ON_FAIL( ROT->EnumRunning( &enumMoniker ) );
CComPtr<IMoniker> dteMoniker;
RETURN_ON_FAIL( CreateClassMoniker( clsid, &dteMoniker ) );
CComBSTR bstrSolution( solutionPath );
CComPtr<IMoniker> moniker;
ULONG monikersFetched = 0;
while ( enumMoniker->Next( 1, &moniker, &monikersFetched ) == S_OK)
{
if ( moniker->IsEqual( dteMoniker ) )
{
result = ROT->GetObject( moniker, &punk );
if ( result == S_OK )
{
dte = punk;
if ( dte )
{
CComPtr<EnvDTE::_Solution> solution;
RETURN_ON_FAIL( dte->get_Solution( &solution ) );
VARIANT_BOOL isOpen = FALSE;
RETURN_ON_FAIL( solution->get_IsOpen( &isOpen ) );
if ( !isOpen )
{
RETURN_ON_FAIL( solution->Open( bstrSolution ) );
break;
}
else
{
CComBSTR fullName;
RETURN_ON_FAIL( solution->get_FullName( &fullName ) );
if ( fullName == bstrSolution )
break;
}
}
}
punk = NULL;
}
moniker = NULL;
}
if ( !dte )
{
RETURN_ON_FAIL( ::CoCreateInstance( clsid, NULL, CLSCTX_LOCAL_SERVER, EnvDTE::IID__DTE, (LPVOID*)&punk ) );
dte = punk;
if ( !dte )
return false;
if ( solutionPath )
{
CComPtr<EnvDTE::_Solution> solution;
RETURN_ON_FAIL( dte->get_Solution( &solution ) );
CComBSTR bstrSolution( solutionPath );
RETURN_ON_FAIL( solution->Open( bstrSolution ) );
}
}