Author Topic: Autocad SendStringToExecute problem  (Read 12288 times)

0 Members and 1 Guest are viewing this topic.

Werner

  • Guest
Autocad SendStringToExecute problem
« on: August 31, 2011, 02:42:29 AM »
Hi there! I've got some issues using the SendStringToExcute method. I use this command to add drawings to the Autocad Electrical project. (ace_add_dwg_to_project).

See http://www.kxcad.net/autodesk/autocad/AutoCAD_Electrical_API_Reference/ for more info on this command.

The basic function of my program is: (just general markup, no specific syntax used in the example below...)

Do
  AddDrawing
  InsertBlock(s)
  CloseSaveDrawing
Until finished with all data

It all works except the SendStringToExecute command. In my opinion this is the result of the asynchronished behaviour of this method. (The pages is closed even before the SendStringToExecutes is finished) Can anyone give me some pointers on how to solve the problem?

I am using:

Autocad Electrical 2009
Microsoft Visual Studio Express 2010 C#

zoltan

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #1 on: August 31, 2011, 10:45:08 AM »
Doesn't the SendStringToExecute have a parameter called wrapUpInactiveDoc that will wait until the document is idle before calling the command?

Here is the description from the docs:
Input Boolean indicating whether to queue current active document to complete in the next OnIdle() when switching active documents


zoltan

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #2 on: August 31, 2011, 10:47:19 AM »
Sorry, I had it backwards.

Can you use the Document.CommandEnded Event to set a flag or close the document in a call-back when the command is done.

Werner

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #3 on: September 01, 2011, 02:57:31 PM »
Hi zoltan, thank you for your reply.

The CommandEnded event does not work. But the LispEnded event is fired after completing the SendStringToExecute command. I have tried to set a flag when the event is triggerd. My problem is that I have to pauze the calling method until this event is completed. I have tried a loop to wait for the command to complete. But the wait loop (while not lispended) is causing the Autocad GUI to freeze.

So I tried to incorporate a Thread.Sleep line inside the wait loop. So far I have not found a solution which enables me to use the program structure as mentioned in my first message.

I must mention that my C# knowledge is not enough to solve treading or synchonisation problems. So at the moment I don't know how to try youre call back solution. (I will google it and hope to find some extra info) I hope someone can give me a more detailed solution.

Kind regards,

Werner


zoltan

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #4 on: September 01, 2011, 04:17:43 PM »
Welcome to TheSwamp, Werner.

I was thinking about something like this, but maybe someone else has a better idea.

Code: [Select]
        private bool acadIsBusy = false;

        private void DoSomeStuff()
        {
            Application.DocumentManager.MdiActiveDocument.CommandWillStart += new CommandEventHandler(MdiActiveDocument_CommandWillStart);
            Application.DocumentManager.MdiActiveDocument.CommandEnded += new CommandEventHandler(MdiActiveDocument_CommandEnded);

            // Make AutoCAD do some stuff

            while (this.acadIsBusy) ;  // Wait for AutoCAD.

            Application.DocumentManager.MdiActiveDocument.CommandWillStart -= new CommandEventHandler(MdiActiveDocument_CommandWillStart);
            Application.DocumentManager.MdiActiveDocument.CommandEnded -= new CommandEventHandler(MdiActiveDocument_CommandEnded);
        }

        private void MdiActiveDocument_CommandWillStart(object sender, CommandEventArgs e)
        {
            this.acadIsBusy = true;
        }

        private void MdiActiveDocument_CommandEnded(object sender, CommandEventArgs e)
        {
            this.acadIsBusy = false;
        }

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Autocad SendStringToExecute problem
« Reply #5 on: September 01, 2011, 04:23:05 PM »
Welcome to the Swamp!!!!
I guess your using VB by your code description.
To show a simple basic example that zoltan mentioned about using  CommandEnded event
************************************
zoltan already posted an example as I was posting this one, but I will go ahead and post it

Code: [Select]
        <CommandMethod("ACommandToAddEventHandler")> _
        Public Sub ACommandToAddEventHandler()
            AddHandler Application.DocumentManager.MdiActiveDocument.CommandWillStart, New CommandEventHandler(AddressOf CommandBeginHandler)
        End Sub

        <CommandMethod("ace_add_dwg_to_project")> _
        Public Sub ace_add_dwg_to_project()
            Dim rdn As New Random()
            Dim intList As New List(Of Integer)
            For i As Integer = 0 To 1000
                intList.Add(i)
            Next

        End Sub
        '''''''''''''''HANDLERS'''''''''''''''''''''''''''''''''''''''''
        Public Sub CommandBeginHandler(ByVal sender As Object, ByVal e As CommandEventArgs)
            If e.GlobalCommandName.ToLower = "ace_add_dwg_to_project" Then
                Dim doc As Document = sender
                Dim ed As Editor = doc.Editor
                ed.WriteMessage(Environment.NewLine & "Command Begin")
                AddHandler doc.CommandEnded, New CommandEventHandler(AddressOf CommandEndedHandler)
            End If
        End Sub

        Public Sub CommandEndedHandler(ByVal sender As Object, ByVal e As CommandEventArgs)
            If e.GlobalCommandName.ToLower = "ace_add_dwg_to_project" Then
                Dim doc As Document = sender
                Dim ed As Editor = doc.Editor
                ed.WriteMessage(Environment.NewLine & "Command ended")
                RemoveHandler doc.CommandEnded, AddressOf CommandEndedHandler
            End If
        End Sub

 

