52949.fb2 theForgers Win32 API Tutorial - читать онлайн бесплатно полную версию книги . Страница 5

theForgers Win32 API Tutorial - читать онлайн бесплатно полную версию книги . Страница 5

Appendices

Appendix A: References

Books

If you expect anyone online to treat you with respect while you are learning, you NEED to get a good book to learn from. We're here to provide direction and explain things that need explaining, not to be your librarian or teach you step by step.

Programming Windows

by Charles Petzold. The book to get on Win32 API. If you want to write programs using just the API (which is what this tutorial covers), you need this book.

Programming Windows with MFC

by Jeff Prosise. If you want to venture into MFC (after becoming fully accustomed to using the Win32 API), this is the book for you. If you don't like MFC but intend on getting a job doing windows developement, get this anyway, it's better to know than not.

Programming Applications for Windows

by Jeffrey Richter. Not for newbies, if you want to be up on managing processes and threads, dlls, windows memory management, exception handling, and hooking into the system, then this is the book for you.

Visual C++ Windows Shell Programming

by Dino Esposito. For anyone interested in the visual and user-friendly aspects of windows, this book covers writing extentions to the windows shell, working efficiently with files and drag and drop, customizing the taskbar and windows explorer, and numerous other tricks. Well worthwhile for anyone writing GUI apps in windows.

Network Programming for Microsoft Windows

Up to date information on network programming, including NetBIOS, mailslots and pipes, and of course the ever important windows sockets, complete with winsock2 and raw sockets. Also contains specific information on the various windows platforms including 2000 and CE.

Links

MSDN Online

This site has references for all imaginable Microsoft technologies, including full Win32 API and MFC documentation. If this didn't come with your compiler (ie. VC++) then the completely free online site will provide you with the required information. People will get really pissed off if you ask questions you could answer by doing a simple search on MSDN.

#winprog homepage

See Links and Resources

Appendix B: Free Borland C++ Command Line Tools

Getting Them

Fortunately for anyone that wants to get into windows developement, Borland has offered its command line tools to the general public for FREE. Isn't that nice of them? There is no pretty IDE or resource editor, but beggers can't be choosers, and I'd have to say the compiler itself is of far better quality than either LCC-Win32 (which doesn't even do C++) or the various ports of other tools, gcc, mingw, cygwin, djgpp etc…

Read the readme to get yourself set up.

Borland C++ 5.5

What's extra spiffy is it even comes with a debugger! I don't use this, so I can't offer much help on it, but it's better than nothing. And if you're used to Turbo C++ from the DOS days, then this should be right up your ally.

For some reason Internet Explorer seems to have a problem with downloading this file, so if it clicking the link doesn't work, right click and Copy Shortcut, and then use your favourite FTP client to get it.

Turbo Debugger

Last but not least, a windows help file with full Win32 API reference. It's a few years old but still entirely accurate and much more convenient than MSDN online unless you need access to the most recent additions to the API (which if you're on this page, you don't). I use it regularly.

Win32 API Reference

Using Them

Basic commands

If you want to compile a single file program (simple_window.c for example), then you can use the following command:

bcc32 –tW simple_window.c

The -tW switch specifies a Win32 GUI application, instead of the default console application. You can compile multiple files into a single.exe by adding the other files to the end  of this command.

Linking in Resources

This is a very frustrating issue for many users of the command line tools, and no wonder, since it seems borland tried to make it as hard as possible to link resources into your applications, the resource compiler brc32 no longer behaves as it did in earlier versions of the program where it would link the compiled resource into the .exe itself. When you run brc32 with no option to get the usage help, it still lists an option to turn .exe linking OFF, there simply appears to be no way to turn it ON.

I tried various combinations of command and options, but couldn't find any way to add a .res file to an .exe build with the above method. Which really sucks, cause the way I found to do it is a lot more complicated.

There is an easier way however…

BC++ now has an alternative method of including resources in a program by use of a #pragma (a non-standard preprocessor directive that compilers will ignore if they don't recognise it).

#pragma resource "app_name.res"

Placing this code in your main .c or .cpp file will cause the compiler to automatically link in the .res file that is generated from your .rc (.res is like an .obj file for resources).

Using the #pragma will allow you to compile programs nearly as simply as above, but you still need to compile the .rc file first using brc32. If you still want to use command line options as I did in the tutorial makefiles, read on…

The hard way…

These are the commands to use to compile the dlg_one example, including the resource.

bcc32 –c –tW dlg_one.c

ilink32 –aa –c –x –Gn dlg_one.obj c0w32.obj,dlg_one.exe,,import32.lib cw32.lib,,dlg_one.res

Nice eh? The -c option to bcc32 means compile only, don't link into an .exe. The -x –Gn options get rid of some extra files the linker creates that you probably don't need.

The real bugger with this is that since we are manually specifying the linker command, we need to include the default libraries and objs that the compiler would normally do for us. As you can see above, I've specified the appropriate files for a regular windows application.

To make things easier on yourself, it's best to do all this in a makefile. I've prepared a generic one that should work with all of the examples in the tutorial, and you should be able to adapt it to any of your own programs.

