Exercise To The Reader
Exercise To The Reader

Reputation: 617

Windows executable fails to start despite having correct DLLs in root directory

My ultra simple 2D game Caventure depends on and .

When compiled, the directory looks like

Caventure.exe
libfreetype-6.dll
notomono-regular.ttf
SDL2.dll
SDL2_ttf.dll
zlib1.dll

I'm using Microsoft Visual Studio 2015. I've been following Lazy Foo's tutorials on building with Windows and even after following the steps, it doesn't work. Here's what I've done:

  1. Linked the compiler to include and library directories in x64.
  2. Linked the libraries.
  3. Copied the libraries to C:\Windows\SysWOW64.
  4. Included <Windows.h>.
  5. Used compatibility mode.
  6. Tested it in the Visual Studio IDE, including with the debugger.

When I open it, it immediately closes, it doesn't return any error.

Here's the main source file:

#include <stdio.h>
#include <stdexcept>
#include <Windows.h>
#include <SDL.h>
#include <SDL_ttf.h>

#include "TextMenu.h"
#include "TextBox.h"

#include "Graphics.h"
#include "Event.h"

// Screen dimensions, constants
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
// 600 for ground, 280 for output, 20 for input

Graphics Global;
Event Loop;

void Init(Graphics& Global)
{
    if (SDL_Init(SDL_INIT_VIDEO) > 0)
    {
        throw(::std::runtime_error("SDL failed to initialise! ERROR: "));
    }
    Global.Window = SDL_CreateWindow("Caventure",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        SCREEN_WIDTH,
        SCREEN_HEIGHT,
        SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
    if (Global.Window == NULL)
    {
        throw(::std::runtime_error("Window failed to initialise! ERROR: "));
    }
    Global.ScreenSurface = SDL_GetWindowSurface(Global.Window);
    if (Global.ScreenSurface == NULL)
    {
        throw(::std::runtime_error("Surface failed to initialise! ERROR: "));
    }
    Global.Renderer = SDL_CreateRenderer(Global.Window, -1, 0);
    if (Global.Renderer == NULL)
    {
        throw(::std::runtime_error("Renderer could not be initialised! ERROR: "));
    }
    if (TTF_Init() > 0)
    {
        throw(::std::runtime_error("TTF could not be initialised! ERROR: "));
    }
}

void UpdateMedia(Graphics& Global)
{
    SDL_GetWindowSize(Global.Window, &Global.width, &Global.height);

    // Set geomtry dimensions, apart from rcTextInput.
    Global.rcGround = { 0, 0, Global.width, (Global.height / 3) * 2 };
    Global.rcTextOutput = { 0, (Global.height / 3) * 2, Global.width, Global.height - 40 };
    Global.rcTextOutputGrd = { 0, (Global.height / 3) * 2, Global.width, Global.height - 40 };

    Global.SpriteDefaultX = Global.width / 2;
    Global.SpriteDefaultY = Global.height / 2;
};

void LoadMedia(Graphics& Global)
{
    UpdateMedia(Global);

    Global.rcSprite = { Global.SpriteDefaultX, Global.SpriteDefaultY, 4, 4 };

    Global.Font = TTF_OpenFont("src/graphics/resources/notomono-regular.ttf", 14);
    if (Global.Font == NULL)
    {
        throw(::std::runtime_error("Font failed to load! ERROR: "));
    }

    SDL_SetTextInputRect(&Global.rcTextInput);
}

void InputLoop(Graphics& Global, Event& Loop)
{
    if (Loop.event.type == SDL_QUIT)
    {
        Loop.bQuit = true;
    }
    else if (Loop.event.type == SDL_KEYDOWN)
    {
        // Sprite movement
        switch (Loop.event.key.keysym.sym)
        {
        case SDLK_UP:
            Global.rcSprite.y -= 5;
            break;

        case SDLK_DOWN:
            Global.rcSprite.y += 5;
            break;

        case SDLK_LEFT:
            Global.rcSprite.x -= 5;
            break;

        case SDLK_RIGHT:
            Global.rcSprite.x += 5;
            break;
        }

        // Backspace handler
        if (Loop.event.key.keysym.sym == SDLK_BACKSPACE && Loop.InputText.length() > 0)
        {
            Loop.InputText.pop_back();
            if (Loop.InputText.length() == 0)
            {
                Loop.InputText = " ";
            }
        }

        // Creates new line of text
        else if (Loop.event.key.keysym.sym == SDLK_RETURN && Loop.InputText.length() != 0 && Loop.InputText != " ")
        {
            Global.Menu.NewBox(Loop.InputText);
            Loop.bRenderText = true;
            Loop.InputText = " ";
        }
    }
    else if (Loop.event.type == SDL_TEXTINPUT)
    {
        Loop.InputText += Loop.event.text.text;
    }
}

void RenderLoop(Graphics& Global, Event& Loop)
{
    UpdateMedia(Global);

    // Renders sprite movement
    if (Global.rcSprite.x < 0 || Global.rcSprite.y < 0 || Global.rcSprite.y > Global.rcGround.h || Global.rcSprite.x > Global.rcGround.w)
    {
        Global.rcSprite.x = Global.SpriteDefaultX;
        Global.rcSprite.y = Global.SpriteDefaultY;
    }

    // Sets background to black
    SDL_SetRenderDrawColor(Global.Renderer, 0x00, 0x00, 0x00, 0x00);
    SDL_RenderClear(Global.Renderer);

    // Renders background of sprite to black
    SDL_RenderFillRect(Global.Renderer, &Global.rcGround);
    SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcGround);

    // Renders background of text box to grey
    SDL_SetRenderDrawColor(Global.Renderer, 0x40, 0x40, 0x40, 0x40);
    SDL_RenderFillRect(Global.Renderer, &Global.rcTextOutputGrd);
    SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcTextOutputGrd);

    SDL_SetRenderDrawColor(Global.Renderer, 0x00, 0x00, 0x00, 0x00);
    // Renders text input
    Global.TextInput.Render(Global.Renderer, Global.Font, Loop.InputText.c_str(), Global.TextColor);
    Global.rcTextInput = { 0, Global.height - 20, Global.TextInput.GetWidth(), Global.TextInput.GetHeight() };
    SDL_RenderCopy(Global.Renderer, Global.TextInput.GetTexture(), NULL, &Global.rcTextInput);

    // Renders text output
    if (Loop.bRenderText)
    {
        Global.Menu.Update(Global.Renderer, Global.Font, Global.TextColor, Global.rcTextOutput);
    }
    SDL_RenderSetClipRect(Global.Renderer, NULL);

    // Renders text box background edges white
    SDL_SetRenderDrawColor(Global.Renderer, 0xFF, 0xFF, 0xFF, 0xFF);
    SDL_RenderDrawLine(Global.Renderer, 0, (Global.height / 3) * 2, Global.width, (Global.height / 3) * 2);
    SDL_RenderDrawLine(Global.Renderer, 0, Global.height - 20, Global.width, Global.height - 20);

    // Renders sprite
    SDL_RenderFillRect(Global.Renderer, &Global.rcSprite);
    SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcSprite);

    // Presents render
    SDL_RenderPresent(Global.Renderer);
}

