【问题标题】:Synchronising C++ (.dll) with a C# Unity script将 C++ (.dll) 与 C# Unity 脚本同步
【发布时间】:2016-11-14 08:29:15
【问题描述】:

我正在尝试将本机代码(c++ 项目)作为 .dll 与 C# 统一脚本同步。 本机代码:

音频.h:

#pragma once
#include <iostream>
#define EXPORT __declspec(dllexport)

extern "C" {    
    EXPORT void initialize(std::string soundFilePaths[]);
    EXPORT void setSourcePosition(std::string soundFilePath, float x, float y, float z);
    EXPORT void play();
    EXPORT void stop();
    EXPORT void setListenerRotation(float x, float y, float z);
}

class Audio {

public:

    static Audio& instance() {  // Singleton
        static Audio INSTANCE;
        return INSTANCE;
    }

    void initialize(std::string soundFilePaths[]);
    void setSourcePosition(std::string soundFilePath, float x, float y, float z);
    void play();
    void stop();
    void setListenerRotation(float x, float y, float z);
    ~Audio();

private:    
    Audio();
};

音频.cpp:

#include "Audio.h"

extern "C" {    

    void initialize(std::string soundFilePaths[]) {
        Audio::instance().initialize(soundFilePaths); 
    }

    void setSourcePosition(std::string soundFilePath, float x, float y, float z) {
        Audio::instance().setSourcePosition(soundFilePath, x, y, z);
    }

    void play() {
        Audio::instance().play();
    }

    void stop() {
        Audio::instance().stop();
    }

    void setListenerRotation(float x, float y, float z) {
        Audio::instance().setListenerRotation(x, y, z);
    }
}

Audio::Audio()
{
}

Audio::~Audio()
{
}

void Audio::initialize(std::string soundFilePaths[])
{   
}

void Audio::setSourcePosition(std::string soundFilePath, float x, float y, float z)
{

}

void Audio::play()
{
}

void Audio::stop()
{
}

void Audio::setListenerRotation(float x, float y, float z)
{
}

Unity C# 脚本如下:

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

public class AudioPlugin : MonoBehaviour
{
    public AudioContainer[] audioContainers;
    //public AudioClip[] audioFiles;
    //public Transform[] audioSources;
    public Transform headGeometry;
    public float rotationSpeed = 50;
    public float maxYRotation = 90;
    public float minYRotation = -90;
    float _currentYRotation;

    void Start()
    {
        _currentYRotation = headGeometry.transform.rotation.eulerAngles.y;
        string[] filePaths = GetAllFilePathsFromClips();
        AudioPluginConnection.Initialize(filePaths);
        AudioPluginConnection.Play();
    }

    void Update()
    {
        TurnHeadWithInput();
        UpdateListenerRotation();
        UpdateSoundPositions();
    }

    void OnDestroy()
    {
        AudioPluginConnection.Stop();
    }

    void TurnHeadWithInput()
    {
        float horizontal = Input.GetAxis("Horizontal");
        horizontal *= Time.deltaTime * rotationSpeed;
        _currentYRotation = Mathf.Clamp(_currentYRotation + horizontal, minYRotation, maxYRotation);
        Vector3 eulerAngles = headGeometry.rotation.eulerAngles;
        eulerAngles.y = _currentYRotation;
        headGeometry.rotation = Quaternion.Euler(eulerAngles);
    }

    void UpdateListenerRotation()
    {
        Vector3 eulerAngles = headGeometry.rotation.eulerAngles;
        AudioPluginConnection.SetListenerRotation(eulerAngles.x, eulerAngles.y, eulerAngles.y);
    }

    void UpdateSoundPositions()
    {
        foreach (AudioContainer container in audioContainers)
        {
            Vector3 position = container.source.position;
            AudioPluginConnection.SetSourcePosition(container.filePath, position.x, position.y, position.z);
        }
    }

    string[] GetAllFilePathsFromClips()
    {
        List<string> audioFilePaths = new List<string>();
        foreach (AudioContainer container in audioContainers)
        {
            audioFilePaths.Add(container.filePath);
        }
        return audioFilePaths.ToArray();
    }
}

[System.Serializable]
public class AudioContainer
{
    public AudioClip clip;
    public Transform source;
    public string filePath { get { return Application.dataPath + "/Audio/" + clip.name + ".wav"; } }
}

public class AudioPluginConnection
{
    [DllImport("AudioPlugin", EntryPoint = "test")]
    public static extern int Test();
    [DllImport("AudioPlugin", EntryPoint = "initialize")]
    public static extern void Initialize(string[] soundFilePaths);
    [DllImport("AudioPlugin", EntryPoint = "setSourcePosition")]
    public static extern void SetSourcePosition(string soundFilePath, float x, float y, float z);
    [DllImport("AudioPlugin", EntryPoint = "play")]
    public static extern void Play();
    [DllImport("AudioPlugin", EntryPoint = "stop")]
    public static extern void Stop();
    [DllImport("AudioPlugin", EntryPoint = "setListenerRotation")]
    public static extern void SetListenerRotation(float x, float y, float z);
}

每次我尝试运行 unity 场景时,Unity 程序都会崩溃。我认为问题出在本机代码中,因为我真的不知道如何将类和方法导出到 .dll。 我的假设是字符串(我已将其用作两种方法的参数)可能不起作用,因为当我使用字符串返回值创建测试方法时程序也崩溃了。但我不确定。

我想知道我的程序为什么会崩溃以及如何同步两个代码(c++ 和 c#)。

提前谢谢你

【问题讨论】:

标签: c# c++ unity3d dll


【解决方案1】:

在 C# C++ 互操作的同一主题上查看 my answer to this question。我描述了如何使用 MarshalAsAttribute 以及 System.String 和 std::string 中的一些差异。

我立即看到的一个问题是您编写了这样的 C++ 函数:

EXPORT void initialize(std::string soundFilePaths[]);

您的 C++ 函数应采用 const char* 类型的参数,而不是 std::string 对象。您还需要将 [MarshalAs(UnmanagedType.LPStr)] 添加到 extern C# 方法的字符串参数,以便互操作层知道如何处理对本机代码的封送处理。有很多不同的方法可以做到这一点,但这是我能想到的更简单、更直接的方法之一。

此外,只要您有选择,在您的 C++ 代码中使用 wchar_t* 和 wstring* 通常可以使事情变得更简单。 C++ 的 std::string 完全不同,它使用 8 位 ASCII 和 UTF-8 字符,而 C# 使用 16 位 Unicode 字符。在 C++ 中,wchar_t 是实现定义的 16 位字符类型。在 Windows 上,您基本上是在处理编码为 UTF-16LE 的 Unicode 字符(大部分时间),因此在本机端使用 wchar_t 和 wstring 可以在许多情况下使互操作情况变得更加简单(这可能会变得更加复杂比这个,相信我)。而采用 string[] 类型数组的 extern 方法根本不起作用。我的朋友,你将不得不完全重新考虑那个和你想要做的事情!

C/C++ 中的数组只是指向数据缓冲区的指针。 myArray[2] 就像获取基地址 int* ptr = &amp;myArray[0] 然后向该地址添加偏移量 0x02 以执行指针运算:int n = *(ptr + 2); 这是我很快找到的一些 basic info about pointer arithmetic and arrays。

因此,您在 C/C++ 代码中实质上处理的是指向指针缓冲区的指针,而不是托管的字符串数组。因此,您的 C++ 函数将采用 const char** str_array 参数。而且您必须将您的 string[] 数组正确地编组到它。这是一些关于 Marshaling Managed Arrays 与本机代码之间的 Microsoft 文档。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-14
    • 2018-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多