Obtaining input from textbox Visual C++ 2010 Express - c++

I am new here and hope to learn a lot from a great community.
I am beginning to learn some GUI C++ pogramming, but only the basics. I have made one win32 GUI app before using mingw and creating my own resource and header file. All I need the program to do at this point is get text from a text box.
With mingw, I would use a callback function like this, using GetDigItem() to get user input from a text box when a certain button is clicked.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_FILE_EXIT:
DestroyWindow(hwnd);
break;
case ID_STUFF_GO:
break;
case REG_BUTTON:
char NameInput[MAX_PATH];
// Gets inputted info from text boxes
// this is what I want to do in vc++
GetWindowText(GetDlgItem(hwnd, NAME_BOX), NameInput, MAX_PATH);
break;
case WM_CREATE:
{
CreateWindow (TEXT("EDIT"), TEXT("Name Here"), WS_VISIBLE | WS_CHILD | WS_BORDER, 10, 10, 230, 20, hwnd, (HMENU) NAME_BOX, NULL, NULL);
CreateWindow (TEXT("EDIT"), TEXT("Number Here"), WS_VISIBLE | WS_CHILD | WS_BORDER, 10, 35, 230, 20, hwnd, (HMENU) SERIAL_BOX, NULL, NULL);
CreateWindow (TEXT(button), TEXT(button1), WS_VISIBLE | WS_CHILD, 75, 60, 90, 20, hwnd, (HMENU) REG_BUTTON, NULL, NULL);
I've noticed the code is a little different in VC++. I created a button and text box from the Windows Form Designer. I have managed to manipulate inputted info, and have it displayed on the text box, but I need to get inputted info and have it returned as a char, std::string, etc. Here is the code in question that I have, which does not compile as is.
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
// Storage buffer for serial and name
std::string test;
// Upon button click, this will transfer inputted text to the label next to it
label1->Text = textBox1->Text;
// this does not compile
test = textBox1->Text;
// Gets inputted info from text boxes
// This does not compile either
//GetWindowText(GetDlgItem(NULL, textBox1), NameInput, MAX_PATH);
//GetWindowText(GetDlgItem(NULL, textBox2), SerialInput, MAX_PATH);
Does anyone have any ideas on how to get the inputted information in text box to return as a char, char*, (std::)string, or other type for further manipulation? Thanks.
EDIT-
I figured out where in mingw I can use GetDigItem() to return user input, I do that in VC++ by using a System::String^ as indicated in the code below.
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
label1->Text = textBox1->Text;
//char SerialInput[MAX_PATH];
//test -> textBox1->Text
// The following compiles and works to retrieve input
// as a System::String^
System::String^ userinput;
textBox1->Text = userinput;
// However this yields 2 compiler error
// error C2065: 'marshal_as' : undeclared identifier
// error C2275: 'std::string' : illegal use of this type as an expression
std::string stdString = marshal_as<std::string>(newer);
// Forgive any spacing errors, this 4 space indent to repr code
// isn't working with my long expressions
The problem now seems to be getting the System::String^ to something I can work with. My attempts to convert it to an std::string aren't working as I showed, I also included in my stdafx.h. A char or anything would be great. Any ideas?
EDIT 2:
I need to convert a SYstem::String^ to whatever else I can (preferably std::string or char). Here is what I have tried, and the compiler errors recieved.
System::String^ userinput;
userinput = textBox1->Text;
// method 1
const __wchar_t __pin * str1 = PtrToStringChars(userinput);
// error recieved
error C4980: '__pin' : use of this keyword requires /clr:oldSyntax command line option
// method 2
char* str2 = (char*)(void*)Marshal::StringToHGlobalAnsi(str);
// error recieved
error C2653: 'Marshal' : is not a class or namespace name
error C3861: 'StringToHGlobalAnsi': identifier not found
// method 3
// #include <atlstr.h>
// CString str3(userinput);
// error recieved
fatal error C1083: Cannot open include file: 'atlstr.h': No such file or directory
// Where can I get this header file from?
I feel like there's something obvious I"m not doing...
P.S - It's very misleading of Microsoft to call this Visual C++, as this is not C++!
P.S.S - For any c++ coders reading this, VC++ has standards and languages all of it's own, completely different than traditional C++ and even the win api. It's over complication at it's finest - do yourself and your clients a favor and stick to QT for win guis!

You should indicate which framework you're using (e.g., MFC or WTL), and give the specific compiler error rather than simply saying it doesn't compile. Without more information, I'm guess this is the problem:
std::string test;
test = textBox1->Text;
The Text field is probably a wide character string. (Windows uses UTF-16 internally, so--on Windows--a std::wstring is a string of 16-bit character values. Most Windows functions handle surrogates to access characters beyond the BMP. On other OSes, a std::wstring is often a string of 32-bit character values.)
You cannot assign a wide character string to a std::string without a conversion. Your choices are to use a wide string (e.g., std::wstring) or to apply a conversion.
For conversions, Windows has a WideCharToMultibyte function you could use. C++ has std::codecvt.

Related

How to get input into a messageBox

I'm fairly new to C++. I tried practicing my code but I hit an error I'm not sure how to fix:
Error: expression cannot be used as a function
switch (message)
{
case WM_CREATE:
TextBox = CreateWindow("EDIT",
"",
WS_VISIBLE|WS_CHILD|WS_BORDER,
10,10,80,20,
hwnd,NULL,NULL,NULL);
BUTTON = CreateWindow("BUTTON",
"GO",
WS_VISIBLE|WS_CHILD|WS_BORDER,
100,10,70,20,
hwnd,(HMENU)1,NULL,NULL);
break;
case WM_COMMAND:
case 1:
int gwtstat=0;
//char *t=&textSaved[0];
gwtstat=GetWindowText(TextBox,&textSaved[0], 50);
::MessageBox(
hwnd,
"I am" ()textSaved "and i am Beautiful!",
"smile",
MB_YESNO);
The issue is here:
"I am" ()
The expression "I am" is of type char const[5] which doesn't support function call syntax. What you intended to do is probably string interpolation. For that you can use std::format starting with C++20.
The following solves the immediate issue:
::MessageBox(
hwnd,
std::format("I am {} and i am Beautiful!", textSaved).c_str(),
"smile",
MB_YESNO);
There are lots of other issues with the code, some less fatal than others:
Use of the ANSI API as opposed to the Unicode API. The latter is strongly recommended, as it allows use of the entire set of Unicode code points (and has less overhead)
Assigning terribly low IDs to controls (0 and 1, respectively) (see Why do dialog editors start assigning control IDs with 100? for details)
Defining a variable in a case label; your compiler warned you about this
Failure to extract the control ID from the WM_COMMAND message handler
A more appropriate implementation could look like this:
// Declare symbolic constants for control IDs
constexpr int TextBoxId = 100;
constexpr int GoButtonId = 101;
// ...
switch (message)
{
case WM_CREATE:
TextBox = ::CreateWindowW(L"EDIT",
L"",
WS_VISIBLE|WS_CHILD|WS_BORDER,
10,10,80,20,
hwnd,(HMENU)TextBoxId,NULL,NULL);
BUTTON = ::CreateWindowW(L"BUTTON",
L"GO",
WS_VISIBLE|WS_CHILD|WS_BORDER,
100,10,70,20,
hwnd,(HMENU)GoButtonId,NULL,NULL);
break;
case WM_COMMAND:
// Evaluate control ID of the sender
switch(LOWORD(wParam)) {
case GoButtonId: {
// ^ Introduce new scope for automatic
// lifetime management of local variables
// Retrieve text from text box
size_t const length = ::GetWindowTextLengthW(TextBox);
std::wstring text(length, L'\0');
::GetWindowTextW(TextBox, text.data(), text.length() + 1);
::MessageBoxW(
hwnd,
std::format(L"I am {} and i am Beautiful!", text).c_str(),
L"smile",
MB_YESNO);
// ...
}
break;
While this implementation reads the edit control's contents into a std::wstring variable the following will work as well, and doesn't require C++20 (compiles with C++98):
::MessageBoxW(
hwnd,
(L"I am " + text + L" and i am Beautiful!").c_str(),
L"smile",
MB_YESNO);

WinAPI GetWindowText as string

I was wondering if it were possible to take text input from a text box (CreateWindowEx "EDIT") and store it as a string or even better a vector
I need to have a textbox that the user can enter or paste text and when I click a button it will alphabetize the words and count unique words etc...
so far I have it reading it in as characters (i dont know how to make it a string) and alphabetizes the characters
so if I type in: how now brown cow
it will output: bchnnoooorwwww
instead of: brown cow how now
my code under the WM_COMMAND case is
int length;
length = GetWindowTextLength(textbox) + 1;
vector<wchar_t> list(length);
GetWindowText(textbox, &list[0], length);
wstring stxt = &list[0];
wstring str(stxt);
sort(str.begin(), str.end());
SetWindowText(sortedOutput, &str[0]);
This answer may be of use to you in devising a solution. I don't really know of one that is not hacky, but it can be done casting of the constness of c_string() from std::string.
https://stackoverflow.com/a/1986974/128581
A std::string's allocation is not guaranteed to be contiguous under the C++98/03 standard, but C++11 forces it to be. In practice, neither I nor Herb Sutter know of an implementation that does not use contiguous storage.
Notice that the &s[0] thing is always guaranteed to work by the C++11 standard, even in the 0-length string case. It would not be guaranteed if you did str.begin() or &*str.begin(), but for &s[0] the standard defines operator[] as:
Returns: *(begin() + pos) if pos < size(), otherwise a reference to an object of type T with value charT(); the referenced value shall not be modified
Continuing on, data() is defined as:
Returns: A pointer p such that p + i == &operator for each i in [0,size()].
(notice the square brackets at both ends of the range)
Thus it follows you can do something like this:
int len = GetWindowTextLength(hwnd) + 1;
std::string s;
s.reserve(len);
GetWindowText(hwnd, const_cast<char*>(s.c_str()), len - 1);
Which is pretty ugly. Welcome any more "correct" answers, though.
Regarding when unicode is enabled on your build, you have to use a wstring or equivalent. Testing that out just a moment ago, this works:
std::wstring title;
title.reserve(GetWindowTextLength(m_window_handle) + 1);
GetWindowText(m_window_handle, const_cast<WCHAR *>(title.c_str()), title.capacity());
In general, regarding the windows api its useful to google their all caps typedefs and figure out what they really are.
Regarding splitting strings, std::string isn't particular good at this kind of manipulation. This is where std::stringstream (or wstringstream for unicode) comes in handy. I am fairly certain stringstream is not guaranteed to be contiguous in memory, so you can't really go around writing directly into its buffer.
// Initialize a stringstream so we can extract input using >> operator
std::wstringstream ss;
ss.str(title);
// Make a vector, so we can store our words as we're extracting them
// and so we can use sort later, which works on many stl containers
std::vector<std::wstring> words;
std::wstring word;
// This will evaluate to false and thus end the loop when its done
// reading the string word by word
while(ss >> word)
{
words.push_back(word);
}
Then proceed with your sorting, but on the new vector words.
Your problem is not a winapi problem. While not the only way, you found a solution to transfer a string back and forth to your edit box.
How to turn that string into a list/vector of strings, with words being the elements of that list/vector is in fact an STL problem.
Basically, you are looking for the C++ equivalent of the C# function String.Split().
And there is already a good question and answer for that, here:
Most elegant way to split a string?
So, all you have to do is a sort of round trip:
Get string from TextBox
Convert string to a std::vector<string>, using your split function (see the other question for how to do that).
Sort the vector in the usual way.
Convert the vector back to a string, which is the inverse of your split function (Hint: std::ostringstream).
Set the resulting string as the text of your TextBox.
Depending on your preferences regarding multi character strings and globalization, you might decide to stick to the ASCII versions at first. On windows, you can compile to MBCS or ASCII. The respective string types are then respectively (TCHAR and LPCTSTR or WCHAR and LPCWSTR or CHAR and LPCSTR). All win32 functions come in two flavors, distinguished by a trailing A or W at the end of the function name, respectively.
AFAIK, while there is std::string and std::wstring, there is no standard implementation for std::basic_string<TCHAR>, which would work along with your compile options.
As for the window handling, here some code example (snippets):
In InitInstance(), I created the dialog (IDD_FORMVIEW) with my input edit box, my button and my static output area as a child window of the main application window:
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
HWND hWndChild = CreateDialogW(hInstance, MAKEINTRESOURCE(IDD_FORMVIEW), hWnd, dlgProc);
if (NULL == hWndChild)
{
DWORD lastError = GetLastError();
wchar_t msg[100];
swprintf_s(msg, _countof(msg), L"error code: 0x%0X\n", lastError);
OutputDebugString(msg);
}
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
ShowWindow(hWndChild, SW_SHOW);
UpdateWindow(hWnd);
return TRUE;
}
CreateDialogW() takes as the last parameter a pointer to the dialog handler function, which is called dlgProc() in this example.
This is how that dlgProc() function looks like:
// Message handler for our menu which is a child window of the main window, here.
static INT_PTR CALLBACK dlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
BOOL processed = false;
switch (uMsg)
{
case WM_INITDIALOG:
break;
case WM_NOTIFY:
break;
case WM_COMMAND:
{
auto sourceId = LOWORD(wParam);
auto code = HIWORD(wParam);
if (IDC_BUTTON1 == sourceId)
{
if (BN_CLICKED == code)
{
wchar_t text[1024];
GetDlgItemText(hwndDlg, IDC_EDIT1, text, _countof(text));
// TODO: do your string processing here (string -> string)
SetDlgItemText(hwndDlg, IDC_STATIC, text);
processed = TRUE;
}
}
}
break;
default:
break;
}
return processed;
}
I have just mixed a few lines of code to convert wchar_t to wstring to std::string. Here you go!
string GetWindowStringText(HWND hwnd)
{
int len = GetWindowTextLength(hwnd) + 1;
vector<wchar_t> buf(len);
GetWindowText(hwnd, &buf[0], len);
wstring wide = &buf[0];
string s(wide.begin(), wide.end());
return s;
}
This has a vector so you'll need to include it.

how do I get a windows text winapi c++?

I am currently making a Win32 DLL project with WinAPI, with a User Interface.
I am confused on how I get a textbox's text in C++. Here is what a bit of my code looks like.
case Execute:
char text[256];
TCHAR TextBuffer[_MAX_PATH];
LRESULT result = SendMessage(Pointers::ExecuteBar, WM_GETTEXT, 256, LPARAM(text));
HandleCommands(std::string(text));
std::string UserInput = (std::string)(char*)TextBuffer;
if (Enabled)
{
HandleCommands(UserInput);
}
else
{
PushMessage(L"Not Initialized.", RGB(255, 140, 0));
};
break;
};
break;
that's my case Execute function.
Here's my WinApi Button for Execute.
HWND ExecuteButton = CreateWindow(L"BUTTON", L"EXE", (WS_CHILD | WS_VISIBLE),
340, 380, 60, 20, Pointers::Window, (HMENU)Execute, DllModule, NULL);
I need help because whenever I try and type in something it goes to a message that I put in to notify the user if they typed in something wrong.
If you want to get the text of a window just use the GetWindowText() function
1st param is the handle to the window you want to copy its text.
2nd param is the char that must be previously defined .
3rd param is the max number of chars you will copy.
Example:
char copy[ ] = " ";
GetWindowText(hWndTextBox, &copy[0], sizeof(copy)-1);
Here the 3rd param will give it an unlimited numbers of chars to get copied you can set it to any integer number like 20

Output LRESULT to console

I'm trying to output text from Notepad window to console and it's always 0.
What I'm doing wrong?
int main()
{
HWND hwnd = (HWND)0x0031019C; // Window Handler of Notepad
char szBuf[4096];
HWND hwndEdit;
LRESULT result;
hwndEdit = FindWindowEx(hwnd, NULL, L"Edit", NULL); // Class for edit box
result = SendMessage(hwndEdit, WM_GETTEXT, sizeof(szBuf) / sizeof(szBuf[0]), (LPARAM)szBuf);
cout<<"Contents: \n"<<result;
cin.get();
return 0;
}
I tried print_f, but it outputs unreadable characters:
printf( "Contents: %s\n", result, szBuf );
It looks to me like you probably have a little bit of a mismatch happening.
Based on the L"Edit", you seem to be doing a Unicode build (otherwise, you'd get an error message about not being able to convert an wchar_t const[5] to LPCSTR, and the code wouldn't compile.
If you do a Unicode build, however, WM_GETTEXT is going to write Unicode data to your buffer, so you need to prepare for and use Unicode instead of narrow characters for your buffer.
For convenience, I've modified it a little to find Notepad instead of using a hard-coded Window handle.
#include <windows.h>
#include <stdio.h>
#define elements(b) (sizeof(b)/sizeof(b[0]))
int main() {
HWND hwnd; // Window Handler of Notepad
wchar_t buf[4096]={0};
HWND hwndEdit;
LRESULT result;
hwnd=FindWindowEx(NULL, NULL, L"Notepad", NULL);
hwndEdit=FindWindowEx(hwnd, NULL, L"Edit", NULL); // Class for edit box
result = SendMessage(hwndEdit, WM_GETTEXT, elements(buf), (LPARAM)buf);
printf("%S", buf);
return 0;
}
I built with:
cl /DUNICODE whatever.cpp user32.lib
Then I did a quick test that printed out exactly the text I'd typed into Notepad. To verify the result, I then edited the text in notepad, ran it again, and it printed out the modified text.

Windows API dialogs without using resource files

I'm trying to create a dialog box using C++ and the windows API, but I don't want the dialog defined in a resource file. I can't find anything good on this on the web, and none of the examples I've read seem to define the dialog programmatically.
How can I do this?
A simple example is fine. I'm not doing anything complicated with it yet.
Raymond Chen wrote a few posts about the dialog manager:
The dialog manager, part 1: Warm-ups
The dialog manager, part 2: Creating the frame window
The dialog manager, part 3: Creating the controls
The dialog manager, part 4: The dialog loop
The dialog manager, part 5: Converting a non-modal dialog box to modal
The dialog manager, part 6: Subtleties in message loops
The dialog manager, part 7: More subtleties in message loops
The dialog manager, part 8: Custom navigation in dialog boxes
The dialog manager, part 9: Custom accelerators in dialog boxes
If all you want to do is show a window with controls, it's possible to create a window without using resource (.rc) files / scripts.
This isn't the same as a dialog, but it might be easier than creating a dialog programmatically.
First, a few notes about how this is done:
Instead of designing the dialog in the rc file, you could manually use CreateWindow (or CreateWindowEx) to create child windows of a main window. (for .NET Windows Forms programmers, these windows are like Controls).
This process will not be graphical at all (you will need to manually type in the location and size of each window), but I think this can be a great way to understand how dialogs are created under the hood.
There are some disadvantages to not using a real dialog, namely that tab will not work when switching between controls.
About the example:
This example features a dialog box with two buttons, an edit box (.NET Windows Forms programmers would think of it as a TextBox), and a check box.
It has been tested under the following conditions:
x86 build
x64 build
Unicode build (UNICODE and _UNICODE defined)
Non-Unicode build (UNICODE and _UNICODE not defined)
Built with Visual Studio's C compiler
Built with Visual Studio's C++ compiler
OS: Windows 10 64 bit
Note: UNICODE
As of the time of writing, UTF-8 is still in beta for Windows 10
If you have not enabled this setting, you should assume that any char* is ACP, not UTF-8, this applies to standard library functions too
Even though in Linux, that same standard library function would be UTF-8.
Sadly, some C++ standard library features only work with char* (e.g., exception messages).
You can still use UTF-8 in Windows without the option set, you will just have to encode it back to UTF-16 before calling winapi functions.
Here is a reddit thread with a reply from somebody who claims to have worked on UTF-8 on Windows, it has some good information.
UNICODE in Windows means "UTF-16", not "UTF-8".
Using Unicode of some kind is strongly recommended for any version of Windows that is not very old.
Be aware that if you don't use Unicode, your program may be utterly unable to open file names containing Unicode characters, handle directories (e.g., usernames) with non-ACP characters, etc.
Using ACP functions (SendMessageA,etc) without somehow verifying that UTF-8 is enabled (it's disabled by default) is probably a bug.
For max portability/flexibility, I would recommend using UTF-16 and the W version of all API functions, translating from UTF-8 to UTF-16 at the last minute. Read this page very carefully.
Now for the code:
Note that a large amount of comments have been added to try to document the windows functions, I recommend copy/pasting this into a text editor, for best results.
// This sample will work either with or without UNICODE, it looks like
// it's recommended now to use UNICODE for all new code, but I left
// the ANSI option in there just to get the absolute maximum amount
// of compatibility.
//
// Note that UNICODE and _UNICODE go together, unfortunately part
// of the Windows API uses _UNICODE, and part of it uses UNICODE.
//
// tchar.h, for example, makes heavy use of _UNICODE, and windows.h
// makes heavy use of UNICODE.
#define UNICODE
#define _UNICODE
//#undef UNICODE
//#undef _UNICODE
#include <windows.h>
#include <tchar.h>
// I made this struct to more conveniently store the
// positions / size of each window in the dialog
typedef struct SizeAndPos_s
{
int x, y, width, height;
} SizeAndPos_t;
// Typically these would be #defines, but there
// is no reason to not make them constants
const WORD ID_btnHELLO = 1;
const WORD ID_btnQUIT = 2;
const WORD ID_CheckBox = 3;
const WORD ID_txtEdit = 4;
const WORD ID_btnShow = 5;
// x, y, width, height
const SizeAndPos_t mainWindow = { 150, 150, 300, 300 };
const SizeAndPos_t btnHello = { 20, 50, 80, 25 };
const SizeAndPos_t btnQuit = { 120, 50, 80, 25 };
const SizeAndPos_t chkCheck = { 20, 90, 185, 35 };
const SizeAndPos_t txtEdit = { 20, 150, 150, 20 };
const SizeAndPos_t btnShow = { 180, 150, 80, 25 };
HWND txtEditHandle = NULL;
// hwnd: All window processes are passed the handle of the window
// that they belong to in hwnd.
// msg: Current message (e.g., WM_*) from the OS.
// wParam: First message parameter, note that these are more or less
// integers, but they are really just "data chunks" that
// you are expected to memcpy as raw data to float, etc.
// lParam: Second message parameter, same deal as above.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
// Create the buttons
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Note that the "parent window" is the dialog itself. Since we are
// in the dialog's WndProc, the dialog's handle is passed into hwnd.
//
//CreateWindow( lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam
//CreateWindow( windowClassName, initial text, style (flags), xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( TEXT("Button"), TEXT("Hello"), WS_VISIBLE | WS_CHILD, btnHello.x, btnHello.y, btnHello.width, btnHello.height, hwnd, (HMENU)ID_btnHELLO, NULL, NULL);
CreateWindow( TEXT("Button"), TEXT("Quit"), WS_VISIBLE | WS_CHILD, btnQuit.x, btnQuit.y, btnQuit.width, btnQuit.height, hwnd, (HMENU)ID_btnQUIT, NULL, NULL);
// Create a checkbox
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CreateWindow( TEXT("button"), TEXT("CheckBox"), WS_VISIBLE | WS_CHILD | BS_CHECKBOX, chkCheck.x, chkCheck.y, chkCheck.width, chkCheck.height, hwnd, (HMENU)ID_CheckBox, NULL, NULL);
// Create an edit box (single line text editing), and a button to show the text
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Handle = CreateWindow(windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
txtEditHandle = CreateWindow(TEXT("Edit"), TEXT("Initial Text"), WS_CHILD | WS_VISIBLE | WS_BORDER, txtEdit.x, txtEdit.y, txtEdit.width, txtEdit.height, hwnd, (HMENU)ID_txtEdit, NULL, NULL);
//CreateWindow( windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( TEXT("Button"), TEXT("Show"), WS_VISIBLE | WS_CHILD, btnShow.x, btnShow.y, btnShow.width, btnShow.height, hwnd, (HMENU)ID_btnShow, NULL, NULL);
// Create an Updown control. Note that this control will allow you to type in non-number characters, but it will not affect the state of the control
break;
// For more information about WM_COMMAND, see
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647591(v=vs.85).aspx
case WM_COMMAND:
// The LOWORD of wParam identifies which control sent
// the WM_COMMAND message. The WM_COMMAND message is
// sent when the button has been clicked.
if (LOWORD(wParam) == ID_btnHELLO)
{
MessageBox(hwnd, TEXT("Hello!"), TEXT("Hello"), MB_OK);
}
else if (LOWORD(wParam) == ID_btnQUIT)
{
PostQuitMessage(0);
}
else if (LOWORD(wParam) == ID_CheckBox)
{
UINT checked = IsDlgButtonChecked(hwnd, ID_CheckBox);
if (checked)
{
CheckDlgButton(hwnd, ID_CheckBox, BST_UNCHECKED);
MessageBox(hwnd, TEXT("The checkbox has been unchecked."), TEXT("CheckBox Event"), MB_OK);
}
else
{
CheckDlgButton(hwnd, ID_CheckBox, BST_CHECKED);
MessageBox(hwnd, TEXT("The checkbox has been checked."), TEXT("CheckBox Event"), MB_OK);
}
}
else if (LOWORD(wParam) == ID_btnShow)
{
int textLength_WithNUL = GetWindowTextLength(txtEditHandle) + 1;
// WARNING: If you are compiling this for C, please remember to remove the (TCHAR*) cast.
TCHAR* textBoxText = (TCHAR*) malloc(sizeof(TCHAR) * textLength_WithNUL);
GetWindowText(txtEditHandle, textBoxText, textLength_WithNUL);
MessageBox(hwnd, textBoxText, TEXT("Here's what you typed"), MB_OK);
free(textBoxText);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// hInstance: This handle refers to the running executable
// hPrevInstance: Not used. See https://blogs.msdn.microsoft.com/oldnewthing/20040615-00/?p=38873
// lpCmdLine: Command line arguments.
// nCmdShow: a flag that says whether the main application window
// will be minimized, maximized, or shown normally.
//
// Note that it's necessary to use _tWinMain to make it
// so that command line arguments will work, both
// with and without UNICODE / _UNICODE defined.
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS mainWindowClass = { 0 };
// You can set the main window name to anything, but
// typically you should prefix custom window classes
// with something that makes it unique.
mainWindowClass.lpszClassName = TEXT("JRH.MainWindow");
mainWindowClass.hInstance = hInstance;
mainWindowClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
mainWindowClass.lpfnWndProc = WndProc;
mainWindowClass.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&mainWindowClass);
// Notes:
// - The classname identifies the TYPE of the window. Not a C type.
// This is a (TCHAR*) ID that Windows uses internally.
// - The window name is really just the window text, this is
// commonly used for captions, including the title
// bar of the window itself.
// - parentHandle is considered the "owner" of this
// window. MessageBoxes can use HWND_MESSAGE to
// free them of any window.
// - menuHandle: hMenu specifies the child-window identifier,
// an integer value used by a dialog box
// control to notify its parent about events.
// The application determines the child-window
// identifier; it must be unique for all
// child windows with the same parent window.
//CreateWindow( windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( mainWindowClass.lpszClassName, TEXT("Main Window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, mainWindow.x, mainWindow.y, mainWindow.width, mainWindow.height, NULL, 0, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// This code is based roughly on tutorial code present at http://zetcode.com/gui/winapi/
Further reading
The builtin set of window classes are rather limited, so you might be curious as to how you can define your own window classes ("Controls") using the Windows API, see the articles below:
Custom Controls in Win32 API: The Basics (Code Project)
The WINE emulator source serves as a good example of how the Windows API could be implemented, and how you can make your own window classes that imitate the behavior of builtin classes.
Zetcode.com's tutorials
NOTE: I originally intended this post to cover the creation of dialogs programmatically. Due to a mistake on my part I didn't realize that you can't just "show" a window as a dialog. Unfortunately I wasn't able to get the setup mentioned by Raymond Chen working. Even looking at WINE's source, it's not super clear.
Take a look at this toolkit that describes how to create dialogs without resource files.
It's in WTL. However, I'm sure you can pick apart the internals to achieve the same thing using the Win32 API directly.
Here you can find how to use Windows API dialogs without using resource files.
The Windows API (only the C Win32 API, no MFC) tutorial:
Windows API tutorial
Try to search MSDN for "dialog templates in memory".
See this for example: Dialog Boxes