Contents

Tutorials
Win32 Hello World in a Message Box
Win32 Hello World in a Dialog Box
Win32 Hello World in a Window

Advanced Topics
Allowing only a single instance to run
Using DDE.

Related Links

Q83456 Introduction to STRICT and Message Crackers
Q243953 HOWTO: Limit 32-bit Applications to One Instance Using C++
Avoiding Multiple Instances of an Application Written by Joseph M. Newcomer Co.



Tutorial 1 - MessageBox Hello World

This tutorial (and those that follow) assume some familarity with the C language. I do not want to waste paragraphs explaining how to create projects in a particular development enviroment, or explain the difference between compile and link errors, and how to solve them.

So this tutorial demonstrates how to create the most simple "Hello World" application possible. Start by - in your particular development enviroment - creating an empty Win32 application project. Now, add a single .C file to it and paste in the following text.

#include <windows.h>

int
CALLBACK
WinMain(
  HINSTANCE hInstance,
  HINSTANCE hInstNULL,
  LPSTR lpszCmdLine,
  int nCmdShow)
{
  return MessageBox(
    NULL,
    "Hello World",
    "Tutorial Example 1",
    MB_OK|MB_ICONINFORMATION);
}

This incredibly simple application should now compile and run. There are some things worth noting even in this simple example:



Tutorial 2 - Dialog Box Hello World

Welcome to Tutorial number 2: A simple dialog box application.

If you want to make a "form" type of application, a Dialog box is the way to go. Dialog boxes are created from a resource that specifies the layout of a number of controls. Text, buttons, edit controls, list boxes etc, all can be embedded in a dialog box.

Using a dialog box for your main window in a form type application has a number of advantages.

To create a Dialog box: CreateDialog, CreateDialogIndirect, CreateDialogParam, CreateDialogIndirectParam, DialogBox, DialogBoxIndirect, DialogBoxParam, DialogBoxIndirectParam are the functions that will create a dialog box. The CreateDialogXXX functions all create the dialog box, and then return control. The DialogBoxXXX functions create and show the dialog box, and only return when the dialog box is destroyed.

#define STRICT
#include <windows.h>
#include "resource.h"

BOOL CALLBACK DialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
  switch(uMsg)
  {
  case WM_INITDIALOG:
    return TRUE;
    
  case WM_COMMAND:
    if(wParam==IDOK || wParam==IDCANCEL)
      EndDialog(hwndDlg,wParam);
      
    return TRUE;
  }
  return FALSE;
}


int WINAPI WinMain(
  HINSTANCE hInstance,
  HINSTANCE hInstNULL,
  LPSTR pszCmdLine,
  int nCmdShow)
{
  return DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DIALOG),HWND_DESKTOP,DialogProc,0L);
}

Remarks:



Window Classes:

Microsoft windows applications are usually made up of a number of "window" objects that interact with the user and display information. There are a number of diffrent types of window (window classes) provided by the system that each perform diffrent functions. Each class has a class name that is used to identify it.

Here are most of Windows built in classes:

Some other types that you don't access directly:



Tutorial 3 - Window Hello World

Welcome to Tutorial number 3: Implementing a "frame window".

For applications more complex that can be handled by a dialog box, you will need to implement your own window class. Implementing your own window class gives you full control over whats displayed, when its displayed, and how the keyboard interacts with the window.

The "Classic" Window application:

The classic frame window visually consits of an application encompassing border (hence "frame" window), a title bar a menu bar, and a "client" area (the "client" area is the large square area left over in the middle ). The frame window normally paints its client area some neutral color (grey), and uses a number of "child" windows to display information. Child windows would be: A status bar, a tool bar, and a "view" window.

Use spy++ to look at this notepad window now: You will see that it is a "Notepad" class window with an "EDIT" class window as its child.

Example Files:

Window Classes: (again)

A "window class" is a type of window that Windows knows how to work with. Each class has a text name used to identify the class, when an application needs to create an instance of that class. You register a new window class by calling the API function RegisterClass.

Creating Windows:

