Examples Part 2
Complex types and Strings between unmanaged and managed environments
-
00:10 - Passing Unicode strings from C# to unmanaged C++ ((host side)). Samples for arguments and for the return value.
-
05:21 - Passing complex types from C# to unmanaged C++ ((host side)). Samples for structures.
-
08:42 - Passing arrays from unmanaged C++ ((host side)) to C#.
-
11:33 - By the way, How to debug at runtime both managed + unmanaged environments. ~(.NET Clr & native unmanaged C++)
-
12:27 - Passing multidimensional arrays from C++ ((host side)) to C#.
-
14:22 - Passing Unicode strings from C++ to C# ((host side)).
-
16:23 - Passing complex types from C++ to C# ((host side)). Samples for structures.
-
20:50 - An alternative. Native C/C++ structures without declaration. Manual accessing at runtime.
-
22:47 - Passing arrays to C# from Java ((host side)). Do it anywhere.
-
@ 24:34 how it can be implemented without information about size. Think different -_*
Raw Source code from Screencast
First way
C++
const TCHAR* pemodule = _T("D:\\Samples\\PEClr\\bin\\PEClr.dll"); HMODULE lib = LoadLibrary(pemodule); typedef void(__cdecl *alloc)(); typedef void(__cdecl *free)(); ((alloc)GetProcAddress(lib, "alloc"))(); // -- getString() typedef const TCHAR* (__cdecl *getString)(); auto pGetString = (getString)GetProcAddress(lib, "getString"); const TCHAR* msg = pGetString(); // -- via out/ref typedef void (__cdecl *getStringArgs)(const TCHAR** ); auto pGetStringArgs = (getStringArgs)GetProcAddress(lib, "getStringArgs"); const TCHAR* msgArg = nullptr; pGetStringArgs(&msgArg); // TVer struct TVer { int major; int minor; int patch; }; typedef const TVer* (__cdecl *getTVer)(); auto pGetTVer = (getTVer)GetProcAddress(lib, "getTVer"); const TVer* ver = pGetTVer(); // -- setArray typedef bool(__cdecl *setArray)(const int*, int size); auto pSetArray = (setArray)GetProcAddress(lib, "setArray"); int data[] = { 0x0D, 0x0E, 0x0F, 0x3F }; pSetArray(data, 4); int datam[2][2] = { { 0x0D, 0x0E }, { 0x0F, 0x3F } }; pSetArray(*datam, 4); ((free)GetProcAddress(lib, "free"))(); FreeLibrary(lib);
C#
public static class Sample2 { private static UnmanagedString msg; private static UnmanagedStructure data; private struct TVer { public int major; public int minor; public int patch; public TVer(int major, int minor, int patch) { this.major = major; this.minor = minor; this.patch = patch; } } [DllExport] public static IntPtr getString() { return msg; } [DllExport] public static void getStringArgs(out IntPtr ptr) { ptr = msg; } [DllExport] public static void printArray(IntPtr ptr) { int _r(IntPtr src, int ofs) { return Marshal.ReadInt32(ptr, ofs); }; string _get(IntPtr _ptr, int zzz) { string ret = String.Empty; int ofs = Marshal.SizeOf(typeof(Int32)); int num, i = 0; while((num = _r(ptr, ofs * i++)) != zzz) { ret += $"\n-> {num}"; } return ret; }; MessageBox.Show(_get(ptr, 7), "-_*"); } [DllExport] public static bool setArray(IntPtr ptr, int size) { // I'll add more features soon (I hope) for work with different arrays in Conari via pointers ! // stay in touch :) github.com/3F int[] data = new int[size]; Marshal.Copy(ptr, data, 0, data.Length); // TODO: .... return data?.Length > 0; } [DllExport] public static IntPtr getTVer() { return data; } [DllExport] public static void alloc() { msg = new UnmanagedString("Hello ! this is a unicode characters from .NET clr", UnmanagedString.SType.Unicode); data = new UnmanagedStructure(new TVer(2, 7, 1)); } [DllExport] public static void free() { msg?.Dispose(); data?.Dispose(); } }
Second way
C++
EXAPI const TCHAR* getString() { return _T("Hello from unmanaged C++"); } // what about complex types ? struct MyStruct { int x; int y; int z; }; EXAPI const MyStruct* allocStruct(int x, int y, int z) { return new MyStruct{ x, y, z }; } EXAPI void freeStruct(const MyStruct* obj) { delete obj; }
C#
[StructLayout(LayoutKind.Sequential)] public struct MyStruct { public int x, y, z; } ... using(var l = new ConariL(@"D:\Samples\PENative\x64\Debug\DllNative.dll")) { var d = l.DLR; // or with details via bind<> .. etc. string msg = d.getString<WCharPtr>(); IntPtr ptr = d.allocStruct<IntPtr>(7, 4, 12); l.BeforeUnload += (object sender, DataArgs<Link> e) => { d.freeStruct(); }; var us = new UnmanagedStructure(ptr, typeof(MyStruct)); var g = (MyStruct)us.Managed; unchecked { long v = g.x + g.y - g.z; } // or like var z = ptr.Native() .align<int>(2) .t<int>("z") .Raw.Type.DLR.z; // ~ z = ptr.Native().field<int>(3); // etc. }
References
- Part-1. Managed & Unmanaged; PInvoke. C++ ❤ C#.
- Conari.
- JNA.
- You can also use my old an explanation, for example, from here:
...