HoloLens与本地库的回调函数

8
我的目标是从我的UWP DLL中调用在Unity代码中实现的方法(这样我就可以在我的HoloLens项目中使用它们)。我尝试过一个更大的项目,但失败了。因此,我写了一个简单的示例来更轻松地找到错误并排除其他影响。但是,我仍然得到相同的错误。
我的工作环境:
- 64位电脑,安装了Windows 10操作系统 - Microsoft Visual Studio Community 2015版本14.0.25431.01 Update 3 - HoloLens模拟器10.0.14393.0 - Unity 5.5.0f3 Personal(64位)
创建UWP DLL:
为了实现这一点,我在Visual Studio 2015中创建了一个C++ DLL(Windows Universal),具体步骤如下:
新建项目 > Visual C++ > Windows > Universal > DLL(Universal Windows)
项目自动生成后,我添加了我的代码。所以代码看起来像这样:
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正在准备委托:

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进行任何更改。

最后,我以“Release”模式和架构“x86”构建项目以生成DLL文件。 DLL文件的位置现在是:project-root-folder/Release/SimpleProject/SimpleProjectDLL.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设备上运行它,出现了同样的问题,因此问题不在模拟器上。


1
你把DLL放在哪里了?DLL应该放在Assets\Plugins中。更多信息请参见:https://docs.unity3d.com/Manual/Plugins.html。 - Scavenger
我可以通过创建一个Unity项目,为Hololens构建,使用D3D,生成C#项目来重现这个问题。在Visual Studio中打开.sln文件,构建并运行,关闭应用程序窗口后,我会收到一个0xc0000409的未处理异常。 - jvcleave
补丁5.6.0p1已经为我修复了上述问题。 - jvcleave
1
请看一下这个问题,特别是它的被接受的答案:https://dev59.com/7m435IYBdhLWcg3wvy2_。在C#中,使用属性[UnmanagedFunctionPointer(CallingConvention.Cdecl)]来定义委托,因为C和C#在处理栈内存时有不同的行为,即cdecl与stdcall。 - RCYR
这个链接有一个使用 RCYR 建议的示例解决方案: https://www.gamedev.net/articles/programming/general-and-gameplay-programming/c-plugin-debug-log-with-unity-r3349/ - ickydime
1个回答

0

出现了 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"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接