Why I'm getting these exceptions?

-1

In my winforms project I implemented this Microsoft solution for high-resolution timing in a repeat media button which repeats a sequence from A to B, however during the sequence loop I get the following exceptions when doing browsing operations:

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

An unhandled exception of type 'System.ArgumentNullException' occurred in System.Windows.Forms.dll Value cannot be null.

DeleteTimerQueue failed (this one is set to print out as in the code bellow)

Exception thrown at 0x7712EC75 (ntdll.dll) in MyProgram.exe: 0xC000000D: An invalid parameter was passed to a service or function. Unhandled exception at 0x7712EC75 (ntdll.dll) in MyProgram.exe: 0xC000000D: An invalid parameter was passed to a service or function.

That often happens during browsing operations of a System::Windows::Forms::WebBrowser.

According to this CP solution:

You should be aware that Windows is not a real time operating system. You will not get constant timer intervals; especially when the system load is high or there are many disk or network data transfers.

So that makes sense why getting issues during browsing operations then I looked for a Microsoft solution and according to this Microsoft documentation:

Multimedia timer services allow applications to schedule timer events with the greatest resolution (or accuracy) possible for the hardware platform. These multimedia timer services allow you to schedule timer events at a higher resolution than other timer services.

These timer services are useful for applications that demand high-resolution timing. For example, a MIDI sequencer requires a high-resolution timer because it must maintain the pace of MIDI events within a resolution of 1 millisecond.

When you get on those documentation pages so Microsoft points out the following:

This topic describes an obsolete function. New applications should use the CreateTimerQueueTimer function to create timers.

So I based my code on this Microsoft example.

Here's my code:

//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();
    }
}

It also slows down the repeat sequence overpassing a bit the time I set and sometimes breaking up the sequence and proceeding beyond the position B. So what would be a reliable solution or fix for such a scenario like this?

.net
winforms
timer
c++-cli
clr
asked on Stack Overflow Apr 25, 2020 by Simple • edited Apr 25, 2020 by Simple

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0