Причиной повреждения данных в векторе C ++? - PullRequest
0 голосов
/ 09 апреля 2020

Я пытаюсь написать базовый c MP3-плеер, чтобы попробовать кое-что для Windows для C ++, и до сих пор все шло хорошо. Я пытался написать класс очереди для воспроизведения большего количества песен после окончания текущей, каждый раз, когда новая песня добавляется в очередь, все остальные данные в очереди, похоже, повреждаются, что, очевидно, вызывает проблемы. Повреждение, кажется, происходит между строками 202 и 212 в функции handleOpen () в моем главном файле. Я пытался изменить область видимости переменной и возиться с кодом вставки, но ничего из этого не устранило проблему. Я обычно пишу на Java, поэтому C ++ иногда немного сложен для меня.

Main. cpp

#include <Windows.h>
#include <tchar.h>
#include <ShObjIdl.h>
#include "Player.h"
#include "Song.h"
#include "Queue.h"

#define BUTTON1 1
#define BUTTON2 2
#define NEXTBUTTON 3
#define PREVBUTTON 4

//I think these are just function prototypes
int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow);

LRESULT CALLBACK WndProc(_In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam);

HRESULT BasicFileOpen(PWSTR* ptr_to_path);

void handleOpen(void);

//some static variables
static TCHAR szWindowClass[] = _T("Desktop App");
static TCHAR szTitle[] = _T("MP3 Player");

HWND h_window;
HWND h_button1;
HWND h_button2;
HWND h_nextbutton;
HWND h_prevbutton;

Player player = NULL;
Queue queue = Queue();
PWSTR path;
Song s;
wchar_t* ext;

int x = GetSystemMetrics(SM_CXSCREEN);
int y = GetSystemMetrics(SM_CYSCREEN);

//function definitions
int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) {
    //struct for a window
    WNDCLASSEX window;

    //initialize struct values
    window.cbSize = sizeof(WNDCLASSEX);
    //to combine multiple flags, OR them together
    window.style = CS_HREDRAW | CS_VREDRAW;
    //I think this defines the process function for window events
    window.lpfnWndProc = WndProc;
    window.cbClsExtra = 0;
    window.cbWndExtra = 0;
    window.hInstance = hInstance;
    window.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    window.hCursor = LoadCursor(NULL, IDC_ARROW);
    window.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    window.lpszMenuName = NULL;
    window.lpszClassName = szWindowClass;
    window.hIconSm = LoadIcon(window.hInstance, IDI_APPLICATION);

    if (!RegisterClassEx(&window)) {
        MessageBox(NULL, _T("Call to RegisterClassEx failed!"), szTitle, NULL);

        return 1;
    }

    h_window = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);

    //check if the window was create successfully
    if (!h_window) {
        MessageBox(NULL, _T("Call to CreateWindow Failed"), szTitle, NULL);

        return 1;
    }

    h_button1 = CreateWindow(L"BUTTON", L"Open", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, (x / 2) - 100, y - 200, 200, 50, h_window, (HMENU)BUTTON1, (HINSTANCE)GetWindowLong(h_window, GWL_HINSTANCE), NULL);
    h_button2 = CreateWindow(L"BUTTON", L"\u25B6", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, (x / 2) - 100, y - 140, 200, 50, h_window, (HMENU)BUTTON2, (HINSTANCE)GetWindowLong(h_window, GWL_HINSTANCE), NULL);
    h_nextbutton = CreateWindow(L"BUTTON", L"\u23E9", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, (x / 2) + 110, y - 140, 200, 50, h_window, (HMENU)NEXTBUTTON, (HINSTANCE)GetWindowLong(h_window, GWL_HINSTANCE), NULL);
    h_prevbutton = CreateWindow(L"BUTTON", L"\u23EA", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, (x / 2) - 310, y - 140, 200, 50, h_window, (HMENU)PREVBUTTON, (HINSTANCE)GetWindowLong(h_window, GWL_HINSTANCE), NULL);
    //tell the OS to show the window
    ShowWindow(h_window, nCmdShow);
    UpdateWindow(h_window);

    //send any messages to the process function
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(_In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam) {
    PAINTSTRUCT paint_struct;
    HDC hdc;
    //TCHAR greeting[] = _T("Hello Windows Desktop!");

    switch (message) {
        //handle button presses based on IDs
    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case BUTTON1:
            //PWSTR path;
            handleOpen();
            break;
        case BUTTON2:
            //MessageBox(NULL, _T("BUTTON2 Clicked"), szTitle, NULL);
            if (player.paused && player.playing) {
                h_button2 = CreateWindow(L"BUTTON", L"\u23F8", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, (x / 2) - 100, y - 140, 200, 50, h_window, (HMENU)BUTTON2, (HINSTANCE)GetWindowLong(h_window, GWL_HINSTANCE), NULL);
                player.play(h_window);
                //player.paused = false;
            }
            else if (!player.paused && player.playing) {
                h_button2 = CreateWindow(L"BUTTON", L"\u25B6", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, (x / 2) - 100, y - 140, 200, 50, h_window, (HMENU)BUTTON2, (HINSTANCE)GetWindowLong(h_window, GWL_HINSTANCE), NULL);
                player.pause();
                //player.paused = true;
            }
            else {
                player = Player(queue.getCur().ext);
                player.open(queue.getCur().path);
                player.play(h_window);
                h_button2 = CreateWindow(L"BUTTON", L"\u25B6", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, (x / 2) - 100, y - 140, 200, 50, h_window, (HMENU)BUTTON2, (HINSTANCE)GetWindowLong(h_window, GWL_HINSTANCE), NULL);
            }
            break;
        default:
            break;
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &paint_struct);

        //update window stuff in here
        //TextOut(hdc, 5, 5, greeting, _tcslen(greeting));

        EndPaint(hWnd, &paint_struct);
        break;

    case MM_MCINOTIFY:
        player.close();
        queue.advance();
        //if (lstrcmpW(queue.getCur().path, L"") != 0) {
        player = Player(queue.getCur().ext);
        player.open(queue.getCur().path);
        player.play(h_window);
        //}
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }
}

