Thursday, March 28, 2024 | Toby Opferman
 

WIN32 Programming

Toby Opferman
http://www.opferman.net
programming@opferman.net




                              Win32 Quick Tutor

     This is a quick Win32 tutor that should get you started making Win32
API programs quickly.  This is by no means a reference but only a starter.
We will cover general operations and programs, we will not get into a lot
of detail, but only touch on a few topics.


     Getting started, I first want to point out that windows is an event
driven operating system.  This means that your programs do not run 
independently of the Operating System, but rather they run in conjunction
and cooperate with the Operating System.  They must wait until the Operating
System sends them a message.  If you do not know the concept of event driven
programming, please read the GUI tutor.

     What I assume in this tutor is that you know the concept of event 
driven programming, you have programmed before in some operating system,
you have worked with C and/or Assembly language.  Let's get started.


     First thing you want to do in windows program is create your window.
Now, this is very basic tutor with a very basic program model.  When you
learn more and need to do more, you should be at a level to be able to
figure it out or find an advanced tutor on what you want to do.  For this
tutor, we just want to create a window that performs some actions.

     Now, it varies what you want to do.  You may want to force one 
instance of your program with FindWindow API Function, but we are not
going to do so in this example.  We are going to:

   Define Our Window
   Create Our Window
   Process Messages That Are Sent To Our Window

    First, let me exaplain the WinMain.  If you are using assembly, you can
skip this section for the most part, and read the Win32 Assembly tutors
after reading this document.  You may want to refer back for the
description of a HINSTANCE though.

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR Cmdlne, int nCmdShow)

Ok, we will start disecting the WinMain call.

HINSTANCE hInstance
 
  What is a HINSTNACE??? That's probably your first thought.  You look 
