• simple 80 * 25

    From Paul Edwards@21:1/5 to All on Tue Jul 18 21:32:43 2023
    I remembered that a long time ago I wrote a very simple
    Win32 graphics program. I can't remember where I got
    the concepts from. I'm pretty sure this was before I was
    even on the internet.

    Original source is here:

    https://sourceforge.net/p/mvs380/mvssrc/ci/master/tree/ozpd/c/simpwin.c

    And I have made modifications (below) after consulting some
    online documentation.

    I was able to see that I got a stack of messages.

    However, if I press a key, I don't get a WM_CHAR message.

    And when I move the window, I don't get another WM_WINDOWPOSCHANGED message.

    Which suggests to me that there is something technically
    incorrect about my original simple program, even though
    it nominally works (ie if you don't inspect the messages
    that are being received and given to the default handler).

    So the first thing I'd like is for that bug to be fixed.

    It's a simple program. I'm not trying to win Miss America
    (any such competition can be done another day). But I
    do want it to be technically correct.

    I also want it to conform to Win32s 1.25 (the last version
    to be supported by OS/2) as well as Windows 11.

    After that I can see (via experimentation) that I am currently
    getting proportional fonts, when I actually want console
    fonts I believe. But any fixed width font will do (highest
    quality for 80 * 25 to help distinguish between B and 8).

    Note that when the keyboard is actually working, I will want
    a fullscreen window, not the default one that I am apparently
    getting now.

    Note that I am after simplicity, so if an application wants to
    print a single character, and my handler updates a 80 * 25
    buffer and repaints the entire screen - that's perfectly fine.
    If there is an alternative that is almost as simple and much
    more efficient, that's fine too.

    The goal is to get my 32-bit Win32 console back, on two
    environments where that is gone/difficult.

    Also I'm guessing that to position on the second row, I
    need to divide the number of pixels high (from WM_SIZE)
    by 25. And it would be convenient to do the same for
    width and use TextOut one character at a time. This would
    circumvent the problem of proportional fonts too, but
    perhaps not the best solution.

    Current code below.

    Thanks. Paul.



    /*********************************************************************/
    /* */
    /* This Program Written by Paul Edwards. */
    /* Released to the Public Domain */
    /* */ /*********************************************************************/ /*********************************************************************/
    /* */
    /* simpwin - the simplest windows program (roughly speaking) */
    /* */ /*********************************************************************/

    #include <stdio.h>

    #include <windows.h>

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam);

    int WINAPI WinMain(IN HINSTANCE inst,
    IN HINSTANCE previnst,
    IN LPSTR cmd,
    IN int cmdshow)
    {
    WNDCLASS wndClass = { 0, (WNDPROC)simpwin, 0, 0, 0, NULL, NULL,
    (HBRUSH)(COLOR_WINDOW+1), "simpwin", "simpwin" };
    HWND hwnd;
    MSG msg;

    (void)previnst;
    (void)cmd;
    wndClass.hInstance = inst;
    RegisterClass(&wndClass);
    hwnd = CreateWindow("simpwin", "Simple Windows",
    WS_SYSMENU,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, inst, NULL );
    ShowWindow(hwnd, cmdshow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
    }

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam)
    {
    int calldefault = 1;
    LONG ret = 0;

    switch (msg)
    {
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* DrawText(hdc, "Hello There", -1, &rect,
    DT_SINGLELINE | DT_CENTER | DT_VCENTER); */
    /* TextOut(hdc, 0, 0, "WWWW", 4); */
    /* TextOut(hdc, 1, 1, "IIII", 4); */
    EndPaint(hwnd, &ps);
    break;
    }
    case WM_DESTROY:
    PostQuitMessage(0);
    calldefault = 0;
    break;

    case WM_NCPAINT:
    case WM_GETICON:
    case WM_WINDOWPOSCHANGING:
    case WM_ACTIVATEAPP:
    case WM_NCACTIVATE:
    case WM_ACTIVATE:
    case WM_IME_NOTIFY:
    break;

    case WM_IME_SETCONTEXT:
    lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
    break;

    case WM_SETFOCUS:
    ret = 0;
    calldefault = 0;
    break;

    case WM_ERASEBKGND:
    /* not sure how to actually erase the background - print spaces? */
    ret = 1;
    calldefault = 0;
    break;

    case WM_WINDOWPOSCHANGED:
    {
    char buf[80];
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    static int cnt = 0;

    sprintf(buf, "%d %d %X %X\n",
    cnt++, (int)msg, (int)wparam, (int)lparam);
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    break;
    }
    /* lparam is WINDOWPOS and may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_SIZE:
    /* low 16 bits of lparam are width - in pixels it seems */
    /* high 16 bits are height */
    /* unclear why this message is being received in the first
    place when the documentation says if I handle WINDOWPOSCHANGED
    then these messages are not generated. Maybe what they mean
    is that the WM_SIZE will just be a once-off message */
    ret = 0;
    calldefault = 0;
    break;

    case WM_MOVE:
    /* low 16 bits of lparam are x-pos (start). high 16 bits are
    y-pos - same consideration as WM_SIZE */
    ret = 0;
    calldefault = 0;
    break;

    case WM_KEYDOWN:
    case WM_CHAR:
    default:
    {
    char buf[80];
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    sprintf(buf, "%d %X %X\n", (int)msg, (int)wparam, (int)lparam);
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* DrawText(hdc, "Hello There", -1, &rect,
    DT_SINGLELINE | DT_CENTER | DT_VCENTER); */
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    break;
    }
    }
    if (calldefault)
    {
    ret = DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return (ret);
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to Paul Edwards on Wed Jul 19 17:07:55 2023
    On Tue, 18 Jul 2023 21:32:43 -0700 (PDT), Paul Edwards wrote:
    I remembered that a long time ago I wrote a very simple
    Win32 graphics program. I can't remember where I got
    the concepts from. I'm pretty sure this was before I was
    even on the internet.

    Original source is here:

    https://sourceforge.net/p/mvs380/mvssrc/ci/master/tree/ozpd/c/simpwin.c

    And I have made modifications (below) after consulting some
    online documentation.

    I was able to see that I got a stack of messages.

    However, if I press a key, I don't get a WM_CHAR message.

    And when I move the window, I don't get another WM_WINDOWPOSCHANGED message.

    It's because there are more than one code which writes text at the same
    window client position - overwriting each other's text. So you only see the last written one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to All on Wed Jul 19 05:11:34 2023
    On Wednesday, July 19, 2023 at 6:07:59 PM UTC+8, JJ wrote:

    And when I move the window, I don't get another WM_WINDOWPOSCHANGED message.

    It's because there are more than one code which writes text at the same window client position - overwriting each other's text. So you only see the last written one.

    Thanks. I had a static counter, but it turned out that I was
    indeed missing some messages. So I have added those,
    but I'm still back at the same spot.

    I'm getting PPP 1 0 ... printed, and when I move the window,
    that doesn't change. Nor do keypresses get through.

    The 0 means that there are no messages that haven't
    been handled.

    The 1 means that poschanged is only called once.

    Any ideas?

    Thanks. Paul.


    /*********************************************************************/
    /* */
    /* This Program Written by Paul Edwards. */
    /* Released to the Public Domain */
    /* */ /*********************************************************************/ /*********************************************************************/
    /* */
    /* simpwin - the simplest windows program (roughly speaking) */
    /* */ /*********************************************************************/

    #include <stdio.h>

    #include <windows.h>

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam);

    int WINAPI WinMain(IN HINSTANCE inst,
    IN HINSTANCE previnst,
    IN LPSTR cmd,
    IN int cmdshow)
    {
    WNDCLASS wndClass = { 0, (WNDPROC)simpwin, 0, 0, 0, NULL, NULL,
    (HBRUSH)(COLOR_WINDOW+1), "simpwin", "simpwin" };
    HWND hwnd;
    MSG msg;

    (void)previnst;
    (void)cmd;
    wndClass.hInstance = inst;
    RegisterClass(&wndClass);
    hwnd = CreateWindow("simpwin", "Simple Windows",
    WS_SYSMENU,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, inst, NULL );
    ShowWindow(hwnd, cmdshow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
    }

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam)
    {
    int calldefault = 1;
    LONG ret = 0;
    static int cnt = 0;
    static char newbuf[80];

    switch (msg)
    {
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* TextOut(hdc, 0, 0, newbuf, strlen(newbuf)); */
    EndPaint(hwnd, &ps);
    break;
    }
    case WM_DESTROY:
    PostQuitMessage(0);
    calldefault = 0;
    break;

    case WM_NCPAINT:
    case WM_GETICON:
    case WM_WINDOWPOSCHANGING:
    case WM_ACTIVATEAPP:
    case WM_NCACTIVATE:
    case WM_ACTIVATE:
    case WM_IME_NOTIFY:
    case WM_SHOWWINDOW:
    break;

    case WM_IME_SETCONTEXT:
    lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
    break;

    case WM_SETFOCUS:
    ret = 0;
    calldefault = 0;
    break;

    case WM_ERASEBKGND:
    /* not sure how to actually erase the background - print spaces? */
    ret = 1;
    calldefault = 0;
    break;

    case WM_WINDOWPOSCHANGED:
    {
    char buf[80];
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    static int loccnt = 0;

    loccnt++;
    sprintf(buf, "PPP %d %d %d %X %X\n",
    loccnt, cnt, (int)msg, (int)wparam, (int)lparam);
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* TextOut(hdc, 0, 0, newbuf, strlen(newbuf)); */
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    break;
    }
    /* lparam is WINDOWPOS and may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_SIZE:
    /* low 16 bits of lparam are width - in pixels it seems */
    /* high 16 bits are height */
    /* unclear why this message is being received in the first
    place when the documentation says if I handle WINDOWPOSCHANGED
    then these messages are not generated. Maybe what they mean
    is that the WM_SIZE will just be a once-off message */
    ret = 0;
    calldefault = 0;
    break;

    case WM_MOVE:
    /* low 16 bits of lparam are x-pos (start). high 16 bits are
    y-pos - same consideration as WM_SIZE */
    ret = 0;
    calldefault = 0;
    break;

    case WM_GETMINMAXINFO:
    /* MINMAXINFO in lparam may be useful or need to be set */
    ret = 0;
    calldefault = 0;
    break;

    case WM_NCCALCSIZE:
    /* if 0, this may have useful information in RECT */
    if (wparam == 0)
    {
    ret = 0;
    /* if we don't call the default, we don't get a window! */
    calldefault = 1;
    }
    else
    {
    cnt += 50000; /* detect if we're getting true */
    }
    break;

    case WM_NCCREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 1;
    calldefault = 0;
    break;

    case WM_CREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_KEYDOWN:
    case WM_CHAR:
    default:
    {
    char buf[80] = "DUMMY";
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    cnt++;
    sprintf(newbuf, "ZZZ %d %X %X\n", (int)msg, (int)wparam, (int)lparam);
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    break;
    }
    }
    if (calldefault)
    {
    ret = DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return (ret);
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Uwe Sieber@21:1/5 to Paul Edwards on Fri Jul 21 09:11:51 2023
    MSDN:
    "An application should not call BeginPaint except in response to a WM_PAINT message."

    Replace BeginPaint + EndPaint by GetDC + ReleaseDC in any other place then WM_PAINT.

    At WM_CHAR you print to newbuf but TextOut(buf)




    Paul Edwards wrote:
    On Wednesday, July 19, 2023 at 6:07:59 PM UTC+8, JJ wrote:

    And when I move the window, I don't get another WM_WINDOWPOSCHANGED message.

    It's because there are more than one code which writes text at the same
    window client position - overwriting each other's text. So you only see the >> last written one.

    Thanks. I had a static counter, but it turned out that I was
    indeed missing some messages. So I have added those,
    but I'm still back at the same spot.

    I'm getting PPP 1 0 ... printed, and when I move the window,
    that doesn't change. Nor do keypresses get through.

    The 0 means that there are no messages that haven't
    been handled.

    The 1 means that poschanged is only called once.

    Any ideas?

    Thanks. Paul.


    /*********************************************************************/
    /* */
    /* This Program Written by Paul Edwards. */
    /* Released to the Public Domain */
    /* */ /*********************************************************************/ /*********************************************************************/
    /* */
    /* simpwin - the simplest windows program (roughly speaking) */
    /* */ /*********************************************************************/

    #include <stdio.h>

    #include <windows.h>

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam);

    int WINAPI WinMain(IN HINSTANCE inst,
    IN HINSTANCE previnst,
    IN LPSTR cmd,
    IN int cmdshow)
    {
    WNDCLASS wndClass = { 0, (WNDPROC)simpwin, 0, 0, 0, NULL, NULL,
    (HBRUSH)(COLOR_WINDOW+1), "simpwin", "simpwin" };
    HWND hwnd;
    MSG msg;

    (void)previnst;
    (void)cmd;
    wndClass.hInstance = inst;
    RegisterClass(&wndClass);
    hwnd = CreateWindow("simpwin", "Simple Windows",
    WS_SYSMENU,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, inst, NULL );
    ShowWindow(hwnd, cmdshow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
    }

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam)
    {
    int calldefault = 1;
    LONG ret = 0;
    static int cnt = 0;
    static char newbuf[80];

    switch (msg)
    {
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* TextOut(hdc, 0, 0, newbuf, strlen(newbuf)); */
    EndPaint(hwnd, &ps);
    break;
    }
    case WM_DESTROY:
    PostQuitMessage(0);
    calldefault = 0;
    break;

    case WM_NCPAINT:
    case WM_GETICON:
    case WM_WINDOWPOSCHANGING:
    case WM_ACTIVATEAPP:
    case WM_NCACTIVATE:
    case WM_ACTIVATE:
    case WM_IME_NOTIFY:
    case WM_SHOWWINDOW:
    break;

    case WM_IME_SETCONTEXT:
    lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
    break;

    case WM_SETFOCUS:
    ret = 0;
    calldefault = 0;
    break;

    case WM_ERASEBKGND:
    /* not sure how to actually erase the background - print spaces? */
    ret = 1;
    calldefault = 0;
    break;

    case WM_WINDOWPOSCHANGED:
    {
    char buf[80];
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    static int loccnt = 0;

    loccnt++;
    sprintf(buf, "PPP %d %d %d %X %X\n",
    loccnt, cnt, (int)msg, (int)wparam, (int)lparam);
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* TextOut(hdc, 0, 0, newbuf, strlen(newbuf)); */
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    break;
    }
    /* lparam is WINDOWPOS and may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_SIZE:
    /* low 16 bits of lparam are width - in pixels it seems */
    /* high 16 bits are height */
    /* unclear why this message is being received in the first
    place when the documentation says if I handle WINDOWPOSCHANGED
    then these messages are not generated. Maybe what they mean
    is that the WM_SIZE will just be a once-off message */
    ret = 0;
    calldefault = 0;
    break;

    case WM_MOVE:
    /* low 16 bits of lparam are x-pos (start). high 16 bits are
    y-pos - same consideration as WM_SIZE */
    ret = 0;
    calldefault = 0;
    break;

    case WM_GETMINMAXINFO:
    /* MINMAXINFO in lparam may be useful or need to be set */
    ret = 0;
    calldefault = 0;
    break;

    case WM_NCCALCSIZE:
    /* if 0, this may have useful information in RECT */
    if (wparam == 0)
    {
    ret = 0;
    /* if we don't call the default, we don't get a window! */
    calldefault = 1;
    }
    else
    {
    cnt += 50000; /* detect if we're getting true */
    }
    break;

    case WM_NCCREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 1;
    calldefault = 0;
    break;

    case WM_CREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_KEYDOWN:
    case WM_CHAR:
    default:
    {
    char buf[80] = "DUMMY";
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    cnt++;
    sprintf(newbuf, "ZZZ %d %X %X\n", (int)msg, (int)wparam, (int)lparam);
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    break;
    }
    }
    if (calldefault)
    {
    ret = DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return (ret);
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul N@21:1/5 to Paul Edwards on Fri Jul 21 07:58:15 2023
    On Friday, July 21, 2023 at 3:35:25 PM UTC+1, Paul Edwards wrote:
    On Friday, July 21, 2023 at 3:40:56 PM UTC+8, Uwe Sieber wrote:
    MSDN:
    "An application should not call BeginPaint except in response to a WM_PAINT message."

    Replace BeginPaint + EndPaint by GetDC + ReleaseDC in any other place then WM_PAINT.

    At WM_CHAR you print to newbuf but TextOut(buf)
    Thanks. I didn't really need it printed at that exact spot, so I
    just changed it to stop printing. Am I expecting to get a
    fresh WM_PAINT message after moving the window or
    pressing a key?

    Because currently I'm getting PPP 1 1 ...

    which means that I'm just getting a single position changed, and
    I'm not getting any keystrokes at all.

    Unless I'm only ever receiving a single WM_PAINT message,
    which would explain why I don't see any more action.
    Thanks. Paul.


    /*********************************************************************/
    /* */
    /* This Program Written by Paul Edwards. */
    /* Released to the Public Domain */
    /* */ /*********************************************************************/ /*********************************************************************/
    /* */
    /* simpwin - the simplest windows program (roughly speaking) */
    /* */ /*********************************************************************/

    #include <stdio.h>

    #include <windows.h>

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam);

    int WINAPI WinMain(IN HINSTANCE inst,
    IN HINSTANCE previnst,
    IN LPSTR cmd,
    IN int cmdshow)
    {
    WNDCLASS wndClass = { 0, (WNDPROC)simpwin, 0, 0, 0, NULL, NULL, (HBRUSH)(COLOR_WINDOW+1), "simpwin", "simpwin" };
    HWND hwnd;
    MSG msg;

    (void)previnst;
    (void)cmd;
    wndClass.hInstance = inst;
    RegisterClass(&wndClass);
    hwnd = CreateWindow("simpwin", "Simple Windows",
    WS_SYSMENU,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, inst, NULL );
    ShowWindow(hwnd, cmdshow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
    }

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam)
    {
    int calldefault = 1;
    LONG ret = 0;
    static int cnt = 0;
    static char newbuf[80];

    switch (msg)
    {
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, newbuf, strlen(newbuf));
    EndPaint(hwnd, &ps);
    break;
    }
    case WM_DESTROY:
    PostQuitMessage(0);
    calldefault = 0;
    break;

    case WM_NCPAINT:
    case WM_GETICON:
    case WM_WINDOWPOSCHANGING:
    case WM_ACTIVATEAPP:
    case WM_NCACTIVATE:
    case WM_ACTIVATE:
    case WM_IME_NOTIFY:
    case WM_SHOWWINDOW:
    break;

    case WM_IME_SETCONTEXT:
    lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
    break;

    case WM_SETFOCUS:
    ret = 0;
    calldefault = 0;
    break;

    case WM_ERASEBKGND:
    /* not sure how to actually erase the background - print spaces? */
    ret = 1;
    calldefault = 0;
    break;

    case WM_WINDOWPOSCHANGED:
    {
    char buf[80];
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    static int loccnt = 0;

    loccnt++;
    cnt++;
    sprintf(newbuf, "PPP %d %d %d %X %X\n",
    loccnt, cnt, (int)msg, (int)wparam, (int)lparam);
    #if 0
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* TextOut(hdc, 0, 0, newbuf, strlen(newbuf)); */
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    #endif
    break;
    }
    /* lparam is WINDOWPOS and may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_SIZE:
    /* low 16 bits of lparam are width - in pixels it seems */
    /* high 16 bits are height */
    /* unclear why this message is being received in the first
    place when the documentation says if I handle WINDOWPOSCHANGED
    then these messages are not generated. Maybe what they mean
    is that the WM_SIZE will just be a once-off message */
    ret = 0;
    calldefault = 0;
    break;

    case WM_MOVE:
    /* low 16 bits of lparam are x-pos (start). high 16 bits are
    y-pos - same consideration as WM_SIZE */
    ret = 0;
    calldefault = 0;
    break;

    case WM_GETMINMAXINFO:
    /* MINMAXINFO in lparam may be useful or need to be set */
    ret = 0;
    calldefault = 0;
    break;

    case WM_NCCALCSIZE:
    /* if 0, this may have useful information in RECT */
    if (wparam == 0)
    {
    ret = 0;
    /* if we don't call the default, we don't get a window! */
    calldefault = 1;
    }
    else
    {
    cnt += 50000; /* detect if we're getting true */
    }
    break;

    case WM_NCCREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 1;
    calldefault = 0;
    break;

    case WM_CREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_KEYDOWN:
    case WM_CHAR:
    default:
    {
    char buf[80] = "DUMMY";
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    cnt++;
    sprintf(newbuf, "ZZZ %d %X %X\n", (int)msg, (int)wparam, (int)lparam);
    /* hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps); */
    break;
    }
    }
    if (calldefault)
    {
    ret = DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return (ret);
    }

    WM_PAINT is sent when the computer thinks that what is actually on the screen needs to be updated. So you don't normally get one just because you have decided to change the content of the window. If you want what is actually on the screen to reflect what
    you now think ought to be there, the easiest way is to use the command InvalidateRect which will cause an WM_PAINT to be sent.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to Uwe Sieber on Fri Jul 21 07:35:23 2023
    On Friday, July 21, 2023 at 3:40:56 PM UTC+8, Uwe Sieber wrote:
    MSDN:
    "An application should not call BeginPaint except in response to a WM_PAINT message."

    Replace BeginPaint + EndPaint by GetDC + ReleaseDC in any other place then WM_PAINT.

    At WM_CHAR you print to newbuf but TextOut(buf)

    Thanks. I didn't really need it printed at that exact spot, so I
    just changed it to stop printing. Am I expecting to get a
    fresh WM_PAINT message after moving the window or
    pressing a key?

    Because currently I'm getting PPP 1 1 ...

    which means that I'm just getting a single position changed, and
    I'm not getting any keystrokes at all.

    Unless I'm only ever receiving a single WM_PAINT message,
    which would explain why I don't see any more action.

    Thanks. Paul.


    /*********************************************************************/
    /* */
    /* This Program Written by Paul Edwards. */
    /* Released to the Public Domain */
    /* */ /*********************************************************************/ /*********************************************************************/
    /* */
    /* simpwin - the simplest windows program (roughly speaking) */
    /* */ /*********************************************************************/

    #include <stdio.h>

    #include <windows.h>

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam);

    int WINAPI WinMain(IN HINSTANCE inst,
    IN HINSTANCE previnst,
    IN LPSTR cmd,
    IN int cmdshow)
    {
    WNDCLASS wndClass = { 0, (WNDPROC)simpwin, 0, 0, 0, NULL, NULL,
    (HBRUSH)(COLOR_WINDOW+1), "simpwin", "simpwin" };
    HWND hwnd;
    MSG msg;

    (void)previnst;
    (void)cmd;
    wndClass.hInstance = inst;
    RegisterClass(&wndClass);
    hwnd = CreateWindow("simpwin", "Simple Windows",
    WS_SYSMENU,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, inst, NULL );
    ShowWindow(hwnd, cmdshow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
    }

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam)
    {
    int calldefault = 1;
    LONG ret = 0;
    static int cnt = 0;
    static char newbuf[80];

    switch (msg)
    {
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, newbuf, strlen(newbuf));
    EndPaint(hwnd, &ps);
    break;
    }
    case WM_DESTROY:
    PostQuitMessage(0);
    calldefault = 0;
    break;

    case WM_NCPAINT:
    case WM_GETICON:
    case WM_WINDOWPOSCHANGING:
    case WM_ACTIVATEAPP:
    case WM_NCACTIVATE:
    case WM_ACTIVATE:
    case WM_IME_NOTIFY:
    case WM_SHOWWINDOW:
    break;

    case WM_IME_SETCONTEXT:
    lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
    break;

    case WM_SETFOCUS:
    ret = 0;
    calldefault = 0;
    break;

    case WM_ERASEBKGND:
    /* not sure how to actually erase the background - print spaces? */
    ret = 1;
    calldefault = 0;
    break;

    case WM_WINDOWPOSCHANGED:
    {
    char buf[80];
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    static int loccnt = 0;

    loccnt++;
    cnt++;
    sprintf(newbuf, "PPP %d %d %d %X %X\n",
    loccnt, cnt, (int)msg, (int)wparam, (int)lparam);
    #if 0
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* TextOut(hdc, 0, 0, newbuf, strlen(newbuf)); */
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    #endif
    break;
    }
    /* lparam is WINDOWPOS and may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_SIZE:
    /* low 16 bits of lparam are width - in pixels it seems */
    /* high 16 bits are height */
    /* unclear why this message is being received in the first
    place when the documentation says if I handle WINDOWPOSCHANGED
    then these messages are not generated. Maybe what they mean
    is that the WM_SIZE will just be a once-off message */
    ret = 0;
    calldefault = 0;
    break;

    case WM_MOVE:
    /* low 16 bits of lparam are x-pos (start). high 16 bits are
    y-pos - same consideration as WM_SIZE */
    ret = 0;
    calldefault = 0;
    break;

    case WM_GETMINMAXINFO:
    /* MINMAXINFO in lparam may be useful or need to be set */
    ret = 0;
    calldefault = 0;
    break;

    case WM_NCCALCSIZE:
    /* if 0, this may have useful information in RECT */
    if (wparam == 0)
    {
    ret = 0;
    /* if we don't call the default, we don't get a window! */
    calldefault = 1;
    }
    else
    {
    cnt += 50000; /* detect if we're getting true */
    }
    break;

    case WM_NCCREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 1;
    calldefault = 0;
    break;

    case WM_CREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_KEYDOWN:
    case WM_CHAR:
    default:
    {
    char buf[80] = "DUMMY";
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    cnt++;
    sprintf(newbuf, "ZZZ %d %X %X\n", (int)msg, (int)wparam, (int)lparam);
    /* hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps); */
    break;
    }
    }
    if (calldefault)
    {
    ret = DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return (ret);
    }


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to Paul Edwards on Fri Jul 21 08:44:40 2023
    On Friday, July 21, 2023 at 11:26:33 PM UTC+8, Paul Edwards wrote:

    That should be the vast bulk of what I need (at least as
    far as Windows graphics code, anyway).

    I checked on win32s under Windows for Workgroups 3.11.

    Although my program (compiled with Open Watcom 1.6)
    worked, the window was transparent.

    Under Windows 10 I instead get a clean window with a
    clean white background.

    It may be related to the fact that Watcom says it is creating
    a console mode application, when it is actually graphics.
    Not sure what the wcl386 option is to set that.

    BFN. Paul.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to Paul N on Fri Jul 21 08:26:29 2023
    On Friday, July 21, 2023 at 10:58:17 PM UTC+8, Paul N wrote:

    WM_PAINT is sent when the computer thinks that what is
    actually on the screen needs to be updated. So you don't
    normally get one just because you have decided to change
    the content of the window. If you want what is actually on
    the screen to reflect what you now think ought to be there,
    the easiest way is to use the command InvalidateRect which
    will cause an WM_PAINT to be sent.

    Thanks! That literally brought a smile to my face when I
    started seeing activity, and I could indeed see the ASCII
    character codes come through when I press keys.

    That should be the vast bulk of what I need (at least as
    far as Windows graphics code, anyway).

    BFN. Paul.




    /*********************************************************************/
    /* */
    /* This Program Written by Paul Edwards. */
    /* Released to the Public Domain */
    /* */ /*********************************************************************/ /*********************************************************************/
    /* */
    /* simpwin - the simplest windows program (roughly speaking) */
    /* */ /*********************************************************************/

    #include <stdio.h>

    #include <windows.h>

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam);

    int WINAPI WinMain(IN HINSTANCE inst,
    IN HINSTANCE previnst,
    IN LPSTR cmd,
    IN int cmdshow)
    {
    WNDCLASS wndClass = { 0, (WNDPROC)simpwin, 0, 0, 0, NULL, NULL,
    (HBRUSH)(COLOR_WINDOW+1), "simpwin", "simpwin" };
    HWND hwnd;
    MSG msg;

    (void)previnst;
    (void)cmd;
    wndClass.hInstance = inst;
    RegisterClass(&wndClass);
    hwnd = CreateWindow("simpwin", "Simple Windows",
    WS_SYSMENU,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, inst, NULL );
    ShowWindow(hwnd, cmdshow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
    }

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam)
    {
    int calldefault = 1;
    LONG ret = 0;
    static int cnt = 0;
    static char newbuf[80];

    switch (msg)
    {
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, newbuf, strlen(newbuf));
    EndPaint(hwnd, &ps);
    break;
    }
    case WM_DESTROY:
    PostQuitMessage(0);
    calldefault = 0;
    break;

    case WM_NCPAINT:
    case WM_GETICON:
    case WM_WINDOWPOSCHANGING:
    case WM_ACTIVATEAPP:
    case WM_NCACTIVATE:
    case WM_ACTIVATE:
    case WM_IME_NOTIFY:
    case WM_SHOWWINDOW:
    break;

    case WM_IME_SETCONTEXT:
    lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
    break;

    case WM_SETFOCUS:
    ret = 0;
    calldefault = 0;
    break;

    case WM_ERASEBKGND:
    /* not sure how to actually erase the background - print spaces? */
    ret = 1;
    calldefault = 0;
    break;

    case WM_WINDOWPOSCHANGED:
    {
    char buf[80];
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    static int loccnt = 0;

    loccnt++;
    cnt++;
    sprintf(newbuf, "PPP %d %d %d %X %X\n",
    loccnt, cnt, (int)msg, (int)wparam, (int)lparam);
    InvalidateRect(hwnd, NULL, TRUE);
    #if 0
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* TextOut(hdc, 0, 0, newbuf, strlen(newbuf)); */
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    #endif
    break;
    }
    /* lparam is WINDOWPOS and may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_SIZE:
    /* low 16 bits of lparam are width - in pixels it seems */
    /* high 16 bits are height */
    /* unclear why this message is being received in the first
    place when the documentation says if I handle WINDOWPOSCHANGED
    then these messages are not generated. Maybe what they mean
    is that the WM_SIZE will just be a once-off message */
    ret = 0;
    calldefault = 0;
    break;

    case WM_MOVE:
    /* low 16 bits of lparam are x-pos (start). high 16 bits are
    y-pos - same consideration as WM_SIZE */
    ret = 0;
    calldefault = 0;
    break;

    case WM_GETMINMAXINFO:
    /* MINMAXINFO in lparam may be useful or need to be set */
    ret = 0;
    calldefault = 0;
    break;

    case WM_NCCALCSIZE:
    /* if 0, this may have useful information in RECT */
    if (wparam == 0)
    {
    ret = 0;
    /* if we don't call the default, we don't get a window! */
    calldefault = 1;
    }
    else
    {
    cnt += 50000; /* detect if we're getting true */
    }
    break;

    case WM_NCCREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 1;
    calldefault = 0;
    break;

    case WM_CREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_KEYDOWN:
    case WM_CHAR:
    {
    char buf[80] = "DUMMY";
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    cnt++;
    sprintf(newbuf, "ZZZ %d %X %X\n", (int)msg, (int)wparam, (int)lparam);
    InvalidateRect(hwnd, NULL, TRUE);
    /* hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps); */
    break;
    }
    /* we're still getting some of these, but we no longer care */
    default:
    break;
    }
    if (calldefault)
    {
    ret = DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return (ret);
    }


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to Paul Edwards on Fri Jul 21 14:41:56 2023
    On Friday, July 21, 2023 at 11:44:42 PM UTC+8, Paul Edwards wrote:

    I checked on win32s under Windows for Workgroups 3.11.

    Although my program (compiled with Open Watcom 1.6)
    worked, the window was transparent.

    The problem was that I still had my "debug" code left when
    I was trying to figure out which message I needed to do
    something with.

    I commented out the obvious one, and the default window
    proc did the trick, so the background is fixed now.

    Thanks. Paul.



    /*********************************************************************/
    /* */
    /* This Program Written by Paul Edwards. */
    /* Released to the Public Domain */
    /* */ /*********************************************************************/ /*********************************************************************/
    /* */
    /* simpwin - the simplest windows program (roughly speaking) */
    /* */ /*********************************************************************/

    #include <stdio.h>

    #include <windows.h>

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam);

    int WINAPI WinMain(IN HINSTANCE inst,
    IN HINSTANCE previnst,
    IN LPSTR cmd,
    IN int cmdshow)
    {
    WNDCLASS wndClass = { 0, (WNDPROC)simpwin, 0, 0, 0, NULL, NULL,
    (HBRUSH)(COLOR_WINDOW+1), "simpwin", "simpwin" };
    HWND hwnd;
    MSG msg;

    (void)previnst;
    (void)cmd;
    wndClass.hInstance = inst;
    RegisterClass(&wndClass);
    hwnd = CreateWindow("simpwin", "Simple Windows",
    WS_SYSMENU,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, inst, NULL );
    ShowWindow(hwnd, cmdshow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
    }

    LONG FAR PASCAL simpwin(HWND hwnd, WORD msg, WORD wparam, LONG lparam)
    {
    int calldefault = 1;
    LONG ret = 0;
    static int cnt = 0;
    static char newbuf[80];

    switch (msg)
    {
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, newbuf, strlen(newbuf));
    EndPaint(hwnd, &ps);
    break;
    }
    case WM_DESTROY:
    PostQuitMessage(0);
    calldefault = 0;
    break;

    case WM_NCPAINT:
    case WM_GETICON:
    case WM_WINDOWPOSCHANGING:
    case WM_ACTIVATEAPP:
    case WM_NCACTIVATE:
    case WM_ACTIVATE:
    case WM_IME_NOTIFY:
    case WM_SHOWWINDOW:
    break;

    case WM_IME_SETCONTEXT:
    lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
    break;

    case WM_SETFOCUS:
    ret = 0;
    calldefault = 0;
    break;

    #if 0
    case WM_ERASEBKGND:
    /* not sure how to actually erase the background - print spaces? */
    ret = 1;
    calldefault = 0;
    break;
    #endif

    case WM_WINDOWPOSCHANGED:
    {
    char buf[80];
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    static int loccnt = 0;

    loccnt++;
    cnt++;
    sprintf(newbuf, "PPP %d %d %d %X %X\n",
    loccnt, cnt, (int)msg, (int)wparam, (int)lparam);
    InvalidateRect(hwnd, NULL, TRUE);
    #if 0
    hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    /* TextOut(hdc, 0, 0, newbuf, strlen(newbuf)); */
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps);
    #endif
    break;
    }
    /* lparam is WINDOWPOS and may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_SIZE:
    /* low 16 bits of lparam are width - in pixels it seems */
    /* high 16 bits are height */
    /* unclear why this message is being received in the first
    place when the documentation says if I handle WINDOWPOSCHANGED
    then these messages are not generated. Maybe what they mean
    is that the WM_SIZE will just be a once-off message */
    ret = 0;
    calldefault = 0;
    break;

    case WM_MOVE:
    /* low 16 bits of lparam are x-pos (start). high 16 bits are
    y-pos - same consideration as WM_SIZE */
    ret = 0;
    calldefault = 0;
    break;

    case WM_GETMINMAXINFO:
    /* MINMAXINFO in lparam may be useful or need to be set */
    ret = 0;
    calldefault = 0;
    break;

    case WM_NCCALCSIZE:
    /* if 0, this may have useful information in RECT */
    if (wparam == 0)
    {
    ret = 0;
    /* if we don't call the default, we don't get a window! */
    calldefault = 1;
    }
    else
    {
    cnt += 50000; /* detect if we're getting true */
    }
    break;

    case WM_NCCREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 1;
    calldefault = 0;
    break;

    case WM_CREATE:
    /* lparam is CREATESTRUCT which may have useful information */
    ret = 0;
    calldefault = 0;
    break;

    case WM_KEYDOWN:
    case WM_CHAR:
    {
    char buf[80] = "DUMMY";
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    cnt++;
    sprintf(newbuf, "ZZZ %d %X %X\n", (int)msg, (int)wparam, (int)lparam);
    InvalidateRect(hwnd, NULL, TRUE);
    /* hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &rect);
    TextOut(hdc, 0, 0, buf, strlen(buf));
    EndPaint(hwnd, &ps); */
    break;
    }
    /* we're still getting some of these, but we no longer care */
    default:
    break;
    }
    if (calldefault)
    {
    ret = DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return (ret);
    }


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)