# How can multiple null terminated strings be handled in a DLL-function result?

I am trying to connect a classic System Dynamics tool (Vensim DSS) with Mathematica using a DLL that is included in Vensim DSS. Reading though the instructions on how to define DLL functions on how to declare arguments - here strings - I found that if there are [out] strings one should use the .NET class System.Text.StringBuilder.

So applying the advice given will look like this:

(* definitions *)
$maxBufLen = 1000; strOutput = NETNew["System.Text.StringBuilder",$maxBufLen];
vensimGetInfo = DefineDLLFunction["vensim_get_info", vensimDLL,
"int", {"int", "System.Text.StringBuilder", "int"}];

(* usage *)
infoWanted = 3; bufLen = $maxBufLen; vensimGetInfo[infoWanted, strOutput, bufLen]; strOuput@ToString[]  Unfortunately this only works properly for a single string and some information will be returned by the DLL function as a series of null terminated strings that is finally ended by a double null. In such a case the above procedure will only return the first string omitting the rest. What can be done? - IMO, this is really a Windows/.Net question rather than a Mathematica issue per se. Relevant: blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx, snipplr.com/view/27336. The answer would seem to be that System.Text.StringBuilder does not support this type of string and something else should be used instead. I personally have no experience with .Net, so I will let someone else make the suggestion as to what that should be. – Oleksandr R. Nov 24 '13 at 12:26 ## 1 Answer First off, I should mention that Vensim also has a Java interface that you could call using J/Link. The Java signature of this particular function is static String[] get_info(int infowanted);  so you can see that the different strings are conveniently returned in an array for you. But you can also do what you want using .NET/Link's DefineDLLFunction. You have to drop down to low-level memory allocations. Declare the buffer that will be filled with the strings as an IntPtr: vensimGetInfo = DefineDLLFunction["vensim_get_info", vensimDLL, "int", {"int", "IntPtr", "int"}];  Then allocate a buffer of a size large enough to hold all the data: LoadNETType["System.Runtime.InteropServices.Marshal"]; buf = MarshalAllocHGlobal[$maxBufLen];


Call the DLL function:

infoWanted = 3;
numBytes = vensimGetInfo[infoWanted, buf, \$maxBufLen];


One way to get the data from buf is to copy it into a .NET array, and then use NETObjectToExpression to convert it into a list of character values.

managedArray = NETNew["System.Byte[]", numBytes];
MarshalCopy[buf, managedArray, 0, numBytes];
bytes = NETObjectToExpression[managedArray]


bytes will look something like {100, 105, ..., 0, 97, 100, ..., 0, 105, 102, ... 0, 0}. Use whatever method you like to convert these character values into separate strings, such as

FromCharacterCode[DeleteCases[SplitBy[bytes, # != 0 &], {0..}]]

-
Thanks a lot, Todd, that pretty much looks like THE answer to the problem. For completeness I will also point out a solution using the DLL function "vensim_get_substring" which Ventana posted on the Vensim Forum: vensim.com/documentation/index.html?26210.htm –  gwr Nov 25 '13 at 11:26