VIEWING PROCESS AND THREAD DATA PROGRAMATICALLY


 


Today, I am going to talk about how to retrieve process and thread information from PB debugger. This post assumes that you already know how to download a debug image to a Device Emulator using PB. Please look at Brent Bishop’s post on "Automating the Download of a Run-Time Image" for getting code for this purpose.


 


We will follow the following steps for this post.


 


Step 1: Create a new Visual Studio add-in by following all steps that you followed for Brent Bishop’s post on “Automating the Download of a Run-Time Image ” with two modifications.


 



  1. I named my project ViewProcessAndThreadInfo (in Visual Studio’s New Project dialog).

  2. I gave it the following name and description.(on page 3 of the Visual Studio Add-in Wizard):

 


1)      Name: Platform Builder – View Process and Thread Information from Debugger


2)      Description: This can be used to view Processes and Thread information on a device.


  


Step 2: Add all the references that Brent Bishop added to his post on “Automating the Download of a Run-Time Image ” by right clicking on the References node in the Solution Explorer and then clicking on "Add Reference...".


 


Step 3: Add a new class to the project for all the code that we will be adding for the add-in. Add a new class to the project by right clicking on the project in the Solution Explorer and clicking Add -> Class. Next name the class, I named my class ViewProcessAndThreadInfo, and click Add.


 


Step 4: Open Connect.cs (created by Visual Studio) and find the OnConnection method. I modified this to add two menu items to the tools menu. One for Viewing process and Thread and the other for detaching. Note that AddNamedCommand2 has a lot of parameters, I just copied the parameters generated by Visual Studio. Check out the MSDN for more information on those parameters if you are interested.


 


//Add a command to the Commands collection:


Command command1 = commands.AddNamedCommand2(_addInInstance, "ViewProcessAndThreadInfo", "View Process And Thread Info", "Executes the command for ViewProcessAndThreadInfo", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);


 


Command command2 = commands.AddNamedCommand2(_addInInstance, "Detach", "Detach From Device", "This detaches the PB instance from device", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);


 


       //Add a control for the command to the tools menu:


        if ((command1 != null) && (toolsPopup != null))


        {


            command1.AddControl(toolsPopup.CommandBar, 1);


        }


       //Add a control for the command to the tools menu:


      if ((command2 != null) && (toolsPopup != null))


      {


            command2.AddControl(toolsPopup.CommandBar, 2);


      }


 


Step 5: Next scroll to the bottom to the Exec method, which is called when our add-in's menu item is clicked. Here we can add code to handle the two menu items. As in previous examples, add calls to static methods in our newly created ViewProcessAndThreadInfo class.


 


public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)


{


            handled = false;


           


            if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)


            {


                if (commandName == "ViewProcessAndThreadInfo.Connect.ViewProcessAndThreadInfo")


                {


                    ViewProcessAndThreadInfo.GetProcessAndThreadInfo(_applicationObject);


                    handled = true;


                    return;


                }


                else if (commandName == "ViewProcessAndThreadInfo.Connect.Detach")


                {


                    ViewProcessAndThreadInfo.Detach(_applicationObject);


                    handled = true;


                    return;


                }


            }


}


 


Step 6: Next, I made changes to QueryStatus method which gets called to decide if our menu items should appear enabled or disabled.This code uses a static method Connected and CommandNotCompleted . We will impliment CommandNotCompleted in the ViewProcessAndThreadInfo class. We will use the implementation of Connected from Brent Bishop's blog on "Automating the Download of a Run-Time Image"


 


public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)


{


                 


            if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)


            {


                if (commandName == "ViewProcessAndThreadInfo.Connect.ViewProcessAndThreadInfo")


                {


                    if (ViewProcessAndThreadInfo.CommandNotCompleted)


                    {


                        status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported;


                    }


                    else


                    {


                        status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;


                    }


                    return;


                }


                else if (commandName == "ViewProcessAndThreadInfo.Connect.Detach")


                {


                    if (!ViewProcessAndThreadInfo.Connected(_applicationObject) || ViewProcessAndThreadInfo.CommandNotCompleted)


                    {


                        status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported;


                    }


                    else


                    {


                        status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;


                    }


                    return;


}


           


Step 7: I copied all the variables and functions defined in DownloadSample class in Brent Bishop‘s post for “Automating the Download of a Run-Time Image” to my class. My addin uses his code for the purpose of downloading image to a Device Emulator after making the following  4 changes.


 


1)      I deleted the Attach() function implementation completely.


2)      I changed


private const string Caption = "PB - Download Sample";


to


private const string Caption = "PB - View Process and Thread Info";


 


     3) In DetachToThread call, I set the variable done to false at the end. I did this to  make sure that image got downloaded when I next click the menu item View process and Thread Info.


     4) I modified the function call WaitTillImageIsUpAndRunning as follows to set a boolean flag when the image is booted up.


 


