PDA

View Full Version : Getting the last command typed from AutoCAD via .NET program



ChristinaSeay
31st Aug 2010, 02:25 pm
Hello,

I am trying to get the last command typed from AutoCAD via a VB.NET program. Does anyone know how to do that... or a better way possibly to achieve this:

User Types "B1" on the command line, which uses a lisp routine to launch program A and put a Purchased Balloon on the drawing.

User Types "B2" on the command line, which uses a lisp routine to launch program B and put an Assembly Balloon on the drawing.

What I'd like to be able to do is to make programs A and B into a single program, X, and then when the user types "B1", launch program X and put a purchased balloon on the drawing, and when the user types "B2" launch program X again, but put an Assembly Balloon on the drawing.

Is this possible?

BlackBox
31st Aug 2010, 06:09 pm
Without having more detailed information, the short answer is YES... it is possible.

More specifically though, you potentially require the source code for programs A and B.

If you do not have the source code, then you might consider using a reactor.

Sidebar: You have not specified which application you're using, but if this is simply a series of commands to insert some blocks, then why not use LISP instead?
(Does not apply to non-ActiveX API applications)

Hope this helps!

ChristinaSeay
31st Aug 2010, 06:51 pm
I have the source code for everything since I wrote it all, so that won't be a problem.

The programs A and B are doing a lot more than just inserting a block into AutoCAD, so doing them in AutoLisp just isn't feasible, and VBA would be doable, but significantly more complicated... especially since the programs have already been written in .NET.

I think if there were some way to determine the last command entered in AutoCAD, that would probably give me what I need. Then I could launch program X no matter if the user types B1 or B2 and then the first thing X would do is to determine what the user typed last into AutoCAD to determine if they wanted a Purchased Balloon or Assembly Balloon... if that makes sense...?

BlackBox
31st Aug 2010, 07:18 pm
Yes that make perfect sense.

Would it not be simpler to add a condition to the beginning of program X, which seeks global variables defined at the end of programs A and B respectively?

For example:

If you were to run Program A, once complete, define variable *prgA* = True.
If you were to run Program B, once complete, define variable *prgB* = True.

In this case, when you run program X:

if *prgA* /= True, then run program A
if *prgB* /= True, then run program B

Make sense?

Note - Please forgive my lack of .NET syntax, as I am relegated to working with Visual LISP only at work.

ChristinaSeay
31st Aug 2010, 07:46 pm
What I'm trying to go for is that there wouldn't be a Program A and Program B anymore... they would be combined into one Program X. (There are actually about 15 different programs that will combined into Program X.)

Currently the drafters are used to working with shortcuts on the command line and they want to keep those versus just popping up a form with all the options on it. So that leaves me forced to maintain 15 separate programs that have a lot of similar code in them and would be soooo much cleaner and easier for me to maintain as one program.

I wish I was stuck with one language... it would make it easier. The company I work for is more of the opinion that I should do whatever in whatever language it takes so long as it works... lol

BlackBox
31st Aug 2010, 08:08 pm
Conceptually speaking, let's consider Toolbox functions...

Instead of duplicating segments of code among your 15 separate programs, is it not possible to pick out a few representative segments and make a single toolbox function for each of those specific, repeated tasks?

For example:

If you repetitively need to extract the layer of an item, you make a toolbox function that does nothing but that, provided an argument (where the argument is the object, or reference item the layer is being extracted from). In the middle of your program, when you need the layer of an object, simply call that toolbox function.

As another example, I have a toolbox function that does nothing but return the blocks collection of my active drawing, as this can be updated within a command. Sort of like a snapshot, if you will. I can store this function (as it returns a snapshot) to a variable, within my current program.

I am speaking conceptually, and lacking .NET code for these examples, so I hope I am making sense...?

ChristinaSeay
31st Aug 2010, 08:39 pm
What you're saying makes perfect sense... but I'm not repeating AutoCAD functions... my programs are connecting to our ERP system, our drawing database program, our file vault system, etc.... so toolbox functions wouldn't save much effort.

BlackBox
31st Aug 2010, 08:42 pm
Sorry I could not be of more help.

ChristinaSeay
31st Aug 2010, 08:49 pm
Thanks for trying though!! I'm sure someone else will find all your information really helpful for another project.

BlackBox
31st Aug 2010, 08:50 pm
That is very kind of you, my friend. :)

stmoong
1st Sep 2010, 08:32 am
Hi, just wondering, if your program X is going to be in .Net, can you skip the Lisp routine and just call the appropriate method in your .Net program directly? Just need to netload it on startup.

You could implement design pattern such as strategy pattern to take advantage of the object oriented methodology, or use procedural methods (if-else, switch-case) to call the appropriate methods based on user input on command line.

ChristinaSeay
1st Sep 2010, 03:42 pm
It sounds like you've got the right idea for what I'm trying to accomplish, but I'm not sure how to do exactly what you're saying... Can you elaborate on it a bit...?

stmoong
1st Sep 2010, 04:05 pm
Hi, I'm not sure if you already know how to set up the AutoCad project in Visual Studio. In case you don't, here are the steps you can take.

1) Download the appropriate ObjectArx SDK from AutoCad website (http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=773204). You need to download the correct SDK for the different version of AutoCad.

