For this release, we’ve re-architected AutoCAD to completely strip out the use of Fibers and Fiber switching. Fibers are an old technology used in Windows that Microsoft stopped supporting several years ago. AutoCAD made heavy use of fibers and they are what allowed users to switch easily between drawings without interrupting commands. You’ve probably all seen this in action in old versions of AutoCAD – start a LINE command in one drawing, switch to another and draw a CIRCLE, then switch back to the first drawing and the LINE command is still active.

But using fibers was causing a lot of problems for us that we were spending more and more effort working around. For example, the .NET Framework has never supported Fiber Switching, and this is why when you switched documents in AutoCAD when debugging a .NET application, you’d often find that Visual Studio would fail to stop at a breakpoint– or it did break, but couldn’t display your code. That was Visual Studio getting confused by AutoCAD switching Fibers. You won’t experience that problem in Longbow now that we’ve removed Fibers. It also allows us to expose more of the ObjectARX SDK to .NET – the most exciting of which is that we now have a .NET version of acedCommand ((command) in LISP). That wasn’t possible before due to the problems caused by Fibers.

Migration in ObjectARX

That means ObjectARX has more significant migration requirements. There are two migration areas of concern: the MDI API and use of acedCommand/acedCmd. Then you’ll have to make changes. How big a change depends on how you’re using it.

If you’re passing a complete set of command tokens to the AutoCAD commandline, then all you have to do is add an ‘S’ to the end of acedCommand or acedCmd. S stands for subroutine. This is when you’re sending an entire command, and not pausing for user input.

If you’re sending a PAUSE, or if you’re sending an incomplete set of command tokens (for example starting a line command and leaving it for the user to finish) then you have a lot more work to do. In this situation, you’ll be using acedCommandC – the coroutine version of the command – and you’ll now have to pass a pointer to a callback function as a command parameter. It’s a lot more complicated – so much so that you might even consider migrating your code that needs this to .NET instead.

Here’s an example of the most basic acedCommand usage – its also the most popular use case – where we’re invoking a complete command in a single call to acedCommand. All you have to do here is change acedCommand to acedCommandS.

void foo(void)

{

acedCommandS(RTSTR,

_T("_Line"),

RTSTR,

_T("0,0"),

RTSTR,

_T("111,111"),

RTSTR, _T(""),

RTNONE);

acutPrintf(_T("\nFinished LINE command - \control returned to addin\n"));

}

But a lot of people use acedCommand like this. Starting a command and then prompting for user input until the command ends. In this case we’re starting the LINE command and issuing PAUSEs to allow the user to keep drawing additional line segments. When we migrate this code for Longbow, we have to use acedCommandC, because acedCommandS doesn’t support partial command token stacks or PAUSEs.

