Search code examples
cwindowswinapivisual-c++d

Same _exact_ code in C and D give different results -- why?


When I run this C code:

// Get rid of the CRT and stuff; we don't need it
#pragma comment(linker, "/Entry:mainCRTStartup")
#pragma comment(linker, "/NoDefaultLib:msvcrt.lib")
#pragma comment(linker, "/NoDefaultLib:kernel32.lib")
#pragma comment(linker, "/NoDefaultLib:ntdll.lib")
#pragma comment(linker, "/Subsystem:Console")

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

#include <windows.h>

int mainCRTStartup()
{
    MSG msg;
    HWND hWndParent;
    WNDCLASS wndClass =
    {
        0, &DefWindowProc, 0, 0, NULL, NULL, LoadCursor(NULL, IDC_ARROW),
        GetSysColorBrush(COLOR_3DFACE), NULL, TEXT("MyClass")
    };
    RegisterClass(&wndClass);
    hWndParent = CreateWindow(
        wndClass.lpszClassName, NULL, WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        0, 0, 33, 100, NULL, NULL, NULL, NULL);
    CreateWindow(TEXT("Button"), wndClass.lpszClassName,
        WS_VISIBLE | WS_CHILD | BS_GROUPBOX,
        5, 5, 100, 50, hWndParent, NULL, NULL, NULL);
    while (GetMessage(&msg, hWndParent, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

I get:

But when I run the equivalent D code:

// Again, get rid of the runtime
pragma(startaddress, mainCRTStartup);
pragma(lib, "dmd_win32.lib");

import win32.windows;

int mainCRTStartup()
{
    MSG msg;
    HWND hWndParent;
    WNDCLASS wndClass =
    {
        0, &DefWindowProc, 0, 0, NULL, NULL, LoadCursor(NULL, IDC_ARROW),
        GetSysColorBrush(COLOR_3DFACE), NULL, "MyClass"
    };
    RegisterClass(&wndClass);
    hWndParent = CreateWindow(
        wndClass.lpszClassName, NULL, WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        0, 0, 33, 100, NULL, NULL, NULL, NULL);
    CreateWindow("Button", wndClass.lpszClassName,
        WS_VISIBLE | WS_CHILD | BS_GROUPBOX,
        5, 5, 100, 50, hWndParent, NULL, NULL, NULL);
    while (GetMessage(&msg, hWndParent, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

I get:

I'm so confused... what can possibly be causing this white background?!

Edit:

I'm not sure it's actually a library bug... I just removed the dependency (and I don't see anything wrong with the code), but the problem is still there:

version = Unicode;
extern(Windows):
alias void* HWND, HMENU, HINSTANCE, HCURSOR, HBRUSH, HICON;
alias ushort ATOM, WORD;
alias uint UINT, DWORD;
alias int[2] POINT;
alias int BOOL;
alias int LONG;
alias size_t WPARAM, LPARAM, LRESULT;
alias char* LPSTR;
alias const(char)* LPCSTR;
alias wchar* LPWSTR;
alias const(wchar)* LPCWSTR;
version(Unicode)
{
    alias LPCWSTR LPCTSTR;
    alias LPWSTR LPTSTR;
    alias GetMessageW GetMessage;
    alias CreateWindowExW CreateWindowEx;
    alias DispatchMessageW DispatchMessage;
    alias DefWindowProcW DefWindowProc;
    alias LoadCursorW LoadCursor;
    alias RegisterClassW RegisterClass;
    alias WNDCLASSW WNDCLASS;
}
else
{
    alias LPCSTR LPCTSTR;
    alias LPSTR LPTSTR;
    alias GetMessageA GetMessage;
    alias CreateWindowExA CreateWindowEx;
    alias DispatchMessageA DispatchMessage;
    alias DefWindowProcA DefWindowProc;
    alias LoadCursorA LoadCursor;
    alias RegisterClassA RegisterClass;
    alias WNDCLASSA WNDCLASS;
}
LPCTSTR MAKEINTATOM(ATOM atom) { return cast(LPCTSTR)atom; }
ATOM RegisterClassA(WNDCLASSA*);
ATOM RegisterClassW(WNDCLASSW*);
HCURSOR LoadCursorA(HINSTANCE, LPCSTR);
HCURSOR LoadCursorW(HINSTANCE, LPCWSTR);
LRESULT DefWindowProcA(HWND, UINT, WPARAM, LPARAM);
LRESULT DefWindowProcW(HWND, UINT, WPARAM, LPARAM);
BOOL GetMessageA(const(MSG)*, HWND, UINT, UINT);
BOOL GetMessageW(const(MSG)*, HWND, UINT, UINT);
LONG DispatchMessageA(const(MSG)*);
LONG DispatchMessageW(const(MSG)*);
BOOL TranslateMessage(const(MSG)*);
HWND CreateWindowExA(int, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, void*);
HWND CreateWindowExW(int, LPCWSTR, LPCWSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, void*);
HBRUSH GetSysColorBrush(int);
alias LRESULT function(HWND, UINT, WPARAM, LPARAM) WNDPROC;
enum
{
    NULL = null,
    COLOR_3DFACE = 15,
    BS_GROUPBOX = 7,
}
const LPCTSTR IDC_ARROW = cast(LPCTSTR)32512;
struct MSG
{
    HWND hwnd;
    UINT message;
    WPARAM wParam;
    LPARAM lParam;
    DWORD  time;
    POINT  pt;
}
struct WNDCLASSA
{
    UINT      style;
    WNDPROC   lpfnWndProc;
    int       cbClsExtra;
    int       cbWndExtra;
    HINSTANCE hInstance;
    HICON     hIcon;
    HCURSOR   hCursor;
    HBRUSH    hbrBackground;
    LPCSTR   lpszMenuName;
    LPCSTR   lpszClassName;
}
struct WNDCLASSW
{
    UINT      style;
    WNDPROC   lpfnWndProc;
    int       cbClsExtra;
    int       cbWndExtra;
    HINSTANCE hInstance;
    HICON     hIcon;
    HCURSOR   hCursor;
    HBRUSH    hbrBackground;
    LPCWSTR   lpszMenuName;
    LPCWSTR   lpszClassName;
}
enum
{
    WS_OVERLAPPED       = 0,
    WS_TILED            = WS_OVERLAPPED,
    WS_MAXIMIZEBOX      = 0x00010000,
    WS_MINIMIZEBOX      = 0x00020000,
    WS_TABSTOP          = 0x00010000,
    WS_GROUP            = 0x00020000,
    WS_THICKFRAME       = 0x00040000,
    WS_SIZEBOX          = WS_THICKFRAME,
    WS_SYSMENU          = 0x00080000,
    WS_HSCROLL          = 0x00100000,
    WS_VSCROLL          = 0x00200000,
    WS_DLGFRAME         = 0x00400000,
    WS_BORDER           = 0x00800000,
    WS_CAPTION          = 0x00c00000,
    WS_OVERLAPPEDWINDOW = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
    WS_TILEDWINDOW      = WS_OVERLAPPEDWINDOW,
    WS_MAXIMIZE         = 0x01000000,
    WS_CLIPCHILDREN     = 0x02000000,
    WS_CLIPSIBLINGS     = 0x04000000,
    WS_DISABLED         = 0x08000000,
    WS_VISIBLE          = 0x10000000,
    WS_MINIMIZE         = 0x20000000,
    WS_ICONIC           = WS_MINIMIZE,
    WS_CHILD            = 0x40000000,
    WS_CHILDWINDOW      = 0x40000000,
    WS_POPUP            = 0x80000000,
    WS_POPUPWINDOW      = WS_POPUP|WS_BORDER|WS_SYSMENU,
}

pragma(startaddress, mainCRTStartup);

int mainCRTStartup()
{
    MSG msg;
    HWND hWndParent;
    WNDCLASS wndClass =
    {
        0, &DefWindowProc, 0, 0, NULL, NULL, LoadCursor(NULL, IDC_ARROW),
        GetSysColorBrush(COLOR_3DFACE), NULL, "MyClass"
    };
    ATOM atom = RegisterClass(&wndClass);
    hWndParent = CreateWindowEx(
        0, wndClass.lpszClassName, NULL, WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        0, 0, 33, 100, NULL, NULL, NULL, NULL);
    CreateWindowEx(0, "Button", wndClass.lpszClassName,
        WS_VISIBLE | WS_CHILD | BS_GROUPBOX,
        5, 5, 100, 50, hWndParent, NULL, NULL, NULL);
    while (GetMessage(&msg, hWndParent, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

Either I'm doing something wrong, or it's a compiler bug... but even if it's a compiler bug, I still have no idea how something like this can happen, because it would need to call very specific APIs! Ideas?


Solution

  • This is subsystem version issue (linker responsibility). Add -L/SUBSYSTEM:CONSOLE:4.0 to dmd command line to fix MyClass background color. Walter likes old systems so default OPTLINK subsystem version is 3.10. Looks like Microsoft's link 9.0 use 5.0 as default subsystem version.