2) Either download the documentation or view it online from here (http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=1911627#section8).

The documentation will give you an idea how to set up a project in Visual Studio. There are also sample codes that you can work with to get a feel on how the methods are called via the command line in AutoCad.

ChristinaSeay
1st Sep 2010, 04:19 pm
I've been programming to AutoCAD for a while, but I haven't used the ObjectARX method because we're using so many different versions of AutoCAD and it isn't available for some of the versions. Instead, I made my projects where they include a late-binding reference to AutoCAD so one program can communicate with all the versions.

We have AutoCAD 2002 Standard, 2010 Standard, 2010 Electrical, 2009 Standard and 2009 Mechanical.

stmoong
1st Sep 2010, 04:42 pm
I'm not familiar with Lisp.

If purely on OO programming, you could use the strategy pattern (http://www.dofactory.com/Patterns/PatternStrategy.aspx). Basically, you declare an interface. Your various programs will be a concrete class that will implement this interface.

I assume you are able to pass in some value when your Lisp routine calls the .Net application. In order for your program X to know what concrete class to instantiate, you could use a factory pattern (http://www.oodesign.com/factory-pattern.html), which takes in the value and instantiate the right concrete class (your program A, B, C, etc).

Then, your main program X will just call the generic interface method.

ChristinaSeay
1st Sep 2010, 05:00 pm
I'm just using LISP to kick off the program... they have a startup lisp set up that loads some base functions... when they type "B1" it will start Program A.exe for example.

I don't think I can pass values in because of the ClickOnce Application in .NET. I'm launching the setup.exe program, not the program application... so any values passed to the launching program go into the ClickOnce exe application and not the actual Program A.

Which leaves me, I think, stuck where I need to have Program X determine the last command typed by the user so I can say "If the user typed B1 then do this, if the user typed B2 then do this, etc"... which the switch-case statement would be perfect for.

Kerry Brown
2nd Sep 2010, 12:04 am
At a pinch ;
use your launching App to write a 'Start Data File'

Read the 'Start DataFile' from AutoCAD for the initialisation info.

stmoong
2nd Sep 2010, 01:11 am
Yup, Kerry's method will work. :)

I was thinking along command line arguments, but seems it is not suitable for your purpose.

ChristinaSeay
2nd Sep 2010, 04:38 pm
Yeah... that thought crossed my mind... it seemed a bit clunky... but doable.

It just seems like AutoCAD should have the information somewhere for the last commands typed by the user since ENTER, SPACEBAR both repeat the last command typed and you can press the up arrow key and scroll through the last commands as well... so AutoCAD has that information somewhere...

ChristinaSeay
2nd Sep 2010, 06:04 pm
It looks like this guy is doing what I'm needing to do somewhat:
http://www.visiblevisual.com/index.php/AutoCad-VB/VBA/last-command-stoolbar.html

He's making a toolbar of the last 10 commands used... but I'm not sure exactly how. It looks like the program is set to be launched each time a command is used in AutoCAD... but somehow he's getting the command they typed into the program as a string and using it... which is what I need to do...

BlackBox
2nd Sep 2010, 06:27 pm
Have you tried the copyhist command?



COPYHIST

Copies the text in the command line history to the Clipboard.

http://docs.autodesk.com/ACD/2010/ENU/AutoCAD%202010%20User%20Documentation/images/ac.keyboard.gif Command entry: copyhist

The text is copied to the Clipboard.

Source: http://docs.autodesk.com/ACD/2010/ENU/AutoCAD%202010%20User%20Documentation/index.html?url=WS73099cc142f48755-1257e12111bf108800e-2b2.htm,topicNumber=d0e5422



I just came accross this, but do not have 2010 software.

ChristinaSeay
2nd Sep 2010, 07:30 pm
Hmmm... that command works on 2002... definitely worth a shot... I just have to parse clipboard contents to get the info I need... but it is in there at least.

Thanks for that!! I'll post back if I get working in case someone else needs it. :D

BlackBox
2nd Sep 2010, 07:31 pm
Good luck! :thumbsup:

ChristinaSeay
2nd Sep 2010, 07:48 pm
I think the gist of this is going to be something like (code is approximate... typing off the top of my head, so not 100% accurate):

1. User types "B1" in command line in AutoCAD that uses LISP to kick off ProgramX
2. ProgramX will do the following on load:
- SendCommand("COPYHIST")
- V_CopyHistResult as string = Clipboard.GetText
- If V_CopyHistResult.LastIndexOf("B1") > V_CopyHistResult.LastIndexOf("B2") Then Run form B1, else Run form B2

Since LastIndexOf will return a -1 if it's not found, I shouldn't have to worry about null string values and the > and < operators should work.

There may be a more efficient way to test all the values since there are about 12 possible entries... not just B1 and B2... but I'll investigate that as I go. Maybe the Select-Case statement like what was mentioned earlier.

Thank-You guys for all your help!!!!

stmoong
3rd Sep 2010, 09:55 am
The Last Command Toolbar seems to be written in VBA, and the AcadDocument_BeginCommand is an event handler that traps the command name.

Well, just throwing out some more ideas.

Would the Document.CommandInProgress works for you?

If it doesn't work, how about implementing an event handler for the Document.LispEnded or Document.CommandEnded event. In the event handler, you can get the command that raised this event, via CommandEventArgs.GlobalCommandName property.