News:

Download Pelles C here: http://www.pellesc.se

Main Menu

Recent posts

#21
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by rweidner - March 06, 2026, 08:48:41 PM
Quote from: TimoVJL on March 04, 2026, 05:19:10 PMThose libraries needs a RAD environment too to survive.
Just think what happened to Borland RADs.

Small programs are easy to develop with basic Win32 GUI.

Hi TimoVJL,

I agree with you - libraries tend to survive longer when they have a good RAD story around them, and Win32 GUI work can still be very productive with the right tools.

For context on why I am writing this raylib + PellesC tutorial: I am actively working on a 2D game in C using raylib right now. Once I finish it, I plan to do a couple of ports:

* Port 1: GDI + Win32 API (including input and sound)
* Port 2: Direct2D + Win32 API

Those ports are mostly for me: they are a learning project, and also an excuse to explore and document programming techniques. I enjoy writing tutorials, so I am trying to capture the "gotchas" and the practical setup steps as I find them.

Thanks again for chiming in on the thread.

Ronald
#22
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by rapte - March 06, 2026, 04:28:21 PM
Thanks for the explanation :)
#23
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by rweidner - March 06, 2026, 03:25:21 PM
The problem is that in C23 bool is a keyword.  What's happening here in the raylib.h on line 210 is:

// Boolean type
#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
    #include <stdbool.h>
#elif !defined(__cplusplus) && !defined(bool)
    typedef enum bool { false = 0, true = !false } bool;
    #define RL_BOOL_TYPE
#endif

The developer is trying to define bool. There are fixes for this. The primary one is to fix the header and submit a pull request to the raylib project. But, I didn't go that route, yet. Instead, I changed to C17 and kept moving.
#24
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by rapte - March 06, 2026, 02:27:50 PM
Thank you rweidner and Vortex for the detailed steps and examples on how to get raylib working with Pelles C.

I got the example working for both 32-bit and 64-bit and it works with c99, c11 and c17, but gives the following error with c23

Building main.obj.
C:\SDK\raylib-5.5\include\raylib.h(210): warning #2090: Missing enum tag.
C:\SDK\raylib-5.5\include\raylib.h(210): error #2002: Invalid combination of 'enum' and 'bool'.
C:\SDK\raylib-5.5\include\raylib.h(210): warning #2014: Empty declaration.
C:\SDK\raylib-5.5\include\raylib.h(210): error #2001: Syntax error: expected ';' but found '{'.
C:\SDK\raylib-5.5\include\raylib.h(210): error #2156: Unrecognized declaration.
C:\SDK\raylib-5.5\include\raylib.h(210): warning #2014: Empty declaration.

#25
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by Vortex - March 05, 2026, 08:15:27 PM
Thanks, I managed to build the project without game_main.h  Here is a modified version :

Main project file :

#pragma comment(lib, "raylibdll.lib")

extern void raylibProc(void);

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    raylibProc();
    return 0;
}

Second module :

#include "raylib.h"

void raylibProc(void)
{
SetTraceLogLevel(LOG_NONE);
    InitWindow(800, 450, "raylib hello");
    SetTargetFPS(60);

    while (!WindowShouldClose())
    {
        BeginDrawing();
        ClearBackground(RAYWHITE);
        DrawText("Hello, raylib!", 190, 200, 40, BLACK);
        EndDrawing();
    }

    CloseWindow();
}

Default calling Convention : __cdecl
#26
Graphics programming / A GDI Double Buffered Example
Last post by rweidner - March 05, 2026, 05:04:36 AM
A GDI Double-Buffered Example (Pelles C)

Note: This is not meant to be a GDI32 programming tutorial. I am not an expert in GDI32 (yet), so I probably should not try to write a tutorial on it right now. :)

Instead, this is a one-file example intended to show a working GDI double-buffered program in Pelles C v13.00.9. It may also be useful to some people as a small foundation for GDI32 experiments.

Prereq (how I tested it)

I used the Windows SDK on my machine.

If you already have it installed, it is usually somewhere under:

C:\Program Files (x86)\Windows Kits

The one I am using specifically is here:

 C:\Program Files (x86)\Windows Kits\10\Lib\10.0.26100.0\um\x86  (libs)
 C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um  (headers/includes)

If you do not have the Windows SDK, start here:

https://learn.microsoft.com/en-us/windows/apps/windows-sdk/

Side note: If you have Visual Studio / Build Tools installed, the Windows SDK may already be installed with it.


To compile in Pelles C

