C# 当DLL被多次使用时,如何防止它引起问题?

C# 当DLL被多次使用时,如何防止它引起问题?,c#,dll,barcode-scanner,motorola,reentrancy,C#,Dll,Barcode Scanner,Motorola,Reentrancy,正如彼得·杜尼霍(Peter Duniho)在一篇评论中指出的那样,当我本应该专注于其他事情的时候,我被一条红鲱鱼迷住了 当我以一种形式使用Symbol.Barcode.Reader和Symbol.Barcode.ReaderData时,它们工作正常。我使用它们作为我的文档 然而,当我从一个使用条形码扫描代码的表单转到另一个同样使用条形码扫描代码的表单时,所有达拉斯都崩溃了。在启动时,我在第二种形式中得到以下异常: Symbol.Exceptions.OperationFailureExcept

正如彼得·杜尼霍(Peter Duniho)在一篇评论中指出的那样,当我本应该专注于其他事情的时候,我被一条红鲱鱼迷住了

当我以一种形式使用Symbol.Barcode.Reader和Symbol.Barcode.ReaderData时,它们工作正常。我使用它们作为我的文档

然而,当我从一个使用条形码扫描代码的表单转到另一个同样使用条形码扫描代码的表单时,所有达拉斯都崩溃了。在启动时,我在第二种形式中得到以下异常:

Symbol.Exceptions.OperationFailureException: SCAN_GetInterfaceParams
   at Symbol.Barcode.InterfaceParams.GetInterfaceParams()
   at Symbol.Barcode.InterfaceParams..ctor(Reader reader)
   at Symbol.Barcode.Actions.Enable()
   at HHS.frmFind.InitReader()
   at HHS.frmFind.textBoxScan_GotFocus(Object sender, EventArgs e)
   at System.Windows.Forms.Control.OnGotFocus(EventArgs e)
   at System.Windows.Forms.Control.WnProc(WM wm, Int32 wParam, Int32 lParam)
   at System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
   at Microsoft.AGL.Forms.WL.SetVis(IntPtr hwnThis, BOOL fVis)
   at System.Windows.Forms.Control.set_Visible(Boolean value)
   at System.Windows.Forms.Form.ShowDialog()
两个表单之间的条形码扫描代码是相同的,因此它不是代码本身(在第一个表单中,它第一次工作正常)

当输入设置为扫描的文本框时,第二个表单中会立即出现异常。触发GotFocus()事件是因为文本框在显示表单时获得焦点;OnGotFocus()调用InitReader(),然后失败。InitReader()是:

处理的对象位于摩托罗拉的Symbol.Barcode.dll中。声明格式如下:

private Symbol.Barcode.Reader barcodeReader;
private Symbol.Barcode.ReaderData barcodeReaderData;
如果我绕过第一个表单,它有相同类型的条形码扫描代码,直接转到这个表单,它不会崩溃

所以很明显,紧密相关的代码不能共存。为什么不,更重要的是,我如何才能防止这种令人反感的发展

更新 将此日志添加到InitReader后:

private bool InitReader()
{
    ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader");
    // If reader is already present then retreat
    if (this.barcodeReader != null)
    {
        return false;
    }

    // Create new reader, first available reader will be used.
    ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #2");
    this.barcodeReader = new Symbol.Barcode.Reader();

    // Create reader data
    ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #3");
    this.barcodeReaderData = new Symbol.Barcode.ReaderData(
        Symbol.Barcode.ReaderDataTypes.Text,
        Symbol.Barcode.ReaderDataLengths.MaximumLabel);

    // Create event handler delegate
    ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #4");
    this.barcodeEventHandler = this.BarcodeReader_ReadNotify;

    // Enable reader, with wait cursor
    ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #5");
    this.barcodeReader.Actions.Enable();
    this.barcodeReader.Parameters.Feedback.Success.BeepTime = 0;
    this.barcodeReader.Parameters.Feedback.Success.WaveFile = "\\windows\\alarm3.wav";

    // Attach to activate and deactivate events
    ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #6");
    this.Activated += ReaderForm_Activated;
    this.Deactivate += ReaderForm_Deactivate;

    ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #7");
    return true;
}
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
…在打开Find表单并使应用程序崩溃后,我在日志文件中看到了这一点(它在消失之前会挂起大约20秒):

…所以在这段代码之后,它几乎在瞬间崩溃:

if (this.barcodeReader != null)
{
    return false;
}
…因为它只通过了下一条记录线的一半,就粗暴地打断了自己

更新2 Fejesjoco可能仍然是对的(在下面的评论中),但我将此日志代码作为附件“A”提交:

在将每行写入日志后,应该刷新流

更新3 故障在崩溃前“挂起”的时间上总是非常一致的;我可以在find表单的条形码文本框中看到光标闪烁,并且它跳动了大约20次(我上次实际数了一下:24)

这也有点奇怪,;在更新2中,我显示了日志文件的内容,其中所有日志条目都散布在InitReader方法中。对于注释掉的日志文件(第一个除外),日志文件以以下内容结束:

