使用本机库的 HoloLens 回调

HoloLens Callbacks with Native Library

提问人:alexfeh 提问时间:1/25/2017 最后编辑:JoshDMalexfeh 更新时间:8/23/2019 访问量:675

问:

的目标是我的 UWP DLL 调用在 Unity 代码中实现的方法。(因此我可以在我的 HoloLens 项目中使用它们)

我尝试过一个更大的项目,但失败了。因此,我写了一个简单的例子,以便更容易找到错误并排除其他影响。 但是,我仍然收到同样的错误。

我的工作环境:

  • 操作系统为 Windows 10 的 64 位计算机
  • Micsrosoft Visual Studio 社区 2015年版本14.0.25431.01 Update 3
  • HoloLens 模拟器 10.0.14393.0
  • Unity 5.5.0f3 个人版(64 位)

创建 UWP DLL:

为了解决这个问题,我在Visual Studio 2015中创建了一个C++ DLL(Windows Universal),如下所示:

新项目 > Visual C++ > Windows > Universal > DLL(通用 Windows)

自动生成项目后,我添加了代码。 因此,代码如下所示:

本机库代码:

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 正在准备委托:

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);
}

我没有对自动生成的文件 dllmain.cpp、pch.cpp、pch.h 或 targetver.h 进行任何更改。

最后,我为“发布”模式和架构“x86”构建项目以生成DLL文件。 DLL 文件的位置现在是:项目根文件夹/发布/简单项目/简单项目DLL.dll

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

下一步,我创建了一个新的 Unity 项目,添加了 HoloLens-Toolkit,并确保新项目在模拟器上运行良好。

Unity项目代码:

之后,我在资产文件夹中添加了 SimpleProjectDLL.dll 并实现了以下代码:

首先,我们需要在委托之间建立连接。 Cpp.cs 预装代表:

Cpp.cs

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

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

SimpleInterfaceCpp.cs 初始化连接:

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
    );
}

主要:

MainController.cs

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

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

SimpleInterface.cs 正在调用以下方法:

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);
    }
}

现在,如果我创建一个 SLN,请在 Visual Studio 中打开项目,并使用“HoloLens 仿真器”启动它,我会得到以下输出:

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).

之后,应用程序将关闭。

所以我的问题是,有谁知道问题可能是什么?

这是在 HoloLens 项目中使用回调的正确方法吗?

或者有人知道如何找到代码“-1073740791 (0xc0000409)”的错误描述?


其他信息:我也在真正的 HoloLens 设备上尝试过,同样的问题,所以问题不在于模拟器。

unity-game-engine UWP 回调 HoloLens

评论

1赞 Scavenger 2/2/2017
你把DLL放在哪里了?DLL 应放置在 Assets\Plugins 中。有关详细信息,请参阅:docs.unity3d.com/Manual/Plugins.html
0赞 jvcleave 5/9/2017
我只需创建一个 Unity 项目、为 Hololens、D3D 构建、生成 C# 项目即可重现这一点。在 Visual Studio 中打开.sln,生成、运行、关闭应用窗口,我收到一个带有0xc0000409的未处理异常。
0赞 jvcleave 5/10/2017
补丁 5.6.0p1 为我修复了上述问题
1赞 RCYR 9/17/2018
看看这个问题,尤其是公认的答案:stackoverflow.com/questions/5235445/......属性 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 用于 C# 中的委托,因为 C 和 C# 在堆栈内存的处理方式上行为不同,即 cdecl 与 stdcall。
0赞 ickydime 3/28/2019
此链接有一个使用 RCYR 建议的此解决方案的示例 gamedev.net/articles/programming/...

答:

0赞 Tania Chistyakova 4/25/2019 #1

错误STATUS_STACK_BUFFER_OVERRUN。调用销毁了调用堆栈。

在 SimpleProjectDLL.cpp 和 SimpleProjectDLL.h 中有不同的回调声明。Cpp文件使用“CPP”呼叫对话,标头使用“C”呼叫会话。

您应该通过删除来更改 SimpleProjectDLL.cpp

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

并添加

#include "SimpleProjectDLL.h"