Adding a InputBox() to any c++ program

June 14, 2019

Introduction

There are several building blocks in programming that are available in most of the languages and make life easy. For example, the ability to pop up a message. In Win32 that would be MessageBox(). Another building block is Inputbox. InputBox() is a very handy command for prompting the user for an input. You can find it in VBA and Visual Basic. However, while Message Boxes can be easily displayed in any c++ program, there is no direct way for calling InputBox like command. For that reason I created SGInputBox(). I am providing this code as a Static library, and with no Resources, which I think is the most comfortable way to be used, and it can be used by Console Applications, plain Win32 applications or any other type of c++ application.

 

The Function

The goal is to create a very simple and easy to use InputBox function that can be called like this:

 

LPWSTR result = SG_InputBox::GetString(
         L"Code Project Demo - by Michael Haephrati", 
         L"What is your name");

 

 

and as a result, we would like to see something like:

 

 

Or... even better, why not add a "default" value, so the user will be shown this value as default and will then be able either to confirm or to edit it. To make it even more user friendly, we will already "select all" the default text, so if the user types different text, it will replace the old one.

For supporting default text (but not forcing the programmer using this library to have one), we add an optional argument:

 

LPWSTR GetString(LPCTSTR szCaption, LPCTSTR szPrompt, LPCTSTR szDefaultText = L"");

 

and call the function like this:

 

LPWSTR result = SG_InputBox::GetString(
     L"Code Project Demo - by Michael Haephrati", 
     L"What is your name",
     L"My name is Michael");

 

 

We can also make the Dialog a bit fancy, set background and foreground colors, align the text to the center and set a default button. These will be explained in my "How To" section, as these are tips and tricks not necessarily associated with the scope of the article. 

 

The Test Program
 

For the purpose of testing the SGInputBox() function I have created a default Windows Console application where all I do is link to the InputBox.lib. The best is to work with a single Solution (.sln) where there is the Static Library project and the Test Program project, both refer to $(SolutionDir)\$(Configuration)\$(Platform)\ so you can easily link to the library and can define it once and for all configurations (x64 / Win32 / Debug, etc.):

 

$(SolutionDir)\$(Configuration)\$(Platform)\InputBox.lib;​

 

Then I have created a minimal header file just to make it possible to call our SGInputBox() function:

 

#include <Windows.h>

class SG_InputBox
{
public:
    static LPWSTR GetString(LPCTSTR szCaption, LPCTSTR szPrompt, LPCTSTR szDefaultText = L"");
};

 

Then, all that is left to do is to call the function and use the return value it returns.

The most part of our main() function will then be:

 

#include "SG_InputBoxLib.h"
int main()
{
    wprintf(L"Testing the InputBox static lib\n"); 
    LPWSTR result = SG_InputBox::GetString(
        L"Code Project Demo - by Michael Haephrati", 
        L"What is your name",
        L"My name is Michael");
    wprintf(L"User entered '%s'\n", result);
    
}

 

How to

In my various articles I always try to include some useful code that can be used for many purposes other than within the scope of the article.

 

Aligning text

I wrote the setTextAlignment() function for the purpose of aligning text. I placed it in my utils.cpp file, as it is adviced to place any helper functions in a set of utils.cpp / utils.h source files, which can be used by other projects. 

 

void setTextAlignment(HWND hwnd,int intTextAlignment)
{
        LONG_PTR s;
    LONG_PTR textalignment = GetWindowLongPtr(hwnd, GWL_STYLE);
    if (textalignment != intTextAlignment)
    {
        //delete the last text alignment
        if (intTextAlignment == 0)
        {
            s = GetWindowLongPtr(hwnd, GWL_STYLE);
            s = s & ~(SS_LEFT);
            SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
        }
        else if (intTextAlignment == 1)
        {
            s = GetWindowLongPtr(hwnd, GWL_STYLE);
            s = s & ~(SS_CENTER);
            SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
        }
        else if (intTextAlignment == 2)
        {
            s = GetWindowLongPtr(hwnd, GWL_STYLE);
            s = s & ~(SS_RIGHT);
            SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
        }

        textalignment = intTextAlignment;

        //put the new text alignment
        if (textalignment == 0)
        {
            s = GetWindowLongPtr(hwnd, GWL_STYLE);
            s = s | (SS_LEFT);
            SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
        }
        else if (textalignment == 1)
        {
            s = GetWindowLongPtr(hwnd, GWL_STYLE);
            s = s | (SS_CENTER);
            SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
        }
        else if (textalignment == 2)
        {
            s = GetWindowLongPtr(hwnd, GWL_STYLE);
            s = s | (SS_RIGHT);
            SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
        }
        SetWindowPos(hwnd, 0, 0, 0, 0, 0,
            SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_DRAWFRAME);
    }
}

 

