Questions similar to this appear on the Bentley Discussion Groups. This problem appeared in the MicroStation Programming Forum.
Q Sometimes you need to verify programatically that a file is, or is not,
compatible with MicroStation® before attempting to open it.
Although we mentally associate a file having a .dgn
extension with MicroStation, that concept is not cast in stone.
What if someone in your organisation has decided that .dgn
means something else, such as a diagnostic log?
What if you want to build a list of DGN files, for subsequent batch processing, from one or more folders
when those folders contain a mix of drawings, spreadsheets, text files and other documents?
A MicroStation VBA does not include a method that can check a file before opening it. However, such a function does exist in the C++ MicroStationAPI (formerly MDL), and it's easy enough to use it in VBA if you know how. This article shows you how!
Before looking at the MicroStation VBA solution, note that the code shown on this page will not work with VBA in other applications such as Excel™ or Word™. However, an alternative solution exists for those cases.
The example below uses the functionality provided by the Microsoft Scripting Runtime DLL. This library is provided with Windows and is almost certainly installed on your computer.
We describe how to reference and use Microsoft Scripting Runtime.
Although MicroStation VBA does not include a method to test an unopened file, the MicroStationAPI does include one.
mdlFile_validDesignFile
does exactly what we want, but we must write some slightly unusual VBA code
in order to be able to use it.
When you use an MDL or other foreign function in VB or VBA you must Declare
it.
Declare
is a VB keyword that tells the compiler about the function's arguments,
and which DLL contains the implementation of that function. You can find more about Declare
in VBA help.
The following VBA code wraps the MDL function so it's easy to use.
The Main
entry point simply passes the keyin argument to the VBA function that does the real work: CanMicroStationOpen
.
CanMicroStationOpen
returns True
if MicroStation can open the specified file, whether it
be a V7 or V8 MicroStation design file, or an AutoCAD® DWG or DXF file.
To use this code, follow these steps…
CheckFile
vba run CheckFile.Main <file path>
Option Explicit' --------------------------------------------------------------------- ' Module CheckFile includes MicroStation VBA code that enables you ' to test a file before attempting to open it in MicroStation. This ' lets you verify that it's a valid design file, irrespective of its ' file extension (i.e. A .DGN file may not really be a design file, ' and a .XYZ file could be a DGN file with an unusual extension). ' ' The real work is done by function CanMicroStationOpen. The Main ' subroutine provides an interactive test capability ' ' Function IsWritable tests a file to see whether it is read-only or ' available for modification. This function references Microsoft's ' Scripting Runtime library. The comments preceding the function ' decribe how to reference that library ' ' ---------------------------------------------------------------------
Const MODULE_NAME As String = "CheckFile"' --------------------------------------------------------------------- ' Notice: ' This code is supplied for illustration purposes by LA Solutions Ltd. ' It is neither licensed nor supported. You are free to copy this ' code for your own use provided this notice is retained in full. ' Visit our web site for more hints and tips about MicroStation VBA: ' www.la-solutions.co.uk/content/Publications.htm ' --------------------------------------------------------------------- ' MDL function declarations ' ---------------------------------------------------------------------
Declare PtrSafe Function mdlFile_validDesignFile Lib "stdmdlbltin.dll" ( _ ByVal pThreeD As LongPtr, _ ByVal pFormat As LongPtr, _ ByVal pMajorVersion As LongPtr, _ ByVal pMinorVersion As LongPtr, _ ByVal ppThumbnail As LongPtr, _ ByVal pThumbnailSize As LongPtr, _ ByVal pfilePath As String) As Long
Option Explicit' --------------------------------------------------------------------- ' Main ' Main entry point. Provide a file name with the MicroStation keyin ' when calling this module. For example: ' vba run CheckFile.Main C:\projects\project1\dgn\myfile.dgn ' ---------------------------------------------------------------------
Public Sub Main() Const PROC_NAME As String = "Main" On Error GoTo err_Main Dim filePath As String filePath = KeyinArguments ' Must be a complete path specification If (0 < Len(filePath)) Then' Test whether MicroStation understands this file type
If (CanMicroStationOpen(filePath)) Then' Do something with file
End If Else' Advise user of correct command-line syntax
Dim msg As String msg = "CheckFile: keyin ""vba run CheckFile.Main""" ShowMessage msg, msg, msdMessageCenterPriorityWarning End If ' Test whether this file can be opened for writing
If (IsWritable(filePath)) Then msg = "File'" & filePath & "' may be opened for modification" ShowMessage msg, msg, msdMessageCenterPriorityInfo Else msg = "File'" & filePath & "' can be opened read-only" ShowMessage msg, msg, msdMessageCenterPriorityWarning End If Exit Sub err_Main: ReportError PROC_NAME, MODULE_NAME End Sub
Option Explicit
' ---------------------------------------------------------------------
' CanMicroStationOpen
' This is a wrapper around the MDL function mdlFile_validDesignFile
' Args:
' Full path of file to test
' Returns: True if file can be opened by MicroStation
' ---------------------------------------------------------------------
Public Function CanMicroStationOpen(ByVal filePath As String) As Boolean
CanMicroStationOpen = False
On Error GoTo err_CanMicroStationOpen
Const PROC_NAME As String = "CanMicroStationOpen"
Dim threeD As Long, _
format As Long, _
major As Long, _
minor As Long
Dim msg As String
If (0 <> mdlFile_validDesignFile(threeD, format, major, minor, 0, 0, filePath)) Then
Dim dimension As String
If (threeD) Then
dimension = "3D"
Else
dimension = "2D"
End If
Select Case format
' Note: msdDesignFileFormatV7 is invalid from MicroStation CONNECT Update 17
'Case msdDesignFileFormatV7
'msg = "'" & filePath & "' is a " & dimension & " V7 DGN file"
Case msdDesignFileFormatV8
msg = "'" & filePath & "' is a " & dimension & " V8 DGN file"
Case msdDesignFileFormatDWG
msg = "'" & filePath & "' is a DWG file"
Case msdDesignFileFormatDXF
msg = "'" & filePath & "' is a DXF file"
End Select
ShowMessage msg, msg, msdMessageCenterPriorityInfo
CanMicroStationOpen = True
Else
msg = "'" & filePath & "' is not a MicroStation design file"
ShowMessage msg, msg, msdMessageCenterPriorityWarning
End If
Exit Function
err_CanMicroStationOpen:
ReportError PROC_NAME, MODULE_NAME
End Function
Option Explicit
' ---------------------------------------------------------------------
' IsWritable
' Determine whether a particular file is read-write or read-only.
' This function is generic: it just tests a file without concern for its type
'
' This function references Microsoft's Scripting Runtime library (scrrun.dll),
' which provides an invaluable library of functions for file and
' folder interrogation and manipulation
'
' Use VBA's Tools|References menu to pop the References dialog.
' Search for "Microsoft Scripting Runtime" and check the box beside it.
'
' Returns: True if file is read-write
' ---------------------------------------------------------------------
Public Function IsWritable(ByVal filePath As String) As Boolean
IsWritable = False
On Error GoTo err_IsWritable
Const PROC_NAME As String = "IsWritable"
Dim oFileSystem As New Scripting.FileSystemObject
If (oFileSystem.FileExists(filePath)) Then
Dim oFile As Scripting.File
Set oFile = oFileSystem.GetFile(filePath)
If (Not (oFile.Attributes And ReadOnly) = ReadOnly) Then
IsWritable = True
End If
Set oFile = Nothing
End If
Set oFileSystem = Nothing
Exit Function
err_IsWritable:
ReportError PROC_NAME, MODULE_NAME
End Function
Option Explicit
' ---------------------------------------------------------------------
' ReportError provides generic error-reporting functionality
' ---------------------------------------------------------------------
Public Sub ReportError(ByVal procName As String, ByVal moduleName As String)
MsgBox "Error no. " & CStr(Err.Number) & ": " & Err.Description, vbOKOnly Or vbCritical, "Error in " & moduleName & ":" & procName
End Sub
Post questions about MicroStation programming to the MicroStation Programming Forum.