Author Topic: AccessViolation when changing printers for layouts in multiple dwgs  (Read 2455 times)

0 Members and 1 Guest are viewing this topic.

pbpmid

  • Guest
I am getting an AccessViolation exception when changing printer & media in all layouts of a set of drawings.
The error message is "Attempted to read or write protected memory.  This is often an indication that other memory is corrupt."   
Exception stack trace shows: at Autodesk.AutoCAD.ApplicationServices.TransactionManager.FlushGraphics()
 at PrintUtil.PrintUtil.ConvertLayoutPrinters(Database db, String sDwgName, Dictionary'2&dictPrinters, StreamWriter& txtwriLog) at
 PrintUtil.PrintUtil.ConvertPrinters
For a particular set of drawings, always errors on the same drawing.
However,  will not error on that drawing if I only process that drawing and a few drawings before it.
If I change the order of the drawings,  will error on a different drawing or not at all.
If I don't call my function to change the layouts,  I can loop through and save drawings with no error.


My main ConvertPrinters procedure:
 - stores current working database to dbOld
 - create dictionary of old and new printer names for the conversion
 - opens log file so we record exceptions - dwg that were open, printers not found in dictionary, etc
 - loops through a set of drawings, reading drawing names from text file
  do while ... there are drawings
Code - vb.net: [Select]
  1. ' -- pseudocode
  2.   try
  3.      db = New Database (False, False)
  4.      db.ReadFile(sDwgName, FileOpenMode.OpenForReadAndWriteNoShare, False, Nothing)
  5.      HostApplicationServices.WorkingDatabase = db
  6.      --- here I call my function to process / change each layout for that drawing
  7.      bSuccess = ConvertLayoutPrinters(db,sDwgName, dictPrinters, txtwriLog)
  8.      
  9.  
  10.      catch ex as AccessViolationException..
  11.        'catching the problem here and showing a message box
  12.      catch
  13.      
  14.      finally
  15.        db.CloseInput(True)
  16.        HostApplicationServices.WorkingDatabase = dbOld
  17.      end try
  18.  
  19.      if bSuccess ... save the drawing
  20.      db.dispose
  21.      db = Nothing
  22.   loop

'----------------------------------------------------------------------
'Here is the function to change printers in the layouts for one drawing
Code - vb.net: [Select]
  1. 'convert printers in all layouts for a drawing
  2. Public Shared Function ConvertLayoutPrinters(ByVal db As Database, ByVal sDwgName As String, ByRef dictPrinters As Dictionary(Of String, String), ByRef txtwriLog As System.IO.StreamWriter) As Boolean
  3.         Dim doc As Document = appAcad.DocumentManager.MdiActiveDocument
  4.         Dim ed As Editor = appAcad.DocumentManager.MdiActiveDocument.Editor
  5.         Dim sPlotConfigurationName As String = ""
  6.         Dim sLCasePlotConfigurationName As String = ""
  7.         Dim sNewPlotConfigurationName As String = ""
  8.         Dim sCanonicalMediaName As String = ""
  9.         Dim sNewCanonicalMediaName As String = ""
  10.         Dim sPageSetup As String = ""   'named page setup associated with layout
  11.         Dim bModel As Boolean           'is model space?
  12.         Dim bChanged As Boolean         'whether we changed anything in this dwg
  13.         Dim bError As Boolean = False  'was there an error somewhere
  14.  
  15.         Using tr1 As Transaction = db.TransactionManager.StartTransaction()
  16.             Try
  17.                 Dim layoutDic As DBDictionary
  18.                 layoutDic = TryCast(tr1.GetObject(db.LayoutDictionaryId, OpenMode.ForRead), DBDictionary)
  19.                 If layoutDic Is Nothing Then
  20.                     MessageBox.Show(sDwgName & " layoutDic is nothing in ConvertLayoutPrinters")
  21.                 End If
  22.  
  23.                 'assume no changes are made and no errors found at start of each drawing
  24.                 bChanged = False
  25.                 bError = False
  26.  
  27.                 For Each entry As DBDictionaryEntry In layoutDic
  28.                     Dim layout As Layout = Nothing
  29.                     Dim layoutId As ObjectId = ObjectId.Null
  30.  
  31.                     layoutId = entry.Value
  32.                     layout = TryCast(tr1.GetObject(layoutId, OpenMode.ForRead), Layout)
  33.  
  34.                     If layout IsNot Nothing Then
  35.                         sPlotConfigurationName = layout.PlotConfigurationName
  36.                         'We have stored lower case printer name in the dictionary
  37.                         sLCasePlotConfigurationName = LCase(sPlotConfigurationName)
  38.                         sCanonicalMediaName = layout.CanonicalMediaName
  39.                         ' Get any page setup associated with this layout
  40.                         sPageSetup = layout.PlotSettingsName
  41.                     Else
  42.                         sPlotConfigurationName = ""
  43.                         sCanonicalMediaName = ""
  44.                         sLCasePlotConfigurationName = ""
  45.                         sPageSetup = ""
  46.                     End If
  47.  
  48.                     If dictPrinters.ContainsKey(sLCasePlotConfigurationName) And sPlotConfigurationName <> "" And sCanonicalMediaName <> "" Then
  49.                         'Lookup new printer name from the conversion dictionary
  50.                         sNewPlotConfigurationName = dictPrinters.Item(sLCasePlotConfigurationName)
  51.                         bModel = layout.ModelType
  52.                         sCanonicalMediaName = layout.CanonicalMediaName
  53.  
  54.                         'get a copy of the current plot settings for this layout
  55.                         'we can make changes and then save back
  56.                         Using currPlotSet As PlotSettings = New PlotSettings(layout.ModelType)
  57.                             currPlotSet.CopyFrom(layout)
  58.  
  59.                             Dim plotSetVal As PlotSettingsValidator
  60.                             plotSetVal = PlotSettingsValidator.Current
  61.                             'AutoCAD recommends getting the latest list of devices and layouts
  62.                             ' before we do anything.  Only need to do once.
  63.                             layout.UpgradeOpen()
  64.                             plotSetVal.RefreshLists(layout)
  65.                             layout.DowngradeOpen()
  66.  
  67.                             'validate layout media / paper size to be safe
  68.                             'we can't validate plot settings that are not applied to a layout
  69.                             Using plotinf As PlotInfo = New PlotInfo
  70.                                 'To validate plot settings
  71.                                 Using plotinfval As PlotInfoValidator = New PlotInfoValidator
  72.                                     ' This allows AutoCAD to match equivalent media on different plotting devices,
  73.                                     '  e.g., map a RICOH plotter "Tabloid" page to the AutoCAD PDF "ANSI_expand_B_(11.00x17.00_inches)".
  74.                                     plotinfval.MediaMatchingPolicy = MatchingPolicy.MatchEnabled
  75.  
  76.                                     ' Make sure the PlotInfo has a Layout object it can latch onto.
  77.                                     ' Looking at the layout of the drawing we are processing
  78.                                     plotinf.Layout = layout.ObjectId
  79.  
  80.                                     ' validating paper size / media settings
  81.                                     plotinf.OverrideSettings = currPlotSet
  82.                                     ' Person running this must have new printer installed already or will have an error
  83.                                     plotinf.DeviceOverride = PlotConfigManager.SetCurrentConfig(sNewPlotConfigurationName)
  84.  
  85.                                     ' Validate the combined settings with the new device override.
  86.                                     ' Layout we are testing against must be the current layout
  87.                                     LayoutManager.Current.CurrentLayout = layout.LayoutName
  88.                                     plotinfval.Validate(plotinf)
  89.                                 End Using 'plotinfval
  90.                                 ' Set the plot configuration and media names for pushing to the new plot settings.
  91.                                 sNewPlotConfigurationName = plotinf.ValidatedSettings.PlotConfigurationName
  92.                                 sNewCanonicalMediaName = plotinf.ValidatedSettings.CanonicalMediaName
  93.                             End Using 'plotinf
  94.  
  95.                             'update current plot settings
  96.                             plotSetVal.SetPlotConfigurationName(currPlotSet, sNewPlotConfigurationName, sNewCanonicalMediaName)
  97.                             ' txtwriLog.WriteLine(sDwgName & "," & layout.LayoutName & "," & sPlotConfigurationName & "," & sNewPlotConfigurationName)
  98.  
  99.                             ' Update the layout with the validated plot settings
  100.                             layout.UpgradeOpen()
  101.                             layout.CopyFrom(currPlotSet)
  102.                             bChanged = True
  103.                         End Using  'currPlotset
  104.  
  105.                     Else
  106.                         'ed.WriteMessage(sDwgName & vbTab & layout.LayoutName & " printer " & sPlotConfigurationName & " not found in conversion file dictionary." & vbNewLine)
  107.                         'txtwriLog.WriteLine(sDwgName & "," & layout.LayoutName & "," & sPlotConfigurationName & "," & "not found in conversion file.")
  108.                     End If 'dictPrinters.ContainsKey
  109.  
  110.                 Next 'layout
  111.  
  112.                 'catch per tr1
  113.            Catch ex As System.AccessViolationException
  114.                 'txtwriLog.WriteLine(sDwgName & "," & Layout.LayoutName & "," & "Error" & "," & ex.Message & "," & "Access violation / unhandled error in ConvertLayouts/For each layout.")
  115.                 MessageBox.Show("convert Layout TR1 " & ex.Message & vbNewLine & vbNewLine & ex.StackTrace, sDwgName)
  116.                 bError = True
  117.            Catch ex As System.Exception
  118.                 MessageBox.Show("convert Layout TR1 " & sDwgName & " Unhandled exception in ConvertLayoutPrinters")
  119.                 'txtwriLog.WriteLine(sDwgName & "," & Layout.LayoutName & "," & ex.Message & "," & " system error " & sNewPlotConfigurationName)
  120.                 bError = True
  121.             Finally
  122.                 If bError Then
  123.                     tr1.Abort()
  124.                     bChanged = False
  125.                 Else
  126.                     tr1.Commit()
  127.                 End If
  128.             End Try 'tr1
  129.         End Using 'tr1
  130.  
  131.         'return whether we changed anything so we know whether to save the dwg
  132.         Return bChanged
  133.  
  134.     End Function
« Last Edit: September 05, 2014, 04:51:07 PM by musak »

BlackBox

  • King Gator
  • Posts: 3770
Re: AccessViolation when changing printers for layouts in multiple dwgs
« Reply #1 on: September 05, 2014, 04:43:40 PM »
I am getting an AccessViolation exception when changing printer & media in all layouts of a set of drawings.

Welcome to TheSwamp!

Why not instead simply create/copy a named page setup that is properly configured, and then apply said page setup to all Layouts?

For the latter, here's a .NET LispFunction Method that you can cull.

HTH
"How we think determines what we do, and what we do determines what we get."

pbpmid

  • Guest
Re: AccessViolation when changing printers for layouts in multiple dwgs
« Reply #2 on: September 05, 2014, 04:58:20 PM »
Good thought but we are changing our print server and thus changing most printer names and possibly media for several drafting groups and types of drawings.  There is no one page setup that fits and not all drawings have an associated named page setup.   Will keep in mind for the future.  Thanks.

BlackBox

  • King Gator
  • Posts: 3770
Re: AccessViolation when changing printers for layouts in multiple dwgs
« Reply #3 on: September 05, 2014, 05:14:20 PM »
Good thought but we are changing our print server and thus changing most printer names and possibly media for several drafting groups and types of drawings.  There is no one page setup that fits and not all drawings have an associated named page setup.   Will keep in mind for the future.  Thanks.

That's kind of the point... Manually create the required named page setups in your template(s), for example, and delete any contained within the drawings you're processing, import those saved in your template(s) as needed, and simply set as active. Lemon squeezy. :angel:

Cheers
"How we think determines what we do, and what we do determines what we get."

pbpmid

  • Guest
Re: AccessViolation when changing printers for layouts in multiple dwgs
« Reply #4 on: September 08, 2014, 10:44:35 AM »
In this case,  there are not common page setups to use for all.  We have 1000's of drawings for different jobs and clients.  We are only changing the print server and have the same physical printers.  I would prefer to change the PlotConfigurationName and avoid settings that are job/specific.  Matching the CanonicalMedia is needed since some show up as Tabloid and need resolved to 11x17.  Will keep your idea in mind for future projects.   Thanks.

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: AccessViolation when changing printers for layouts in multiple dwgs
« Reply #5 on: September 08, 2014, 03:06:51 PM »
Code - vb.net: [Select]
  1. ' -- pseudocode
  2.   try
  3.      db = New Database (False, False)
  4.      db.ReadFile(sDwgName, FileOpenMode.OpenForReadAndWriteNoShare, False, Nothing)
  5.      HostApplicationServices.WorkingDatabase = db
  6.      --- here I call my function to process / change each layout for that drawing
  7.      bSuccess = ConvertLayoutPrinters(db,sDwgName, dictPrinters, txtwriLog)
  8.      
  9.  
  10.      catch ex as AccessViolationException..
  11.        'catching the problem here and showing a message box
  12.      catch
  13.      
  14.      finally
  15.        db.CloseInput(True)
  16.        HostApplicationServices.WorkingDatabase = dbOld
  17.      end try
  18.  
  19.      if bSuccess ... save the drawing
  20.      db.dispose
  21.      db = Nothing
  22.   loop
Would be nice to see where the error is actually being thrown.

Seems you have not included full calling code either, I'm guessing the last if statement here has an endif before the loop. 

I'm wondering if maybe instead of the way you've set up your code here preserving the variable 'db' you should have it inside a using statement.. I'm wondering what is happening behind the scene with that pointer and if there is some issue of memory leak that is causing your issue, since it isn't an error in the code doing the changes (i.e. doesn't have error on just that drawing or just a few drawings) it is your calling code we need full details on, not your implementation of the change.


CADDOG

  • Newt
  • Posts: 82
  • wishbonesr
Re: AccessViolation when changing printers for layouts in multiple dwgs
« Reply #6 on: September 15, 2014, 12:23:46 PM »
What are the side affects of the error?
Does it prevent saving of the drawing, or an interruption of the batch process?  Perhaps a corruption of the drawing?

If none of the above, then what about just clearing the error and continuing.

pbpmid

  • Guest
Re: AccessViolation when changing printers for layouts in multiple dwgs
« Reply #7 on: September 15, 2014, 01:17:13 PM »
This 'Attempted to read or write protected memory' error is happening on the commit statement but will cause error 'Operation is not valid due to current state of the object' if I let it return to the main sub.  I can change order of the drawings and it happens on a different drawing or not at all.  I'm already skipping recovery/unreadable files.  In a version where I continue after the 'memory' error, it happens about every 7th drawing.