首页 文章

P / Invoke AccessViolationException

提问于
浏览
0

当我尝试将路径传递给文件名时,我有一个非托管函数调用抛出此异常 .

我已经读过这可能是由DLL本身引起的,但我不认为是这种情况,因为DLL在另一个应用程序中使用,所以问题很可能在我调用该函数的方法中 .

规格:

libvlc_media_new_path (libvlc_instance_t *p_instance, const char *path)

描述:

p_instance  the instance
path    local filesystem path

我的方法:

[DllImport("libvlc", EntryPoint = "libvlc_media_new_path")]
public static extern IntPtr NewMedia(IntPtr instance,
                            [MarshalAs(UnmanagedType.LPStr)] string path);

我想我错过了常规电话,但这可能是什么?或者是否会导致此异常?

编辑:基于一些评论,我做了一些探索,发现......好吧,没有 . 该实例的结构是不透明的,这意味着我不知道Laymans术语 . 我的猜测是,这意味着你不需要在使用它的应用程序中重建它?

在基于this的盲猜中,我用负责将* p_instance值设置为 long 而不是 IntPtr 的函数替换了我一直使用的返回值,因为当它是 IntPtr 时它返回0,并且有一个长的我看到了一个 Value . 再一次,我真的不知道 IntPtr . 我很高兴在实例变量中看到不是0的东西但是当我跑过它时,它再次出错了 .

编辑:我已将问题扩展到here .

2 回答

  • 0

    基于您所看到的异常以及您为本机函数提供的声明,

    libvlc_media_new_path (libvlc_instance_t *p_instance, const char *path)
    

    你的p / invoke声明不正确 . 你的调用约定不匹配 . .NET p / invoke系统的默认设置是stdcall(以匹配Windows API函数),但C和C代码的默认值是cdecl . 您必须明确告诉.NET您的函数使用cdecl调用约定 .

    所以改成它看起来像这样:

    [DllImport("libvlc", EntryPoint = "libvlc_media_new_path", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr NewMedia(IntPtr instance,
                                         [MarshalAs(UnmanagedType.LPStr)] string path);
    

    当然,我猜你的回归值是指针是正确的 . 您显示的本机函数声明缺少返回类型 .

    至于你关于 instance 参数的问题,以及你是否正确使用 IntPtr 类型:该参数是一个指向 libvlc_instance_t 的指针,因此你有两种基本方法可以使用p / invoke来完成这项工作 . 首先是将参数声明为 IntPtr ,它将其编组为原始指针值 . 这对于指针需要不透明(即从一个本机函数检索,存储,然后传递给另一个本机函数)的情况不是特别有用 . 其次是声明一个镜像本机结构的托管结构,然后编写p / invoke声明来使用这个结构,以便编组器自动处理事物 . 如果您确实需要与存储在指针指向的结构中的值进行交互,那么这将非常有用 .

    在这种情况下,在Google搜索之后,您似乎正在使用其中一个VLC API . 特别是this one . also tells us libvlc_instance_t 是什么:它是一个不透明的结构,代表一个libvlc实例 . 因此,声明托管结构不是一种选择,因为即使本机代码也将结构视为不透明 . 你真正需要的只是指针,来回传递;我上面谈到的第一种方法的完美案例 . 因此,上面显示的声明是您的赢家 .

    现在唯一的战斗是获取一个指向libvlc实例的有效指针,只要你调用它就可以传递给该函数 . 很有可能会事先调用像libvlc_new之类的函数,它被记录为创建和初始化新的libvlc实例 . 它的返回值正是您所需要的 . 因此,除非您已经创建了一个libvlc实例(在这种情况下,使用该指针),您还需要调用此函数并存储其结果 .

    如果the documentation对于 libvlc_new 函数的参数所需的值是正确的,您可以非常简单地声明它:

    [DllImport("libvlc", EntryPoint = "libvlc_new", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr NewCore(int argc, IntPtr argv);
    

    并称之为:

    IntPtr pLibVlc = NewCore(0, IntPtr.Zero);
    // now pLibVlc should be non-zero
    

    当然,我对VLC API一无所知,但是我对API设计的一般知识告诉我,一旦你完成它,你可能需要使用相同的指针来调用libvlc_release函数 .

  • 1

    尝试没有[MarshalAs(UnmanagedType.LPStr)],通常适合我 .

相关问题