В моем проекте winforms я реализовал это решение Microsoft для синхронизации с высоким разрешением в повторяющейся медиа-кнопке, которая повторяет последовательность от A до B, однако во время последовательности l oop я получаю следующие исключения при выполнении операций просмотра:
System.AccessViolationException: 'Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена. '
Произошло необработанное исключение типа' System.ArgumentNullException 'в System. Windows .Forms.dll Значение не может быть нулевым.
Ошибка DeleteTimerQueue (этот параметр настроен на печать, как показано ниже)
Исключение, выданное в 0x7712EC75 (ntdll.dll) в MyProgram.exe: 0xC000000D: неверный параметр был передан в услуга или функция. Необработанное исключение в 0x7712EC75 (ntdll.dll) в MyProgram.exe: 0xC000000D: неверный параметр был передан службе или функции.
Это часто происходит во время операций просмотра System::Windows::Forms::WebBrowser
.
Согласно этому решению CP :
Вы должны знать, что Windows не является операционной системой реального времени. Вы не получите постоянные интервалы таймера; особенно, когда нагрузка на систему высока или существует много передач с диска или по сети.
Так что имеет смысл, почему возникают проблемы во время операций просмотра, тогда я искал решение Microsoft и, согласно , это Документация Microsoft :
Службы мультимедийного таймера позволяют приложениям планировать события таймера с максимально возможным разрешением (или точностью) для аппаратной платформы. Эти мультимедийные службы таймера позволяют планировать события таймера с более высоким разрешением, чем другие службы таймера.
Эти службы таймера полезны для приложений, которые требуют синхронизации высокого разрешения. Например, для MIDI-секвенсора требуется таймер высокого разрешения, поскольку он должен поддерживать темп событий MIDI с разрешением в 1 миллисекунду.
Когда вы попадаете на эти страницы документации, Microsoft указывает на следующее :
Этот топи c описывает устаревшую функцию. Новые приложения должны использовать функцию CreateTimerQueueTimer для создания таймеров.
Поэтому я основал свой код на этом примере Microsoft .
Вот мой код:
//repeatbutton.h
#include <Windows.h>
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired);
public ref class repeatButton {
public:
HANDLE hTimerQueue;
int positionA = 0;
int positionB = 0;
int currentTime = 0;
AxWMPLib::AxWindowsMediaPlayer^ axWindowsMediaPlayer;
repeatButton(AxWMPLib::AxWindowsMediaPlayer^ mediaPlayer) {
this->axWindowsMediaPlayer = mediaPlayer);
}
public: System::Void getCurrentPosition() {
if (this->axWindowsMediaPlayer->InvokeRequired) {
this->currentTime = System::Convert::ToInt32(this->axWindowsMediaPlayer->Ctlcontrols->currentPosition);
}
else {
this->currentTime = System::Convert::ToInt32(this->axWindowsMediaPlayer->Ctlcontrols->currentPosition);
}
}
public: System::Void setCurrentPosition() {
if (this->axWindowsMediaPlayer->InvokeRequired) {
this->axWindowsMediaPlayer->Ctlcontrols->currentPosition = this->positionA;
}
else {
this->axWindowsMediaPlayer->Ctlcontrols->currentPosition = this->positionA;
}
}
// Delete all timers in the timer queue.
public: System::Void stopTimer() {
if (this->hTimerQueue != NULL) {
if (!DeleteTimerQueue(this->hTimerQueue))
System::Diagnostics::Debug::WriteLine("DeleteTimerQueue failed", GetLastError());
}
this->hTimerQueue = NULL;
}
public: System::Void timerTick() {
this->axWindowsMediaPlayer->Invoke(gcnew System::Action(this, &repeatButton::getCurrentPosition));
if (this->currentTime < this->positionA || this->currentTime > (this->positionB + 1)) {
stopTimer();
return;
}
else if (this->currentTime != this->positionB) return;
this->axWindowsMediaPlayer->Invoke(gcnew System::Action(this, &repeatButton::setCurrentPosition));
}
public: System::Void startTimer(PVOID parameter) {
HANDLE hTimer = NULL;
this->hTimerQueue = NULL;
// Create the timer queue.
this->hTimerQueue = CreateTimerQueue();
if (NULL == this->hTimerQueue)
{
System::Diagnostics::Debug::WriteLine("CreateTimerQueue failed", GetLastError());
}
// Set a timer to call the timer routine every 100 milliseconds.
if (!CreateTimerQueueTimer(&hTimer, this->hTimerQueue,
(WAITORTIMERCALLBACK)TimerRoutine, parameter, 0, 100, 0))
{
System::Diagnostics::Debug::WriteLine("CreateTimerQueueTimer failed", GetLastError());
}
}
};
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
if (lpParam == NULL)
{
System::Diagnostics::Debug::WriteLine("TimerRoutine lpParam is NULL");
}
else
{
// lpParam points to timerTick;
((repeatButton^&)lpParam)->timerTick();
}
}
Это также замедляет повторяющуюся последовательность, немного превышая время, которое я установил, а иногда нарушая последовательность и выходя за пределы позиции B. Так что было бы надежным решением или исправлением для такого сценария, подобного этому?