Questions similar to this appear on the Bentley Discussion Groups. These appeared in the VBA discussion group.

Q Level Libraries (DGNLIBs)

A MicroStation administrative facilities include level libraries, also known as DGNLIBs, as a way to provide consistent settings and symbology in your projects.

A level library has a predefined set of named levels, complete with line colour, weight, and style definitions. Your workspace may attach one or multiple level libraries. They make it easy for your MicroStation users to use consistent settings. A level library is attached to your DGN model as a special sort of reference model, whose settings you can see but can't modify. A level library differs from a normal reference model in that you can see its levels but you don't see any graphics elements.

A level library is a design file with a .dgnlib extension. You can open a level library with MicroStation just like any other DGN file. Typically, a system administrator would do just that when defining levels. Because a user never sees the graphics in a level library, the administrator is free to include graphics in the DGNLIB such as, for example, a legend. It's not a bad idea to include a legend in each DGNLIB, which displays an element for each level definition, maybe with some annotation that describes the purpose of that level and its symbology. That way, it's easy to see your symbology definitions and it becomes easier to publish your standards: just print the DGNLIB to an Adobe PDF and put it in a public place on your Intranet.

Configuration Variables

Level libraries and DGNLIBs are synonymous. This can lead to some confusion because when you discuss DGNLIBs, your listener may not realise that you are talking about level libraries, and vice versa. In fact, there is already some confusion at Bentley Systems, evidenced by the names of configuration variables (CfgVars) used to define folders and files related to level libraries.

MS_LEVEL_LIB_DIR is the CfgVar that defines the folder or folders that contain level libraries. For example …

MS_LEVEL_LIB_DIR	= //server/projects/standards/dgnlibs/

MS_DGNLIBLIST is the CfgVar that defines a list of level libraries for a workspace. For example …

MS_DGNLIBLIST = $(MS_LEVEL_LIB_DIR)electrical.dgnlib
MS_DGNLIBLIST > $(MS_LEVEL_LIB_DIR)mechanical.dgnlib

You can see information about level libraries from the Configuration dialog that pops when you choose MicroStation's Workspace|Configuration menu. The value of MS_LEVEL_LIB_DIR is shown when you select the Levels category …

The value of MS_DGNLIBLIST is shown when you select the Primary Search Paths category …

Finding DGNLIBs with VBA

How do I find DGNLIBs with VBA? If you scan referenced models, you won't find them. The Attachments collection doesn't include level libraries.

MDL to the rescue!

As is usual, MDL provides ways to do things in MicroStation that are sometimes missing in VBA. In this case, there are MDL functions that work with DGNLIBs that have no direct VBA equivalent. Fortunately, it's possible to use MDL functions from a VBA macro.

In order to use an MDL function in VBA, it's necessary to Declare the function, along with the library (or DLL) that contains its implementation. The following declarations should go at the beginning of your VBA code, before any procedure (subroutine or function) definitions …

Declare PtrSafe Function mdlLevelLibrary_getFirst Lib "stdmdlbltin.dll" () As Long
Declare PtrSafe Function mdlLevelLibrary_getName Lib "stdmdlbltin.dll" (ByVal pLibraryNameOut As Long, ByVal stringSizeIn As Long, ByVal pLibraryRefIn As Long) As Long
Declare PtrSafe Function mdlLevelLibrary_getNext Lib "stdmdlbltin.dll" (ByVal pLibraryRefIn As Long) As Long

The following code snippet uses the MDL functions we've declared to iterate the list of level libraries attached to the current DGN model. mdlLevelLibrary_getFirst obtains a pointer to the first level library. mdlLevelLibrary_getNext uses the current value of that pointer to find the next library. mdlLevelLibrary_getName does what you expect, but it's camouflaged by some syntactic sugar we have to sprinkle around it to convert the Unicode string it finds to something that VBA can understand …

Function IterateLevelLibs() As Long
    Dim iterator        As Long
    Dim levelLib        As Long
    Dim status          As Long
    Const Length        As Integer = 255
    Dim lngLength       As Long
    Dim fileName        As String * Length
    Dim name            As String
    Dim vtName          As Variant
    fileName = String(Length, vbNull)

    levelLib = mdlLevelLibrary_getFirst()
    Do While 0 <> levelLib
        vtName = StrConv(fileName, vbFromUnicode)
        mdlLevelLibrary_getName StrPtr(vtName), Length, levelLib
        name = StrConv(vtName, vbUnicode)
        Debug.Print "Level Library '" & vtName & "'"
        levelLib = mdlLevelLibrary_getNext(levelLib)
    Loop
End Function

Macro Output

In this example, we're doing nothing more useful than to trace the level library names with Debug.Print …

Level Library 'X:\ … \Architectural\dgnlib\Architectural.dgnlib'
Level Library 'X:\ … \Civil\dgnlib\Civil.dgnlib'