Hi,
I have been trying to write an Excel VBA macro which:
1. opens all .dgn files from selected location
2.scans for all cell elements in active model
3. builds an array with found cells
4. checks if cells have tags
5. if 4 true then builds arrays with tag elements for each cell
The code below works fine until I try to access any array with tag elements. Any operation like reading or writing of any tag element array causes Excel crash every time. Excel stops working and restarts with any other error message. The tag element arrays are created correctly because I can see them in watch window while I stop program before the "crashing" program line. There are some suspicious value in the tag element array like "Subtype- attempting to perform a non-graphical operation on graphical element". Any help would be appreciated.
Option Explicit Dim directory As String, fileName As String Sub ImportStart_Click() 'PROGRAM START ExportTexts End Sub Sub ExportTexts() 'On Error Resume Next directory = GetFolder("c:\") & "\" fileName = Dir(directory & "*.dgn") Do While fileName <> "" obslugaDGN (directory & fileName) fileName = Dir Loop MsgBox "Done", vbOKOnly End Sub Sub obslugaDGN(plik As String) Dim myDGN As DesignFile Dim oAL As ApplicationObjectConnector Set oAL = New MicroStationDGN.ApplicationObjectConnector Set myDGN = oAL.Application.OpenDesignFile(plik, False) Dim ee As ElementEnumerator Dim es As ElementScanCriteria Dim elArray() As element Dim i, j As Integer Set es = New ElementScanCriteria es.ExcludeAllTypes es.IncludeType msdElementTypeCellHeader es.IncludeType msdElementTypeSharedCell Set ee = ActiveModelReference.Scan(es) elArray = ee.BuildArrayFromContents For i = LBound(elArray) To UBound(elArray) If (elArray(i).HasAnyTags) Then Dim oTags() As TagElement oTags = elArray(i).GetTags() For j = LBound(oTags) To UBound(oTags) If oTags(j).TagDefinitionName = "TAG" Then 'here Excel stops working and restarts 'procedure.... End If Next j End If Next i myDGN.Close Set myDGN = Nothing Set ee = Nothing End Sub Function GetFolder(strPath As String) As String ' function gets folder picked by user Dim fldr As FileDialog Dim sItem As String Set fldr = Application.FileDialog(msoFileDialogFolderPicker) With fldr .Title = "Select a Folder" .AllowMultiSelect = False .InitialFileName = strPath If .Show <> -1 Then GoTo NextCode sItem = .SelectedItems(1) End With NextCode: GetFolder = sItem Set fldr = Nothing End Function
Thanks,
Darius
Try changing Dim oTags() As TagElement to Dim oTags() As Variant
"Can't assign to array" Compile error
I can't speak for others but I have never had success using GetTags(). Instead I prefer not to scan for specific host elements (in your case, Normal and shared cells) but instead target the tag elements themselves i.e. instead of:
es.IncludeType msdElementTypeCellHeader es.IncludeType msdElementTypeSharedCell
try using:
es.IncludeType msdElementTypeTag
This will unlikely work with your existing code as is so you will probably need to edit your loop code suit the new scan element type.
Yes, I could use msdElementTypeTag but I do not know how to group all tags by cell they are attached to. There is the parent parameter but it seems to be empty. Please note that one drawing may have 2 or more the same cells with the same tag set attached. The goal is to update all tags of the tagset if the value of one tag meets my criteria.
Unknown said:Dim oTags() As TagElement to Dim oTags() As Variant
No! It makes the code worse and dirty. It's defined that GetTags method returns TagElement(), so if there is an error, it will be not caused by correctly declared variable.
To use Variant is (with a couple of exceptions) seriously bad practice and always lead to worse code.
Unknown said:I can't speak for others but I have never had success using GetTags().
I recall I used it several times in the past, both in VBA and C#, and it works fine.
Unknown said:Instead I prefer not to scan for specific host elements (in your case, Normal and shared cells) but instead target the tag elements themselves
It's different approach that provides different results (existing elements vs. existing tags) and it depends on a local conditions and requirements what is better.
Unknown said:Any help would be appreciated.
Are you sure the tag is attached to cell header? I assume it's attached to a graphics element inside the cell. Can you provide an example of the file?
One more question, not related to the discussed issue: Is there any reason to use .BuildArrayFromContents? It increases memory requirements a lot.
With regards,
Jan
Bentley Accredited Developer: iTwin Platform - AssociateLabyrinth Technology | dev.notes() | cad.point
>>I assume it's attached to a graphics element inside the cell
You are right. I found those criteria online and I am not sure they are correct.
>>Is there any reason to use .BuildArrayFromContents?
No there is no particular reason. As well I found it online. I tried also regular Do While oEnumerator.MoveNext with the same devastating result. As I said both arrays with cells and their tag elements are created correctly since I can look into them if I interrupt the program. I am an amateur programmer and all suggestions how to alter the program are appreciated
Thanks
good morninga small example of my tag update if useful
update_tag.zip
Ciao
Unknown said:You are right. I found those criteria online and I am not sure they are correct.
The criteria itself is correct, but the next step not. You have to iterate through elements inside cell to find element(s) with tag(s). The cell header is not graphical element, so GetTags returns I guess nothing, but
An example how your cells with tags look like would be helpful.
Is there always one element with tag inside cell or there can be more?
Unknown said:No there is no particular reason.
In such case don't use it. To build an array upfront requires substantial more memory, is slower and is necessary only when elements during the iteration are modified in such way they have to be rewritten to the end of file. Which I suppose is not this case.
Unknown said:As I said both arrays with cells and their tag elements are created correctly since
In such case there is a contradiction, because it means the tags are attached to cell headers. not inside the cell. But if you are sure this part of the code works, it's fine.
Unknown said:all suggestions how to alter the program are appreciated
You code highly depends on the data and its structure, but you have not shared any file example, so it's hard to provide any guess why it does not work.
Regards,
Unknown said:The code below works fine until I try to access any array with tag elements
I suggest that you move your code into a MicroStation VBA macro. See if it works there, before attempting to control MicroStation from Excel. If it doesn't work in MicroStation VBA, it definitely won't work in Excel VBA.
Regards, Jon Summers LA Solutions
Jon, Jan,
After stripping out the code (.filedialog doesn't work with MS anyway) and running it with already open dgn, it works fine. I will upload tomorrow the library with questionable cell.
Option Explicit Dim directory As String, fileName As String Sub ImportStart_Click() 'PROGRAM START obslugaDGN End Sub 'Sub ExportTexts() ''On Error Resume Next ' ''directory = GetFolder("c:\") & "\" 'fileName = Dir(directory & "*.dgn") 'Do While fileName <> "" ' obslugaDGN (directory & fileName) ' fileName = Dir 'Loop 'MsgBox "Done", vbOKOnly 'End Sub Sub obslugaDGN() 'Dim myDGN As DesignFile 'Dim oAL As ApplicationObjectConnector 'Set oAL = New MicroStationDGN.ApplicationObjectConnector 'Set myDGN = oAL.Application.OpenDesignFile(plik, False) Dim ee As ElementEnumerator Dim es As ElementScanCriteria Dim elArray() As Element Dim i, j As Integer Set es = New ElementScanCriteria es.ExcludeAllTypes es.IncludeType msdElementTypeCellHeader es.IncludeType msdElementTypeSharedCell Set ee = ActiveModelReference.Scan(es) elArray = ee.BuildArrayFromContents For i = LBound(elArray) To UBound(elArray) If (elArray(i).HasAnyTags) Then Dim oTags() As TagElement oTags = elArray(i).GetTags() For j = LBound(oTags) To UBound(oTags) If oTags(j).TagDefinitionName = "TAG" Then 'here Excel stops working and restarts MsgBox "yes" 'procedure.... End If Next j End If Next i 'myDGN.Close 'Set myDGN = Nothing Set ee = Nothing End Sub 'Function GetFolder(strPath As String) As String ' function gets folder picked by user 'Dim fldr As FileDialog 'Dim sItem As String 'Set fldr = Application.FileDialog(msoFileDialogFolderPicker) 'Set fldr = Application.fo 'With fldr ' .Title = "Select a Folder" ' .AllowMultiSelect = False ' .InitialFileName = strPath ' If .Show <> -1 Then GoTo NextCode ' sItem = .SelectedItems(1) 'End With 'NextCode: 'GetFolder = sItem 'Set fldr = Nothing 'End Function
Thanks Jon and Jan for all your input. If you have any suggestion how to find and hold tag sets by value of one tag, please let me know