Windows Programming Tutorial



Windows Programming Tutorial
By: AZTEK


Contents


1. Basics

1.1 Introduction

First off if you are reading this tutorial, I am going to assume a few things. Because windows programming is "more advanced" than console programming I am going to have to assume you have a good grasp on C/C++. You need to know what #include's are and how to use them, you need to know how to use arrays and pointers, you need to know how to use switch() and case's, and you need to know what a typedef is. These are things this tutorial will not cover. I will format my code to my style, this to make it easier for me and you to read.
You are also going to need a C/C++ Compiler that supports Windows API. I used Borlands Free C/C++ 5.5 Compiler to compile all of these examples, basically because I am to cheap to get Microsoft Visual C++ and Borland is free alternative. For information on getting a free compiler see the Tools Appendix. For information on how to compile windows programs with the compiler see the Compiler Section.
I like to look at the code and compiled examples before I go over what it all means so after each example I will go over the code to clarify what it means.
1.2 Simple Message
Source - Screen Shot
This first example is here just to make sure that your compiler does support windows.

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        MessageBox (NULL, "Hello World" , "Hello", 0);
        return 0;
}


Put that code in a test file and compile it, any errors you get consult your compilers help files. Now lets go through the code.

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

WinMain() is the windows equivalent of main() in DOS and UNIX. This is where the program starts. WinMain() takes the following parameters:


hInstance
Identifies the programs current instance (the programs place in the memory)
hPrevInstance
Identifies the previous instance of the application. For a Win32-based application, this parameter is always NULL.
lpCmdLine
All of the command-line arguments in a string (does not include the program name)
nCmdShow
A value that can be passed to ShowWindow()


Many of the keywords and types have windows specific definitions, like UINT is unsigned int and LPSTR is char *, this is intended to increase portability. If you are more comfortable using char * instead of LPSTR, feel free to do so.

MessageBox() is the function that pops up a message box, hence the name. MessageBox() takes the following parameters:

