【发布时间】:2020-04-14 01:56:34
【问题描述】:
我正在尝试从我的 .Net Core 应用程序中调用 C 中的函数。 为了深入了解,C 函数来自 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);
但首先,它不再起作用,其次我怎么能从中得到结果?
那么我应该如何创建和调用函数以便创建渲染上下文?
MpvRenderParam声明如下:
[StructLayout(LayoutKind.Sequential)]
public struct MpvRenderParam
{
public MpvRenderParamType Type { get; }
public IntPtr Data { get; }
public MpvRenderParam(MpvRenderParamType type, IntPtr data)
{
Type = type;
Data = data;
}
}
还有MpvRenderParamType:
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
}
更新
我已经考虑了 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);
}
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;
}
遗憾的是,它仍然抛出同样的错误,我不确定我做错了什么,这真的很令人沮丧。
【问题讨论】:
-
第一个看起来不错,但是MpvRenderParam怎么声明呢?
-
MpvRenderParam 的声明一直都是一样的,像这样
new [] { new MpvRenderParam(MpvRenderParamType.ApiType, apiTypePtr), new MpvRenderParam(MpvRenderParamType.Invalid, IntPtr. },声明是MpvRenderParam[] parameters -
我的意思是如何声明 MpvRenderParam 类型
-
对不起,我已经添加了
MpvRenderParam和MpvRenderParamType的声明。 @jdweng 我试过了,似乎没有什么区别,因为编译器告诉我我应该把它改成 new[] -
不要在 p/invoke 结构中使用属性,而是使用字段(删除 {get;})
标签: c# pinvoke dllimport unmanaged mpv