HRESULT BasicFileOpen(PWSTR* ptr_to_path) {
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr)) {
        IFileOpenDialog* p_file_open;

        hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<void**>(&p_file_open));
        if (SUCCEEDED(hr)) {
            hr = p_file_open->Show(NULL);

            if (SUCCEEDED(hr)) {
                IShellItem* p_item;
                hr = p_file_open->GetResult(&p_item);
                if (SUCCEEDED(hr)) {
                    PWSTR file_path;
                    hr = p_item->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
                    *ptr_to_path = file_path;
                    //if (SUCCEEDED(hr)) {
                    //  MessageBox(NULL, file_path, L"File Path", MB_OK);
                    //  CoTaskMemFree(file_path);
                    //}
                    CoTaskMemFree(file_path);
                    p_item->Release();
                }
            }
            p_file_open->Release();
        }
        CoUninitialize();
    }
    return hr;
}

void handleOpen(void) {
    if (SUCCEEDED(BasicFileOpen(&path))) {
        //check if the selected file is a supported audio format
        ext = wcsrchr(path, L'.');
        ext = ext ? ext + 1 : path;
        //MessageBox(NULL, ext, L"Extension", MB_OK);
        if (!lstrcmpW(ext, L"mp3")) {
            //Song s;
            s.path = path;
            s.ext = ext;
            queue.add(s);
            MessageBox(NULL, L"Added MP3 to Queue", L"", MB_OK);
        }
        else {
            MessageBox(NULL, path, L"Invalid or unsupported file extension", MB_OK);
        }
    }
}

Очередь. cpp

#include <Windows.h>
#include "Song.h"
#include "Player.h"
#include "Queue.h"
#include <vector>
#include <iterator>

Queue::Queue() {
    q.reserve(32);
    it = q.begin();
    cur = 0;
}

