TheSwamp
Code Red => VB(A) => Topic started by: MikeJarosz on August 29, 2006, 03:45:53 PM
-
I posted the following topic on the AUGI programming page. I'm pasting it here in case anyone can shed some light on a tough problem........
"We have a never ending problem with engineering consultants submitting files to us with proxy objects in them, usually from third party software they bought to do their calculations. We have tried everything to persuade them not to send us files with proxies, but nothing stops them. I have decided that a better approach might be to delete the objects on our end.
My first thought was to use a selection filter in VBA to select the proxy objects then delete them. The problem is finding the DXG group code to make the selection. I can't get the codes to work. The proxy notice that pops up on my test file indicates 170 objects. I am able to make a DXF file from this file, and "AcDbProxyObject" appears in the DXF file 170 times. Here's a sample of the DXF code:
0
ACAD_PROXY_OBJECT
5
813D7E
102
{ACAD_REACTORS
330
3859C9
102
}
330
3859C9
100
AcDbProxyObject
90
499
91
937
95
2555929
70
0
93
105
310
4A34D128929A894251896A5A9680
340
813D7F
94
0
I understand what most of this is, but I can't get a selection set that grabs the 170 proxies.Here's my VBA code:
Dim Sset As AcadSelectionSet
Dim Codes(0) As Integer
Dim CodeValues(0) As Variant
Dim Entity As AcadEntity
Codes(0) = 100
CodeValues(0) = "ProxyObject"
Set Sset = ThisDrawing.SelectionSets.Add("Proxy")
Sset.Select acSelectionSetAll, , , Codes, CodeValues
Debug.Print "Drawing has " & Sset.Count & " proxy entities"
Is this the right approach, or is there some other way to accomplish the task of eliminating proxies?"
-
I am not sure what proxy objects you are getting, but those generated by LDT and Civil 3D can be exploded into a block and exploded again into native AutoCAD elements.
-
First of all, you cannot filter the 100 group codes. Use the 0 group instead. That being said, I'm not so sure you can do anything with the Proxy objects without the object enabler for them. I don't have a Vanilla install here to test on, but you could try Codes(0) = 0 and CodeValues(0) = "*PROXY*"
Of course, If you are going to be sending these drawing back to the consultant, and they are depending on those objects to be there, they may take issue with you deleting them.
-
Try this on a copy, I'm not quite sure it's what you want and of course there is what Jeff said
Sub Apps()
Dim App As AcadRegisteredApplication
For Each App In ThisDrawing.RegisteredApplications
Debug.Print App.Name
DeleteApplicationXData App.Name
Next
End Sub
'Cadvault
Public Function DeleteApplicationXData(strAppName As String) As Boolean
Dim objSelSet As AcadSelectionSet
Dim objSelCol As AcadSelectionSets
Dim objEnt As AcadEntity
Dim intXData(0) As Integer
Dim varXData(0) As Variant
Dim varData(0) As Variant
Dim intData(0) As Integer
On Error GoTo Err_Control
Set objSelSet = ThisDrawing.PickfirstSelectionSet
intData(0) = 1001
varData(0) = strAppName
objSelSet.Select 5, FilterType:=intData, FilterData:=varData
For Each objEnt In objSelSet
objEnt.SetXData intData, varData
Next objEnt
objSelSet.Delete
DeleteApplicationXData = True
Exit_Here:
Exit Function
Err_Control:
Select Case Err.Number
Case Else
MsgBox Err.Description
Resume Exit_Here
End Select
End Function
-
A selection set will NOT get all proxy objects. Some will live in the land of NOD (named objects dictionary) so you will have to process those as well, but VBA can't from memory.
-
I had a similar problem with proxy objects in drawings coming from outside contractors.
I ended up using Microstation to "clean up" these proxy objects.
However I was able to find them using this:
Option Explicit
Public Sub Find_Proxy()
Dim objEnt As AcadEntity
Dim intCnt As Integer
Dim iLp As Integer
Dim iDx As Integer
Dim objDic As AcadDictionary
Dim tempObj As AcadObject
For Each objEnt In ThisDrawing.ModelSpace
If objEnt.HasExtensionDictionary Then
objEnt.Color = acRed
Set objDic = objEnt.GetExtensionDictionary
iLp = objDic.Count
For iDx = 0 To iLp - 1
Set tempObj = objDic.Item(iDx)
tempObj.Delete
Next iDx
intCnt = intCnt + objDic.Count
End If
Next objEnt
Debug.Print intCnt
End Sub
-
These are a pain for me too. I just tried both of your's code and they did not work. Like Jeff said!!!
I just had a double fusion in my neck so I am not 100% at the moment. Hopefully someone will figure out a way to get them clean without having the handler.
Funny thing is it says its deleting the Genius MDT stuff, but it is still there in the drawing database viewer. I tried purging and it did no good.
I think the solution code will be exporting out what we want instead of removing what we don't. Even then, who knows?
-
This might make a good starting point:
Option Explicit
Sub main()
scanDictionary ThisDrawing.Dictionaries
scanTable ThisDrawing.DimStyles
scanTable ThisDrawing.Layers
scanTable ThisDrawing.Linetypes
scanTable ThisDrawing.TextStyles
scanObjects
End Sub
Sub scanDictionary(ByRef dictionary As Object)
Dim obj As AcadObject
For Each obj In dictionary
If obj.ObjectName Like "AcDbZombie*" Then
obj.Delete
Else
If obj.HasExtensionDictionary Then
scanDictionary obj.GetExtensionDictionary
End If
End If
Next obj
Set obj = Nothing
End Sub
Sub scanTable(ByRef table As Object)
Dim obj As Object
For Each obj In table
If obj.HasExtensionDictionary Then
scanDictionary obj.GetExtensionDictionary
End If
Next obj
Set obj = Nothing
End Sub
Sub scanObjects()
Dim block As AcadBlock
For Each block In ThisDrawing.Blocks
Dim ent As AcadEntity
For Each ent In block
If ent.ObjectName = "AcDbZombieEntity" Then
ent.Delete
Else
If ent.HasExtensionDictionary Then
scanDictionary ent.GetExtensionDictionary
End If
End If
Next ent
Set ent = Nothing
Next block
Set block = Nothing
End Sub
-
Hey Chuck,
I gave your code a walk through on some old MDT proxy stuff.
The line here:
" If obj.ObjectName Like "AcDbZombie*" Then
obj.Delete"
This caught this name, "AcDbZombieObject"
Then it refused to delete it with this error (see attached jpg):
Sorry, I could not be more help in fiuring out why it won't delete. AEven at 100% I am only maybe 5% of you guys. ;)
Also, I did bump it down to the next line and it returned:
? obj.HasExtensionDictionary
False
I have attached the drawing if someone wants see this MDT stuff. I think ADT will be worse.
-
When an ObjectARX developer designs a custom object, he gets to decide what operations will be allowed on proxies for that object when his code is not loaded. Apparently the MDT developers decided to prohibit erasure of MDT proxies (and probably all other operations as well).
I knew this would be a problem for some proxies, but I thought we might get lucky with the particular proxies Mike is confronted with. Sorry for the wild goose chase.
I believe someone else [edit] err... you I mean [/edit] mentioned exporting everything but the proxies to a new drawing. That sounds like a pretty good idea to me. In fact, the code I provided could be adapted to do just that without too much effort.
-
It was fun Chuck. It was something important, but not so important, that I could toss around to get my mind off healing. I see your point about how your code can be converted and I may give it a go in few days. I can poke around, but I can't really code right now. It does look pretty simple using your code with an opposite to delete. I know I can get clean 3D solids with an acisout, but most people want some things other than 3D solids. It would be nice to have free utility for everyone to clean the garbage out.
I really do not agree with giving a programmer the right to decide what you can delete. What is yours is yours. They do that with Macromedia/Adobe Flash. They give the creator of the content the ability to control whether or not you can stop playing the media. Although many reputable sites use this software, many more take advantage of the fact you installed it on a reputable site and now hijack your box with noise and flashing crap everywhere. It should be illegal and I bet it probably is, for both the developers of the custom object that make it undeleteable AND for the content creators that create content that the end user is prohibited from controlling. I really hate to go off on this tangent, but this crap is really pissing me off. On my last purchase of InstallShield I noticed I did not have to provide an uninstaller! Now it may be legal for a software company to give you that option, you do not have that option if you are selling software in the USA and many other countries an uninstaller is required by law.
I wonder if Owen Wengerd has a utility for cleaning this stuff out.
edit: He does. It is thirty bucks. http://www.manusoft.com/Software/SuperPurge/index.stm
Figures!
-
Owen's utility DID work on that drawing. You have to choose hard purge and specifically choose what you want to remove. Choosing all effectively removes everything, as it should. I am going to buy a copy for myself.
-
I purchased Owen's SuperPurge quite some time ago. It works great....mostly. There have been a few drawings that refused to open again after using it, so make sure you always have a valid backup first. And No, I did not report those problems to Owen, as they were on drawings that I really didn't need for much of anything so I just copied out what I did need and called it good.
-
Has anyone tried to copy the entities and save them in a new drawing using VBA?
Then saveas to overwrite the drawing with the proxy entities.
That might work every time.
John
-
Here is another attempt. It seems to work for me with ADT objects.
Sub main()
Dim sourceDoc As AcadDocument
Dim targetDoc As AcadDocument
Set sourceDoc = Application.ActiveDocument
Set targetDoc = Documents.Add
scanObjects sourceDoc, targetDoc
Application.ZoomExtents
Set targetDoc = Nothing
End Sub
Private Sub scanObjects(ByRef sourceDoc As AcadDocument, _
ByRef targetDoc As AcadDocument)
Dim block As AcadBlock
For Each block In sourceDoc.Blocks
If block.IsLayout Then
Dim index As Long
Dim objects() As AcadObject
index = -1
ReDim objects(0 To block.Count) As AcadObject
Dim ent As AcadEntity
For Each ent In block
If ent.ObjectName <> "AcDbZombieEntity" Then
If ent.HasExtensionDictionary Then
scanDictionary ent.GetExtensionDictionary
End If
index = index + 1
Set objects(index) = ent
End If
Next ent
Set ent = Nothing
If index > -1 Then
ReDim Preserve objects(index) As AcadObject
sourceDoc.CopyObjects objects, targetDoc.Blocks(block.Name)
End If
End If
Next block
Set block = Nothing
End Sub
Sub scanDictionary(ByRef dictionary As AcadDictionary)
Dim obj As AcadObject
For Each obj In dictionary
If TypeOf obj Is AcadDictionary Then
scanDictionary obj
ElseIf obj.ObjectName Like "AcDbZombie*" Then
obj.Delete
ElseIf obj.HasExtensionDictionary Then
scanDictionary obj.GetExtensionDictionary
End If
Next obj
Set obj = Nothing
End Sub
This code copies the non-proxy objects to a new drawing. The new drawing will be left open and unsaved in the editor.
-
Nice try Chuck.
It gave me this error:
After deleting the paperspace viewports the drawing then crashes with a fatal error.
The drawing is attached if you are interested. I ran it through on ACAD 2002.
Once cleaned, viewports deleted and saved, before crashing, if I close and reopen it it appears stable and the proxy warning is gone.
-
It works on MDT drawings too. Very nice! It does crash too after deleting a viewport and moving around. Not a big deal, just save the drawing, then open it, then delete allt he layout tabs and save it again.
Kind of strange, but very useful indeed.
Oh, BTW, I did not get the error in the picture above on an MDT drawing.
-
Next iteration:
Option Explicit
Private Const ERR_DUPLICATE_KEY As Long = -2145386475
Sub main()
Dim sourceDoc As AcadDocument
Dim targetDoc As AcadDocument
Set sourceDoc = Application.ActiveDocument
Set targetDoc = Documents.Add
scanObjects sourceDoc, targetDoc
Application.ZoomExtents
Set targetDoc = Nothing
End Sub
Private Sub scanObjects(ByRef sourceDoc As AcadDocument, _
ByRef targetDoc As AcadDocument)
On Error GoTo ERROR_HANDLER
Dim sourceBlock As AcadBlock
For Each sourceBlock In sourceDoc.Blocks
If Not sourceBlock.IsLayout And _
Not sourceBlock.IsXRef And _
Left(sourceBlock.Name, 1) <> "*" Then
Dim index As Long
Dim objects() As AcadObject
index = -1
ReDim objects(0 To sourceBlock.Count) As AcadObject
Dim ent As AcadEntity
For Each ent In sourceBlock
If ent.ObjectName <> "AcDbZombieEntity" Then
If ent.HasExtensionDictionary Then
scanDictionary ent.GetExtensionDictionary
End If
index = index + 1
Set objects(index) = ent
End If
Next ent
Set ent = Nothing
If index > -1 Then
Dim targetBlock As AcadBlock
Set targetBlock = targetDoc.Blocks.Add(sourceBlock.Origin, sourceBlock.Name)
ReDim Preserve objects(index) As AcadObject
sourceDoc.CopyObjects objects, targetBlock
End If
End If
Next sourceBlock
Set sourceBlock = Nothing
Dim sourceLayout As AcadLayout
For Each sourceLayout In sourceDoc.Layouts
index = -1
ReDim objects(0 To sourceLayout.block.Count) As AcadObject
For Each ent In sourceLayout.block
If ent.ObjectName <> "AcDbZombieEntity" Then
If ent.HasExtensionDictionary Then
scanDictionary ent.GetExtensionDictionary
End If
index = index + 1
Set objects(index) = ent
End If
Next ent
Set ent = Nothing
If index > -1 Then
Dim targetLayout As AcadLayout
Set targetLayout = targetDoc.Layouts.Add(sourceLayout.Name)
ReDim Preserve objects(index) As AcadObject
sourceDoc.CopyObjects objects, targetLayout.block
End If
Next sourceLayout
Set sourceLayout = Nothing
Exit Sub
ERROR_HANDLER:
Select Case Err
Case ERR_DUPLICATE_KEY
Set targetLayout = targetDoc.Layouts(sourceLayout.Name)
Resume Next
Case Else
Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
End Select
End Sub
Sub scanDictionary(ByRef dictionary As AcadDictionary)
Dim obj As AcadObject
For Each obj In dictionary
If TypeOf obj Is AcadDictionary Then
scanDictionary obj
ElseIf obj.ObjectName Like "AcDbZombie*" Then
obj.Delete
ElseIf obj.HasExtensionDictionary Then
scanDictionary obj.GetExtensionDictionary
End If
Next obj
Set obj = Nothing
End Sub
-
Works flawlessly on mDT and ADT drawings!!!!
Great job Chuck. You know your stuff.
Thank you very much for your time and sharing.
Dave
-
This is a bit off topic, but every time I see a new post in this thread, this old civil engineering type phart gets more alarmed. Have you yet determined what these proxy objects are that you are eliminating? Do you anticipate ever sending your file back to the department that created these files? Are they part of what is normally displayed in the drawing?
If I were to send you a Civil 3D drawing that had been exported to AutoCAD and you applied a routine to purge all proxy objects, you would have little more than the title block and whatever annotation that was placed in the layout tabs remaining in the drawing. Virtually everything in the model will come to you as proxy objects. These objects are protected from manipulation because ANY such tampering would render them useless if they were again opened in Civil 3D and it is doubtful they could open the drawing at all.
-
My opinion is your wrong to use any software to puts anything in drawing that is not 100% controllable by the person receiving it. Period. No if's, and's or but's.
When I work in a drawing it is mine and only mine. I will not accept anything less.
Nothing belongs in DWG that is not 100% dxf compliant across all platforms. The programmers of your custom objects should have coded what they were aiming at another way. They were were wrong to do what they did. People should not buy and use their software, effectively giving away the rights of the end user to have complete control of all data on his machine.
Again, this is my opinion, but I stand by it firmly. As far as I am concerned it is taking out the trash.
Sorry it sounds so harsh man. I am really passionate about this issue. It is nothing presonal with you at all.
-
if they were again opened in Civil 3D and it is doubtful they could open the drawing at all.
it is just a clean dwg. if they can open that, they are fine.
I am pretty sure Adesk will not be too happy with Chucks code. I can say I know of several happy people using it already.
-
Sorry it sounds so harsh man. I am really passionate about this issue. It is nothing presonal with you at all.
No problems here. The main problem is that Autodesk is trying to make non-Autodesk (catia) compatible with dwg and still do all of its magic - it is not working yet. In reality, a 2007 Civil 3D dwg file is only fully compatible with 2007 Civil 3D. Autodesk has created a situation that is just unacceptable in my opinion. if they were again opened in Civil 3D and it is doubtful they could open the drawing at all.
it is just a clean dwg. if they can open that, they are fine.
I am pretty sure Adesk will not be too happy with Chucks code. I can say I know of several happy people using it already.
I was meaning that Civil 3D may not be able to open the file again if an object were altered, a recovery sometimes will fix it but one should not depend on that working. . . even saving in something other than Civil 3D usually requires a recover operation.