2012-02-03 73 views
2

早上好。静态非托管dll C#包装和多线程,多域名

这是我的场景:我有一个第三方非托管foo.dll与自动快速回报设备交互,称之为FooDevice。我写了一个关于foo.dll的方法的包装器,称它为FooWrapper,并且用编组和一些锤子敲打我最终使其工作;如您所知,在使用DllImport时,所有暴露的方法都需要标记为staticextern foo.dll公开了一些方法和回调函数指针;当我尝试在不同的线程中同时连接两个设备时,当tryng钩住此回调函数时,包装会挂起。 我知道static stuff是线程共享的,所以我想为每个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 ... 
    } 
} 

您能否提供我的方式来istantiate正确FooWrapper超过一次(在相同或differente线程或应用程序域)?

谢谢你们。 干杯, Nando

+1

“快速回报装置”,当你使用它错误时,它会冲你脸上吗?考虑到appdomains会是错误的,本机代码没有它的概念。使用线程往往是错误的,没有很多代码可以在多个线程中自由调用,而不会在*客户端*代码中进行任何同步。可以肯定的是,死锁并不是一种不寻常的失败模式。请联系此代码的供应商或作者以获取支持。 – 2012-02-03 13:27:38

+0

谢谢汉斯的回复。不幸的是,移动一个大型跨国公司并不是那么简单,考虑到“不要触摸有效的软件”的口头禅。 :-) 但我会尝试,如果有必要。 再见! :-) – 2012-02-14 16:40:37

回答

3

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

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

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

  3. 第三个麻烦但很容易的选择是将P/Invoke类封装器封装到可执行文件中,并为每个线程启动一个进程并使用远程处理与类封装器的实际实例进行通信。你可以使用ThreadId来确定哪个进程是针对哪个线程和独立的调用启动的。

希望这些选项之一有所帮助!

+0

谢谢Ananth的回复。对于选项1),正如我对汉斯所说的那样,供应商可能不会对他的实际DLL进行更改(最新的更改是2000年的日期,你知道......)。对于选项2):嗯,实际上它正是我们所做的;挂钩foo.dll的回调时出现问题;试图在同一个线程或不同的线程中多次钩住它,使事情变得疯狂(挂起,溢出等)。我搜索了多个AppDomain作为解决方案,但我不知道如何设置它,如果它能工作,所以我试着问一些像你这样的专家。 :-) – 2012-02-14 16:44:17

+0

我会在需要时尝试(现在不是阻塞功能),我会报告我的经验。 谢谢! :-) – 2012-02-14 16:49:13