It's been quite some time since I posted anything actually useful, so I decided to share a tutorial I wrote a little while back which will give you a basic introduction to Win32 Programming and will show you how to make a GUI in C++.
Tutorial Index:
- The WinMain function
- Creating your very first WIN32 GUI
- Creating Button controls
- Responding to Button clicks
- Message Boxes
- Message Box types
- Type Of buttons to add on a message box
- Handling Message box events
- Message Box icons
- Working with a DLL
- Attach a DLL
- Detach a DLL
- Do something when attached
- Do something when detached
Part 1 - The WinMain Function:
The WinMain function is the entry point of the Win32 programs just like the main() function is for the C++ console application. In this function will be stored all the information about the program events and GUI controls, but i'll explain this later and will get more in depth.
Here is a simple example of the WinMain Function:
Code:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nShowCmd) { return 0; }
HINSTANCE hInstance - Its called “instance handle”
HINSTANCE hPrevInstance - Was used in earlier version of Windows. When you run the same program more than ones you created multiple instances
LPSTR szCmdLine - What it really is is a “long pointer to a zero terminated string” L for long, P for pointer and STR for string
int nShowCmd - The way that your program will be loaded ex: Minimized, Maximized, Hidden, Shown normally etc.
Lets just make a small add-in code to demonstrate the procedure of the WinMain function.
Code:
#include <Windows.h> int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nShowCmd) { MessageBox(NULL, "My First Win32 Program", "Caption", MB_OK); return 0; }
This was a very simple example that will do the following things:
1: Load the program.
2: Go to the WinMain function (Entry Point).
3: Show a MessageBox.
4: See there are no loops or anything that requires the program to run.
5: Exit the program.
Part 2 - Creating your first GUI:
First i will give the code for a simple GUI window then i'll go in depth to explain every single detail.
Here is the code:
Code:
#include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nShowCmd) { static char name[] = "My Window Class"; WNDCLASSEX wc; HWND hwnd; MSG Msg; //Step 1: Registering the Window Class wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) CreateSolidBrush(RGB(255, 0, 0)); wc.lpszMenuName = NULL; wc.lpszClassName = name; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Window Registration Failed!", "Registration Failure", MB_ICONEXCLAMATION | MB_OK); return 0; } // Step 2: Creating the Window hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, name, "Win32LSS1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nShowCmd); UpdateWindow(hwnd); // Step 3: The Message Loop while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return (int)Msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd, msg, wParam, lParam); }
First we need to declare the Windows Procedure function ( WndProc ) that function will handle all the events in our program.
Code:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
Code:
static char name[] = "Window Class Name"; WNDCLASSEX wc; HWND hwnd; MSG Msg;
In the second line we declare a windows class structure.
In the third line we declare our Main Window Handle.
In The fourth line we declare a Message Structure.
Now lets look at how we register our windows class:
Code:
wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) CreateSolidBrush(RGB(255, 0, 0)); wc.lpszMenuName = NULL; wc.lpszClassName = name; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.style - is the window style. Spesifies how the window will look.
wc.lpfnWndProc - requires a pointer to the WndProc function.
wc.cbClsExtrxtra - here u give how many extra bytes to allocate. Set it to 0. Do the same for wc.cbWndExtra.
wc.hInstance - This is the Instance handle passed to WinMain
wc.hIcon - a handle to the icon of the program.
wc.hCursor - a handle to the Cursor that our program will use
wc.hbrBackground - the background color of the window. For this tutorial i've set it to a solid red color. If u want a normal window color use:
Code:
(HBRUSH) (COOR_WINLDOW+1);
wc.lpszClassName - the class name that we declared.
wc.hIconSm - a handle to small icon that will be displayed in the upper left corner.
Now we need to register the class:
Code:
if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Window Registration Failed!", "Registration Failure", MB_ICONEXCLAMATION | MB_OK); return 0; }
If the registration was successful lets move to the window creation:
Code:
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, name, "Win32LSS1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, NULL, NULL, hInstance, NULL);
The first parameter is the extended windows style. You can combine more that one using " | " this symbol to seperate the styles.
The second parameter is the class name.
The third parameter is the caption of our window.
The fourth parameter is the Windows Style of how our window will look.
The fifth and sixth parameters are the X and Y position of our window. The place it will be drawn. Set them to CW_USEDEFAULT so windows will decide where to put it.
The seventh parameter is the how wide our window will be.
The eight parameter is how tall our window will be.
The ninght parameter is the handle to the parent window. But since this will be the parent window set that ot NULL. It wont be null if we are creating some Control like a button or textbox or something.
The tenth parameter is the handle to a menu. But since we are not gonna use one set it to NULL.
The eleventh parameter is a instance handle to the window.
The twelfth parameter is a pointer to be passed to the Windows procedure WM_Create. We wont use that set it to NULL.
Ok, now that that is done we need to display our window:
Code:
ShowWindow(hwnd, nShowCmd);
Code:
UpdateWindow(hwnd);
Code:
while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return (int)Msg.wParam;
Code:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd, msg, wParam, lParam);
Inside the Windows Procedure we use a switch statement to check what message Windows has sent to the program.
Part 3 - Creating Button Controls:
Ok so we've reached part 3 of our Win32 Programming tutorial. Now i'm gonna teach u how to create a simple button.
Get the source from Part2 ( The complete one ). Now Add a header file to your project and give it the following Name -> "hWndDec". At the top of your main C++ file right under the "#Include <window.h>" include the header file like so:
Code:
#include "hWndDec.h"
Open hWndDec.h and fill the following code:
Code:
HWND hCloseBTN; #define BUTTON_CLOSE 40000
Now replace your origninal WndProc Funtion with this one:
Code:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: hCloseBTN = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Close", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 50, 80, 30, hwnd, NULL, GetModuleHandle(NULL), NULL); break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; }
Lets look at the following lines of code:
Code:
case WM_CREATE:
Now lets look at the actual code that we've used to create the button:
Code:
hCloseBTN = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Close", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 50, 80, 30, hwnd, NULL, GetModuleHandle(NULL), NULL);
Second is the button class "BUTTON"
Third is the button caption.
And now the styles: WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON
* WS_CHILD makes it a child window for our main one. If this wasn't here the button would of been painted someone on the screen and not on the main window.
* WS_VISIBLE - this is self explaining.
* BS_PUSHBUTTON - makes it a button and being able to push it ?
The next 4 parameters are as they follow: X, Y, Wight , Height .
Next parameter we give the parent handle ( the handle of our MainWindow)
Next parameter is the menu... NULL
GetModuleHanlde(NULL) gets the instance handle which is passed to
main (HINSTANCE hInstance)
Part 4 - Responding to button clicks:
Ok we've added the button to our form now it's time to give it some functionality. Add the following lines to your WndProc function:
Code:
case WM_COMMAND: switch(LOWORD(wParam)) { case BN_CLICKED: if(hCloseBTN == (HWND)lParam) { } } break;
If a button is clicked
Code:
case BN_CLICKED:
Code:
if(hCloseBTN == (HWND)lParam) { }
Code:
if(hCloseBTN == (HWND)lParam) { MessageBox(hwnd, "The Button WORKED", "Info", MB_OK); }
Code:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: hCloseBTN = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Close", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 50, 80, 30, hwnd, NULL, GetModuleHandle(NULL), NULL); break; case WM_COMMAND: switch(LOWORD(wParam)) { case BN_CLICKED: if(hCloseBTN == (HWND)lParam) { MessageBox(NULL, "The Button WORKED", "Info", MB_OK); } } break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; }
Part 5: Message Boxes:
Lets view a simple message box syntax:
Code:
MessageBox(NULL, "Text Here", "Caption Here", MB_OK);
Code:
case WM_COMMAND: switch(LOWORD(wParam)) { case BN_CLICKED: if(hCloseBTN == (HWND)lParam) { MessageBox(hwnd, "Text u want goes here", "Caption", MB_OK); } } break;
The second parameter is the text to be displayed on the message box.
The third parameter is the message box caption.
The fourth is the message box BUTTONS and ICONS.
The different buttons:
- MB_OK -> Displays a OK button
- MB_OKCANCEL -> Displays a OK and Cancel buttons
- MB_YESNO -> Displays a Yes and No buttons.
- MB_RETRYCANCEL -> Displays a Retry and Cancel buttons
- MB_YESNOCANCEL -> Displays a Yes, No, And Cancel buttons.
The different icons:
- MB_ICONEXCLAMATION -> Displays a "!" icon
- MB_ICONWARNING -> Displays a warning icon
- MB_ICONINFORMATION
- MB_ICONASTERISK
- MB_ICONQUESTION
- MB_IConstop
- MB_IConerror
Try them out. The syntax for a combination - button(s) + Icon is the following:
Code:
MessageBox(NULL, "Want to continue?", "Question", MB_YESNO | MB_ICONQUESTION);
Go to the WndProc function and find "case WM_CLOSE:"
replace the code with the following one:
Code:
case WM_CLOSE: int iResult; iResult = MessageBox(hwnd, "Are u sure u want to exit?", "Confirmation", MB_YESNO | MB_ICONQUESTION); if(iResult == IDYES) { DestroyWindow(hwnd); } else if(iResult == IDNO) { return false; } break;
Declared iResult as integer.
Set iResult = to the messagebox code.
Then passed a If statement: if the user presses Yes button (IDYES) then distroy the window. else to return false and do nothing.
The ID's For all the buttons are taken from WinUser.h:
Code:
#define IDOK 1 #define IDCANCEL 2 #define IDABORT 3 #define IDRETRY 4 #define IDIGNORE 5 #define IDYES 6 #define IDNO 7 #define IDCLOSE 8 #define IDHELP 9 #define IDTRYAGAIN 10 #define IDCONTINUE 11
Now it's time to teach u a little something about the DLL's.
How to import a dll that's in the same directory as our program:
Code:
LoadLibrary("DllName.dll");
Then Add the following code:
Code:
#include <windows.h> BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) { if(dwReason = DLL_PROCESS_ATTACH) { MessageBox(NULL, "Dll Attached successfully", "Success", MB_OK | MB_ICONINFORMATION); } return TRUE; }
The following code will show u how to attach and detach a DLL:
Code:
HANDLE hWnd; hWnd = LoadLibrary("DllName.dll"); // And now the detach: CloseHandle(hWnd);
Code:
#include <windows.h> BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) { if(dwReason = DLL_PROCESS_DETACH) { MessageBox(NULL, "Dll Detached successfully", "Success", MB_OK | MB_ICONINFORMATION); } return TRUE; }