Author Topic: Wrappers for ObjectARX functions, ErrorStatus and so on.  (Read 6031 times)

0 Members and 1 Guest are viewing this topic.

Alexander Rivilis

  • Bull Frog
  • Posts: 214
  • Programmer from Kyiv (Ukraine)
Wrappers for ObjectARX functions, ErrorStatus and so on.
« on: June 18, 2006, 09:24:21 AM »
Question for .NET masters. I write the next wrappers:
Code: [Select]
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;

[assembly: CommandClass(typeof(XrefLib.XrefClass))]

namespace XrefLib
{
  class Wrapper
  {
    static int version = Autodesk.AutoCAD.ApplicationServices.Application.Version.Major;
    // For AutoCAD 2006:
    [System.Security.SuppressUnmanagedCodeSecurity]
    [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi,
       EntryPoint = "?acedXrefUnload@@YA?AW4ErrorStatus@Acad@@PBD_NPAVAcDbDatabase@@@Z")]
    extern public static ErrorStatus acedXrefUnload16(string XrefBlockname, bool bQuiet, IntPtr db);
    // For AutoCAD 2007:
    [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
       EntryPoint = "?acedXrefUnload@@YA?AW4ErrorStatus@Acad@@PB_W_NPAVAcDbDatabase@@@Z")]
    extern public static ErrorStatus acedXrefUnload17(string XrefBlockname, bool bQuiet, IntPtr db);

    // For AutoCAD 2006:
    [System.Security.SuppressUnmanagedCodeSecurity]
    [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi,
       EntryPoint = "?acedXrefReload@@YA?AW4ErrorStatus@Acad@@PBD_NPAVAcDbDatabase@@@Z")]
    extern public static ErrorStatus acedXrefReload16(string XrefBlockname, bool bQuiet, IntPtr db);
    // For AutoCAD 2007:
    [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
       EntryPoint = "?acedXrefReload@@YA?AW4ErrorStatus@Acad@@PB_W_NPAVAcDbDatabase@@@Z")]
    extern public static ErrorStatus acedXrefReload17(string XrefBlockname, bool bQuiet, IntPtr db);

    // For AutoCAD 2006:
    [System.Security.SuppressUnmanagedCodeSecurity]
    [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi,
       EntryPoint = "?acedXrefBind@@YA?AW4ErrorStatus@Acad@@PBD_N1PAVAcDbDatabase@@@Z")]
    extern public static ErrorStatus acedXrefBind16(string XrefBlockname, bool bInsertBind, bool bQuiet, IntPtr db);
    // For AutoCAD 2007:
    [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
       EntryPoint = "?acedXrefBind@@YA?AW4ErrorStatus@Acad@@PB_W_N1PAVAcDbDatabase@@@Z")]

    extern public static ErrorStatus acedXrefBind17(string XrefBlockname, bool bInsertBind, bool bQuiet, IntPtr db);

    static public ErrorStatus acedXrefUnload(string XrefBlockname, bool bQuite, Database db)
    {
      switch (version)
      {
        case 16: return acedXrefUnload16(XrefBlockname, bQuite, (db == null) ? IntPtr.Zero : db.UnmanagedObject);
        case 17: return acedXrefUnload17(XrefBlockname, bQuite, (db == null) ? IntPtr.Zero : db.UnmanagedObject);
      }
      return ErrorStatus.NotImplementedYet;
    }

    static public ErrorStatus acedXrefReload(string XrefBlockname, bool bQuite, Database db)
    {
      switch (version)
      {
        case 16: return acedXrefReload16(XrefBlockname, bQuite, (db == null) ? IntPtr.Zero : db.UnmanagedObject);
        case 17: return acedXrefReload17(XrefBlockname, bQuite, (db == null) ? IntPtr.Zero : db.UnmanagedObject);
      }
      return ErrorStatus.NotImplementedYet;
    }

    static public ErrorStatus acedXrefBind(string XrefBlockname, bool bInsertBind, bool bQuite, Database db)
    {
      switch (version)
      {
        case 16: return acedXrefBind16(XrefBlockname, bInsertBind, bQuite, (db == null) ? IntPtr.Zero : db.UnmanagedObject);
        case 17: return acedXrefBind17(XrefBlockname, bInsertBind, bQuite, (db == null) ? IntPtr.Zero : db.UnmanagedObject);
      }
      return ErrorStatus.NotImplementedYet;
    }
  }

  public class XrefClass
  {
    [CommandMethod("X_UNLOAD")]
    static public void XUnload()
    {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
      PromptStringOptions pr = new PromptStringOptions("\nType XrefBlockName: "); pr.AllowSpaces = true;
      PromptResult res = ed.GetString(pr);
      if (res.Status == PromptStatus.OK)
      {
        ErrorStatus es = Wrapper.acedXrefUnload(res.StringResult, true, HostApplicationServices.WorkingDatabase);
        if (es != ErrorStatus.OK)
        {
          ed.WriteMessage("\nError in unloading xref <{0}>: {1}", res.StringResult, es);
        }
      }
    }
    [CommandMethod("X_RELOAD")]
    static public void XReload()
    {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
      PromptStringOptions pr = new PromptStringOptions("\nType XrefBlockName: "); pr.AllowSpaces = true;
      PromptResult res = ed.GetString(pr);
      if (res.Status == PromptStatus.OK)
      {
        ErrorStatus es = Wrapper.acedXrefReload(res.StringResult, true, HostApplicationServices.WorkingDatabase);
        if (es != ErrorStatus.OK)
        {
          ed.WriteMessage("\nError in reloading xref <{0}>: {1}", res.StringResult, es);
        }
      }
    }
    [CommandMethod("X_BIND")]
    static public void XBind()
    {
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
      PromptStringOptions pr = new PromptStringOptions("\nType XrefBlockName: "); pr.AllowSpaces = true;
      PromptResult res = ed.GetString(pr);
      if (res.Status == PromptStatus.OK)
      {
        ErrorStatus es = Wrapper.acedXrefBind(res.StringResult, false, true, HostApplicationServices.WorkingDatabase);
        if (es != ErrorStatus.OK)
        {
          ed.WriteMessage("\nError in binding xref <{0}>: {1}", res.StringResult, es);
        }
      }
    }
  }
}
It is interesting that sometime ErrorStatus es has wrong value. For example, while unloading nonexisting in this drawing xref name. Who can explain me what is wrong? In native ObjectARX equivalent I get eNotImplementedYet for this situation. In .NET I get different values, such as number 156168256, which can not be member of enum Acad::ErrorStatus.