void Quit(Graphics& Global)
{
    // Deallocate memory
    SDL_DestroyWindow(Global.Window);
    SDL_DestroyRenderer(Global.Renderer);
    TTF_CloseFont(Global.Font);
    Global.Window = NULL;
    Global.Renderer = NULL;
    Global.Font = NULL;

    // Quit SDL subsystems
    TTF_Quit();
    SDL_Quit();
}

int main(int argc, char *argv[])
{
    try
    {
        Init(Global);
        LoadMedia(Global);
        SDL_StartTextInput();
        while (!Loop.bQuit)
        {
            while (SDL_PollEvent(&Loop.event) != 0)
            {
                InputLoop(Global, Loop);
                RenderLoop(Global, Loop);
            }
        }
        SDL_StopTextInput();
    }
    catch (std::runtime_error const& msg)
    {
        printf("%s", msg.what());
        if (SDL_GetError() != NULL)
        {
            printf("%s", SDL_GetError());
        }
        else if (TTF_GetError() != NULL)
        {
            printf("%s", TTF_GetError());
        }
        else
        {
            printf("%s", "NULL");
        }
        Quit(Global);
        return EXIT_FAILURE;
    }
    Quit(Global);
    return EXIT_SUCCESS;
}

Upvotes: 0

Views: 92

Answers (3)

Exercise To The Reader
Exercise To The Reader

Reputation: 617

I inserted SDL_Log() after every successful initialisation to find the error. I used to monitor the log.

It turned out that

Global.Font = TTF_OpenFont("src/graphics/resources/notomono-regular.ttf", 14);

was faulty.

Replacing it with a simple

Global.Font = TTF_OpenFont("notomono-regular.ttf", 14);

corrected the error.

Upvotes: 1

Dietrich Epp
Dietrich Epp

Reputation: 213298

When an error occurs, the program

  1. Prints a message to the console, but there is no console, so the message goes nowhere, then

  2. Immediately quits so that even if there were a console, it disappear in a flash.

If you want to actually report an error from a GUI Windows program, you have to wait around long enough for the user to see the error. With SDL, the SDL_ShowSimpleMessageBox is a good choice for doing that.

Upvotes: 1

Arafangion
Arafangion

Reputation: 11910

Four suggestions:

  1. Check the windows event log.
  2. Run it in a debugger.
  3. Start it from the windows command line.
  4. Add logging.

Upvotes: 1

Related Questions