Book a Demo

Author Topic: Notification of process exit within an EA add-in  (Read 7148 times)

fwoolz

  • EA User
  • **
  • Posts: 435
  • Karma: +0/-0
  • We have met the enemy, and he is us.<Pogo, 1970>
    • View Profile
Notification of process exit within an EA add-in
« on: January 25, 2010, 03:21:06 pm »
I'm working on a .NET requirements management add-in for EA that integrates viewing of linked documents together with the normal requirement attributes (and then some). To allow advanced editing of the linked documents (beyond the editing capability offered by a .NET RichTextBox), I fire up Wordpad and load the linked document into it (after saving the linked doc to a temp file); this allows the user to remain within the add-in environment to do fancy editing without having to open EA's document editor. The add-in then "waits" for Wordpad to close, reads the modified file back into the linked document, then updates the display. The problem is the "wait" doesn't wait at all... the add-in blows right through the wait statement and updates the linked document with the original temp file - in other words, without the changes made in Wordpad. Adding a message box to the code, however, forces a wait (until it's closed at least); this "fixes" the wait problem and the update to the linked doc is now successful.

Here's the (C#) code:

Code: [Select]
private void editToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool res;

            if (this.processEditor == null)
            {
                this.processEditor = new System.Diagnostics.Process();
                this.processEditor.EnableRaisingEvents = true;
            }

            tempdoc = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\\EA_" + Guid.NewGuid().ToString().Replace("{", "").Replace("}", "") + ".rtf";
            theRequirement.SaveLinkedDocument(tempdoc);

            processEditor.StartInfo.FileName = Strings.AdvancedEditor; // C:\Windows\write.exe in this case
            processEditor.StartInfo.Arguments = tempdoc;

            processEditor.Start();
            processEditor.WaitForExit(); // This happens immediately; it doen't wait for the process to exit...

            MessageBox.Show(processEditor.HasExited.ToString()); // This provides the required wait to allow the process to exit!

            res = theRequirement.LoadLinkedDocument(tempdoc);
            res &= theRequirement.Update(); // Unsure whether this is needed, but what the heck.

            this.rtfEditor1.TheRichTextBox.Rtf = theRequirement.GetLinkedDocument();
            this.rtfEditor1.Refresh();

            processEditor.Dispose();
            processEditor = null;
        }

This seems to be a Windows problem rather than an EA problem, but I'm hoping that the Sparxians or one of our crackerjack EA gurus (and there are quite a few of them on this forum) can offer some advice. It's as if the wait call, viewed metaphorically as a yodeler waiting to hear his/her echo return from across a wide valley (!), has his/her yodel bounced back immediately by an invisible wall (non-metaphorically, the COM barrier of the add-in model or the EA process itself?). I'm no Win32 expert, so this is just a wild guess (a yodel in the dark?)

Cheers,
Fred W

PS: I know, I need to add code to clean up the temp file...
« Last Edit: January 25, 2010, 03:59:21 pm by fwoolz »
Fred Woolsey
Interfleet Technology Inc.

Always be ready to laugh at yourself; that way, you beat everyone else to the punch.


Geert Bellekens

  • EA Guru
  • *****
  • Posts: 13523
  • Karma: +574/-33
  • Make EA work for YOU!
    • View Profile
    • Enterprise Architect Consultant and Value Added Reseller
Re: Notification of process exit within an EA add-
« Reply #1 on: January 25, 2010, 06:04:20 pm »
Fred,

I'm doing something similar to edit the postconditions of an operation in an external text editor (of your own choice), but I'm taking another approach.
I create a temporary file in the users temp directory with the contents of the postcondition.
The name of the file contains the key to find the postcondition (operationID + postcondition name) and the extension .postcondition
I then let Windows open the file with the associated program (based on the extension).
Then I also fire up a FileSystemWatcher to monitors all .postcondition file in the temp directory.
Once a file gets saved I get a notification from the FileSystemWatcher, find the appropriate postcondition and update its notes.

This is working out very well, and it doesn't tie me to a specific editor.

I'll post the code in a second reply (why only 5000 char >:()

The classes like "ACVModel" and "ACVOperation" are my wrappers for the EA objects.

