使用非托管DLL访问冲突

时间:2010-09-01 22:57:00

标签: c# timer pinvoke unmanaged access-violation

目前,我们使用来自供应商的非托管DLL,允许我们访问特定的工具。感兴趣的特定功能在头文件中指定为:

extern "C" short CCONV acq_get_board_count ();

在我的申请中,我有pinvoke声明:

public class bograms
{
    [DllImport("bograms.dll", EntryPoint = "acq_get_board_count", CallingConvention = CallingConvention.StdCall)]
    public static extern short acq_get_board_count();
}

现在,在我的代码中,我试图处理冗余,所以我创建了一个试图让事情继续运行的计时器:

public class Instrument
{
    private System.Threading.Timer keepAliveTimer;
    public Instrument()
    {
        keepAliveTimer = new Timer(new TimerCallback(this.KeepAlive), null, 0, 300000);
    }

    void KeepAlive(object state)
    {
        if(instrumentIsUninitialized) // some check that accomplishes this
        {
            Console.WriteLine("Some status statements"); // in console
            short numBoards = bograms.acq_get_board_count();
            Console.WriteLine("Initialization caught {0} boards.", numBoards); // not in console
        }
    }
}

计时器的第一个滴答,它得到零板(可能是因为硬件没有完成初始化),并将两个消息都打印到控制台。但是,第二个滴答,我在bograms.dll中得到APPCRASH错误0xc0000005,我发现这是一个访问冲突错误。在调用周围放置try / catch不会发现错误。第一行是在控制台中,第二行不是。在调试转储文件时(尽我所知),这次调用似乎发生了错误。

我的pinvoke声明错了吗?它是如此简单的功能,我无法相信它,但我错过了什么?由于计时器导致某些类型的问题导致线程化吗?

我猜测第一次调用会将其置于某种类型的状态,导致第二次调用失败,尤其是在考虑幕后硬件初始化时。如果是这种情况,有没有办法卸载驱动程序DLL,以便它可以重置回它应该在的初始状态?

或者你还能想到其他什么吗?

1 个答案:

答案 0 :(得分:2)

立即想到的一件事是API是否可以跨线程安全使用。 System.Threading.Timer回调来自ThreadPool线程,因此每次都可能不同。某些API具有线程关联性要求,这意味着它们只能从单个线程调用。代替这一点,如果同时发生对同一API的两次调用,仍可能存在一些并发问题。最后,您可能会发现问题与线程无关。我只是想提出一个可能的解释。