Почему я получаю эти исключения? - PullRequest
0 голосов
/ 25 апреля 2020

В моем проекте 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. Так что было бы надежным решением или исправлением для такого сценария, подобного этому?

...