Geert
« Last Edit: January 25, 2010, 06:08:05 pm by Geert.Bellekens »

Geert Bellekens

  • EA Guru
  • *****
  • Posts: 13523
  • Karma: +574/-33
  • Make EA work for YOU!
    • View Profile
    • Enterprise Architect Consultant and Value Added Reseller
Re: Notification of process exit within an EA add-
« Reply #2 on: January 25, 2010, 06:06:11 pm »
Here is the first part of the class that does most of the work
Code: [Select]
public class PostConditionEditor
    {
        private string textFilePath = @"C:\temp\" ;
        private System.IO.FileSystemWatcher listener;
        string tempDescription;
        private ACVModel model;
        /// <summary>
        /// create a new postcondition editor
        /// </summary>
        /// <param name="model">the current model</param>
        public PostConditionEditor(ACVModel model)
        {
            this.model = model;
            this.startListener();
        }

        /// <summary>
        /// starts the edit of the postconditions of the given operation
        /// </summary>
        /// <param name="operation">the operation for wich the postconditions are to be edited</param>
        public void editPostConditions(ACVOperation operation)
        {
            List<ACVPostCondition> postConditions = operation.getPostConditions();
            if (postConditions.Count < 1)
            {
                MessageBox.Show("No PostConditions found");
            }
            foreach (ACVPostCondition postCondition in postConditions)
            {
                string fullFileName = System.IO.Path.Combine(textFilePath, postCondition.getID() + ".postcondition");
                //write the file to the temp directory
                System.IO.StreamWriter postConditionFile = new StreamWriter(fullFileName);
                postConditionFile.Write(postCondition.getDescription());
                postConditionFile.Close();
                //open the file with the associated editor
                using (System.Diagnostics.Process process = new System.Diagnostics.Process())
                {
                    process.StartInfo.FileName = fullFileName;
                    try
                    {
                        process.Start();
                    }
                    catch (Win32Exception ex)
                    {
                        // no editor associated yet with the .postcondition extension.
                        // let the user choose his preferred editor.
                        if (ex.ErrorCode == -2147467259)
                        //ErrorCode for No application is associated with the specified file for
                        //this operation
                        {
                            System.Diagnostics.ProcessStartInfo openWithInfo = new
                            System.Diagnostics.ProcessStartInfo(@"C:\WINDOWS\system32\rundll32.exe");
                            openWithInfo .Arguments = @" C:\WINDOWS\system32\shell32.dll, OpenAs_RunDLL " + fullFileName;
                            process.StartInfo = openWithInfo;
                            process.Start();
                        }
                    }

                }
            }
        }
        /// <summary>
        /// starts the listener that will monitor the temp directory for any changes in file with a .postcondition extension
        /// </summary>
        private void startListener()
        {
            //create new watcher
            this.listener = new FileSystemWatcher(this.textFilePath, "*.postcondition");
            listener.NotifyFilter = NotifyFilters.LastWrite;
            //turn on events
            listener.EnableRaisingEvents = true;
            //add subscribe to save event
            listener.Changed += new FileSystemEventHandler(listener_FileChanged);
        }
     }
« Last Edit: January 25, 2010, 06:09:34 pm by Geert.Bellekens »

Geert Bellekens

  • EA Guru
  • *****
  • Posts: 13523
  • Karma: +574/-33
  • Make EA work for YOU!
    • View Profile
    • Enterprise Architect Consultant and Value Added Reseller
