2007年3月16日

Showing AutoCAD's hatch dialog from a .NET application

Showing AutoCAD's hatch dialog from a .NET application

Showing AutoCAD's hatch dialog from a .NET application

This question was posted by csharpbird:

How to get the Hatch dialog using .NET? It seems that there is no such class in the .NET API?

It's true there is no public class - or even a published function - to show the hatch dialog inside AutoCAD. It is, however, possible to P/Invoke an unpublished (and therefore unsupported and liable to change without warning) function exported from acad.exe.

Here's some C# code that shows how. The code works for AutoCAD 2007, but will be different for AutoCAD 2006: the function takes and outputs strings, so the change to Unicode in 2007 will have modified the function signature.

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.ApplicationServices;

using System.Reflection;

using System.Runtime.InteropServices;


namespace HatchDialogTest

{

  public class Commands

  {

    [DllImport(

        "acad.exe",

        EntryPoint =

          "?acedHatchPalletteDialog@@YA_NPB_W_NAAPA_W@Z",

        CharSet = CharSet.Auto

      )

    ]

    static extern bool acedHatchPalletteDialog(

      string currentPattern,

      bool showcustom,

      out string newpattern

    );


    [CommandMethod("SHD")]

    static public void ShowHatchDialog()

    {

      string sHatchType;

      string sNewHatchType;

      bool bRet;

      sHatchType = "ANGLE";

      bRet =

        acedHatchPalletteDialog(

          sHatchType,

          true,

          out sNewHatchType

        );

      if (bRet)

      {

        Editor ed =

          Application.DocumentManager.MdiActiveDocument.Editor;

        ed.WriteMessage(

          "\nHatch type selected: " + sNewHatchType

        );

      }

    }

  }

}

Here's what happens when you run the code:

Command: SHD


Hatch_dialog


Hatch type selected: SWAMP

Update

Someone asked me for the VB.NET code for this one (it was quite tricky to marshall the new string being returned). As I'd put it together, I thought I'd post it here:

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.EditorInput

Imports System.Text


Namespace HatchDialogTest


  Public Class Commands


    Private Declare Auto Function acedHatchPalletteDialog _

    Lib "acad.exe" _

    Alias "?acedHatchPalletteDialog@@YA_NPB_W_NAAPA_W@Z" _

    (ByVal currentPattern As String, _

    ByVal showcustom As Boolean, _

    ByRef newpattern As StringBuilder) As Boolean


    <CommandMethod("SHD")> _

    Public Sub ShowHatchDialog()


      Dim sHatchType As String = "ANGLE"

      Dim sNewHatchType As New StringBuilder

      Dim bRet As Boolean = _

        acedHatchPalletteDialog(sHatchType, _

          True, sNewHatchType)

      If bRet And sNewHatchType.ToString.Length > 0 Then

        Dim ed As Editor

        ed = _

          Application.DocumentManager.MdiActiveDocument.Editor

        ed.WriteMessage( _

          vbLf + "Hatch type selected: " + _

          sNewHatchType.ToString)

      End If


    End Sub


  End Class


End Namespace


Update 2

I've recently come back to this post at the prompting of a colleague who was struggling to get it working with AutoCAD 2010. Sure enough, the dialog would appear but the marshalling back of the return string to AutoCAD is now causing a problem, for some unknown reason (at least it's unknown to me :-).

Anyway - to address the issue I've updated the code to perform the string marshalling a little more explicitly, and it now works. This may also address the issue one of the people commenting on this post experienced trying to get the code to work with AutoCAD 2009 (although I do remember testing it there and having no issues, which has me scratching my head somewhat).

Here's the updated C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.EditorInput;

using System.Runtime.InteropServices;

using System;

 

namespace HatchDialogTest

{

  public class Commands

  {

    [DllImport(

        "acad.exe",

        EntryPoint =

          "?acedHatchPalletteDialog@@YA_NPB_W_NAAPA_W@Z",

        CharSet = CharSet.Auto

      )

    ]

    static extern bool acedHatchPalletteDialog(

      string currentPattern,

      bool showcustom,

      out IntPtr newpattern

    );

 

    [CommandMethod("SHD")]

    static public void ShowHatchDialog()

    {

      string sHatchType = "ANGLE";

      IntPtr ptr;

      bool bRet =

        acedHatchPalletteDialog(

          sHatchType,

          true,

          out ptr

        );

      if (bRet)

      {

        string sNewHatchType = Marshal.PtrToStringAuto(ptr);

        if (sNewHatchType.Length > 0)

        {

          Editor ed =

            Application.DocumentManager.MdiActiveDocument.Editor;

          ed.WriteMessage(

            "\nHatch type selected: " + sNewHatchType

          );

        }

      }

    }

  }

}

And here's the updated VB code:

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.EditorInput

Imports System.Runtime.InteropServices

Imports System

 

Namespace HatchDialogTest

 

  Public Class Commands

 

    Private Declare Auto Function acedHatchPalletteDialog _

    Lib "acad.exe" _

    Alias "?acedHatchPalletteDialog@@YA_NPB_W_NAAPA_W@Z" _

    (ByVal currentPattern As String, _

    ByVal showcustom As Boolean, _

    ByRef newpattern As IntPtr) As Boolean

 

    <CommandMethod("SHD")> _

    Public Sub ShowHatchDialog()

 

      Dim sHatchType As String = "ANGLE"

      Dim ptr As IntPtr

      Dim bRet As Boolean = _

        acedHatchPalletteDialog(sHatchType, _

          True, ptr)

      If bRet Then

        Dim sNewHatchType As String = _

          Marshal.PtrToStringAuto(ptr)

        If sNewHatchType.ToString.Length > 0 Then

          Dim ed As Editor

          ed = _

            Application.DocumentManager.MdiActiveDocument.Editor

          ed.WriteMessage( _

            vbLf + "Hatch type selected: " + sNewHatchType)

        End If

      End If

 

    End Sub

 

  End Class

 

End Namespace

留下您的评论