Werner

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #6 on: September 01, 2011, 05:07:02 PM »
Hi zoltan,

Thank you for making a simple and clear example for me. Unfortunately Autocad "freezes" in the while (this.acadIsBusy); loop. The events are not even triggerd. If a use the SendStringToExecute command once (so not in de do until no data loop) the event LispEnded is raised. (Both CommandWillStart and CommandEnded events are not raised when using the SendStringToExecute with the Autocad Electrical API command acd_add_dwg_to_project) So I tried youre solution also with the LispWillStart and LispEnded events. (Making sure that these events attach to the System.EventArgs) But the result is the same the method hangs in the while (this.acadIsBusy); wait loop.

In the past (when I used VB for these kind of programs) I added a DoEvents() inside the while (this.acadIsBusy) loop. I tried to find a simulair function before. (Like mentioned before the Thread.Sleep() etc..)

So far I don't know how to solve this thing...

Kind regards,

Werner

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Autocad SendStringToExecute problem
« Reply #7 on: September 01, 2011, 05:16:51 PM »
Are you able to check the GlobalCommandName if it the correct command that has started?
Code: [Select]
        [CommandMethod("ACommandToAddEventHandler")]
        public void ACommandToAddEventHandler()
        {
            Application.DocumentManager.MdiActiveDocument.CommandWillStart += new CommandEventHandler(CommandBeginHandler);
        }
        [CommandMethod("ace_add_dwg_to_project")]
        public void ace_add_dwg_to_project()
        {
            Random rdn = new Random();
            List<int> intList = new List<int>();
            for (int i = 0; i <= 1000; i++)
            {
                intList.Add(i);
            }
        }
        /////////////////HANDLERS//////////////////////////
        public void CommandBeginHandler(object sender, CommandEventArgs e)
        {
            if (e.GlobalCommandName.ToLower() == "ace_add_dwg_to_project")
            {
                Document doc = (Document)sender;
                Editor ed = doc.Editor;
                ed.WriteMessage("\nCommand Begin");
                doc.CommandEnded += new CommandEventHandler(CommandEndedHandler);
            }
        }
        public void CommandEndedHandler(object sender, CommandEventArgs e)
        {
            if (e.GlobalCommandName.ToLower() == "ace_add_dwg_to_project")
            {
                Document doc = (Document)sender;
                Editor ed = doc.Editor;
                ed.WriteMessage(Environment.NewLine + "Command ended");
                doc.CommandEnded -= CommandEndedHandler;
            }
        }
 

Werner

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #8 on: September 01, 2011, 05:40:21 PM »
Hi zoltan and Jeff H,

Thank you for helping. This is what I have so far. (I left out some obvious code lines to keep the code compact) Like mentioned I tried the CommandWillStart and CommandEnded events and the LispEnded Events. Both approaches cause autocad to freeze in the while (this.acadIsBusy) loop. I am quite new to Autocad programming so maybe I overlooked something obvious for you guys. I use the program class to define the CommandMethods which I start from the autocad command line. I am not sure what the Commandflags.Session thing is doing. Maybe the problem is related with that?

Code: [Select]
using System;
using System.Threading;
using System.Collections.Generic;
using System.Text;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;

namespace XX
{
    public class YE_AutoCad
    {

        // Add drawing
        public void AddDrawing(string DrawingName)
        {
            Document acDoc = Application.DocumentManager.Add(this.template);
            acDoc.Database.SaveAs(this.ProjectDirectory + DrawingName, DwgVersion.Current);           
            this.drawingName = DrawingName;
            if (this.electrical)
            {
                this.AddDrawingToProject();
            }
        }

        // Close active drawing
        public void CloseDrawing()
        {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            acDoc.CloseAndSave(acDoc.Name);         
        }
       
