locked
Trying to connect to the VS 2010 IDE from an app being debugged in it RRS feed

  • Question

  • Hi --

    In an app we're developing we have for some time pursued the strategy of connecting to the instance of the IDE in which the app itself is being debugged and developed.  Here's the code we use to do this, which is written in C++.   By and large it works pretty well. 

     

    		DTE2^ FindDTEPtr()
    		{
    			System::Diagnostics::Process^ theProcess = System::Diagnostics::Process::GetCurrentProcess();
    
    			IRunningObjectTable^ theROT;
    			IBindCtx^ theContext; 
    			CreateBindCtx(0, theContext);
    			theContext->GetRunningObjectTable(theROT);
    
    #pragma push_macro("GetObject")
    #undef GetObject
    
    			while (((DTE2^)dte) == nullptr)
    			{
    				IEnumMoniker^ theMonikerEnumerator;
    				theROT->EnumRunning(theMonikerEnumerator);
    				Int32 theReturnedCount;
    				IntPtr theCountPtr(theReturnedCount);
    				System::String^ theReturnedName = gcnew System::String("");
    				array<IMoniker^>^ theROTMonikers = gcnew array<IMoniker^>(1);
    				IMoniker^ theDummyMoniker;
    				int numTries = 0;
    				while ((!theMonikerEnumerator->Next(1,theROTMonikers,theCountPtr)) &&
    					   (numTries < 100))
    				{
    					try
    					{					
    						theROTMonikers[0]->GetDisplayName(theContext,theDummyMoniker,theReturnedName);
    						if (theReturnedName->StartsWith("!VisualStudio.DTE.10.0"))
    						{
    							System::Object^ theDTEObject;
    							theROT->GetObject(theROTMonikers[0],theDTEObject);
    							DTE2^ theDTE = dynamic_cast<DTE2^>(theDTEObject);
    							Debugger2^ theDebugger = dynamic_cast<Debugger2^>(theDTE->Debugger);
    							Process2^ theROTProcess = dynamic_cast<Process2^>(theDebugger->DebuggedProcesses->Item(1));
    							if (theROTProcess->ProcessID == theProcess->Id)
    							{
    								return theDTE;
    							}
    							numTries++;
    						}
    					}
    
    					catch (...)
    					{
    						theMonikerEnumerator->Reset();
    						numTries++;
    					}
    				}
    
    				return nullptr;
    			}	
    		}
    
    		bool InitializeVSEnv()
    		{
    				dte = FindDTEPtr();
    
    				DTE2^ theDTE = (DTE2^)dte;
    				if (theDTE != nullptr)
    				{
    					EnvDTE::Windows^ theWindows = theDTE->Windows;
    					EnvDTE::Window^ theWindow = theDTE->Windows->Item(EnvDTE::Constants::vsWindowKindOutput);
    					EnvDTE::OutputWindow^ theDebugWin = (EnvDTE::OutputWindow^)theWindow->Object;
    
    					try
    					{
    						theMachineForthOutputPane = theDebugWin->OutputWindowPanes->Item("MachineForthMainThreadOutput");
    					}
    
    					catch (...)
    					{
    						theMachineForthOutputPane = theDebugWin->OutputWindowPanes->Add("MachineForthMainThreadOutput");
    					}
    
    					debugWindowOutputStreambuf = new windowbuf<EnvDTE::OutputWindowPane>(theMachineForthOutputPane);
    					debugWindowOutputStream = new std::ostream(debugWindowOutputStreambuf); 
    	//				debugWindowOutputStream->imbue(debugWindowOutputStream->getloc());
    
    					try
    					{
    						theMachineForthStatePane = theDebugWin->OutputWindowPanes->Item("MachineForthMainThreadState");
    					}
    
    					catch (...)
    					{
    						theMachineForthStatePane = theDebugWin->OutputWindowPanes->Add("MachineForthMainThreadState");
    					}
    
    					debugWindowStateStreambuf = new windowbuf<EnvDTE::OutputWindowPane>(theMachineForthStatePane);
    					debugWindowStateStream = new std::ostream(debugWindowStateStreambuf); 
    	//				debugWindowStateStream->imbue(debugWindowStateStream->getloc());
    
    					objectDescriptions[ObjDesc_Cout].Initialize((void*)GetCOut());
    					objectDescriptions[ObjDesc_Cerr].Initialize((void*)GetCErr());
    					objectDescriptions[ObjDesc_DebugOutput].Initialize((void*)GetDebugOutputWindow());
    					objectDescriptions[ObjDesc_DebugState].Initialize((void*)GetDebugStateWindow());
    
    					return true;
    				}
    				else
    					return false;
    	#pragma pop_macro("GetObject")
    
    		}
    
    

     

    Now the issue we encounter (and the reason for the numTries mechanism in the code above and the throwing of an exception if we can't get a pointer to the IDE after 100 tries) is that as often as not we will get back a Server Busy COM error on any given attempt to connect to the IDE from an app that is running in the IDE itself.   The VSE SDK takes the approach of loading a completely separate instance of the IDE when one develops VSE packages, etc.  so this issue is probably circumvented completely when following the VSE SDK samples.  But we have a desire to limit our debugging to a single instance of the IDE and by and large the approach we've taken seems to work.  However, still on some occasions we get a server busy message when we try to use the pointers that we acquire in the code above.  In these cases, we can't wrap the use of the pointers inside looping logic the way we do when we first acquire them in the code above, so it simply causes our app to stop with an exception.  By the time we are using these pointers, it is no longer the C++ program that is in control, but a custom language that we have developed on top of our own runtime.  We don't have good exception handling built into this yet, and so we can't stop our app from failing.  It doesn't happen very often, but enought times to be pretty annoying. 

    I'm wondering if there is any other strategy that anyone is familiar with to accomplish what we are trying to do and circumvent the server busy errors?

    Anybody have any ideas?  Any guidance would be much appreciated.

    Thanks.

    Mike

     

    Sunday, April 11, 2010 7:53 PM