vba2mdl

There's an MDL example vba2mdl. The MDL code compiles, but is there a VBA project to go with this? I'm trying to figure out how to declare the MDL functions in VBA to be able to call them.

Regards, Jon Summers
LA Solutions

  • Hi John,

    That example vba2mdl (MDL side) and it's corresponding example mdl2vba (VBA side) was created to show how to pass data between a VBA app and an MDL app through the use of a "shared data structure" that is declared and published in the MDL code. There is nothing in this example to show how to directly call MDL functions in a .MVBA application.

    At some point back in time, I believe there was some documentation on how to declare and call MDL functions directly from inside a .MVBA application....I will have to check my archive data at my home office to see if I can find any documentation for you.

    At the bottom of each MDL Function Reference page, there is a VBA Wrapper Declaration....if you use this at the top of your VBA code, you should be able to make a call later in your VBA code to the declared function....using the VBA data types.

    On a side note....I could not find any delivered VBA documentation with the MS SS1 version that I have installed at my clients office, so I can't say if there is any info in that document for you....not sure why it is missing either!

    Regards,

    Bert Fegyverneki

  • VBA and pure MDL

    The cited pre-V8i example vba2mdl.mc publishes various objects. It publishes a structure and a couple of functions. By 'publish' we mean making a symbol available to the MicroStation C Expression Parser.

    When a symbol is published it can be used by VBA's GetCExpression() function. The syntax is idiosyncratic and unintuitive …

    MDL
    
    Private void	mdl2VbaInfo_printStructure () { … }
     …
    mdlCExpression_symbolPublish (pSymbolSet, "mdl2VbaInfo_function",
    			  SYMBOL_CLASS_FUNCTION, 0,
    			  mdl2VbaInfo_function);
    
    VBA
    
    GetCExpression "mdl2VbaInfo_function"  ' Executes MDL function
    

    Idiosyncratic & unintuitive it may be, but it works! As Dr Johnson said, " …like a dog's walking on his hind legs. It is not done well; but you are surprised to find it done at all."

    The problem with the pure MDL approach via C expressions is the disconnect between the formality of C and VBA's 'make it up as you go along' idiom. From the VBA developer's perspective, unless you already know the internals of the MDL function, you are writing the C expression in the dark. There's no way for VBA to check whether your syntax is correct or not, because the C expression is no more than a quoted string, and VBA doesn't know or care about the contents of a quoted string.

    The MDL help documentation, as you note, provides VBA function declarations. You can use an MDL function that is declared correctly in your VBA code. The benefit of this approach is that the syntax is now clear to both man & machine, and the VBA compiler can use the formal function definition to tell you when you make a mistake.

    VBA and Native Code MDL

    The documented MDL functions live these days in DLLs. VBA's Declare syntax provides the function signature and names the DLL where the function lives.

    Now that we can compile native-code MDL that lives in a DLL, it occurs to me that there's no reason why we should not be able to write our own public functions, with a C-style call syntax. Taking the V8i example vba2mdl.cpp …

    
     '	Although this is compiled with C++, we're stipulating a C-style call to be compatible with VBA's expectations
    extern "C" void	mdl2VbaInfo_printStructure  () { … }
    

    That function lives in vba2mdl.dll. Shouldn't we be able in VBA to write this …

    Declare Sub mdl2VbaInfo_function Lib "vba2mdl.dll" ()
    

    Now we should be able to use that function explicitly, rather than wrapping it in a C expression handler …

     ' Execute declared MDL function
    mdl2VbaInfo_function
    

    Because neither example vba2mdl.mc (pure MDL) nor vba2mdl.cpp (native code) includes a matching VBA project, we don't know Bentley's intention.

    Regards, Jon Summers
    LA Solutions

     
    Regards, Jon Summers
    LA Solutions

  • Hi John,

    Thanks for the great explanation of this topic.

    There is a delivered MVBA example found in:

    C:\Documents and Settings\All Users\Application Data\Bentley\MicroStation V8i (SELECTseries 1)\WorkSpace\System\vba\examples\mdl2vba.mvba

    It is the only delivered VBA project that Bentley has supplied to match the vba2mdl code, but it is a bit dated.

    My explanation to you was based on what I was told by Mark Anderson several years ago when I first used this methodology to have a data processing "pure MDL" application communicate with a VBA dialog instead of an MDL dialog.

    The MDL app launched and immediately called the MVBA app to supply the interface for the user. After selecting a few settings and an Okay button, the MVBA dialog closed and the MVBA app was unloaded and the MDL app did it's thing. And you are right...it works, but from the VBA side, you need to know how the MDL code works.

    It would be nice if this MVBA app could be updated or a new example created to do what you describe, as I have not tried this approach.

    It is also why I try to stay away from VBA.....if I have to make calls to MDL functions, I would just as soon write an MDL or Native Code application.

    Perhaps Mark Anderson or someone else from Bentley could add their thoughts on what you want to do?

    Regards,

    Bert Fegyverneki

    PS. I just went back into the above noted VBA example directory and noticed an MVBA app called "NativeCodeUtilities.mvba".

    I think this app my have what you are looking for.....

    Regards, Bert

     

     

  • There is a delivered MVBA example found in: C:\Documents and Settings\All Users\Application Data\Bentley\MicroStation V8i (SELECTseries 1)\WorkSpace\System\vba\examples\mdl2vba.mvba
    I just noticed an MVBA app called NativeCodeUtilities.mvba.

    Thanks for pointing out those two VBA projects. It's not always obvious, in this 21st century folder organisation, where to look for stuff.

    Regards, Jon Summers
    LA Solutions

     
    Regards, Jon Summers
    LA Solutions

  • You are welcome John....I'm glad I could help!

    I hear that it will continue to get worse as Bentley continues to restructure directories to meet the Windows 7 certification requirements in the upcoming new releases of Bentley products!

    Something to look forward to....sort of like an Easter Egg hunt!

    Cheers!

    Bert

  • Some comments from me here.

    The favour of that old VBA interface against a 'exported functions' version is the version independency and support. I have a far old Access VBA (not only MVBA will work)  that still calls my published functions while I would have to redesign the stuff to use my own exports.

    The backpack is clear, no type checking, not support for debugging consistently. Exporting functions should work as expected, and as long as no interface changes were made.

    I even implemented some message-handling stuff, as a third way to intercommunicate, which enables me to be called from where ever I like. I instantiate a hidden window that accepts special messages and react upon the typical LParam/WParam combinations.

    MIchael



  • I have used the GetCExpression method in VBA fo fill gaps in the VBA Object Model where the MDL functions were not published out to StdCalls.  A recent example is: communities.bentley.com/.../accessing-geocoordinate-information-in-vba.aspx  Where I access the GeoCoordinate api (which is C++ or .NET) only.

    Some background on this topic:  MDL functions while they are native code dll's now are declared as Cdecl which is not what VBA needs (VBA can call StdCall functions) so when the MDL documentation is created it also creates the StdCall wrapper for the functions.  Now not all functions can be processed, for example variable argument functions so not all of MDL is directly accessable.  

    I think that this is a tool that developers can leverage to create best fit solutions.  If you find that you are calling a large number of C functions then maybe the app should have been written in C?  It can also be used nicely for divide and conquer programming.  Have the UI done quickly in VBA but then some solids or other more difficult parts do in C/C++?  

    HTH,

    mark anderson [Bentley]

  • _stdcall wrappers

    I've been working on an updated pair of MDL/VBA vba2mdl2 examples, which I'm about to publish. This native-code example exports functions and provides the required Declare statement for VBA. The result is a set of custom functions in a native-code DLL that can be called directly from VBA. The VBA developer obtains the benefits of type checking and IntelliSense.

    The article explains, from the MDL developer's side, what needs to be done to export a function and make it visible to VBA with the correct C-style _stdcall syntax in C++.

    A problem I have not been able to solve is exporting the plain, undecorated name of the C++ function. The only way I have succeeded in making a function visible to VBA is by declaring it like this …

    extern "C" DLLEXPORT int _stdcall FuncName (int arg1, double arg2);

    VBA can't see the function unless I add it to the EXPORTS section of the C++ project's .def file. Unfortunately, _stdcall decorates the function name with an underscore prefix and a suffix that indicates the number of bytes in the argument list. That is, the above in VBA becomes …

    Declare _FuncName@12 Lib "MyLib.dll" (ByVal arg1 As Long, ByVal arg2 As Double) As Long

    I can't figure out what needs to be done, as Bentley does with the MDL wrappers, to make the function name appear in VBA as the original does in C++. I guess this is some kind of smoke-and-mirrors to overcome the Microsoft-specific way of exporting functions. A hint would be appreciated.

    Another problem I came across is Unicode string exchange. If a function has a char* string argument VBA works with it, converting between the C-style multibyte string to VBA's internal Unicode string. But, if I pass a wchar_t* Unicode string from the native-code DLL, VBA doesn't see it. What do I need to do to exchange Unicode strings successfully?

    Regards, Jon Summers
    LA Solutions

     
    Regards, Jon Summers
    LA Solutions

  • Unknown said:

    A problem I have not been able to solve is exporting the plain, undecorated name of the C++ function. The only way I have succeeded in making a function visible to VBA is by declaring it like this …

    extern "C" DLLEXPORT int _stdcall FuncName (int arg1, double arg2);

    VBA can't see the function unless I add it to the EXPORTS section of the C++ project's .def file. Unfortunately, _stdcall decorates the function name with an underscore prefix and a suffix that indicates the number of bytes in the argument list. That is, the above in VBA becomes …

    Declare _FuncName@12 Lib "MyLib.dll" (ByVal arg1 As Long, ByVal arg2 As Double) As Long

    I can't figure out what needs to be done, as Bentley does with the MDL wrappers, to make the function name appear in VBA as the original does in C++. I guess this is some kind of smoke-and-mirrors to overcome the Microsoft-specific way of exporting functions. A hint would be appreciated.

    Jon, I had no problem to export function without decorates... Are you exporting functions from class or namespace?

    I'm exporting it directly from .cpp file to avoid decoration

    in cpp file:

    bool _stdcall NoZero(Point3d& P)
    {
        if(P.x != 0.0) {
            if(P.y != 0.0) {
                if(P.z != 0.0) {
                    return true;
                }
            }
        }
        return false;
    }

    in def file:

    LIBRARY TestExport

    EXPORTS
    NoZero   @1

    Unknown said:

    Another problem I came across is Unicode string exchange. If a function has a char* string argument VBA works with it, converting between the C-style multibyte string to VBA's internal Unicode string. But, if I pass a wchar_t* Unicode string from the native-code DLL, VBA doesn't see it. What do I need to do to exchange Unicode strings successfully?

    Jon, this is described in MicroStation v8 VBA help in section Overview -> Developing Code in VBA -> Calling DLL functions from VBA, here look over heading Strings. There is all explained.

    Declare Function mdlFile_find _
         Lib "stdmdlbltin.dll" _
         (ByVal outname As String, _
         ByVal inname As String, _
         ByVal envvar As String, _
         ByVal iext As StringAs Long

    Sub FindFile()
         Dim strFullName As String
         'Allocate the buffer
         strFullName = Space(512)

         'Call the function
         If mdlFile_find(strFullName, "accudraw""MS_MDL"".ma") = 0 Then
              'Truncate at C’s end-of-string
              strFullName = Left$(strFullName, _
                InStr(1, strFullName, _
                vbNullChar) - 1)
              Debug.Print "The full path is " & strFullName
         End If
    End Sub
  • VBA2MDL2

    The VBA2MDL2 project is available here.

    Thanks for comments received so far — more are welcome. My goal is to provide a well-documented example C++ project and VBA project, together with helpful documentation.

    Regards, Jon Summers
    LA Solutions

     
    Regards, Jon Summers
    LA Solutions