0

I am experimenting with creating a class-based abstraction over the Win32 API and I have run into some very strange behaviour where depending on how I access the same piece of data, the application will either crash with error code 1407 or work as expected.

Here is a snippet from my Window.cpp file

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;
}

If I change windowClass.lpszClassName on line 28 to be app->getAppId().c_str() then the application crashes with error code 1407.

Why does this happen? They are accessing exactly the same data and there is no modification of the string performed in-between the first call to app->getAppId().c_str() on line 15 and the second call on line 28.

Please note: I know there have been questions on other forums related to this topic but none of those answers actually explained why one line worked over the other which is what I am looking for with this question.

txk2048
  • 281
  • 3
  • 15

1 Answers1

2

Following MSDN, second argument of CreateWindowExW is of type LPCWSTR which stands for Long Pointer to Constant Wide STRing. The long pointer part clearly states that you have to provide pointer that will be valid during the function call. That is not the case when you pass a c_str() from temporary object returned by getAppID().

NRUB
  • 404
  • 4
  • 17
  • "*That is not the case when you pass a `c_str()` from temporary object returned by `getAppID()`*" - only because the pointer is being saved and used **after** its owning string object has gone out of scope and been destroyed. Keep the string in scope, then this problem will go away – Remy Lebeau Nov 24 '20 at 21:11