[CoinMp] How to use CoinMP.Dll in Visual Basic (Excel)

Larry A. Taylor ltaylor at seas.ucla.edu
Thu Jul 19 21:22:15 EDT 2007


I have succeeded in calling the downloaded CoiniMP.Dll through a
wrapper DLL in Visual Studio C++.

Visual Studio, Visual Basic and related languages use MicroSoft's
managed code options and a common language runtime.

For managed code:
(1) arrays are handled differently, and references to elements are
checked for lengths. This means passing the array itself as a
parameter is not by pointing to the first element, but to a
structure containing the data.
(2) Strings are arrays, but the characters are all Unicode, which
is two bytes.
(3) Pointers as such don't exist. This solves a lot of security and
integrity problems; you can't just mess up a random bit of system
memory or somebody else's program.
(4) Instead, there are references. These are sort of like pointers
to safe data structures.
(5) Related to this, you can't have "variants," treated the same
physical memory as different memory areas. The COINMP.DLL
routines depends on a C-language pointer to void (void*) type,
to hold C++ data structures.
(6) All VB memory is "managed" memory; it has to keep track
of who is using each piece in order to know when to delete it.
Garbage collection is good, and prevents a whole set of problems,
but it is absolutely incompatible with C++ memory allocations.

The C++ language itself has  features that present problems:
(1) Standard C/C++ strings are arrays of char, with null
terminations. Char in C is a byte = 8 bits. The null terminator
adds one byte to each string.
(2) There are no multiple-level arrays as such. Instead, data
with more than one level is treated as an array of pointers
at the top level.

Putting this together, it appears that char** structures needed for
rowNames and colNames parameters are impossible to create
in Visual Basic.

However, MS Visual Studio also includes a version of Visual C++
that allows you to write a wrapper as an interface between
managed and unmanaged code.

Even in managed code, arrays of basic types like Byte, Char,
Integer and Double have elements stored in consecutive storage.
And you can specify calling by reference as a keyword ByRef.
If you specify an array as a ByRef to the first element, it is
equivalent to a pointer to the array storage.

Thus, I can specify a VB array like this:
  Dim rhsValues() As Double = {20.0, 30.0, 0.0}

I declare the calling routine with a set of parameters like this;
...
    ByRef RHSValues As Double, _
...

Then I call the routine with a reference to the first element of each
array, like this:
...
                  rhsValues(0), _
...
And, as a result, the C++ routines can see the physical storage
allocated in VB as a series of adjacent elements at an address.

The HPROB data structure created and returned by the COINMP
calls are also antithetical to managed code. The only way I found
to get around this was to make the Visual C++ wrapper, and store
the pointer as a global variable. (It might work to create a new
object type with HPROB member for each instance.)

static void * theHProb;

which is saved by a wrapping routine like this:

         WSOLVAPI void  WCoinCreateProblem(char * ProblemName) {
                 theHProb = CoinCreateProblem (ProblemName);
                 return;
         } // end wrapCoinMP

and used by the other wrapping calls like this:

         WSOLVAPI int WCoinOptimizeProblem(int Method){
                 return CoinOptimizeProblem(theHProb,Method);
         } // WCoinOptimizeProblem

so that the offending data structure is never stored the managed code
routine.

In Visual Basic, I use the DLLImport attribute. I was not able to 
call any other
way than this. Here is a sample declaration of a call to one of my wrapper
functions:

     <DllImport("WrapCoinMP.dll")> _
     Function WCoinOptimizeProblem(ByVal Method As Integer) _
     As Integer

     End Function

My wrapper for CoinLoadProblem includes a routine for unpacking byte
arrays for rowNames and ColNames.

VB caller: converts VB strings to Byte arrays, and passes the first element
VC++ wrapper: converts the passed Byte arrays (char arrays) to a series
      of separate C strings with null terminators, and an array of C 
pointers to
      the strings.

Then the wrapper routine calls the CoinMP routine DLL.

This message provides clues about how to do all this. If I get the code cleaned
up OK, I might send the whole code for the test caller and the 
wrapper functions.

LAT 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://list.coin-or.org/pipermail/coinmp/attachments/20070719/ec782ecd/attachment.html


More information about the CoinMp mailing list