Setting a Default Button

We would like that the Confirm button will be shown as Default, indicating that if the user hits the ENTER key, it will be as if he/she pressed that button. To do so we use the following code:

 

// Set default button
SendMessage((HWND)m_hWndOK, BM_SETSTYLE,
    (WPARAM)LOWORD(BS_DEFPUSHBUTTON), MAKELPARAM(TRUE, 0));
SendMessage((HWND)m_hWndCancel, BM_SETSTYLE,
    (WPARAM)LOWORD(BS_PUSHBUTTON), MAKELPARAM(TRUE, 0));

 

Setting Background and Foreground Colors

First I have chosen a nice background color and defined it once so I can use it later in one or several places:

 

#define SOFT_BLUE RGB(206,214,240)

 

Then I defined a Brush:

 

HBRUSH SG_InputBox::hbrBkgnd =  NULL;

 

Then, in our Dialog's Callback function

LRESULT CALLBACK SG_InputBox::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 

We address the WM_CTLCOLORSTATIC message:

 

case WM_CTLCOLORSTATIC:
{
    HDC hdcStatic = (HDC)wParam;
    if (hbrBkgnd == NULL)
    {
        hbrBkgnd = CreateSolidBrush(SOFT_BLUE);
    }
    SetTextColor(hdcStatic, RGB(0, 0, 0));
    SetBkColor(hdcStatic, SOFT_BLUE);

    return (INT_PTR)hbrBkgnd;
}
break;

 

Setting Default Text and Selecting it
 
// Set default text
SendMessage(m_hWndEdit, EM_SETSEL, 0, -1);
SendMessage(m_hWndEdit, EM_REPLACESEL, 0, (LPARAM)szDefaultText);
SendMessage(m_hWndEdit, EM_SETSEL, 0, -1);
SetFocus(m_hWndEdit);
 
Handling Errors
 
When the creation of any element of the window or the window (dialog) itself fail, we call REPORT_ERROR. This is in fact a MACRO I created:
 
#define REPORTERROR ReportError(__FUNCTION__)
 

and the actual ReportError() function then gets as its parameter the name of the function where the error occurred, which is useful. The ReportError() function can be expanded to log any "wprintf" so then you can always check the log file. 

 

//
// void ReportError(const char *CallingFunction)
{
    DWORD error = GetLastError();
    LPVOID lpMsgBuf;
    DWORD bufLen = FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        error,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0, NULL);
    wprintf(L"%S: Error '%s'\n", CallingFunction,(wchar_t *)lpMsgBuf);
}
//

 

Further Reading

- Dialog Boxes: https://docs.microsoft.com/en-us/windows/desktop/dlgbox/using-dialog-boxes

- Using Brushes: https://docs.microsoft.com/en-us/windows/desktop/gdi/using-brushes

- Handling the WM_CTLCOLORSTATIC message: https://docs.microsoft.com/en-us/windows/desktop/controls/wm-ctlcolorstatic

- Visual Studio Solutions (.sln): https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/solution-dot-sln-file?view=vs-2019 

 

More on Github: https://github.com/haephrati/SGInputBox

 

 

Please reload

Featured Posts

Integrating a Desktop application with Pay Pal in c++

July 3, 2018

1/4
Please reload

Recent Posts

March 14, 2017

Please reload

Archive
Please reload

Search By Tags
Follow Us
  • Facebook Basic Square
  • Twitter Basic Square
  • Google+ Basic Square

© 2008-2018 Secured Globe Inc.