Author Topic: Unsafe code and debug  (Read 10747 times)

0 Members and 1 Guest are viewing this topic.

Bryco

  • Water Moccasin
  • Posts: 1882
Unsafe code and debug
« on: December 17, 2010, 07:06:06 PM »
I have a vba routine  that uses the Flatshot routive via sendcommand that takes flatshot views for top front and side views. It also names the blocks and puts the items in the blocks on a layer named after the views.

Trying to do this in C# has proven difficult as sendcommand has worked nor has the p/invoke alternatives mentioned by Kean Walmsley. However Tony's method does work, but only  in debug. When I rebuild in Release and use it I get a crash with no error report.
Anyone have an idea as to why or how to fix it?

Hopefully this will run now
Code: [Select]
        class test
        {


        const int RTNONE = 5000; /* No result */
        const int RTREAL = 5001; /*Real number */
        const int RTPOINT = 5002; /* 2D point X and Y only */
        const int RTSHORT = 5003; /* Short integer */
        const int RTANG = 5004; /* Angle */
        const int RTSTR = 5005; /* String */
        const int RTENAME = 5006; /* Entity name */
        const int RTPICKS = 5007; /* Pick set */
        const int RTORINT = 5008; /* Orientation */
        const int RT3DPOINT = 5009; /* 3D point - X, Y, and Z */
        const int RTLONG = 5010; /* Long integer */
        const int RTVOID = 5014; /* Blank symbol */
        const int RTLB = 5016; /* list begin */
        const int RTLE = 5017; /* list end */
        const int RTDOTE = 5018; /* dotted pair */
        const int RTNIL = 5019; /* nil */
        const int RTDXF0 = 5020; /* DXF code 0 for ads_buildlist only */
        const int RTT = 5021; /* T atom */
        const int RTRESBUF = 5023; /* resbuf */
        const int RTMODELESS = 5027; /* interrupted by modeless dialog */


        //http://forums.autodesk.com/t5/NET/acedcommand-function-in-Net-managed-classes/m-p/1332900
        //TonyT
        //Requires Allow Unsafe code to be checked in Build

        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl,
            EntryPoint = "acedCmd")]
        extern static int acedCmd(IntPtr pResbuf);

        unsafe static int Command(ResultBuffer args)
        {
            if (!acadApp.DocumentManager.IsApplicationContext)
                return acedCmd((IntPtr)args.UnmanagedObject.ToPointer());
            else
                return 0;
        }








             [CommandMethod("Flatshot3Views")]
        public static void Flatshot3Views()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            acadApp.SetSystemVariable("TILEMODE", 1);
            string[] sName = new string[] { "Top", "Front", "Left" };

            ObjectIdCollection ViewIds = new ObjectIdCollection();
            string cLayer = (string)acadApp.GetSystemVariable("CLAYER");
            ViewTableRecord CurrentVtr = ed.GetCurrentView();

           
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                bool hasSolid = false;
                RXClass rxSolid = RXClass.GetClass(typeof(Solid3d));

                ViewTable vt = tr.GetObject(db.ViewTableId, OpenMode.ForWrite) as ViewTable;
                ViewTableRecord vtr;
                //Make the views
                for (int i = 0; i < 3; i++)
                {
                    string name = sName[i];
                    if (vt.Has(name))
                        ViewIds.Add(vt[name]);
                    else
                    {
                        OrthographicView ov;
                        vtr = new ViewTableRecord();
                        vtr.Name = name;

                        if (i == 0)
                            ov = OrthographicView.TopView;
                        else if (i == 1)
                            ov = OrthographicView.FrontView;
                        else
                            ov = OrthographicView.LeftView;

                        vtr.SetViewDirection(ov);
                        vtr.SetUcs(ov);
                        ViewIds.Add(vt.Add(vtr));
                        tr.AddNewlyCreatedDBObject(vtr, true);
                    }
                }
                tr.Commit();
            }

            //Get the insertion point
            PromptPointOptions ppo = new PromptPointOptions("\nPick the insertion point:");
            PromptPointResult per = ed.GetPoint(ppo);
            if (per.Status != PromptStatus.OK) return;
            Matrix3d ucs = ed.CurrentUserCoordinateSystem;
            Point3d p = per.Value.TransformBy(ucs);


            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                for (int i = 0; i < 3; i++)
                {
                    string name = sName[i];
                    ed.SetCurrentView((ViewTableRecord)tr.GetObject(ViewIds[i], OpenMode.ForRead));
                    ResultBuffer args = new ResultBuffer();
                    args.Add(new TypedValue(RTSTR, "Flatshot"));
                    args.Add(new TypedValue(RT3DPOINT, p));
                    args.Add(new TypedValue(5001, 1.0));
                    args.Add(new TypedValue(5001, 1.0));
                    args.Add(new TypedValue(5001, 0.0));

                    try
                    {
                        ed.WriteMessage(Environment.NewLine + "Command=" + Command(args).ToString());
                    }
                    catch (System.Exception ex)
                    {
                        //ed.WriteMessage(Environment.NewLine + ex);
                        throw;
                    }

                    //com doesn't work
                    //((com)acadApp.AcadApplication).ActiveDocument.SendCommand("Flatshot " + sPoint +"    " );

                    ObjectId brefId = SelectLastEnt(doc);
                    BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                    if (brefId != ObjectId.Null)
                    {
                        BlockReference br = tr.GetObject(brefId, OpenMode.ForWrite) as BlockReference;
                        if (br == null) continue;
                        BlockTableRecord btr = tr.GetObject(br.BlockTableRecord, OpenMode.ForWrite) as BlockTableRecord;
                        string bname = name;
                        if (!bt.Has(name))
                            btr.Name = name;
                        else
                        {
                            int j = 1;
                            while (true)
                            {
                                bname = name + j.ToString();
                                if (!bt.Has(bname))
                                {
                                    btr.Name = bname;
                                    break;
                                }
                                j++;
                            }
                        }
                    }
                }
                tr.Commit();
            }
            ed.SetCurrentView(CurrentVtr);
           
        } //end Flatshot3Views



             //Kerry
             static public ObjectId SelectLastEnt(Document doc)
             {
                 PromptSelectionResult LastEnt = doc.Editor.SelectLast();
                 if (LastEnt.Value != null && LastEnt.Value.Count == 1)
                 {
                     return LastEnt.Value[0].ObjectId;
                 }
                 return ObjectId.Null;
             }



        } //endclass test