1. Create a new Win32 GUI Project (this example uses WinMain, not main)
2. Open Project -> Project Options
3. Click General -> Folders
4. Notice the drop-down menu that probably says Libraries
5. Add the path to the SDK library folder (under Windows Kits)
6. Change the drop-down menu to Includes
7. Add the path to the SDK include folder (under Windows Kits)
8. Create main.c
9. Paste the code below

Code (main.c)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

static const char g_szClassName[] = "WinGdiHelloBackbufferedClass";

static int   g_running = 1;
static HFONT g_font = NULL;

/* Backbuffer objects */
static HDC     g_backDC = NULL;
static HBITMAP g_backBmp = NULL;
static HBITMAP g_backOldBmp = NULL;
static int     g_backW = 0;
static int     g_backH = 0;

static void DestroyBackbuffer(void)
{
    if (g_backDC)
    {
        if (g_backOldBmp)
        {
            SelectObject(g_backDC, g_backOldBmp);
            g_backOldBmp = NULL;
        }

        if (g_backBmp)
        {
            DeleteObject(g_backBmp);
            g_backBmp = NULL;
        }

        DeleteDC(g_backDC);
        g_backDC = NULL;
    }

    g_backW = 0;
    g_backH = 0;
}

static int EnsureBackbuffer(HWND hwnd, int w, int h)
{
    HDC hdcWindow;
    HBITMAP newBmp;

    if (w <= 0 || h <= 0)
        return 0;

    if (g_backDC && g_backBmp && g_backW == w && g_backH == h)
        return 1;

    DestroyBackbuffer();

    hdcWindow = GetDC(hwnd);
    if (!hdcWindow)
        return 0;

    g_backDC = CreateCompatibleDC(hdcWindow);
    if (!g_backDC)
    {
        ReleaseDC(hwnd, hdcWindow);
        return 0;
    }

    newBmp = CreateCompatibleBitmap(hdcWindow, w, h);
    ReleaseDC(hwnd, hdcWindow);

    if (!newBmp)
    {
        DeleteDC(g_backDC);
        g_backDC = NULL;
        return 0;
    }

    g_backBmp = newBmp;
    g_backOldBmp = (HBITMAP)SelectObject(g_backDC, g_backBmp);
    g_backW = w;
    g_backH = h;

    return 1;
}

static void RenderSceneToBackbuffer(HWND hwnd)
{
    RECT rc;
    RECT textRc;
    HBRUSH whiteBrush;

    GetClientRect(hwnd, &rc);

    if (!EnsureBackbuffer(hwnd, rc.right - rc.left, rc.bottom - rc.top))
        return;

    whiteBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
    FillRect(g_backDC, &rc, whiteBrush);

    SetBkMode(g_backDC, TRANSPARENT);
    SetTextColor(g_backDC, RGB(0, 0, 0));

    if (g_font)
        SelectObject(g_backDC, g_font);

    SetRect(&textRc, 190, 200, rc.right, rc.bottom);
    DrawTextA(g_backDC, "Hello, GDI Backbuffer!", -1, &textRc, DT_LEFT | DT_TOP | DT_SINGLELINE);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
        g_font = CreateFontA(
            -40, 0, 0, 0, FW_NORMAL,
            FALSE, FALSE, FALSE,
            ANSI_CHARSET, OUT_DEFAULT_PRECIS,
            CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
            DEFAULT_PITCH | FF_DONTCARE,
            "Arial"
        );
        return 0;

    case WM_SIZE:
    {
        int w = LOWORD(lParam);
        int h = HIWORD(lParam);
        EnsureBackbuffer(hwnd, w, h);
        return 0;
    }

    case WM_ERASEBKGND:
        /* We paint the full frame ourselves from a backbuffer. Prevent default erase flicker. */
        return 1;

    case WM_KEYDOWN:
        if (wParam == VK_ESCAPE)
        {
            DestroyWindow(hwnd);
            return 0;
        }
        break;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);

        RenderSceneToBackbuffer(hwnd);

        if (g_backDC && g_backBmp)
        {
            BitBlt(
                hdc,
                0, 0, g_backW, g_backH,
                g_backDC,
                0, 0,
                SRCCOPY
            );
        }

        EndPaint(hwnd, &ps);
        return 0;
    }

    case WM_DESTROY:
        DestroyBackbuffer();

        if (g_font)
        {
            DeleteObject(g_font);
            g_font = NULL;
        }

        g_running = 0;
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProcA(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSA wc;
    HWND hwnd;
    RECT wr;
    MSG msg;
    DWORD frameMs = 1000 / 60;
    DWORD lastTick = GetTickCount();

    (void)hPrevInstance;
    (void)lpCmdLine;

    ZeroMemory(&wc, sizeof(wc));
    wc.lpfnWndProc   = WndProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = g_szClassName;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL; /* no default brush; we fully repaint */

    if (!RegisterClassA(&wc))
        return 1;

    wr.left = 0;
    wr.top = 0;
    wr.right = 800;
    wr.bottom = 450;
    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);

    hwnd = CreateWindowExA(
        0,
        g_szClassName,
        "GDI backbuffer hello",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        wr.right - wr.left,
        wr.bottom - wr.top,
        NULL, NULL, hInstance, NULL
    );

    if (!hwnd)
        return 1;

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (g_running)
    {
        while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
            {
                g_running = 0;
                break;
            }
            TranslateMessage(&msg);
            DispatchMessageA(&msg);
        }

        if (!g_running)
            break;

        if ((GetTickCount() - lastTick) >= frameMs)
        {
            lastTick = GetTickCount();

            /* Trigger one frame render */
            InvalidateRect(hwnd, NULL, FALSE); /* FALSE: do not erase background */
            UpdateWindow(hwnd);
        }
        else
        {
            Sleep(1);
        }
    }

    return 0;
}

