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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.