Postcommand doesn't read AutoLisp expression [Python 2.7 & AutoCAD 2016 Windows]

Postcommand doesn't read AutoLisp expression [Python 2.7 & AutoCAD 2016 Windows]

serag.hassouna
Advocate Advocate
4,271 Views
6 Replies
Message 1 of 7

Postcommand doesn't read AutoLisp expression [Python 2.7 & AutoCAD 2016 Windows]

serag.hassouna
Advocate
Advocate

I'm trying to run a simple AutoLISP file from a python script, But there are 3 issues facing me.
My purpose is to obtain a test case, that demonstrates if this approach can be implemented or not.
[1] The Code:-

1- The Python Script:

#import needed modules
import os
import comtypes.client
from comtypes import COMError
from comtypes.client import CreateObject, GetActiveObject

def main():
    #1- Get the AutoCAD instance
    try:
        acad = GetActiveObject("AutoCAD.Application.20")
        print "AutoCAD is Active"
        print "########"
    except(OSError, COMError): #If AutoCAD isn't running, run it
        acad = CreateObject("AutoCAD.Application.20",dynamic=True)
        print "AutoCAD is successfuly Opened"
        print "########"

    #2- Get the paths to the lisp file and the dwg file
    directory_name = "E:\\Dir1\\Dir2" #replace it with a real path, use "\\" as directory delimiters.
#Note that "\\" is transformed automatically to "\", & in order to comply with
the AutoLISP "load" function, every "\" must be transformed again to "/". temp="" for char in directory_name: if char == "\\": temp += "/" else: temp += char directory_name = temp filename = directory_name + "/TestDWG.dwg" lispfile = directory_name + "/linedraw.lsp" #3- Open the drawing file print "Opening Drawing File ..." doc = acad.Documents.Open(filename) print "Drawing is successsfuly Opened" print "########" #4- Construct the AutoLISP expression that loads AutoLISP files command_str = '(load ' + '"' + lispfile + '")' #command_str = '_line 0,0 5,3 ' #an ordinary command that worked as expected #5-Execute the AutoLISP expression print "Sending AutoLISP Expression ..." print "Expression: " + command_str doc.PostCommand(command_str)
#doc.PostCommand("_qsave") #an error occurs here print "AutoLISP Expression is sent" #don't believe what this line tells you. print "########" #6- Save & Close the drawing file and AutoCAD application #doc.Save() #doesn't work! #doc.Close() #doesn't work! acad.Quit() print "Process Finished" print "__________" if __name__ == '__main__': main()

2- The AutoLisp script:

;Just a simple script to draw a line from (0,0) to (5,3)
(defun linedraw ()
  (command "._line" '(0 0) '(5 3) "")
  (command "_qsave") ;added in response to the failure of "doc.Save()" in the python script
  );end defun

(linedraw)

 

[2]The Issues:-

1- ((The main issue)): the AutoLISP expression isn't sent/posted to the drawing.
I did check this by leaving AutoCAD actively running, running the python script and looking for what happen in the command line & the Model Space.

2- "Save" & "Close" methods of the "document" cause errors and don't work.

3- Two invocations of "postcommand" creates an error.

________________________________________

I really appreciate any help, and keep notified that if this "test case" succeed we will have another way of running AutoLISP routines from outside without the need to open AutoCAD itself.
P.S: The real challenge is to NOT use AutoCAD script files (of extension .scr), AutoCAD must not be -by necessary-  opened by the user.

0 Likes
4,272 Views
6 Replies
Replies (6)
Message 2 of 7

DGRL
Advisor
Advisor

hI @serag.hassouna

 

Nice test case your opening

Do know that not every command invoked using LISP can be executed when ACAD IS NOT RUNNING

So you are very limited in posibilties

 

If this was of any help please kudo and/or Accept as Solution
Kind Regards
0 Likes
Message 3 of 7

serag.hassouna
Advocate
Advocate

@DGRL
Well, your response has inspired me in a magical way.

  1. GetActiveObject  (which fetches the running ACAD) was throwing an error, its description and how it was solved with me are here.
  2. Slightly changed the code to be
    #Import needed modules
    import os
    import comtypes.client
    from comtypes import COMError
    from comtypes.client import CreateObject, GetModule, GetActiveObject

    #Uncomment it if you need to load these type libraries.
    '''
    #Load all needed type libraries
    GetModule("C:/Windows/System32/stdole2.tlb")
    import comtypes.gen.stdole as ole
    print "stdole2 successfully loaded"
    GetModule("C:/Program Files/Common Files/Autodesk Shared/acax20enu.tlb")
    import comtypes.gen._4E3F492A_FB57_4439_9BF0_1567ED84A3A9_0_1_0 as acax
    print "acax20enu successfully loaded"
    GetModule("C:/Program Files/Common Files/Autodesk Shared/AcSmComponents20.tlb")
    import comtypes.gen._ED125AFF_6294_4BE4_81E2_B98DCBBA214E_0_1_0 as AcSm
    print "AcSmComponents20 successfully loaded"
    '''

    def main():
    #1- Get the AutoCAD instance
    try:
    acad = GetActiveObject("AutoCAD.Application.20")
    print "AutoCAD is Active"
    print "########"
    except(OSError, COMError): #If AutoCAD isn't running, run it
    acad = CreateObject("AutoCAD.Application.20",dynamic=True)
    print "AutoCAD is successfuly Opened"
    print "########"

    #2- Get the paths to the lisp file and the dwg file
    directory_name = "E:\\Dir1\\Dir2" #replace it with a real path, use "\\" as directory delimiters.
    #Note that "\\" is transformed automatically to "\", & in order to comply with
    the AutoLISP "load" function, every "\" must be transformed again to "/".

    temp=""
    for char in directory_name:
    if char == "\\":
    temp += "/"
    else:
    temp += char
    directory_name = temp
    filename = directory_name + "/TestDWG.dwg"
    lispfile = directory_name + "/linedraw.lsp"

    #3- Open the drawing file
    print "Opening Drawing File ..."
    doc = acad.Documents.Open(filename)
    print "Drawing is successsfuly Opened"
    print "########"

    #4- Construct the AutoLISP expression that loads AutoLISP files
    command_str = '(load ' + '"' + lispfile + '")' + " "

    #5-Execute the AutoLISP expression
    print "Sending AutoLISP Expression ..."
    print "Expression: " + command_str
    doc.SendCommand("(setq *LOAD_SECURITY_STATE* (getvar 'SECURELOAD)) ")
    doc.SendCommand("(setvar \"SECURELOAD\" 0) ")
    doc.SendCommand(command_str)
    doc.SendCommand("(setvar \"SECURELOAD\" *LOAD_SECURITY_STATE*) ")
    print "AutoLISP Expression is successfuly sent"
    print "########"

    #6- Close the drawing file and AutoCAD application
    doc.Close()
    acad.Quit()

    print "Process Finished"
    print "__________"

    if __name__ == '__main__':
    main()
     