//inserts a song into the queue at the start
void Queue::add(Song s) {
    //q.insert(q.begin(), 1, s);
    q.push_back(s);
}

//removes all instances of a specified song from the queue
//returns -1 if the song was not found, 0 if successfully removed
int Queue::remove(Song s) {
    bool found = false;
    for (std::vector<Song>::iterator i = q.begin(); i != it; ++i) {
        if (!lstrcmpW(s.path, (*i).path)) {
            q.erase(i);
            found = true;
        }
    }
    return found ? 0 : -1;
}

//sets the current song to the specified Song object
//returns -1 if the song was not found in the queue, 0 if successful
int Queue::seek(Song s) {
    for (unsigned int i = 0; i < q.size(); i++) {
        if (!lstrcmpW(s.path, q[i].path)) {
            cur = i;
            return 0;
        }
    }
    return -1;
}

//sets the current song to the specified indice
//same return values as the previous function
int Queue::seek(int i) {
    if (i < q.size() - 1) {
        cur = i;
        return 0;
    }
    return -1;
}

//returns the Song current song in the queue
Song Queue::getCur(void) {
    return q[cur];
}

//returns the previous song in the queue, or an empty one if none exists
Song Queue::getPrev(void) {
    if (cur - 1 > 0) {
        return q[cur - 1];
    }
    Song s{};
    return s;
}

//returns the next song in the queue, or an empty one if none exists
Song Queue::getNext(void) {
    if (cur + 1 < q.size()) {
        return q[cur + 1];
    }
    Song s{};
    return s;
}

void Queue::advance(void) {
    cur++;
}

Player. cpp

    #include <Windows.h>
    #include "Player.h"

    #pragma comment(lib, "WinMM.lib")



Player::Player(wchar_t* ext) {
        this->ext = ext;
        playing = false;
        paused = true;
        started = false;
    }

    MCIERROR Player::open(wchar_t* filepath) {
        if (playing) {
            mciSendString(L"close mp3", NULL, 0, NULL);
        }
        wchar_t command[1024] = L"open \"";
        if (sizeof(filepath) < 1000) {
            lstrcatW(command, filepath);
            lstrcatW(command, (wchar_t*)L"\" type mpegvideo alias mp3");
        }
        playing = true;
        return mciSendStringW(command, NULL, 0, NULL);
    }

    MCIERROR Player::play(HWND handle) {
        paused = false;
        if (started) {
            return mciSendString(L"resume mp3 notify", NULL, 0, handle);
        } else {
            started = true;
            return mciSendString(L"play mp3 notify", NULL, 0, handle);
        }
    }

    MCIERROR Player::restart(void) {
        return mciSendString(L"play mp3 from 0", NULL, 0, NULL);
    }

    MCIERROR Player::pause(void) {
        paused = true;
        return mciSendString(L"pause mp3", NULL, 0, NULL);
    }

    MCIERROR Player::close(void) {
        playing = false;
        paused = true;
        started = false;
        return mciSendString(L"close mp3", NULL, 0, NULL);
    }

Очередь - это в основном просто вектор с некоторой добавленной функциональностью, поэтому я немного запутался, когда ошибаюсь. Спасибо за любую помощь, спасибо!

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

Одной из проблем является недействительность q iterator в классе Queue в функции remove. Вы удаляете элемент из vector, перебирая его.

Для iterate над vector и удаляя элемент из него, выполните следующие действия:

for ( auto it = std::begin( q ); it != std::end( q ); )
{
     if ( condition )
         it = q.erase( it );
     else
         ++it;
}
0 голосов
/ 15 апреля 2020

Почему бы сразу не вернуть успех, когда remove () найдет песню, чтобы итератор не растерялся.

int Queue::remove(Song s) {
    for (std::vector<Song>::iterator i = q.begin(); i != it; ++i) {
        if (!lstrcmpW(s.path, (*i).path)) {
            q.erase(i);
            return 0;
        }
    }
    return -1;
}
...