在C#AccesViolationException中调用Pocketsphinx

在C#AccesViolationException中调用Pocketsphinx,c#,c,pinvoke,pocketsphinx-android,C#,C,Pinvoke,Pocketsphinx Android,我试图使用pinvoke在C#中执行pocketsphinx,但当我尝试使用ps_decode#u raw()进行解码时,会出现AccessViolationException 函数包装如下 //ps_decoder_t* ps_init(cmd_ln_t* config) [DllImport("pocketsphinx.dll", SetLastError = true, CallingConvention = CallingConventio

我试图使用pinvoke在C#中执行pocketsphinx,但当我尝试使用ps_decode#u raw()进行解码时,会出现AccessViolationException

函数包装如下

    //ps_decoder_t* ps_init(cmd_ln_t* config)
    [DllImport("pocketsphinx.dll",
        SetLastError = true,
        CallingConvention = CallingConvention.Cdecl)]
    public extern static IntPtr ps_init(
        IntPtr config);

    //int ps_decode_raw(ps_decoder_t *ps, FILE *rawfh, char const *uttid, long maxsamps);
    [DllImport("pocketsphinx.dll",
        SetLastError = true,
        CallingConvention = CallingConvention.Cdecl)]
    public extern static int ps_decode_raw(
        IntPtr ps,
        IntPtr rawfh,
        [MarshalAs(UnmanagedType.LPStr)] string uttid,
        int maxsamps);

    [DllImport("msvcrt.dll",
        SetLastError = true,
        CallingConvention = CallingConvention.Cdecl)]
    public extern static IntPtr fopen(
        [MarshalAs(UnmanagedType.LPStr)] string _Filename,
        [MarshalAs(UnmanagedType.LPStr)] string _Mode);
我也包装了C的fopen,因为这是我能想到的实现教程的最快方法

我试着在ps上调用cmd_ln_retain以确保ps没有引起问题。(事实并非如此)。我还删除了上面的调试代码

我很确定fopen出了什么问题,但我不确定是什么问题


有人要了Pocketsphenx的日志

您不会在任何地方检查错误。对于这些函数,将
SetLastError
设置为true是错误的。他们不会调用
SetLastError

不过,最大的问题是库使用了一个特定的C运行时实例,这取决于构建它的方式。您的
fopen
导入来自C运行时的另一个实例


您需要向库中添加一些代码,以公开创建和销毁
文件*
对象的函数。通过这样做,您将得到一个由正确的运行时生成的
文件*

看到标准输出(日志)上的pocketsphinx输出添加到日志的链接会很有帮助。我将删除pInvoker添加的
SetLastError
。我不知道如何测试C运行时是否正确。DLL是system32文件夹中的DLL。我还包装了
fgets()
以检查它是否是
文件*
,它的工作让我更加不知所措。我将尝试包装
fseek()
,看看这是否会导致下一步出现任何问题。你只会让事情变得更糟。当然,当从系统msvcrt传递一个用
fopen
创建的
文件*
时,系统msvcrt的其他功能也可以正常工作。这证明不了什么。问题是您的
pocketsphinx.dll
没有使用系统msvcrt。它使用MSVC中的运行时来构建DLL。你为什么不照我说的做呢?我不得不用它来发现pocketsphinx是用MSVCR100D.DLL而不是msvcrt.DLL编译的,现在它可以工作了。还有比这更多的东西。无法重新分发调试运行时。所以,一旦你想重新发布它,你就需要切换到发布版本,然后你就会回到你现在的位置。解决这个问题的聪明方法正是我在最后一段中所说的。添加到pocketsphinx.dll中,以生成所需运行时函数的一些导出。
    //ps_decoder_t* ps_init(cmd_ln_t* config)
    [DllImport("pocketsphinx.dll",
        SetLastError = true,
        CallingConvention = CallingConvention.Cdecl)]
    public extern static IntPtr ps_init(
        IntPtr config);

    //int ps_decode_raw(ps_decoder_t *ps, FILE *rawfh, char const *uttid, long maxsamps);
    [DllImport("pocketsphinx.dll",
        SetLastError = true,
        CallingConvention = CallingConvention.Cdecl)]
    public extern static int ps_decode_raw(
        IntPtr ps,
        IntPtr rawfh,
        [MarshalAs(UnmanagedType.LPStr)] string uttid,
        int maxsamps);

    [DllImport("msvcrt.dll",
        SetLastError = true,
        CallingConvention = CallingConvention.Cdecl)]
    public extern static IntPtr fopen(
        [MarshalAs(UnmanagedType.LPStr)] string _Filename,
        [MarshalAs(UnmanagedType.LPStr)] string _Mode);