« Last Edit: December 20, 2010, 08:49:39 PM by Bryco »

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Unsafe code and debug
« Reply #1 on: December 20, 2010, 05:47:30 PM »
Cannot get it to complie has Layers, ssSet and Util missing

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Unsafe code and debug
« Reply #2 on: December 20, 2010, 08:50:16 PM »
Jeff I modified it.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Unsafe code and debug
« Reply #3 on: December 20, 2010, 09:02:29 PM »
Hi Bryce

In the time since SelectLastEnt(Document doc) was devised AutoDesk has added

public static ObjectId EntLast();
Declaring Type: Autodesk.AutoCAD.Internal.Utils
Assembly: acmgd, Version=18.1.0.0

.. not sure of the initial release version :)

time flies, heh  :wink:
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Unsafe code and debug
« Reply #4 on: December 21, 2010, 12:05:51 PM »
Thanks Kerry I didn't know that, works in 2010 but
Declaring Type:using Autodesk.AutoCAD.Internal;
then Utils.EntLast();

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Unsafe code and debug
« Reply #5 on: December 21, 2010, 09:36:49 PM »
I have no idea how I got it working but this is what happened and steps

1. Checked Allow Unsafe code and built  in debug mode.
2. Checked Allow Unsafe code and built  in release mode.
3. Went through with no solids in drawing with debug bulid and nothing happened.
4. Tried in release mode with no solids and crashed after a couple of the dialog boxes
5. Tried with solids in release mode and crashed right after picked insertion point
6. Rebuilt it and for some reason 2 warnings went away about hasSolid is assinged and not used and another variable with same warning
7. Tried it and work

The only line of code I added

Code: [Select]
[assembly: CommandClass(typeof(ClassLibrary4.test))]

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Unsafe code and debug
« Reply #6 on: December 22, 2010, 06:19:20 PM »
Thanks for trying it out Jeff.
I can't figure it out either, but with the following code (very little changed) I crashed 1 machine and 4 others didn't.
On the machine that crashed, reopening cad and running it again numerous times there were no more crashes.
So perhaps something gets set after the first try. (Very Scientific explanation lol).
Code: [Select]
using System;

using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Internal;
using Autodesk.AutoCAD.Colors;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;


