静态非托管dll C#包装器和多线程,多域

时间:2012-02-03 10:39:08

标签: c# multithreading appdomain static-classes

早上好。

这是我的方案:我有一个第三方非托管foo.dll,它与一个自动快速回报设备交互,称之为FooDevice。我写了一个关于foo.dll方法的包装器,称之为FooWrapper,并且通过编组和一些锤击我终于使它工作了;您可能知道,在使用DllImport时,所有公开的方法都需要标记为staticextern foo.dll暴露了一些方法和一个回调函数指针;当我尝试在不同的线程中同时连接两个设备时,我的包装器在tryng挂钩此回调函数时挂起。 我知道静态的东西是线程共享的,所以我想为每个FooWrapper istances使用不同的AppDomain。 你认为这是做这种工作的正确方法吗?

这里有点我的FooWrapper:


    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void FOO_EventHandlerFunc([In] UInt16 event_id, [In, Out] ref IntPtr data, [In] IntPtr param);

    [SuppressUnmanagedCodeSecurity]
    internal static class FOO
    {
        static FOO()
        {
            //...
        }

        ///
        ///    FOO_RegisterEventHandler 
        ///    The FOO_RegisterEventHandler function registers an application-defined callback 
        ///    function, which will subsequently be called for all FooDevice generated events. 
        /// 
        ///    long FOO_RegisterEventHandler(FOO_EventHandlerFunc handler, BYTE evmask, LONG param); 
        /// 
        ///    Parameters 
        ///    handler 
        ///    [in] Pointer to an application-defined callback function (see below). 
        ///    evmask 
        ///    [in] Specify which events to enable (see EnableEvents). 
        ///    param 
        ///    [in] An application-defined value to be passed to the callback function 
        /// 
        ///    Return Values 
        ///    If the function succeeds, the return value is zero. 
        ///    If the function fails, the return value is nonzero. 
        /// 
        ///    Remarks 
        ///    The FOO_EventHandlerFunc type defines a pointer to a callback function, which must 
        ///    comply with the following, where FOO_EventHandlerFunc is a placeholder for the 
        ///    application-defined function name. 
        /// 
        ///    void FOO_EventHandlerFunc(WORD event_id, LPVOID data, LONG param); 
        /// 
        ///    Parameters 
        ///    event_id 
        ///    [in] Event index as specified by the FooDevice protocol. 
        ///    data 
        ///    [in] Event data. The type of data depends on event_id. 
        ///    (See the event specifications for FooDevice). 
        ///    param 
        ///    The application-defined value passed during registration. 
        /// 
        ///    Remarks 
        ///    Avoid lengthy callback functions, since it will stall the underlying protocol, 
        ///    thereby interrupting a steady communications flow. 
        ///    FooDevice will only be generating events during operation. 
        ///    That is - between FOO_LogIn and FOO_LogOut.
        ///
        ///The handler.
        ///The evmask.
        ///The param.
        ///
        [DllImport("foo.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Ansi)]
        public static extern UInt32 FOO_RegisterEventHandler([In] [MarshalAs(UnmanagedType.FunctionPtr)] FOO_EventHandlerFunc handler, [In] byte evmask, [In] IntPtr param);

        ///
        ///    FOO_LogIn
        ///    The FOO_LogIn function opens FooDevice for normal operation.
        ///
        ///    long FOO_LogIn(LPSTR oper, LPSTR datetime);
        /// 
        ///    Parameters
        ///    oper
        ///    [in] Pointer to a null-terminated string identifying the cashier.
        ///    The string can have any content, but a maximum of 50 characters will be used.
        ///    datetime
        ///    [in] Pointer to a null-terminated string indicating the current date and time.
        ///    The string must have 'YYYYMMDDhhmmss' format to take effect.
        ///    Return Values
        ///    If the function succeeds, the return value is zero.
        ///    If the function fails, the return value is nonzero.
        ///
        ///The oper.
        ///The datetime.
        ///
        [DllImport("foo.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Ansi)]
        public static extern UInt32 FOO_LogIn([In] string oper, [In] string datetime);

        //... and so on ...
    }
}

你能建议我一种方法来正确地反映FooWrapper多次(在相同或不同的线程或AppDomain中)吗?

谢谢你们。 干杯, 南多

1 个答案:

答案 0 :(得分:3)

我完全理解你的问题。这些是我会尝试的选项,选择一个适合您特定情况的选项

  1. 我会尝试联系Foo.dll的供应商,并获得一个线程安全的版本。

  2. 如果在DLL上调用方法不会影响性能(它们花费很少的时间),我会通过锁定,登录,设置状态,执行操作和注销每个来使包装器线程安全呼叫。这是一个干净的解决方案,可以在以后使用线程安全的foo.dll或甚至基于C#的新实现进行替换。它也很容易测试和维护。

  3. 第三个,简单易用的选项 - 将P / Invoke类包装器包装成可执行文件,并为每个线程启动一个进程,并使用远程处理与类包装器的实际实例进行通信。您可以使用ThreadId来确定为哪个线程启动了哪个进程,并以这种方式单独调用。

  4. 希望其中一个选项有所帮助!