Black Locust Software

Technology Solutions for Business

Daniel Wilson's repost of
Steve Loughran's WinAPI FAQ


Original Source (if still available)


Right after ... Books for Win32 Programming

Buy at Amazon! Dan Appleman's Visual Basic Programmer's Guide to the Win32 API
Buy at Amazon! Charles Petzold's Programming Windows, The Definitive Guide to the Win32 API using C/C++
Buy at Amazon! Jerry Lozano's The Windows 2000 Device Driver Book: A Programmer's Guide

Frequently Asked Questions about Win32 Programming

Revision 3.08

Welcome to Steve Loughran's utterly unofficial and sporadically accurate list of frequently asked questions about the Win32 API. This document covers common issues raised in the comp.os.ms-windows.programmer.win32 USENET group. It also covers lots of the hard questions that colleagues come up and ask me, and things that have caused much hair pulling as project deadlines approached.

Warning: This document is probably out of date by the time you read this, as are most other Windows programming documents on Web. The reason for this is simple: programmers are always too busy getting programs to work to worry about keeping the documentation to date.

1 Introduction: Win32
2 Getting Started
3 Development Tools
4 Win32 Platforms
5 Programming Questions
6 Internet Programming
7 DLLs: Dynamic Linked Libraries
8 Console Mode Applications
9 Services
10 Help! My Program does not Compile and Link!
11 Debugging -or 'help, my program doesnít work'
12 Shipping -or 'help, my customers say my program doesn't work'
13 Miscellany

1. Introduction: Win32

1.1 What is Win32?
1.2 What is the Win32 API?
1.3 How does it differ from the Win16 API?
1.4 Why should I port my code to 32 bits?
1.5 Why shouldn't I port my code to 32 bits?
1.6 Can I write programs using NT's Posix API?
1.7 What is the history of the Win32 API?

1.1. What is Win32?

Win32 really refers to the "Microsoft(r) 32 bit Windows(tm) API", the Win32 API, . "Win32 Applications" are programs which are built with the Win32 API. Computers running operating systems capable of executing Win32 Applications are referred to as Win32 platforms.
[Top of Section] [Index]

1.2. What is the Win32 API?

It is the 32 bit successor of the Win16 API: the Application Programming Interface which has been used for writing Windows programs since version 1.0. It is the combination of data types, definition and functions which C programmers include as a set of header files. Most of the functions are implemented in DLLs, to which applications link at run time -either directly or through COM interfaces.

The core API divides into three sections:

Each is pretty much built on top of the other. In Windows 95 the services are provided by three DLLs -USER32, KERNEL32 and GDI32, which either implement the calls or pass them down to their 16 bit predecessors. In Windows NT many of the services are implemented in Kernel Mode and various forms of inter-process communication are used to manage this.

To C++ programmers this is known as "the raw API" as opposed to the API functions which are wrapped up by C++ classes. Beginners quite often have an unexplained fear of using this API, as though you shouldn't have to use it in an MFC or OWL program. This is not true: the C++ classes are there to provide a framework for applications, but the raw API covers a lot more functionality.

As well as the base "Platform API", the Win32 API has grown to provide many more features and function calls, from the games and entertainment related DirectX APIs to the high throughput networking and service related calls used on NT servers to provide minicomputer and mainframe like performance in commercial systems.
[Top of Section] [Index]

1.3. How does it differ from the Win16 API?


[Top of Section] [Index]

1.4. Why should I port my code to 32 bits?

When starting out coding a new program, it is far easier to write a pure 32 bit app than old 16 bit programs -even if you used to use the large model. For working 16 bit apps there are a lot of benefits to be gained by porting to 32 bits:-

In April 1997 it was estimated that there were 60 Million Win95 systems, increasing at 4M units/month, an 3 Million NT systems increasing at 300K units/month (source: Microsoft at WinHec). By September 1997 it was estimated that there were 100 Million Win32 systems, out of a total of 200 Million Windows platforms. There is clearly still merit and profit in supporting Win31. This can be done -sort of- with Win32s.
[Top of Section] [Index]

1.5. Why shouldn't I port my code to 32 bits?

If you choose not to upgrade your application to Win32, then you can still stamp the exe as requiring Windows 4.0, so that the OS will automatically clean up all resources it has allocated.
[Top of Section] [Index]

1.6. Can I write programs using NT's Posix API?

Don't even bother trying to use this. It's the bare minimum of Posix compliance and doesn't offer much functionality. For example, there is no sockets support or integration with the real Win32 API. It's only there to help NT win sales in tenders where Posix support is mandatory (i.e. governments)

The win32 console API is close enough to Posix functionality that many Posix apps should be compilable within the win32 subsystem -this is what the Gnu/win32 project is trying to support.
[Top of Section] [Index]

1.7. What is the history of the Win32 API?

This is a fairly long story, which is partially documented in an appendix
[Top of Section] [Index]

2. Getting Started

This sections answers questions important to anyone just starting to program for win32.

2.1 How do I write Win32 programs?
2.2 What is a suitable computer?
2.3 What is a suitable development tool?
2.4 What OS should I use?
2.5 Do I need the Win32 'Platform' SDK?
2.6 What important things should a newbie learn?
2.7 Are there any on line introductions to Windows programming?
2.8 Do I need MFC to write an application?
2.9 Are there alternative C++ class libraries to MFC?
2.10 How do I migrate from Unix?

2.1. How do I write Win32 programs?

  1. Get a suitable computer.
  2. Get a suitable development environment.
  3. Get a decent book or two. Read them. And ideally an MSDN subscription
  4. Start writing Win32 programs, keeping those books handy
  5. Don't give up when things donít work the way you intended.

[Top of Section] [Index]

2.2. What is a suitable computer?

Ideally, the fastest box with the most memory and hard disk you can afford. However, if you already have bought a PC in the last two or three years, then it should be up to the task. One purchase that will probably be required is extra RAM: 64 MB is realistically the bare minimum for development -and 128 MB preferable. With only 48 Mb or less you will find that a PII system compiles no faster than a '486, as it will be continually swapping to hard disk. Above 256 MB compiler performance seems to top out, but the box takes ages to reboot.

Other desirable features of a development PC are -in approximate order of desirability

Having a backup solution and process is also considered pretty important. DAT and Tape drives are good for this; Zip are drives only so-so. CD-RW is pretty coo.

For team development a team server with shared directories, web server (integrated with the shared directories) and source code management system is great for development and delivery. NT server or a Linux box with Samba both fit in here. Either way, this should really be a separate system from any server you are testing code on.

Anyone doing device driver work will need one -maybe two- target PCs.

The issue of a development PC is covered in more depth in a separate article.
[Top of Section] [Index]

2.3. What is a suitable development tool?

Any environment which can link to the Win32 API libraries to execute code you have written can be used to develop Win32 programs.

This includes not just the classic programmer tools of assemblers and C/C++ compilers, but rapid application development environments such as Visual Basic and Delphi, Database systems such as Access and many "office" applications which have been enhanced with programming languages.

Some versions of the Java programming language -specifically Microsoft J++- can also be used for Win32 programming.

Many of the RAD tools simplify programming by hiding the API, making it rather tortuous to perform some relatively simple tasks. This means that most serious Win32 coding is done in the classic programmer languages of C and C++, and to a lesser extent in x86 assembly or the Delphi variant of Pascal.
[Top of Section] [Index]

2.4. What OS should I use?

This is mainly a matter of personal choice.

Windows NT is excellent for development, mainly because it is so robust and you can still use other applications during compiles. It does use a fair bit of RAM, even before you add the compiler's requirements. Developing 16 bit apps in NT is good too, simply because you can reboot the 16 bit subsystem so easily.

Windows 9x is not quite as robust as NT, but it runs better on a lower-end machine. If you want to use libraries for which there are no current NT equivalents then win9x is a must. [Or cheat and have two computers]. As more "consumer-class" functionality is added to NT the need for using win9x is lessening

Likewise, NT offers many features which are not available in Win95.

Win31 and Win32s is not really suited for application development. Borland C++ certainly can be used in this situation, but not Visual C++. Consider relegating this platform to a test environment if a Win32s version is required.

Windows CE is currently only a target platform, and not one to run on your primary development PC.
[Top of Section] [Index]

2.5. Do I need the Win32 'Platform' SDK?

Not necessarily, because your compiler should be sufficient. The SDK contains the header files and import libraries for the latest version of the API, along with samples and useful debugging and stress tools. So it is worthwhile if you have the spare bandwidth and disk space. You can download this 20+MB "Platform SDK" off the Microsoft Web site.
[Top of Section] [Index]

2.6. What important things should a newbie learn?

  1. The class libraries are only a foundation: there is nothing wrong in using the raw Win32 API.
  2. Use the on-line help. Everyone else does.
  3. Learn to write 32 bit applications without bothering to serve a 16 bit apprenticeship. And ignore dated books which cover 16 bit programming: there are some things programmers were not meant to know.
  4. Look through the sample programs your compiler ships with: they are a good way of learning how to write windows applications and a source of code.
  5. Resource files (.RC) are really text files and sometimes are best edited as such instead of with a resource editor.
  6. Step into the source of the class libraries when debugging to find out what's really happening, but avoid modifying the source or making big assumptions about the implementation unless you have to -either of these tricks increase your maintenance costs. If you do have to modify the class libraries, cutting and pasting the source into your own classes first is usually better.
  7. Sometimes there really are bugs in the OS, class libraries and compiler code generators. But usually, when a routine doesn't work the way you expected, the fault is yours. Either there is a defect in your code, or there is a defect in your assumptions. With experience, both of these situations will arise less often.
  8. Allow about six months to become reasonably competent, but never think you can stop learning.

[Top of Section] [Index]

2.7. Are there any on line introductions to Windows programming?

Yes, but they are not on a par with any printed documents. There is a simple reason for this: no-one makes much money from such on-line documents, so there is no incentive to either write them or get them technically correct, other than the appreciation of your peers. Some advertising funded sites are changing this, so things are getting better. Try entering for "Win32 Tutorial" into your favourite search engine to see what gets found. Also, there are lots of MSDN articles covering all aspects of Windows programming, from the introductory to the obscure.
[Top of Section] [Index]

2.8. Do I need MFC to write an application?

No you most certainly do not -you can still quite happily write a program in the 'raw API' -as much of the base OS and bundled appliccccations are. Everything you can do with MFC and/or ATL can be done in the raw API, the only issue being how much work is involved. [CS graduates call this concept "Turing Equivalence"]

The main justification for raw API code is usually size and performance -raw Win32 apps don't need MFC libraries, so can load faster and take up space. Anything intended primarily for background use -a little taskbar applet for example- should consider a raw implementation rather than MFC, which is a bit of overkill. For ActiveX controls downloaded from the net, download time is critical, and eliminating the need for MFC libraries helps there. With a really large program the gains of MFC are less clear -so much of the wheel gets reinvented that you end up with something almost as large but with worse documentation and more maintenance issues. You also lose all the performance gains the MFC code and the class wizards can deliver once you know how to make effective use of them.

Some things are very hard to write in raw Win32. OLE automation is a case in point, while database access needs a fair amount of support code whether the connectivity interface is ODCB, RDO, ADO or OLE DB. The ATL libraries are a halfway house -lighter weight than MFC, purer C++ than MFC, and utterly unreadable to the uninitiated. The STL (Standard Template Libraries) are also a good accessory to raw API and ATL coding, they give you the C++ standard string classes and semi decent vector and list structures. As for COM, if you use the "#import" pre-processor directive in VCC5 and up, the compiler makes COM calls in C++ workable, even for IDispatch derived interfaces.

