Techniques for calling AutoCAD commands programmatically

It's quite common to want to call commands from one or other of AutoCAD's programming environments. While it's cleanest (from a purist's perspective) to use an API to perform the task you want, the quickest way - and the one which will appeal to the pragmatists (and the lazy) among us is often to call a sequence of commands. And there are, of course, a few places in AutoCAD where APIs have not been exposed, so scripting commands is the only way to achieve what you want.

Let's take the simple example of adding a line. Here's what you'd do from the different environments from a low-level API perspective:

  • LISP - create an association list representing the entity and then (entmake) it
  • VBA (or COM) - get the ModelSpace object from the active drawing and call AddLine (the COM API is probably the simplest in that respect)
  • .NET and ObjectARX - open the block table and then the model-space block table record, create a new line object and append it to the model-space (and to the transaction, if you're using them), closing the various objects along the way

Having first started coding for AutoCAD with LISP (for R10), I know that the simplest way to do what you want from that environment is to call the LINE command, passing in the start and end points:

(command "_LINE" "0,0,0" "100,100,0" "")

LISP is great in that respect: as you're not able to define native commands (only LISP) functions, it's perfectly acceptable to use it to script commands to do what you want, rather than rely on low-level APIs.

ObjectARX in particular has potential issues with respect to defining native commands calling commands, as AutoCAD is only "re-entrant" up to 4 levels. Without going into specifics, it's basically best to avoid calling commands using acedCommand() from ObjectARX, unless the command is registered as a LISP function using acedDefun().

While you do have to be careful when calling commands from VBA or ObjectARX, there are a few options available to you.

ObjectARX

  • ads_queueexpr()
    • This old favourite is intended to be used from acrxEntryPoint() to execute a sequence of commands after (s::startup) has been called from LISP (as you are not able to use acedCommand() from this context)
    • You need to declare it yourself (extern "C" void ads_queueexpr( ACHAR *);) before use
    • It has been unsupported as long as I can remember, but is widely-used and mentioned in the Tips & Techniques section of the ObjectARX Developer's Guide
  • AcApDocManager::sendStringToExecute()
    • This function has the advantage of a few more options being available as arguments, mainly around where to execute the string (which document, and whether it be activated), and whether to echo the string to the command-line
  • ::SendMessage()
    • This is a standard Win32 platform API and so can, in effect, be used to drive AutoCAD from an external client. It uses a structure to pass the string that is often a bit tricky to set up (it became a migration issue when we switched to Unicode, for example)
  • IAcadDocument::SendCommand()
    • This COM method is the only way (other than acedCommand() or acedCmd()) to execute a command synchronously from AutoCAD (and even then it may not be completely synchronous if requiring user input)
  • acedCommand()
    • This is the ObjectARX equivalent to (command), and is genuinely synchronous. Unfortunately (as mentioned earlier) there are issues with using it directly from a natively-registered command, so I'd recommend only using it from acedDefun()-registered commands (see the ObjectARX documentation and the below sample for more details)

VBA (some of which also applies to VB)

  • ThisDrawing.SendCommand
    • This is the same as IAcadDocument::SendCommand() from C++
  • SendKeys
    • This is just a simple technique to send key-strokes to the command-line
  • SendMessage
    • This is just the Win32 API mentioned above, but declared and called from VB(A)

So, now for some sample code...

ObjectARX sample code

The first can be dropped into an ObjectARX Wizard-defined project (I used Visual Studio 2005 and ObjectARX 2007). You'll need to make sure "COM-client" is selected and you name your project "SendingCommands" (or you search and replace to change the name in the below code to something you prefer).

The code creates points along a line (from 0,0 to 5,5), using different techniques to send the command to AutoCAD. I would, of course, use the proper ObjectARX APIs to do this (creating an AcDbPoint etc.) - I just used this as an example of a command that could be sent.

It creates the first point on load, using ads_queueexpr(), and defines commands (TEST1, TEST2, TEST3 and TEST4) for the subsequent tests (the last being an acedDefun()-registered command).

#include "StdAfx.h"

#include "resource.h"

#define szRDS _RXST("Adsk")

extern "C" void ads_queueexpr( ACHAR *);

//----- ObjectARX EntryPoint

class CSendingCommandsApp : public AcRxArxApp {

public:

  CSendingCommandsApp () : AcRxArxApp () {}

  virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {

    // You *must* call On_kInitAppMsg here

    AcRx::AppRetCode retCode =AcRxArxApp::On_kInitAppMsg (pkt) ;

    return (retCode) ;

  }

  virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt) {

    // You *must* call On_kUnloadAppMsg here

    AcRx::AppRetCode retCode =AcRxArxApp::On_kUnloadAppMsg (pkt) ;

    return (retCode) ;

  }

  virtual AcRx::AppRetCode On_kLoadDwgMsg(void * pkt) {

    AcRx::AppRetCode retCode =AcRxArxApp::On_kLoadDwgMsg (pkt) ;

    ads_queueexpr( _T("(command\"_POINT\" \"1,1,0\")") );

    return (retCode) ;

  }

  virtual void RegisterServerComponents () {

  }

public:

  // - AdskSendingCommands._SendStringToExecTest command (do not rename)

  static void AdskSendingCommands_SendStringToExecTest(void)

  {

    acDocManager->sendStringToExecute(curDoc(), _T("_POINT 2,2,0 "));   

  }

  static void SendCmdToAcad(ACHAR *cmd)

  {

    COPYDATASTRUCT cmdMsg;

    cmdMsg.dwData = (DWORD)1;

    cmdMsg.cbData = (DWORD)(_tcslen(cmd) + 1) * sizeof(ACHAR);

    cmdMsg.lpData = cmd;

    SendMessage(adsw_acadMainWnd(), WM_COPYDATA, NULL, (LPARAM)&cmdMsg);

  }

  // - AdskSendingCommands._SendMessageTest command (do not rename)

  static void AdskSendingCommands_SendMessageTest(void)

  {

    SendCmdToAcad(_T("_POINT 3,3,0 "));

  }

  // - AdskSendingCommands._SendCommandTest command (do not rename)

  static void AdskSendingCommands_SendCommandTest(void)

  {

    try {

      IAcadApplicationPtr pApp = acedGetIDispatch(TRUE);

      IAcadDocumentPtr pDoc;

      pApp->get_ActiveDocument(&pDoc);

      pDoc->SendCommand( _T("_POINT 4,4,0 ") );

    }

    catch(_com_error& e) {

      acutPrintf(_T("\nCOM error: %s"), (ACHAR*)e.Description());

    }

  }

  // ----- ads_test4 symbol (do not rename)

  static int ads_test4(void)

  {

    acedCommand(RTSTR, _T("_POINT"), RTSTR,_T("5,5,0"), RTNONE);

    acedRetVoid();

    return (RSRSLT);

  }

} ;

