2

おはようございます。

これが私のシナリオです。私は、FooDevice と呼ばれる自動高速ペイバック デバイスと対話する、サード パーティの管理されていない foo.dll を持っています。私は foo.dll のメソッドのラッパーを作成し、それを FooWrapper と呼び、マーシャリングと少しのハンマーで最終的に機能させました。ご存知かもしれませんが、公開されてDllImportいるすべてのメソッドを使用する場合は、としてマークする必要がありstaticextern foo.dll はいくつかのメソッドとコールバック関数ポインターを公開します。異なるスレッドで 2 つのデバイスを同時に接続しようとすると、このコールバック関数をフックしようとするとラッパーがハングします。静的なものはスレッド共有であることを知っているので、AppDomainFooWrapper インスタンスごとに異なるものを使用することを考えました。それがこの種の仕事をする正しい方法だと思いますか?

ここに私の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 で) 正しくインスタンス化する方法を教えてください。

君たちありがとう。乾杯、ナンド

4

1 に答える 1

3

私はあなたの問題を完全に理解しています。これらは私が試すオプションです。特定の状況に合ったものを選択してください

  1. Foo.dll のベンダーに連絡して、スレッド セーフなバージョンを入手してみます。

  2. DLL でメソッドを呼び出してもパフォーマンスに影響がない場合 (ほとんど時間がかからない場合)、呼び出しごとにロック、ログイン、状態の設定、操作の実行、ログアウトを行うことで、ラッパーをスレッドセーフにします。これは、後でスレッドセーフな foo.dll または新しい C# ベースの実装に置き換えることができるクリーンなソリューションです。また、テストと保守も簡単です。

  3. 面倒ですが簡単な 3 番目のオプションは、P/Invoke クラス ラッパーを実行可能ファイルにラップし、スレッドごとに 1 つのプロセスを起動し、リモート処理を使用してクラス ラッパーの実際のインスタンスと対話することです。ThreadId を使用して、どのプロセスがどのスレッドに対して起動されたかを特定し、その方法で呼び出しを分離することができます。

これらのオプションのいずれかが役立つことを願っています!

于 2012-02-13T19:43:53.047 に答える