Introduction

The MicroStation Development Library (MDL) and MicroStationAPI provide APIs for developers wanting to create custom applications for MicroStation® from Bentley Systems. We create a MicroStation application as a DLL, written using C++ and built with the Microsoft C++ compiler and linker provided with Visual Studio.

When editing your source code, you can choose whether to use Microsoft Visual Studio, Microsoft Visual Studio Code, or one of your favourite text editors.

When building your app, you can use Visual Studio or the Bentley Systems make (bmake) tools.

Undo Manager

I want to enable MicroStation's undo logic when I change several elements in my MDL application. The application is written in C++, so I'm able to benefit from some aspects of C++ constructors and destructors.

There are two ways to accomplish this: the MicroStationAPI way and the MDL way.

MicroStationAPI Transaction Manager

#include <DgnPlatform/ITxnManager.h>

If you're using the MicroStationAPI, which provides a set of C++ classes, then you can use the Transaction Manager. The Transaction Manager includes the method pair ITxnManager::StartTxnGroup and ITxnManager::EndTxnGroup. Bentley Systems staffer Brien Bastings commented:

Be very careful not to mis-match these — that can be disastrous. Test that your tool behaves properly if the user does a Ctrl+Z in the middle of its operation, starts another tool, restarts your tool, etc.

The Transaction Manager provides more than the MDL API. See the MicroStationAPI help documentation for ITxnManager::Activate and ITxnManager::Deactivate

MDL: mdlUndo_xxx

MDL function mdlUndo_startGroup should precede one or more DGN operations on elements. The MDL documentation about that function states: Calls to mdlUndo_startGroup can be nested, but should always be matched with a corresponding call to mdlUndo_endGroup.

I'm pretty good at forgetting to do things, so that last statement raised a warning flag in my mind. How could I be sure always to call mdlUndo_endGroup? The solution, with a C++ class, is very simple: we design a class to manage undo groups by calling mdlUndo_endGroup in its destructor.

We should be able to use the class something like this …

void SomeFunctionThatModifiesElements ()
{
    UndoGroup undo;
    ...
    //  Code that modifies multiple elements
    ...
    //  UndoGroup calls mdlUndo_endGroup in its destructor
}

Here's the source code of the UndoGroup class. Feel free to add this to your own C++ projects. UndoGroup's constructor calls mdlUndo_startGroup. UndoGroup's destructor calls mdlUndo_endGroup. That's it!

UndoGroup Header File

UndoGroup.h

#if !defined(UNDO_GROUP_H_INCLUDED)
#define UNDO_GROUP_H_INCLUDED

//////////////////////////////////////////////////////////////////////
//	UndoGroup example provided by LA Solutions Ltd
//	You may freely copy this code for use in your own C++ projects
//	whether commercial or otherwise.
//	http://www.la-solutions.co.uk
//////////////////////////////////////////////////////////////////////
//	UndoGroup class is a helper to ensure that undo groups are
//	managed correctly and automatically.  Instantiate this class
//	before changing one or more elements.
//////////////////////////////////////////////////////////////////////
class UndoGroup
{
public:
    //////////////////////////////////////////////////////////////////////
    //  Construction
    UndoGroup  ();
    ~UndoGroup ();
    //////////////////////////////////////////////////////////////////////
};

#endif //   UNDO_GROUP_H_INCLUDED

UndoGroup Implementation File

UndoGroup.cpp

//    Our header
#include "UndoGroup.h"
//    MDL header files
#include <msundo.fdf>
//////////////////////////////////////////////////////////////////////
//  UndoGroup example provided by LA Solutions Ltd
//  You may freely copy this code for use in your own C++ projects
//  whether commercial or otherwise.
//  http://www.la-solutions.co.uk
//////////////////////////////////////////////////////////////////////
//  UndoGroup constructor
UndoGroup::UndoGroup      ()
{
  mdlUndo_mark ();
  mdlUndo_startGroup ();
}
//////////////////////////////////////////////////////////////////////
//  UndoGroup destructor
UndoGroup::~UndoGroup     ()
{
  mdlUndo_endGroup ();
  mdlUndo_mark ();
}
//////////////////////////////////////////////////////////////////////

UndoGroup HPP File

UndoGroup.hpp

Given the modest amount of code required to implement this class, you could merge the header and implementation files into a single .hpp file.

Questions

Post questions about C++ and the MicroStationAPI to the MicroStation Programming Forum.