Finally, if you do want to reinvent the wheel and build a better class library, go ahead. It is not impossible, just time consuming. Borland's OWL2.x library is still regarded by many as a better class library than MFC [this FAQ's author is one of them], and other people have done commercial class libraries (Metrowerks do a cross platform one, for example), or freeware (e.g. Sam Blackburn's WFC classes). An alternate trick is to write 'raw API' classes which can be used standalone or mixed in with MFC and ATL code, to fill in their gaps. For example a CDIBitmap class can provide bitmap access, while the core NT device hierarchy can be supported by a single header file's worth of classes with names like COSDevice, COSFile, COSSerialPort, COSWaitableTimer and so on. This lets you extend MFC where it is weak, yet not be tied to its use.
[Top of Section] [Index]

2.9. Are there alternative C++ class libraries to MFC?

Oh yes. As well as alternative commercial libraries from compiler vendors such as Borland and Metrowerks, there are also third party class libraries on sale.

However, one of the most valuable class libraries is free and comes in source form: Sam Blackburn's WFC class library . This library (as of release 39) includes a better XML parser than the IE5 one, and lots of really interesting goodies. It also provides an example of a) how a skilled programmer can build up a reusable library set to enhance their own productivity, and b) how a generous programmer can give away their work for the benefit of the entire community. Even if you choose not to use it, it can be used as a reference example of Win32 class library design and implementation.
[Top of Section] [Index]

2.10. How do I migrate from Unix?

Firstly, welcome to the dark side of software. You'll find that it isn't as bad as it's been made out, and pays quite well.

It's inevitable that when learning the Win32 API you will discover a lot of things that don't make a lot of sense. For example, why are there so many slightly different APIs -TextOut, ExTextOut and TabbedTextOut and PolyTextOut? Historical reasons. Likewise the split between NT Executive objects and all those other objects in a system: GDI objects, Windows and sockets. As the platform evolved, the API grew to match. Legacy support and a rapid evolution has been key strengths of Windows, and this shows in an API that from a Unix developer perspective is an incoherent mess. Well, too bad. It's like the x86 - an ugly duckling that has grown up into a successful, but still ugly, duck. Resistance, as they say is futile.

Migration Tips

There are various ISVs who support a Unix API on top of Windows, letting you support multiple platforms with a minimal amount of source divergence. In Cygnus and the CygWin Project have an open source product, and AT&T Research have a Unix library written under the guiding hand of David Korn.
[Top of Section] [Index]

3. Development Tools

This is a list of shipping products which can be used to generate Win32 code. This is also the section of the FAQ which dates the fastest, as many vendors update their products every 12-18 months, with bug fixes -"service packs"- available in the meantime.

Important Fact Number 1. No particular preference over development tools is being made here: purchase decisions need to made by individuals/groups based on their own needs, abilities, funds and long term plans.

Important Fact Number 2. There are no silver bullets in software engineering. Despite what the advertisments will tell you about application development at a click of a button, Windows programming requires skill, knowledge and hard work. Debug facilites and customer support can be as important as compilation speed or syntax highlighting.

As most products are available in "lite" editions, evaluating them all may cost time more than money. But it may prove a worthwhile investment.

NB: detailed but moderately opinionated product reviews are available nearby

3.1 Visual C++ /Visual Studio
3.2 Visual Basic
3.3 Borland/Inprise Delphi
3.4 Borland/Inprise C++5.x and C++ builder
3.5 Metrowerks CodeWarrior
3.6 Intel VTune
3.7 lcc-win32
3.8 Assemblers
3.9 Also Available
3.10 Watcom C++ 11
3.11 Microsoft Visual J++
3.12 Gnu for Win 32
3.13 Configuration Management Tools
3.14 What other tools are useful?
3.15 Books

3.1. Visual C++ /Visual Studio

A single integrated IDE which can be used for C/C++, Java and web page development. It's fairly heavyweight (64+MB RAM best) and hard on the disk drive , but very powerful.

The C and C++ compilers are probably the currently most popular compilers of these languages in the Win32 community. This means that many books and add-on tools focus exclusively on these tools. They are also invariably the first compilers to support new OS developments from Microsoft. Compilation speed and generated code performance are so-so, debugging facilities excellent once you get the hang of them.

One critique of these tools is that their development evolves for strategic reasons, rather than those of immediate benefit to the customers. For example the 32 bit IDE/compilers can not generate or debug 16 bit or DOS applications, and provide much more support for developing COM objects than displaying GIF and JPEG images. Likewise the Java tools may be great for 'DNA' use, but not for portable Java application development. But if you want to go where Wintel want to take you, these products can make the journey easier -especially if you prefer SQL server over Oracle.

Although single language options can be purchased separately, it may be cost effective to buy the complete set. A large hard disk is then obligatory. The Enterprise edition needs an even larger hard disk, but gives you a source code control tool (invaluable) and lots of back office integration toys (variable value). The amount of after sales support you get is still near zero.

Links: A more detailed review; the product's home page
[Top of Section] [Index]

3.2. Visual Basic

The successor to the 16 bit Visual Basic system. Comes with OCX equivalents of all the old VBXs which it used to ship with, plus a more OO language that adds classes but not inheritance. A compiler now generates reasonably fast code.

Although through VB many Win32 API calls can be made, it can be a rather tortuous process, as you need to cut and paste in every function declaration prior to usage. Some data structures and programming paradigms do not translate easily to the VB world. Tip: The reason you can't import a function such as ShellExecute() is that functions exported by the OS which take strings have an ASCII version -ending in 'A" and a UNICODE version ending in W: you need to import ShellExecuteA.

Visual Basic is a very fast way of getting an application up and running -and the built in setup kit is pretty good for distributing programs. (except that it always includes the version of CTL3D32.DLL used by your OS, and not theare separate versions required for NT and '9x). In particular it's very good at seamless OLE Automation and ActiveX integration -much better than Visual C++. This -and the fact that cut down versions come with MS Office programs means it is worth learning and using in the 'appropriate' parts of any major programming project. For example, it can be used to integrate your compiler, source code and project management tools with relative ease.

In terms of popularity, Visual Basic is probably the most widely used language on the planet, although it is not so common in commercial shrink-wrapped software products. It's good for quick and dirty development, database integration and the development of usable front ends. With the native compiler and a rudimentary object model, the language may even be usable for large or commercial performance applications.

For low level Windows hacking, it is not the tool of choice -unless backed up by DLLs, OCXs or even device drivers.

Link: review
[Top of Section] [Index]

3.3. Borland/Inprise Delphi

Delphi combines the Pascal programming language with a GUI focussed on RAD -both database and low level programs are possible in this IDE.

Like VB, it can be a fast development tool in the hands of a moderately experienced user, and there is enough of a developer community to ensure that support for new OS technologies -DirectX, IE4 Common Controls- comes out relatively rapidly. Many people love it, especially recreational programmers'. Once nice feature is that it is a reasonable language in software engineering terms.

It's worth noting that Delphi does seem to be popular for an in house development tool in many high salary financial organisations. Time to market and database integration are probable reasons for this.
[Top of Section] [Index]

3.4. Borland/Inprise C++5.x and C++ builder

A true 32 bit IDE which can still develop 16 bit and dos applications. OWL 5 provides wrappers for the common controls and windows sockets., while MFC can be used for applications where use of that framework is deemed politic.

Although apparently the system does support OCX creation and use, the lack of OCX support in the Resource Workshop, and the absence of any OCX Expert, means that it isn't really suitable for OCX development and use. It does still support VBXs in 32 bit apps though, which can be very useful for porting legacy apps.

The early 5.0 version had a reputation for leaks and bugs. Version 5.02 ships with the MFC source, so that MFC applications can also be built with the compiler.

C++ Builder is a newer Delphi-like interface to the compilation tools: it seems to be a nifty way of doing C++ coding. The Enterprise edition of this is particularly well rounded.

Links: Inprise home page
[Top of Section] [Index]

3.5. Metrowerks CodeWarrior

Mac programmers will know and love this product, which has long been the definitive development tool for "the other platform". They've recently branched out into the Windows and embedded market, and offer C++, Pascal and Java development tools for Win32 and WinCE.

With MFC support now, and a resource editor due in summer '98, and too, this could become a reasonably productive Win32 development. Low cost editions are available. One major weakness: the resource editor is very primitive compared to modern Windows IDEs.

Link: Metrowerks
Link: review
[Top of Section] [Index]

3.6. Intel VTune

This is an add on compiler and profiler for Visual Studio. It's key features are
  1. C++ and Fortran compiler that knows about Pentium III floating point registers and can generate code which makes use of them.
  2. Other compiler switches to do RISC-style aggressive optimisation techniques such as loop unrolling and conditional moves instead of branching.
  3. A very good graphical code profiler.
Because this tool is an add on purchase, it should not be viewed in the same light as the IDEs. But the compilers give it an edge over other profiling tools. As a way of speeding up code it may be exacly what you need.

Link: review
[Top of Section] [Index]

3.7. lcc-win32

This is a free win32 compiler and IDE, available in a 2 MB download, source and documentation for a $40 fee.

The IDE is not as full of 'wizards' and other clutter, and is relatively low level, but it is a good low cost introduction to Windows programming. A good install program is a nice feature, as it helps get you started easily.
[Top of Section] [Index]

3.8. Assemblers

Most of the compilers support in-line 32 bit assembly language, except Borland C++ which requires you to buy Turbo Assembler (TASM) just to get the 32 bit in-line assembler to work. Sometimes the x86 language supported in compilers is a subset of the full x86 language, with new instructions (CPUID, CMOV) omitted. Full assemblers have an edge here, such as Borland TASM and Microsoft MASM. TASM is really an add on to Borland C++, while MASM is a relic which ships with a DOS based install program but can be hosted by VC++.

There are freeware assemblers,in particular NASM . This can generate Pentium and MMX opcodes and output .obj files in Borland or Microsoft formats.

Links: Paul Hsieh's x86 Assembly page; Win32 coding in assembler
[Top of Section] [Index]

3.9. Also Available

Deserving a mention are These products exist, but do not get a regular mention, something which may reflect their lack of popularity.
[Top of Section] [Index]

3.10. Watcom C++ 11

The Watcom compilers have a reputation for generating high performance code, and also of being slightly harder to use than the MS and Borland tools. Some "real programmers" swear by them.
[Top of Section] [Index]

3.11. Microsoft Visual J++

A Java compiler which supports COM, so that Java can be used to write OLE/COM objects and call out to the OS via COM interfaces and the standard java.* packages. Many DLL exported functions can also be called from the latest (2.x) version of the compiler and VM.

Standard Java code should execute on all Java VMs, but the COM enhanced code requires a special JVM, which runs a far more limited set of devices.

For reliable code development fetch the updated compiler patches and the full Microsoft Java SDK, which contains the tools to turn a set of Java binaries into a standalone windows app. Because the MS JVC compiler is free for download it is a low cost way to start programming.

Visual J++ 6.0 is a Java 'variant' which produces code for Windows only. Given the current legal dispute the longevity of this product may be measurable in weeks rather than years: avoid it for anything other than a throwaway application.

Symantec Visual Cafe generates native Win32/x86 binaries, so could be used for developing applications, but you are restricted to the standard Java libraries (or manual imports).
[Top of Section] [Index]

3.12. Gnu for Win 32

This is project underway at Cygnus to port the gnu compiler to windows 32. It is intended to help in cross platform portability rather than windows app development, but can be used to build win32 apps.

There are four versions available, Cygnus's original Cygwin32 and Colin Peters' Mingw32 (Minimalist GNU Win32) version, each with either GCC 2.7.2 or EGCS 1.0 as the compiler. Mingw32 + EGCS is recommended as the best version for Win32 development.

The main difference between Cygwin32 and Mingw32 is that Mingw32 doesn't need the compatibility library (Cygwin32.dll and associated material) that Cygnus provides. This loses part of the Unix compatibility layer, but gives smaller and faster compiled binaries. The only reason to prefer Cygwin32 over Mingw32 would be for porting code from Unix.

Regardless of which version you intend to eventually use, you need to download the complete Cygwin32 development kit first; Mingw32 is distributed as a patch for Cygwin32. If you intend to use EGCS rather than GCC as your compiler, you only need the "user tools" version of Cygwin32, instead of the much larger "developer tools" version.

All versions come with the Win32 header files and link libraries (not quite complete and up to date, but close enough for most development requirements).

Installation can be a bit of a pain; coming as they do from the Unix world, these tools don't have the sophisticated automatic installers that Windows users expect. But if you follow the instructions and apply a bit of common sense, it's not too hard.

Relevant web sites:

  1. Colin Peters' Mingw32 project . this is the best place to start; it has pointers to everything else you need)
  2. Cygnus Solutions' GNU-Win32 project
  3. The EGCS home page
  4. Mumit Khan's port of EGCS to Win32
(thanks to Ross Smith of New Zealand for these details)
[Top of Section] [Index]

3.13. Configuration Management Tools

A source code control system is fundamental to productive, professional programming. The choice of which tool to use is a long term decision, and not to be taken lightly: most vendors have trial versions to download to enable a thorough evaluation to made prior to spending $500-$1000 a head on an inappropriate product. It doesn't take long before the system becomes a critical part of your process and the repository of all your software assets, so a mistake can cost far more than the purchase price.

Some criteria which may be used to assess a product, depending on your current and future needs are:-

Financially constrained developers can make do with the freeware gnu RCS tools, or just use the copy of Visual SourceSafe which comes with every Enterprise edition of Visual Studio.

Popular products -usually with free trial editions for downloading- include:-

Merant PVCS
A full blown CM system with optional defect tracking and web integration. Its feature set seems comparable with MKS Source Integrity. Formally marketed by Intersolv.
Visual Source Safe
This comes for free with enterprise editions of Visual Studio. It's relatively easy to start using, and integrates well with the Visual Studio product line. It's weaknesses show up over time:-
  • Branching isn't too successful as it's hard to break Studio's bindings to particular projects
  • Lacks an integrated defect tracking system.
  • The administrator can't override someone else's actions -such as undo a file checking out.
  • Doesn't scale well to very large or distributed projects.
  • Very slow on Samba servers -but good on NT. File locking is the problem, apparently.
  • Web publishing only really works to NT/Windows servers.
MKS Source Integrity
This is an expensive but well proven product. A nice feature about this one is that you can define actions to to be invoked when certain triggers occur. For example, after every check in the project leader can be emailed with a summary message, or a recompilation can be forced to verify that the code being checked in doesnít break the build.
The GNU implementation of RCS
The ci and co commands can be used to build up an RCS database, and integrated with make and batch files with some effort. For team development you need a file system with symbolic linking, so that each team member's RCS directory points to the same place. That effectively means a Unix file server has to be used as the source repository.
Reliable Software's Code Co-op
This is an interesting shareware tool: a CM system which can use email as the synchronisation mechanism. This makes it ideal for peer-peer and distributed development.
QVCS
A shareware CM tool, which looks reasonable for individual use.
For more information, see the configuration management FAQ

NB: donít just check it in - back it up. It's what tape drives and CD Writers are for. Most commercial products support OLE automation: with this it's an interesting exercise to write a script to get the entire heirachy into a directory tree and then tar/zip up for a vendor independent database snapshot.
[Top of Section] [Index]

3.14. What other tools are useful?

There are lots of commercial, shareware and freeware products which can improve your product's quality or development schedules.

Code analysers

Other items to consider include:- Also consider something for artwork & web page support. PhotoShop is a bit of an expensive luxury for most programmers: graphic design should really be delegated to someone with talents and skills in that area.
[Top of Section] [Index]

3.15. Books

Any manuals which come with your development tools are usually adequate in showing you round the tools themselves, but are rarely ideal for learning basic or advanced Windows programming. They are also becoming rarer and rarer, despite the feature growth of the products. Books by third parties can be significantly better -or significantly worse, if you are unlucky. The complexity of Windows applications is now such that there are also many books addressing niche areas: sockets, COM, MAPI, device IO, as well as Win32 fundamentals.

Some of the books which are highly regarded are listed below. The exact suitability of individual books depends on what you want to do and what your background knowledge is. Most of the books listed are by the Microsoft Press, as they are the publishers most interested in addressing the needs of Windows Programmers. Addison Wesley and Wrox press also have valuable and high quality titles. All of these books assume prior knowledge of C and C++. NB: DDJ maintains a good database of their book reviews, which is a good source of independent opinions on many of these titles as is this other site

One good strategy on choosing a book comes with experience: go into a bookshop and look for an explanation of something which caused you grief but you now understand -such as COM object thread safety or MFC message routing. Verify that a book which should cover this topic does so in way which you understand. If it doesn't, then you should question the book's value. Then go back to your desk and find the best value on line book store. In particular European developers will find that the cost of US editions is so much lower that they will save money on a US purchase, even once shipping costs have been included.

As well as books, there are some monthly magazines which cover Windows programming in detail:-

Microsoft Systems Journal.
A regular magazine, combining information with some evangelism for the company's latest API, tool or strategy. Often more up to date with operating systems and products than anything else.
Dr. Dobbs Journal.
Another regular magazine, good for reviews of various tools. More independent; less Windows focussed.
3.15.1 Introductory Windows Programming
3.15.2 Advanced Programming Topics
3.15.3 Low level hacking
3.15.4 Software Engineering and other topics

3.15.1. Introductory Windows Programming

These are books you can use when starting off, but may need to keep handy and even re-read in future years. A good beginners book should teach you the fundamentals of the Win32 API, including the message loop, Windows, Dialogs and Controls, drawing with GDI, and fundamental concepts of DLLs and COM. Quite a few of the entry level books tend to skimp over the full feature set of GDI, and try to cover multithreading in about ten pages. Advanced books cover multithreading in hundreds of pages, and with good reason -when things go wring it's nightmare. So steer clear of threads until you are happy with single threaded apps.
Programming Windows, Petzold (and Yao), MS Press
Charles Petzold wrote the original Windows programming 'bible' -"Programming Windows" back in the mid eighties -everyone who started Windows programming in those days had -or needed- a copy of this book. Now updated for Win32, Petzold starts the basic paradigms of windows programming -Windows and message queues- and goes on to cover many advanced topics. The book uses C and assumes a prior knowledge of this language. Although the structure of the book does not match C++ and OWL or MFC applications, the chapters on advanced topics -such as drawing- are still invaluable reference material, while the introductory chapters provide an invaluable explanation as into how Windows applications work.
Critique: Some of it is -well- dated, and not really adequately updated to the new OS platforms. The OLE section looks like an afterthought.
March 99: The latest edition is fatter, drops the OLE/COM section in exchange for a music app and adds a rudimentary Internet chapter containing a time synchronisation sample which would never work on Windows NT. There are better alternatives.
Programming Visual C++ , David Kruglinski, Shepherd and Wingo , MS Press, ISBN 1-57231-857-0
This is the successor to Kruglinski's Inside Visual C++ series. In it the authors explain how to write professional looking applications in VCC, covering areas such as the Wizards, OLE, databases, document/view models dialog boxes and basic Internet and ATL programming. For low level Win32 programming this is not the book of choice -but if you need to use MFC as the framework for your app, this is a good starting off point and a reference tome to return to.
Critique: The early editions of this book used to contain an appendix with a reasonable introduction to C++, but this is now absent. Cut and Paste is about the only code reuse strategy covered.
Win32 Programming Rector and Newcomer, Addison Wesley
An excellent alternative to Petzold. Thick and thorough, and without any reminiscing about the old days of Win16. Good value.
Programming Windows 95 with MFC, Jeff Prosise, MS Press
Covering much the same ground as Petzold, Jeff assumes you have a copy of Visual C++ and want to use the MFC classes as the framework for your applications. Knowledge of C++ or C & the Windows API is a prerequisite. This is not your average "how to use the wizards" book.
The Windows 32 API Reference
You should get an on line copy of this. The overview chapters may be worthwhile having on paper and reading, but they date so fast it's hard to justify.

[Top of Section] [Index]

3.15.2. Advanced Programming Topics

Advanced Windows, Jeffery Richter
This is the definitive guide to the new features of the Win32 API -especially on NT. Jeff covers advanced topics such as processes and threads, Overlapped IO, Completion Ports, Structured Exception Handling and UNICODE. Through a skilful use of Dialogs, he manages to demonstrate all these features without appearing to write full scale applications. Application structure and the user interface and graphical aspects of windows are not covered. [Buy this book and then write your name on it in big letters to stop it going for a walk].
A new version is due in late '99
MFC Internals, Scott Wingo
If you use MFC and want to know how it works -or why your code doesnít behave as expected- this is a good book. It assumes you are already experienced with Win32 and MFC. One of the best adjucts to the on line documents competent MFC programmer needs. This book is not recommended as an introduction to MFC programming.
Inside Windows NT, Second Edition, David Solomon, ISBN 1-57231-677-2
The original edition by Helen Custer was mindnumbingly dull, but after a near complete rewrite the book can now be read from cover to cover. Not only that, it is full of valuable snippets of information and little experiments you can run on your own NT box to peek behind the scenes.
Worthwhile if you're getting into device drivers or want to know what the OS is really up to. Applications should not have to know all this nitty gritty, but the section on scheduling is useful are other chapters on subjects such as file I/O and memory management.
Critique: it lives in an ideal world, in which Blue Screens never happen, NTFS corruption never occurs and NT's security model is both comprehensible and comprehensive.
Programmer's Guide to Windows 95, ISBN 1-55615-834-3
Covers all the new Win95 features and differences with NT. Fairly readable. Part of the MSDN/Win32 on line documentation, so not worth shelling out for on paper. Clearly due for an upgrade.
Inside COM, Dale Rogerson
A book which covers the fundamentals of the component interface model without covering the specifics of the OLE linking and embedding interfaces. Vaguely useful for anyone using COM within or between applications. NB: sequels to this book -Inside COM+ and Inside Distributed COM are in the pipeline.
Inside OLE, Kraig Brockschmidt,
This was the original OLE and COM book -and was never an easy read, even if the second edition is much better than the first. Nowadays it has less appeal: other books cover COM better, so this one is only of interest to people with the unwelcome task of implementing OLE2 in raw C/C++. Flicking though this book, you will realise why this is best left to suppliers of libraries such as MFC, OWL and ATL.
Essential COM, Don Box, ISBN 0-201-63446-5
This is a good book -good enough to supplant Inside COM as the definitive bible for COM development. Don's experience broad experience in COM and CORBA, and critical insights into COMs failings give the book more value than MS press offerings. Also it's reasonably up to date, and covers NT5 to an extent. Some chapters are on MSDN. As is common with all COM books, you may get a headache reading it.
Professional ATL and COM, Richard Grimes, Wrox Press
This book fills a niche: how to really make use of ATL, and is a practical counterpart to Don's book. It seems overpriced, the ATL3.0 version costing 50% more than the ATL2.0 book. But if ATL is your chosen class library, $60 is a trivial investment, and if you look round the online booksellers you can get down to a more reasonable price. And it is reasonably readable, full of practical examples and relatively error free.
Win32 System Programming, Johnson M. Hart, ISBN 0-201-63465-1
This is quite a good follow on book to Richter's, focusing on low level synchronisation and communication with a definate Unix like flavour. J.M. Hart is pretty rigorous when it comes to thread safety, so this book may come in handy if you are writing low level or server applications.
Visual Basic, Bruce McKinney ,ISBN 1-57231-422-2
If you really must insist on doing Win32 coding in VB, then read this book -it's on the MSDN CD, albeit without the sample apps. It's actually stricter on coding practices than many of the C++ books, which is as good a reason as any for VB programmers to read this book. And in a world with ubiquitous VBA, all windows Programmers benefit from acquiring VB skills. This book will let you write moderately serious Win32 apps without having to take on the MFC Wizard.

[Top of Section] [Index]

3.15.3. Low level hacking

Inner Loops, Ralph Brown, ISBN 0-201-47960-5
An introduction to x86 assembler for anyone interested in tuning the core of their apps. It's probably due for an upgrade in the 'Katmai timeframe', as it doesn't cover all the subtleties of programming for the latest generations of Intel processors or AMD/Cyrix cores.
Windows Assembly Language and Systems Programming, Barry Kauler, ISBN-0-87930-474-X
Apparently the only book on Windows programming in assembler there is.
Computer Architecture: A Quantitive Approach, Patterson and Hennessy, ISBN 1-55860-329-8
This isn't really an x86 or Windows programming book, but its sections on Pipelining and Instruction Level Parallelism provide the underpinnings of how P6 generation cores work. The memory-hierarchy chapter explains everything you need to know about uniprocessor caches, while the multiprocessing section is the definitive reference of 'relaxed consistency models' for multiprocessing. These are where different CPUs get to see memory writes in different orders: exactly the behaviour you see on a multiway P6/PII box. After reading this book and inner loops you may be able to write code to extract maximum performance from these systems -although for ease of maintenance you may well conclude that is not the route you wish to follow.
Intel Processor Documentation, Intel
PDF files you can download from Intel's developer web site. Get the Intel Architecture Optimisation Manual at the very least.
Developing Windows NT Device Drivers Dekker and Newcomer, Addison Wesley, ISBN 0-201-69590-1
A gentle introduction to device drivers which is as up to date as you can hope (Win98 and NT5 beta 1) with NT and WDM drivers. Readable and with an appendix of common kernel mode API calls. A valuable counterpart to the OSR book, especially if you are just starting out. The list of hardware tasks to run away from is particularly amusing, perhaps even poignant.
Windows NT Device Drivers Mason and Viscarola, OSR
This is the new bible of Device Driver hacking -best value when bought direct from OSR. After reading it you still will be a long way off from writing production quality device drivers, but at least you will have a vague idea of the effort involved. A lot less of an entertaining read than Dekker and Newcomer

[Top of Section] [Index]

3.15.4. Software Engineering and other topics

Many books teach Windows application programming -but the whole engineering process gets neglected somewhat. If you are interested in delivering quality Windows applications to meet schedules -or are working in a team, then software engineering skills are as important to develop as programming skills. To an extent, they are even more important, especially if you have long term career plans.

Recommended reading here includes:-

Code Complete, Steve McConnell, MS press
This is a great book on learning how to write high quality code -and how to debug the bits that aren't so good. It predates C++, COM and interfaces, so some of it's strictures have to be taken with a pinch of salt. However, it is still one of the best books to get 'programmers' on the path to becoming 'software engineers'. Mandatory Reading for software professionals.
Rapid Development, Steve McConnell, MS press
This covers many of the process and organisational issues of team software development. If you are developing by yourself, for yourself, then you can skip this book. Otherwise, it's great. The 'classic mistakes' page is worth photocopying and pinning up on your wall -and the 'what to do when things go wrong' chapter is an excellent rarity in methodology books which always assume that processes are followed and disasters never happen.
Design Patterns, Gamma et al
This is a good book during application design, although in the MFC world half the design is given to you, whether you want it or not.
About Face, Alan Cooper
This book deserves a mention as a classic book on UI design which anyone who designs applications ought to own. It's getting a bit dated these days, as it predates a ubiquitous web.
The Art of Software Testing, Glenn Myers.
There are seemingly no books which cover testing of Windows applications. Instead you have to resort to books such as this 1979 volume, which covers the basics of testing software. It hasn't dated much, although you can help laughing when it describes a thousand line program as 'large'. NB: if testing is important, download our Win32 app walkthrough checklist

[Top of Section] [Index]

4. Win32 Platforms

This section covers the various platforms which support Win32, and the differences between them.

4.1 What Win32 Platforms are there?
4.2 What's in Windows 95?
4.3 What's in Windows NT?
4.4 What about Win32s?
4.5 And WinCE?
4.6 What's in Windows 98?
4.7 What's coming in Windows 2000 Professional?
4.8 Do I need to worry about Win64?

4.1. What Win32 Platforms are there?

Although Win32 is a single programming "interface", there are multiple implementations of this interface, each with their own strengths and weaknesses.

The most widespread platform is Windows95, although Win98 will eventually replace this. Because these two OS versions are often similar, "Win9x" and "Windows 9x" is often used to refer to both of them. The Win9x implementation of Win32 is the most common one found in households and laptops. Because it has evolved from DOS and Win31, its legacy application and hardware support the best, but the overall performance and functionality is hampered by the all the legacy code it both contains and supports.

Windows NT is the heavyweight implementation of Win32, offering much more functionality. Because of its heavy system requirements (realistically a P5/133 and 32+MB RAM), it is normally only used in office desktop and server environments, although corporate laptop use of NT4 is quite high despite its lack of mobile user support.

A well written application can usually run on Windows 9x and NT, possibly changing its functionality at run time. Tip: GetVersionEx is the API call to distinguish between platforms and versions.

Windows CE is the latest addition to the Windows Family. It contains a very cut down kernel and is intended for consumer products and embedded systems. Although an experienced Windows programmer can be programming for CE within a matter of days, the hardware for CE platforms is so radically different from that of classic PCs that designing a single application to run across Win9x, NT and CE is not currently a common practice.

It has long been Microsoft's stated objective to replace the Windows9x kernel with NT. This will be a slow process, as it will not happen until the majority of PCs in regular use are up to running a consumer variant of NT, and all applications and hardware support the OS. Application and hardware developers need to bear this long term strategy in mind, and design for both desktop operating systems.

The future of WinCE is unclear. Its current rate of evolution is immense, and is appearing in some interesting products -especially the Sega games console. It has the potential to become the most widespread Windows platform of all: used almost everywhere a 32 bit embedded CPU is found. It may also fail to justify the current levels of investment, and become another "whatever happened toÖ?" story in the computing press.

Also deserving a mention is "Win32s", a subset of the Win32 API which can be supported on Windows 3.1 if the appropriate drivers are installed. Use of Win32s is not advised by Microsoft, and recent products (Visual C++ since version 4.2, VB5) can not be used to generate Win32s executables. It was originally intended to serve as a transitional API between Win31 and Nt/Win95, and it is generally now felt that people should really have upgraded to one of these operating systems by now. In the corporate world, support for Win31 may still be a requirement, in which case Win32s is one way of doing so. The platform has also been making a comeback with web browsers for Windows 3.1.
[Top of Section] [Index]

4.2. What's in Windows 95?

Win95 has lot of "gotchas", as not all of the full Win32 API could be implemented. Reasons for the restricted functionality are probably a combination of time, effort and compatibility needs. The missing features are mostly documented in the "platform differences" section associated with each API call entry in the manuals.
[Top of Section] [Index]

4.3. What's in Windows NT?

NT tends to lag on some of the home oriented APIs-such as DirectX, although this may change in future. Some of the major details for programmers are:-
[Top of Section] [Index]

4.4. What about Win32s?

Win32s is "Win32 for Win31", and is a half way house between 16 bit windows and the 32 bit world. A better Win31 application can usually be written with 16 bit tools. Using Win32s enables you to use slightly more modern tools, but there is still bound to be enough differences between full Win32 and Win32s executables that a separate code base is often required. This code base separation can usually be restricted to a few #defines and platform specific modules.

The most up to date version of Win32s is version 1.3: this came out with Win95 and supports the common controls such as tree and list views. Future development is unlikely, as MS do not want anyone to run Win31 any more.

Versions of Visual C++ after -and including- 4.2 do not support Win32s; version 4.1 is the most modern one to do so. The apps you build with VCC4.1 must link dynamically (not statically) to the RTL and class libraries. Look under win32s\redist and win32s\debug on the CD for these DLLs.
[Top of Section] [Index]

4.5. And WinCE?

Windows CE has a very cut down API, with a completely different kernel, an Object Store as well as a file system and lots of support for networking from the devices. The API is documented on MSDN Library, the emulation SDK shipped in the Professional subscription and the full cross compiler with a universal subscription.

Some features of the current (CE 2.x) versions of the OS are:-

Expect a new release of the OS annually -at least until the end of the century. [Top of Section] [Index]

4.6. What's in Windows 98?

  • Internet Explorer 4.x becomes integral to the OS, bringing many Internet related services to all systems. [Win98SE comes with IE5 instead].
  • Waitable Timers and new power management API calls. -like SetSystemPowerState()
  • DirectX 5.1 with AGP support and DrawPrimitive for 3D gaming.
  • A new driver API "WDM" for writing drivers for devices on new buses such as USB and FireWire (1394)
  • A new video streaming architecture with an emphasis on IEE1394 and USB bus devices
  • FAT32 upgrades for large hard disks
  • Multiple Monitor support
  • Visual Basic Scripting & an OLE automated shell
  • Built in features now include the task scheduler, font smoothing and deep (256/64K) colour icons.
  • The Microsoft implementation of the Java VM and associated class libraries (most of Java 1.1, plus AFC)
  • Many new UI controls: the "CoolBar", Bands, a date/time picker, an IP address control.
The most visible change for programmers is the IE4 shell: a web browser will be built in, the new common controls can be used and applications can be made to look better -or at least different. This also forces programmers to upgrade their Win95 applications to avoid looking too dated.

Win98 retail includes IE4, and a Java compatible virtual machine which includes most of the Java1.1 APIs. Windows 98 Second edition adds IE5, DirectX 6.1 and other new features as well as various bug changes.

Link: review for programmers
Link: Win98 SE update
[Top of Section] [Index]

4.7. What's coming in Windows 2000 Professional?

In the OS formerly known as NT5, we can probably expect:-
  • Almost verything in Windows 98 SE
  • Lots of server-side stuff: Active Directory, multiple mount points in the file system
  • Com+ : an upgraded version of COM/DCOM. COM+ Events are kind of neat.
  • Asynchronous RPC/COM -good over slow links.
  • Native Structured Storage. This will boost the access speed of OLE files.
  • New GDI services: Alpha Blending and gradient shading.
  • The long promised "Cairo" Object File System extensions to NTFS.
  • RegisterSysMsgHandler() to let console applications catch messages.
  • Security enhancements such as smart card support and file system encryption.
  • Toolhelp32 is finally supported.
The most up to date information will come via MSDN, and from Microsoft Systems Journal.

Hints are already arriving as to the features of later operating systems. GDI 2K may be the drawing interface for this -it sounds like a COM based successor to classic GDI. DirectDraw is probably the most realistic forerunner of this API. A consumer version of Win2K will use the NT kernel, probably with all the enterprise baggage stripped out. Given the historical difference between promised and actual ship dates of MS OS products, don't hold your breath for these new toys.
[Top of Section] [Index]

4.8. Do I need to worry about Win64?

Not for a while, no. Although the Win32 API for NT5 is being made compatible with a 64 bit version of Windows, it looks like it won't be late 2000 before a Win64(TM) OS ships. Expect to see it first on Merced servers with high end workstations following. Win32 systems will still sell in their millions for years afterwards, as Merced implementations are too power hungry for laptops and too expensive for home systems. And no doubt the Win64 boxes include support for everyone's Win32 apps

Unless you make or sell server side products that need 3+ GB of real or virtual memory an early migration to Win64 could be a dangerous diversion. If you sell end user applications for the home and office market, then you may not have to worry for years. After all, Merced will run x86 apps at a decent rate -so they say.

But server apps and high end workstation apps could benefit from a Win64 port, so developers in these segments should start getting Win64 ready. Everyone else: avoid putting in fatal flaws in your Win32 code, so as to make the migration to Win64 that much easier when the time comes. Beware of starting too early however and wasting development time on what may turn out to be the wrong direction -the mistake Lotus and Wordperfect made when porting their DOS apps to OS/2 instead of Windows 2.x

Microsoft are starting to evangelise Win64, and no doubt Intel will too as Merced's ship date draws nearer. Intel want to ensure the success of Merced. Microsoft want NT to enter the Mainframe world, and view Merced as the key. Intel are vulnerable to MS NT5.x timescales slipping, or simply to their inability to produce a decent compiler. To get maximum performance from an 'EPIC' architecture you need a compiler which not only unrolls loops, but interleaves different loop iterations for parallel execution. Given that Visual C++ for x86 still hasn't discovered loop unrolling or the P6/PII conditional move opcodes, they have some way to go. This may explain Intel's recent backing of Linux.

For professional developers (or their employers), the main priority is usually obtain maximum revenue for the minimum amount of work. Each platform to support is another compilation and QA process, with the extra complexity of even more complex support calls. In other words, cost. Minimising (or eliminating) source code variations between platforms is critical.

Things to do now

  1. Note that Win64 Pointers are eight bytes long, not 4. So casting between DWORD and VOID* is no longer acceptable.
  2. There are extra typedefs for ints and longs that are pointer sized and can be used for arithmetic.
  3. Data structures need to be aligned in memory for maximum performance. DWORD on 4 byte boundaries, QWORDS/int64 on 8 byte boundaries. The compiler will do this automatically -but packed structures can burn you.
  4. Don't include any x86 assembler or machine code -or keep it in a module with replacement implementations in your language of choice.
  5. Stop trying to write dual mode win16/win32 code. You probably won't regret it.
  6. Be careful of #ifdef WIN32 sections intended to hide features from a 16 bit build catching you out on a WIN64 build.
  7. The size of LRESULT, WPARAM and LPARAM will all expand to 64 bits, so message handlers will have to be checked for inappopriate casts. Presumably a new version of windowsx.h will help crack any changed messages.
  8. Design persistent data structures (files, down the wire formats) to scale gracefully to 64 bits. Using __int64 for the persistent form is easy enough to do today. LONGLONG works in IDL files, but VB doesnít yet know what do do with it.
  9. Make your source UNICODE ready today, even if you don't ship a Unicode build. The earlier you use TCHAR and the portable functions, the less work you'll have in the future.

WinCE developers may already have noticed that some of the MIPS processors used by some OEMS (NEC, for example) are based on the R4000 design, which already uses 64 bit registers. So it may be that a 64 bit version of WinCE is waiting in the wings.

There is of course "another way". If you write Java apps you offload the final translation from bytecodes to native CPU until the last moment -giving you an instant rebuild to Alpha, Merced, Power PC, whatever. And with both key players in the Merced project (HP & Intel) Java licensees, hopefully they will be busy funding work on aggressive JIT compilers for the platform. Now portable Java apps may not offer all the OS support you need, but MS JVM apps -or even better COM objects- may well migrrrrate from Windows platform to Windows platform seamlessly.
[Top of Section] [Index]

5. Programming Questions

This section covers many common programming questions. Because the possible ways in which a windows program does not work is probably provably infinite, only a small subset of the possible questions are covered here. Other useful Internet Resources are listed near the end of the FAQ.

5.1 Application Design
5.2 Sound and Graphics
5.3 Low Level, Device and Real Time stuff
5.4 Shell and User Interface

5.1. Application Design

Fundamental application design problems
5.1.1 How do I port my 16 bit app to 32 bits?
5.1.2 Common Pitfalls in porting from 16 to 32 bits
5.1.3 How can two programs communicate with each other?
5.1.4 How can two programs communicate across a network?
5.1.5 How can I tell what version of windows I'm running?
5.1.6 How do I write a screen saver?
5.1.7 What is a Callback function?
5.1.8 How can my 32 bit program call a 16 bit library?
5.1.9 How do I translate the value returned by GetLastError() into a string?
5.1.10 Why are all my Exe files so big?
5.1.11 How many threads can a program have?
5.1.12 How do I get my program to start even if a user is not logged on?
5.1.13 What is the file format of .{exe, ico, bmp, ttf, wav, avi,doc,xls, ...etc} files?
5.1.14 How do I patch API entry points?
5.1.15 How do I add power awareness to my app?

5.1.1. How do I port my 16 bit app to 32 bits?

The good news: it's easier to go from 16 bit to 32 bits than vice versa. The bad news: it can still be hard work.
  1. Get the 32 bit version of your development tools
  2. Get the 32 bit versions of any support DLLS/VBXs
  3. Read the "Creating Great Applications for Windows 95" and "windows 9x logo requirements" articles and understand the implications.

Trying to compile your program with a 32 bit compiler is usually the first big step: fix all the errors it shows and then see if it works when it is run. A raw API app can just be rebuilt, using PORTTOOL.EXE to help you. Using the "windowsx.h" macros and message crackers can assist you here. Class libraries often provide the message cracking for you, so make life a bit easier. MFC Apps can be ported fairly quickly by opening up the project in Visual C++ and rebuilding. For OWL apps, just create a new 32 bit target or a new project with a 32 bit exe as the destination.

You may be disappointed to find little or no performance improvement, or even worse a slowdown. The latter is most likely on Windows 95, where a lot of the OS is still 16 bits wide. The real speedup of win32 comes with higher power processors, and Windows NT. The new features of Win32 will still benefit application son Win95, and with some extra programming (threads & async IO) performance can be significantly improved.
[Top of Section] [Index]

5.1.2. Common Pitfalls in porting from 16 to 32 bits

  • Integers are bigger. This can break IPC and reading old files.
    Fix: For legacy structures redefine int references to short
  • Structure alignment has changed. Causes the same problems as above.
    Fix: return packing to BYTE alignment for these structures. The include files "pushpack1.h" and "poppack.h" can be used around these structure to fix them.
  • 0xffff is no longer equivalent to (UINT)-1. Use the macros in "limits.h"
  • No DIB.DRV. Use CreateDIBSection() to create a DIB which you can apply GDI calls to, and use BitBlt() to draw it afterwards.
  • A changed comms API. Some thing like DCBs remain, but comms ports are just another type of file now, with blocking I/O being the easiest way to wait for input.
  • Long file names. Make sure that MAX_PATH is used to declare all string that can hold a path, and do not assume that file names have an 8.3 format.
  • The implementation of Unicode or ANSI in the Win32 API is assisted by lots of macros to bind to different actual functions. For example TextOut is a macro mapping to TextOutA()or TextOutW(). This can cause problems in C++ when you have a member function whose name matches a windows API function as the macro renames it.
  • No VBX support. Actually Borland 4.5 manages this with a mixture of thunking (Win32s, win95) and inter-app message redirection (NT3.5 onwards) .
    Fix: Use OCXs instead. C++ users will need BC5.0 or VCC4.0 to use these.
  • Passing handles to GDI & memory objects between applications in PostMessage calls is harder. System objects must be duplicated using DuplicateHandle(). Memory can only be exchanged via shared memory or WM_COPYDATA messages.
  • Calling DOS and other interrupts direct. You will probably find an API substitute somewhere in all the documentation, but BIOS calls are pretty much off-limits.

[Top of Section] [Index]

5.1.3. How can two programs communicate with each other?

In Win16 this used to be done by posting/sending messages containing pointers to data structures in the single shared memory space. With each Win32 process this no lnger works -although it is great for inter-thread communication
  • SendMessage() and PostMessage()
    Only works for the data which can be fitted in to the two 32 bit parameters WPARAM and LPARAM, unless you can pass a pointer to shared memory.
  • WM_COPYDATA.
    Easy, good for small quantities of data. Works between 16 & 32 bit programs. NB: you need to manually add it to your 16 bit header files.
  • OLE Automation.
    Fairly easy but restricts you to automation data types and is not as fast as other methods.
  • COM
    Fast but requires interface declarations and the MIDL compiler. The ATL wizard simplifies this
  • Memory mapped files
    Only for 32:32 IPC. Needs some synchronisation mechanism/objects
  • Named Pipes
    Distributable, but you can't create the server side on win9x. This limits their value somewhat
  • Sockets
    Communication to a local host via winsock is certainly feasible, and good for writing apps which can be distributed. You do need to verify that such apps running on modem based PCs do not keep on trying to dial to their ISP when connections are made.

[Top of Section] [Index]

5.1.4. How can two programs communicate across a network?

There are lots of ways to do this: the most popular are probably sockets and DCOM.
  • Winsock
    Powerful & cross platform, but often a bit low level. Winsock 2 provides more protocol independence so socket apps can run over IPX, IP and other protocols, but is a bit fiddlier to use. Used as the foundation for pretty much everything else, especially when you are trying to implement an Internet protcol from scratch. NB: Beware of byte ordering and structure packing issues when talking to non-Win32 platforms.
  • Distributed COM
    This is built into NT4 and win98, and available as an update for Win95 -and with all IE4 upgrades. DCOM has a lot of security support, which can be geod or bad, depending on the task. With DCOM1.3 you can even use HTTP as a transport, which lets you talk DCOM through a firewall via a proxy server.
  • Inet.dll
    This library comes with IE3 and later and gives you rapid client access to web and ftp servers. Implement your server as a web server extension (IIS, Perl, ASP, JSP, whatever) and you are away.
  • DCE/Microsoft RPC
    You need the win32 SDK to use this. But you may be able to talk to Unix boxes.
  • Named Pipes
    Note that you can't create the server side on win9x, which limits their value as a peer-peer tool.
  • Mailslots
    When broadcasting a message to all clients in a workgroup, the message is sent over every transport: clients may therefore receive multiple copies. Design your protocol to handle this.
  • Email
    You can use an email system such as Exchange or SMTP as the transport.

[Top of Section] [Index]

5.1.5. How can I tell what version of windows I'm running?

With the function GetVersionEx(). This fills in a structure indicating whether or not the OS is NT, and what the version number of the OS is
BOOL  InWinNT() //test for NT nature
{
	OSVERSIONINFO osv;
	osv.dwOSVersionInfoSize=sizeof(osv);
	GetVersionEx(&osv);
	return osv.dwPlatformId==VER_PLATFORM_WIN32_NT;
}
The major and minor elements of the structure help to differentiate beween versions more usefully than build number. NT4 is (NT, 4, 0), NT5 is (NT, 5, 0). Win95 is (no NT, 4, 0) while '98 is (no NT, 4, 0x10), build 1998. Win98 SE is build 2222 or later.
[Top of Section] [Index]

5.1.6. How do I write a screen saver?

You look in the on line help: "Screen Savers", or in the example code which your compiler ships with for a sample saver. The main points to know are
  1. a saver is just an executable (.EXE) with a .SCR extension
  2. the setup dialog is invoked with a /c argument; otherwise the app just shows the saver.
  3. when invoked with "/p hwnd" then it's preview mode
  4. On Win98 the savers need to handle mouse and keyboard presses and password checks themselves: on NT this is all done for you by the OS, which closes the window when it is appropriate.

There are some more details elsewhere on this site, but the best documentation and example code is at Lucien's Screensaver Site.
[Top of Section] [Index]

5.1.7. What is a Callback function?

These are quite common in Windows, and can be an intimidating concept. Put simply, a callback function is a function in your program, the address of which you pass to the OS or some other DLL. This external code 'calls back' your function when it feels like it.

Callback functions are central to Windows: every window has a callback function -the Window Procedure- associated with it, which is called whenever the OS wants to send a message to the window. Other places that callback functions crop up is in hook procedures, callbacks invoked when a hooked system event occurs, and in enumerations -such as when you call EnumWindows().

A key feature of callback functions is that the rules for passing parameters and the number and type of parameters passed must exactly match what the OS expects, or Bad Things happen. Usually the compiler warns you when you try and break the rules -most often when you try and use a C++ member function as a callback. The hidden 'this' pointer prevents non-static member functions from being used in this way.
[Top of Section] [Index]

5.1.8. How can my 32 bit program call a 16 bit library?

NT: You can't do this directly. You will have to write a 16 bit stub app which forwards commands and responses via some IPC mechanism such as COM.

Win9x: Use flat thunks. The thunk compiler is in the SDK, and the documentation is in the Programmer's guide to win95.

Win32s: Generic Thunks
[Top of Section] [Index]

5.1.9. How do I translate the value returned by GetLastError() into a string?

With FormatMessage(), asking for the system message tables. This is a good i18n technique, as the OS can return translated strings itself. NB: does not work in CE, as the error strings aren't included in the ROM images.
BOOL GetFormattedError(LPTSTR dest,int size)
{
	DWORD dwLastError=GetLastError();
	if(!dwLastError)
		return 0;
	BYTE width=0;
	DWORD flags;
	flags  = FORMAT_MESSAGE_MAX_WIDTH_MASK &width;
	flags |= FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS;
	return 0 != FormatMessage(flags,
			NULL,
			dwLastError,
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
			dest,
			size,
			NULL);
}

[Top of Section] [Index]

5.1.10. Why are all my Exe files so big?

Either you have all the debug and browse info included in it, or you have statically linked to MFC/OWL instead of using the DLL versions.
[Top of Section] [Index]

5.1.11. How many threads can a program have?

Every thread created takes up some space in the system. At least 12KB of unpageable memory is used kernel side for a stack, plus whatever is created user side on a per thread basis by the application and associated DLLs. Any DLL which uses thread local storage will add per-thread overhead.

The OS reserves -but does not commit- the thread's user side stack in virtual memory. Thus 128 KB or more of the 2 GB VM space is taken up for each thread.

There is no CPU overhead of having large numbers of threads waiting to run -the scheduler uses a doubly linked list oooor to schedule threads in each priority queue.

That seems to hint that you can have as many as you want, within the bounds of available memory on the target system. However, to get productive work done, keeping the number of threads ready to run close to the number of processors is the most efficient thread design. One thread per processor on an otherwise idle system should give peak performance. If you have a design that uses 2000 threads -one per client connection or whatever, thhhhen you have come up with an application design that may be elegant but it doesnít scale well. The "thread pool" architecture -as supported in IO Completion ports and implemented in most web, file and database servers is a better design.

NT4 (service patch 3) and NT5 support "fibers" which are threads scheduled by the applications themselves. These are possibly lighter weight than standard threads, but seem so rarely used that the limits have never been explored.
[Top of Section] [Index]

5.1.12. How do I get my program to start even if a user is not logged on?

NT: Make it a service.
Win9x: add it to the list of registered apps under HKCU\Software\Windows\CurrentVersion\RunServices. This only runs when someone is logged in, and gets reloaded whenever one user logs out and another user logs in -use a Mutex to catch re-entrancy.
[Top of Section] [Index]

5.1.13. What is the file format of .{exe, ico, bmp, ttf, wav, avi,doc,xls, ...etc} files?

Common file formats are documented on the MSDN disks. The 'Office' formats come with a very strict license agreement, specifically that you are only going to use these formats for Windows platforms and then not to write your own spreadsheet and word processor. TrueType fonts are documented somewhere on Microsoft's ftp site and are more complicated than you'd think.

The definative on line site for file formats is Wotsit
[Top of Section] [Index]

5.1.14. How do I patch API entry points?

Unlike the Win16 world, you are not allowed to patch the API calls for all applications by editing USER, KERNEL and GDI. However, patching the API calls a single app makes is easier in Win32 than Win16: you just modify the jump table at then end of the application. To modify all applications' entry points you need to apply the same technique but also inject your DLL into each ones' address space.

Consult [MSJ Dec 1994 v9#12], and Richter's Advanced Windows for details.
[Top of Section] [Index]

5.1.15. How do I add power awareness to my app?

Now that the Windows logos require apps to be power aware, a lot more people have to worry about implementing what was previously as much a curiosity as non rectangular windows. Actually implementing it isn't that hard -it's testing it that really hurts.

This topic is covered in detail in the Team Iseran Programming Articles
[Top of Section] [Index]

5.2. Sound and Graphics

5.2.1 How do I load/display a 256 color bitmap using LoadBitmap (or CBitmap)?
5.2.2 How do I get the screen into a bitmap?
5.2.3 How do I draw a pixel in a faster than with SetPixel?
5.2.4 How do I get a handle to the desktop window?
5.2.5 How do I play a sound?
5.2.6 How do I play multiple sounds simultaneously?

5.2.1. How do I load/display a 256 color bitmap using LoadBitmap (or CBitmap)?

You can't, it throws away the palette. Use {Find, Lock, Load}Resource() to load a device independent bitmap (DIB) instead. The function LoadImage() can also load deep color images, and do other tricks such as load it into a high performance 'DIB Section'

You will also have to learn about palettes and their management. "Animation in Win32" has some good explanations of this.
[Top of Section] [Index]

5.2.2. How do I get the screen into a bitmap?

If all you want is a static snapshot of the screen, ALT-printscreen works quite well, and HTML help workship includes tools to snap wndows quite nicely. If it is a run time screen grab you are looking after, then a call to GetDC(NULL) returns a device context covering the whole display. Writing into this is considered rude, but copying from it into a bitmap is easy.
[Top of Section] [Index]

5.2.3. How do I draw a pixel in a faster than with SetPixel?

Well, there is SetPixelV -a marginally faster implementation. It still involves a lot of overhead and is unworkably slow for filling in a whole bitmap.

The standard technique is to use a device independent bitmap (DIB), where the bitmap's data is actually stored in the app's own memory. Standard memory reads and writes are all that is needed to manipulate the image. To get the image on screen, call SetDIBitsToDevice. Note that DIBs are usually upside down, and each scan line must be aligned to end on a 4 byte boundary. You can use the CreateDibSection function to do something profound: return a region of memory which can be addressed like a dib, and a HBITMAP handle with which the same region can be drawn using the standard bitmap function calls. This gives you faster blitting of the pixels to the display, and lets you use GDI commands to draw into the bitmap.

Finally, the absolute fastest drawing mechanism is DirectDraw, which lets you draw directly into the frame buffer.
[Top of Section] [Index]

5.2.4. How do I get a handle to the desktop window?

The function GetDeskTopWindow() used to return the window on the desktop, and it still returns the base window of which all others are effectively children. Since Win95, the desktop that you see is actually provided by the explorer, usually a couple of windows under one called "Program Manager".

IE4 and successors go one step further, with the ActiveDesktop. Again, you can rummage around with spy to find out the names and classes of windows which your own program will have to find and manipulate itself -but you run a major risk of things breaking unless you are very careful.
[Top of Section] [Index]

5.2.5. How do I play a sound?

With PlaySound(), MessageBeep() or the low level waveOut() calls. You will probably need to link in the multimedia libraries too. (add WINMM.LIB to your project). The games sound API, DirectSound, permits advanced techniques: mixing, 3D positioning of sources and provides low latency access to the sound buffers.
[Top of Section] [Index]

5.2.6. How do I play multiple sounds simultaneously?

You have to use the DirectSound API to do this; it provides a means to mix multiple sound streams into a single output stream.
[Top of Section] [Index]

5.3. Low Level, Device and Real Time stuff

5.3.1 How do I access hardware via IO ports or mapped memory?
5.3.2 How do I handle interrupts in my Win 32 program?
5.3.3 How do I read/write the serial port?
5.3.4 How do I read/write the parallel port?
5.3.5 How can I get a thread to respond in under 10 milliseconds?
5.3.6 Can I use Win9x, NT or CE as a real time OS?
5.3.7 How do I do system wide keyboard and mouse hooks?
5.3.8 How do I measure time in my program?

5.3.1. How do I access hardware via IO ports or mapped memory?

You can get away with port IO in user level code on Windows 95 & 98 through assembly language instructions like "__asm in al,dx" and "_asm out dx,al" . The VC5 header file <conio.h> defines _outp() and _inp() functions which you can use -even if you aren't supposed to. However, some ports may not respond as expected, because device drivers can talk to them simultaneously. Life is easier (and more portable) if you can use device drivers -and for standard COM port and parallel port programming this is usually the case.

For any port IO in NT, or serious device access in win9x, you'll need a device driver. Have a look at the device driver FAQ , or some of the driver programming groups -none of which have the word driver in their title to improve the signal to noise ratio. (key words: VxD and kernel mode) The NT DDK samples you need to look at are DDK\SRC\GENERAL\{MAPMEM, PORTIO}

Doctor Dobbs Journal in May 96 had an article called DirectIO which showed how to add a device driver to tweak the NT task protection masks so that in and out instructions are allowed in user mode code. This is an invaluable trick for non-commercial & prototype applications, but not acceptable for shipping products. NT separates device drivers from user code for valid reasons: performance, reliability on multi-processor systems and to enable applications to be more portable.

There are a pair of low cost shareware device drivers which claim to support device IO and interrupts from user mode code. The commercial product WinRT from Blue Water Systems can do this and more.

Link: Interfacing hardware to the PC
[Top of Section] [Index]

5.3.2. How do I handle interrupts in my Win 32 program?

You can't. You have to write a device driver or VxD, or buy a tool which catches the IRQ and forwards it to your application.

Writing device drivers is not as hard as it sounds -especially WDM drivers. It just needs extra learning and a more complex debugging setup. Otherwise, follow up some of the URLs in the previous section to see if their products meet your needs.

NB: Some device drivers (such as the standard serial port driver) can set Event objects in response to external state changes (i.e. some of the RS232 lines). These can be used by normal applications. The response time is under 20 milliseconds on NT workstation, months (well, 55+ milliseconds) on Win9x.
[Top of Section] [Index]

5.3.3. How do I read/write the serial port?

Win16 used to have lots of special functions such as ReadComm() and WriteComm() to do this, but in Win32 you just open a serial port like any other file:-
                 //open COM1 for read and write
hPort=CreateFile( "COM1",
                  GENERIC_READ | GENERIC_WRITE, //bidirectional
                  0, 
                 NULL, //no security
                 OPEN_EXISTING,  //this must be set; the ports are already created
                 FILE_ATTRIBUTE_NORMAL, // maybe with | FILE_FLAG_OVERLAPPED  
                 NULL );
Standard ReadFile() and WriteFile() functions can then be used to read or write to the port. To set the port up reliably, COM port specific functions need to be used, so look up the online help for details on the following functions:- GetCommModemStatus(), SetCommState(), SetCommMask(), SetupComm(), PurgeComm(), ClearCommError(), SetCommTimeouts() and EscapeCommFunction()

Tips:-

  1. Even on Win9x, you can use overlapped IO with a com port
  2. The Signalled state of a port seems to indicates it is ready for reading or writing, even if you only opened the port unidirectionally.
  3. WaitCommEvent() lets you block waiting for something interesting to happen, such as data arriving or various lines (e.g. RI -Ring Indicator) toggling.
  4. On win98/NT5, RequestDeviceWakeup() may even let the external port wake up your app -especially if RI is used as the signal.

[Top of Section] [Index]

5.3.4. How do I read/write the parallel port?

Open it as per a serial port, using "LPT1" or "LPT2" as the port name. This works provided the device which you are talking to uses the standard ECP/EPP protocols. If you are trying to use the parallel port as a non standard IO port, then you have to access the port using port IO instructions -something you are not mean't to do from a user mode application, and may not be able to do reliably even in a driver a couple of years from now.
[Top of Section] [Index]

5.3.5. How can I get a thread to respond in under 10 milliseconds?

Getting a user mode thread to respond to a signal even in 20mS or less on a Win9x box is an achievement, so use of NT is the first step. Next set your process as real time, and give the thread a high priority. Finally, play with timeBeginPeriod to see if increasing the RTC interrupt frequency helps. Even with all these tricks, a heavy load on the system can mean that your thread doesnít get scheduled for tens to hundreds of milliseconds.

Locking down memory with VirtualLock helps to ensure that memory isn't paged out, which can make response time worse. The app/user needs SE_INC_BASE_PRIORITY_NAME rights to be able to do this. In practise it is of little benefit. Maybe the new AllocateUserPhysicalPages() call in NT5 will work better.
[Top of Section] [Index]

5.3.6. Can I use Win9x, NT or CE as a real time OS?

Not as far as the authors of the comp.os.realtime FAQ are concerned. The lack of priority inheritance can make priority inversion deadlocks possible, and there are not enough process and thread priorities for their scheduling needs. Neither Win9x or NT are very good for time critical user mode code. Win9x, lacking a re-entrant Win16 subsystem, cannot be used very deterministically. (I.e. you can't predict whether or not you thread gets locked out from a many API calsl).

Win9x should certainly be avoided for time critical code -unless you want to write assembler routines in VxDs, whose their time to respond to an interrupt is very deterministic.

Windows NT does have real time priority process and threads, which can be used to get as close to real time as you can hope to do with a Windows app. It can be used more easily for "soft real time" applications; its interrupt handling architecture (interrupt handlers should just schedule deferred procedure calls) make hard real time tasks (such as soft modems) hard to implement reliably. Embedded NT sounds like NT tweaked to treat {masked,flash} ROM as memory so that diskless and displayless operation is possible: no scheduling changes apparent.

WDM is emerging as a single driver model for new bus (1394, USB) drivers on both platforms. The related video handling driver architecture "WDM Streaming" could be useful not just for time critical video processing, but also as a way of gluing together other high bandwidth kernel mode data sources and sinks.

Windows CE has some potential as a light weight Win32 platform for embedded use. However there is a fundamental problem in the Win32 system architecture: applications and device drivers are cleanly split. This is great for hardware independent applications, and application independent hardware, but not so good for anyone trying to write a custom application coupled directly to a piece of non standard hardware.

DOS, DR-DOS, and RTOS products like QNX and VxWorks may be better for your needs. There are stated plans for CE to evolve to become a hard RTOS, but as this platform's evolution seems to follow the needs of high visibility product categories (WebTV, HP/C, Dreamcast & others), it is hard to predict when CE will reach this state.
[Top of Section] [Index]

5.3.7. How do I do system wide keyboard and mouse hooks?

You can use SetWindowsHook to do this, but need to put the hooks into a DLL which is then mapped into the address space of all applications. Richter's book covers this process.
[Top of Section] [Index]

5.3.8. How do I measure time in my program?

There are lots of ways of measuring time, each with their own advantages and disadvantages. Variables are accuracy, portability, overhead and ease of use.

time
part of ANSI standard C, found in time.h and measuring seconds since 1/Jan/1970. Works reliably until some time in January 2038. Portable, and good for both external displaying (via ctime) and for arithmetic. Also integrates well with time zone settings. Not useful for dates before 1970.
GetTickCount
Returns elapsed CPU tick count to nominally millisecond resolution. On Win9x, the minimum resolution is 55mS, on WinNT it is usually a smaller value (such as 10-15 mS). Wraps every 49 days, and bears little relation to the outside world. Laptops and OnNow PCs may suspend the timer while in some sleep states. A call to timeBeginPeriod to increase the timer interrupt frequency makes this function more accurate.
GetSystemTime
Returns system time in a fairly complex SYSTEMTIME structure. Converting it to a FILETIME format makes comparisons and differences easier. The resolution is no better than that of the GetTickCount call: 10 or 55 mS. This time format won't wrap around for millenia, which makes it ideal for persistent data.
QueryPerformanceCounter
A higher resolution counter, whose frequency and accuracy varies from OS to OS, and from CPU to CPU. You need to use QueryPerformanceFrequency to discover the frequency. On a single processor NT platform the counter frequency is 1+ MHz, so is accurate to microseconds. On a multiprocessor system it uses the RDTSC opcode to measure CPU clock ticks. Good for low level performance measurement, although the switch to kernel mode adds enough overhead to hamper profiling of small routines.
rdtsc
The Pentium's "Read Time Stamp Counter" instruction is what NT4's Multiway HAL's version of QueryPerformanceCounter must use. If inserted inline into code, you end up with an application which will break on a 486 or earlier. But it does measure CPU clocks with the least amount of overhead, so can be used in non release profiling builds on Pentiums and later. Theoretically If you use this on a multi CPU system you can get into trouble, as each CPU has its own clock, but in practise they seem to be synchronised to a few ticks. Portables can be ever wierder -they can suspend the clock or change frequency on the fly.
There is also the MFC CTime structure, with a CTimeSpan function to measure elapsed time. These classes exhibit "unusual" behaviour when measuring the time spans between two dates with a transition to summer or winter time between them. Being based on the ANSI time() functions, they have the same weaknesses of only being valid from 1970 to 2038
[Top of Section] [Index]

5.4. Shell and User Interface

This may seem a minor area, but it can often contain some of the hardest programming problems Windows has to offer. Things that are both commonplace and simple to interact with, turn out to be programming nightmares to implement. And don't expect the SDK or class library to give you everything on a plate: a lot of hand crafting is needed to make a good UI.
5.4.1 How do I create/use Shortcuts (.lnk files)?
5.4.2 What are shell extensions?
5.4.3 How do I get the shell to automatically create new documents of my type?
5.4.4 Why doesn't my app have nice 16x16 and 48x48 icons? (aka: Why does my app still have the MFC icon?)
5.4.5 How I put my application into the start bar
5.4.6 How do I hide my window from the task bar?
5.4.7 How do I get Internet Explorer/Office 97/Win98 menus & toolbars?

5.4.1. How do I create/use Shortcuts (.lnk files)?

You have to use IShellLink to manipulate these. To invoke the shortcut, use ShellExecuteEx(): ShellExecute() does not work on all link types -e.g. dial up networking links.
[Top of Section] [Index]

5.4.2. What are shell extensions?

These are in-process COM objects which implement a sparsely documented set of interfaces (see MSDN/MSDN on the web) and enable anyone to write their own "folder" within the Windows Explorer shell
[Top of Section] [Index]

5.4.3. How do I get the shell to automatically create new documents of my type?

By adding a shellNew handler. The default is to get the shell to create a zero length file of the appropriate name. Your application's file loading code must handle this case and treat it as creating a new blank but named file, instead of as an error.

Note that although this is a Win95 integration guideline, it is now often considered good form to ask the user if they actually want you to extend their shell in this way -as once you have 20+ applications installed, that pop up menu ceases to be too useful.
[Top of Section] [Index]

5.4.4. Why doesn't my app have nice 16x16 and 48x48 icons? (aka: Why does my app still have the MFC icon?)

Because you haven't written any. Use your icon editor to create new device images of the appropriate size within each existing icon. Then update your windows by using either RegisterClassEx or WM_SETICON. The latter is a message which can be posted to any window to get it to change its icons and is very useful for dialogs and other situations where the class is registered out of your control.

When the MFC App wizard is used to generate an application, it generates 16x16 and 32x32 icons: you need to modify both when customising your program.
[Top of Section] [Index]

5.4.5. How I put my application into the start bar

Those little icons at the end of the start bar are called tray icons, and should be used sparingly. Too many applications take up the tray with clutter, and the latest Windows UI guidelines advise very strongly against joining in.

To find out how to create one, look in the manuals for the Shell_NotifyIcon() API call. This lets you add new icons to the tray. Also register a handler for the message "TaskbarCreated" which is sent out whenever IE4 restarts, and recreate the icon after such an event.

MSJ March 1995 has a good article covering the whole subject, although sadly it is no longer in the MSJ section of MSDN. Otherwise see "Adding and Deleting Taskbar Icons" in MSDN or the "Programming the Win95 User Interface" .
[Top of Section] [Index]

5.4.6. How do I hide my window from the task bar?

A window will show up in the taskbar button area if
  1. The window is visible
  2. The window is not a child window.
  3. The window is not owned.
  4. The window is not a tool window.

There are some exceptions to the above rules, but they apply only to legacy ("designed for Windows 3.1 or earlier") applications.

To make your application minimise to a tray icon: hide it when you get the WM_SYSCOMMAND message requesting a minimise; restore it and bring it the foreground manually.
[Top of Section] [Index]

5.4.7. How do I get Internet Explorer/Office 97/Win98 menus & toolbars?

You can do these with the Rebar/Coolbar common control, available from the COMMCTRL.DLL library distributed with IE3 and IE4. Documentation for using this control comes with the Internet SDK, and VC++ 6.0

Note that once you use this control, you end up in a complex situation regarding redistribution: for pre IE3/IE4 users you have to redistribute a common controls update. This is simple, but if the update was applied does add a reboot to the installation process. Alternatively, design an application which only uses the rebar if the library is up to date, and drop to the previous version if not.
[Top of Section] [Index]

6. Internet Programming

There are lots of ways to "Internet Enable" an application, from the simple one of opening up URLs in the default web browser, through Winsock and WinInet right up to integration of URL monikers and asynchronous pluggable protocol handles.

The Internet Client and Platform SDKs contain the document all the techniques. No-one ever asks questions about the really complicated methods , so either they are rarely used or the people who use them are very smart indeed. If you are just starting out then stick to Winsock WinInet and the Web Browser ActiveX control.

The Winsock FAQ covers a lot of the low level sockets questions, and includes sample code too.

6.1 How do I open a URL in the default web browser?
6.2 How do I programatically download files?
6.3 How do I write a Web Browser?
6.4 Where is the standard of HTTP/FTP/SMTP/NNTP/some-other-protocol documented?
6.5 How do I write raw sockets programs (like ping)?
6.6 How do I programatically connect to the net?
6.7 How do I tell if a machine is connected to the Internet?
6.8 How do I get a machine's MAC address?
6.9 How do I get a machine's IP address and hostname?
6.10 How do I display a JPEG or GIF file?

6.1. How do I open a URL in the default web browser?

This is easily done by calling ShellExecute() HTTP and FTP URLs should be processed by both Netscape and IE: the "default" browser will handle them. Other protocols such as mailto and news may also handled by the browser. IE4 adds handlers for things like "Callto:" for Net Meeting contacts.
#include "windows.h"
   //include ShellExecuteA
#include "shellapi.h"
  
   //link in the library
#pragma comment(lib,"shell32.lib")
int main(int argc, char *const argv[])
{
    ShellExecute(NULL,"open", "http://www.iseran.com/", "", "c:\\", SW_SHOWNORMAL);
    return 0;
}

NB: Some versions of Netscape do not reliably set up the appropriate registry entries: see an article in Windows Developer Journal for details and workaround to this.
[Top of Section] [Index]

6.2. How do I programatically download files?

With the WinInet DLL and API (and MFC wrappers), MS have provided us developers with a relatively easy to use set of APIs for retrieving files using any of the known Internet protocols. A nice feature is that these calls make use of the Internet Explorer cache. A weakness is that they rely on IE3 or later being installed on the machine, which is almost universal nowadays.
[Top of Section] [Index]

6.3. How do I write a Web Browser?

You don't if you can avoid it: you build an application which uses the MS Web browser ActiveX control and provides its own menu and toolbars. This gives you state of the art functionality in an afternoon's work. Note that the Browser control is much more idiosyncratic than commercial ActiveX controls, and it can take some time to fully understand it. That's why a whole afternoon will be needed.

Alternate methods exist but are harder work:

  1. Take the Netscape source and somehow integrate it with your program.
  2. Buy the Sun HTML Java bean. Portable, but flaky.
  3. Talk to vendors such as Spyglass.

[Top of Section] [Index]

6.4. Where is the standard of HTTP/FTP/SMTP/NNTP/some-other-protocol documented?

All official internet standards are documented on the net itself, rather than in win32 manuals. The Internet Engineering Task Force is a good starting point.
[Top of Section] [Index]

6.5. How do I write raw sockets programs (like ping)?

This is very difficult, with implementation specific APIs provided for some Win32 platforms. For NT, look for ICMP.DLL and associated documentation in the Win32 SDK. Also consult the Winsock FAQ
[Top of Section] [Index]

6.6. How do I programatically connect to the net?

Automatically, if the user has the appropriate dial-up settings and your application makes a call which goes out over the network. Otherwise, ShellExecuteEx() can be used to open a dial up networking link file.

The IE4 version of WinInet adds functions like InternetGoOnline(), InternetAutodial() and InternetAttemptConnect() , all in an attempt to make life simple. In fact, they make things more confusing as you have to know which to use and in what order. InternetAttemptConnect() seems the best bet.
[Top of Section] [Index]

6.7. How do I tell if a machine is connected to the Internet?

There is no single function for determining if a machine is connected to the Internet, and it is impossible to reliably determine what is happening without side effects -such as automatic network connections taking place. What you can do is reliably detect when there definitely isn't an Internet link: in the absence of any dial up or LAN connection the system is definitely on line.

Some techniques include :-

  • RasEnumConnections() . A reliable technique for modems and direct dial up networking, but not for situations where Internet access is via a LAN. You should dynamically load "RasEnumConnectionsA" from "RASAPI32.DLL", as LAN installations of Windows may not include the library.
  • InternetGetConnectedState() : a Wininet/IE4 function call. Can distinguish between modem and LAN, but can't handle complex LAN+autodial router situations. It is "offline state aware". Important: handling of the off line flag changed for IE5 -it returns TRUE for connected' even when off line, but signals the flag in the LPDWORD parameter.
  • InternetCheckConnection() : a Wininet/IE4 function call. This is meant to determine if a URL is reachable -in practice it is pretty unreliable and best avoided.
  • Using the Offline flag which is part of IE4 to allow users to manually control the online/offline state of applications. This flag is stored in the registry and can be manipulated via some new function calls
  • WM_DEVICECHANGE messages, which tell your app when a slow or fast network adapter has arrived or departed. There is no way to tell if the adapters are actually connected to anything though.
  • NT4 SP4, NT5: The IP Helper API can tell you which network 'interface' to use to connect to a supplied IP address, and what the bandwidth and current status of that link is.
These calls mostly determine the presence or absence of network connections -not Internet access, so can't handle a home network sharing a dial up connection, or two laptops connected directly to each other.

The global offline state flag of IE4 (and hence win98, NT5) and the call to test it - InternetGetConnectedState()- look the best long term options, but will take time to become universal. The IP Helper APIs even let you find out how much traffic is going over a link, but only detect the 'loopback' interface on Windows 98, so is not a lot of use. Wouldn't a 'GetSpeedToHost() function call be great?

Finally, whatever technique you use, when it's time to talk to a remote site, always add timeouts or a cancel button. Even a quick functions like gethostbyname() can lock up an app if something in the network chain is broken.
[Top of Section] [Index]

6.8. How do I get a machine's MAC address?

Not all machines have a real MAC address, only those with LAN cards. Given that fact, an NdisRequest() for OID_802_3_CURRENT_ADDRESS will give you the right answer, provided the NetBIOS protocol stack is installed on the PC. This used to be common on Win95 boxes, but with Win98 and NT installing TCP/IP as the default stack, it is becoming rarer.

NB: The OLE function CoCreateGUID() will try to create a unique GUID, the last 64 bits of which are usually the MAC address of a card on the PC. Do not rely on this 100% of the time, as the algorithm does other things when running on a PC without a network interface.
[Top of Section] [Index]

6.9. How do I get a machine's IP address and hostname?

The IP address can be tricky, as a PC with multiple network interfaces (such as LAN and modem) will have multiple IP addresses. Furthermore DHCP and dial up networking allow systems to change their IP address on a regular basis.

The hostname is more constant than anything else, and a call to gethostname() will return this. gethostbyname() can take this name and return a list of its IP addresses. What you actually get back varies from machine to machine -and, on a laptop hor home system- from minute to minute.
[Top of Section] [Index]

6.10. How do I display a JPEG or GIF file?

In C++ this is not always easily done for free, as no one of the standard class libraries automate this. Using an ActiveX control which can handle the formats is one option -and such controls often ship with the professional versions of development products. Check the redistribution license before use, as you may have to pay distribution fees.

GIF is -relatively- easy to parse, especially compared to JPEG, although UNISYS require upfront licensing fees before you redistribute commercial, shareware or freeware applications using the file format. This is because they own a patent on the LZW compression algorithm used.

Windows 98 and NT5 will decompress a JPEG for you, provided you create a bitmap BITMAP with the right flags and point it at the compressed image in memory. For Win95 and NT4 you have to roll your own solution. Most people use the C source from the independent JPEG group

NB: Java and IE can both display JPEG and GIF images, and can be made to render the images within your app via ActiveX, although it can be tricky to integrate such a solution. The royalty issue of using either of these tools for GIF display within your own products is "unclear".
[Top of Section] [Index]

7. DLLs: Dynamic Linked Libraries

7.1 What is a DLL?
7.2 Why would I need to create one?
7.3 How do I create one?
7.4 How do I export functions?
7.5 How do I load a DLL?
7.6 How do I debug a DLL?
7.7 How do I create C++ classes in a DLL?
7.8 Why does my MFC-based DLL only work in some applications?
7.9 I have a 3rd Party DLL with no documentation: how can I use it?

7.1. What is a DLL?

It is a collection of functions which do not constitute a process, but which can be loaded into a process and invoked. The loading is done at run time rather than at compile time (those are static libraries). DLLs have a special entry point DllMain which is invoked when processes and threads are attached and detached, allowing data structures to be created and destroyed appropriately.

A lot of the system is implemented in DLLs, even though their extension changes somewhat. The file types OCX, CPL, DRV are all really DLLs.

In Windows 2.x and 3.x each DLL had only one instance of its data segment regardless of the number of applications using it. In Windows 32 a DLL can be marked as shared, for the same behaviour, but the default is for each process to have a private copy of the DLLs data.
[Top of Section] [Index]

7.2. Why would I need to create one?

  • To divide a program into separate modules which can be loaded on demand.
  • To store language/region specific resources
  • To enable a core code library to be used by your own and other applications
  • To produce in-process COM objects, or an ActiveX control (OCX)
  • Implementing OLE objects as in-process DLLs is the best way to get performance out of an OLE link.
  • To implement a control panel extension or some types of driver.

[Top of Section] [Index]

7.3. How do I create one?

By setting the options in your compiler's IDE to generate a DLL rather than an EXE. You also need to replace WinMain with a DllMain function.
[Top of Section] [Index]

7.4. How do I export functions?

In win16 you needed to add FAR EXPORT to all exported DLL functions. This is not required in win32. Many 32bit compilers provide the function 'decorators' declspec(dllexport) and declspec(dllimport) to be placed in front of function declarations to replace this call.

It is important to remember to put extern "C" {} around function declarations to turn off C++ name mangling if you wish to have them usable by any application other than those created with the same compiler.

Visual C++ now uses the stdcall naming convention, which adds a number to the function name to indicate the number of bytes expected. This can complicated importing functions in some languages (I.e. delphi). Either look at the DLL to determine the extended name and import that, or create a .DEF file which explicitly renames the functions.

If you are doing COM development then things are "different": you need to export a method of accessing the class factories, another to determine if the DLL is no longer needed, plus optional functions to register and unregister the library in the registry.
[Top of Section] [Index]

7.5. How do I load a DLL?

  • Implicitly by creating an import library with IMPLIB.EXE and then linking this library with the application.
  • Explicitly with LoadLibrary() and LoadLibraryEx()
  • Automatically with CreateDC() for printer and display drivers.
  • Magically with CoCreateObject()

If you use LoadLibrary() then a call to SetErrorMode() first can be used to let your app know of a load failure without a dialog box popping up.
[Top of Section] [Index]

7.6. How do I debug a DLL?

By debugging the application which loads the DLL, even though the debugger may complain about its lack of any debug information: set breakpoints in your DLLs source and continue.

Writing a special test harness in the same language as the DLL can often simplify the debugging process when the DLL is really intended for use by another development tool or language.
[Top of Section] [Index]

7.7. How do I create C++ classes in a DLL?

Do this very carefully.

You can't mix C++ classes between vendors- the different name mangling and object creation schemes prevent this. Use C functions or create COM objects instead. Also make sure that exceptions are not thrown from the DLL to the app, as stack unwinds can be disastrous.

You can implement C++ classes in a DLL when used within a C++ application built with the same compiler. You can still end up with heap corruption if you mix run time libraries: both app and DLL should use the same debug versus non debug CRTL. Better still, always let the DLL create and free the memory used by the object. Use the declspec(dllexport) and declspec(dllimport) decorators in front of your class definitions in header files. Use something like #include "pushpack4.h" at the start and #include "poppack.h" and finish of the class header file to ensure that structure packing is consistent
[Top of Section] [Index]

7.8. Why does my MFC-based DLL only work in some applications?

You may have created A DLL with the "Use MFC in a shared DLL" option. This creates DLLS which can only be used within another MFC application. Change to using the static MFC library instead.
[Top of Section] [Index]

7.9. I have a 3rd Party DLL with no documentation: how can I use it?

It may not be possible to reuse someone else's DLLs. Firstly, it is often prohibited by the licensing agreement of the software. Secondly, it is pretty hard to work out how to use many DLLs.

Quickview or other DLL viewers can list the exported functions of a library, but they provide little or no information on what parameters must be supplied, or what those parameters mean. Furthermore inproc COM objects are not listed among the exports, as pointers to their exported functions are returned by the factory objects.

For progress any further you will need a dissassembler, a debugger and patience. Within the European Community it is actually legal to reverse engineer the interfaces to another program provided this is done in order to facilitate the development of compatible products. However the exact details on this pro-competition law are complex: consult a legal expert before attempting to take advantage of it.
[Top of Section] [Index]

8. Console Mode Applications

8.1 What is a console application?
8.2 Why write a console application?
8.3 Why shouldn't I write a console mode application?
8.4 Why doesn't SetTimer work in a console app?
8.5 Why don't asynchronous socket calls or the MFC CSocket classes work in a console app?

8.1. What is a console application?

A console application is a windows application, plain and simple.

They have a different flag in the executable header to indicate a win32 character subsystem application, which the OS recognises and knows to create a new console window unless the application is executed from an existing console window.

C & C++ Compilers usually bind the entry point of a console mode app to int main(int argc, char *argv[]) and stdin, stdout and stderr bound to the console. Otherwise, there are no real differences. A console application has access to the entire win32 API, can create visible or hidden windows, and generally do what it wants within the win32 environment.

Windows NT has a whole console API, enabling applications to interact with the user within the confines of the console window. This is often used by console based editors.
[Top of Section] [Index]

8.2. Why write a console application?

It's an easy way to start porting an application from Unix or similar OS to Win32. It's also a simple way to test and demonstrate aspects of Win32, without having to worry about window creation or management for text output.

If you want to write programs specifically for console users, then console mode applications are the only way to do it.
[Top of Section] [Index]

8.3. Why shouldn't I write a console mode application?

  1. Windows95 doesnít properly implement the whole win32 console APIs, or even display the icons of console applications in the explorer reliably.
  2. When a console app is started from outside a console, the OS always creates a console window for output: this is often undesirable.
  3. Many Windows API calls expect a the calling application to have a message queue and a window somewhere.
  4. If you want to have a console for debugging output, then you can just create one with AllocConsole(). One trick is only to create these consoles in a debug build, or when a special registry key is set.
You can easily use WinMain() as the entry point to an application which intends to create no windows, enabling the application to start cleanly from the explorer.
[Top of Section] [Index]

8.4. Why doesn't SetTimer work in a console app?

All SetTimer does is tell the system to stick WM_TIMER messages into your window's/thread's message queue after all other messages have been processedand the timer has expired: DefWindowProc secretly invokes the function when it gets this message. Lacking such a queue or a GetMessage()/DispatchMessage() pumping loop the messages never get delivered.

Use Sleep(), WaitForSingleObject() and Waitable timers instead
[Top of Section] [Index]

8.5. Why don't asynchronous socket calls or the MFC CSocket classes work in a console app?

Again, because windows need to be created to handle received messages. Creating a hidden window is the workaround here -or use blocking sockets instead.
[Top of Section] [Index]

9. Services

9.1 What is a service?
9.2 How do I create one?
9.3 How do I start/stop/install/uninstall a service?
9.4 How do I debug a service?
9.5 How does it gain the same rights as a user?
9.6 How do I change the parameters of a running service?
9.7 How do I run an existing program as a service?
9.8 How do I run a service under Win95?

9.1. What is a service?

It is a process which can run on an NT box without a user being logged in, effectively acting as a user mode part of the operating system. It is similar to a Unix Daemon.

One strength of the service model is the way they can run on a machine continuously, another is that the service control manager can be controlled across the network, so services can be started and stopped remotely. A third advantage is the rights of the service can be different from those of any logged on user, so that it can do things which are not otherwise possible.

There are weaknesses. Services can not directly interact with the desktop unless they are an "Interactive Service" executing from the local system account. (*) Some of the functionality which services can perform is restricted because of this -for example prior to calling COM objects in a service prior to NT4 was barely possible. Services are NT only applications, so a product which aims to support Win9x and NT will have to provide different programs.

(*) Services can always pop up a message box with the MB_SERVICE_NOTIFICATION flag. But remember, on a real server, there is often no-one at the console.
[Top of Section] [Index]

9.2. How do I create one?

The Win32 platform documentation covers the basics of creating, installing, configuring and using services -this is an essential read.

There is some sample code in the Win32 SDK, and the Microsoft Java SDK includes the information and samples to build a Java service.
[Top of Section] [Index]

9.3. How do I start/stop/install/uninstall a service?

The NET START and NET STOP command lines can be used to start/stop services, or they can be started from the control panel.

The service control utility (SC.EXE) which comes with the Win32 SDK is probably the most powerful way of controlling services from the command line during development.
[Top of Section] [Index]

9.4. How do I debug a service?

If your IDE lets you attach to a running process, you can attach to a service already in execution. A DebugBreak() entry in the code (or anything which raises an unhandled exception) will also cause your chosen JIT debugger to start up.

Another trick is to have your main() function recognise a "-debug" parameter and provide a test harness to the core functions you wish to debug -this lets you get code working without having to worry about the extra life cycle complexity of a full service.
[Top of Section] [Index]

9.5. How does it gain the same rights as a user?

With the functions LogonUser() and ImpersonateUser()
[Top of Section] [Index]

9.6. How do I change the parameters of a running service?

Not easily. The registry should be used to store configuration information, so the service would have to regularly check for the appropriate registry entries changing, or respond to a "reread changed parameters and restart" message somehow passed to it.

ChangeServiceConfig() is used to change the operational parameters of any service which the OS cares about.
[Top of Section] [Index]

9.7. How do I run an existing program as a service?

There's a program in the NT resource kit which will let you do this, to a greater or lesser degree.
[Top of Section] [Index]

9.8. How do I run a service under Win95?

This is not possible; the best substitute is the list of registered apps under HKLM\Software\Windows\CurrentVersion\Run or RunServices. Once your app has been started, it must call RegisterServicesProcess() to tell the OS it wishes to stay active after a user logs off.

Warning: win9x "services" may not get executed until someone is actually logged on.
[Top of Section] [Index]

10. Help! My Program does not Compile and Link!

Getting your program to build can be hard, especially when you are just starting out. Most of the problems are relatively simple -it just takes time to learn what they are and how to react.

10.1 The compiler can't find functions which I know are in Windows.h
10.2 I get compiler errors when I try assign a C++ member function to a Windows callback routine.
10.3 I get 'unknown symbol' errors when linking

10.1. The compiler can't find functions which I know are in Windows.h

There are a number of common reasons for this.
  1. Your code has VC_EXTRALEAN or WIN32_LEAN_AND_MEAN defined, and the symbols you want are not in the 'lean' subset
  2. The functions you want are actually in a different header file: a quick search can test for this. Example: ShellExecute is in SHELLAPI.H
  3. The function is a recent addition and your Win32 headers are out of date. Try downloading a later version.
  4. The function is a recent addition, but you are not telling the compiler to include it. You need to define _WIN32_WINNT as 0x0400 for the NT4 extensions, 0x0410 for Win98 extras, and 0x0500 for a full NT5 header set.
  5. In C++, a local implementation of a function may hide the base API implementation. Preceding a function such as SendMessage() with double colons "::" will give you the base API call.
  6. Last, but definitely by no means least, you may have misspelt the function, or got the capitalisation wrong.

[Top of Section] [Index]

10.2. I get compiler errors when I try assign a C++ member function to a Windows callback routine.

There is a very simple reason for this: you can't use non static member functions as callbacks. All such functions have a pointer to the 'this' object added as a first parameter, so that the function knows which object it belongs to. OS callback functions -WndProc, TimerProc, Enum*Proc and the likkkke- do not have these pointers, so member functions can not be cast.

Static member functions can be used. If you can store a pointer or reference to the C++ object with the the Windows callback (or attach it to the Window for a WNDPROC), then these static functions can be used to invoke the C++ member. This is how most C++ class libraries work, except for the really devious ones that create a lump of code on the fly to do the dirty deed (a thunk is the technical name)
[Top of Section] [Index]

10.3. I get 'unknown symbol' errors when linking

This means that the linker needs to link to a library/object file to invoke a referenced function. There are a number of causes for this.
  1. Check you are including all the relevant libraries -such as WINMM.LIB and WSOCK32.LIB, needed for multimedia and sockets, respectively.
  2. The calling convention/name mangling on the exported function may different from what you expect, so the routine is not being found. C functions need to be declared as extern "C" {} to stop the C++ compiler corrupting the name -but even C functions which use the stdcall calling convention include a parameter size flag in the imported/exported name.
    Sometimes you don't even have a matching LIB file for a header file: this is usually the case with DLLs. The tool IMPLIB can create a library file, or LIB.EXE itself in Visual Studio 97 and later. There is also the brute force solution of run time linking with LoadLibrary. This is inelegant but very effective.
  3. If the unknown symbol is main() or WinMain, then the cause is usually you are providing a different entry point to yor application from that which it expects. Either fiddle with the compiler settings till the linker knows what entry point to look for, or use the expected entry point.
  4. Finally, if it is beginthread, beginthreadex, and endthread that are missing, then you are linking to the single threaded C library but parts of the app expect the multithreaded equivalent. Change the run time library settings.

[Top of Section] [Index]

11. Debugging -or 'help, my program doesnít work'

Debugging: the process of discovering how many invalid assumptions you made during the design and implementation of your program.

It can be hard to get anything working when you are just learning Windows: not only is there a lot to go wrong, the debugging tools and techniques are all foreign. Worst of all, there are a lot things you don't understand, which can lead to serious flaws in your code.

With time you will get better at debugging. But remember: it is often better to be able to write working code than to be good at finding fixing broken code.

11.1 My application keeps on stopping with "an unhandled exception C000005"
11.2 What is Just In Time Debugging?
11.3 What do all those exceptions mean?
11.4 What is SEH and how do I use it?
11.5 Why does a Win32 API call keep failing?
11.6 How do I print a message to the debugger?
11.7 How do I break to the debugger?
11.8 NT Crashes with a Blue Screen of Death when my program runs!
11.9 My STL code does not compile/work!

11.1. My application keeps on stopping with "an unhandled exception C000005"

You have a bug. This is the 32 bit equivalent to Exception 13: General Protection Violation. The NT kernel will also raise it when an application has done something wrong which it has detected: invalid arguments [checked build only?], overwriting the guard bytes at the end of GlobalAlloc()'d memory & the like.
[Top of Section] [Index]

11.2. What is Just In Time Debugging?

It is a feature of windows95/NT where a debugger can be attached to a process after an exception has occurred, and is very useful for debugging your applications. It is less useful when developing with more than one compiler/debugger combination, or when you end up starting to debug third party applications.

It is controlled by the [AeDebug] section of win.ini in Win95, and in the NT registry section
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AeDebug

Auto: REG_SZ "0" or "1" : Set to "1" if you want your debugger to run automatically

Debugger: REG_SZ: the command line to start the debugger, which is used as a printf argument and should contain two %ld strings to be replaced by the process ID and exception number.
E.g. "Windbg -p %ld -e %ld"
[Top of Section] [Index]

11.3. What do all those exceptions mean?

See the separate list of exceptions
[Top of Section] [Index]

11.4. What is SEH and how do I use it?

Structured Exception handling is a formalized, cross language method of raising and processing exceptions. It can be used to make your application more robust or crash more gracefully. At its simplest, an SEH handler around an application can be used to ensure that no matter how the C/C++ program exits or crashes, the program has left external files and devices in a stable state.

At its most advanced, it can be used to implement innovative coding techniques such as sparse arrays and expandable shared memory heaps. Jeffery Richter's book covers the topic in significant detail. Note that most programs don't attempt such advanced SHE tricks.

SEH is very similar to C++ exception handling, and the two can both be used. The C++ handler catches exceptions raised by C++ libraries, COM interface wrappers and the like, while the SEH handler will catch the really low level stuff like pointer faults, illegal instructions and other symptoms of a slightly substandard program. Logging and cleanup routines can still be called, but you need to make no assumptions about the state of the program and attempt as little as possible. The worst case to deal with is usually something like an SEH exception in the destructor of something important like the application object.

__try {

	try {
		//app stuff here
		}
	catch (...)
		{
		//C++ exception handler
		}
	}
__except (ExFilter(GetExceptionCode(),GetExceptionInformation()))
	{ /* Ö */ }

[Top of Section] [Index]

11.5. Why does a Win32 API call keep failing?

If a Win32 function call fails, then GetLastError() will return a DWORD value describing the error. A call to FormatMessage() can often turn this into an error string, from which the cause of the error may be determined. The header file "Winerror.h" contains the definitions of the standard errors.

Some common reasons for a function call failing are

  • The function is not implemented on that version of Windows ( GetLastError()==120); ERROR_CALL_NOT_IMPLEMENTED
  • You passed in arguments which failed the parameter checks. A common mistake here is failing to fill in the dwSize or cbSize member of a data structure with the full size of the structure as returned by sizeof()
  • The object you are working on is in the wrong state. I.e the socket is unbound, or a handle refers to an object which is now closed.
  • You are trying to do something which is simply not possible. This may be due to limitations of the systems you are using, or mistaken assumptions on your part.
When starting off, you may get frustrated at the number of things which donít seem to work, and blame the tools and platform. With time, you will learn more about the API, and you realise that is many your assumptions are broken and not the platforms. Once you reach this state, then you can spend ages looking at a broken routine before discovering that it really is the API Call which is not working as specified. A check through the MSDN disks and on-line knowledge base is often invaluable at this point.
[Top of Section] [Index]

11.6. How do I print a message to the debugger?

With the OutputDebugString() function. Compilers and class libraries usually include macros to perform printf style formatting and to omit the output when a release build is generated.
[Top of Section] [Index]

11.7. How do I break to the debugger?

Use the DebugBreak() function, which will break to the debugger somewhere in the OS. A couple of steps over assembly language statements and you'll return to your code.

The statement: _asm { int 0x03 } does the same thing on x86 systems, and lets you skip having to step out of the OS.
[Top of Section] [Index]

11.8. NT Crashes with a Blue Screen of Death when my program runs!

This should not happen -and when it does, it is either the result of hardware problems on that system, or due to a bug in the OS or third party drivers.

Microsoft maintain a list of errors to help you understand what is going on. However, it does not always help you to solve the problem.

Try to produce a small piece of code which replicates the problem: the easier it is to replicate, the easier it is tracked down. If you can track the BSOD down to a particular driver then get in touch with the support group of that organisation. Yes, even Microsoft support, if it is clearly part of the OS. Also check the companies' on line support pages to see if the problem is already known.
[Top of Section] [Index]

11.9. My STL code does not compile/work!

This is more common than you'd think with Visual C++, and it stems from the fact that the STL library on the product was one licensed from a third party a few years and then seemingly broken in the pursuit of some incomprehensible goal. The early releases of this library (in VCC4.x) were dire: Strings leaked, dequeue crashed on adding the ninth element, you name it, it broke. Today it is somewhat more stable, but not as good as commercial products from third part vendors, including that available from the original supplier of the VCC implementation.

Patches for the VCC distribution can be obtained from the supplier DinkumWare
[Top of Section] [Index]

12. Shipping -or 'help, my customers say my program doesn't work'

Shipping: the process of delivering working code to customers. Ideally this should take place after "debugging", although there is almost invariably a bit of overlap. A decent QA process, in which the purpose of a test is defined as An input sequence designed to show the presence of bugs is what is often omitted. It is a lot easier to test when the overall goal, and hence tests, are designed to show the absence of bugs -but that just hides problems till the product gets into the hands of end users.

12.1 What do I need to do before I ship my program?
12.2 How do I determine which DLLs are needed?
12.3 Help, my release build won't work, although the debug build does!
12.4 Help, my program's too slow!
12.5 Can I stop my application being pirated?

12.1. What do I need to do before I ship my program?

The exact process for shipping code is very variable, but the steps for actually producing a release distribution of your software should include the following
  1. Get a release build of your code working to the current customer expectations.
  2. Determine all dependencies of the code : OS versions, DLLs, OCXs, system extensions, and ensure that you have legitimately redistributable versions of all the components which you need to include with your app.
  3. Build an installation system -using MS, third party or your own installation apps.
  4. Verify the installation on multiple configurations, such as clean builds of the supported operating systems.
  5. Verify the uninstallation also works reliably. On a clean build it should delete shared DLLs no longer in use -and on a dirty platform it should leave them alone.
The first point of contact an end user has with your product is the installation application: it is critical to invest effort early on making installation seamless for end users and corporate IT departments. Start working on it long before the product is ready to ship.
[Top of Section] [Index]

12.2. How do I determine which DLLs are needed?

This can be quite a hard process. It is inevitable that you will need the C run time and C++ class libraries for your app -or the Visual Basic or Delphi equivalents. You must not rely on the destination platforms having any -or up to date- copies. You will also need any application specific libraries, such as a database run time, common controls, Borland custom controls or OCXs used.

The "Quick View" operation to view an EXE, DLL, or OCX will give you a list of which DLLs a program implicitly imports -and viewing these imports will let you build up a total list of hard coded imports. What can not be determined is which dynamically loaded libraries are required -such as libraries COM objects. A bit of intuition and testing is important here. Noting what libraries the debugger lists as being loaded is the best starting point.

If you have the platform SDK installed, then you can use the excellent "DEPENDS" utility to offload the hard work of recursively determining which libraries an EXE or DLL depends upon. It also lists the exact imports and DLL version information, which is very convenient.

Important: It is the DLL requirements of the release build which you must determine, not the debug version. You are not allowed to redistribute the debug versions of the MFC library, even if you wanted to.

Another potential gotcha is the fact that there can be different DLL versions for different platforms: CTL3D32.DLL is a case in point. Application distributions must include both versions of such libraries and install the appropriate one. The VB5 setup wizard gets this wrong

One trouble spot is that some libraries can not be distributed singly -wininet.dll for example -you have to provvvvide something like a full redistribution of Internet Explorer to get these to work on 'legacy' platforms. This bloats your redistribution by tens of megabytes, and forces a system reboot during the install process, neither of which endear you to end users.

Tip: Any DLL with "OleSelfRegister" in the version fields needs to be loaded and registered via an invocation of its DllRegisterServer() function -REGSVR32.EXE will do this, as will many installation packages.
[Top of Section] [Index]

12.3. Help, my release build won't work, although the debug build does!

This can be a common problem, with multiple causes.
  • Debug builds automatically zero memory when allocated -this catches some variable initialisation problems (null pointers) but hides others.
    Test: change the memory allocator, or use Bounds Checker, Purify or an equivalent tool.
    Fix: explicitly initialise all variables
  • Debug builds sometimes contain extra padding between variables -or extra variables, which hide overruns.
    Test: use Bounds Checker, Purify or an equivalent tool.
    Fix: donít overrun arrays, especially string arrays. For strings, strncpy() beats strcpy() for safe copies, but note that the length bound version does not zero the last character on an overflow.
  • Functions in ASSERT() statements aren't being called.
    Test: redefine ASSERT() as an empty macro in the debug build and see if it breaks.
    Fix: Take all functions with side effects out of assert statements -use the assertions to verify the results afterwards. Or use the VERIFY() macro, if present.
  • The program contains other side effecting code only included with _DEBUG is defined
    Test: define _DEBUG in the release build and see if it works -or undefine it in the debug build.
    Fix: Take all functions with side effects out of assert statements -use the assertions to verify the results afterwards. Or use the VERIFY() macro, if present.
  • The optimising code generator is generating broken code.
    A problem which can occasionally arise, especially with an x.0 version of a compiler.
    Test:turn off all optimisations in the release build and see if it goes away. If it does, then try different switches on different modules until the problem can be located.
    Fix: It's often possible by breaking up complex statements, else disable that optimisation for the offending module.
The best way to avoid these problems is to regularly produce and test the release build throughout the development process. The release build should exhibit the exact same defects as the debug build, just at a faster rate.
[Top of Section] [Index]

12.4. Help, my program's too slow!

Code optimisation tricks are now covered in more detail in a very long article

If you discover you have performance when your program is about to ship, then you are in trouble, as it may be too late to fix in revision 1.0. An action plan such as the following is probably appropriate.

  • Identify potential locations for optimisation, and estimate potential savings and effort required.
  • Get management/customers to agree to the expected slippage -or to accept the current version as an initial release, with the performance tuned version as a x.1 upgrade.
Ideally you should have enough of an idea of performance and load requirements early on in the development process that you can begin to stress test core components before the product is complete. "Inadequate Performance" should be just another risk to be managed.

Ways to make windows programs faster:-

Traditional optimisation techniques
A good source here is the book "Inner Loops" which provides details on optimising assembler and C code for the Intel x86 processor family. A useful, but it really needs a counterpart covering the fast and slow bits of Win32.
Application code size and layout optimisation
Tuning your application for size may not seem to have immediate speed benefits, but an overall shrink and tuning of the app's memory requirements can reduce the working set of the app and so minimise the chance that needed routines are off on disk. WSTUNE in the Win32 SDK is useful here.
Optimise for cache access
A Pentium system will have 8-16 KB of level 1 code cache, and an equivalent amount of data cache. (Pentium classic: 8 KB, Pentium MMX: 16 KB), plus -probably- 256 KB of level 2 cache. These caches speed up memory access -provided your code makes effective use of them by referring to sequential and nearby memory locations. So walk through arrays in the order they are stored in memory, and lay out classes and data structures so that member items often used together are adjacent. Another good trick is to prefetch 32-byte cache lines by fetching a DWORD of data from each line in advance of looking at the contents.
Align data structures
The performance penalty of a misaligned data access is frightening. Either implicitly align data with compiler pack options, or add padding bytes to explicitly align WORDS, DWORDS and QWORDS on the appropriate boundaries.
Minimise mispredicted branches
Pentium class processors use branch prediction to guess the likely path of code: remembering the taken/not taken status of a number of branches, and having rules about the likely direction of other branches -usually "backwards branches taken, forward branches not taken". A mispredicted branch on a Pentium requires the instruction pipeline to be flushed and restarted, wasting a few cycles. On a Pentium Pro/PII or other CPU which "speculatively" executes instructions, the results of all speculated instructions have to be thrown away if a branch is mispredicted: an even more expensive process.
Branch misprediction can be minimised by reducing the number of tests in your code and having easily guessed outcomes: backward branches (for, do {} while) should normally be taken, and forward branches (if()) not. So put the most likely outcome of a test in the "then" clause and not the "else" clause. Code written for the P6/PII only can also use the CMOV instruction to conditionally move data without having any branches at all, though you need a modern assembler to generate this opcode.
Multithread for improved throughput
This is the only effective way to benefit from the extra processors on a multi-CPU system. On a single CPU system, the threads can still provide a throughput boost enable productive work to be done while some of the threads are busy.
Critical Sections are the lowest penalty synchronization mechanism (about 17 cycles on '9x if a thread is not blocked) and the InterlockedXXX functions perfect for manipulating shared data when a critical section is not required. Aligned WORD, DWORD and QWORD reads and writes are always atomic, although on a Pentium Pro/II they can take place in a different order than that the program expects. NB: when data is written to memory in one CPU, the cache line containing the data will be invalidated in any other CPUs in the system. Separate shared readable and shared writeable data into different 32 byte cache lines to minimize the effect of this.
Make the app more responsive
For an interactive application, responsiveness can be more important than actual performance. Splitting the user interaction thread from the worker threads can create a very responsive application, which is better to use than a slow single threaded application. A underused technique here is to "speculate": if you have spare CPU time why not do some background work on the likelihood it will be needed later. [don't try this on laptops, please]
Use the overlapped/asynchronous IO operations in NT
These can be used to stop threads blocking when slow disk or network operations are taking place. Win95 only implements asynchronous IO on sockets and serial ports, so this is mostly an NT performance trick.
Use MMX
The MMX extensions to x86 enable your program to perform high performance integer SIMD operations, at the expense of disabling the floating point unit. As the installed base of MMX CPUs increases (especially in the home market), the likelihood of customers benefiting from an optional MMX code module is increasing.
Offload work to the OS
The platform and extensions such as DirectX can often deliver high performance to your application, provided they are used to the full. Spending some time to discover the most effective approach -as opposed to the most obvious- is worthwhile. For example, using memory mapped files can reduce application startup times as there is no need to read in a file byte by byte: the OS's pager fetches blocks on demand instead.
Turning a single threaded program into a multithreaded application is not trivial -and you do need to stress test it on a 2-way, 4-way or greater system to ensure that it really is immune from deadlocks and race conditions. Such bugs can be exceedingly troublesome to track down. They are therefore not a last minute solution to any performance problem. Program Profiling, algorithm tuning, and optimization for three memory levels are more appropriate at this point in development.

Corollary: it is often a waste of time getting a high performance algorithm to work early on in the development process, as the tuned algorithm may be exceedingly inflexible, and may not even turn out be the bottleneck. It also creates another major problem: if you replace a fast but flaky beta with a slow but reliable build, customers often complain about speed. Keeping speed down until all the bugs have been ironed out avoids you having to worry so much about the negative performance impact of a bug fix.
[Top of Section] [Index]

12.5. Can I stop my application being pirated?

Not in software, no. You can make it very hard for anyone trying to crack whatever protection scheme you use, in the hope this will discourage all but the most dedicated. Serial number checking schemes, expiry coded apps, 'dongle' based designs -all are ultimately defeatable. One possible exception: smart card hardware which actually executes an algorithm internally - an algorithm whose correct functioning is actually vital to the operation of the app (eg. it contains an encryption routine, or some other important computation function). If you were sure of a permanent Internet connection and had a 100% uptime server then maybe you could offload that computation to the server (and have many dial up and notebook users abandon your product). But even with such tricks, someone can still reimplement your algorithm in software and patch it into the app. What does not work is hard coding software to a PC via the hard disk number, the network address or a PIII serial number; MAC addresses can change easily, and even CPUs get upgraded -no hardware change should break apps.

Link: a site covering the theory and practise of cracking apps
[Top of Section] [Index]

13. Miscellany

This section contains miscellaneous items

13.1 Internet Resources
13.2 Miscellaneous Terminology
13.3 Credits
13.4 Copyright

13.1. Internet Resources

This is a list of some web sites which are a good source of Win32 programming information. Maintaning such a list is a time consuming exercise in its own right, which is why it is so brief. Some of the places referenced are good jumping off points to other sites.
  • Index of Windows FAQs
  • Anyone programming MFC should read and understand Scot Wingo's definitive MFC FAQ
  • The Microsoft software developer pages and the hardware equivalents are worth regular visits.
  • Intel have developer pages which can be a source of low level information -ideal for extracting maximum performance from systems.
  • #C++ A good index of lots of c++ resources
  • Programmer magazines: Dr Dobbs Journal, Microsoft Systems Journal and Windows Developer Journal
  • NT/Sys Internals A great site for reverse engineering NT and '9x, plus the infamous "Blue Screen" screen saver.
  • The MFC code guru site. This is a very professional site full of MFC code snippets, and with win32 and ATL stuff too. Visit it before you reinvent an MFC wheel.
  • Finally Robert Mashlan's web site is a good source of URLs, but doesnít seem to have been updated recently, so its value is rapidly diminishing.

[Top of Section] [Index]

13.2. Miscellaneous Terminology

Cairo, NT5 Windows 2000 Professional

Chicago, Win95 Windows 95

Checked Build A debug build of a an OS which verifies all arguments and contains lots of assertions to verify its internal state. Invaluable for device driver and some program development.

Free Build The faster but less forgiving OS version shipped to paying customers.

Gold A development term -the 'Gold build' is the one sent to the manufacturers and customers. Often used to describe OS versions- Win95 gold versus Win95 OSR2 (that's OEM Service Release 2)

Handle In Win32, a HANDLE is an opaque number which is usually used to look up a table within part of the OS, and so index OS side data structures. GDI handles are things like pens, brushes, device contexts and bitmaps, USER handles are windows and controls, while Kernel Handles can refer to lots of low level handles. The NT handle model is somewhat more coherent than the other handles -these are the only handles that you can ppppass in to WaitForSingleObject() and related functions. Usually only User handles (window handles) can be passed around to other applications without any effort.

Kernel Mode The state of the CPU in which software is 'privileged', can read or write any valid memory locations and do things otherwise forbidden, such as talk to hardware. A bug here leads to a Blue Screen. Commonly called 'Ring 0'.

Memphis, Win98 Windows 98

NT, WinNT Windows NT, and nothing to do with Northern Telecom

Thunk Small piece of code to indirectly link two otherwise incompatible programs. Used to link 16 and 32 bit applications, and to bind a windows callback or message proc to a non static C++ member function.

User Mode The underprivileged CPU state, the one applications execute in. Application crashes here often leave the system standing, especially on NT. Also known as Ring 3 from the x86 privilege model.

VxD Virtual Device Driver. Very powerful (but low level) device drivers, the foundation of Windows 9x.

Win16 The generic term for the 16 bit windows API used in Windows versions 1.0 to 3.1 and still supported in later versions.

Win2K/Windows 2000 NT5, rebadged by marketing weasels.

Win32 The generic term for the 32 bit windows API

Win32s An early implementation Win32 on top of Windows 3.1. A miracle of technology, hated by all who had to program it as a half way house between Win16 and Win32

Win9x A term to mean either Windows 95 or 98.

Windoze This is rather derogatory term used to describe Microsoft Windows. Use of this term in questions offends many professional programmers, and doesn't garner respect. Only if you are a really good Windows guru canyou get away with it, and even then it has be semi affectionate.
[Top of Section] [Index]

13.3. Credits

Credit for answering many of these questions must go to the following gurus: Their email addresses aren't listed here to stop them being sent unsolicited questions. Chris Marriott, Mike Geary, Bernie Greenberg, John Grant, Robert Mashlan, Matt Arnold, Niels Jacobsen, Raymond Chen, Paul Dixon, Michael Schubart +many others.
[Top of Section] [Index]

13.4. Copyright

This FAQ is copyright 1996-1999 Steve Loughran. You can keep and print out copies for your own use, provided this copyright notice is retained, and you can also store it for the benefit of your colleagues/team members/fellow students/whatever on your local intranet web server. You may not redistribute it for profit, in printed or on line form. Any included code samples in the document are yours to reuse as you wish, without any copyright restrictions at all.

If you keep an on line copy of ths FAQ, please retain a pointer to the original document at http://www.iseran.com/Win32/FAQ/. This is the only way to stop getting email complaints about the document being wildly out of date, when it's really that the reader just needs to see a recent copy.

The author can be contacted at faq-contact99 at iseran.com. Corrections, additions and constructive criticism are welcomed. Programming questions are -sadly- not and are likely to be ignored. I would like to help but I have too many outstanding tasks from my paid work to act as an unpaid consultant to the rest of the world. Please read and understand the FAQ then post to the newsgroups instead.

Disclaimer This document contains code samples and "tips" intended to help you write better Windows programs. Use all of them at their own risk. It is not my problem if you use the information in here in a flight control system on a passenger jet which then falls out of the sky. OK?

Finally, I hope you found this useful. Enjoy your programming and don't let impossible deadlines or broken applications get you down -they are part of every Win32 programmer's life!

-Steve.
[Top of Section] [Index]