at the parameters to WinMain() and what the hell is all this shit.  I
once read borland documentation years back for Turbo C++ 3.0 for Windows.
That compiler would let you make DOS programs and they would run in
windows.  printf would work, main() could be used, it would generate
the window for you (It was slow as shit of course).  But in the documentation
it said something simular to the effect of you can use main() instead of
WinMain and having to deal with all the confusing parameters and confusing
& complex WinMain declaration, etc.  Basicaly, was saying that declaring a 
WinMain function is complex and the parameters it takes are so hard to 
understand what they do.  This is totally untrue.  WinMain is just as
easy to understand as a main().  It has 4 parameters and will always
have 4 parameters.  main() has from 2 or 3 depending.  (The 3rd isn't ANSI)
So, you have more parameters to learn, but let me tell you this.
You will only be interested in ONE.  Maybe later, you may do something
with the others but basically a Windows program can ignore them.  Infact
one of them is obselete and you will NEVER use it, it will ALWAYS be 0.

Ok, back to our original Question.  What is an HINSTANCE and why are there
two of them???

HINSTANCE is Handle to an Instance.  Basically your application is
one instance of itself.  HINSTANCE is a handle to your application.
Just like files had handles in DOS, everything in windows has handles.
When you make certain applcation API calls, it wants to know what
application called it.  So, you send it a handle to your instance.
It also tells what instance of your application called it.

The second parameter, PrevhInstance is obselete.  It used to bring in
the previous instance of your program (If you have more than 1 session
of it running).  This enabled you to see if there were more than 1
of your program running, there you could not create this window and
say "Only One Session Allowed" or something.  Windows provides an API
function called FindWindow()  That should help you do the same.
But, you may ignore this parameter to winmain.


PSTR  is Pointer To a String.  It's the command line arguments.
You can basically ignore this for now, unless you plan on doing
command line.   Most windows programs are clicked without parameters,
but you can still make this take parms.


int nCmdShow  There is a special parm to tell the window how you want to
start it.  Default is maximumized. You can either use this or ignore it and
use your own.  In my examples, I ignore this and use my own.  This would
be used in the CreateWindowEx function and in the ShowWindow Function
usually.  You can ignore it and pass 0 to CreateWindowEx and pass
a SW_xxx constant to ShowWindow.


If you are using Assembly, you probably would also like to have an
HINSTANCE variable.  HINSTANCE hInstance; in C, but this is given to
you in the WinMain in C.  You can get it in assembly with a GetModule
Call.  It returns it in EAX.  HINSTANCE can be defined as a dd (dword).
(Please referr back up for the description of a HINSTANCE and what it's
purpose is.)

PUSH L 0
CALL GetModule
MOV [hInstance], EAX

That is how to get your instance.


    Ok, first up is Creating our window.  There is a structure, called
WNDCLASS (WNDCLASSEX also) (Window Class) that defines everything you need to define your
window.  We will go through them here.  

 The Structure of WNDCLASS
   I'm  NOT going to go into detail on this.  I will just show you what you need so
   you don't have to deal with this until you are more experienced with Win32.  For now,
   I am going to show you just what you need so you can just start making small programs.

  style = 0;
     This specifies a certain style, for more information, look this up in
     a win32 reference manual to see what styles you can use.  You can just
     assign a 0 to it for most of your beginner programs.
    
  cbSize = sizeof(wndclass);
     Just the size of WNDCLASS here.

  lpfnWndProc = WndProc;
    This is a pointer to your callback function.  Put the CALLBACK function name
    and assign it to this.  We will get into callback functions later.      


  cbClsExtra = 0;
  cbWndExtra = 0;
    Just extra data you can define, you can just say 0 for now.


  hInstance = hInstance;
     Just your HINSTANCE.


  hIcon = LoadIcon(NULL, IDI_APPLICATION);
      This defines an ICON.  If you have one in a resource file, you
      can assign it (You can look that up later in a Win32 ref manual) but for
      now, just assign the above default app.

  hCursor = LoadCursor(NULL, IDC_ARROW);
      Assigns a cursor.  You will probably just want to use the default for now.


  hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
      Paint the background.  You can specify GRAY_BRUSH, WHITE_BRUSH or BLACK_BRUSH.
      You can look up how to define other colors later, just use these 3 for now.

  lpszMenuName = NULL;
      Defines a menu, don't worry about this until you learn resource files.

  lpszClassName = "ProgName";
      Just put a 1 word description of your program and also use it in the CreateWindow
      Function.

  hIconSm = LoadIcon(NULL, IDI_APPLICATION);
     Same as other Icon.  Just load default. 
 


   Now, you call RegisterClass with the address of your WNDCLASS structure.

Asm:
PUSH OFFSET WC
CALL RegsiterClass
MOV [hwnd], EAX

C:
hwnd = RegisterClass(&wc);


   Now, you ask what that hwnd thing is.  Well, RegisterClass will return                                              
a HWND, or Handle To a Window.  If this hwnd is 0, then the window wasn't
created. You may want to exit your program.  With this handle to a window,
you use it in any function that pertains to a window.  that hwnd can get you
everything associated with the window.  If you ever worked with FILES in
C or assembly.  INT 21h returned a handle in BX and fopen returned a FILE*.
Those were handles.  When you wanted to do something to that file, you HAD
to specify that handle (or called a pointer in C).  Well, this is no
differnt, same concept with a window.
   

   Now, we got our handle and our window is registered, we need to 
create the window.  We do this with CreateWindowEx.  This function
takes a few parameters that describe how the window will look &
start out when it's created.  It also describes the type of window
you want.  We will go through the parameters here.

This tutor is just tring to get you familar enough to make minimal programs.
To get a better understanding of the functions, please look in a Win32 reference
guide as they can explain the parameters better and list all the options.


hwnd = CreateWindowEx(NULL, "ProgName", "First Program",WS_OVERLAPPEDWINDOW,
                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                        NULL, NULL, hInstance, 0);
Use NULL as first parameter.

Second parameter, use the same class name you used int the WndClass strucutre.

Next parameter sets the Window Bar Program Title.

The next parm describes the type of window.  You should look up this function for a complete
list and description.

The Next define the starting position, and the size of the window on start up, you
can just use CW_USEDEFAULT to have it just start anywhere.

Ignore next two parameters, and then just pass your hInstance and just ignore the last
parameter.

Assembly people: Check the return value in EAX, if it is 0, then 
window wasn't created and you should exit.

C People: Check the return value of CreateWindowEx and if it's 0,
then the window wasn't created and you should exit.


Two steps here.   They help to display the window.

ShowWindow(hwnd, SW_SHOWNORMAL);
Tells the window to be shown.


UpdateWindow(hwnd);

This makes the window paint itself.



Finally, the message loop.
This is quite simple.

while(GetMessage(&msg, 0, 0, 0))
{
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}



Variables needed in WinMain:

MSG msg;
  This is your Message Structure, you don't really need to worry about
  what all it contians as a beginning Win32 programmer.


HWND hwnd;
  This is a Handle to a window.  As I explained before, it's just like
  getting handles in any Operating System, it is basically an ID that
  lets the OS know what you are referring to when you issue specific
  API calls.  Basically, any Window API call needs a handle to a
  window. (Any window you create has it's own HWND.  If your program
  has multiple windows or dialog boxes, each one has a unique HWND
  associated with it).

WNDCLASS wc;
  This you only need to worry about on defining your window.  It helps
  windows know what your window will contain and it will accomodate 
  what you specifiy on a RegisterClass Call.
  

  (NOTE: There is also WNDCLASSEX and RegisterClassEx, just a few more
         places on the windows structure, you could use either.)
                                             


Handles And Windows
        Mostly everything in windows is referred to as a Handle.  You 
learned HINSTANCEs are handles to an instance of your application,
you learned HWND's are handles to a specific window, and now I will
show you HDC's.  HDC is Handle to Device/Display Context.  Majority of
the time you will use HDC's for your display or screen functions.  If
you were a DOS user who liked low level access to the screen, that is
no more (This is Win32 not DirectX).  You get a HDC to your window, 
bitmaps, or double buffers and you draw on them.  Most the Win32
Graphics API functions take a HDC as a parameter.  You can define
a double buffer HDC and then "blt" it onto your screen HDC. That
was for those who use double buffers in DOS.  Your application may
not require a double buffer.




What is a CALLBACK function?

	Our final stop.  This is a quick overview.



 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static HINSTANCE hInstance;
    
  switch(msg)
  {
      case WM_CREATE:
                      hInstance = ((LPCREATESTRUCT) lParam)->hInstance;
                      
                      return 0;
                        
      case WM_DESTROY :  PostQuitMessage(0);
                       return 0;
  }

 return DefWindowProc(hwnd, msg, wParam, lParam);
}