void foo(void){

//Invoke partial command and leave command active.

acedCommandC(RTSTR,

_T("_Line"),

RTSTR,

_T("0,0"),

RTSTR,

_T("111,111"),

RTNONE);while(isLineActive())

acedCommandC(RTSTR,

PAUSE,

RTNONE); acutPrintf(_T("\nFinished LINE command - \

control returned to addin\n"));

}

The migrated code will look something like this. We’ve defined a callback function, which we pass to acedCommandC. Now when AutoCAD is ready to pass control from the user back to you, it will do so by calling the callback function you provided. In this example, the callback function keeps passing itself as a callback until the command ends. If the user cancels the command you invoked using acedCommand, then AutoCAD will also cancel your command that called it. Otherwise, control is handed back to your code when the command invoked by acedCommand ends.

void foo(void){

//Invoke partial command and leave command active.

acedCommandC(&myCallbackFn,

NULL, RTSTR,

_T("_Line"),

RTSTR,

_T("0,0"),

RTSTR,

_T("111,111"),

RTNONE);

//Control is passed to myCallbackFn1 from AutoCAD

}

//Your callback functionint myCallbackFn(void * pData){

int nReturn = RTNONE;

//Keep command active until user ends it.

if (isLineActive())

nReturn = acedCommandC(&myCallbackFn,

NULL, RTSTR,

PAUSE, RTNONE);

else

{

//This is never reached if the user cancels the command –

// that cancels your command as well.It is reached if command is ended

//(e.g. by hitting ENTER)

acutPrintf(_T("\nFinished LINE command - \

control returned to addin\n"));

}

return nReturn;

}

Migration in .NET

I would say the most exciting new API in Longbow is the introduction of .NET versions of acedCommand ((command) in LISP). This hasn’t been possible before because of AutoCAD’s use of Fibers – and because the .NET Framework doesn’t support Fibers. So these new APIs – synchronous and asynchronous versions of acedCommand – are now possible for the first time.

acedCommand is probably the most powerful API in ObjectARX. It allows you to embed entire AutoCAD commands within your own commands; and even to invoke partial commands, and then programmatically respond to how the user interacts with those commands. This saves ObjectARX and LISP developers a huge amount of work where otherwise they’d have to reproduce all the native command behavior in their own code – and now .NET developers get the same benefit.

The synchronous version of Command is Editor.Command, the equivalent of the subroutine version of acedCommand. This is how you invoke a complete command from your code. As you can see, the code is very similar to the ObjectARX version – you pass a full set of command tokens to the AutoCAD commandline (the editor), AutoCAD completes the command and immediately returns control back to your code.

//simple use of Editor.Command

//most popular case - invoke a whole command with no user interaction

[CommandMethod(“MyCommand")]

publicstaticvoid MyMethod()

{

Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

ed.Command(newObject[] {

"_.LINE", "0,0,0", "10,10,0", "" });

}

There is also the asynchronous version of Command Editor.CommandAsync. This is the equivalent of the coroutine version of acedCommand. You’ll recall that acedCommandC required you to pass in a reference to a callback function. The .NET version is a little simpler. Because we’re using .NET Framework 4.5, we can make use of the async and await keywords to greatly simplify our asyncronous code. We mark our .NET commandmethod with the async keyword, and we can then use the await keyword inside that method. The await keyword tells AutoCAD where in your code to return control to after it has finished gathering user input. In this example, we’re simply starting the circle comamnd, using a PAUSE to let the user specify the circle center, and then specifying the circle radius in our code.

03/18/2014

QuestionI'm trying to change DIMPOST to \X in a lisp routine. The program will not accept \X in a lsp program. I'm want to change Dimstyle using the set up; Method set to NONE for both primary(Metric) and alternate units(English) and alternate unit placement under the primary units. I can do this manually but not in the lisp.

Solution With these Lisp statements, the dimension formatting were as requested by the developer :

<<<

; To reset the alternative dimension prefix and suffix

(command-s "DIMAPOST" ".")

; To reset the primary dimension prefix and suffix

(command-s "DIMPOST" ".")

; To set the orientation of the alternative dimension over the primary dimension

08/21/2013

AutoCAD API provides AcEdInputPointManager.Inputpointmonitor which can monitor any input of the user, including mouse. API also allows you to monitor Windows message. Sometimes you may just need to get the current mouse position without any event. The following is code demo. Actually, it just get the current cursor position and convert it to AutoCAD coordinate. It also takes UCS into consideration.

;;; The following code will not work, do not use it. ;(setq RecordSetObject ;;; The following fails with a "Type mismatch" error ; (vlax-invoke-method; ConnectionObject "Execute" SQLStatement 'RecordsAffected ; adok-adCmdText ; ); )

;;; Close only works if it's Opened !, this can usually be tested by checking if a LDB file exists. ;;; Check to see that the Connection Object is open here -> (setq coState (vlax-get-property ConnectionObject 'State))(if(and (findfile (strcat MDB_File ".ldb"))(= coState adok-adStateOpen))(vlax-invoke-method ConnectionObject "Close")(princ"\nConnection Object is not Open, please delete the LDB file if needed."))(Clean_Up));;; Exit if Type Library has NOT been loaded. (progn(alert(strcat"Exiting - Type Library was Not Loaded: \"" ADO_DLLPath "msado15.dll\""))(exit))))

03/28/2013

There are two ASILISP functions that help here. Both return cursors to system tables so you can step through the records to find what you need. For example, this code will return all the available providers:

Issue Can I gain access to the "Open File Dialog" (with preview) found only in AutoCAD with VBA?

Solution You can do this through the communication interface with AutoLISP and AutoCAD. The AutoLISP function, getfiled, behaves as the AutoCAD "Open File Dialog" and allows .DWG files to be previewed.

;;; Get a linkTemplate named "EmployeeLink1", This linkTemplate ;;; can be created from the Employee table in the DB sample that ships with ;;; AutoCAD (setq LT (vlax-invoke-method LTs "Item""EmployeeLink1"))

Issue I can't close documents using the closeDocument API from an CAdUiDialog derived dialog because AutoCAD reports that the documents are busy. Why does this occur?

Solution Make sure that you call the closeDocument API from the application context (see the executeInApplicationContext API). Once you do that, you must also enable document activation (enableDocumentActivation API). CAdUiDialog disables document activation in its DoModal override. As a result, AutoCAD cannot close documents when document activation is disabled.

The reason CAcUiDialog does this is that when you prompt for user input from your dialog then you re-enable the main frame thus giving a chance to the user to change the active document... CAcUiDialog tries to prevent this scenario.