2012-02-03 71 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