Приложение Win32 аварийно завершает работу в зависимости от метода, используемого для доступа к строке

Я экспериментирую с созданием абстракции на основе классов через API Win32 и столкнулся с очень странным поведением, когда в зависимости от того, как я получаю доступ к одному и тому же фрагменту данных, приложение либо падает с кодом ошибки 1407, либо работает как ожидалось.

Вот фрагмент из моего файла Window.cpp

bool Window::show(const GUI::Application *const app)
{
    WNDCLASSEXW windowClass = { 0 };
    windowClass.cbSize = sizeof(WNDCLASSEXW);
    windowClass.lpfnWndProc = m_WindowProc;
    windowClass.hInstance = app->getInstance();
    
    // Load standard cursor
    if (!(windowClass.hCursor = ::LoadCursorW(NULL, IDC_ARROW)))
    {
        return false;
    }
    
    windowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
    windowClass.lpszClassName = app->getAppId().c_str();
    
    // Register window class with system
    if (!::RegisterClassExW(&windowClass))
    {
        return false;
    }
    
    OutputDebugStringW(L"Registered window class");
    
    // Actually create the window
    m_handle = ::CreateWindowExW(
        0,
        windowClass.lpszClassName,
        m_title.c_str(),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        m_width, m_height,
        NULL,
        NULL,
        app->getInstance(),
        NULL
    );

    if (!m_handle)
    {
        DisplayErrorMessage(GetLastError());
        return false;
    }
    
    OutputDebugStringW(L"Created window");

    ::ShowWindow(m_handle, app->getShowCmd());
    
    OutputDebugStringW(L"ShowWindow executed, going into message loop");

    MSG msg = { 0 };
    while (::GetMessageW(&msg, NULL, 0, 0))
    {
        ::TranslateMessage(&msg);
        ::DispatchMessageW(&msg);
    }
    
    // Cleanup resources
    ::UnregisterClassW(windowClass.lpszClassName, app->getInstance());
    
    return true;
}

Если я изменю windowClass.lpszClassName в строке 28 на app->getAppId().c_str(), приложение вылетит с кодом ошибки 1407.

Почему это происходит? Они обращаются к одним и тем же данным, и между первым вызовом app->getAppId().c_str() в строке 15 и вторым вызовом в строке 28 не выполняется никаких изменений в строке.

Обратите внимание: я знаю, что на других форумах были вопросы, связанные с этой темой, но ни один из этих ответов на самом деле не объяснял, почему одна строка работала над другой, что я и ищу с этим вопросом.


person Toothless204    schedule 24.11.2020    source источник
comment
Для этого нужен минимальный воспроизводимый пример.   -  person Ulrich Eckhardt    schedule 24.11.2020
comment
windowClass.lpszClassName = app->getAppId().c_str();, вероятно, является временной строкой, время жизни которой заканчивается на этой строке, из-за чего сохраненный указатель болтается.   -  person drescherjm    schedule 24.11.2020
comment
Опубликуйте свою реализацию GUI::Application::getAppId().   -  person aalimian    schedule 25.11.2020
comment
Исправление может быть auto className = app->getAppId(); windowClass.lpszClassName = className.c_str();   -  person drescherjm    schedule 25.11.2020


Ответы (1)


После MSDN второй аргумент CreateWindowExW имеет тип LPCWSTR, что означает Long Pointer to Cconstant Wide STR< /сильно>инг. В части long pointer четко указано, что вы должны указать указатель, который будет действительным во время вызова функции. Это не тот случай, когда вы передаете c_str() from временный объект, возвращенный getAppID().

person Michał Kaczorowski    schedule 24.11.2020
comment
Это не тот случай, когда вы передаете c_str() из временного объекта, возвращенного getAppID(), только потому, что указатель сохраняется и используется после его строкового объекта-владельца, который вышел из области видимости. и был уничтожен. Держите строку в области видимости, тогда эта проблема исчезнет - person Remy Lebeau; 25.11.2020