If I missed a Pelles C option/setting that matters, let me know and I will update this post.
#27
Bug reports / stdckdint.h bug report
Last post by ander_cc - March 05, 2026, 02:59:33 AM
Yesterday,I learn some c23 new features. Maybe there is a bug in stdckdint.h.

bool ckd_add( type1 *result, type2 a, type3 b );
bool ckd_sub( type1 *result, type2 a, type3 b );
bool ckd_mul( type1 *result, type2 a, type3 b );

Macros always return false. Pelles c 13.01. Windows 11 Simplified Chinese.

#include <stdio.h>
#include <stdckdint.h>
int main(void)
{
int a = 655350;
int b = 10;
short int c = 0;
//int c = 0;
bool result = true;
result = ckd_mul(&c, a, b); // ckd_add(&c, a, b); ckd_sub(&c, a, b);
if (result == true) {
puts("true\n");
}else{
puts("false\n");
}
printf("c = %d\n", c);
return 0;
}
#28
General discussion / Re: Compiling using pomake
Last post by rweidner - March 05, 2026, 02:48:18 AM
It took me a long minute to understand what you're building. You're building a replacement process for managing projects and project configuration. You're doing so with the intention of making the whole process less manual, scriptable, and easier to control. If I understand what you're doing, brilliant.
#29
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by rweidner - March 05, 2026, 01:23:24 AM
Here is a solution, possibly. There are 2 "tricks" to making this work.

1. Never include windows.h in the same file where raylib.h is included also.  The example below demonstrates.

2. Project -> Project Options.  Under Compiler click Code generation. Change "Default calling Convention" to __cdecl

Now I'm building an Win32 app.  Notice in the code there isn't a int main(void) function.  Does this help?


//File: game_main.h
#ifndef GAME_MAIN_H
#define GAME_MAIN_H

int GameMain(void);
#endif
//File: main.c
#include "game_main.h"
#include <windows.h>
// Do not include raylib.h because windows.h is included.

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    return GameMain();
}
// File: game_main.c
#include "game_main.h"
#include "raylib.h"
// Do not include windows.h because raylib.h is included.

int GameMain(void)
{
    InitWindow(800, 450, "raylib hello");
    SetTargetFPS(60);

    while (!WindowShouldClose())
    {
        BeginDrawing();
        ClearBackground(RAYWHITE);
        DrawText("Hello, raylib!", 190, 200, 40, BLACK);
        EndDrawing();
    }

    CloseWindow();
    return 0;
}
#30
General discussion / Re: Compiling using pomake
Last post by John Z - March 04, 2026, 09:59:42 PM
Useful to be sure.  Attached it an example output .bat file from the BBBBuilder.DLL.  It built a bat file that builds itself (builds the dll that is).  It does not use pomake but uses pocc, poasm, porc, and polink.  It does not use the .prj file either.  One other possible use is to use the resulting  .bat file as a template to build using another compiler package.

Once the .bat is built the supporting file .lst files can be edited for example to add a new source file, then run the bat for a new executable.

Current limitations (working to resolve)
1) a file in the source list marked 'exclude' can't be determined as excluded (feature request submitted)
2) file names should preferably be ASCII, but ANSI might be ok too (cmd limitation)
3) sub directories with source files are not handled.  All sources must be in one directory.  This is probably the biggest issue to solve.  (fixed subdirs under the main project dir are automatically handled)

Also working on outputting a Powershell script to do the build. It is working up to polink. The polink use requires an @ preface which unfortunately is a Powershell special character . . . :(

John Z