Bill Tillman Posted July 24, 2012 Posted July 24, 2012 I have a nice method for launching AutoCAD from an Excel VBA program but now we're moving over to a VB.NET application. Will the code for VBA work for VB.NET? I usually find that the codes do not interchange very well. Quote
BlackBox Posted July 24, 2012 Posted July 24, 2012 VBA VB.NET In an effort to save yourself some grief, consider using Shell to open a specific application icon (which includes the applicable startup switches already), if there is not a current instance (i.e., a Process) for you to access. A while back, I gave you an example of this from an Excel application that would 'get or create'. Quote
Bill Tillman Posted July 24, 2012 Author Posted July 24, 2012 Renderman, Yes, I recall that well and I used it for a while, however, several of the IT guys here told me that using Shell from a VBA program was frowned upon...by them at least. As I recall from my long ago days of programming in BASIC, the shell command, while useful, left the original code in control. And if the application had a problem, it would be hard to trace, etc...I know things have come a long way from that time, but I have always stayed away from the Shell command, mainly for this reason. The current VBA method I'm using is like this, and you will notice it allows me to put in the needed arguments to launch the correct LISP program and execute it: Set acDoc = acApp.Documents.Open(strDrawing) acDoc.Activate Set acDoc = acApp.ActiveDocument acDoc.SendCommand ("(load ""//a_very_long/path/deep_inside/a_novell_network/MyLisp.lsp"" ""The load failed"") mylisp" & Chr(13)) I'm looking for something that is VB.NET compatible and our good friend Fixo had a posting on another forum which I modified. It works well but it opens AutoCAD in a small window, not maximized, which is what I'm after. Now, I would like to add this caveat. I have been learning VB.NET because the IT guys here tell me that it's .NET or the highway. I don't make the rules, I just follow them. They want me to wean the engineering department off of VBA as soon as possible. No problem, I love a challenge and thus far we've made some decent progress, But as I look at Fixo's code to launch AutoCAD from VB.NET it's hard to fathom how one could program this from scratch. Long ago with BASICA and QBASIC is was not that difficult to build new and exciting things from scratch. But this block of code for this class is 24 lines long and has strings in it that are a meter long. The IDE in VB 2010 Express which I'm using makes it easy to type the stuff in, but to try and find where someone would have come up with this code in the first place has been the challenge. Like I showed someone this morning, I used to open a file and read lines of text in with just 3 or 4 lines of code. With VB.NET it now takes about 12 or 15 lines of code to do the very same thing. And the namespace requirements....every time I find something which claims it will work, the poster failed to include the Import statements...which as you well know, render the rest of the code useless...and until such time that I'm as familiar with all the nuisances with .NET I'm kind of stuck with asking for lots of advice. And if anyone wants to argue the point, I'll be glad to show how lacking the available documentation on this subject is. I read dozens of articles each day and night which are missing imperative points, have typos of all kinds and just plain useless because the author assumes anyone reading it knows as much about it as they do. Sorry for the rant...! I do appreciate everyone's assistance on these forums. Quote
BlackBox Posted July 24, 2012 Posted July 24, 2012 I am no full-time professional developer myself, but methinks we're talking about two different things with regard to Shell... You mention the Shell Command specifically, and I am suggesting that you consider incorporating the Shell.Application Object (i.e., Windows Shell?) into your VB.NET application for launching AutoCAD (outside of AutoCAD, i.e., from a stand-alone EXE). The VB.NET example I provided you previously (the one for Excel) would first check for an instance of Excel (read: a Process), and if present, 'get' the Excel Application Object, otherwise, if no instance of Excel (read: a Process) existed, a new one would be created. Following this concept, you can (again, from a stand-alone application outside of AutoCAD) check for an Active instance of AutoCAD (Process), and if none exist, use the Shell.Application Object to launch AutoCAD using the specified Application Icon (read: Shortcut, or .LNK) which will include the applicable Profile switch (/p), etc.. ... Does this make (more?) sense to you now? Please clarify, are you performing this task within, or outside of AutoCAD? The OP mentions 'launching AutoCAD', but your last example is ambiguous but suggests using SendCommand from within AutoCAD. Not really sure. As for the amount of code in .NET vs. LISP, VBA, etc... Believe me, I know... But that's the way it is if you want to use the upper level, full-blown development environments. As for the missing Imports... You say you're using Visual Studio 2010 Express, right? So paste the code into a blank Class (i.e., *.vb, *.cs, or other), and hover the error, select the down arrow that appears and check to see what options are available. Often times (provided you have the necessary Assemblies referenced) you'll be presented with an option to add the necessary 'Imports' (VB), or 'using' (C#) statement to the Class. .NET development requires a greater knowledge level than a LISP, or VBA developer; that's just a fact. You should have all of the necessary ObjectARX SDKs installed for your version(s), and using a Wizard (again because you're using Express) helps with a lot of the repeated tasks of adding certain reference Assemblies, enabling Debugging, etc.. I know you're doing this for work and all, but the better your information (and code?) up front, the easier it will be for myself, or others to assist you. Quote
Bill Tillman Posted July 24, 2012 Author Posted July 24, 2012 I've gotten the process condensed down to this: Imports Autodesk.AutoCAD.Interop.AcadDocumentClass Imports Autodesk.AutoCAD.InterOp.Common Module Module1 Sub Main() Dim vAcadApp As Autodesk.AutoCAD.Interop.AcadApplication Dim vAcadDoc As Autodesk.AutoCAD.Interop.AcadDocuments vAcadApp = New Autodesk.AutoCAD.Interop.AcadApplication vAcadApp.Visible = True End Sub End Module Now this is what I'm talking about. A few lines of code to do what the other 24 lines did. The trouble with this is that it open up AutoCAD in a small, narrow window. Do you think this will work by adding some additional information to open a template file and then launch one of the LISP programs? Quote
BlackBox Posted July 24, 2012 Posted July 24, 2012 Sorry to ask again, but can you please clarify... Stand-alone EXE (outside of AutoCAD), or .NET plug-in (inside of AutoCAD, and get's NETLOADed)...? Also, if you could link (or post) Fixo's code that would be helpful as well... Just want a better understanding of where you were, and are now. Quote
Bill Tillman Posted July 24, 2012 Author Posted July 24, 2012 Renderman, Yes sir. I saw that other posting and I highly agree. I am a full-time developer. Why? Because they couldn't find anyone else around here stupid enough to take it on. But like I said, I do love a challenge. I don't claim to know everything about the problem with the SHELL command, I only know what the IT guys here advise me on and I don't want to get caught with my fly open in a meeting where some problem with the network was caused by something they warned me against. All of the VBA code I am writing is performed from an Excel spreadsheet. And the VB.NET code I'm working on is of course stand-alone. Only the LISP codes I prepare are running inside of AutoCAD. The sendCommands I use are in the VBA codes which run from the Excel files. That all works very well. But the new process I'm working on will not be VBA. The same LISP programs will be used but we're moving away from VBA to VB.NET. I use VB 2010 Express...not Visual Studio. It's allegedly a watered down version of VS and only contains the VB.NET language. It's FREE...and that's what I sold them on. I've been advised by others that the Express version has plenty of capabilities to do what I want...and so far it appears to be up to the task. If the time comes when it will not, then I will have some ammunition to request a budget for Visual Studio...although they do have several seats for VS 2005 around here. The trouble with that is that 2005 may as well be 1985 because the .NET codes required here are not compatible. I have to be careful on my requests for purchases, especially now because they just bought a new license for Acad 2013...and billed it to my department. Until I show them an ROI on that it will be difficult to ask for a new VS seat. As for the Imports, I have noticed that sometimes....sometimes, the error messages will present either what to Import or make a suggestion about it. But in many instances, there is only an error which says "no go" and I'm stuck with finding another method. Quote
Bill Tillman Posted July 24, 2012 Author Posted July 24, 2012 Here is the link to the code I found from Fixo. It's way down the page at post #12. Fixo is really good at this kind of stuff and he has been a big help in the past. I sent him a PM with the code I modified to see if he has time to assist. The code works and it will actually open an existing drawing, which is what I'm eventually going to have to do, like the VBA code I am using now. It also opens AutoCAD up in a very tall and narrow window instead of maximized. In addition, I will need to load and execute the LISP program. http://www.dreamincode.net/forums/topic/244731-how-to-connect-to-autocad-and-open-a-drawing/ Here is the code from Fixo as I have modified it. It was actually a form, but I am working on a user-input-less process so I changed it over to a Console Application. Imports System.Runtime.InteropServices Imports System.Reflection Imports System.Globalization Imports System.Collections Public Class ReflectionCommands <System.Security.SuppressUnmanagedCodeSecurity()> _ Public Shared Sub TestACAD(ByVal dwgname As String) 'Save current culture to variable Dim thisThread As System.Globalization.CultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture 'Set culture to whatever you want thisThread = New System.Globalization.CultureInfo("en-US") Dim appProgID As String = "AutoCAD.Application" Dim filename As String = dwgname 'NGet reference on intergrace IDispatch Dim AcadType As Type = Type.GetTypeFromProgID(appProgID) 'Launch AutoCAD Dim AcadApp As Object = Activator.CreateInstance(AcadType) Dim visargs() As Object = New Object(0) {} visargs(0) = True 'Set Application Window visible AcadApp.GetType().InvokeMember("Visible", BindingFlags.SetProperty, Nothing, AcadApp, visargs, Nothing) Dim AcadDocs As Object = AcadApp.GetType().InvokeMember("Documents", BindingFlags.GetProperty, Nothing, AcadApp, Nothing) 'Create array of parameters Dim args() As Object = New Object(1) {} args(0) = filename args(1) = False ' read-only=false 'open a drawing Dim AcDoc As Object = AcadDocs.GetType.InvokeMember("Open", BindingFlags.InvokeMethod, Nothing, AcadDocs, args, Nothing) Dim Util As Object = New Object Try 'Get reference on active document AcDoc = AcadApp.GetType.InvokeMember("ActiveDocument", BindingFlags.GetProperty, Nothing, AcadApp, Nothing, Nothing) 'Get reference on AcadUtility Util = AcDoc.GetType().InvokeMember("Utility", BindingFlags.GetProperty, Nothing, AcDoc, Nothing) 'Get reference on ModelSpace Dim oSpace As Object = AcDoc.GetType.InvokeMember("ModelSpace", BindingFlags.GetProperty, Nothing, AcDoc, Nothing) Catch ex As Exception End Try End Sub End Class Module Module1 Sub Main() Dim fname As String = "H:\Test123.dwg" ReflectionCommands.TestACAD(fname) End Sub End Module Quote
Bill Tillman Posted July 25, 2012 Author Posted July 25, 2012 (edited) Renderman, At the risk of making this post too long and too boring for most folks, here is some of what I accomplished last night. Again, my newbie status with .NET is clear to see but I'm trying to make use of a shorter version of this code. Imports Autodesk.AutoCAD.Interop.AcadDocumentClass Imports Autodesk.AutoCAD.InterOp.Common Module Module1 Sub Main() Dim vAcadApp As Autodesk.AutoCAD.Interop.AcadApplication Dim vAcadDoc As Autodesk.AutoCAD.Interop.AcadDocument vAcadApp = New Autodesk.AutoCAD.Interop.AcadApplication vAcadApp.Visible = True vAcadApp.WindowState = AcWindowState.acMax 'vAcadDoc = vAcadApp.Documents.Open("I:\Automated Drawings\APS(Automated).dwg", True) 'vAcadDoc.SendStringToExecute("(load ""//mypath/mylisp.lsp"" ""The load failed"") mylisp" & Chr(13)) End Sub End Module OK, I had to change the keyword AcadDocuments to AcadDocument...and that seemed to have fixed the exception error. This works now and it maximizes the window. I just need to get the LISP program loaded and executed. Edited July 25, 2012 by Bill Tillman Quote
Bill Tillman Posted July 25, 2012 Author Posted July 25, 2012 The sweet smell of success. Or at least the darn thing is working now. The SendCommandToExecute method did not work, or maybe there is another import required for it. I will research that more because the initial information I got from AutoDesk's forum said that SendCommand is not recommended for VB.NET. That may well be true but I found many other articles which said no problem. Anyway, here is the code, which now opens Autocad, opens the template drawing, loads the lisp and executes it and poof....there is my requested assembly drawing all done in about 10 seconds instead of the usual 2-3 hours. Imports Autodesk.AutoCAD.Interop.AcadDocumentClass Imports Autodesk.AutoCAD.Interop.Common Module Module1 Sub Main() Dim vAcadApp As Autodesk.AutoCAD.Interop.AcadApplication Dim vAcadDoc As Autodesk.AutoCAD.Interop.AcadDocument vAcadApp = New Autodesk.AutoCAD.Interop.AcadApplication vAcadApp.Visible = True vAcadApp.WindowState = AcWindowState.acMax vAcadDoc = vAcadApp.Documents.Open("I:\Automated Drawings\Automated.dwg", True) vAcadDoc.SendCommand("(load ""//a_very_long_novell/server_path/LISP/mylisp.lsp"" ""The load failed"") mylisp" & Chr(13)) End Sub End Module Quote
BlackBox Posted July 25, 2012 Posted July 25, 2012 ... Now you just need to code your LISP into .NET Congrats, Bill! Quote
BlackBox Posted July 25, 2012 Posted July 25, 2012 Before I forget, to make your code more 'portable' there's a couple of things you can do: Instead of coding the entire solution in Main(), consider writing a Method that accepts two arguments, a DWT as String, and a LSP as String. This Method can go into your code library, and can easily be added as a Reference Assembly to any other solution. Going one step further, these arguments as Strings may not require the file path, provided they both reside within the Support File Search Path (SFSP), as you can use the HostApplicationServices.FindFile() Method... As shown in this thread. Gile's awesome! HTH Quote
Bill Tillman Posted July 26, 2012 Author Posted July 26, 2012 As for moving all the LISP to .NET, I'd do it except the big boss will come in and ask me why I'm reinventing the wheel. In other words, if it ain't broke, don't fix it. And as for using variables for the DWT, etc...that's a great idea and I've already got that working. The LISP file and the drawing template which this will open are all based on whatever the first part of my project found in the text file it read. It's coming together nicely. Thanks again for the very helpful advice. Quote
BlackBox Posted July 26, 2012 Posted July 26, 2012 It's coming together nicely. Thanks again for the very helpful advice. Happy to have helped, Bill. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.