Date: 3/20/2009 12:01:22 AM
Message: Reached frmFind.InitReader

Date: 3/20/2009 12:01:22 AM
Message: From application-wide exception handler: Symbol.Exceptions.OperationFailureException: SCAN_GetInterfaceParams
   at Symbol.Barcode.InterfaceParams.GetInterfaceParams()
   at Symbol.Barcode.InterfaceParams..ctor(Reader reader)
   at Symbol.Barcode.Actions.Enable()
   at HHS.frmFind.InitReader()
…因此,其他日志文件条目阻止记录异常消息

更新4 操作。启用

我不熟悉这个,当我添加“操作”时,我可以在Symbol.Barcode.Actions和Symbol.Generic.Actions之间进行选择

我选择了第一个,但它没有“Enable”方法。添加它会责骂我:“非静态字段、方法或属性'Symbol.Generic.Actions.Enable()'需要对象引用。”

然后我注释掉了添加的using,再次输入了“Actions.”,这次选择了Symbol.Generic.Actions(并为我的问题得到了相同的err msg)

如何使用Actions.Enable()

更新5 C.Evenhuis:“某些事件每次发生时都需要重新连接”,您的意思是:

private void StartRead()
{
    // If we have both a reader and a reader data
    if ((this.barcodeReader != null) && (this.barcodeReaderData != null))
    {
        // Submit a read
        this.barcodeReader.ReadNotify += this.barcodeEventHandler;
        this.barcodeReader.Actions.Read(this.barcodeReaderData);
    }
}

private void StopRead()
{
    // If we have a reader
    if (this.barcodeReader != null)
    {
        // Flush (Cancel all pending reads)
        this.barcodeReader.ReadNotify -= this.barcodeEventHandler;
        this.barcodeReader.Actions.Flush();
    }
}
…(barcodeReader.ReadNotify附加在StartRead中,并在StopRead中分离),还是更为必要

在InitReader()中,我还有:

…实现方式如下:

private void ReaderForm_Activated(object sender, EventArgs e)
{
    // If there are no reads pending on barcodeReader start a new read
    if (!this.barcodeReaderData.IsPending)
    {
        this.StartRead();
    }
}

private void ReaderForm_Deactivate(object sender, EventArgs e)
{
    this.StopRead();
}
InitReader()是从textBoxScan_GotFocus()调用的;textBoxScan在表单显示时具有焦点

更新6 至于“在Dispose()类之前显式关闭()类”,我调用Dispose的两个对象是Symbol.Barcode.Reader和Symbol.Barcode.ReaderData,这两个对象都不允许Close()调用

更新7 C.Evenhuis的这句话:“您不能启用两个(前台)读卡器”让我尝试了以下方法:

private void FrmDelivery_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    this.barcodeReader.Actions.Disable();
}
…这似乎已经完成了大部分的技巧-我可以打开Find表单而不会挂起导致最终崩溃。我可以在扫描到送货单后扫描到Find表单。唯一的(无关的)问题,我仍然看到,我的发现形式仍然部分被遮蔽,出于某种原因……

符号摩托罗拉斑马是建立在遗留C++库与遗产.NET包装器。有相当多的陷阱(有些事件每次发生时都需要重新附加,有些类需要显式的

Close()
,然后才能
Dispose()
等等)

正如您可能已经发现的,您可以从多个线程/表单调用符号类的成员,但不能启用两个(前台)读取器,并且只有在未启用后台读取器的情况下才能设置某些属性,并且无法确定是否启用了后台读取器(即Data楔形)

在我们公司,我们选择在
窗体中初始化扫描仪。激活的
事件,并在
停用的
事件中取消初始化。然后,当需要扫描时,调用
Actions.Enable()
就可以了。在
try-catch
块中设置读卡器属性:(

<>你的应用程序在<强> > <强>接口FARAMS时非常奇怪,我希望设置它们造成麻烦。尝试使用最小的应用程序;不要设置<代码> BEPTIMEST/<代码> > WaveFLILE < /C>属性> .P/> < P>符号摩托罗拉斑马是用遗留的C++库构建的。使用一些陷阱(有些事件每次发生时都需要重新附加,有些类需要显式的
Close()
才能
Dispose()
处理它们,等等)

正如您可能已经发现的,您可以从多个线程/表单调用符号类的成员,但不能启用两个(前台)读取器,并且只有在未启用后台读取器的情况下才能设置某些属性,并且无法确定是否启用了后台读取器(即Data楔形)

在我们公司,我们选择在
表单中初始化扫描仪。激活
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
private void ReaderForm_Activated(object sender, EventArgs e)
{
    // If there are no reads pending on barcodeReader start a new read
    if (!this.barcodeReaderData.IsPending)
    {
        this.StartRead();
    }
}

private void ReaderForm_Deactivate(object sender, EventArgs e)
{
    this.StopRead();
}
private void FrmDelivery_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    this.barcodeReader.Actions.Disable();
}