This document was originally prepared by Michael Janzen <mjanzen@uoguelph.ca> during the 2004 Winter term.


This assumes you have downloaded the newskel code.  For an explanation of the newskel code you can see the heavily commented version.

Please note that there is more than one way to do things. This is only explaining on possible way.

To Add a Resource Script

To Add a Menu

To Respond to Menu Selections

Adding an Accelerator

Changing the icons

Changing the Cursor

Adding a Bitmap

The two step process is a bit weird, but here it is

Things to Note

When modifying the WndProc function you probably want to only call a function, which actually accomplishes what you want to do. Otherwise the WndProc function becomes unweildly lengthy.

Some windows messages

WM_CREATE

WM_DESTROY

WM_COMMAND

WM_PAINT

WM_LBUTTONDOWN

WM_RBUTTONDOWN

Creating a Static Library

  • Right click on your project workspace and select "Add New Project to Workspace"
  • Select Win32 Static Library, name your project and click "OK"
  • Click "Finish" then "OK". You don't need to check off either of the checkboxes
  • Add a source file and header file to your new project (File->New->C++ Source file, etc ..)
  • Include windows.h in your header file and prototype any functions you want to have
  • In your source file, include your header file and define the body of the functions specified in the header file
  • Using a Static Library

  • Click your "Windows 32 Application" project (the first one) and then select "Dependencies" from the "Project" menu.
  • Add your static library as a dependency by clicking the checkbox
  • Alternatively you could include the .lib file. You may need to do this is you are using someone elses library and you cannot simply specify a dependency since you do not have access to the static library project.
  • Include the resource header in your application's .cpp file. Be careful to specify the correct directory (wherever your static library's header file is located
  • Call the function somewhere from your application's code
  • Creating a Dynamic Library

    Using a Dynamic Library

    Using a Timer

    Sometimes it is handy to have a windows message come at regular intervals. To do this you can use a timer. There are three main parts to using a timer.

    Preliminary

    Okay. Prior to the first part you need to have an identifier for your timer. You can just use an integer or you can define a constant.
    const INT TIMER_ID =	100;	/* ID for timer control */
    

    Starting the Timer

    Handling the Timer Message

    The timer will send a message at regular intervals. The message is a WM_TIMER message. To handle the message just as the case to your WndProc function.

    Stopping the Timer

    To shut off the timer, use the KillTimer function. You need to pass the handle of the window, and the ID of the timer. (Remember there could be more than one timer, so you need to specify which one to stop).

    Something to Note

    The timer is approximately correct. However, Windows could get busy so the interval between WM_TIMER messages might be a little longer than your specified. Also timer messages can build up in the message queue, so you may get a whole bunch of timer messages on after each other.

    Dialogs

    Modal versus Non-Modal

    Dialogs come in two forms: modal and non-modal. When a modal dialog is activated you must close the dialog before returning to your main window. (You can do things in the dialog before returning to the main window.) A modeless dialog is slightly more complicated because both the dialog and the rest of the program can receive input.

    Writing back-end of a dialog

    Windows will "handle" a lot of your controls with respect to appearance. When a radio button is clicked windows changes which radio button is selected. Windows will draw the checkbox automatically when the checkbox is toggled. However you will need to add the code of what should actually be done.

    Buttons

    As mentioned above when a button is clicked your dialog function is sent a WM_COMMAND message. The button ID is in the LOWORD of the wParam.
    Some dialog items are actually buttons where you may not consider to be buttons. For example, push buttons, checkboxes and radio buttons are all buttons.

    Edit Boxes

    You can read from an edit box using the GetDlgItemText(...) function. You can also set the text in a dialog box using the SetDlgItemText It should be noted that you can use GetDlgItemText and SetDlgItemText with dialog items that are not edit boxes. For example, you can change the text (or read the text) on a button.

    Check Boxes

    As mentioned above the Check Box sends a WM_COMMAND message when clicked. You can also send the check box messages using SendDlgItemMessage

    Radio Buttons

    Same as checkboxes. Note: Although possible, it is not a good idea to check more than one radio button at once. (A quick way to confuse a user).

    WM_INITDIALOG

    This message is sent to your dialog function when the dialog is started. (Like the WM_CREATE message sent to your main window).

    Tackbar (a.k.a slider control)

    Some messages that can be sent to your trackbar include: Note: There are other messages that can be sent to trackbars.

    Ending the Dialog Box

    Use EndDialog(..) to end the dialog box

    Modeless Dialog Boxes

    To create a modeless dialog box use the CreateDialog(..) function instead of the DIalogBox(...) function One more thing to do to make a modeless dialog box
    Your GetMessage(...) box in your message loop may take a handle to a window as a parameter. This causes only messages for your window to be received. However, you also want the messages for your modeless dialog box. So change the handle to the window to NULL in the GetMessage(...) function call. This will cause the message loop to receive all messages - both the ones for your window and the ones for your modeless dialog box.

    Creating a Thread

    A thread allows you to have two parts of your program run concurrently. This can be very useful. For example, you if one part of your program freezes or deadlocks, the other part of your program can continue to run (very useful for running a server, especially when the client can be untrustworthy or unstable). Another example is that you can put computationally expensive processes in their own thread so that your program can continue responding to GUI processing.

    One way to create a thread is to use the CreateThread function

    The lpThreadFunc should point to a function that has the following form: Unfortunately, there is a bit of a memory leak with the CreateThread function. Threre are two solutions to this problem

    Other Thread Functions

    Note: Some people consider it problematic to pause and resume threads as the code can become deadlock prone.

    Semaphores

    Sometimes it is required that only one process or thread use a resource or section of code at a time. The solution is to have a semaphore.

    Think of a bathroom that doesn't lock properly. Before someone enters the bathroom they ask to doorman if it is okay. If the doorman says it is alright, they enter and use the bathroom. After they are finished they tell the doorman that they are done.
    Now rather than say okay, the doorman may say to wait. The process waits until one of two things happens. First the person ahead of them may leave the bathroom and the doorman will then allow the waiting process access to the controlled resource. Alternatively the process may become "impatient" and leave. This corresponds to a timeout.

    If you haven't guessed yet the doorman corresponds to a semaphore.

    A semaphore works by decrementing a count when a thread requests access and incrementing when the thread releases the semaphore. When the count is zero the semaphore blocks access (the threads wait until another thread releases).

    To create a semaphore use the following API call

    Using a semaphore

    To request access use WaitForSingleObject() To release a semaphore use use ReleaseSemaphore().

    Back to CTEC1638