Issue

Per default powerJobs uses TrueView to generate PDF of AutoCAD drawings and can be configured via setup drawings and manipulation of a temporary DSD file that is created for every file export. When configuration capabilities beyond this scope are required or limitations of TrueView prevent the creation of usable PDF files it is necessary to use AutoCAD.

The AutoCAD API runs in a single threaded apartment(STA). In order for a thread, this means a job, to be able to communicate with it it must run in a STA as well. However powerJobs starts the PowerShell runspace in a multi threaded apartment(MTA).


Solution

In order to get a stable connection to the AutoCAD API you have to start it in a STA thread and use some message filters to prevent communication issues. Without the message filters you will get random COM exceptions when using the AutoCAD API.


First things first

  • Download MessageFilter.zip and InvokeApartmentState.zip from the attachments
  • Make sure that the files are unblocked
  • Copy them into your powerJobs modules folder
  • Make sure the Windows user that will run powerJobs has permissions to add, edit and delete files in the powerJobs modules folder

Using the modules

  • Before you can use the message filters you have to add them to the current runspace. Call the function Load-AutoCADMessageFilter to do that.
  • The fully qualified name of the class is cOCommunication.MessageFilter and it contains to static methods Register() and Revoke()
  • You always have to call the Register() method before you use any AutoCAD API call
  • You always have to call the Revoke() method after you used your last AutoCAD API call
  • You can open a new AutoCAD instance with the New-Object commandlet
    • For example $application = New-Object -ComObject AutoCAD.Application
    • If you want to start a specific version of AutoCAD you have to use its precise class name. For example AutoCAD.Application.20 for AutoCAD 2016

Example


Invoke-Script -apartmentState STA -script {
    try {
        Open-VaultConnection
        $fileName = "Test.dwg"
 
        $file = Get-VaultFile -Properties @{ "File Name" = $fileName }
 
        Load-AutoCADMessageFilter  
        $application = New-Object -ComObject AutoCAD.Application.20 #AutoCAD 2016. For 2015 use: AutoCad.Application.19
        [cOCommunication.MessageFilter]::Register()  
 
        # Open ACAD document    
        $application.Documents.Open($file._FullPath)  
        #$application.Visible = $true
 
     } finally {
        if($application.ActiveDocument) {
            $application.ActiveDocument.Close($false) #object.Close([SaveChanges] [, FileName])
        }
        $application.Quit()
        [cOCommunication.MessageFilter]::Revoke()
        Add-Log "Closed the application."
     }
}


Remarks

  • As the Invoke-Script commandlet creates a new thread within your current runspace you'll have access to all the objects and variables that were declared before calling it
  • Please note that we cannot offer support for the AutoCAD API in the scope of product support, but you can post any questions in our forum if you want. If you need one of our supporters to work out a solution you will need a support card
  • If you are using Powershell 2 you will have issues accessing the AutoCAD API without reflection. You should update the the latest version.


Links

More information about COM apartments

AutoCAD help

Sources for a chunk of the code

Powershell Update