Document Type: TechNote
Product(s): MicroStation
Version(s): V8
Original Author: Bentley Technical Support Group
Online documentation and examples for MicroStation's programming tools (e.g. MDL, Java, JMDL, Swing, etc.) are in a separate delivery available via SELECTservices Online Web Downloads and MySELECT CD. Note that the programming tools themselves are included with the MicroStation V8 delivery. Important information regarding VBA, MicroStation BASIC, and User Commands can be found in MicroStation V8's ReadMe.
A general overview of V8 changes affecting MDL applications
Almost all MDL applications will need to be modified to run with MicroStation V8. The amount of work required to adapt an application depends upon the technology that it uses, the degree to which it interacts with DGN file graphical or control elements, and the method that it uses to interact with such elements. At a minimum, all applications must be recompiled. In extreme cases, where elements are directly manipulated without the aid of MicroStation's API, substantial rework may be necessary. Bentley anticipates that most applications can be adapted with relatively simple changes to data types, with no change to program flow or logic.
The MicroStation V8 development environment requires the following environment variables be set for successful MDL compilation:
These variables are automatically set when you use the MicroStation V8 Development Shell that is delivered with MicroStation. Bentley highly recommends that you use this Development Shell and encourages its use as the basis for any custom development environments.
The MDL compiler in MicroStation V8 provides significant assistance in the upgrading of MDL applications for use in V8. By default, the compiler is set to be strict, meaning that all functions are required to have prototypes. MicroStation's prototypes can be found in .fdf or .h files located in the MDL include directory. Also, the V8 MDL compiler checks for unused and un-initialized variables. And as part of the language update, MDL supports the const
keyword and enum
types.
In V8, the global TCB structure has changed. Some previously accessible structures are no longer public, some have been removed, and some have been changed. If your application accessed information about MicroStation directly through the TCB, you may have to make some code changes for V8.
There are various API calls that provide information previously accessible only through public structures (like TCB). For example, view information that used to come directly from the TCB is available by calling mdlView_getParameters(), and can be modified by calling other mdlView_... functions.
As a general rule to follow: it is ALWAYS safer and more preferable to accomplish a task using API functions rather than directly accessing public static structures. The public static structures you access directly in this version of V8 may not be present in a later version.
MicroStation stores all strings internally as Unicode (using the type "MSWChar *" rather than "char *"). This provides support for character sets necessary for many foreign languages.
The API for the following MDL function areas have changed:
The primary change to these calls is to take MSWChar * strings instead of char * strings. This enables you to store Unicode names in the DGN file for all entities with names. Also, these functions have been added to aid in the conversion process.
There are also standard C functions available for swscanf, wtoi, wtol, wcscpy, wcscmp, mdlwcscmpi among others which can be called for string manipulation. For MDL, a version of swprintf and the ability to do L"name" to create a wide character string is being developed.
The user interface for entering text does not support inputting strings in Unicode format, so strings must be converted to Unicode. The mdlCnv_convertMultibyteToUnicode() function does this nicely, and conversely mdlCnv_convertUnicodeToMultibyte() does the reverse. Also, TrueType fonts can be stored. Since a text element can be significantly larger that previous versions it might be useful to allocate the buffer for the actual character string at runtime as opposed to a statically defined buffer. To do this you can get the number of characters from the text element. This number of characters can then be multiplied by two and then add one to get the max size in bytes of the string.
The Dialog Manager and Resource Manager have been enhanced to support Unicode strings, in addition to Multibyte strings, as Text item values, ListCell and GuiTreeCell values, and GUI item label, flyover, balloon, disabledBalloon and popupMenu text. Outstanding enhancements include window titles and MLText item values. This was accomplished by either adding ValueDescr variables or replacing char * variables with ValueDescr variables. The ValueDescr structure is defined in vartypes.h and contains a format type and value union. Multibyte strings have a format type of FMT_STRING; Unicode strings have a format type of FMT_MSWCHAR. The MDL API has been enhanced to provide functions for this new feature.
MicroStation automatically converts elements from V7 DGN to V8 DGN format when a V7 file is opened. However, application-specific user attribute linkages on elements are not converted because MicroStation can not interpret their literal meaning. MDL applications should convert these linkages in a manner that best suits them. For instance, when a V8 MicroStation Modeler solid containing V7 linkages is edited by the user, Modeler removes the old linkage and replaces it with a newer version. Typically, the difference between V8 and pre-V8 linkages exists due to:
For example:
/* V7 ... note color, weight, style are certain bits of a Ulong */typedef struct symbologyLinkageData_v7 { ElementID tag; struct { ULong weight:5; ULong style:3; ULong color:8; ULong unused:16; } symb; } SymbologyLinkageData_v7;/* V8 ... color, weight, style are assigned larger sizesand tag, which is an element assoc id, is larger */typedef struct symbologyLinkageData { ElementID tag; ULong weight; long style; ULong color; } SymbologyLinkageData;
In V8, DGN files can contain more than one model. Applications can take advantage of multiple models, but most applications can work only on the active model and its attached references.
In pre-V8 MicroStation, the two pieces of information that an application needed to refer to an element was its "file position" and "file number". The file position was an offset into the DGN file, and the file number was an index into an array of opened files (filenum 0 was the master file and 1-255 for the attached reference files.) That system could not be used in V8, since it allows unlimited hierarchical reference file attachments. In V8, a "file position" is simply a "sequence number" and generally works with existing source code. The replacement for the file number is the DgnModelRefP. This is an opaque pointer to an object that MicroStation maintains for each open Model. There is a DgnModelRefP for the Active Model (the analog to the Master File in V8), that can be obtained by calling mdlModelRef_getActive(). There is a DgnModelRefP for each reference file that is currently open. A DgnModelRefP is also returned by the mdlWorkDgn_openFile and mdlWorkDgn_createFile functions.
Generally, converting from the previous system of "file" identification to the DgnModelRefP
system of identifying models requires some source code changes. Most of these changes are fairly mechanical and easily accomplished.
All MDL functions that previously accepted a file number or reference file slot now accept a DgnModelRefP. To make the transition to DgnModelRefP's as easy as possible, functions that accept a DgnModelRefP also accept the value NULL to indicate the Active Model. This means that programs that only manipulate the Active Model (Master File for pre-V8) may require no source code changes at all. Applications that operate on elements from reference files, particularly if they iterated through all attached reference files, will require more changes.
The most common way applications obtained a file number in previous versions, was to use tcb->curefl (the file number of the most recently located element.) That member of the TCB has been removed, and the new "mdlLocate_..." API that returns DgnModelRefP replaces it. In general, modifying an application to use DgnModelRef's
instead of file numbers consists of attempting to compile it and correcting the compilation errors. Since the type has changed, the compiler will readily point the errors out to you. To speed things along, you can often search for variables named fileNumber
, fileNum
, and fileNo
and replace them with "modelRef
", properly changing the type declaration from int
to DgnModelRefP
.
Please also note that there are many instances where Pre-V8 applications test against a value of 0 for "file number" to determine whether it is a master file or a reference file. For example:
if (0 == fileNumber)
[meaning "is master file"]if (MASTERFILE == fileNo)
[meaning "is master file"]if (0 < fileNum)
[meaning "is reference file"]These should be changed to use one of the mdlModelRef_ functions that characterize a DgnModelRefP, usually mdlModelRef_isActiveModel
, mdlModelRef_isReference
, or mdlModelRef_isReadOnly
. All mdlModelRef_...
functions are defined in msdgnmodelref.fdf
.
All view information is accessible through the MDL API.
Since MicroStation users can freely create new levels in a DGN file, the nature of levels has changed dramatically. Levels are elements and are stored as entries within a LevelTable element. Functions are used to get a LevelEntry from the LevelTable, and to get particular settings for the level, such as color, weight, style, display and plot, among others. The entries in a LevelTable can be treated like elements within a complex element descriptor, using mdlLevelIterator_getFirst
() and mdlLevelIterator_getNext
() to iterate through a list of levels.
A LevelList dialog item replaces the LevelMap dialog item used previously. A LevelList item defaults to the same size as a LevelMap, and will provide horizontal scrollbars to navigate through the level fields. The options on the LevelList item allow display of multiple columns. The LevelList item can have a hook function attached, unlike the LevelMap item. There are two access strings for the LevelList, like the LevelMap, except that the levels are represented by a BitMask type item. Correct initialization of the BitMask is shown in the example below.
To build the user interface for level combo box item:
Private void initialize (void) { ULong highestLevelId; if (NULL == myStruct.pLevelMask) mdlBitMask_create(&myStruct.pLevelMask); mdlLevelTable_getHighestLevelId(&highestLevelId, MASTERFILE); mdlBitMask_ensureCapacity(myStruct.pLevelMask, highestLevelId, 0); return ; }
Functions for accessing the properties of the LevelItem item and customizing its behavior are also provided. The API also allows access to the item structure so the standard dialog functions can be used.
The Scanning API provides a convenient mechanism for applications to filter the elements of a model, to operate on just the subset of them that meet a certain criteria or combination of criteria. For programmers familiar with relational database concepts, the Scanner fills the same role for DGN elements that SQL fills for relational tables.
In MicroStation V8, the Scanning API has been substantially improved. However, the pre-V8 API is also maintained for compatibility.
The new API consists of the mdlScanCriteria_...
functions, and is described in msscancrit.fdf
. The MicroStation V8 mdlScanCriteria_
API provides two ways for applications to filter the elements of a model. The first way is to allocate a buffer The scan can then use a new way of processing the file by using an iterator to process all the elements at one time. For examples, see the Scan and WorkDgn examples.
To take advantage of new capabilities in the MicroStation DGN file format, scanning routines need two categories of change. The first change is to ensure your buffers are large enough to hold the elements returned from the scanner. One way to optimize the memory allocation is to use the alloca()
function to allocate memory on the stack that is automatically released when your function exits.
The second change requires adapting scan request to use the new mdlScanCriteria_... functions. This process involves creating a ScanCriteria object, initializing it with the mdlScanCriteria_ functions, calling mdlScanCriteria_scan
, and then freeing the ScanCrieria object by calling mdlScanCriteria_free
.
The global variable, RefFileP
has been removed. Use mdlRefFile_getInfo
to get a reference file pointer that can be passed into the various functions that query for information, such as update sequence, etc. The correct way to iterate through the active file and reference files is to use the new mdlModelRefIterator_
... functions (see msdgnobj.fdf
). For example:
DgnModelRefP modelRef; ModelRefIteratorP iterator; mdlModelRefIterator_create (&iterator, MASTERFILE, MRITERATE_Root | MRITERATE_PrimaryChildRefs, 0); while (NULL != (modelRef = mdlModelRefIterator_getNext (iterator))) { ... do something to each modelRef. } mdlModelRefIterator_free (&iterator);
In this case, the code iterates through the DGN file and its primary reference files. To get just the reference files, change the third argument to MRITERATE_PrimaryChildRefs
. The fourth argument is the nesting depth. Setting it to zero gets only the primary reference files, setting to -1 goes through all nesting no matter how deep. Remember to call mdlModelRefIterator_free
to free the iterator.
Raster Manager
Raster Manager's API, mdlRaster
, supercedes any previous version of mdlRastRef
. Additionally, all code created for mdlRastRef
WILL NOT RUN under the mdlRaster
API. Any code created for mdlRastRef
must be ported to mdlRaster
API.
Many dimension settings have been moved from the TCB. Most of the variables can be retrieved using mdlDimStyle_... functions. Dimension style elements are table entry elements.
mdlCell_extract, mdlCell_extractName, etc. return the cell name as MSWChar *. To convert the returned wide-string Unicode cell name to an array of chars, mdlCnv_convertUnicodeToMultibyte() should be used. To convert an array of chars to Unicode, then mdlCnv_convertMultibyteToUnicode() should be used first.
There are currently a number of #defines for name lengths (e.g. MAX_CELLNAME_LENGTH), and there is also an equivalent define for MAX_CELLNAME_BYTES. This is because the conversion from Unicode to Multibyte can take 2x the number of bytes as letters in the wide string name. So when converting from Unicode to Multibyte your Multibyte buffer should be declared to be the _BYTES length. If on a single byte code page operating system (i.e. English Windows), you fill up the char buffer with characters and then convert to Unicode, your string will be truncated to the _LENGTH size.
If you write names out to ASCII files you will need to use the mdlCnv_unicodeToUTF functions to create a null terminated ASCII string of the name so that the ASCII file is portable across different localized versions of Windows.
Cell libraries are DGN files with each cell being a model in that file.
Sample code for generating a list of cells in a Cell Library:
{ DgnIndexIteratorP cellIterator; DgnIndexItemP cellIndexItem; DgnFileObjP pLibObj; if (0 != tcb->celfilenm[0]) { MSWChar wCellName [MAX_CELLNAME_LENGTH]; int iStatus; int cellType; BoolInt isThreeD; iStatus = mdlCell_getLibraryObject (&pLibObj, tcb->celfilenm, TRUE); cellIterator = mdlModelIterator_create (pLibObj); mdlModelIterator_setAcceptCellsOnly (cellIterator, TRUE); while (NULL != (cellIndexItem = mdlModelIterator_getNext (cellIterator))) { char mbCellName[MAX_CELLNAME_BYTES]; MSWChar wCellDescription[MAX_CELLDSCR_LENGTH]; // Get the cell name mdlModelItem_getName (cellIndexItem, wCellName, MAX_CELLNAME_LENGTH); // Convert the name to multibyte mdlCnv_convertUnicodeToMultibyte (wCellName, -1, mbCellName, sizeof(mbCellName)); // Get the description mdlModelItem_getDescription (cellIndexItem, wCellDescription, MAX_CELLDSCR_LENGTH); // Get other information mdlModelItem_getData (cellIndexItem, NULL, &isThreeD, NULL, NULL, NULL); cellType = mdlModelItem_getCellType (cellIndexItem); printf ("the cellname is '%s' and the description is '%S' \n", mbCellName, wCellDescription); } mdlModelIterator_free (cellIterator); } }
MicroStation provides equivalent functions for manipulating solid elements using the Parasolids Solid Modeling Kernel and the ACIS Solids Modeling Kernel. A third API, the Kernel Independent API (KISolids) is appropriate for most cases. This will allow your application to automatically accommodate the workmode chosen by the user without writing specific support for both libraries. MicroStation's preference is for using Parasolids functions, though ACIS functions can be accessed if DWG compatibility is necessary. Most source code will require updating.
The function to open a work file is mdlWorkDgn_openFile
. It returns a DgnModelRefP
that can be passed to the standard mdlElmdscr functions. Also available is the mdlWorkDgn_create
function to create a new file. NOTE: Files modified with the WorkDgn_... functions not saved until the mdlWorkDgn_closeFile
function is called.
Miscellaneous Notes
File masks are a DgnModelRefLists
. This change affects mdlView_fit, mdlView_updateMulti, mdlView_updateMultiExtended, mdlView_setFunction
(UPDATE_PRE/POST).
A resourceFileHandle argument has been added to the resource manager functions that convert from external to internal format.
The mdlParams_storeType9Variable
function has been eliminated. The only two uses of this function were to update the GraphicGroup setting, which is accomplished with the mdlSystem_updateGraphicGroup
function, and to update the text node (canode) number, which is accomplished with the mdlSystem_updateCurrentNode
function.
The pre-V8 colorPicker, levelMap, and levelPicker user interface items are obsolete.
The "nameSpace" argument is currently work-in-progress and is not supported yet. This argument is in the signature for several functions for manipulating models (for example, mdlDgnFileObj_createModel). For V8, you should always pass NULL for this argument.
Any JMDL code referencing the DGN Package needs to be recompiled for MicroStation V8.
[Note: Starting with MicroStation V8 XM Edition, Java and JMDL are no longer supported.]
MicroStation V8 includes and supports Java 2 (v1.3)
Java applets and applications can be run from a DOS command line using appletviewer.exe
(for applets) and java.exe
(for applications). They can also be executed inside a MicroStation session using the following keyins from the Key-in Browser:
appletviewer <appletURL>
and
java <applicationURL>
For example, to run the delivered HelloWorld from within MicroStation V8, use the syntax
java examples.java.HelloWorld
More information on JMDL and Java (including examples of both) can be found in the JMDL Documentation that is provided when the Programming Tools Documentation are installed. See this note for more information regarding Programming Documentation and Examples.
[Note: Starting with MicroStation V8 XM Edition, Java and JMDL are no longer supported.]
MicroStation Desktop TechNotes and FAQs
Bentley Technical Support KnowledgeBase
Bentley's Technical Support Group requests that you please confine any comments you have on this Wiki entry to this "Comments or Corrections?" section. THANK YOU!