Статическая неуправляемая оболочка dll C # и многопоточность, мультидомены - PullRequest
2 голосов
/ 03 февраля 2012

Доброе утро.

Это мой сценарий: у меня есть неуправляемый foo.dll третьей стороны, который взаимодействует с устройством автоматической быстрой окупаемости, назовите его FooDevice. Я написал обертку вокруг методов foo.dll, назвал ее FooWrapper, и с помощью маршалинга и небольшого забивания я наконец заставил его работать; как вы знаете, при использовании DllImport все методы должны быть помечены как static и extern foo.dll предоставляет некоторые методы и указатель на функцию обратного вызова; Когда я пытаюсь соединить два устройства одновременно в разных потоках, моя оболочка зависает при попытке перехватить эту функцию обратного вызова. Я знаю, что статический материал используется совместно с потоками, поэтому я подумал об использовании разных AppDomain для каждого экземпляра FooWrapper. Как вы думаете, это правильный способ сделать такую ​​работу?

Вот немного моего 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)?

Спасибо, ребята. Ура, Nando

1 Ответ

3 голосов
/ 13 февраля 2012

Я полностью понимаю вашу проблему. Это варианты, которые я бы попробовал, выберите тот, который подходит вашей конкретной ситуации

  1. Я бы попытался связаться с поставщиком Foo.dll и получить версию, которая является поточно-ориентированной.

  2. Если вызов методов в DLL не влияет на производительность (они занимают очень мало времени), я бы сделал оболочку поточно-ориентированной, заблокировав, войдя в систему, настроив состояние, выполнив операцию и выйдя из нее на каждом из них. вызов. Это чистое решение, которое может быть позже заменено поточно-безопасным foo.dll или даже новой реализацией на C #. Это также легко проверить и поддерживать.

  3. Третий, грязный, но простой вариант - это обернуть оболочку класса P / Invoke в исполняемый файл и запустить один процесс на поток и использовать удаленное взаимодействие для связи с реальным экземпляром оболочки класса. Вы можете использовать ThreadId, чтобы определить, какой процесс запущен для какого потока, и таким образом разделить вызовы.

Надеюсь, что один из этих вариантов поможет!

...