早上好。
这是我的方案:我有一个第三方非托管foo.dll,它与一个自动快速回报设备交互,称之为FooDevice。我写了一个关于foo.dll方法的包装器,称之为FooWrapper,并且通过编组和一些锤击我终于使它工作了;您可能知道,在使用DllImport
时,所有公开的方法都需要标记为static
和extern
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中)吗?
谢谢你们。 干杯, 南多
答案 0 :(得分:3)
我完全理解你的问题。这些是我会尝试的选项,选择一个适合您特定情况的选项
我会尝试联系Foo.dll的供应商,并获得一个线程安全的版本。
如果在DLL上调用方法不会影响性能(它们花费很少的时间),我会通过锁定,登录,设置状态,执行操作和注销每个来使包装器线程安全呼叫。这是一个干净的解决方案,可以在以后使用线程安全的foo.dll或甚至基于C#的新实现进行替换。它也很容易测试和维护。
第三个,简单易用的选项 - 将P / Invoke类包装器包装成可执行文件,并为每个线程启动一个进程,并使用远程处理与类包装器的实际实例进行通信。您可以使用ThreadId来确定为哪个线程启动了哪个进程,并以这种方式单独调用。
希望其中一个选项有所帮助!