This is basically a minimal Windows CALL BACK function.  As you know, windows will
send this a message when something happens.  There are differnt Messages like WM_PAINT,
WM_KEYDOWN, WM_KEYUP, etc.  You should consult a reference manual on the specs of all 
of them.  Each message can have values passed in wParam and lParam you can typecast
into differnt variables.  As you see in the above example, lParam in WM_CREATE message
is a pointer to a CREATESTRUCT.  And it's used to get the hInstance.

You must define the function as LRESULT CALLBACK and if you don't process the message,
you need to call DefWindowProc(); or depending on the message, you can have evil side
affects happen to your program.  Mostly, the main message WM_PAINT is the one that will
mess up the most if you don't process it right.  If you are making the function and do:

WM_PAINT:
          return 0;

and just have that there as temp until you write the whole code, windows will think
your program handled the WM_PAINT and may cause side affects such as window not even
display on the screen.  So, you must be careful.  Basicly, the parameters to a callback are:

Handle to the Window
The Message
Parameter #1
Parameter #2

Param #1 and #2 vary depending on the message as I said before.  You should look up the
specs for the message so you know what's in them.




Well, I hope you understand Win32 a little better than you did before.  I suggest you either 
experiment and look at some examples or look for another tutor with more detail.  If you
are going to do ASM, I suggest you can look at the Win32 tutors here.  Otherwise, you can
also search the net or go to web links on my page to find more tutors/examples.  Under Code,
there is a WinPong Win32 asm code example.  
 
About Toby Opferman

Professional software engineer with over 15 years...

Learn more »
Codeproject Articles

Programming related articles...

Articles »
Resume

Resume »
Contact

Email: codeproject(at)opferman(dot)com