News:

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

Main Menu

Recent posts

#91
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.
#92
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;
}
#93
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.
#94
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;
}
#95
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

#96
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by Vortex - March 04, 2026, 09:54:25 PM
Hi rweidner,

The reason is simple. If you wish to build a "standard" GUI application, you need the specify the WinMain function instead of main :

#include "raylib.h"

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    InitWindow(800, 450, "raylib hello");
    SetTargetFPS(60);

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

    CloseWindow();
    return 0;
}

Here are some links for you to check the issue :

https://github.com/raysan5/raylib/issues/2806

https://github.com/raysan5/raylib/issues/1217

https://raylib.handmade.network/forums/t/7294-raylib_and_winmain

https://www.reddit.com/r/raylib/comments/vnnha0/how_do_i_prevent_the_console_from_opening_on_all/

https://keasigmadelta.com/blog/raylib-hide-the-console-window-on-windows-release-builds/?srsltid=AfmBOorcOL85hkGTczvcJKJe9SH9kLlUMKWtaLq7DNnO2Z6Wjoq5O3ms
#97
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by rweidner - March 04, 2026, 09:23:43 PM
Wow, Vortex. That is an interesting problem. I'll look at this more closely. I might have run into this too, sooner or later. What's interesting is that if you look at the raylib.h file on lines 1323, 1475, 1476, and 1649, raylib didn't define LoadImageA, DrawTextA, DrawTextExA, or PlaySoundA. This smells like some macro voodoo to me.

Question: For whatever reason it was that you included windows.h is it necessary that windows.h is included in the same file as raylib.h? Would a separate .c file help so that raylib.h and windows.h are not included in the same file?
#98
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by Vortex - March 04, 2026, 08:13:59 PM
Hello rweidner,

Thanks for the sample, I managed to build it. The problem is the serious name conflicts if one needs to use the master Windows header file windows.h :

Building raylibDemo.obj.
E:\PellesC\raylibDemo\raylib.h(260): error #2119: Redeclaration of 'Rectangle', previously declared at E:\PellesC\Include\Win\wingdi.h(3938).
E:\PellesC\raylibDemo\raylib.h(969): error #2119: Redeclaration of 'CloseWindow', previously declared at E:\PellesC\Include\Win\winuser.h(3561).
E:\PellesC\raylibDemo\raylib.h(1019): error #2119: Redeclaration of 'ShowCursor', previously declared at E:\PellesC\Include\Win\winuser.h(6875).
E:\PellesC\raylibDemo\raylib.h(1323): error #2119: Redeclaration of 'LoadImageA', previously declared at E:\PellesC\Include\Win\winuser.h(7950).
E:\PellesC\raylibDemo\raylib.h(1474): error #2119: Redeclaration of 'DrawTextA', previously declared at E:\PellesC\Include\Win\winuser.h(6099).
E:\PellesC\raylibDemo\raylib.h(1475): error #2119: Redeclaration of 'DrawTextExA', previously declared at E:\PellesC\Include\Win\winuser.h(6119).
E:\PellesC\raylibDemo\raylib.h(1649): error #2119: Redeclaration of 'PlaySoundA', previously declared at E:\PellesC\Include\Win\playsoundapi.h(64).
*** Error code: 1 ***
Done.
#99
Graphics programming / Re: raylib 5.5 + PellesC v13.0...
Last post by TimoVJL - March 04, 2026, 05:19:10 PM
Those 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.

TLPeView have a bit an experiment GUI, that many don't like it.
But with free source, people can make a basic GUI too or what ever they want.
Only internal functions are important, as those needs improvements.
Like resource section handling.

TLPEView is a just blackbox clone of Wayne J. Radburn excellent PEView for 32-bit files.
Wayne have full TLPEView sources how checking binary parsers was made for x64 too.
#100
Graphics programming / raylib 5.5 + PellesC v13.00.9 ...
Last post by rweidner - March 04, 2026, 06:24:32 AM
raylib 5.5 + PellesC v13.00.9 Tutorial
Hello World using precompiled raylib binaries (Windows, 32-bit)