// ----------------------------------------------------------

ACED_ARXCOMMAND_ENTRY_AUTO(CSendingCommandsApp, AdskSendingCommands, _SendStringToExecTest, TEST1, ACRX_CMD_TRANSPARENT, NULL)

ACED_ARXCOMMAND_ENTRY_AUTO(CSendingCommandsApp, AdskSendingCommands, _SendMessageTest, TEST2, ACRX_CMD_TRANSPARENT, NULL)

ACED_ARXCOMMAND_ENTRY_AUTO(CSendingCommandsApp, AdskSendingCommands, _SendCommandTest, TEST3, ACRX_CMD_TRANSPARENT, NULL)

ACED_ADSCOMMAND_ENTRY_AUTO(CSendingCommandsApp, test4, true)

// ----------------------------------------------------------

IMPLEMENT_ARX_ENTRYPOINT(CSendingCommandsApp)

VBA sample code

This sample defines VBA macros that create points from 6,6 to 8,8, using techniques that mirror the ones shown in the ObjectARX sample.

Option Explicit On

Private Const WM_COPYDATA = &H4A

Private Type COPYDATASTRUCT

    dwData As Long

    cbData As Long

    lpData As String

End Type

Private Declare Function SendMessage Lib "user32" Alias _

  "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal _

  wParam As Long, ByVal lParam As Any) As Long

Public Sub SendMessageToAutoCAD(ByVal message As String)

    Dim data As COPYDATASTRUCT

    Dim str As String

    str = StrConv(message, vbUnicode) 'converts to Unicode

    data.dwData = 1

    data.lpData = str

    data.cbData = (Len(str) + 2)

    SendMessage(ThisDrawing.Application.hwnd, WM_COPYDATA, 0, data)

