Here are answers to questions about locale-sensitive data that are posted from time to time on the Bentley Discussion Groups. The questions are posted mostly by MDL and VBA developers working with MicroStation®.
Q How do I generate a country-specific string in my MDL code? I don't see a way to do this.
This generic question is informed by specific questions about your computer's locale. For example …
A The C language, and hence MDL, doesn't provide very good support for locale. However, Microsoft Visual Basic (VB), and hence MicroStation Visual Basic for Applications (MVBA), do provide a locale-sensitive language.
This article describes an MDL Hack. It shows you how to jump the language barrier between C and MVBA to produce the desired result. It isn't especially pretty, but your users won't know that: they will be too lost in admiration at your magnificent application to worry about coding techniques. You can download a complete MDL project, ready for compilation.
Look at the gallery of results sent by MDL developers to see what this hack can do for you. If your locale uses a language not already shown here, send us a screen shot.
Your computer's locale is the set of country-specific or language-specific settings that govern how dates, currency, and numeric information are displayed. Microsoft can explain the Windows locale better than I.
First, let's start with some Visual Basic. As a hard-core MDL programmer, you rightly scorn VB and its simplistic approach to programming. However, buried in that language are some nuggets, and you're going to learn how to use some of them here.
VB provides a number of functions that handle dates and currencies.
For example, Now() returns a Variant (Date) specifying the current date and time according your computer's system date and time.
There's also an invaluable Format() function, which will reformat a date, currency or numeric string to a locale,
or to some other format that you can define.
MDL includes several functions related to VBA. Amongst them is mdlVBA_executeLine.
mdlVBA_executeLine accepts a literal VBA statement and executes it,
returning an appropriate status code to indicate success (E_VBAINTERFACE_NO_ERROR) or failure.
Here's an example of a VB statement that provides a date in my locale's medium date format …
Format(Now(), "medium date")
The returned value, in my British English locale, is 24-Dec-06, whereas in a US English locale it might be Dec 24 06.
You can obtain different results by specifying a different format such as "long date", or your own custom string.
Unfortunately, mdlVBA_executeLine doesn't provide a way to return a value other than its status code.
So, how do we use VB's Now() function and get its value with MDL?
MicroStation VBA provides functions that get and set MicroStation configuration variable values.
We're going to format the date and use the result in the definition of a configuration variable.
Subsequently, our MDL calling function can pick up the value of the CfgVar set by the VBA statement.
Here's the above statement wrapped in another function call to assign a CfgVar TEMP_DATE …
ActiveWorkspace.AddConfigurationVariable "TEMP_DATE", Format(Now(), "medium date")
When we use that VBA statement in the MDL call, the escape characters required by the double-quote characters obfuscate the meaning of the string. The statement below is the previous VBA statement expressed in C syntax …
const char* vba = "ActiveWorkspace.AddConfigurationVariable \"TEMP_DATE\", Format(Now(), \"medium date\")";
We can use that string in the MDL function call like this …
const char* vba = "ActiveWorkspace.AddConfigurationVariable \"TEMP_DATE\", Format(Now(), \"medium date\")";
switch (mdlVBA_executeLine (NULL, vba))
{
case E_VBAINTERFACE_NO_ERROR:
{
// Successful execution: result is in CfgVar TEMP_DATE
break;
}
}
I hope you can see where we're going with this. We've created a CfgVar with our localised string. All we need to do now it to get that CfgVar's value …
void text_getDateW ( MSWChar* date,// <= Localised date stringsize_t size// => Length of buffer) {// VBA statement formatted as a C stringconst char* vba = "ActiveWorkspace.AddConfigurationVariable \"TEMP_DATE\", Format(Now(), \"medium date\")"; const char* cfgvar = "TEMP_DATE";// Execute VBA statement that sets a configuration variableswitch (mdlVBA_executeLine (NULL, vba)) { case E_VBAINTERFACE_NO_ERROR: {// Successful execution: result is in CfgVar TEMP_DATEchar* p = mdlSystem_getExpandedCfgVar (cfgvar); if (p) { mdlCnv_convertMultibyteToUnicode (p, -1, date, size);// Delete temporary variablemdlSystem_deleteCfgVar (cfgvar); free (p); } break; } } }
We've provided an MDL project, ready to compile, in this ZIP archive.
Download the ZIP file, unpack the archive, then compile using bmake Date.
There are only two files: the make file and the MDL source code Date.mc.
Execute this MDL code using keyin MDL LOAD Date. It writes the current date, in your locale as interpreted by VBA,
into the MicroStation message center.
If your locale is not included in the gallery, e-mail us a screen-shot of your message center, and we will add it to the list of examples.
VB and VBA provide an extensive set of date and time tools.
The Format() function provides a one-stop shop for localisation.
But it's an arcane topic, and I don't want to reproduce Microsoft's documentation.
We've written some articles about VB numeric formatting
and date formatting.
Look at our links page to find web sites that specialise in VB.
There are examples of format strings embedded in the MDL source code.
This hack is fine for interactive purposes, when your users won't notice any performance issues. There may be a perceptible lag as the VBA run-time fires up on the first invocation. However, don't use this code in any kind of compute-intensive task. The overhead involved in moving data between MDL and VBA is large: all strings are copied at least once and also suffer conversion between multibyte and Unicode.
VBA code is always interpreted, so mdlVBA_executeLine is optimistic.
A better name for that function might be
mdlVBA_loadVbaRunTimeEnvironmentAndInterpretThisLine, but that would discourage people from using it.
Here are some results from people who have tested this code. If your locale is not included here, e-mail us a screen-shot of your message center, and we will add it to the list of examples.
Thanks to Miroslav Maťaš of Berit, a.s. in the Czech Republic.
Thanks to Michael Stark of DeskWare Products GmbH in Germany.
Thanks to Chris Zakrewsky of Team uStation AB in Sweden, the developers of InfoSnap for MicroStation.
Windows provides support for numerous locales. If you're writing a DLL using C++ you can use Win32 locale functions.
Here's a Code Project article about programming locales.
Return to MDL articles index.