APP = dlg_one

EXEFILE = $(APP).exe

OBJFILES = $(APP).obj

RESFILES = $(APP).res

LIBFILES =

DEFFILE =

.AUTODEPEND

BCC32 = bcc32

ILINK32 = ilink32

BRC32 = brc32

CFLAGS = –c –tWM– –w –w-par –w-inl –W –a1 –Od

LFLAGS = –aa –V4.0 –c –x –Gn

RFLAGS = –X –R

STDOBJS = c0w32.obj

STDLIBS = import32.lib cw32.lib

$(EXEFILE) : $(OBJFILES) $(RESFILES)

 $(ILINK32) $(LFLAGS) $(OBJFILES) $(STDOBJS), $(EXEFILE), , \

  $(LIBFILES) $(STDLIBS), $(DEFFILE), $(RESFILES)

clean:

 del *.obj *.res *.tds *.map

You only need to modify the first 6 lines with the appropriate information.

Appendix C: Why you should learn the API before MFC

The Controversy

Too many people come on to IRC and ask "What is better, MFC or API?" and too many people are willing to say "MFC sucks" or "API sucks" either because of traumatic events involving one or the other in early childhood, or because everyone else is saying it.

The standard arguments are:

• API is too hard

• MFC is too confusing

• API is too much code

• MFC is bloated

• API doesn't have wizards

• MFC is badly designed

• API isn't Object Oriented

• MFC kicked my dog

• API stole my girlfriend

And so on…

My Answer

My opinion, although by no means the only one, is that you should use the right framework for the right job.

First of all a clarification on what the API and MFC are. API is a generic term meaning Application Programming Interface, however in the context of Windows programming, it means specifically the Windows API, which is the lowest level of interaction between applications and the windows operating system. Drivers of course have even lower levels, and different sets of function calls to work with, but for the vast majority of windows development this is not an issue. MFC is a Class Library, it's a bunch of C++ classes that have been written to reduce the amount of work it takes to do certain things with the API. It also introduces an (arguably) Object Oriented framework into the application that you can either take advantage of or ignore, which is what most beginners do since the framework isn't really aimed at writing MP3 players, IRC clients or games.

Every program, whether it is written with MFC, Delphi, Visual Basic, perl, or any other wacked out language or framework you can think of, is eventually built upon the API. In many cases this interaction is hidden, so you don't deal directly with the API, the runtime and support libraries do it for you. Some people ask, "MFC can do Blah Blah Blah, can the API?" The answer is that MFC can only do what the API can do, because it's built on top of it. However doing things yourself with the API may take considerably more code than using the pre-written MFC classes.

So what is the right framework? For starters, for people that are just learning to program, I strongly believe that you should work with the API untill you are comfortable with the way windows applications work and you understand all of the basic mechanics behind things like the message loop, GDI, controls, and maybe even multithreading and sockets. This way you will understand the fundamental building blocks of all windows applications, and can apply this common knowledge to MFC, Visual Basic, or whatever other framework you choose to work with later. It's also important because these other frameworks don't support everything that the API does, simply because it does a whole lot and they can't necessarily support all of the arcane little things that most people won't use. So when you finally do need to use them you need to add it yourself, you can't rely on the framework to do it for you and if you don't understand the API this could be quite the chore.

But isn't MFC easier? In a certain sense it's easier in that many common tasks are done for you, thus reducing the amount of code that you need to actually type. However, less code does not mean "easier" when you don't understand the code you DO need to write, or how all of the code that is there to support you actually works. Generally beginners who use the wizards to start there applications have no idea what most of the generated code does, and spend a great deal of time trying to figure out where to add things, or what changes to make to acheive a certain result. If you start your programs from scratch, either in the API or with MFC, then you know where everything is because you put it there, and you will only use features that you understand.

Another important factor is that most people that are learing the Win32 API for the first time don't already have a strong base in C++. To try and comprehend windows programming with MFC and learn C++ at the same time can be a monumental task. Although it's not impossible, it will take you considerably longer to become productive than if you already knew either C++ or the API.

So basically…

What it comes down to is that I think you should learn the API untill you feel comfortable with it, and then try out MFC. If it seems like it's making sense to you and saving you time, then by all means use it.

However, and this is important… If you work with MFC without understanding the API and then ask for help with something, and the answer you get is stated using the API (such as "Use the HDC provided in the WM_CTLCOLORSTATIC message") and you say "huh?" because you don't know how to translate an API subject into MFC on your own, then you are in trouble and people will get frustrated with you for not learning what you need to know before you try and use MFC.

I personally prefer to work with the API, it just suits me better, but if I were to write a database frontend, or a host for a set of ActiveX controls I would seriously consider using MFC, as it would eliminate a lot of code that I would need to reinvent otherwise.

Appendix D: Resource file notes

Argh!

The one thing I really hated when I switched my primary development environment from Borland C++ to MS Visual C++ was the way VC++ handles resource scripts (.rc files).

In BC++ was free to control the layout and content of the .rc files, and when using the resource editor, only the things that I specifically changed in the editor got changed in the resource file. Much to my dismay, the VC++ resource editor will completely rewrite your .rc file, and possibly destroy or ignore any changes that you personally make.

