A C++ Class to Convert MicroStation ElementRefs to MSElement

MDL Element references (ElementRefs) are useful because they are lightweight. However, they don't contain all the data that's in a full element (MSElement or MSElementUnion) structure.

Many MDL functions require an element's data to work with: they take an MSElement* as an argument. If you have an ElementRef, then you have to get its MSElement data. I want to obtain a temporary MSElement from an ElementRef handle in several places in my code. Rather than writing the same handful of lines each time, I created a class to manage memory allocation, data copying, and memory deallocation. The application is written in C++, so I'm able to benefit from some aspects of C++ constructors and destructors.

Below you will find extracts from the following files …

CElement Header File

CElement.h

#if !defined(MICROSTATION_UTILITIES_H_INCLUDED_)
#define MICROSTATION_UTILITIES_H_INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

//////////////////////////////////////////////////////////////////////
//	CElement 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
//////////////////////////////////////////////////////////////////////
//	CElement class is a helper to ensure that MSElement memory allocation
//	is handled correctly and automatically.  Instantiate this class
//	and assign an ElementRef in the constructor.
//	The Element() method returns an MSElement pointer.
//	The destructor deallocates memory automatically
//////////////////////////////////////////////////////////////////////

class CElement
{
public:
    //////////////////////////////////////////////////////////////////////
    //	Construction
    CElement		(const ElementRef		elemRef);
    ~CElement		();
    //////////////////////////////////////////////////////////////////////
    //	Implementation
    MSElement*		Element	();
private:
    MSElement*			el_;
    const size_t		size_;
};
//////////////////////////////////////////////////////////////////////

#endif //   MICROSTATION_UTILITIES_H_INCLUDED_

CElement Implementation File

CElement.cpp

//    Standard include for MFC projects
#include "stdafx.h"
//    Our header
#include "CElement.h"
//    MDL header files

#include <mselemen.fdf>
#include <mssystem.fdf>
#include <tcb.h>
//////////////////////////////////////////////////////////////////////
//	CElement 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
//////////////////////////////////////////////////////////////////////
//  CElement constructor
CElement::CElement      (const ElementRef		elemRef)
    :   size_           (elementRef_getElemSize (elemRef)),
        el_             (NULL)
{
    el_	= (MSElement*)new byte [size_];
    if (!elementRef_getElement (elemRef, el_, size_))
    {
        //	Issue warning
    }
}
//////////////////////////////////////////////////////////////////////
//  CElement destructor
CElement::~CElement     ()
{
    if (el_)
        delete [] el_;
}
//////////////////////////////////////////////////////////////////////
//	CElement's sole method: return a pointer to our element
MSElement*	CElement::Element	()
{
    return el_;
}

CElement Const-ness

I'm keen on const: it's a valuable C++ language feature that keeps us honest. Why isn't CElement::Element () const? The unfortunate fact is that most of the MDL functions that take an MSElement* have a non-const function declaration in the MDL header files.

If I made CElement::Element (), like this
MSElement const* CElement::Element () const;
then most of the time I would have to cast it back to non-const to quieten the C++ compiler.

CElement Example

Here's an example that illustrates the use of CElement. In this case I have an ElementRef from somewhere, and I want to find its database linkages. Because there is no function to get database linkages from an ElementRef, I convert it to an MSElement …

//////////////////////////////////////////////////////////////////////
void SomeFunctionThatRequiresAnMSElement (ElementRef* elementRef)
{
    CElement el (elementRef);
    //  Call some function that takes an MSElement*
    DatabaseLink*	links	= NULL;
    int				nLinks	(0);
    if (SUCCESS == (status = mdlDB_extractLinkages (&links, &nLinks, el.Element ())))
    {
        //  do something with data
        dlmSystem_mdlFree (links);
    }
    //  CElement destructor deallocates memory automatically
}
//////////////////////////////////////////////////////////////////////