[assembly:CommandClass(typeof(Testing.test))]

    namespace Testing
    {
        class test
        {
        const int RTREAL = 5001; /*Real number */
        const int RTSTR = 5005; /* String */
        const int RT3DPOINT = 5009; /* 3D point - X, Y, and Z */

        //http://forums.autodesk.com/t5/NET/acedcommand-function-in-Net-managed-classes/m-p/1332900
        //TonyT
        //Requires Allow Unsafe code to be checked in Build

        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl,
            EntryPoint = "acedCmd")]
        extern static int acedCmd(IntPtr pResbuf);

        unsafe static int Command(ResultBuffer args)
        {
            if (!acadApp.DocumentManager.IsApplicationContext)
                return acedCmd((IntPtr)args.UnmanagedObject.ToPointer());
            else
                return 0;
        }




        [CommandMethod("Flatshot3Views")]
        public static void Flatshot3Views()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            acadApp.SetSystemVariable("TILEMODE", 1);
            string[] sName = new string[] { "Top", "Front", "Left" };

            ObjectIdCollection ViewIds = new ObjectIdCollection();
            string cLayer = (string)acadApp.GetSystemVariable("CLAYER");
            ViewTableRecord CurrentVtr = ed.GetCurrentView();

            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                    bool hasSolid = false;
                    RXClass rxSolid = RXClass.GetClass(typeof(Solid3d));

                    //Check for no solids
                    foreach (ObjectId blockId in bt)
                    {
                        foreach (ObjectId id in (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead))
                        {
                            if (id.ObjectClass.IsDerivedFrom(rxSolid))
                            {
                                hasSolid = true;
                                break;
                            }
                        }
                        if (!hasSolid)
                        {
                            System.Windows.Forms.MessageBox.Show("There are no solids.");
                            return;
                        }
                    }

                    ViewTable vt = tr.GetObject(db.ViewTableId, OpenMode.ForWrite) as ViewTable;
                    ViewTableRecord vtr;
                    //Make the views
                    for (int i = 0; i < 3; i++)
                    {
                        string name = sName[i];
                        if (vt.Has(name))
                            ViewIds.Add(vt[name]);
                        else
                        {
                            OrthographicView ov;
                            vtr = new ViewTableRecord();
                            vtr.Name = name;

                            if (i == 0)
                                ov = OrthographicView.TopView;
                            else if (i == 1)
                                ov = OrthographicView.FrontView;
                            else
                                ov = OrthographicView.LeftView;

                            vtr.SetViewDirection(ov);
                            vtr.SetUcs(ov);
                            ViewIds.Add(vt.Add(vtr));
                            tr.AddNewlyCreatedDBObject(vtr, true);
                        }
                    }
                    tr.Commit();
                }

                //Get the insertion point
                PromptPointOptions ppo = new PromptPointOptions("\nPick the insertion point:");
                PromptPointResult per = ed.GetPoint(ppo);
                if (per.Status != PromptStatus.OK) return;
                Matrix3d ucs = ed.CurrentUserCoordinateSystem;
                Point3d p = per.Value.TransformBy(ucs);
                ed.WriteMessage(Environment.NewLine + "Set the Foreground Lines color field to bylayer" + Environment.NewLine);
                //Add layers
                AddLayer("Top", 200, "Continuous");
                AddLayer("Front", 205, "Continuous");
                AddLayer("Left", 210, "Continuous");

                AddLayer("Top-Hidden", 5, "HIDDEN2");
                AddLayer("Front-Hidden", 5, "HIDDEN2");
                AddLayer("Left-Hidden", 5, "HIDDEN2");

                ResultBuffer args = new ResultBuffer();
                args.Add(new TypedValue(RTSTR, "Flatshot"));
                args.Add(new TypedValue(RT3DPOINT, p));
                args.Add(new TypedValue(5001, 1.0));
                args.Add(new TypedValue(5001, 1.0));
                args.Add(new TypedValue(5001, 0.0));


                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    for (int i = 0; i < 3; i++)
                    {
                        string name = sName[i];
                        acadApp.SetSystemVariable("CLAYER",name);
                        ed.SetCurrentView((ViewTableRecord)tr.GetObject(ViewIds[i], OpenMode.ForRead));
                       
                        try
                        {
                             Command(args);
                        }
                        catch (System.Exception ex)
                        {
                            ed.WriteMessage(Environment.NewLine + ex);
                            throw;
                        }


                        //((com)acadApp.AcadApplication).ActiveDocument.SendCommand("Flatshot " + sPoint +"    " );


                        ObjectId brefId = Utils.EntLast();
                        BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                        if (brefId != ObjectId.Null)
                        {
                            BlockReference br = tr.GetObject(brefId, OpenMode.ForWrite) as BlockReference;
                            if (br == null) continue;
                            BlockTableRecord btr = tr.GetObject(br.BlockTableRecord, OpenMode.ForWrite) as BlockTableRecord;
                            string bname = name;
                            if (!bt.Has(name))
                                btr.Name = name;
                            else
                            {
                                int j = 1;
                                while (true)
                                {
                                    bname = name + j.ToString();
                                    if (!bt.Has(bname))
                                    {
                                        btr.Name = bname;
                                        break;
                                    }
                                    j++;
                                }
                            }
                            foreach (ObjectId entId in btr)
                            {
                                Entity ent = tr.GetObject(entId, OpenMode.ForWrite) as Entity;
                                if (ent.ColorIndex == 0)
                                {
                                    ent.Layer = sName[i] + "-Hidden";
                                    ent.ColorIndex = 256;
                                    ent.Linetype = "ByLayer";
                                }
                            }
                        }
                    }
                    tr.Commit();
                }

                acadApp.SetSystemVariable("CLAYER",cLayer);
                ed.SetCurrentView(CurrentVtr);
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage(Environment.NewLine + ex);
                throw;
            }
        } //end Flatshot3Views



        static private bool AddLayer(string sLayer, short iColor, string sLtype)
        {

            Database db = HostApplicationServices.WorkingDatabase;     
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead, false) as LayerTable;
                if (lt.Has(sLayer)) return true;
                lt.UpgradeOpen();
                LayerTableRecord ltr = new LayerTableRecord();
                ltr.Name = sLayer;
                ltr.Color = Color.FromColorIndex(ColorMethod.ByAci, iColor);
                LinetypeTable linet = tr.GetObject(db.LinetypeTableId, OpenMode.ForRead, false) as LinetypeTable;
                if (linet.Has(sLtype))
                    ltr.LinetypeObjectId = linet[sLtype];
                else
                {
                    string Acadlinetypes ="acadiso.lin";           
                    AddLinetype(sLtype, Acadlinetypes,db);
                }
                lt.Add(ltr);
                tr.AddNewlyCreatedDBObject(ltr, true);
                tr.Commit();
                return true;
            }

        } //end AddLayerCode


        static public ObjectId AddLinetype(string sLType, string sFile, Database db)
        {
            ObjectId LTypeID = ObjectId.Null;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                LinetypeTable LTypeTable = tr.GetObject
                    (db.LinetypeTableId, OpenMode.ForRead, false) as LinetypeTable;
                if (LTypeTable.Has(sLType))
                    LTypeID = LTypeTable[sLType];
                else
                {
                    db.LoadLineTypeFile(sLType, sFile);
                    LTypeID = LTypeTable[sLType];
                }
                tr.Commit();
                return LTypeID;
            }
        } //end AddLinetype



        } //endclass test
     

}

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Unsafe code and debug
« Reply #7 on: December 22, 2010, 10:19:40 PM »
Maybe saying it needed to warm up sounds more scientific

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8661
  • AKA Daniel
