Summary:  Paper describes a technology of using MFC non modal dialog boxes inside MicroStation

 

Date: January 2001

Published in : MSM January 2002

Author: Stanislav Sumbera

 

*

download code

 

 

 

*

pdf version

 

 

 

MSM online

 

 

 

 

  

 

 

 

 

 

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.