This was terribly frustrating at first, but I basically learned to deal with it and it's not SO bad after a while, since in general I don't write any amount of my resources by hand, but reserve that for minor changes that perhaps I can't quite accomplish in the editor.

Compatibility

One small challange for this tutorial was to make the resource files compile properly under VC++ and BC++ without changes. In the original tutorial I used the Borland naming convention for the resource header, which was project_name.rh . However by default in VC++ this header is ALWAYS called resource.h, so for simplicity I've adopted this for the current tutorial revision, as it doesn't impact BC++ at all.

For the curious, it is possible to change the name of the resource that VC++ uses by editing the .rc file manually and changing the name in two places, once where it is #include d, and second where it is contained in a TEXTINCLUDE resource.

The next problem is that by default VC++ requires the file afxres.h to be included in it's .rc files, whereas BC++ has all the necessary preprocessor macros defined automatically and requires no such include. Another dumb thing about this is that afxres.h is only installed when you insall MFC which not everyone does, even when you are creating an API application which only requires winres.h which is always installed.

Since I work in VC++ and use it's resource editor I've solved this problem by slightly altering each .rc file that is generated to include the following:

#ifndef __BORLANDC__

#include "winres.h"

#endif

Which under default circumstances would usually read:

#include "afxres.h"

For those of you that are using VC++ you can find the option to change this text within the IDE under "View→Resource Includes". There is generally no need to ever use this in normal practice, it's simply a way I used to work around the problem of making things work with BC++ and VC++.

To those of you using BC++, I'm sorry about the extra mess in the .rc files that are generate by the VC++ editor, but it shouldn't interfere with anything.

Compiling resources under BC++

Try as I might I couldn't find a simple way to compile a program with BC++ that included RC files, and ultimately had to settle on the non-optimal configuration that you will find in the makefiles included with the source for this tutorial. You can find the notes for the BC++ compiler in Appendix B.

Appendix E: Solutions to Common Errors

Error LNK2001 : unresolved external symbol _main

An unresolved external occurs when some code has a call to a function in another module and the linker can't find that function in any of the modules or libraries that you are currently linking to.

In this specific case, it means one of two things. Either you are trying to write a Win32 GUI application (or non-console application) and accidently compiled it as a Console application… or you really are trying to compile a console application and didn't write or properly compile in a main() function.

Generally the first is the most common, if you specify Win32 Console as the project type in VC++ when you create your project you will get this error. You will also likely get it if you try to compile from the command line using BC++ but you neglect to specify the correct parameters to tell it to make a Win32 GUI application instead of a console app which is the default.

Fixing

If you're using VC++ re-create your project and select the Win32 Application project type (NOT "Console").

If you're using BC++ command line compiler, use –tW to specify a windows application.

Error C2440 : cannot convert from 'void*' to 'hicon__ *' (or similar)

If you're compiling the code from this tutorial, it means that you are trying to compile it as C++ code. The code is written for the bcc32 and VC++ C compilers, and as such may not compile exactly the same under C++ since C++ has much stricter rules about converting types. C will just let it happen, C++ wants to you to make it explicit.

If you're compiling code not from this tutorial, I can't guarantee that it's correct and therefor it may actually be an error that needs resolving. You'll have to use your own judgement to determine if it's safe to cast the value and remove the error, or if you are actually trying to make a variable be something it's not.

Fixing

Cast. You DO know C right, it's a prerequisite for this tutorial :)

For example, in C this will work:

HBITMAP hbmOldBuffer = SelectObject(hdcBuffer, hbmBuffer);

But in C++ requires a cast:

HBITMAP hbmOldBuffer = (HBITMAP)SelectObject(hdcBuffer, hbmBuffer);

Fatal error RC1015 : cannot open include file 'afxres.h'.

Oddly enough, VC++ adds afxres.h

to resource files even when you aren't using an MFC project, and yet the file may only be installed if you install MFC. This perticular file isn't actually required, so to fix the error you can edit the .rc file in notepad and replace both occurances of "afxres.h" with "winres.h" (note that there should be two of them, and you need to change both).

Error LNK2001 : unresolved external symbol initcommoncontrols

You aren't linking to comctl32.lib which this API is defined in. This library is not included by default so you will either need to add it to the libraries on your command line, or add it in your VC++ project settings on the Link tab.

Dialog does not display when certain controls are added

Controls such as the ListView, TreeView, Hotkey, Progress Bar, and others are classified as Common Controls, as they were added to windows in comctl32.dll and were not available prior to Windows 95. Controls such as BUTTON, EDIT, LISTBOX, etc… while no doubt being common, are not "Common Controls" and I generally refer to them as "Standard Controls".

If you add a Common Control to a dialog and it fails to display, you most likely failed to call InitCommonControls() before running your dialog, or perhaps at all. The best place to call it is first thing in WinMain(). Calling it in WM_INITDIALOG is too late, since the dialog will fail before it reaches this point and it will never get called.

Some people and documentation may tell you that InitCommonControls() is deprecated and you should use InitCommonControlsEx().