And voila, it works fine.
___________________
The differences here are:

  1. Using SendCommand instead of PostCommand.
  2. To successfully invoke an AutoLISP expressions it must followed an empty space, which is equivalent to hitting ENTER on the keyboard.
  3. Before using the load routine, the SECURELOAD system variable must be set to 0, this is to prevent the security message, which I guess is the main reason for making the program previously crash with SendCommand.
0 Likes
Message 4 of 7

serag.hassouna
Advocate
Advocate

Same code but with the right indentations.

 

#Import needed modules
import os
import comtypes.client
from comtypes import COMError
from comtypes.client import CreateObject, GetModule, GetActiveObject

#Uncomment it if you need to load these type libraries.
'''
#Load all needed type libraries
GetModule("C:/Windows/System32/stdole2.tlb")
import comtypes.gen.stdole as ole
print "stdole2 successfully loaded"
GetModule("C:/Program Files/Common Files/Autodesk Shared/acax20enu.tlb")
import comtypes.gen._4E3F492A_FB57_4439_9BF0_1567ED84A3A9_0_1_0 as acax
print "acax20enu successfully loaded"
GetModule("C:/Program Files/Common Files/Autodesk Shared/AcSmComponents20.tlb")
import comtypes.gen._ED125AFF_6294_4BE4_81E2_B98DCBBA214E_0_1_0 as AcSm
print "AcSmComponents20 successfully loaded"
'''

def main():
    #1- Get the AutoCAD instance
        try:
            acad = GetActiveObject("AutoCAD.Application.20")
            print "AutoCAD is Active"
            print "########"
        except(OSError, COMError): #If AutoCAD isn't running, run it
            acad = CreateObject("AutoCAD.Application.20",dynamic=True)
            print "AutoCAD is successfuly Opened"
            print "########"

    #2- Get the paths to the lisp file and the dwg file
    directory_name = "E:\\Dir1\\Dir2" #replace it with a real path, use "\\" as directory delimiters.
    '''
Note that "\\" is transformed automatically to "\", & in order to comply with the AutoLISP "load" function, every "\" must be transformed again to "/".
''' temp="" for char in directory_name: if char == "\\": temp += "/" else: temp += char directory_name = temp filename = directory_name + "/TestDWG.dwg" lispfile = directory_name + "/linedraw.lsp" #3- Open the drawing file print "Opening Drawing File ..." doc = acad.Documents.Open(filename) print "Drawing is successsfuly Opened" print "########" #4- Construct the AutoLISP expression that loads AutoLISP files command_str = '(load ' + '"' + lispfile + '")' + " " #5-Execute the AutoLISP expression print "Sending AutoLISP Expression ..." print "Expression: " + command_str doc.SendCommand("(setq *LOAD_SECURITY_STATE* (getvar 'SECURELOAD)) ") doc.SendCommand("(setvar \"SECURELOAD\" 0) ") doc.SendCommand(command_str) doc.SendCommand("(setvar \"SECURELOAD\" *LOAD_SECURITY_STATE*) ") print "AutoLISP Expression is successfuly sent" print "########" #6- Close the drawing file and AutoCAD application doc.Close() acad.Quit() print "Process Finished" print "__________" if __name__ == '__main__': main()

 

 

Message 5 of 7

DGRL
Advisor
Advisor

@serag.hassouna

 

Nice work 
Is it working now as it should?

 

If this was of any help please kudo and/or Accept as Solution
Kind Regards
0 Likes
Message 6 of 7

serag.hassouna
Advocate
Advocate

Thanks @DGRL
Yes, it works fine whether AutoCAD is opened or not .. the code will deal with the running AutoCAD application, and if AutoCAD is not opened this python code will open it, load the lisp file to the drawing,then close the drawing itself.
This is really useful if you don't want to lean on the traditional solution of "script creation" & if you want to deal with AutoCAD externally.
Script Creation is described in more detail in this answer of Lee Mac in stackoverflow.
In fact, this test code is another answer to the same problem, & I think it's more compact if the equivalently-created script has more lines than the python code itself, in other words, with large number of drawings.
______________
P.S. I removed the line 

(command "_qsave")

from the lisp file, and added the line 

    doc.Save()

just before

    doc.Close()

into the python code, and it is working as it should.

Message 7 of 7

DGRL
Advisor
Advisor

@serag.hassouna

 

Thanks for the update

Really appriciate this 

If possible keep me informed 
Maybe i can be of any help in a later stadium

 

If this was of any help please kudo and/or Accept as Solution
Kind Regards