public static void WaitTillImageIsUpAndRunning(int timeout, int idletime)


{


            //Get the current text in the active pane


            string oldText = GetCurrentText();


            string newText;


 


            bool ImgBootedUp = false;


            // Calculate how many times to try


            int attempts = timeout * 60 / idletime;


 


            do


            {


                System.Threading.Thread.Sleep(idletime * 1000);


               


                //Get the latest text from Active Pane


                newText = GetCurrentText();


 


                //If we have no new text, it means device has booted up completely


                if (oldText == newText)


                    ImgBootedUp = true;


 


                oldText = newText;


                newText = null;


                attempts--;


 


            } while ((!ImgBootedUp) && (attempts != 0));


 


            if (0 == timeout)


                MessageBox.Show("ERROR: The device did not launch in 10 minutes..", Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);


            else


            {


                imagebooted = true;


            }


               


}



Step 8: Add the following using statements to the top of ViewProcessAndThreadInfo.cs:


 


// Standard namespaces


using System;


using System.IO;


using System.Collections;


using System.Windows.Forms;


 


// PlatformBuilder and Visual Studio namespaces


using EnvDTE;


using EnvDTE80;


using Interop.Microsoft.PlatformBuilder.Diagnostics;


 


Step 9: I defined a Boolean variable to keep track if we are in between executing a menu item operation and also a property CommandNotCompleted that we called earlier in Connect.cs. I added a Boolean variable imageBooted that we have set in the WaitTillImageIsUpAndRunning function call when the image has booted up. Here is the code for it.


 


/// <summary>


/// A value indicating whether image booted up completely.


/// </summary>


private static bool imagebooted = false;


 


/// <summary>


/// A value indicating whether the ViewProcessandThreadInfo call is still running.


/// </summary>


private static bool commandNotCompleted = false;


 


/// <summary>


/// Checks if the command is still running and menu option should be disabled


/// </summary>


/// <returns>A boolean indicating command is running or not</returns>


public static bool CommandNotCompleted


{


    get


    {


         return commandNotCompleted;


    }


}


 


Step 10: I created the GetProcessAndThreadInfo function which is called in Connect.cs when the Tools menu item View Process and Thread info is clicked.  Here is the implementation


 


 /// <summary>


/// Downloads a run-time image to a device. Displays the process and thread information


/// </summary>


/// <param name="dte">A reference to the DTE for controlling Visual Studio.</param>


public static void GetProcessAndThreadInfo(DTE2 vsdte)


 {


          


            // Save the reference to the DTE


            dte = vsdte;


 


            // Start the thread


            System.Threading.Thread thread = new System.Threading.Thread(GetProcessAndThreadInfo);


            thread.Start();


}


 


Step 11: In the GetProcessAndThreadInfo() , I set the commandNotCompleted flag to true so that option ViewProcessAndThreadInfo appears disabled in Visual Studio Tool menu till the function call has been completed. I download an image to a device and wait for it to boot up after making sure that we are in a disconnected state. We have used AttachThread call implemented in Brent Bishop’s post “Downloading an image to Device Emulator”. Once we are sure that the image has booted up we make a call to ViewProcessAndThreadInformation function to get process and thread information for process "shell.exe".


 


 /// <summary>


/// Downloads a run-time image to a device. Displays the process and thread information


/// </summary>


public static void GetProcessAndThreadInfo()


{


            //Setting it so that we can disable the menu option for ViewProcessandThreadInfo call while its running


            commandNotCompleted = true;


 


            //Check if PB is already connected to a device           


            if (!done || !imagebooted)


            {


                //Connect PB to a device


                AttachThread();


                //Wait for the image to be completely launched on the device


                WaitTillImageIsUpAndRunning(10,20);


                if (imagebooted)


                {


                    MessageBox.Show("PB has successfully downloaded and connected to the device.", Caption, MessageBoxButtons.OK);


                }


                else


                {


                    MessageBox.Show("PB was not able to connect to device.", Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);


                }


            }


            if (imagebooted)


            {


               string processName = "shell.exe";


                //Get Process and Thread Information for a particular process


                ViewProcessAndThreadInformation(processName);


            }


 


            // Command has completed and we are ready for next one


            commandNotCompleted = false;


}


 


Step 12: We need to implement the method ViewProcessAndThreadInformation() that we called in GetProcessAndThreadInfo method.This method gives the process and thread infromation for a particular process.



/// <summary>

/// This displays information about the process and Thread running on the device


/// </summary>


/// <param name="processName">Process we want to get information about</param>


public static void ViewProcessAndThreadInformation(string processName)


