You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过‘运行时导入’实现跨平台C++终端窗口大小获取函数

Runtime Import Approach for Cross-Platform Terminal Window Size Retrieval

Got it, let's switch your compile-time conditional checks to a runtime-based approach for getting terminal window sizes across Linux and Windows. Here's a clean, maintainable way to do this:

Core Idea

Instead of wrapping platform-specific code in #ifdef blocks, we'll:

  1. Isolate Linux and Windows logic into separate helper functions.
  2. Use runtime platform detection to pick the right implementation.
  3. For Windows, dynamically load the required kernel32.dll functions (true runtime import) instead of linking at compile time. For Linux, we can either use standard libc functions directly or go full runtime with dlopen/dlsym (I'll show both options).

Step-by-Step Implementation

1. Define Platform Detection & Function Types

First, add a simple way to detect the current platform at runtime (we use compile-time macros just to set a runtime flag, not to wrap logic):

// Adjust this to match your actual Vector class definition
class Vector {
public:
    int w;
    int h;
};

enum class Platform {
    Linux,
    Windows,
    Unknown
};

Platform getCurrentPlatform() {
#ifdef __linux__
    return Platform::Linux;
#elif _WIN32 || _WIN64
    return Platform::Windows;
#else
    return Platform::Unknown;
#endif
}

// Function pointer type for our platform-specific size getters
using GetWindowSizeFunc = bool(*)(Vector&);

2. Linux Implementation

Option 1: Direct use of libc functions (simpler, still avoids compile-time logic blocks):

#include <sys/ioctl.h>
#include <unistd.h>

bool getLinuxWindowSize(Vector& windowsize) {
    struct winsize window;
    // Check if ioctl succeeds (system calls don't throw C++ exceptions, so try/catch was unnecessary)
    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &window) == -1) {
        return false;
    }
    windowsize.w = window.ws_col;
    windowsize.h = window.ws_row;
    return true;
}

Option 2: Full runtime import with dlopen (strict runtime loading of libc functions):

#include <dlfcn.h>

bool getLinuxWindowSize(Vector& windowsize) {
    void* libcHandle = dlopen("libc.so.6", RTLD_LAZY);
    if (!libcHandle) {
        return false;
    }

    // Get pointer to ioctl function
    using ioctlFunc = int(*)(int, unsigned long, ...);
    ioctlFunc pIoctl = reinterpret_cast<ioctlFunc>(dlsym(libcHandle, "ioctl"));

    if (!pIoctl) {
        dlclose(libcHandle);
        return false;
    }

    struct winsize window;
    if (pIoctl(STDOUT_FILENO, TIOCGWINSZ, &window) == -1) {
        dlclose(libcHandle);
        return false;
    }

    windowsize.w = window.ws_col;
    windowsize.h = window.ws_row;
    dlclose(libcHandle);
    return true;
}

3. Windows Implementation (True Runtime Import)

We'll dynamically load kernel32.dll and fetch the required functions at runtime instead of linking at compile time:

// Minimal type definitions to avoid global windows.h inclusion
typedef void* HMODULE;
typedef void* HANDLE;
typedef unsigned long DWORD;
typedef long BOOL;

typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
    struct { short Left, Top, Right, Bottom; } srWindow;
} CONSOLE_SCREEN_BUFFER_INFO;

// Helper to get GetProcAddress without linking kernel32
extern "C" void* GetProcAddress(void*, const char*);

bool getWindowsWindowSize(Vector& windowsize) {
    // Load kernel32.dll at runtime
    HMODULE kernel32Handle = reinterpret_cast<HMODULE>(
        reinterpret_cast<void*(*)(const char*)>(
            GetProcAddress(reinterpret_cast<HMODULE>(-1), "LoadLibraryA")
        )("kernel32.dll")
    );
    if (!kernel32Handle) {
        return false;
    }

    // Get pointers to required functions
    using GetStdHandleFunc = HANDLE(*)(DWORD);
    GetStdHandleFunc pGetStdHandle = reinterpret_cast<GetStdHandleFunc>(
        GetProcAddress(kernel32Handle, "GetStdHandle")
    );

    using GetConsoleScreenBufferInfoFunc = BOOL(*)(HANDLE, CONSOLE_SCREEN_BUFFER_INFO*);
    GetConsoleScreenBufferInfoFunc pGetConsoleScreenBufferInfo = reinterpret_cast<GetConsoleScreenBufferInfoFunc>(
        GetProcAddress(kernel32Handle, "GetConsoleScreenBufferInfo")
    );

    using FreeLibraryFunc = BOOL(*)(HMODULE);
    FreeLibraryFunc pFreeLibrary = reinterpret_cast<FreeLibraryFunc>(
        GetProcAddress(kernel32Handle, "FreeLibrary")
    );

    if (!pGetStdHandle || !pGetConsoleScreenBufferInfo || !pFreeLibrary) {
        pFreeLibrary(kernel32Handle);
        return false;
    }

    // Retrieve window size
    const DWORD STD_OUTPUT_HANDLE = static_cast<DWORD>(-11);
    HANDLE stdoutHandle = pGetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;

    if (!pGetConsoleScreenBufferInfo(stdoutHandle, &csbi)) {
        pFreeLibrary(kernel32Handle);
        return false;
    }

    windowsize.w = csbi.srWindow.Right - csbi.srWindow.Left + 1;
    windowsize.h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;

    pFreeLibrary(kernel32Handle);
    return true;
}

4. Update Your DisplayManager Method

Now, wire everything together in your main function, with zero compile-time platform logic blocks:

class DisplayManager {
private:
    Vector windowSize;
public:
    bool getWindowSize();
};

bool DisplayManager::getWindowSize() {
    Vector windowsize;
    Platform currentPlatform = getCurrentPlatform();

    GetWindowSizeFunc sizeGetter = nullptr;
    switch (currentPlatform) {
        case Platform::Linux:
            sizeGetter = getLinuxWindowSize;
            break;
        case Platform::Windows:
            sizeGetter = getWindowsWindowSize;
            break;
        default:
            return false;
    }

    if (sizeGetter && sizeGetter(windowsize)) {
        // Assign the retrieved size to your class member
        this->windowSize = windowsize;
        return true;
    }
    return false;
}

Key Notes

  • No Compile-Time Logic Blocks: The only #ifdef usage is for setting a runtime platform flag, not wrapping core functionality.
  • True Runtime Import: Windows functions are loaded dynamically at runtime, no compile-time linking to kernel32.lib required.
  • Error Handling: We check all function loads and system calls for failures, replacing the unnecessary try/catch blocks (system calls don't throw C++ exceptions by default).

内容的提问来源于stack exchange,提问作者anon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:55:39