Dear VBA Experts,
I am trying to write some codes which will help me batch process levels visibility on multiple models in several DGN files. The codes I have written is posted below. My codes work perfectly fine when I open the DGN and activate each models at least once. But as a part of the batch process this code only works on the active model but throws error when I refer to other models in the DGN file. I come to realize that in non-active models the references are not loaded. How can I edit this code so I can tell MicroStation to load all references so that the codes will find whats it looking for. In this case the levels in the referenced file.
I tried activating models before it moves on to next model but with no luck. It breaks with an error message saying the reference index were not found. Any help or thoughts would be great.
Sincerely,
Rabi
Option Explicit Private Declare Function mdlModelRef_loadReferenceModels Lib "stdmdlbltin.dll" (ByVal modelRef As Long, _ ByVal loadCache As Long, ByVal loadRasterRefs As Long, ByVal loadUndisplayedRefs As Long) As Long Sub ControlLayerVisibility()
'On Error Resume Next Dim myDGN As DesignFile Set myDGN = Application.ActiveDesignFile Dim myActiveModel As ModelReference Dim oAtt As Attachment 'Determine the sheet model with msdModelTypeSheet property Dim modelCount As Integer Dim myModel As String Dim tempString As String Dim myView As View For modelCount = 1 To myDGN.Models.Count If myDGN.Models(modelCount).Type = msdModelTypeSheet Then tempString = myDGN.Models(modelCount).Name Dim myLevel As String Dim myModelLogicalName As String Dim myAttachmentIndex As Integer Dim i As Integer If InStr(1, tempString, "RECORD") > 0 Then myModel = myDGN.Models(modelCount).Name 'Determine the Attachment Index and run the levels. ' For i = 1 To myDGN.Models(myModel).Attachments.Count ' 'Debug.Print myDGN.Models(myModel).Attachments(i).AttachName ' If myDGN.Models(myModel).Attachments(i).AttachName = "50014746_TB 30x42.dgn" Then ' myAttachmentIndex = i ' myModelLogicalName = myDGN.Models(myModel).Attachments(myAttachmentIndex).AttachName ' End If ' Next Set myActiveModel = myDGN.Models(myModel) 'myActiveModel.Activate Set myActiveModel = myActiveModel.DesignFile.Models("50014746_TB 30x42.dgn") mdlModelRef_loadReferenceModels myActiveModel.MdlModelRefP, 1, 1, 1 Set oAtt = myActiveModel.Attachments("default") 'If myActiveModel.IsReadOnly = True Then 'myDGN.Models(myModel).Activate For Each myView In myDGN.Views oAtt.Levels("G-ANNO-TTLB-NO AS BUILT").IsDisplayed = True oAtt.Levels("G-ANNO-TTLB-NO AS BUILT").IsDisplayedInView(myView) = True oAtt.Levels("G-ANNO-TTLB-AS BUILT").IsDisplayed = False oAtt.Levels("G-ANNO-TTLB-AS BUILT").IsDisplayedInView(myView) = False ' myDGN.Models(myModel).Attachments(myAttachmentIndex).Levels("G-ANNO-TTLB-NO AS BUILT").IsDisplayed = True ' myDGN.Models(myModel).Attachments(myAttachmentIndex).Levels("G-ANNO-TTLB-NO AS BUILT").IsDisplayedInView(myView) = True ' myDGN.Models(myModel).Attachments(myAttachmentIndex).Levels("G-ANNO-TTLB-AS BUILT").IsDisplayed = False ' myDGN.Models(myModel).Attachments(myAttachmentIndex).Levels("G-ANNO-TTLB-AS BUILT").IsDisplayedInView(myView) = False ' 'myLevel = "LEVEL SET DISPLAY ON file:" & myModelLogicalName & " """ & Row.Value & """" myView.Redraw Next myView 'End If 'Close the file appropriately myDGN.Models(myModel).Levels.Rewrite CadInputQueue.SendCommand "FILEDESIGN" CadInputQueue.SendCommand "SAVE DESIGN" End If End If Next End Sub
'On Error Resume Next
Dim myDGN As DesignFile Set myDGN = Application.ActiveDesignFile
Dim myActiveModel As ModelReference Dim oAtt As Attachment
'Determine the sheet model with msdModelTypeSheet property Dim modelCount As Integer Dim myModel As String Dim tempString As String Dim myView As View
For modelCount = 1 To myDGN.Models.Count If myDGN.Models(modelCount).Type = msdModelTypeSheet Then tempString = myDGN.Models(modelCount).Name Dim myLevel As String Dim myModelLogicalName As String Dim myAttachmentIndex As Integer Dim i As Integer
If InStr(1, tempString, "RECORD") > 0 Then myModel = myDGN.Models(modelCount).Name 'Determine the Attachment Index and run the levels. ' For i = 1 To myDGN.Models(myModel).Attachments.Count ' 'Debug.Print myDGN.Models(myModel).Attachments(i).AttachName ' If myDGN.Models(myModel).Attachments(i).AttachName = "50014746_TB 30x42.dgn" Then ' myAttachmentIndex = i ' myModelLogicalName = myDGN.Models(myModel).Attachments(myAttachmentIndex).AttachName ' End If ' Next Set myActiveModel = myDGN.Models(myModel) 'myActiveModel.Activate Set myActiveModel = myActiveModel.DesignFile.Models("50014746_TB 30x42.dgn") mdlModelRef_loadReferenceModels myActiveModel.MdlModelRefP, 1, 1, 1
Set oAtt = myActiveModel.Attachments("default") 'If myActiveModel.IsReadOnly = True Then 'myDGN.Models(myModel).Activate For Each myView In myDGN.Views oAtt.Levels("G-ANNO-TTLB-NO AS BUILT").IsDisplayed = True oAtt.Levels("G-ANNO-TTLB-NO AS BUILT").IsDisplayedInView(myView) = True oAtt.Levels("G-ANNO-TTLB-AS BUILT").IsDisplayed = False oAtt.Levels("G-ANNO-TTLB-AS BUILT").IsDisplayedInView(myView) = False ' myDGN.Models(myModel).Attachments(myAttachmentIndex).Levels("G-ANNO-TTLB-NO AS BUILT").IsDisplayed = True ' myDGN.Models(myModel).Attachments(myAttachmentIndex).Levels("G-ANNO-TTLB-NO AS BUILT").IsDisplayedInView(myView) = True ' myDGN.Models(myModel).Attachments(myAttachmentIndex).Levels("G-ANNO-TTLB-AS BUILT").IsDisplayed = False ' myDGN.Models(myModel).Attachments(myAttachmentIndex).Levels("G-ANNO-TTLB-AS BUILT").IsDisplayedInView(myView) = False ' 'myLevel = "LEVEL SET DISPLAY ON file:" & myModelLogicalName & " """ & Row.Value & """" myView.Redraw Next myView 'End If 'Close the file appropriately myDGN.Models(myModel).Levels.Rewrite
CadInputQueue.SendCommand "FILEDESIGN" CadInputQueue.SendCommand "SAVE DESIGN"
End If
Next
End Sub
Rabi: Set myActiveModel = myDGN.Models(myModel) 'myActiveModel.Activate Set myActiveModel = myActiveModel.DesignFile.Models("50014746_TB 30x42.dgn")
Set myActiveModel = myDGN.Models(myModel) 'myActiveModel.Activate Set myActiveModel = myActiveModel.DesignFile.Models("50014746_TB 30x42.dgn")
Code like the above is confusing. You first set myActiveModel, but you don't activate it (.Activate is commented). You then attempt to set it to another value, which is probably invalid — do you really have a model named "50014746_TB 30x42.dgn"? Finally, you don't attempt to activate the new assignment, which explains why you cannot find any attachments.
Put a few Debug statements in there to let you trace the progress of your code. Also, test for valid assignments:
Set myActiveModel = myActiveModel.DesignFile.Models("50014746_TB 30x42.dgn")
will almost certainly result in a NULL model.
Dim strModelName As String strModelName = "abc" Dim oModel1 As ModelReference Dim oModel2 As ModelReference Set oModel1 = myDGN.Models(strModelName) Debug.Assert (Not oModel1 Is Nothing) oModel1.Activate Debug.Print "Activated model '" & oModel1.Name & "'" Set oModel2 = oModel1.DesignFile.Models("model name") Debug.Assert (Not oModel2 Is Nothing) oModel2.Activate Debug.Print "Iterating model '" & oModel2.Name & "' Attachments" …
Regards, Jon Summers LA Solutions
oModel1.Activate gives exception 'bad argument'
Marty Robbins
Unknown said:Can you use oModel1.Activate if you open a dgn file using OpenDesignFileForProgram?
The purpose of OpenDesignFileForProgram is to enable a macro to do things with a model that require no user interaction. ModelReference.Activate implies that a user has access to an active model. It's best to regard the two cases as mutually exclusive.
Jon,
To clarify, I did not want any explicit user interaction for the models. I want programattic interaction for a batch processing of a set of dgn files and an iteration of the dgn file models. I would like to iterate over a set of dgn files and in each dgn file iterate over the models - make changes, rewrite and save the dgn files. The OpenDesignFileForProgram would a have been more appropriate and pleasant for the user experience versus having each dgn physically open using OpenDesignFile.
I understand that models cannot be activated using OpenDesignFileForProgram and can be activated using OpenDesignFile. However, in both cases the models are read-only even when the dgn is opened using OpenDesignFile and the model is activated. When an attempt to re-write a changed element I recieve a file access error. I.e., ele(I).rewrite. Debuging shows the initial element and the element after change. This showed that element did change in the model, but it could not be re-writtened to the model.
Tested using OpenDesignFile as shown...
The full name of each dgn is stored as key in the fileDictionary dictionary
Private Sub DgnIteration
'Open Design file in dgn dictionary set
For Each kvpFileDictionary As KeyValuePair(Of String, String) In fileDictionary
model(ustn.OpenDesignFile(kvpFileDictionary.Key, True))
Private Sub model(dgn As Bentley.Interop.MicroStationDGN.DesignFile)
Dim oModel As Bentley.Interop.MicroStationDGN.ModelReference
Dim oModels As Bentley.Interop.MicroStationDGN.ModelReferences
oModels = dgn.Models
For Each oModel In oModels
oModel.Activate()
ModelScan(oModel)
Private Sub ModelScan(oModel As Bentley.Interop.MicroStationDGN.ModelReference)
Dim oScanEnumerator As Bentley.Interop.MicroStationDGN.ElementEnumerator
Dim ele() As Bentley.Interop.MicroStationDGN.Element
oScanCriteria.ExcludeNonGraphical()
oScanEnumerator = oModel.Scan(oScanCriteria)
ele = oScanEnumerator.BuildArrayFromContents
Dim i As Integer
For i = 0 To UBound(ele)
If ele(i).IsTextElement Then
ele(i).AsTextElement.Text = "Test"
ele(i).Rewrite()
ele(I).Rewrite() produces the following exception...
System.Runtime.InteropServices.COMException was unhandled by user code
ErrorCode=-2147218396
Message=File is read-only
Source=""
StackTrace:
at Bentley.Interop.MicroStationDGN.Element.Rewrite()
at reptext.ReplaceTextForm.ModelScan(ModelReference oModel) in C:\Documents and Settings\robbinsm000\My Documents\Visual Studio 2010\Projects\reptext\reptext\ReplaceTextForm.vb:line 608
at reptext.ReplaceTextForm.model(DesignFile dgn) in C:\Documents and Settings\robbinsm000\My Documents\Visual Studio 2010\Projects\reptext\reptext\ReplaceTextForm.vb:line 648
at reptext.ReplaceTextForm.btnReplaceAll_Click(Object sender, EventArgs e) in C:\Documents and Settings\robbinsm000\My Documents\Visual Studio 2010\Projects\reptext\reptext\ReplaceTextForm.vb:line 395
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
InnerException:
I notice that you're using VB.NET rather than pure VBA. Are you building a stand-alone executable (.exe) or an add-in (.dll)?
The current one is an add-in, but I plan on a similar process in a stand alone exe. I can do both, but I have these small hurdles to overcome.
Unknown said:ustn.OpenDesignFile(kvpFileDictionary.Key, True)
That line instructs MicroStation to open the file read-only! From VBA Help ...
I was sure I had the parameter as False at one time. That was it... Thanks. Now I only I have to deal with and live with the fact the each dgn file must be phyiscally opened to modify their respective models. I will call this a programmatic limitation.
Unknown said: Each dgn file must be phyiscally opened to modify their respective models. I will call this a programmatic limitation
You can't do anything to the contents of any file unless you open it first. For example, change 'DGN' to 'Word document'. To review, print or edit a document you must open it using an application (usually, in this example, Word), with minimum access right 'read-only'. If you want to edit a document you must open it with 'read-write' access. A DGN file is no different.
Marty,
You should look into batch process to apply all your changes to mulitiple files. Batch Process will open make the change close each file. It will take minutes to process many files.
Good luck, Roland
Roland
V8i SS4 v.08.11.09,829AECOsim BD V8i
Roland,
I am basically doing a batch process. However, initially I did not want to physicall open the file, The program does work now.
I have another question... For Roland, Jon or whomever. I could find a forum to post this question to, so if it is not the correct location for this question, please redirect me.
My addin works correct on local installs and I have a installation package that I send out to my end users. However, I have been attempting to install this on the network. Of course I get this message
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Security.SecurityException: That assembly does not allow partially trusted callers.
at fwdptrem.fwdptrem.vbAddInMain..ctor(IntPtr mdlDesc)
The action that failed was:
Our IT department has our Intranet security set to low. This can not be changed.
I signed the dll using the Bentley SDK dllsign.exe and separatley signed the dll using the visual studio tools signtool.exe and I assigned the dll a Strong Name using the SN.exe tool and project propeties.
In my AssemblyInfo.vb, as shown, I am allowing partially trusted callers -
<Assembly: ComVisible(False)>
'The following GUID is for the ID of the typelib if this project is exposed to COM
<Assembly: Guid("6afecf8b-0653-4f64-b708-d0efe4db8a50")>
'<Assembly: AssemblyVersion("1.1.2.1")>
<Assembly: AssemblyFileVersion("1.1.2.1")>
'<Assembly: CLSCompliant(True)>
<Assembly: Security.AllowPartiallyTrustedCallers()>
Note this is signed with a test certificate, If this makes a difference. My digital signatures states that the signature is OK.
Unknown said:My addin works correct on local installs and I have a installation package that I send out to my end users. However, I have been attempting to install this on the network.
This is a Microsoft .NET generic question of security on networks. It doesn't apply specifically to MicroStation.
Microsoft prefers that a user cannot execute an EXE or DLL across a network. I believe that in the extreme case — where the executable resides on a public network — there's no way to get around that security. You can't execute a DLL on a public network, and that's that.
On 'trusted' networks, you (by which I mean network admin.) have the option of lowering security to permit invocation of remote DLLs. However, as you have found, this boils down to what your IT people think of as 'safe'. If IT have a policy that any DLL other than one installed locally is a security risk, then you have no option but to install your DLL individually on each & every computer, where needed, in the organisation. However, IT should also be able to tell you how to distribute your installation package, and they may even be able to deploy your DLL for you.
Signatures and manifests don't come into this.