明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 704|回复: 0

Calling unexposed ObjectARX methods using P/Invoke from .NET

[复制链接]
发表于 2011-5-3 12:41 | 显示全部楼层 |阅读模式

作者:kean

原文地址:http://through-the-interface.typepad.com/through_the_interface/2011/05/calling-unexposed-objectarx-methods-using-pinvoke-from-net.html

 

As promised, last week, today we’re going to look at a technique pointed out to me by Viru Aithal for calling unexposed ObjectARX member functions via P/Invoke.

It sometimes happens that ObjectARX (unmanaged C++) methods fail to get exposed immediately via .NET, which is currently the case for MLeader.Scale (both getting and setting this property). The technique shown in this post allows you to work around this, prior to the managed API in AutoCAD being updated to include it. It’s worth noting that if you need a more complex exposure via .NET – as Dan Smith sometimes reminds me (thanks, Dan :-) – it’s preferably to go directly with C++/CLI rather than P/Invoke. This approach isn’t for everyone, of course – you should be comfortable with C++ to consider it – but I did want to just mention that (pre-emptively ;-).

There are a few steps involved in defining your P/Invoke statements, as covered in this old post of mine and also here (a nice article which inspired me to include the System.Security.SuppressUnmanagedCodeSecurity attribute in our class).

I won’t go into that side of things, again, but will cut to the chase: when P/Invoking a method – which is really just a normal function with a “this” argument denoting the object for the method to work on – we simply need to pass in the UnmanagedObject property of our .NET object prior to the other arguments (making sure the method signature has been DllImported using the ThisCall calling convention).

Here, for instance, we get the value of our MLeader’s scale property:

double mls = Scale(ent.UnmanagedObject);

And here we set it to double the original value:

SetScale(ent.UnmanagedObject, mls * 2);

Here’s the full C# code defining our DMLS (DoubleMLeaderScale) command:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using System.Runtime.InteropServices;

using System.Security;

using System;

 

namespace PInvokeMethods

{

  public class Commands

  {

    [SuppressUnmanagedCodeSecurity]

    [DllImport(

      "acdb18.dll",

      CallingConvention = CallingConvention.ThisCall,

      EntryPoint = "?scale@AcDbMLeader@@QBENXZ"

     )]

    private static extern double Scale(IntPtr mleader);

 

    [DllImport(

      "acdb18.dll",

      CallingConvention = CallingConvention.ThisCall,

      EntryPoint =

        "?setScale@AcDbMLeader@@QAE?AW4ErrorStatus@Acad@@N@Z"

     )]

    private static extern int SetScale(

      IntPtr mleader, double scale

    );

 

    [CommandMethod("DMLS")]

    public static void DoubleMLeaderScale()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed = doc.Editor;

 

      PromptEntityOptions peo =

        new PromptEntityOptions("\nSelect MLeader");

      peo.SetRejectMessage(

        "\nMust be an MLeader."

      );

      peo.AddAllowedClass(typeof(MLeader), false);

 

      PromptEntityResult per = ed.GetEntity(peo);

      if (per.Status != PromptStatus.OK)

        return;

 

      Transaction tr =

        doc.TransactionManager.StartTransaction();

      using (tr)

      {

        try

        {

          // Open the selected entity

 

          Entity ent =

            (Entity)tr.GetObject(

              per.ObjectId,

              OpenMode.ForRead

            );

 

          // We use is instead of as, because we don't

          // actually need an MLeader object reference

          // to P/Invoke the unmanaged methods

 

          if (ent is MLeader)

          {

            // Get the scale

 

            double mls = Scale(ent.UnmanagedObject);

 

            // Double it and write it back to the MLeader

 

            ent.UpgradeOpen();

            SetScale(ent.UnmanagedObject, mls * 2);

          }

          tr.Commit();

        }

        catch (Autodesk.AutoCAD.Runtime.Exception ex)

        {

          ed.WriteMessage("\nException: {0}", ex.Message);

        }

      }

    }

  }

}

The command works predictably enough. Here’s an MLeader prior to modification:

And here it is after having been updated by the DMLS command:

 

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
"觉得好,就打赏"
还没有人打赏,支持一下

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-5-18 14:54 , Processed in 0.226030 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表