{


            try


            {


                // Get the debugger object model


                CCeSystemDiagnostics diagnostics = (CCeSystemDiagnostics)dte.GetObject("Yamazaki-OM");


                csdConnection connection = (csdConnection)diagnostics.GetConnection();


 


                //Get the interface to get information about modules/processes window


                csdDebugViews debugView = (csdDebugViews)diagnostics.GetDebugViews();


 


                //Get the List of Process


                csdProcesses processList = (csdProcesses)debugView.GetProcesses();


 


                //Get the Total number of process running on device


                int processCount = processList.Count();


 


                if (processCount == 0)


                {


                    MessageBox.Show("ERROR: There are no processes running on the device..", Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);


                }


                else


                {


                    bool matchFound = false;


                    csdProcess process = null;


 


                    //Get an enumerator to read through the list of process


                    IEnumerator enumProcess = (IEnumerator)processList._NewEnum;


                    enumProcess.MoveNext();


 


                    //Looping through all the processes


                    while (!matchFound && (process = (csdProcess)enumProcess.Current) != null)


                    {


                        //Messages variables to be displayed


                        string Caption = "View Process Information for Shell.exe";


                        string message = "";


 


                        //Set the enumerator for the PropertyList of the current Process


                        CProperty property = null;


                        IEnumerator enumProcessProperties = (IEnumerator)Proc.GetProperties();


                        enumProcessProperties.MoveNext();


 


                        //Get the current Process name by looking at the first property


                        string CurrentProcessName = (String)(((CProperty)(enumProcessProperties.Current)).Value);


 


                        //Check if the current process is the one we are looking for


                        if (CurrentProcessName == processName)


                        {


                            //We found the process "shell.exe"


                            matchFound = true;


 


                            //Looping though all the properties of a process                  


                            while ((property = (CProperty)enumProcessProperties.Current) != null)


                            {


                                //Generating a message which has all the property names and Values


                                message += property.Name + ": " + property.Value + "\t ";


 


                                //Move the enumerator to point at next entry


                                enumProcessProperties.MoveNext();


                            }


                            //Display the Process Information


                            MessageBox.Show(message, Caption, MessageBoxButtons.OK);


 


                            //Get the threads for the process shell.exe


                            GetThreadInformation(process);


                        }


                        else


                        {


                            //Move to the next process as the current process is not the one we are looking for


                            enumProcess.MoveNext();


 


                        }


                    }


                }


            }


            catch (Exception e)


            {


            MessageBox.Show(e.Message, Caption, MessageBoxButtons.OK, MessageBoxIcon.Error);


            }


}


 


 /// <summary>


 ///Gets the information about all the threads in the process Proc


 /// </summary>


 /// <param name="Proc"> Process for which we want Thread information</param>


public static void GetThreadInformation(csdProcess Process)


{


            //Messages to be displayed


            string Caption = "View Thread Information for Shell.exe";


            string message = "ThreadNo \tHandle\t\t State\tAccessKey\tCurProcHandle\tCurPrio\tBasePrio\tKernelTime\tUserTime\n";


 


            //Retrieves the Thread infromation for the process


            csdThreads Threads = (csdThreads)Process.GetThreads();


 


            int ThreadCounter = 1;


            csdThread Thread = null;


 


            //Initialize the enumerator to read thread list


            IEnumerator enumThread = (IEnumerator)Threads._NewEnum;


            enumThread.MoveNext();


 


            //Looping through all the threads


            while ((Thread = (csdThread)enumThread.Current) != null)


            {


                message += "Thread[" + ThreadCounter++ + "]\t";


 


                //Set the enumerator for the property list of a Thread


                IEnumerator enumThreadProperties = (IEnumerator)Thread.GetProperties();


                enumThreadProperties.MoveNext();


 


                CProperty threadProperty = null;


                //Looping though all the properties of a thread                   


                while ((threadProperty = (CProperty)enumThreadProperties.Current) != null)


                {


                    //Generating a message which has all the thread property Values


                    message += threadProperty.Value + "\t";


                    //Move the enumerator to point at next entry


                    enumThreadProperties.MoveNext();


                }


                message += "\n";


                //Move to the next thread


                enumThread.MoveNext();


            }


            MessageBox.Show(message, Caption, MessageBoxButtons.OK);


}


 


 

Comments (4)
  1. Posted by: Sankar Ramasubbu I am going to show you how to automate the operation of setting and deleting

  2. Today I am going to talk about how to automate the opertaion of running target control command and retrieveing

  3. Martyn says:

    This would be a lot more useful if the source files were attached, rather than requiring the iteration of several posts and multiple cut / copy / paste cycles.

  4. ce_base says:

    We would like to post the source files too as it would make it more simpler. However, there are certain legalities in this that we would need to take care before. we are looking into this

Comments are closed.

Skip to main content