MickD

  • King Gator
  • Posts: 3636
  • (x-in)->[process]->(y-out) ... simples!
Re: Wrappers for ObjectARX functions, ErrorStatus and so on.
« Reply #1 on: June 18, 2006, 11:37:47 PM »
Just a guess but the returned value from the imported function is just an int/short or similar where you are after the managed enum which the imported function is not aware of to be able to return it.
I'm not sure how you would get around this, I couldn't find the def's for the AcDb::ErrorStatus enum in the headers (after just a brief look anyway).

Just thinking about it, I haven't used a function that returns an ErrorStatus yet ...
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

MickD

  • King Gator
  • Posts: 3636
  • (x-in)->[process]->(y-out) ... simples!
Re: Wrappers for ObjectARX functions, ErrorStatus and so on.
« Reply #2 on: June 18, 2006, 11:49:22 PM »
...
Just thinking about it, I haven't used a function that returns an ErrorStatus yet ...

This is probably because you have to trap an Exception that returns the ErrorStatus enum :)

Try wrapping your functions in a try/catch block to catch the exception and return your errorstatus for diagnosis.
Something like this -
Code: [Select]
[CommandMethod("X_BIND")]
static public void XBind()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
PromptStringOptions pr = new PromptStringOptions("\nType XrefBlockName: "); pr.AllowSpaces = true;
PromptResult res = ed.GetString(pr);
try
{
if (res.Status == PromptStatus.OK)
{
Wrapper.acedXrefBind(res.StringResult, false, true, HostApplicationServices.WorkingDatabase);
}
}
catch(Autodesk.AutoCAD.Runtime.Exception err)
{
ed.WriteMessage("\nError in binding xref <{0}>: {1}", res.StringResult, err.ErrorStatus);
}
}

You will also have to catch the int returned from the imported function in your Wrapper class though it is of no further use.

hth,
Mick.
"Programming is really just the mundane aspect of expressing a solution to a problem."
- John Carmack

"Short cuts make long delays,' argued Pippin.”
- J.R.R. Tolkien

Alexander Rivilis

  • Bull Frog
  • Posts: 214
  • Programmer from Kyiv (Ukraine)
Re: Wrappers for ObjectARX functions, ErrorStatus and so on.
« Reply #3 on: June 19, 2006, 03:42:26 AM »
Thanks for reply!
I'm not sure how you would get around this, I couldn't find the def's for the AcDb::ErrorStatus enum in the headers (after just a brief look anyway).
Acad::ErrorStatus in acadstrc.h
I tried some other variants:
1) I declare as int, as short, as uint, as ushort return value - without success. :(
2) I tried with try/catch - without succes. :(
3) I tried with Autodesk.AutoCAD.Runtime.Interop.Check() - without success :(
It is interesting that in other wrapped finctions I get right return values. Maybe acedXrefXXX function return not initialized value as error.