Windows 尽管根目录中有正确的 DLL,但可执行文件无法启动

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

我的超简单2D游戏冒险依赖 and

编译后目录如下

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

我使用的是 Microsoft Visual Studio 2015。我一直在关注 Lazy Foo's tutorials on building with Windows,但即使按照这些步骤操作,它也不起作用。这是我所做的:

  1. 将编译器链接到 x64 中的包含和库目录。
  2. 链接库。
  3. 已将库复制到 C:\Windows\SysWOW64
  4. 包括<Windows.h>
  5. 使用兼容模式。
  6. 在 Visual Studio IDE 中对其进行了测试,包括调试器。

当我打开它时,它立即关闭,没有 return 任何错误。

这是主要的源文件:

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

四点建议:

  1. 检查 windows 事件日志。
  2. 运行 它在调试器中。
  3. 从 windows 命令行启动它。
  4. 添加日志记录。

发生错误时,程序

  1. 向控制台打印一条消息,但是没有控制台,所以消息无处可去,然后

  2. 立即退出,即使有控制台也瞬间消失

如果您想从 GUI Windows 程序实际报告错误,您必须等待足够长的时间让用户看到错误。对于 SDL,SDL_ShowSimpleMessageBox 是一个不错的选择。

我插入了SDL_Log() after every successful initialisation to find the error. I used 来监控日志

原来是

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

出错了。

将其替换为简单的

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

更正了错误。