javascript - Unity C#如何正确加载托管DLL?
问题描述
基于此处的其他问题Using OpenH264 DLL in C# Project我基本上是在尝试统一使用库https://github.com/secile/OpenH264Lib.NET来实时编码 H264 视频文件,使用统一的 JINT 本机用于 JavaScript interperting 的库
不过,我在统一引用 DLL 时遇到了很多困难。
我按照 GitHub 站点的说明,设法编译为 OPenH264Lib.dll(以及示例项目,并让示例项目与 Visual Studio 2019 一起工作,在 Windows x64 上很好,它对所有内容进行编码等),但是当我只是将编译后的文件拖到OpenH264Lib.dll
Unity 项目的 Assets 文件夹中的 Plugins 文件夹中,我无法访问命名空间OpenH264Lib
,该命名空间在标准 C# 示例中用于访问 DLL 托管函数,它只是在统一控制台中说未找到命名空间。
好的,所以我决定用 Visual Studio 构建一个 C# DLL,它本身在 OpenH264Lib.dll 中加载,然后从那里调用它的函数,然后统一使用 C# DLL,所以这是我在 visuaal Studio 中的 C# 代码(在放在 Debug 文件夹中编译(使用 .NET 版本 4.6.1)OpenH264Lib.dll,就像在示例中一样,我在 Visual Studio 2019 中没有收到任何参考错误):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sayfir
{
public class Class1
{
public static OpenH264Lib.Encoder ok(string path)
{
var code = new OpenH264Lib.Encoder(path);
return code;
}
}
}
好的,所以它可以完美地构建,没有错误,并且它似乎与示例文件夹(在 Assets/Plugins 中)一样。
然后,当我获取在我的解决方案的 x64/Debug 文件夹中生成的 DLL 文件(OpenH264Lib.dll 和 Sayfir.dll)并将它们复制到 Unity 中的 Plugins 文件夹时,然后尝试像这样统一访问它
public class Yetzirah {
public static void Wellz() {
var k = Sayfir.Class1.ok("2");
Debug.Log(k);
}
}
我在 Unity 控制台中遇到错误
Assets\scripts\Yetzirah.cs(45,12): error CS0012: The type 'Encoder' is defined in an assembly that is not referenced. You must add a reference to assembly 'OpenH264Lib, Version=1.0.7598.38705, Culture=neutral, PublicKeyToken=null'.
所以它似乎识别出从上面的源代码编译的 Sayfir.dll 文件,但不是它所依赖的 OpenH264Lib.dll,即使两者都在同一个文件夹中(在 Assets/Plugins 中)
我听说过 .rsp 文件,但我尝试使用名称制作一个并将其csc.rsp
添加到带有内容的资产中
-r:OpenH264Lib
依然没有
我也听说过.asmdef 文件,但是当我用内容制作了一个文件时
{
"references": "OpenH264Lib"
}
但仍然一无所获,我对 asmdef 文件知之甚少,我也不太了解这个错误,或者总体上如何统一使用托管 C++ DLL。
我还看到一篇文章提到统一引用外部 DLL 文件,但它说去
Project > Edit References > .NET Assembly
问题是,我不知道如何在 UnityEditor 2020 中到达该屏幕,或者是否有办法到达那里或完成相同的事情,如果是这样,我不知道如何也无法找到它搜索
我尝试使用标准 dllexports 制作另一个 DLL,头文件内容为
extern "C" __declspec(dllexport) int well();
然后在 .cpp 文件中
#include "deeall.h"
__declspec(dllexport) int well() {
return 634;
}
然后在统一 C#
DllImport("deeall.dll", EntryPoint="well")]
public static extern int well();
然后它可以工作,但是当我在 dll extern int 中包含任何类型的托管库时,我得到一个错误__declspec(dllexport) cannot be applied to a function with the __clrcall calling convention.
如果我想为 C# 包装器使用 __declspec 导出,这是必要的
作为 hack,我尝试将以下内容添加到 Encoder.cpp 文件本身(来自 OpenH264Lib .dll 的源代码)
__declspec(dllexport) int well() {
String ^h = "ok";
Encoder
^enc =
gcnew Encoder(
h
);
return 4;
}
尝试直接调用 Encoder 函数,(以及对 Encoder.h 的以下头文件修改:
namespace OpenH264Lib {
extern "C" __declspec(dllexport) int well();
//etc.. rest of code in namespace.....
) 然后统一
[DllImport("OpenH264Lib6.dll", EntryPoint="well")]
public static extern int well();
但是当我打电话时well()
,统一挂了一段时间然后崩溃了,没有任何错误
那么如何让 OpenH264Lib.dll 统一工作,或其他类似的托管编译 C++ DLL 统一工作?如果这是不可能的,有没有其他方法可以在 Unity 中使用 OpenH264?如果没有,还有其他解决方案可以统一实时编码 H264 视频(来自 byte[]s)吗?
解决方案
这是从内存中编写的,未经测试,但我认为它会起作用。
- 确保正确加载 OpenH264Lib.dll,否则手动加载,例如在 Wrapper 中使用 Assembly.Load/Assembly.LoadFrom
- 确保 openh264-1.7.0-win32.dll 位于可执行文件旁边或指定完整路径
- 确保不要混合使用 32Bit 和 64Bit
- 像您一样构建您的 Sayfir 包装程序集,但不要公开 Encoder 类本身,而是包装您要使用的方法。这样 Unity 就不需要知道任何关于 OpenH264Lib.dll 的信息
例如
public class Wrapper
{
private Encoder _encoder;
public Wrapper()
{
// Be sure the openh264-1.7.0-win32.dll can be found!
// Native dlls should be located next to the actual executable if you call it without a full path!
_encoder = new OpenH264Lib.Encoder("openh264-1.7.0-win32.dll");
}
public void Setup(/* ... */)
{
//_encoder.Setup(...)
}
}
如果它仍然不起作用,请在尝试加载 OpenH264Lib.dll 之前尝试使用此方法重定向 DLL 查找路径。在编码器类的源代码中,我们看到对 LoadLibrary 的调用,然后它将使用您在此处提供的路径来搜索 DLL。null
加载后通过使用as 参数再次调用函数来恢复正常的搜索顺序。
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetDllDirectory(string lpPathName);
推荐阅读
- spring - Spring框架导入失败
- google-cloud-firestore - 错误:(gcloud.firestore.operations.delete)HTTPError 404
- python - 通过 Anaconda 安装时在 PyCharm 中引用库
- python - 将数据附加到 Pandas 全局数据框变量不会持续存在
- assembly - 从 16 位实模式 (x86) 切换到 32 位保护模式
- c++ - C++ 文件编译:-L 和 -I 参数不适用于 boost 库
- android - 如何使 (NotificationCompat.Builder) 在 API 级别 28 上工作?
- html - 如何将css添加到没有id或class的输入字段?
- django - 在 django 2.2 的 admin.py 中注册抽象类的派生子类
- android - 使用 aws cloudfront 滑动,抛出 403 错误,但是当我使用 okhttp 发出请求时,我得到了正确的响应