Re: Unsafe code and debug
« Reply #8 on: December 22, 2010, 11:28:16 PM »
Are you using attach to process?  If it's an access violation or similar, you may be able to  catch it there..
or it could be a gamma ray blasting a single bit in memory, those bugs are really hard to catch

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Unsafe code and debug
« Reply #9 on: December 23, 2010, 10:24:33 AM »
I don't know what attach to process is, can I do that with express?

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8661
  • AKA Daniel
Re: Unsafe code and debug
« Reply #10 on: December 23, 2010, 11:09:47 AM »
Ack! probably not with express, sorry   :|

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Unsafe code and debug
« Reply #11 on: March 07, 2012, 01:26:52 PM »
2010 Express and cad 2012  won't run this at all without crashing. Must be less leeway with threading or something

TheMaster

  • Guest
Re: Unsafe code and debug
« Reply #12 on: March 08, 2012, 04:07:56 AM »
2010 Express and cad 2012  won't run this at all without crashing. Must be less leeway with threading or something

Look at the type of the parameter in the declaration for acedCmd(),
and look at the type of the ResultBuffer's UnmanagedObject
property.


exmachina

  • Guest
Re: Unsafe code and debug
« Reply #13 on: March 08, 2012, 05:29:03 PM »
sorry, maybe I'm wrong but acedCmd expects an IntPtr, not a pointer.

just today i am playing with a similar code (not for autocad)
Code - C#: [Select]
  1. public unsafe int AnnotationGetStyles(int line, out byte[] styles) {
  2.   int lenght = SendScintilla(Constants.SCI_ANNOTATIONGETSTYLES, line);
  3.   if (lenght == 0) {
  4.     styles = null;
  5.     return 0;
  6.   }
  7.   styles = new byte[lenght];
  8.   fixed (byte* pB = &styles[0]) // THIS A POINTER
  9.     SendScintilla(Constants.SCI_ANNOTATIONGETSTYLES, (IntPtr)line, (IntPtr)pB);
  10.   return lenght;
  11. }
  12.  
  13. public IntPtr SendScintilla(uint msg, IntPtr wParam, IntPtr lParam) {
« Last Edit: March 08, 2012, 05:35:23 PM by exmachina »

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Unsafe code and debug
« Reply #14 on: March 08, 2012, 07:33:14 PM »
(IntPtr)args.UnmanagedObject.ToPointer()  AND  args.UnmanagedObject  print out as system.intPtr so I am lost on this one.