What we are using in this tutorial (important)
For this tutorial, we are using this exact raylib package:
- `raylib-5.5_win32_msvc16.zip`

Notes:
- `5.5` = raylib version
- `win32` = 32-bit build
- `msvc16` = compiled with Microsoft Visual Studio toolchain
At the time this tutorial was written, this is the version/package tested for these steps.

Step 1 - Go to the raylib release page
Open the official raylib release page in your browser:
https://github.com/raysan5/raylib/releases

Find the release that contains this asset:
- `raylib-5.5_win32_msvc16.zip`

(For this tutorial, we are using the 5.5 release page.)
https://github.com/raysan5/raylib/releases/tag/5.5

Step 2 - Download the exact zip file
Download this file:
- `raylib-5.5_win32_msvc16.zip`

The file is listed near the bottom of the release page assets.
Note:
- Other precompiled packages/versions may also work.
- This tutorial was only tested with the package listed above.

Step 3 - Create a clean third-party folder (recommended)
If you do not already have a place to keep third-party DLLs/libs/headers, this works well:
- `C:\dev\3rdparty\raylib\`

For this tutorial, I assume this is where you put the files.

Step 4 - Extract the zip into a versioned folder
Extract `raylib-5.5_win32_msvc16.zip` into a versioned folder, for example:
- `C:\dev\3rdparty\raylib\raylib-5.5\`

Tip:
- Avoid accidental double nesting like:
  - `C:\dev\3rdparty\raylib\raylib-5.5\raylib-5.5\...`

Step 5 - Create a project in PellesC IDE
For this example, create a Win32 Console Program named `raylib_pellesc_hello` in:
- `C:\dev\`

Create a `main.c` file with the following contents:

#include "raylib.h"
int main(void)
{
    InitWindow(800, 450, "raylib hello");
    SetTargetFPS(60);

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

    CloseWindow();
    return 0;
}

Step 6 - Configure the project
Go to:
`Project -> Project Options`

Compiler
Click on `Compiler`:
* Change C Standard to `C17`
* Enable `Microsoft Extensions`
* Click on `Compiler -> Code Generation`
* Change Default Calling Convention to `__cdecl`

Folders
Click `General -> Folders`
Notice the dropdown next to `Type` (it may default to `Libraries`).

With `Type = Libraries`, add:
`C:\dev\3rdparty\raylib\raylib-5.5\lib`

Change dropdown to `Includes`, then add:
`C:\dev\3rdparty\raylib\raylib-5.5\include`

Linker
Click on `Linker`
Under `Library and object files`, include:
`kernel32.lib advapi32.lib delayimp.lib raylibdll.lib opengl32.lib gdi32.lib winmm.lib user32.lib shell32.lib`

Important:
Repeat Step 6 for each build target you plan to use (`Debug` / `Release`).

Step 7 - Build and Run
Build and run using PellesC.
- Copy the raylib.dll found in C:\dev\3rdparty\raylib\raylib-5.5\lib to the root of the project. The exe built by the compiler should reside next to the copied dll.
- `ESC` will close the program.

If everything is configured correctly, you should see a raylib window with:

`Hello, raylib!`

Common Problems with Solutions
Build works but program will not start):
Because this tutorial links against `raylibdll.lib`, you will also need `raylib.dll` available at runtime. Copy `raylib.dll` into the same folder as your compiled `.exe`

Several compile-time errors about the redeclaration of previously declared functions.
This guide was written for Win32 console-based programming. Your project is almost certainly configured as a Win32 GUI program. The problem is windows.h and raylib.h can't be included in the same file. These are two solutions:

Tried to compile but got errors about enums
This error can pop up:
C:\SDK\raylib-5.5\include\raylib.h(210): error #2002: Invalid combination of 'enum' and 'bool'.

The fastest solution is make sure you change the C Standard option of the compiler to `C17`. (See Step 6 above) Slightly more info here: https://forum.pellesc.de/index.php?msg=42018

Unresolved externals like _InitWindow@12
This is a calling convention mismatch.  Adjust the calling convention to __cdecl.  (See step 6 above.)

Final Note
Let me know if I missed anything and I will update the steps.