Tag Archives: MicroStation

MicroStation View v8i is free WMS viewer

xwms-setI was evaluating new MicroStation View8i from the WMS perspective- it is much more better than previous version that just stuck while the window was redrawing. View8i is reading WMS request in background, allowing you to do some manipulations with application. Bentley added support for reading WMS servers and switching layers( but it works only with newer XWMS format 1.1.2 that is not recognized by previous XM version).  XM edition could read WMS layers at once, however v8i just uses tiles – this might be based on speed of WMS server more time consuming than obtaining one image at once..[updated: I didn’t realize how bad this might happne to be …v8i with its  tiling on WMS request (from slow servers) is nearly 9 times slower than XM edition that just request whole window at once. See the second picture bellow. That turn your 45 sec in XM edition into 6,5 minutes. Note I didn’t check  any extra settings and I use defaults in both versions]  XWMS is a format that is XML and describes WMS server parameters, but you can’t join various WMS servers into one XWMS.

For Czech WMS servers I have prepared some set of XWMS files for viewing them in freely available MicroStation v8i. But the free version doesn;t allow you to do any modifications – it uses only read-only mode. Thus I have wrapped each XWMS under dgn file and all referenced into top most dgn file called “openMe.dgn” (otevriMe). There you will find among WMS references also free slots (called “myDrawing/dgn” or “MyDrwaing.dxf”/MujVykres.*) for attaching your custom files (understand you need to rename you file and put it into the root folder of the XWMS set. This is displayed in picture.

You can download experimental XWMS pre-set for Czech Republic  here http://www.sumbera.com/blog/XWMS-SET.zip

If you have installed MicroStaiton Bentley V8i then just click on file OtevriMe.dgn.

example1

To display this arrangement V8i took 6m38sec but XM only 45 sec !

XWMS example (for Czech Cadastral Map) in JTSK projection  (katastr.xwms):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BentleyWMSFile>
    <VERSION>1.1</VERSION>
    <URL>geoportal2.uhul.cz/cgi-bin/oprl.asp?</URL>
    <REQUEST>
 <VERSION>1.1.1</VERSION>
       <SRS>EPSG:102067</SRS>
<LAYERS>BIOCENTRUM_USES,BIOKORIDOR_NR_F,BIOKORIDOR_R_F,BIOKORIDOR_L_F</LAYERS>   
        <WIDTH>800</WIDTH>
        <HEIGHT>500</HEIGHT>
 <BBOX>-910000,-1230000,-420000,-930000</BBOX>
        <FORMAT>image/png</FORMAT>
    </REQUEST>
    <SERVERCAPABILITIES>
        <MAXBITMAPSIZE width="1024" height="1024" />
    </SERVERCAPABILITIES>
</BentleyWMSFile>

Using VC++.NET for MicroStation v8 programming

VC++.NET offers perfect platform for developing traditional MDL application together with innovative .NET technology. This research is focused on integration .NET Forms with MDL applications.

Date: February 2003

Programming languages: VC++.NET,

Published in : PenBrush’s CAD III/Q 2003, pp 30-33.

PDF: Using VC++ .NET for MicroStation v8

Code: Download Code

Intro’dust’ion

Nowadays we may here .NET everywhere. Recently I have published article on .NET and VBA interoperability where you may find basic information. However you as core MDL programmer you would like to get something more natural to get smoothly into .NET. I mean we need direct access to MDL API without any P/Invoke. The ultimate solution is VC++.NET. It offers mixing managed (pure .NET code) with unmanaged (traditional native code) into one piece of code. Oh yeah ! this allows nearly miracles, specially through technology called IJW -It Just Work! In VC++.NET you are a king of .NET as well as native code and of course of MDL API. Moreover with beta release of Visual Studio 2003 it is possible to visually design .NET Forms GUI even for VC++. OK, still reading ? today is not 1.April…

Designing one little .NET box

VisualStudio.NET is very comfortable for developing VC++ application. After visual design of dialog box, it is necessary to add some support for MicroStation native window handling and for mixing native data with managed garbage collected class:

lets create a class for handling pointers to registered MicroStation native window and for hook

class HwndWrap
{
public: GuiWindowP pWindow; // handler for MicroStation native window
public: HHOOK hHook; // hook handler for routing messages
};

here is a snippet of dllForm.h – the file is originally made from visual design of GUI but here it must be slightly modified for MicroStation

#pragma once
#include “stdafx.h”
#include “windows.h”
#undef MessageBox

#define winNT
#define NO_BOOLEAN_TYPE
#include “mssystem.fdf”
#include “msnativewindow.h”
#include “HwndWrap.h”

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;

namespace NETDLL{

public __gc class dllForm : public System::Windows::Forms::Form {

public:

HwndWrap *wrapper; // handler of native pointers

dllForm(void);
~dllForm();

// GUI definition follows here
private: System::Windows::Forms::TextBox * textBox1;
private: System::Windows::Forms::MonthCalendar * monthCalendar1;

// EVENTS..button and size changed
private: System::Void button1_Click(System::Object * sender,
System::EventArgs * e){
//… do something from MDL on button press
mdlSystem_newDesignFile(“nic.dgn”);
}

private: System::Void dllForm_SizeChanged(System::Object * sender,
System::EventArgs * e){
// let MS adjust window min and max size
if (this->WindowState == FormWindowState::Minimized)
mdlNativeWindow_minimize(wrapper->pWindow);
else if (this->WindowState == FormWindowState::Maximized)
mdlNativeWindow_maximize(wrapper->pWindow);
}
}

let’s create a storage for our form managed object

using namespace NETDLL;
__gc class ManObj {
public: static dllForm *form;
};

constructor and destructor of .NET form

dllForm::dllForm(void) {
wrapper = new HwndWrap();
InitializeComponent();
this->Show();
HWND formWin = FindWindow(NULL,”DllForm”); // not perfect…
mdlNativeWindow_initialize(“NETDLL”); // init native window for MS
mdlNativeWindow_createMSWindow (&(wrapper->pWindow), formWin, FALSE, TRUE,1);
mdlNativeWindow_addToWindowList(wrapper->pWindow); // add to window list in MS
mdlNativeWindow_setAsChild(wrapper->pWindow,0,FALSE); // set parent to MS
// set redirection for hooks ..still same old way..
wrapper->hHook = SetWindowsHookEx( WH_GETMESSAGE, GetMsgProc, NULL, GetCurrentThreadId());
}

dllForm::~dllForm(){
mdlNativeWindow_removeFromWindowList(wrapper->pWindow);
mdlNativeWindow_destroyMSWindow(wrapper->pWindow,FALSE);
UnhookWindowsHookEx(wrapper->hHook);
delete wrapper;
}

finally export function for MDL and create dialog

extern “C”
__declspec(dllexport) void loadNETbox(){
ManObj::form = new dllForm();
}

Conclusion
VC++.NET is perfect and straightforward for use in mixed environments where traditional native as well as .NET code must be used. Transparency of native and .NET code is amazing. Even MFC is still alive, it is more or less deprecated object oriented technology so use .NET forms instead.

Image Storage with Oracle 9i and MicroStation

Summary: Paper describes a technology of storing rasters in Oracle database with usage of Oracle Spatial, Oracle intermedia option and Workspace managers. Rasters are displayed in MicroStation v8

Date: October 2002, Published in : ControlAltDelete III. 2002, Authors: Stanislav Sumbera, Petr Vinduska

Original site location 2002: http://www.sumbera.com/ustation/articles/Rasters/Rasters2.htm

download Java code

pdf version

Introduction

MicroStation plays important role in geoinformation systems (GIS) especially in Automated Mapping/Facility Management (AM/FM). In these areas, raster data such as satellite images, air photos, scanned topographical maps or other types of imagery are becoming increasingly popular. It has been estimated that these data may represents more than 90% of the average GIS data holding by volume. MicroStation V8 comes with Raster Manager as a solution for united raster management of different raster formats. Oracle 9i brings its GIS technologies like Spatial option, interMedia or Database Workspace Manager for effective database storing of geographical-related data. Oracle database is used in number of organizations to manage all kinds of data across the enterprise.

In this article, we will join Oracle GIS technologies with MicroStation v8 to build up a prototype called “Image Storage” for storing rasters in Oracle9i database using Oracle interMedia, Oracle Spatial, Oracle Workspace Manager and finally displaying query results with help of Raster Manager and it’s clipping capabilities. We are going to point out some interesting concepts and techniques in Image Storage.

Nowadays there are only a few solutions for storing rasters in databases, actually most of the interest in raster management lies in using compressed proprietary formats like Mr.SID or ECW. Note ECW is supported in MicroStation v8 as well. Continue reading

.NET and VBA interoperability in MicroStation v8

Date: July 2002
Published in : ControlAltDelete 2002
Download Code
Pdf version

Introduction
MicroStation v8 brings to developers among others two practical features: First in form of integration of Microsoft’s Visual Basic for Application and second complete possibility to compile MDL code into native DLL and use Visual Studio for debugging. On Bentley newsgroup someone says that the letter “L” in MDL now means Library not Language. Third time lucky, Microsoft has recently released final version of .NET framework and its SDK which defines a new platform for software solutions. This platform we my immediately use for MicroStation development as will be shown in the article. The key feature of each new technology is often backward compatibility or interoperability with the current code. We will focus in this contribution to these features – mutual interoperability among different platforms accessible in MicroStation.

Interoperability overview
Fig 1. shows that the central point of intercommunication is a Dynamic Link Library (DLL) which is capable to interact with different platforms. This could be one of the good reason why to compile MDL code into DLL – just to be in the “centre”.  The upper right part of the picture was already discussed in article:”Java/Jmdl communication with MDL application” (MicroStation Manager 12/2001). We will give our attention to the VBA and .NET interoperability.

Fig. 1 In-process interoperability schema.

Designing DLL native code for interoperability
We will go through code which demonstrate interoperability to point out some interesting techniques. The native code handles up coming calls from VBA and .NET and invokes their procedures and methods. The interoperability is designed through direct function pointers, thus make it more simpler for understanding. The dll library is called nativeLib.dll and is referred inVBA and .NET code bellow. The following steps to interact with the DLL are common to VBA and .NET:

1. Calling exported function in any DLL is almost trivial – you only need to declare function as exported and set proper calling convention to stdcall (VBA require this convention)

#define DLLEXPORT __declspec(dllexport)
#define STDCALL __stdcall
void DLLEXPORT STDCALL Dllfoo(int params){}

2. Calling procedure or method in VBA or .NET requires to declare function prototype with its parameters, obtain its pointer and then it is possible to call it :

// a) declare function with one parameter :
typedef int (STDCALL *METHODPTR)(int limit);
//global variable to hold pointer to the method
METHODPTR MethodQ= NULL;
// b) function to set method pointer (will be called from VBA or .NET)
int DLLEXPORT STDCALL dll_setMethodPointer (void (*MethodPtr) (void)){
return MethodQ = (METHODPTR) MethodPtr;
// c) function to invoke method stored in MethodQ variable
int DLLEXPORT STDCALL dll_callMethod (short limit){
return (MethodQ ? MethodQ(limit): FALSE);
}

Fig. 2. incomming and outgoing functions in DLL.

Of course thee are different functions for VBA, .NET , MDL and Java in nativelib.dll to enable calling between them.

Designing VBA to call DLL code
VBA can invoke any standard DLL function in very simple and straightforward way. This possibility allow to call Window’s API or MDL built in functions (from version 8.00.02). For instance to call MDL function for opening dialog box you need to declare at global section of VBA code imported function from stdmdlbltin.dll, then it is possible to call it:

Private Declare Function mdlDialog_openInfoBox_
Lib "stdmdlbltin" (ByVal promt As String) As Long
Private Sub UserForm_Activate()
mdlDialog_openInfoBox ("called from VBA")
End Sub

Designing .NET to call DLL code
.NET allows to call native (unmanaged) functions that are implemented in a DLL via Platform Invocation Services (PInvoke) . The called function in DLL need not to be declared as standard :

public class DLLWrap{
[DllImport("ustation.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int mdlDialog_openInfoBox(String message);
}
private void Button_Click(object sender, System.EventArgs e){
DLLWrap.mdlDialog_openInfoBox("message from .NET");
}

Designing VBA to accept calls from DLL
DLL is able to call VBA procedures through its pointer (see above). We need to set the proper procedure pointer first with help of AddresOf operator and than call DLL function to store the pointer for later invocation of VBA method :

'Define a function to be called from DLL in VBA module:
Public Sub OnVBACall(ByVal limit As Long)
VBANonModal.Label1 = "VBA got " + Str$(limit)
End Sub
' Declare function from DLL which accept pointer to the VBA method:
Private Declare Function dll_setVBAMethodPointer_
Lib "nativeLib.dll" (ByVal pMethod As Any) As Long
' Call the DLL function to set pointer on method OnVBACall
Private Sub UserForm_Activate()
Call dll_setVBAMethodPointer(AddressOf OnVBACall)
End Sub

Designing .NET to accept calls from DLL
The .NET Framework defines a special type called Delegate that provides the functionality of a type-safe function pointer. We need to design method to be called from DLL, declare and call the native DLL function to set method pointer:

//declare signature of called method through a delegate
public delegate void OnNETCallDelegate(int limit);
public class DLLWrap{
// declare member onNetCallRef to hold method reference
public static OnNETCallDelegate onNetCallRef =
new OnNETCallDelegate (DLLWrap.OnNETCall);
// declare member to refer to Form (dialog box)
public static NetForm netFormRef;
[DllImport("nativeLib.dll"]
public static extern int
dll_setNETMethodCall(OnNETCallDelegate method);
// receiving method of DLL call
public static void OnNETCall(int limit){
netFormRef.setLimitToNetForm(limit);
}
}
// a class of Form
public class NetForm : System.Windows.Forms.Form{
public NetForm(){
// set reference to this form
DLLWrap.netFormRef = this;
// set method to accept dll calls
DLLWrap.dll_setNETMethodCall(DLLWrap.onNetCallRef);
}
}

Wrapping .NET into COM
.NET Framework provides COM callable Wrapper (CCW) enabling an arbitrary COM client to seamlessly call a method on a .NET object. .NET object appears to COM clients just as if it were a native COM object. This feature fits perfectly to the VBA concept which provide easy way to call COM methods and manage COM events. CCW makes COM object from .NET just as simple as possible:

// declare delegate for events
public delegate void onTransmitDelegateVba(int limit);
// define interfaces InterfaceType identifies
// how to expose an interface to COM
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ITransmit{
[DispId(1)]
int setLimitToNetForm(int limit);
}
// interface to sink events by COM clients
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITransmitEvent{
[DispId(1)]
void OnTransmitEventVba(int limit);
}
// define class inherited from interface
[ComSourceInterfaces(typeof(ITransmitEvent))]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class NetForm : System.Windows.Forms.Form,ITransmit{
// declare event
public event onTransmitDelegateVba OnTransmitEventVba;
// implement interface
public int setLimitToNetForm (int limit){
this.LabelRec.Text= ".NET Form got " + limit.ToString();
return limit;
}
// raising event handled by the COM sink
private void ButtonCallVba_Click (object sender, System.EventArgs e){
OnTransmitEventVba(Convert.ToInt16(this.TextLimitVBA.Text));
}
}

VBA client would use this object as ordinary COM:

'declare events and NetForm object
Dim WithEvents NetEvent As NetForm
Dim dotNetForm As New NETobject.NetForm
'show form, set event handle to COM object
Private Sub UserForm_Activate()
dotNetForm.Show
Set NetEvent = dotNetForm
End Sub
'call .NET method when button is pressed
Private Sub Button_OnNet_Click()
dotNetForm.setLimitToNetForm (Val(NETLimit.Text))
End Sub
Public Sub NetEvent_OnTransmitEventVba(ByVal limit As Long)
VBANonModal.Label1 = "VBA got from .NET " + Str$(limit)
End Sub

Accessing MicroStationDGN object from .NET
Calling COM object is possible via callable wrapper (RCW). RCW serves as proxy which exposes COM objects for .NET Framework, thus .NET clients may call any COM client. Thus we may deploy whole MicroStationDGN object into .NET application. A .NET client (event sink) can receive events raised by an existing COM server (event source). COM interop generates the necessary delegates in metadata that you include in your managed client. An imported delegate signature comprises the sink event interface, an underscore, the event name, and the word EventHandler: SinkEventInterface_EventNameEventHandler.

MicroStationDGN.Application msApps = new MicroStationDGN.Application();
// set COM property
msApps.Caption = " Caption set by .NET";
MicroStationDGN.View msView;
msView = msApps.ActiveDesignFile.Views[1];
// do zoom on view 1
msView.Zoom(2);
msView.Redraw();
// wire event handler for OnDesignFileClosed event
MicroStationDGN.__ApplicationEvents_OnDesignFileClosedEventHandler
DesignEventClose = new MicroStationDGN.__ApplicationEvents_OnDesignFileClosedEventHandler
(OnDesignClose);
msApps.OnDesignFileClosed += DesignEventClose;
// event handler
static void OnDesignClose(String designName){
MessageBox.Show(".NET recieved File Close event + designName");
}

Final words
It has been shown how to interoperate among DLL, .NET and VBA code. Moreover you may download complete code for this article to test interoperability. In a code for this article there is actually done much more. There are dialog boxes created in MDL, Java , VBA and .NET which serve as a test for application interaction, see fig. 3. In VBA code there are used some tricks to allow VBA and .NET Forms to be displayed behind ordinary MDL dialog boxes and behave as child window of MicroStation.


Fig. 3 dialog boxes for interaction between MDL, Java, VBA and .NET

We can use all good features of particular language for our solution. Most promising is to use .NET together with MDL compiled into native code. Moving MDL code into native DLL would save one step in interaction between different platforms and MDL.. NET platform is no doubt ready for MicroStation software solution. We may use it even instead of VBA with possibilities to write the application in C#, VB.NET, VC.NET or other. These examples were compiled using Java 2 SE, VBA v.6, VC++.NET 7 , C#.NET 7, and MicroStation V8 (08.00.02.20) compilers runing on Windows XP Pro.

The programming code in this article is offered to the MicroStation community „as is“, without any responsibility for its use elsewhere. http://www.sumbera.com

Writing MFC dialogs for MicroStation v8

published: MSM, January 2002
code download
pdf version
MicroStation V8 provides strong support for writing application for MicroStation in native form. This feature allow us to write and debug our C/C++ based applications inside one of the Integrated Development Environment (IDE), for instance Visual C++. Naturally it will lead developers to write in native code also Graphical User Interface (GUI). Now the problem may come – how to effectively write native GUI items for MicroStation environment ? This article will give you short introduction how to start using native GUI in MicroStation.

Windows application programming interface (Win32 API) provides rich set of user interface functions. These functions are very similar to traditional mdlDialog_ functions to operate with windows, dialogs, items etc. Large portion of the Win32 API was encapsulated into classes called MFC – Microsoft Foundation Classes. The MFC make up an application framework based on C++ language on which you can build your native user interface. Visual C++ provides several utilities for rapid application development : Application Wizard for starting up your project,

Class Wizard to help you mange MFC classes, Resource editors to visually create user interface and more. I will not go further with writing advantages of Visual Studio, you can read them and learn via MSDN (Microsoft Developer Network).

Rather let’s go step by step to create simple non modal dialog for MicroStation using VC++ v.6.0 and MFC. First create new project called for instance “nativeDlg” using MFC AppWizard (dll). In wizard options choose only “Regular DLL using shared MFC DLL”. Now you get skeleton of your native dll code using MFC libraries. We will create simple window class called CNativeFrame using CWnd as base class. This step can be done simply in Class Wizard by pressing the button “add class”.

The class will provide frame window for all other native dialog box or items. For opening the frame window you will need an export function which will be called by mdl invoker. :

extern "C"
{
// exported DLL function for opening dialog box
__declspec(dllexport) int OpenDialog(void){
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HWND parent = frameWin.OpenFrame("Frame Window",400,180)
return true;
}}

Here OpenFrame method is defined in class CNativeFrame and creates window using methods of base CWnd class AfxRegisterWndClass and CreateEx. Your mdl invoker could be very simple, you need just to import function OpenDialog via dynamic link specification, declare it as a nativeCode in mdl source and call it in main function. Now run your code and you should see your non modal Frame Window. But may be you will not be satisfied with the behaviour of the window – it has no parent window, it doesn’t behave as Child MicroStation window. To solve the problem you must set parent window of your Frame window to MicroStation main window. The function used in example code to get MicroStation main window enumerates all created windows, checks if the windows is MicroStation one and compare process id of founded window with process id of your dll. If all criteria are fulfilled the function returns MicroStation main window.

Unfortunately another problem may come concerning minimization and maximization of Frame Window. When window is minimized it disappear from the visible area of MicroStation window. If window is maximized, it covers whole area including menu and status bars. This behaviour can be easily changed in event handler of window message WM_SIZE.

void CNativeFrame::OnSize(UINT nType, int cx, int cy)
{
if (nType == SIZE_MINIMIZED)
MoveWindow(...);
else if (nType == SIZE_MAXIMIZED)
MoveWindow(...);
}

Now we have nice MFC Frame Window but without any items. This would be our second task. Let’s create dialog box and items using Resource Editor and Class Wizard to join dialog resource with our new created class CNativeBox. To display dialog box correctly set its parent to Frame Window :

//..in OpenDialog function
HWND parent = frameWin.OpenFrame("Frame Window",400,180)
box.Create(IDD_NATIVE_DIALOG,CWnd::FromHandle(parent));
return box.ShowWindow(SW_SHOW);

In this version TAB key between dialog items doesn’t work. The solution to this problems is well described on MSDN. For a modeless dialog box to process a TAB key, the message pump needs to call the IsDialogMessage API. However, if you are writing a DLL and do not have access to the .exe’s source code, you cannot modify the message pump to do this. To work around this problem, you can use a WH_GETMESSAGE hook to capture the keystroke messages and call the IsDialogMessage API. If IsDialogMessage returns TRUE, then do not pass the message on to the message pump. Set the hook when handling WM_INITDIALOG and unset it when handling the WM_DESTROY message.

BOOL CNativeBox::OnInitDialog(){
CDialog::OnInitDialog();
hHook = ::SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc, NULL, GetCurrentThreadId());
return TRUE;
}
void CNativeBox::OnDestroy(){
UnhookWindowsHookEx(hHook);
CDialog::OnDestroy();
}
// hook function capturing dialog messages
LRESULT FAR PASCAL GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LPMSG lpMsg = (LPMSG) lParam;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if( ( nCode >= 0 && PM_REMOVE == wParam ) &&
(lpMsg->message >= WM_KEYFIRST &&
lpMsg->message <= WM_KEYLAST) &&
(IsDialogMessage((HWND)box.m_hWnd, lpMsg))) {
lpMsg->message = WM_NULL;
lpMsg->lParam = 0;
lpMsg->wParam = 0;
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}

You may add into dialog box also any ActiveX component or call via OLE automation MicroStation methods available in Visual Basic for Application. All you need to do is enable OLE in your dll, add new class from template library of MicroStation (ustation.exe) using ClassWizard and call your method:

_Application MSapp;
AfxEnableControlContainer( );
OleInitialize( NULL);
MSapp.CreateDispatch( "MicroStationDGN.Application",NULL);
MSapp.SetCaption( "MicroStation with MFC");

Fig.1 MFC based non modal dialog with Excel ActiveX

To create non modal dialog boxes based on MFC need not to be difficult. Utilizing all Windows features for GUI development gives us rich possibilities to extend current user interface. There are also a lot of ActiveX components we can easily add into MFC dialogs to create rich and user friendly modern GUI for MicroStation. The examples given in the article are for learning purpose so I removed all errors and exceptions handling for shorter code. The code was tested on MicroStation v8. 08.00.00.21.

Java communication with MDL in MicroStation v8


Printed : December 2001, MSM
download code
pdf version

Introduction

For the last several years, MicroStation developers have been using the C-style MDL language in which gigabytes of codes are written in the form of utility applications (.ma files), shared libraries (.msl –files), static libraries (.ml – files) and resource files (.r) for graphic interfaces, command tables etc. What is more important, such MDL codes have been maintained and tested to have the best qualities for thousands of hours. There also exist a lot of supported native codes written in DLL to perform time-critical tasks in MicroStation. Such codes can be easily incorporated into MDL programs via dlm set of functions.

On the other side, there is a new, modern, easy to learn, platform-independent and object-oriented language called Java and its JMDL extension which enables rapid application development with a lot of advantages for MicroStation programmers such as the usage of pure Java classes from the third-party vendors, safety in memory management, scalability etc. However, Java or JMDL applications seem to have some deficiencies; for instance, they do not look and feel like the MDL application (docking, tool tips, color or level dialog box control etc.), or the standard Java class library does not support some platform-dependent features rarely required by your application, or their performance is low in case some time-consuming operation is to be optimalised.

Natural questions arose when Java was integrated into MicroStation/J : “How to communicate between MDL and Java applications?“, “How to access a low-level code from the Java environment?”, or “How to recall the Java code from MDL?”

The Java development kit delivered along with MicroStation/J contains documented and supported specifications of interface that allows the programs written in other languages to be called up from the Java code that runs within Java Virtual Machine. Vice versa, the native code is able to call up methods and access objects written in the Java language. This standard programming interface is well-known in the Java community and its name is Java Native Interface (JNI).

If we have read the article carefully up to now, we have already found the answers. Both MDL as well as Java have full, both-direction access to the native code. But it would not be sufficient to make the communication easy if the virtual machines for interpreting these two different codes would run in separate process space. Fortunately, MDL runtime (ustation.dll) and Java/JMDL runtime (javai.dll) are mapped and run within the process address space of MicroStation (ustation.exe). That is why the DLL native code attached to the Java application and then to the MDL application will receive only one DLL_PROCESS_ATTACH message from the first one. Thus, we can speak about an in-process communication between MDL and Java/JMDL.

Fig.1 Types of communication between Java/JMDL and MDL

Use the jmdl_import keyword to call MDL or DLL

The easiest and most straightforward way of invoking a shared library written either in the MDL or a native code from a JMDL code is to use a mechanism that is very similar to the J/Direct technology. The jmdl_import keyword is a part of a native function declaration in which we specify the MDL or DLL library name and their exported functions which we are going to invoke. The jmdl method succeeding the jmdl_import statement must be declared as static.

An example of a JMDL method is mdl_printPromp which refers to a mdl shared library (mdlPrompt) and its function (printPrompt) :

jmdl_import (mdl = "mdlPrompt", name = printPrompt)
public static native void mdl_printPrompt(byte *showText);
Similarly, in order to invoke a native function from DLL, you can use the dll = instead of mdl =...:
jmdl_import (dll = "dllPrompt", name = printPrompt)
public static native void dll_printPrompt(byte *showText);

Using Java Native Interface to interact with MDL

To use the JNI for accessing the MDL code we need an intermediate native layer for passing calls from Java to MDL and vice versa. This DLL “gateway” consists of the JNI interface to interact with Java on one side, and on the other side there must be an interface to communicate with the MDL code in a way of a dynamic link module.

Java Native Interface to invoke the DLL function

The JNI is quite a rich application interface that enables the interaction between the native code and Java. If we are on Win32 platform, such a native code is represented by a regular DLL with exported functions which we are going to invoke. Through the JNI we can:

  • call Java methods
  • call native methods
  • operate with a Java object
  • process exceptions
  • load classes and obtain their information

Let’s suppose we have a class which will invoke a function in a native library called nativeLib.dll. First, Java must load the DLL library into memory and link to it via calling the System.loadLibrary. The only parameter of the method is a name of the desired dynamic library. The specified DLL must be stored in one of the system path directories or in the same directory containing a Java class file. The Java virtual machine will automatically append the appropriate extension according to the given platform so you do not need to write “.dll” extension there. An example of the method is given below:

static {
System.loadLibrary(" nativeLib"); // loading the library nativeLib.dll
}
public native void callDllFunc(short limit); // declaration of a native function

Then to implement the a Java method in C++, we need to create a “Java to C++” mapping header file with function prototype of given method. The task could be done simply by a standard Java Development Kit (JDK) utility javah.exe with the –jni command parameter and the name of the class that will be processed. The result is a declaration of native function placed in the header file named as the processed class. For instance, we can enter a command javah – jni JavaJni and the header file “ JavaJni.h” will contain a prototype for the function callDllFunc in the C++ code :

#include
extern "C" {
JNIEXPORT jint JNICALL Java_JavaJni_callDllFunc (JNIEnv *, jobject, jshort);
// declartion of native function
}

The header file begins with an include directive for jni.h. In Jni.h there are among other things the data types and function prototypes of the JNI defined. The JNIEXPORT macro is defined in jni_md.h for Win32 platform as __declspec(dllexport). Such a function declaration means that we do not need an additional module-definition (.DEF) file of the exported functions. The JNICALL is expanded into __stdcall which expressesthe definition of the calling convention for Win32 API functions. The JNI imposes a naming style (so-called name mangling) on the native methods through which the Java Virtual Machine links the Java calls to the native methods. So the name of the native language function that implements a native method consists of the Java keyword, followed by a package name (here we have a default package, hence, in our example, this part is omitted), then the class name JavaJni, and finally the name of the native method callDllFunc. Between each name part is an underscore “_” separator. A question may come up about the number of parameters in our Java_JavaJni_callDllFunc prototype where there are three arguments in total instead of an only one. These two additional arguments are passed from Java to all native functions using the JNI. The first of them is the Java Environment interface pointer containing all the necessary function pointers for the native processing of parameters and objects passed from Java. The second one is, in this case, a reference to the current instance of the JavaJni object – an equivalent to “this” in Java. These two parameters make a gateway to call back the Java method but only in the current context of calling. The third one is a corresponding argument to short type passed from the Java code.

The example code nativeLib.cpp given below in which we implement the Java native function with an only short parameter is written in C ++ and displays the parameter value using the Win32 API:

#include "stdafx.h"
#include "JavaJni.h" // header file generated by the javah utility
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason,LPVOID lpReserved){
return TRUE; // dll entry point
}
JNIEXPORT jint JNICALL Java_JavaJni_callDllFunc
(JNIEnv * env,jobject jthis, jshort limit){
char message[255];
sprintf(message,"Native Dll recieved value %d",limit);
:: MessageBox(NULL,message,"nativeLib",MB_OK); // displaying a message
return (jint) dll_callMdlFunc(limit); // call to mdl will be explained soon
}

Calling the Java method from the native code

To invoke the Java non-static method from a native code, we need to do a little bit more of programming than before. First of all, we need to design a JavaJni class to implement the calling from the native code and compile it with javac utility to have a JavaJni.class. The class displays simple dialog box with a label item where will be reflected passed parameter from a native function :

import java.awt.*;
public class JavaJni extends Frame{
Label label = new Label ("Label",Label.CENTER);
static JavaJni javaObj = new JavaJni("Java dialog");
public JavaJni(String title){ // constructor to display a dialog box
super(title);
resize(150,100);
setBackground(SystemColor.control);
add(label); show();
}
public int onMdlCall(short limit){ // reciever method of a MDL call via DLL
label.setText("Native call, value = " +limit);
return true;
}
public static void main(String[] args) {
javaObj.show();
}
}

Now we are prepared to implement calling from a native method.

The necessary steps are listed below:

1. Get a Java Virtual Machine (JVM) pointer  – The JNI_GetCreatedJavaVMs function from the JNI library will successfully process your request if the JVM has already been started. The returned pointer will be used in the second task.

2. Get an interface pointer – To obtain a valid interface pointer, a member function of the JVM pointer called AttachCurrentThread needs to be invoked.The function attaches the current thread to the JVM and returns the JNI interface. If the thread has already been attached, no operation is performed, just the valid interface pointer is returned.

3. Retrieve a class reference of the called method – The JNI interface pointer received in the previous task includes all the necessary functions to operate with the JNI. One of them is FindClass which will realize the current task. The returned value is a representation of the searched class.

4. Retrieve a method and object identifier- A method and object identifiers can be obtained from within a class. The identifier is requested when calling up the method. The methods of the JNI called GetMethodID and GetStaticFieldID accept the class object we received in the previous step, the method or object name of the Java code and its signature as parameters. To find out what signature is used for the given method, we need to run javap utility fromJDK as follows: javap –s JavaJni. Then, in the commentary below the method, we will find its signature. For instance, the public native int onMdlCall(short) method has the “(S)I” signature. Similarly, we may find the signature for a static javaObj object – “LJavaJni;”

5. Obtain a requested instance of an object- Because we designed the JavaJni object as a static one, we can use the GetStaticObjectField function to get a reference to it. The input parameters are represented by the class and object identifier. The returned value is represented by a reference to the static javaObj object.

6. Invoke the non-static method- Now we know all the necessary gadgets to perform a call. There is a special function for each type of the calling method in Java. In our case we have designed a method returning the integer type, hence the CallIntMethod function is the right one. The input arguments must be represented by the object reference from the previous step, then the method identifier and the parameter expected by the Java method, in our case represented by the jshort value.

We can add now into the file nativeLib.cpp we used before an example of calling the Java method onMdlCall via native function dll_javaMethodCall :

int JNICALL dll_javaMethodCall(short limit)
{
JavaVM *jvm; /* denotes a Java VM */
JNIEnv *env; /* pointer to java native interface */
jsize nVMs; /* number of created JVM, should be 1 */
/* 1.*/ jint res = JNI_GetCreatedJavaVMs(&jvm,(jsize)1,&nVMs);
/* 2.*/ res = jvm->AttachCurrentThread(&env,NULL);
/* 3.*/ jclass cls = env->FindClass("JavaJni");
/* 4.*/ jmethodID mid = env->GetMethodID(cls, "onMdlCall", "(S)I");
jfieldID fid = env->GetStaticFieldID(cls, "javaObj", "LJavaJni;");
/* 5.*/ jobject obj = env->GetStaticObjectField(cls, fid);
/* 6.*/ return = env->CallIntMethod(obj, mid,limit);
}

Now we have achieved the full interaction between Java and the native code. We are able to call up native functions from the Java environment as well as Java methods from the native code. Our task now is to create a bridge in the native code for interaction with the MDL code.

Designing a native code to interact with MDL

A technology for communicating between the MDL code and DLL is well-known and is described in the MicroStation help texts. Functions from the DLL code can be imported into the MDL code by declaring a function with the nativeCode specification. The native code is able to invoke MDL as well via the documented dlmSystem_callMdlFunction function.

Let’s create a C++ file “MDLLib.cpp” to operate with MDL. A first function dll_setMdlFuncCall accepts the mdl function offset as a parameter, gets a MDL task descriptor and saves them into a global variable for later use. The second function dll_callMdlFunc will make use of the saved variables and invoke a particular offset function of the MDL task with one argument of the short type.

Te MDLLib.cpp file :

#include "stdafx.h"
extern "C"{ // mdl communication include
#define winNT
#include "mssystem.fdf"
#include "dlmsys.fdf"
}
mdlDesc *mdlDescP = NULL; // Pointer to Call back the MDL module
MdlFunctionP funcOffset = 0L; // offset to MDL function
int __stdcall dll_setMdlFuncCall(MdlFunctionP mdlFunc){
if ((funcOffset = mdlFunc) && (mdlDescP = mdlSystem_getCurrMdlDesc()))
return true;
return false;
}
int __stdcall dll_callMdlFunc(short limit){ // Invoker of a MDL function
if ((funcOffset) && (mdlDescP))
return dlmSystem_callMdlFunction(mdlDescP, funcOffset,limit);
return false;
}

Finally, we need to create a module-definition file (.DEF extension) to provide the linker with information about exported functions about the nativeLib.dll to be linked.

The Export.def file exports two functions:

The first one has just been described above, the second one is the Java method invoker function we designed in the section 2.2. Note that the previous JNI function of Java_JNIgo_callDllFunc is exported automatically.

LIBRARY "nativeLib"
DESCRIPTION 'JAVA - MDL gateway library'
EXPORTS
dll_setMdlFuncCall @1 ; MDL function call back saver
dll_javaMethodCall @2 ; Java method invoker

Designing a MDL application to interact with DLL

Finally we must design a MDL application to interact with the finished nativeLib.dll. First of all we need to map exported DLL function to the MDL import functions conventions. The linker mlink.exe needs for native function references in MDL code the Dynamic Link Specification object file (.DLS extension for source and .DLO for the precompiled object). This object is treated as a static library and is linked with an MDL program. The MDL virtual machine automatically loads the specified DLL defined in DLO file when MDL application is loaded. Compare it to the Java where the DLL must be explicitly loaded. The import.dls file reflecting just created file Export.def:

%Version 0x700
%ModuleName nativeLib
%Functions
dll_setMdlFuncCall
dll_javaMethodCall
%EndFunctions
%End

Steps to design MDL code to be able to call DLL native functions and also to be called from the DLL are listed below:

1) Add the native declarations to the global part of the mdl module corresponding to the function declarations in the Import.dls file.

nativeCode int dll_setMdlFuncCall(ULong);
nativeCode int dll_javaMethodCall(short);

2) Create a function mdlOnJavaCall to be called from the native DLL library nativeLib.dll by the function Java_JavaJni_callDllFunc which has been called by the Java class JavaJni from the method callDllFunc.

int mdlOnJavaCall ( short limit)
{
char message[255];
sprintf(message,"We got request on %d iterations",limit);
mdlDialog_openMessageBox(DIALOGID_MsgBoxOK,message,
DIALOGID_MediumInfoBox); // display info box
// do some interations...
return TRUE;
}

3) Set the function hook offset of mdlOnJavaCall for the native code in the main entry point of a MDL

int main(int argc, char *argv[]){
// some init of MDL code here...
dll_setMdlFuncCall((ULong)mdlOnJavaCall ); // set a hook for DLL
return TRUE;
}

4) Finally vice versa make a call to the nativeLib.dll on some user input event or whenever you like to call up the native function dll_javaMethodCall which will invoke Java method onMdlCall from the class JavaJni

case DITEM_MESSAGE_BUTTON:
dll_javaMethodCall(i);// call a Java method via dll
break;

Final words

The technology of interaction between Java/JMDL virtual machine and MDL gives us possibility to utilize existing MDL code for new language platform without needs of rewriting an existing code into Java. We can concentrate on new features of Java language when designing new applications without loosing low level accessing capability of our software. The examples given in the article are for learning purpose so I removed all errors and exeptions handling for shorter code. The code was tested on MicroStation v. 07.01.01.36, and native library was compiled using Microsoft Visual C++ 6.0.