hWnd
Identifies the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window.
lpText
This is the text contained in the window.
lpCaption
This is the text contained in the titlebar of the window.
uType
This is the style of the message box (like if its an error, warning, etc. and what buttons should appear. Setting this to 0 will add no icon and just a Ok button)
1.3 Simple Window
Source - Screen Shot
On of the first questions that plagues a new windows programmer is "How Do I make A Window?" Well I am afraid that the answer is not entirely simple. Here is the source for a simple window.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        switch(Message) {
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


As you can see its a good 70 or so lines to make a simple window.

Windows Programs unlike DOS or UNIX programs are event driven. Windows programs generaly stay idle untill they recive a message, they act on that message, and then wait for the next one. When a windows program does respond to a message its called handling the message.

As you see I decalred my WiinProc function so that it can be used later on. I decalerd my variables (I prfer to use Hungarian Notation, but you can use what you want).

Inside the function WiNmain() we see some new variables. These are WndClass, hwnd, and msg. The WndClass is the structure that holds all of the widnows class information which is later passed to RegisterClassEx(). The hwnd structure identifies the window. The msg structure contains message information from a thread's message queue. The next thing we come to is when the hInstance is made global in the variable ghInstance. After that we come to the defining of each of the WndClass settings:


cbSize
Is the size (in bytes) of this structure. Always set this to sizeof(WNDCLASSEX).
style
The Class style sof the window. Usually net to NULL.
lpfnWndProc
This points to the windows callback procedure.
cbClsExtra
Amount of extra data allocated for this class in memory. Usually 0.
cbWndExtra
Amount of extra data allocated in memory per window. Usually 0.
hInstance
This is the handle for the window instance.
hIcon
The icon shown when the user presses Alt-Tab. We will worry about this more when we get into resources.
hCursor
The cursor that will be displayed when the mouse is over our window. We will worry about this more when we get into resources.
hbrBackground
The brush to set the color of our window.
lpszMenuName
Name of the menu resource to use. We will worry about this more when we get into resources.
lpszClassName
Name to identify the class with.
hIconSm
The small icon shown in the taskbar and in the top-left corner. We will worry about this more when we get into resources.
After that the next thing we do is register our window class. The program registers it and if it tell the user in an message box. Then we have the defineation of hwnd. This is what we will later pass on to ShowWindow(). Here are what parameters CreateWindowEx() takes:

dwExStyle
This tells it what style of window we want (In the example I used a plain static window)
lpClassName
This points to our class name we came up with earlier.
lpWindowName
This is the text that will apear in the title bar of out window.
dwStyle
This tells tells what style of window we are creating.
x
The inital horizontal starting position of the window (Set this to CW_USEDEFAULT if you want windows to pick a place)
y
The inital verticle starting position of the window (Set this to CW_USEDEFAULT if you want windows to pick a place)
nWidth
The width of the window (In pixels)
nHeight
The heighth of the window (In pixels)
hWndParent
The handle of the parent window (If one does not exist this is NULL)
hMenu
I dentifies a menu for the window (Only appleys if its a child window)
hInstance
Points to the hInstance of the window.
lpParam
Points to a value passed to the window through the CREATESTRUCT structure (I have never found a use for this, but I am sure one exists)
ShowWindow() sets the specified window's show state. UpdateWindow() updates the client area of the specified window by sending a WM_PAINT message to the window. The while loop will set our program to loop untill the WM_QUIT Message is recived. TranslateMessage() translates virtual-key messages into character messages. DispatchMessage() dispatches a message to a window procedure.

Now we get to probably the most important part of the program. The CallBack Procedure. What this is is a function with a giant switch() statment to switch off what each message should do (Sometimes this is a bunch of if's). Our callback takes the following parameters:

hwnd
Identifies the window.
uMsg
Specifies the message.
wParam
Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter.
lParam
Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter.
In our switch statment we see the first case is WM_CLOSE. This message tells us our use tried clicking the X in the corner or they press Alt-F4. Here we can prompt them to save or any other action we need to do. Then we call DestroyWindow(hwnd). Destroy Window takes one parameter:

hWnd
Identifies the window to be destroyed.
DestroyWindow() will sent the WM_DESTROY Message to our program, here we call PostQuitMessage(0). PostQuitMessage() takes one parameter:

nExitCode
Specifies an application exit code. This value is used as the wParam parameter of the WM_QUIT message.
PostQuitMessage() Will then send out the message WM_QUIT, but we will never get this message. WM_QUIT will cause the loop to return 0 and to exit the loop and also close our application. 1.4 Text
Source - Screen Shot
Now most windows programmers (including myself) never memorize much of that. We usually take a simple window application like that and use it as a skelaton for all of our new applications, adding what we need and changning things. This is what I am going to do throughout the entire tutorial. I will take this code form the last section and I will reuse it in all outher applications that have a window. Now next up how do we write text to our window? This to is not as simple as it may seem.


#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        HDC hdc;
        PAINTSTRUCT ps;
        LPSTR szMessage = "Hello World";

        switch(Message) {
                case WM_PAINT:
                        hdc = BeginPaint(hwnd, &ps);
                        TextOut(hdc, 70, 50, szMessage, strlen(szMessage));
                        EndPaint(hwnd, &ps);
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


This prints Hello World out on the screen, not very interesting I know, but we are learning. First to exapling what I added. At the top of the WinProc I added a few variables. hdc Identifies the display DC to be used for painting. ps is our paint structure the PAINTSTRUCT structure contains information for an application. This information can be used to paint the client area of a window owned by that application. message is just a simple character array that hold our message.

After that we can see i also added another case. Remember when I said above in Section 1.3 how the UpdateWidnow() send the message WM_PAINT, well here we can use it. First we tell hdc to recive painting information from BeginPaint(). BeginPaint() takes the following parameters:

hwnd
Identifies the window to be painted.
pPaint
Pointer to the PAINTSTRUCT structure that will receive painting information.
Then we use TextOut() to print text to the screen. TextOut() takes the following parameters:

hdc
Identifies the device context.
nXStart
Specifies the logical x-coordinate of the reference point that Windows uses to align the string.
nYStart
Specifies the logical y-coordinate of the reference point that Windows uses to align the string.
lpString
Points to the string to be printe dout (The string does not have to be \0 terminated, because cbString is the length)
cbString
Specifies the number of characters in the string.
Then EndPaint() tells the program to stop painting the screen. EndPaint() takes the following parameters:

hwnd
Identifies the window that was painted.
lpPaint
Points to a PAINTSTRUCT structure that contains the painting information retrieved by BeginPaint.
1.5 Menus

When programming there are usually a few ways to do things, making a windows menu is no different. I am going to go over the two main ways you can make a menu. I will have each one make the same menu but it will show you different ways of doing things.
1.5.1 Resources
Source - Screen Shot
Resources is probably the simplest way of making a menu. The menu is predefined in a resource file (always something.rc). The resource files are compiled by the resource compiler and linked to the program when the linker runs. This is the first program where I am also going to throw other files besides the source files in. There will be a resource file (*.rc) and a header file (*.h) in the zip along with a make file. Type make when you are in the directory of the source and Borlands should compile and link it all in the right order.


#define ID_FILE_NEW           1000
#define ID_FILE_OPEN          1001
#define ID_FILE_SAVE          1002
#define ID_FILE_EXIT          1003
#define ID_DO_SOMETHING       1004
#define ID_DO_SOMETHING_ELSE  1005
#define ID_HELP_ABOUT         1006


That is our header file. Here we just define all of the id's we are going to use so that we can just include this in both the resource file and the source file.

#include "section_1_5_1.h"

ID_MENU MENU DISCARDABLE
BEGIN
        POPUP "&File"
        BEGIN
                MENUITEM "&New",             ID_FILE_NEW
                MENUITEM "&Open",            ID_FILE_OPEN
                MENUITEM "&Save",            ID_FILE_SAVE
                MENUITEM SEPARATOR
                MENUITEM "E&xit",            ID_FILE_EXIT
        END
        POPUP "&Do"
        BEGIN
                MENUITEM "&Something",       ID_DO_SOMETHING
                MENUITEM "Something &Else",  ID_DO_SOMETHING_ELSE
        END
        POPUP "&Help"
        BEGIN
                MENUITEM "&About",           ID_HELP_ABOUT
        END
END


This is our resource file. Here we are derfining the layout of the menus and giving them message id's. These message id's have to be defined in both the resource file and the source file. This is why we use a header file to define them and then we just include the header file.

#include <windows.h>
#include "section_1_5_1.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = "ID_MENU";
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        switch(Message) {
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                case WM_COMMAND:
                        switch(LOWORD(wParam)) {
                                case ID_FILE_NEW:
                                        MessageBox(hwnd, "New File", "Menu", 0);
                                        break;
                                case ID_FILE_OPEN:
                                        MessageBox(hwnd, "Open File", "Menu", 0);
                                        break;
                                case ID_FILE_SAVE:
                                        MessageBox(hwnd, "Save File", "Menu", 0);
                                        break;
                                case ID_FILE_EXIT:
                                        PostQuitMessage(0);
                                case ID_DO_SOMETHING:
                                        MessageBox(hwnd, "Do Something", "Menu", 0);
                                        break;
                                case ID_DO_SOMETHING_ELSE:
                                        MessageBox(hwnd, "Do Something Else", "Menu", 0);
                                        break;
                                case ID_HELP_ABOUT:
                                        MessageBox(hwnd, "Written By AZTEK", "About", 0);
                                        break;
                        }
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


You see we changed the WndClass.lpszMenuName to what the name for our menu is. Then we added WM_COMMAND. This is the message that is posted when the user clicks a menu item. The ID of the item is sent with the message. We use LOWORD() to get the message from the lower owrd of the 32-bit. LOWORD() takes the following parameter:

dwValue
The value to get the low word from.
The next part will look to see what to do from the cases. If the user selects Exit it tells the program to do a PostQuitMessage(). None of this should be new. We already went over message boxes and the PostQuitMessage function. 1.5.2 On The Spot
Source - Screen Shot
Using resource menus are great if you have a menu that won't change. Some applications although require menus that can be made on the spot. This might be used to add or delete items from the menu or to make some items gray.


#define ID_FILE_NEW           1000
#define ID_FILE_OPEN          1001
#define ID_FILE_SAVE          1002
#define ID_FILE_EXIT          1003
#define ID_DO_SOMETHING       1004
#define ID_DO_SOMETHING_ELSE  1005
#define ID_HELP_ABOUT         1006


Since we are making an identicle program we will use the same header file as above.

#include <windows.h>
#include "section_1_5_2.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        HMENU hMenu, hSubMenu;

        switch(Message) {
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                case WM_CREATE:
                        hMenu = CreateMenu();

                        hSubMenu = CreatePopupMenu();
                        AppendMenu(hSubMenu, MF_STRING, ID_FILE_NEW, "&New");
                        AppendMenu(hSubMenu, MF_STRING, ID_FILE_OPEN, "&Open");
                        AppendMenu(hSubMenu, MF_STRING, ID_FILE_SAVE, "&Save");
                        AppendMenu(hSubMenu, MF_SEPARATOR, 0, 0);
                        AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");
                        AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");

                        hSubMenu = CreatePopupMenu();
                        AppendMenu(hSubMenu, MF_STRING, ID_DO_SOMETHING, "&Something");
                        AppendMenu(hSubMenu, MF_STRING, ID_DO_SOMETHING_ELSE, "Something &Else");
                        AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Do");

                        hSubMenu = CreatePopupMenu();
                        AppendMenu(hSubMenu, MF_STRING, ID_HELP_ABOUT, "&About");
                        AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Help");

                        SetMenu(hwnd, hMenu);
                        break;
                case WM_COMMAND:
                        switch(LOWORD(wParam)) {
                                case ID_FILE_NEW:
                                        MessageBox(hwnd, "New File", "Menu", 0);
                                        break;
                                case ID_FILE_OPEN:
                                        MessageBox(hwnd, "Open File", "Menu", 0);
                                        break;
                                case ID_FILE_SAVE:
                                        MessageBox(hwnd, "Save File", "Menu", 0);
                                        break;
                                case ID_FILE_EXIT:
                                        PostQuitMessage(0);
                                case ID_DO_SOMETHING:
                                        MessageBox(hwnd, "Do Something", "Menu", 0);
                                        break;
                                case ID_DO_SOMETHING_ELSE:
                                        MessageBox(hwnd, "Do Something Else", "Menu", 0);
                                        break;
                                case ID_HELP_ABOUT:
                                        MessageBox(hwnd, "Written By AZTEK", "About", 0);
                                        break;
                        }
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


At the top you may notice I set WndClass.lpszMenuName back to NULL. Thats because we are making the menu on the spot and don't need the resource file. First you might notice we added WM_CREATE. This is the message sent when the window is first created. We also declared two varibales of the type HMENU. You see that we set hMenu to CreateMenu(). This will start the whole menu. Then you see we set hSubMenu to CreatePopupMenu(). This will make a blank individual sub menu. We need to fill it. You see we call AppendMenu() to add items to our menus. AppendMenu() takes the following parameters:

hMenu
Identifies the menu bar.
uFlags
Specifies flags to control the appearance and behavior of the new menu item. This parameter can be a combination of values.
uIDNewItem
Specifies either the identifier of the new menu item or, if the uFlags parameter is set to MF_POPUP, the handle to the drop-down menu or submenu.
lpNewItem
Specifies the content of the new menu item.
After that we see SetMenu(), this is what actually displays the menu. SetMenu() takes the following parameters:

hWnd
Identifies the window to which the menu is to be assigned.
hMenu
Identifies the new menu. If this parameter is NULL, the window's current menu is removed.
1.6 Dialogs
Source - Screen Shot
Dialogs are a special kind of windows message box where you have a lot more control than just a title and some text. In dialogs you can have edit boxes, check boxes, icons, bitmaps, change colors, etc. It is easiest to design dialog boxes using a resource editor, you can find some in the Tools Section.


#define ID_FILE_EXIT   1000
#define ID_HELP_ABOUT  1001
#define IDOK           2000
#define IDEMAIL        2001
#define IDAZTEK        2003
#define IDBSRF         2004


This is our header file.

#include "section_1_6.h"

ABOUTDLG DIALOG 19, 17, 182, 71
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "About"
FONT 8, "MS Sans Serif"
BEGIN
        CTEXT         "Written by AZTEK", 101, 17, 30, 81, 11
        GROUPBOX      "About", 102, 11, 11, 95, 48, WS_TABSTOP
        DEFPUSHBUTTON "&Ok", IDOK, 112, 6, 64, 14
        PUSHBUTTON    "&E-mail AZTEK", IDEMAIL, 112, 21, 64, 14
        PUSHBUTTON    "Visit &AZTEK", IDAZTEK, 112, 36, 64, 14
        PUSHBUTTON    "Visit &Blacksun", IDBSRF, 112, 51, 64, 14
END

ID_MENU MENU
BEGIN
        POPUP "&File"
        BEGIN
                MENUITEM "E&xit",  ID_FILE_EXIT
        END
        POPUP "&Help"
        BEGIN
                MENUITEM "&About", ID_HELP_ABOUT
        END
END


This is our resource file. Next the ABOUTDLG DIALOG there are the diameters of our popup dialog box. The next line decalres some styles for the dialog. The third line is the caption or what will appear in the title bar of our window. The FONT 8, "MS Sans Serif" just states 8 point type in the font MS Sans Serif. CTEXT starts some standard text for our dialog. Group box just adds the frame aorund the text. Then DEFPUSHBUTTON decalres the default push button. The rest of the PUSHBUTTON's decalre normal pushable buttons. Now for our source file.

#include <windows.h>
#include "section_1_6.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        switch(Message) {
                case WM_COMMAND:
                        switch(LOWORD(wParam)) {
                                case ID_FILE_EXIT:
                                        PostMessage(hwnd, WM_CLOSE, 0, 0);
                                        break;
                                case ID_HELP_ABOUT:
                                        DialogBox(ghInstance, "ABOUTDLG", hwnd, DlgProc);
                                        break;
                        }
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        switch(Message) {
                case WM_INITDIALOG:
                        return TRUE;
                case WM_COMMAND:
                        switch(LOWORD(wParam)) {
                                case IDOK:
                                        EndDialog(hwnd, IDOK);
                                        return TRUE;
                                case IDEMAIL:
                                        ShellExecute(hwnd, "open", "mailto:aztek@faction7.com", 0, 0, 0);
                                        EndDialog(hwnd, IDEMAIL);
                                        return TRUE;
                                case IDAZTEK:
                                        ShellExecute(hwnd, "open", "http://aztek.faction7.com", 0, 0, 0);
                                        EndDialog(hwnd, IDAZTEK);
                                        return TRUE;
                                case IDBSRF:
                                        ShellExecute(hwnd, "open", "http://blacksun.box.sk", 0, 0, 0);
                                        EndDialog(hwnd, IDBSRF);
                                        return TRUE;
                        }
                        break;
        }
        return FALSE;
}


You will notice I added a new function, DlgProc(). This is known as the Dailog Procedure. This function although it returns the Boolen type takes the same parameters as WndProc(). This function is alot like the WndProc() function, it recives and acts on the messages for the dialog. We call DialogBox() to create the dialog. DialogBox() takes the following parameters:

hInstance
Handle to the windows instance.
lpTemplate
Identifies the dialog box template. Usually a null-terminated string.
hWndParent
Identifies the parent window of the dialog box.
pDialogFunc
Points to the window procedure for the Dialog Box
To end the dialog we use the function EndDialog(). EndDialog() takes the following parameters:

hDlg
Identifies the dialog box to be destroyed.
nResult
Specifies the value to be returned to the application.
What value you choose to give to nResult will be returned by the function DialogBox(). We use the function ShellExecute() to open the defualt e-mail and browser programs. ShellExecute() takes the following parameters:

hwnd
Specifies a parent window. This window receives any message boxes that an application produces.
lpOperation
Pointer to a null-terminated string that specifies the operation to perform.
lpFile
Pointer to a null-terminated string that specifies the file to open or print or the folder to open or explore.
lpParameters
If lpFile specifies an executable file, lpParameters is a pointer to a null-terminated string that specifies parameters to be passed to the application.
lpDirectory
Pointer to a null-terminated string that specifies the default directory.
nShowCmd
If lpFile specifies an executable file, nShowCmd specifies how the application is to be shown when it is opened.
1.7 Controls
Source - Screen Shot
Controls are just child windows like buttons, checkboxess, edit boxes, etc. For each control we make a new window using CreateWindowEx() but these are childs of the first main window and not new windows.


#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        HWND hButton, hCombo, hEdit, hList, hScroll, hStatic;

        switch(Message) {
                case WM_CREATE:
                        hButton = CreateWindowEx(
                                NULL,
                                "Button",
                                "Button",
                                WS_BORDER | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                0, 0,
                                100, 30,
                                hwnd, NULL,
                                ghInstance,
                                NULL);
                        hCombo  = CreateWindowEx(
                                NULL,
                                "ComboBox",
                                "",
                                WS_BORDER | WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST,
                                0, 30,
                                100, 100,
                                hwnd, NULL,
                                ghInstance,
                                NULL);
                        hEdit   = CreateWindowEx(
                                NULL,
                                "Edit",
                                "Edit",
                                WS_BORDER | WS_CHILD | WS_VISIBLE,
                                0, 60,
                                100, 30,
                                hwnd, NULL,
                                ghInstance,
                                NULL);
                        hList   = CreateWindowEx(
                                NULL,
                                "ListBox",
                                "",
                                WS_BORDER | WS_CHILD | WS_VISIBLE,
                                100, 0,
                                100, 200,
                                hwnd, NULL,
                                ghInstance,
                                NULL);
                        hScroll = CreateWindowEx(
                                NULL,
                                "ScrollBar",
                                "",
                                WS_BORDER | WS_CHILD | WS_VISIBLE | SBS_VERT,
                                210, 0,
                                100, 200,
                                hwnd, NULL,
                                ghInstance,
                                NULL);
                        hStatic = CreateWindowEx(
                                NULL,
                                "Static",
                                "",
                                WS_BORDER | WS_CHILD | WS_VISIBLE | SS_BLACKRECT,
                                0, 90,
                                100, 30,
                                hwnd, NULL,
                                ghInstance,
                                NULL);
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


In this example add some very simple controls to this window. There are many other controls you can use but these are the most simple and easy ones to add. Lokk in your windows programming help files for how to recive and send messages to these controls we added. 2. Intermediate

2.1 Bitmaps

In this section I will discus how to display a bitmap file in your program. The first way I will discus is the static way using a resource. The second way is to do it dynamicly using a actual bitmap file. Throughout our examples here I will use this bitmap file.
2.1.1 Resource
Source - Screen Shot
Using a bitmap from a resource file is probbaly the best way to do it unless you need the expandibility of a dynamic bitmap file.


#define IDB_BITMAP1   1000


This is are header file.

#include "section_2_1_1.h"

IDB_BITMAP1 BITMAP "bitmap.bmp"


Now for our source code.

#include <windows.h>
#include "section_2_1_1.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        HBITMAP hBitmap;
        HWND hBmpStat;

        switch(Message) {
                case WM_CREATE:
                        hBitmap  = LoadBitmap(ghInstance, MAKEINTRESOURCE(IDB_BITMAP1));
                        hBmpStat = CreateWindowEx(
                                NULL,
                                "Static",
                                "",
                                WS_VISIBLE | WS_CHILD | SS_BITMAP,
                                0, 0,
                                0, 0,
                                hwnd, NULL,
                                ghInstance,
                                NULL);
                        SendMessage(hBmpStat, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBitmap);
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


We use a new resource type BITMAP in our resource file. We use the type HBITMAP to define a variable to hold all of the information for loading the bitmap. We give hBitmap the value returned by LoadBitmap(). The function LoadBitmap() takes the following parameters:

hInstance
The instance of the current window.
lpszBitmapName
Points to a null-terminated string that contains the name of the bitmap resource to be loaded. We will use the macro MAKEINTRESOURCE()
The macro MAKEINTRESOURCE() takes the following parameters:

wInteger
Specifies the integer value to be converted.
You will notice that we also have to define a new static child window. This static window has the style SS_BITMAP. Then we use the function SendMessage() to tell the window to display the bitmap. The function SendMessage() takes the following parameters:

hWnd
Identifies the window whose window procedure will receive the message.
Msg
Specifies the message to be sent.
wParam
Specifies additional message-specific information.
lParam
Specifies additional message-specific information.
2.1.2 From a File
Source - Screen Shot
Loading a bitmap from a file is alot like loading one from a resource, in fact there is actually only 1 line change.


#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        HBITMAP hBitmap;
        HWND hBmpStat;

        switch(Message) {
                case WM_CREATE:
                        hBitmap  = (HBITMAP) LoadImage(NULL, "bitmap.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
                        hBmpStat = CreateWindowEx(
                                NULL,
                                "Static",
                                "",
                                WS_VISIBLE | WS_CHILD | SS_BITMAP,
                                0, 0,
                                0, 0,
                                hwnd, NULL,
                                ghInstance,
                                NULL);
                        SendMessage(hBmpStat, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBitmap);
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


You can see we only changed 1 line from LoadBitmap() to LoadImage(). The function LoadImage() takes the following parameters:

hInstance
The instance of the current procedure.
lpszName
Identifies the image to load.
uType
Specifies the type of image to be loaded.
cxDesired
Specifies the width, if this parameter is zero and LR_DEFAULTSIZE is not used, the function uses the actual image width.
cyDesired
Specifies the height, if this parameter is zero and LR_DEFAULTSIZE is not used, the function uses the actual image width.
fuLoad
Specifies additional flags for the image.
2.2 System Tray
Source - Screen Shot
The "Big Thing" for windows programs right now seems to be to put a icon in the system tray. In this next example we will go over putting a icon in in the system tray and having a menu pop up when the user right clicks on the icon.


#include "section_2_2.h"

IDI_ICON1 ICON "icon.ico"


Here is our resource file.

#define WM_TRAYNOTIFY (WM_USER + 1000)
#define IDI_ICON1     1000
#define IDC_TRAYICON  1001
#define IDM_EXIT      1002
#define IDM_ABOUT     1003


Our header file.

#include <windows.h>
#include "section_2_2.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;
HMENU hMenu;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        NOTIFYICONDATA notifyIconData;

        switch(Message) {
                case WM_CREATE:
                        notifyIconData.cbSize           = sizeof(NOTIFYICONDATA);
                        notifyIconData.hWnd             = hwnd;
                        notifyIconData.uID              = IDC_TRAYICON;
                        notifyIconData.uFlags           = NIF_MESSAGE | NIF_ICON | NIF_TIP;
                        notifyIconData.uCallbackMessage = WM_TRAYNOTIFY;
                        notifyIconData.hIcon            = (HICON) LoadImage(
                                                                        ghInstance,
                                                                        MAKEINTRESOURCE(IDI_ICON1),
                                                                        IMAGE_ICON,
                                                                        16, 16,
                                                                        NULL);
                        lstrcpyn(notifyIconData.szTip, "Tray Icon", sizeof(notifyIconData.szTip));
                        Shell_NotifyIcon(NIM_ADD, &notifyIconData);

                        hMenu = CreatePopupMenu();
                        AppendMenu(hMenu, MF_STRING, IDM_EXIT, "E&xit");
                        AppendMenu(hMenu, MF_SEPARATOR, NULL, NULL);
                        AppendMenu(hMenu, MF_STRING, IDM_ABOUT, "&About");
                        break;
                case WM_TRAYNOTIFY:
                        switch(wParam) {
                                case IDC_TRAYICON:
                                        switch(lParam) {
                                                case WM_LBUTTONDOWN:
                                                case WM_RBUTTONDOWN:
                                                        POINT point;

                                                        GetCursorPos(&point);
                                                        SetForegroundWindow(hwnd);
                                                        TrackPopupMenu(hMenu, TPM_RIGHTALIGN, point.x, point.y, NULL, hwnd, NULL);
                                                        SendMessage(hwnd, WM_NULL, NULL, NULL);
                                                        break;
                                        }
                                        break;
                        }
                        break;
                case WM_COMMAND:
                        switch(wParam) {
                                case IDM_EXIT:
                                        SendMessage(hwnd, WM_CLOSE, NULL, NULL);
                                        break;
                                case IDM_ABOUT:
                                        MessageBox(
                                                hwnd,
                                                "Example of a windows system tray program\r\nWritten by AZTEK",
                                                "About",
                                                NULL);
                                        break;
                                        break;
                        }
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        notifyIconData.cbSize = sizeof(NOTIFYICONDATA);
                        notifyIconData.hWnd   = hwnd;
                        notifyIconData.uID    = IDC_TRAYICON;
                        Shell_NotifyIcon(NIM_DELETE, &notifyIconData);

                        DestroyMenu(hMenu);

                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


You see we use a new resource type ICON. In our header file we define our messages. We use the NOTIFYICONDATA structure to hold the data that initilize the tray icon. The structure NOTIFYICONDATA has the following settings:

cbSize
Size of the NOTIFYICONDATA structure.
hWnd
Handle of the window that receives notification messages associated with an icon in the taskbar status area.
uID
Application-defined identifier of the taskbar icon.
uFlags
Array of flags that indicate which of the other members contain valid data.
uCallbackMessage
Application-defined message identifier. The system uses the specified identifier for notification messages that it sends to the window identified by hWnd whenever a mouse event occurs in the bounding rectangle of the icon.
hIcon
Handle of the icon to add, modify, or delete.
szTip
Tooltip text to display for the icon.
I will not go into the function lstrcpyn() since its a common C function and should be known aleady. We use the function Shell_NotifyIcon() to add/delete the icon from the tray. The function Shell_NotifyIcon() takes the following parameters:

dwMessage
Identifier of the message to send.
pnid
Pointer to a NOTIFYICONDATA structure. The content of the structure depends on the value of dwMessage.
We will use the POINT structure to hold data recived from GetCursorPos(). The structure POINT takes the following settings:

x
Specifies the x-coordinate of the point.
y
Specifies the y-coordinate of the point.
The function GetCursorPos() finds the cordinates of the mouse pointer and puts the data in a givin POINT structure. The function GetCurorPos() takes the following parameter:

lpPoint
Points to a POINT structure that receives the screen coordinates of the cursor.
The function SetForgroundWindow() sets what ever hwnd givin to the front and makes it the active window. The function SetForgroundWindow() takes the following parameter:

hWnd
Identifies the window that should be activated and brought to the foreground.
We use the function TrackPopupMenu() to popup and show the shortcut menu hMenu. The function TrackPopupMenu() takes the following parameters:

hMenu
Identifies the shortcut menu to be displayed.
uFlags
A set of bit flags that specify function options.
x
Specifies the horizontal location of the shortcut menu, in screen coordinates.
y
Specifies the vertical location of the shortcut menu, in screen coordinates.
nReserved
Reserved; must be zero.
hWnd
Identifies the window that owns the shortcut menu. This window receives all messages from the menu. The window does not receive a WM_COMMAND message from the menu until the function returns.
prcRect
Points to a RECT structure that specifies the portion of the screen in which the user can select without dismissing the shortcut menu. If this parameter is NULL, the shortcut menu is dismissed if the user clicks outside the shortcut menu.
Then we use SendMessage() to send the window a NULL message. When we recive the WM_DESTROY message we use the Shell_NotifyIcon() function to destroy and remove the icon from the system tray. 2.3 Toolbars
In this section I will cover how to add a toolbar to you window. I will first go over adding custom buttons from a bitmap file. The I will go over common buttons that are predefined.
2.3.1 Custom Buttons
Source - Screen Shot
Custom buttons are just a bitmap image that is devided up in 16x16 squares. In this next example, I use this bitmap file.


#include "section_2_3.h"

IDB_TOOLBAR BITMAP "toolbar.bmp"


Here is our resource file.

#define IDC_TOOLBAR  1000
#define IDB_TOOLBAR  1001
#define IDM_BUTTON0  1002
#define IDM_BUTTON1  1003
#define IDM_BUTTON2  1004
#define IDM_BUTTON3  1005
#define IDM_BUTTON4  1006
#define IDM_BUTTON5  1007
#define IDM_BUTTON6  1008
#define IDM_BUTTON7  1009


This is our header file.

#include <windows.h>
#include <commctrl.h>
#include "section_2_3_1.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;
HWND   ghToolBar;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        switch(Message) {
                case WM_CREATE:
                        TBADDBITMAP tbAddBitmap;
                        TBBUTTON tbButton[8];

                        InitCommonControls();

                        ghToolBar = CreateWindowEx(
                                NULL,
                                TOOLBARCLASSNAME,
                                NULL,
                                WS_CHILD | WS_VISIBLE,
                                0, 0,
                                0, 0,
                                hwnd, (HMENU)IDC_TOOLBAR,
                                ghInstance,
                                NULL);
                        SendMessage(ghToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), NULL);

                        tbAddBitmap.hInst = ghInstance;
                        tbAddBitmap.nID   = IDB_TOOLBAR;
                        SendMessage(ghToolBar, TB_ADDBITMAP, 0, (LPARAM) &tbAddBitmap);

                        ZeroMemory(tbButton, sizeof(tbButton));

                        tbButton[0].iBitmap   = 0;
                        tbButton[0].fsState   = TBSTATE_ENABLED;
                        tbButton[0].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[0].idCommand = IDM_BUTTON0;

                        tbButton[1].iBitmap   = 1;
                        tbButton[1].fsState   = TBSTATE_ENABLED;
                        tbButton[1].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[1].idCommand = IDM_BUTTON1;

                        tbButton[2].fsStyle   = TBSTYLE_SEP;

                        tbButton[3].iBitmap   = 2;
                        tbButton[3].fsState   = TBSTATE_ENABLED;
                        tbButton[3].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[3].idCommand = IDM_BUTTON2;

                        tbButton[4].iBitmap   = 3;
                        tbButton[4].fsState   = TBSTATE_ENABLED;
                        tbButton[4].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[4].idCommand = IDM_BUTTON3;

                        tbButton[5].fsStyle   = TBSTYLE_SEP;

                        tbButton[6].iBitmap   = 4;
                        tbButton[6].fsState   = TBSTATE_ENABLED;
                        tbButton[6].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[6].idCommand = IDM_BUTTON4;

                        tbButton[7].iBitmap   = 5;
                        tbButton[7].fsState   = TBSTATE_ENABLED;
                        tbButton[7].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[7].idCommand = IDM_BUTTON5;

                        SendMessage(ghToolBar, TB_ADDBUTTONS, 8, (LPARAM) &tbButton);
                        break;
                case WM_COMMAND:
                        switch(LOWORD(wParam)) {
                                case IDM_BUTTON0:
                                case IDM_BUTTON1:
                                case IDM_BUTTON2:
                                case IDM_BUTTON3:
                                case IDM_BUTTON4:
                                case IDM_BUTTON5:
                                        MessageBox(hwnd, "A Button was clicked.", "Toolbar Message", MB_ICONINFORMATION | MB_OK);
                                        break;
                        }
                        break;
                case WM_SIZE:
                        SendMessage(ghToolBar, TB_AUTOSIZE, 0, 0);
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


You will notice that we added a new header file, commctrl.h, this is the header file use for common controls. Common controls are dialogs like Open, Save, Print, etc that many program use it is also a set of controls to make toolbars and statusbars we will get into common controls more in the next tutorial. We declare a TBADDBITMAP structure. The TBADDBITMAP structure adds a bitmap that contains button images to a toolbar. It has the following parameters:

hInst
Handle to the module instance with the executable file that contains a bitmap resource.
nID
Resource identifier of the bitmap resource that contains the button images.
We also added a TBBUTTON structure. This is an array of the settings for each button of our toolbar. The array size has to be the number of buttons in our toolbar including separators since they are considered buttons also. The TBBUTTON structure has the following parameters:

iBitmap
Zero-based index of button image.
idCommand
Command identifier associated with the button. This identifier is used in a WM_COMMAND message when the button is chosen.
fsState
This is the state of the button.
fsStyle
This is the style of the button.
dwData
Application-defined value.
iString
Zero-based index of button string.
Then you see we run the function InitCommonControls(), the InitCommonControls() function ensures that the common control dynamic-link library (DLL) is loaded and that we can use the common controls such as toolbars. The we create our toolbar with CreateWindowEx(). The we send our toolbar the message TB_BUTTONSTRUCTSIZE to tell the system how much space to allocate for our toolbar. The we set our TBADDBITMAP parameters and then send then to the toolbar with the message TB_ADDBITMAP. We use ZeroMemory() to make sure that there is no data in the tbButton structure. We then create 2 buttons then a separator and so on. Then at the end we send our tbButtons structure to the toolbar with the message TB_ADDBUTTONS. We also added a new message trap the WM_SIZE, this message is sent to the program everytime the user resizes the window. When the window is resized we need to tell the toolbar to move and adjust so we send it the TB_AUTOSIZE message. 2.3.2 Common Buttons
Source - Screen Shot
It would be a real pain if you had to make new New, Open, Save, etc. buttons for every application you write, so they came up with common buttons. Common buttons are buttons used by alot of apps. Below I have a common button program example, I will explain the new parts but its pretty much the same as the custom button example above.


#define IDC_TOOLBAR  1000
#define IDM_BUTTON0  1001
#define IDM_BUTTON1  1002
#define IDM_BUTTON2  1003
#define IDM_BUTTON3  1004
#define IDM_BUTTON4  1005
#define IDM_BUTTON5  1006
#define IDM_BUTTON6  1007
#define IDM_BUTTON7  1008


Our header file.

#include <windows.h>
#include <commctrl.h>
#include "section_2_3_2.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;
HWND   ghToolBar;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        switch(Message) {
                case WM_CREATE:
                        TBADDBITMAP tbAddBitmap;
                        TBBUTTON tbButton[7];

                        InitCommonControls();

                        ghToolBar = CreateWindowEx(
                                NULL,
                                TOOLBARCLASSNAME,
                                NULL,
                                WS_CHILD | WS_VISIBLE,
                                0, 0,
                                0, 0,
                                hwnd, (HMENU)IDC_TOOLBAR,
                                ghInstance,
                                NULL);
                        SendMessage(ghToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), NULL);

                        tbAddBitmap.hInst = HINST_COMMCTRL;
                        tbAddBitmap.nID   = IDB_STD_SMALL_COLOR;
                        SendMessage(ghToolBar, TB_ADDBITMAP, 0, (LPARAM) &tbAddBitmap);

                        ZeroMemory(tbButton, sizeof(tbButton));

                        tbButton[0].iBitmap   = STD_FILENEW;
                        tbButton[0].fsState   = TBSTATE_ENABLED;
                        tbButton[0].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[0].idCommand = IDM_BUTTON0;

                        tbButton[1].iBitmap   = STD_FILEOPEN;
                        tbButton[1].fsState   = TBSTATE_ENABLED;
                        tbButton[1].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[1].idCommand = IDM_BUTTON1;

                        tbButton[3].iBitmap   = STD_FILESAVE;
                        tbButton[3].fsState   = TBSTATE_ENABLED;
                        tbButton[3].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[3].idCommand = IDM_BUTTON2;

                        tbButton[5].fsStyle   = TBSTYLE_SEP;

                        tbButton[4].iBitmap   = STD_CUT;
                        tbButton[4].fsState   = TBSTATE_ENABLED;
                        tbButton[4].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[4].idCommand = IDM_BUTTON3;

                        tbButton[6].iBitmap   = STD_COPY;
                        tbButton[6].fsState   = TBSTATE_ENABLED;
                        tbButton[6].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[6].idCommand = IDM_BUTTON4;

                        tbButton[7].iBitmap   = STD_PASTE;
                        tbButton[7].fsState   = TBSTATE_ENABLED;
                        tbButton[7].fsStyle   = TBSTYLE_BUTTON;
                        tbButton[7].idCommand = IDM_BUTTON5;

                        SendMessage(ghToolBar, TB_ADDBUTTONS, 7, (LPARAM) &tbButton);
                        break;
                case WM_COMMAND:
                        switch(LOWORD(wParam)) {
                                case IDM_BUTTON0:
                                case IDM_BUTTON1:
                                case IDM_BUTTON2:
                                case IDM_BUTTON3:
                                case IDM_BUTTON4:
                                case IDM_BUTTON5:
                                        MessageBox(hwnd, "A Button was clicked.", "Toolbar Message", MB_ICONINFORMATION | MB_OK);
                                        break;
                        }
                        break;
                case WM_SIZE:
                        SendMessage(ghToolBar, TB_AUTOSIZE, 0, 0);
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


As you can see not much overall has changed but the first thing you might notice is that tbAddBitmap.hInst is now set to HINST_COMMCTRL and that tbAddBitmap.nID is set to IDB_STD_SMALL_COLOR this just tell it to use the standard buttons and not a bitmap. And now our iBitmap is a STD_ and not a number. The STD_ is what our button will be like STD_COPY is the copy button. There is not much difference besides that. 2.4 Status Bars
Source - Screen Shot
We have all seen status bars. Most text editing programs have a statusbar. They can be very useful, but they can also be one of the most abused thing in windows programming.


#define IDC_STATBAR 1000


Our header file.

#include <windows.h>
#include <commctrl.h>
#include "section_2_4.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[]  = "MyWindowClass";
static HINSTANCE ghInstance = NULL;
HWND   ghStatBar;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        WNDCLASSEX WndClass;
        HWND hwnd;
        MSG Msg;

        ghInstance = hInstance;

        WndClass.cbSize        = sizeof(WNDCLASSEX);
        WndClass.style         = NULL;
        WndClass.lpfnWndProc   = WndProc;
        WndClass.cbClsExtra    = 0;
        WndClass.cbWndExtra    = 0;
        WndClass.hInstance     = ghInstance;
        WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
        WndClass.lpszMenuName  = NULL;
        WndClass.lpszClassName = gszClassName;
        WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

        if(!RegisterClassEx(&WndClass)) {
                MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        hwnd = CreateWindowEx(
                WS_EX_STATICEDGE,
                gszClassName,
                "Windows Title",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                320, 240,
                NULL, NULL,
                ghInstance,
                NULL);

        if(hwnd == NULL) {
                MessageBox(0, "Window Creation Failed!", "Error!", MB_ICONSTOP | MB_OK);
                return 0;
        }

        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

        while(GetMessage(&Msg, NULL, 0, 0)) {
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
        }
        return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
        switch(Message) {
                case WM_CREATE:
                        int iBarWidths[] = {100, 200, 300, -1};
                        InitCommonControls();

                        ghStatBar = CreateWindowEx(
                                NULL,
                                TOOLBARCLASSNAME,
                                NULL,
                                WS_CHILD | WS_VISIBLE,
                                0, 0,
                                0, 0,
                                hwnd, (HMENU)IDC_TOOLBAR,
                                ghInstance,
                                NULL);
                        SendMessage(ghStatBar, SB_SETPARTS, 4, (LPARAM) iBarWidths);

                        SendMessage(ghStatBar, SB_SETTEXT, 0, (LPARAM) "Part 1");
                        SendMessage(ghStatBar, SB_SETTEXT, 1, (LPARAM) "Part 2");
                        SendMessage(ghStatBar, SB_SETTEXT, 2, (LPARAM) "Part 3");
                        SendMessage(ghStatBar, SB_SETTEXT, 3, (LPARAM) "Part 4");
                        break;
                case WM_SIZE:
                        SendMessage(ghStatBar, WM_SIZE, 0, 0);
                        break;
                case WM_CLOSE:
                        DestroyWindow(hwnd);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hwnd, Message, wParam, lParam);
        }
        return 0;
}


You will see I defined a array of integers at the top of WM_CREATE these are the widths of the sections we will break the statusbar into. A value of -1 will take up the remaining space. Then we create our statusbar with CreateWindowEx(). We then send our statusbar the widths with the message SB_SETPARTS the WPARAM is how many parts we will brak it into. The we set some text fo the parts with the message SB_SETTEXT. The WPARAM of SB_SETTEXT is the zero-based index of the part. When we received the windows you will see in the WM_SIZE trap that we send the statusbar the WM_SIZE message that we just received so it can adjust properly. Appendix

A. The Compiler

I like most of you are pretty low on cash most of the time. So I use a free compiler from Borland. I also use the old Borland 5.02 the last one with an IDE. I also got my hands on a copy of Visual C++ 6 ( not going to say how) which I didn't find all that great and pretty intrusive. All of the examples in this tutorial were compiled with the Borland Free Compiler v5.5 check the tools section for a link to where you can download it. After you get the compiler set up correctly just open up a command line and browse to where you unziped the tutorials. The compile using:


C:\Cpp\tutorial\examples\section_1_2> bcc32 -tW section_1_2.cpp


The -tW parameter tells the compiler to link to the windows library and make a windows application and not a dos application. Some of the more complicated examples have a makefile.mak file, this is a make file. Just browse to that directory and type "make" (without quotes) to compile that example. I do not support people who e-mail me about Dev-C++. Personally I do not like that program. The IDE is great but the compiler is probably the worst I have ever used. So just use the program for an IDE and the use Borland for a compiler its what I did for a while until I found a better IDE (its listed in the tools section). B. Tools

Every great programmer has to have a few good tools he uses. The first being his compiler and IDE. Here I have listed a few tools I find that might be useful.


  • Borland Free 5.5 Compiler - A great overall windows compiler, and its FREE!
  • MultiEdit - A good overall IDE that I use all the time
  • Komodo - Another really good IDE that I find myself using alot
  • Win API Reference - You cannot consider yourself a windows programmer unless you have this, it is a must have!
  • LCC-Win32 - A fairly nice compiler with a user interface and a good resource editor
That probably pretty much covers it for the major tools I would recommend. C. Links

These are a few sights I find invaluable to learning programming of any type.

I am sure there are alot more so if you think of any I missed e-mail me. D. Shoutouts

Wow I can't believe I finaly got this thing done. I hope this tutorial has helped you all. I am looking forward to writing another one. To go over even more advanced topics. I would like to give shout outs to all my felow Blacksun Research Facility Members especialy Mikkkeee, DigitalFallout, Cyberwolf, and SpiderMan. Also To all of those of you in #bsrf, #neworder, #linux, and #code who wouldn't shut up until we help you with your questions :) And especially to cube and the rest of the Box Network Team for the great job they have done.

AZTEK

How to hack someone with his IP address

Introduction
1. Welcome to the basic NETBIOS document created by aCId_rAIn. This document
will teach you some simple things about NETBIOS, what it does, how to use it, how to
hack with it, and some other simple DOS commands that will be useful to you in the
future.
1. Hardware and Firmware
1a. The BIOS
The BIOS, short for Basic Input/Output Services, is the control program of the PC.
It is responsible for starting up your computer, transferring control of the system to
your operating system, and for handling other low-level functions, such as disk access.
NOTE that the BIOS is not a software program, insofar as it is not purged from
memory when you turn off the computer. It's
firmware, which is basically software on a chip.
A convenient little feature that most BIOS manufacturers include is a startup
password. This prevents access to the system until you enter the correct password.
If you can get access to the system after the password has been entered, then there
are numerous software-based BIOS password extractors available from your local
H/P/A/V site.
NETBIOS/NBTSTAT - What does it do?
2. NETBIOS, also known as NBTSTAT is a program run on the Windows system and is
used for identifying a remote network or computer for file sharing enabled. We can
expoit systems using this method. It may be old but on home pc's sometimes it still
works great. You can use it on your friend at home or something. I don't care what
you do, but remember, that you are reading this document because you want to learn.
So I am going to teach you. Ok. So, you ask, "How do i get to NBTSTAT?" Well, there
are two ways, but one's faster.
Method 1:Start>Programs>MSDOS PROMPT>Type NBTSTAT
Method 2:Start>Run>Type Command>Type NBTSTAT
(Note: Please, help your poor soul if that isn't like feeding you with a baby spoon.)
Ok! Now since you're in the DOS command under NBTSTAT, you're probably
wondering what all that crap is that's on your screen. These are the commands you
may use.Your screen should look like the following:
NBTSTAT [ [-a RemoteName] [-A IP address] [-c] [-n]
[-r] [-R] [-RR] [-s] [-S] [interval] ]
-a (adapter status) Lists the remote machine's name table given its name
-A (Adapter status) Lists the remote machine's name table given its IP address.
-c (cache) Lists NBT's cache of remote [machine] names and their IP addresses
-n (names) Lists local NetBIOS names.
-r (resolved) Lists names resolved by broadcast and via WINS
-R (Reload) Purges and reloads the remote cache name table
-S (Sessions) Lists sessions table with the destination IP addresses
-s (sessions) Lists sessions table converting destination IP addresses to computer
NETBIOS names.
-RR (ReleaseRefresh) Sends Name Release packets to WINS and then, starts
Refresh
RemoteName Remote host machine name.
IP address Dotted decimal representation of the IP address.
interval Redisplays selected statistics, pausing interval seconds between each display.
Press Ctrl+C to stop redisplaying
statistics.
C:\WINDOWS\DESKTOP>
The only two commands that are going to be used and here they are:
-a (adapter status) Lists the remote machine's name table given its name
-A (Adapter status) Lists the remote machine's name table given its IP address.
Host Names
3. Now, the -a means that you will type in the HOST NAME of the person's computer
that you are trying to access. Just in case you don't have any idea what a Host Name
looks like here's an example.
123-fgh-ppp.internet.com
there are many variations of these adresses. For each different address you see
there is a new ISP assigned to that computer. look at the difference.
abc-123.internet.com
ghj-789.newnet.com
these are differnet host names as you can see, and, by identifying the last couple
words you will be able to tell that these are two computers on two different ISPs.
Now, here are two host names on the same ISP but a different located server.
123-fgh-ppp.internet.com
567-cde-ppp.internet.comIP Addresses
4. You can resolce these host names if you want to the IP address (Internet Protocol)
IP addresses range in different numbers. An IP looks like this:
201.123.101.123
Most times you can tell if a computer is running on a cable connection because of the
IP address's numbers. On faster connections, usually the first two numbers are low.
here's a cable connection IP.
24.18.18.10
on dialup connections IP's are higher, like this:
208.148.255.255
notice the 208 is higher than the 24 which is the cable connection.
REMEMBER THOUGH, NOT ALL IP ADDRESSES WILL BE LIKE THIS.
Some companies make IP addresses like this to fool the hacker into believing it's a
dialup, as a hacker would expect something big, like a T3 or an OC-18. Anyway This
gives you an idea on IP addresses which you will be using on the nbtstat command.
Getting The IP Through DC (Direct Connection)
5. First. You're going to need to find his IP or host name. Either will work. If you are
on mIRC You can get it by typing /whois (nick) ...where (nick) is the persons nickname
without parenthesis. you will either get a host name or an IP. copy it down. If you do
not get it or you are not using mIRC then you must direct connect to their computer
or you may use a sniffer to figure out his IP or host name. It's actually better to do
it without the sniffer because most sniffers do not work now-a-days. So you want to
establish a direct connection to their computer. OK, what is a direct connection?
When you are:
Sending a file to their computer you are directly connected.
AOL INSTANT MESSENGER allows a Direct Connection to the user if accepted.
ICQ when sending a file or a chat request acception allows a direct connection.
Any time you are sending a file. You are directly connected. (Assuming you know the
user is not using a proxy server.)
Voice Chatting on Yahoo establishes a direct connection.
If you have none of these programs, either i suggest you get one, get a sniffer, or
read this next statement.
If you have any way of sending thema link to your site that enables site traffic
statistics, and you can log in, send a link to your site, then check the stats and get
the IP of the last visitor. It's a simple and easy method i use. It even fool some
smarter hackers, because it catches them off guard. Anyway, once you are directly
connected use either of the two methods i showed you earlier and get into DOS. Type
NETSTAT -n. NETSTAT is a program that's name is short for NET STATISTICS. It
will show you all computers connected to yours. (This is also helpful if you think you
are being hacked by a trojan horse and is on a port that you know such as Sub Seven:
27374.)Your screen should look like this showing the connections to your computer:
------------------------------------------------------------------------------------------------
C:\WINDOWS\DESKTOP>netstat -n
Active Connections
Proto Local Address Foreign Address State
TCP 172.255.255.82:1027 205.188.68.46:13784 ESTABLISHED
TCP 172.255.255.82:1036 205.188.44.3:5190 ESTABLISHED
TCP 172.255.255.82:1621 24.131.30.75:66 CLOSE_WAIT
TCP 172.255.255.82:1413 205.188.8.7:26778 ESTABLISHED
TCP 172.255.255.82:1483 64.4.13.209:1863 ESTABLISHED
C:\WINDOWS\DESKTOP>
------------------------------------------------------------------------------------------------
The first line indicated the Protocol (language) that is being used by the two
computers.
TCP (Transfer Control Protocol) is being used in this and is most widely used.
Local address shows your IP address, or the IP address of the system you on.
Foreign address shows the address of the computer connected to yours.
State tells you what kind of connection is being made ESTABLISHED - means it will
stay connected to you as long as you are on the program or as long as the computer is
allowing or is needing the other computers connection to it. CLOSE_WAIT means the
connection closes at times and waits until it is needed or you resume connection to be
made again. One that isn't on the list is TIME_WAIT which means it is timed. Most
Ads that run on AOL are using TIME_WAIT states.
the way you know the person is directly connected to your computer is because of
this:
------------------------------------------------------------------------------------------------
C:\WINDOWS\DESKTOP>netstat -n
Active Connections
Proto Local Address Foreign Address State
TCP 172.255.255.82:1027 205.188.68.46:13784 ESTABLISHED
TCP 172.255.255.82:1036 205.188.44.3:5190 ESTABLISHED
TCP 172.255.255.82:1621 24.131.30.75:66 CLOSE_WAIT
TCP 172.255.255.82:1413 abc-123-ppp.webnet.com ESTABLISHED
TCP 172.255.255.82:1483 64.4.13.209:1863 ESTABLISHED
C:\WINDOWS\DESKTOP>
------------------------------------------------------------------------------------------------Notice the host name is included in the fourth line instead of the IP address on all.
This is almost ALWAYS, the other computer that is connected to you. So here, now,
you have the host name:
abc-123-ppp.webnet.com
If the host name is not listed and the IP is then it NO PROBLEM because either one
works exactly the same. I am using abc-123-ppp.webnet.com host name as an example.
Ok so now you have the IP and/or host name of the remote system you want to
connect to. Time to hack!
Open up your DOS command. Open up NBTSTAT by typing NBTSTAT. Ok, there's
the crap again. Well, now time to try out what you have leanred from this document
by testing it on the IP and/or host name of the remote system. Here's the only thing
you'll need to know.
IMPORTANT, READ NOW!!!
-a (adapter status) Lists the remote machine's name table given its name
-A (Adapter status) Lists the remote machine's name table given its IP address.
Remember this?
Time to use it.
-a will be the host name
-A will be the IP
How do i know this?
Read the Statements following the -a -A commands. It tells you there what each
command takes.
So have you found which one you have to use?
GOOD!
Time to start.
Using it to your advantage
6. Type this if you have the host name only.
NBTSTAT -a (In here put in hostname without parenthesis)
Type this is you have the IP address only.
NBTSTAT -A (In here put in IP address without parenthesis)
Now, hit enter and wait. Now Either one of two things came up
1. Host not found
2. Something that looks like this:
--------------------------------------------
NetBIOS Local Name Table
Name Type Status
---------------------------------------------
GMVPS01 <00> UNIQUE Registered
WORKGROUP <00> GROUP Registered
GMVPS01 <03> UNIQUE Registered
GMVPS01 <20> UNIQUE Registered
WORKGROUP <1E> GROUP Registered---------------------------------------------
If the computer responded "Host not found" Then either one of two things are the
case:
1. You screwed up the host name.
2. The host is not hackable.
If number one is the case you're in great luck. If two, This system isn't hackable
using the NBTSTAT command. So try another system.
If you got the table as above to come up, look at it carefully as i describe to you each
part and its purpose.
Name - states the share name of that certain part of the computer
<00>, <03>, <20>, <1E> - Are the Hexidecimal codes giving you the services available on
that share name.
Type - Is self-explanatory. It's either turned on, or activated by you, or always on.
Status - Simply states that the share name is working and is activated.
Look above and look for the following line:
GMVPS01 <20> UNIQUE Registered
See it?
GOOD! Now this is important so listen up. The Hexidecimanl code of <20> means that
file sharing is enabled on the share name that is on that line with the hex number. So
that means GMVPS01 has file sharing enabled. So now you want to hack this. Here's
How to do it. (This is the hard part)
LMHOST File
7. There is a file in all Windows systems called LMHOST.sam. We need to simply add
the IP into the LMHOST file because LMHOST basically acts as a network,
automatically logging you on to it. So go to Start, Find, FIles or Folders. Type in
LMHOST and hit enter. when it comes up open it using a text program such as
wordpad, but make sure you do not leave the checkmark to "always open files with
this extension" on that. Simply go through the LMHOST file until you see the part:
# This file is compatible with Microsoft LAN Manager 2.x TCP/IP lmhosts
# files and offers the following extensions:
#
# #PRE
# #DOM:
# #INCLUDE
# #BEGIN_ALTERNATE
# #END_ALTERNATE
# \0xnn (non-printing character support)
#
# Following any entry in the file with the characters "#PRE" will cause
# the entry to be preloaded into the name cache. By default, entries are
# not preloaded, but are parsed only after dynamic name resolution fails.
## Following an entry with the "#DOM:" tag will associate the
# entry with the domain specified by . This affects how the
# browser and logon services behave in TCP/IP environments. To preload
# the host name associated with #DOM entry, it is necessary to also add a
# #PRE to the line. The is always preloaded although it will not
# be shown when the name cache is viewed.
#
# Specifying "#INCLUDE " will force the RFC NetBIOS (NBT)
# software to seek the specified and parse it as if it were
# local. is generally a UNC-based name, allowing a
# centralized lmhosts file to be maintained on a server.
# It is ALWAYS necessary to provide a mapping for the IP address of the
# server prior to the #INCLUDE. This mapping must use the #PRE directive.
# In addtion the share "public" in the example below must be in the
# LanManServer list of "NullSessionShares" in order for client machines to
# be able to read the lmhosts file successfully. This key is under
# \machine\system\currentcontrolset\services\lanmans
erver\parameters\nullsessionshares
# in the registry. Simply add "public" to the list found there.
#
# The #BEGIN_ and #END_ALTERNATE keywords allow multiple #INCLUDE
# statements to be grouped together. Any single successful include
# will cause the group to succeed.
#
# Finally, non-printing characters can be embedded in mappings by
# first surrounding the NetBIOS name in quotations, then using the
# \0xnn notation to specify a hex value for a non-printing character.
Read this over and over until you understand the way you want your connection to be
set. Here's an example of how to add an IP the way I would do it:
#PRE #DOM:255.102.255.102 #INCLUDE
Pre will preload the connection as soon as you log on to the net. DOM is the domain or
IP address of the host you are connecting to. INCLUDE will automaticall set you to
that file path. In this case as soon as I log on to the net I will get access to
255.102.255.102 on the C:/ drive. The only problem with this is that by doin the
NETSTAT command while you are connected, and get the IP of your machine. That's
why it only works on simple PC machines. Because people in these days are computer
illiterate and have no idea of what these commands can do. They have no idea what
NETSTAT is, so you can use that to your advantage. Most PC systems are kind of
hard to hack using this method now because they are more secure and can tell when
another system is trying to gain access. Also, besure that you (somehow) know
whether they are running a firewall or not because it will block the connection to
their computer. Most home systems aren't running a firewall, and to make it better,they don't know how operate the firewall, therefore, leaving the hole in the system.
To help you out some, it would be a great idea to pick up on some programming
languages to show you how the computer reads information and learn some things on
TCP/IP (Transfer Control Protocol/Internet Protocol) If you want to find out
whether they are running a firewall, simply hop on a Proxy and do a port scan on their
IP. You will notice if they are running a firewall because most ports are closed. Either
way, you still have a better chance of hacking a home system than hacking Microsoft.
Gaining Access
7. Once you have added this to you LMHOST file. You are basically done. All you need
to do is go to:
Start
Find
Computer
Once you get there you simply type the IP address or the host name of the system.
When it comes up, simply double click it, and boom! There's a GUI for you so you
don't have to use DOS anymore. You can use DOS to do it, but it's more simple and
fun this way, so that's the only way i put it. When you open the system you can edit,
delete, rename, do anything to any file you wish. I would also delete the command file
in C:/ because they may use it if they think someone is in their computer. Or simply
delete the shortcut to it. Then here's when the programming comes in handy. Instead
of using the NBTSTAT method all the time, you can then program you own trojan on
your OWN port number and upload it to the system. Then you will have easier access
and you will also have a better GUI, with more features. DO NOT allow more than one
connection to the system unless they are on a faster connection. If you are
downloading something from their computer and they don't know it and their
connection is being slow, they may check their NETSTAT to see what is connected,
which will show your IP and make them suspicious. Thats it. All there is to it. Now go
out and scan a network or something and find a computer with port 21 or something
open.

How To Rename Your Recycle Bin

1. Click Start / Run
2. Type regedit and press enter.
3. Open the HKEY_CLASSES_ROOT folder
4. Open the CLSID folder
5. Open the {645FF040-5081-101B-9F08-00AA002F954E} folder
6. Open the ShellFolder folder
7. Change the "Attributes" data value from "40 01 00 20" to "50 01 00 20". Once
completed change the "CallForAttributes" dword value to "0x00000000" (double-
click and change value data to 0). You must change both of these values to get the
rename to appear.
After performing the above steps you will be able to rename the icon like any other
icon. Right-click the Recycle Bin icon on the desktop and click Rename and rename it
to whatever you wish.

How To Close Ports

So i've been looking for a while on just how to close a port on a computer. I simply
couldn't find a way. Well, i finally found it. This'll only work for windows users (unless
your unix version OS has netsh).
it's actually quite simple. here's the command for it:
netsh firewall delete portopening TCP portnumber
it's that simple. Simply go to START -> RUN -> and type in that command up there,
and it'll close it for you.
or, you can also open up command prompt (START -> RUN -> CMD) and type in "netsh"
without the quotes to get to your windows firewall settings.
however, since i'm such a nice guy, i wrote it all out in a vbs script for you so that it's
automatically runable. as well as a batch script. so here you are fellas:
.VBS Script
set ss = createobject("wscript.shell")
set ws = wscript
dim PORT
PORT = InputBox("Enter the port you wish to close:")
ss.run "netsh.exe"
ws.sleep 1000
ss.sendkeys "firewall delete portopening TCP " & PORT
ss.sendkeys "{enter}"
ws.sleep 500
'ss.sendkeys "exit"
'ss.sendkeys "{enter}"
.BAT Script
@echo off
title Port Closer
echo Port Closer
echo.
set /p port=Type the port number you wish to close here:
netsh firewall delete portopening TCP %port%
msg /w * Port %port% has been closed.
exit