End Sub

Public Sub Test4()

    ThisDrawing.SendCommand("_point 6,6,0 ")

End Sub

Public Sub Test5()

    SendKeys("_point 7,7,0 ")

End Sub

Public Sub Test6()

    SendMessageToAutoCAD("_point 8,8,0 ")

End Sub

  1. Isn't this what the labs demonstrate? 🙂 Just wondering about the target group of people of this blog.

  2. Hi Stephan,

    Thanks for your comment, but I'm not sure what you mean...

    1) Which labs?
    2) Do you mean this specific entry or the blog as a whole?

    Regards,

    Kean

  3. Alexander Rivilis Avatar
    Alexander Rivilis

    Hi, Kean!
    Additional methods:
    1) int acedPostCommand(char const *cmd);
    2) PostMessage() to commandline window - useful in order cancel active command from external application: autocad.ru/cgi-b...

  4. Hi Alexander,

    Thanks - these two are also definitely worth mentioning, and - as I'm sure you're aware - both are useful for cancelling running commands that have paused for user input.

    Please keep the comments coming! 🙂

    Kean

  5. Thanks for the helpful information.

    As one that has been using acedCommand() and acedCmd() via P/Invoke for some time with great success, I don't think its entirely fair to discourage the use of these APIs from registered command handlers, only because the specifics relating command level nesting were left out.

    Perhaps a better strategy would be to get into those specifics, to help readers understand the limitations and caveats of the use of these APIs.

    For most practicle purposes, where the need is to execute a built-in AutoCAD command like PEDIT or what have you, and where there is little or no potential that others will attempt to script the registered command via the same API or the LISP (command) function, there is little danger that the command depth nesting limit will be reached.

    But there are also other issues relating to the use of acedCommand() which wasn't covered in your article, that can also result in problems when that API is improperly used from the handler of a registered command. Namely, any command which is scripted via calls to acedCommand(), must be exited before the handler that calls acedCommand() exits. Failing to do that usually results in a fatal condition.

    Another somewhat obscure issue relating to the use of all the various asynchronous methods you covered, is that their use can often corrupt or disable undo and/or redo, and prevent the user from redoing an operation that've undone. This usually occurs when attempting to use one of the asynchronous methods to execute commands that involve user interaction via the command line.

    The files below provide convienent wrappers for acedCmd(), that allow those whose needs are relatively simple to avoid the hideous issues that plague all of the asynchronous forms of command execution, and thanks for covering some of the issues relating to the use of acedCommand from registered command handlers.

    caddzone.com/Com...
    caddzone.com/Com...

  6. Kean,

    Sorry for the double post, I mistakenly posted this comment in the wrong topic earlier.

    Anyway to repeat the question: Is there a way to send a command from VBA to command line, such that you call a lisp interface exposed through ARX which takes some input parameters too?

    For example: I have a function written in ARX that is exposed through LISP. So you can type on command line (doSomethingWithThisFunction selectionset name)

    where:
    doSomethingWithThisFunction is the name of function exposed through LISP interface from ARX

    selectionset is an AutoCAD selectionset

    name is just a string

    Problem is when I use ThisDrawing.SendCommand () from VBA it treates the LISP function and its arguments as three separate commands

    To sum it up I need to be able to call a command line function from VBA, such that the function also takes some parameters.

    Is that possible?

    Thanks

  7. Vector,

    This is altogether possible: you just need to format the SendCommand() string appropriately. Make sure you use an opening parenthesis and pass the quotes for the string (and probably an apostrophe before the variable name containing the selection set).

    The other option is to expose your function as a command that gets the selection set (which you would now pass with an exclamation mark: "!") and the string using acedSsGet() and acedGetString().

    Regards,

    Kean

  8. Kean,

    I tired using send command using the following syntax in VBA

    Dim objNewSS As Object

    objNewSS.SelectOnScreen

    Dim tagNum As String
    tagNum = "UDE-121"

    strincom = "(at_UserDefinedFromSelSetAndTag 'objNewSS tagNum)" & vbCr

    ThisDrawing.SendCommand strincom

    When I do that I get the following error on the command line.

    "; error: invalid data type or data overflow: OBJNEWSS"

    Remember that this function is working perfectly from LISP when I do the following

    (setq OBJ_SS (ssget) ; pick objects one at a time
    NDX 0
    )
    (if OBJ_SS
    ;; if there is a selection set, do...
    (progn
    (while (< NDX (sslength OBJ_SS))
    (setq OBJ (ssname OBJ_SS NDX)
    NDX (+ NDX 1)
    )
    (setq tagnum "UDE-121")
    (at_UserDefinedFromSelSetAndTag OBJ_SS tagnum)
    )
    )
    ;; otherwise, no selection set
    (progn
    (alert "Nothing selected.\nExiting.")
    (exit)
    )

    Could it be that the send command can only process data of type string and has no clue what a selection set type, or an object type means? Any help would be appreciated.

    Thanks,
    Vector

  9. Kean Walmsley Avatar

    Vector,

    Your problem is that you're trying to pass VBA-defined variables by name through LISP to ObjectARX. Unlike with LISP symbols, VBA variable names are not exposed to AutoCAD itself - neither LISP or ObjectARX will understand them.

    For the string argument, this is easy - just change your code to this:

    strincom = "(at_UserDefinedFromSelSetAndTag """ + tagNum + """)" & vbCr

    For the selection set, it's trickier. The simplest is probably to use acedSsGet("P") from your ObjectARX application to pick up the most recent selection set. Otherwise it gets very diffidult (another option would be to use COM client code in your ObjectARX app to query the contents of a named selection set in VBA).

    Speaking of named selection sets - I assume you've simplified out a line such as this from your code:

    Set objNewSS = ThisDrawing.SelectionSets.Add("SS")

    Regards,

    Kean

  10. Kean,

    I tried another approach. It worked partially

    Set objNewSS = ThisDrawing.SelectionSets.Add("SS")

    Then used
    strincom = "(at_UserDefinedFromSelSetAndTag objNewSS.Name tagNum)" & vbCr

    ThisDrawing.SendCommand strincom

    This worked and I could get access to "SS" name entity in ARX. However, when I tried to get selection set in the ARX, using the resbuf filter, it fails to get the selection set. For example

    struct resbuf rb;

    rb.restype = 0; // Entity name filter
    rb.resval.rstring = EName; //Ename is coming
    //fromVBA properly
    rb.rbnext = NULL;

    if (ads_ssget("_X",NULL, NULL, &rb, selSet) == RTNORM)
    {
    The check fails and the code won't execute here
    ---
    ---
    ---
    }

    Now what?!?! Any Ideas?

  11. Kean Walmsley Avatar

    Vector,

    That's why I didn't suggest it: the "SS" name doesn't correspond to a symbol that's accessible from LISP or ObjectARX (that I can tell). Your best bet is to omit the argument altogether and rely on the previous selection, as I suggested (hopefully that's an option for you). Otherwise things get messy.

    Kean

  12. Kean,

    I tried another approach and it solved my problem. I am posting it here for the benefit of other users.

    VBA doesn't expose a handle for the AcadSelectionset object, that's true. This is kind of a sticky area that makes for some messy code. There are a couple of other options, but they basically require doing most of it in lisp, either having code execute from the lisp environment, or running lisp from vba.

    In the lisp you can access the activex SS. For example, in VBA create your
    SS and name it "SSforLisp". Then in lisp:

    (vl-load-com)
    (setq ss-vba (vla-item
    (vla-get-selectionsets
    (vla-get-activedocument
    (vlax-get-acad-object)))
    "SSforLisp"));; gets the ActiveX SS
    (setq ss-lisp (ssadd));;creates a new ename-based ss
    (vlax-for ent ss-vba
    (ssadd (vlax-vla-object->ename ent) ss-lisp)
    );;add each object's ename to the ename-ss

    Thanks,
    Vector

  13. Vector,

    Great - glad you found a solution!

    This is basically the approach I meant when I said "(another option would be to use COM client code in your ObjectARX app to query the contents of a named selection set in VBA)."

    My assumption was that you were working in C++, but this is essentially the same technique from LISP.

    Kean

  14. Hi
    I am try to create a selection select in vb and then use the sendcommand function to run a autocad command and pick the selectionset created in vb as the previous selectionset.
    I do not seem to be able to get the selectionset created in vb to be the previous set. Do you have any ideas how to do it for pass a selectionset from vb to a command with the send command.

    Sub Example_SelectwithVB()
    ' This example adds objects to a selectionset with vb

    On Error Resume Next

    'SSetColl.Item("CURRENT").Delete
    ThisDrawing.SelectionSets.Item("TEST_SSET").Delete

    ' Create the selection set
    Dim ssetObj As AcadSelectionSet
    Set ssetObj = ThisDrawing.SelectionSets.Add("TEST_SSET")

    ' Add objects to a selection set by prompting user to select on the screen
    'ssetObj.SelectOnScreen

    ' Iterate through the model space collection.
    ' Collect the objects found into an array of objects
    ' to be added to the selection set.
    ReDim ssobjs(0 To ThisDrawing.ModelSpace.Count - 1) As AcadEntity
    Dim I As Integer
    For I = 0 To ThisDrawing.ModelSpace.Count - 1
    Set ssobjs(I) = ThisDrawing.ModelSpace.Item(I)
    Next

    ' Add the array of objects to the selection set
    ssetObj.AddItems ssobjs

    ssetObj.Update

    ThisDrawing.Regen acActiveViewport

    MsgBox "A new SelectionSet called " & ssetObj.Name & " has been added to the SelectionSets collection.", vbInformation, "SelectionSets Example"

    'Once the selectionset has been created in the previous code in vb it becomes the previous
    'selectionset at the command line and can be accessed with the select p enter enter series
    'of commands

    ThisDrawing.SendCommand "AecIsolateObjects" + vbCr
    ThisDrawing.SendCommand "P" + vbCr + vbCr

    End Sub

    Regards

    Justin

  15. Hmm... SelectOnScreen will modify the previous selection set (as it's using AutoCAD's selection process), but selection sets created programmatically do not.

    In this case, I'd suggest either using SelectOnScreen (which is probably not what you need), or sending a much more complex text string to the command lines, one that contains a LISP command using (ssget "X") to select the various entities you want and save the selection set in a LISP variable. You should then be able to plug this into AecIsolateObjects using "!ss".

  16. hi there

    I have been scripting by using VBA for sometime. is there any other language(s) other than lisp. how about CSharp ? it it possible to write a code and use with Autocad as we do with VBA?

    thanks

  17. hi kean

    I am facing problem with VBA System when ever i am
    opening a cad drawing there is message is coming
    "VBA System... execution error execution error.

    please find some solution

    thanks
    awes

  18. Hi Awes,

    Sorry - it's not clear to me what the problem is. I suggest posting a more detailed description to the AutoCAD Visual Basic Customization Discussion Group.

    Regards,

    Kean

  19. hi kean

    regarding "VBA System... execution error execution error.
    I think it's a computer virus that is stored in the macros of a vba project. if we open a drawing that contains this virus, a virus can become active and be transmitted to your computer.
    from that point on, every drawing file you save can become infected with the virus. when other users open the infected drawing file, the virus can also be transmitted to their computers. so when ever we open any drawing file this execution error comes before starting the drawing and then it's normal. I want to remove this message, i tried antivirus but it's not detacting. please find some solution and advice.

  20. This sounds unlikely - I've never come across an AutoCAD VBA virus (but there's a first time for everything, I suppose).

    This isn't really the right place to get help on this: I suggest contacting your reseller, or otherwise someone on the discussion group I mentioned in my last comment.

    Kean

  21. Has anyone successfully been able to replicate and port this to VB.NET and been able to run it on Vista? Been struggling for hours without being able to send a WM_COPYDATA using SendCommand with a COPYDATASTRUCT to AutoCAD. Any ideas or samples would be highly appreciated.

    Thanks!

  22. dear kean.
    I found you as a professional programmer so I believe thats a good idea to consult with you. I am going to filter the points of the dwg file using selectionsets and select function. the problem is that i am going to filter them by symbol ( as an example select those points which have symbol tree. but i find no groupcode to filter it. I have got no Idea how to do it. I will really be grateful if you give me a hint.

  23. by the way i forgot to mention i am using vba

  24. Kean Walmsley Avatar

    Shahin - please post your questions to the discussion groups, or via the ADN website, if you're a member. I don't have the luxury of spending time providing specialised support for people, unless it's very much related to a post of mine.

    Kean

  25. How can i call superhatch command with all input paramters using vb.net? I just don't want to prompt the dialog boxes of superhatch to get inputs from user. I want to provide it programmatically.
    For eg: similar to this
    doc.SendCommand("_superhatch par1,par2.....")

    For rectangle, its :
    doc.SendCommand("_rec 10,10 20,20")

    But dont know the fromat to pass parameters for superhatch.
    Can anybody help me on this?

    Thanks,
    Sandip

  26. Sandip,

    Judging from your email address, you work for an ADN member, so I suggest posting your questions to the ADN website, in future.

    Superhatch is an old Express Tool that doesn't appear to provide a command-line version.

    The source is in the Express folder (sprhatch.lsp and sprhatch.dcl). The simplest thing would be to use the LISP source for your own custom function implementation.

    Kean

  27. hi kean

    I am facing problem with VBA System when ever i am
    opening a cad drawing there is message is coming
    "VBA System... execution error execution error.

    please find some solution

    Thanks,
    baidas

  28. Kean Walmsley Avatar

    baidas,

    This is not a support forum. I suggest submitting your question via ADN (if you're a member) or posting to one of the Autodesk Discussion Groups.

    Kean

  29. Hi Kean,

    Is there a way to send a command to autocad while in a sub routine. I made a VB.net addin to batch print drawing. For each drawing being plot i want to execute a lisp file before and after the plot. The problem is that the command isnt execute at the right time. In the example below the command "TEST" is execute after the MsgBox (well when the sub is completed)

    p.s. I also tried with ads_queueexpr, acedInvoke and SendStringToExecute and it's the same result


    Private sub Batch ()

    'the Test function show message box
    acedPostCommand("Test ")
    MsgBox("Hello!")

    end sub

    Thank you

  30. Those are all asynchronous calls... have you tried SendCommand() through COM?

    Kean

  31. Thank you very much, this is exactly what i need!

  32. Hi,
    This might be a trivial question.
    In the code I want to draw a polyline by selecting points on the screen interactively. When I call: ThisDrawing.SendCommand "_3DPoly" & vbCr, the execution does not stop and wait for the polyline to be entered but runs to the end.
    Could you suggest me what to do to make program pause until the user finishes input?
    Thanks

  33. You could use (command "_3DPOLY" pause pause "") for a fixed number of segments (in this case a single segment between two points).

    Stopping for an arbitrary number of picks is harder: you might need a custom command to drive the 3DPOLY command and then pass execution off to another, at the end.

    Bear in mind this is mostly thinking about the behaviour of SendStringToExecute(), rather than SendCommand().

    Kean

  34. Hello!

    Maybe it is stupid question 🙂 I'am beginner 🙂

    I have a function in LISP. It's name "ReadFile".
    In AutoCad's command line I use it, by writing:

    (ReadFile "c:\file.txt").

    Now, I have a ObjectArx application.
    I can invoke simply commands like _circle from ObjectArx application:

    acedCommand(RTSTR, _T("_circle"), RTSTR, _T("10,10"),RTSTR , _T("10") ,RTSTR, _T(""), 0);

    but I don't know how to invoke: (ReadFile "c:\file.txt") ?

    Best regards!
    Peter

  35. Try looking at acedInvoke().

    Kean

  36. I'm having trouble implementing a SendMessage procedure in C#. The following code compiles but nothing is received by AutoCAD. Any advice would be appreciated. Thanks.

    [DllImport("user32.dll")]
    private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);

    private struct COPYDATASTRUCT
    {
    public int dwData;
    public int cbData;
    public string lpData;
    }

    private const int WM_COPYDATA = 0x4A;

    public static AcadApplication AcadApp = null;

    public bool SendCmd(string cmd)
    {
    // AcadApp must be preset by caller
    IntPtr AcadHand = (IntPtr)AcadApp.HWND;
    IntPtr wParam = IntPtr.Zero;
    COPYDATASTRUCT cds;
    cds.dwData = 1;
    cds.lpData = cmd;
    cds.cbData = cmd.Length + 1;
    return (SendMessage(AcadHand, WM_COPYDATA, wParam, ref cds) != 0);
    }

  37. Hi Peter,

    There should be a number of examples on this blog (just search for "WM_COPYDATA").

    If those don't help, please contact ADN or post your question to the AutoCAD .NET Discussion Group.

    Regards,

    Kean

  38. Thanks. The samples here work very nicely:
    keanw.com/user_interface/page/3/

  39. Hello!
    Thank You for your last ansver. acedInvoke() is working very nice 🙂

    I have a another problem 🙂

    I create dinamicaly a resbuf for acedInvoke().

    I have a string into CString variable.

    When I create new element of resbuf I want to pass this string into resval.rstring. I can't do this!! 🙁

    My code:
    pTail = pTail->rbnext = acutNewRb(RTSTR);
    pTail->resval.rstring = ...string_from_CString_Variable;

    I have tried, for example:

    USES_CONVERSION;
    CString str2(_T("HELLO!!!"));
    wchar_t* wstr_name = T2W(str2.GetBuffer());
    ....and..
    pTail->resval.rstring = wstr_name;

    but in autocad i achive tekst "Propeties" instead of "HELLO!"

    🙁

    Could You help me?

  40. Hello Peter,

    Sorry - this is beyond me. I expect you need to use something like acutStrDup() (if such a thing exists - I haven't checked). You might try posting your question to the ObjectARX Discussion Group.

    Regards,

    Kean

  41. Hi Kean,

    "ObjectARX in particular has potential issues with respect to defining native commands calling commands, as AutoCAD is only "re-entrant" up to 4 levels. Without going into specifics..."

    Could you explain in lamens terms what you mean by re-entrant command calling in AutoCAD?

    I see the words but I have not the foggiest clue what this is about 🙂

    Art

  42. Does this mean that a command that calls a command that calls a command that calls a command can't call another command? 🙂

  43. Exactly (although it may mean one more level - not sure about that :-).

    Kean

  44. Hi Kean,
    Is it possible to view Autocad drawing in trueview programmatic-ally in VB 6.0

  45. Yes, although it depends on what exactly you mean. You should be able to embed a TrueView control in a VB6 form and then use the control's properties to load a drawing.

    BTW - this is way off topic for this post. Please post questions via our discussion forums in future (forums.autodesk.com).

    Kean

  46. Hi Kean,

    Now that 64bit VBA is again available, I'm trying to upgrade your SendMessage method. I'm working in ACAD 2015.

    I have tried using the new data types but cannot get it to compile:

    Private Const WM_COPYDATA = &H4A

    Private Type COPYDATASTRUCT
    dwData As LongPtr
    cbData As Long
    lpData As String
    End Type
    '''''
    '''''
    Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
    (ByVal hwnd As LongPtr, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Any) As Integer
    '''''
    '''''

    Public Sub SendMessageToAutoCAD(ByVal message As String)

    Dim data As COPYDATASTRUCT
    Dim str As String
    Dim test As String

    str = StrConv(message, vbUnicode) 'converts to Unicode

    data.dwData = 1
    data.lpData = str
    data.cbData = (Len(str) + 2)

    SendMessage ThisDrawing.Application.hwnd, WM_COPYDATA, 0, data

    End Sub

    It throws a compile error: type mismatch for the data argument.
    Has something changed in VBA 7.1 to prevent this method? Or am I simply not getting the new 64bit data types right?
    Thanks,
    Dave

    1. Hi Dave,

      I suggest checking pinvoke.net, to see whether there's information there that can help:

      pinvoke.net/defa...
      pinvoke.net/defa...

      Regards,

      Kean

  47. Hi, Kean,
    Awesome post.
    I have a requirement of reading points from another application which would send points to Autocad.
    I am stuck at reading points: On clicking Line button, Autocad is waiting at below line, here the points are read from another application.
    Specify first point:

    In the readsocket: when used below
    1:SendCmdToAcad : reads only 1st point and control stucks,
    2:acedCommand(RTSTR, _T("_POINT"), RTSTR, _T("308923.54867,458923.54867,50,0 ") , RTNONE);:crashes
    3:acDocManager->sendStringToExecute(curDoc(),_T("_POINT 2,2,0 ")); :crashes

    Any pointer would be greatly appreciated.
    Thanks

    1. You need to look up a few posts on calling AutoCAD commands from another process. If you can't find them, please post to the AutoCAD .NET forum.

      Kean

  48. please guide me to automatically execute a command when a new entity is added on autocad drawing

  49. I saw your name while reading ObjectARX 2000 Developer's Guide

    1. Yes, I've been around for a while.

Leave a Reply to kannan Cancel reply

Your email address will not be published. Required fields are marked *