Re: Notification of process exit within an EA add-
« Reply #3 on: January 25, 2010, 06:07:02 pm »
and here's the second (and last) part
Code: [Select]
/// <summary>
        /// A file with a .postcondition extension has been changed.
        /// Find the postcondition that corresponds to this file and
        /// save the contents of the file to the postcondition of the operation
        /// </summary>
        /// <param name="sender">the sender</param>
        /// <param name="arguments">the arguments</param>
        private void listener_FileChanged(object sender, FileSystemEventArgs arguments)
        {
            //sleep to allow the file to be completely written before reading it again.
            System.Threading.Thread.Sleep(200);
            
            string filechanged = arguments.FullPath;
            FileStream fs = new FileStream(filechanged, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            System.IO.StreamReader reader = new StreamReader(fs);
            string newDescription = reader.ReadToEnd();
            reader.Close();
            //because of some weird behavior of the filesystemwatcher the changed event sometimes gets fired twice
            // for a single change. Therefore we check if the new description has changed before doing anything.
            if (newDescription != this.tempDescription)
            {
                this.tempDescription = newDescription;
                ACVPostCondition postCondition = this.model.findPostCondition(this.parseID(filechanged));
                if (postCondition != null)
                {
                    if (newDescription != postCondition.getDescription())
                    {                      
                        DialogResult updateEA = MessageBox.Show("Do you want to update the postcondition in EA?", "Save postcondition to EA?", MessageBoxButtons.YesNo);
                        
                        if (updateEA == DialogResult.Yes)
                            
                        {
                            this.updatePostCondition(postCondition, newDescription);
                        }
                    }
                  
                }
            }
            
        }
        /// <summary>
        /// updates the given postconditions description with the given description
        /// </summary>
        /// <param name="postCondition">the postcondition to update</param>
        /// <param name="description">the new description</param>
        private void updatePostCondition(ACVPostCondition postCondition, string description)
        {
            if (postCondition.getOwningOperation().isReadOnly())
            {
                DialogResult lockElement = MessageBox.Show("Operation is read only, lock element and update postcondition?", "Lock Element", MessageBoxButtons.YesNo);
                if (postCondition.enableWrite())
                {
                    this.updatePostCondition(postCondition, description);
                }
                else
                {
                    MessageBox.Show("Cannot update postcondition, element locked by another user");
                }
            }
            else
            {
                postCondition.setDescription(description);
            }

        }
        /// <summary>
        /// get the id from the filepath of a postcondition file
        /// </summary>
        /// <param name="filepath">the full pathname of the file</param>
        /// <returns>the id of the postcondition</returns>
        private string parseID(string filepath)
        {
            string filename = filepath.Split('\\').Last<string>();
            string extension = filename.Split('.').Last<string>();
            string id = filename.Remove(filename.Length - extension.Length -1);
            return id;
        }

Geert Bellekens

  • EA Guru
  • *****
  • Posts: 13523
  • Karma: +574/-33
  • Make EA work for YOU!
    • View Profile
    • Enterprise Architect Consultant and Value Added Reseller
Re: Notification of process exit within an EA add-
« Reply #4 on: January 25, 2010, 06:13:08 pm »
As you can see I too had this "wait" issue because I had to wait untill the file was completely written. I solved that in a very dirty way by waiting for an arbitrary 200 milliseconds. :-[

It's not pretty, but it works.

Geert

fwoolz

  • EA User
  • **
  • Posts: 435
  • Karma: +0/-0
  • We have met the enemy, and he is us.&lt;Pogo, 1970&gt;
    • View Profile
Re: Notification of process exit within an EA add-
« Reply #5 on: January 25, 2010, 06:34:01 pm »
Geert,

I wish I'd thought of that! Thanks, Geert! I will do some tinkering along the same lines and let you know how it works out. Brilliant!

As a side note, I tried the same thing with AbiWord instead of WordPad, primarily due to the fact that there appears to be a rather large version gap between the RTF version in Windows 7 WordPad and that used in the Windows Forms RichTextBox (which uses, I think, v1.6). This causes some formatting changes which, while minor, are annoying. AbiWord seems to do a better job at preserving the formatting. The interesting thing is the "wait" WORKS when using AbiWord (although an annoying "busy" box pops up in the add-on). The busy box doesn't appear when using WordPad (or at least it didn't).

Cheers,
Fred
Fred Woolsey
Interfleet Technology Inc.

Always be ready to laugh at yourself; that way, you beat everyone else to the punch.


fwoolz

  • EA User
  • **
  • Posts: 435
  • Karma: +0/-0
  • We have met the enemy, and he is us.&lt;Pogo, 1970&gt;
    • View Profile
Re: Notification of process exit within an EA add-
« Reply #6 on: January 27, 2010, 09:44:16 am »
Geert,

Works like a charm! Thanks again for the help.

Fred
Fred Woolsey
Interfleet Technology Inc.

Always be ready to laugh at yourself; that way, you beat everyone else to the punch.