You (the programmer) creates an instance of a window class by calling the CreateWindowEx function. The second parameter is the name of the window class that is required. There are a number of possible sytle parameters."WS_OVERLAPPEDWINDOW" is the most common used for frame windows :- it tells Windows to create the window with a thick sizeable border, with a title bar, an icon, close button, minimise and maximise buttons. CW_USEFEFAULT is passed in for the position and size to tell windows to use its defaults.

CreateWindowEx returns a "window handle" that the application uses in calls to API functions to identify the window.

Header Files:

A header file, it is important to remember, is no diffrent from a .cpp file - only its extension differs. The diffrence between .cpp and .h is purely one of convention, and the convention goes as follows:

C and C++ are like pascal in that the compiler cannot compile a refrence to an undefined or undeclared function. In laymans terms, if you wanna use a function in your code, the compiler has to have compiled it already. C and C++ make the matter worse, as functions may be defined in an entirely diffrent .cpp file from where the programmer wishes to use them.

So, what you do is "declare" the function or variable: a simple statement tells the compiler what the function looks like, but not whats actually in it. Like so:

int my_function();

This statement tells the compiler that a function called "my_function" exists that returns an int, and takes no parameters. If this statement is palced in a .cpp file, and subsequently a call is made to the function, the call will compile as the compiler knows about the function.

Of course you must also define the function, that is give it some meat. This can be done later in the same .cpp file, or even in a diffrent .cpp file in the project:

int my_function()
{
  return 5+36;
}

So, what we c and c++ programmers do when we write a new .c or .cpp file is make a header file with all the functions declared in it, so other programmers don't have to type them in every time they wish to use them.

The crunch: The crunch is that you must never include any definitions (any "body") in a header file. Quite often a single header file is included multiple times in multiple .cpp files in a project, and while the compiler will happily handle seeing the same declaration over and over again, it will hurl chunks if it sees any definition a 2nd time.

The windowsx.h file:

windowsx.h is a usefull file supplied by microsoft for the API programmer. It defines a number of things very usefull to the budding hacker. One of the more usefull are the HANDLE_MSG macros. Instead of writing a rather complicated switch statement, full of cases, breaks, returns, and function calls to handle your window procedure you simply make a switch statement, and on each line indicate which message to handle:

  switch(uMsg)
  {
  HANDLE_MSG(hwnd,WM_CREATE,OnCreate);
  HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy);
  }

The 1st parameter is the window handle. the 2nd is the message id of the message, and the 3rd function is the name of the function that you want to handle the message. windowsx.h decodes the parameters for each message, and requires that the function takes the decoded parameters. Look in windowsx.h for prototypes for each message type.

See Q83456 for more info regarding windowsx.h



Single Instance Applications

For a number of applications it is usefull to only allow a single instance to run at a time. The simplest behaviour to implement is an application that on startup attempts to find a previous instance of itself and give that instance the foreground. Note that if the application in question is registered with the shell to open documents a better solution would be to register it as a DDE server. Also, the method presented here has a number of caveats:

  1. Ensure that the windows classname (mpszClassName) is unique. A GUID would make a very good candidate.
  2. This method only protects against the same application being run multiple times on the same desktop. For a more extreme solution, go here.

// Function: CreateAppWindow
//
// Return Values:
//   TRUE - the app window was created successfuly.
//   FALSE - the app window was not created - probably because a previous
//           instance was found (and restored). Abort this instance.
BOOL CreateAppWindow()
{
  BOOL fResult = false;

  HANDLE hLock = CreateMutex(NULL,FALSE,"MYCREATEMUTEX");

  // If WaitForSingleObject(,0) returns anything other than WAIT_OBJECT_0
  // it should indicate that something else owns the mutex already.
  // Rather than waiting around we take the cue to exit immediately.
  if(WAIT_OBJECT_0 == WaitForSingleObject(hLock,0))
  {
    HWND hwndPrev;

    if(hwndPrev = FindWindow(mpszClassName,NULL))
    {
      ShowWindowAsync(hwndPrev,SW_RESTORE);
      SetForegroundWindow(hwndPrev);
    }
    else
    {
      fResult = RealCreateAppWindow();
    }
    ReleaseMutex(hLock);
  }
  CloseHandle(hLock);

  return fResult;
}



Using DDE as a means to open documents.

no info yet.