Как я могу предотвратить возникновение проблем с DLL, если она используется более одного раза?
Как отмечает Питер Дунихо в своем комментарии, я был зациклен на красной сельди, когда мне следовало сосредоточиться на чем-то другом.
Когда я использую 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 () - это:
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.
this.barcodeReader = new Symbol.Barcode.Reader();
// Create reader data
this.barcodeReaderData = new Symbol.Barcode.ReaderData(
Symbol.Barcode.ReaderDataTypes.Text,
Symbol.Barcode.ReaderDataLengths.MaximumLabel);
// Create event handler delegate
this.barcodeEventHandler = this.BarcodeReader_ReadNotify;
// Enable reader, with wait cursor
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
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
return true;
}
Обсуждаемые объекты находятся в Symbol.Barcode.dll от Motorola. Они объявлены в виде примерно так:
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;
}
... Я вижу это в файле журнала после открытия формы Find и сбоя приложения (оно зависает примерно на 20 секунд перед исчезновением):
Date: 3/19/2009 11:43:38 PM
Message: Reached frmFind.InitReader
Date: 3/19/2009 11:43:38 PM
Message: Reached frmFind.I
... так что он почти мгновенно падает после этого блока кода:
if (this.barcodeReader != null)
{
return false;
}
... так как он проходит только половину следующей строки регистрации, прежде чем грубо прервать себя.
ОБНОВЛЕНИЕ 2
Fejesjoco все еще может быть прав (в своем комментарии ниже), но я отправляю этот код регистрации как выставку "A":
public void WriteLog(string message)
{
if (!HHSConsts.Logging) return;
StringBuilder formattedMessage = new StringBuilder();
formattedMessage.AppendLine("Date: " + DateTime.Now.ToString());
formattedMessage.AppendLine("Message: " + message);
_streamWriter.WriteLine(formattedMessage.ToString());
_streamWriter.Flush();
}
Поток должен очищаться после записи каждой строки в журнал.
ОБНОВЛЕНИЕ 3
Отказ всегда очень последовательный относительно того, как долго он "зависает", прежде чем он падает; Я вижу, как курсор мигает в текстовом поле штрих-кода формы поиска, и он пульсирует около 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()
... поэтому дополнительные записи в файле журнала препятствовали регистрации исключения msg.
ОБНОВЛЕНИЕ 4
Actions.Enable?
Я был незнаком с этим, и когда я добавил "Действия". У меня есть выбор между Symbol.Barcode.Actions и Symbol.Generic.Actions.
Сначала я выбрал первый, но у него нет метода "Включить". Добавив его, я отругал его: "Ссылка на объект требуется для нестатического поля, метода или свойства Symbol.Generic.Actions.Enable()".
Затем я прокомментировал добавленное использование и ввел "Действия". снова, и на этот раз выбрал Symbol.Generic.Actions (и получил то же сообщение об ошибке для моих проблем).
Как я могу использовать 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 ():
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();
}
InitReader () вызывается из textBoxScan_GotFocus(); textBoxScan имеет фокус при отображении формы.
ОБНОВЛЕНИЕ 6
Что касается "явного закрытия классов Close() перед их Dispose()", я вызываю Dispose для двух вещей, Symbol.Barcode.Reader и Symbol.Barcode.ReaderData, и ни один из них не допускает вызова Close().
ОБНОВЛЕНИЕ 7
Это утверждение С. Эвенхейса: "нельзя включить двух (на переднем плане) читателей" заставило меня попробовать следующее:
private void FrmDelivery_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.barcodeReader.Actions.Disable();
}
... который, кажется, в значительной степени добился цели - я могу открыть форму поиска без зависания, что может привести к аварийному завершению. Я могу сканировать в форму поиска после сканирования в форму доставки. Единственная (не связанная?) Проблема, которую я до сих пор вижу, заключается в том, что моя форма Find по какой-то причине частично закрыта...
2 ответа
Symbol Motorola Zebra использует устаревшую библиотеку C++ с устаревшей оболочкой.NET. Есть довольно много подводных камней (некоторые события требуют повторного присоединения каждый раз, когда они происходят, некоторые классы требуют явного Close()
до тебя Dispose()
их и т. д.).
Как вы, возможно, узнали, вы можете вызывать члены классов Symbol из нескольких потоков / форм, но вы не можете включить два (передних) считывателя, и некоторые свойства можно установить, только если не включены фоновые считыватели, и невозможно определить, включены ли фоновые программы чтения (например, DataWedge).
В нашей компании мы решили инициализировать сканер в Form.Activated
событие и деинициализировать его в Deactivated
событие. Затем, когда требуется сканирование, вызов Actions.Enable()
сделал бы трюк. Настройка свойств читателя выполняется в try catch
блоки:(
Довольно странно, что ваше приложение вылетает при Get InterfaceParams, я ожидаю, что установка их вызовет проблемы. Попробуйте ваше приложение с минимумом; не устанавливайте BeepTime
или же WaveFile
свойства.
Я не знаком с этим типом сканера, но могу представить, что initreader сделает что-то на аппаратном уровне. Вероятно, он попытается открыть какой-нибудь порт. Поскольку порт уже открыт, он не работает.
Вам нужно внедрить единый сервис для вашего сканера вместо того, чтобы обращаться к нему прямо в вашей форме. Затем вы можете инициализировать считыватель один раз для всего приложения и использовать его в любом месте.
Это будет намного более "твердым" и, следовательно, более легким в обслуживании.