调用非托管函数,该函数采用指向指针参数的指针

2024-02-27

我正在尝试从我的 .Net Core 应用程序调用 C 中的函数。 深入了解一下,C 函数来自libmpv 渲染.h https://github.com/mpv-player/mpv/blob/master/libmpv/render.h函数的头部如下所示:

int mpv_render_context_create(mpv_render_context **res, mpv_handle *mpv, mpv_render_param *params);

问题是我不知道如何从 C# 调用该函数。所以我尝试了以下方法:

[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int mpv_render_context_create([Out] out IntPtr renderContext, IntPtr mpvHandle,
        MpvRenderParam[] parameters);

自从**res参数应该由函数更新我认为这是有意义的。我尝试使用以下内容进行调用:

var ptr = IntPtr.Zero;
var apiTypePtr = Marshal.StringToHGlobalAuto("opengl");
var i = mpv_render_context_create(out ptr, _mpvHandle, new []
{
    new MpvRenderParam(MpvRenderParamType.ApiType, apiTypePtr),
    new MpvRenderParam(MpvRenderParamType.Invalid, IntPtr.Zero
});

这给我带来了一个 AccessViolationException,事实上每次我调用mpv_render_context_create方法我得到了相同的异常,所以当我说“它不起作用”时,我的意思是调用抛出了该异常。

所以我想也许我必须将其设为 ref 参数:

[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int mpv_render_context_create(ref IntPtr renderContext, IntPtr mpvHandle,
        MpvRenderParam[] parameters);

这在调用它时导致了同样的错误。

然后我在另一个 stackoverflow 问题中读到,我应该传递裸 IntPtr,如下所示:

[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int mpv_render_context_create(IntPtr renderContext, IntPtr mpvHandle,
        MpvRenderParam[] parameters);

但首先,它又不起作用了,其次我怎么能从中得到结果呢?

那么我应该如何创建和调用该函数以便创建渲染上下文?

The Mpv渲染参数声明如下:

[StructLayout(LayoutKind.Sequential)]
public struct MpvRenderParam
{
    public MpvRenderParamType Type { get; }
    public IntPtr Data { get; }

    public MpvRenderParam(MpvRenderParamType type, IntPtr data)
    {
        Type = type;
        Data = data;
    }
}

And The Mpv渲染参数类型:

public enum MpvRenderParamType
{
    Invalid = 0,
    ApiType = 1,
    InitParams = 2,
    Fbo = 3,
    FlipY = 4,
    Depth = 5,
    IccProfile = 6,
    AmbientLight = 7,
    X11Display = 8,
    WlDisplay = 9,
    AdvancedControl = 10,
    NextFrameInfo = 11,
    BlockForTargetTime = 12,
    SkipRendering = 13,
    DrmDisplay = 14,
    DrmDrawSurfaceSize = 15,
    DrmDisplayV2 = 15
}

Update

我已经考虑了 Mattias Santoro 提供的所有资源,但我只是不完全确定如何将它们翻译成 C#,因为它是一种托管语言。我调用 mpv 函数的方法现在如下所示:

OpenGlControl.OpenGL.MakeCurrent();
IntPtr ptr;
var apiTypePtr = Marshal.StringToHGlobalAuto("opengl");
var opengl = new MpvOpenGlInitParams {get_proc_address = getProcAdress};
var size = Marshal.SizeOf(opengl);
var arr = new byte[size];

fixed (byte* arrPtr = arr)
{
    Marshal.StructureToPtr(opengl, (IntPtr)arrPtr, true);
    var parameters = new MpvRenderParam[]
    {
        new MpvRenderParam {Type = MpvRenderParamType.ApiType, Data = &apiTypePtr},
        new MpvRenderParam {Type = MpvRenderParamType.OpenGlInitParams, Data = &arrPtr},
        new MpvRenderParam {Type = MpvRenderParamType.Invalid, Data = null}
    };
    var i = mpv_render_context_create(&ptr, _mpvHandle, parameters);
}

The MpvOpenGlInitParams:

[StructLayout(LayoutKind.Sequential)]
public struct MpvOpenGlInitParams
{
    public delegate IntPtr GetProcAdressDelegate(IntPtr ctx, string name);

    public GetProcAdressDelegate get_proc_address;
    public IntPtr get_proc_address_ctx;
    public string extra_exts;
}

可悲的是它仍然抛出同样的错误,我不确定我做错了什么,这真的很令人沮丧。


我已将我的代码放入此存储库中:(适用于 .net core 2.1 和 sdl2 以及适用于 X64 的 mpv dll)https://github.com/shodo/MPVCore.git https://github.com/shodo/MPVCore.git

更新2:DOOOONEEEEE! 首先,这是我的(真的很难看)代码。我不知道我所做的每件事是否都需要:

函数定义为:

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 private delegate int MpvRenderContextCreate(ref IntPtr context, IntPtr mpvHandler, IntPtr parameters);
 private MpvRenderContextCreate _mpvRenderContextCreate;

和代码(它是 c++ sdl 示例的硬编码 Frankestein 以及 winform 和其他内容的一部分)

if (_mpvHandle != IntPtr.Zero)
            _mpvTerminateDestroy(_mpvHandle);

        LoadMpvDynamic();
        if (_libMpvDll == IntPtr.Zero)
            return;

        _mpvHandle = _mpvCreate.Invoke();
        if (_mpvHandle == IntPtr.Zero)
            return;

        _mpvInitialize.Invoke(_mpvHandle);



        MpvOpenGlInitParams oglInitParams = new MpvOpenGlInitParams();
        oglInitParams.get_proc_address = (ctx, name) => SDL.SDL_GL_GetProcAddress(name);
        oglInitParams.get_proc_address_ctx = IntPtr.Zero;
        oglInitParams.extra_exts = IntPtr.Zero;

        var size = Marshal.SizeOf<MpvOpenGlInitParams>();
        var oglInitParamsBuf = new byte[size];

        fixed (byte* arrPtr = oglInitParamsBuf)
        {
            IntPtr oglInitParamsPtr = new IntPtr(arrPtr);
            Marshal.StructureToPtr(oglInitParams, oglInitParamsPtr, true);

            MpvRenderParam* parameters = stackalloc MpvRenderParam[3];

            parameters[0].type = MpvRenderParamType.ApiType;
            parameters[0].data = Marshal.StringToHGlobalAnsi("opengl");

            parameters[1].type = MpvRenderParamType.InitParams;
            parameters[1].data = oglInitParamsPtr;

            parameters[2].type = MpvRenderParamType.Invalid;
            parameters[2].data = IntPtr.Zero;

            var renderParamSize = Marshal.SizeOf<MpvRenderParam>();

            var paramBuf = new byte[renderParamSize * 3];
            fixed (byte* paramBufPtr = paramBuf)
            {
                IntPtr param1Ptr = new IntPtr(paramBufPtr);
                Marshal.StructureToPtr(parameters[0], param1Ptr, true);

                IntPtr param2Ptr = new IntPtr(paramBufPtr + renderParamSize);
                Marshal.StructureToPtr(parameters[1], param2Ptr, true);

                IntPtr param3Ptr = new IntPtr(paramBufPtr + renderParamSize + renderParamSize);
                Marshal.StructureToPtr(parameters[2], param3Ptr, true);


                IntPtr context = new IntPtr(0);
                _mpvRenderContextCreate(ref context, _mpvHandle, param1Ptr);
            }
        }

该函数起作用的原因是:

parameters[0].data = Marshal.StringToHGlobalAnsi("opengl");

而不是使用

parameters[0].data = Marshal.StringToHGlobalAuto("opengl");

我认为这不仅仅是识别使用 opengl 渲染上下文初始化 mpv 播放器所需的“opengl”参数

更新: 为了调用该函数,您需要一个初始化的 opengl 上下文,或者,您应该传递 MPV_RENDER_PARAM_OPENGL_INIT_PARAMS 类型的参数以及访问 open gl 函数所需的回调。 检查这个 C++ 示例,它使用 SDL 来初始化窗口并获取 opengl 上下文。

https://github.com/mpv-player/mpv-examples/blob/master/libmpv/sdl/main.c https://github.com/mpv-player/mpv-examples/blob/master/libmpv/sdl/main.c

如果没有正确初始化的 OpenGl 上下文,您总是会收到有关正确 c# 封送处理的 ViolationException 错误:github.com/mpv-player/mpv/issues/6249 http://github.com/mpv-player/mpv/issues/6249
https://github.com/mpv-player/mpv/issues/6507 https://github.com/mpv-player/mpv/issues/6507

- 老的: 看看这个:https://stackoverflow.com/questions/20419415/c-sharp-call-c-dll-passing-pointer-to-pointer-argument https://github.com/mpv-player/mpv/issues/6507

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

调用非托管函数,该函数采用指向指针参数的指针 的相关文章

  • 检查空参数的最佳方法(保护子句)

    例如 您通常不希望构造函数中的参数为空 因此看到类似的内容是很正常的 if someArg null throw new ArgumentNullException nameof someArg if otherArg null throw
  • 更快的算法来计算有多少数字可以被范围内的特定整数整除

    int a b c d 0 cin gt gt a gt gt b gt gt c for int i a i lt b i if i c 0 d cout lt
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工
  • C# 中的协变和逆变

    首先我要说的是 我是一名正在学习 C 编程的 Java 开发人员 因此 我会将我所知道的与我正在学习的进行比较 我已经使用 C 泛型几个小时了 我已经能够在 C 中重现我在 Java 中知道的相同内容 除了几个使用协变和逆变的示例 我正在读
  • Android NDK C++“wstring”支持

    我有用 C 编写的源代码 lib 现在我想在 Android NDK 项目 NDK 6 中编译并使用相同的源代码 lib 我能够编译大多数 C 文件 除了基于 std wstring 的功能 在 Application mk 中 当我指定时
  • 通过单个 GPIO 引脚转储闪存

    我正在使用 Infineon 的 XMC4500 Relax Kit 并尝试通过单个 GPIO 引脚提取固件 我非常天真的想法是通过 GPIO 引脚一次转储一位 然后用逻辑分析仪以某种方式 嗅探 数据 伪代码 while word by w
  • 特定设备的不同字体大小

    我目前正在开发通用应用程序 我需要分别处理移动设备和桌面的文本框字体大小 我找到了一些方法 但都不能解决问题 使用 VisualStateManager 和 StateTrigger 为例
  • 如何使用泛型类型的 DataContractSerializer 编写自定义序列化器?

    我想编写一个自定义序列化器 用于将会话状态存储到Azure 缓存 预览版 这意味着这个自定义序列化器必须实现IDataCacheObjectSerializer 如果我错了 请告诉我 我需要编写这个自定义序列化程序的原因是我需要序列化一些包
  • 如何不在类中实现接口的功能?

    面试时面试官问了我以下问题 但我不知道这个问题的答案是什么 请帮忙 如果我不想 我必须做什么 在我的类中实现一个函数 在接口中声明为 由我班实施 Edited 我正在使用 NET 和 C 如果有人可以提供 C 示例代码示例 那就太好了 Th
  • 如何将字符串转换为 Indian Money 格式?

    我正在尝试将字符串转换为印度货币格式 例如如果输入为 1234567 则输出应为 12 34 567 我编写了以下代码 但它没有给出预期的输出 CultureInfo hindi new CultureInfo hi IN string t
  • `cosf`、`sinf` 等不在 `std` 中 [重复]

    这个问题在这里已经有答案了 根据这里的讨论 我有报告了一个错误 https bugs launchpad net ubuntu source gcc 8 bug 1831385给 Ubuntu 开发者 编译以下示例 C 程序时 includ
  • realloc():重新分配为 char * 上的 strcat 腾出空间时下一个大小无效 [重复]

    这个问题在这里已经有答案了 我在以下代码中收到无效内存错误 printf s n FINE 5 printf s LENGTH IS d n FINE 6 strlen buffer char realloc buffer strlen b
  • 理解 C++11 中的 std::atomic::compare_exchange_weak()

    bool compare exchange weak T expected T val compare exchange weak 是 C 11 中提供的比较交换原语之一 它是weak即使对象的值等于 它也会返回 falseexpected
  • 将 bignum 类型结构转换为人类可读字符串的有效方法是什么?

    我有一点问题 为了增长我的 C 知识 我决定尝试实现一个基本的 bigint 库 bigint 结构的核心将是一个 32 位整数数组 选择它们是因为它们适合寄存器 这将允许我在数字之间进行操作 这些操作将在 64 位整数中溢出 这也将适合寄
  • 展开路径中具有环境变量的文件名

    最好的扩张方式是什么 MyPath filename txt to home user filename txt or MyPath filename txt to c Documents and settings user filenam
  • 微软语音识别速度

    我正在使用微软的语音识别器开发一个小型练习应用程序 对于我正在做的事情来说 我似乎无法让它足够快地识别单个单词 我希望能够正常说话 系统将从我所说的内容中抓取 关键字 并生成一个字符串 目前我正在使用 5 个单词的自定义语法 红 蓝 黄 绿
  • 将一个 long 转换为两个 int 以进行重构

    我需要将一个参数作为两个 int 参数传递给 Telerik Report 因为它不能接受长参数 将 long 拆分为两个 int 并在不丢失数据的情况下重建它的最简单方法是什么 使用掩蔽和移位是最好的选择 根据文档 long 保证为 64
  • 如何强制执行特定的 UserControl 设计

    我正在编写一个基本用户控件 它将由一堆其他用户控件继承 我需要对所有这些后代控件强制执行某种设计 例如 顶部必须有几个按钮以及一个或两个标签 后代用户控件区域的其余部分可以自由放置任何内容 最初 我认为我可以将一个面板放到 Base Use
  • 将文本从文本文件添加到 PDF 文件[重复]

    这个问题在这里已经有答案了 这是我的代码 using FileStream msReport new FileStream pdfPath FileMode Create step 1 using Document pdfDoc new D
  • 如何从函数返回矩阵(二维数组)? (C)

    我创建了一个生成宾果板的函数 我想返回宾果板 正如我没想到的那样 它不起作用 这是函数 int generateBoard int board N M i j fillNum Boolean exists True initilize se

随机推荐

  • Angualr2 错误:无法设置仅具有 getter 的 # 的属性值

    表格看起来像
  • IntelliJ + JUnit 5(木星)

    My build gradle has testCompile org junit jupiter junit jupiter api 5 0 0 使用标准示例http junit org junit5 docs current user
  • XmlSerializer 和 IEnumerable:可以进行序列化,无需无参数构造函数:Bug?

    在我们的项目中 我们广泛使用 XmlSerializer 偶然我发现了一个没有无参数构造函数的类 我认为这一定会破坏序列化过程 但事实并非如此 通过调查这个问题 我发现 XmlSerializer 在序列化 反序列化时表现得很奇怪IE可枚举
  • 在 git 中为每个部署构建创建一个标签是一个好习惯吗?

    我刚刚从 Subversion 切换到 Git Subversion 的集中式架构为其提供了一个有意义的修订号 我将其构建到基于 Web 的应用程序的更改日志中 以便轻松登录并查看任何给定服务器上正在运行的版本 Git 没有友好的内部版本号
  • 如何使用 REST API 为领事附加手表?

    我使用 REST API 来访问领事 例如 这是我创建条目的方法 curl X PUT d localhost 8500 v1 kv example lt lt lt FooValue 我想添加watches当键值更改时通知我的服务的领事
  • 将函数发布到门户后,Azure 函数在函数列表中不可见

    我是Azure函数的新手 在函数发布到门户后发现这里 但它在函数列表中不可见 我附上了示例代码的快照和一个空的天蓝色列表 请帮忙 添加kudu ui 这里我找到了 wwwroot下唯一的host json Hi All 添加了kudu ui
  • 如何定义 Airflow 上 STFP Operator 的操作?

    class SFTPOperation object PUT put GET get operation SFTPOperation GET NameError name SFTPOperation is not defined 我在这里定
  • 维吉尼亚密码解密

    我正在尝试使用维吉尼亚密码进行加密和解密 这是一项更大任务的一部分 而维吉尼亚密码只扮演了一小部分 我从 bash 得到了这个加密脚本 可以正常工作 问题是我如何反向使用相同的代码来解密代码 usr local bin bash vigen
  • Java / Android 编程 - 循环失败

    我正在使用带有计时器的 while 循环 问题是计时器并不是在每个循环中都使用 仅在第一次使用 第一次之后 循环内包含的语句将在没有我设置的延迟的情况下执行 既然计时器包含在 while 循环内 这怎么可能呢 有什么解决办法吗 int co
  • 如何在 HTML 中将文本和图像并排放置?

    我希望文本和图像彼此相邻 但我希望图像位于屏幕的最左侧 而我希望文本位于屏幕的最右侧 这就是我目前所拥有的 img src website art png height 75 width 235 h3 font face Verdana T
  • 如何确定 Django 模型中的类实例是否是另一个模型的子类?

    我有一堂课叫BankAccount作为基类 我也有CheckingAccount and SavingsAccount继承自的类BankAccount BankAccount 不是一个抽象类 但我不从中创建对象 只创建继承类 然后 我执行如
  • 我不知道为什么这个画布是空的

    因此 我一直在研究如何用其他图像填充画布的几个示例 一旦我稍微重新排列代码 它们就会停止工作 我注意到画布上的一些行为与其他类型的 JavaScript 变量相比没有意义 我想知道发生了什么 例如 如果我做这样的事情
  • 在python中读取标头之间的文件

    我有一个大文本文件 其中的值由以 开头的标题分隔 如果条件与标头中的条件匹配 我想读取文件直到下一个标头 并跳过文件的其余部分 为了测试我正在尝试读取以下名为 test234 txt 的文本文件 abcdefgh 1fnrnf mrkfr
  • 我可以在 Play Framework 上的模板/视图中调用会话吗

    我是 Play Framework 2 0 的新手 我使用的是 Scala 并且有一个关于会话的问题 我有 Ruby on Rails 背景 因此我倾向于将在 Play Framework 中学到的所有内容都与 Ruby on Rails
  • 新的 Facebook API 3.0。和 ActionBarSherlock 兼容性

    我正在阅读 facebook Android API 3 0 文档 我不明白会话与后台活动有什么关系 在所有示例中 我都应该扩展 FacebookFragment 好吧 如果我的整个应用程序不扩展 SherlockFragment 那就太好
  • 将模块内的所有函数和类导入到 python 类中

    我正在尝试将子文件夹中的所有对象导入到 python 3 8 中的类中 并且正在努力寻找一种方法来执行此操作 我不想手动导入所有对象 因为要列出的文件太多 class Foo from bar import one two three 当我
  • Once_flag 可以移动吗?

    这是怎么回事 标准没有提到once flag的可移动性 我希望应用与 std mutex 相同的参数 至少对于 gcc 4 8 版 来说 移动似乎被禁用了 如果某个编译器允许移动 那么最终可能会得到不可移植的代码 概要是 30 4 thre
  • ASP.NET MVC 3 Razor 性能

    重要更新 请参阅底部的更新 5 asp net mvc 3 中没有性能问题 这是基准问题 我在 asp net mvc2 3 aspx 和 3 razor 中制作了一个简单的 hello world 项目并对它们进行了基准测试 我看到的是
  • 如何在 Windows 上安装 OpenJPEG 并将其与 Pillow 一起使用?

    我想使用Python Pillow库将16位灰度数组保存在jp2 JPEG 2000 格式 我在尝试在 Windows 计算机上安装所需的 OpenJPEG 库时遇到了困难 这文档 https github com uclouvain op
  • 调用非托管函数,该函数采用指向指针参数的指针

    我正在尝试从我的 Net Core 应用程序调用 C 中的函数 深入了解一下 C 函数来自libmpv 渲染 h https github com mpv player mpv blob master libmpv render h函数的头