-
-
Save zah/fe8f5956684abee6bec9 to your computer and use it in GitHub Desktop.
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Runtime.InteropServices; | |
namespace nim_sharp | |
{ | |
[StructLayout(LayoutKind.Sequential)] | |
public unsafe struct NimSring | |
{ | |
public Int32 Len; | |
public Int32 Capacity; | |
public char Text; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public unsafe struct NimSeq | |
{ | |
public Int32 Len; | |
public Int32 Capacity; | |
public byte Data; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public unsafe struct NimType_ext | |
{ | |
public Int32 x; | |
public Int32 y; | |
public NimSring* s; | |
} | |
public struct NimType | |
{ | |
public int x; | |
public int y; | |
public string s; | |
} | |
class Program | |
{ | |
[DllImport("nimlib.dll", CallingConvention = CallingConvention.Cdecl)] | |
public static unsafe extern void populateArraySruct(int length, NimSeq** ArrayStructs); | |
public static unsafe List<NimType> getResultsFromNim(int ArrL) | |
{ | |
List<NimType> convertedResults = new List<NimType>(ArrL); | |
NimSeq* nimResults = null; | |
populateArraySruct(ArrL, &nimResults); | |
NimType_ext* currentItem = (NimType_ext*) &(nimResults->Data); | |
for (int i = 0; i < ArrL; i++, currentItem++) | |
{ | |
convertedResults.Add(new NimType() {x = currentItem->x, y = currentItem->y, s = new string(&(currentItem->s->Text))}); | |
} | |
return convertedResults; | |
} | |
static void Main(string[] args) | |
{ | |
var list = getResultsFromNim(10); | |
foreach (var elem in list) { | |
Console.WriteLine("x: {0}, y: {1}, s: {2}", elem.x, elem.y, elem.s); | |
} | |
} | |
} | |
} |
# compile with nim c -app:lib nimlib.nim | |
# place next to the C# executable together with a compiled copy of nimrtl.dll | |
type | |
NimTypeSeq = seq[NimType] | |
NimType = object {.packed.} | |
x: int | |
y: int | |
s: string | |
proc populateArraySruct(outputLength: int, output: var NimTypeSeq) {.exportc,dynlib.} = | |
setupForeignThreadGc() | |
output.newSeq(outputLength) | |
for i in 0 .. <outputLength: | |
output[i] = NimType(x: i, y: i*2, s: $i) | |
the only problem i have left as i mention in former post, as we only pass numeric char now it does work but encoding is wrong shows string as??? is this an issue or simple solution ? try concat $i as s= "abc" & $i
Nim strings are usually stored in UTF-8, although the language doesn't require that. In C#, the encoding is UCS-2 (UTF-16). Take a look at the following stackoverflow answer that features some conversion code:
http://stackoverflow.com/questions/10773440/conversion-in-net-native-utf-8-managed-string
StringFromNativeUtf8 is the one i think, i will take a time to test both ways to see if that is the solution, as this has to be the one, i will report to you as soon as i find the time to play with it again, thanks i think that concludes the subject of the string passing from nim to c# which was not a simple task for me, as soon as i will confront this, and do some more tests i will be more familiar and it will be simpler from that point, i'll let you know. thanks a lot as ususall !
Yes, my builds were 32-bit and I'm using a Nim compiler compiled straight from the devel branch. On Windows, I also use the older 32-bit mingw distribution.
Basically, these problems are not very hard to trouble-shoot, but you have to be a bit more seasoned C/C++ developer. You can always examine the C code produced by Nim (placed in the nimcache folder) and you can use the "Memory" debug window in Visual Studio to see the actual data written by the Nim dll. From there, it's just a matter of comparing your conceptual model expectations with the reality you see in the debugger.