        // Add drawing to AutoCad Electrical project       
        private void AddDrawingToProject()
        {
            char chrQuote = (char)34;
            char chrSingQuote = (char)39;           
            string str = "(c:ace_add_dwg_to_project '"
                + this.drawingName
                + "' (list 'Section' 'Sub section' 'Page Description' nil))\r";
            str = str.Replace(chrSingQuote, chrQuote);  // Replace ' for "         
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
             //doc.LispWillStart += new LispWillStartEventHandler(doc_LispWillStart);
             doc.LispEnded += new EventHandler(doc_LispEnded);
             //doc.CommandWillStart += new CommandEventHandler(doc_CommandWillStart);
             //doc.CommandEnded += new CommandEventHandler(doc_CommandEnded);
             this.aCadIsBusy = true;
             doc.SendStringToExecute(str, true, false, false);

             while (this.aCadIsBusy) ;

             //doc.CommandWillStart -= new CommandEventHandler(doc_CommandWillStart);
             //doc.CommandEnded -= new CommandEventHandler(doc_CommandEnded);
             //doc.LispWillStart -= new LispWillStartEventHandler(doc_LispWillStart);
             doc.LispEnded -= new EventHandler(doc_LispEnded);
        }

        void doc_CommandEnded(object sender, CommandEventArgs e)
        {
            this.aCadIsBusy = false;
        }

        void doc_CommandWillStart(object sender, CommandEventArgs e)
        {
            this.aCadIsBusy = true;
        }

        void doc_LispEnded(object sender, System.EventArgs e)
        {
            this.aCadIsBusy = false;           
        }

        void doc_LispWillStart(object sender, System.EventArgs e)
        {
            this.aCadIsBusy = true; 
        }

        private Boolean electrical;
        private Boolean aCadIsBusy;
        private string drawingName;
        private string template;
        private string eProjectDirectory;
       
    }
}



using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Autodesk.AutoCAD.Runtime;

namespace XX
{
    public class Program   
    {

        [CommandMethod("TestAdd", CommandFlags.Session)]
        public void TestAdd()
        {
            yeCad.ProjectDirectory = @"C:\";
            yeCad.AddDrawing(@"Werner3.dwg");           
        }

        [CommandMethod("TestAdds", CommandFlags.Session)]
        public void TestAdds()
        {
            yeCad.ProjectDirectory = @"C:\";
            yeCad.AddDrawing(@"Werner3.dwg");
            yeCad.CloseDrawing();
            yeCad.AddDrawing(@"Werner4.dwg");
            yeCad.CloseDrawing();
        }

        XX.YE_AutoCad yeCad = new XX.YE_AutoCad();       
    }
}



zoltan

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #9 on: September 02, 2011, 12:34:35 PM »
Try adding Modal to your CommandFlags as well as session, like this:

[CommandMethod("TestAdd", CommandFlags.Modal | CommandFlags.Session)]

Also, can you call your lisp function using acedInvoke instead of SendStringToExecute?  You may have to do some searching to find out how to use it since I have not had to mess with it.

Werner

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #10 on: September 02, 2011, 03:48:14 PM »
Hi zoltan,

Thank you for youre advise. I have tried your suggestion. No luck so far. If I remove the the while (aCadIsBusy) loop then both LispWillStart and LispEnded events are raised. (Just for one AddDrawing). I will lookup information about the acedInvoke option.

I will get back if I find some solution.
« Last Edit: September 02, 2011, 04:21:58 PM by Werner »

Werner

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #11 on: September 04, 2011, 11:10:52 AM »
So I tried the acedInvoke command. After some searching I found some code and was able te transform to code to send the ace_add_dwg_to_project command via de acedInvoke. This seems to help the "freezing" of the autocad application but stil causes some problems.

Is theire anybody else how tried doing the following:

Do
  AddDrawing
  InsertBlocks
  AddDrawingToAutocadElectricalProject
  CloseAndSaveDrawing
Until data finished

I am able to do all steps but so far it seems to be impossible to combine the several steps in a working solution. I have this solution working in a Autocad VBA so it must be possible to solve this in c# as well. In my opinioun most problems relate to the c# code not being synchronised with the Autocad application. (Code does not automattically hold for commands to finish but just overloads Autocad.)

Werner

  • Guest
Re: Autocad SendStringToExecute problem
« Reply #12 on: September 04, 2011, 04:27:20 PM »
What I do now is:

Code: [Select]
        [CommandMethod("TestRun", CommandFlags.Session)]
        public void TestRun()
        {
            string dwgName = "";
            yeCad.ProjectDirectory = @"C:\TEST WERNER\";

            for (int i = 1; i <= 5; i++)
            {
                dwgName = "WH" + i.ToString() + ".dwg";               
                yeCad.AddDrawing(dwgName);
                yeCad.InsertTypical(@"C:\RESET.dwg", 0, 0);
                yeCad.CloseDrawing();               
            }

            for (int i = 1; i <= 5; i++)
            {
                dwgName = "WH" + i.ToString() + ".dwg";
                XX.YE_AutoCad.AddDwgToAeProject(dwgName);
            }

        }

Each loop seperatly is working. But together in one method it produces a FATAL ERROR UNHANDLED ACCESS VIOLANTION READING ...etc...

Anyone??