Skip to content
Denis Kuzmin [ github.com/3F ] edited this page Jul 16, 2018 · 2 revisions

Complex types and Strings between unmanaged and managed environments

(Screencast) 🔀 Complex types and Strings between unmanaged and managed env. [native C++/C#/Java] :: Part2

  • 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

...