Incorrect alignment when using HDC from zigwin32 in calls to OpenGL

I’m facing an alignment issue when dealing with two different external C functions. I have a working Windows application using zigwin32 to call the Windows API. Now I am trying to introduce OpenGL but the HDC I get from zigwin32 doesn’t work with the opengl functions that I get from importing GL/gl.h.

I have tried simply using @ptrCast(@alignCast()) but that gives an incorrect alignment panic about 90% of times, but sometimes the alignments happens to match and I get the opengl context setup, and it then outputs the color I ask for via glClearColor. So I know that the code works in general.

I have also tried to use std.mem.alignForward, and that does solve the incorrect alignment panic. Unfortunately opengl gives me error 6 (ERROR_INVALID_HANDLE) in that case. This doesn’t surprise me since the HDC returned by GetDC is already on an invalid address, so alignForward just gives me the closest valid address, it doesn’t change where the DC actually is. I tried using align(1), but it doesn’t seem to be possible without editing zigwin32 or the autogenerated code I get from @cImport.

What could I do to resolve the incorrect alignment?

Error

src\win32_handmade.zig:1208:63: error: expected type '[*c]cimport.struct_HDC__', found '*win32.graphics.gdi.HDC__opaque_36346'
    const suggested_pixel_format_index = gl.ChoosePixelFormat(dc, &desired_pixel_format);

zigwin32 HDC:

pub const HDC = *opaque{};

opengl HDC:

pub const struct_HDC__ = extern struct {
    unused: c_int = @import("std").mem.zeroes(c_int),
};
pub const HDC = [*c]struct_HDC__;

build.zig

const zigwin32 = b.dependency("zigwin32", .{}).module("zigwin32");
exe.root_module.addImport("win32", zigwin32);
exe.linkSystemLibrary("opengl32");

win32_handmade.zig

const win32 = struct {
    usingnamespace @import("win32").graphics.gdi;
};

const gl = @cImport({
    @cInclude("GL/gl.h");
});

fn initOpenGL(window: win32.HWND) void {
    const dc: win32.HDC = win32.GetDC(window).?;
    var desired_pixel_format: gl.PIXELFORMATDESCRIPTOR = .{
        .nSize = @sizeOf(gl.PIXELFORMATDESCRIPTOR),
        .nVersion = 1,
        .iPixelType = gl.PFD_TYPE_RGBA,
        .dwFlags = gl.PFD_SUPPORT_OPENGL | gl.PFD_DRAW_TO_WINDOW | gl.PFD_DOUBLEBUFFER,
        .cColorBits = 32,
        .cAlphaBits = 8,
        .iLayerType = gl.PFD_MAIN_PLANE,
    };

    const suggested_pixel_format_index = gl.ChoosePixelFormat(dc, &desired_pixel_format);
    // ...

Hello @codegasm welcome to ziggit :slight_smile:

zigwin32 includes opengl wrappers in win32/graphics/open_gl.zig

const gl = @import("win32").graphics.open_gl;
1 Like

The panic is coming from Zig, not from the OS or OpenGL.
Microsoft declares theses types as pointers, but they aren’t, they are handles. You’re not supposed to touch them, you receive them from API calls and you pass them along to other API calls, untouched. This is why aligning it wouldn’t work. However, because they are declared as pointers, Zig is doing its runtime checks, and detects that they don’t look like pointers. In essence, this happens because Microsoft abused the type system.
You can turn off Zig’s runtime checks locally with @setRuntimeSafety or you can change the definition of the functions to take a *anyopaque.

I had missed that there was an opengl section in zigwin32, thanks!

Thanks for the explanation @LucasSantos91, that definitely helps me better understand what was happening. So one solution would be to define any functions that I need using extern and use *anyopaque instead of the auto-generated types that I got from @cImport?

1 Like

Yes, this is usually the better option, although more laborious.

1 Like