HoloLens Callbacks with Native Library
Asked Answered
A

1

9

My goal is to call methods, which are implemented in the Unity Code, from my UWP DLL. (So I can use them in my HoloLens Project)

I tried this with a bigger project but failed. Therefore I wrote a simple example to make it easier to find the mistake and exclude other influences. But still, I get the same error.

My Working Environment:

  • 64-bit Computer with OS Windows 10
  • Micsrosoft Visual Studio Community 2015 Version 14.0.25431.01 Update 3
  • HoloLens Emulator 10.0.14393.0
  • Unity 5.5.0f3 Personal (64 bit)

Creating the UWP DLL:

To approach this I created a C++ DLL(Windows Universal) in Visual Studio 2015 as followed:

New Project > Visual C++ > Windows > Universal > DLL(Universal Windows)

After the project was auto generated I added my code. So the code looks like this:

Native Library Code:

SimpleProjectDLL.cpp:

#include "pch.h"
#define DLL_EXPORT __declspec(dllexport)

typedef void(*CB_V)();
typedef void(*CB_V_VI)(const char * a, int b);

CB_V_VI cb_native_log;
CB_V cb_call;

void log()
{
    // this method makes problems !
    cb_native_log("Call for callback", 1);
}

extern "C" {
    DLL_EXPORT void initInterfaceCallbacks(
        CB_V_VI native_log,
        CB_V call
    ) {
        cb_native_log = native_log;
        cb_call = call;
    }

    DLL_EXPORT void callSmth() 
    {
        cb_call();
    }

    DLL_EXPORT int getSomeInt()
    {
        return 42;
    }

    DLL_EXPORT void initCallback() 
    {
        log();
    }
}

SimpleProjectDLL.h is prepearing the delegates:

SimpleProjectDLL.h:

#pragma once
#include <cstdint>
#define DLL_EXPORT __declspec(dllexport)

extern "C" 
{
    typedef void(*CB_V)();
    typedef void(*CB_V_VI)(const char * a, int b);
}

I did not make any changes to the auto generated files dllmain.cpp, pch.cpp, pch.h or targetver.h.

Finally I build the project for "Release" mode and architecture "x86" to generate the DLL-file. Location of the DLL-file is now: project-root-folder/Release/SimpleProject/SimpleProjectDLL.dll.

---------------------

Next step I created a new Unity Project added the HoloLens-Toolkit and made sure that the new project is running fine on the emulator.

Unity Project Code:

After that I added the SimpleProjectDLL.dll in the Asset-Folder and implemented the following code:

First of all we need to create the connection between the delegates. Cpp.cs prepears the Delegates:

Cpp.cs

using UnityEngine;
using System;
using System.Runtime.InteropServices;

namespace Cpp
{
    delegate void DelegateV();
    delegate void DelegateVVi(IntPtr a, int b);
}

SimpleInterfaceCpp.cs initializes the connection:

SimpleInterfaceCpp.cs

using Cpp;
using System.Runtime.InteropServices;
using UnityEngine;

public static class SimpleInterfaceCpp
{
    public static void Init()
    {
         initInterfaceCallbacks(
            SimpleInterface.NativeLog,
            SimpleInterface.Call
        );
    }

    [DllImport(SimpleInterface.DLL)]
    private static extern void initInterfaceCallbacks(
        DelegateVVi native_log,
        DelegateV call
    );
}

Main:

MainController.cs

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

public class MainController : MonoBehaviour 
{
    void Start ()
    {
        SimpleInterfaceCpp.Init();
        SimpleInterface.TestCalls();
    }
}

SimpleInterface.cs is calling the methodes:

SimpleInterface.cs

using System;
using UnityEngine;
using System.Runtime.InteropServices;
using AOT;
using IntPtr = System.IntPtr;
using Cpp;

using StringReturn = System.IntPtr;

public class SimpleInterface
{
    public const string DLL = "SimpleProjectDLL";

    public static void TestCalls()
    {
        // This works fine
        int number = getSomeInt();
        Debug.Log("getSomeInt: " + number);

        // This also works fine and outputs "--- A callback ---"
        callSmth();

        // This call gives the output "call_log: native log" but crashes afterwards !
        initCallback();

    }

    [MonoPInvokeCallback(typeof(DelegateVVi))]
    public static void NativeLog(IntPtr logMessage,
         int logLevel)
    {
        string result = StringFromCReturn(logMessage);
        UnityEngine.Debug.Log(result); // outputs "call_log: native log"
    }

    [MonoPInvokeCallback(typeof(DelegateV))]
    public static void Call()
    {
        UnityEngine.Debug.Log("--- A callback---");
    }

    [DllImport(DLL)]
    private static extern void initCallback();
    [DllImport(DLL)]
    private static extern void callSmth();
    [DllImport(DLL)]
    private static extern int getSomeInt();

    public static string StringFromCReturn(StringReturn someReturnVal)
    {
        return Marshal.PtrToStringAnsi(someReturnVal);
    }
}

Now if I create a SLN, open the project in Visual Studio and start it with the "HoloLens Emulator" I get the following Output:

getSomeInt: 42

(Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)


--- A callback---

(Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)


call_log: native log

(Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)


The program '[1932] SimpleProject.exe' has exited with code -1073740791 (0xc0000409).

After that the App just closes.

So my Question is, does anyone know what the problem could be?

Is this the right way to use callbacks in a HoloLens Project?

Or does someone know how to find an error description for the code "-1073740791 (0xc0000409)" ?


Additional Information: I also tried it on a real HoloLens device, same issue, so the problem does not lays at the emulator.

Anaxagoras answered 25/1, 2017 at 14:21 Comment(5)
Where did you put the DLL? The DLL should be placed in Assets\Plugins. For more info, please see: docs.unity3d.com/Manual/Plugins.html.Pitre
I can reproduce this with just creating a Unity Project, build for Hololens, D3D, Generate C# projects. Open the .sln in Visual Studio, build, run, close the app window and I get an Unhandled Exception with 0xc0000409.Claus
patch 5.6.0p1 fixed the above for meClaus
Take a look at this question and especially the accepted answer for it: #5235945. The attribute [UnmanagedFunctionPointer(CallingConvention.Cdecl)] is used on delegates in C# as C and C# behave differently on how stack memory is handled i.e. cdecl vs stdcall.Hawken
This link has an example of this solution using RCYR's suggestion gamedev.net/articles/programming/…Millburn
S
0

The error is STATUS_STACK_BUFFER_OVERRUN. The call destroyed callstack.

You have different declarations of callbacks in SimpleProjectDLL.cpp and SimpleProjectDLL.h. Cpp file uses "CPP" call conversation, header uses "C" call conversation.

You should change SimpleProjectDLL.cpp by removing

typedef void(*CB_V)();
typedef void(*CB_V_VI)(const char * a, int b);

and adding

#include "SimpleProjectDLL.h"
Schnurr answered 25/4, 2019 at 15:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.