-2

I am so new to developing with Win32 API in C++, and I have made a first program like this:

The program's apperance

Below is my code, but if you want to build it, then this is my project archive.

// The feedback interface with GUI.

#include "stdafx.h"
#include "Win32Project1.h"
#include <string>
#include <fstream>
#include <Windows.h>
#define MAX_LOADSTRING 65536
#include <strsafe.h>
HFONT defaultFont;
HWND hwnd2;
HWND Button;
HWND Help;
void ErrorExit(LPTSTR lpszFunction) //Function used for debugging
{
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0, NULL);

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(TCHAR), 0);
}
LPWSTR Convert(const std::string& s)
{
    LPWSTR ws = new wchar_t[s.size() + 1]; // +1 for zero at the end
    copy(s.begin(), s.end(), ws);
    ws[s.size()] = 0; // zero at the end
    return ws;
}


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

TCHAR Feedback[MAX_LOADSTRING];
std::string Msg;
std::string MsgTitle;
std::ofstream FeedbackFile;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    // Get UI font
    NONCLIENTMETRICS ncm;
    ncm.cbSize = sizeof(ncm);

    // If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
    // will be the wrong size for previous versions, so we need to adjust it.

    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
    defaultFont = CreateFontIndirect(&(ncm.lfMessageFont));
    // Register the window class.
    std::string CLASS_NAME = "The first program!";

    WNDCLASS wc = {};

    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = L"First program!";

    RegisterClass(&wc);

    // Create the window.

    HWND hwnd = CreateWindowEx(
        WS_EX_CONTEXTHELP,                              // Optional window styles.
        L"First program!",                     // Window class
        L"The first program!",          // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

                                        // Size and position
        0, 0, 640, 360,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if (hwnd == NULL)
    {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);

    // Create the window.

    hwnd2 = CreateWindowEx(
        WS_EX_CLIENTEDGE,              // Optional window styles.
        L"edit",                       // Window class
        L"Insert feedback here :)",    // Window text
        WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_LEFT | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL,            // Window style

                                        // Size and position
        10, 50, 300, 200,

        hwnd,       // Parent window    
        (HMENU)(123),       // Menu
        (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),  // Instance handle
        NULL        // Additional application data
    );
    Button = CreateWindowW(
        L"BUTTON",
        L"Submit feedback!",
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
        160, 255, 150, 20,
        hwnd,
        (HMENU) BT_PRESS,
        (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
        NULL
    );
    Help = CreateWindowW(
        L"BUTTON",
        L"What is this?",
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
        10, 280, 80, 20,
        hwnd,
        (HMENU)HELP_PRESS,
        (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
        NULL
    );
    SendMessage(hwnd2, WM_SETFONT, WPARAM(defaultFont), TRUE);
    SendMessage(Button, WM_SETFONT, WPARAM(defaultFont), TRUE);
    SendMessage(Help, WM_SETFONT, WPARAM(defaultFont), TRUE);

    if (hwnd2 == NULL)
    {
        return 0;
    }

    ShowWindow(hwnd2, nCmdShow);

    // Run the message loop.

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_HELP:
        MessageBox(Help, L"This is my first program made by Visual Studio 2017.\nYou can type your feedback in the box and then press Submit feedback!\nYour feedback will be saved and we will read it.\n\nThanks so much for using this program. :)", L"About this program", MB_OK);
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        SelectObject(hdc, defaultFont);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
        TextOut(hdc, 10, 5, TEXT("Hi! This is my first program made by Visual Studio 2017."), 57);
        TextOut(hdc, 10, 20, TEXT("Do you have something to tell me?"), 34);
        TextOut(hdc, 10, 35, TEXT("Just write below and I will listen. :)"), 39);
        EndPaint(hwnd, &ps);
    }
    case WM_COMMAND:
    {
        switch (wParam)
        {
        case BT_PRESS:
        {
            GetWindowText(hwnd2, Feedback, MAX_LOADSTRING);
            FeedbackFile.open("Feedback.txt", std::ios::out | std::ios::app);
            FeedbackFile << Feedback;
            FeedbackFile << "\n------------------------\n";
            FeedbackFile.close();
            LPWSTR Msg = L"Thanks for your feedback! I appreciated!";
            LPWSTR MsgTitle = L"Feedback accepted!";
            MessageBox(hwnd, Msg, MsgTitle, MB_OK);
            SendMessage(hwnd, WM_DESTROY, NULL, NULL);
        } break;
        case HELP_PRESS:
            SendMessage(hwnd, WM_HELP, 0, 0);
            break;
        }
    }
    return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

I intended to make the program display a messagebox that tells the user about the program, then when click OK, the box closes and the program is still there. But when OK button is clicked, the messagebox disappeared, and the program closed either. Is there anyway to keep the program running after the user click OK? Thank you so much.

Lê Duy Quang
  • 45
  • 1
  • 6
  • 2
    What shall your program do after the message box is closed? On a side note, please put *relevant* source code directly inside the post instead of linking to external site which might not be available all the time. – zett42 Jun 30 '17 at 06:44
  • 2
    Posting links to information required to answer the question is not recommended. If the linked information is removed or the link is shuffled, the question becomes meaningless. – user4581301 Jun 30 '17 at 06:45
  • We need to see a [mcve], and a clear problem statement. Please remove all code that isn't necessary to illustrate the issue, while still keeping it complete. No need to post the `ErrorExit` function, when you aren't even calling it, for example. There's lots more unrelated code. – IInspectable Aug 05 '17 at 10:24

3 Answers3

0

You should not use a SendMessage(hwnd, WM_DESTROY, NULL, NULL); this essentially tells the program to quit.

MessageBox() is a blocking call. There is no need to post a message in the message queue.

This will your new WM_COMMAND (UPDATE 1)

case WM_COMMAND:
    {
        switch (wParam)
        {
        case BT_PRESS:
        {
            GetWindowText(hwnd2, Feedback, MAX_LOADSTRING);
            FeedbackFile.open("Feedback.txt", std::ios::out | std::ios::app);
            FeedbackFile << Feedback;
            FeedbackFile << "\n------------------------\n";
            FeedbackFile.close();
            LPWSTR Msg = L"Thanks for your feedback! I appreciated!";
            LPWSTR MsgTitle = L"Feedback accepted!";
            MessageBox(hwnd, Msg, MsgTitle, MB_OK);
            SendMessage(hwnd2, WM_DESTROY, NULL, NULL);
        } break;
        case HELP_PRESS:
            SendMessage(hwnd, WM_HELP, 0, 0);
            break;
        }
    }
Suraj S
  • 1,019
  • 7
  • 18
  • The program is broken when your suggestion is applied. After pressing the Submit feedback! button the program didn't close, and the issue is still there. – Lê Duy Quang Jul 01 '17 at 12:39
  • The BT_PRESS is the handle when the user click the "Submit feedback!" button, and the HELP_PRESS is for "What is this?". I am meaning to that HELP_PRESS, not the BT_PRESS (it is OK!). – Lê Duy Quang Jul 02 '17 at 01:13
0

OK, after 2 days of editing and debugging I finally got my own answer. I think maybe the message loop

while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

is the problem. So I added a BOOL helped and edited the code like this:

//Message loop in the wWinMain function
while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

if (helped) {
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}  //Repeat the loop again if user clicked "What is this?"

//The HELP_PRESS handle in WM_COMMAND
        case HELP_PRESS:
            SendMessage(hwnd, WM_HELP, 0, 0);
            helped = true;
            break;

Anyway, thank Suraj S and i486 so much for trying to help me. I hope this can help other coders that having the same problem. Once again, thanks so much.

Lê Duy Quang
  • 45
  • 1
  • 6
0

The first problem I've seen is that the break statement is missing in some parts of the switch structure.

In the case where return is the last statement of a part this is not a problem:

case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
    break; // This line has no effect after a return

However if there is neither a break nor a return statement you'll have a problem:

case WM_HELP:
    MessageBox(Help, ... , MB_OK);
    // break; <- This line is missing in your program!
case WM_DESTROY:
    PostQuitMessage(0);

In this case the WM_DESTROY part will be entered after the WM_HELP part. After showing the MessageBox the PostQuitMessage function will be executed which will stop your program.

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38