Copyright Notice
Copyright Notice for Visual Workbench Help

Information in this document is subject to change without notice. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without express written permission of Microsoft Corporation.

© 1993 Microsoft Corporation. All rights reserved.

Microsoft is a registered trademark and Windows and Windows NT are trademarks of Microsoft Corporation.


Book Cover


  General Information

If you want to:	See:
Install Visual C++	Getting Started
Edit and debug programs	Visual Workbench User's Guide
Use command-line utilities	Build Tools User's Guide
Look up an error message	ERRORS.HLP
Get answers to commonly asked questions	Getting Started
Configure and optimize your system	Visual Workbench User's Guide
Learn about using Help	Visual Workbench User's Guide
Learn about using Books Online	Run Books Online and click the Help button


  C++ Programming

If you want to:	See:
Learn about MFC programming	Class Library User's Guide
Use the Microsoft Class Library (MFC)	Class Library Reference
Understand C++ syntax and usage	C++ Language Reference
Compile code written for other C++ compilers	C++ Language Reference


  C Programming

If you want to:	See:
Understand C syntax and usage	C Language Reference
Use the C run-time library	C Run-Time Library Reference
Optimize programs	Programming Techniques
Compare Microsoft C with ANSI C	C Language Reference
Write portable programs	Programming Techniques


  Windows Programming

If you want to:	See:
Build an application for Windows	Visual Workbench User's Guide
Create an MFC application for Windows with AppWizard and ClassWizard	Class Library User's Guide, App Studio User's Guide
Port a program to 32 bits	Programming Techniques
Target Win32s	Programming Techniques
Use App Studio resource tools	App Studio User's Guide
Find reference information on the Windows API	Windows NT SDK Programmer's References, Vols. 1-5
Get Help on Windows tools	Help files in the HELP subdirectory


  Special Topics

If you want to:	See:
Use precompiled headers	Programming Techniques
Profile your program	32-Bit Profiler User's Guide
Decode your program's Windows messages	Spy++ User's Guide
Create your own WinHelp files	Help Compiler User's Guide


Book Location
Presenting Visual C++ for Windows NT


Customer Centered Product Design
  Customer-Centered Product Design

A conversation with Paul Mitchell

We started working on Visual C++™ for Windows NT™ at the same time we started working on Visual C++ for Windows™. The real focus of both of those products was to revamp our entire organization — instead of just doing things that we thought were really cool from an academic perspective, we focused on things that customers really wanted and that would make customer's jobs easier.

We got beat up over time for having products that may have produced really tight code and done a great job, but were difficult to use — they were non-intuitive and had ugly tools wrapping a great compiler engine. So with all of the VC++ products, especially with the Windows NT version, we spent a lot of time listening to customers, trying to get rid of the baggage of past attitudes and find out what was really important to the customer.

We seek out our customers in lots of different ways. We've done a number of focus groups where we bring a lot of customers together and bounce ideas off them. We've had conferences with our ISV's (Independent Software Vendors). We've done a lot of research — we've done a major developer satisfaction study, and we've also done follow-up surveys as part of our C7 registered base mailing program. We visit one to three user groups per month, where we have very open dialogue with the developers who are there. We feel them out on a number of issues: what features are important to them, what we've done well, and what we haven't done so well. Getting all that customer feedback makes it really easy to design the product.

Ever since Visual C++ for Windows was released, customers have been asking "when can I get VC++ for Windows NT?" Well, now it's here.


  The New Paradigm for Windows Development

A conversation with Eric Lang and Andy Padawer

Eric: If I had to describe this product...what would it be? Well, just yesterday I read a review of Visual C++ for Windows where the author was describing the competition among C++ compiler vendors as a heavyweight boxing match. He wound it up by saying that Visual C++ is the most productive Windows-based C/C++ platform available, and that it is the new heavyweight champ. That made me feel really good because I know that we made Visual C++ even better for Windows NT.

Andy: I think the most compelling thing about this product is simply that it's 32 bits.

You get all the simplicity of programming and performance that go with a professional 32-bit environment. We also kept it simple for people coming from the Windows 3.1 world. It's a lot easier than you'd think to port your 16-bit Windows apps to Win32 — in fact, for MFC apps, it's downright trivial. The level of integration in our tools is impressive. The way the IDE, App Studio, and the Wizards work together really makes it easier to develop a Windows app. And of course, our code quality is the best in the business. This is the compiler that builds the Windows NT operating system, so it has to be rock-solid and efficient.

Eric: We've done a few new things to the tools for this product. Naturally we added multithread and structured exception support to the IDE debugger. A lot of people said they wanted a memory window, so we added that, too. We added multi-file search to the IDE — now you don't have to switch back to a DOS box anymore to grep for strings in your source code. We also extended the Tools menu, so any tool you add can pipe its output directly into an IDE output window.

Each tool gets its own window for output. You can switch between them in the IDE. Also, we made the output windows able to parse for the standard file tag syntax, so if a tool writes that syntax to the output window, you can put your mouse over that line in the output window, double-click, and voila — it takes you right to that line in your source code.

Andy: We also made some big improvements to the Source Profiler. The command-line interface is easier to use, and we've integrated the profiler into the IDE — just a couple of mouse clicks and you're profiling. The accuracy of the profiler has also been improved, and it's less invasive with function call timing because it doesn't use interrupts. If you've avoided the profiler before because you thought it was hard to use, there are no more excuses.

Eric: There are a couple of new tools in this product that we know people will love: Spy++ and Books Online.

This is not just a makeover of the old Spy — we started from scratch and wrote a new one. It's really hot! Not only does it show all the message stream information that the old Spy did, it now gives you full information about individual window details, process and thread details, and complete tree views of all processes, threads and windows currently active. There's never been an easier way to get system information. Books online makes your documentation more accessible than it's ever been. Imagine packing 40 pounds of books into a single featherweight CD with nothing missing. That's what we've done, and it gets even better. You can now use the full text search and contents browser to find exactly the information you're looking for.

Andy: Bottom line, I'd have to say this is the development environment you've always wanted.

Note  For information on installing Visual C++ for Windows NT, see Chapter 1 of Getting Started.


  Doing It All in One Environment

A conversation with Bruce Johnson

What's new in the Visual Workbench for this release? Well, the Find In Files feature is my favorite new feature. Some people would call this a multi-file grep facility, I guess.

It searches for strings across a number of files in the system. It's very handy to quickly find things that aren't found by the browser or aren't loaded in my browser system.

We also extended the output window to collect and save the output from different tools, including user tools, in their own virtual window. So you don't have to worry about losing output as you move from tool to tool. If you do a build and get errors, and then say, "Oh, I need to do a Find In Files to see why this error occurred," you can do that and it won't overwrite the output of the build. You can go back to the build output window and resume going through your errors. It's just another way we help smooth the way through the whole edit, compile, debug cycle.

Dependency generation is another thing we improved for this release. As you work on new files and, say, add a header file to your project, we have a scan that allows you to rebuild the dependency list for the makefile. I know lots of people have homegrown tools for this, but ours is built into the IDE and comes for free. Now the dependency generation is integrated with the compiler options, so if you specify the include directory in the compiler options, it searches that directory in addition to the directories specified in the Directories dialog.

Visual C++ supports the notion of what we call internal projects — that is, a project managed by the IDE.

It's a great tool for coordination of a large project. You have essentially one reference point to deal with: the .mak file, which you open from the Project dialog. I think it's even better at managing a lot of small projects. The IDE remembers what files are associated with the project and how to do the build. It's very easy for me to go back to a project that I built months ago, and just load it up and run it.

Another cool thing is that your project .MAK files can be used by NMAKE, so you can use the command-line tools if you need to. Of course, in reverse, we handle external projects, so we can load up makefiles that have previously been developed. This is a big customer requirement. If you want to use Visual C++ on an existing project and you make the decision that you need to use your makefile as is, we give you that capability. The other possibility is that you don't need a project at all — all you need is one source file. It's what we call a project-less build. Just from one source file you can create a quick test, build the .EXE, run and debug it — great for those small test programs.

You can also now load an .EXE file at the command prompt, with the arguments. This allows you to specify a long list of arguments easily, and you won't have to re-type the arguments into the Debug dialog as they change.

The whole point of the environment is to crack your program for you — to cut it open, so you can look inside your program and see how it's evolving. Our job is to help you do this as simply and as quickly as possible.

The Visual Workbench team uses our own environment to build and debug our environment, so my own work is devoted to building tools that help me do my job. Every time that I improve a situation for a customer, I improve my own situation — I'm a customer myself.

Note  For more information on Visual Workbench, see the Visual Workbench User's Guide.


  Targeting 16-Bit and 32-Bit Platforms with Win32s

A conversation with Jim Sather

The Win32s™ extension is basically a subset of Windows NT. It runs on top of Windows and gives the user nearly all the benefits of Windows NT on the 16-bit Windows platform.

For a developer, Win32s presents a huge opportunity to market to all those existing Windows users. At first, the NT market's going to be small, so what developers can do now is develop their app as a Win32s app and market to this huge Windows base (over 16 million people!), but still protect their investment for the future. There are a few limitations in that you don't have threads on Win32s and some of the APIs aren't supported but will return failure. This allows developers to limit the amount of #ifdef's in their code by calling APIs, checking for failures, and taking a different code path. For instance, if a CreateThread fails, the code can take an alternate route and do things synchronously. Any application you create can be written in such ways to run optimally on either operating system. By and large, most code won't need any special modifications to run on either Windows NT or Win32s.

How do you create great applications for Windows NT or Win32s? You use the Visual C++ IDE — it's got the same look and feel as Visual C++ for Windows. If you did things right and followed the rules of what Win32s supports, it just works. After you build your app, you can debug it there on Windows NT. Now you're ready to say, OK, does it run on Win32s? You can try to run it and if it fails, you can use our Win32s debugger to figure out what are the minor details or discrepancies that are preventing this thing from running on Win32s when it runs on Windows NT. Or, you can just go straight to the Win32s debugger and start there, not even worrying about whether it runs on Windows NT first or not.

Visual C++ for Windows NT makes it easy as possible to verify that your Windows NT app will also run on Win32s. Going back to the thread example, if you did a CreateThread in a Windows NT application and you didn't check return codes right or something like that, it won't run on Win32s because the thread creation never succeeded. That's where the Win32s debugger comes in handy. You can actually take it to Win32s and see what the problem is and why it's different here than on Windows NT. What's really great about the Win32s debugger is that it's just jazzed up CodeView. The command set is the familiar CodeView command set, with the addition of structured exception handling; all the menus and dialogs and window behavior are the same. It's simple to use, yet very powerful.

This product really allows people a lot of freedom for mixing and matching platforms. Here in my office, I have one machine with Windows NT running on it, but it's my Win32s machine for developing CodeView as well. I don't necessarily like to have to boot into Windows NT to build my application and then reboot back into Win32s to debug it — that's time consuming. It's nice to be able to use the command-line tools from the DOS box in Win32s.

Win32s also has special support for universal thunking, which allows you to call 16-bit code from your 32-bit application. This is important if you've already put an investment into writing DLL's for 16-bit Windows and you don't want to have to port them. Likewise, universal thunking is absolutely necessary if you want to use a 16-bit device driver.

The transition to Win32s is faster because you can port your code in pieces. How does it work? Basically, you get thunked from 32-bit code to 16-bit code. You register your application's instance handle, the name of the 16-bit DLL you want to load, and its dispatch routine with the universal thunking layer. You then get back a 32-bit function pointer that you can call. Then you write a function dispatcher, and you're done! All the thunking from 32-bit to 16-bit code is done for you.

Note  For more information on the Win32s extension, see Chapter 9 of Programming Techniques.


  Automating Labor-Intensive Programming Tasks with Wizards

A conversation with Greg Demichillie

OK, here's the bottom line: AppWizard and ClassWizard help you get your work done by removing a lot of the grunge work that goes along with Windows programming. We're all familiar with the sort of hoops you have to jump through to get a Windows app up and running and the kinds of things programmers do day in and day out, so we created the Wizards to help you get through that stuff and get to the job of writing the code that makes your app special.

Basically, AppWizard creates a framework for your app — it takes advantage of the MFC framework and just derives a couple key classes from it, using C++. The total volume of code it emits is pretty small and most of that is taken up with comments. So when you look at an AppWizard-generated app, you see that not only is it not a lot of code but it has placeholders there giving you hints — here's where you want to put your drawing code, here's where you want to put your document initialization code, that sort of thing.

The other side of the coin is ClassWizard. Where AppWizard saves you a lot of work up front, ClassWizard automates the kinds of things you do over and over again. For example, one very common programming task is to create a menu command and write the code to handle it. ClassWizard automates that for you. You just select the menu command from the list and ClassWizard creates the function definition and prototype. It uses MFC to unpack wParam and lParam so you automatically have type safe parameters that are portable between Win16 and Win32. With two clicks of the button you can create the function and jump to the code and edit it. Plus, it fits the mental model of how we, as programmers, want to think. We want to think that I write a menu command and when the user selects it my code gets run. We don't want to think: "a WM_COMMAND message got sent to a WndProc and the wParam was the ID of my menu command." You don't have to worry about what we call the grunge of Windows programming.

Here's an example — the other day I was giving a demo of the product. We were writing a sample app and it was amazing that every time I used ClassWizard, everything worked fine. Every time I actually had to write code myself I introduced some kind of typographical error, syntax error, whatever, and it failed to compile. Because ClassWizard never makes typographical mistakes and never generates code with syntax errors, I never have to get halfway through a compile and discover that I screwed up the header somehow. For me, that's a huge time savings.

The big win, I think, between AppWizard and ClassWizard on Windows NT is that they provide you with the same environment as Windows 3.1. And you can edit the code without worrying about Win16 and Win32 portability issues. The same coding techniques and codes you used under Win16 work under Win32. MFC protects you from having to worry about those portability issues.

As programmers, we tend to fall into these traps of doing the same thing the same old way. There was a lot of promise when object-oriented programming first came out, about how this was going to make your life easier and you'd never have to worry about these details again. I think that, taken together, MFC, AppWizard, and ClassWizard are a real step toward delivering these promises.

I think once you get used to the whole notion of having Wizards around, you quickly find yourself wondering "how did I ever do this sort of work manually?" and you think about the time savings you get. If we've done our job right, the Wizards just become a natural extension to the way you program.

Note  For more information on Wizards, see Chapter 9 of the App Studio User's Guide and Chapters 2, 6, and 7 of the Class Library User's Guide.


  Providing Your Application Framework

A conversation with Dean McCrory

MFC leads you down a path of least resistance in terms of the Windows API. There are a lot of things that you can do wrong in a Windows program. One thing that helps is if you have a framework sitting there that already implements a lot of those issues for you and only calls upon you to do the things that are application-specific. It's as if you're a beginning programmer for Windows, but you've got a senior architect by your side who's helping you design your application. That senior architect is the MFC architecture — all you need to do is follow the guidelines.

The cool thing about this new version for Windows NT is that you write MFC applications the same way as Win16 applications. You don't have to think about being on a different operating system and that a lot of things have been extended to 32 bits. A good example of that is parameter packing. How parameters are packed for certain windows messages in NT has changed drastically. This is something that you constantly have to be worried about if you're writing a C program to the Windows SDK. But with MFC, you just write code like you do for Win16. Portability to other systems such as Win32™ is really important to us, so chances are your code will work with minimal changes under Win32.

Another cool thing in the Windows NT version is OLE support. If you use the document/view/doc template architecture in MFC, you don't have to deal with the hardest details of object linking and embedding — they're handled by the framework. That's going to become even more important on future systems. As we move to future Windows releases, people will move more to a document-based user interface where having multiple documents on a particular application just doesn't make any sense. Users edit documents, period. If you use the MFC document/view architecture, you can move into a document-based UI fairly painlessly, whereas if you've written code to the Windows API, you have all kinds of dependencies on old UI paradigms that you're going to have to rip out. We try to have MFC provide the sensible defaults.

But there's a lot of flexibility for overriding the existing framework behavior if you find that it isn't appropriate for your application. For example, for Windows NT we don't have any abstractions for threads. But that doesn't stop you from using threads in your application.

One of the guys in our group has put together an application which is really single document, multiple view — it has a Windows multiple document interface with multiple frame windows that exist inside of another frame window. But it's only really got a single document. All of those frame windows are fused onto one document. When you choose File New, you get a whole new set of these four frame windows. That was implemented with just a custom document template class. All the rest of the framework code for File New, File Open, Window New, etc. works fine in that scenario. So you only replace this one class to get a very different UI.

MFC makes it easier to write apps for Windows — like all the canned functionality that's provided in MFC, such as toolbars and status bars. These are things that you just plug in and they just work. You can create a toolbar with only about five lines of code, and it's handled automatically. If you resize the main window, the toolbar is automatically resized and moved as appropriate. I can see probably spending at least a week just writing a good toolbar class. Even then, it probably wouldn't have some of the same flexibility as our toolbar implementation because you designed it to fill a certain purpose.

This group is really here to make Windows-based programming easier, period. If we're not doing something to make Windows-based programming easier, we're not doing our jobs. In the end, that's what MFC is: the framework that makes it easier.

Note  For more information on the Microsoft Foundation Class Library, see the Class Library User's Guide and the Class Library Reference.


  Creating and Modifying Your User Interface

A conversation with Garth Hitchens

Basically, App Studio is the world's best resource editor for Windows. Not only does it edit your resources, but it lets you connect those resources to code through ClassWizard.

App Studio is where you construct all of your visual user interface components. It then helps you to connect these things to code by automatically generating identifiers for them, or letting you bring up ClassWizard and providing enough context so that ClassWizard can just go in and make it all happen automatically. In addition to being the central workplace, it really is the state of the art in each of those areas.

How is it state-of-the-art? In general, App Studio does a great job of presenting a unified user interface; keeping the user from having to munge around in the .RC file. Some other resource editors are very tweak-centered. To use them, you have to understand how things are organized at the lowest level and understand what WS_ABSALIGN means, as opposed to seeing an English description of what that style does. The dialog editor always gives you a view of exactly how your dialog will turn out, because you're working with real controls, not bitmaps of controls. There are enough layout tools for you to quickly and painlessly build your dialog. We support both the layout type tools and a grid; so whatever way you like to work, we work with you.

We used App Studio to write App Studio. All of the property sheets, dialogs, menus, accelerator tables, strings, icons, cursors, bitmaps in App Studio were designed with previous versions of App Studio. Of course, we had to use other tools to begin with, but we found that App Studio was the quickest way to get work done, so naturally we adopted it and used it. As we were developing App Studio, we found little problems in its user interface that we'd fix because we used it day in and day out as a development tool. It really helped with laying out all the property pages. Also, we frequently changed our menu structure and App Studio made it very easy to drag and drop the menus without having to break the connections of those menus to code. So, when we couldn't make up our mind about how a particular menu should be organized, it didn't really matter because we could easily change it at a moment's notice.

I'll tell you a few of my favorite features, OK?

The preview window in the bitmap editor is really helpful. You have 500 bitmaps and you're trying to find the one little cursor that allows you to resize a corner of a dialog control and the chance of figuring it out from the ID doesn't seem too high, so, being able to just have the preview window tagged up and hit the down arrow a few times until you find it is great. I also like the zoom features in the bitmap editors — it allows you to have two different panes, each of which you can zoom in and zoom out at any ratio you want. The menu editor has a neat feature that lets you specify prompt strings for menus.

But my absolute favorite feature in App Studio is multi-level undo/redo. When you're making all kinds of really tiny, detailed changes, like changing style bits, and you go into test mode and realize that you totally broke a dialog, it's nice to be able to back out five levels and say, OK, well, that didn't work, let's try something else.

This product makes it easy to transition your 16-bit apps to 32 bits. In other words, your 16-bit App Studio files will load seamlessly to the 32-bit world and you'll find using 32-bit App Studio to be very, very similar or identical to using 16-bit App Studio — except that you can build 32-bit apps! Also, the system feels like an integrated system. ClassWizard, MFC, AppWizard and App Studio all just feel solid and work with the integrated development environment, making it really easy to build great apps.

Note  For more information on App Studio, see the App Studio User's Guide.


  Compiling Your Code

A conversation with Philip Lucido

The big thing about our new compiler is that it's 32 bits, which allows you a lot of freedom simply because you don't have to worry any more about all that 16-bit stuff. No more 64K segments, no more near pointers or far pointers, or small, large, or huge model. Now there's a single model — flat — and everything is 32-bit pointers and 32-bit integers.

Your life becomes a lot easier. It also significantly speeds up compute-bound code. You may not see a huge difference in code that's just sitting around waiting for the user to click the mouse. But certainly we've seen, in the compiler itself, a significant increase in the speed of the code — maybe two or three times faster.

This is not just a simple rewrite of the 16-bit compiler. It has a common front end, so you can still use the same Microsoft extensions and syntax, but the optimizer and the code generator are completely rewritten with an eye towards speed of compilation, robustness, and making sure that we have the ability to do the sort of aggressive optimizations that Microsoft compilers are known for. Most of the optimizations that you used on the 16 bit compiler — /Oe, /Oc, /Og, /Ol — have all been subsumed within a single switch: /Og, for global optimizations. There are still some extra optimizations that we give you — for example, you can go for /Oy, Frame Pointer Omission, which saves you a little time on function entry by making it unnecessary to set up a standard EBP frame. That way, the prologue is shorter, and it also frees up an extra register. Really great optimization requires you to load everything that you can into registers and leave them there. The more registers that you have available, the better it is. That's why we have /Oy — it makes function entry and exit faster and it allows us to have an extra register.

What else have we done? Well, it's a 32-bit compiler running under Windows NT, which means we can exploit this robust operating system. A good example is the stack-checking mechanism. Under 16 bit, you'd throw /Ge while writing and debugging, so you'd check your stack constantly and determine when it overflowed. Then, when you were ready to release your program, you'd throw /Gs and turn off stack checking, taking it on faith that no user would hit some portion of your program that would recurse in the stack any deeper than you did on testing. This is crazy — any users worth their salt can find some bizarre mechanism to make your program blow up. Now, under Windows NT, stack checking is directly supported. Windows NT will actually detect a stack overflow at the operating system level as part of its memory-protection mechanism. So when your stack overflows, the operating system grows the stack automatically. This means /Gs is now the default on the compiler, and your programs will run much faster now that you don't have to worry about it.

The compiler isn't all new, new, new — you have to keep all of the important features that people have grown to know and love.

Everything that you saw in the original Visual C++ compiler is basically still here. We share a common front end. You still have the precompiled headers, which can make your builds much faster — that becomes even more important on Windows NT. We still have our strong inlining capabilities. And, of course, we're still ANSI compatible. We still have /Za for strict ANSI compatibility mode.

This may be our first retail release of a 32-bit compiler, but it's not some brand-new untested technology. This project has been used for daily builds of Windows NT for over a year now. The Windows NT group was doing a huge project under tight schedules, so they were an ideal test case for us. We want our external customers to know that this compiler has had millions and millions of lines of code pumped through it. It's been thrashed out — it's a well-tested, robust compiler.

Note  For more information about improving program performance, see Chapters 10 and 11 of Programming Techniques.


  Analyzing Program Structure with the Class Browser

A conversation with Rico Mariani

You want to know what the Browser can do for you? Okay, I'll give you an example of what I was doing yesterday. Here I am, looking at this function, and I don't quite understand it — I wasn't sure that this structure was being used correctly. So I just put my cursor on this global variable, and I hit F11, and there was the definition of that variable. So now I know the type. Then I moved the cursor over to the type and hit F11 again and boom! There I was at the structure definition, so I can look at the members and so forth.

As it turned out, there was a problem with the usage. Having looked at the members, I saw that it wasn't being done quite right (there was a comment there that helped me), so I used the Pop Context feature, and there I was back at my initial global variable reference, and I made the fix there to use the field correctly. Then I hit Shift+F11 on the global variable and I visited all of the references to that variable to make sure that the same construction didn't appear anywhere else.

So it was all pretty simple — I figured out how the variable was supposed to be used and then fixed it. And I have no idea which files I visited. I suppose I could go and look at the logs to see where I checked in changes, but other than that, I don't know — I just fixed it. Which is the way it ought to be.

You can also use the browser to find a particular member name, — you just type it in the Name field and it shows you all the possible overloads of that name. Or maybe you just want to see all the places where that name was defined, which is an end unto itself, right? You can see all the places where it's defined just by typing the member name in that box.

You can also use the Browser to query graphs. There are four kinds of graphs available — class graphs, call graphs, function graphs, and caller's graphs — but of these, the one I use the most is probably the one that seems most esoteric — the caller's graph. Let me tell you how I used that yesterday to fix a bug.

Once again, I was in code that I'm not terribly familiar with. There was a problem with the searching code, and I had no idea where to even start. I knew I needed to make a change to one of the window procs, but I had no idea what the name of it was or what file it might be in. But I knew it had to do with searching, and I figured, well, ultimately, there's some code there that's calling some find function.

So I opened the Browser window and I picked the reverse call graph, and I said, "Show me all the functions called FIND*," figuring that there was bound to be some worker function down there called FIND-something, and I got a dialog box that let me pick the one I wanted. So I picked the one that looked like it was the most primitive — it was called FINDNEXT or something like that — and that became the base of the caller's graph. And then I said, "Do the query," and I expanded it fully.

So now I had all the places in the program by which you could reach that primitive worker function. And I knew that it had to do with finding, so I knew, ultimately, we were on the right track. And then I looked through that call graph until I found the thing that looked like a window proc. I double-clicked on it, and presto! I was in the function that I needed. So my input to this whole thing was just guessing, "Well, the function's probably called FIND-something," and the rest was just following the dots.

One last point — Visual C++ is the first Microsoft product that lets you browse while debugging. This is really handy because it lets you begin a browser-assisted autopsy from the site of a crash. If you run your application and get an access violation, the debugger catches this and you get placed at the offending line. If you don't understand the offending line, you can quickwatch the variable to see its value and use the Go To Definition/Reference to see how it's defined or used. The debugger and browser have good synergy.

Note  For more information on the browser, see Chapter 4 of the Visual Workbench User's Guide.


  Analyzing Your Application

A conversation with Byron Dazey and Koos Rommelse

Byron, Spy++: Spy++ carries on the tradition of Spy, but it adds a lot more. What does it do? Well, in a nutshell, it lets you spy on the messages going to a window. If you're trying to get something accomplished in your code and something strange is going on, you can use Spy++ to see exactly which messages are going to your application. But while the old Spy was cryptic and just gave you the raw values for the parameters, Spy++ gives you fully decoded parameters for each of the messages.

For instance, you could start Spy++ and select a window from the Window Tree, double-clicking on it to show its details. Then you can double-click on the Thread I.D. to show information about the thread that owns that window, or double-click on the Process I.D. to show information about the process that owns that thread. If you want, double-click on the Window Class to see its details. Finally, you can open what we call a "Message Stream View," which shows the messages going to that window. So in only a few seconds, with just a few mouse clicks, you've got a wealth of information about the window.

You can easily navigate around in Spy++ because we've added links everywhere. For instance, wherever a window handle appears in the system — whether it's in a Window Tree View or a detail view, or even in the message stream as a parameter of a message — you can double-click on it to get information on that window. You can even double-click on any message name to get full help on that message.

Developers need to get information about windows, processes, and threads, and they need to get it quickly. They need to be able to see it without having to write a lot of test code, and they need a way to flexibly filter out unnecessary information. Spy++ does just that — it presents all that information in a flexible, readable format.

Koos, Profiler: Essentially, the profiler helps you to speed up your program by showing you where you spend the most time and where you should concentrate your efforts. To use it, you first take a typical example input of your program and run some coarse profiles.

There are six built-in profiles: function timing, function counting, function coverage, function sampling, line coverage, and line counting. You might first do function counting to see which functions were accessed a lot and maybe combine that data with a function timing, which tells you which functions take up a whole lot of time. And clearly it's a trade-off. You look at the time the function took and how many times it was called and you can consider how you might reduce it, perhaps by inlining. If you're lucky, one function sticks out by taking up 20-25% of the time, and you can concentrate on that one. But that's not typical — I find that I usually get fairly flat profiles for my code.

The Visual C++ compiler team used the profiler quite a bit for this release. They profile as part of their build — they changed the driver so that it automatically calls the profiler whenever they start a build, so they can keep track of how things are going. This way, they can pinpoint what parts of the program take up a lot of time and look at the code generators for that part of the program to see if they can speed things up — by scheduling things differently, or whatever.

In the past, people haven't used the profiler a lot because they didn't really know how. They also didn't like the command line because you always had to specify switches. So I worked hard on making the command line as simple as possible. We also got rid of the profile command files, which were much too elaborate and very hard even for us to understand; so we now use command-line spaces instead. We're hoping that people will give the new version a try — we think you'll be surprised at how usable it is.

Note  For more information on these tools, see the Spy++ User's Guide and the 32-Bit Source Profiler User's Guide.


  Debugging Your Applications for Windows NT

A conversation with Mike Morearty

By design, the debugger for Visual C++ for Windows NT isn't too different from the original Visual C++ debugger — we just needed to add Windows NT support, plus a few new features. So we had a pretty good tool to start with. The original debugger already had a lot of power, and it had terrific integration with the browser. That was really useful to me — if I'm stepping through and I get an assertion or an access violation and I'm in some code that I'm not familiar with, then I can easily use the browser to find the definition of the variable or to search for other references to it or something like that. Also, the quickwatch window is something I use very heavily, and that was also in the old debugger.

We now have a memory window  —  it's on the Window menu — that has all the power of the CodeView one, including multiple display formats of your data and the ability to display a live expression, so as you're stepping through your program the memory location that's displayed will adjust. It really gives you a feel for what's going on in your program.

Another feature that I like is hardware breakpoints. Let's say you want to find out when a certain variable changes. Visual C++ for Window NT sets a hardware breakpoint, so the program is running at full speed, and the moment that memory changes the debugger stops. It happens automatically — you can even enter an expression that involves two variables, and it will stop and test only when either one of those variables changes.

The main Windows NT-specific features that we added were support for debugging of exception handlers and support for debugging multithreaded applications. In the case of the exception debugging, I really like the way that worked out. The default operation of the IDE debugger is just to continue running the app without stopping for exceptions, because usually that's what you want to have happen. But you also have the power to debug your exception handlers — you can change the IDE so that when an exception occurs, it will stop immediately. Multithread support is pretty straightforward. There's a Threads dialog that allows you to determine which thread currently is the active thread for stepping and for display of register values and so on. It also shows you the priority of each thread and its suspend count.

A strong testament to the debugger is that the moment it was possible to do any debugging with it, I immediately switched from using the debuggers that come with the SDK to using this debugger, because it was so much easier to use. I use the IDE debugger to debug itself, since I'm an IDE debugger developer. It's a complete change from Windows 3.1, where as a debugger developer I had to use WDEB386 to debug the debugger. It's a whole different world. Now I have source level debugging, browsing, editing on the fly — it's so much easier.

The new debugger definitely sped up my development time. One reason for that is now I can see my source code. I can do other things while the debugger is running — I'm not restricted to just living in this little world of the debugger and finally exiting my debugging session and doing something else like editing code or starting help. I also like the fact that I can debug a debugger and carry that several levels down. Sometimes I have three or four levels deep of debugging — the debugger is debugging something that is debugging something else. It's cool!

Note  For more information on the IDE debugger, see Chapter 5 of the Visual Workbench User's Guide.


  Maximize Usability with Intelligent Design

A conversation with Virginia Howlett

What are your concerns about using color in interface design? Color is a very complicated phenomenon in terms of how humans perceive and get information from it. People have very personal reactions to color — it can really make us feel specific things, not rational things. For example, when you see a lot of bright colors together, your reaction generally is that this is something for children — you get a sense that it's sort of cheap. If you think about advertising material, the stuff on gray paper with only one color or two — maybe black, seems more expensive and of higher quality. Because people like color a lot when they're designing Windows applications, they tend to use a lot of color — perhaps without realizing that a lot of color makes people think that the thing is cheap or poorly put together. People will have strong feelings about all colors, except for blue and probably red. That's why you should use color as little as possible in an interface, and wherever you do use color, you must always let the user change it. You should never hard-code a color because there will always be somebody who hates that color.

How can programmers learn about good interface design? One book is the Windows Interface and Application Design Guide, the best reference that you can get about good interface design for Windows. It tells you everything you need to know. If you get the book, you can also get a disk which has some online pieces on it, including an interactive guide that shows you the rules in the Interface Guide in a running app.

Do you have any practical advice you could give about how you, as a designer, deal with multiple display devices? Microsoft has done some surveys to find out the percentage of various display devices in use, and we found that very few people who run Windows — less than 10% — have CGA or EGA displays. Generally, when people upgraded to get enough memory and a faster chip, they upgraded to VGA. And a lot of the LCD displays — in fact, all the current LCD displays in portables — use a VGA display driver. So what we do is design for VGA, and then we let that same design run pretty much as is on higher-res machines. In a high-res machine, like Super VGA, the pixel is still a square pixel and it's smaller than the VGA one. And everything will run, but everything will be smaller. And it seems to work pretty well. The fonts are proportional, and so everything goes down in size proportionally.

Any final words of advice? Graphic design is a well-established profession. Graphic designers have a well-honed procedure that solves problems by producing a large number of initial ideas, reducing those to the best ones, further developing all of those — maybe three or four ideas, then reducing those some more, and eventually coming up with a good design. When designing an interface, programmers should think about hiring a graphic designer. If they're a small shop, they don't have to spend a lot of money on an interface designer. If all they do is pull in somebody visual — the person who's designing the documentation, the person who's designing the packaging, their marketing person, their advertising person — whoever it is, just somebody who has visual training, they will be ahead if they take the designer's feedback seriously. I think the main thing is to realize that graphic interfaces need to look the way they work and work the way they look. Don't get carried away by something cool — just try to make something usable that people will understand.


  Testing the Product

A conversation with Judith Laplante

How do you test Visual C++ for Windows NT? Well, it's a big job. The 32-bit technology meant a lot of new challenges for our QA group, but fortunately we already had a lot of expertise to build on from Visual C++ 1.0, our first C++ Windows-hosted development system. The QA team for VC++ NT was about fifteen to twenty people overall, divided into small teams that specialize in different parts of the product: the development environment, the compiler, the utilities, and so on.

Testing is a group activity. It involves a lot of people, all sorts of machines, and a series of steps taking place over days or weeks. The tests themselves analyze the product at different levels. At the lowest level, we have many small tests that test a certain feature or area of functionality. For the compiler alone, we run approximately forty thousand tests every time the developers give us a new drop. At higher levels, you're testing more how things work together. You know, two things might work fine in isolation, but then when you put them together, something blows up. So, besides the low-level testing, which asks whether these little things work or don't work, you have to make sure all the parts and pieces are talking to each other and behaving in consistent ways. It's analyzing how well things work together, and that gets you into areas like performance, or even fit-and-finish, which can be more subjective.

The methods we use depend on the component we're testing. For command-line components like the compiler and linker, we have automated command scripts that download test sources, build and execute them, and check the results. For graphical parts like the development environment, we write scripts for Microsoft Test to validate what happens in the UI. When you click this button, does the correct dialog appear? Is it the right size and shape? Is the list box filled with the correct items, and so on.

Configuration testing is another big activity. Our test lab has about 75 machines with different hardware and system configurations — a variety of processors, different keyboards and mice, different versions of operating systems all kinds of video boards — whatever a significant number of customers might be using.

Since our staff is comparatively small, it's more efficient to automate our tests. Over the years we've built up pretty elaborate systems for running a lot of tests in parallel, on a number of different machines, using the local area network. And we have ways for other people in the product group to enlist their machines in overnight test runs. So testing can go on around the clock, when most of us have gone home.

But there's only so much you can automate. At some point, you have to sit down with all these test logs, figure out what they mean, and get that information back to the people who need it. On average, I guess the QA group spends about half our time coding — writing and maintaining tests — and the other half running the tests, analyzing the logs, and communicating the results.

Another really important area is beta testing. You can't release a product that's never been tested in the field, and especially with a product this complex, you really can't predict all the possible interactions and scenarios that customers might try. In QA, we have a separate group that focuses all their energy on beta customers, choosing a representative sample of sites who will be motivated to really bang on the product intensively. Beta testing gives us another entire view of the product. Often, the beta period uncovers new bugs that we hadn't seen for whatever reason. And it also gives us immediate feedback on how the product works as a whole.

What is a VC++ tester like? Well, you have to be pretty technical — that goes without saying — and you need a sort of fierce devotion to quality, but we also emphasize a well-rounded background. A number of us come from the Product Support group, so we've had customer contact before. In our job, you have to be an advocate for the customer's needs, and get involved in every part of the process — specs, design reviews, documentation — basically, anything you can think of to help the whole product team share that quality perspective and customer focus.


  Delivering World-Class Developer Support

A conversation with Rich Davies

For our last release, we put a lot of effort into expanding our CompuServe services, and it's worked out very well. We've seen CompuServe activity increasing quite a bit, and we've also put a lot more resources towards CompuServe. With the release of this product, Visual C++ for Windows NT, we want to expand on all of our services, not just CompuServe. We want to give the customer the highest service through every medium, so if they want to use the phone, they can get the detail they need, or if they want to use electronic services, they can get the detail they need — from basic installation help to usage to programming.

Support engineers give service to our customers over multiple mediums. In an average day, they'll have time scheduled to help customers over the phone, as well as to work on our electronic services such as CompuServe. Much of their time is spent researching problems — working with other support engineers to track down problems and then getting back to the customer. Other time is spent working on improving our Knowledge Base — making sure there are a lot of technical articles in there about the product — or maybe taking training courses to improve their skills, or developing training for other engineers to take, or just working with the product group to get customer feedback into future products.

We've taken the customer feedback from Visual C++, whether it be suggestions for improvements or problem reports, and brought them back to the product group for future development. We also participate very actively in the beta process. So we're really a good representative for the customer as far as getting information back into the development cycle.

We've been working hard on increasing the technical expertise of our support engineers. One thing that customers have told us is that they want to work with people who understand what they're going through. So, we've been hiring engineers that have done development work themselves. We also do a lot of training — for example, our core team that supports this product will have a lot of training on Windows NT and its fundamental technologies. Also, if we run into a really tough, specific problem, we have defined escalation paths to the development team.

We'll initially have between ten and fifteen support engineers focusing solely on Visual C++ for Windows NT. We'll also be leveraging the engineers working on Visual C++ for Windows and what we learned from that product. For the Windows NT version, as for any new product, we'll look at the major areas of functionality and make sure that we have someone who focuses on that area. Most engineers do have an area of specialty. It gives them a chance to really focus their knowledge and then gives us a critical point person if we really need to get in-depth with a problem.

We want to completely solve the customer's problem, as opposed to just solving the problem quickly. It's more important to give the customer technically correct and complete information than to turn calls or electronic requests around really quickly. Today, a high percentage of our phone questions are answered during that phone call, but our goal is to increase our percentage of first-call resolutions while still maintaining completeness and quality.

In the future, we're looking at ways to meet the challenge of delivering the world's best developer support. Things like making it easier for our customers to get to us — getting the right question to the right engineer — making ourselves more available for the customer — whatever we can do to help our developer customers be successful.

Note  For more information on product support services, see the Introduction to Getting Started.


  Books Online

A conversation with Peter Lancaster

Why Books Online? It was natural for us to try to put our books online once Visual C++ for Windows NT became a CD product. We knew how enthusiastic developers were about Microsoft Developer's Network, so it was a safe bet that our customers would love it. I find it interesting that our own developers who love print but just tolerate help have really warmed up to Books Online.

A big reason we wanted to do Books Online is it makes our documentation portable. You stick the CD in your bag and take it with you — no need to lug around a C Run-Time Reference or Foundation Class Reference. Just a CD. You can also put the CD on a server and allow access across a network. Many people can get at the same information — just like at a library — but everyone can check out the same book.

Books Online don't replace print — the books are all available for anyone who wants them. It's just an additional, and very powerful, way to present the information our customers need.

Books Online is different from online help because the design is based on what I call a "paging model." The information is laid out page-by-page, and all navigational devices reinforce the book metaphor. You can literally "turn" the pages of a book by pressing browse buttons or by clicking icons in the Contents browser. Nothing is unfamiliar to customers—εveryone knows how to find information in books. With Books Online you get the advantage of a table of contents — the Contents browser. Browsers are essential for large hypertext databases. It's like holding a magic map in your hand — you point to a destination, and phht! you're there. Gutenberg, Shakespeare, and even my great uncle Prince Albert Lancaster would have been impressed.

And then there is full-text search. Suppose you want to find out about some message such as wm_destroy. You choose the Search Plus button, then enter the string WM_DESTORY — perhaps even narrow the search with boolean characters if you want to. Then let the software do its magic and all occurrences of wm_destroy in the doc set are listed. You could even add bookmarks so you have the reference ready at hand. To make a long story short, Books Online becomes just a hypertext database that can be queried. This is certainly one future of books.

Improvements in screen resolution have made Books Online possible. No one could have used Books Online with CGA. We know that most of our users — about 90% — have high-res monitors, so we design accordingly. For example, we think a lot of bold on screen is hard to take — reading bold on screen for me is like riding a bike over cobblestones. I also feel that green hyper jumps interfere with readability, so we've created a variation on that theme. All jumps in Books Online are enclosed in green chevrons that really don't stand out that much. I take the view that users are trying to read text and don't want to be distracted by too much color.

We've come out of the cave as far as hypertext systems go. I've been working on help systems since 1987. We're finally getting it right for all customers — we have instant reference with F1 help, extensive how-to help for various environments, and now Books Online. But I'm still waiting for the day when I can say to my computer, "Thank goodness I don't need help."


  Microsoft Visual C++: Product Overview

Microsoft® Visual C++™ Development System version 1.0 for Windows™ and Windows NT™, 32-bit Edition is the latest generation of C++ products from Microsoft that significantly shortens the path to writing C++ applications for the Microsoft Windows operating system. Visual C++ 32-bit Edition does this by offering an integrated, task-oriented and 100-percent Windows NT operating system-hosted graphical environment that provides significant productivity benefits and ease of use with complete access to the power of C++.


  Design Goals of Visual C++ Standard and Professional Editions

Visual C++ Standard and Professional Editions were introduced in February 1993 for use with the Windows operating system version 3.1.

The major design goals of Microsoft Visual C++ Standard and Professional Editions centered around providing solutions to specific needs that had been identified by the developer community in extensive research. Specifically, Visual C++ was created to be the shortest path to C++ programs for Windows. Ease of use was the number one design goal. Additionally, customers wanted a development tool that protects their investment in learning the tool, as well as their application source code. Visual C++ was designed to accomplish this while providing the smallest and fastest executables in the industry.


  Visual C++ Standard and Professional Editions Deliver

Visual C++ Standard and Professional Editions deliver comprehensive solutions to these problems.

Shortest path to C++ Programs for Windows  A completely new integrated graphical tool set, including the Visual Workbench, a combined editor, debugger, graphical browser and a project management system designed to be intuitive allowed programmers to easily control project options for the compiler and linker. All options can easily be set through dialog boxes. Extensive online help facilities were also provided.

Two wizards, the App Wizard and Class Wizard, combine to assist the developer in setting up new projects and in managing the derivation of classes from the MFC 2.0 application framework. Developers can work with the application framework to create new classes and member functions, allowing Class Wizard to manage the mundane details of hooking the new classes up to user interface components.

App Studio is a completely integrated resource editor that combines new visual editors for all of the standard Windows resources into one easy-to-use tool featuring drag-and-drop and point-and-click simplicity. The streamlined integration with Visual Workbench and Class Wizard make it the easiest way to connect user interface elements to C++ classes and application code.

Safest Investment  Microsoft Foundation Class (MFC) 2.0 improves upon the popular C++ development set for Windows with the Microsoft Foundation Class Library 1.0. Applications written using MFC 1.0 move easily to MFC 2.0 to take advantage of the new high level features. The new library provides architecture classes and classes for advanced features such as Toolbars, Status Bars, Printing and Print Preview, Splitter Windows and more.

In addition, MFC was designed to coexist with existing C and C++ code so that developers can add new features to existing applications without having to completely rewrite them.

Smallest and Fastest Code  Building on the legacy of code generation quality set with previous versions of Microsoft compilers, the optimization technology in Visual C++ Professional Edition is second to none, providing highly tuned applications with unlimited flexibility. The developer controls exactly which optimizations are used. Visual C++ Professional Edition also added new switches to automatically create either the smallest, or the fastest executable, avoiding the complications of custom optimizations where such fine control is not necessary.

The entire Visual C++ family is the result of listening to the concerns of developer customers. Making C++ and programming for Windows easy is the number one concern. All versions of Visual C++ have been designed with these goals in mind.


Whats New For The 32-bit Edition
  What's New For The 32-bit Edition

Visual C++ 32-bit Edition version 1.0, formally announced in August 1993, includes SDK tools and advanced optimizations for the Win32™ and Win32s™ application program interface (API) and is designed to be hosted under the Windows NT operating system. Like the other Visual C++ editions, the 32-bit Edition was designed with specific customer-driven design goals. The specific design goals for the 32-bit Edition include the following:

Shortest Path to 32-bit Windows  Bringing the ease-of-use features from the 16-bit product to 32-bits was crucial. Streamlined integration and wizards can be used to assist the developer in creating powerful 32-bit applications for both Windows NT and Windows 3.1. The power of the Windows NT host operating system can be exploited to allow seamless background compilation and simultaneous multiple project builds. In addition, the developer is assisted in all phases of 32-bit development, from project creation to debugging.

Safest Investment  Visual C++ 32-bit Edition is the safest investment in C++ development tool technology because it provides an easy 16-bit to 32-bit migration path from previous Microsoft C++ products. It enables developers to use existing NMAKE files, and to work with existing C and C++-based projects. Visual C++ 32-bit provides a way for developers to write applications from a single source code base that will run on both Windows 3.1 and the new Windows NT operating system, taking advantage of the performance benefits of 32-bit programming on both platforms.


  Visual C++ 32-bit Edition Delivers

Visual C++ 32-bit Edition is the latest addition to the Visual C++ family. It delivers on each of these objectives. Visual C++ 32-bit Edition uniquely addresses these objectives by providing the ease-of-use features introduced in the Standard and Professional Editions, and incorporating enhancements for support of 32-bit programming and the Windows NT host platform.


  Shortest Path to 32-bit Windows

IDE Enhancements  The Visual Workbench and integrated debugger have been enhanced with new features for 32-bit programming while providing the same intuitive interface as the 16-bit products. Developers already familiar with Visual C++ Standard or Professional Editions will be right at home working with the new 32-bit edition. However, to improve on the ease of use, we added several new enhancements, including the following:

•	IDE is a completely 32-bit application itself and takes advantage of the advanced features of the Windows NT operating system, including preemptive multitasking and multithreading. This allows the developer to continue working in project files while builds are progressing in the background. Additionally, it is possible to have multiple builds occurring simultaneously.

•	Integrated Profiler makes profiling just a few mouse clicks away. It has tremendous improvement in its ease of use and enables developers to see potential performance problem areas in their code at a glance.

•	Find-in-files utility allows global searching through source files for any text string. The integration of this feature allows the developer to go directly to the place in the source code the references are found by simply clicking the result in the output window. This is just one of many ways that the Visual Workbench allows virtually unlimited navigation of complex project files, dramatically improving programmer productivity when navigating through the Win32 API.

•	Enhanced support for third-party tool integration — tools can now direct their output to the IDE output window. Tools can easily be added to the Tools menu for easy access. Again, the improved integration provides a more seamless environment for the developer, making it much easier to take advantage of capabilities offered by third-party tools.

Debugger Enhancements  The IDE debugger in Visual C++, 32-Bit Edition, has been enhanced with the features developers have asked for most. In addition to all of the features included in the Standard and Professional Editions, the 32-bit Edition includes the following:

•	New memory window — displays current memory contents.

•	Support for Structured Exception Handling — allows the developer to control the action of the debugger when an exception is thrown. Options include stop if unhandled, and stop always. User defined exceptions can be created. This configurability allows the developer greater control of the application during the debugging stage, and assists in locating coding errors.

•	Support for threads — allows the developer to view the current execution state of all threads in the target application, pause or resume thread execution, view addresses or functions and begin additional debugging tasks such as obtaining a stack trace. Double clicking opens the appropriate source file and positions the highlight on the line of execution. This can dramatically ease the task of debugging a multithreaded application because it is possible to easily follow the execution path of any given thread.

New Spy++ Windows Analysis Tool  Spy++ is the greatly enhanced window message spy utility for Visual C++ 32-bit Edition that allows a developer to quickly discover a great deal of information about his or her Windows-based application. The display of window messages now shows decoded parameters as well as return values. Flexible "filters" allow precise control over the messages, windows and other information displayed. In addition to the view that shows the messages going to a window, three different "Tree" view types show the hierarchical relationships of windows, processes and threads in the system. Four other "Detail" view types show details about specific windows, processes, threads and window classes in the system. Any number of these different views can be displayed at once. Links are used throughout the Spy++ views to allow a developer to quickly get more information about the items that are shown.

Compiler Enhancements  The Visual C++ 32-bit Edition compiler is a proven technology. More than 100 million lines of code were run through this compiler during the development process. In fact, it is the compiler that was used to build Windows NT itself. New code generation for i486™ and Pentium™ processors, coupled with advanced optimization for the new Pentium superscalar architecture, assures the fastest and smallest code possible for the highest performing application. Microsoft worked closely with Intel in implementing this advanced optimization technology. The new i486 and Pentium optimizations offer dramatic performance improvements for target applications.

The 32-bit Edition also continues support for precompiled headers, and all compiler options can be easily controlled from the Visual Workbench.


Safest Investment  Still
  Safest Investment — Still

MFC 2.0  The Microsoft Foundation Class Library 1.0 became a standard for C++ application development for Windows. Microsoft committed to ensuring that applications written to the MFC standard would move forward to our newer operating systems. MFC 1.0 has been shipping with the Win32 prerelease SDK, and many 32-bit applications have been written using it. MFC 2.0 builds on the foundation established with MFC 1.0 by adding architecture classes and classes for such advanced user interface features as Splitter Windows, Toolbars, Status Bars, Printing and Print Preview and more. Applications written using MFC 1.0 can easily be moved to MFC 2.0, preserving the developer's investment.

Now, 16-bit applications written using either MFC 1.0 or MFC 2.0 can easily be moved to 32-bits, providing improved application performance. The resulting 32-bit application can run on Windows 3.1 or Windows NT, allowing developers to maintain a single source code base for both operating systems.

Windows 3.1 Targetting  The Visual C++ 32-bit Edition includes the Win32 SDK components necessary for building applications for Windows NT. It also includes Win32s, a product that allows 32-bit Win32-based applications to run binary-compatibly under both Windows NT and Windows operating system version 3.1. By writing applications to the Win32 API using Win32s, developers can create single source base 32-bit applications that will run on both Windows 3.1 and Windows NT. Because of the flat address model of 32-bit programming, it is often easier to write 32-bit applications, and these applications often will run faster than comparable 16-bit applications, even when running on Windows 3.1.

Win32s is a complete development solution, including a debugger and command line tools that operate on the Windows 3.1 target. A developer can edit, build and debug the application under Windows NT, and then move the source code to a Windows 3.1 target for final performance tuning and debugging.

Applications written using MFC 2.0 are fully compatible with Win32s.

Exploits CD-ROM with Books Online  Visual C++ 32-bit Edition is the first PC based development tool to fully exploit the power of CD-ROM media. In addition to the software and online help, more than 10,000 pages of documentation has been cross referenced and indexed into a new »Books Online system«. Developers have instant access to the users' guides, tutorials, language references and API references. The new viewer technology shipped with Visual C++ 32-bit Edition includes extensive browsing capabilities and an enhanced full-text search feature so that even topics that cannot be found through the extensive indexing can easily be found using wild cards, pattern matching, etc. Books Online includes all of the graphics and source code samples in the available printed documentation and is truly information at your fingertips.

For those developers who also wish printed documentation, it can be obtained at additional cost.

Visual C++ 32-bit edition, also allows developers to run the development environment directly from the CD-ROM, saving up to 75 megabytes of hard disk space for developers who use this option.

As summarized in the chart below, Visual C++, 32-Bit Edition is the product to choose if you wish to create powerful 32-bit applications for Windows 3.1 and Windows NT.

	Visual C++  Standard Edition	Visual C++  Professional Edition	Visual C++ 32-bit Edition
Hosted on	Windows 3.1	Windows 3.1	Windows NT
Targets	Windows 3.1 (Win 16)	Windows 3.1 (Win 16) MS-DOS® (DOS 16)	Windows 3.1 (Win32s) Windows NT (Win32)


  Moving to 32-bit C++ Programming in Windows

As mentioned above, the difficulty of moving to C++ programming in the Windows environment is a major issue for developers. The fastest way to show how the Visual C++ development system helps programmers overcome these difficulties is to briefly describe the process needed to create a new application that uses the new features of Microsoft Foundation Class version 2.0.

In the next few pages, a series of steps demonstrate how Visual C++ 32-Bit Edition can speed the development of 32-bit C++ applications for the Windows or Windows NT environments. An overview of these steps are as follows:

1.	Visual Workbench: Starts the integrated development environment.

2.	AppWizard: Creates a new "skeleton" application that supports Microsoft Foundation Class 2.0.

3.	App Studio: Creates, edits and browses application resources.

4.	ClassWizard: Connects user interface elements to C++ code.

5.	Microsoft Foundation Class 2.0: Leverages the architecture and high-level abstractions of the application framework.

6.	Visual Workbench: Builds and debugs the application.

The following "demo" covers only a few of the more important features. For a more comprehensive discussion of the features of Visual C++, see »Appendix A« For an actual programming exercise, see »Appendix B«.


  Step 1: Start Visual Workbench

Double-clicking the Visual Workbench icon launches the Visual C++ completely new, 100-percent Windows-hosted development environment. Visual Workbench is a fully integrated environment that enables programmers to edit, build, debug and browse program code in a visually oriented manner. It includes a source code editor, compiler/linker, debugger and class browser.

Visual Workbench also provides completely seamless access to all other Visual C++ tools, including App Studio for resource editing and ClassWizard for connecting user interface elements to application code.

Visual Workbench allows programmers to build or edit code in the background. For example, you can click the build button to compile and link your application and then use the editor to write a new function while the build is completed as a background task.


  Step 2: AppWizard

To create a new application, you select »AppWizard« from the Visual Workbench Project menu. The purpose of AppWizard is to create a full set of "skeleton" application source code files and project files that give programmers a "jump start" into programming with Visual C++ using Microsoft Foundation Class 2.0. By clicking check boxes in an AppWizard dialog (»see figure«), you can choose which Microsoft Foundation Class 2.0 features you want the application to contain, including:

•	Print and Print Preview

•	Multiple document interface (MDI) support

•	OLE client support

•	Context-sensitive Help

•	Toolbar capabilities

The key productivity benefit of AppWizard is that it reuses a substantial amount of prefabricated code in the application framework. All the initial source code for the selected features is included in the application's project files. It takes only a few seconds to create the skeleton application, which you can build and run immediately. Because so much functionality is included, creating the skeleton application manually would have taken considerably longer.

Additionally, the application automatically supports the new Microsoft Foundation Class 2.0 document and view architecture (described in Appendix A and the Microsoft Foundation Class 2.0 white paper).

AppWizard is therefore the fastest way to get started with Microsoft Foundation Class 2.0 programming because it creates baseline Microsoft Foundation Class 2.0 source code that programmers can extend or modify.


  Step 3: App Studio

Once the initial program files are created, you can use »App Studio« to edit all the resources associated with the project. Accessed from the Visual Workbench Tools menu, App Studio is a Windows-hosted program that provides a graphical and interactive approach to designing user interfaces and editing resources of Windows applications.

App Studio includes editors for:

•	Application menus

•	Dialogs and forms

•	Bitmaps, cursors and icons

•	String table entries

•	Accelerator tables

Editing your application's user interface in App Studio is similar to drawing your interface in the Visual Basic programming system. In addition to letting you draw menus and dialogs, App studio also supports drawing bitmaps, icons and cursors. App Studio lets you open multiple resource files and drag and drop resources between them. It is 100 percent compatible with the Microsoft Resource Compiler — allowing you to edit resources for both C and C++ applications. And it is fully integrated with Class Wizard and the Visual Workbench so that you can draw user interface objects and connect them to code quickly and error free. In total, App Studio provides a completely integrated user interface editor to make drawing and coding user interfaces easy and efficient.

»This diagram« shows a simple dialog being edited with the App Studio dialog editor:


  Step 4: ClassWizard

While working with resources in App Studio, the next step is to run ClassWizard, which you select from the App Studio toolbar. ClassWizard allows you to quickly connect the components of your program's user interface (menus, dialogs, etc.) to the code that handles them. ClassWizard is important because it allows you to browse and change messages, message-handler functions and member variables many times faster (and with fewer errors) than would otherwise be possible manually.

Once inside ClassWizard (see »this figure«), you can select which messages from Windows the resource will respond to, and enter the names of functions that will handle the messages. ClassWizard updates the appropriate header files with all the necessary variable and function declarations. It also adds "empty" function definitions in the implementation files, along with comments to help you understand what code you need to add. At any time, you can jump directly to these functions in your source code by clicking the Edit Code button. You can also press F1 on a Windows message to display a Help screen on that message.

When relationships between a program's user interface and its code change, you can use ClassWizard to automatically edit the class members, message maps or dialog data macros within the source files to keep them consistent. However, ClassWizard is completely noninvasive; it never changes any code you write and is therefore completely safe. ClassWizard only does exactly what you tell it to do.

Class Wizard also allows you to set up and manage the new dynamic dialog data exchange and validation (DDX/DDV) capabilities of the application framework. DDX/DDV is a capability that allows data values entered into an application dialog to be automatically validated and assigned to member variables at run time.


  Step 5: Implementation with Microsoft Foundation Class 2.0

At this point, a complete skeleton application with all the appropriate resources and declarations has been built interactively and without any programming. The next step is to use the integrated Visual Workbench editor to complete the function implementations that respond to user interaction and add any other code necessary to complete the application.

To do this, you can use the Microsoft Foundation Class 2.0 library, an application framework built on the core set of functionality in Microsoft Foundation Class 1.0. Microsoft Foundation Class 2.0 provides an architecture and a set of prebuilt components that significantly simplify programming for Windows in C++. It offers a high level of abstraction that lets you focus on the details specific to your application, while simultaneously providing access to lower-level classes and the native Windows API for maximum flexibility and power.

Microsoft Foundation Class 2.0 offers more than one hundred reusable and extensible C++ classes, many of which already encapsulate the basic building blocks of a professional application written for the Windows environment. For example, to add a toolbar to an application requires fewer than 10 lines of code, but this represents more than 1,500 lines of Microsoft Foundation Class 2.0 framework code. Similarly, adding printing and print preview capability can be done in just a few minutes, but represents several thousand lines of framework code.

Because Microsoft Foundation Class 2.0 code can be intermixed with native Win32 or Win32s SDK calls, programmers can migrate existing 32-bit Windows-based applications to C++ at their own speed. Additionally, the Microsoft Foundation Class 2.0 code is completely portable between 16-bit and 32-bit Windows.


  Step 6: Build and Debug With Visual Workbench

After the appropriate functions have been implemented, you can build your application by clicking the Build button on the Visual Workbench toolbar. The Visual C++ compiler offers all the size and speed benefits of the C/C++ 7.0 compiler, and adds additional features (see size and speed improvements section). As a result, Visual C++ produces executable files that are still among the fastest and smallest in the industry.

Visual Workbench can automatically create and maintain build options in its own makefiles, or you can use existing project files, which are 100-percent compatible with the NMAKE command-line tool from the Microsoft C/C++ development system version 7.0 and from the Win32pre-release SDK. You can use existing makefiles from C/C++ 7.0 or the Win32 pre-release SDK if you want to use special build rules or to invoke command-line tools.

You then debug your application using the »Visual C++ debugger«, a completely new Windows-hosted debugger that is fully integrated with the Visual Workbench.

To set a breakpoint, select a line of source code in the editor and click the breakpoint button on the Visual Workbench toolbar. You can edit source code or set new breakpoints while you debug, or vice versa.


  Key Points

The product overview previously discussed demonstrates the following key points about the design of Visual C++:

Delivers the benefits of Visual Basic to programmers using C++  Visual C++ offers many of the ease-of-use and productivity benefits associated with the Visual Basic™ programming system while providing complete access to the power of C++ for programming in Windows.

Highly integrated tool set  Visual C++ provides a highly integrated tool set that makes the development cycle more efficient from start to finish. This integration allows programmers to switch rapidly between distinct tasks such as editing, building and debugging, or to even do some of these tasks concurrently.

Full-featured applications with less work  Through Microsoft Foundation Class 2.0, programmers can build better applications in a fraction of the time that it takes using C and the Win32 or Win32s SDKs. This is because the Microsoft Foundation Class Library 2.0 contains a large amount of reusable code, high-level abstractions and "canned" functionality that programmers can add to their applications with very little effort.

Easy to learn  Its graphical and visual nature helps make Visual C++ easy to learn. Since all of Visual C++ (including all the tools) are now 100-percent Windows NT-based, all of the advantages of the Windows NT environment (rich user interface graphics, consistent operation, multitasking, toolbars, floating palettes and so on) are offered to programmers. Comprehensive product testing at Microsoft's usability lab helped to refine all aspects of the user interface and make it both fast and intuitive. New with Visual C++ 32-Bit edition is the extensive on-line documentation: over 10,000 pages of documentation is included in browsable, cross-referenced, and hot-linked Books Online form. Printed documentation is also available. Extensive sample code, online help and product support are available to assist developers of all levels of experience.

Easy migration path  Microsoft Foundation Class 2.0 allows programmers to easily migrate their existing C/Win32 SDK program code to C++. Developers can freely mix Microsoft Foundation Class 2.0 code with native Win32 SDK or Win32s SDK calls, enabling programs to be gradually transitioned into C++ instead of rewriting them from scratch. Also, since the Microsoft Foundation Class 2.0 library follows function and parameter naming conventions that closely match the Win32 SDK, a developer's knowledge of programming for Windows NT is preserved.

Still the smallest and fastest executables files  Visual C++ incorporates Microsoft code optimization technology that is now in its fifth generation. All of the optimizations of C/C++ 7.0 and in the Win32 pre-release SDK compiler are available in Visual C++, and a number of further improvements have been made, which are described below. In short, executable files built with Visual C++ 32-Bit Edition are still the smallest and fastest in the industry, and are smaller and faster than those built with any previous Microsoft compiler.

The remainder of this guide discusses additional improvements and features in greater detail.


  Executable Size and Speed Improvements

All of the code optimizations of C/C++ 7.0 and the Win32 pre-release SDK compiler are available in Visual C++ along with the additional improvements described below. As a result, executable files built with Visual C++ are still the smallest and fastest in the industry, and are even smaller and faster than those built using C/C++ 7.0 - the compiler that set the standard for small and fast code.


  Smart Linking

Smart linking is a capability that can significantly reduce executable size by eliminating functions that are not referenced in the program. It is especially important for programs that use large code libraries (such as C++ class libraries) because linking with libraries usually results in the incorporation of a considerable number of unused functions.


  New optimizations for Pentium and i486 Processors

The compiler generates code specifically for the 80386, 80486, or Pentium instruction sets, which results in faster execution and smaller code. Visual C++ 32-Bit Edition includes new optimization specifically for Pentium and i486 processors. These optimizations take advantage of the superscalar architecture of the Pentium processor to deliver even faster application performance than ever before.


  Simpler Compiler Switches

A number of programmers asked Microsoft to incorporate two additional compiler switches, and we have done so: /O1 and /O2.

The /O1 switch provides all the best optimizations for size, while the /O2 switch provides all the best optimizations for speed. These further simplify the selection of build options.

Another improvement is the simplification of the process to create and use precompiled headers. Now, by specifying the /YX switch, a precompiled header is automatically created if none existed, and the file is automatically reused in subsequent builds.


  32-bit Programming

Microsoft Visual C++ 32-bit Edition is designed to write 32-bit applications for either Windows 3.1 or Windows NT. 32-Bit applications offer higher performance, and because of the flat 32-bit address space, are often easier to program. When writing 32-bit applications, developers need not worry about various compiler memory models and segment sizes as they have had to with traditional 16-bit development systems.

Developers write 32-bit applications using the Win32 or Win32s API. The Win32 API is the complete 32-bit API for the Windows NT operating system. It includes support for preemptive multitasking, symmetric multiprocessing, bezier curves, security and more. The Win32s API is a subset of the Win32 API that allows applications to run binary-compatibly on Microsoft Windows 3.1. It is an operating system extension that allows Windows 3.1 to run Win32-based applications.

Win32s offers software developers the following:

•	A powerful 32-bit programming model for Windows 3.1, which is binary compatible with Windows NT

•	The performance advantages of 32-bit mode

•	Win32 semantics for the API

•	A rich subset of the full Win32 API

•	The ability to ship Win32 applications today for Windows 3.1 and Windows NT

Win32s consists of a virtual device driver and a set of dynamic link libraries that extend Windows 3.1 to support Win32 applications. The Win32s files must be shipped with the Win32 application and installed on the Windows 3.1 system. Visual C++ 32-bit edition provides the Win32s binaries and a setup program to install Win32s on a Windows 3.l system.


  Long-term Investment

Microsoft strives to make its family of language products a safe choice for long-term investment. The Microsoft Foundation Classes have become widely used among ISVs and corporate developers, and Microsoft has publicly stated its long-term commitment to MFC as the future direction for Windows-based and Windows NT-based programming in C++.

Microsoft Foundation Class 2.0 extends the Microsoft Foundation Class C 1.0 library so that the investment in Microsoft Foundation Class 1.0 applications is preserved. Microsoft Foundation Class 1.0 programs need only be recompiled to begin taking advantage of Microsoft Foundation Class 2.0. Future versions of Microsoft Foundation Class will offer the same backward compatibility so that programs written to previous Microsoft Foundation Class library versions will be able to run without a problem. Programmers can therefore incorporate new capabilities of new Microsoft Foundation Class libraries at their own pace.

Microsoft Foundation Class is also designed for compatibility with new versions of the Windows operating system. Applications written with the Microsoft Foundation Class 2.0 library on Windows version 3.1 can be recompiled and run with no source code changes on Windows NT  operating system and Win32s API using Visual C++ 32-Bit edition.


  Appendix A: List of Features

Visual Workbench

The Microsoft Visual C++ development system contains a completely new Windows-hosted development environment called Visual Workbench. Visual Workbench replaces the Programmer's Workbench of previous Microsoft C versions. Using Visual Workbench, programmers can edit, build, debug and browse C/C++ code from a single integrated Windows-based environment. Visual Workbench also offers seamless access to AppWizard for skeleton application generation, App Studio for creation and management of application resources and ClassWizard for connecting code to resources.


Features
  Visual Workbench Features

Editor  Windows-hosted. By default, language keywords, identifiers, comments and strings are displayed in different colors. You can disable the colors entirely or customize them to suit your own taste. Visual C++ 32-Bit Edition includes a new Find-in-files tool that allows global search through source files with many possible options.

Debugger  Fully Windows-hosted. You can start the debugger from within the Visual Workbench and use toolbar buttons to set or remove breakpoints and step through the application source code. Visual C++ 32-Bit Edition includes support for Windows NT exceptions and threads, as well as a new memory window.

Class browser  Windows-hosted, and can be used for both C and C++ code. You can now see graphical trees of class hierarchies and expand and collapse graphs by clicking a mouse on icons that represent class "nodes."  This new method enables programmers to browse the class hierarchy more quickly than before. The browser can also display the relationships between calling and called functions.

Improved ease of use  Throughout its development, the Visual Workbench designers refined the product's user interface by studying data from Microsoft's usability lab. As a result, the Visual Workbench interface is intuitive and designed to minimize the number of steps needed to perform each task, from editing through debugging.

Seamless access to all tools  All tools, including App Studio, AppWizard, ClassWizard, the debugger, browser and editor can be accessed directly from Visual Workbench.

Multiple document interface  Allows you to simultaneously display the debugger, source code windows, class browser information and status/error information.

Toolbar  One-click access to frequently used operations for file saving, text finding/replacing, building, running and debugging.

Concurrent editing while building  Allows programmers to edit source code while they build. For example, while a build occurs, a programmer can code a new function that will be compiled and linked during the next build.

External makefile support  Visual Workbench enables programmers to run existing makefiles (called external makefiles) from within the Visual Workbench environment. In these cases, Visual Workbench does not alter the contents of the makefile, but allows programmers to maintain the contents of the makefile outside of the development environment. If the external makefile generates output compatible with CodeView®, the program can also be debugged from within Visual Workbench.


  App Studio

App Studio is a major new component of Visual C++. It is a graphical, visual and interactive program that encompasses the following three programming tasks:

•	User interface design and editing

•	Resource creation, editing and maintenance

App Studio uses a completely graphical approach to user interface design, and resource editing.

Despite the visual approach to designing resources, all of the control normally provided through the direct editing of resource files is still available in App Studio. If desired, programmers can always use the traditional method of directly editing resource files in the usual manner.


Features
  App Studio Features

Suite of tools  App Studio includes a dialog editor, graphics (bitmap, cursor, icon) editor, symbol editor, string table editor, menu editor and accelerator table editor.

Completely integrated  App Studio is fully integrated with both Visual Workbench and Microsoft Foundation Class 2.0 (through ClassWizard). At any time, programmers editing code within Visual Workbench can start App Studio by selecting it from the Visual Workbench menu bar. Control is returned automatically to Visual Workbench when resource editing is completed.

Resource browsing  Allows you to view all resources associated with the application, either in summary (list) form or in detail through any one of the resource editors.

Simultaneous resource editing  You can edit multiple resources at once in different windows. You can also open multiple resource files at the same time and drag and drop resources to move or copy them between files.

Drag and drop  App Studio supports a wide range of drag-and-drop operations between resources that are being edited.

Automatic symbol management  The symbol editor of App Studio lets you name and rename resources with text names while numeric values are managed automatically for you. This makes managing symbols much faster and less error-prone.

Modeless property sheets  You can enter exact values for any object properties (such as button style) by displaying that object's property sheet. Property sheets are modeless, and they dynamically update as you click on different items. This allows properties for all user interface elements to be set very quickly.

Edits multiple file types  Programmers can directly edit a wide range of file types, including .RC, .BMP, .ICO and .CUR. Since it reads .RC files, it is compatible with the command-line resource compiler of C/C++ 7.0 and the Win32 pre-release SDK.


  AppWizard

AppWizard is a program that can be run as a standalone utility from Program Manager or from Visual Workbench. Its purpose is to create the "skeleton" application source code files that give programmers a "jump start" into programming with Visual C++ and Microsoft Foundation Class 2.0.


Features
  AppWizard Features

Creates Microsoft Foundation Class 2.0 applications  Creates working applications that contain Microsoft Foundation Class 2.0 functionality, including printing and print preview, support for Visual Basic custom controls, documents and views, multiple document applications, OLE support, context-sensitive help and toolbar capabilities. For programmers building a new application with Visual C++, AppWizard is an indispensable tool for getting started with the new Microsoft Foundation Class 2.0 features, such as the new document/view architecture. And AppWizard creates very little code since the implementation for core application features is provided by the Microsoft Foundation Classes 2.0 class library.

Creates all project files  AppWizard creates not just the source files, but all the project files necessary to build the application immediately.


  ClassWizard

ClassWizard is an important new tool that is the first of its kind. It can best be described as a "programmer's assistant" that helps developers with many of the details of C++ programming in the Windows environment while enabling them to have full control over every line of their source code.

Programmers can use ClassWizard to connect user interface controls (such as dialog buttons) to the application code that handles them. This replaces the old method of tediously opening and closing different source files to directly edit message maps, class declarations and dialog data routines. As a result, using ClassWizard is far more productive and less error-prone than editing this type of code by hand, especially for large projects with dozens or hundreds of files.


Features
  ClassWizard Features

Manage messages  Allows programmers to map messages from Windows to their function handlers.

Browse messages  Allows programmers to quickly browse all the messages and handler functions associated with user interface objects from a single location. This is much faster than opening and scrolling through multiple source files. Context-sensitive help on each message is available at any time.

Dialog data exchange and validation  Programmers can take advantage of the dialog data exchange (DDX) and dialog data validation (DDV) capabilities of Microsoft Foundation Class 2.0. ClassWizard maintains the relationship between dialog controls and their member variables in the dialog's class. For more information on DDX and DDV, see the following section on Microsoft Foundation Class 2.0.

Jump to code  Programmers can jump directly to the correct source file to create or edit the implementations of the message handler functions. This is done through seamless communication with the Visual Workbench editor.

Completely safe  ClassWizard never changes any code written by programmers. Whenever ClassWizard makes a change in a source file, it is only to sections of code that are maintained by ClassWizard. Since ClassWizard doesn't parse code written by programmers, it is error-free and has none of the interpretation problems inherent in code generators.

Completely integrated  ClassWizard can be accessed from both Visual Workbench and App Studio so you can edit class information at any time.

Imports existing projects  In just a few steps, you can import existing Microsoft Foundation Class 1.0 projects to make them compatible with ClassWizard.


  Microsoft Foundation Class Library Version 2.0

Microsoft C/C++ 7 included the first version of the Microsoft Foundation Class library (Microsoft Foundation Class 1.0), an extensive set of classes that encapsulated most of the basic functionality of the Windows 3.1 SDK while providing higher-level classes that simplified programming. This class architecture, coupled with the internal mechanisms that implement the classes is called the framework.

In Visual C++ 32-bit Edition, the framework has been greatly enhanced through the introduction of Microsoft Foundation Class version 2.0, which offers programmers a set of higher level classes that simplify Windows and Windows NT-based programming. Through these classes, programmers are able to quickly create high-level objects that contain pre-built application behavior. For example, the new CFormView class allows programmers to build form-processing applications by encapsulating the functionality of scrollable data entry forms. Creating new forms requires almost no programming. Normally, features such as this would consume a considerable amount of development time. Microsoft Foundation Class 2.0 applications written using Visual C++ 32-bit Edition can be compiled to run under either Windows 3.1, using the Win32s API, or Windows NT, using the Win32 API.

If desired, programmers can still continue to build any functionality they desire using standard Win32 or Win32s SDK calls. Microsoft Foundation Class 2.0 therefore gives programmers a means of hiding the details of Windows-based development or fully exposing it, depending on their needs.

The following is a list of the major new classes and capabilities offered by Microsoft Foundation Class 2.0:


Features
  Microsoft Foundation Class Library Version 2.0 Features

Documents and views  A document is an object with which the application user interacts during an editing session, and is typically created by the New or Open commands on the application's File menu. Users interact with the data contained in a document through a view object, which represents the client area of a frame window.

With the CDocument class, Microsoft Foundation Class 2.0 automatically supports high-level commands such as File New, File Save, File Save As and File Open. Microsoft Foundation Class 2.0 does all the work of displaying a dialog to gather information from the user and managing the disk file.

Each document in a running application is attached to one or more views, which control the graphical display of application data on the screen. Programmers will typically derive a class from the Microsoft Foundation Class 2.0 CView class and then implement the display code. Once you implement drawing code within a CView object, the framework will automatically provide device-independent printing and print preview within your application.

Toolbar and status bar classes  The new CToolbar class lets programmers easily create toolbars that have a row of bitmapped buttons and optional separators.

The new CStatusBar class enables programmers to easily incorporate status bar capabilities into their applications. These include multiple paned bars that separate information into groups and can be used to display almost any text such as help messages or key state indicators.

Form and edit views  CFormView provides form window capabilities for applications that present a user interface based on a dialog template that contains controls. CEditView allows you to create views with text editing and scrolling capabilities, and also supports printing, find and replace, cut, copy, paste and undo, as well as standard File commands (Open, Save, Save As).

Scrolling and split-pane windows  Derived from CView, the CScrollView class provides documents with built-in scrolling capability, and CSplitterWnd splits Windows into multiple panes.

OLE classes  Three categories of classes are provided to support object linking and embedding (OLE): OLE client classes, OLE server classes and an OLE exception class. These classes greatly simplify the work needed to implement OLE capabilities in an application.

Microsoft Foundation Class 2.0 OLE support is tightly integrated with the document/view and command architectures, so you can easily implement OLE capabilities within objects belonging to the CDocument and CView classes.

The COleClientDoc and COleServerDoc classes allow programmers to create document objects that support OLE client or server capabilities, while inheriting all the features of the CDocument class. The COleServerItem and COleClientItem classes allow you to directly manipulate OLE items and manage either the server or client side of an OLE connection.

Also included is the COleException class, which enables handling of failures that occur during OLE processing. This class can be used by both clients and servers.

Dialog data exchange and validation (DDX/DDV)  Dialog data exchange/validation is a capability that allows data values entered into a dialog by the application user to be automatically validated and assigned to a member variable.

Data from the dialog's member variables can be used to automatically initialize the values of the dialog's control when the dialog is displayed. You no longer have to write code to assign initial values to the controls.

Also, data entered into a dialog by a user can be automatically assigned directly to the dialog's member variables when the dialog exits. You no longer have to write a Get function to get the data and assign it to a variable.

Validating the data input to a dialog control can also be handled automatically. A range of default validations (such as number of characters entered into an edit box) are now performed automatically, and you can add custom validations to build on the existing functionality.

Context-sensitive Help  Microsoft Foundation Class 2.0 provides an architecture that makes it easy to incorporate Help support in applications. Help support includes a Help menu with the standard commands, and a mechanism that maps command or resource IDs to the various help contexts. Help contexts are easily created in Visual C++ because every time a user interface element is created in App Studio, a help context for that element is automatically created. When a user presses the F1 key, Microsoft Foundation Class 2.0 automatically processes the keystroke as a help request for the current command target.

Compiler-independent  Microsoft Foundation Class 2.0 source code is designed to be compiler-independent, enabling Microsoft Foundation Class 2.0 applications to be compiled with other standard C++ compilers. Compiler vendors need only supply a simple version header file (and possibly a version source file), and a project file before Microsoft Foundation Class 2.0 applications can be compiled.

For more detailed information on Microsoft Foundation Class 2.0, see the white paper on this subject.


  Compatibility of Visual C++ with Existing Tools

SDK compatibility  Visual Workbench and App Studio are designed to work with C++ programming as well as with C programming using the Win32 SDK, or the Win32s SDK. Programmers who want to program in C and work entirely within one of the SDKs may do so. The same benefits that Visual Workbench and App Studio offer C++ programmers are also available to C developers.

If desired, programmers can mix and match Microsoft Foundation Class 2.0 code with native Win32 or Win32s SDK calls, which makes it easy to gradually migrate existing SDK-based code to Microsoft Foundation Class.

Since ClassWizard and AppWizard are tightly integrated with Microsoft Foundation Class 2.0, these are not available to SDK programmers.

Microsoft Foundation Class 1.0 compatibility  Projects created with Microsoft Foundation Class 1.0 can easily be converted into the new Visual C++ project format at any time. Any source code written with Microsoft Foundation Class 1.0 can be rebuilt within Visual C++ with no problems. To make Microsoft Foundation Class 1.0 code work with ClassWizard, programmers must add a small amount of code to their source files. This involves placing simple C++ comment delimiters around program statements that ClassWizard will maintain.


  Spy++ Analysis Tool

Spy++ allows a developer to quickly discover a tremendous amount of information about his or her Windows-based application. The display of »window messages« shows decoded parameters as well as return values. Flexible "filters" allow precise control over the messages, windows and other information displayed.

To see Spy++ in action, start it and look at the Window, Process and Thread Tree views. Clicking on a "plus" sign next to a window in the Window Tree view shows its child windows. Double-click on a window name (the green color means that it is a hot-link) and you can open a Window Details view of that window to see detailed information about it. Double-click on the displayed window class to open a Window Class Details view for the class. Go back to the Window Details view and notice that the process and thread for that window are shown. Double-click on each of these to open a Process Details and Thread Details view for them.

Finally, go back to the Window Tree view and find a window for one of your running applications, like Program Manager for instance. Hold the Shift key down and double-click on its window handle and you will open a Message Stream view for that window. Run the mouse over the Program Manager window to generate some messages that will be displayed complete with return values and decoded parameters shown. Use the View menu filter commands to specify the messages, windows to include and output format of the display for the message stream view. If you are unsure of what a specific message is, just double-click on its name in the message stream view and you will get full help on the message and its parameters.


  Technical Support for Developers

Microsoft Product Support Services (PSS) provides support to individuals and organizations through a variety of channels, which are described below.

Microsoft forums on CompuServe  The MSLANG forum is provided via the Microsoft Developer Services Area on CompuServe. This forum provides easily accessible, high-quality developer information through interactive dialog between peer developers and Microsoft developer support engineers. Also offered are developer-specific Microsoft Knowledge Base articles, the Software Library and query menus. A "no charge" area for bug reports and product suggestions is provided.

Microsoft download service  Customers can use their own modems and terminal emulation software to access application notes, printer drivers and technical notes. This service is for downloading only; sending and receiving messages is supported through CompuServe forums. The number for the download service is (206) 936-6735.

Microsoft FastTips  An interactive, automated touch-tone system providing support at no additional charge, via toll lines. It provides fast answers to commonly asked questions, delivered to the customer by phone recording or fax. It also includes a library of technical notes that are available by fax or mail. FastTips is available seven days a week, 24 hours a day, including holidays. The FastTips number for Languages is (206) 635-4694.

Dedicated support numbers  Direct lines to Microsoft product support personnel via toll lines. These support lines are designed to answer set-up, install and general usage questions, and to receive product suggestions and bug reports. Hours for these lines are Monday through Friday, 6:00 a.m. to 6:00 p.m., Pacific time, excluding holidays. The number for Microsoft C/C++ products is (206) 635-7007.

TDD/TT (Text Telephone)  This service enables hearing-impaired users to access the same phone support provided for all Microsoft products and support levels. Access requires a TT modem. Available Monday through Friday,6:00 a.m. to 6:00 p.m., Pacific time, excluding holidays.

Professional support  This service is designed primarily for larger companies seeking priority technical assistance on Microsoft products. Direct contact with senior Microsoft technical engineers is provided, along with guaranteed 24-hour response time, a problem escalation process and other services.

Premier support  The highest level of support, also designed for larger companies. Premier support includes individualized technical consulting, a dedicated technical account manager, access to senior Microsoft technical engineers, a response time of less than four hours and other services.

For details on any of these services, call PSS sales at (800) 227-4679, extension 11700.


  Product Target

Visual C++ 32-bit Edition is designed for experienced C++ programmers who want to create powerful 32-bit applications for either Windows 3.1 using the Win32s API, or Windows NT using the Win32 API. It is the best choice for programmers who want their applications to run on the next generation of 32-bit operating systems. It includes complete software, documentation and extensive sample code on CD-ROM. Printed documentation may also be purchased additionally.

The following table lists the major features of Visual C++ 32-bit Edition

Feature	32-bit Edition
Visual Workbench	•
App Studio, AppWizard, ClassWizard	•
Microsoft Foundation Class 2.0	•
Windows-based application development	•
DLL development for Windows	•
MFC and user guide samples	•
Optimizing compiler	•
Complete Win32 and Win32s SDKs	•
Develop 32-bit Applications for Windows 3.1	•
Develop Applications for Windows NT	•
Source profiler	•
Debugger support for Windows NT Exceptions	•
Debugger support for threads	•
New Spy++ enhanced spy utility	•
Books Online	•


  Availability, Pricing and Requirements

The Visual C++ 32-bit Edition is scheduled to be available August 24, 1993 at a suggested retail price of $599. The system requirements are as follows:

•	An IBM®-compatible personal computer running Windows NT 3.1

•	An Intel® 80386 or higher processor

•	16MB of available RAM (20MB recommended)

•	One CD-ROM drive supported by Windows NT

•	A hard disk with enough disk space to install the options needed. 6MB of available storage space is the minimum requirement to run your installation from the CD-ROM. To install the full configuration of the 32-bit Edition, 80MB of free disk space is required.

•	A VGA (or higher resolution) adapter and monitor

•	A mouse or other pointing device supported by Windows NT


  Appendix B: An Exercise with Visual C++

The exercise in this Appendix gives you a brief tour of some of the components of Microsoft Visual C++. The goal is to demonstrate how quickly you can get started programming for Windows with C++ and Microsoft Foundation Class 2.0. This is not a comprehensive exercise that demonstrates all the features of the product, but is intended to show how Visual C++ allows you to quickly build C++-based applications for the Windows environment.

To perform this exercise, you must first install the Visual C++ 32-bit Edition on your computer.


  Step 1: Create a Skeleton Application

In Program Manager, click the Visual Workbench icon in the Visual C++ group. From the Visual Workbench Project menu, select AppWizard, then enter a project name (for this example use "COOL"). Enter a project directory if you wish to put the project in a different location. You can do this using the directory browser in the dialog.

Click the OK button. You'll be presented with a confirmation dialog that lists the major features of your new COOL application. Click the Create button, and a Visual C++ project will be created for you. This project contains the files and declarations common to every standard Microsoft Foundation Class 2.0 application.

Unlike a code generator or a CASE tool, the skeleton application relies on the reusable code in the Microsoft Foundation Class 2.0 application framework to do most of the work. We'll look at these files in a moment. At this point, you can view the various features for your application using the Options and Classes buttons. Feel free to browse them, but for this exercise we'll demonstrate the power of Microsoft Foundation Class 2.0 and Visual C++ without adjusting them.


  Step 2: Compile the Application

Click the Build button on the Visual Workbench toolbar (the one with the two downward-pointing arrows). While this project is building (it should take about 90 seconds on a standard 486/33-class machine) you can look at the source files in your project. Since Visual C++ allows you to continue editing while building, you don't have to wait for the build to finish.

To view the project source files, click the Project File button (the leftmost button) on the toolbar. Open MAINFRM.H, which contains the declaration for the main window of the application. As you can see, this declaration is just a class derived from the built-in Microsoft Foundation Class 2.0 class CMDIFrameWnd. Also notice the syntax coloring supported by the Visual Workbench editor, which makes your code more readable.

As you scroll downward through the file, you will see that the declaration is commented and documented. The class contains two member variables: one for the application's toolbar and one for its status bar. These variables use the two Microsoft Foundation Class 2.0 classes CToolBar and CStatusBar.

Now open COOL.CPP, which implements the application initialization code. Scrolling downward through the file, look for the InitInstance function which initializes many features of the application. For example, the LoadStdProfileSettings call automatically loads the most recently used file list in the File menu. The OnFileNew call creates an empty document for users of the application. The important point to note here (and in the rest of this exercise) is that there is very little user-written code in this application, despite the large amount of functionality. Most of the statements are simply class declarations and function stubs ¾ all of the reusable code is in the Microsoft Foundation Class 2.0 library.


  Step 3: Execute COOL.EXE

From the Project menu, select the Execute command (or press Ctrl+F5) to run COOL.EXE. Although you've written no code, you have a complete Microsoft Foundation Class 2.0 C++ application for Windows that contains the following features:

•	An MDI application (SDI is optional)

•	A toolbar with buttons that map to the menu commands File New, File Open, File Save, Edit Cut, Edit Copy, Edit Paste, File Print, and Help About

•	A status bar with menu command prompt strings for all commands, and indicators for Num Lock, Scroll Lock and Caps Lock keys

•	File menu commands for New, Open, Close, Save, Save As, Print, Print Preview, Print Setup, recent file list, and Exit

•	Standard dialog support for obtaining file name information from the user (through the Open and Save As commands on the File menu)

•	Standard dialog support for print and print setup

•	Print preview support, including Next/Prev Page, Two Page view, and Zoom In/Out

•	Edit menu hooks for Undo, Cut, Copy, Paste

•	View menu to enable or disable the toolbar and/or status bar

•	Window menu commands New Window (that correctly names each window by appending a numeric index), Cascade, Tile, Arrange Icons, and an active window list

Some of these features require you to write a small amount of additional code before they are fully enabled. For example, select the File Open command and you'll see that it requires you to add a small amount of code to read the data. However, notice that the most recently used list in the File menu is updated, and that multiple MDI child windows are automatically displayed with the correct title as you open files. There is even a default icon for documents when you minimize child windows. All of this functionality is handled by Microsoft Foundation Class 2.0, without requiring you to write any code.

Similarly, the File Save (and Save As) commands create a new file for you, but don't write anything to disk until you add application-specific code (which is added to COOLDOC.CPP's Serialize member function). Also notice that the Edit menu commands (and the accompanying toolbar buttons) are disabled because no code has been written to handle the Clipboard. However, many of these functions are fairly simple to write, and you can have a fully functional basic application for Windows that supports all of the above features with just a small amount additional work.

Now exit the COOL application (be sure to exit COOL by using the File Exit command).


Step 4: Edit COOLs Windows Resources
  Step 4: Edit COOL's Windows Resources

Open the project's resource file by choosing App Studio in the Tools menu. This automatically starts App Studio, the integrated resource editor, and loads the projects resource file (COOL.RC). App Studio is a full-featured resource editor that lets you edit all of the standard resources of Windows 3.1 cursors, icons, bitmaps, accelerator tables, string tables and dialogs.

Select the Icon resource type to display a list of all the icon resources in the COOL project, then double-click the IDR_COOLTYPE icon. This is the icon that is used for minimized MDI documents. The App Studio graphics editor is started, and you can edit the icon any way you like. You might try clicking on a contrasting color and use the Fill Tool (the "paint can") to change the background color.

Now return to Visual Workbench by pressing Alt+Tab, or click on the Visual Workbench window if it is visible.


  Step 5: Add Some Drawing Code

Using the Project File list, open COOLVIEW.CPP, which contains the code for the application's "view." The view is the window that displays the visible portion of the current document.

Scroll down the COOLVIEW.CPP file until you see the OnDraw member function. This function is the abstract device-independent drawing routine used by the framework. Completing this code automatically gives your application support for printing, print preview and standard drawing.

Replace the "TODO" comment with the following lines:

CString str = "Hello World";

pDC->TextOut(20, 20, str);

CString is a dynamic string class in Microsoft Foundation Class 2.0. The parameters to TextOut are the coordinates to draw the string and the string itself.


  Step 6: Use ClassWizard to Connect Messages to Code

Select the ClassWizard item on the Browse menu command (Ctrl+W). This launches ClassWizard, a tool that enables you to connect user interface elements and messages to code, create new C++ visual classes, and manage dialog data exchange and validation (DDX/DDV).

Select the CCoolView class from the Class Name dropdown list, then choose CCoolView from the Object IDs list (this contains all of the various visual objects you can connect).

Select WM_SETCURSOR from the Messages list, which contains all the messages to which you can connect the selected visual object. In this case, CCoolView is a standard window so you see all messages appropriate for a window. If you are not sure what a message does, select the message and press F1 to display context-sensitive help on the message handler in Microsoft Foundation Class 2.0.

Now click Add Function (or double-click WM_SETCURSOR). This creates a new message handler for the message. If you are familiar with Microsoft Foundation Class 1.0, this is equivalent to automatically adding the function to the message map.

Now click Edit Code, and you are taken to the appropriate place in the implementation file to add code for this message. This is very similar to Visual Basic, because you have gone from a message (an event in Visual Basic) to the code that is specialized for your application.

In the source file, replace the "return" statement and TODO comment, with the following two lines:

SetCursor(LoadCursor(NULL, IDC_CROSS));

return TRUE;

Now, whenever the cursor is positioned over one of our views it will appear as a cross hair.

Note how ClassWizard helped you manage your classes from a single location, which makes it easier to visualize your application's classes, the messages they respond to, and the code that handles the messages.


  Step 7: Connect User Interface Elements to Code

Remember that the Edit menu commands were all disabled when you first ran the application because no user code was written to handle the commands, and a default implementation was not provided by the application framework (because the Clipboard is application-specific).

Press Ctrl+W to once again display ClassWizard. Notice that the CCoolView class is already selected, because ClassWizard remembered where you left off. For the object ID, select the ID_EDIT_COPY user interface element. This represents the command for both the menu and the toolbar button. Double-click the COMMAND message to handle the command. ClassWizard suggests a function name, which you can accept. Note that the UPDATE_COMMAND_UI is also sent by the application framework and can be used to dynamically update menu items and/or toolbar buttons (e.g., enable or disable), depending on the state of your application.

Click Edit Code, which takes you directly to the code for handling the message. However, you don't need to add any code, since the framework now knows that your application is handling the message, so it enables the menu command and toolbar button.


  Step 8: Run the Application

Run the application using the Project Execute command (Ctrl+F5). You'll be asked if you want to rebuild the project, so click Yes. Notice that all the files are saved for you, even the resource script, so there's no chance of losing any information.

When the application is displayed, notice that the cursor is a cross hair when positioned over a child window. Minimize a child window to see the new icon.

Notice that the Edit Copy menu item and toolbar button are now enabled, and that the text "Hello World" is in your view. Select Print Preview, which allows you to preview you document before printing. (Depending on the printer you have selected for your machine, you might need to Zoom In on the page to see the text clearly.)  If you like, you can print your document because printing is fully enabled. With almost no effort, full Print Preview and Printing are already implemented for your application, allowing you to focus on more application-specific code. The Microsoft Foundation Class 2.0 Print Preview even maps the system font to an appropriate font on your selected printer.


  Step 9: Continue to Explore

By now, it should be evident how Visual C++ can speed development of applications for the Windows operating system by supplying much of the functionality for you through Microsoft Foundation Class 2.0, and by providing a set of integrated tools that do much of the work for you. Although you've written only a few lines of code, your application has a large amount of ready-to-run functionality.

If you want to continue exploring on your own, you can add a menu item or a  dialog, and explore compiler options (such as RETAIL) to see that the retail version of this application is smaller than 90K, despite the large amount of functionality. For more information on how to do this, see the Visual C++ Class Libraries User's Guide.


  Microsoft Foundation Class Library 2.0

The Microsoft® Foundation Class Library 2.0 (MFC 2.0) is a robust C++ application framework designed for writing applications in C++ for the Microsoft Windows™ and Windows NT™ operating systems. Built upon the core set of functionality in the MFC 1.0 application framework, MFC 2.0 adds an architecture and set of prebuilt components that make it possible to write professional, full-featured applications for Windows in a fraction of the time it would take using C and the SDK or other application frameworks. MFC 2.0 offers a high level of abstraction that lets you focus on the details specific to your application, while allowing its classes to be customized and extended. Like its predecessor, MFC 2.0 also allows access to the native Windows application programming interfaces (APIs) for maximum flexibility and power.

MFC 2.0 makes programming in Windows and C++ a much more productive endeavor. Through its carefully designed architecture, MFC 2.0 provides substantial programming power in an intuitive and uncomplicated package.

MFC 2.0 offers more than 100 reusable C++ classes, including general-purpose classes that support the non-graphical portion of your application, classes for the core Windows graphical user interface (GUI) features, architectural classes to help you organize and structure your application programming and high-level abstractions and canned functionality that provide major building blocks. Rigorous tuning and optimizing of the source code has resulted in very fast execution speeds and small executable sizes that are comparable to C.

The Microsoft Application Framework (AFX) group received a great deal of feedback on MFC 1.0 that was based upon many real-world projects and shipping applications. Microsoft received critical acclaim from both developers and the press, and were generally recognized as the "standard application framework for Windows."  AFX also received hundreds of suggestions and feature requests through CompuServe®, our MSAFX e-mail address and the dozens of conferences and shows where we sent AFX team members to hear from users who had developed mission-critical applications with MFC 1.0. MFC 1.0 was also provided as part of the Windows NT PDK program, which provided additional feedback from the beta developers of Windows NT . MFC 2.0 implemented many of these requested features, and this release of the application framework truly represents the collective wisdom of our user community. The ability to incorporate user feedback is important to the AFX group and will continue to be as we improve MFC for future releases. We also practice what we preach, and the AFX team at Microsoft has been using MFC 2.0 for our products as well. As a case in point, App Studio, AppWizard and ClassWizard were all built using MFC 2.0.

The Microsoft Foundation Classes are appropriately named because they represent the foundation of a class architecture that is constantly evolving to bring developers the best support for the Windows operating system. The class hierarchy, as well as the functionality it encapsulates, has been designed for scalability. Applications written for MFC 1.0 are compatible with MFC 2.0.

MFC applications written for 16 bits using Visual C++ for Windows 3.1 can be recompiled with very minor changes with the Microsoft Visual C++ Development System, 32-bit Edition version 1.0 to run as a full 32-bit program under Windows NT or Windows 3.1 using Win32s™.

This paper provides a technical description of the major features of the Microsoft Foundation Classes version 2.0. MFC 2.0 is integrated with the Microsoft Visual C++™ Development System, 32-bit Edition version 1.0 and, in particular, with App Studio, ClassWizard and AppWizard. Many features of MFC 2.0 are made simpler, less error-prone and more streamlined by using these tools and the Visual C++ integrated development system. The application framework, however, does not require any of the tools; all of the features are accessible to users choosing not to take advantage of the entire family of tools.


  Distinguished Benefits

C++ Windows API  MFC 1.0 introduced a standard application framework interface for programmers using C++ to develop applications for Windows. MFC 2.0 continues this standard. MFC 1.0 applications need only be recompiled to begin taking advantage of MFC 2.0 features.

MFC follows a simple set of conventions that leverage the Windows API; those already familiar with the Windows API are able to look at MFC code and have a clear understanding of the concepts involved. To those that are new to Windows-based programming, this leveraging of the Windows API helps programmers take advantage of the many sources of information available for learning the concepts behind Windows. For example, sample code and concepts from Charles Petzold's Programming Windows can be easily translated to the MFC API. In addition to being able to reuse concepts, MFC lets you easily reuse low-level C code in MFC applications because of these conventions.

MFC provides a comprehensive object-oriented encapsulation of most Windows API functions. Its classes provide support for application start-up, window creation, multiple document interface windows, menus, dialog boxes, controls, list boxes, graphical primitives and so forth.

High-level Abstractions  Many users commented that MFC 1.0 did not contain abstractions that make it easier to write Windows-based applications. MFC 2.0 addresses this by providing high-level abstractions that let programmers concentrate on the real task of the application being written, rather than on mundane Windows-based tasks such as implementing a toolbar. MFC 2.0 provides classes that encapsulate thousands of lines of robust and optimized Windows C++ code. For example, the Print Preview feature, which requires no additional code on the programmer's part, consists of more than 2,000 lines of MFC 2.0 framework code. A programmer wishing to add a toolbar to an application needs to add less than 10 lines of code calling three APIs to exploit more than 1500 lines of MFC 2.0 framework code.

Canned Functionality  MFC 2.0 includes a large amount of prebuilt, canned functionality. The primary benefit of an application framework is the use of professional code written by experienced developers. The C++ programming language, using inheritance, encapsulation and polymorphism, makes it much easier to take advantage of reusable components. MFC 2.0 leverages these features of C++ to provide a body of expertly written, and easily customizable, Windows-based functionality. For example, the standard MFC 2.0 implementation of the File Open command automatically handles all the steps necessary to prompt the user, open a file, read the data, create a window, draw the contents and so on. Programmers only need to provide an implementation of application-specific file I/O and drawing code, and MFC 2.0 does the rest. Perhaps the most important part of MFC 2.0's prebuilt functionality is that it represents an evolved and standard implementation of the recommended techniques for solving common Windows-based programming problems.

Small and Fast Executables  Research shows that the one of the most important concerns of Windows developers is the need for small and fast executables. Because MFC 1.0 was modeled so closely after the Windows API, the size of an MFC 1.0 C++ application was only slightly larger than its equivalent C/SDK application. MFC 2.0 is still the smallest and fastest application framework available for Windows. MFC 2.0 applications are only slightly larger than MFC 1.0 applications (if you recompile MFC 1.0 code and use MFC 2.0 libraries). If an application uses the high-level features and canned functionality of MFC 2.0, it is comparable in size to any other implementation of those same features.


  MFC 2.0 Components

MFC 2.0 encompasses most of the functionality available through the Windows API. Since the nearly 60,000 lines of standard C++ source code for the application framework are included with the product, developers can use the framework in its original form or fully customize it for their own purposes. This source code serves as an example of robust and professional C++ code for Windows. In addition, programmers are able to use this code to learn new implementation techniques and look "under the hood" of MFC. Consistent naming conventions and coding style, along with standalone documentation, make the learning curve minimal. A tutorial is included that steps programmers through development of a substantial C++/MFC program for Windows that incorporates most application framework features. In addition, more than 20 complete sample applications are included that demonstrate the most common uses (and many advanced uses) of the framework.

The application framework divides logically into four components:  general-purpose classes, Windows API classes, application architecture classes and high-level abstractions. General-purpose classes assist the programmer with the lower-level coding tasks such as file manipulation, string processing and building block data structures. Windows API classes provide developers with a complete object-oriented implementation of the GUI portions of the Windows API. The general-purpose and Windows classes were present in MFC 1.0, and have been enhanced for MFC 2.0. A complete class hierarchy diagram is included in this document.

MFC 2.0 introduces application architecture and high-level abstractions. The application architecture classes provide core implementations that are common among standard Windows-based applications, such as documents and views, printing and command processing. The high-level abstractions give programmers optimized and reusable building blocks to speed the development of sophisticated applications. The following sections explore each of these areas in more detail.


  Architecture Classes

A key benefit of an application framework is that it not only provides a large body of prebuilt functionality, but offers an architecture in which to add your own functionality. When you need to implement a feature in your application, an elegant architecture provides you with a logical and obvious location to add your application-specific code. For example, when implementing the File Save command, the application framework should have an obvious technique (a member function, a hook, etc.) to add this functionality. It is not enough, however, to point programmers to the right place, since there is often no single right place, or the application framework could not foresee the exact situation. MFC 2.0 addresses these issues with a group of tightly integrated classes collectively known as the application architecture classes. These classes provide support for the important areas common to many parts of your application such as commands, documents, views, printing, Online help and dialog processing.


  Commands

Menu items, keyboard accelerators and toolbar buttons are the most common sources of commands in an application. A command is an instruction to your program to perform a certain action. Unlike a procedure or function call, a command is a message that is routed to various command targets that may carry out the instruction. Command targets are objects derived from the CCmdTarget class, and include documents, views, windows and the application itself.

The command architecture ensures that any user-interface action, such as clicking a toolbar button or selecting a menu item, will route the command to the appropriate handler. Command routing can also be used to update the visual state of menu items or toolbar buttons. For example, the Edit Cut command might have both a menu item and a toolbar button that can be enabled or disabled. Using the command architecture, it is easy to maintain the visual enabled/disabled state of both the menu item and the toolbar button with a single line of code in a single location.

Another integral part of the MFC architecture is message maps, which were introduced in MFC 1.0 and have been extended in MFC 2.0. A message map provides a typesafe mechanism for directing any windows message, control notification or command to a C++ member function in the appropriate class. Each command target has a message map, and it contains entries that map each command ID defined in App Studio to a C++ member function. Since there can be a large number of commands (as well as Windows messages and notifications) handled by each command target, ClassWizard is usually invoked to manage the creation and maintenance of message maps and message handler functions. ClassWizard can be invoked from either App Studio or the Visual WorkBench.


  Documents and Views

The document/view architecture of MFC 2.0 is the basis for managing the storage and display of application-specific data. The CDocument class provides support for managing your application's data, and an application will typically derive a new class from CDocument for each document type. A CDocument class will add member variables and member functions that allow you to manage application-specific data. The key feature of a document class is its ability to save a document object to a file for later use. The programmer's responsibility is to override the serialize member function, which saves and loads application-specific data to and from storage. By implementing this function, MFC 2.0 automatically supports high-level commands such as File New, File Save, File Save As and File Open. MFC 2.0 does all the work of displaying a dialog to gather information from the user and managing the disk file. Although most documents are typically associated with disk files, the CDocument architecture is flexible enough to allow manipulation of data stored in other ways, such as in a database file, or to allow data manipulation of data without any kind of stored representation.

Each document in a running application is attached to one or more views on that document. Views control the graphical display of your application's data on the screen. Programmers will typically derive a class from the MFC 2.0 CView class, which is itself derived from CWnd, and then implement the display code. A view represents the main area of a window on the screen, and is a simple child window that you can manipulate with CWnd member functions. This usually involves implementation of the OnDraw member function and writing the code that displays the currently visible data to the user. The OnDraw function replaces the low-level OnPaint handler of MFC 1.0 with a high-level abstraction. After implementing OnDraw, your program automatically supports printing and Print Preview. The CView-derived class is usually the best place to handle most of the commands and window messages that graphically manipulate the data. To support high throughput and fast updates, there are a number of APIs that enable optimization of the drawing process to support most professional applications. It is also easy to have many views on the same document, and each view can be a different CView-derived class. For example, a splitter window will have one view for each pane.

To coordinate documents and views, MFC 2.0 uses the helper class CDocTemplate. This class orchestrates the creation of documents, views and frame windows in response to user input. One document template object is created for each document type, and is the glue that connects the document and view types. The application object maintains the document templates. Two MFC 2.0 document template classes are supplied:  one for Multiple Document Interface (MDI) and one for Single Document Interface (SDI). The significant differences between an MDI and SDI user-interface model are encapsulated in the document template and frame window classes.


  Printing

By leveraging the document/view architecture, MFC 2.0 is able to provide an application with device-independent printing. This means that the same code written for OnDraw in the CView-derived class can be used to draw on the screen and printer. When the user asks to print a document using the standard File Print command, MFC 2.0 calls the OnDraw member function with a special device context that is aware of the current printer and knows how to translate your screen display into appropriate printed output. MFC 2.0 also provides support for all the standard printing user-interface dialogs. Full-featured Print Preview is implemented using the printing architecture.


  Dialog Data Exchange and Validation (DDX/DDV)

Through a new capability known as dialog data exchange (DDX), MFC 2.0 provides an easy way to initialize the controls in a dialog box and gather input from the user. An associated mechanism known as dialog data validation (DDV) provides validation of the dialog data. The heart of the DDX/DDV feature is the DoDataExchange member function. This function is called automatically by the application framework. Consider the following short example:

void CMyDialog::DoDataExchange(CDataExchange* pDX)

{

DDX_Check(pDX, IDC_CHECKBOX, m_bUser);

DDX_Text(pDX, IDC_EDIT, m_strName);

DDV_MaxChars(pDX, IDC_EDIT, m_strName, 20);

}

This example shows a data exchange function for a checkbox with a control ID of IDC_CHECKBOX. The state of the checkbox (checked or not) will be stored in a BOOL member variable called m_bUser. This variable is a member of the CMyDialog class, so the dialog is fully encapsulated and easily reused in other parts of the application. The application framework automatically calls DoDataExchange, and DDX_Check transfers the data between the control and the member variable. The example also shows a data exchange entry and a validation entry for a string variable. The DDX_Text function is automatically called to transfer data between a CString member variable called m_strName and the edit control in the dialog box. The DDV_MaxChars function is called to validate that the data entered by the user into the edit control does not exceed 20 characters. If the entry is invalid, the application framework automatically displays a message box informing the user of the error and returns the input focus to the edit control.

Because there are so many possibilities for exchange and validation (e.g., the use of custom controls or application-specific validation schemes), Microsoft made the DDX/DDV architecture fully extensible. You can supply your own DDX and DDV functions and integrate them seamlessly with MFC 2.0. The DDX/DDV architecture supports data types and Windows controls and includes a number of prebuilt DDX/DDV routines. Standard support for data types includes 16-bit integers (signed and unsigned), 32-bit integers (signed and unsigned) and strings (raw and formatted). DDX/DDV supports all the standard Windows controls, including checkboxes, radio groups, list boxes and combo boxes. Built-in DDV support is provided for maximum string length and ranges of integers.

The DDX/DDV architecture is tightly integrated with ClassWizard, which enables you to define all necessary member variables and DDX/DDV routines without having to write any code. Of course, ClassWizard is only a tool, and it follows the logical steps you would normally take by directly editing the source code. ClassWizard, however, is generally faster than manual file editing and is also less error prone.


  Help

Support for online and context-sensitive documentation is essential for most applications. MFC 2.0 provides an architecture that makes it easy to incorporate the two most common types of help support in applications for Windows. Help support includes a Help menu with the standard commands, and provides an architecture for the application framework to map from command or resource IDs to the various help contexts. Help contexts are easily created in Visual C++ since every time a user-interface element is created in App Studio, a help context for that element is automatically created. Help files (.HLP) are authored using standard authoring tools.

When a user presses the F1 key, MFC 2.0 automatically processes the keystroke as a help request for the current command target. For example, the CDialog class processes the help request by invoking WinHelp on the help topic for the currently displayed dialog. If no help context is defined for the current command target, then the application framework automatically launches the default help. The CFrameWnd, CMDIFrameWnd and CDialog classes all provide handler functions for help support. You can add support to any class that is a command target.

When a user presses SHIFT+F1, MFC 2.0 captures the mouse and changes the cursor into the standard context-sensitive help cursor (arrow+question mark). With this cursor displayed, clicking on a user-interface object tells the application framework to invoke WinHelp with the correct help context based on the selected object.

MFC 2.0 provides a tool to manage the help context information, which associates user-interface elements with help contexts. In addition, AppWizard provides much of the standard WinHelp format file with pre-written information on all of the standard commands. All that is needed is an editor capable of editing rich text format (RTF) text, such as Microsoft Word, to add application-specific information. Therefore, the combination of MFC 2.0, AppWizard and App Studio works together to provide programmers with most of their application's help features automatically.


  High-level Abstractions

MFC 1.0 was the cornerstone of a robust framework for building reusable classes, but it did not provide enough high-level abstractions to reduce programming time. MFC 2.0 addresses this with a set of classes that supports the most common user-interface idioms and provides capabilities for taking advantage of other prebuilt functionality. These classes, collectively called the high-level abstractions, are designed to be used as supplied by MFC 2.0 and can result in a dramatic reduction in programming time. In a few lines of code, programmers can build a text processing window that integrates seamlessly with other MDI windows, or change the base class to turn a view into a scrolling view. In addition to this power, all of these high-level classes are designed to be easily modified using C++ inheritance.


  Form View

One of the most common types of Windows-based applications is form processing. A form is like a dialog that the user can interact with to fill in edit controls, select options from listboxes and radio groups, as well as work with other dialog controls. For example, an order/entry database application would probably use forms to allow customer service representatives to enter order information.

The problem is that the Windows dialog manager does not support much of what true form processing applications require, such as scrolling, multiple forms for the same data, synchronous update and printing. MFC 2.0 enhances this model with the CFormView class. A CFormView provides a view (a class derived from CView) based on a dialog resource you edit with App Studio. You can use this view to create form views containing arbitrary Windows controls. The user can scroll the form view and tab among controls. The benefit of CFormView over standard dialogs is that CFormView objects integrate with the entire application framework architecture, so you get automatic support for command handling and document management. A form view can also be an MDI child window.


  Edit View

A number of MFC 1.0 users requested that MFC 2.0 provide an abstraction that makes it easy to create a simple text editor. MFC 2.0 responded to that request by introducing the CEditView class. CEditView is like the low-level CEdit class since it provides the functionality of the standard Windows edit control. In addition, however, CEditView supports high-level functionality such as printing, Find and Replace, Cut, Copy, Paste and Undo, as well as the standard File commands (Open, Save, Save As). Of course, since CEditView is derived from CView, all of the architectural benefits described above apply. The sample program discussed later in this document shows the power of the CEditView; by simply creating a document template that uses CEditView, without even the need to derive your own view class, an application can have an MDI text editor.


  Scrolling View

Most applications can only show a portion of their data files on the screen at a single time. The CScrollView class, which is another high-level view class derived from CView, supports views that scroll and views that are automatically scaled to the size of the frame window that displays them. By deriving from CScrollView, you can add the ability to scroll or scale to your view class. CScrollView manages window sizes and mapping mode for graphics, and scrolls automatically in response to user-interface actions, such as clicking on the scroll bar. It is also possible to specify that you require all of your data to fit within the frame window, in which case the CScrollView will stretch or shrink the logical view to fit within the main drawing area of the window.


  Splitter Window

In a splitter window, the window can be split into two or more separately scrollable panes. A splitter control in the window frame next to the scroll bars allows the user to adjust the relative sizes of the panes. Each pane is a different view on the same document. This type of user interface is useful, for example, when a user wishes to view both the beginning and end of a very long document on a single screen. MFC 2.0 provides the high-level class CSplitterWnd to support this user-interface model. The CSplitterWnd class also supports the two most common types of splitters:  dynamic and static. With dynamic splitters the user can add or remove arbitrary split panes, while static splitters have a predefined number of panes. Each of the splitter pane's views can be the same class, or each can be a different derived CView class. In all cases, the application framework automatically manages all aspects of the user interface and standard commands.


  Print Preview

In combination with the printing and document/view architectures, MFC 2.0 supports print preview functionality. Print Preview shows a reduced image of either one or two pages of a document as they would appear when printed on the currently selected printer. The implementation provides the standard user interface for navigating between pages, toggling between one- and two-page viewing, as well as zooming the display in and out to different levels of magnification. The ability to support Print Preview is a true measure of the amount of prebuilt functionality and high-level of abstraction in MFC 2.0. The Print Preview feature represents several thousand lines of code in the application framework, but programmers only need to handle the display output code in the OnDraw member function of class CView and make sure that the File Print Preview menu command is available — the framework does the rest.


  Toolbar

One of the most commonly requested user-interface elements is the toolbar. A toolbar is a row of buttons represented by bitmaps and optional separators. These bitmap buttons can behave like push buttons, checkbox buttons or radio group buttons. The MFC 2.0 class CToolBar supports the recommended standard toolbar look and feel. All the toolbar buttons are normally taken from a single bitmap image, which is edited using App Studio, and contains one image for each button. One of the key advantages of the MFC 2.0 CToolBar implementation is that by using commands, the various buttons in the toolbar can be enabled and disabled in conjunction with any menu items for those same commands. This is important because toolbar buttons almost always duplicate menu items, as is recommended in the Windows Application Design Guide. If you require additional standard Windows controls on the toolbar, such as drop-down listboxes or edit controls, the CToolBar class can easily support them. In addition, CToolBar provides programmatic APIs for dynamically changing the buttons on the toolbar for highly customized user interfaces.


  Status Bar

The CStatusBar class implements a row of text output panes, or indicators. The output panes are commonly used as message lines and status indicators. Examples include the menu help-message lines that briefly describe the selected menu command and the indicators for the keyboard states of Num Lock, Scroll Lock and Caps Lock. The CStatusBar class supports any number of panes and automatically lays them out based on the width of the contents. Each pane can have a customized style, including 3-D borders, pop-out text, disabled and stretchy. The MFC 2.0 command architecture supports automatic menu prompt strings, and when using App Studio to edit menus for MFC 2.0 applications, you can also define the prompt string for the menu item. The standard status bar code that is output by AppWizard in new applications supports the Windows Application Design Guide recommendations.


  Dialog Bar and Control Bar

The CDialogBar class is like a modeless dialog in that it easily supports any combination of Windows controls and is created from a dialog template edited by App Studio. Dialog bars support tabbing among controls and can be aligned to the top, bottom, left or right edge of the enclosing frame window. The most common example of a dialog bar is the Print Preview user interface.

CToolBar, CStatusBar and CDialogBar all derive from the common base class CControlBar. The CControlBar abstraction enables the MFC 2.0 implementation to reuse code among these classes. CControlBar provides the functionality for automatic layout within the parent frame window of the derived classes. CControlBar demonstrates the power of a base class that provides a partial implementation that is completed in a series of closely related derived classes.


  OLE 1.0 Support

MFC 2.0 provides nine classes that support Object Linking and Embedding (OLE) 1.0. These classes build upon the support in MFC 1.0, making it even easier to build applications that support OLE. MFC support for OLE includes classes for implementing a client, implementing a server and several helper classes, as well as most of the standard dialogs and menu items. The main benefit of the OLE support is its integration with the document/view and command architectures, which smoothes the transition to an OLE application. Checking the OLE Client support option in AppWizard provides an excellent start with OLE because it automatically enables an application to act as an OLE client. In the future, MFC will provide support for OLE 2.0, so using the OLE 1.0 support today will make the transition to the new OLE 2.0 paradigm much easier.


  Windows API Classes

MFC 2.0 provides classes that simplify programming for Windows while at the same time permitting application developers to leverage both existing Windows code and programming experience. For the inexperienced programmer of Windows-based applications, the Microsoft Foundation Classes simplify programming for Windows by providing canned functionality for many standard Windows-based programming idioms. These classes have evolved from the MFC 1.0 implementation, but backward compatibility has been maintained. Developers with MFC 1.0 applications need only recompile their application to begin using MFC 2.0. A brief technical note provided with Visual C++ describes the few minor changes that must be made to the application's source code.


  Standard Application Support

MFC encapsulates the standard application structure in an easily customizable application object. In addition to standard initialization, message processing and termination, the CWinApp class supports idle time processing of user-defined operations. The scope of the CWinApp class has been expanded in MFC 2.0 to include support for profile settings, context-sensitive help, File Manager drag and drop, shell registration for launching the application from File Manager and other user-interface features. The CWinApp class frees the programmer from the details of the WinMain, LibMain and WEP routines, and provides a standard abstraction across Windows platforms.


  Frame Windows

Along with an application object, most programs use a standard frame window. MFC 2.0 provides support for both the single-document interface and the multiple document-interface (MDI). The CMDIFrameWnd and CMDIChildWnd structure of MFC 1.0 has been maintained. In MFC 2.0, however, many of the common MDI commands and user-interface functionality, such as changing the menu bar that is based on the active window, are now provided as canned functionality by the framework. In addition, error-prone areas of Windows-based programming, such as keyboard accelerators and implementation of default behavior, are handled in a seamless manner by the application framework. Frame windows are managed by the document template class in applications that take advantage of the document/view architecture. A view is contained within a frame window (usually a CFrameWnd or a CMDIChildWnd).


  Controls

Controls are windows that are drawn in the client area of frame windows, or as controls in a dialog box. MFC 2.0 provides classes for all of the standard controls: static text, buttons, edit control, list boxes, combo boxes, scroll bars, handwriting controls and user-defined child windows. MFC 2.0 makes it easy to derive your own child windows (including deriving from the standard Windows controls) and to customize their behavior using C++ inheritance and message maps. MFC 2.0 has also enhanced the CBitmapButton class introduced in MFC 1.0.


  Graphics/GDI

The MFC 1.0 device context class, CDC, provided a simple Windows API wrapper. MFC 2.0 extends the DCC implementation to allow polymorphic implementations of device context output functions. This enables a virtual display context that allows MFC 2.0 applications to use the same drawing code to send output to the screen, a printer, a metafile or a Print Preview view. MFC 2.0 provides a complete set of classes for drawing graphical objects and managing device contexts. These graphical object classes include all of the standard Windows objects, including pens, brushes, bitmaps, fonts, regions and palettes. Several device context classes are also supplied to make the handling of common idioms (such as window repainting) simple and less error prone. The graphical objects are designed to automatically free system resources when they are no longer needed, which simplifies common object-ownership problems and enables an application to run safely in a resource-constrained environment.


  Dialogs

MFC 2.0 makes it even easier to use dialogs within an application. The application framework manages many of the intricate Windows operating system-oriented details of dialogs automatically, including the handling of dialog-specific messages. Dialogs are handled with the CDialog class, which supports both modal and modeless dialogs. Programmers simply derive from a dialog class and customize it by overriding member functions and message handlers. This customization model is exactly like every other CWnd-derived class, which provides good programming consistency.


  General-purpose Classes

The general-purpose classes provide programmers with a wide range of functionality designed to take advantage of the powerful features of C++. These classes are available for programmers to develop the non-graphical portion of the application. In many respects, the general-purpose classes, together with the Windows API classes, are the building blocks for the entire application framework and provide fundamental functionality to those classes as well as programmer-defined classes.


  Run-time Object-type Information

Most MFC classes are derived, either directly or indirectly, from the class CObject, which provides the most basic object-oriented features of the framework. CObject supports dynamic type checking, which allows the type of an object to be queried at run time. This feature provides programmers with a type-safe means to cast down a pointer from a base class to a derived class. Without dynamic type checking, this cast can be a source of errors and can break the type safety of C++. Most programmers find this feature useful, but since it incurs a very small runtime overhead (approximately 24 bytes per class) its use is optional.


  Object Persistence

Persistence is the ability of any object to save its state to a persistent storage medium such as a disk. For example, if a collection is made persistent, then all members of that collection are made persistent. The CArchive class is used to support object persistence and allows type-safe retrieval of object data. To use persistence, a class implementor must override the Serialize member function, call the base class's Serialize function, and then implement the data storage routines for member data that is specific to a derived class. Entire networks of objects, with references to other objects, including both multiple and circular references, can be saved with a single line of code. As with dynamic type checking, the use of persistence is optional.


  Data Structures

The efficiency of standard data structures is an area in which MFC 2.0 excels. The provided collection classes, a standard component of any C++ class library, are well-tested, well-coded and highly reusable. The MFC collection classes include double-linked list classes, map (dictionary) classes and dynamic (growable) array classes. All of these have been implemented using the proposed ANSI template syntax for type-safe usage. For example, the list class is supplied with variants supporting UINT, BYTE, WORD, DWORD, void*, CObject* and CString elements. The map and array classes have similar sets of variants. In all, MFC 2.0 supplies 17 collection classes. For users who wish to take advantage of the template syntax to generate a type-safe variant of a supplied implementation (or write their own template), a template expansion tool written using MFC 2.0 is provided as a sample application.


  Strings

The CString class supports a very fast string implementation that is compatible with standard C "char*" pointers. This class allows strings to be manipulated with syntax similar to the Basic language that includes concatenation operators and functions such as Mid, Left and Right. CString also provides its own memory management, freeing the programmer from allocating and freeing string memory.


  Files

MFC 2.0 offers three file classes:  CFile and its two derived classes, CStdioFile and CMemFile. CFile supports low-level binary file I/O (read, write, seek). CStdioFile provides buffered file I/O similar to the standard I/O run-time libraries. CMemFile supports file semantics in RAM-resident files for managing clipboard data as well as other forms of interapplication communication. The polymorphism provided by the three file classes (CFile, CStdioFile and CMemFile) allows the same code to be used for sending data to a variety of destinations using the CFile interface. MFC 2.0 has added support for reading and writing huge data blocks greater than 64K.


  Time and Date

In addition to the standard time and date functions, a class is provided to conveniently support time and date arithmetic using overloaded operators. Binary time values are automatically formatted into human readable form.


  Exception Handling

MFC 2.0 supports a robust exception-handling mechanism that is upwardly compatible with the proposed ANSI try/throw/catch standard. The CException class (including several derived classes) provides exception-specific support for memory, archiving, filing, resource and other exceptions. Rather than using return codes that are often overlooked and result in inefficient code, the exception syntax is a clean and efficient mechanism for handling fatal conditions.


  Debugging and Diagnostic Support

An area overlooked by many class libraries is the inclusion of sophisticated diagnostic and debugging facilities. Incorporated directly into the fabric of MFC 2.0 is a backbone of diagnostic code that is supported in the debug version of the framework. Applications written with MFC 2.0 and compiled for debugging can be up to twice as large as their non-debug counterparts — an indication of the extensive diagnostic support within the application framework.

Programmers can add debug code anywhere in an application that will print out all currently allocated heap objects. This capability is invaluable for the detection of serious memory leaks that are often impossible to track by other means. A memory leak is a slow depletion of system resources that can go undetected for several days until all resources are consumed. For all heap-allocated objects, a record is kept of the size, source file and line number of the allocation. After a debug version of an MFC 2.0 application terminates, the application framework automatically displays all heap objects the programmer failed to free.

Other debug support includes functions that are able to validate any pointer and determine if it refers to a genuine C++ CObject-derived object. Other facilities provided by the framework are run-time assertions and class invariants, which were popularized by the Eiffel programming language. Every class in MFC 2.0 implements a member function that checks the current state of the object and causes a debug assert if the object is not in a proper state. Library member functions validate parameters to functions in the debug version of the framework.

There are more than 2,300 ASSERT statements within the implementation of MFC 2.0, each of which checks the condition of the internal state of a class or parameters passed into an API. If a programmer erroneously causes the application framework to enter an unpredictable state, the application will immediately break into the debugger (if it is running) or an alerting message box will be displayed. ASSERT statements catch errors much earlier and can save hours of development time. All major Microsoft applications use assertion statements extensively. In the release (non-debug) version of an MFC application, ASSERT statements are not executed and generate no code. They are designed for testing purposes only and thus incur no cost to the application's end users. The ASSERT mechanism is provided for users of MFC as well, and programmers are encouraged to take advantage of it within their own code.

MFC 2.0 also provides TRACE statements, which are formatted information messages. As with ASSERT statements, TRACE statements are executed only in the debug version of an application. The TRACE statements in the application framework display possible misuse of a feature, low memory conditions, rarely executed boundary conditions, and full message and command tracing. Since the output can be verbose (there are nearly 300 TRACE statements in MFC 2.0), it is easy to select which categories of messages are reported using the TRACER.EXE application. For example, if you are only interested in information about OLE, you can filter out all the other TRACE output. The TRACE facility can also be used by programmers within their own code.


  Professional Windows-based Development

MFC 2.0 takes into account the needs of engineers developing large-scale professional applications for Windows.

Much effort has gone into optimizing the code size of executables and keeping them as small as possible. A combination of the advanced features of the Microsoft C++ compiler/linker (such as function-level linking) and the module granularity of MFC 2.0 reduce the size of MFC applications.

The Microsoft Foundation Classes use C++ idioms in the commonly accepted manner and do not overlook advanced issues such as copy construction, assignment operators and correct object destruction. These issues are a common source of errors in user code, and can be difficult to track down. MFC 2.0 code serves as an example of both professional C++ code and professional Windows code.


  Sample Program: MultiPad

In the following pages, a sample application using MFC 2.0 is demonstrated. The purpose is to show the power and simplicity of the framework's architecture and implementation. The application is a simple MDI text editor, similar to the MultiPad sample application shipped with the Windows SDK. MFC 1.0 also supplied a similar sample application.

This example is not designed to cover every aspect of MFC 2.0 nor is it designed to make you an expert in all the features of MFC 2.0. The intent is to illustrate the powers of the MFC 2.0 architecture, and to show how useful the high-level abstractions can be for quickly implementing large amounts of functionality. This example originated as an AppWizard-created application, but has been merged into a single source file in order to serve better as an example.

1.	// MultiPad : Simple MDI text editor written using MFC 2.0

2.	/////////////////////////////////////////////////////////////////////////////

3.	// Interface

4.	#include <afxwin.h> 	// MFC core and standard components

5.	#include <afxext.h>	// MFC high-level abstractions

6.	#include "resource.h"	// Resource symbols

7.	class CMultiPadApp : public CWinApp

8.	{

9.	virtual BOOL InitInstance();

10.	afx_msg void OnAppAbout();

11.	DECLARE_MESSAGE_MAP()

12.	};

13.	class CMainFrame : public CMDIFrameWnd

14.	{

15.	CStatusBar  m_StatusBar;

16.	CToolBar    m_ToolBar;

17.	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

18.	DECLARE_MESSAGE_MAP()

19.	DECLARE_DYNCREATE(CMainFrame)

20.	};

21.	class CPadDoc : public CDocument

22.	{

23.	virtual void Serialize(CArchive& ar);

24.	DECLARE_DYNCREATE(CPadDoc)

25.	};

26.	/////////////////////////////////////////////////////////////////////////////

27.	// Implementation

28.	CMultiPadApp NEAR theApp;	// define a single application object

29.	BEGIN_MESSAGE_MAP(CMultiPadApp, CWinApp)

30.	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

31.	ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)     // file commands...

32.	ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

33.	ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)

34.	END_MESSAGE_MAP()

35.	BOOL CMultiPadApp::InitInstance()

36.	{

37.	SetDialogBkColor();

38.	LoadStdProfileSettings();

39.	AddDocTemplate(new CMultiDocTemplate(IDR_TEXTTYPE,

40.	RUN-TIME_CLASS(CPadDoc), RUN-TIME_CLASS(CMDIChildWnd),

41.	RUN-TIME_CLASS(CEditView)));

42.	m_pMainWnd = new CMainFrame;

43.	((CFrameWnd*)m_pMainWnd)->LoadFrame(IDR_MAINFRAME);

44.	m_pMainWnd->DragAcceptFiles();

45.	EnableShellOpen();

46.	RegisterShellFileTypes();

47.	m_pMainWnd->ShowWindow(m_nCmdShow);

48.	if (m_lpCmdLine[0] == 0)

49.	OnFileNew();

50.	else

51.	OpenDocumentFile(m_lpCmdLine);

52.	return TRUE;

53.	}

54.	void CMultiPadApp::OnAppAbout()

55.	{

56.	CDialog about(IDD_ABOUTBOX)

57.	about.DoModal();

58.	}

59.	IMPLEMENT_DYNCREATE(CMainFrame, CMDIFrameWnd)

60.	BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)

61.	ON_WM_CREATE()

62.	END_MESSAGE_MAP()

63.	static UINT buttons[] =

64.	{

65.	ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_SAVE, ID_SEPARATOR,

66.	ID_EDIT_CUT, ID_EDIT_COPY, ID_EDIT_PASTE, ID_SEPARATOR,

67.	ID_FILE_PRINT, ID_APP_ABOUT

68.	};

69.	static UINT indicators[] =

70.	{

71.	ID_SEPARATOR, ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL

72.	};

73.	int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

74.	{

75.	CMDIFrameWnd::OnCreate(lpCreateStruct);

76.	return ((m_ToolBar.Create(this) &&

77.	m_ToolBar.LoadBitmap(IDR_MAINFRAME) &&

78.	m_ToolBar.SetButtons(buttons, sizeof(buttons)/sizeof(UINT)) &&

79.	m_StatusBar.Create(this) &&

80.	m_StatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))

81.	  	? 0 : -1);

82.	}

83.	IMPLEMENT_DYNCREATE(CPadDoc, CDocument)

84.	void CPadDoc::Serialize(CArchive& ar)

85.	{

86.	((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);

87.	}

The following is a description of the major program elements of the MultiPad application.

Lines 1-6  These include the standard MFC 2.0 header files. The file RESOURCE.H, which isn't shown here, contains the symbol definitions for the commands and user-interface elements; it is usually edited only by App Studio.

Lines 7-12  Every MFC application must declare a class derived from CWinApp. The CWinApp class encapsulates much of the mundane work normally associated with getting an application started and running. There are overridable member functions for initialization, message-loop processing, idle-loop processing, as well as support for File Manager drag and drop, Shell registration, and most recently used file list management. In this example, we override InitInstance to perform some one-time initialization. Since a CWinApp-derived class is a command target, there is also a message map for this class. The OnAppAbout command handler is used for the About box. Lines 10 and 11 are usually maintained by ClassWizard, so this is code you do not normally write manually.

Lines 13-20:  CMainFrame is a class derived from the MFC 2.0 class CMDIFrameWnd, which provides support for MDI window management. The CMainFrame class adds two member variables for the toolbar and status bar, each of which is one of MFC 2.0's high-level abstractions. Lines 17-19 are usually maintained by ClassWizard and indicate that the class has a message map that will handle the OnCreate message (WM_CREATE). The DECLARE_DYNAMIC macro allows the application framework to dynamically create the frame window.

Lines 21-25  MultiPad manages documents that are merely standard text files. The CPadDoc class is needed to implement the Serialize overridable member function. Serialize is called automatically by the application framework in response to File Open, File Save and File SaveAs commands.

Line 28  By declaring a CMultiPadApp class object, the constructor for that object will be invoked at program start-up. Every MFC application must define a single application object that replaces the normal WinMain functionality. When the program starts, MFC 2.0 automatically calls the initialization functions, and if they are successful, the framework's message loop will be run. When the user executes the File Exit command, the application terminates.

Lines 29-34  These lines implement the message map for the CMultiPadApp. Each one is a command handler and each handles one of MFC 2.0's standard commands. If you are familiar with MFC 1.0, you will notice that the message-map structure is unchanged. Further down in the code is a definition for the OnAppAbout member function, which is called when the user executes the Help About command. The three other commands are all implemented using the canned implementation, which is why there are references to the application framework class CWinApp. These message map entries implement the File New, File Open and File Print Setup commands. Although these entries could automatically be supplied for all applications, MFC 2.0 requires that you pay only for functionality that you use. For example, if an application does not support printing, then MFC 2.0 does not force the application to link in all of its printing code. MFC 2.0 follows this swap-tuning practice frequently. Rather than having large executables, MFC 2.0 allows programmers to add a single line of code that enables the canned library implementation.

Lines 35-36  The InitInstance function is actually the bulk of the code that needs to be written to implement the application. This function is called automatically by MFC 2.0 when the application starts.

Line 37  MFC 1.0 supported new look gray-colored dialog boxes by default. However, a number of users commented that they would prefer a single function that lets them choose the background color of dialogs. MFC 2.0 therefore added the SetDialogBkColor function for that purpose. The default arguments, which are not shown, set the dialog background and text colors to the MFC 1.0 values.

Line 38  The LoadStdProfileSettings function loads the user's preferences from the MULTIPAD.INI file stored in the user's Windows directory, that is the preferred mechanism for saving profile settings. If an application has other settings which should be restored, then InitInstance is the best place to restore them, along with the standard MFC 2.0 settings. The standard profile settings include the most recently used file list in the File menu, and some print preview information. This API is an example of how MFC 2.0 provides prebuilt functionality that a program does not need to pay for if it does not use the feature. If an application does not need the profile settings, then omitting this line will not require the application to maintain an .INI file, and leaves the MFC 2.0 code that implements the feature out of the final executable.

Lines 39-41  In order to use the document/view architecture, it is necessary to create a document template for each document type, which is done by calling the AddDocTemplate API. The document template orchestrates the creation of the document, view and frame window. Since this is an MDI application, the CMultiDocTemplate class is used. Also, since the document template needs to be used after InitInstance, it is allocated on the heap using the C++ new operator. MFC 2.0 automatically frees the memory associated with the document template. The constructor for CMultiDocTemplate requires four parameters. The first parameter is the ID of a string resource that contains several strings, including the default window title, the description of the document type and the strings needed by the standard file dialog. Each of the other three arguments is a run-time class, which gives the application framework enough information to create objects of the given type. The second argument is the run-time class of the document type, which in this program is CPadDoc. The third argument is the run-time class of the frame window to be used for this application. Since this is an MDI application, the CMDIChildWnd class is used directly. The frame window can also be an SDI frame or it can be any class derived from CFrameWnd. The fourth argument is the name of the view class. MultiPad requires a view that can draw and edit text, manage the clipboard, and implement find/replace and printing. MFC 2.0 provides this canned functionality in the high-level abstraction class CEditView. The programmer only needs to pass the run-time class for CEditView to the document template and the application will use the built-in MFC 2.0 class with the document class. For more specialized applications one can supply any CView-derived class to the document template.

Lines 42-43  The next step in initializing the application is to create an application window. (The allocation of the application window was declared previously in lines 13-20). The LoadFrame API creates the application window and integrates it with the application framework architecture. For example, the API assigns a help context to the window, and loads the appropriate icon, accelerator table and menu from the resources in the executable file. The cast is required because the m_pMainWnd member variable in the CWinApp class is a CWnd pointer and CMDIFrameWnd is derived from that class. The application framework is flexible in allowing any window such as a dialog to be the application window.

Lines 44-46  In order to support the File Manager drag and drop and the File Manager Open and Print commands, these three lines are required. Adding these three lines enables these features for applications that require them, and eliminates the need to add a larger amount of code and a separate registration file (.REG file). In fact, if a document extension is specified when creating an MFC 2.0 application with AppWizard, these lines are automatically placed in the application's InitInstance, as they are in this example.

Lines 47-53  At this point, the application only needs to process the command line. If a file name is present on the command line, the OnFileOpen command handler is called directly; otherwise the OnFileNew handler is called to display a blank "Untitled" window. These functions are implemented in the application framework. In line 47, the ShowWindow API is called to display the application window. As with MFC 1.0, any MFC 2.0 API that is implemented as a direct call to the Windows API, such as ShowWindow, is named the same as the corresponding Windows API. Returning TRUE from InitInstance indicates that the initialization was successful.

Lines 54-58  The OnAppAbout command handler demonstrates how easy it is to bring up a modal dialog in MFC 2.0. The constructor for CDialog requires the ID of the dialog resource, which is created and edited with App Studio. The DoModal call creates the dialog and processes messages until the end user clicks OK.

Lines 59-62  These lines create the message map for the application window. Although MFC 1.0 message maps were edited by hand, MFC 2.0 includes ClassWizard, which maintains message maps automatically. Of course, you are still free to use a standard text editor to manage message maps, as the syntax is unchanged.

Lines 63-72  The toolbar and status bar both require command IDs for the commands that these user-interface abstractions handle. The commands are defined in a simple array of integers. For a toolbar, the array implements one-to-one mapping based on the positions of the button tiles in the toolbar bitmap, which is edited within App Studio. For status bars, the array implements a one-to-one mapping based on the indicator fields of the status bar. Separator entries in either array indicate buttons or indicators that will be skipped.

Lines 73-82  The OnCreate message handler is called in response to the LoadFrame call. OnCreate is the first message a window receives, and is usually the best place to implement one-time initialization of a window. Notice that instead of having to parse wParam and lParam, as is required in C code, the message was mapped directly to a C++ member function. The OnCreate interface provides type-safety and recompile-only portability to Windows NT and Win32s™, where a number of messages have changed their wParam and lParam encoding. For the application window, the toolbar and status bar need to be created. First, the base class OnCreate function is called, which is an MFC convention, and then several CToolBar member functions are called. Next, the toolbar is created, the bitmap resource is loaded from the executable, and the buttons are hooked to the commands using the array defined above. This example shows the buttons defined at program initialization, but it is just as easy to alter the buttons programmatically for a fully end-user customizable user interface. The status bar is handled in two steps:  First it is created, and then the indicators are set using the commands in the array defined above. Should any of these calls fail (for example, if there are not enough system resources to load the bitmap) then the OnCreate function will fail and the application will not run.

Line 83  The IMPLEMENT_DYNCREATE macro initializes the data structure required by the run-time class mechanism. There will be such a line for each class that maintains run-time type information.

Lines 84-87  In order to read and write the text data of a CPadDoc document, it is necessary to override the Serialize member function. The CEditView class provides an interface that reads and writes the data in the view, so calling the view's Serialize member function is all that is required. As previously mentioned, a document can have any number of views attached to it, which is why there is a reference to the list of views, m_viewList. This line simply gets the first view, which is known to be a CEditView, and calls the CEditView API that reads and writes the text of the file in a raw (unmodified) format.

A screen image of the running application is shown in »this figure«. Although it shows a number of useful features, it is difficult to capture them all on one screen. MFC 2.0 MultiPad implements the following menu commands: File (New, Open, Close, Save, SaveAs, Print, Print Setup, Exit and four most recently opened files); Edit (Undo, Cut, Copy, Paste, Delete, Find, Find Next, Replace, Select All, View) (toolbar and status bar); Window (Cascade, Tile, Arrange Icons and an MDI child window list); and Help (About). There are toolbar buttons for File New, File Open, File Save, Edit Cut, Edit Copy, Edit Paste, File Print and Help About. The status bar has indicators for the prompt string of the currently selected menu item (or Ready if no menu is selected), Num Lock, Caps Lock and Scroll Lock. MultiPad supports opening files from the File Manager by double clicking on any .TXT file. From the File Manager, any .TXT file can be dragged onto MultiPad and it will automatically be opened. The application also follows standard MDI window management and has the appropriate title bars and minimized/maximized behavior.

Looking at this example program, which contains only 87 lines, there are a number of key points to notice beyond the features.

First, the application is standard C++ and makes use of the standard Windows APIs where appropriate. The code contains no language extensions and can compile with any standard C++ compiler for Windows. This example application only required one call to a Windows API that is wrapped by an MFC 2.0 class (this is the same function as in MFC 1.0). In general, MFC 2.0 will have fewer calls to these wrapped functions because of the higher level of abstraction. On the other hand, when a programmer requires direct access to the Windows API, MFC 2.0 is designed to facilitate that as well.

Several times in this example we took advantage of the canned functionality within the MFC 2.0 application framework. The functionality is a robust, small and fast implementation of standard programming paradigms for Windows. These features exist for two reasons: First, they save programmers time and effort; second, they show programmers the standard way of implementing a Windows user-interface idiom. For example, the OnFileOpen command handler prompts the user with a standard File Open dialog, selects files of the appropriate type, validates the existence of the file, opens the file, reads the data into the document object, creates a frame window, sets the title of the window using the Windows standard, and resets the menu bar as appropriate for the particular document. If programmers need to customize any of this functionality, they only need to override a function. Since MFC 2.0 source code is included and serves as an example of a correct implementation, programmers have  all the information needed to implement any user-interface paradigm required by an application.

MFC 1.0 was often categorized as being a thin veneer or a literal wrapping of the Windows API. This was true, because the goals of MFC 1.0 were such that providing something close to the Windows API would help get C and SDK programmers into the world of C++. As it turns out, most MFC applications took fewer lines of code to implement an application than other application frameworks. For MFC 2.0, the AFX group set out to help more programmers write programs for Windows in C++ by providing high-level abstractions that encapsulate a large amount of functionality with a few lines of code.

An important design goal of MFC 1.0 was that applications written with MFC 1.0 be as small and fast as those written with C and the SDK. MFC 1.0 received much praise for the small size of the executables compared to all other application frameworks. In terms of execution speed, MFC 1.0 proved to be faster than other techniques for handling Windows messages. With MFC 2.0, we have maintained the same commitment to size and speed. If an MFC 1.0 application is recompiled and linked with MFC 2.0 libraries, only a minor increase in size is expected — on the order of 20-30K. This increase is due to the fact that some functions, even if they are not directly called, cannot be removed by the Microsoft smart linker. However, as MFC 2.0 features are used, an application will grow in size depending on the particular features that are used.


  Developer Support

MFC 2.0 provides developer support in a number of key areas. Based on the feedback from MFC 1.0, Microsoft made a number of improvements in the support provided. Online documentation and technical notes are supplied in WinHelp format:  the tutorial has been expanded to implement more features; the amount of technical overview material in the documentation has increased; and the dependencies on the Microsoft C++ compiler have decreased.

Complete API Reference  A complete printed reference for all public member functions and member variables is available. This information is also available via the online help system (in WinHelp format). In addition, references are provided to Windows APIs where appropriate. MFC 2.0 includes much more overview material and has been written assuming less Windows API knowledge on the part of the programmer.

Tutorial  To familiarize users with MFC 2.0, a tutorial is provided. Users are guided through a step-by-step procedure for developing a non-trivial Windows-based application that includes windows, dialogs, graphics, menus, commands, scrolling, files, printing and persistent data. The source code to the application is also provided.

Cookbook  Topics covered in the Class Libraries User's Guide require more detail than the tutorial and API reference provide. A broad range of topics is covered in depth and includes programming examples for exceptions, collections, diagnostics and application design. Users can refer to these chapters for answers to more complex questions.

Technical Notes  Many questions and problems faced by programmers are not easily documented in traditional forms such as the Class Libraries User's Guide, tutorial and API reference. Realizing this, MFC 2.0 includes technical notes, which are concise notes written by the AFX development and quality-assurance engineers. These notes describe specific problems and solutions encountered by users of the system, and include source-code examples and detailed technical information for intermediate to advanced users. The notes also provide details on the implementation of the application framework. The technical notes are provided in WinHelp format in MFC 2.0.

Sample Source Code  Many feel that the best way to learn how to program for Windows and use an application framework is by using sample programs written by the developers of the product. MFC 2.0 includes 24 sample programs consisting of over 22,000 lines of C++ code. These programs demonstrate nearly all aspects of the framework in a series of non-trivial applications including OLE clients and servers, a full-featured MDI text editor, a charting application, use of DLLs and so forth. To help navigate the samples, a complete description of the sample programs organized by feature area (in addition to an alphabetic reference) is provided in WinHelp format.


  Source Code:  Design Philosophy

With the introduction and acceptance of MFC, many developers have asked Microsoft to provide a succinct set of design goals that the AFX group followed in designing MFC. The central design tenet of MFC is to facilitate and simplify programming for the Windows environment, while providing a path for growth into future Windows environments. Achieving this design goal included adherence to a set of design principles which were the result of a design and prototype phase.

•	Application frameworks for Windows should fully exploit the power of the C++ language without overwhelming the programmer. C++ is a complex language with hundreds of new features. A class library should therefore utilize a sensible subset of the C++ language while at the same time permitting the use of the entire C++ language.

•	Application frameworks for Windows should present a model that requires minimal relearning on the programmer's part. Developers who have experience with the Windows Software Development Kit (SDK) should be able to quickly comprehend the programming model, class hierarchy and naming conventions. By mixing traditional C-language SDK code with C++ objects for Windows, programmers should be able to produce readable source code that can be easily maintained. In addition, programmers should be able to leverage third-party materials such as books, sample code and courses, and should not be forced to learn an entirely new paradigm or API. Developers who are not familiar with C/SDK programming should be able to learn Windows-based programming faster using an application framework, because the application framework shields the programmer from the low-level details and labor associated with SDK programming.

•	Recognizing that a major end-user benefit of Windows is the standard user-interface paradigm shared by most applications, an application framework should support the standard Windows interface with minimal coding. At the same time, the application framework should be flexible enough to be used for specialized user-interface elements. The ability to customize the user interface by overriding a member function is important; but equally important is the ability to call native Windows APIs for maximum flexibility and power.

•	An application framework should represent a balance between power and efficiency. Application frameworks that attempt to provide too high a level of abstraction through "heavy" classes with many virtual member functions usually produce large, slow applications. But abstraction does not necessarily imply big and slow. The most elegant solutions are usually those that are the smallest and fastest.

•	With its broad market support, the Windows environment will be around for many years. Its capabilities will grow substantially as new versions, such as Windows NT and Win32s, are released. An application framework must therefore represent more than a set of classes; it must be a scalable architecture that grows as the Windows environment grows.

As this paper demonstrated, the MFC 2.0 application framework working in concert with AppWizard, ClassWizard, and App Studio implements these principles. Following these principles over the course of the development of MFC 1.0 and MFC 2.0 has resulted in an application framework that is the C++ interface to Windows needed by C++ programmers; that provides an architecture and high-level functionality expected from an application framework; and that at the same time satisfies the size and speed requirements of professional developers for Windows.


  Appendix A: AppWizard

AppWizard makes it easy to get started using MFC 2.0 because it automates the first steps in using the application framework. For nearly all applications, the fastest and easiest way to get started using MFC 2.0 is to run AppWizard and work with the application template that it creates. AppWizard creates a fully compilable, ready-to-go, full-featured, standard application for Windows.

One of the toughest problems faced by a developer trying to use an application framework is trying to figure out where to start. The C/SDK programmer starts a new application by copying a template, such as GENERIC, that has the standard message loop, WinMain, and other associated grunge. With MFC 2.0 these steps are not needed, since the architecture supports them already without any coding. If you want your application to use some of the high-level architectural features, such as printing documents and views, then you need an infrastructure to build upon. AppWizard provides that infrastructure by supplying the project files you need to immediately reap the benefits of MFC 2.0 for writing Windows-based applications.

AppWizard is run from the Visual WorkBench's Project menu. To get started, you just supply a directory for your application. Since AppWizard is tuned for substantial applications, it enforces the rule that each application must have its own source directory. You can select a number of options to customize the initial contents of your application.

Before we explore what AppWizard does for you, it is important to understand what AppWizard does not do for you. AppWizard is not a CASE tool or code generator, but rather it is an efficient way to leverage the power of the code within the application framework. AppWizard is only run a single time for each application. If at a later time you require some of the functionality that AppWizard can provide, you must add the code manually; or often you can use ClassWizard. This permits MFC 2.0 applications to be free form and not impose any artificial structure on programmers, as is common with CASE tools and code generators. AppWizard does not require you to maintain any special data files, but rather it works the way you do. The output of AppWizard is a set of source files that use the application framework, and as such provides more structure than code. The code that does the work for you is in the application framework.

As an indication of the powerful combination of AppWizard and MFC 2.0, the following is a list of features in a fully enabled AppWizard-created application template.

•	MDI application (SDI is optional)

•	Toolbar with buttons mapping to the menu commands File New, File Open, File Save, File Print, Edit Cut, Edit Copy, Edit Paste, Help About and context-sensitive SHIFT-F1

•	Status bar with menu command prompt strings for all commands and indicators for Num Lock, Scroll Lock and Caps Lock

•	File menu commands for New, Open, Close, Save, Save As, Print, Print Preview, Print Setup, Exit and recent file list

•	Standard dialog support for obtaining file name information from the user (for Open, Save As)

•	Standard dialog support for Print and Print Set-up

•	Print preview support including Next/Prev Page, Two Page view and Zoom In/Out

•	Edit menu hooks for Undo, Cut, Copy and Paste

•	OLE 1.0 command and user-interface support for Edit menu commands Paste Link, Insert New Object, Links and Object

•	View menu to enable or disable the toolbar and/or status bar

•	Window menu commands New Window (including correctly naming each window by appending a numeric index), Cascade, Tile, Arrange Icons and an active window list

•	Online Help support including a help file with content covering all of the standard commands

This functionality requires no coding on your part — just invoke AppWizard from the Visual WorkBench and compile the program. This application contains an enormous amount of functionality, but since it leverages MFC 2.0's reusable classes this AppWizard application contains fewer than 700 lines of C++ source code and its executable occupies only 117K.

In order to use the architectural features in MFC 2.0, you usually need to derive one or more C++ class(es) that will contain your application-specific code. AppWizard automatically derives classes for the most common MFC 2.0 components. First, AppWizard will derive an application class from CWinApp, as every MFC application requires this. Every application also has a main window, which can be either MDI or SDI, and AppWizard will provide you with a derived CFrameWnd or CMDIFrameWnd class for your application based upon your preference. AppWizard will derive a CDocument and CView class for you and install a document template so that you are automatically taking advantage of the document/view architecture. For your CDocument-derived class, AppWizard lets you specify the file type (suffix) and descriptive name for the document types, and provides intelligent defaults for all class and file names. Most MFC 1.0 users indicated they are implementing toolbar and status bar user-interface elements in their applications, so AppWizard will create these automatically if you require them. Similarly, if your application will support printing and print preview, AppWizard will add the necessary menu commands and command handlers to your application. Other options available for creating an MFC 2.0 application include context-sensitive help and OLE client support.

In addition to the required and optional classes that AppWizard provides for your application, AppWizard also creates a number of supporting files. Every Windows-based application requires a resource script, so AppWizard provides one. The supplied script includes all of the application's menus, strings, keyboard accelerators, default icons, a default toolbar bitmap, version resource and even a dialog for the About box. The binary files such as bitmaps and icons are placed in a subdirectory, so they do not clutter your project's main directory. If your application requires OLE client or context-sensitive help support, then AppWizard will create several additional files, such as an OLE registration file or a subdirectory containing online documentation in WinHelp format.

Finally, AppWizard will create a project file (.MAK file) for use with the Visual WorkBench. This file will contain all the required compiler settings for building a debug or retail version of your application template. This project will be opened by the Visual WorkBench after AppWizard is finished, so all you need to do is build the project and you will have a running application.

After running AppWizard you will have a project directory that contains a number of files. For example, AppWizard creates a separate header file (.H) and separate source file (.CPP) for each of the classes in the application, which includes classes derived from CWinApp, CDocument, CView, and CFrameWnd (or CMDIFrameWnd). AppWizard is only used to get you started with the application framework, and is only used a single time for a given project. Since AppWizard creates only standard source files and places no restriction on how they are organized, you are free to structure your project in any manner that you see fit. Using AppWizard, you are free to work the way you are used to working. To make it easy to document the project structure, AppWizard also creates a standard text file that describes all the files in the project. It is a good practice to keep this file up to date as you add new files to your application source.

Once you have completed your application template with AppWizard, you are ready to begin adding application-specific code and user-interface elements. AppWizard will, optionally, comment your derived classes with indications of where to add specific code. The following example shows how AppWizard indicates where to add code for loading and saving a document. The class CMyDoc is the CDocument-derived class created by AppWizard.

void CMyDoc::Serialize(CArchive& ar)

{

if (ar.IsStoring())

{

// TODO: add storing code here

}

else

{

// TODO: add loading code here

}

}

You can use the Visual WorkBench to browse your application's source code and add your own functionality. At this point in the application development cycle you are done with AppWizard. Another tool is provided that enables you to connect user-interface elements to your code as easily as Microsoft's Visual Basic programming system and to add classes and maintain message maps. ClassWizard, which is discussed in the next section, works with standard C++ source code to provide all of this support.


  Appendix B: ClassWizard

ClassWizard ties together MFC 2.0, App Studio and the Visual Workbench, and makes it easy for you to move seamlessly between user-interface elements and application code. ClassWizard is modeled after the point-and-click interface in Visual Basic. In Visual Basic you can double-click on a user-interface element such as a menu item, and immediately edit the code for that command. ClassWizard gives you that same functionality using interfaces that are built using standard Windows resources and App Studio connected to standard C++ code and MFC 2.0. Thus you gain the benefits of moving directly between C++ code and user-interface elements as in Visual Basic, while at the same time you have the full power of industry-standard C++, MFC 2.0, as well as the Windows API. ClassWizard assists you in handling all standard Windows messages and commands by maintaining the class' message map, adding new MFC 2.0-derived classes, and maintaining all of the dialogs' data exchange code.

After you create an application template with AppWizard, you have several derived classes to customize. Normally you will be adding code for application-specific responses to standard Windows messages, and you will be adding code to handle commands for the new user-interface elements you will create with App Studio. In MFC 1.0 each CWnd-derived class had a message map that you were required to maintain manually. The MFC message-map implementation requires some macro syntax. We chose to use macros rather than implement a non-standard compiler extension so that MFC would be compiler-independent. Unfortunately MFC 1.0 programmers found it somewhat cumbersome to maintain the message-to-member function mapping. Microsoft introduced ClassWizard to automatically maintain all message maps for you, while at the same time continuing to use only standard C++. ClassWizard performs source-code maintenance exactly as you would manually, but is less error-prone and much faster. Just as with AppWizard, ClassWizard was designed to work the way you do. You can continue to organize your source code in the manner you require, without fear of losing any data, because ClassWizard works on small, well-defined portions of your source.

As an example of how ClassWizard works for you, let's consider adding a message handler for the WM_MOUSEMOVE message to a CView-derived class. Assuming a message map has already been set up, which ClassWizard does automatically, you will need to add three pieces of code to two different files:  a function prototype for OnMouseMove in the .H file, a message map entry in the .CPP file, and a member function definition in the .CPP file. ClassWizard does these steps for you. In the Figure 7 all of the ClassWizard added lines are highlighted.

class CMyView : public CView

{

// ...

// Generated message map functions

protected:

//{{AFX_MSG(CMyView)

afx_msg void OnFilePrint();

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

afx_msg void OnMouseMove(UINT nFlags, CPoint point);

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

BEGIN_MESSAGE_MAP(CMyView, CView)

//{{AFX_MSG_MAP(CMyView)

ON_COMMAND(ID_FILE_PRINT, OnFilePrint)

ON_WM_LBUTTONDOWN()

ON_WM_LBUTTONUP()

ON_WM_MOUSEMOVE()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

void CMyView::OnMouseMove(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

CView::OnMouseMove(nFlags, point);

}

So as you can see from this example, ClassWizard saves you programming and editing time, greatly reduces the number of potential errors in your code, and removes the bookkeeping responsibility associated with messages and commands. As with AppWizard, ClassWizard uses comments to indicate where you should insert code and any special notes for a particular message. The OnMouseMove also contains a call to the base-class message handler, which will perform any default processing of the message if required. Since ClassWizard is smart about which message you are handling, it will automatically insert message-specific code in the handler stub, such as calling the base-class handler when needed. Using this context-based intelligence, ClassWizard filters the list of messages that a given user-interface object or class can handle, based on the type of the object. The comments containing AFX_MSG delimit the portions of your code that ClassWizard will modify. ClassWizard will never modify any code outside of these comments. In fact, if you wish to prevent ClassWizard from modifying a particular message handler or message map entry, you are free to move it outside of the comment blocks. By using these standard C++ comments as indicators to ClassWizard, your code can be maintained as standard C++ code without any secondary files or additional database, and without parsing C++ code. ClassWizard's main function is to assist the programmer with managing user-interface to C++ code mapping, which utilizes the MFC message-map structure and the MFC 2.0 command architecture.

In addition, ClassWizard also makes it easy to add new classes that are derived from the MFC 2.0 class CCmdTarget, or any of its derived classes. With ClassWizard you can create a new class derived from any of the basic Windows classes such as CWnd, CFrameWnd CMDIChildWnd and CDialog. ClassWizard also lets you create new classes derived from the CView and CDocument architectural classes, which makes it easy to add a new view type to your existing application. ClassWizard can derive new classes based on the high-level abstractions CFormView, CScrollView and splitter windows. Each class you create with ClassWizard is a standard C++ class that uses the MFC 2.0 base class. ClassWizard allows you to specify the header file and implementation file for a class, and supports maintaining multiple classes in a single file.

If you have an MFC 1.0 application that you wish to use with ClassWizard, all you need to do is add the AFX_MSG comments described above and use the ClassWizard Import Class feature, which interprets the class declaration. Migrating your classes to ClassWizard is discussed in the documentation.

ClassWizard, in conjunction with App Studio, supports several additional features for managing CDialog-derived classes. When you are editing a dialog resource in App Studio, you can invoke ClassWizard and automatically create a C++ class for that dialog if one does not exist. Thus without typing any code you can connect a dialog resource to a C++ class derived from an MFC 2.0 base class. Also, for dialogs (as well as CFormView classes, since they are based on dialog resources) ClassWizard can be used to implement DDX/DDV functionality for initializing, validating and obtaining information from end-user dialogs. ClassWizard's Edit Variables command lets you attach class member variables to each control in the dialog. Since ClassWizard understands all of the Windows controls, the variables you add are correctly typed. For example, if your dialog contains a checkbox control, ClassWizard knows that it should be represented by a Boolean variable in the CDialog-derived class. The application framework uses these variables to initialize the state of the controls in your dialog. While the dialog is visible to the user, MFC 2.0 will validate any information entered by the user based on criteria specified using ClassWizard. If the user clicks the OK button, MFC 2.0 will automatically transfer the contents of the controls to these variables, which can then be used by your code as needed. ClassWizard handles all of this DDX/DDV functionality for dialogs without any additional coding.


Presenting Visual C++ for Windows NT


Sample Screen for MultiPad


Books Online


Visual Workbench


AppWizard Options Dialog


App Studio


ClassWizard


Debugger Breakpoints Dialog


SPY++


Introduction
Getting Started

Introduction

The Microsoft® Visual C++™ Development System for Windows™ and Windows NT™, 32-Bit Edition, represents an evolutionary step in the progress of high-performance program development tools for the Microsoft Windows NT™ operating system. Visual C++ uses fully integrated Windows-hosted development tools and a "visual" user-interface-driven paradigm to the traditional C/C++ development process.


Book Location
Getting Started


  About This User Guide

This User Guide includes information to help you install Visual C++, become familiar with Visual Workbench, and understand how to use the main Visual C++ development tools. The following chapters are included:

•	»Chapter 1« describes how to install Visual C++. It also provides the basic configuration and system requirements for Visual C++, as well as configuration requirements for running Visual C++ from the command line.

•	»Chapter 2« provides answers to common questions about the Visual C++ development system. Questions and answers are provided on installation, cross-platforms, Visual Workbench, App Studio and the Microsoft Foundation Class Library.

•	»Chapter 3« provides a brief introduction to projects, then takes you through a build of a Microsoft Foundation Class Library sample program.

•	»Chapter 4« describes how to use Visual Workbench and App Studio to develop a Visual C++ application. It presents an overview of the development process and describes how the tools are used during development.

•	»Chapter 5« takes you through a development session using Visual C++ tools to create, build, and debug a Microsoft Foundation Class Library C++ application.

•	»Appendix A« provides information about products and services that make the Microsoft Visual C++ development system for Windows NT more accessible for people with disabilities.


Getting Started Document Conventions
  Document Conventions

This book uses the following typographic conventions:

Example	Description
STDIO.H	Uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
char, _setcolor, __far	Bold type indicates C and C++ keywords, operators, language-specific characters, and library routines. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
	Many constants, functions, and keywords begin with either a single or double underscore. These are required as part of the name. For example, the compiler recognizes the __cplusplus manifest constant only when the leading double underscore is included. It may be difficult at first glance to distinguish a single underscore from a double underscore because the two run together on the screen. Therefore, the width of the character(s) is your guide. The sample term setcolor, in the left column above, has one underscore in front of it, while the term far has two underscores in front of it.
expression	Words in italics indicate placeholders for information you must supply, such as a filename. Italic type is also used occasionally for emphasis in the text.
[option]	Items inside square brackets are optional.
#pragma pack {1 | 2}	Braces and a vertical bar indicate a choice among two or more items. You must choose one of these items unless square brackets ([ ] ) surround the braces.
#include <io.h>	This font is used for examples, user input, program output, and error messages in text.
CL [option...]  file...	Three dots (an ellipsis) following an item indicate that more items having the same form may appear.
while() {  .  .  . }	A column or row of three dots tells you that part of an example program has been intentionally omitted.
CTRL+ENTER	Small capital letters are used to indicate the names of keys on the keyboard. When you see a plus sign (+) between two key names, you should hold down the first key while pressing the second.
	The carriage-return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
"argument"	Quotation marks enclose a new term the first time it is defined in text.
"C string"	Some C constructs, such as strings, require quotation marks.
Dynamic-Link Library (DLL)	The first time an acronym is used, it is usually spelled out.
see »Using Projects«	Hypertext cross-references are enclosed in green double chevrons. Click the term enclosed in the chevrons to jump to display the referenced information.
CEnterDlg;	The blue box adjoining the blue code indicates that it has been altered from a previous example, usually because you are being instructed to edit it


  Chapter 1   Installing Microsoft Visual C++

This chapter describes how to use the CD-ROM to install and use the Visual C++™ Development System for Windows™ and Windows NT™. It also describes how to install the Win32s™ files from the CD-ROM.


  System Requirements

Visual C++ requires the following minimum configuration:

•	An IBM™ Personal Computer, or 100 percent compatible running Microsoft Windows NT.

•	A VGA monitor.

•	An 80386 or higher processor.

•	16 megabytes of available memory (20 megabytes recommended).

•	A Windows NT-compatible CD-ROM drive connected to your computer.

•	A hard disk with enough disk space to install the options you need. The Setup program lets you select installation options and provides you with the disk space requirements for the options you select. It then checks to make sure you have enough space before copying files.

If you are developing and testing applications for Win32s, you also need either a dual-boot computer or a separate computer with:

•	Microsoft Windows or Microsoft Windows for Workgroups version 3.1 running in enhanced mode (command-line utilities can be run outside Windows but you need Windows to install Win32s files).

•	MS-DOS® version 3.3 or greater.

You must install the Win32s Dynamic Link Libraries (DLLs) and debugger on the computer you plan to use for testing and debugging Win32s programs. For example, if you plan to use a second computer for testing and debugging Win32s programs, you must install the Win32s DLLs and debugger on the second computer. This requires that the second computer have a CD-ROM drive.


Installing Visual C++ For Windows NT
  Installing Visual C++

This section describes the basic installation for the Visual C++ development system and the Win32s files.The Setup program provided by Visual C++ performs all tasks necessary for installing the Visual C++ components.

Quick Guide to Installation

Read this section as an overview to the installation procedures or simply for background information on the installation process.

The Setup Programs

There are two installation programs on the Visual C++ CD:

•	\MSVCNT\SETUP.EXE, the Visual C++ setup program

•	\MSVC32S\SETUP.EXE, the Win32s setup program

The Visual C++ setup program can be used to:

•	Install 32-bit development tools and files from the CD-ROM to your hard drive

•	Install Visual C++ to run from the CD-ROM drive or a network installation

The Win32s setup program is used to install:

•	Win32s DLLs

•	CodeView® for Win32s

•	Profiler for Win32s

•	Phar Lap® Files

Where to Start

If you are only developing  applications targeted for Windows NT, run the Visual C++ setup program. This setup program must be run from Windows NT.

If you are developing applications for Win32s, first run the Visual C++ setup program from Windows NT then run the Win32s setup program  from Windows 3.1. This means you will  need to reboot in MS-DOS and run Windows 3.1 or use a separate computer that is running Windows 3.1 and has a CD-ROM drive.

CD-ROM Directories

The Visual C++ CD-ROM root directory includes the directory \MSVCNT with the following subdirectories:

\MSVCNT\BIN  This directory contains executables for applications and build tools for building 32-bit applications.

\MSVCNT\INCLUDE  This directory contains C/ C++ run-time and Microsoft Win32™ Software Development Kit (SDK)  header files.

\MSVCNT\LIB  This directory contains C/ C++ run-time and Win32 SDK libraries.

\MSVCNT\HELP  This directory contains all Help files for Visual C++.

\MSVCNT\MFC  This directory contains subdirectories for all Microsoft Foundation Class Library files, including directories for libraries, samples, source files, and include files.

\MSVCNT\SAMPLES  This directory contains sample programs from the Microsoft Win32 SDK.

Win32s files are located in the following \MSVC32S subdirectories:

\MSVC32S\BIN  This directory contains the Win32s debugging tool, Microsoft CodeView for Win32s, and Microsoft Profiler for Win32s.

\MSVC32S\WIN32S  This directory contains the debug and retail Win32s DLLs as well as Win32 SDK components for Win32s.

\MSVC32s\PHARLAP  This directory contains the Phar Lap TNT Dos-Extender Lite files.


  Installation Procedures

For help on any of the dialog boxes presented by the »Setup program« during installation, press the F1 key or choose the Help button in the dialog box.

You can install Visual C++ in one of the following ways:

Complete Installation  This installs all tools and libraries for targeting applications for Windows NT. It also installs Microsoft Foundation Class Library files, sample files, and Help files.

Custom Installation  This opens the Custom Installation dialog box. In this dialog box you can select files to install, or files to add to your current installation. For more information, see »Custom Installation Options«.

Minimum Installation  This installs Visual Workbench, App Studio, Microsoft Foundation Class Library files, and the tools and libraries needed for targeting applications for Windows NT.

CD-ROM Installation  This copies App Studio and Visual Workbench from the CD-ROM drive to your hard disk and modifies Windows NT Registry keys for Visual C++ environment paths. When modified, the registry keys for executables, include files, libraries, Help files, and Microsoft Foundation Class components point to the corresponding directories on the CD-ROM drive. See »Installing Visual C++ to Run From a CD-ROM or Network Server«


To run Setup
  Setup Program

To run Setup

1.	Place the Visual C++ CD in the CD-ROM drive.

2.	Log on to Windows NT if you have not already done so.

3.	Use the File Manager to run SETUP, located in the MSVCNT directory of the CD-ROM drive.

-Or-

Choose Run from the Program Manager File menu and type [X]:\MSVCNT\SETUP in the Command Line box (where [X] represents the drive letter associated with the CD-ROM drive).

After initialization, setup prompts you with a dialog box that describes the program and lets you continue or exit.

4.	Choose Continue.

The Installation Options dialog box appears (»see Figure 1.1«).

5.	If you decide to perform either the Complete Installation or Minimum Installation, compare the disk space required for the option you have chosen (displayed next to the option) with the total disk space available (listed at the bottom of the dialog box).

If you have enough disk space on the default drive (drive C) proceed to the next step.

If you want to change the installation disk drive to one with more disk space, use the Directory Options dialog box (accessed from the Directories button) to change the drive.

6.	To perform a default installation without customization, choose Complete Installation, Minimum Installation, or CD-ROM Installation.

Or, if you want to customize the installation, choose Custom Installation.

7.	If you chose »Custom Installation« in the previous step, select the options you want to install, and choose Continue.

Compare the amount of disk space required by the components you select with the total amount of disk space available. You may need to free up some disk space before continuing, or install fewer components initially and add components later.

Setup checks for sufficient disk space,  prompts you for registration confirmation, builds the file list and copies files from the CD-ROM drive to your hard drive.

8.	Select the Register 32-bit Environment Variables check box to make the PATH, INCLUDE, and LIB environment variables available in a Windows NT  command window.

Or clear the check box if you always plan to use Visual Workbench to build applications for Visual C++ . If you clear this check box and and plan to use command-line tools, you must run VCVARS32.BAT to set environment variables. This file is installed in \MSVCNT\BIN, which represents your executable directory.

9.	Choose OK .

The Setup program finishes and returns you to Windows NT.


  Custom Installation Options

When you choose Custom Installation from the Installation Option dialog box, the Custom Instalation dialog box appears (»see Figure 1.2«).

This section describes each of the options available from this dialog box.

Directories

The Directories button opens the Directory Options dialog box, shown in »Figure 1.3«. You can change the directories and disk drives for the files groups you want to install in this dialog box.

This dialog box is used to change to a disk drive with adequate space for the options you choose. You can also change the root directory name and names of subdirectories for the following file groups:

Install Directory  This directory is specified as the root for all the directories in this dialog box.

Executable Files  This file group includes all the programs and tools.

Include Files  This file group includes the system header files for C and C++, but does not include the Microsoft Foundation Class Library header files.

Sample Source Files  This file group includes the Win32 SDK samples.

Library files  This file group includes the C and C++ run-time libraries.

MFC Files  This file group includes all of the Microsoft Foundation Class Library files except the Help files.

Help Files  This file group includes all the Help files for Visual C++.

Microsoft Visual Workbench

Select this check box to install the Visual Workbench integrated development environment. By default, this is installed in the \MSVCNT\BIN directory.

Microsoft App Studio: Resource Editor

Select this check box to install the App Studio resource editor. This is installed in \MSVCNT\BIN by default.

Microsoft C/C++ Compiler

Select this check box to install the Microsoft C/C++ 32-bit Compiler, all 32-bit build utilities and libraries, and the 32-bit profiler. The compilers, build utilities, and profiler are installed by default in the \MSVCNT\BIN directory. The libraries are installed by default in the \MSVCNT\LIB directory. The include files are installed by default in the \MSVCNT\INCLUDE directory.

Microsoft Foundation Classes

Select this check box to install the Microsoft Foundation Class files and directories. These are installed by default in the \MSVCNT\MFC directory. You can use the MFC Files button to open the MFC Options dialog box (see »Figure 1.4«) and select which tools to install. You can install Microsoft Foundation Class Help files using the Help Options dialog box (from the Help Files button) and sample files using the Sample Source Options dialog box (Samples button).

The Microsoft Foundation Class Options Dialog box lets you install libraries for the following target types: Windows NT.EXE, Windows NT.DLL, and Console.EXE. You can also choose to install Release and/or Debug versions of these libraries.

Tools

Select this check box to install Windows NT development tools. You can use the Tools button to open the Tool Options dialog box (»see Figure 1.5«) and select which tools to install. By default, the  tools are installed in the \MSVCNT\BIN directory.

The Tool Options dialog box has check boxes for three categories of tools. You can install the following tools:

•	Spy++

•	Win32 SDK tools

•	Help Compiler

Online Help Files

Select this check box to install Help files associated with Visual C++. You can use the Help Files button to open the Help File Options dialog box (see »Figure 1.6«) and select which files to install. Use the file size and disk space information in this dialog box to help determine which files to install. By default, Help files are installed in the \MSVCNT\HELP directory.

The Help File Options dialog box has check boxes so you can choose whether or not to install the following Help files:

C/C++ Language Help  This installs the MSCXX.HLP file, a reference to the C/C++ run-time library functions.

Win32 API Help  This installs the API32WH.HLP file, a reference to Win32 APIs.

MFC Help  This installs the MFC.HLP file containing Microsoft Foundation Class library descriptions.

Sample Source Code

Select this check box to install sample source code. To modify the installation of sample code, choose the Samples button to open the Sample Source Options dialog box (»see Figure 1.7«).

The Sample Source Options dialog box lets you select from the following categories of sample files:

MFC Samples  This includes Microsoft Foundation Class samples. These are installed in \MSVCNT\MFC\SAMPLES.

Win32 Samples  This includes all the Win32 SDK samples installed by default in the \MSVCNT\SAMPLES directory.


  Installing Visual C++ to Run From a CD-ROM or Network Server

If you have limited space on your hard drive, you may want to run Visual C++ directly from the CD-ROM drive. Visual C++ may run somewhat slower as a result of the increased access time for build utilities, libraries, include files and Help files. If performance becomes an issue, you can install Visual C++ to run from the hard disk.

Warning  If you are a using a Write Once Read Many (WORM) drive, copy all of the files on the Visual C++ CD to the WORM drive. Run setup from the WORM drive, using the CD-ROM installation option. This installs App Studio, Visual Workbench, App Wizard, and Class Wizard on your hard drive. All other Visual C++ components will run from the WORM drive. If you install Visual C++ on the WORM drive, as described in the following installation procedure, you will permanently lose some of your drive space every time you run Visual Workbench or App Studio.

To install files on a network server so that they may be shared, copy the files onto the network server exactly as they appear on the CD-ROM. Then use the following procedure to install Visual C++ on individual network computers.

To install Visual C++ to run from the CD-ROM drive or network server:

1.	Run Setup as described .

2.	Choose CD-ROM Installation in step 6.

The setup program copies Visual Workbench and App Studio files onto your hard drive. It also modifies Windows NT Registry keys for Visual C++ environment paths to point to the directories on the CD-ROM or network server drive.

Installing Visual C++ to run from CD-ROM allows you to run the Visual C++ tools from Visual Workbench or from the command-line in a Windows NT command window. Note that you cannot build sample application projects that reside on the CD-ROM since it is a read-only medium. To build sample applications, copy the sample application's directory to your hard drive and build the application from there.

When Visual C++ is installed to run from the CD-ROM, it writes its default workspace and project files to the Windows directory.


  Adding Libraries or Files to Your Installation

You can upgrade your Visual C++ installation by copying libraries or files you didn't install the first time. The following procedure describes how to install additional files.

To add libraries or files to your installation

1.	Run Setup as described  .

2.	Choose Custom Installation in step 6.

3.	In the Custom Installation dialog box, clear all check boxes except the category you want to install.

4.	If you have selected a category that has an associated dialog box, choose the associated button, otherwise skip to step 7.

5.	Clear all default options and select the new option or options.

For example, if you want to install Win32 API Help files, clear all options in the Custom Installation dialog box except Online Help Files, choose the Help Files button, and select only Win32 API Help in that dialog box.

6.	Choose OK to close the associated category dialog box.

7.	Choose Continue to proceed with the installation.


  Installing Win32s

You can use Visual C++ to develop applications for Win32s, however, these applications must be debugged using a computer running  MS-DOS and Windows 3.1. For this reason, the Win32s files are installed separately from the Visual C++ files.

You must install the Win32s files on a system that has a CD-ROM drive and runs MS-DOS, version 3.3 or later, and Windows 3.1 in enhanced mode. If you want to copy these files to another computer that doesn't have a CD-ROM, you should remember to modify the SYSTEM.INI and TOOLS.INI files on the second computer. »Win32s Configuration« for a description of what is changed in these files by the Win32s setup program.

Running Win32s Setup

The Win32s setup program copies files from the MSVC32S subdirectories on the CD-ROM to your hard drive.

To run Win32s Setup

1.	Place the Visual C++ CD in the CD-ROM drive.

2.	Run Windows 3.1 in enhanced mode.

3.	Use the File Manager to run SETUP, located in the MSVC32S directory of the CD-ROM drive.

-Or-

Choose Run from the Program Manager File menu and type [X]:\MSVC32S\SETUP in the Command Line box (where [X] represents the drive letter associated with the CD-ROM drive).

After initialization, setup prompts you with a dialog box that describes the program and lets you continue or exit.

4.	Choose Continue.

The Installation Options dialog box appears. »Win32s Installation Options« or choose the Help button for more information on options in this dialog box.

5.	After selecting installation options, choose Continue.

Setup builds the file list, checks for sufficient disk space and copies files from the CD-ROM drive to your hard drive.

After all files have been copied, a Configuration Files dialog box appears to let you choose to have Setup modify configuration files or write a modified version to another location.

6.	Choose one of the options in the Configuration Files dialog box and choose Continue.


  Win32s Installation Options

The Installation Options dialog box appears when you run the setup program. (See »Figure 1.8«.)

The Installation Options dialog box contains options and a Directories button, which opens a Directory Options dialog box. Use the Directory Options dialog box to change the installation disk drive or file directories.

Win32s DLLs

The Win32s DLLs option has selections for retail and debug versions of the Win32s DLLs. At least one of these DLLs must be installed on a system that runs applications that call Win32s APIs. The Win32s DLLs are first installed to the MSVC32S\WIN32S directory. They are then automatically copied to the Windows directory. If you choose to install the retail versions of the DLLs, or both retail and debug versions, the retail versions are copied to your Windows directory. You can run WIN32S\BIN\SWITCH.BAT to change from one version to the other.

Win32s Tools

The Win32s Tools option has selections for the CodeView debugger and the Profiler. If you select the CodeView check box, the setup program installs Microsoft CodeView for Win32s. If you select the Profiler check box, the setup program installs Profiler for Win32s.

Phar Lap

Select the checkbox in this group to install the Phar Lap TNT Dos-Extender Lite files. Information on using the Phar Lap utilities is provided in the Phar Lap installation directory.


  Win32s Configuration

The Win32s setup program adds lines to the TOOLS.INI and SYSTEM.INI files when it installs Win32s files. Modifications vary depending on which options you choose during installation. Remember to make these modifications if you copy the Win32s files to another computer.

Note  If your CD-ROM is not supported by Windows NT, open Windows and refer to the Installation Notes in Readme.WRI.


  Chapter 2  Questions and Answers

The questions in this chapter represent a cross-section of some of the typical questions asked by developers about the Visual C ++ development system for Windows NT and its components. For more detailed questions and answers, consult the Technical Support Help, which can be accessed from the Help menu in Visual Workbench. Questions and answers are provided on the following topics:

•	»Installation«

•	»Cross-Platforms«

•	»General Information«

•	»Visual Workbench«

•	»App Studio«

•	»Microsoft Foundation Class Library«


  Installation

Q.	What does the setup program do when it modifies the Windows NT registry?

A.	It registers the directories for the executable files, include files, library files, and Help files used by Visual C++. If you install Visual C++ to run from your hard drive, the drives and directory paths specified at installation are registered. If you install Visual C++ to run from the CD-ROM, the CD-ROM drive and directory paths are registered.

Q.	How do I change the default installation directory?

A.	During installation, choose the Directories button in the Installation Options dialog box and type a new directory in the Install Directory text box.

Q.	Can I run Visual C++ from the CD-ROM?

A.	Yes, an option in the Installation Options dialog box of the Setup program lets you run Visual C++ from the CD-ROM or from a network. This installation will install the Visual Workbench, App Studio, App Wizard, and Class Wizard files on your hard drive.


  Cross-Platforms

Q.	How do I port my 16-bit Windows application to Win32?

A.	First, read the section titled "Moving to Windows NT" in Programming Techniques to learn how to port applications to Windows NT. Then use the Microsoft PortTool application, located in the \MSVCNT\BIN directory, to help identify areas in your program that require revision. To port Microsoft Foundation Class Library 16-bit applications to 32-bit applications, see "Writing Microsoft Foundation Class Library Applications for Windows NT" in the Class Library Reference.

Q.	How do I port my character-mode applications to Windows NT?

A.	Character-mode applications that use standard I/O calls such as printf and scanf can be built in Windows NT as Console applications. Code that uses BIOS calls, graphics libraries, or direct hardware calls cannot be used in Windows NT. You can use the Win32s Console APIs to perform similar functions.

Console applications will not run directly under Win32s. You can use the Phar Lap TNT Dos-Extender Lite to run 32-bit Console applications under MS-DOS.

Q.	Can I write or debug 16-bit applications using Visual C++?

A.	No. The Visual C++ development system for Windows NT is designed for developing 32-bit applications to run in Windows NT or Win32s. The Win32s extensions allow you to run 32-bit applications that use a subset of the Win32 APIs on either Windows NT or Windows 3.x. Win32s is provided with Visual C++ and can be installed by running MSVC32S\SETUP.EXE.

Q.	Can I debug Win32s programs using the Visual Workbench debugger?

A.	Since Win32s applications use a subset of Win32 APIs, you use the Visual Workbench debugger to debug under Windows NT. To debug under Win32s, use Microsoft CodeView for Win32s. You can install Microsoft CodeView for Win32s by running MSVC32S\SETUP.EXE.

Q.	How do I use libraries to build a Win32s executable under Windows NT?

A.	Link with the same libraries used for any Win32s application. This is enabled automatically when you choose Windows application (.EXE) as a project type in Visual Workbench.


  General Information

Q.	How do I port my Win32 Software Development (SDK) Projects to Visual C++?

A.	You have two options, depending on how integrated you want your Win32 SDK projects to be with Visual C++:

•	Update the CL options in the Win32 SDK makefiles and run the makefiles from the command line or as an external project in Visual Workbench. Visual C++ doesn't support the CL MIPS options and treats the /Zi options differently. The LINK options are totally compatible. See the Build Tools User's Guide for more information.

•	Recreate your projects as Visual Workbench projects. See Chapter 3, "Using Projects," and Chapter 10, "Build Options Reference," in the Visual Workbench User's Guide for information on creating Visual Workbench projects and selecting compiler and linker options.

Q.	Can I run Visual C++ command-line tools from MS-DOS?

A.	Yes, all command-line tools include the Phar Lap TNT Dos-Extender Lite, allowing them to be run under MS-DOS.

Q.	Can I use Visual C++ to write Posix or OS/2® applications?

A.	No. The Visual C++ development system for Windows NT is designed for developing Console or GUI applications for the Win32 subsystem. You can use the Win32 Software Development Kit to build Posix applications.

Q.	Does Visual C++ target MIPS?

A.	No, only Intel®-compatible microprocessors are supported with the Visual C++ development system for Windows NT.


  Visual Workbench

Q.	Can I do mixed-language programming in Visual C++?

A.	You can mix C and C++ source code, however Visual C++ does not directly support mixing other languages such as assembly language with C or C++, except by using the _asm keyword to inline assembly instructions. You can integrate any language, such as MASM, with the Visual C++ tools by installing the compiler on the Tools menu and adding the resulting object files to your C or C++ project. Or you can modify your C or C++ internal project makefile to include mixed language build statements and then load the resulting makefile as an external project in Visual Workbench.

Q.	What differences are there between the version of Visual Workbench provided with the Visual C++ development system for Windows NT and the version provided with the Visual C++ development system for Windows?

A.	The version of Visual Workbench provided with the Visual C++ development system for Windows NT has the following differences and additions:

•	Project types of 32-bit executable, DLL, and static library

•	New compiler and linker options for 32-bit build tools

•	Integrated Profiler and Find in Files tools

•	Multi-threaded debugging capability

•	Win32 Structured Exception Handling debugging

•	A Break command on the Debug menu

•	A Memory window in the debugger

•	Generalized output window that accepts output from any tool including build tools, Find in Files, Profiler, or custom tools added to the Tools menu

•	A Stop command on the tools menu that will also stop build tools

There are also some option differences in the Editor, Colors, Tools, and Debug dialog boxes.

Q.	How do I display memory addresses in the integrated debugger?

A.	Use the Memory window, opened from the Windows menu, to display memory addresses. Use the Memory Window Options dialog box to set memory addresses and display options.

Q.	How do I see which command-line options are passed to the compiler?

A.	The C/C++ Compiler Options and Linker Options dialog boxes each contain an options String box that displays the compiler or linker options. Also, if you clear the "Suppress Display of Sign-On Banner" check box in either of these dialog boxes, you can see the options string in the Output window during a build.

Q.	Can I use project files from the version of Visual Workbench provided with the Visual C++ development system for Windows in the version of Visual Workbench provided with the Visual C++ development system for Windows NT?

A.	No, you will need to create new project files since the compiler and linker options will be different.

Q.	How do I watch my variables in the Watch window?

A.	Choose Debug from the Options menu and select the Hexadecimal Display check box or use the keyboard shortcut ALT+F9 to toggle the display between decimal and hexadecimal.

Q.	What are the differences between the CodeView debugger and the Visual Workbench debugger?

A.	If you are familiar with CodeView, you'll find the Visual Workbench debugger similar in operation and functionality. Both debuggers use similar breakpoint syntax; Watch, Locals, Registers, and Memory windows; and QuickWatch, Call Stack, and tracing capabilities. The primary difference is that CodeView supports a command window for command-line syntax and the Visual Workbench debugger uses only graphical controls. The Visual Workbench debugger also supports multi-threaded debugging and structured exception handling.


  App Studio

Q.	Can I edit 8- or 24-bit-per-pixel color bitmaps in App Studio?

A.	App Studio supports monochrome and 16-color graphics editing only. In general, the use of such advanced bitmaps for user-interface elements is not recommended.

Q.	Can I use App Studio as a general purpose resource editor?

A.	Yes, App Studio is a powerful resource editor when used with traditional SDK applications or with Microsoft Foundation Class Library applications. You can use ClassWizard with App Studio to create Microsoft Foundation Class Library code to support resource objects.

Q.	Are there any differences between the Windows 3.1 and Windows NT versions of App Studio?

A.	App Studio for Windows NT has the following differences:

•	VBX custom controls are not supported

•	App Studio for Windows NT cannot load or save Windows NT executables (.EXE), dynamic-link libraries (.DLL) or resource files (.RES).

•	App Studio for Windows NT does not support resources or resource objects specific to Windows NT.


  Microsoft Foundation Class Library

Q.	Can I use VBX custom controls with Visual C++ applications?

A.	VBX custom controls are 16-bit dynamic-link libraries and can only be used with 16-bit applications.

Q.	What is the difference between the 16-bit and 32-bit versions of the Microsoft Foundation Class Libraries?

A.	The message handlers, CWnd::OnCommand and CWnd::OnParentNotify, and the CTime class have changed. Also, there is no support for VBX controls, the Microsoft Windows for Pen Computing extensions, or MFC200.DLL. For more information, see "Microsoft Foundation Class Library Update for Windows NT" in the Class Library Reference.

Q.	Can I use ClassWizard to recognize my own classes?

A.	No. ClassWizard only recognizes classes that have been added using ClassWizard. These, by definition, are derived from the framework classes.

Q.	Can I use AppWizard to create C or C++ code without foundation class support?

A.	No. AppWizard is specifically designed to create Microsoft Foundation Class Library, version 2.0 application source code.


  Chapter 3  Building a Sample Application for Windows NT

The first thing many programmers want to do after installing a new language and development environment is to perform a test build to make sure everything is installed correctly and to see how the build process works. A "test drive" gives you confidence in your setup and helps you get acquainted with the new development environment.

This chapter provides a brief introduction to projects, then takes you through a build of a Microsoft Foundation Class Library sample program. It assumes that you have installed the Microsoft Foundation Class Library and sample programs and that the samples reside in the MSVCNT\MFC\SAMPLES directory on your hard disk.


  Introducing Projects

Projects are the cornerstone of Microsoft Visual Workbench. A project references the source files and libraries that make up a program, as well as the compiler and linker commands that build the program. It is composed of a makefile (.MAK), which is compatible with the Microsoft Program Maintenance Utility (NMAKE), a workspace file (.WSP), and a status file (.VCW). A project is identified by its makefile; the makefile has the same base name as the project with a .MAK extension. All sample programs have project files associated with them.

Project files from existing 32-bit projects can be used from within Visual Workbench by loading them as external projects. This does not give you access to compiler and linker options (other than Release versus Debug mode), but it does help you bring applications into Visual C++ quickly and build, run, and debug your existing applications within Visual Workbench.


A Sample Windows-Based C++ Application
  Sample Application

You can use any of the sample projects in the Microsoft Foundation Class Library samples directory to build and run a sample Visual Workbench project. The HELLO program is used in this example.

To build and run a sample program

1.	Run Visual Workbench by choosing the Visual C++ icon in Program Manager.

2.	From the Project menu, choose Open.

The Open Project dialog box appears (»see Figure 3.1«).

3.	Select the HELLO.MAK project file.

This file is in the \MSVC\MFC\SAMPLES\HELLO directory using the default installation.

4.	Choose OK.

5.	From the Options menu, choose Project.

The Project Options dialog box appears (»see Figure 3.2«).

6.	From the Build Mode options, select Release or Debug (select Debug for this example for a faster build).

7.	Choose OK to close the Project Options dialog box.

8.	From the Project menu, choose Build HELLO.EXE.

The build occurs entirely in the background, so you are free to continue working in Visual Workbench (although some menu commands are disabled). When the build is complete, Visual Workbench displays the final results on the status bar. In this case, the status bar should indicate 0 errors and 0 warnings.

9.	To run the program without invoking the internal debugger, choose Execute HELLO.EXE from the Project menu.

To run the program in the debugger, choose Go from the Debug menu.

Choose Close from the System menu to quit the program and return to Visual Workbench.


  Chapter 4  Developing a Microsoft Visual C++ Application

This chapter describes how to use Visual Workbench and App Studio to develop a Visual C++ application. It presents an overview of the development process and describes how the tools are used during development.

It is recommended that you complete the Scribble tutorial in the Class Library User's Guide to learn how to develop a Visual C++ application. You can read this chapter before beginning the tutorial or as a quick refresher.

After reading this chapter, you might want to follow the tutorial in »Chapter 5«, "A Test Drive of Visual C++".


  What Is a Visual C++ Application?

A Visual C++ application is an application for Windows that you design and develop using the Microsoft Foundation Class Library, the Microsoft Visual C++ build tools, and the Visual Workbench and App Studio Windows-hosted development tools.

By using a totally integrated environment, you can develop your application by focusing on the visual interface elements. Visual C++ calls these elements "user-interface objects." You first design the user-interface objects and then use Visual C++ tools to create and manage the code to support them. Visual C++ tools automate the often tedious and error-prone process of deriving classes, creating member functions, and mapping functions to messages. This lets you concentrate on designing the resources for your application and writing the functional code to handle messages.

You can also use the Visual C++ tools to develop standard applications for Windows SDK in C or C++, since Visual C++ includes a text editor, project manager, build utility, browser, debugger, and resource editor. If you are familiar with SDK programming for Windows, you'll find that the Visual C++ tools make the transition to object-oriented program development, and the Microsoft Foundation Class Library, easier than you might have imagined.


  Introducing the Tools

The Visual C++ tools consist of two applications, Visual Workbench and App Studio, and two wizards, AppWizard and ClassWizard. You also have other tools you can use with Visual C++. However, since these are not fundamental to developing a Visual C++ application using the Microsoft Foundation classes, they are not discussed in this chapter.

The Applications

Visual Workbench and App Studio work together to help you develop Visual C++ applications.

Visual Workbench

Visual Workbench is the main editing and debugging tool and acts as the anchor for the programming environment by creating and maintaining project information (see »Figure 4.1«). It incorporates a text editor, project manager, browser, and debugger in a single integrated development environment.

App Studio

App Studio lets you create and edit your application's resources, including dialog boxes, menus, icons, bitmaps, cursors, and more, in a single environment (see »Figure 4.2«). It can be used as a stand-alone resource editor to read and generate resource files for standard Windows SDK program development. It can also be integrated with ClassWizard, AppWizard, and Visual Workbench to develop Visual C++ applications using the Microsoft Foundation classes.

The Wizards

Two Visual C++ wizards, AppWizard and ClassWizard, help you design, create, and implement Visual C++ applications using the Microsoft Foundation classes. The Wizards perform much of the tedious work in application development for you.

AppWizard

AppWizard is a tool that generates a complete suite of source files and resource files for a Microsoft Foundation Class Library application (see »Figure 4.3«). It is important that AppWizard be used first during the development of a Visual C++ application because it creates source code that is compatible with ClassWizard.

By selecting options in AppWizard, you can create C++ source files for skeleton applications with differing levels of functionality. If you select all of the AppWizard options, generate a project, and then build it without adding a single line of code, you'll get an application for Windows with the following features:

•	A multiple document interface (MDI).

•	Menus and dialog boxes for opening and saving files, previewing print jobs, and printing.

•	Support for object linking and embedding (OLE).

•	Support for Help.

•	A functional toolbar and status bar.

You access AppWizard from the Visual Workbench Project menu.

ClassWizard

ClassWizard (see »Figure 4.4«) is a tool that allows you to:

•	Create new classes.

•	Map messages to class-member functions.

•	Map controls to class-member variables.

Creating a new class using ClassWizard is as simple as selecting a base class from a list of available base classes and typing in the name of the new class. ClassWizard automatically creates the necessary source files and declaration and implementation code to derive the new class.

You use ClassWizard most often to "bind" user-interface objects to code. After creating the user-interface objects in App Studio, you use ClassWizard to create member functions and message maps to handle messages from these objects.

For example, you can create the menu item "Test" and add it to the Edit menu in App Studio. You can then open ClassWizard, select the class to which you want the message-handler function added, select the resource identifier, (ID_EDIT_TEST in the Object ID list), specify that it is a COMMAND in the Messages list, and choose the Add Function button. After presenting you with a message box to allow you to alter the function name, ClassWizard inserts the message-map entry, function prototype, and skeleton function code.

You can also create message-handler functions for standard Windows messages, such as WM_MOUSEMOVE. ClassWizard displays a list of standard Windows messages for each of the classes that can handle messages. To hook up a message with a message-handler member function, you just select a class, select the message you want to handle, and choose the Add Function button.

ClassWizard can also be used to automate development of most of the code needed for getting data into and out of dialog boxes and for checking the validity of user input to a dialog-box edit control. ClassWizard's dialog-data-exchange feature creates source code to map data from dialog-box controls to class-member variables. The dialog-data-validation feature creates source code to respond to incorrect user entries in a dialog box.

You can access ClassWizard from the Visual Workbench Browse menu or the App Studio Resource menu.


  The Development Process

Developing a Visual C++ application can be broken into two stages: creating the application and developing the application.


  Creating the Application

The first step in creating a Visual C++ application is to use AppWizard to generate a set of application starter files. (see »Figure 4.5«). These starter files will be used by ClassWizard during the development stage.

To run AppWizard, you start Visual Workbench and choose AppWizard from the Project menu. You then specify a name for the project and select a location for the source files. You can also select from the available options in AppWizard's Options dialog box. When first exploring AppWizard, you might want to start with the default options.

When you choose OK, AppWizard creates all the files required for a standard Visual C++ application, including source files, resource files, and a Visual Workbench project file. Visual Workbench then loads the project. You can immediately compile and link the files by choosing Build Targetname (where Targetname represents the name of the project you created) from Visual Workbench's Project menu.


  Developing the Application

This section describes how to develop a Visual C++ application using Visual Workbench, App Studio, AppWizard, and ClassWizard. Since so much of the development process involves Visual Workbench, the Visual Workbench tools are also introduced.

The development stage of an application for Windows involves editing source and resource files, compiling and linking, testing, and debugging. These activities are repeated throughout a normal development cycle. There is an order involved, however, because you always create user-interface objects (resources) first, then use ClassWizard to create the code shell, and use Visual Workbench to write the functional code.


  Creating and Editing User-Interface Objects

»Figure 4.6« shows the starter files that are created by AppWizard. Although AppWizard creates some basic user-interface objects (such as menus, a toolbar, and so on) when it generates the resource files, you will probably want to add user-interface objects of your own.

You can open App Studio within Visual Workbench by choosing App Studio from the Tools menu. This opens App Studio and passes it the name of the resource file (.RC). To learn how to use App Studio to create and edit user-interface objects, see the App Studio User's Guide.


  Connecting User-Interface Objects to Code

After creating the user-interface objects in App Studio, the next step is to create the Microsoft Foundation Class Library code that supports them. »Figure 4.7« shows the tools, ClassWizard and Visual Workbench, that are used to connect the resources to code.

You use ClassWizard to generate the message-handler functions and message maps for each user-interface object created in App Studio.

With the prototype and function code inserted by ClassWizard, you use Visual Workbench to add the code. ClassWizard lets you jump directly into Visual Workbench at the proper location to add code.

You may prefer to connect each user-interface object to code as it is created in App Studio, or wait until you are finished creating all of your resources in App Studio before using ClassWizard and Visual Workbench to connect them to code.


  The Complete Process

»Figure 4.8« shows how AppWizard, App Studio, ClassWizard, and Visual Workbench work together. If you have developed applications for Windows prior to Visual C++, you can see the "standard" development process by mentally removing ClassWizard and AppWizard from the picture — where Visual Workbench represents the source editor and App Studio represents the resource editor (or editors) you might have used to create source and resource files. This development model has been widely used and is fully supported in Visual C++.

AppWizard helps you by creating customized starter files in a location of your choice. ClassWizard keeps track of source code and user-interface objects and lets you derive classes, connect resource identifiers to code, and edit source code from a single point.

Visual Workbench coordinates all the other tools by maintaining the project information. Visual Workbench is not just where you edit files; it is also where you manage the source code, and build and debug the application. The next two sections describe the tools you use in Visual Workbench during application development.


  Managing Your Source Code

ClassWizard and the Visual Workbench source browser are source-code management tools that allow you to access your source code from a structured viewpoint.

As discussed earlier, ClassWizard keeps track of all resource objects and member functions. It lets you immediately jump to the message-handler source code from ClassWizard so that you can edit it.

The Visual Workbench browser is another Visual C++ tool for managing source code. You open the browser by opening the Browse window in Visual Workbench (see »Figure 4.9«). You can use the browser to:

•	Graphically display hierarchical class trees of derived or base classes.

•	Graphically display all the functions that call, or are called by, a particular function.

•	Display a list of source-code locations where references to a symbol are made and where a symbol is defined.

•	Display member-function and member-variable lists for C++ classes.

•	Jump directly to definitions and references from list entries in the Browse window or from a selected symbol in a source file.

You can use the browser to show relationships between base and derived classes and between calling and called functions. You can also jump directly from the Browse window to source code simply by double-clicking a reference or definition in the Browse window. Or, without using the Browse window, you can select a symbol in a source file, jump to its definition or first reference, view all references to the symbol, and return to the original location, all using menu commands or shortcut keys.


  Building and Running Your Application

Visual Workbench helps you build, run, and debug your application with as little interruption as possible. You can build a project in Visual Workbench by:

•	Choosing the Build or Rebuild All toolbar button.

•	Choosing the Build Targetname or Rebuild All Targetname command from the Project menu.

When the build is complete, you can run the program in the debugger (assuming it includes debug information) by:

•	Choosing the Run toolbar button.

•	Choosing the Go command from the Debug menu.

You can run the program outside the debugger by choosing Execute Targetname from the Project menu.


  Debugging Your Application

You can use the Visual Workbench debugger to debug your application within Visual Workbench. The Visual Workbench debugger is a Windows-hosted debugger that is integrated with Visual Workbench and compatible with Microsoft CodeView (see »Figure 4.10«).

The Visual Workbench debugger has many powerful features, including:

•	Breakpoints for breaking a program at a location, on an expression evaluation, or on a Windows message or class of messages

•	A QuickWatch dialog box for examining and changing variable values

•	A Watch window for examining specific variables and expressions

•	A Locals window for examining local variables

•	A Memory window for examining memory contents

•	A Registers window for examining and changing hardware register values

•	Tracing commands to step over, step into, or step out of functions

•	Multi-threaded debugging capabilities

•	Structured exception handling

•	Mixed source and assembly listings and assembly-line tracing

To use the Visual Workbench debugger, you must build your application with the Debug configuration. You then set breakpoints and run the application in a debug session from Visual Workbench.

When the debugger reaches a breakpoint, you have several options. You can examine variables or expressions using the Watch window, the Locals window, or the QuickWatch dialog box. Or you can single-step through the code, choosing to step over functions or trace into functions that are encountered.


  For More Information

The topics introduced in this chapter are covered in detail in a number of places in the Visual C++ printed documentation. Please refer to the following documentation for more information:

•	»Chapter 5«, "A Test Drive of Visual C++," contains a quick tutorial that walks you through development of a sample Visual C++ program.

•	The Class Library User's Guide contains a comprehensive tutorial on developing a Visual C++ application.

•	Chapters 1 through 6 of the Class Library Reference cover conceptual information on using the Microsoft Foundation classes.

•	Chapters 1 through 7 of the Visual Workbench User's Guide describe how to use general Visual Workbench features.

•	Chapter 7 of the Visual Workbench User's Guide describes AppWizard in detail and discusses both using ClassWizard and running App Studio from within Visual Workbench.

•	Chapters 3 through 8 of the App Studio User's Guide describe how to use general App Studio features.

•	Chapter 9 of the App Studio User's Guide discusses using ClassWizard from within App Studio and presents a comprehensive description of ClassWizard.


  Chapter 5  A Test Drive of Visual C++

This chapter takes you through a development session using Visual C++ tools to create, build and debug a Microsoft Foundation Class Library C++ application. This tutorial demonstrates the core Visual C++ development tools and the general development process. You can probably finish the entire tutorial in about an hour.

This tutorial doesn't teach you about the C++ foundation classes, but it does give you a tour of the product and it shows you how easy it is to get started with Visual C++ programming. For a more detailed tutorial, see the Scribble tutorial in the Class Library User's Guide. If you are unfamiliar with the tools and overall development process, it may be helpful to read »Chapter 4«, "Developing a Visual C++ Application," in this guide before starting this tutorial.

The tutorial includes three sections: "Developing an Application," "Browsing the Application," and "Debugging the Application." The first section develops the application that is used by the other two sections.

Developing an Application  This section demonstrates how to use AppWizard to generate a set of starter files for an application. It then describes how to use App Studio to create Windows-based resources and Class Wizard to create and manage the code that supports these resources. When you complete this section, you will have a completed Visual C++ application.

Browsing the Application  This section shows you how to use the Visual Workbench source browser to examine class information in the Browse window or to jump to definitions and references from a symbol in a source file.

Debugging the Application  In this section, you will use the Visual Workbench integrated debugger to set a breakpoint, examine variables, and trace through code.


  Developing an Application Using Visual C++ Tools

The application you'll create (called MYAPP) is based on a subset of the VIEWEX sample application, provided with the Microsoft Foundation Class Library samples. MYAPP lets you open new child windows in a Multiple Document Interface (MDI) application, each displaying an initial message. When you choose Change Text in MYAPP's Edit menu, a dialog box opens and allows you to change the text of the message in the currently active child window.

MYAPP starts off as a default application created by AppWizard. You'll add eight lines of code to this starter application to print a message in each new document window (MDI child window) that is opened. Then, using the integrated Visual C++ tools, you'll add a dialog box to edit the message and a menu command to open the dialog box.


  Running AppWizard

The first step in creating a foundation class Visual C++ application is to use AppWizard to create the starter application.

To generate a set of application starter files using AppWizard

1.	Open Visual Workbench by double-clicking the Visual C++ icon in the Microsoft Visual C++ Program Manager group.

2.	From the Visual Workbench Project menu, choose AppWizard

The MFC AppWizard dialog box appears (see »Figure 5.1«). The dialog box requires that you enter a project name and select a project location.

3.	In the Project Name box type myapp

4.	Use the graphical directory controls to select the directory under which you want the MYAPP directory to be created (this tutorial will use C:\MSVCNT\).

Although MYAPP will use the default AppWizard template, you could open AppWizard's Options dialog box and customize the application. By default the following options are selected in the Options dialog box:

•	Multiple Document Interface

•	Initial Toolbar

•	Printing and Print Preview

•	Generate Source Comments

You could also open the Classes dialog box from AppWizard and change the names of classes and files in the starter application. (AppWizard derives a set of names based on the project name you enter.) For this tutorial you should not change the classes or files.

5.	In the MFC AppWizard dialog box, choose OK.

AppWizard presents you with a confirmation dialog box, titled New Application Information, that shows all of the files and classes it is about to create (see »Figure 5.2«).

6.	Choose Create to confirm this selection.

AppWizard generates the starter files, creates a project, and loads the project into Visual Workbench.

Since this is a new project, Visual Workbench scans through all the project files to create an internal list of dependencies so it knows what files to recompile when you build the project. For example, if a source file includes a header file and you edit the header file, the source file must be recompiled.


  Building and Running MyApp

You may want to see just how much functionality you get with a basic AppWizard starter project created with default options. In this optional step you'll build and run MYAPP.

To build and run the application

1.	Click Visual Workbench's »Build« button on the toolbar (or choose Build MYAPP.EXE from the Project menu).

As MYAPP is being built, the Output window appears and you'll see output from each of the tools — the compiler and linker, for instance — as the build progresses.

By default, a debug version of MYAPP is built.

2.	To run MYAPP, choose Execute MYAPP.EXE from the Project menu.

MYAPP (see »Figure 5.3«) is an MDI application that contains a toolbar and a status bar that displays prompt messages. Among other features are a File menu with Open and Save commands (already hooked up to COMMDLG dialog boxes), a Window menu to arrange child windows opened from the File menu's New command, an About box, and much more.

3.	Close MYAPP before continuing by choosing Exit from the File menu.


  Modifying the Application

In this step, you'll add a few lines of code to the application to initialize and display a message string. In Microsoft Foundation Class Libraries version 2.0, the data is stored in document classes and displayed using view classes.

Note  Every line of code to be added in this tutorial is indicated by an arrow in the left-hand margin.

First, you'll use the following procedure to open MYAPPDOC.H and add a member variable to the class CMyappDoc.

To edit MYAPPDOC.H

1.	From Visual Workbench's toolbar, choose the »Project Files« toolbar button (on the far left of the toolbar).

A list of project files for MYAPP appears.

2.	In the project files list, click on MYAPPDOC.H.

A source window opens on the file. AppWizard constructed the files MYAPPDOC.CPP and MYAPPDOC.H, derived from the project name you entered, to contain the document class CMyappDoc.

3.	Find the CMyappDoc class declaration and add the m_strData declaration in the public section:

// Attributes

public:

CString m_strData;  // add for tutorial

4.	Choose the »Save« toolbar button to save the file.

Next, you'll edit MYAPPDOC.CPP to initialize the member variable m_strData for each new document window:

To edit MYAPPDOC.CPP

1.	Using the Project Files toolbar button, open MYAPPDOC.CPP.

2.	Find the CMyappDoc::OnNewDocument function and add the specified line following the comments:

BOOL CMyappDoc::OnNewDocument()

{

if (!CDocument::OnNewDocument())

return FALSE;

// TODO: add reinitialization code here

// (SDI documents will reuse this document)

m_strData = "Sample Data String";

return TRUE;

}

3.	Choose the »Save toolbar button« to save the file.

Finally, you need to edit MYAPPVW.CPP to display the text.

To edit MYAPPVW.CPP

1.	Using the »Project Files« toolbar button, open MYAPPVW.CPP.

 	2.	Find the CMyappView::OnDraw function and add the specified lines following the comments:

void CMyappView::OnDraw(CDC* pDC)

{

CMyappDoc* pDoc = GetDocument();

// TODO: add draw code here

CRect rect;

GetClientRect(rect);

pDC->SetTextAlign(TA_BASELINE | TA_CENTER);

pDC->SetBkMode(TRANSPARENT);

pDC->TextOut(rect.Width() / 2, rect.Height() / 2,

pDoc->m_strData, pDoc->m_strData.GetLength());

}

3.	Choose the Save button to save the file.

At this point, if you build and run the application, you'll see that each new MDI window you create displays the string "Sample Data String."

To build and run the application:

1.	Click Visual Workbench's »Build« button on the toolbar (or choose Build MYAPP.EXE from the Project menu).

If necessary, correct any typing errors you might have made that cause syntax errors and repeat step 1. When there are no errors reported, continue.

2.	To run MYAPP, choose Execute MYAPP.EXE from the Project menu.


  Adding User-Interface Objects to MyApp

In this step, you use App Studio to design a new dialog box, and you use ClassWizard to generate the code that supports it.


  Creating a Dialog Box

In this step you will create a new dialog box and add an edit control and a static text control to it. The dialog box will let the user change the message that is displayed in the active child window.

To create MYAPP's dialog box in App Studio

1.	Open App Studio by choosing App Studio from the Visual Workbench Tools menu.

When opened from Visual Workbench, App Studio compiles the current project's resource file.

2.	Choose the »Dialog Box« toolbar button to open a new dialog box form (see »Figure 5.4«).

Notice that the OK and Cancel buttons are already added for you.

3.	From the Control Palette, drag the edit control into the middle of the dialog box (see »Figure 5.5«).

If the Control Palette did not appear when you opened the Dialog Editor, press F1 or choose Show Control Palette from the Window menu.

4.	From the Control Palette, drag the static text control to the left of the edit control.

5.	In the static text control, type Edit

Notice that as soon as you start to type, the property page appears. When you click the dialog box window again, the property page disappears (unless you choose to pin it open).

6.	Now double-click the title (Dialog) and, in the caption box of the properties window that opens, type Change Text in place of Dialog

7.	Finally, size the two controls and the dialog box itself (see »Figure 5.6«).

8.	Save your work in App Studio by clicking the »Save« toolbar button.


  Creating a Dialog Class and Adding a Member Variable

You can now use ClassWizard to connect this new dialog box to Microsoft Foundation Class framework code.

To create a dialog class

1.	Make sure the dialog box from the previous procedure is still open in App Studio.

2.	Open ClassWizard by clicking the »ClassWizard« toolbar button (or by choosing ClassWizard from the Resource menu.)

Since the dialog editor is still active, ClassWizard's Add Class dialog box appears (see »Figure 5.7«).

3.	In the Class Name box, type CEnterDlg, the name of the new dialog class.

Notice that the filenames "enterdlg.h" and "enterdlg.cpp" are automatically generated in the Header File and Implementation File boxes.

4.	Choose the Create Class button.

Class Wizard creates the header and implementation files and generates class declarations and skeleton implementation code. It then returns you to the main ClassWizard dialog box (see »Figure 5.8«).

Don't close ClassWizard yet, you'll be using it in the next procedure.

The dialog class now exists, but you still need to have the program initialize the data for the edit control and retrieve data that has been entered into the edit control.

ClassWizard and the Microsoft Foundation Class framework make this easy with dialog data exchange (DDX). To implement DDX, you associate a member variable with a dialog box control. The framework transfers any initial values to the control when the dialog box is displayed, and updates the member variable with any data the user has entered when the dialog box is dismissed.

You use ClassWizard to add a member variable to the CEnterDlg class for the dialog's edit control data.

To add a member variable to CEnterDlg

1.	With the CEnterDlg Class showing in the Class Name drop-down list box, click ClassWizard's Edit Variables button.

2.	Select the resource ID for the edit control (IDC_EDIT1),

 	3.	Choose the Add Variable button.

The Add Member Variable dialog box appears (see »Figure 5.9«).

4.	In the Member Variable Name box, type: m_strInput

5.	In the Property box, choose Value.

6.	In the Variable Type drop-down list box, select CString.

 	7.	Choose OK to exit the Add Member Variable dialog box.

8.	Choose Close to exit the Edit Member Variables dialog box.

9.	Choose OK to exit ClassWizard.

ClassWizard creates the required code in the CEnterDlg class for the m_strInput member variable in the files ENTERDLG.H and ENTERDLG.CPP.

10.	Double-click in the Dialog Editor window's system box to close the window.


  Adding a Menu Command

In this step you use App Studio to create a new menu command, and Class Wizard to connect it to code. You then use Visual Workbench to write the code that will invoke the new dialog box and to handle its data when a user chooses the menu command.

To add a menu command

1.	Click the resource browser window, titled MYAPP.RC (MFC Resource Script), to bring it to the front (see »Figure 5.10«).

2.	In the Type box, select Menu.

3.	In the Resources box, select IDR_MYAPPTYPE.

This selects the menu that applies to each of the child windows, not the frame window (the menu when no child windows are open).

4.	Choose Open.

The menu editor window appears.

5.	Click on the Edit menu in this window and the menu appears.

6.	At the bottom (below Paste), type &Change Text...

As soon as you begin to type, the property page for that menu item appears and the text you type appears in the Caption box and the menu editor window.

Notice that the ID box is empty. Leave it empty and App Studio will generate an ID for the menu item when you close the property page. If you want to enter it manually in the ID box, type: ID_EDIT_CHANGETEXT. (It may be necessary to type it in if you explore the ID drop-down list.)

7.	In the property page's Prompt box type:
Opens a dialog box to change window text

This text will automatically appear in the prompt section of the status bar whenever the menu command is highlighted by the user.

8.	Press ENTER to close the property page for your new command.

9.	Remove all menu commands above Change Text by selecting each and pressing the Delete key.

10.	Save your work by clicking the »Save« toolbar button.


Creating the Menus Message-Handler Code
  Creating the Menu's Message-Handler Code

Now you need to create the code that will be called when the user chooses the Change Text menu command. In the Microsoft Foundation Class Library, this means that you need both a message map entry and a member function associated with the menu command.

To add message-handler code for the menu command

1.	In App Studio, open ClassWizard by choosing the »ClassWizard« toolbar button.

2.	In the Class Name drop-down list, select CMyAppDoc.

This is the class you want the message handler code added to.

3.	In the Object IDs list, select the menu item's resource ID (ID_EDIT_CHANGETEXT).

4.	In the Messages list, select COMMAND.

(Do not select UPDATE_COMMAND_UI, which is used to dynamically update menu commands.)

5.	Choose the Add Function button.

The Add Member Function dialog box appears (see »Figure 5.11«) to allow you to change the name that ClassWizard has derived for the member function.

6.	Leave the name as it is (OnEditChangeText) and choose OK.

Notice that the OnEditChangeText function is listed in the Member Functions box and that the COMMAND entry in the Messages box has a hand symbol next to it.

Don't close ClassWizard just yet, you'll be using it in the next procedure.


  Writing the Message-Handler Function

ClassWizard created a shell of the message-handler function. Now you need to write the body of the function. You can use ClassWizard to jump directly to the code in a Visual Workbench source window for any member functions that have been added by ClassWizard (see »Figure 5.12«). This procedure assumes you have just finished the previous procedure and the OnEditChangetext function is selected in ClassWizard.

To open a Visual Workbench window at the message-handler function

1.	In ClassWizard, click Edit Code.

2.	Add the following code after the TODO comments:

void CMyappDoc::OnEditChangetext()

{

// TODO: Add your command handler code here

CEnterDlg dlg; 	// create a CEnterDlg variable

dlg.m_strInput = m_strData;	// initialize the edit string

if (dlg.DoModal() != IDOK)	// open dialog box

return;

m_strData = dlg.m_strInput;	// retrieve edit string

UpdateAllViews(NULL);   	// general update

}

3.	Include the ENTERDLG.H header file at the top of MYAPPDOC.CPP:

// myappdoc.cpp : implementation of the CMyappDoc class

//

#include "stdafx.h"

#include "myapp.h"

#include "myappdoc.h"

#include "enterdlg.h"

4.	Choose the Save toolbar button to save the file.


  Building and Running the Application

The final step in this section of the tutorial is to build and run the MYAPP application.

To build and run MYAPP

1.	From the Visual Workbench Project menu, choose Build MYAPP.EXE

Or, choose the »Build« toolbar button.

Assuming you've typed everything correctly and the build is successful, you can now run the program. If you have syntax errors, correct any typing mistakes and build the program again.

2.	From the Visual Workbench Project menu, choose Execute MYAPP.EXE.

The application, shown in »Figure 5.13«, should have the following properties:

•	A default message "Sample Data String" appears for every new window opened

•	The Edit menu has one command, Change Text

•	When you highlight Change Text (or any command), a help message is displayed on the status bar.

•	When you open the Change Text dialog box the default message is already in the edit box. Any message you type in the edit box appears in the active child window when you close the dialog box.

3.	Close the MYAPP application by choosing Close from the File menu.


  Browsing MyApp

This section of the tutorial uses the MYAPP project you created in the preceding section. By default, generation of browser information is enabled and a browser database is created.


  Examining a Derived Class Graph

In this step you'll use the Browse window to display a Derived Class Graph, and then pick a member variable of the class and jump to the first location in the source code where it is referenced.

To browse a Derived Class Graph

1.	From Visual Workbench Browse menu, choose Open MYAPP.BSC.

The Browser window, shown in »Figure 5.14«, opens.

2.	From the drop-down list in the Type box, select Derived Class Graph.

3.	In the Symbol box type CD*

The asterisk ( * ) symbol is a wildcard that tells the browser to give you a list of all classes that start with CD. Of course, you can also type the complete name of the class, but the wildcard is useful if you don't remember the exact name or don't want to type the full name.

4.	Choose the Display Result button.

The Symbols dialog box opens with a list of classes that start with the letters "CD."

5.	In the Symbols box, double-click CDialog(class).

»Figure 5.15« shows the results of the query. Each node in the Derived Class Graph represents a class. When you select a class on the graph, the member variables and member functions of the class are displayed in the upper-right panel, and a list of source locations where the class is defined and referenced appears in the lower-right panel.

To jump to a reference from the Browse window

1.	Click the CEnterDlg class at the bottom of the graph. (See »Figure 5.16«.)

CEnterDlg is the class you added, using ClassWizard, to handle the Change Text dialog box. CEnterDlg now appears in the Query group's Symbol box since it is selected.

In the upper-right panel you will see the member variable you added to the class using ClassWizard (CEnterDlg::m_strInput).

2.	Click on CEnterDlg::m_strInput in the upper-right panel.

CEnterDlg::m_strInput now appears in the Symbol box and there is a list of definitions and references for this member variable in the lower-right panel.

3.	In the lower-right panel, double-click the first reference in the list of references: c:\msvcnt\myapp\myappdoc.cpp

A Visual Workbench source window, shown in »Figure 5.17« opens on the corresponding file at the location of the first reference to CEnterDlg::m_strInput.

If you want to continue browsing references or definitions, you can:

•	Choose Next from the Browse Menu to jump to the next reference.

•	Choose Go to Definition from the Browse Menu to jump to the definition.

•	Return to the Browse window to select another reference or definition.

Note that you can always use the definitions and references commands on the Browse menu without entering the Browse window.

For example, put the insertion point on any symbol in a source file and press SHIFT+F11 (Go to Reference from the Browse Menu) and you jump to the first reference of that symbol, or press F11 and you jump to the symbol's definition.

You don't need to open the Browser window to use these commands since the browser database .BSC file loads automatically.


  Examining a Base Class Graph

It is often helpful, especially when learning the architecture of the foundation classes, to view the inheritance path of a class—that is, to view its base class, the base class of its base class, and so on. Base class graphs are usually composed of a single list of class nodes unless there is multiple inheritance somewhere in the hierarchy. Also, Base Class Graphs are arranged so that each base class appears to the right of its derived class.

To browse a Base Class Graph

1.	Return to the Browse window.

2.	In the Symbol box, type CEnterDlg

Or, if you've kept the derived graph in the browser, simply click on the CEnterDlg class node in the graph to put its name in the Symbol box.

3.	In the Type drop-down list box, select Base Class Graph.

4.	Choose Display Result.

The result of this query (see »Figure 5.18«) shows the line of inheritance for the CEnterDlg class. The first node to the right of CEnterDlg is CDialog, the framework class from which CEnterDlg is derived. To the right of CDialog is its base class, CWnd.

5.	Double-click on CWnd and it expands one level to show its base class.

6.	Choose the Expand Tree button and you can see the entire hierarchical path of the CEnterDlg class.

7.	Optionally, close or minimize the Browse window.


  Debugging MyApp

This section assumes you have loaded and built a debug version of the MYAPP project as you will have done if you completed the first section of this tutorial.


  Setting and Running to a Breakpoint

There are two ways to set a breakpoint in the Visual Workbench debugger. You can use the Toggle Breakpoints toolbar button at a location in a source file, or you can use the Breakpoints dialog box, which allows more complex breakpoint expressions. The following procedure demonstrates how to use the toolbar to set a breakpoint.

To set a breakpoint and run MYAPP to the breakpoint

1.	In Visual Workbench, open the MYAPPDOC.CPP file.

2.	Move to the end of the file (CTRL+END).

3.	Move the insertion point to the following line in the CMyappDoc::OnEditChangetext function:

m_strData = dlg.m_strInput;	// retrieve edit string

4.	Click the »Toggle Breakpoint« button on the toolbar, or press F9, to set a breakpoint.

Notice that the line changes color to indicate that the breakpoint is set. This breakpoint will be invoked whenever you close the MYAPP's Change Text dialog box during a debug session.(See »Figure 5.19«)

5.	Click the »Run« button on the toolbar, or choose Go on the Debug menu.

The MYAPP application is loaded into the debugger and run.

6.	In the MYAPP Edit menu, choose Change Text.

The Change Text dialog box appears.

7.	In the Edit text box, type New String to replace Sample Data String.

8.	Choose OK to close the Change Text dialog box.

Visual Workbench should now appear with the execution line on the breakpoint you just set.

Next, you will use the debugger to examine variables at the breakpoint. Don't close MYAPP yet.


  Examining Variables

This step demonstrates how to use the QuickWatch dialog box to view the value of a variable and add the variable to the Watch Window. It is assumed you have just finished the preceding procedure, and execution is now paused at the breakpoint.

To open QuickWatch on a variable and add it to the Watch window

1.	On the breakpoint line, place the insertion point on the variable m_strData.

2.	Click the »QuickWatch« button on the toolbar, or press SHIFT+F9.

The QuickWatch dialog box appears, displaying the contents of m_strData (see »Figure 5.20«). Since the line at the breakpoint has not yet executed, m_strData has not yet been assigned its new value.

m_strData is a variable of type CString (a class). You can hide or display its member by double-clicking the variable name, which expands or contracts the structure. Two of the members are protected and therefore cannot be viewed.

3.	Click the Add to Watch Window button to add this variable to the Watch window.

4.	Optionally, choose Watch from the Window menu to open the Watch Window.

Whereas QuickWatch is handy for examining variables on the fly, you can use the Watch window to store variables and expressions so they are readily available at any time.

The next procedure opens the Watch window (if not already opened) and shows you another way to add variables to it.

To open and use the Watch window

1.	If you haven't already done so, choose Watch from the Window menu.

The Watch window appears (see »Figure 5.21«). You should see the m_strData variable that you just added from QuickWatch. You may want to arrange the Watch window and the source window containing the breakpoint so that you can see them both at the same time.

2.	Switch to the MYAPPDOC.CPP source window, select dlg.m_strInput on the breakpoint line and copy it to the Clipboard (CTRL+C).

3.	Switch back to the Watch Window.

4.	Move the insertion point to the bottom line in the Watch Window and paste (CTRL+V) dlg.m_strInput from the Clipboard into the Watch window.

5.	Double-click dlg.m_strInput to expand the structure.

The Watch window now contains both the CString variables that appear on both sides of the assignment operator in the line that contains the breakpoint:

m_strData = dlg.m_strInput;

6.	Choose the »Step Over« toolbar button.

The execution point is now on the line following the breakpoint line. Notice that the dlg.m_strInput value has been assigned to m_strData, since both variables now show the same values in the Watch window.

7.	Choose the »Run« button on the toolbar to resume the MYAPP program.

The MYAPP application appears again. Don't close MYAPP if you want to continue the tutorial and learn about other trace commands.


  Tracing Through Code

Although you used a couple of the trace commands in the last procedure, this procedure exercises them all. It assumes you have just finished the preceding procedure.

To trace through code

1.	In the MyApp application, open and close the ChangeText dialog box by choosing Change Text from the Edit menu.

The execution should now be stopped at the breakpoint.

2.	Open the file MYAPPVW.CPP and move the insertion point to the first line in the CMyappView::OnDraw function:

CMyappDoc* pDoc = GetDocument();

3.	Choose Step to Cursor on the Debug menu.

The current insertion point location acts as a temporary breakpoint.

4.	Choose the »Step Into« toolbar button.

Notice that you traced into the opening brace of the GetDocument function in the same source file.

5.	Now choose Step Into again.

Execution is now at the first line of the GetDocument function:

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyappDoc)));

6.	Choose Step Into again.

This time you've trace into the Microsoft Foundation Class library source code (the OBJCORE.CPP file). Although you may want to trace through this library code, you probably want to go back to the MYAPPVW.CPP file.

7.	Choose the »Step Out« toolbar button.

You have returned to the function call in MYAPPVW.CPP.

In general, it's a good idea to step over most framework function calls. You can use the Step Out command to trace into a function that you don't want to step all the way through.

8.	To conclude this tutorial, choose the Run button on the toolbar and exit MYAPP.

You should see a message box indicating that the process has terminated normally, meaning that the debugging session has finished and the program being debugged has exited.


  For More Information

If you've completed all the procedures so far, you now have a pretty good idea of how to use the tools provided with Visual C++ to create, browse and debug Microsoft Foundation Class applications.

The tutorial has shown you how to use AppWizard to create the starter files, how to use App Studio to create the resource objects, and how to use ClassWizard to create code to support these objects and help navigate among them so you can add functional code. The tutorial has also shown how to use Visual Workbench to edit, browse and debug code.

Use the information in the following books to help complete your understanding of the Microsoft Foundation Class Library or any of the Visual C++ tools:

•	Class Library User's Guide for tutorial and overview information.

•	Class Library Reference for Microsoft Foundation Class Library classes and function reference.

•	Visual Workbench User's Guide for help on editing, building, browsing, debugging and using AppWizard.

•	App Studio User's Guide for help using the resource editor and Class Wizard.


  Appendix A  Accessibility for People with Disabilities

Microsoft is committed to making its products and services easier for everyone to use. This appendix provides information about the following products and services, which make the Microsoft Visual C++ Development System for Windows NT more accessible for people with disabilities:

•	»Microsoft services for people who are deaf or hard-of-hearing«.

•	»Keyboard layouts  for single-handed users«.

•	»Microsoft documentation on audio cassettes and floppy disks«.

•	»Hints for customizing Microsoft Windows NT«.

•	»Other products and services for people with disabilities«.

Note  The information in this section applies only to users who purchased Windows NT in the United States. If you purchased Windows NT outside the United States, your Windows NT package contains a subsidiary information card listing Microsoft support services telephone numbers and addresses. You can contact your subsidiary to find out whether the type of products and services described in this appendix are available in your area.


  Microsoft Services for People Who Are Deaf or Hard-of-Hearing

Through a text telephone (TT/TDD) service, Microsoft provides people who are deaf or hard-of-hearing with complete access to Microsoft product and customer services.

You can contact Microsoft Sales and Service on a text telephone by dialing (800) 892-5234 between 6:30 A.M. and 5:30 P.M. Pacific time. For technical assistance you can contact Microsoft Product Support Services on a text telephone at (206) 635-4948 between 6:00 A.M. and 6:00 P.M. Pacific time. Microsoft support services are subject to Microsoft prices, terms, and conditions in place at the time the service is used.


  Keyboard Layouts for Single-Handed Users

Microsoft distributes Dvorak keyboard layouts that make the most frequently typed characters on a keyboard more accessible to people who have difficulty using the standard "QWERTY" layout. There are three Dvorak layouts: one for two-handed users, one for people who type with their left hand only, and one for people who type with their right hand only. The left-handed or right-handed keyboard layouts can also be used by people who type with a single finger or a wand. You do not need to purchase any special equipment in order to use these features.

Microsoft Windows NT already supports the two-handed Dvorak layout, which can be useful for coping with or avoiding types of repetitive-motion injuries associated with typing. To get this layout, choose International from the Windows NT Control Panel. The two layouts for people who type with one hand are distributed as Microsoft Application Note GA0650. It is also contained in file GA0650.ZIP on most network services or GA0650.EXE on the Microsoft Download Service.


  Microsoft Documentation on Audio Cassettes and Floppy Disks

People who have difficulty reading or handling printed documentation can obtain most Microsoft publications from Recording for the Blind, Inc. Recording for the Blind distributes these documents to registered members of their distribution service either on audio cassettes or on floppy disks. The Recording for the Blind collection contains more than 80,000 titles, including Microsoft product documentation and books from Microsoft Press. You can contact Recording for the Blind at: Recording for the Blind, Inc., 20 Roszel Road, Princeton, NJ 08540. Or phone inside the U.S. (800) 221-4792, phone outside the U.S. (609) 452-0606, Fax (609) 987-8116.


  Customizing Windows NT

There are many ways you can adjust the appearance and behavior of Microsoft Windows NT to suit varying vision and motor abilities without requiring any additional software or hardware. These include ways to adjust the appearance as well
as the behavior of the mouse and keyboard. The specific methods available depend on which operating system you are using. Application notes are available describing the specific methods available for each operating system. For information relating to customizing Windows NT 3.1, see Application Note WN0789.

The application note is included on the Microsoft Windows NT  Driver Library
in the file ACCESS.EXE. If you have a modem, you can download Microsoft Windows Driver Library components, including the following, from network services:

•	CompuServe®

•	GEnie™

•	Microsoft OnLine

•	Microsoft Download Service (MSDL), which you can reach by calling (206) 936-MSDL (936-6735) any time except between 1:00 A.M. and 2:30 A.M. Pacific time. Use the following communications settings:

For this setting	Specify
Baud rate	1200, 2400, or 9600
Parity	None
Data bits	8
Stop bits	1
•	Various user-group bulletin boards (such as the bulletin-board services on the Association of PC User Groups network)

People within the United States who do not have a modem can order disks by calling Microsoft Product Support Services at (206) 637-7098 or (206) 635-4948 (text telephone).


  Getting More Information

For more information on Microsoft products and services for people with disabilities, contact Microsoft Sales and Service at (800) 426-9400 (voice) or
(800) 892-5234 (text telephone).

The Trace R&D Center at the University of Wisconsin−Madison produces a book and a compact disc that describe products that help people with disabilities use computers. The book, titled Trace ResourceBook, provides descriptions and photographs of about 2,000 products. The compact disc, titled CO-NET CD, provides a database of more than 17,000 products and other information for people with disabilities. It is issued twice a year.

You can contact the Trace R&D Center at: Trace R&D Center, S-151 Waisman Center, 1500 Highland Avenue, Madison, WI 53705-2280. Or at the voice telephone (608) 263-2309, text telephone (608) 263-5408, or Fax (608) 262-8848.

For general information and recommendations on how computers can help specific people, you should consult a trained evaluator who can best match your needs with the available solutions. An assistive technology program in your area will provide referrals to programs and services that are available to you. To locate the assistive technology program nearest you, you can contact: the National Information System, Center for Developmental Disabilities, Benson Building, University of South Carolina, Columbia, SC 29208. Or voice/text telephone outside South Carolina (800) 922-9234, ext. 301, voice/text telephone inside South Carolina (800) 922-1107, voice/text telephone outside the U.S. (803) 777-6222, or Fax (803) 777-6058.


Figure 1.1 The Installation Options Dialog Box


Figure 1.2 The Custom Installation Dialog Box


Figure 1.3 The Directory Options Dialog Box


Figure 1.4 The Microsoft Foundation Class Options Dialog Box


Figure 1.5 The Tool Options Dialog Box


Figure 1.6 The Help File Options Dialog Box


Figure 1.7 The Sample Source Options Dialog Box


Figure 1.8 The Installation Options Dialog Box


Figure 3.1 The Open Project Dialog Box


Figure 3.2 The Project Options Dialog Box


Figure 4.1 Visual Workbench


Figure 4.2 App Studio


Figure 4.3 AppWizard


Figure 4.4 ClassWizard


Figure 4.5 Creating the Visual C++ Application Starter Files


Figure 4.6 Creating and Editing User-Interface Objects


Figure 4.7 Connecting User-Interface Objects to Code


Figure 4.8 The Visual C++ Development Process


Figure 4.9 The Visual Workbench Browse Window


Figure 4.10 The Visual Workbench Debug Windows


Figure 5.1 The MFC AppWizard Dialog Box


Figure 5.2 The New Application Information Dialog Box


Build button


Figure 5.3 The Default AppWizard Application


Project Files toolbar button


Save toolbar button


Project Files toolbar button


Build button


Dialog Box toolbar button


Figure 5.4 The New Dialog Box Form


Figure 5.5 Dragging and Dropping Controls in the Dialog Editor


Figure 5.6 The Completed Change Text Dialog Box


Save toolbar button


Class Wizard toolbar button


Figure 5.7 ClassWizards Add Class dialog box


Figure 5.8 The ClassWizard dialog box


Figure 5.9 The Add Member Variable Dialog Box


Figure 5.10 The App Studio Resource Browser Window


Save Toolbar button


Class Wizard toolbar button


Figure 5.11 Adding a Message Handler in ClassWizard


Figure 5.12 A Visual Workbench Source Window Opened by ClassWizard


Build toolbar button


Figure 5.13 The MyApp Application


Figure 5.14 The Browser Window


Figure 5.15 Derived Class Graph of the CDialog Class


Figure 5.16 Jumping to a Reference from the Browser Window


Figure 5.17 The First Reference


Figure 5.18 Base Class Graph of the CEnterDlg Class


Toggle Breakpoint button


Figure 5.19 Setting a Breakpoint


Run button


QuickWatch button


Figure 5.20 The QuickWatch Dialog Box


Figure 5.21 The Watch Window


Step Over toolbar button


Run button


Step Into toolbar button


Step Out toolbar button


Introduction
Visual Workbench User's Guide

Introduction

The Microsoft® Visual C++™ Development System for Windows™ and Windows NT™ 32-Bit Edition, includes fully integrated Windows-hosted development tools and a "visual" user-interface-driven paradigm to the traditional C/C++ development process.

Microsoft Visual Workbench is the cornerstone of the Visual C++ development system.  Visual Workbench is a powerful development environment, containing an integrated editor, debugger, and graphical browser. Visual Workbench is the central point from which all other development activities are performed.  From Visual Workbench menus you can:

•	Invoke the Visual C++ build tools, such as the compiler and linker.

•	Run the App Studio resource editor to develop user-interface components.

•	Run AppWizard and ClassWizard to help you develop Microsoft Foundation Class Library applications.

•	Run your own tools, which can be installed on the tools menu.

Visual Workbench provides the tools you need most and makes them easy to use by integrating them with the development process.


Book Location
Visual Workbench User's Guide


  About This User Guide

This User Guide describes how to use the Visual Workbench integrated development environment to develop applications using Visual C++.

•	»Chapter 1« describes the basic components of the environment such as the toolbar, status bar, and the Help system.

•	»Chapter 2« describes how to use the integrated text editor to manage, edit, and print source files.

•	»Chapter 3« describes how to create and use projects to build your applications as well as how to use workspaces to save and restore an arrangement of windows associated with a project.

•	»Chapter 4« describes how to use the Visual Workbench browser to display relationships between program elements.

•	»Chapter 5« provides information on the Visual Workbench integrated debugger, which is compatible with the Microsoft CodeView® debugger. This chapter also describes how to set breakpoints; monitor variables, expressions, and registers; and step through code.

•	»Chapter 6« describes how to customize Visual Workbench by adding commands and applications to the Tools menu, modifying display colors, and changing the font type and size in source windows.

•	»Chapter 7« describes how App Wizard, Class Wizard and App Studio are integrated with Visual Workbench.

•	»Chapter 8« summarizes many of the Visual Workbench procedures and provides a comprehensive overview of the menus.

•	»Chapter 9« includes lists of keyboard sequences and shortcuts for Visual Workbench tasks.

•	»Chapter 10« provides a quick reference to the Visual C++ compiler and linker options accessed from Visual Workbench.


  Document Conventions

This book uses the following typographic conventions:

Example	Description
STDIO.H	Uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
char, _setcolor, __far	Bold type indicates C and C++ keywords, operators, language-specific characters, and library routines. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
	Many constants, functions, and keywords begin with either a single or double underscore. These are required as part of the name. For example, the compiler recognizes the __cplusplus manifest constant only when the leading double underscore is included. It may be difficult at first glance to distinguish a single underscore from a double underscore because the two run together on the screen. Therefore, the width of the character(s) is your guide. The sample term setcolor, in the left column above, has one underscore in front of it, while the term far has two underscores in front of it.
expression	Words in italics indicate placeholders for information you must supply, such as a filename. Italic type is also used occasionally for emphasis in the text.
[option]	Items inside square brackets are optional.
#pragma pack {1 | 2}	Braces and a vertical bar indicate a choice among two or more items. You must choose one of these items unless square brackets ([ ] ) surround the braces.
#include <io.h>	This font is used for examples, user input, program output, and error messages in text.
CL [option...]  file...	Three dots (an ellipsis) following an item indicate that more items having the same form may appear.
while() {  .  .  . }	A column or row of three dots tells you that part of an example program has been intentionally omitted.
CTRL+ENTER	Small capital letters are used to indicate the names of keys on the keyboard. When you see a plus sign (+) between two key names, you should hold down the first key while pressing the second.
	The carriage-return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
"argument"	Quotation marks enclose a new term the first time it is defined in text.
"C string"	Some C constructs, such as strings, require quotation marks.
Dynamic-Link Library (DLL)	The first time an acronym is used, it is usually spelled out.
see »Using Projects«	Hypertext cross-references are enclosed in green double chevrons. Click the term enclosed in the chevrons to display the referenced information.
CEnterDlg;	The blue box adjoining the blue code indicates that it has been altered from a previous example, usually because you are being instructed to edit it.


The Visual Workbench Environment
  Chapter 1  The Visual Workbench Environment

Microsoft Visual Workbench is an integrated programming environment that runs with the Microsoft Windows NT™ operating system. It integrates a text editor, browser, compiler, linker, debugger, make utility, and Help database.

This chapter introduces the Visual Workbench environment, shown in »Figure 1.1«. It describes how to start and exit Visual Workbench, how to arrange windows, and how to access the Help system. It also describes the toolbar and status bar.


Chapter 1 Starting and Exiting Visual Workbench
  Starting and Exiting Visual Workbench

Start Visual Workbench by double-clicking the Visual C++ icon in the Program Manager window.

If you had a project open when you last exited Visual Workbench, it is automatically loaded. Or, if you have installed Visual Workbench with command-line options to load a project or source files, the project or files will automatically load into Visual Workbench.

To quit Visual Workbench, choose Exit from the File menu. This returns you to the Windows Program Manager.


  Visual Workbench Features

Visual Workbench uses a multiple document interface (MDI) window that can contain several different types of child windows to let you edit source code, debug programs, and get status and error information. In addition, there is a toolbar for accessing commonly used functions and a status bar for displaying build information and descriptions of toolbar buttons and menu items.


  Visual Workbench Windows

There are seven types of windows available in Visual Workbench, in addition to the Windows Help window. These windows are listed below:

•	»Source windows«

•	»Output window«

•	»Browse window«

•	»Locals window«

•	»Watch window«

•	»Registers window«

•	»Memory window«


  Source Windows

Source windows, shown in »Figure 1.2«, are used to edit files containing plain text. You can open one or more windows on the same file by using the Duplicate command in the Windows menu. To learn how to use the Visual Workbench editor with source windows see »Chapter 2« "Using the Editor."


  Output Window

The Output window, shown in »Figure 1.3«, is used to display standard output from tools that are integrated with Visual Workbench. This includes output from the following tools:

•	Find in Files

•	Profiler

•	Integrated build tools

•	Integrated debugger

•	Custom tools added to the Tools menu

A separate buffer, or "virtual window," is maintained for each of the tools that uses the Output window. For example, output from the most recent build is maintained while you switch the Output window to display output from a multifile search using Find in Files.

To switch the Output window from one virtual window to another, click the Output command in the View window. A popup menu appears with all the virtual windows available. Select the virtual window you want displayed in the Output window.

The Output window contains a parser that checks for error syntax format, such as that produced by the compiler or linker. The error syntax describes a file name and line number, and may contain an error number. For example:

c:\test.cpp(77) : error C2143: syntax error : missing ';' before '}'

When the syntax is detected on a line of text in the Output window, several additional functions become accessible. For example, you can double-click the line and jump to the source file and line number specified. Or, when the Output window contains more than one line with error syntax, you can use the Next Output Tag and Previous Output Tag commands (where Output represents the virtual Output window) on the View menu. You can use these commands to traverse the list, and open each file that is referenced at the specified line number.

To learn how to use the tools with the Output window, see »Using the Find Dialog Box« in Chapter 2, or see »Building a Project« in Chapter 3. The integrated profiler is described in 32-Bit Source Profiler User's Guide.


  Browse Window

The Browse window, shown in »Figure 1.4«, is part of the integrated source and class browser. You must generate a source browser database during a build of the project to use the Browse window. The Browse window gives you access to references, definitions, classes, and functions. For more information on using the Browse Window, see »Chapter 4«, "Using the Browser."


  Locals, Watch, Registers, and Memory Windows

The Locals, Watch, Registers, and Memory windows, shown in »Figure 1.5«, are used for debugging run-time errors. (In addition, the Output window is used to debug build errors.) These windows are only active during a debug session. They become available when the program is paused at a break, such as at a breakpoint, after a break command, or when stepping through the program.

The debugging windows are as follows:

•	The Locals window displays the values of all local variables in the scope of the most recently executed instruction.

•	The Watch window displays variables or expressions added to it. These can have any scope.

•	The Registers window displays all register values.

•	The Memory window displays memory values using a specified format and starting address.


  The Toolbar

The toolbar appears beneath the menu bar. It provides shortcut commands for opening and saving files, finding text, and building, running, and debugging a program.

You can hide or display the toolbar with the Toolbar command on the View menu. When this command is selected, the toolbar appears. When it is turned off (cleared), the toolbar is hidden. The controls (buttons and list boxes) on the toolbar are grouped according to function.

»Project Files«  The Project Files button opens a drop-down list that gives you a convenient way to open source files associated with your active project. The drop-down list contains all the files in the project list that can be edited. Click the Project Files button, then click any filename in the list to open a source window on the file.

»Open, Save«  Clicking the Open button opens the Open File dialog box. This dialog box can also be opened by choosing Open from the File menu. The Save button becomes available (not dimmed) when you make changes to the active source file and lets you save the file.

»Find, Find Next«  The Find drop-down list box and the Find Next button let you quickly find text strings in a source file. To search for text in a source file, type the text in the Find box or select a text string from the drop-down list box. The drop-down list box contains the last 16 text strings searched for. Then press Enter, double-click the text string, or click the Find Next toolbar button. To repeat the last search, click the Find Next toolbar button. This lets you find multiple occurrences of a text string. Use the SHIFT key with the Find drop-down list box or the Find Next button to search backwards through the file.

»Compile File, Build, Rebuild All«  You use these toolbar buttons to compile files and build projects. The Compile File button compiles the active file. Use the Build button to build the parts of the project modified since the last build, or the Rebuild All button to force a complete rebuild of all project files.

»Toggle Breakpoint, QuickWatch«  These are two of the six debugging buttons on the toolbar. The Toggle Breakpoint button turns a breakpoint on or off at the insertion point. When the program reaches a breakpoint, or is paused between trace steps, you can use the QuickWatch button to examine and modify variables.

»Run, Step Into, Step Over, Step Out«  These four debugging buttons control program execution during a debugging session. They let you run the program to a breakpoint, single-step through the program, and handle function execution.

When a button cannot be used (such as when a project is not open), the button is dimmed.


  The Status Bar

The »status bar«, at the bottom of the main Visual Workbench window, provides information about Visual Workbench and the active source window.

You can use the Status Bar command on the View menu to display the status bar. When displayed, the status bar shows the following information about the active window:

•	Summary help about the current operation

•	Messages from the environment: For example, when you are viewing compile-time errors the current error message is displayed here

•	Thread ID: shows the thread with the focus during a debug session

•	OVR: shows whether the editor is in over-type or insertion mode

•	READ: shows that the current file is read-only

•	CAPS: shows the state of the CAPS LOCK key

•	NUM: shows the state of the NUM Lock key

•	Line: shows the current line number

•	Column: shows the current column number


  Arranging and Displaying Windows

Visual Workbench uses standard commands for displaying and arranging windows. These commands appear on the Window menu and include:

Command	Action
Cascade	Overlaps all open windows. The top of each window appears below the previous window's title bar. The active window appears at the front.
Tile	Resizes windows so that all open windows appear on the screen without overlapping.
Visual Workbench windows support the standard Control menu commands, including the Minimize command. When a window is minimized, an icon representing the window appears at the bottom of the main Visual Workbench window (see »Figure 1.6«). Double-click the icon to restore the window.


  Filename Support

Visual Workbench supports filenames for the following file systems recognized by Windows NT:

•	FAT (MS-DOS)

•	NTFS

•	HPFS

There are some restrictions as to the use of NTFS and HPFS filenames in Visual Workbench.

Lower-case and mixed-case filenames specified in Visual Workbench are converted to upper-case when the file is written to disk.

Embedded spaces, trailing spaces, and leading spaces are not allowed in filenames that are included in a project list. Also, the following characters are not allowed in filenames: * ? " [ ] : | < > + = ; ,


  Getting Help

Visual Workbench features an on-line reference system that provides information about Visual Workbench, build tools, C and C++ programming languages, C run-time libraries, Windows 32-bit APIs, Microsoft Foundation classes, module-definition file statements, resource file statements, and compiler and linker errors.

You can go directly to the point in the Help system that documents the feature you need help on. You can do this in the following ways:

•	Press the F1 key with the insertion point on a language keyword, library routine, or error number to open a Help window with a description of the item.

•	With a menu command highlighted, press F1 to open a Help window with a description of the menu command.

•	In a dialog box, press F1 (or choose the Help button) to open a Help window with a description of the dialog box.

•	From the Help menu, choose Search for Help On (or choose the Search button in a Help window).

You can also choose a contents category from the Help menu. The Help menu contains several commands that open a Help window with a contents screen about the Help category:

•	Visual Workbench

•	App Studio

•	Build Tools

•	C/C++ Language

•	Foundation Classes

•	Win32 SDK

After choosing one of the commands from the Help menu, you navigate the Help system from the contents screen down to the individual Help topics.


  Getting Context-Sensitive Help

The F1 key gives you immediate help on language elements, error codes, and Visual Workbench features. The status bar provides a description of every menu command and toolbar button. You can also get help on the toolbar buttons. To see the description of the toolbar button without activating the button, follow the procedures described below.

To get Help on a keyword or an error

1.	Place the insertion point anywhere on the keyword or error.

2.	Press F1.

If information on the keyword or error can be found in more than one Help file, a Search dialog box opens with a list of Help files from which to choose. Select a Help file and choose OK.

To get a Help description of a menu command using F1

1.	Click the menu title to open the menu (or use the menu access key).

2.	Use the arrow key to highlight the command.

3.	Press F1.

You also get a brief description in the status bar of any toolbar button that you select. To see the description without activating the button (for buttons that are not dimmed) use the following procedure.

To get a status-bar definition of a toolbar button

1.	Move the mouse pointer over the toolbar button and press and hold the mouse button.

2.	With the mouse button pressed, read the status-bar text.

3.	Move the mouse pointer off the toolbar button before releasing the mouse button (releasing the mouse button with the mouse pointer on the toolbar button activates the button).

Every dialog box in Visual Workbench has a Help topic that describes the function of the dialog box and its elements.

To get a Help description of any dialog box

1.	Open the dialog box.

2.	Press F1 or choose Help.

Note that the C/C++ Compiler Options and Linker Options dialog boxes have additional Help capabilities to assist you in customizing compiler and linker options for your program.


  Navigating Help from the Contents Screen

The Help system is divided into several sections, each covering different  information. The Help menu contains several commands corresponding to the Help categories.

To open a contents screen on any category

•	Choose a Help category from the Help menu.

 − Or −

•	If you already have a Help window open, click the Contents button.

The Visual Workbench command on the Help menu opens an environment Help window for Visual Workbench. All other commands open reference Help windows.


  Chapter 2  Using the Editor

This chapter describes how to use the integrated text editor to manage, edit, and print source files. Most of the procedures involved in using the editor, such as file and text handling and moving around in a file, should seem familiar if you have used other Windows-based text editors.


  Managing Source Files

You can use the editor to create, save, open, and close a source file. You can use the C++ sample program, CONSOLE.CPP, which follows, to try the editing features described in this chapter. This program can be built and run as a Console application.

Note  Before building this application, be sure that the project type is set to Console Application (.EXE) and that the Microsoft Foundation Classes option is turned off. You can set these options in the Project Options dialog box, accessed by choosing Project from the Options menu.  See »Chapter 3«, "Using Projects," for more information.

 // CONSOLE.CPP - A console test program

#include <iostream.h>

void main()
{
    cout << "Hello C++ world \n";
}


  Creating and Saving Source Files

Visual Workbench lets you create source files and manage multiple source files. Each source window associated with a source file can retain its own fonts, sizing, and other window attributes. When you make changes to a source window, the Save button on the toolbar becomes available (not dimmed) to indicate that the information in the source window is different from the information in the source file.


  Creating a Source File

Use the New command on the File menu to create new source windows for entering text. To save the file on a disk, use the Save command on the File menu or the Save button on the toolbar.

To create a new source file:

1.	From the File menu, choose New.

2.	Type your program in the new window.

If you are following the example, type in CONSOLE.CPP as described in »Managing Source Files«.

3.	Save your program as described in  »Saving Source Files«.

New files are labeled UNTITLED.n in the source-window title bar, where n is a sequential number, until they are saved.

Note  Before you can save or close a window, it must be active. To make a window active, switch to the window (by clicking anywhere in it) or choose the window name or number from the Window menu.


  Saving Source Files

In Visual Workbench, you can save programs using the Save and Save As commands on the File menu or the Save button on the toolbar. You can also set save preferences in the Editor dialog box, accessed from the Options menu.

To save a source file

1.	Switch to the source window.

2.	From the File menu, choose Save (CTRL+S).

Or click the Save button on the toolbar.

If you have not named your file, Visual Workbench displays the Save As dialog box (see »Figure 2.1«.) In this case, continue with the following steps.

3.	In the File Name box, type the filename.

If you are using the sample program, name the file CONSOLE.CPP.

4.	In the Drives and Directories list boxes, select the drive and directory in which to save the file.

5.	Choose OK.

If CONSOLE.CPP already exists in the directory you choose, you are presented with a message box asking if you want to replace the existing file. Choose Yes.

If the file has already been named, the Save command saves any changes without displaying the Save As dialog box.

The Save button on the toolbar becomes available when you make any modification in the source file.

To save all open source files that are new or have been changed:

•	From the File menu, choose Save All.

The Save As dialog box lets you type the filename and select the drive and directory in which to save the file for each new source file that has not already been saved.

To save a source file under a different name:

1.	Switch to the source window.

2.	From the File menu, choose Save As.

The Save As dialog box appears.

3.	Type a new name for the file.

4.	Choose OK.

Renaming a file is useful for maintaining revised copies of a source file while keeping the original unchanged. You can also use the Save As command to name and save a newly created file.


  Setting Save Preferences

You can set the following save preferences in the Editor dialog box, accessed from the Options menu:

•	Save Before Running Tools

•	Prompt Before Saving Files

Selecting the Save Before Running Tools check box causes all open files to be saved when you run any tool installed on the Tools menu. This lets you integrate Visual Workbench with any tool that opens a source file also opened by Visual Workbench.

Selecting the Prompt Before Saving Files check box causes Visual Workbench to prompt you before saving files whenever you perform a build or run a program from the Tools menu. See »Source File Options« for more information on the Editor dialog box.


  Opening, Editing, and Closing Source Files

Because the editor works with any text file, you can open and edit text files created with Visual Workbench or several other editors.


  Opening a Source File

When you open a source file, its name is added to the Window menu. Use the Duplicate command if you want to see more than one view of a source file.The Open command on the File menu cannot be used to open more than one view of a source file at a time.

If you use the Duplicate command to display more than one view of a file, each window on the file is titled filename:n, where n is a unique window number.

If a filename extension is not given, Visual Workbench adds the extension of the last file opened that had either a .C or .CPP extension.

To open a source file

1.	From the File menu, choose Open (CTRL+O).

Or choose the Open toolbar button.

2.	Select the drive and directory where the file is stored.

The default is the current drive and directory.

3.	In the List Files of Type box, select the types of files to display or type a filename filter in the File Name text box.

The List Files of Type list box lists commonly used filename extensions and serves as a filter in displaying files to open. For example, Header (*.h;*.hpp;*.hxx) displays all files with the .H, .HPP or .HXX extensions.

You can type in your own filter by separating filename extensions with semicolons. For example:

*.CPP ; *.H ; *.RC

4.	Choose OK to see a list of files in the selected directory.

5.	Select the file from the list or type its name in the File Name box.

6.	Choose OK.

Tip  You can also open a file by using the Windows File Manager to display the file icon and then dragging and dropping the file icon into Visual Workbench.

Opening Recently Used Files

The last four files that you opened appear at the bottom of the File menu. You can open one of these files by choosing its name from the list.


  Opening Resource Files

Resource files (files with an extension of .RC) are source files that define resources such as menus and dialog-box controls. These files are compiled by the resource compiler as part of building an application for Windows.

The Editor dialog box (accessed from the Options menu) contains the Open .RC File Using App Studio check box. This check box determines how Visual Workbench opens the file:

•	If the check box is cleared (the default), opening a resource file is like opening any text file as a source window in Visual Workbench.

•	If the check box is selected, opening a resource file from Visual Workbench automatically invokes App Studio on that resource file.

When the option is selected, Visual Workbench invokes App Studio and passes it the filename you selected. App Studio can open any resource file that the resource compiler can compile without errors. You can use App Studio with any existing resource files simply by opening the resource file from Visual Workbench or from App Studio.

Note that you can use the Windows NT File Manager to display a list of resource files and then drag and drop any resource file icon into Visual Workbench. The state of the Open .RC File Using App Studio check box in the Editor dialog box determines whether Visual Workbench or App Studio opens the file.

App Studio is installed on the Tools menu with the $RC macro argument, which automatically opens the first resource file in the project list. Since you can open App Studio with your resource file from the Tools menu, the default action in the Open File dialog box (or Project Files toolbar button) is not to invoke App Studio on resource files. However, when you learn to use App Studio, you may decide you want the advantage of opening App Studio directly on files you select.

To open App Studio on a resource file

1.	From the Options menu, choose Editor.

2.	Select the Open .RC Files Using App Studio check box.

3.	Choose OK to close the dialog box.

4.	Open the resource file as described in »Opening a Source File« or »Opening Project Source Files«.


  Using File Filters

Visual Workbench lets you use filename filters in the Open File and Save As dialog boxes. Since these dialog boxes recall the filename filter that was last used, you can specify a special file type or a set of file types that you always want to see during the session. For example, the first time you open the Open File dialog box during a Visual Workbench session, you can enter *.CPP ; *.H to look for only C++ source and header files. This filter appears each time you open that dialog box during the session.


  Opening Project Source Files

You can use the Project Files button at the left end of the toolbar to access project source files. Click the Project Files button (or press CTRL+P) and the drop-down list displays all the project source files.

To open any source file in the active project

1.	Click the Project Files button on the toolbar.

2.	Choose the source file from the drop-down list.


  Closing Source Files

All files are automatically closed when you quit Visual Workbench (you are prompted to save any altered files). You can also close any individual source file without quiting Visual Workbench. If you have more than one window open on a source file, the file is not closed until all windows associated with it are closed.

To close a source file

1.	Switch to the source window.

2.	From the File menu, choose Close.

Or double-click the document Control-menu box.

Or press CTRL+F4.

If you are using the sample program, use one of these techniques to close the CONSOLE.CPP source window.

If you create a new source file and try to close it before saving, a message appears asking if you want to save the changes before closing.


  Source File Options

The Editor dialog box, opened from the Options menu, includes two open options:

•	Open New Source Window

•	Open .RC Using App Studio

To set open options:

1.	From the Options menu, choose Editor.

The Editor dialog box appears (see »Figure 2.2«).

2.	Select the Open New Source Window check box to cause a new source window to appear whenever a new source file is opened in the editor.

Or clear this check box to cause a new source file to appear in the active source window. If no source window is active, a new source window is always opened.

3.	Select the Open .RC Using App Studio check box to cause Visual Workbench to invoke App Studio on any resource file you choose using the Open dialog box or the Project Files toolbar button.

Or clear this check box to open resource files as ordinary text files in Visual Workbench.

4.	Choose OK.

The Editor dialog box also includes two save options:

•	Save Before Running Tools

•	Prompt Before Saving Files

To set save options:

1.	From the Options menu, choose Editor.

The Editor dialog box appears.

2.	Select the Save Before Running Tools check box to automatically save source files before any tool on the Tool menu is run.

3.	Select the Prompt Before Saving Files check box to cause Visual Workbench to ask you whether the file should be saved each time you start a build (or run a tool if Save Before Running Tools is checked).

4.	Choose OK.


  Using Bookmarks

You can use Bookmarks to quickly access different locations within a source file. This section describes how to set and clear bookmarks.

To set a bookmark in the source window

1.	Move the insertion point to the line where you want to set a bookmark.

2.	From the View menu, choose Toggle Bookmark, or press CTRL+F2.

The line containing the bookmark is highlighted.

You can mark frequently accessed lines in your source file. Once a line is marked, use the Next Bookmark and Previous Bookmark commands on the View menu to move to that line. Bookmarks can be cleared when you no longer need them.

To clear a bookmark

1.	Move the insertion point to the marked line.

2.	From the View menu, choose Toggle Bookmark.

Or press CTRL+F2.

The bookmark and the highlight are removed.

To remove all bookmarks

•	Choose Clear All Bookmarks from the View menu.

You can place bookmarks on every instance of a specified text string in a source file by using the Find dialog box.

To place bookmarks on all multiple occurrences of text

1.	Position the insertion point where you want to start the search.

2.	From the Edit menu, choose Find.

The Find dialog box appears.

3.	In the Find What box, type the text you want to mark with a bookmark. Or select from the 16 previous instances of text searched for, which are listed in the drop-down box.

4.	Select any of the »Find options«, as appropriate.

5.	Choose Set Bookmarks on All.


  Moving Around in Files

This section describes techniques for moving around in source files in Visual Workbench.

To move to a specific line within the source file

1.	From the View menu, choose Line.

The Line dialog box appears.

2.	Type the line number you want to move to.

3.	Choose OK.

To move to the next bookmark after the insertion point

•	From the View menu, choose Next Bookmark, or press F2.

To move to the previous bookmark before the insertion point:

•	From the View menu, choose Previous Bookmark, or press SHIFT+F2.

To switch to a source window

•	Click anywhere in the window (use the right mouse button to keep the insertion point from jumping to where you click).

•	Choose the window from the Window menu.

•	Use the shortcut key listed on the title bar (ALT+ <window number>).

•	Use CTRL+F6 to cycle through all active document windows.

•	Use F6 to cycle through all active windows (includes document windows and all other windows).

•	Use CTRL+TAB to switch to the last active window (release the CTRL key to switch to the window).

To move from one brace to the matching brace

1.	Place the insertion point immediately in front of a brace.

2.	From the Edit menu, choose Find Matching Brace, or press CTRL+M.

You can move from the opening brace to the closing brace or from the closing brace to the opening brace. This also works for parentheses and brackets.

To select a block of text from one brace to the matching brace

1.	Place the insertion point immediately in front of a brace.

2.	Press the shift key.

3.	From the Edit menu, choose Find Matching Brace, or press CTRL+SHIFT+M.

You can tab an entire block of code to the left or right using the tab and SHIFT+TAB keys.


  Using the Keyboard Commands

The editor includes a number of keyboard commands for editing and moving around in a source file. These are in addition to the arrow keys, the SPACEBAR, and the ENTER key. For a complete reference to all keyboard commands, see »Chapter 9«, "Shortcut Key Summaries."

To	Press
Move one word to the left	CTRL+LEFT ARROW
Move one word to the right	CTRL+RIGHT ARROW
Move to the first indentation of the current line	HOME
Move to the beginning of the current line	HOME, then HOME
Move to the first indentation of the next line	CTRL+ENTER
Move to the end of the current line	END
Move to the beginning of the file	CTRL+HOME
Move to the end of the file	CTRL+END
Scroll up	CTRL+UP
Scroll down	CTRL+DOWN
Scroll right	CTRL+PAGE UP
Scroll left	CTRL+PAGE DOWN
Undo the last edit	CTRL+Z  -OR-  ALT+BACKSPACE
Redo the last edit	CTRL+A
Delete to the end of the word	CTRL+T  -OR-  CTRL+DELETE
Delete entire line	CTRL+Y
Delete previous word	CTRL+BACKSPACE
Copy text to the Clipboard	CTRL+C  -OR-  CTRL+INS
Cut text to the Clipboard	CTRL+X  -OR-  SHIFT+DEL
Paste text from the Clipboard	CTRL+V  -OR-  SHIFT+INS
Move to the matching brace	CTRL+M
Insert a tab	TAB
Tab a block of selected lines to the right	TAB
Tab a block of selected lines to the left	SHIFT+TAB
Remove selection highlight from text	ESCAPE
Toggle display of tab symbols	CTRL+ALT+T


  Controlling the Source Window

The editor features a number of options that control the source window. These include the ability to set tabs, highlight language syntax within the window, and make the window read-only.


  Setting Tabs

The editor supports tab stops in a source file. You can set the number of spaces a tab consists of, and then save them as tabs or spaces when you save the file. You can also toggle the display of tab symbols in a source file.

To change tab settings:

1.	From the Options menu, choose Editor.

The Editor dialog box appears (see »Figure 2.3«).

2.	In the Tab Stops box, type the number of spaces to be used as a tab stop.

3.	Under Tab Settings, select the Keep Tabs option to treat tabs as a single tab character when the source file is saved.

Or select Insert Spaces to convert tabs to the number of spaces shown in the Tab Stops box.

4.	Choose OK.

To display or hide tab symbols

•	Press CTRL+ALT+T.

Tab symbols are displayed as » wherever there is a tab in a source file. The CTRL+ALT+T keyboard shortcut is the only means of toggling the display of tab symbols.


  Inserting and Deleting Tabs

You can press the tab key to insert a single tab anywhere in your source file. You can also move a block of lines one tab to the right or left.

To insert tabs in front of a group of lines

1.	Select the group of lines.

2.	Press TAB.

To delete tabs preceding a group of lines

1.	Select the group of lines.

2.	Press SHIFT+TAB.


  Highlighting Language Syntax

Visual Workbench highlights language keywords, identifiers, comments, and strings in different colors. This feature is useful when learning a language or when viewing lengthy and complex source files. For example, if you are editing a file with a .CPP extension, all C++ keywords are highlighted.

You can select the colors to use in highlighting language syntax items with the Color command on the Options menu.

To highlight language syntax in the source window:

1.	From the Options menu, choose Color.

The Color dialog box appears.

2.	Select the Syntax Coloring check box.

3.	Choose OK.


  Making a File Read-Only

The Read Only command on the Edit menu makes the active source file read-only. When you choose this command, the file cannot be edited.

This command is useful when you are viewing a program and don't want to accidentally make any changes to the file.

To make a source file read-only:

1.	Switch to the source window containing the file.

2.	From the Edit menu, choose Read Only.

To cancel the command, choose it again.

A check mark next to the menu command and the word "READ" on the status bar at the bottom of the screen indicate that the source file is read-only.


  Finding and Replacing Text

Visual Workbench offers advanced find and replace capabilities. You can search for text in a single source file or use the Find in Files dialog box to search for text in multiple files.

You can search for literal text or use regular expressions to find words or characters. You can even use tagged regular expressions for searching and replacing.


  Using the Find Dialog Box

The Find command on the Edit menu is used to open the Find dialog box.

To find a character or group of characters in the active source window

1.	Position the insertion point where you want to start the search.

2.	From the Edit menu, choose Find.

The Find dialog box appears (see »Figure 2.4«).

3.	In the Find What box, type the text you want to find. Or select from the 16 previous instances of text searched for, in the drop-down box.

4.	Select any of the »Find options«, as appropriate. .

After selecting the options, you can choose either the Find Next or the Set Bookmarks on All button. If you choose Set Bookmarks on All in the Find dialog box, bookmarks will be set at all occurrences of located search text. See »Using Bookmarks« for more information.

5.	Choose Find Next.

If the text is found, it is highlighted. Depending on the state of the Modeless Dialog for Searches check box in the Editor dialog box, a smaller Find dialog box may appear so you can choose Find Next to search again or choose Cancel to quit searching.

You can also use the Find Next toolbar button to continue searching.

When you choose the Find command, the editor uses the location of the insertion point to select a default search string. If the insertion point is inside a word, that word is displayed as the search text in the Find What box.

If the insertion point is between words, the word to the right is displayed. If there is no word to the right, the word to the left is displayed.


  Find Dialog Box Options

The Find dialog box includes the following options:

Match Whole Word Only  Locates separate occurrences of the search text. If you don't select this option, the editor finds embedded occurrences, for example, "main" in remainder.

Match Case  Performs a case-sensitive search.

Regular Expression  Finds text using regular expressions. For more information about using regular expressions, see the Using the Editor section of Help.

Direction  The Up option searches from the insertion point to the beginning of the file. The Down option searches from the insertion point to the end of the file.

Using the Toolbar  The Find box and Find Next button on the toolbar let you look for text without using a menu dialog box.

To use the toolbar Find box and Find Next button to search for text

1.	Position the insertion point where you want to start the search.

2.	Move the insertion point to the Find box on the toolbar (CTRL+F) and type the text you want to search for.

Or select from the 16 previous instances of text searched for, listed in the drop-down box.

3.	To search forward in the file, press ENTER.

Or double-click the selection.

Or click the Find Next button.

4.	To search backward in the file, press SHIFT+ENTER.

Or press SHIFT and double-click the selection.

Or press SHIFT and click the Find Next button.

5.	To repeat the search, click the Find Next button (hold down SHIFT for a backward search).

Or, with the insertion point in the Find box, press Enter or SHIFT+ENTER to search forward or backward, respectively.

If the text is found, the active source window jumps to it and highlights the text.

To quickly find the next or previous occurrence of a text string

1.	Select the text or place the insertion point anywhere in a single word.

2.	Press CTRL+F3 to find the next occurrence of the selected text or word.

Or press CTRL+SHIFT+F3 to find the previous occurrence of the selected text or word.

If you use the CTRL+F3 keys with the selected text or word, the text is entered in the Find list box. You can then continue to press CTRL+F3 to jump to each occurrence of the selected text or word.


  Finding Text in Multiple Files

The Find in Files utility lets you search for text in a group of files.  When you choose Find in Files from the Edit menu, the Find in Files dialog box opens to let you search multiple files.

The following procedure performs a multiple-file search of system include files.

To search for a text string in one or more files

1.	From the Edit menu, choose Find in Files.

The Find in Files dialog box opens.

2.	In the Directories box, select a directory that includes files you wish to include in the search.

For example, select C:\MSVCNT\INCLUDE.

3.	From the List of File Types list box, select the type of files you want to search.

Or type the file filter (such as *.cpp) directly in the File Name box and press ENTER.

For example, type  win*.h  and press ENTER to get a list of all Windows header files.

4.	From the list of filenames choose one or more files to add to the Selected Files list. (If you want to add all files, skip this step.)

5.	Choose the Add button or, if you want to add all files listed, choose Add All.

For example, choose Add All to add all Windows headers files to the Selected Files list.

6.	Optionally repeat steps 2 through 5 to add other files in different directories.

7.	In the Find What text box, type the character string or regular expression that you want to search for, or select from the drop-down list of find entries.

For example, type: exception

The contents of the drop-down list in the Find What box are the same as the drop-down lists in the Find dialog box and the toolbar's Find box.

8.	Choose Find to begin the search.

If you've been following the example, you should see a list of all Windows headers files that include the word "exception" and the locations of that word in each file.

When you perform a multiple-file search, the Output window displays the list of file locations where the text string was located. You can then jump to other occurrences of the text string by using the Next Find in Files Tag (F4) or Previous Find in Files Tag (SHIFT+F4) commands on the View menu or by double-clicking on the specific entries in the Output window.

When you jump to a found string location from the Output window, the corresponding source file is opened in the editor, if it is not already open. The insertion point is placed at the correct location in the file, and the string is highlighted. (Press escape to remove the highlight). The Open New Source Window check box in the Editor dialog box determines whether this new source file opens a new window or uses the active source window.

The Find in Files Output window is a virtual window that is maintained even when not displayed.  You can display the output from the last multiple-file search done during the current Visual Workbench session by choosing the Output command in the View menu and choosing Find in Files from the popup menu.


  Replacing Text

You can search for and replace text in a single source file. The Replace command on the Edit menu opens the Replace dialog box (see »Figure 2.5«).

To find and replace text

1.	From the Edit menu, choose Replace.

The Replace dialog box appears.

2.	In the Find What box, type the search text or regular expression.

Or choose from the 16 previous instances of text searched for, listed in the drop-down box.

3.	In the Replace With box, type the replacement text.

Or choose from the 16 previous instances of replacement text, listed in the drop-down box.

4.	Select any find options you need.

These options are the same as those in the »Find dialog box« .

5.	Choose either Find Next to find the next occurrence of the text or Replace All to find and replace all occurrences of the text.

If you choose Find Next, the next occurrence of the text is found if it exists, and the Replace dialog box is replaced by an abbreviated dialog box containing only Replace control buttons. You can replace the found text, find the next occurrence of the text, replace all occurrences of the text, or cancel the operation using this dialog box.

To repeat the last find or find and replace

•	Choose Find Next in either the Find or Replace dialog box.

An abbreviated portion of the Find or Replace dialog box remains open until the search reaches the starting location (after wrapping) or until you choose Cancel.


  Using Regular Expressions

Visual Workbench uses UNIX-style regular expressions to search for text.  Using "tagged" expressions you can also perform structured text replacement. Regular expressions are used in the Find, Replace, and Find in Files dialog boxes by selecting the Use Regular Expressions check box. With this check box selected, regular expressions can also be used in the Find box on the toolbar. Table 2.1 describes the syntax of regular expressions in Visual Workbench. Table 2.2 summarizes the available predefined regular expressions.

Table 2.1    Regular Expression Syntax

Syntax	Description
\c	Escape: matches a literal occurrence of the character c and ignores any special meaning of c in a regular expression.
.	Wildcard: matches any character.
^	Matches the beginning of the line.
$	Matches the end of the line.
x*	Repeat operator: matches zero or more occurrences of x where x is a single character, a character class, or a grouped expression. For example, the regular expression ba*b matches baab and baaab and bb.
x+	Repeat operator: matches one or more occurrences of x. For example, the regular expression ba+b matches baab and bab but not bb.
[class]	Character class: matches any one character in the class. Use a dash (−) to specify a range of characters. Within a class, all characters except ^-\] are treated literally. For example, [a-zA-Z0-9] matches any character or digit.
[^class]	Inverse of character class: matches any character not specified in the class. For example [^0-9] matches any character that is not a digit
\{x\}	Grouping. Groups a regular expression so that you can use a repeat operator on the subexpression. For example, \{Test\}+  finds Test and TestTest.
\(x\)	Tagged expression: marks text so it can be referred to elsewhere in find or replacement string.
\n	References the characters matched by a tagged expression, where n is a one-digit number indicating which expression. The first expression is \1, the second \2, and so on. The entire expression is represented as \0.
Table 2.2   Predefined Expressions

Syntax	Description
\:a	Alphanumeric character
\:b	White space
\:c	Alphabetic character
\:d	Digit
\:f	Part of a filename
\:h	Hexadecimal number
\:i	Microsoft C/C++ identifier
\:n	Unsigned number
\:p	Path
\:q	Quoted string
\:w	English word
\:z	Unsigned integer


  Using Tagged Expressions

The following procedure demonstrates how to use tagged regular expressions to find all occurrences of header file names enclosed in quotes with an extension of .h and replace them with the matched header filename prefix with an extension of .hxx.

To find and replace text using tagged expressions

1.	From the Edit menu, choose Replace.

The Replace dialog box appears.

2.	Select the Regular Expression check box.

3.	In the Find What box, type the tagged regular expression.

For example, type:  "\(.*\.\)h"

This tagged expression takes the ".*\.h" search string, and marks the text found in the .*\. part of the string.

4.	In the Replace With box, type the replacement expression using the tag reference.

For example, type:  \1hxx

This expression replaces each matched expression with the same name but an extension of .hxx. For example, "myapp.h" becomes "myapp.hxx".

5.	Choose either Find Next to find the next occurrence of the text or Replace All to find and replace all occurrences of the text.


  Printing

If you have installed a printer driver and connected to a printer port within Windows, you can print text from the active window.

If you have more than one printer, you can change the default printer selection in the Print dialog box.

For information on installing printers, see your Windows NT documentation.

To print text from the active window

1.	From the File menu, choose Print.

The Print dialog box appears (see »Figure 2.6«).

2.	Under Print Range, select the All option.

Or under Print Range, select the Selection option.

3.	Choose OK.

4.	Choose the Setup button to set printer-specific information.

The Setup button opens a printer-supplied dialog box (see »Figure 2.7«), in which you can change the paper size, the orientation of the printing, the number of copies, and various other printing options.

To change the default printer

1.	From the File menu, choose Print.

2.	Choose a printer from the drop-down list.

3.	Choose OK.


  Chapter 3  Using Projects

You use a project to track the files and libraries that are needed to build a program or a library. A project also contains information about compiler and linker options, and information about workspaces, such as window sizes and positions.

Projects are stored on disk as two files: a makefile (.MAK extension) and a status file (.VCW extension). The makefile, which is compatible with the NMAKE utility, specifies the rules for the compiler and linker to build the target file. Visual Workbench calls this file the project file. When you open the project file within Visual Workbench, the status file is automatically loaded.

When you create a project, you can choose a project type. This specifies the target file you want to generate when you build the project. To create a project, you add the filenames to the project list. Visual Workbench uses these names to construct the project file. When you open a project, all source filenames in the project list are available in the toolbar's Project Files drop-down list. This gives you quick access to the main source files.

You can use projects to speed development time since only the files that have changed since the program's last compilation or build are recompiled. You also have the option of recompiling all files from the start, using the Project menu's Rebuild All command.

This chapter describes how to use projects in Visual Workbench. The following topics are included:

•	»Project types«

•	»Creating a project«

•	»Opening and closing projects«

•	»Adding and deleting project files«

•	»Project compiler and linker options«

•	»Customizing project build options«

•	»Using workspaces«

•	»Using external projects«


  Project Types

The project type specifies the kind of target file to be generated by a build.  You choose a project type when you create the project using the New Project dialog box (accessed from the Project menu).  If you use AppWizard to create a project, AppWizard chooses the project type when it creates the project.

To change the project type of an existing project, use the Project Options dialog box (see »Figure 3.1«), accessed from the Options menu . For step-by-step instructions on how to create a project and choose a project type, see »Creating a Project«.

When you select a project type, the appropriate compiler and linker options are automatically set to generate the target file. These default options, which are sufficient for most needs, can be edited in the C/C++ Compiler Options and Linker Options dialog boxes.

You can use the following four project types in Visual C++ for Windows NT:

•	»Windows application«

•	»Windows dynamic-link library«

•	»Console Application«

•	»Static library«

If you select the Use Microsoft Foundation Classes check box in the New Project or Project Options dialog box, you can use the Microsoft Foundation Class Library with any of these types. Selecting Use Microsoft Foundation Classes links an extra library during the build and sets the library as a default linker option.


  Windows Application

Applications written for Windows have a full graphical interface and are developed using Windows NT Win32™ API functions, or using the Microsoft Foundation Class Library. A filename for an application for Windows has an .EXE extension.


  Windows Dynamic-Link Library (DLL)

Dynamic-link libraries are written using Win32 API functions and contain functions that are called at run time by 32-bit Windows-based programs. A Windows-based DLL application filename has a .DLL extension.


  Console Application

Console Applications use the Console APIs, which provide character-mode support for applications that run in a Console window in NT. The Visual C++ run-time libraries also provide output and input from the Console window with standard I/O functions, such as printf() and scanf(); however, the Console APIs provide additional flexibility.


  Static Library

Static libraries are standard libraries that can be created directly from the build using object files that belong to the project. To create a static library (.LIB), create a project with normal project files and/or other object (.OBJ) or library (.LIB) files in the project file list, then build the project. The library file is composed of all the object and library files in the project list and/or all object files generated by the build. This is a quick way to develop your own libraries from within Visual Workbench.


  Creating a Project

Before creating a program, you need to create a project for it. A project may comprise several files including source files, resource files, and library files. Everything that applies to projects for programs also applies to projects for libraries.

Note  If your program consists of only one file, you can build and run it without creating a project. However, it is a good idea to create a project if you have unique compiler or linker settings, since these will be lost if another project is loaded or Visual Workbench is restarted.

You can become more familiar with the steps in building a project by using the files located in the \MSVCNT\MFC\SAMPLES\HELLO directory (HELLO.CPP, HELLO.DEF, and HELLO.RC) to create a multiple-file C++ project. Although there is already a project called HELLO.MAK in the directory, you can create a second project with a different name in that directory. This example assumes that you have installed the Microsoft Foundation Class Library sample programs.

The directory listed above is the default directory created by the Setup program. If you changed the default directory names during installation, the location of the required files will be different.

To create a project

1.	From the Project menu, choose New.

The New Project dialog box appears.

If you know the directory for the project, you can simply type the project name, including the complete path, in the Project Name box and skip to step 6. For example, if you installed Visual C++ on drive C, enter the following in the Project Name box:

C:\MSVCNT\MFC\SAMPLES\HELLO\MYHELLO.MAK.

If you would rather browse the directory, continue with step 2.

2.	Choose the Browse button to browse and change directories.

The Browse dialog box appears. This dialog box allows you to change directories and look at filenames. The purpose of browsing your directories is to make sure you use a unique name for the project and to change to the correct directory for the project.

3.	Use the Directories and Drives list boxes to change to the drive and directory containing the example files (\MSVCNT\MFC\SAMPLES\HELLO if you've installed sample files in the default directory).

You should see the name of the existing project file (HELLO.MAK) in the directory.

4.	In the File Name box, type the new project filename.

For example, type MYHELLO.

All project files have a .MAK extension. You don't need to type any more than the first eight characters of the filename. The .MAK extension is automatically added when you choose OK.

5.	Choose OK.

The Browse dialog box disappears, and the project name you specified appears in the Project Name box preceded by its path. You must now specify a project type.

6.	From the drop-down list in the Project Type box, select a project type.

For this example, select Windows application (.EXE).

7.	Select the Use Microsoft Foundation Classes check box if your application uses the foundation classes (the HELLO sample does).

8.	Choose OK.

The Edit  −  Projectname dialog box appears (see »Figure 3.2«).

9.	Add the necessary filenames in the project to the project list by selecting each file and choosing the Add button.

In this example, you need to add HELLO.CPP, HELLO.DEF, and HELLO.RC. (HELLO.H cannot be added now since all include files are automatically found and added when the dialog box is closed.) If you need help using this dialog box, see »Adding and Deleting Project Files«.

10.	Choose the Close button to save the project and scan all the source files for include files.

Whenever you close (not cancel) the Edit  −   Projectname dialog box, Visual Workbench recursively scans all files in the project list for #include directives and automatically adds any include files it finds to the project list. For more information on include file dependencies, see »Using Include Dependencies«.


  Opening and Closing Projects

Although you can maintain many projects on your disk, Visual Workbench can work with only one project at a time. You can recall any previously created project by opening it. When you open an existing project, the current project is automatically closed, or you can close it manually.

To open an existing project

1.	From the Project menu, choose Open.

2.	From the file list, select a project file (.MAK extension).

3.	Choose OK.

Tip  You can also open a project by using the Windows File Manager to display the project file icon and then dragging and dropping the project file icon into Visual Workbench.

To close a project

•	From the Project menu, choose Close.

 − Or −

•	Open another project.

 − Or −

•	Create another project.

To learn how to open a makefile created outside the Visual Workbench environment, see »Using External Projects«.


  Adding and Deleting Project Files

When you create a project, you can add files to the project. As your program develops, however, you may need to add or delete files. When you delete a file from the project, only the reference to that file is removed. The actual file is not deleted from the hard disk.

Assuming you have a project open, choose the Edit command from the Project menu to open a dialog box where you can add or delete project files. This dialog box is identical to the dialog box used to add files to a new project.

To add a file to the project

1.	From the Project menu, choose Edit.

The Edit  −  Projectname dialog box appears.

2.	Use the List Files of Type drop-down list box to set the type of files that appear in the File Name box.

3.	From the file list in the File Name box, select the file to add to the project and choose Add.

Or double-click the file in the file list.

Or you can choose Add All to add every file that appears in the file list to the project list. This can save steps if you have several source files you want to add.

4.	Repeat steps 2 and 3 for each file (or set of files) you want to add to the project.

5.	Choose Close when you finish editing the list of project files.

An include dependency scan now takes place. For more information, see »Using Include Dependencies«.

To delete a file from the project:

1.	From the Project menu, choose Edit.

The Edit  −  Projectname dialog box appears.

2.	Select the file from the Files in Project box and choose Delete.

Or double-click the file in the Files in Project box.

3.	Repeat step 2 for each file you want to delete from the project.

4.	Choose Close when you finish editing the list of project files.

An include dependency scan now takes place. For more information, see »Using Include Dependencies«.


  Using Include Dependencies

Visual Workbench creates include dependency lists whenever you create or edit a project. It does this by recursively scanning the project files for #include directives and adding each included filename to the project list. Both source files (.C, .CPP, or .CXX) and resource files (.RC) are scanned, so the include files in the dependency list can have extensions of .H, .HXX, .HPP, .INC, .FON, .CUR, .BMP, .ICO, or .DLG. Since these file types are automatically added to the project list, you cannot add them manually. These files are part of the project list and are available in the Project Files drop-down list, accessed from the  Project Files button on the toolbar.

An include dependency list associates each included file with the files that include it and are therefore dependent upon it. This allows Visual Workbench to generate the correct build dependencies. For example, when you edit a header file and perform a build, the build compiles only the files that include the modified header file.

Visual Workbench scans for include dependencies when you close the Edit − Projectname dialog box, after you have either created or edited the project list. If you subsequently add a statement to include a new file in any source file in the project list, you should scan the include dependencies for the project again.

To scan include file dependencies for the entire project

•	From the Project menu, choose Scan All Dependencies.

To scan include file dependencies for the active file

•	From the Project menu, choose Scan Dependencies Filename (Filename appears on the menu as the name of the active source file).

A status window appears showing the status of the include dependency scan as it searches files. You can cancel the dependency scan at any time by choosing the Cancel button. If you cancel the scan, the previous include dependency list remains in effect.

Visual Workbench scans bracketed include files (<includefile.h>) and user include files ("includefile.h"). Visual Workbench uses an exclusion file called MSVCINCL.DAT that contains a list of system include files. Whenever Visual Workbench scans for include dependencies, it uses this list to exclude the filenames in this list.

You can edit the exclusion file to fine-tune your build dependencies. For example, if you have a large header file that you never change, you could add it to the list in the exclusion file. Then, whenever you generate include dependencies, that file will not be scanned. As another example, you may want a Microsoft system include file scanned because you are altering it, in which case you could remove that include filename from the exclusion file. Visual Workbench never overwrites the exclusion file. However, if Visual Workbench starts and does not find the MSVCINCL.DAT file, it creates a default exclusion file, which includes all system include files shipped with Visual C++. So you can regenerate the original exclusion file  by deleting or renaming MSVCINCL.DAT.


  Project Compiler and Linker Options

Projects also contain information about compiler and linker settings. When you select a project type, the project configures the compiler and linker options to build that type of program or library. These options, and any compiler and linker options you set yourself, are automatically saved with the project information when you perform a build.

To customize the compiler and linker options generated by the project type, use the Customize Build Options group in the Project Options dialog box. This group contains three command buttons that open dialog boxes to let you set compiler, linker, or resource compiler options. To learn more about these dialog boxes, see »Customizing Project Build Options«.


  Building a Project

You create a project so that you can eventually build a program or a library. Visual Workbench lets you build or rebuild a project. When you build a project, only the files in the project list that have changed since the last build are included in the build. When you rebuild a project, all files are included in the build.

Before you build a project, you need to determine whether you want to produce a debug or release version of the program. The debug version contains information that can be used by Visual Workbench's integrated debugger or by other CodeView®-compatible debuggers. The release version does not contain debug information and therefore is smaller and faster. To learn how to use the debugger on a debug version of a program for Windows, see »Chapter 5«, "Debugging Programs."

To select debug or release build options

1.	From the Options menu, choose Project.

The Project Options dialog box appears.

2.	Under Build Mode, select either Debug or Release.

3.	Choose OK.

To build a project

•	From the Project menu, choose Build Targetname (Targetname represents the name of the target file displayed on the menu).

 − Or −

•	Click the Build button on the toolbar.

To rebuild a project

•	From the Project menu, choose Rebuild All Targetname (Targetname represents the name of the target file displayed on the menu).

 − Or −

•	Click the Rebuild All button on the toolbar.

The Output window provides information from the build tools and lists any errors or warnings that occur during the build. Since the build occurs in the background, you can continue to use Visual Workbench. Some menu commands and toolbar buttons are disabled during a build (for example, you are not allowed to exit Visual Workbench without stopping the build).

An audible message notifies you when the build is complete. The audible message corresponds to one of three standard system events in Windows:

System Event	Indicates
Asterisk	Build has completed without errors or warnings
Question	Build has completed with warnings
Exclamation	Build has completed with errors
If you have a sound card installed, you can use the Sound application in the Windows Control Panel to assign these system events to different sounds. Otherwise, all audible messages issue a beep.

To stop a build at any time, choose the Stop Build command on the Project menu. The build will stop as soon as the build tool that is executing finishes.

If no errors are reported, the build is successful. If errors are reported you will need to debug them. For information on debugging build errors, see »Debugging During Building«.

If the project type is a program, you can run it by choosing Execute Targetname from the Build menu. You can run the program in the debugger by choosing Go from the Debug menu or by clicking the Run button on the toolbar.


  Customizing Project Build Options

When you choose a project type, Visual Workbench sets up the compiler and linker options necessary to build that project type. You can customize these options using the Project Options dialog box, which contains a Customize Build Options group with three buttons:

•	Compiler

•	Linker

•	Resources

Selecting one of these buttons opens a corresponding dialog box that allows you to customize settings for the build tool. For example, you can open the C/C++ Compiler Options dialog box to optimize a program for size or speed as a final step after development and debugging. Or you can select the Linker button to open the Linker dialog box to add import libraries to your link options. Selecting the Resources button opens the Resource Compiler Options dialog box where you can add a custom resource compiler option.

This section describes how to set options in each of the dialog boxes opened from the Project Options dialog box. It also describes how to use the Help system used by the C/C++ Compiler Options and Linker Options dialog boxes. See »Chapter 10« for a list of compiler and linker options supported in Visual Workbench, including the dialog box control,  the option string mnemonic, and a brief description of each option.


  The Compiler and Linker Options Dialog Boxes

The C/C++ Compiler Options dialog box and the Linker Options dialog box are similar in operation. Each is divided into two sections (see »Figure 3.3«). The upper section displays the options string, which is a representation of the options given to the compiler and linker when you perform a build. There are also three Build Options buttons:

•	Debug Specific

•	Release Specific

•	Common to Both

Choose the Debug Specific or Release Specific button before you select compiler or linker options to apply the options to a Debug or Release build. You can choose Common to Both to have the options you select apply to both Debug and Release builds.

Note  The options string represents the actual command-line string, with one exception: /Yu appears twice on the options string when header filenames are specified for both C and C++ precompiled headers in the same project.

The lower section of the C/C++ Compiler Options and Linker Options dialog includes a category list box and a category settings box. When you select a category, a new Category Settings group appears to allow you to set options in that category.

Within the Category Settings group, you use various controls (list boxes, text boxes, check boxes, and option buttons) to select compiler or linker options. The selected options are then reflected by their corresponding command-line mnemonics in the options string at the top of the dialog box.

When the control is a list box, a "default" is indicated by an asterisk. The default is the option that the compiler or linker provides when a command-line argument is not provided. When you select a default option, the mnemonic for that option does not appear in the options string.

For example, the default compiler option for warning level is W1. However, most project types have a default of W3. This is automatically added to the options string when you select the project type.

Chapter 10 contains a quick reference to the compiler and linker options. For detailed information about any build tool, or for explanations of  specific compiler or linker options, see the Build Tools User's Guide or consult Help. The Help facilities provided in the C/C++ Compiler Options and Linker Options dialog boxes are described in "»Getting Help on Build Options«."


  Getting Help on Build Options

You can use a specialized Help facility to access definitions of the options in the options string. Also, Visual Workbench Help for dialog boxes provides quick access to help on the check boxes, text boxes, and list boxes that set options. The Resource Compiler Options dialog box uses the same Help interface as standard Visual Workbench dialog boxes.

The Help Command Button

As with any Visual Workbench dialog box, you can get a general overview of the compiler, linker, and resource compiler dialog boxes by choosing the Help command button.

Context Sensitive Help

Help for compiler and linker options is context sensitive when you use the F1 key. You can get either a short pop-up description of an option in the options string, or a complete description of an option, depending on the location of the insertion point when you press F1.

To get a short description of any option in the options string

1.	Highlight the option in the options string (double-click the option).

Or place the insertion point on the option.

2.	Press F1.

A pop-up window appears with a brief description of the compiler or linker option.

To get help on any option in the Category Settings group

1.	Move the dialog focus to the option control.

For example, place the dialog focus in a list box, on a check box, or in a text box.

2.	Press F1.

A Help window appears with definitions and descriptions of all the options associated with the control. For example, if it is a list box, all list box entries are described.

Once a Help window is open, you can get help on any option, either by category or alphabetically, by going to the Contents screen.


  Using Workspaces

A workspace is a convenient way of saving and restoring an arrangement of windows associated with a project. Loading a workspace also restores font settings and the status of the toolbar and status bar (displayed or hidden).

For example, suppose you like to debug with a narrow Registers window to the right of your source window and Watch and Locals windows below your source. If you save this arrangement as a workspace, you can load it at the start of each debugging session. Workspaces also keep track of the insertion points in all files, so you can continue working where you left off.

Three named workspaces, plus the last workspace used, are available for each project you create and for Visual Workbench's default state (that is, when no projects are loaded). You can load any of the named workspaces from the Project menu. Also, you can specify any of the named workspaces or the last workspace used to be loaded when you open a project.


  Restoring the Last Workspace Used

It is often useful to maintain your Visual Workbench setup between sessions. Whenever you exit Visual Workbench or close a project, the current workspace for the application is automatically saved. When a project is closed, either directly or by exiting Visual Workbench, the current project workspace is saved in the project's workspace file. If a project is not open when you exit Visual Workbench, the current workspace is saved in Visual Workbench's workspace file.

If you want the workspace you were last using to be automatically loaded the next time you open Visual Workbench, use the Workspace dialog box, accessed from the Options menu, to set the initial workspace to "Last Workspace Used." (See »Loading an Initial Workspace«.) Then, since Visual Workbench always loads the most recently used project when it starts, the last workspace associated with that project is also loaded. If a project was not active at the end of the last session, the last workspace used in Visual Workbench's default state is loaded.


  Saving a Workspace

You can save up to three workspaces for each project, besides the current workspace. The current workspace is automatically saved and becomes the Last Workspace Used. You can also save up to three workspaces for Visual Workbench when a project is not open.

The following procedure demonstrates how to save a workspace. To save a workspace for a project, open the project before saving the workspace. To save a workspace for Visual Workbench, close any open project first.

To save a workspace

1.	Arrange and size the appropriate windows.

2.	From the Project menu, choose Save Workspace.

3.	From the cascading menu, choose Edit, Debug, or Custom.

Edit, Debug, and Custom are default workspace names. You can change the default names by choosing the Workspace command from the Options menu.

The workspace information is stored in a file with the project name and a .WSP extension.


  Loading a Workspace

When a project is open, you can only load the workspaces defined for that project. If no projects are open, you can load the workspaces defined for Visual Workbench.

To load a workspace

1.	From the Project menu, choose Load Workspace.

2.	From the cascading menu, choose Edit, Debug, or Custom.

Any files already open that do not belong in the current workspace are either minimized to an icon or are closed depending on the setting of the Close Non-Workspace Windows on Load check box in the Workspace dialog box.


  Loading an Initial Workspace

When you open a project, the project can automatically open a workspace. When you start Visual Workbench, it can also load an initial workspace.

Use the Workspace command on the Options menu to define an initial workspace. If a project is open when you use the command, you define an initial workspace for the project. If a project is not open, you define an initial workspace for Visual Workbench.

To define an initial workspace to load

1.	From the Options menu, choose Workspace.

The Workspace dialog box appears (see »Figure 3.4«).

2.	From the Initial Workspace box, select a workspace name.

3.	Choose OK.


  Using External Projects

You can use existing makefiles in place of Visual Workbench's project makefiles, and run them from Visual Workbench. These makefiles are called "external projects" because they are external to the normal mode of selecting project options within Visual Workbench.

When you use an external project, you are responsible for the contents and actions of that makefile, since Visual Workbench does not read or alter the makefile. You can build an external project and run any resulting program from within Visual Workbench.

If your external project generates a CodeView-compatible debug version of the executable file, you can debug the target from within Visual Workbench. Note that the CodeView information must be compatible with the CodeView information used by Visual C++. For example, CodeView information in  programs built using Win32 SDK Beta utilities is not compatible until it is repacked using the Visual C++ for Windows NT version of CVPACK.


  Opening External Projects

You open an external project as you would any Visual Workbench project; the only difference is that you select the Use as an External Makefile check box in the Open Project dialog box.

To open an external project

1.	From the Project menu, choose Open.

The Open Project dialog box appears.

2.	In the File Name box, type the name of the external makefile.

3.	Select the Use as an External Makefile check box.

If you don't select this check box, Visual Workbench prompts you when it tries to open the project as a Visual Workbench project and fails. You can specify at that time that it is an external project.

4.	Choose OK.


  Using External Project Options

Once the external makefile is loaded, you can set build options by choosing the Project command from the Options menu. This opens the External Project Options dialog box (see »Figure 3.5«), where you can set build options.

The build options you can set in the External Project Options dialog box are described in the following paragraphs.

Debug Target Name  The Debug Target Name specifies the target executable produced by the external project. By default, Visual Workbench uses the base name of the project as the Debug Target Name. This name also appears on the Project menu following several commands. If you change this default name in the Debug Target Name box, you are responsible for making sure your external makefile generates an executable file with this same name

Project Type  This is the target file type (Executable, DLL, or other). Depending on the project type specified here, the Debug dialog box, accessed from the Options menu, presents slightly different options. If the project type is specified as Executable, the upper text box in the Debug dialog box is labeled "Program Arguments" and lets you enter any parameters to pass to the program. If the project type is specified here as DLL, the upper text box in the Debug dialog box is labeled "Calling Program" and lets you enter the executable filename that calls the DLL.

Debug Build  This is the program maintenance utility, such as NMAKE, along with any command-line options it requires to build a debug version of the project type. The command in this box is invoked when you choose Build Targetname from the Project menu or click the Build button on the toolbar if you have Debug selected under Build Mode in the External Project Options dialog box.

Release Build  This is the program maintenance utility, such as NMAKE, along with any command-line options it requires to build a release version of the project type. The command in this box is invoked when you choose Build Targetname from the Project menu or click the Build button on the toolbar if you have Release selected under Build Mode in the External Project Options dialog box.

Rebuild All Options  This is the command-line option required by the program maintenance utility to generate a complete rebuild. The command line specified in either the Debug Build or Release Build text box (depending on which mode you are building) and the command-line option in this text box are combined and invoked when you choose Rebuild All Targetname from the Project menu or click the Rebuild All button on the toolbar.

If you want to build both Release and Debug versions, you can use the same makefile for both and add DEBUG=1 as a command-line option in the Debug Build text box and DEBUG=0 as a command-line option in the Release Build text box.


  Building and Running External Projects

To build an external project, click the Build button on the toolbar or choose Build Targetname from the Project menu. To rebuild an external project, click the Rebuild All button on the toolbar or choose Rebuild All Targetname from the Project menu.

To run an external project target file, choose the Execute Targetname command from the Project menu. Or to debug an external project target file that contains debug information, choose Go from the Debug menu, click the Run button on the toolbar, or use any of the trace commands, Step Into, Step Over, or Step to Cursor, from the Debug menu.


Using the Browser
  Chapter 4  Using the Browser

The Visual Workbench browser, an integrated version of the Microsoft Source Browser, displays relationships between program elements, such as between base and derived classes, or between called and calling functions. It also enables you to move quickly between related program elements that may be located in several different files.

The browser uses a database generated by the compiler to help you find related symbols and display symbol relationships. The database contains information about where each symbol is defined and used, and about the relationships among modules, constants, macros, variables, functions, and classes.

This chapter describes the capabilities of the browser and shows techniques for viewing class hierarchies, function call trees, and symbol definitions and references.


Chapter 4 Creating a Browser Database
  Creating a Browser Database

Visual Workbench creates a browser database during a build when the Browser Information check box in the C/C++ Compiler Options dialog box is selected. This check box is selected by default. Since creating a browser database adds time to the build, and browser database files can be very large, you may want to clear the Browser Information check box when you do not want to build a browser database. However, if you plan to use the browser on a project, you must create a browser database for the project.

The following procedure assumes that you have a project loaded in Visual Workbench. You may want to use the SCRIBBLE sample project located in the \MSVCNT\MFC\SAMPLES\SCRIBBLE directory to experiment with the browser's capabilities. See »Chapter 3«, "Using Projects," to learn how to open and build a project.

To create a browser database (.BSC) file:

1.	From the Options menu, choose Project.

The Project Options dialog box appears.

2.	Under Customize Build Options, choose Compiler.

The C/C++ Compiler Options dialog box appears.

3.	In the Category box, select Listing Files.

This opens the Category Settings: Listing Files group. This group includes the Browser Information categories (see »Figure 4.1«).

4.	Select the Browser Information check box.

The Include Local Variables check box should be selected and the Don't Pack Information checkbox should be cleared.

5.	Choose OK in the C/C++ Compiler Options dialog box.

6.	Choose OK in the Project Options dialog box.

7.	Click the Rebuild button on the toolbar or choose Rebuild All Targetname from the Project menu.

During the build, Visual Workbench creates a browser database file with the name of your project and the extension .BSC in your project directory.


  Opening a Browser Database

You can use one of the following methods to open a browser database:

•	Choose the Open [Project.BSC] command on the Browse menu

•	Choose the Open command on the File menu. The name of the most recently opened database appears after the Open command.

•	Choose the Next Definition or Next Reference command on the Browse menu

•	Drag a browser database file (.BSC) from the Windows File Manager and dropping it into Visual Workbench

To open the Browse window for the current project

•	From the Browse menu, choose Open Project.BSC (where Project is the name of the current project).

If you have created a browser database for the current project, the Browse window appears. Otherwise, a message appears, indicating that the browser database file cannot be opened.

You can also open any existing browser database by using the Open command on the File menu. This can be a browser database generated by Visual Workbench or any other build process that uses the Microsoft BSCMAKE utility.

To open a browser database using the Open command on the File menu

1.	From the File menu, choose Open.

Or click the Open button on the toolbar.

Or choose Open from the Browse menu if no filename follows the Open command (that is, Open is followed by an ellipsis ...).

The Open File dialog box appears.

2.	From the drop-down list in the List Files of Type box, select Browse Database (*.bsc).

3.	Use the Directories and Drive list boxes to locate the directory that contains the browser database.

The browser file appears in the file list.

4.	Double-click the browser database filename.

The Browse window appears (see »Figure 4.2«).

The filename of the currently open database appears on the Browse menu following the Open command.

Another method of opening a browser database is to use the Go to Definition or Go to Reference command on the Browse menu when a browser database is associated (named on the Browse menu) but not open.

To open a browser database and jump to the first definition or reference

1.	Select a symbol name in a source file (or place the insertion point at the beginning of a symbol name).

Note that the browser database filename associated with the source file must appear on the Browse menu after the Open command.

2.	Choose Go to Definition (F11) to jump to the first definition, or Go to Reference (SHIFT+F11) to jump to the first reference of the symbol.

The database named in the Open command on the Browse menu is opened, the Browse window is minimized, and the source file containing the first definition (or first reference if you chose Go to Reference) appears with the insertion point at that definition or reference.

.

See »Browsing Definitions and References« for information on using the Browse window for querying definitions and references.

You can also use the Windows File Manager to open a browser database. Open the File Manager, select a browser database file icon (with an extension of .BSC),  and drag and drop the icon into Visual Workbench. The Browse window opens with the browser database that you dropped in Visual Workbench.


  Querying a Browser Database

You can query a browser database by using the query controls in the Browse window or by using the commands on the Browse menu.

The Browse window lets you see representations of class and function relationships and lets you construct lists of symbols from which to query definitions and references.

The Browse menu commands let you jump to definitions and references of a symbol while you are writing or editing code. The Go to Definition and Go to Reference commands on the Browse menu work with the Next and Previous commands to traverse all definitions or references of a particular symbol.


  Using the Browse Window

To perform a query in the Browse window, you first set the parameters in the Query group at the top of the Browse window (see »Figure 4.3«) and then choose the Display Result button.

The Query group contains three controls: Type, Subset, and Symbol. You can use these controls  to set and display query parameters as described in the following paragraphs.

Type  This drop-down list box determines the type of symbol relationship you want to view. The five choices are:

•	Definitions and References

•	Call Graph

•	Caller Graph

•	Derived Class Graph

•	Base Class Graph

Subset   This drop-down list box determines the type of symbols you are browsing. For Definitions and References queries, Subset lets you determine the subset of symbol types to be included in the search. This can be useful when you use a wildcard in the Symbol text box that matches several symbol names and a lengthy list of symbols appears in the left display panel. You can narrow the  list by choosing a subset of symbol types from the Subset drop-down list. Or you can choose All to have a list of all symbols placed in the left display panel. For the Call Graph and Caller Graph query types, Subset is always set as Functions. For the Derived Class Graph and Base Class Graph query types, Subset is always set as Classes.

Symbol  This text box determines the function, variable, type, macro, or class you want to browse. You can type in a symbol name or choose from the previous eight symbol names you have queried. You can also use a wildcard in the symbol name as described in Table 4.1.

Table 4.1    Wildcards in Symbol Names

Type	Represents
*	All symbols
Sym*	All symbols starting with some common characters (denoted here by Sym)
ClassName::	All member functions and member variables of a class (denoted here by ClassName) when the query type is Definitions and References
When a wildcard matches more than one symbol, all matching symbols appear either in the left display panel (if the query type is Definitions and References) or in a Symbol dialog box (for all other query types). When a Symbol dialog box appears, you may select only one of the symbols, since all graphs require a single root.

The following procedure assumes you have opened a Browse window:

To query the browser database from the Browse window

1.	From the Type drop-down list box, select a query type.

2.	In the Subset drop-down list box, if the query type is Definitions and References, select a symbol type for the query to search, or select ALL to search all symbol types.

For example, to display all member functions of the class CCmdTarget in the left panel, type CCmdTarget:: in the Symbol text box and select Functions from the Subset list box.

3.	In the Symbol text box, type the name of the symbol you want to browse.

Or, using the drop-down list, select a symbol you have browsed recently.

Or type a wildcard combination to match one or more symbol names.

4.	Choose the Display Result button, or press ENTER, to start the query.

If the query type is Definitions and References, the left panel below the Query group displays the symbol, or lists of symbols. For all other query types, the left panel displays a graph.

Techniques for manipulating the graphs and lists in the Browse window are described in »Browsing Classes and Functions«.

You can choose the Previous Query button to recall the state of the previous browse operation. You can recall all the browse operations you have performed since opening the Browse window.


  Using Menu Commands

You can use menu commands and shortcut keys to browse for definitions and references directly from any symbol in a source file associated with the open database file, or any symbol in the Browse window. To do this, you use the five menu commands on the Browse menu:

•	Go to Definition (F11)

•	Go to Reference (SHIFT+F11)

•	Next (CTRL+NUMPAD +)

•	Previous (CTRL+NUMPAD  - )

•	Pop Context (CTRL+NUMPAD *)

To query the browser database from a source file

1.	Select a symbol by highlighting it or placing the insertion point anywhere inside the symbol.

2.	From the Browse menu, choose Go to Definition (F11) to jump to the first definition of that symbol.

Or choose Go to Reference (SHIFT+F11) to jump to the first reference of that symbol.

If the Browse window isn't already open, it is opened and minimized when you choose either Go to Definition or Go to Reference.

When you choose Go to Definition, a source window opens on the file containing the definition of the selected symbol. The insertion point is placed at the definition's location in the source file. If the source for the definition is not available, such as a definition for a library function like printf(), the insertion point jumps instead to the first reference, which is usually the prototype.

When you select Go to Reference, a source window opens on the file containing the first reference to the selected symbol, with the insertion point placed at the reference's location in the source file.

When you choose either Go to Definition or Go to Reference, a list is maintained  of all definitions or references of that symbol, depending on which menu command you chose. You can traverse this list forward or backward using the Next and Previous command on the Browse menu. To change the list type—for example, from definitions to references—you must use one of the "Go to" commands.

To jump to the next or previous definition or reference in a source file

•	From the Browse menu, choose Next or Previous.

If you last chose Go to Definition, a source window appears with the insertion point on the Next or Previous definition of the queried symbol.

If you last chose Go to Reference, a source window appears with the insertion point on the Next or Previous reference of the queried symbol.

To return to the last symbol queried:

•	From the Browse menu, choose Pop Context.

The queried symbol is displayed in the source window containing the current query context (the symbol selected before the last Go to Definition or Go to Reference).

Note  The Go to Definition and Go to Reference commands generate an internal list that can be traversed using the Next and Previous Browse menu commands. This list  is not related to the currently selected definition or reference in the Browse window.


  Browsing Classes and Functions

One of the most appealing features of the browser is the ability to view C++ class hierarchies and relationships between called and calling functions. Class and function relationships are more easily understood when they are displayed as graphs. For example, you can use class graphs to view the classes from which a class is derived as well as the member functions and variables available to each class. You can use function graphs to trace the path of function calls visually.

Once you have queried the browser database for a graphical representation, you can manipulate the nodes of the resulting tree to view a section of a tree or the fully expanded tree. As you click each node, the browser displays a list of definitions and references for the symbol at that node. The browser also displays a list of member functions and variables for each node you select on a class tree.


  Graphical Browser Query Types

You can use the following graphical query types in the Browse window:

•	Call Graph

•	Caller Graph

•	Derived Class Graph

•	Base Class Graph

The browser uses graphical trees to display relationships between base and derived C++ classes, and between called and calling functions. This is similar to the way the Windows File Manager displays directories. In a class graph, each node of the tree represents a class; in a function graph, each node represents a function. Each node can be expanded if it contains further branches or collapsed to hide all its branches.

»Figure 4.4« illustrates the graphs used to display C++ class-hierarchy information. A Derived Class Graph branches from left to right with the base class on the left and derived classes expanding to the right. A Base Class Graph also branches from left to right, but with the derived class on the left and the class or classes from which it is derived expanding to the right.

Derived Class Graphs and Base Class Graphs automatically provide a list of member functions and member variables in the top window panel to the right of the graph. You can click a member variable name to open the source window where it is defined, or click a member function name to open the source window where it is implemented.

»Figure 4.5« illustrates the graphs used to display function-calling relationships. A node on the left of a Call Graph represents a function that calls all functions labeled in nodes to its right. Conversely, in a Caller Graph, a node on the left represents a function that is called by all the functions labeled in nodes to its right.

The browser also displays locations of symbol definitions and references when you select any of the four graphical query types. To see where any class or function in a graphical tree is defined and a list of all locations where it is referenced, simply click the node. The definitions and references appear to the right of the graph.

You can double-click any reference or definition to open the corresponding source file. The insertion point will be on the corresponding line.


  Expanding and Collapsing Graphs

A node in a class graph or function graph can be collapsed or expanded to hide or display subordinate nodes. A node icon that looks like an empty file box indicates that a node has either been expanded or has no subordinate nodes. A node icon that looks like a file box containing files indicates that a node has subordinate nodes but is collapsed (see »Figure 4.6«).

You can expand a graph one level at a time, or all at once, using the mouse or various keyboard shortcuts. The "active node" refers to the selected symbol in the graph.

To expand the active node one level

•	Choose the Expand Node button, double-click the node, or press PLUS SIGN (+) on the number pad.

To collapse the active node one level

•	Choose the Collapse Node button, or double-click the node, or press MINUS SIGN (-) on the number pad.

To fully expand the active branch

 •	Press ASTERISK (*) on the number pad.

To expand the entire graph

 •	Choose the Expand Tree button or press ALT+x.


  Browsing Classes

When you select Derived Class Graph or Base Class Graph as a query type, the browser displays a graphical tree. You can view class hierarchical relationships by picking a class name and then viewing a tree of all classes derived from the class (»Derived Class Graph«) or a tree of all the classes from which it is derived (»Base Class Graph«).

Once a class graph is displayed, you can view information about each class in the two window panels to the right of the graph. When you select any class in the graph, the location where it is defined and all locations where it is referenced are displayed in the bottom right panel. All member functions and variables are displayed in the top right panel.


  Derived Class Graph

The Derived Class Graph query type is used to display a graph of all classes derived from the class you select as the base class.

To display a tree of all classes that are derived from a class

1.	From the Type drop-down list box, select Derived Class Graph.

Notice that Classes appears automatically in the Subset box and is the only choice.

2.	In the Symbol box, type the class name, type a wildcard, or select a previously used symbol from the drop-down list.

For example, type CWnd.

If you type a wildcard, such as C*, that matches several symbol names, a disambiguation dialog box appears with a list of all symbols matched by the wildcard. Select one name from the list and choose OK.

3.	Choose the Display Result button or press ENTER.

The CWnd derived class graph is displayed in the Browse window (see »Figure 4.7«).


  Base Class Graph

When you want to view the inheritance path of a particular class, select the Base Class Graph query type. This graph is a chain of single nodes unless the class uses multiple inheritance, in which case the multiple base classes appear as multiple branches.

To display a graph of base classes from which a class is derived

1.	From the Type drop-down list box, select Base Class Graph.

Notice that Classes appears automatically in the Subset box and is the only choice.

2.	In the Symbol box, type the class name, type a wildcard, or select a recently queried class from the drop-down list.

For example, select or type CDialog.

3.	Choose the Display Result button or press ENTER.

The CDialog base class graph appears in the Browse window.

4.	To see the complete inheritance path (»Figure 4.8«), choose Expand Tree.


  Member Functions and Variables

Member functions and variables are displayed for any query using the Derived Class Graph or Base Class Graph query type.

To display a list of all member functions and variables belonging to a class

1.	Perform either a Derived Class Graph or Base Class Graph query.

Specify the class in the Symbol box or make sure it is included in the resulting graph.

2.	Click the name of the class in the resulting graph to make it the active node.

The upper panel to the right of the class tree displays all member functions and variables belonging to the class (not inherited).

Tip  You can also get a list of all member functions and variables by using the Definitions and References query type and specifying the wildcard ClassName::, where ClassName represents the name of the class whose member functions and variables you want to examine.


  Browsing Function Relationships

You can use the browser to display relationships between calling and called functions by selecting the Caller Graph or Call Graph query type. These graphs are tree structures unless they display a recursive function node. Nodes representing recursive functions, or any functions that appear more than once, are followed by an ellipsis (...).

To view a list of locations where a function is defined and referenced, select the function in the Caller Graph or Call Graph tree. The panel to the right of the graph panel in the Browse window lists the locations of the function definition and all references to it. Double-click any location in this list to open a source window at that location in the specified file.

To display a graph of all functions that are called by a function

1.	From the Type drop-down list box, select Call Graph.

The Subset box displays Functions.

2.	In the Symbol box, type the function name, type a wildcard, or select a previously queried function from the drop-down list.

3.	Choose the Display Result button or press ENTER.

The call graph of the selected function is displayed (see »Figure 4.9«).

To display a graph of all functions that call a function

1.	From the Type drop-down list box, select Caller Graph.

The Subset box displays Functions.

2.	In the Symbol box, type the function name, type a wildcard, or select a previously queried function from the drop-down list.

Note that if you type the name of a function with more than one definition (such as a C++ class constructor), a disambiguation dialog box appears to let you choose the function from a list box. This dialog box also appears when you use wildcards that match more than one symbol name.

3.	Choose the Display Result button or press ENTER.

The caller tree of the selected function is displayed.


  Browsing Definitions and References

You can use the browser to move between files and access common program elements. For example, if you want to examine or change a definition of a function, you can use the browser to jump to the function's definition. Or, after changing a function's definition, you can use the browser to visit every place where it is referenced.

When you select a class or function graph query type, references and definitions are automatically displayed for the active node to the right of the graph. To view  references and definitions of all other types of symbols, or to get reference or definition information on any class or function, use the following procedures.

Note  The browser database is based on the state of source files at the time of the last build. If you edit source files and then perform browse operations, the locations of definitions and references may not be accurate.

If a definition is listed as <Unknown>, it is probably located in a library for which you are not provided the source code. For example, the macro _MSC_VER is generated by the compiler and defined in code that isn't provided with Visual C++.

To display a list of locations where a symbol is defined or referenced

1.	From the Type drop-down list box, select Definitions and References.

2.	In the Subset drop-down list box, select the symbol type you are interested in.

3.	In the Symbol box, type the symbol name.

Or, using the drop-down list, select a symbol you have browsed recently.

Or type a wildcard combination to match one or more symbol names (for example, type * to produce a list of all symbol names).

4.	Choose the Display Result button or press ENTER.

A list of all symbols that match the query parameters appears in the left display panel. The list may contain a single symbol, if you typed a symbol name, or many symbols if, for example, you typed a wildcard or typed the name of an overriden C++ class member function.

5.	Click any symbol in the left panel to get a list of its definitions and references in the panel on the right.

The top symbol in the list is selected by default when there is more than one symbol.

Once you have a list of definitions and references, you can jump directly from the Browse window to a definition or reference using one of the following procedures:

To jump to any definition or reference from the Browse window

1.	Select the symbol in the left display panel.

2.	Double-click the definition or reference in the list in the right panel.

Or select the item and press ENTER.

The source file is opened (or is made the active file if it is already open), and the insertion point is placed on the line containing the definition or reference.

To jump to the first definition or reference from the Browse window

1.	Select the symbol in the left display panel.

2.	Choose Go to Definition (F11) to jump to the first definition, or choose Go to Reference (SHIFT+F11) to jump to the first reference of the symbol.

Once you have jumped to the first definition of, or reference to, a particular symbol, you can jump to subsequent definitions or references using the Next (CTRL+NUMPAD+) and Previous (CTRL+NUMPAD -  ) commands on the Browse menu.

Note  The current position of the definition or reference in a list generated by a "Go to" command (and traversed using the Next and Previous Browse menu commands) is not related to the currently selected definition or reference in the Browse window.


  Chapter 5  Debugging Programs

Debugging a program is a two-phase process. Visual Workbench offers features for performing both phases of debugging. The first phase involves correcting compiler and linker errors during the build process. These errors usually consist of incorrect language syntax, undeclared variables, or misspelled keywords.

The second debugging phase occurs after any syntax errors are corrected and the project is successfully built. If the program does not perform as desired, you need to analyze its internal workings. You can use a debugger to set breakpoints and examine variables. This allows you to locate bugs and correct them with the editor.


  Using the Debugging Windows

Visual Workbench displays information in a series of windows that you can view as you debug a program. You can use commands from the Window menu to active the debugging windows.

Table 5.1 lists the debugging windows and the information they show.

Table 5.1    Debugging Windows

Window	Information
Watch	Displays values of variables and expressions in the Watch window. Watch expressions are entered directly into the Watch window. Values are displayed only while the debugger is running.
Locals	Displays values of local variables within the function currently being stepped through. Values are used only while the debugger is running.
Registers	Displays current contents of the memory and status registers.
Memory	Displays current contents of memory; the format and  location are specified in the Memory  Window Options dialog box.
Output	Displays information about the build process, including any compiler errors. This window also displays output during a debugging session, such as output from OutputDebugString function calls (or the class library afxDump), thread termination codes, first-chance exception notification, and Windows NT warning and error messages.
You can size and minimize these windows during debugging so that you can see various types of information at one time.

»Figure 5.1« shows the debugging windows.


  Debugging During Building

The first phase of debugging is to fix language syntax errors. When a program is built, any compiler and linker errors are displayed in the Output window. If you need help on an error, move the insertion point to the error number and press F1 to display on-line information about the error.

To move through the list of errors

•	From the View menu, choose Next Error (F4).

 − Or −

•	Choose Previous Error (SHIFT+F4).

 − Or −

•	Double-click or press ENTER on an error in the Output window.

As each error is highlighted in the Output window, the corresponding line containing the error is highlighted in the source window. You can edit the line in the source window. To get help on any error or warning in the Output window, place the insertion point on the line containing the error or warning and press F1. Note that the Output window behaves like a source window, allowing you to copy and print information from the window.


  Using the Visual Workbench Debugger

Phase two of debugging occurs after your program is built. If your program has run-time errors or doesn't work correctly, you can use the Visual Workbench debugger to set breakpoints in the source code, view variables, and control program execution.


  Preparing a Debug Version of a Program

Before a program can be debugged, you must include debugging information in the executable file with the project. A debug version of a program runs slower and is larger than a release version.

To prepare a project for debugging

1.	Open the project.

2.	From the Options menu, choose Project.

The Project Options dialog box appears (see »Figure 5.2«).

3.	Under Build Mode, select the Debug option.

4.	Choose OK to close the Project Options dialog box.

5.	From the Project menu, choose Build.

The current project is compiled and linked and, if no errors occur, a version of the executable file containing debug information is created.


  Setting and Removing Breakpoints

Breakpoints are useful when you have a general idea of where a bug occurs in a program. The debugger runs until it reaches the breakpoint, then stops. At this point, you can step to the next line of code or trace through a function until you find the problem. While the program is paused at a breakpoint, you can also examine variable values using the QuickWatch dialog box or the Watch or Locals window, or examine register values using the Registers window.

You can set and clear breakpoints using the Breakpoints dialog box or the Toggle Breakpoint button on the toolbar. The Toggle Breakpoint toolbar button sets or clears a breakpoint at the insertion point. The Breakpoints dialog box allows you to set more complex breakpoints, such as breaking if an expression is true or breaking on a window message.

All breakpoints that are active when a project is closed are saved as part of the project information and become active when the project is opened again. (Expressions and variables in the Watch window are also saved as part of the project information and restored each time the project is reopened.) A project is closed when you choose Close from the Project menu or when you open or create another project.


  Using the Toggle Breakpoint Button

The Toggle Breakpoint button on the toolbar is a quick way to set and clear breakpoints in a program. If you prefer to use shortcut keys, use F9 to toggle breakpoints.

To quickly set a breakpoint

1.	Move the insertion point to the line where you want the program to break.

2.	Click the Toggle Breakpoint button on the toolbar (or press F9).

Visual Workbench highlights the line, indicating that the breakpoint is set.

To quickly remove a breakpoint

1.	 Move the insertion point to the line containing the breakpoint.

2.	 Click the Toggle Breakpoint button on the toolbar (or press F9).


  Using the Breakpoints Dialog Box

The Breakpoints dialog box (see »Figure 5.3«) keeps a list of all breakpoints assigned to your project. Breakpoints can be set in any of your project source files or in an executable file. To add a breakpoint, you first select the breakpoint type, fill in parameters if needed, and choose the Add button. To remove a breakpoint, you select it in the list and choose Delete. To deactivate a breakpoint, you select it and choose Disable. For additional information on breakpoints, search for breakpoints in Help or press F1 in the Breakpoints dialog box.

You can choose six types of breakpoints from the Type list box in the Breakpoints dialog box. These let you determine where and when the program will pause execution. The breakpoints are described in the following paragraphs.


  Break at Location

This is the simplest type of breakpoint and is the default type used. If you have the insertion point on a line of code in a source file, this line automatically appears in the Location text box. You can then choose Add to add this breakpoint. When your program's execution reaches the breakpoint location, the program stops temporarily and you can use other debugging features. See »Breakpoints Involving Location« for information on proper location values.


  Break at Location if Expression is True

When the debugger reaches a specified location, the debugger checks the expression specified in the Breakpoints dialog box. If the expression is true (non zero), the program stops at the breakpoint location.


  Break at Location if Expression has Changed

You specify a location and an expression that represents a variable or a portion of memory and type a variable or memory address in the Expression text box. The debugger checks this variable or memory location after every line (or every instruction if in mixed mode). If the value of any byte has changed, the program stops at the breakpoint location. This type of breakpoint can greatly slow your program's execution. See »Breakpoints Involving Expressions« for more information.


  Break when Expression is True

The debugger evaluates a specified expression after every line or every instruction and stops at the current line or instruction if the expression is true. This type of breakpoint can greatly slow your program's execution.


  Break when Expression has Changed

The debugger checks the specified variable or range of memory as each line or each instruction is executed. You can also specify a range of memory by typing the starting address in the Expression text box and the length in the Length text box. This type of breakpoint can also slow your program's execution. See »Breakpoints Involving Expressions« for more information.


  Break at WndProc if Message is Received

You can specify a Windows callback function in the WndProc text box and use the Messages dialog box to select a single message or one or more classes of messages. When a targeted message is received or a message from a targeted class of messages is received, the program's execution is paused at the specified WndProc. See »Breakpoints on Messages« for more information.


  Breakpoint Types Involving Location

You can enter a location directly into the Location text box by typing a location and choosing the Add button. The location can be entered either as a line number (with an optional filename) or as an address (in either hexadecimal or decimal notation). Registers can also be used to form the address. Use a period (.) to indicate a line number and an exclamation point (!) to separate a filename from a line number. The following table shows the various formats for specifying location:

Format	Example	Sets breakpoint at:
Filename!.linenumber	MyApp.cpp!.35	Line 35 in MYAPP.CPP
.linenumber	.35	Line 35 in the active source file
Offset	0x10222	Code offset
Offset	EIP	Instruction pointer offset


  Breakpoint Types Involving Expressions

The breakpoint types that involve expressions evaluate whether an expression is true or has changed. Depending on the breakpoint type, when the expression evaluates correctly, the program pauses either immediately or as soon as the program reaches the specified location. To use one of these types, you must first specify the desired expression in the Expression text box.

To detect when an expression has changed, you must enter a variable with a memory location (an l-value) in the Expression text box when you set the breakpoint. For variables that are not pointers, the value of the Length text box should normally be left as 1, since the length is calculated as the size of the variable multiplied by the number in the Length text box.

When you specify the name of a pointer in the Expression text box (such as Ptr, where Ptr is defined as int *Ptr), the breakpoint is set only when the address of the pointer changes. To set a breakpoint when the memory pointed to by the pointer changes, dereference the pointer in the Expression text box (for example, *Ptr) and then specify the number of bytes in memory to examine in the Length text box.

Memory ranges can be set by typing a starting address in hexadecimal or decimal notation in the Expression text box and the number of bytes in the Length text box. Registers can be used for addresses.


  Breakpoints on Messages

The breakpoint type "Break at WndProc if Message is Received" lets you set a breakpoint that tests messages received by any exported Windows callback function (window procedure). You can select whether to break on a specific message, or on any message from a class or several classes of messages.

To set a breakpoint on a message

1.	From the Debug menu, select Breakpoints.

The Breakpoints dialog box appears.

2.	In the Type drop-down list box, select Break at WndProc if Message is Received.

3.	In the WndProc text box, specify the name of the Windows callback function you want to test for messages.

If you are setting a breakpoint during a debug session, the drop-down list contains all the exported functions in your project determined by the debugger to be Windows callback functions; otherwise, it is blank.

4.	Choose the Messages button to open the Messages dialog box (see »Figure 5.4«).

5.	In the Message Type group, select the Selection option button.

6.	In the Selection list box, select the message.

7.	Choose OK to close the Messages dialog box.

8.	Choose Add to set the breakpoint.

9.	Choose Close to close the Breakpoints dialog box.

You can follow the same basic procedure, with slight modification, to set a breakpoint on one or more classes of messages.

To set a breakpoint on any message in one or more classes

1.	From the Debug menu, select Breakpoints.

2.	In the Type drop-down list box, select Break at WndProc if Message is Received.

3.	In the WndProc text box, specify the name of the exported Windows function.

4.	Choose the Messages button to open the Messages dialog box.

5.	In the Message Type group, select the Class option button.

6.	In the Class list box, select one or more message classes.

7.	Choose OK to close the Messages dialog box.

8.	Choose Add to set the breakpoint.

9.	Choose Close to close the Breakpoints dialog box.

When you set a breakpoint on a message, the program will pause execution at the specified exported Windows function (WndProc) when it receives a message matching the qualifications.

Note  If you are debugging a Microsoft Foundation Class Library program, setting a breakpoint on a message may trace into the Microsoft Foundation Class Library source code. The debugger then requires the path to the Microsoft Foundation Class directory in order to open the file containing the breakpoint. If you do not have the MFC Files Path text box set correctly in the Directories dialog box (accessed from the Options menu), the debugger prompts you for a path. The debugger requires only the base path (for example, C:\MSVCNT\MFC).


  Controlling Program Execution

Once a breakpoint is reached and the program stops, you can control program execution with commands on the Debug menu. Table 5.2 lists the Debug Menu commands and their actions (asterisks denote commands with equivalent buttons on the toolbar).

Table 5.2    Debug Menu Commands

Command	Action
Go	Executes code from the current statement until a breakpoint is reached, a watchpoint expression becomes true, or the end of the program is reached.(Equivalent to the Run button on the toolbar.)
Restart	Resets execution to the first line of the program. It reloads the program into memory and discards the current values of all variables (breakpoints and watch expressions still apply). It automatically halts at the main() or WinMain() function.
Stop Debugging	Terminates the debugging session and returns to a normal editing session.
Break	Breaks the program at its current location.
Step Into	Single-steps through instructions in the program and enters each function call that is encountered. (Equivalent to the Step Into button on the toolbar.).
Step Over	Single-steps through instructions in the program. If this command is used when you reach a function call, the function is executed without stepping through the function instructions.(Equivalent to the Step Over button on the toolbar.).
Step Out	Executes the program out of a function call and stops on the instruction immediately following the call to the function. (Equivalent to the Step Out button on the toolbar.).
Step to Cursor	Executes the program as far as the line that currently has the cursor. This is equivalent to setting a temporary breakpoint at the cursor location.


  Viewing and Modifying Variables

When you are stopped at a breakpoint or between tracing steps you can view variables in your program. You can also modify variables to test different strategies or recover from bugs. This section describes how to view and modify variables using the following debugging features:

•	»Locals Window«

•	»Watch Window«

•	»QuickWatch«


  Using the Locals Window

The Locals window (see »Figure 5.5«) displays values of all variables that are within local scope of the instruction pointer. For example, if you break in a function, the local variables declared in that function appear in the Locals window. You cannot enter variables into this window but you can copy variables from it to the clipboard and paste them into the Watch window. You can also modify the value of any variable in the Locals window.


  Using the Watch Window

The Watch window allows you to enter variables you want to view or expressions you want to see evaluated as the program progresses. You can enter values or expressions into the Watch window at any time, but they are only evaluated while the program is in a debug session. The Watch window displays an error on watch variables and expressions until a debug session begins.

A watch expression can be any valid C or C++ expression. For example, the following are all valid watch expressions in C and C++:

count

count + 1

count + 1 == 5

For relational expressions, the Watch window shows 0 if the expression is false and 1 if the expression is true:

count + 1 == 5 = 0

count + 1 == 5 = 1

Cast operators can be used in the Watch window, even on user-defined types.

Adding and Deleting Variables and Expressions

The following procedures describe how to add variables and expressions to, and delete them from, the Watch window.

To add a variable or expression to the Watch window

1.	While the program is paused between steps or at a breakpoint, optionally copy a variable in your code to the clipboard (CTRL + C).

2.	Move the insertion point to the first blank line in the Watch window (see »Figure 5.6«).

3.	Type the variable name or expression,

Or press CTRL+V to paste a variable you have previously copied to the Clipboard.

4.	Press ENTER.

The variable or expression is evaluated immediately. If the expression or variable cannot be evaluated, an error message appears in the window next to the variable or expression.

Important  If you use the copy (CTRL+C) and paste (CTRL+V) commands to copy variable names from your program source files into the Watch window, you must always press Enter to insert the variable or expression into the window.

You can also use the QuickWatch dialog box to add variables to the Watch window.

To delete a variable or expression from the Watch window

1.	 Move the insertion point to the line containing the variable or expression.

2.	Press CTRL+Y

or

Select the entire variable name or expression using either the mouse or SHIFT+LEFT ARROW and SHIFT+RIGHT ARROW and press the DEL key.

To learn how to modify variables in the Watch window, see »Modifying a Variable«.

Expanding and Collapsing Variables

In the Watch window, Locals window, and QuickWatch dialog box, variables that contain more than one element, such as arrays, structures, classes, or enumerated types, are displayed with either a + or − sign preceding them (see »Figure 5.7«).

The + symbol indicates that the variable contains elements and can be expanded. The − symbol indicates that the variable is fully expanded and can be collapsed.

To expand or collapse a variable

1.	Move the insertion point to the line containing the variable.

2.	Press ENTER.

Or double-click on the variable.


  Using QuickWatch

The QuickWatch dialog box gives you a fast way to view and modify variables and expressions (see »Figure 5.8«). Unlike watch expressions, which remain in the Watch window, the values of QuickWatch variables and expressions appear only when you open the QuickWatch dialog box.

You can use QuickWatch to check variables that are suspect but are not in the Watch window. You can also use QuickWatch to add variables to the Watch window. Note that the QuickWatch dialog box is active only when your program is running in the debugger.

To view a variable or expression

1.	Place the insertion point on a variable or expression in your code.

2.	Press SHIFT+F9.

Or click the QuickWatch button on the toolbar.

To add a variable or expression to the Watch window

1.	Place the insertion point on a variable or expression in your code.

2.	Press SHIFT+F9.

Or click the QuickWatch button on the toolbar.

3.	Choose Add to Watch Window.

The Watch window opens if it is not already open.

The QuickWatch dialog box also provides controls that allow you to expand arrays or structures to see all their elements and to modify variables while the program is at a breakpoint. The following buttons appear in the QuickWatch dialog box:

Zoom  The Zoom button expands or contracts an array or structure. The button is unavailable if the selected item cannot be expanded.

Modify Value  The Modify Value button changes the value of a variable (not an expression) in the Expression text box to the value you specify in the New Value text box. The variable cannot be part of an expression.

New Expression  The New Expression button evaluates the variable or expression in the Expression text box and updates the Current Value box with the value. If you want that value assigned to a variable, be sure to assign it in the expression. For example, the expression x+10 evaluates to the current value of x plus 10 but does not assign this value to x when the dialog box is closed; to do this you need to type x+=10 in the Expression text box.

Modifying a Variable

While the program is paused at a breakpoint or between steps, you can change the value of any variable in your program. This gives you the flexibility to try out changes and see their results in real time or to recover from a logic error and continue. You can modify any variable using one of three methods:

•	Use the Modify Value button in the QuickWatch dialog box

•	Modify the variable in the Watch window

•	Modify the variable in the Locals window

To modify the value of a variable using the QuickWatch dialog box

1.	Place the insertion point on a variable in your code.

This is optional since you can type the name of any variable in the QuickWatch dialog box (see step 3).

2.	Click the QuickWatch button on the toolbar.

Or press SHIFT+F9.

The QuickWatch dialog box appears and displays the variable at the insertion point along with its current value.

3.	Optionally, type the name of the variable you want to modify in the Expression text box.

4.	Type a new value in the Modify Value text box.

5.	Choose the Modify Value button.

»Figure 5.9« shows a QuickWatch dialog box with a modified variable.

6.	Choose Close to close the QuickWatch dialog box.

Note  To change the value of a structure or array, modify the individual fields or elements. You cannot modify an entire array or structure at one time.

To modify the value of a variable in the Watch window or Locals window

1.	In the Watch window or Locals window, place the insertion point at the end of the variable or expression and delete it using the backspace key.

2.	Type the new value.

3.	Press Enter.


  Using Call Stack

During a debug session, you can view all the functions that have been called but have not returned. The Call Stack command on the Debug menu opens a dialog box that lists the function calls that led to the current statement (see »Figure 5.10«). If the Show Function Parameters check box is selected, each call is shown with the arguments passed to it. The most recently executed function is listed first.

To view a function call

1.	Place the insertion point at the desired location in the function.

2.	From the Debug menu, choose the Step to Cursor command to execute your program to the location of the insertion point.

The Locals window is updated automatically to show the local variables for the function or procedure. Expressions and variables in the Watch window are also reevaluated in the call context.

3.	From the Debug menu, choose Call Stack.

While the Call Stack dialog box is open, you can select any function shown in the function list, and the function's code will be displayed in the source window.


  Using the Registers Window

The Registers window (see »Figure 5.11«) displays the names and current values of the native CPU registers and flags. You can change the value of any register or flag in the Registers window while the program is being debugged.

To change the value of any register in the Registers window

1.	Use the TAB key or mouse to move the insertion point to the beginning of a register value.

2.	Enter the new value by over-typing the current value.

Important  Changing register values may affect the next execution command. Be especially careful with EIP and EBP registers.

The flag values displayed in the Registers window are shown in Table 5.3.

Table 5.3  Register Window Flags

Flag	Set	Clear
Overflow	O=1	O=0
Direction	D=1	D=0
Interrupt	I=1	I=0
Sign	S=1	S=0
Zero	Z=1	Z=0
Auxiliary carry	A=1	A=0
Parity	P=1	P=0
Carry	C=1	C=0
To set or clear a flag in the Registers window

1.	Move the insertion point to the flag.

2.	Double-click on the flag value,

Or press the SPACEBAR to toggle the flag.


  Handling Exceptions

Exceptions are hardware or software generated events that occur when an unexpected condition is encountered during program execution. For example, divide-by-zero errors and the ctrl-c break are exceptions. You can provide exception handlers in your program to recover from exceptions or at least to terminate your program under control when an exception occurs.

When you are running a program in the debugger and an exception occurs, the debugger is notified. Using the Exceptions dialog box, opened from the Debug menu, you can list each exception that might occur in your program and determine how the debugger will act when that exception occurs. The Exception dialog box is shown in »Figure 5.12«.


  Modifying the Exception List

A list of system exceptions is provided in the Exception List in the Exceptions dialog box. You can modify this list, deleting system exceptions or adding your own exceptions for each project. The exceptions list is maintained along with other project information. System exceptions are identified by descriptive names such as "Access Violation," which correspond to their macro definitions in WINBASE.H. The following procedures describe how to add, delete, and restore exceptions:

To add a new exception to the exception list

1.	From the debug menu, choose Exceptions to open the Exceptions dialog box.

2.	In the Exception Number box, type the DWORD exception number for the user-defined exception.

3.	Optionally, type the name of the exception in the Name box.

4.	Optionally, select an action to apply to the exception from the Action options.

5.	Optionally, choose Add.

6.	Choose OK.

You can also change any parameter associated with an exception.

To change an existing exception in the exception list

1.	From the debug menu, choose Exceptions.

The Exceptions dialog box opens.

2.	Select the exception in the Exception List.

3.	Change any of the parameters.

4.	Optionally, choose the Change button.

5.	Choose OK.

To delete an exception from the exception list

1.	From the debug menu, choose Exceptions.

The Exceptions dialog box opens.

2.	Select the exception in the Exception List.

3.	Choose the Delete button.

When exceptions are deleted from the Exception List, their action reverts to  Stop if Not Handled.

4.	Choose OK.

To restore all default system exceptions to the exceptions list

1.	From the debug menu, choose Exceptions.

The Exceptions dialog box opens.

2.	Choose the Default button.

All default system exceptions are restored to the Exception List without disturbing any of the user-defined exceptions that have been added.

3.	Choose OK.


  Determining an Action for an Exception

When an application is running in the debugger, an exception always notifies  the debugger the first time. This is called the first-chance notification. You can choose to stop the debugger at this point (Stop Always action option) or simply have it notify you in the Output window that the exception has occurred (Stop if Not Handled action option). When you stop the debugger at first-chance notification, you can use the debugger to fix the problem and dismiss the exception before continuing the program, or you can pass the exception on to be handled by the program's exception handlers.

When you continue a program that has stopped at first-chance notification, you are asked whether you want to pass the exception on to the program's exception handlers, or to dismiss the exception.

If the exception is passed to the exception handlers and it isn't handled properly, the debugger is notified again. This is call the last-chance notification. If you continue the program from a last-chance notification, the exception is automatically dismissed. Any exception encountered by the program at this point results in a first-chance notification. (As defined by Win32, programs continued from a last-chance notification are terminated by the system. The debugger protects you from this automatic termination by dismissing  last-chance exceptions.)

If you dismiss the exception at first-chance notification and it occurs again, the result is another first-chance notification.

For each exception in the exceptions list, you can choose Stop Always to stop in the debugger at both notifications, or Stop if Not Handled to stop only on the last-chance notification.

To specify an action for an exception

1.	Select the exception from the Exception List.

2.	Choose one of the action options from the Action group.

The Action group contains two options:

•	Stop Always: When the exception occurs, stop at the first-chance notification and at the last-chance notification, if there is one. When you continue the program from a first-chance notification, a dialog box asks you whether to pass the exception back to the program or to dismiss it. An exception that is passed on will result in a last-chance notification if the exception handlers fail.

•	 Stop If Not Handled: When the exception occurs, don't stop at the first-chance notification. Pass the exception back to the program and post a notification message to the Output window that a first-chance exception occurred. If the program's exception handlers fail, then stop in the debugger on last-chance notification.

For any exception not in the exception list, the actions is Stop if Not Handled, which is also the default for most exceptions in the list.


  Debugging Threads

Windows NT supports multiple threads of execution per application. If the application you are debugging has more than one thread, use the Threads dialog box, accessed from the Debug menu, to choose a single thread to debug. The Threads dialog box is shown in »Figure 5.13«.

The Threads dialog box displays a list of application threads. To use the dialog box, select a thread and choose one of three buttons:

•	The Suspend button increases the suspend count by one. If it was in a runnable state this suspends the thread.

•	The Resume button decreases the suspend count by one. If this decrements the suspend count to 0 the thread will resume.

•	The Set Focus button makes the selected thread the active thread in the debugger.

The Thread List in the Threads dialog box displays status information on each thread as described in the following paragraphs:

Thread ID  This is the DWORD that uniquely identifies the thread. When you set focus on a thread, it is displayed in the Thread List with an asterisk next to its identifier.

Suspend Count  If the suspend count is 0, the thread is in a runnable state. A suspend count of 1 or greater indicates that the thread is suspended.

Priority  This can be one of seven priorities: Idle, Lowest, Below Normal, Normal, Above Normal, Highest, or Time Critical

Current Location  This is the current address of the thread. It is displayed either as a function name or an address, depending on the state of the Current Location Display option at the bottom of the dialog box. If Function Name is selected, the current function name is displayed if known by the debugger. If Address is selected, the current address is always displayed.


  Using the Memory Window

During a debugging session, you can view and alter memory contents by opening the Memory window. To open the Memory window, choose Memory from the Window menu.

The Memory window displays memory locations starting at a specified address. You can scroll the memory window to view any memory location in the program's available address space. Options in the Memory Window Options dialog box control, among other parameters, the starting address, the display format, and the number of values to display on each line.


  Viewing memory at a Dynamic Address

Live expressions make it easy for you to watch a dynamic view of an array or pointer in the Memory window. The starting address of memory in the window changes to reflect the current value of the address expression in the Memory Window Options dialog box.

To create a live expression

1.	From the Options menu, choose Memory.

The Memory Window Options dialog box opens.

2.	Type the address expression in the Address text box.

For example, type *pPtr in the Address text box to cause the Memory window to display memory contents starting at the address pointed to by *pPtr.

3.	Select the Re-evaluate Expressions Always check box.

It is usually more convenient to view a program element, such as a variable, in the Watch window than the Memory window. However, some items are more easily viewed using live expressions in the Memory window. For example, you can examine what is currently on top of the stack by entering SS:ESP as the live expression.

Altering Memory Contents

To change the contents of a memory location, move the insertion point to the memory address, by using the mouse or the tab key, and type the new memory contents over the existing contents. The Memory window ignores any characters that are not compatible with the current display format.

Setting Memory Window Options

To change the format and starting location of data displayed in the Memory window, open the Memory Window Options dialog box by choosing Memory from the Options menu.

The following parameters can be set in the Memory Window Options dialog box:

Address Expression  You can specify any address expression in the Address text box. An address expression must evaluate to a memory address, such as a numeric value, a register, or a variable address.

Display Format  This drop-down list box contains several formats, from ASCII to Real Long (64-bit float), that can be applied to the data in memory. By default, memory is displayed in Byte (8-bit hex) format, which automatically provides an additional field of the equivalent ASCII characters in the right column.

Re-evaluate Expression Always (Live)  Select this check box to cause the Memory window to continuously display  the memory location evaluated from the expression in the Address text box. The live address is always displayed in Memory window.

Show Raw Data  Select this check box to display data in Byte (8-bit hex) format along with the display format you choose using the Display Format drop-down list box.

Number of Values per Line  This parameter determines how many formatted values to put on each line of the Memory window. By default, this is specified as Var (variable) and is dependent on the dimensions of the Memory window. You can specify an integer in this text box to hard-code the number of columns of values displayed the Memory window.


  Setting Debug Display Options

The Visual Workbench debugger also has debugging commands and options for  viewing numbers in hexadecimal or decimal format, for determining whether or not to open new source windows during debugging, and for viewing source code as mixed source and assembly listings.

The debugging display options are listed in Table 5.4. The menus or dialog boxes where you find these features are listed in parentheses following the action.

Table 5.4    Debugging Display Options

Feature	Action
Hexadecimal Display	Toggles the format of all numbers displayed in the Locals and Watch windows, as well as in several dialog boxes. The default format is base 10. When this option is selected, the format is base 16. (Options menu, Debug dialog box, also accessed using alt-F9)
Single Debug Window	Toggles whether a new source window is opened when you step into a source file that is not already open, or whether the file is loaded into the currently active source window. (Options menu, Debug dialog box.)
Mixed Source/Asm	Toggles a source display that includes assembly code integrated with source code. When this command is selected the debugger single-steps assembly lines and breakpoints can be set in assembly code. (View menu, also accessed using CTRL-F7)
See Help for complete information about these commands.


  Debugging DLLs

You can debug DLLs using the same techniques used to debug an EXE project by first specifying an executable program that calls the dynamic-link library.

To debug a DLL project

1.	Create an appropriate .EXE shell program that calls the DLL.

2.	From the Options menu, choose Debug to open the Debug dialog box.

3.	In the Calling Program text box, enter the name of the executable shell program that calls the DLL.

4.	Choose OK to close the Debug dialog box.


  Chapter 6  Customizing Visual Workbench

Many parts of Visual Workbench can be customized to suit your programming needs. You can add commands and applications to the Tools menum, modify display colors, and change the font type and size in source windows.

You can also customize many features of the Visual Workbench editor using the Editor dialog box, opened from the Options menu. For information on customizing the editor, see »Chapter 2« "Using the Editor."


  Modifying the Tools Menu

You use the Tools command on the Options menu to add, delete, and edit Tools menu items. You can add frequently used utilities to the Tools menu and run them within Visual Workbench.


  Adding Commands to the Tools Menu

You can add up to eight commands to the Tools menu. A tool can be any program that you can run in Windows NT, such as native Windows NT programs, Windows 3.1 programs, MS-DOS® programs, Posix programs, or OS/2® programs.

To become familiar with the steps in adding a command to the Tools menu, use the Notepad accessory that comes with Windows NT.

To add a command to the Tools menu and then run it

1.	From the Options menu, choose Tools.

The Tools dialog box appears (see »Figure 6.1«).

2.	Choose Add to open the Add Tool dialog box (see »Figure 6.2«).

3.	Select the directory in which Windows NT is installed.

4.	Select NOTEPAD.EXE from the list of filenames and choose OK.

The Tools dialog box reappears.

You can change the default menu name by editing the Menu Text text box.
You can also add arguments to be passed to the program by typing them in the Arguments text box (see »Using Argument Macros«) or set the initial directory for your program by typing it in the Initial Directory text box.

Note  If the program you are adding to the Tools menu has a .PIF file, the startup directory specified by the .PIF file overrides the directory specified in the Initial Directory text box.

5.	Choose OK.

The command now appears on the Tools menu. To run the program, choose it from the menu.


  Editing a Tools Menu Command

To edit a Tools menu command:

1.	From the Options menu, choose Tools.

2.	Under Menu Contents, select the menu command you want to edit.

3.	Perform one or more of the following actions:

•	To move the selected command up one position in the menu, choose
Move Up.

•	To move the selected command down one position, choose Move Down.

•	To change the menu title, the command line (tool path), command-line arguments, or the initial directory, type the new information in the appropriate text box.

If you want to specify a letter in the menu title as an access key (a menu accelerator key), precede that letter in the Menu Text text box with an ampersand (&). The first letter in the title is the keyboard access key by default.

If you want to be prompted for command-line arguments each time you run the tool, select the Ask for Arguments check box.

4.	Choose OK.

.

To delete a command from the Tools menu:

1.	From the Options menu, choose Tools.

2.	Under Menu Contents, select the command you want to delete from the Menu Contents list.

3.	Choose Delete to remove the program from the list.

4.	Choose OK.


Tools Checkboxes
  Tools Options

The Tools dialog box includes three check boxes that let you customize options that apply to the active tool in the Menu Contents list. The check boxes are described in the following paragraphs.

Ask for Arguments  When this check box is selected, an argument dialog box will appear when you run the tool and the arguments you type in will be passed to the program.

Redirect to Output Window  When this check box is selected, the standard I/O output from the tool will appear in the Output window. A separate virtual output window is maintained for each tool whose output has been redirected to the Output window. These tools are given the label Output - toolname (the name of the tool). You can switch between virtual Output windows by using the Output command on the View menu. See »Using Error Syntax for Tools« to learn about additional capabilities gained by redirecting tool output to the Output window.

Close Window on Exit  When this check box is selected, the Command window automatically closes when the tool has finished executing. This applies to character-mode applications only.


  Using Error Syntax for Tools

When you redirect the output from a tool to the Output window by selecting the Redirect to Output Window check box for the tool in the Tools dialog box, you gain access to the Output window's error parser.

The error parser is used by the internal build tools to detect filename, error and line number information on an output string and make that line a hot link to the specified file and line number. For example, you can double-click an error line in the Output window that contains the error number, filename and line number where the error occurred, and jump directly to the referenced line in the correct source file.

The Find in Files and Profiler dialog boxes also use the error parser. For instance, you can double-click any output line from a Find in Files operation  and jump to the referenced file and line.

If the output to a tool you have installed and redirected to the output window has the correct error syntax, you can use it in the same way.

Example

For example, you could install Microsoft MASM on the Tools menu to compile assembly code and then jump to source code syntax errors directly from its error list in the Output window. The error syntax is as follows (+ denotes one or more; * denotes zero or more):

error_string	::=	file_spec  error_spec   (STRING   |  file_spec STRING )
file_spec	::=	FILENAME '(' line_spec ')' ':'
line_spec	::=	NUMBER  | NUMBER '-' NUMBER
error_spec	::=	ERRORKEYWORD ERRORNUMBER ':'
where:

STRING	::=	Null terminated string
FILENAME	::=	Valid file specification  &  text file
NUMBER	::=	{1-9}{0-9}*
ERRORNUMBER	::=	{A-Z}+{0-9}{0-9}{0-9}{0-9}
ERRORKEYWORD	::=	"error" | "warning" | "fatal error"
Note  Although the error number is part of this syntax, it is optional and not really useful to any tool except internal build tools. This error number is used internally to link to Help files.


  Using Argument Macros

You can specify arguments for any program that you add to the Tools menu by entering the arguments in the Arguments text box. To help you integrate your tools with the current status of the Visual Workbench environment, Visual Workbench provides a set of 11 argument macros (see Table 6.1).

Table 6.1    Visual Workbench Argument Macros

Macro Name	Expands to a String Containing
$File	The complete filename of the current source (defined as drive+path+filename), blank if a nonsource window is active.
$FileName	The filename of the current source (defined as filename), blank if a nonsource window is active.
$FileDir	The directory of the current source (defined as drive+path), blank if a nonsource window is active.
$Proj	The current project base name (defined as filename), without the .mak extension, blank if no project is currently open.
$ProjDir	The directory of the current project (defined as drive+path), blank if no project is currently open.
$Cmdline	The command-line arguments passed to the application (obtained from the Debug dialog in the Options menu).
$Line	The current cursor line position within the active window.
$Col	The current cursor column position within the active window.
$Dir	The current working directory (defined as drive+path).
$Target	The current project target name (defined as drive+path+filename).
$RC	A resource file (*.RC). For Visual Workbench projects, this is the first resource file in the project list. For external projects, it is $Target.RC. If there is no resource file or there is no active project, $RC is blank.
Macro recognition is not case sensitive. All path macros end in a backslash (\).

To use a macro as an argument, type the macro name in the Arguments text box. Or, for macros that expand to a directory, you can type the macro name in the Initial Directory box. As an example, the following procedure demonstrates how to add the $File argument macro to the Windows Notepad accessory (installed in a previous procedure).

To add the $File macro to an installed tool and then run it:

1.	From the Options menu, choose Tools.

2.	Under Menu Contents, select the command you want to edit.

In this case, select the Notepad accessory installed earlier.

3.	In the Arguments text box, type $File.

4.	Choose OK to close the Tools dialog box.

5.	Open any source file or click an open source to make it active.

6.	From the Tools menu, choose Notepad.

The Windows Notepad editor opens with the active Visual Workbench source file as its text file.


  Setting Directories

When Visual C++ is installed, the Setup program determines the correct directory paths for several file types and updates the Directories dialog box with these paths. The file types are:

•	Build utilities (executable files)

•	Include files

•	Libraries

•	Microsoft Foundation Class Library source files

•	Help files

The Directories dialog box, accessed by choosing Directories from the Options menu (see »Figure 6.3«), lets you edit the directory paths where Visual Workbench looks for the file types. The directories for the executable files, include files, and libraries are drop-down lists that can contain up to four different paths. This makes it easy to quickly change build environments.

The Directories dialog box contains the following drop-down list boxes:

Executable Files Path  Specifies where the build utilities, such as NMAKE, CL, LINK, and BSCMAKE, reside.

Include Files Path  Specifies where the compiler should look for include files surrounded by angle brackets (< and >) (for example, #include <stdio.h>).

Library Files Path  Specifies where the linker should look for libraries to resolve external references.

In addition, the Directories dialog box contains the following text boxes:

Help Files Path  Specifies where Help files accessed from Visual Workbench are located. This path may contain more than one directory, separated by semicolons. To conserve disk space, you can leave large Help files on the CD-ROM and include the path to the CD-ROM Help files in this text box.

MFC Files Path  Specifies where the base directory for the Microsoft Foundation Class Library is located. This is needed when you use the debugger to trace into class library source code or when you use the browser to jump to definitions or references in the class library source code.

Directory information is stored in a Windows NT registry entry.


  Changing Syntax Coloring

Using different colors for various language elements such as functions and variables gives you immediate visual clues about the structure of your source code. You can change the default colors of these elements as well as the color of other text in the development environment such as reserved words, breakpoints, errors, and tags. You can also turn off syntax coloring for all source files. These changes are global and affect all source files with extensions recognized by Visual Workbench. To make global syntax coloring changes, choose Color from the Options menu.

Visual Workbench performs syntax coloring based on file extensions. You can override Visual Workbench's default coloring for a file by choosing Syntax Coloring from the View menu. This allows you to specify C, C++, or no syntax coloring for any individual file.


  Making Global Display Changes

To familiarize yourself with the steps in changing screen colors, change the color of comments in the source window to black text on a light-blue background.

To change the colors in the source window:

1.	From the Options menu, choose Color.

The Color dialog box appears (see »Figure 6.4«).

2.	From the Items list, select the item you want to change.

For this example, select Comment.

3.	In the Foreground Color and Background Color groups, select the color squares to represent the item.

For example, select the light-blue square in the Background Color group and the black square in the Foreground Color group. The new color combination is shown in the Sample Text box.

4.	Choose OK to apply the change to the source window.

You can change several items in the Items list before choosing OK.

To change a source window item back to its original colors:

1.	From the Options menu, choose Color.

2.	From the Items list, select the source item to be restored.

For example, select Comment.

3.	Choose Restore to Default.

4.	Choose OK.

Display items such as keywords and identifiers can be changed back to their default colors without changing the foreground and background colors of the source text.

To restore all items to their default values, choose Restore All Defaults.


  Source File Syntax Coloring

For any source file in Visual Workbench, you can specify which syntax coloring to apply (C or C++), or whether to turn off syntax coloring. This is useful if you have C or C++ code in a header file with a filename extension other than .H, .HPP, or .HXX, or if you have C or C++ source code with filename extensions that Visual Workbench doesn't recognize. (You should be cautious when using nonstandard filename extensions, however, since the filename extensions .CPP, .CXX, and .C are used by Visual Workbench to determine whether the C++ or C compiler is used during the build.)

To change syntax coloring in an individual source file

1.	Click in the source file window or use the Window menu to make the source window active.

If there are multiple windows open on the source file, select one of them. Syntax coloring changes will appear in all windows opened on the source file.

2.	From the View menu, select Syntax Coloring.

A cascading menu appears on the right with three choices: C, C++, and None.

3.	Choose C or C++ to determine syntax coloring for that source file.

Or choose None to turn syntax coloring off.

Note  Global syntax coloring must be enabled before you can use the Syntax Coloring command on the View menu on any specific file. To enable global syntax coloring, choose Color from the Options menu and then select the Syntax Coloring check box in the Color dialog box.


  Setting Font Type and Size

You can specify which font type and size appear in a Visual Workbench source window. You can choose any font type and size found in your setup of Windows. You can also determine what will be the default font for any new window.

To set the font type, style, and size

1.	From the Options menu, choose Font.

The Font dialog box appears (see »Figure 6.5«).

2.	From the Font list box, select the font you want to apply.

The sample text in the Sample box changes to the font you selected.

3.	Optionally, select the font style from the Font Style list box.

The sample text in the Sample box changes to the font style you selected.

4.	From the Size list box, select the font size.

The sample text in the Sample box changes to the font size you selected.

5.	Choose OK.

To set the default font for new source windows

1.	Choose a font, style, and size as just described.

2.	Choose the Use as Default Font button.

The currently selected font, style, and size appear in the Default Font description.

3.	Choose OK.

The default font is automatically applied to any new or opened window. The default font information is stored with other Visual Workbench information and is persistent between sessions.

Text within the source window can be only one font and size. Multiple fonts cannot be displayed in the same source window. However, each source window can contain a different font and size, even when source windows with different fonts are attached to the same source file.


  Chapter 7  Using AppWizard, ClassWizard, and App Studio

To develop a Visual C++ application, you use four Visual C++ tools. Two of these, Visual Workbench and App Studio, are applications. The other two, AppWizard and ClassWizard are specialized "wizards" installed as menu items in the applications:

•	AppWizard is used to generate Visual C++ application starter files. AppWizard is accessed from Visual Workbench.

•	ClassWizard is used to create classes, map messages to class-member functions, and map controls to member variables. ClassWizard is accessed from either Visual Workbench or App Studio.

This chapter describes how AppWizard, ClassWizard and App Studio are integrated with Visual Workbench. It focuses on programming activities you encounter while running Visual Workbench, such as opening App Studio and running AppWizard and ClassWizard.

Since AppWizard is only run from Visual Workbench, it is described in detail. Since ClassWizard can be run from either App Studio or Visual Workbench, the activities likely to be performed within Visual Workbench are described here. The primary reference information for ClassWizard can be found in Chapter 9, "Using ClassWizard," in App Studio User's Guide.

For a global view of how all the tools work together, see Chapter 4 "Developing a Microsoft Visual C++ Application" in Getting Started.


  Using AppWizard

AppWizard is used to generate a set of starter files for a Visual C++ application that uses the Microsoft Foundation classes. The starter files include the files required to build a graphical application for Windows NT. These could include source and header files, resource files, a module-definition file, and  a project file. AppWizard must be used first in the development process so you have starter files that are compatible with ClassWizard.

Building the resulting project produces a shell application with a wealth of built-in functionality. For example, you get built-in handling of the File menu's Open and Save As commands, an About dialog box, and an icon. By selecting options in AppWizard, you can add a toolbar and status bar, a Printer Setup dialog box, a fully implemented Print Preview, a Print command and toolbar button, context-sensitive Help, and support for object linking and embedding (OLE).

For tutorial information on using AppWizard to create a Visual C++ application, see Chapter 2, "Creating a New Application with AppWizard," in Class Libraries User's Guide.


  Opening and Closing AppWizard

To open AppWizard, choose the AppWizard command from the Visual Workbench Project menu. After using AppWizard to specify your application's name, directory, options, and classes choose the OK button to generate the starter files.

When AppWizard is finished, it creates a Visual Workbench project that allows you to immediately build and run the application. A message box appears to tell you AppWizard has generated the files. Choose OK in the message box to close AppWizard and to open the newly created project in Visual Workbench.


  Specifying the Project Name and Location

The MFC AppWizard dialog box (see »Figure 7.1«) allows you to select the project name and the subdirectory name and root path where the project files will reside. The project name is given the extension .MAK and appears in the complete path at the top of the Project Path group. It is also used as a base to create class names and source and header filenames.

To select the project name and subdirectory name

1.	Open the MFC AppWizard dialog box, if it isn't already open, by choosing AppWizard from the Project menu.

2.	Type a name in the Project Name box.

Notice that the name you type is automatically entered as a directory name in the New Subdirectory box. It is also entered in the project file path above the Directory box. The maximum number of characters in the Project Name box and the New Subdirectory box is eight.

3.	If you do not want the subdirectory name to be the same as the project name, you can type a different name in the New Subdirectory box, or you can leave the subdirectory name blank.

See the next procedure if you want to change the directory path that precedes the subdirectory.

You must select the drive and directory path to the subdirectory that will contain the generated files. To do this, you use the Directory box and the Drive box. These two controls work the same as similar controls in the Open File and Save As dialog boxes.

To select a drive and directory path for the application's subdirectory

1.	In the Drive drop-down list box, select the drive you want.

2.	In the Directory box, select the directory path by double-clicking the directory icons.

The drive letter and directory path you select are reflected in the project path. You can omit the subdirectory. The format for the entire path is:

drive:\directorypath[\subdirectory]\projectname.MAK


  Selecting Options

AppWizard can add the basic code to support a comprehensive set of application options. To select the options you want your application to support, choose the Options button in the MFC AppWizard dialog box and then select the various check boxes in the resulting Options dialog box (see »Figure 7.2«). When you have finished selecting options, close the Options dialog box by choosing OK.

You can select the following options in the Options dialog box:

Multiple Document Interface  This option lets you select the type of project you want to create. There are two project types available. When this option is selected, AppWizard creates an MDI application. When this option is cleared, it creates an SDI application.

•	An SDI (single document interface) application allows a user to work with just one document at a time. The Windows Notepad is an example of an SDI application.

•	An MDI (multiple document interface) application allows a user to open multiple documents, each with its own window.

Initial Toolbar  AppWizard generates code for a toolbar and a status bar. The toolbar contains buttons for creating a new document, opening and saving document files, cutting, copying and pasting, printing, displaying the About dialog box, and invoking Help. The status bar contains automatic indicators for the keyboard's Caps Lock, Num Lock, and Scroll Lock keys and a message line that displays help strings for menu commands and toolbar buttons. Enabling this option also adds menu commands to display or hide the toolbar and status bar.

Printing and Print Preview  AppWizard generates the code to handle print, print setup, and print preview commands by calling member functions in the CView class from the Microsoft Foundation Class Library. It also adds commands for these functions to the application's menu.

Context Sensitive Help  AppWizard generates a set of help files that are used to provide context-sensitive help.

OLE Client  AppWizard generates application support code for an OLE (object linking and embedding) client application. This allows OLE-linked and OLE-embedded objects to be placed in your application's documents. When you select this option, the document class is derived from COleClientDoc instead of CDocument. Selecting this option also enables the standard OLE resources and adds extra OLE commands to the application's menu bar.

External Makefile  By default, AppWizard generates a project file that is compatible with Visual Workbench (and NMAKE). Select this option if you want AppWizard to generate an NMAKE makefile that can be edited but must be used as an external project from within Visual Workbench (see »Using External Projects« in Chapter 3).

Generate Source Comments  AppWizard generates and inserts comments in the source files that guide you in writing your program. This includes indicators where you need to add your own code.


  Modifying Classes

AppWizard names your application's classes and files by using the project name you specify in the Project Name box. The Classes dialog box (see »Figure 7.3«), accessed with the Classes button in the MFC AppWizard dialog box, lets you modify components of each of the four classes that are created by AppWizard. Some classes allow more modification of options than others.

New Application Classes

Three of the four classes available in the New Application Classes list box are derived from your project name. In each of the following class names, the placeholder Prjname indicates the project name you have specified.

CPrjnameApp

This is the main application class. The Base Class, Header File, and Implementation File text boxes are all dimmed, indicating that you cannot change any of these options, since these must reside in the main project. You can, however, change the name of the class.

CMainFrame

This is the class that handles the window frame, which contains the toolbar and status bar. You cannot change the base class, since this is determined by the project type you choose (MDI or SDI). However, you can change the name of the class or the names of the header and source files associated with the window frame code by typing new names in the Header File and Implementation File text boxes.

CPrjnameDoc

This is the class that contains the document data and handles saving it to disk and recalling it from disk, among other things. You cannot change the base class, which will be CDocument (or COleClientDoc if OLE support is selected), but you can change the names of the class, the header file, and the source (implementation) file.

A CPrjnameDoc class is associated with a document type and can automatically serialize (save and load) the document to and from disk in response to the Save As and Open commands on the File menu. You can change the name that is used wherever the application's native document type is referred to by typing a new name (up to six characters) in the Doc Type Name box. Examples of where the document type name is used include the default filename (CPrjname.DOC), the Windows shell registration name, the title bar of a document window, and constants referred to in the code created by AppWizard. This name is also used in the File Manager shell and OLE server options when a file type is needed.

You can also choose a filename extension for the document by typing up to three characters in the File Extension box. The filename extension is added to document files saved from the application and appears as a file filter in the application's Open File and Save As dialog boxes.

CPrjnameView

This class is used to display document data inside a window. You can change the name of the class, the header file, or the source file, but you cannot change the name of the base class.


  AppWizard-Generated Files

AppWizard always generates a basic list of files, regardless of which options you choose. The Context Sensitive Help and Initial Toolbar options result in additional files. This section first describes the standard files common to all AppWizard-generated applications and then describes files that are added when you select toolbar and Help support.

AppWizard uses the name that you specify in the Project Name box to derive names for most of its files and classes. Names derived by AppWizard assume a project name with a maximum of eight characters. In the following descriptions, where the full project name is used in the filename, PRJNAME is used as a placeholder for the name you specify. For some filenames, the project name is truncated to five characters. In those cases, PRJNA is used as a placeholder for the truncated project name.

Note  The name substitutions indicated in these filenames may not apply if you have used the Classes dialog box to alter any of these names.


  Standard AppWizard Files

This section describes the various files generated by AppWizard. In the project directory, you'll also find a file named README.TXT, which describes each of the files created by AppWizard using the actual filenames created by AppWizard for your specific project.

Project and Makefiles

PRJNAME.MAK  This is the project file for Visual Workbench. It is also an NMAKE-compatible file. If you select the External Makefile option in AppWizard's Options dialog box, this can only be used as an external project from within Visual Workbench.

PRJNAME.CLW  This file contains information used by ClassWizard to edit existing classes or add new classes. ClassWizard also uses this file to store information needed to generate and edit message maps and dialog data maps, and to generate prototype member functions.

Resource and Module-Definition Files

PRJNAME.RC, RESOURCE.H  This is the resource file for the project and its header file. The resource file contains the default menu definition and accelerator and string tables for a generic Visual C++ application. It also specifies a default About dialog box and an icon file (RES\PRJNAME.ICO). The resource file includes the file STDAFX.RC for standard Microsoft Foundation class resources. If toolbar support has been specified as an option, it also specifies the toolbar bitmap file (RES\TOOLBAR.BMP).

RES\PRJNAME.ICO  This is the icon file for the generic Visual C++ application. This icon appears when the application is minimized.

PRJNAME.DEF  This is the module-definition file for the application, which includes the name and description of the project as well as the size and type of the run-time heap and run-time stack. The heap and stack sizes are typical for this type of Microsoft Foundation Class Library application.

Application Source and Header Files

MAINFRM.CPP, MAINFRM.H  These files derive the CMainFrame class from either CFrameWnd (for SDI applications), or CMDIFrameWnd (for MDI applications). The CMainFrame class handles the creation of toolbar buttons and the status bar, if the Initial Toolbar check box is selected in the AppWizard Options dialog box. The MAINFRM.CPP file also contains the array of object IDs for the default toolbar buttons provided with a Visual C++ application.

PRJNAME.H  This is the main include file for the application. It contains all global symbols and #include directives for other header files.

PRJNAME.CPP  This file is the main application source file. It creates one instance of the class CPrjnameApp (which is derived from CWinApp) and overrides the InitInstance member function.

CPrjnameApp::InitInstance does several things. It registers document templates, which serve as a connection between documents and templates, creates a main frame window, and creates an empty document (or opens a document if one is specified as a command-line argument to the application). It also enables support for F1 help if this options has been chosen.

PRJNADOC.CPP, PRJNADOC.H  These files derive and implement the document class, named CPrjnameDoc, and include skeleton member functions to initialize a document, serialize (save and load) a document, and implement debugging diagnostics. In an MDI application, you use ClassWizard to add more document classes.

PRJNAVW.CPP, PRJNAVW.H  These files derive and implement the view class, named CPrjnameView, that is used to display and print the document data. The CPrjnameView class is derived from CView and has skeleton member functions to draw the view and implement debugging diagnostics. In an MDI application, you use ClassWizard to add more view classes. If you have enabled support for printing, message-map entries are added for print, print setup, and print preview command messages. These entries call the corresponding member functions in the CView class.

Precompiled Header Files

STDAFX.CPP, STDAFX.H  These files are used to build a precompiled header file PRJNAME.PCH and a precompiled types file PRJNAME.PCT.


Files Added by Options‹
  Files Added by Options

Most options use the standard files to implement their features. The exceptions are the Toolbar and Context Sensitive Help options. Toolbar support adds just one file, RES\TOOLBAR.BMP. Help support provides a number of files and creates a new directory \HLP to contain most of them.

Help Option

MAKEHELP.BAT  This batch file can be used to create Help for your application.

PRJNAME.HPJ  This is the Help project file used by the help compiler to create your application's help file.

HLP\*.BMP  These are a collection of bitmap files used by the help file topics.

HLP\ALIAS.H  This file is used to create help topic aliases, which map one context to another existing context. These are used when several commands need to be mapped to the same help topic. This is included in the [ALIAS] section of the Help project (.HPJ) file.

HLP\MAP.H  This file contains mappings for objects and commands that are application specific. This is included in the [MAP] section of the .HPJ file.

HLP\AFX.RTF  This file contains the standard help topics for Microsoft Foundation Class Library commands and screen objects.

HLP\KEYS.RTF  This file contains Help for keys used in applications for Windows.

HLP\MDI.RTF  This is the template help file for MDI applications.

HLP\TERMS.RTF  This is the template help file for your application's glossary of terms.


  Running App Studio

App Studio is the application you use to create and edit resources. Although you can run App Studio independently, App Studio, Visual Workbench, and ClassWizard are more easily integrated if you run App Studio from within Visual Workbench. You can run App Studio from Visual Workbench using one of two methods:

•	Select App Studio from the Tools menu

•	Open a project resource file (assuming the Open .RC Files Using App Studio check box in the Editor dialog box is enabled)

If you occasionally edit your resource files in a text editor, you may prefer to open App Studio from the Tools menu and use the Open File dialog box to open resource files as text in a Visual Workbench source window.

App Studio is installed on the Tools menu with the $RC argument macro. When you choose App Studio from the Tools menu, the $RC macro expands to either the first resource file in the project list (for Visual Workbench projects) or the target name with an .RC extension (for external projects). For external projects, the target name is displayed in the Debug Target Name box in the Project Options dialog box. If the project doesn't include a resource file, App Studio is opened without one.

Since App Studio creates and edits resources graphically, you may not feel the need to edit your resource files in a text editor. In this case, it can be useful to open App Studio by simply selecting a resource file in Visual Workbench's Open File dialog box.

Note  To open App Studio on a resource file that you select in the Open File dialog box or from the toolbar's Project Files list, select the Open RC Files Using App Studio check box in the Editor dialog box (accessed from the Options menu). The state of this check box persists between Visual Workbench sessions.

You can use the Visual Workbench Open File dialog box to open App Studio on several file types, including:

•	Resource files (.RC).

•	Graphics image files (.BMP, .ICO, or .CUR).

When you open App Studio on a resource file, the file is first compiled using the resource compiler and the resulting data is stored in memory for App Studio's use. App Studio stores this information in a file with the extension .APS for later recall and for caching when memory is limited.

When you open a graphics image file, it becomes an App Studio resource.

To run App Studio on a resource or graphics image

1.	From the Visual Workbench File menu, choose Open.

2.	In the Open File dialog box, select the filename.

3.	Choose OK.

App Studio is launched with the filename as an argument. App Studio compiles the resource file first. If an error occurs during this stage, the resource file is opened in Visual Workbench as a text file with the insertion point on the line that caused the error.

Since the resource file is usually included in the project list, you can also use the Project Files button on the toolbar to open App Studio.

To run App Studio on a project resource or graphics file using the toolbar

1.	Click the Project Files button (on the far left of the toolbar).

The Project Files list appears.

2.	Click the filename in the Project Files list.

3.	App Studio is launched with the filename as an argument.


  Using ClassWizard

ClassWizard is a Microsoft Foundation Class Library class generator and manager that automates the process of creating and editing code to handle messages and dialog-box data. It generates the source code for new classes that can receive messages and generates member functions and message maps in those classes to bind the messages to code. It also maps dialog-box data to member variables and automates the validation of data entered in a dialog box.

ClassWizard can be opened from either App Studio or Visual Workbench (see »Figure 7.4«). Since you design the user-interface objects in App Studio, you usually open ClassWizard from App Studio and generate the message-handler functions for the user-interface objects as you go. Chapter 9, "Using ClassWizard," in App Studio User's Guide contains a comprehensive description of ClassWizard.

You can derive classes and create message handlers for standard Windows messages while running ClassWizard from Visual Workbench. These activities can be performed at any time in ClassWizard, regardless of whether you open it from Visual Workbench or App Studio. However, since deriving classes and creating message handlers aren't directly related to developing resources, you may want to perform these activities while editing and developing code in Visual Workbench.


  Creating New Classes

You can use ClassWizard to add new classes to your application. ClassWizard can derive a new class from any class with CCmdTarget as a base class.

Important  If you plan to use ClassWizard to create message-handler member functions in any new classes, you should use ClassWizard to create the new classes so that the class code is in a format recognized by ClassWizard.

»Figure 7.5« shows a segment of the Microsoft Foundation Class Library hierarchy. The CCmdTarget class provides message-routing services for user-interface objects, so any classes with CCmdTarget as a base class can be used to handle messages from user-interface objects such as menu items, dialog-box controls, and toolbar buttons. (These are actually IDs passed by WM_COMMAND messages.) This applies to document view classes (those derived from CView), which can also handle Windows messages, as well as document structure classes, such as those derived from CDocument.

Most often, you will create new dialog classes for dialog resources you have created in App Studio. This should be done after creating the dialog resources. Chapter 9, "Using ClassWizard," in App Studio User's Guide provides the procedure for creating new dialog classes.

You may also want to create new classes that can respond to user input and display or contain data. For example, when AppWizard creates an application, it derives one document class and one view class. You might want to add a second view class so a user can display the document data in different ways, for example as a graphic chart or as a table. Both the document class and the view class can respond to user-interface object events. The document class is used to contain and serialize the data. The view class is used to display the data and respond to Windows messages.

To derive a new class using ClassWizard

1.	From the Browse menu, choose ClassWizard.

The ClassWizard dialog box appears.

2.	Choose the Add Class button to open the Add Class dialog box (see »Figure 7.6«).

3.	In the Class Name box, type the name of the class you want to create.

Notice that as you type the name, the Header File and Implementation File text boxes automatically use the first eight characters of the class name for the suggested filenames.

4.	From the Class Type drop-down list, select the type of class from which you want to derive your application's class.

5.	If you want the class prototype code to be generated in a different file, type the filename in the Header File text box, or use the Browse button to select the name of an existing header file.

6.	If you want the class implementation code to be generated in a different file, type the filename in the Implementation File text box, or use the Browse button to select the name of an existing source file.

7.	If you are creating a class that is derived from either CDialog or CFormView, select the resource identifier from the Dialog ID drop-down list.

8.	Choose Create Class.

If you skipped step 7, ClassWizard prompts you with a message box to warn you about using a resource identifier. If your new class is not derived from CDialog or CFormView, choose Yes.

ClassWizard generates the source code for the new class and returns to the ClassWizard dialog box with the new class selected in the Class Name drop-down list.


  Creating Message Handlers for Windows Messages

The classes that handle Windows messages, derived from the CWnd class,  are often used to deal with the graphical overhead of programming in Windows, such as responding to resize messages (WM_SIZE) or mouse messages (such as  WM_LBUTTONDOWN).You can use ClassWizard to generate skeleton code that handles these standard messages from Windows. It displays a list of all the messages that can be received by each class type so all you need to do is select the message and choose the Add Function button.

To create message-handler code for Windows messages

1.	If ClassWizard is not already open, open it from the Browse menu (or press CTRL+W).

2.	In the Class Name drop-down list, select the class to which you want to add the message-handler member function and message-map entry.

3.	In the Object IDs box, select the class name, which will be the first entry in the list.

A list of Windows messages is displayed in the Messages box. The contents of this list depend on the Message Filter set for that class, which you can see by choosing the Class Info button. The message filter is automatically set for each class type to display the appropriate types of messages. For example, a class derived from CView displays messages filtered for a child window.

To change the selection of the Message Filter box, choose the Class Info button, select a different filter in the Message Filter box, and choose Close.

4.	Select a message.

Notice that as you select different messages in the Messages list box, a description of each message appears at the bottom of the dialog box (see »Figure 7.7«).

5.	Choose the Add Function button.

ClassWizard automatically writes the member function prototype definition, enters the function name and message name in the message map, and enters the declaration in the header file.

Notice that the function appears in the Member Functions box and that a hand icon appears at the left of the message to indicate that it is handled.

6.	If you want, you can now choose the Edit Code button to write code for the message-handler member function that has been inserted in your code.

ClassWizard closes and Visual Workbench opens a source window with the insertion point in the message-handler member function that was just created.

7.	If you skipped step 6, close ClassWizard by choosing OK.


  Chapter 8  Fast Track to Visual Workbench

This chapter summarizes many of the Visual Workbench procedures and provides a comprehensive menu overview. The tables in this chapter will help you find the right menu command, dialog box, or window to accomplish your task.


  Managing Files and Printing

To		Shortcut	Comments
Create a new sourcefile	New	CTRL+N	Creates an empty source window that will be named when it is saved.
Open a source file	Open...	CTRL+O	The Open button on the toolbar is equivalent.
Close a source file	Close		You can also double-click the Control-menu box.
Save a source file	Save	CTRL+S	The Save command and the Save button on the toolbar are inactive until you alter text in the source window.
Rename a source file	Save As...		Opens the Save As dialog box, which prompts you for a filename.
Save all open source files	Save All		Saves all source files currently opened.
Print the active window	Print...		Opens the Print dialog box and prints selected text.
Set print margins, headers, and footers	Page Setup...		Opens the Page Setup dialog box.
Exit Visual Workbench	Exit		Exits the development environment and prompts you to save any modified files.


  Editing Files

To		Shortcut	Comments
Reverse the last edit	Undo	CTRL+Z	To set the undo buffer size, see the Editor dialog box (Options menu).
Reverse the last undo	Redo	CTRL+A	Must be used before any other editing is done.
Delete to the Clipboard	Cut	CTRL+X	Overwrites the current Clipboard contents.
Copy to the Clipboard	Copy	CTRL+C	Overwrites the current Clipboard contents.
Paste from the Clipboard	Paste	CTRL+V	Pastes text only.
Delete text from a file	Delete	DEL	Does not save the deleted text to the Clipboard.
Search for text	Find...	ALT+F3	Opens the Find dialog box.
Search and replace text	Replace...		Opens the Replace dialog box.
Find text in multiple files	Find in Files...		Opens the Find in Files dialog box.  Output from search goes to the Output window.
Move to the corresponding brace	Find Matching Brace	CTRL+M	Moves the insertion point from a brace or parenthesis to its matching brace or parenthesis.
Write-protect a file	Read Only		Useful for viewing files that you don't want to accidentally alter.


  Window Display and Quick Access

To		Shortcut	Comments
Go to a specific line	Line...		Opens the Line dialog box. Type a line number and press Enter.
Display assembly code	Mixed Source/Asm	CTRL+F7	Displays assembly code mixed with source code.
Jump to the next Output window reference	Next OUTPUT Tag	F4	OUTPUT is the name of the selected virtual output window. Jumps to the next source file and location specified in the Output window list.
Jump to the last Output window reference	Previous  OUTPUT Tag	SHIFT+F4	OUTPUT is the name of the selected virtual output window. Jumps to the previous  source file and location specified in the Output window list.
Display virtual output window	Output		Select virtual output window from pop-up menu to be displayed in the Output window.
Turn bookmark on or off	Toggle Bookmark	CTRL+F2	Line is highlighted when bookmark is set.
Jump to the next bookmark	Next Bookmark	F2	Places insertion point at next bookmark.
Jump to the previous bookmark	Previous Bookmark	SHIFT+F2	Places insertion point at previous bookmark.
Remove all bookmarks	Clear All Bookmarks		Clears all bookmarks.
Toggle toolbar display	Toolbar		Checked when toolbar is displayed.
Toggle status bar display	Status Bar		Checked when status bar is displayed.
Override syntax coloring	Syntax Coloring		Select C, C++, or None from pop-up menu to set syntax coloring for a single source file. To set global syntax coloring, use the Color dialog box from the Options menu.


  Working with Projects

To		Shortcut	Comments
Create a new application using AppWizard	App Wizard...		Opens the MFC AppWizard dialog box.
Create a new project	New...		Opens the New Project dialog box.
Open an existing project	Open...		Closes any current project. Loads browser database, if available, for the project.
Add files to or delete files from a project	Edit... PRJNAME.MAK		To change the project type, use the Project command on the Options menu.
Close the current project	Close		Other ways to close a project are opening another project, creating a project, or exiting Visual Workbench.
Compile the active source file	Compile File FILENAME	CTRL+F8	Compiles active source file specified by FILENAME. Also available on the toolbar.
Build the project using dependency rules	Build TARGETNAME	SHIFT+F8	Builds only the files that are not up-to-date and creates a target file. Also available on the toolbar.
Build the project from start	Rebuild All TARGETNAME	ALT+F8	Builds all the files regardless of dependencies and creates a target file. Also available on the toolbar.
Stop building a project	Stop Build		Cancels the build as soon as the build tool being used is finished.
Run a program outside the debugger	Execute TARGETNAME	CTRL+F5	TARGETNAME is the name of the executable file produced by building the current project
Update include dependency list for active file	Scan Dependencies FILENAME		Recursively scans all files included by the active source file and updates the list.
Update include dependency list for entire project	Scan All Dependencies		This is also done when a project list is created or edited.
Load a workspace	Load Workspace		Loads one of three saved workspaces associated with the current project.
Save a workspace	Save Workspace		Saves one of three workspaces associated with the current project.


  Accessing Symbols and Classes

To		Shortcut	Comments
Jump to first place where symbol is defined	Go to Definition	F11	Select symbol in source window or Browse window.
Jump to first place where symbol is referenced	Go to Reference	SHIFT+F11	Select symbol in source window or Browse window.
Jump to the next reference or definition	Next	CTRL+NUMPAD+	Depends on whether Go to Definition or Go to Reference was used last.
Jump to the previous reference or definition	Previous	CTRL+nUMPAD −	Depends on whether Go to Definition or Go to Reference was used last.
Jump to location of selected symbol	Pop Context	CTRL+NUMPAD*	Returns to the symbol that was used before the last Go to Definition or Go to Reference.
Open the Browse window	Open [PRJNAME.BSC]		Opens the Browse window with the database listed. Opens the Open File dialog box if a database name is not listed.
Create a new class or maps  a Windows message to a member function	ClassWizard...	CTRL+W	Opens a dialog box that lets you create new classes and automate the creation of message maps and message-handler member functions.


  Debugging Programs

To		Shortcut	Comments
Start or continue a program using the debugger	Go	F5	Runs program associated with the current project.
Reload program and start	Restart	SHIFT+F5	Discards variable values. Use when execution has paused at a breakpoint, between steps, or when program has completed.
Stop a debugging session	Stop Debugging	ALT+F5	Stops the debugger at any time, whether the program is running or paused. If this is dimmed (unavailable), the program being debugged has focus or has finished.
Break a program.	Break		Breaks the running program at its current position.
Single-step through every line of the program	Step Into	F8	Enters functions when encountered.
Single-step through program but skip functions	Step Over	F10	Runs functions when encountered and stops immediately after.
Run to first instruction after call to current function	Step Out	SHIFT+F7	Continues program out of function then stops at line after function call.
Run to the location of the insertion point	Step to Cursor	F7	Treats the insertion point location as a breakpoint.
Display the call stack	Call Stack...	CTRL+K	The Call Stack dialog box lists all function calls that lead to current statement.
Set or clear a breakpoint	Breakpoints...	CTRL+B	The Toggle Breakpoint button on the toolbar also sets and clears breakpoints.
Open QuickWatch to view the value of a variable	QuickWatch...	SHIFT+F9	The insertion point must be on a variable with the program paused at a breakpoint or between steps.
Add a variable to the Watch window.			To add a variable, open QuickWatch on the variable and choose the Add to Watch Window button.
Change a variable value			To change a variable value, open QuickWatch on the variable, enter a new value in the Modify Value text box and choose the Modify Value button .
Set handling of Win32 Structured Exceptions	Exceptions...		Exceptions dialog box lets you determine the action taken by the debugger for individual exceptions.
Suspend, resume, or set focus on a thread	Threads...		Threads dialog box shows status of all active threads including state, priority, and current location.
View analysis of application's performance	Profile...		See the 32-Bit Source Profiler User's Guide for information on using the Profiler within Visual Workbench


  Running Tools from Visual Workbench

To		Shortcut	Comments
Stop a tool	Stop	CTRL+BREAK	This also stops compiles and builds
Create menus, dialog boxes, icons, and other resources	App Studio		App Studio lets you design and construct the user-interface objects for your program.
Add a tool to or remove a tool from the Tools menu			See the Tools command on the Options menu.


  Setting Preferences and Custom Options

To		Comments
Set custom compiler and linker options.	Project...	Choose the Compiler, Linker, or Resources button.
Set the build mode (debug vs. release).		You can set the build mode for Visual Workbench projects or external projects.
Set the project type		Project type can also be set when you create a new project.
Specify an .EXE file to debug a DLL.	Debug...	You must specify a host program to debug a DLL.
Toggle single debug window.		Determines whether stepping into new source file opens a window or uses the active window.
Toggle hexadecimal display		Format for display of all variable values wherever they are shown (Watch window).
Set directories paths	Directories...	Set directories for include files, libraries, executable files, help files, and MFC source files.
Set miscellaneous options	Editor...	Options include tab settings, scroll bar enabling, save before build, prompt before save, and undo buffer size.
Set workspace options	Workspace...	Lets you set the menu names and shortcut keys and other options for workspaces.
Add a tool to, or remove a tool from, the Tools menu	Tools...	You can use this feature to integrate an editor with Visual Workbench.
Adjust parameters of the Memory window	Memory Window...	Lets you set an address expression and arrange how data is displayed in the Memory window.
Change syntax coloring,	Color...	The Color dialog box lets you customize colors for all syntax elements.
Or turn syntax coloring off for all files		Clear the Syntax Coloring check box. See the Syntax Coloring command on the View menu to select syntax coloring for a single file.
Change the font in a window	Font...	Select from a variety of fonts and sizes and apply bold and/or italic styles.


  Arranging and Opening Windows

To		Comments
Arrange windows as overlapped	Cascade	To bring an overlapped window to the top, select the window from this menu or press ALT+F6 to cycle through the windows.
Arrange windows as side-by-side	Tile	Useful to show several debug windows at the same time.
Open an additional window on an open source file	Duplicate	Useful for viewing different sections of the same source file.
Close all open windows	Close All	Prompts you to save altered files.
Open the Watch window (or bring it to the top)	Watch	Watch window variables and expressions are saved with the project. To add a variable or expression, type it into the Watch window during a debug session. (Or use QuickWatch to add the variable.)
Open the Locals window (or bring it to the top)	Locals	Shows all local variables and their values.
Open the Registers window (or bring it to the top)	Registers	Shows all registers and flags. To change a register value, type over the current value. To toggle a flag value press the spacebar.
Open the Memory window (or bring it to the top)	Memory	Shows entire memory space.  Use the Memory  Window Options dialog box to change parameters in this window.
Open the Output window (or bring it to the top)	Output	Output from build utilities, including errors and warnings, Debugger, Grep and Profiler tools, and optionally from tools on the Tools menu appears here.


  Getting Online Help

To		Comments
Find help on Visual Workbench	Visual Workbench	Opens Visual Workbench Help at the top-level Contents screen.
Find help on App Studio	App Studio	Opens the App Studio Help at the top-level Contents screen.
Find help on specific compiler or linker options	Build Tools	Includes the C/C++ Compiler Options and Linker Options dialog boxes and module-definition-file statements.
Find help on the C or C++ language and functions	C/C++ Language	C run-time functions and C/C++ language descriptions.
Find help on the Microsoft Foundation Class Library	Foundation Classes	Description of classes, member functions, and macros.
Find help on 32-bit Windows NT APIs.	Win32 SDK	Descriptions of all Win32 APIs, messages and macros
Search for a keyword in Help	Keyword Search...	Opens the Search dialog box with the selected word or word at the insertion point as a keyword and lets you choose the Help file to search.
Get product support	Technical Support...	Describes how to contact Microsoft Product Support.
Find information about your copy of Visual Workbench	About Visual C++...	Displays a dialog box that shows software version and registered owner.


  Chapter 9  Shortcut Key Summaries

The tables in this chapter list keyboard sequences and shortcuts for Visual Workbench tasks.

»Table 9.1   Moving the Insertion Point«

»Table 9.2   Selecting Text«

»Table 9.3   Modifying Text«

»Table 9.4   Deleting Text«

»Table 9.5   Scrolling«

»Table 9.6   Searching«

»Table 9.7   Using the Toolbar«

»Table 9.8   Managing Windows«

»Table 9.9   Building and Compiling«

»Table 9.10  Browsing«

»Table 9.11  Debugging«

»Table 9.12  Using the Register and Memory Windows«


Table 9.1    Moving the Insertion Point

To move the insertion point	Press
One character left	LEFT ARROW
One character right	RIGHT ARROW
One word left	CTRL+LEFT ARROW
One word right	CTRL+RIGHT ARROW
One line up	UP ARROW
One line down	DOWN ARROW
To the first indentation of current line	HOME
To the first indentation of next line	CTRL+ENTER
To the end of line	END
To the beginning of file	CTRL+HOME
To the end of file	CTRL+END


Table 9.2    Selecting Text

To select	Press
Character to the left	SHIFT+LEFT ARROW
Character to the right	SHIFT+RIGHT ARROW
One word to the left	CTRL+SHIFT+LEFT ARROW
One word to the right	CTRL+SHIFT+RIGHT ARROW
Current line	SHIFT+DOWN ARROW
Line above	SHIFT+UP ARROW
To end of line	SHIFT+END
To beginning of line	SHIFT+HOME
To matching brace	CTRL+SHIFT+M
One screen up	SHIFT+PAGE UP
One screen down	SHIFT+PAGE DOWN
To beginning of file	CTRL+SHIFT+HOME
To end of file	CTRL+SHIFT+END


Table 9.3    Modifying Text

To	Press
Turn keyboard insert mode on or off	INS
Insert one blank line below	END, then ENTER
Insert one blank line above	HOME, then ENTER
Insert carriage return at insertion point	CTRL+SHIFT+N
Insert contents of Clipboard	CTRL+V  or  SHIFT+INS
Copy selected text to Clipboard, keeping it	CTRL+C  or  CTRL+INS
Copy selected text to Clipboard, deleting it	CTRL+X   or  SHIFT+DEL
Copy current line to Clipboard, deleting it	CTRL+Y
Change selection to uppercase	CTRL+SHIFT+U
Change selection to lowercase	CTRL+U
Undo the last edit	CTRL+Z  or  ALT+BACKSPACE
Redo the last edit	CTRL+A
Insert a tab	TAB
Move all selected lines one tab stop right	TAB
Move all selected lines one tab stop left	SHIFT+TAB
Toggle display of tab symbols	CTRL+ALT+T


Table 9.4    Deleting Text

To	Press
Delete one character to the left	BACKSPACE
Delete one character to the right	DEL
Delete to the end of the word	CTRL+T
Delete word to the left	CTRL+BACKSPACE
Delete selected text and copy to Clipboard	CTRL+X  -OR-  SHIFT+DEL


Table 9.5    Scrolling

To scroll	Press
Up one line at a time	CTRL+UP ARROW
Down one line at a time	CTRL+DOWN ARROW
Up one page at a time	PAGE UP
Down one page at a time	PAGE DOWN
Left one window width	CTRL+PAGE UP
Right  one window width	CTRL+PAGE DOWN


Table 9.6    Searching

To	Press
Find the selected text (forwards)	CTRL+F3
Find the selected text (backwards)	CTRL+SHIFT+F3
Repeat the last find	F3
Open the Find dialog box	ALT+F3
Search backward	SHIFT+F3
Find the next error or output window item	F4
Find the previous error or output window item	SHIFT+F4
Find matching brace	CTRL+M
Find next bookmark	F2
Find previous bookmark	SHIFT+F2


Table 9.7    Using the Toolbar

To access the	Press
Project Files button	CTRL+P
Open button	CTRL+O
Save button	CTRL+S
Find box	CTRL+F
Find box: search forward	RETURN
Find box: search backward	SHIFT+RETURN
Find Next button	F3
Compile File button	CTRL+F8
Build button	SHIFT+F8
Rebuild All button	ALT+F8
Toggle Breakpoint button	F9
QuickWatch button	SHIFT+F9
Run button	F5
Step Into button	F8
Step Over button	F10
Step Out button	SHIFT+F7


Table 9.8    Managing Windows

To	Press
Switch to the next document window	CTRL+F6
Switch to the previous document window	CTRL+SHIFT+F6
Switch to the next window (includes all windows)	F6
Switch to the previous window (includes all windows)	SHIFT+F6
Switch to the previously active window	CTRL+TAB
Close the active window	CTRL+F4


Table 9.9    Building and Compiling

To	Press
Compile the active source file	CTRL+F8
Build the project using dependency rules	SHIFT+F8
Build the project from the start	ALT+F8


Table 9.10    Browsing

To	Press
Jump to the definition of selected symbol	F11
Jump to the first reference of selected symbol	SHIFT+F11
Jump to the next reference in browser list	CTRL+NUMPAD+
Jump to the previous reference in browser list	CTRL+NUMPAD -
Return to original symbol location	CTRL+NUMPAD*
Expand active node one level	NUMPAD+
Collapse active node one level	NUMPAD -
Expand all nodes in a branch	NUMPAD*
Expand an entire graph	ALT+X


Table 9.11    Debugging

To	Press
Restart program execution from beginning	SHIFT+F5
Continue execution from current statement	F5
Stop debugging	ALT+F5
Execute program to insertion point position	F7
Execute next statement, tracing into function calls	F8
Single-step, stepping over functions calls	F10
Execute program out of current function and stop on first line after function call	SHIFT+F7
Open QuickWatch dialog box	SHIFT+F9
Open Breakpoints dialog box	CTRL+B
Open Call Stack dialog box	CTRL+k
Toggle hexadecimal display	ALT+F9
Toggle breakpoint	F9
Toggle mixed mode	CTRL+F7


Table 9.12    Using the Register and Memory Windows

To	Press
In a Register Window:
Move to next register	TAB
Move to previous register	SHIFT+TAB
Move to the first register of the line	HOME
Move to the last register of the line	END
Move to the first register	CTRL+HOME
Move to the last register	CTRL+END
In a Memory Window:
Display the next memory format	ALT+F7
Display previous memory format	ALT+SHIFT+F7


  Chapter 10  Build Options Reference

This chapter provides a quick reference to the Visual C++ compiler and linker options accessed from Visual Workbench.

You can customize build options for any project by choosing the Project command from the Options menu. This opens the Project Options dialog box from which you can choose one of three buttons in the Build Options group:

•	Compiler

•	Linker

•	Resource

Each of these buttons opens a dialog box to let you customize options for that build utility. This chapter lists the compiler and linker options with brief information on each option.  For information on the resource compiler option help, press f1 or choose Help in the Resource Options dialog box. For more information on using the Project Options dialog box, see »Customizing Project Build Options« in Chapter 3.


  Compiler Options

The tables in this section describe the compiler options in the C/C++ Compiler Options dialog box. These tables are organized by category, following the categories that are presented in the C/C++ Compiler Options dialog box.

For detailed information on any option, consult Help or see Chapter 2, "Using the 32-Bit CL," in Build Tools User's Guide.

In all tables, the option with the asterisk is the default CL option and does not appear in the options string in the C/C++ Compiler Options dialog box.

The following tables are included:

»Code Generation Category«

»Custom Options Category«

»Custom Options (C++) Category«

»Debug Options Category«

»Listing Files Category«

»Optimizations Category«

»Precompiled Headers Category«

»Preprocessor Category«

»Runtime Category«


Code Generation Category

Category Setting	Option	Comment
CPU
80386	/G3	Generate 80386 instructions
80486 *	/G4	Generate 80486 instructions
Pentium	/G5	Generate Pentium instructions
Calling Convention
C/C++ (_cdecl)*	/Gd	Use the C calling convention
C/C++ (_fastcall)	/Gr	Use the register calling convention
C/C++ (_stdcall)	/Gz	Use the standard call calling convention
Struct Member Byte Alignment
1 Byte	/Zp1 (/Zp)	Pack structures on 1-byte boundaries
2 Bytes	/Zp2	Pack structures on 2-byte boundaries
4 Bytes	/Zp4	Pack structures on 4-byte boundaries
8 Bytes *	/Zp8	Pack structures on 8-byte boundaries
16 Bytes	/Zp16	Pack structures on 16-byte boundaries


Custom Options Category

Category Setting	Option	Comment
Custom Options
Disable Microsoft Language Extensions	/Za	Disables the default (/Ze)
Enable Function-Level Linking	/Gy	Package functions
Eliminate Duplicate Strings	/Gf	Implement string pooling
Warnings as Errors	/WX	Treat all warnings as errors
Suppress Display of Sign-On Banner	/nologo	Banner not sent to Output window
Warning Level
None	/W0	Display no warnings
Level 1 *	/W1	Display only the most severe warnings
Level 2	/W2	Display intermediate level of warnings
Level 3	/W3	Display most warnings
Level 4	/W4	Display all warnings
Other Options
valid CL option	valid CL option	If an option entered here is also set in a dialog box control, the corresponding control is updated


Custom Options (C++) Category

Category Setting	Option	Comment
Representation Method
Best-case always *	/vmb	Always declare class before declaring pointers to class members
General-purpose always	/vmg	Can declare pointers to class members before defining class
General Purpose Representation
Point to any class *	/vmv	Declare virtual inheritance
Point to single-inheritance classes	/vms	Declare single inheritance
Point to multiple-inheritance classes	/vmm	Declare multiple inheritance
Disable Construction Displacements	/vd0	May reduce program size


Debug Options Category

Category Setting	Option	Comment
Debug Options
None	none	No debug information is created
Partial (Line Numbers Only)	/Zd	Only public symbols and line numbers
Full (C7 Compatible)	/Z7	Put all debug information in object files
Full, Use Program Database	/Zi	Enabled by the /Od (Disable (Debug)) option button in the Optimizations category


Listing Files Category

Category Setting	Option	Comment
Browser Information
Browser Information	/Fr	Generate .SBR files (ignore local variables)
Include Local Variables	/FR	Generate .SBR files
Don't Pack Information	/Zn	Generate .SBR files but don't compact them
Assembly
Assembly	/FA	Default assembly-code listing
Include Machine Code	/FAc	Generate combined assembly- and machine-code listing
Include Source Code	/FAs	Generate combined assembly- and source-code listing


Optimizations Category

Category Setting	Option	Comment
Optimizations
Default	none	This is the same as Disable (Debug) without /Od
Disable (Debug)	/Od	Turn off all optimization and generate debug information
Maximize Speed	/O2	Apply optimizations for fastest program
Minimize Size	/O1	Apply optimizations for smallest program
Customize		Select options using the Custom Optimizations list box
Custom Optimizations
Assume no aliasing	/Oa	Enable use of registers
Assume aliasing across function calls	/Ow	Reload variables after function call
Global optimizations	/Og	Search functions for common subexpressions
Generate intrinsic functions	/Oi	Replace intrinsic functions with their inline code
Improve float consistency	/Op	Use coprocessor registers to improve speed and size
Favor small code	/Os	Optimize for space
Favor fast code	/Ot	Optimize for time
Frame-Pointer Omission	/Oy	Omit frame pointers on the program stack
Full optimization	/Ox	Maximize for speed. Same as: /Ob1  /Og /Oi /Ot /Oy
Include Expansion of Functions
Disable *	/Ob0	Disable inline expansion
Only __inline	/Ob1	Inline expansion is user-defined
Any suitable	/Ob2	Inline expansion at compiler discretion plus user-defined


Precompiled Headers Category

Category Setting	Option	Comment
Automatic Use of Precompiled Headers	/YX	Automatically creates and uses a precompiled header file
Precompile through Headers (for Automatic  Use of Precompiled Headers )
headerfilename	/YX "headerfilename"	Name of the last header file used in the precompiled header
Precompile through Headers (for both C Files and C++ Files)
headerfilename	/Yu "headerfilename"	Name of the last header file used in the precompiled header
Precompile with Source  (for both C Files and C++ Files)
sourcefilename	/Yu "sourcefilename"	sourcefilename is the name of the source file that includes the last header file used in the precompiled header


Preprocessor Category

Category Setting	Option	Comment
Symbols and Macros to Define
identifier	/D "identifier"	Maximum of 30 identifiers
Individual Symbols to Undefine
name	/U "name"	Undefines existing symbols
Undefine All Symbols	/u	Undefines all defined symbols
Include Path
directory	/I "directory"	Searches directory for include files
Ignore Standard Places of Include Files	/X	Ignore the current directory and the Visual Workbench include directories


Runtime Category

Category Setting	Option	Comment
Use Runtime Library
Single-Threaded (LIBC.LIB)	/ML	Default compiler action
Multi-Threaded (LIBCMT.LIB)	/MT	Defines _MT
Multi-Threaded using DLL (MSVCRT10.LIB)	/MD	Defines _MT and _DLL


  Linker Options

The tables in this section describe the linker options in the Linker Options dialog box. For detailed information on linker options, see Help or Chapter 4, "Using the 32-Bit LINK" in Build Tools User's Guide.

The following tables are included:

»Debug Category«

»Image Attributes Category«

»Input Category«

»Miscellaneous Category«

»Output Category«


Debug Category

Category Setting	Option	Comment
Generate Mapfile	/MAP	Produce a mapfile with the base name of the output file and an extension of .MAP.
Mapfile Name
filename	/MAP:filename	Name the mapfile and override the default name
Debugging Information	/DEBUG	Put debugging information in the output file
Debugging Information
CodeView Format	/DEBUGTYPE :cv	Create CodeView debug information
COFF Format	/DEBUGTYPE:coff	Create COFF debug information.
Both Formats	/DEBUGTYPE:both	Create COFF and CodeView debug information


Image Attributes Category

Category Setting	Option	Comment
Stack Allocations
Rese/rve
n1	/STACK:n1	Total stack space in virtual memory
Commit
n2	/STACK:n1,n2	Amount of memory allocated each time
Base Address
hex_n	/BASE: 0xhex_n	Set the base address of the executable image
Name of Entry-Point Symbol
symbolname	/ENTRY:"symbolname"	Set the starting address for the program


Input Category

Category Setting	Option	Comment
Object/Library Modules
libraryname	libraryname	Specify additional libraries and object files
Ignore Default Libraries	/NOD	Remove all default libraries from the library search
Ignore Specific Libraries
libraryname	/NOD:"libraryname"	Remove the specified default libraries from the library search
Include Symbols
symbolname	/INCLUDE:"symbolname"	Force a reference to a symbol so the symbol's object will be linked
Name of .DEF File
filename	/DEF:"filename"	Specify a module-definition file
MS-DOS Stub Filename
filename	/STUB:filename	Add the specified MS-DOS program to the beginning of the output file


Miscellaneous Category

Category Setting	Option	Comment
Version Information
Major
n1	/VERSION:n1	Write a major version number in the header of the output file
Minor
n2	/VERSION:n1,n2	Write a minor version number in the header of the output file
Verbose	/VERBOSE	Display additional information about the linking process
Supress Display of Sign-On Banner	/NOLOGO	Prevent display of the copyright message and option string
Other Options
valid LINK option	valid LINK option	Add the specified options to the LINK command line.


Output Category

Category Setting	Option	Comment
Force File Output	/FORCE	Create an output file even if a symbol is undefined
Name of Output
filename	/OUT"filename"	Name the executable or DLL and override the default name


Figure 1.1 The Visual Workbench Environment


Figure 1.2 Source Windows


Figure 1.3 The Output Window


Figure 1.4 The Browse Window


Figure 1.5 The Debugging Windows


Figure 1.6 Minimized Windows


Figure 2.1 The Save As Dialog Box


Figure 2.2 The Editor Dialog Box


Figure 2.3 The Editor Dialog Box


Figure 2.4 The Find Dialog Box


Figure 2.5 The Replace Dialog Box


Figure 2.6 The Print Dialog Box


Figure 2.7 A Printer Setup Dialog Box


Figure 3.1 The Project Options Dialog Box


Figure 3.2 The Edit    Projectname Dialog Box
Figure 3.2 The Edit  --  Projectname Dialog Box


Figure 3.3 The C/C++ Compiler Options Dialog Box


Figure 3.4 The Workspace Dialog Box


Figure 3.5 The External Project Options Dialog Box


Figure 4.1 C/C++ Compiler Options: Listing Files


Figure 4.2 The Browse Window


Figure 4.3 Browse Window Query Group


Figure 4.4 Class Graphs


Figure 4.5 Call and Caller Graphs


Figure 4.6 Expanded and Collapsed Nodes


Figure 4.7 Derived Class Graph of the CWnd Class


Figure 4.8 Base Class Graph of the CDialog Class


Figure 4.9 A Call Graph


Figure 5.1 Debugging Windows


Figure 5.2 The Project Options Dialog Box


Figure 5.3 The Breakpoints Dialog Box


Figure 5.4 The Messages Dialog Box


Figure 5.5 The Locals Window


Figure 5.6 The Watch Window


Figure 5.7 The Watch Window with Expanded and Collapsed Variables


Figure 5.8 The QuickWatch Dialog Box


Figure 5.9 Modifying a Variable Using the QuickWatch Dialog Box


Figure 5.10 The Call Stack Dialog Box


Figure 5.11 The Registers Window


Figure 5.12 The Exceptions Dialog Box


Figure 5.13 The Threads Dialog Box


Figure 6.1 The Tools Dialog Box


Figure 6.2 The Add Tool Dialog Box


Figure 6.3 The Directories Dialog Box


Figure 6.4 The Color Dialog Box


Figure 6.5 The Font Dialog Box


Figure 7.1 The MFC AppWizard Dialog Box


Figure 7.2 AppWizards Options Dialog Box


Figure 7.3 AppWizards Classes Dialog Box


Figure 7.4 ClassWizard


Figure 7.5 Classes Derived from CCmdTarget


Figure 7.6 ClassWizards Add Class Dialog Box


Figure 7.7 Creating Message Handlers for Windows Messages


Introduction
App Studio User's Guide

Introduction

This manual contains information and procedures for working with App Studio, a powerful and easy-to-use Microsoft® Windows™ operating system resource editor. In addition to editing Windows resources, App Studio works together with the Microsoft Foundation Class Library and ClassWizard to let you connect your resources to code. With ClassWizard, you can also quickly define class member variables that make it easier to work with dialog-box controls.

Chapter 1, »App Studio Overview«,  provides an overview of the App Studio user interface, including the main App Studio window, the resource browser window. Chapter 1 also contains important information on how to use the App Studio Properties window, a convenient way for setting the Windows styles of each resource and controlling the resource's appearance and behavior.

Chapter 2, »Working with Files and Symbols«,  discusses how to work with App Studio resource script files and details important issues to consider when updating existing resource files for use with App Studio. Also in Chapter 2 is information on working with resource identifiers in App Studio.

Chapters 3 through 8 offer specific step-by-step procedures for using App Studio's editing windows to create or modify Windows resources. Among the topics covered are the following:

•	Using the dialog editor to create dialog-box and form-view templates, and using drag-and-drop to place dialog-box controls or transfer them from one dialog box to another.

•	Using the menu editor to quickly create and modify menu resources in an editing window that lets you work with the menu in a menu-bar format similar in appearance to the finished application.

•	Using the accelerator table editor to create and edit accelerator-table entries.

•	Using the string editor to create, find, or modify strings in your application's string table.

•	Using App Studio's full-featured graphics editor to edit bitmaps, icons, cursors and special-purpose images such as toolbars.

Chapter 9, »Using ClassWizard«, introduces ClassWizard, a kind of programmer's assistant that makes it easier for you to do certain routine tasks such as creating new classes and gathering data from controls in a dialog box or form view.

Part 2 of this manual provides a reference to the resource properties that you can set in the App Studio Properties window and a complete reference to the App Studio menus and toolbars. This information (including additional information about App Studio dialog boxes) is also contained in online Help.


 Document Conventions

This book uses the following typographic conventions:

Example	Description
STDIO.H	Uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
char, _setcolor, __far	Bold type indicates C and C++ keywords, operators, language-specific characters, and library routines. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
	Many constants, functions, and keywords begin with either a single or double underscore. These are required as part of the name. For example, the compiler recognizes the __cplusplus manifest constant only when the leading double underscore is included.
expression	Words in italics indicate placeholders for information you must supply, such as a filename. Italic type is also used occasionally for emphasis in the text.
[option]	Items inside square brackets are optional.
#pragma pack {1 | 2}	Braces and a vertical bar indicate a choice among two or more items. You must choose one of these items unless square brackets ([ ] ) surround the braces.
#include <io.h>	This font is used for examples, user input, program output, and error messages in text.
CL [option...]  file...	Three dots (an ellipsis) following an item indicate that more items having the same form may appear.
while() {  .  .  . }	A column or row of three dots tells you that part of an example program has been intentionally omitted.
CTRL+ENTER	Small capital letters are used to indicate the names of keys on the keyboard. When you see a plus sign (+) between two key names, you should hold down the first key while pressing the second.
	The carriage-return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
"argument"	Quotation marks enclose a new term the first time it is defined in text.
"C string"	Some C constructs, such as strings, require quotation marks.
Dynamic-Link Library (DLL)	The first time an acronym is used, it is usually spelled out.
see »Using Projects«.	Hypertext cross-references are enclosed in green double chevrons. Click the term enclosed in the chevrons to display the referenced information.
CEnterDlg;	The blue box adjoining the blue code indicates that it has been altered from a previous example, usually because you are being instructed to edit it.


Book Location
App Studio User's Guide


 App Studio Update

This update material describes the issues involved in using App Studio for Windows NT™.

For specifics on programming with the Microsoft Foundation Class Library for Windows NT, see "Microsoft Foundation Class Library Update" in the Class Library Reference.


 Using App Studio for Windows NT

Because Visual Basic does not support 32-bit programming, App Studio for Windows NT does not support VBX controls.

App Studio for Windows NT cannot load or save executable (.EXE) files, compiled resource script (.RES) files, or dynamic-link libraries that were created with Windows NT.

App Studio for Windows NT does not support resources or resource objects specific to Windows NT, such as the PUSHBOX control. To use Windows NT − specific resources from within App Studio, include them in your resource file as read-only (compile-time) resources. For information on how to use the Set Includes dialog box to add compile-time resources to your application, see »Including Resources From Other Files.«


Chapter 1: App Studio Overview
 Chapter 1  App Studio Overview

App Studio is a powerful, easy-to-use resource editor. You can:

•	Edit both the appearance and behavior of common user-interface objects such as menus, dialogs boxes, accelerator tables, and string tables.

•	Quickly design and edit bitmaps, cursors, icons, and toolbars in the App Studio graphics editor.

However, App Studio is also more than just a resource editor. While working in App Studio with Microsoft Foundation Class Library resource files you can:

•	Attach user-interface objects to code by using ClassWizard to quickly and easily define message-handling functions.

•	Create class member variables that automatically use the Microsoft Foundation Class Library routines for gathering and validating dialog-box data.

If you're new to programming for Windows, see the »Understanding Windows Resources« section near the end of this chapter. It explains the role of resources in a Windows program and gives examples of the most common resources.

You can also use the sample icons, cursors, and toolbar buttons in the sample resource file supplied with Microsoft Visual C++™, COMMON.RES.


 App Studio Basics

Once you have installed App Studio on your machine as part of the Visual C++ installation process, you are ready to begin editing user-interface objects and other resources.

Note  A mouse or other pointing device is required for many App Studio functions.


 Starting App Studio

To begin your App Studio session, use the Visual Workbench Tools menu to open your project's resource script (.RC) file for editing. You can create the menus, accelerators, dialog boxes, and other resources that make up the user interface of your Windows program.

To run App Studio:

•	From the Visual Workbench Tools menu, choose App Studio.

App Studio opens your current project's .RC file.

For more detailed information on running App Studio, see »Opening a Visual C++ Resource File«.

If you used AppWizard when you began to write your program, App Studio opens a resource file that provides you with not only the basic outline of a fully functioning Windows application, but with some basic resource building blocks as well. For more information on AppWizard, see the Visual Workbench User's Guide.

»Figure 1.1« shows the App Studio resource browser as it appears at the beginning of a new project. In this illustration, several other important App Studio windows are open. The major parts of App Studio are described in the sections that follow.


 Using the Resource Browser Window

At the beginning of a resource editing session, the first App Studio window to appear is the resource browser (see »Figure 1.2«). Use the resource browser window to:

•	View the resources in the file by type.

•	Create new resources.

•	Delete existing resources.

•	Move resources from one file to another.

•	View and edit a resource's basic properties in the Properties window.

To browse your application's resources:

•	Select a resource in the Type box.

The resources in your file that are of the type or types you selected are listed in the Resources box.

Select a single resource by clicking with the mouse. Select multiple contiguous resources by holding down the SHFT key and clicking. Select multiple noncontiguous resources by holding down the CTRL key and clicking.

Tip  Use CTRL+F2 to quickly move to the resource browser window for the currently open file.

When a resource in the Resources box is selected but is not currently being edited in an App Studio editing window (or the editing window is minimized), you can view and edit the resource's basic properties in the Properties window. For more information on the Resource property pages and other property pages that appear in the Properties window, see the »Property Page Reference«.


 Creating a New Resource

There are several ways to create a new resource in App Studio. You can use the resource browser window or the App Studio toolbar.

To create a new resource:

•	On the App Studio toolbar, click the button you want.

Table 1.1 shows the toolbar's new-resource buttons.

− Or −

•	In the resource browser window, click New, or from the Resources menu, choose New (CTRL+R). Then select the resource you want from the list of choices and click OK or press ENTER.

The editor window for the resource you chose appears.

Table 1.1 App Studio Toolbar New-Resource Buttons

Resource	Toolbar Button
Dialog box
Menu
Cursor
Icon
Bitmap
String table
Accelerator table
For a complete reference to the App Studio toolbar, see »App Studio Quick Reference«.


 Editing an Existing Resource

To edit an existing resource:

1.	Move to the resource browser window.

2.	In the Type box, select the type of resource you want.

A list of the resources of that type in the current file appears in the Resources box.

3.	In the Resources box, select the name or identifier of the resource you want to edit.

4.	Choose Open.

Or select the resource and press ENTER.

Or double-click the resource.

Or from the Resource menu, choose Open.

The editing window for the resource you chose appears.


 Directly Manipulating User-Interface Objects

In many cases App Studio allows you to edit user-interface objects by directly manipulating them. For example, you can:

•	Place controls in a dialog box by dragging them from the control palette into the dialog box (see »Using the Dialog Editor«).

•	Rearrange menu items by moving them from one place to another with the mouse (see »Using the Menu Editor«).

One of the most common direct-manipulation techniques is referred to throughout this manual as "drag and drop." This means that you position an object by dragging it with the mouse or other pointing device and dropping it in its new location, as shown in »Figure 1.3«.

To move or reposition an object using "drag and drop":

1.	Point to the object you want to move or position and hold down the left mouse button.

2.	While still holding down the button, drag the object to its new location.

3.	When the object is in position, drop it by releasing the button.


 Using Undo and Redo

Multiple-level undo and redo is a powerful tool for iterative design in App Studio. Undo reverses the effect of the last operation and redo reverses the effect of the last undo.

Normally you can undo your last ten actions, but you can change this number by changing the value in the Registry; see »Appendix A«. Most common operations in App Studio can be undone, including actions such as dragging and dropping that involve moving from one App Studio window to another.

To undo an operation:

•	On the App Studio toolbar, click the Undo button [image].

Or from the Edit menu, choose Undo (CTRL+Z).

To redo an operation:

•	On the App Studio toolbar, click the Redo button [image].

Or from the Edit menu, choose Redo (CTRL+A.)


 Using the Properties Window

The Properties window is one of the most important features of App Studio; it allows you to control the appearance and behavior of the resources you create. »Figure 1.4« shows the Properties window as it appears when you first open a dialog box for editing.

Once you use App Studio for a short time, you will become quite familiar with how the Properties window works. To get a head start, however, there are a few things you should know:

•	The Properties window contains one or more property pages that apply to the resource or resource object that is currently selected.

•	If the editing window for the selected resource is closed or minimized, only the Resource property page (showing basic information about the resource) is available. See »Property Page Reference« for more information.

•	You can control whether the Properties window stays visible while you are working in another window (for example, an editor window) or is dismissed once you switch to another window.

•	Changes made on a property page take effect as soon as you make them. For an edit box, changes take effect as soon as you switch to another window or control.

•	You can use App Studio's property pages and multiple-level undo as a design tool. Experiment with various property settings and then back them out with CTRL+Z if they're not what you want.


 Viewing Property Pages

Property pages divide resource properties into logical groupings so that they are easier to view and edit.

To display the Properties window:

•	From the Window menu, choose Show Properties.

 − Or−

•	Choose one of the following shortcuts:

•	For resources with a caption, select the resource and start typing the caption.

•	Press ENTER when a resource is selected in an editing window.

•	Press ALT+ENTER at any time.

•	Choose the Properties command at the bottom of the resource browser window.

Tip  You can display the Properties window quickly by double-clicking the object whose properties you want to edit.

To move from one property page to another in the Properties window:

1.	In the Resources box, select the resource whose properties you want to edit.

2.	Display the Properties window if it is not currently displayed: from the Window menu, choose Show Properties.

3.	In the property page box at the upper-right corner of the Properties window, choose the category of properties you want to edit from the list of property pages.

Tip  With the Properties window displayed, you can quickly move from one property page to another using the PAGE UP and PAGE DOWN keys.


 Controlling the Properties Window

You can control the behavior of the Properties window to suit your working style or the nature of the resource editing task. Use the "pushpin" command button in the upper-left corner of the Properties window:

•	When the button is in the down position [image], the Properties window stays visible even when you are working in another window. This is convenient if, during an editing session, you want to move back and forth frequently between setting properties and editing objects. Pressing ENTER after you change a value in the Properties window returns you to the editing window but leaves the Properties window visible. Pressing ESC cancels any changes you made and returns you to the editing window.

•	When the button is in the up position [image], you can dismiss the active Properties window by pressing ENTER or ESC. This is useful if you want to concentrate on working in an editing window but need to bring up the Properties window briefly to change one or two values.


 Introduction to App Studio Editing Windows

This section presents a visual overview of the main App Studio editing windows and App Studio dialog boxes. For a complete description of each editor, see the appropriate chapter.


 Dialog Editor

Use the dialog editor (»Figure 1.5«) to quickly create dialog boxes , place and arrange controls, and test the finished product. See »Using the Dialog Editor«, Chapter 3.


 Menu Editor

Use the menu editor (»Figure 1.6«) to create and edit menu items by working directly with a menu bar that closely resembles the one in your finished application. See »Using the Menu Editor«, Chapter 4.


 Accelerator Table Editor

Use the accelerator table editor (»Figure 1.7«) to add, delete, change, or browse the accelerator-key assignments in your project. See »Using the Accelerator Table Editor«,Chapter 5.


 String Editor

Use the string editor (»Figure 1.8«) to change or add to your program's standard string-table resource. See »Using the String Editor«, Chapter 6.


 Graphics Editor

Use the graphics editor (»Figure 1.9«) to edit your program's cursor, icon, and bitmap resources. See »Using the Graphics Editor«, Chapter 7.


 Binary Data Editor

Use the binary data editor (»Figure 1.10«) to edit an existing custom resource at the binary level in either hexadecimal or ASCII format. See »Using the Binary Data Editor«.


 Symbol Browser

Use the Symbol Browser (»Figure 1.11«) to edit and browse existing identifiers or create new ones. See »Working with Files and Symbols«, Chapter 2.


 Using ClassWizard

App Studio goes beyond just editing resources. You can use ClassWizard to connect resources to code. This section gives a brief overview of ClassWizard; for more information, see »Using ClassWizard«, Chapter 9.


 Simplifying Message Handling

ClassWizard greatly simplifies the often tedious and time-consuming task of managing Windows message handling. You can browse the Windows messages appropriate to a given user-interface object and define message handlers for them (»Figure 1.12«).


 Gathering and Validating Dialog-Box Data

The Microsoft Foundation Class Library has built-in routines that simplify gathering and validating the data associated with dialog-box controls.

When you are building a dialog box in App Studio, you can use ClassWizard to define member variables in the dialog-box class to take advantage of these built-in routines for Dialog Data Exchange (DDX) and Dialog Data Validation (DDV).


 Understanding Windows Resources

Resources are data objects that are separate from the main body of code in a Windows operating system program. Because of this, resources can be built and edited independently of the rest of the development process. This not only makes a project with a complex user interface easier to manage, but it also makes the application easier to translate into other languages.

Typically, resources are used to describe the contents and appearance of user-interface objects such as menus and dialogs. However, you can also define your own resource type if, for example, you have custom data that you want to make part of your program.

To most efficiently manage available memory, Windows usually leaves resources on disk until they are needed, although you can cause individual resources to be loaded at program startup to improve performance. Once loaded, a resource is usually placed in a "discardable" section of memory so that memory can be freed up for other tasks if needed. When the user-interface object is again required, it is loaded from disk.

The appearance and contents of resources are defined in a "resource script" (.RC) file. The .RC file is compiled into a binary form in a separate step when you build your program and is made a part of the executable file during linking.


 Predefined Windows Resources

The following predefined resource types are supported by built-in Windows library routines:

dialog box	menu
accelerator table	string table
bitmap	icon
cursor


 Dialog Box

A dialog box is a window, usually a pop-up window under the control of the main program window, that allows your program to carry on a two-way conversation with the user. Dialog boxes are used to gather the information needed to comply with a user request (such as the name of a file to open).

App Studio allows you to construct dialog boxes by simply dragging controls from a palette and dropping them into place. You can also arrange controls easily with a variety of layout tools. For information on editing dialog boxes, see »Using the Dialog Editor«, Chapter 3.


 Menu

A Windows menu is a list of program commands. Menus offer a way to group multiple commands into logical units, thus reducing the complexity of the user interface. Since these lists of commands drop down from a "menu bar" at the top of the main program window, they also offer a convenient way for the user to browse and select program commands with a pointing device. »Figure 1.13« shows a program window with a menu bar and two levels of menus open.

The App Studio menu editor allows you to create new menus by pointing to any empty menu cell and filling in the information in the Properties window. To rearrange menu items, you just drag them from one location to another with the mouse. For information on editing menus, see »Using the Menu Editor«, Chapter 4.


 Accelerator Table

An accelerator table contains a list of accelerator (shortcut) keys that can be used to execute a program command directly from the keyboard without having to pull down a menu and choose the command from a list. In »Figure 1.13,« the menu example, the Copy command is assigned to the key combination CTRL+C.

Normally, accelerators are associated with program commands that also appear on a menu. However, some applications use accelerator keys for seldom-used program commands that, if placed on a menu, would make the program's menu structure too complex.

For more information on editing accelerator tables, see »Using the Accelerator Table Editor«, Chapter 5.


 String Table

A string table is a Windows resource type that allows you to store text strings that will be displayed as part of your user interface. Since this information is stored separately from the program source code, you can easily edit or translate program text without having to recompile the entire program.

The App Studio string editor gives you convenient access to all string resources and their associated attributes. For more information about the App Studio string editor, see »Using the String Editor«, Chapter 6.


 Bitmap

A bitmap is a graphical image stored in binary form; the basic element of the bitmap is the pixel, or picture element. One common use of bitmaps in programs for Windows is to define the appearance of the custom command buttons frequently used in toolbars or control palettes. For example, when you create a new application using AppWizard, a basic toolbar bitmap (»Figure 1.14«) is included as part of the application.

The graphics editor in App Studio is full-featured and powerful. In addition to allowing general bitmap editing, it has special provisions for editing bitmaps for use with the CToolBar class in the Microsoft Foundation Class Library. For more information on creating toolbars and other bitmaps using the App Studio graphics editor, see »Using the Graphics Editor«, Chapter 7.


 Icon

An icon is a unique graphical identifier that represents a program on the Windows desktop. An icon is used to launch a program from the Program Manager and also to represent a program window that has been minimized. »Figure 1.9«  shows an icon, which is a 32x32-pixel bitmap, being edited in the App Studio graphics editor.

For information on using App Studio to create or modify icons, see »Using the Graphics Editor«, Chapter 7.
For information on incorporating existing icons into your project, see »Using Advanced Resource File Techniques.«


 Cursor

A cursor is a bitmap, usually 32x32 pixels, that shows the position of the mouse or other pointing device on the screen. Programs use different cursors to show a change in the state or current action.

For example, in the App Studio dialog editor, when you use "drag and drop" to place a radio button in a dialog box, the cursor changes from an arrow to an arrow and a radio button (see »Figure 1.15«) as a visual reminder of what kind of object you are moving.

For information on using the App Studio graphics editor to edit cursors, see Chapter 7. For information on incorporating existing cursor bitmaps into your project, see  Chapter 2, »Working With Files and Symbols.«


 App Studio Sample Resources

Visual C++ includes sample resources that you can use in your own application. These include:

•	A large number of icons that represent common business and data-processing tasks.

•	Several commonly used cursors that are not included as predefined Windows resources.

•	A selection of toolbar-button bitmaps.

These resources are located in a file called COMMON.RES in the \MSVCNT\MFC\SAMPLES\APSTUDIO directory on the drive where you installed Visual C++. Additional sample resources can be found in this directory.

To copy resources from COMMON.RES to your own resource script file:

1.	Use App Studio's File menu to open both your .RC file and COMMON.RES at the same time.

2.	Hold down the CTRL key and drag the resources you want from the COMMON.RES resource browser window to the resource browser window of your own application.

Where to Go from Here

For more information on	See
Managing projects and working with resource files	»Chapter 2«
Using ClassWizard	»Chapter 9«
Editing specific resource types	The chapter covering the editor for that resource
User-interface object properties and styles	»Chapter 11«


Chapter 2: Working With Files and Symbols
 Chapter 2  Working With Files and Symbols

App Studio supports many different ways of working with resources. You can:

•	Load, save, and edit resource script (.RC) files.

•	Use App Studio as a stand-alone editor for bitmaps, icons, or cursors.

•	Import or export graphics resources to or from your current resource file.

In most cases, it is easiest to work with App Studio's single .RC file. However, App Studio can accommodate other ways of organizing a project. You can:

•	Work with nested resource files and conditionally included resource files.

•	Include shared or read-only identifiers (symbols) that can't be modified by App Studio.

•	Include resources in your executable file (.EXE) that don't require editing (or that you don't want to be edited) during your current project (such as resources that are shared between several projects).

•	Include resource types not supported by App Studio.

When you create a new resource or an object within a resource, App Studio assigns it an identifier, or symbol, consisting of a text string mapped to an integer value. You can change the symbol name or value in the Properties window when you create the resource, and you can view existing symbols and add new ones with the Symbol Browser as you work.


 Working with Files

App Studio lets you open the following types of files:

File Extension	Description
.RC	Resource script file
.BMP, .DIB, .ICO, .CUR	Graphics files containing bitmaps, icons, or cursors
Important  App Studio for Windows NT cannot load and save Windows NT .EXEs, DLLs, or .RES files.

App Studio for Windows NT does not support resources or resource objects specific to Windows NT, such as the PUSHBOX control. To use Windows NT-specific resources from within App Studio, include them in your resource file as read-only (compile-time) resources. For information on how to use the Set Includes dialog to add compile-time resources to your application, see »Including Resources From Other Files.«

You can save an existing resource, executable file, or graphics file as one of the following:

•	.RC

•	.BMP, .DIB, .ICO, or .CUR (if you are working with a graphics file only and not a resource script file)

App Studio also works with several additional files during your resource editing session:

Filename	Description
RESOURCE.H	Header file generated by App Studio; contains symbol definitions.
projectname.APS	Binary version of the current resource file; used by App Studio for quick loading.
projectname.CLW	File containing information about the current project; used by ClassWizard.
The following sections cover the most common operations you'll need to set up your project and to manage resources and resource files.


 Creating a New Resource File

You can use App Studio to create a new resource script file or graphics resource file. You can also choose to include Microsoft Foundation Class Library support in the resource file you create.

To create a new resource file:

1.	From the File menu, choose New.

The New dialog box appears.

2.	Choose a file type from the list of choices: bitmap, icon, cursor, or resource script file (.RC).

3.	Set or clear the Use Microsoft Foundation Classes option as appropriate.

For information on features specific to Microsoft Foundation class resource files, see »Features Supported Only in Microsoft Foundation Class Library Resource Files«.

− Or −

•	Click the New File button on the App Studio toolbar.

A new resource script file with Microsoft Foundation Class Library support is created.

Note  You can change the type of resource file created by changing the UseMfc setting in the Registry. See »Appendix A« for details.


 Opening a Visual C++ Resource File

This section provides two ways to start a resource editing session from Visual Workbench. The instructions assume that you have started Visual Workbench and created a basic set of new project files using AppWizard. For more information on AppWizard, see Chapter 7 of the Visual Workbench User's Guide. For information on opening resource files not created with AppWizard or App Studio, see »Reading Resource Files Not Created with App Studio or AppWizard.«

To open a resource file from Visual Workbench:

•	From the Tools menu, choose App Studio.

This executes App Studio and opens the .RC file with the same base name as the current project.

− Or −

1.	From the Options menu, choose Editor.

The Editor dialog box appears.

2.	Under Source Files, select the Open RC Files Using App Studio option (normally turned off).

3.	Click the Project Files button on the Visual Workbench toolbar and choose your project's .RC file from the list.

 − Or−

1.	From the File menu, choose Open.

2.	Open the .RC file for your project.

Visual Workbench executes App Studio and loads the project resource file.

To open a resource file from App Studio:

1.	Start App Studio from the Windows Program Manager.

2.	From the App Studio File menu, choose Open.

3.	Open your project's .RC file for editing.

For information on a recommended file structure for Visual C++ projects, see the discussion of the files generated by the AppWizard in Chapter 7 of the Visual Workbench User's Guide.


 Reading Resource Files Not Created with App Studio or AppWizard

When you start a new Visual C++ product, you normally use AppWizard to create a set of basic starter files. These starter files include an App Studio-compatible .RC file that contains support for Microsoft Foundation Class Library features. However, you can also update existing .RC files for use with App Studio.

To update an existing resource file for use with App Studio:

1.	Make a backup copy of your existing .RC file.

2.	Add the .RC file to your project using Visual Workbench (see Chapter 3 of the Visual Workbench User's Guide).

3.	Open the file in App Studio according to the instructions in the previous section.

Note  App Studio uses the include path set in Visual Workbench (from the Visual Workbench Options menu, choose Directories). In addition, relative include paths in an App Studio resource file must be based on the directory where the .RC file is currently located.

4.	Save the App Studio version of the resource file.

Reading in and then saving resource files not created by AppWizard or App Studio has two results that are important to be aware of:

•	App Studio makes several changes to how your resource files are organized so that you can work with all your resources in one place.

•	Several resource-related features supported by the Microsoft Foundation Class Library are automatically available when your resource script file includes the library file AFXRES.H. See »Updating Existing Code for Use with ClassWizard« for instructions on how to manually add framework support to existing .RC files.


 Converting Existing Resource Files to App Studio Format

Saving a non-App Studio resource script file for the first time in App Studio has several important consequences:

•	Resources contained in files that were added to your old .RC file with include statements are written back to disk as part of the main App Studio resource file.

For example, if your old project had dialog boxes in a separate .DLG file, this separate file is no longer needed since App Studio moves the dialog boxes into the main .RC file.

However, if you have resource files containing resources that you do not want to edit in App Studio, or that you want to continue to store in a separate resource file (such as a version resource file), move the resource to a separate file and add it back by using the File menu's Set Includes command. See »Using Advanced Resource File Techniques« for more information.

•	Any symbol definitions included in your old .RC file are marked as read-only symbols by App Studio the first time you save the .RC file. To make the symbols available for modification and editing, remove them from the included header file and place them in the App Studio resource header, resource.h.

•	Symbols that are defined with expressions rather than integers and used in the resource file are evaluated by App Studio, but they are then written to the App Studio symbols header (.H) file as simple integers. To preserve the expressions for calculated symbol values, include them in a read-only symbols header file.

•	Conditional compilation statements in your old .RC file are evaluated by App Studio the first time the file is read in, but they are not written back to disk when you save the .RC file.

Note  To preserve conditional compilation statements you should place the sections of your old .RC file containing these statements in a separate file, then include the file using the File menu's Set Includes command.

•	Comments in your old .RC file are not preserved.

In most cases, App Studio makes it easy and convenient to work with all your resources and symbols in a single App Studio file. However, App Studio also supports a nested resource file structure, conditionally included resource files, and expressions as symbol values if your project requires it. For more information see the section »Using Advanced Resource File Techniques« later in this chapter.


 Features Supported Only in Microsoft Foundation Class Library Resource Files

Normally when you build a Microsoft Foundation Class Library Windows application from scratch using AppWizard, you start by generating a basic set of files, including a resource file, that contain the core features of the Microsoft Foundation classes.

However, if you are editing a resource file for a Windows program that is not based on the Microsoft Foundation Class Library, the following features specific to the framework are not available in App Studio:

•	»ClassWizard«

•	Menu prompt strings

•	List Contents for combo-box controls

You can, however, add framework support to existing resource script files that do not have it.

To add framework support to .RC files that do not already have it:

1.	From the File menu, choose Set Includes.

The Set Includes dialog box appears.

2.	In the Read-Only Symbol Directives box, replace the include statement for WINDOWS.H with the following:

#include "afxres.h"

3.	You may also need to add additional include files using the Compile-Time Directives box. For more information, see the Class Library Reference.

4.	Close the resource file and then reopen it for the changes to take effect.


 Copying Resources Between Files

The easiest way to copy resources from either an existing resource or an executable file to your current resource file is to have both files open in App Studio at the same time. Then use drag and drop to move items from one resource browser window to another (see »Figure 2.1«).

Note  Visual C++ includes sample resource files that you can use in your own application. See »App Studio Sample Resources«.

You can use the Resource menu's Import command to add bitmap, icon, or cursor files to your current App Studio project. You can save graphics resources to disk as separate files using the Export command.

To copy resources from one file to another:

1.	Open both files. Make sure both resource browser windows are visible.

2.	In the resource browser window of the "from" file, select the resource you want to copy.

3.	Hold down the CTRL key and drag the resource to the resource browser window of the "to" file.

Dragging the resource without holding down the CTRL key moves the resource rather than copies it.

Note  To avoid conflicts with symbol names or values in the existing file, App Studio may change the transferred resource's symbol value, or symbol name and value, when you copy it to the new file.

To import a separate bitmap, icon, or cursor file into your current resource file:

1.	From the Resource menu, choose Import. The Import dialog box appears.

2.	Choose the name of the .BMP, .ICO, or .CUR file you want to import. When you choose OK, the file is added to the current resource file.

Tip  You can also copy a bitmap, icon, or cursor into your current resource file by dragging it from a File Manager window and dropping it into the App Studio resource browser window.

To save a bitmap, icon, or cursor as a separate file:

1.	Select the bitmap, icon, or cursor you want to export. App Studio exports the graphic selected in the resource browser window or the graphic in the currently active image editor window.

2.	From the Resource menu, choose Export.

3.	Enter a new filename for the bitmap, icon, or cursor, or press ENTER to accept the current filename.

The graphics file is saved to disk.


 Using Advanced Resource File Techniques

You can use the File menu's Set Includes command to modify App Studio's normal working arrangement of storing all resources in the project .RC file and all symbols in resource.h. (For more information on symbols, see »Working with Symbols«.) »Figure 2.2« shows the Set Includes dialog box.

Use the Symbol Header File box to change the name of the header file where App Studio stores the symbol definitions for your resource file.

Use the Read-Only Symbol Directives box to include header files that contain symbols that should not be modified during an App Studio editing session. For example, you can use the Read-Only Symbol Directives box to include a symbol file that has been created to be shared among several projects. The Read-Only Symbol Directives box is also used to include Microsoft Foundation Class Library .H files.

Use the Compile-Time Directives box to include resource files that:

•	Are created and edited separately from the resources in your main resource file.

•	Contain compile-time directives, such as directives that conditionally include resources.

•	Contain resources in a custom format.

The Compile Time Directives box is also used to include standard Microsoft Foundation Class Library resource files.

Once you've made changes to your resource file using the Set Includes dialog box, you need to close the file and then reopen it for the changes to take effect.


 Changing the Name of the Symbols Header File

Normally App Studio saves all symbol definitions to RESOURCE.H. However, you may need to change this include filename so that you can, for example, work with more than one resource file in the same directory.

To change the name of the resource symbol header file:

1.	From the File menu, choose Set Includes.

The Set Includes dialog box appears.

2.	In the Symbol Header File box, type the new name for the include file.

3.	Choose OK.


 Using Shared (Read-Only) or Calculated Symbols

The first time App Studio reads a non-App Studio resource file, it marks all included header files as read-only. Subsequently, you can use the File menu's Set Includes command to add additional read-only symbol header files.

One reason you may want to use read-only symbol definitions is for symbol files that you plan to share among several projects.

You would also use included symbol files when you have existing resources with  symbol definitions that use expressions rather than simple integers to define the symbol value. For example,

#define   IDC_CONTROL1 2100

#define   IDC_CONTROL2 (IDC_CONTROL1+1)

App Studio will correctly interpret these calculated symbols as long as:

•	The calculated symbols are placed in a read-only symbols file.

•	Your resource file contains resources to which these calculated symbols are already assigned.

To include shared (read-only) symbols in your resource file:

1.	From the File menu, choose Set Includes. The Set Includes dialog box appears.

2.	In the Read-Only Symbol Directives box, use the #include compiler directive to specify the file where you want the read-only symbols to be kept. (The file should not be called resource.h, since that is the filename normally used by App Studio's main symbol header file.)

3.	Place the symbols in the file you specified.

The symbols in files included in this way are evaluated each time you open your resource file, but they are not rewritten to disk by App Studio when you save your file.

Important  What you type in the Read-Only Symbol Directives box is included in the resource file exactly as you type it. Make sure what you type does not contain any spelling or syntax errors.

You should use the Read-Only Symbol Directives box to include files with symbol definitions only, not resource definitions. App Studio places resources included with the Read-Only Symbol Directives box in the main resource file when it is saved, thus creating duplicate resource definitions.


 Including Resources From Other Files

Normally it is easy and convenient to work with App Studio's default arrangement of all resources in one .RC file. However, you can add resources in other files to your current project at compile time. Use the Set Includes dialog box's Compile Time Directives box.

There are several reasons to place resources in a file other than App Studio's main resource file:

•	To include resources that have already been developed and tested and need no further modification.

•	To include resources that are being used by several different projects, or that are part of a source code version-control system, and thus must exist in a central location where modifications will affect all projects.

•	To include resources (such as RCDATA resources) that are in a custom format.

•	To include statements in your resource file that execute conditionally at compile time using compiler directives such as #ifdef and #else. For example, your project may have a group of resources that are bracketed by #ifdef _DEBUG ... #endif and are thus included only if the constant _DEBUG is defined at compile time.

•	To include statements in your resource file that modify resource-file syntax by using #define to implement simple macros.

If you have sections in your existing resource files that meet any of these conditions, you should place the sections in one or more separate .RC files and include them in your project using the Set Includes dialog box. The projectname.RC2 file created by AppWizard in the RES subdirectory of a new project is used for this purpose.

To include resource files that will be added to your project at compile time:

1.	Place the resources in a resource script file with a unique filename. (Do not use projectname.RC, since this is the filename used for App Studio's main resource file.)

2.	From the File menu, choose Set Includes. The Set Includes dialog box appears.

3.	In the Compile-Time Directives box, use the #include compiler directive to include the new resource file in the main App Studio resource file.

The resources in files included in this way are made a part of your executable at compile time. They are not available for editing or modification when you are working on your project's main .RC file. You need to work on included resource files in a separate App Studio resource script file.


 Working with Symbols

A symbol is a resource identifier that consists of a text string (name) mapped to an integer value. Symbols provide a descriptive way of referring to resources and user-interface objects, both in your source code and while you're working with them in App Studio.

When you create a new resource or resource object, App Studio provides a default name for the resource (for example, IDC_RADIO1) and assigns a value to it. The name-plus-value definition is stored in the App Studio-generated file RESOURCE.H.

In working with symbols from within App Studio, you can:

•	Change the symbol associated with a resource or object.

•	Change a symbol's name or value in the Symbol Browser (if the symbol hasn't been used yet).

•	Change a symbol's name in the Properties window (if the symbol is already in use by a single object).

•	Use the Symbol Browser to browse existing symbols, add new symbols, and change or delete unused symbols.

Note  When you are copying resources or resource objects from one .RC file to another, App Studio may change the transferred resource's symbol value, or symbol name and value, to avoid conflicts with symbol names or values in the existing file.


 Changing a Symbol or Symbol Name

When you create a new resource or resource object, App Studio assigns it a default name —for example, IDD_DIALOG1. Use the Properties window to change the default symbol name or to change the name of any symbol already associated with a resource.

To change a resource's symbol name:

1.	Select the resource and move to the appropriate property page (usually the General property page), or type CTRL+Q to move directly to the property page
ID box.

− Or −

Open the »Symbol Browser«, select the symbol you want to change,
and choose Change. When the Change Symbol dialog box appears, choose
View Use.

This moves you to the property page of the resource where the symbol is used.

2.	In the ID box, type a new symbol name or select from the list of existing symbols.

3.	Press ENTER to accept the change. If you typed a new symbol name, App Studio assigns it a value automatically.

You can use the Symbol Browser to change the name of symbols not currently assigned to a resource. See »Changing Unassigned Symbols«.


Changing a Symbols Numerical Value
 Changing a Symbol's Numerical Value

Usually you can let App Studio assign the numerical value associated with the symbol names you define. However, there may be times when you need to change the symbol value associated with a resource — for example, when you want a group of controls or a series of related strings in the string table to have sequential IDs.

For symbols already associated with a single resource, use the Properties window to change the symbol value. For symbols associated with more than one resource or object, make the changes directly in resource.h using a text editor.

To change a symbol value using the Properties window (applies only to symbols assigned to a single resource or object):

1.	Select the resource and move to the appropriate property page (usually the General property page), or type CTRL+Q to move directly to the property page
ID box.

− Or −

Open the Symbol Browser, select the symbol you want to change,
and choose Change. When the Change Symbol dialog box appears, choose
View Use.

This moves you to the property page of the resource where the symbol is used.

2.	In the property page ID box, type the symbol name followed by an equals sign and an integer. For example,

IDC_EDITNAME=5100

3.	Press ENTER to accept the change.

The new value is stored in the symbol header file the next time you save. Only the symbol name remains visible in the ID box; the equals sign and value are not displayed after they are validated.

To change the numeric value of a symbol assigned to more than one resource or object:

1.	End your App Studio editing session by closing the current resource file or exiting App Studio.

2.	Load resource.h into Visual Workbench and make the necessary changes.

3.	Save RESOURCE.H.

The next time you open the project's .RC file in App Studio, App Studio uses the new symbol values.

Note  While editing resource.h, take special care not to define duplicate symbols. App Studio can only detect duplicate symbols if they are created from within App Studio.

You can use the Symbol Browser to change the value of symbols not currently assigned to a resource. See »Changing Unassigned Symbols«


 Managing Symbols with the Symbol Browser

As your application grows in size and sophistication, so do the number of resources and symbols that must be created. Large numbers of symbols scattered throughout several files can be difficult to keep track of. The Symbol Browser (»Figure 2.3«) simplifies symbol management by offering a central tool through which you can:

•	Quickly browse existing symbol definitions to see the value of each symbol, a list of symbols being used, and the resources assigned to each symbol.

•	Create new symbols.

•	Change the name and value of a symbol that is not in use.

•	Delete a symbol if it is not being used.

•	With the View Use command, move quickly to the appropriate App Studio resource editor where the symbol is being used.

To access the Symbol Browser dialog box:

•	On the App Studio toolbar, click the Symbol Browser button.

 − Or −

•	From the Edit menu, choose Symbols (CTRL+I).


 Creating New Symbols

When you are beginning a new project, you may find it convenient to map out the symbol names you need before creating the resources they will be assigned to.

To create a new symbol using the Symbol Browser:

1.	In the Symbol Browser dialog box, choose New.

The New Symbol dialog box appears.

2.	In the Name box, type a symbol name.

3.	Accept the symbol value assigned by App Studio or, in the Value box, type a new value.

4.	Choose OK or press ENTER to place the new symbol into the symbol list. The symbol appears in alphabetical order.

If you enter a symbol name that already exists, a message box appears stating that a symbol with that name is already defined. You cannot define two or more symbols with the same name, but you can define different symbols with the same numeric value.

See the »Symbol Name Restrictions« and »Symbol Value Restrictions« sections at the end of this chapter for additional information on symbol names and values.


 Changing Unassigned Symbols

While in the Symbol Browser, you can edit or delete existing symbols that are not already assigned to a resource or object. You can change existing symbols that are in use in only one place by using the Change command to move to the appropriate resource's property page or by moving to the property page directly. You cannot change read-only symbols. A check mark in the In Use column of the Symbol Browser indicates that the symbol is being used. If Show Read Only Symbols is selected, read-only symbols are also displayed. Editable symbols are displayed as bold text, and read-only symbols are displayed as normal text.

To change the name or value of a symbol already in use, see »Changing a Symbol or Symbol Name.«

To change an unassigned symbol using the Symbol Browser:

1.	 Select the unassigned symbol you want and choose Change.

The Change Symbol dialog box appears.

2.	Edit the symbol's name or value in the boxes provided, then press ENTER to accept the change.

To delete an unassigned symbol using the Symbol Browser:

•	Select the unassigned symbol that you want to delete, and choose Delete (DEL).

Note  Before deleting an unused symbol in a resource file, make sure it is not used elsewhere in the program or by resource files included at compile time.


 Opening the Resource Editor for a Given Symbol

When you are browsing symbols in the Symbol Editor, you may want more information on how a particular symbol is used. The View Use command provides a quick way to get this information.

To move to the resource editor where a symbol is being used:

1.	In the Name box of the Symbol Browser, select the symbol you want.

2.	In the Used by box, select the resource type that interests you.

3.	Choose View Use.

The editor for the resource you selected appears.


 Symbol Name and Value Restrictions

There are several restrictions to be aware of when you use symbol names and values.


 Symbol Name Restrictions

All symbol names must be unique within the scope of the application. This prevents conflicting symbol definitions in the header files. Legal characters for a symbol name include A-Z, a-z, 0-9, and the underscore (_). Symbol names cannot begin with a number and are limited to 247 characters. Symbol names are case insensitive, but the case of the first symbol definition is preserved.

Symbol names can be used more than once in your application. For example, if you are writing a data-entry program with several dialogs containing an edit box for a person's Social Security number, you may want to give all the related edit boxes a symbol name of IDC_SSN. To do this, you can define a single symbol and use it as many times as needed.

While it is not required, symbol names are often given descriptive prefixes which indicate the kind of resource or object they represent. The Microsoft Foundation Class Library uses the following symbol naming conventions:

Category	Prefix	Use
Resources	IDR_ IDD_ IDC_ IDI_ IDB_	Accelerator or menu (and associated resources) Dialog Cursor Icon Bitmap
Menu items and commands	IDM_ ID_	Menu item Command
Controls and child windows	IDC_	Control
Strings	IDS_ IDP_	String in the string table String-table string used for message boxes
For more information on framework naming conventions, see Technical Note 20, which can be found in \\MSVCNT\HELP\MFCNOTES.HLP.


 Symbol Value Restrictions

In App Studio, a symbol value can be any integer expressed in the normal manner for #define preprocessor directives. Here are some examples of symbol values:

18

4001

0x0012

-3456

Symbol values for resources can be decimal numbers in the range from 0 to 32767. Symbol values for parts of objects (such as dialog box controls or individual strings in the string table) can be from 0 to 65534 or from -32768 to 32767.

Note  Some number ranges are used by App Studio and the Microsoft Foundation Class Library for special purposes. For more information see Technical Note 20, which can be found in \\MSVCNT\HELP\MFCNOTES.HLP.

In App Studio, you cannot define a symbol value using other symbol strings. For example, the following symbol definition is not supported:

#define IDC_MYEDIT  IDC_OTHEREDIT  //not supported

You also cannot use preprocessor macros with arguments as value definitions. For example,

#define   IDD_ABOUT  ID(7) //not supported

is not a valid expression in App Studio regardless of what ID evaluates to at compile time.

If you have an existing file containing symbols defined with expressions, see »Using Shared (Read-Only) or Calculated Symbols« for instructions on how to include the symbols as read-only symbols.


Chapter 3: Using the Dialog Editor
 Chapter 3  Using the Dialog Editor

The App Studio dialog editor allows you to:

•	Create a new dialog-box template.

•	Place and arrange controls in a dialog-box template.

•	Test dialog boxes.

You can define message handlers and manage data gathering and validation using the Visual C++ ClassWizard.

You can also use the App Studio dialog editor to create and edit templates used
with form views and dialog bars. A form view is a template for a program window whose client area contains dialog-box controls. See »Creating a Form View« for more information.


 Types of Controls

The dialog editor lets you create dialog boxes that include the following standard control types (»Figure 3.1«):

pushbutton

radio button

check box

list box

combo box

group box

static graphic

edit box

static text

scroll bar

user-defined control


 Creating Dialog Boxes

This section contains procedures for:

•	Creating a new dialog-box template.

•	Adding controls.

•	Working with more than one control.

•	Moving, deleting, and copying controls.

•	Resizing controls.

•	Modifying the tab order of controls in a dialog box.

•	Defining dialog-box keyboard shortcuts.


 Opening New or Existing Dialog Boxes

To create a new dialog-box template:

•	On the App Studio toolbar, click the New Dialog Box button [image].

− Or −

•	In the resource browser window, click New, or from the Resource menu, choose New (CTRL+R). Then select Dialog from the list of choices and click OK or press ENTER.

The dialog editor window appears (»Figure 3.2«). Press ENTER to move to the property page and type a name for the new dialog box. You can use the Properties window at any time to change the dialog box's properties.

When the dialog box is created, App Studio assigns it a unique symbol name and value. If you need to change the symbol value, you can use the ID box on the General property page. Type the symbol name followed by an equals sign and a new value. For example,

IDD_DIALOG1=1001

For more information on the property page items, see the »Property Page Reference,« Chapter 11, or choose the Property page Help button.

To edit an existing dialog box:

1.	Move to the resource browser window.

2.	In the Type box, select Dialog.

A list of the dialog resources in the current file appears in the Resources box.

3.	In the Resources box, select the name or identifier of the dialog box you want to edit.

4.	Choose Open.

Or select the resource and press ENTER.

Or double-click the resource.

Or from the Resource menu, choose Open.

The dialog editor window appears.


 Dialog Box Coordinates

The location, height, and width of the current control is displayed in the lower-right corner of the App Studio status bar (»Figure 3.3«). When more than one control is selected, the position indicators show the position of the dominant control (the control with solid sizing handles). When the dialog box is selected, the status bar displays the position of the dialog box and its height and width.

The location and size of a dialog box, as well as the location and size of controls within it, are measured in dialog box units (DLUs). A DLU is based on the size of the dialog-box font, normally 8-point MS Sans Serif. A horizontal DLU is the average width of the dialog-box font divided by four. A vertical DLU is the average height of the font divided by eight.


 Adding Controls

You add controls to a dialog box by selecting the control you want from the control palette. When displayed, the palette stays positioned above other open windows on your desktop.

To show or hide the control palette:

•	Press F2 to display or hide the control palette.

− Or −

•	From the Window menu, choose Show Control Palette or Hide Control Palette.

The fastest way to add controls to a dialog box, reposition existing controls, or move controls from one dialog box to another, is to use the drag and drop method described in »Directly Manipulating User-Interface Objects,« Chapter 1 . When you add a control to a dialog box with drag and drop, the control is given a standard height appropriate to that type of control.

You can also add a new control by clicking the control-palette button for the control you want and:

•	"Drawing" the control in the dialog box. This is a good method when you want to specify the initial size of the object.

•	Clicking in the dialog box at the location you want. This is an alternative method to dragging and dropping.

When you add a control to a dialog box or reposition it, its final placement may be determined by whether or not you have Snap to Grid turned on. For information about Snap to Grid and other placement and alignment tools, see the section »Arranging Controls«.

To add a control to a dialog box using drag and drop:

1.	Drag a control from the control palette to the dialog editor window (»Figure 3.4«).

As you drag the control into the dialog box, a dotted outline of the control indicates its position.

2.	When the dotted outline of the control is in the position you want, release the mouse button. The control is given a standard size appropriate to that type of control.

To add controls to a dialog box using point and click:

1.	On the control palette, click the button for the control you want.

Or to add multiple controls of the same type, hold down the CTRL key, and click the control you want.

2.	Move the mouse pointer to the dialog box and click at the position(s) you want. The control is given a standard size appropriate to that type of control.

3.	Press ESC when you are finished placing controls.

To add a control by "drawing" it with the pointing device:

1.	On the control palette, click the control you want.

Or to add multiple controls of the same type, hold down the CTRL key, and click the control you want.

2.	Place the pointer where you want the upper-left corner of the control to be located.

3.	Hold down the left mouse button.

4.	Move the pointer to the right and down; a dotted outline of the control appears.

5.	When the control is the size you want, release the mouse button.

6.	Press ESC when you are finished placing controls.

When you have added a control to the dialog box, you can change its caption or any other of its properties in the Properties window.


 Selecting Controls

To move, copy, delete, or align controls, you select them and then perform the operation you want. In most cases, you need to select more than one control to use the sizing and alignment tools on the dialog-editor toolbar.

When a control is selected, it has a shaded border around it with solid (active) or hollow (inactive) "sizing handles," small squares that appear in the selection border.

When you are sizing or aligning multiple controls, App Studio uses the "dominant control" to determine how the other controls are sized or aligned. When multiple controls are selected, the dominant control has solid sizing handles; all the other selected controls have hollow sizing handles. You can set the dominant control by holding down the CTRL key while clicking that control.

To select a control:

•	Point to the control you want and click. The currently selected object (control or dialog box) is deselected.

− Or −

•	Use TAB to move forward or SHIFT+TAB to move backward through the controls in the dialog box.

To select more than one control:

1.	From the control palette, select the pointer tool.

2.	Hold down the left mouse button and drag to draw a selection box around the controls you want to select (»Figure 3.5«). Controls partially outside the selection box are not selected.

When you release the mouse button, all controls inside the selection box are selected.

Once you have selected one or more controls, you can remove or add individual controls without disturbing the selection as a whole.

To remove from or add to an existing selection:

•	Hold down the SHIFT key and click the control you want to remove from or add to the existing selection.


 Moving Controls

You can use the following procedures to move one or more controls from one location to another in a dialog box or from one dialog box to another. If Snap to Grid is on, the control snaps to the alignment grid. For information on other ways to align multiple controls, see »Aligning Controls«.

To move a control from one location to another in a dialog box:

•	Drag the control to its new location.

− Or −

•	For a single control, select the control and use the arrow keys to move the control one DLU at a time.

To move a control from one dialog box to another:

•	If both dialog boxes are visible, drag the control to its new location. (Hold down the CTRL key while dragging if you just want to copy the control.)

− Or −

•	Use the Edit menu's Cut and Paste commands. The control is placed in the same position as in the original dialog box.

Note  In rare cases, you may need to place a control outside a dialog box. To do this, hold down the ALT key while dragging the control.


 Deleting and Copying Controls

To delete a control:

1.	Select the control.

2.	From the Edit menu, choose Cut (CTRL+X) or Delete (DEL).

To copy a control:

•	Drag the control while holding down the CTRL key.

− Or −

•	Use the Edit menu's Copy (CTRL+C) and Paste (CTRL+V) commands.

When you paste a control into a new dialog, it is placed in the same position it was in the old dialog.


 Sizing Individual Controls

Use the sizing handles to resize a control. When the mouse cursor is positioned on a sizing handle, it changes shape to indicate the direction in which the control will be resized (see »Figure 3.6«). Active sizing handles are solid; if a sizing handle is hollow, the control cannot be resized along that axis. For information on sizing multiple controls, see »Resizing Controls«.

When you change the size of a control, its final shape may be affected by whether or not you have »Snap to Grid« turned on.

To size a control:

1.	Click the control or select it with the TAB key.

2.	Use the sizing handles to change the size of the control:

•	Sizing handles at the top and sides change the horizontal or vertical size.

•	Sizing handles at the corners change both horizontal and vertical size.

− Or −

Use the SHIFT key plus the arrow keys to resize the control one DLU at a time.


 Sizing a Control to Fit Its Caption

You can automatically change the size of a control so that it is the appropriate size for its text caption.

To resize a control to fit its caption:

1.	Select the control.

2.	From the Layout menu, choose Size to Content (F7).


 Sizing Combo Box Drop-downs

When you select a drop-down or drop-list combo box to size it, only the right and left sizing handles are active (»Figure 3.7«). Use these handles to set the width of the combo box as it is initially displayed.

You can also set the vertical size of the drop-down portion of the combo box.

To set the size of the combo box drop-down area:

1.	Click the drop-down arrow at the right of the combo box (»Figure 3.7«).

The outline of the control changes to show the size of the combo box with the drop-down area extended.

2.	Use the bottom sizing handle to change the initial size of the drop-down area.

3.	Click the drop-down arrow again to close the drop-down portion of the combo box.


 Changing the Tab Order

Tab order is the order in which the TAB key moves the input focus from one control to the next within a dialog box. Usually the tab order proceeds from left to right in a dialog box, and from top to bottom. The Tabstop option on the control's General property page (normally set) determines if a control actually receives input focus or not.

Even controls that do not have the Tabstop property set need to be part of the tab order. This can be important, for example, when you define mnemonics for controls that do not have captions. Static text that contains a mnemonic for a related control must immediately precede the related control in the tab order.

Note  If your dialog box contains overlapping controls, changing the tab order may change the way the controls are displayed. Controls that come first in the tab order are always displayed on top of any overlapping controls that follow them in the tab order.

To change the tab order for all controls in a dialog box:

1.	From the Layout menu, choose Set Tab Order (CTRL+D).

A number at the upper left of each control shows the current tab order.

2.	Set the tab order by clicking each control in the same order you want the TAB key to follow (»Figure 3.8«).

3.	Press ENTER to exit Set Tab Order mode.

To change the existing tab order, you usually need to change the selected control first, as explained in the following procedure. The selected control determines the number of the control you click next. For example, if you are in Set Tab Order mode and control number 1 is selected, the next control you click is set to number 2.

To change the existing tab order:

1.	From the Layout menu, choose Set Tab Order (CTRL+D).

2.	Change the selected control. To do this, hold down the CTRL key and click the control prior to the one where you want the changed order to begin.

For example, if you want to change the order of controls 7 through 9, select control 6 first (see »Figure 3.9«).

Note  To set a specific control to number 1 (first in the tab order), double-click the control.

3.	Reset the tab order by clicking the controls in the order you want the TAB key to follow.

4.	Press ENTER to exit Set Tab Order mode.


 Grouping Controls

Use the group box control [image] to visually link a group of radio buttons or related check boxes. Then set the Group property for the first control and clear it for the remaining controls so the user can move among the grouped controls with the arrow keys.

To create a group of radio buttons or check boxes

1.	Click the group box control on the control palette and draw the group box to the approximate size you want. Type an appropriate caption, or leave the Caption box on the property page blank if you want no caption to appear.

2.	Place the radio buttons or check boxes and adjust the size of the group box as necessary.

3.	Set the tab order for the dialog box. The controls in the group should follow each other sequentially in the tab order.

4.	On the General property page for the first control in the group, set the Group property. For radio buttons, also set the Tabstop property for the first control in the group.

5.	Make sure the rest of the controls in the group do not have the Group property set.

6.	Move to the control that, based on the tab order, immediately follows the last control in the group. Set the Group property for this control.


 Defining Dialog Box Keyboard Access

Normally keyboard users move the input focus from one control to another in a dialog box with the TAB and arrow keys. However, you can define a mnemonic key that allows users to choose a control by pressing a single key.

Note  All the mnemonics within a dialog box should be unique.

To define a mnemonic key for a control with its own visible caption (pushbuttons, check boxes, and radio buttons):

1.	Select the control and move to the General property page.

2.	In the Caption box, type an ampersand (&) in front of the letter you want as the mnemonic for that control.

An underline appears in the displayed caption to indicate the mnemonic key.

To define a mnemonic for a control without a visible caption:

1.	Make a caption for the control by using a static text control. In the static text caption, type an ampersand (&) in front of the letter you want as the mnemonic.

2.	Make sure the static text control immediately precedes the control it labels in the tab order.


 Arranging Controls

App Studio provides layout tools that align and size controls automatically. For most tasks, you can use the dialog-editor toolbar (»Figure 3.10«). All commands are also available on the Layout menu and most have keyboard equivalents (see the »App Studio Quick Reference,« Chapter 10).

Many layout commands are available only when more than one control is selected. For information on selecting more than one control, see »Selecting Controls«.


 The Dominant Control

When you are resizing or aligning multiple controls, App Studio uses the dominant control to determine how the other controls are sized or aligned. When multiple controls are selected, the dominant control has solid sizing handles; all the other selected controls have hollow sizing handles.

To change the dominant control when more than one control is selected:

•	Hold down the CTRL key and click the control you want to influence the size or location of the others.

The sizing handles change from hollow to solid. All further resizing or alignment is based on this control.


 Using Snap to Grid

When you are placing or arranging controls in a dialog box, you can use the layout grid for more precise positioning. When the grid is turned on, controls appear to "snap to" the dotted lines of the grid as if magnetized. You can turn this "snap to grid" feature on and off and change the size of the layout grid cells.

To turn Snap to Grid on and off for the currently active dialog editor window:

•	On the dialog-editor toolbar, click Snap to Grid (CTRL+G) [image].

To turn Snap to Grid on or off for all dialog editor windows:

1.	On the Layout menu, choose Grid Settings. The Grid Settings dialog box appears.

2.	Turn the Snap to Grid check box on or off.

You can still control Snap to Grid in individual dialog editor windows using the Snap to Grid button on the dialog-editor toolbar.

To change the size of the layout grid:

1.	On the Layout menu, choose Grid Settings. The Grid Settings dialog box appears.

2.	Enter the height and width in DLUs for the cells in the grid. The minimum height or width is 4 »DLUs.«


 Aligning Controls

Once controls are in place, App Studio offers a variety of ways to regularize their position. You can:

•	Align a group of controls along their left, right, top, or bottom edges.

•	Align a group of controls on their center, either horizontally or vertically.

•	Even the spacing between a group of three or more controls.

•	Center one or more controls in the dialog box, vertically or horizontally.

•	Automatically give pushbuttons a standard position along the bottom or on the right of the dialog box.


 Aligning

To align controls:

1.	Select the controls you want to align.

2.	Make sure the correct dominant control is selected. The final position of the group of controls depends on the position of the dominant control.

3.	Choose one of the following tools on the toolbar:

•	Align Left — aligns the selected controls along their left side (CTRL+LEFT ARROW) [image].

•	Align Right — aligns the selected controls along their right side (CTRL+RIGHT ARROW) [image].

•	Align Top — aligns the selected controls along their top edges (CTRL+UP ARROW) [image].

•	Align Bottom — aligns the selected controls along their bottom edges (CTRL+DOWN ARROW) [image].

To align controls on their center, vertically or horizontally:

1.	Select the controls you want to center.

2.	Make sure the correct dominant control is selected. The final position of the group of controls depends on the position of the dominant control.

3.	From the Layout menu, choose Align Vert. Center (F9) or Align Horiz. Center (SHIFT+F9).


 Making Spacing Even

To even the spacing between controls:

1.	Select the controls you want to rearrange.

2.	Choose one of the following tools on the toolbar:

•	Space Evenly Across (ALT+LEFT ARROW or ALT+RIGHT ARROW)

Controls are spaced evenly between the leftmost and the rightmost control selected.

•	Space Evenly Down (ALT+UP ARROW or ALT+DOWN ARROW)

Controls are spaced evenly between the topmost and the bottommost control selected (»Figure 3.11«).


 Centering in the Dialog Box

To center controls in the dialog box:

1.	Select the control or controls you want to rearrange.

2.	Choose one of the following tools on the toolbar:

•	Center Vertical (CTRL+F9)

Controls are centered vertically in the dialog box.

•	Center Horizontal (SHIFT+CTRL+F9)

Controls are centered horizontally in the dialog box.


 Arranging Pushbuttons

To arrange pushbuttons along the right or bottom of the dialog box:

1.	Select one or more pushbuttons.

2.	From the Layout menu, choose Arrange Buttons, then choose Right or Bottom.

The selected buttons are positioned in a standard arrangement along the bottom or right side of the dialog box. If controls other than pushbuttons are selected, their position is not affected.


 Resizing Controls

You can resize a group of controls based on the size of the dominant control. You can also resize a control based on the dimensions of its caption text.

To make controls the same width, height, or size:

1.	Select the controls you want to resize.

2.	Make sure the correct dominant control is selected. The final size of the controls in the group depends on the size of the dominant control.

3.	Choose one of the following tools on the toolbar:

•	Make Same Width (CTRL+MINUS SIGN)

•	Make Same Height (CTRL+BACKSLASH)

•	Make Same Size (CTRL+EQUAL SIGN)


 Using Custom Controls

A custom control is a special-format dynamic-link library (DLL) or object file used to add additional features and functionality to the user interface of the Windows operating system. A custom control can be a variation on an existing Windows dialog-box control (for example, a text box suitable for use with Windows for Pen Computing) or a totally new category of control.

This includes the format of the custom-control examples in the Windows Software Development Kit (SDK) documentation.


 Working with User-Defined Controls

The App Studio control palette button for user-defined controls is [image]. App Studio user-defined controls let you use existing custom controls regardless of their format.

With user-defined controls, App Studio allows you to:

•	Set the location in the dialog box.

•	Enter a caption.

•	Identify the name of the control's Windows class (your application code must register the control by this name).

•	Type in a 32-bit hexadecimal value that sets the control's style.

When you are designing a dialog box that contains custom controls, the custom control displays as a gray square. In test mode the custom control also displays as a gray square, and its run-time behavior is not simulated.

To edit user-defined control properties:

1.	Select the control and move to the General property page.

2.	Enter or modify the information as appropriate.

For more information on user-defined control properties, see the »Property Page Reference,« Chapter 11, or choose the Property page Help button.


 Connecting to Program Code

App Studio makes it easy to create or update the connections between your user interface and the underlying program code. By using the Resource menu's ClassWizard command (or clicking the ClassWizard toolbar button [image]), you can:

•	Create a dialog-box class derived from the Microsoft Foundation CDialog class.

•	Define dialog box and control-message handlers (the dialog-box class's "message map").

•	Define class member functions that gather and validate the data entered in the dialog box.

For detailed information on using ClassWizard from within App Studio, see »Using ClassWizard«, Chapter 9.


 Creating a Form View

You can use App Studio to create a template that is used as a "form view," a CView-compatible window that contains dialog-box controls. An application that might need a form view is one in which the primary program function is data entry. In this case, the program's main view contains nothing but dialog-box controls for entering data.

To construct a form view, you create a dialog box as you normally would but set several style properties differently (see the following procedure). You then incorporate the form view into your program using the Microsoft Foundation Class Library CFormView class. You can use the same procedure to create a template for use with the CDialogBar class. For more information, see the Class Library Reference.

To create a dialog-box template for use with the CFormView or CDialogBar class:

1.	Use the dialog editor in the usual way to create a dialog-box template with the controls arranged as you want them to appear in the form view.

2.	Move to the Styles property page and set the following properties:

•	In the Style box, select Child from the list of choices.

•	In the Border box, select None from the list of choices.

•	Clear the Visible property.

3.	On the General property page, clear the dialog-box template's caption.

4.	Incorporate the template into your program using the CFormView class.


 Testing a Dialog Box

You can simulate the run-time behavior of a dialog box from within App Studio without compiling your program. This gives you immediate feedback on how the layout of controls appears and performs and thus speeds up the user-interface design process.

When you are in test mode you can:

•	Type in text, select from combo-box lists, turn options on and off, and choose commands.

•	Test the tab order.

•	Test the grouping of controls such as radio buttons or check boxes.

•	Test the dialog box's keyboard interface (controls that have mnemonic keys defined for them).

Note  Connections to dialog-box code made using ClassWizard are not simulated during dialog-box test mode.

When you test a dialog box, it is usually displayed at a location relative to the main App Studio program window. If the dialog box's Absolute Align property is selected, the dialog box is displayed at a position relative to the upper-left corner of the screen.

To test a dialog-box:

1.	On the dialog-editor toolbar, click the Test button [image], or from the Resource menu choose Test (CTRL+T).

2.	To end the test session, take one of the following actions:

•	Press ESC.

•	Close the dialog box using its control-menu box (ALT+F4).

•	Choose a pushbutton with a symbol name of IDOK or IDCANCEL.


Chapter 4: Using the Menu Editor
 Chapter 4  Using the Menu Editor

You can create and edit menus in App Studio by working directly with a menu bar that closely resembles the one in your finished application.

In addition, you can use the Visual C++ ClassWizard to hook menu items up to code. For more information on ClassWizard, see »Using ClassWizard«, Chapter 9.

»Figure 4.1« identifies the terms used to describe menu building in the procedures that follow.


 Working with Menus and Menu Items

This section contains procedures for the following menu editing tasks:

•	Creating a new menu resource or editing an existing one.

•	Creating menus and menu items.

•	Selecting menus and menu items.

•	Moving or copying menus and menu items.

•	Viewing the menu resource as a pop-up menu.


 Opening New or Existing Menu Resources

To create a new menu resource:

•	On the App Studio toolbar, click the New Menu button [image].

− Or −

•	In the resource browser window, click New, or from the Resource menu, choose New (CTRL+R). Then select Menu from the list of choices and click OK or press ENTER.

The menu editor window appears.

To edit an existing menu resource:

1.	Move to the resource browser window.

2.	In the Type box, select Menu.

A list of the menu resources in the current file appears in the Resources box.

3.	In the Resources box, select the menu resource you want to edit.

4.	Choose Open.

Or select the resource and press ENTER.

Or double-click the resource.

Or from the Resource menu, choose Open.

The menu editor window appears.


 Creating Menus or Menu Items

To create a drop-down menu on the menu bar:

1.	Click the new-item box (an empty rectangle) on the menu bar to select it (see »Figure 4.2«). You can also move to the new-item box with the TAB (move right) and SHIFT+TAB (move left) keys or the right and left arrow keys.

2.	Type the name of the menu. When you start typing, focus automatically shifts to the General property page, and the text you type appears both in the Caption box and in the menu editor window.

You can define a mnemonic key that allows the user to select the drop-down menu by typing an ALT plus a single letter. Use an ampersand (&) in front of the letter that represents the mnemonic character you wish to specify. Make sure all the mnemonics on a menu are unique.

Once you have given the menu a name on the menu bar, the new-item box shifts to the right, and another new-item box opens below for adding menu items.

Note  To create a single-item menu on the menu bar, clear the Popup option on the General property page.

To create a menu item:

1.	First create a drop-down menu according to the steps outlined in the previous procedure.

2.	Select the menu's new-item box.

− Or −

Select an existing menu item and press INS. The new-item box is inserted before the selected item.

3.	Type the name of the menu item. When you start typing, focus automatically shifts to the General property page, and the text you type appears in the Caption box.

You can define a mnemonic key that allows the user to select the menu command by typing a single letter. Use an ampersand in front of the letter that represents the mnemonic character you wish to specify. The mnemonic allows the user to select the menu command by typing that letter.

4.	In the ID box, type in the menu item ID, or select an existing command identifier.

5.	On the General property page, select the menu item styles that apply.

For information on what each menu item style means, see Chapter 11, »Property Page Reference,« or choose the Property page Help button.

6.	In the General property page's Prompt box, type the prompt string you want to appear in your application's status bar. This feature is only available with Microsoft Foundation Class Library resource script (.RC) files.

This creates an entry in the string table with the same resource identifier as the menu item you created.

7.	Press ENTER to complete the menu item. The new-item box is selected so you can create additional menu items.

To create a cascading (hierarchical) menu:

1.	Select the new-item box on the drop-down menu where you want the cascading menu to appear. Then type the name of the menu item that, when selected, causes the cascading menu to appear.

− Or −

Select an existing menu item that you want to be the parent item of the cascading menu.

2.	On the General property page, select the Popup check box. The menu item is marked with the cascading menu symbol ( [image]), and a new-item box appears to the right.

3.	Add additional menu items to the cascading menu according to the instructions in the previous procedure.


 Selecting Menus or Menu Items

To select a drop-down or cascading menu and display its menu items:

•	Click the menu caption on the menu bar or the parent item of the cascading menu. Then click the menu item you want.

− Or −

•	Move to the menu caption with the TAB (move right) and SHIFT+TAB (move left) keys or the right and left arrow keys.

To select one or more menu items:

1.	Click the drop-down or cascading menu you want.

Its menu items are displayed.

2.	Click to select a menu item, or hold down the SHIFT key to select multiple menu items. Holding down the SHIFT key and clicking an already-selected menu item deselects it.

− Or −

With the mouse pointer outside the menu, hold down the left mouse button and draw a selection box around the menu items you want to select.


 Moving and Copying Menus or Menu Items

Using the App Studio menu editor you can:

•	Move or copy menus or menu items.

•	Move cascading menus to the menu bar.

•	Make a drop-down menu cascading.

The simplest way to edit a menu resource is to use the drag and drop method described in »Directly Manipulating User-Interface Objects,« Chapter 1. You can also use the Cut, Copy, and Paste commands on the App Studio Edit menu.

To move or copy drop-down menus or menu items using drag and drop:

1.	Drag (or to copy, hold down the CTRL key and drag) the item you want to:

•	A new location in the current menu.

•	A different menu. (You can navigate into other menus by dragging the mouse cursor over them.)

2.	Drop the menu item when the insertion guide (see »Figure 4.3«) shows the position you want.

To move or copy menus or menu items using the App Studio Edit menu:

1.	Select one or more menus or menu items.

2.	From the Edit menu, choose Cut (to move) or Copy (to copy) the objects. You can also use the keyboard shortcuts for Cut (CTRL+X or SHIFT+DEL) and Copy (CTRL+C or SHIFT+INS).

3.	If you are moving the items to another menu resource or resource script file, make that menu editor window active.

4.	Select the menu or menu item you want. The moved or copied item is placed before the item you select.

5.	From the Edit menu, choose Paste.


 Viewing the Menu Resource as a Drop-down Menu

Normally, when you are working in the menu editor, a menu resource is displayed as a menu bar with top-level menu items and drop-down menus. However, you may want to store a single menu as a separate menu resource so you can add it as a drop-down menu to your application's main menu bar while the program is running. To see what the separate menu resource looks like as a drop-down menu, use the menu editor's View as Popup command.

To view a menu resource as a drop-down menu:

•	From the Resource menu, choose View as Popup (CTRL+U).

To change back to the menu-bar view, choose View as Popup (CTRL+U) again.


 Associating a Menu Item with an Accelerator Key

Many times you want a menu item and a keyboard combination to issue the same program command. You do this by assigning the same resource identifier to the menu item and to an entry in your application's accelerator table. You then edit the menu item's caption to show the name of the accelerator key.

To associate a menu item with an accelerator key:

1.	In the menu editor, select the menu item you want and move to the General property page.

2.	In the ID box, give the menu item a descriptive command identifier (for example, ID_FILE_OPEN).

3.	In the Caption box, add the name of the accelerator key to the menu caption:

•	Following the menu caption, type the escape sequence for the TAB key (\t), so that all the menu's accelerator keys are left-aligned.

•	Type the name of the modifier key (CTRL, ALT, or SHIFT) followed by a plus sign and the name, letter, or symbol of the additional key.

For example, if you assign CTRL+O to the File menu's Open command, you modify the menu's caption so that it looks like this:

Open\tCtrl+O

The menu item in the menu editor is updated to reflect the new caption as you type it.

4.	Create the accelerator-table entry and assign it the same identifier as the menu item. Use a key combination that you think will be easy to remember.

See »Using the Accelerator Table Editor« for more information on creating and naming accelerator resources.


Chapter 5: Using the Accelerator Table Editor
 Chapter 5  Using the Accelerator Table Editor

An accelerator table is a Windows resource that contains a list of accelerator keys (also known as shortcut keys) and the command identifiers that are associated with them. A program can have more than one accelerator table.

Normally accelerators are used as keyboard shortcuts for program commands that are also available on a menu or toolbar. However, you can use the accelerator table to define key combinations for commands that don't have a user-interface object associated with them.

You can use Visual C++ ClassWizard to hook accelerator key commands to code. For more information on ClassWizard, see »Using ClassWizard«, Chapter 9.

In this chapter, you'll see how to use the accelerator table editor to:

•	Add, delete, change, or browse the accelerator key assignments in your project.

•	View and change the resource identifier associated with each entry in the accelerator table. The identifier is used to reference each accelerator table entry in program code.

•	Associate an accelerator key with a menu item.


 Opening a New or Existing Accelerator Table

You can call up the accelerator table editor to edit an existing accelerator table or create a new one.

To create a new accelerator table:

•	On the App Studio toolbar, click the New Accelerator Table button [image].

− Or −

•	In the resource browser window, click New, or from the Resource menu, choose New (CTRL+R). Then select Accelerator from the list of choices and click OK or press ENTER.

The accelerator table editor window appears.

Note  Windows does not allow the creation of empty accelerator tables. If you create an accelerator table with no entries, it is deleted automatically when you exit App Studio.

To edit an existing accelerator table:

1.	Move to the resource browser window.

2.	In the Type box, select Accelerator.

A list of the accelerator tables in the current file appears in the Resources box.

3.	In the Resources box, select the accelerator table you want to edit.

4.	Choose Open.

Or select the resource and press ENTER.

Or double-click the resource.

Or from the Resource menu, choose Open.

The accelerator table editor window appears.


 Editing the Accelerator Table

When you edit an existing accelerator table or create a new one, the accelerator table editor window appears. Use the accelerator-table window to browse existing accelerator keys, to delete keys, or to select the new-item box (an empty rectangle) at the end of the list. Move to the accelerator-table property page to edit or define values for each accelerator-table entry.

»Figure 5.1« shows the process of working with individual accelerator-table entries.

To add an entry to the accelerator table:

1.	Select the new-item box at the end of the list, or from the Resource menu, choose New Accelerator (INS).

2.	Move to the General property page to define the key. (Pressing INS, or typing the key name with the new-item box selected, moves you to the Properties window automatically.)

Note  Make sure all accelerators you define are unique. When duplicate accelerator keys are assigned, only the first one works correctly.

To delete an entry from the accelerator table:

1.	Select the entry you want to delete. Use the CTRL or SHIFT keys to select multiple entries.

2.	Choose Delete at the bottom of the accelerator table editor window, or from the Edit menu, choose Delete (DEL).

To move or copy an accelerator-table entry from one resource script file to another:

1.	Open the accelerator table editor windows in both resource script files.

2.	Use the drag and drop method described in »Directly Manipulating User-Interface Objects«, Chapter 1.

− Or −

Use the Edit menu's Copy (or Cut) and Paste commands.

Note  You can also use the CTRL key with drag and drop, or use the Edit menu, to copy keys within an accelerator table. However, exercise caution when doing so as this creates duplicate accelerator keys. App Studio does not prompt you to resolve accelerator key conflicts.


 Editing Accelerator Properties

Use the accelerator table's General property page (»Figure 5.2«) to edit the values for each accelerator.

An accelerator can be either an ASCII value or virtual key. A virtual key is a device-independent identifier. The Key box on the General property page contains a list of standard virtual key identifiers.

To define or change the values for an accelerator-table entry:

1.	Select the entry you want to define or change.

2.	Move to the General property page.

3.	In the Key box, type the name of the key, or choose from the list of virtual key identifiers. Select additional options as appropriate under Modifiers (CTRL, ALT, or SHIFT) and Type (ASCII or VirtKey [virtual key]). When first created, a new key has the CTRL modifier selected.

 − Or−

Choose Next Key Typed and then type the key or key combination you want to enter. The Key box and the options under Modifiers and Type are updated automatically.

Note  Accelerator values entered using the Next Key Typed command are always entered as virtual keys, if possible.


 Typing in Accelerator Values

The following are legal entries in the Key box of an accelerator table's General property page:

•	An integer between 0 and 255 in decimal, hexadecimal, or octal format. The setting of the Type property determines if the number is an ASCII or virtual key value.

Single-digit numbers are always interpreted as the corresponding key, rather than as ASCII values. To enter an ASCII value from 0 to 9, precede it with two zeros (for example, 006).

•	A single keyboard character. Uppercase A-Z or the numbers 0 through 9 can be either ASCII or virtual key values; any other character is ASCII only.

•	A single keyboard character in the range A-Z (uppercase only), preceded by a caret (^) — for example, ^C. This enters the ASCII value of the key when it is pressed with the CTRL key held down.

Note  When entering an ASCII value, the CTRL and SHIFT modifiers on the General property page are not available. You cannot use a control-key combination entered with a caret to create a virtual accelerator key.

•	Any valid virtual key identifier. The Key box on the General property page contains a list of standard virtual key identifiers.


 Associating a Menu Item with an Accelerator Key

Many times you want a menu item and a keyboard combination to issue the same program command. You do this by assigning the same resource identifier to the menu item and to an entry in your application's accelerator table. You then edit the menu item's caption to show the name of the accelerator.

To associate a menu item with an accelerator key:

1.	In the menu editor (see »Using the Menu Editor«, Chapter 4), select the menu item you want and move to the General property page.

2.	In the ID box, give the menu item a descriptive command identifier (for example, ID_FILE_OPEN).

3.	In the Caption box, add the name of the accelerator key to the menu caption:

•	Following the menu caption, type the escape sequence for the TAB key (\t), so that all the menu's accelerator keys are left-aligned.

•	Type the name of the modifier key (CTRL, ALT, or SHIFT) followed by a plus sign and the name, letter, or symbol of the additional key.

For example, if you assign CTRL+O to the File menu's Open command, you modify the menu's caption so that it looks like this:

Open\tCtrl+O

The menu item in the menu editor is updated to reflect the new caption as you type it.

4.	Create the accelerator-table entry and assign it the same identifier as the menu item. Use a key combination that you think will be easy to remember.


Chapter 6: Using the String Editor
 Chapter 6  Using the String Editor

The App Studio string editor is a window and its associated property page that allow you to edit or add to a program's standard Windows string table resource.

In this chapter, you'll see how to use the string editor to:

•	Create a new string table.

•	View the string segments in a program.

•	Add or delete individual strings, or move them from one segment to another.

•	Change a string, or its name or value.


 String Tables

In programming for Windows, strings can be stored in a resource type called a string table. An application can have only one string table.

In a string table, strings are grouped into segments, or blocks, of 16 strings each. The segment a string belongs to is determined by the value of its identifier; for example, strings with identifiers of 0 to 15 are in one segment, strings with values of 16 to 31 are in a second segment, and so on. Thus, to move a string from one segment to another you need to change its identifier.

Individual string segments are loaded on demand in order to conserve memory. For this reason, programmers usually try to group strings into logical groupings of sixteen or less and then to use each group or segment only when it's needed.


 Opening a New or Existing String Table

You use App Studio to create your application's string table or use the string editor to edit an existing one.

To create a new string table:

•	On the App Studio toolbar, click the String Table button.

− Or −

•	In the resource browser window, click New, or from the Resource menu, choose New (CTRL+R). Then select String from the list of choices and click OK or press ENTER.

The string editor window appears.

Note  Windows does not allow the creation of empty string tables. If you create a string table with no entries, it is deleted automatically when you exit App Studio.

Once you create your application's string table, you can use the App Studio resource browser window to view a list of string segments in the string table and to jump to the beginning of a selected segment. »Figure 6.1« shows this process.

To open an existing string table for editing:

1.	Move to the resource browser window.

2.	In the Type box, select String Table.

A list of the string segments in your application's string table appears.

3.	In the Resources box, select the string segment you want to edit.

Selecting a specific segment of the string table allows you to easily jump to a specific group of strings. However, opening the string editor gives you access to the entire string table.

4.	Choose Open.

Or select the resource and press ENTER.

Or double-click the resource.

Or from the Resource menu, choose Open.

The string editor window appears.


 Editing the String Table

The string editor includes a Find command to let you quickly locate strings in the string table by either their caption or resource identifier.

To find a string in the string table:

1.	Open the string table by selecting it in the Type box of the resource browser window and then clicking any of the segments listed in the Resources box.

2.	At the bottom of the string editor window, choose Find.

The Find String dialog appears.

3.	In the Find What box, type the caption text or resource identifier of the string you want to find. Set or clear the Match Case option as appropriate.

4.	Press ENTER.

If a string or its identifier in the string table matches what you typed, it is selected.

Once the string editor window is displayed, you can add or delete entries in the string table. String table segments are separated by a horizontal line in the string editor window.

To add a string-table entry:

1.	Select the new-item box (an empty rectangle) at the end of a string segment.

2.	Type the new string.

Focus shifts to the Properties window as you start typing, and the string is given the next identifier in sequence.

− Or −

1.	Select an existing entry in the string table.

2.	Choose the New command at the bottom of the string editor window, or from the Resource menu, choose New String (INS).

A new string is created and given the next available identifier after the currently selected string.

3.	Type the new string.

Note  Null strings are not allowed in Windows string tables. If you create an entry in the string table that is a null string, the entry is deleted when you close the string editor.

To delete a string in the string editor:

1.	Select the string you want to delete.

2.	Choose Delete at the bottom of the string editor window, or from the Edit menu, choose Delete (DEL).

To move a string from one segment to another:

1.	Select the string you want to move.

2.	Move to the General property page. In the ID box, change the string's value so that it falls in the range you want.

For example, to move a string with a name of IDS_MYSTRING and a value of 100 to a segment in the 200 range, type the following in the ID box:

IDS_MYSTRING=201

3.	Press ENTER to record the change.

To move a string from one resource script (.RC) file to another:

1.	Open the string editor windows in both resource script files.

2.	Use the drag and drop method described in Chapter 1»Directly Manipulating User-Interface Objects«.

− Or −

Use the File menu's Cut and Paste commands.

Note  If the moved string's symbol name or value conflicts with an existing identifier in the destination file, the symbol name is changed (if a symbol by that name already exists) or the symbol value is changed (if a symbol with that value already exists).


Editing a Strings Properties
 Editing a String's Properties

To change a string or its identifier:

1.	Select the string you want to edit.

2.	Move to the string's General property page.

3.	In the Caption box, modify the string itself.

In the ID box, modify the string's identifier:

•	Type in a new symbol name or choose one from the list.

•	Change a string's value by typing the symbol name followed by an equal sign and the new value; for example

IDS_ERROR_MSG=2350

For more information on editing symbols, see Chapter 2,» Working With Files and Symbols«.

To add formatting or special characters to a string:

•	Use the standard escape sequences shown in Table 6.1.

Table 6.1    Formatting and Special Characters in Strings

To Get This:	Type This:
New line	\n (or press CTRL+ENTER when typing in the string)
Carriage return	\r
Tab	\t (or press CTRL+TAB when typing the string)
Backslash (\)	\\
ASCII character	\ddd (octal notation)
Alert (bell)	\a


Chapter 7: Using the Graphics Editor
 Chapter 7  Using the Graphics Editor

The App Studio graphics editor has a rich set of tools for drawing bitmaps, icons and cursors, as well as features to support the creation of toolbar bitmaps and the management of icon and cursor images.

With the graphics editor, you can:

•	Create and edit bitmaps in 2 or 16 colors, in sizes up to 999 x 999 pixels.

•	Use a full complement of drawing tools.

•	Easily copy images from one bitmap to another.

•	Use custom brushes for special effects.

•	Draw cursors and icons with transparent and inverse-color regions.

•	Edit bitmaps for toolbar buttons.

Most editing procedures are the same for bitmaps, icons, and cursors. This chapter first shows the procedures common to all graphical resources. Later sections detail procedures and graphics-editor capabilities specific to icons, cursors, and toolbar-button images.

Note  Many of the graphics editor's functions require a mouse or other pointing device.


 Windows and Tools for Editing Graphics

You edit bitmaps, icons, and cursors in App Studio's image editor window, using the tools on the graphics palette (»Figure 7.1«).


 The Image Editor Window

The image editor window shows two views of an image. A splitter separates the two panes. You can drag the splitter from side to side to change the relative sizes of the panes. The active pane displays a selection border, as shown in »Figure 7.1«.


 The Graphics Palette

The graphics palette has four parts, which are shown in »Figure 7.1«:

•	The toolbox, which contains 15 tools for drawing, painting, erasing, and manipulating views

•	The color indicator, which shows the foreground and background colors and (for icons and cursors) selectors for "screen" and "inverse" color

•	The color palette, which you click to select the foreground and background colors

•	The option selector, which you click to select brush widths and other drawing options

To use the toolbox, color palette, and option selector, you click the desired tool, color, or option.


 The Status Bar

The Status bar, at the bottom of the App Studio frame window, displays two panes when an image editor window is open. When the mouse cursor is over an image, the left pane shows the cursor's current position, in pixels, relative to the upper-left corner of the image. During a dragging operation such as selecting, moving, or drawing a rectangle, the right pane shows the size, in pixels, of the affected area.


 The Image Menu

The Image menu, which appears only when the graphics editor is active, has commands for editing images, managing color palettes, and setting image editor window options.


 Editing Graphical Resources

You need to know just a few fundamental editing operations — creating bitmaps, drawing, copying, and so on — to use the graphics editor. This section describes these graphics-editing tasks:

•	Creating a new bitmap, icon, or cursor, or editing an existing one

•	Setting bitmap properties

•	Drawing and painting

•	Cutting, copying, clearing, and moving selected parts of a bitmap

You can also import existing bitmaps, icons, and cursors and add them to your project, and you can open files that are not part of a project for "stand-alone" editing. See Chapter 2, »Working with Files and Symbols,« for more information on importing resources.

Note  Most graphics-editor operations are the same for all kinds of graphical resources. Unless the text states otherwise, the procedures described in this section can be performed on bitmaps, cursors, or icons.


 Opening New or Existing Graphical Resources

New graphical resources are always added to the current resource script, executable, dynamic-link library, or other file. If more than one file is open, before you create the bitmap, click the resource browser window of the file to which you want to add the new bitmap.

To create a new graphical resource:

•	On the App Studio toolbar, click the button for the resource you want to create:

•	The bitmap button

•	The cursor button

•	The icon button

− Or −

•	In the resource browser window, click New, or from the Resource menu, choose New (CTRL+R). Then select Bitmap, Icon, or Cursor from the list of choices and click OK or press ENTER.

The image editor window appears.

To create a new graphical resource for stand-alone editing:

1.	From the File menu, choose New (CTRL+N).

2.	From the New dialog box, choose Bitmap, Icon, or Cursor.

3.	Choose OK.

The image editor window appears.

To open an existing graphical resource for stand-alone editing:

1.	From the File menu, choose Open (CTRL+O). The Open dialog box appears.

2.	Use the Open dialog box to navigate directories and choose a file name.

To edit an existing graphical resource:

1.	Move to the resource browser window.

2.	In the Type box, select Bitmap, Icon, or Cursor.

A list of the resources in the current file appears in the Resources box.

3.	In the Resources box, select the bitmap resource you want to edit.

4.	Choose Open.

The image editor window appears.

Tip  The Properties window displays a thumbnail view of each graphical resource as you select its entry in the Resources box. To browse through the bitmaps in the file you are working on, select the first bitmap and then press the DOWN arrow key until the desired bitmap appears.


 Setting Properties

You use the Properties window to change most resource properties. Exceptions are the Width, Height, and Colors properties of icons and cursors, which you change by editing the Registry (see »Editing Device Descriptions«) and the cursor's hotspot (see »Setting a Cursor's Hotspot«).

To change a bitmap's properties:

1.	Select the bitmap whose properties you want to change.

2.	Activate the General property page by pressing ENTER or clicking the Properties window.

3.	Change any or all of these properties:

•	In the ID box, modify the resources's identifier. For a bitmap, App Studio by default assigns the next available identifier in a series: IDB_BITMAP1, IDB_BITMAP2, and so forth. Similar names are used for icons and cursors.

•	In the Width and Height boxes, modify the bitmap's width and height (in pixels). The default value for each is 48.

If you change the dimensions of a bitmap using the General property page, the image is cropped or "blank" space is added to the right of or below the existing image.

•	In the Colors list box, select Monochrome or 16. If you have already drawn the bitmap with a 16-color palette, selecting Monochrome causes App Studio to substitute black and white for the colors in the bitmap. Contrast is not always maintained: for example, adjacent areas of red and green are both converted to black.

•	In the Filename box, modify the name of the file in which the bitmap is to be stored. By default, App Studio assigns a base file name created by removing the first four characters ("IDB_") from the default identifier and adding the extension .BMP.

•	Check the Save Compressed check box to cause App Studio to save the bitmap in a compressed format.


 Drawing and Painting

You access most of the graphics editor's drawing tools either by clicking icons on the graphics palette or by entering keyboard commands. More advanced drawing operations, such as creating custom brushes, can be performed only from the keyboard. App Studio's keyboard commands are listed in the »App Studio Quick Reference«, Chapter 10.


 Showing and Hiding the Graphics Palette

Since many of the drawing tools are available from the keyboard, sometimes it is useful to hide the graphics palette.

To show or hide the graphics palette:

•	Press F2.


 Selecting Foreground and Background Colors

Except for the eraser, these tools draw with the current foreground or background color when you press the left or right mouse button, respectively.

To select a foreground color:

•	With the left mouse button, click the desired color on the color palette.

To select a background color:

•	With the right mouse button, click the desired color on the color palette.


 Freehand Drawing and Erasing

The graphics editor's freehand drawing and erasing tools all work in the same way: you select the tool and, if necessary, select foreground and background colors and size and shape options. You then move the cursor to the bitmap and click or drag to draw and erase.

When you have selected the eraser tool, brush tool, or airbrush tool, the option selector displays that tool's options.

Tip  Instead of using the eraser tool, you may find it more convenient to draw in the background color with one of the drawing tools.

To select and use a drawing tool:

1.	Click a button on the toolbox:

•	The eraser tool (SHIFT+P) [image], which "paints over" the image with the current background color when you press the left mouse button and replaces the current foreground color with the current background color when you press the right mouse button.

•	The pencil tool (P) [image], which draws freehand in a constant width of one pixel.

•	The brush tool (D) [image], whose shape and size are determined by the option selector.

•	The airbrush tool (A) [image], which randomly distributes color pixels around the center of the brush.

2.	If necessary, select colors and a brush:

•	In the color palette, click with the left button to select a foreground color or with the right button to select a background color.

•	In the option selector, click a shape representing the brush you want to use. Your selection is highlighted.

3.	Move the cursor to the place on the bitmap where you want to start drawing or painting. The brush or cursor appears on the bitmap.

4.	Press the left mouse button (for the foreground color) or the right mouse button (for the background color), and hold it down as you draw.

5.	Release the mouse button.

To resize the brush tool or eraser tool to a single pixel:

•	Press the PERIOD key.

To change the size of the brush, airbrush, or eraser:

•	Press the PLUS SIGN key to increase the size or the MINUS SIGN key to decrease it.

− Or −

•	Press PERIOD to choose the smallest size.

− Or −

•	Choose a brush in the option selector.


 Drawing Lines and Closed Figures

App Studio's tools for drawing lines and closed figures all work in the same way: you put the cursor at one point and drag to another. For lines, these points are the endpoints. For closed figures, these points are opposite corners of a rectangle bounding the figure.

Lines are drawn in a width determined by the current brush selection, and framed figures are drawn in a width determined by the current width selection. Lines and all figures, both framed and filled, are drawn in the current foreground color if you press the left mouse button or in the current background color if you press the right mouse button.

To draw a line:

1.	From the toolbox, select the line tool (L) [image].

2.	If necessary, select colors: in the color palette, click with the left button to select a foreground color or with the right button to select a background color.

3.	If necessary, select a brush: in the option selector, click a shape representing the brush you want to use. Your selection is highlighted.

4.	Place the cursor at the line's starting point.

5.	Drag the cursor to the line's endpoint.

6.	Release the mouse button.

To draw a closed figure:

1.	From the toolbox, select a closed-figure drawing tool:

•	The framed-rectangle tool (R) [image], which draws a rectangle framed with the foreground or background color.

•	The filled-rectangle tool (SHIFT+R) [image], which draws a rectangle filled with the foreground or background color.

•	The framed-round-rectangle tool (N) [image], which draws a rectangle with rounded corners framed with the foreground or background color.

•	The filled-round-rectangle tool (SHIFT+N) [image], which draws a rectangle with rounded corners filled with the foreground or background color.

•	The framed-ellipse tool (E) [image], which draws an ellipse framed with the foreground or background color.

•	The filled-ellipse tool (SHIFT+E) [image], which draws an ellipse filled with the foreground or background color.

2.	If necessary, select colors: in the color palette, click with the left button to select a foreground color or with the right button to select a background color.

3.	If necessary, select a line width: in the option selector, click a shape representing the brush you want to use. A rectangle appears around the option you have selected.

4.	Move the cursor to one corner of the rectangular area in which you want to draw the figure.

5.	Drag to the diagonally opposite corner.

6.	Release the mouse button.


 Filling Bounded Areas

The graphics editor provides the fill (or "paint-bucket") tool for filling any enclosed bitmap area with the current drawing color or the current background color.

To use the fill tool:

1.	From the toolbox, choose the fill tool (F) [image].

2.	If necessary, choose drawing colors: in the color palette, click with the left button to select a foreground color or with the right button to select a background color.

3.	Move the fill tool to the area you want to fill.

4.	Click the left or right mouse button to fill with the foreground color or the background color, respectively.


 Picking Up Colors

The color-pickup tool makes any color on the bitmap the current foreground color or background color, depending on whether you press the left or the right mouse button.

To pick up a color:

1.	From the toolbox, select the color-pickup tool (COMMA) [image].

The cursor changes to the "eyedropper."

2.	Click the bitmap area containing the color you want to pick up:

•	Left mouse button for the foreground color

•	Right mouse button for the background color

After you pick up a color, the graphics editor reactivates the most recent tool you used before the color-pickup tool.

To cancel the color-pickup tool:

•	Choose another tool or press ESC.


 Using the Selection Tool

The selection tool defines an area of the bitmap that you can cut, copy, clear, resize, invert, or move. You can also create a custom brush from the selection (see »Using the Selection Tool«).

To select an area of the bitmap:

1.	In the toolbox, click the selection tool (S) [image].

2.	Move the cursor to one corner of the bitmap area that you want to select. Cross hairs appear when the cursor is over the bitmap, as shown in »Figure 7.2«.

3.	Drag the cursor to the opposite corner of the area you want to select. A rectangle shows which pixels will be selected. All pixels within the rectangle, including those "under" the rectangle, are included in the selection.

4.	Release the button. The "selection border" — a rectangular frame — encloses the selected area, as in »Figure 7.3«. Now any operation you perform will affect only the pixels within the rectangle.

To select the entire bitmap:

•	Click the bitmap outside the current selection.

− Or −

•	Press ESC.

− Or −

•	Choose another tool in the toolbox.


 Cutting, Copying, Clearing, and Moving

You can perform standard editing operations — cutting, copying, clearing, and moving — with the selection, whether the selection is the entire bitmap or just a part of it. Because the graphics editor uses the Windows Clipboard, you can transfer images between App Studio and other applications for Windows, such as Microsoft Paintbrush™ and Microsoft Word for Windows.

In addition, you can resize the selection, whether it includes the entire bitmap or just a part (see »Resizing a Bitmap«).

To cut the current selection and copy it to the Clipboard:

•	From the Edit menu, choose Cut (CTRL+X).

The original area of the selection is filled with the current background color, and the selection is now in the Clipboard.

To clear the current selection without copying it to the Clipboard:

•	From the Edit menu, choose Clear (DEL).

The original area of the selection is filled with the current background color.

To paste the Clipboard contents into the bitmap:

1.	From the Edit menu, choose Paste (CTRL+V).

The Clipboard contents, surrounded by the selection border, appear in the upper-left corner of the pane.

2.	Position the cursor within the selection border and drag the Clipboard contents to the desired location on the bitmap.

3.	To copy the Clipboard contents into the bitmap at the desired location, click outside of the selection border or choose a new tool.

To move the selection:

1.	Position the cursor inside the selection border or anywhere on it except the sizing handles.

2.	Drag the selection to its new location.

The original area of the selection is filled with the current background color.

3.	To anchor the selection in the bitmap at its new location, click outside the selection border or choose a new tool.

To copy the selection:

1.	Position the cursor inside the selection border or anywhere on it except the sizing handles.

2.	Hold down the CTRL key as you drag the selection to a new location.

The area of the original selection is unchanged.

3.	To copy the selection into the bitmap at its current location, click outside the selection cursor or choose a new tool.

To draw with the selection:

1.	Position the cursor inside the selection border or anywhere on it except the sizing handles.

2.	Hold down the SHIFT key as you drag the selection.

Copies of the selection are left along the dragging path. The more slowly you drag, the more copies are made.


 Choosing Opaque and Transparent Backgrounds

When you move or copy a selection, any pixels in the selection that match the current background color are by default "transparent": they do not obscure pixels in the target location. (A custom brush behaves the same way. See »Creating a Custom Brush.«)

To toggle the background-color transparency:

•	Press O.

− Or −

•	In the option selector, click the appropriate button:

•	Opaque background [image]: existing image is obscured by all parts of the selection.

•	Transparent background [image]: existing image shows through parts of the selection that match the current background color.

You can change the background color while a selection is already in effect to change which parts of the image are transparent.


 Flipping the Selection

To flip the selection along the horizontal axis:

•	From the Image menu, choose Flip Horizontal (X).

To flip the selection along the vertical axis:

•	From the Image menu, choose Flip Vertical (Y).


 Inverting Colors

So that you can tell how a bitmap will appear with inverted colors, App Studio provides a convenient way to invert colors in the selected part of the bitmap.

To invert colors in the current selection:

•	From the Image menu, choose Invert Colors.


 Creating a Custom Brush

A custom brush is a rectangular portion of a bitmap that you "pick up" and use like one of the graphics editor's ready-made brushes. All operations you can perform on a selection, you can perform on a custom brush as well.

To create a custom brush:

1.	Select the part of the bitmap that you want to use for a brush (see the head of this topic).

2.	Press CTRL+B.

Pixels in a custom brush that match the current background color are normally "transparent": they do not paint over the existing image. You can change this behavior so that background-color pixels paint over the existing image.

You can use the custom brush like a "stamp" or a "stencil" to create a variety of special effects.

To draw custom-brush shapes in the background color:

1.	Select an opaque or transparent background (see »Choosing Opaque and Transparent Backgrounds«).

2.	Set the background color to the color in which you want to draw.

3.	Position the custom brush where you want to draw.

4.	Press the right mouse button.

Any opaque regions of the custom brush are drawn in the background color.

To double or halve the custom-brush size:

•	Press PLUS to double the brush size, or MINUS to halve it.

To cancel the custom brush:

•	Press ESC or choose another drawing tool.


 Resizing a Bitmap

App Studio's behavior in resizing a bitmap depends on whether the selection includes the entire bitmap or just part of it:

•	When the selection includes only a part of the bitmap, App Studio shrinks the selection by deleting rows or columns of pixels and filling the vacated regions with the current background color, or it stretches the selection by duplicating rows or columns of pixels.

•	When the selection includes the entire bitmap, App Studio either shrinks and stretches the bitmap, or crops and extends it.

See »Figure 7.4« for illustrations of cropping, extending, shrinking, and stretching.

There are two ways to resize the bitmap: the resizing handles and the Properties window. You drag the sizing handles to change the size of all or part of a bitmap. Sizing handles that you can drag are solid, like those on the lower right corner and the midpoints of the right and bottom sides of the bitmaps in »Figure 7.4«. You cannot drag handles that are hollow. You can use the Properties window to resize only the entire bitmap, not a selected part.

To crop or extend an entire bitmap:

1.	Select the entire bitmap.

If a part of the bitmap is currently selected and you want to select the entire bitmap, click anywhere on the bitmap outside the current selection border, press ESC, or choose another drawing tool.

2.	Drag a sizing handle until the bitmap is the desired size.

Normally, App Studio crops or enlarges a bitmap when you resize it by moving a sizing handle. If you hold down the SHIFT key as you move a sizing handle, App Studio shrinks or stretches the bitmap.

To shrink or stretch an entire bitmap:

1.	Select the entire bitmap.

If a part of the bitmap is currently selected and you want to select the entire bitmap, click anywhere on the bitmap outside the current selection border, press ESC, or choose another drawing tool.

2.	Hold down the SHIFT key and drag a sizing handle until the bitmap is the desired size.

To shrink or stretch part of a bitmap:

1.	Select the part of the bitmap you want to resize (see »Using the Selection Tool«).

2.	Drag one of the sizing handles until the selection is the desired size.

To resize an entire bitmap using the Properties window:

1.	Click the Properties window to activate it.

2.	Type the desired dimensions in the Width and Height boxes.

If you are increasing the size of the bitmap, App Studio extends the bitmap to the right or downward, or both, and fills the new region with the current background color. The image is not stretched.

If you are decreasing the size of the bitmap, App Studio crops the bitmap on the right or bottom edge, or both.

You can use the Width and Height properties only to resize the entire bitmap, not to resize a partial selection.


 Changing the Number of Colors in a Bitmap

When you increase the number of colors in a bitmap, the image does not change but you can then add more colors.

To change the number of colors in a bitmap:

1.	Click the Properties window to activate it.

2.	Choose the appropriate setting in the Colors combo box.


 Managing the Graphics-Editor Workspace

By adjusting the graphics-editor workspace to fit your needs and preferences, you can work more effectively and comfortably. This section describes procedures for:

•	Selecting and sizing image-editor panes

•	Changing the magnification of image editor windows

•	Displaying and hiding pixel grids


 Using Image-Editor Panes

Normally the image editor window displays a bitmap in two panes separated by a splitter. One view is actual size, and the other is enlarged (the default enlargement factor is 6). The views in these two panes are updated automatically: changes you make in one pane are immediately shown in the other. The two panes make it easy for you to work on an enlarged "picture" of your bitmap, in which you can distinguish individual pixels and, at the same time, observe the effect of your work on the actual-size view of the image.

If the bitmap is 200 x 200 pixels or larger, however, only one pane is displayed initially. Move the splitter to display both panes.

You can use the two panes in other ways. For example, you might enlarge the smaller pane and use the two panes to show different regions of a large bitmap.

You move the splitter to change the relative sizes of the panes. The splitter can move all the way to either side if you want to work on only one pane.


 Selecting Panes

To select an image-editor pane:

•	Press TAB or F6, or click anywhere on the pane. The selection border then shows that the pane is active.


 Sizing Image-Editor Panes

To size the image-editor panes:

1.	Position the cursor on the splitter.

The cursor turns into a two-headed arrow (see »Figure 7.5«).

2.	Drag the splitter to the right or to the left.


 Zooming In and Out

By default, the graphics editor displays the view in the left pane at actual size and the view in the right pane at 6 times actual size. There are several ways to change the magnification factor — the ratio between actual and displayed size — of the image you are editing and to toggle between an actual-size view and an enlarged view:

•	The Zoom tool lets you select a magnification factor and choose in advance the portion of the image that appears in the "zoomed" view.

•	Zoom In/Out on the Image menu toggles between the enlarged view and the actual-size view.

•	Zoom Under Cursor, available from the keyboard only, centers the part of the image that is under the mouse cursor in the image-editor pane.

To zoom in or out on an image-editor pane:

1.	On the toolbox, click the Zoom tool (Z)  [image].

2.	Position the mouse cursor over the pane you want to zoom in or out.

If you are zooming in on an actual-size view and the magnified view will not fit in the pane, a tracking rectangle shows the part of the bitmap that will appear in the magnified view (see »Figure 7.6«). Position the tracking rectangle over the area you want to view.

3.	Click the pane you want to zoom in or out.

If you have used the Zoom Decrease or Zoom Increase command (see »Changing the Magnification Factor«) to change the zoom factor for the active pane, the current factor is used. Otherwise the default factor of 6 is used.

To zoom in on the part of the image under the cursor:

1.	Position the mouse cursor on the point that you want to have centered in the zoomed view.

2.	Press M.

To toggle the magnification factor:

•	Press M.


 Changing the Magnification Factor

The magnification factor is the ratio between actual size of the bitmap and the displayed size. The default is 6, and the range is from 1 to 10.

To change the magnification factor:

1.	Select the image-editor pane whose magnification factor you want to change.

2.	On the toolbox, choose the Zoom tool (Z) [image].

The cursor changes to the Zoom tool, and magnification-factor options appear in the option selector. If the current magnification factor matches an option, that option is highlighted.

3.	Click the desired magnification factor.

− Or −

1.	Select the image-editor pane whose magnification factor you want to change.

2.	Press > (SHIFT+PERIOD) to increase the magnification factor, or < (SHIFT+COMMA) to decrease the magnification factor.


 Displaying and Hiding the Pixel Grid

For all image-editor panes with a magnification factor of 4 or greater, you can display a grid that delimits the individual pixels in the image (see »Changing the Magnification Factor«).

To display or hide the pixel grid:

1.	From the Image menu, choose Grid Settings.

2.	In the Grid Settings dialog box, check the Pixel Grid box to display the grid, or clear the box to hide the grid.

3.	Click OK.

− Or −

•	Press G to toggle the grid display.

You can also display a tile grid to simplify editing toolbar graphics (see »Editing Toolbar Graphics«).


 Editing Icons and Cursors

Icons and cursors are like bitmaps, and you edit them in the same ways. But icons and cursors have attributes that distinguish them from bitmaps. For example, each icon or cursor resource can contain multiple images for different display devices. In addition, cursors have a "hotspot" — the location Windows uses to track the cursor's position.


 Creating and Selecting Images

When you create a new icon or cursor, the graphics editor first creates an image for the VGA. The image is initially filled with the "screen" (transparent) color. If the image is a cursor, the hotspot is initially the upper-left corner (coordinates 0,0).

By default, the graphics editor supports the creation of images for the following devices:

Device	Colors	Width	Height
EGA/VGA	16	32	32
Monochrome	2	32	32
CGA	2	32	16
You can create images for other devices if you first create descriptions for those devices in the Registry (see »Editing Device Descriptions«).

To create a new image:

1.	On the control bar of the image editor window, click the Device Image button (INS) [image].

The New Cursor Image or New Icon Image dialog box appears (see »Figure 7.7«). This dialog box lists all devices for which there is not an image in the current resource.

2.	Select the device from the dialog box.

3.	Click OK.

4.	Edit the new image. In many cases, you can copy an image for another device and paste it into the new image.

When you open an existing icon or cursor, the image most closely matching the current display device is opened by default.

To select a device image:

•	On the control bar of the image editor window, select a device image from the Device list box.

To delete a device image:

1.	Display the device image you want to delete.

2.	From the Resource menu, choose Delete Device Image.

If this is the last image for the icon or cursor, App Studio displays a message box informing you that the resource will be deleted. Choose OK to delete the resource or Cancel to not delete the image. You cannot delete the last remaining image of a resource opened for stand-alone editing.

3.	Choose OK to delete the image or Cancel to cancel the operation.

If the image is the last one in the resource, the resource is also deleted from the resource file.


 Editing Device Descriptions

The Registry contains information about the display devices for which App Studio can create icons and cursors. Display devices are described in the sections of the file labeled [IconDevices] and [CursorDevices]. Each device description has the form:

DeviceName = ColorCount, Width, Height

The ColorCount entry must be 2 or 16, and the Width and Height must each be less than or equal to 999.

If the Registry does not contain an [IconDevices] section, the following device descriptions are used by default:

EGA/VGA=16, 32, 32
Monochrome=2, 32, 32
CGA=2, 32, 16

If the Registry does not contain a [CursorDevices] section, the following device description is used by default:

Monochrome=2, 32, 32

To add device descriptions to the Registry:

1.	Open the Registry using Notepad or another text editor.

2.	Create a section label of the form [IconDevices] or [CursorDevices], if the appropriate section label does not already exist.

3.	Under the section label, enter device descriptions in the form

DeviceName = ColorCount, Width, Height

4.	Close the Registry.

5.	Restart App Studio to make the new device descriptions available.


 Drawing with Screen and Inverse Colors

Icon and cursor images are rectangular, but many do not appear so because parts of the image are "transparent": the underlying image on the screen shows through the icon or cursor. And when you drag an icon, parts of the image may appear in an inverted color. You create these effects by choosing screen- and inverse-color options from the color indicator on the graphics palette, as shown in »Figure 7.8«.

To create transparent or inverse regions in an icon or cursor:

1.	On the graphics palette, click a selector:

•	The screen-color selector

•	The inverse-color selector

2.	Apply the screen or inverse color, using the methods described in »Drawing and Painting«.

The screen and inverse "colors" you apply to icons and cursors are really attributes. The colors indicate parts of the image possessing those attributes. You can change the colors that represent the screen- and inverse-color attributes for your convenience in editing. These changes do not affect the appearance of the icon or cursor in your application.

To change the colors representing screen color and inverse color:

1.	On the graphics palette, double-click the screen color or inverse color indicator.

The Color dialog box appears.

2.	Choose a new color from the Color dialog box.


Setting a Cursors Hotspot
 Setting a Cursor's Hotspot

The hotspot is the point to which Windows refers in tracking the cursor's position. By default, the hotspot is set to the upper-left corner (coordinates 0,0). The General property page and the image-editor control bar show the hotspot coordinates.

To set a cursor's hotspot:

1.	On the control bar of the image editor window, click the Hotspot button [image] or from the Image menu, choose Set Cursor Hotspot.

2.	Click the pixel you want to designate as the cursor's hotspot.


 Editing Toolbar Graphics

App Studio's graphics editor has special features to simplify creation of tiled graphics for toolbar buttons (see the class CToolBar in the Class Library Reference). All the button bitmaps for a toolbar are taken from one bitmap, which must contain one image for each button. All images must be the same size: the default is 16 x 15 pixels. Images must be side by side in the bitmap. Typically the order of the images in the bitmap is the order in which they are drawn on the screen.

Each button has one image. The various button states and styles (pressed, up, down, disabled, disabled down, and indeterminate) are generated from that one image. Although bitmaps can be any color, best results are achieved with images in black and shades of gray. »Figure 7.9« shows a typical toolbar bitmap.

The graphics editor can superimpose a tile grid on the view of a bitmap. The tile grid delimits sections of the bitmap in dimensions you specify so that you can properly position tiled images within the bitmap. When the tile grid is displayed, the graphics editor's behavior changes in ways that simplify resizing a tiled bitmap.

To set the tile-grid dimensions:

1.	From the Image menu, choose Grid Settings.

The Grid Settings dialog box appears (see »Figure 7.10«).

2.	In the Grid Settings dialog box, select the Pixel Grid check box if it is not already checked.

You cannot set the Tile Grid dimensions if the Pixel Grid check box is not checked.

3.	Check the Tile Grid check box.

4.	If necessary, edit the Width and Height settings.

Typically, these settings are the same as the width and height of your button bitmaps.

5.	Click OK.

The image editor window now displays a tile grid, as in »Figure 7.11«.

To toggle the display of the tile grid:

•	Press CTRL+G.

Tip  When the tile grid is displayed, the sizing handles on the selection border behave differently from when the tile grid is not displayed (see »Resizing a Bitmap«). When you drag the sizing handles, the bitmap is resized in increments of the tile dimensions.

To create a new toolbar button:

1.	Display the tile grid.

2.	If necessary, select a background color for the new button.

3.	To resize the bitmap, drag the sizing handle on the right side of the bitmap to the right (see »Figure 7.12«). The bitmap's width is increased by an amount equal to the tile grid's Width setting.

4.	If the new button is to be added at a position other than the right end of the bitmap, make room for it:

•	Select the rightmost button images, including the one at the new button's position (see »Figure 7.13«).

•	Drag the selection to the right, using the tile grid to align the images (see »Figure 7.14«).

5.	Draw the new button image in the space you have created.


 Managing Colors and Palettes

The graphics editor's color palette displays 24 of the 48 "ready-made" colors that are available. In addition to the ready-made colors, you can create your own custom colors. Color-palette selections can be saved to disk and reloaded as needed.


 Creating Color Palettes

To change colors on the color palette:

1.	Double-click the color you want to change, or click the color and then from the Image menu, choose Edit Foreground Color.

The Color dialog box appears (see »Figure 7.15«). The color you are changing is outlined.

2.	Click the color you want to assign in place of the current color.

3.	Click OK.

To create a custom color:

1.	Double-click on the color you want to change, or from the Image menu, choose Edit Foreground Color.

The Color dialog box appears.

2.	Choose Define Custom Colors.

The custom-color dialog box then appears (see »Figure 7.16«).

3.	Click the Custom Colors box in which you want to store the new custom color.

4.	Define the color by typing in RGB or HSL values, or by moving the cross hairs on the color box.

5.	Set the luminance by moving the slider on the luminance bar.

6.	Many custom colors are dithered. If you want the solid color closest to the dithered color, choose the Color|Solid control. (If you later decide you want the dithered color, move the slider or the cross hairs again to restore the dithering.)

7.	Choose a disposition for the new color you have created:

•	To add the new color to the Custom Colors control, click Add to Custom Colors.

•	To substitute the new custom color for the current palette color, choose OK. The color will be available for later use only if you add it to the Custom Colors control.

•	To save the custom color for later use without replacing the current palette color, add the color to the Custom Colors control. Choose Cancel.

Custom-color definitions are saved in the Registry and are automatically loaded the next time you start App Studio.


 Saving and Loading Palettes

Tip  Since the graphics editor has no means to restore the default color palette, save the default color palette under a name such as STANDARD.PAL or DEFAULT.PAL so that you can restore the defaults without having to quit and restart App Studio.

To save a custom palette:

1.	From the Image menu, choose Save Palette Colors.

2.	Use the Save Palette Colors dialog box to navigate directories and enter a file name.

To load a custom palette:

1.	From the Image menu, choose Get Palette Colors.

2.	Use the Get Palette Colors dialog box to navigate directories and choose a file name.


Chapter 8: Using the Binary Data Editor
 Chapter 8  Using the Binary Data Editor

The App Studio binary data editor allows you to edit a resource at the binary level in either hexadecimal or ASCII format.

You should use the binary editor only when you need to view or make minor changes to custom resources or resource types not supported by App Studio.

Caution  Editing nondata resources in the binary data editor can corrupt the resource. A corrupted resource can cause App Studio and Windows to behave in unexpected ways.


 Creating a New Data Resource or Custom Resource

You create new custom or data resources by placing them in a separate file using normal .RC file syntax, then including the file with the File menu Set Includes command.

To create a new custom or data resource:

1.	Use Visual Workbench to create an .RC file that contains the custom or data resource.

2.	Custom data can be entered in an .RC file as null-terminated quoted strings, or as integers in decimal, hexadecimal, or octal format. For more information, see the Software Development Kit documentation.

3.	From the App Studio file menu, choose Set Includes.

4.	The Set Includes dialog box appears.

5.	In the Compile-Time Directives box, type an include statement that gives the name of the file containing your custom resource. For example:

#include mydata.rc

6.	Make sure the syntax and spelling of what you enter is correct. The contents of the Compile-Time Directives box is inserted into the resource script file exactly as you type it.

7.	Choose the OK button to record your changes. The custom or data resource is included in your application at compile time.


 Opening the Binary Data Editor

To select a resource for binary editing:

1.	Move to the resource browser window.

2.	In the Type box, choose the resource type you want to edit.

3.	In the Resources box, select the specific resource you want to edit.

4.	From the Resource menu, choose Edit Binary Data (CTRL+B).

The binary data window appears (»Figure 8.1«).

Note  If you use the resource browser window to open a resource whose format App Studio does not recognize (such as a VERSION, RCDATA, or custom resource), App Studio automatically opens the resource in the binary data editor.

Note  If you want to use the binary data editor on a resource already being edited in another App Studio editor window, close the other editor window first.


 Editing Data

To edit a resource in the binary data editor:

1.	Select the byte you want to edit.

The TAB key moves the focus between the hexadecimal and ASCII sections of the editor window. PAGE UP and PAGE DOWN move you through the resource one screen at a time. You can also move to the top of the resource with CTRL+HOME and to the end with CTRL+END.

2.	Type the new value.


Chapter 9: Using ClassWizard
 Chapter 9  Using ClassWizard

ClassWizard is like a programmer's assistant: it makes it easier for you to do certain routine tasks such as creating new classes, defining message handlers, and gathering data from controls in a dialog box or form view.

One of ClassWizard's main tasks is to work with Microsoft Foundation Class Library "message maps." A message map is a message-dispatch table that associates Windows messages with class member functions. This eliminates the cumbersome switch statements needed in traditional programming for Windows.

With ClassWizard, you can:

•	Create new classes derived from any of the main framework base classes that handle Windows messages.

•	Browse the Windows messages associated with windows, dialog boxes, controls, menu items, and accelerators.

•	Create new message-handling member functions by clicking the messages you want to handle.

•	See which messages have message handlers already defined and jump to the handler program code.

•	Define member variables that automatically initialize, gather, and validate data entered into dialog boxes or form views.

Important  ClassWizard never changes any of your code. It only works with the special-format message-map and "data-map" (see »Adding a New Class«) sections of your header and implementation files. The Microsoft Foundation Class Library uses this information for message handling and dialog data exchange and validation.

ClassWizard is used with Microsoft Foundation Class Library version 2 projects. For information on how to convert other projects (including Microsoft Foundation Class Library version 1 projects) for use with ClassWizard, see »Updating Existing Code for Use with ClassWizard« at the end of this chapter.

The following topics discuss three processes that can be automated with ClassWizard:

•	Adding a new class to your application

•	Mapping messages and commands to functions

•	Working with dialog-box data

You can also update ClassWizard when you've made minor changes to the source code or rebuild the entire ClassWizard (.CLW) file when the changes you've made are more extensive.

While you can do any of these common programming functions without using ClassWizard, using ClassWizard together with the framework allows you to accomplish these common chores quickly and efficiently.

»Updating Existing Code for Use with ClassWizard« discusses how to update existing code for use with ClassWizard.


 Adding a New Class or Importing an Existing One

Use ClassWizard to add error-free class declarations to your project for classes that contain message-handling functions.

Note  ClassWizard is only for use with user-interface classes that handle messages or manage dialog-box controls. To add a new class that does not handle messages, create the class directly in the Visual Workbench editor.

ClassWizard allows you to create classes derived from the Microsoft Foundation classes shown in Table 9.1:

Table 9.1   Types of Classes Created in ClassWizard

Class	Description
CDialog	Dialog box
CDocument	Class for managing program data
CFormView	Window that can contain dialog-box controls
CFrameWnd	Main single document interface (SDI) frame window
CMDIChildWnd	Multiple document interface (MDI) child frame window
CView	Class for displaying program data
CScrollView	Scrolling window, derived from CView
CWnd	Custom window
Splitter	MDI child frame window containing a CSplitterWnd
For more information on these classes, see the Class Library Reference.

When you use ClassWizard to create a new class derived from one of the framework classes listed above, it automatically places a complete and functional class in the header (.H) and implementation (.CPP) files you specify. ClassWizard keeps track of the class's message-handling and data-exchange members, and later you can use it to update this information.


 Adding a New Class

To add a new class to your project using ClassWizard:

1.	In Visual Workbench: from the Browse menu, choose ClassWizard (CTRL+W).

 − Or −

In App Studio: click the ClassWizard toolbar button [image], or from the Resource menu, choose ClassWizard (CTRL+W).

Note  For classes associated with a dialog-box resource — classes derived from CDialog or CFormView — create the resource in App Studio before you use ClassWizard to create the class.

2.	Choose Add Class. The Add Class dialog box appears (»Figure 9.1«).

In App Studio, if you are currently editing a dialog box that is not yet associated with a class, the Add Class dialog box appears automatically.

3.	Type the name of your new class in the Class Name box and, in the boxes provided, type the names of the header and implementation files where the class is to be defined.

4.	In the Class Type box, select the name of the class or class type from which your current class is to be derived (»Table 9.1«).

5.	In the Dialog ID box, select the name of the resource identifier from the list. If you are in App Studio, have a dialog box selected, and are creating a class based on CDialog or CFormView, the identifier is already filled in for you.

6.	Choose Create Class to create the class in the files you specified.

For a specific example of how this general procedure works to create a new dialog-box class, see »Example, Part 1:« Defining a Message Handler for a Dialog-Box Control.

When you use ClassWizard to create a new class, it adds skeletal information on the new class to both the header and implementation files. If you specify filenames that don't yet exist, ClassWizard creates the new files and adds them to your project if Visual Workbench is running.

Note  ClassWizard only updates your project file if Visual Workbench is running. If it is not, you need to add the files to the project yourself.

When you add a new class using ClassWizard, special-format comments are placed in your code to mark the sections of the header and implementation files that ClassWizard edits. ClassWizard never modifies code that is outside these commented sections.

For most classes, there are two related sections of code that ClassWizard edits: the member-function definitions in the class header file and the message-map entries in the class implementation file.

The ClassWizard comments in the header file look like this:

//{{AFX_MSG(<classname>)

// ClassWizard adds member functions here

//}}AFX_MSG

The ClassWizard section in the implementation file is set off with comments that look like this:

//{{AFX_MSG_MAP(<classname>)

// ClassWizard adds message map macros here

//}}AFX_MSG_MAP

For more information about these comments, see »Updating Existing Code for Use with ClassWizard«.

For dialog boxes, ClassWizard creates and edits three other sections that are marked with special format comments:

•	Member variable declarations in the class header file (//{{AFX_DATA...//}}AFX_DATA)

•	Member variable initialization in the class implementation file (//{{AFX_DATA_INIT...//}}AFX_DATA_INIT)

•	Data-exchange macros in the implementation file (//{{AFX_DATA_INIT...//}}AFX_DATA_INIT)

For more information see »Working with Dialog-Box Data«.


 Importing Existing Classes

If you add a message-handling class to your current project by copying code from another project, you can update ClassWizard so that it recognizes the new class.

Note  If the new code you have copied contains more than two or three new message-handling classes, you can save time by rebuilding the ClassWizard file completely rather than importing each new class individually. See »Rebuilding the ClassWizard (.CLW) File« for more information.

To add a class copied in from another project to the ClassWizard file:

1.	If the code you are importing doesn't already have ClassWizard comments in it, add the special-format comments ClassWizard uses to locate message-map entries. See »Updating Existing Code for Use with ClassWizard« for more information.

2.	Bring up the main ClassWizard dialog box and choose Add Class. When the Add Class dialog box appears, choose Import Class.

3.	In the Import Class dialog box (»Figure 9.2«), type in the name of the new class and the name of the header and implementation files where it can be found.

4.	Choose OK to add the new class to the ClassWizard file.


 Mapping Messages to Functions

ClassWizard lets you browse the messages associated with a user-interface object in your application and quickly define message-handling functions for them. ClassWizard also automatically updates the message-dispatch table, or message map, when you use ClassWizard to define message-handling functions.

The procedure for handling a message is very similar, regardless of the kind of user-interface object you are working with. Table 9.2 shows the types of objects you work with in ClassWizard and the types of messages associated with them.

 Table 9.2    User-Interface Objects and Associated Messages

Object ID	Messages
Class name, representing the containing window (»Table 9.1«)	Windows messages appropriate to a CWnd-derived class: a dialog box, window, child window, MDI child window, or topmost frame window
Menu or accelerator identifier	COMMAND message (executes the program function) UPDATE_COMMAND_UI message (dynamically updates the menu item)
Control identifier	Control notification messages for the selected control type


 Defining Message Handlers

After creating a class with ClassWizard, or importing an existing class, you can use ClassWizard to browse the messages or control notifications associated with each object and to create handler routines (member functions) as appropriate.

The general procedure for using ClassWizard to define a message or command handler is as follows (see »Figure 9.3«):

To define a message handler with ClassWizard:

1.	In Visual Workbench: from the Browse menu, choose ClassWizard (CTRL+W).

− Or −

In App Studio: select the user-interface object you want to work with. Then click the ClassWizard toolbar button [image], or from the Resource menu, choose ClassWizard (CTRL+W).

The main ClassWizard dialog box appears. If you are in Visual Workbench, ClassWizard displays information about the currently selected class name or the class you last edited with ClassWizard. If you are in App Studio, you see information about the user-interface object that is currently selected.

2.	In the Object IDs box, select the name of the user-interface object you want to define a message handler for. »Table 9.2« shows the types of objects that will appear in the Object IDs box and the messages appropriate to each type.

3.	In the Messages box, select the message for which you want to define a handler and choose Add Function, or double-click the message name.

You can only select messages that do not already have a handler defined. A message with a handler already defined has a picture of a small hand next to it.

Note  The messages you see in the Messages box are those most appropriate to your class. You can change which messages you see by choosing the Class Info command and selecting a new set of messages in the Message Filter box. For information on handling custom messages, see Technical Note 6, which can be found in MSVCNT\HELP\MFCNOTES.HLP.

For messages that don't already have a handler defined in their base class, the Add Member Function dialog box appears.

Tip  Selecting a message displays a brief description of it at the bottom of the ClassWizard dialog box. You can get a more complete description of the message by pressing F1.

4.	For messages that don't already have a handler defined in their base class, type in the member function name you want and press ENTER, or press ENTER to accept the name proposed by ClassWizard. This returns you to the main ClassWizard dialog box.

A picture of a hand appears next to the message name to show that a member function is defined to handle the message. The name of the new message-handling function appears in the Member Functions box.

At this point you have several options. You can:

•	Add more message handlers.

•	Choose Edit Code to jump to the empty ClassWizard-generated function in your source code and begin defining the function's behavior.

•	Choose OK to close ClassWizard. You can return to ClassWizard any time during the development process.

•	Choose Cancel to cancel the changes you have made.

When you choose OK or Edit Code, ClassWizard updates your source code as follows:

•	A function declaration is inserted into the header file.

•	A complete, correct function definition with a skeletal implementation is inserted into the implementation file.

•	The class's message map is updated to include the new message-handling function.


 Deleting Message Handlers

Once you have defined a message handler with ClassWizard, you can also use ClassWizard to delete it. However, you must remove the function definition, as well as any references to the function, from the implementation file yourself. ClassWizard never makes changes to your implementation code — only to the message and data maps.

To delete a message-handling function:

1.	In the main ClassWizard dialog box, from the Class Name box, select the class containing the message-handling function you want to delete.

2.	In the Member Functions box, select the name of the member function to delete.

3.	Use the Edit Code command (see »Working with Dialog-Box Data«) to open the implementation file containing the member function in Visual Workbench. Delete the function header and function body, or copy it to a file not in the current project.

4.	Return to ClassWizard and choose Remove Function. This deletes the member function from the message-map entries for that class in both the header and implementation files.


 Jumping to Source Code from ClassWizard

Once you have defined a procedure with ClassWizard you can use the Edit Code command to jump to the member-function definition and begin to add or modify code. The following procedure assumes that Visual Workbench is running.

To use the ClassWizard Edit Code command (available only when Visual Workbench is running):

1.	In the Member Functions box, select the function you want to edit.

2.	Choose Edit Code (see »Figure 9.3«) or double-click the function name.

ClassWizard switches to Visual Workbench and moves to the beginning of the member function.


 Working with Dialog-Box Data

ClassWizard offers an easy way to take advantage of the dialog data exchange (DDX) and dialog data validation (DDV) capabilities of the Microsoft Foundation classes.

To use DDX, you define member variables in the dialog-box class and associate each of them with a dialog-box control. The framework transfers any initial values to the controls when the dialog box is displayed. It then updates the variables with user-entered data when the user clicks OK to dismiss the dialog box  .

With DDV, dialog-box information entered by the user is validated automatically. You can set the validation boundaries: the maximum length for string values in an edit-box control or the minimum or maximum numeric values when you expect a number to be entered. You can also use ClassWizard to connect dialog-box controls to your own custom data-validation routines.

For an example of how to use DDX and DDV, see »Example: Part 2: Using DDX/DDV«.


 Dialog Data Exchange

ClassWizard lets you create variables that use the framework's automatic dialog data exchange capabilities. For each dialog-box control you want to set an initial value for or gather data from, use ClassWizard to define a data member in the dialog class. The framework then transfers the initial value of each variable to the dialog box when it is created and updates each member variable when the dialog box is dismissed.

Note  You can also use CWnd::UpdateData to transfer data back and forth between controls and member variables while a dialog box is open.

To define data members for dialog data exchange:

1.	Create your dialog box in App Studio, place in it the controls you want, and set the appropriate control styles in the Properties window. Then use ClassWizard to define a new »dialog-box class«.

2.	In the ClassWizard dialog box, choose Edit Variables. The Edit Member Variables dialog box appears.

3.	Select the control for which you want to set up DDX and choose Add Variable. The Add Member Variable dialog box appears (see »Figure 9.4«).

4.	In the Member Variable Name box, type the name of the new variable. ClassWizard provides the m_ prefix to identify it as a member variable.

5.	In the Property box, select whether this variable is a Value variable or a Control variable.

For standard Windows controls, choose Value in the Property box to create a variable that contains the control's text or status as entered by the user. The framework automatically converts the control's data to the data type selected in the Variable Type box (see »Table 9.3«).

6.	In the Variable Type box, choose from a list of variable types appropriate to the control (see »Table 9.3«).

Once you've defined a DDX Value variable for a standard Windows control, the framework automatically initializes and updates the variable for you.

Table 9.3 shows the type of DDX Value variables ClassWizard initially provides. To create additional variable types, see Technical Note 26, which can be found in MSVCNT\HELP\MFCNOTES.HLP.

 Table 9.3   DDX Variable Types for the Value Property

Control	Variable Type
Edit box	CString, int, UINT, long, DWORD, float, double
Normal check box	BOOL
Three-state check box	int
Radio button (first in group)	int
Nonsorted list box	CString, int
Drop list combo box	CString, int
All other list box and combo box types	CString
The following additional notes apply to using DDX Value variables:

•	Possible values for three-state check boxes are 0 (off), 1 (on), and 2 (indeterminate).

•	Values for a group of radio buttons range from 0 for the first button in the group to n−1 for a group with n buttons. A value of −1 indicates that no buttons are selected.

•	When you are using a group of check boxes or radio buttons with a DDX variable, make sure the Auto property is set for all the controls in the group.

•	Set the Group property for the first radio button in a group, and make sure all the other radio buttons immediately follow the first button in the tab order.

•	To use an integer value with a combo box or list box, make sure the Sort property is turned off on the control's Styles property page.

Table 9.4 shows the type of DDX Control variables you can define with ClassWizard.

Table 9.4    DDX Variable Types Defined with the Control Property

Control	Variable Type
Edit box	CEdit
Check box	CButton
Radio button	CButton
Pushbutton	CButton
List box	CListBox
Combo box or drop list combo box	CComboBox
Static text	CStatic


 Using DDX Variables

You can set the initial value of DDX variables by editing the initialization code that ClassWizard places in the constructor for the dialog-box class. (ClassWizard does not disturb these initialization statements once they have been put in place.) The framework transfers the values to the dialog box when it is created.

To see what the user typed once the dialog box is dismissed, access the values of the DDX variables just as you would any C++ member variable.


 Dialog Data Validation

By default, ClassWizard supports the types of data validation shown in Table 9.5, but you can add additional types (see Technical Note 26, which can be found in MSVCNT\HELP\MFCNOTES.HLP).

Table 9.5    DDV Variable Types

Variable Type	Data Validation
CString	Maximum length
Numeric (int, UINT, long, DWORD, float, double)	Minimum value, maximum value
You can define the maximum length for a CString DDX variable or the minimum or maximum values for a numeric DDX variable at the time you create it. For example, the ClassWizard Edit Member Variables dialog box in »Figure 9.5« shows a DDX integer variable associated with an edit box. The variable has a minimum value of 1 and a maximum value of 10.

At run time, if the value entered by the user exceeds the range you specify, the framework automatically displays a message box asking the user to reenter the value. The validation of DDX variables takes place all at once when the user chooses OK to accept the entries in the dialog box.


 Custom Data Exchange and Validation

Although you can write a dialog-box class that gathers and validates its own dialog-box data using custom message handlers, you may find that you have routines for data exchange and validation (containing your own variable types and data formats) that you want to use over and over. You can extend the ClassWizard user interface to reuse your own DDX and DDV routines.

For more information, see Technical Note 26 in MSVCNT\HELP\MFCNOTES.HLP.


 Example: Building a Dialog Box with ClassWizard

In this section you'll see how to define a message-handling function for a simple dialog box that prompts a user to type in a password. You'll then see how to use ClassWizard to take advantage of the framework's built-in DDX and DDV routines. This example uses the procedures described in the previous sections.


 Example, Part 1: Defining a Message Handler for a Dialog-Box Control

The first part of this example steps you through the procedure for creating a dialog box, and then for defining its class name and the names of its header and implementation files.  You will also define a message handler to enable the check-box control in the dialog box and begin filling in the message-handling code.


 Step One: Create the Dialog-Box Resource

To begin, assume that you have created the new dialog box in App Studio (see »Using the Dialog Editor«, Chapter 3) and are ready to define message handlers for it. The App Studio screen at the beginning of the procedure looks like »Figure 9.6.« The dialog box has an ID of ID_PASSWORD. The edit-box control that will accept the password has an ID of IDC_PASSWORD. The check box has an ID of IDC_ALL_ACCESS, and its Disabled property is selected.


 Step Two: Define The Dialog-Box Class

On the App Studio toolbar, click the ClassWizard button. The dialog box you created is open in the dialog editor window so ClassWizard knows what resource identifier to work with. Since the new dialog box isn't yet associated with a class, ClassWizard displays the Add Class dialog box. You supply the name of the new class and the names of its header and implementation files (»Figure 9.1«).


 Step Three: Define the Message Handler

Next, you want to define a handler to enable the check-box control in the dialog box as soon as the user types something into the edit-box control. Since the edit-box control sends an EN_CHANGE message to the dialog box every time the contents of the control is modified, you select the control's identifier, IDC_PASSWORD, in the Object IDs box and double-click EN_CHANGE in the Messages box to define the handler.

Since you've given the edit box a symbol name of IDC_PASSWORD, ClassWizard suggests OnChangePassword as the name of the message-handling function. When you press ENTER, ClassWizard accepts the name and creates the new member function. The ClassWizard dialog box now looks like »Figure 9.3«.


 Step Four: Begin Filling in the Message Handler

You now want to fill in the function body, so you select the new member function (OnChangePassword) and choose Edit Code. (The Edit Code command is not available unless Visual Workbench is running.) ClassWizard switches to Visual Workbench and opens DIALOGS.CPP to the appropriate location in the source code. The following empty function is already in place:

void CPasswordDlg::OnChangePassword()

{

// TODO: Add your control notification handler code here

}

The class's message map has been updated to reflect the message handler
(marked in blue):

BEGIN_MESSAGE_MAP(CPasswordDlg, CDialog)

//{{AFX_MSG_MAP(CPasswordDlg)

ON_EN_CHANGE(IDC_PASSWORD, OnChangePassword)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

The header file, DIALOGS.H, has been updated as well (marked in blue):

// Generated message map functions

//{{AFX_MSG(CPasswordDlg)

afx_msg void OnChangePassword();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

You are now ready to add the necessary EN_CHANGE message-handling code to DIALOGS.CPP. You'll see how to do this at the end of the second part of this example, where the Add Variables dialog box is used to create Control variables that allow you to enable the check box whenever the edit box has something in it.


 Example, Part 2: Using DDX/DDV

Now assume you want to set up a data member in the CPasswordDlg class to contain the password the user types in. You also want to set the password to an initial value of INVALID and make sure that it's no more than eight characters long.


 Step One: Define the Member Variable Using ClassWizard

The first step is to set up a member variable in the dialog-box class. You bring up ClassWizard with the Password dialog box selected, making sure the identifier for the text control that will contain the password (in this case IDC_PASSWORD) is selected. Choose Edit Variables. The Edit Member Variables dialog box appears.

You then choose Add Variable and, in the Add Member Variable dialog box that appears, fill in the name of the member variable (m_strPassword, in this case). Accept the default values in the Property and Variable Type boxes. At this point, the Add Member Variable dialog box looks like »Figure 9.7.«


 Step Two: Set the Maximum Number of Characters for the Variable

When you choose OK after adding the member variable, ClassWizard returns to the Edit Member Variables dialog box. Since you have now defined a CString variable, ClassWizard adds an edit box at the bottom of the dialog box where you can type in the maximum number of characters for this variable. When the program is running and the user types in more than the number of characters you've specified, the framework displays a dialog box asking for the correct number of characters.

In this case, you want the password to be no more than eight characters long, so you type 8 in the Maximum Characters box. The Edit Member Variables Dialog Box now looks like »Figure 9.8.«

ClassWizard adds information to the DoDataExchange member function of the dialog-box class in DIALOGS.CPP based on what you've entered (marked in blue):

void CPasswordDlg::DoDataExchange(CDataExchange* pDX)

{

        CDialog::DoDataExchange(pDX);

        //{{AFX_DATA_MAP(CPasswordDlg)

        DDX_Text(pDX, IDC_PASSWORD, m_strPassword);

        DDV_MaxChars(pDX, m_strPassword, 8);

        //}}AFX_DATA_MAP

}


 Step Three: Set the Initial Value for the Variable in the Dialog-Box Class Constructor

When you first defined the member variable m_strPassword, ClassWizard placed an initialization statement in the dialog-box class constructor that initialized the variable to an empty string (marked in blue):

CPasswordDlg::CPasswordDlg(CWnd* pParent /*=NULL*/)

        : CDialog(CPasswordDlg::IDD, pParent)

{

        //{{AFX_DATA_INIT(CPasswordDlg)

        m_strPassword = "";

        //}}AFX_DATA_INIT

}

To change the initial value of the DDX variable, simply edit the //{{AFX_DATA_INIT section of the dialog-box class code so it reflects the initial value you want. For example, changing the line marked in blue:

CPasswordDlg::CPasswordDlg(CWnd* pParent /*=NULL*/)

        : CDialog(CPasswordDlg::IDD, pParent)

{

        //{{AFX_DATA_INIT(CPasswordDlg)

        m_strPassword = "INVALID";

        //}}AFX_DATA_INIT

}

changes the initial value of the password variable to "INVALID."


 Step Four: Create Control Variables to Use in the Message Handler

The final step is to create two DDX Control variables to use in enabling the All Access check box when something is typed into the Password box. In the Edit Member Variables dialog box, select the IDC_PASSWORD control and choose Add Variable. The Add Member Variables dialog box appears. In the Property box, select Control, and in the Member Variable Name box, type in the name of the variable, in this case m_editPassword. The Add Member Variable dialog box now looks like »Figure 9.9.«

Once you've defined a DDX Control variable for the All Access check box in a similar way, you're ready to fill in the EN_CHANGE message-handling function. The completed function looks like this:

void CPasswordDlg::OnChangePassword()

{

m_btnAllAccess.EnableWindow(

m_editPassword.GetWindowTextLength() != 0 );

}

This completes the example. ClassWizard did most of the work so that you could concentrate on the important part, the actual message-handling code. You also have added a member variable to your dialog-box class that automatically takes advantage of the framework's built-in routines for custom data exchange and validation.


 Keeping ClassWizard Updated When Code Changes

It's very likely that as your program develops you'll need to delete or modify a class, to delete some resources and add others, or to move a class from one source file to another. ClassWizard is designed to keep in sync with your code as you make these changes: it asks you for the updated information when you next edit the affected class.

ClassWizard stores the information about your application's classes in a file with the file extension .CLW. To accommodate source files that have changed, ClassWizard displays the Repair Class Information dialog box (»Figure 9.10«) whenever it finds that the information in the .CLW file is out of date.

The Repair Class Information dialog box has two main functions:

•	Delete obsolete classes from the ClassWizard file.

•	Update the ClassWizard file with the new name or location of classes that you have changed or moved.


 Deleting Classes

When you delete a class from your header and implementation files, the information in the .CLW file needs to be updated as well. The next time you select that class in ClassWizard, you are prompted to update the information in the ClassWizard file.

To delete a message-handling class created with ClassWizard:

1.	Remove the class from your header and implementation files.

2.	Open ClassWizard, and in the Class box, select the class you have modified.

ClassWizard displays a message box warning you that the class cannot be found. Then the Repair Class Information dialog box appears.

3.	Choose Remove.

The class is deleted from the ClassWizard file.


 Renaming or Moving Classes

When you change the name of a class or move it from one implementation file to another, you're prompted to update the information in the .CLW file the next time you edit the class in ClassWizard.

To change the name of a class or move it from one file to another:

1.	Make the desired changes to your source files.

Note  When you change the name of a class, remember to change it everywhere, including in the special-format comments ClassWizard uses. For example,

//{{AFX_MSG_MAP(OldClass) becomes //{{AFX_MSG_MAP(NewClass)

2.	Invoke ClassWizard. In the Class Name box, choose the class you want to change from the list.

ClassWizard displays a message box warning you that the old class could not be found. When you choose OK, the Repair Class Information dialog box appears.

3.	In the Class Name, Header File, and Implementation File boxes, supply the new information about the class. If necessary, use the appropriate Browse command to look for the correct name of the header or implementation file.

4.	Choose OK to update the ClassWizard file.


 Rebuilding the ClassWizard (.CLW) File

If you have made numerous changes to your code or have added a large number of existing user-interface classes to your current project, you may find it convenient to rebuild the ClassWizard file from scratch rather than update it one class at a time. To do this, you delete your project's ClassWizard (.CLW) file and use a dialog box similar to the Visual Workbench's Edit Project dialog box to generate a new one. The newly-generated .CLW file contains information about all the classes that have the special-format ClassWizard comments.

To rebuild the ClassWizard file:

1.	Delete your project's current .CLW file.

2.	Open the project resource file in App Studio so that information about your program's resources can be added to the file as well.

3.	Invoke ClassWizard. A message box is displayed asking if you want to rebuild the ClassWizard file from your project files. Click Yes.

4.	The Select Source Files dialog box appears (»Figure 9.11«). Use the File Name box and the Add, Add All, and Delete commands to create a list of project files in the Files in Project box.

5.	When the list of project files is complete, click OK.

ClassWizard generates a new .CLW file.


 Updating Existing Code for Use with ClassWizard

This section provides the basics for adding ClassWizard comments to existing code so that the code can be used with ClassWizard. Microsoft Foundation Class Library version 1 code is an example of code containing classes that need to be updated in this way. To update a class for use with ClassWizard, it must already have a message map defined.

For more detailed information on updating existing code, see  Technical Note 19, which can be found in MSVCNT\HELP\MFCNOTES.HLP.

To use existing code with ClassWizard, place the special-format comments ClassWizard uses to locate message-map entries in both your header and implementation files.

In your header file, ClassWizard uses comments of the following form, placed before and after message-handler declarations:

//{{AFX_MSG(<classname>)

     //message-handler declaration here

//}}AFX_MSG

The classname is the name of the class to which the message handler belongs. For example:

//{{AFX_MSG(CPasswordDlg)

afx_msg void OnChangePassword();

//}}AFX_MSG

In your implementation file, ClassWizard uses comments of the following form, placed before and after the message-map entries:

//{{AFX_MSG_MAP(<classname>)

          // message map entries here

//}}AFX_MSG_MAP

For example:

BEGIN_MESSAGE_MAP(CPasswordDlg, CDialog)

//{{AFX_MSG_MAP(CPasswordDlg)

ON_EN_CHANGE(IDC_PASSWORD, OnChangePassword)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

You can also upgrade existing dialog classes for use with ClassWizard dialog data exchange and validation, although you may not need to do this if your existing dialog-box code already handles data exchange and validation to your satisfaction.

For an example of the AFX_DATA, AFX_DATA_INIT, and AFX_DATA_MAP comments used by ClassWizard to maintain information for data exchange and validation, see the PENDLG.CPP (and PENDLG.H) module of the SCRIBBLE example program discussed in the Class Library User's Guide.

Once you have placed the necessary ClassWizard comments in your source files, load the project's resource script file into App Studio, invoke ClassWizard, and build the ClassWizard (.CLW) file according to the instructions in the previous section.

To learn how resource script files change when you upgrade from the previous version of the Microsoft Foundation Class Library, see Chapter 2, »Working with Files and Symbols.«


Chapter 10: App Studio Quick Reference
 Chapter 10  App Studio Quick Reference

The first part of this chapter lists common App Studio tasks and shows you which menu items, toolbar buttons, and keystrokes you use to perform them. The second part describes all of App Studio's menus, toolbars and palettes, and accelerator keys.


 Task Reference

This section provides a quick guide to many of the common tasks you perform with App Studio's menus, accelerator keys, and toolbar buttons. Each brief task description includes a reference to the App Studio User's Guide so that you can jump to the passage that describes the task in detail.


 Managing Files

Task	Menu, Command	Key	Button	Comments	See
Create a new resource script, resource file, bitmap, icon, or cursor	File, New...	CTRL+N		Opens the New dialog box, which prompts you to select the file type.	»Creating a New Resource File«
Create a new resource script				The resource browser window for the new resource script appears.	»Creating a New Resource File«
Open a resource script, resource, .EXE, .DLL, .DRV, bitmap, icon, or cursor file	File, Open...	CTRL+O		Opens the Open dialog box, which you use to navigate directories and choose a file.	»Opening a Visual C++ Resource File«
Close the active resource script or resource file	File, Close			Or double-click the file's Control-menu box.	—
Save the active resource script or resource file	File, Save	CTRL+S		Saves the .RC file and any resource files that have changed.	»Working with Files«
Rename the active resource script or resource file	File, Save As...	F12		Opens the Save As dialog box, which prompts you for a filename.	»Working with Files«
Save all open resource scripts and resource files	File, Save All			Saves all resource scripts and resource files currently open.	—
Set names of included header and resource files	File, Set Includes...			Opens the Set Includes dialog box, where you enter the names of header files and compile-time resource scripts.	»Using Advanced Resource File Techniques«
Exit App Studio	File, Exit	ALT+F4		Exits App Studio and prompts you to save any modified files.	—


 Editing

Task	Menu, Command	Key	Button	Comments	See
Undo an action	Edit, Undo	CTRL+Z		By default, 10 operations can be undone. To change the number, see Appendix A.	»Using Undo and Redo«
Redo the last undo	Edit, Redo	CTRL+A		Disabled until an edit action has been undone.	»Using Undo and Redo«
Delete to the Clipboard	Edit, Cut	CTRL+X		Deletes the selection and overwrites the current Clipboard contents.	»Deleting and Copying Controls«
Copy to the Clipboard	Edit, Copy	CTRL+C		Overwrites the current Clipboard contents with the selection.	»Deleting and Copying Controls«
Paste from the Clipboard	Edit, Paste	CTRL+V		Does not overwrite selection in destination.	»Deleting and Copying Controls«
Delete selection	Edit, Delete	DEL		Removes the current selection; does not save to the Clipboard.	»Deleting and Copying Controls«


 Handling Resources

This section lists general resource-handling tasks first, then tasks specific to particular resource types.


 General

Task	Menu, Command	Key	Button	Comments	See
Create a new resource script, resource file, bitmap, icon, or cursor	File, New...	CTRL+N		Opens the New dialog box, which prompts you to select the file type.	»Creating a New Resource File«
Create a new resource	Resource, New...	CTRL+R		Opens the New Resource dialog box. Select a resource type and press ENTER.	»Creating a New Resource File«
Open an existing resource	Resource, Open	ENTER		Enabled only when a resource is selected in the resource browser window.	»Editing an Existing Resource«
Open a resource for binary editing	Resource, Open Binary   Data	CTRL+B		Opens the binary editor window. Enabled only when a resource is selected in the resource browser window.	»Opening the Binary Data Editor«
Change a resource's properties	Resource, Properties...	ALT+ ENTER		Activates the Properties window.	»Viewing Property Pages«
Import a bitmap, cursor, or icon into your project	Resource, Import...			Opens the Import Resource dialog box, where you enter the name of the file containing the bitmap, cursor, or icon resource.	»Copying Resources Between Files«
Export a bitmap, cursor, or icon and save it in a separate file	Resource, Export...			Opens the Export Resource dialog box, where you enter the name of the file in which to save the resource. Enabled only when a bitmap, cursor, or icon resource is selected or contained in the active editor window.	»Copying Resources Between Files«


Dialog Boxes  General
 Dialog Boxes — General

Task	Menu, Command	Key	Button	Comments	See
Test a dialog box	Resource, Test	CTRL+T		Activates the dialog box for testing its controls. Menu command appears only when a dialog editor window is active.	»Testing a Dialog Box«
Show or hide layout grid for current dialog		CTRL+G		Turns grid on or off for current dialog editor only.	»Using Snap to Grid«
Set order of TAB key movement among controls	Layout, Set Tab Order	CTRL+D		Default is order that controls were added to dialog box.	»Changing the Tab Order«
Show or hide the control palette	Window, Show Control   Palette	F2		Appears as Hide Control Palette if palette is shown.	»Adding Controls«


Dialog Boxes  Alignment
 Dialog Boxes — Alignment

Task	Menu, Command	Key	Button	Comments	See
Align controls along left edge	Layout, Align Controls, Left	CTRL+ LEFT ARROW		Selected controls are aligned with edge of the dominant control, which is marked by filled sizing handles.	»Aligning«
Align controls along right edge	Layout, Align Controls, Right	CTRL+ RIGHT ARROW		Selected controls are aligned with edge of the dominant control, which is marked by filled sizing handles.	»Aligning«
Align controls along top edge	Layout, Align Controls, Top	CTRL+ UP ARROW		Controls are aligned with edge of the dominant control, which is marked by filled sizing handles.	»Aligning«
Align controls along bottom edge	Layout, Align Controls, Bottom	CTRL+ DOWN ARROW		Controls are aligned with edge of the dominant control, which is marked by filled sizing handles.	»Aligning«
Align controls on vertical centerline	Layout, Align Controls, Vert. Center	F9		Controls are aligned on centerline of the dominant control, which is marked by filled sizing handles.	»Aligning«
Align controls on vertical centerline	Layout, Align Controls, Horiz. Center	SHIFT+ F9		Controls are aligned on centerline of the dominant control, which is marked by filled sizing handles.	»Aligning«


Dialog Boxes  Spacing and Positioning
 Dialog Boxes — Spacing and Positioning

Task	Menu, Command	Key	Button	Comments	See
Equalize horizontal spacing of three or more selected controls	Layout, Space Evenly, Across	ALT+ RIGHT ARROW		Spacing between selected controls is made the same.	»Making Spacing Even«
Equalize vertical spacing of three or more selected controls	Layout, Space Evenly, Down	ALT+ DOWN ARROW		Spacing between selected controls is made the same.	»Making Spacing Even«
Center controls vertically in dialog box	Layout, Center in   Dialog, Vertical	CTRL+ F9		Horizontal position is not changed.	»Making Spacing Even«
Center controls horizontally in dialog box	Layout, Center in   Dialog, Horizontal	CTRL+ SHIFT+ F9		Vertical position is not changed.	»Making Spacing Even«
Position selected buttons in upper-right corner of dialog box	Layout, Arrange   Buttons, Right	CTRL+B		Buttons are positioned with standard spacing.	»Making Spacing Even«
Position selected buttons at bottom of dialog box	Layout, Arrange    Buttons, Bottom	CTRL+ SHIFT +B		Buttons are positioned with standard spacing.	»Making Spacing Even«


Dialog Boxes  Sizing
 Dialog Boxes — Sizing

Task	Menu, Command	Key	Button	Comments	See
Make controls same size in vertical dimension	Layout, Make Same   Size,  Height	CTRL+ BACK-SLASH		Other selected controls are sized to the dominant control, which is the last control selected.	»Resizing Controls«
Make controls same size in horizontal dimension	Layout, Make Same   Size,  Width	CTRL+ MINUS		Other selected controls are sized to the dominant control, which is the last control selected.	»Resizing Controls«
Make controls same size in both dimensions	Layout, Make Same   Size,  Both	CTRL+ EQUAL		Other selected controls are sized to the dominant control, which is the last control selected.	»Resizing Controls«
Size control to fit text caption	Layout, Size to Content	F7		Does not apply to group boxes.	»Sizing a Control to Fit Its Caption«
Set dimensions of layout grid for all dialogs	Layout, Grid Settings...			Opens the Grid Settings dialog box.	»Using Snap to Grid«
Show or hide layout grid for current dialog		CTRL+G		Turns grid on or off for current dialog editor only.	»Using Snap to Grid«
Set order of TAB key movement among controls	Layout, Set Tab Order	CTRL+D		Default is order in which controls were added to dialog box.	»Changing the Tab Order«
Show or hide the control palette	Window, Show Control   Palette	F2		Appears as Hide Control Palette if palette is shown.	»Adding Controls«


 Menus

Task	Menu, Command	Key	Button	Comments	See
View a menu resource as a drop-down menu	Resource, View as Popup	CTRL+U		Displays the menu bar as a drop-down menu. Appears only when a menu editor window is active. Command is checked when in effect.	»Viewing the Menu Resource as a Drop-down Menu«


Bitmaps, Icons, and Cursors  General
 Bitmaps, Icons, and Cursors — General

Task	Menu, Command	Key	Button	Comments	See
Create new icon or cursor images	Resource, New Device   Image...	INS		Opens New Icon Image or New Cursor Image dialog box. Enabled only if resource does not include images for all known devices.	»Creating and Selecting Images«
View and edit an icon or cursor image for a device	Resource, Open Device   Image			Opens the Open Icon Image or Open Cursor Image dialog box. Can also use the Device drop-down list on the editor toolbar.	»Creating and Selecting Images«
Delete an icon or cursor image for a device	Resource, Delete Device   Image	DEL		Deletes the current device image.	»Creating and Selecting Images«
Toggle between actual-size and magnified views	Image, Zoom In/Out	M		Click zoom tool to select magnification factor.	»Zooming In and Out«
Set a cursor's hotspot	Image, Set Hotspot			Shown only when a cursor is being edited.	»Setting a Cursor's Hotspot«
Flip the selection along its vertical axis	Image, Flip Vertical	Y			»Flipping the Selection«
Flip the selection along its horizontal axis	Image, Flip Horizontal	X			»Flipping the Selection«
Toggle display of pixel grid	Image, Grid Settings...	G			»Displaying and Hiding the Pixel Grid«
Toggle display of tile grid	Image, Grid Settings...	CTRL+G		Tile grid appears only when pixel grid is also shown.	»Editing Toolbar Graphics«
Show and hide pixel and tile grids; change grid dimensions	Image, Grid Settings...			Opens the Grid Settings dialog box.	»Editing Toolbar Graphics«
Show or hide the graphics palette	Window, Show Graphics   Palette	F2		Appears as Hide Graphics Palette if palette is shown.	»Drawing and Painting«


Bitmaps, Icons, and Cursors  Colors
 Bitmaps, Icons, and Cursors — Colors

Task	Menu, Command	Key	Button	Comments	See
Edit the current foreground color	Image,  Edit    Foreground   Color...			Opens the Color dialog box.	»Creating Color Palettes«
Pick up color from a bitmap, icon, or cursor	Image, Pickup Color	COMMA		Preceding tool is selected after color pickup.	»Picking Up Colors«
Load colors from a file	Image, Get Palette   Colors...			Opens the Get Palette Colors dialog box, which you use to navigate directories and choose a file.	»Saving and Loading Palettes«
Save colors to a file	Image, Save Palette   Colors...			Opens the Save Palette Colors dialog box, which you use to navigate directories and choose a file.	»Saving and Loading Palettes«
Toggle opacity of the background color	Image, Draw Opaque	O		Works when moving and copying and when using custom brush.	»Choosing Opaque and Transparent Backgrounds«
Make background color opaque	Image, Draw Opaque	O		Works when moving and copying and when using custom brush.	»Choosing Opaque and Transparent Backgrounds«
Make background color transparent	Image, Draw Opaque	O		Works when moving and copying and when using custom brush.	»Choosing Opaque and Transparent Backgrounds«
Invert colors in the selection	Image, Invert Colors				»Choosing Opaque and Transparent Backgrounds«


 String Tables

Task	Menu, Command	Key	Button	Comments	See
Add a string to a string table	Resource, New,  String	INS			»Editing the String Table«
Search for text	Edit, Find String...	ALT+F3		Opens the Find String dialog box. Appears only when a string editor window is active.	»Editing the String Table«
Search for next occurrence of text	Edit, Find Next   String	F3		Appears only when a string editor window is active.	—


 Accelerator Tables

Task	Menu, Command	Key	Button	Comments	See
Add an accelerator to an accelerator table	Resource, New, Accelerator	INS			»Editing the Accelerator Table«


 ClassWizard

Task	Menu, Command	Key	Button	Comments	See
Connect user-interface objects to code	Resource, ClassWizard	CTRL+W		Invokes ClassWizard. Enabled for Microsoft Foundation Class Library resource scripts only.	»Defining Message Handlers«


 Managing Symbols

Task	Menu, Command	Key	Button	Comments	See
View and change symbol names and values	Edit, Symbols...	CTRL+I		Opens the Symbol Browser dialog box.	»Managing Symbols with the Symbol Browser«
Set names of included header and resource files	File, Set Includes...			Opens the Set Includes dialog box, where you enter the names of header files and compile-time resource scripts.	»Changing the Name of the Symbols Header File«


 Managing App Studio

Task	Menu, Command	Key	Button	Comments	See
Arrange windows in overlapping pattern	Window, Cascade				—
Arrange windows one above the other	Window, Tile Horizontal				—
Arrange windows side-by-side	Window, Tile Vertical				—
Arrange icons along bottom of App Studio window	Window, Arrange Icons				—
Show or hide the toolbar	Window, Toolbar			Checked if toolbar is shown.	—
Show or hide the status bar	Window, Status Bar			Checked if status bar is shown.	—
Show or hide the graphics editor graphics palette	Window, Show Graphics   Palette	F2		Appears as Hide Graphics Palette if palette is shown.	»Showing and Hiding the Graphics Palette«
Show or hide the dialog editor control palette	Window, Show Control   Palette	F2		Appears as Hide Control Palette if palette is shown.	»Adding Controls«
Show or hide the Properties window	Window,  Show   Properties	SHIFT+ F2		Appears as Hide Properties if Properties window is shown.	»Controlling the Properties Window«
Exit App Studio	File, Exit	ALT+F4		Exits App Studio and prompts you to save any modified files.	—


 Getting Online Help

Task	Menu, Command	Key	Button	Comments	See
Open the help system's Contents screen	Help, Contents	F1		Opens App Studio Help at the top-level Contents screen.	—
Search for a keyword in Help	Help, Search...	SHIFT+F1		Opens the Search dialog box.	—
Get help on a part of the App Studio user interface				Click the button, then choose a menu or click the object you want information about.	—
Get information on product support	Help, Product   Support			Explains kinds of support available from Microsoft Product Support.	—
Get information about your copy of App Studio	Help, About App   Studio			Displays a message box that shows software version, registered owner, and serial number.	—


 Menu Reference

This section documents all the commands on App Studio's menus. Menus are described in the order of their appearance on the App Studio menu bar. Some menus appear only under certain circumstances. The Image menu, for example, appears only when an image editor window is active.


 Managing Files

File	Key	Use To
New...	CTRL+N	Create a new resource script, resource file, bitmap, icon, or cursor
Open...	CTRL+O	Open a resource script, resource, .EXE, .DLL, .DRV, bitmap, icon, or cursor file
Close		Close the active resource script or resource file
Save	CTRL+S	Save the active resource script or resource file
Save As...		Rename the active resource script or resource file
Save All		Save all open resource scripts and resource files
Set Includes...		Set names of included header and resource files
Exit		Exit App Studio


 Editing

Edit	Key	Use To
Undo	CTRL+Z	Undo an action
Redo	CTRL+A	Redo the last undo
Cut	CTRL+X	Delete to the Clipboard
Copy	CTRL+C	Copy to the Clipboard
Paste	CTRL+V	Paste from the Clipboard
Delete	DEL	Delete selection
Symbols...	CTRL+I	View and change symbol names and values
Find String...	ALT+F3	Search for text
Find Next String...	F3	Search for next occurrence of text


 Creating and Editing Resources

Resource	Key	Use To
New...	CTRL+R	Create a new resource
Open		Open an existing resource
Open Binary Data	CTRL+B	Open a resource for binary editing
Properties...	ALT+ ENTER	Change a resource's properties
Import...		Import a bitmap, cursor, or icon into your project
Export		Export a bitmap, cursor, or icon and save it in a separate file
ClassWizard	CTRL+W	Connect user-interface objects to code
Test	CTRL+T	Test a dialog box
View as Popup	CTRL+U	View a menu resource as a pop-up menu
New Device Image...	INS	Create new icon or cursor images
Open Device Image...		View and edit an icon or cursor image for a device
Delete Device Image		Delete an icon or cursor image for a device
New String	INS	Add a string to a string table
New Accelerator	INS	Add an accelerator to an accelerator table


 Laying Out Dialog Boxes

The Layout menu appears only when the dialog editor window is active.

Layout	Key	Use To
Align Controls		Align controls along one edge or center them on an axis
Space Evenly		Equalize spacing between three or more aligned controls
Center in Dialog		Center controls in a dialog box
Arrange Buttons		Align buttons at right edge or bottom of dialog box
Make Same Size		Equalize dimensions of selected controls
Size to Content	F7	Size a control to fit its contents
Grid Settings...		Set dimensions of layout grid
Set Tab Order	CTRL+D	Set order of TAB key movement among controls


 Working with Images

The Image menu appears only when an image editor window (for editing bitmaps, icons, or cursors) is active.

Image	Key	Use To
Zoom In/Out	M	Toggle between actual-size and magnified views
Pickup Color	COMMA	Pick up color from a bitmap, icon, or cursor
Set Hotspot		Set a cursor's hotspot
Invert Colors		Invert colors in the selection
Flip Vertical	Y	Flip the selection along its vertical axis
Flip Horizontal	X	Flip the selection along its horizontal axis
Edit Foreground   Color...		Edit the current foreground color
Get Palette Colors...		Load colors from a file
Save Palette Colors...		Save colors to a file
Draw Opaque	O	Make background color opaque
Grid Settings...		Show and hide pixel and tile grids; change grid dimensions


 Managing App Studio

Window	Key	Use To
Cascade		Arrange windows in overlapping pattern
Tile Horizontal		Arrange windows one above the other
Tile Vertical		Arrange windows side-by-side
Arrange Icons		Arrange icons along bottom of App Studio window
Toolbar		Show or hide the toolbar
Status Bar		Show or hide the status bar
Hide Graphics Palette	F2	Hide the graphics palette
Show Graphics Palette	F2	Show the graphics palette
Hide Control Palette	F2	Hide the control palette
Show Control Palette	F2	Show the control palette
Show Properties	SHIFT+ F2	Show or hide the Properties window


 Getting Online Help

Help	Key	Use To
Contents	F1	Open the Help Contents screen
Search...		Search for a keyword in Help
Product Support		Get information on product support
About App Studio...		Get information about your copy of App Studio


 Toolbar and Palette Reference

This section describes the buttons and other controls on App Studio's toolbars, control bars, and palettes.


 The App Studio Toolbar


The Properties Window Toolbar
 The Properties Window Control Bar


 The Dialog Editor Toolbar

This toolbar appears at the top of a dialog editor window.


 The Graphics Editor Palette

This palette appears when an image editor window is active.


 The Control Palette


The Icon Editing Toolbar
 The Icon Editing Control Bar

This toolbar appears at the top of an image editor window that contains an icon.


 The Cursor Editing Toolbar

This toolbar appears at the top of a image editor window that contains a cursor.


 Key Reference

This section lists accelerator keys for common tasks.


 Managing Files

To	Press
Create a new file	CTRL+N
Create a new resource script	F11
Open a file	CTRL+O
Save the current resource script	CTRL+S, SHIFT+F12
Save the resource script under a different name or as a different type	F12


 Editing

To	Press
Undo an action	CTRL+Z
Redo the last undo	CTRL+A
Delete to the Clipboard	CTRL+X, SHIFT+DEL
Copy to the Clipboard	CTRL+C, CTRL+INS
Paste from the Clipboard	CTRL+V, SHIFT+INS
Delete	DEL
View and change symbols	CTRL+I


 Creating and Editing Resources

To	Press
Create a new resource	CTRL+R
Create a new resource in resource browser window, string editor, accelerator editor, Symbol Browser	ALT+N
Create a resource of type currently highlighted in the resource browser window	INS
Create a new dialog box	CTRL+1
Create a new menu	CTRL+2
Create a new cursor	CTRL+3
Create a new icon	CTRL+4
Create a new bitmap	CTRL+5
Create a new string table	CTRL+6
Create a new accelerator table	CTRL+7
Delete a resource in resource browser window, string editor, accelerator editor, Symbol Browser	ALT+D
Open an existing resource selected in the resource browser window	ENTER ALT+P
Open a resource for binary editing	CTRL+B
Activate a resource's Properties window	ALT+ENTER, ENTER
Connect a user-interface objects to code (invoke ClassWizard)	CTRL+W
Test a dialog box	CTRL+T
Open the Properties window and select Styles property page	CTRL+Y
Open the Properties window and select General property page	CTRL+E
Open the Properties window and select ID control	CTRL+Q


 Managing Windows

To	Press
Hide or show the graphics palette or control palette	F2
Hide or show the Properties window	SHIFT+F2
Activate next window	CTRL+F6, CTRL+TAB
Activate previous window	CTRL+SHIFT+F6, CTRL+SHIFT+TAB
Close current window	CTRL+F4
Activate the Properties window	ALT+ENTER, ALT+F6, enter (except in resource browser window)
Activate resource browser window	CTRL+F2
Scroll vertically	PAGE UP, PAGE DOWN
Scroll horizontally	CTRL+PAGEUP, CTRL+PAGEDOWN
Move resource browser window focus to the Resources box	RIGHT ARROW
Move resource browser window focus to the Type box	LEFT ARROW
Shift resource browser window focus between Resources and Type boxes	TAB, SHIFT+TAB


 Using the Properties Window

To	Press
Activate Properties window	ALT+ENTER
Select next page	PAGE DOWN
Select previous page	PAGE UP
Move to next field	TAB
Move to previous field	SHIFT+TAB
Hide or show the Properties window	SHIFT+F2
Open the Properties window and select Styles property page	CTRL+Y
Open the Properties window and select General property page	CTRL+E
Open the Properties window and select ID control	CTRL+Q
Accept changes	ENTER
Cancel change	ESC


 Editing Graphics

To	Press
Increase the magnification factor	> (SHIFT+PERIOD)
Decrease the magnification factor	< (SHIFT+COMMA)
Use framed-rectangle tool	R
Use filled-rectangle tool	SHIFT+R
Use framed rounded-rectangle tool	N
Use filled rounded-rectangle tool	SHIFT+N
Use framed-ellipse tool	E
Use filled-ellipse tool	SHIFT+E
Use pencil tool	P
Use eraser tool	SHIFT+P
Use brush tool	D
Use selection tool	S
Use fill tool	F
Use line tool	L
Use airbrush tool	A
Pick up color	COMMA
Increase brush size	PLUS, EQUAL SIGN
Decrease brush size	MINUS
Use single-pixel brush	PERIOD
Flip along horizontal axis	X
Flip along vertical axis	Y
Toggle background-color opacity	O
Outline custom brush with foreground color	SHIFT+O
Toggle pixel grid	G
Zoom under cursor	M
Use zoom tool	Z
Use custom brush	CTRL+B
Halve size of custom brush	MINUS
Double size of custom brush	PLUS
New device image for icons and cursors	INS
Move to next pane	TAB, F6
Move to previous pane	SHIFT+TAB, SHIFT+F6
Select previous foreground color	[
Select next foreground color	]
Select previous background color	{
Select next background color	}
Show or hide pixel grid	G
Show or hide tile grid	CTRL+G


 Using the Dialog Editor

To	Press
Move to the next control	TAB
Move to the previous control	SHIFT+TAB
Move control right one DLU	RIGHT ARROW
Move control left one DLU	LEFT ARROW
Move control up one DLU	UP ARROW
Move control down DLU	DOWN ARROW
Expand the selected control horizontally	SHIFT+RIGHT ARROW
Contract the selected control horizontally	SHIFT+LEFT ARROW
Expand the selected control vertically	SHIFT+DOWN ARROW
Contract the selected control vertically	SHIFT+UP ARROW
Align selected controls along left edge	CTRL+LEFT ARROW
Align selected controls along right edge	CTRL+RIGHT ARROW
Align selected controls along top edge	CTRL+UP ARROW
Align selected controls along bottom edge	CTRL+DOWN ARROW
Align selected controls horizontally on centerlines	F9
Align selected controls vertically on centerlines	SHIFT+F9
Center selected control vertically in dialog box	CTRL+F9
Center selected control horizontally in dialog box	CTRL+SHIFT+F9
Space selected controls evenly across	ALT+RIGHT ARROW
Space selected controls evenly down	ALT+DOWN ARROW
Align buttons at right edge of dialog box	CTRL+B
Align buttons at bottom of dialog box	CTRL+SHIFT+B
Make selected controls same width	CTRL+MINUS
Make selected controls same height	CTRL+BACKSLASH
Make selected controls same height and width	CTRL+EQUAL
Size control to content	F7
Show or hide alignment grid	CTRL+G
Set tab order	CTRL+D


 Using the Menu Editor

To	Press
View menu as pop-up	CTRL+U
Insert empty menu at current location	INS
Delete menu item	DEL


 Using the String Editor

To	Press
Find text	ALT+F3, CTRL+F
Find next occurrence of text	F3
Add new string	INS
Delete current string	DEL


 Editing Resources as Binary Data

To	Press
Move selection right	RIGHT ARROW
Move selection left	LEFT ARROW
Move selection up	UP ARROW
Move selection down	DOWN ARROW
Move between hexadecimal and ASCII listings	TAB


 Getting Online Help

To	Press
Open the Help Contents screen	F1


Chapter 11: Property Page Reference
 Chapter 11  Property Page Reference

This chapter provides detailed information about each of the App Studio property pages. Property pages are displayed in the App Studio Properties window and are used to control the appearance and behavior of Windows resources. For more information about the App Studio Properties window and how to use it, see »Using the Properties Window«.


 Resource Property Page

The following properties are available in the Properties window when a resource is selected in the resource browser window but the editing window for that resource is not open, or when the editing window is open but minimized:

ID

The resource's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. (For string tables, the ID is always STRINGTABLE and cannot be modified.) Type: Symbol, Integer, or Quoted String.

Preload

Determines if the resource is loaded when the application starts up (True) or is not loaded until it is called (False). Equivalent to the PRELOAD and LOADONCALL resource compiler statements. Type: Bool. Default: False.

Moveable

Permits the resource to be moved to compact memory if necessary (True), or causes it to remain at a fixed memory location. Equivalent to the MOVABLE and FIXED resource compiler statements. Type: Bool. Default: True.

Discardable

Allows the resource to be purged from memory if no longer needed. When the resource is needed again, it is loaded from disk. Type: Bool. Default: True.

Pure

Prevents the resource from being dynamically modified by the application at run time if set to True. If Pure is False, your application cannot have more than one instance running at a time. Has no effect for standard resource types in Microsoft Foundation Class Library applications. Made available for user resource types and backward compatibility with real-mode applications. Type: Bool. Default: True.

Bitmaps, icons, and cursors also have the following fields in the Resource property page:

Filename

The name of the file containing the bitmap, icon, or cursor resource.

Preview

A box showing what the bitmap, icon, or cursor looks like. Useful for browsing through graphics resources without opening them.


Accel Table: Accel Properties  General
 Accel Table: Accel Properties — General

ID

The resource's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol or Integer.

Key

The accelerator key. Can be one of the following (see »Typing in Accelerator Values« , Chapter 5, for more information):

•	Integer — Range 0 to 255. Interpreted as ASCII or virtual-key value, depending on the Type property. Single digits are interpreted as a key value. To enter an ASCII value from 0 to 9, precede the number with two zeros (for example, 006).

•	Character — Single character optionally preceded by ^ to signify a control character.

•	Virtual key identifier — Any one of the virtual-key identifiers in the drop-down list.

Modifiers

Indicate whether the accelerator is a combination formed with Ctrl, Alt, or Shift. When the key is an ASCII key, Ctrl and Shift are not available. Type: Bool. Defaults: Ctrl is True, Alt and Shift are False.

Type

Specifies whether the Key property is an ASCII value or a virtual key (VirtKey) value.

Next Key Typed

When you choose this command, the next key combination typed changes the Key and Modifiers values appropriately. The key is always interpreted as a virtual key if possible.


Bitmap Properties  General
 Bitmap Properties — General

ID

The resource's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol, Integer, or Quoted String.

Filename

The name of the file containing the bitmap resources.

Width

Image width in pixels. Type: Integer. Default: 48.

Height

Image height in pixels. Type: Integer. Default: 48.

Colors

Monochrome (2) or 16. The number of colors in a bitmap is determined by the current display device.

Save Compressed

Saves the image in compressed format to save space; useful for large bitmaps. Only color bitmaps can be compressed. Type: Bool. Default: False.


Cursor Properties  General
 Cursor Properties — General

ID

The resource's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol, Integer, or Quoted String.

Filename

The name of the file containing the cursor resource.

The following properties are displayed only and cannot be modified on the property page:

Width

Image width in pixels. This property is determined by the target-device definition selected by the user.

Height

Image height in pixels. This property is determined by the target-device definition selected by the user.

Hotspot

Location of the cursor's active area. In pixels, relative to the upper-left corner (0,0). Set with the Set Hotspot command on the Image menu.


Dialog Properties  General
 Dialog Properties — General

ID

The resource or resource object's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol, Integer, or Quoted String.

Caption

The text that appears as part of the dialog box to label it. Default: A name based on the type of resource (in this case, "Dialog") plus a number based on the resource identifier assigned by App Studio.

Font Name

The typeface of the font that will be used in all the controls in the dialog box. The bold version of the typeface is always used. Change this value by choosing the Font command in the lower-left corner of the property page. Default: MS Sans Serif.

Font Size

The point size of the font that will be used in all the controls in the dialog box. Default: 8 points. Change this value by choosing the Font command in the lower-left corner of the property page.

Font

Choose the Font command to change the typeface or size of the dialog-box font.

Menu

Contains the resource identifier of the menu used in the dialog box, if any. Type: Resource identifier. Default: None.

X Pos

The x-coordinate, in dialog box units (DLUs), of the upper-left corner of the dialog box. Type: Integer.

Y Pos

The y-coordinate, in DLUs, of the upper-left corner of the dialog box. Type: Integer.

Registered Class

Identifier of a registered dialog class (a Windows operating system window class, not to be confused with a C++ class). Provided to support C programming. If you are using a resource file with Microsoft Foundation Class Library support, this option is disabled. Type: Integer or String. String must be in double quotes. Default: None.


Dialog Properties  Styles
 Dialog Properties — Styles

Style

One of the following:

•	Overlapped — Creates an overlapped window. An overlapped window is always a top-level window and should have a caption and a border.

•	Popup (Default) — Creates a pop-up window.

•	Child — Creates a child window.

Border

One of the following:

•	None — No border. A title bar is not available.

•	Thin — A thin border.

•	Resizing — Creates a thick border that can be used to resize the dialog box.

•	Dialog Frame (Default) — A dialog-box border.

Minimize Box

Creates a minimize box for the dialog box. Disabled if there is no title bar. Type: Bool. Default: False.

Maximize Box

Creates a maximize box for the dialog box. Disabled if there is no title bar. Type: Bool. Default: False.

Titlebar

Creates a title bar for the dialog box. Disabled if the dialog box has no border. Type: Bool. Default: True.

System Menu

Creates a system menu for the dialog box. Disabled if there is no title bar. Type: Bool. Default: True.

Horiz. Scroll

Creates a horizontal scroll bar for the dialog box. Type: Bool. Default: False.

Vert. Scroll

Creates a vertical scroll bar for the dialog box.

If you create horizontal or vertical scroll bars for a dialog box that uses the default border style (the Dialog Frame style), the scroll bars are drawn overlapping the borders of the dialog rather than within them and the contents of the dialog box are clipped improperly. This is standard Windows behavior. To avoid this behavior, use a different border style when creating a scrollable dialog box.Type: Bool. Default: False.

Clip Siblings

Clips child windows relative to each other; that is, when a particular child window is repainted, this style clips all other top-level child windows out of the region of the child window to be updated. If Clip Siblings is False and child windows overlap, it is possible, when drawing in the client area of a child window, to draw in the client area of a neighboring child window. For use with child windows only. Type: Bool. Default: False.

Clip Children

Excludes the area occupied by child windows when drawing within the parent window. Used when creating the parent window. Do not use this style if your dialog box contains a group box. Type: Bool. Default: False.

System Modal

Creates a system-modal dialog box. A system-modal dialog box prohibits switching to another window or program while the dialog box is active. Type: Bool. Default: False.

Absolute Align

Determines whether the dialog box is aligned relative to the screen or relative to its parent window. If True, the dialog is displayed at coordinates relative to the upper-left corner of the screen. Type: Bool. Default: False.

NoIdleMsg

Suppresses the WM_ENTERIDLE message ordinarily sent to a dialog box's owner when no more messages are waiting in its message queue. Type: Bool. Default: False.

LocalEdit

 Specifies that edit-box controls in the dialog box will use memory in the application's data segment. Normally all edit-box controls in dialog boxes use memory outside the application's data segment. Type: Bool. Default: False.

Visible

Specifies that the dialog box is visible when first displayed. Set this property to False for form views and dialog-bar template resources. Type: Bool. Default: True.

Disabled

Creates a dialog box that is initially disabled. Type: Bool. Default: False.


Dialog: Check Box Properties  General
 Dialog: Check Box Properties — General

ID

The resource's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol or Integer.

Caption

The text that appears as part of the control to label it. To make one of the letters in the caption of a control the mnemonic key, precede it with an ampersand (&). Default: A name based on the type of control (for example, "Check") plus a number based on the resource identifier assigned by App Studio.

Visible

Determines whether or not the control is visible when the application is first run. Type: Bool. Default: True.

Disabled

Determines if the resource is displayed as disabled when the dialog box is created. Type: Bool. Default: False.

Group

Specifies the first control of a group of controls in which the user can move from one control to the next by using the arrow keys. All controls in the tab order after the first control with the Group property set to False belong to the same group. The next control in the tab order with Group set to True ends the first group of controls and starts the next group. Type: Bool. Default: False.

Tabstop

Specifies that the user can move to this control with the TAB key. Type: Bool. Default: True.

Auto

Creates a check box that, when selected, automatically toggles between checked and unchecked states. You must set this property to True if you are using a group of check boxes with »Dialog Data Exchange«. Type: Bool. Default: True.

Left Text

Positions the check box's caption text to the left instead of to the right. Type: Bool. Default: False.

Tri-State

Creates a three-state check box. A three-state check box can be grayed as well as checked or not checked. A grayed check box indicates that the state represented by the control is undetermined. Type: Bool. Default: False.


Dialog: Combo Box Properties  General
 Dialog: Combo Box Properties — General

For a description of the following properties see »Dialog: Check Box Properties — General«:

ID
Caption
Visible
Disabled
Group
Tabstop

Combo boxes have an additional property:

Enter list choices

Contains the choices you want to appear in the combo box when the dialog is created. Press CTRL+ENTER at the end of each item in the list to move to the next line. This property is only available in resource files with Microsoft Foundation Class Library support.


Dialog: Combo Box Properties  Styles
 Dialog: Combo Box Properties — Styles

Type

Specifies the type of combo box. Can have one of the following values:

•	Simple — Creates a simple combo box that combines an edit-box control with a list control. The list is displayed at all times, and the current selection in the list is displayed in the edit-box control.

•	Dropdown (Default) — Creates a drop-down combo box. Same as a simple combo box, except the list is not displayed unless the user clicks a drop-down arrow at the right of the edit-box control portion of the combo box.

•	Drop List — Similar to the drop-down style, but the edit-box control is replaced by a static-text item that displays the current selection in the list.

For a description of the following styles see »Dialog: Edit Box Properties — Styles« (following) and »Dialog: List Box Properties — Styles«:

Owner Draw
Has Strings
Sort
Vert. Scroll
No Integral Height
Auto HScroll
Disable No Scroll
OEM Convert


Dialog: Edit Box Properties  General
 Dialog: Edit Box Properties — General

For a description of the following properties see »Dialog: Check Box Properties — General«:

ID
Visible
Disabled
Group
Tabstop


Dialog: Edit Box Properties  Styles
 Dialog: Edit Box Properties — Styles

Align Text

Text aligns left, centered, or right. In a multiline edit box, text is always aligned left. Default: Left.

Multiline

Creates a multiline edit-box control.

When the multiline edit-box control is in a dialog box, the default response to pressing the ENTER key is to activate the default button.

If AutoHScroll is selected, the multiline edit-box control automatically scrolls horizontally when the caret goes past the right edge of the control. To start a new line, the user must press ENTER. If AutoHScroll is not selected, the control automatically wraps words to the beginning of the next line when necessary. A new line is also started if the user presses ENTER, providing the Want Return property is set. The position of the wordwrap is determined by the window size. If the window size changes, the wordwrap position changes and the text is redisplayed.

Multiline edit-box controls can have scroll bars. An edit-box control with scroll bars processes its own scroll-bar messages. Edit-box controls without scroll bars scroll as described in the previous paragraph. They also process any scroll messages sent by the parent window. Type: BOOL. Default: False.

Horiz. Scroll

Provides a horizontal scroll bar for a multiline control. Type: Bool. Default: False.

Auto HScroll

Automatically scrolls text to the right when the user types a character at the end of the line. Type: Bool. Default: True.

Vert. Scroll

Provides a vertical scroll bar for a multiline edit-box control. Type: Bool. Default: False.

Auto VScroll

In a multiline control, automatically scrolls text up one line when the user presses ENTER on the last line. Type: Bool. Default: False.

Password

Displays all characters as an asterisk (*) as they are typed into the edit-box control. Not available in multiline controls. Type: Bool. Default: False.

No Hide Sel

Changes the way text is displayed when an edit box loses and regains focus. Normally, existing text in an edit box is hidden when the control loses focus and is displayed as inverted text when the control regains focus. If NoHideSel is set to True, selected text in a edit box is displayed as selected at all times. Type: Bool. Default: False.

OEM Convert

Converts text entered in the edit-box control from the Windows character set to the OEM character set and then back to the Windows set. This ensures proper character conversion when the application calls the AnsiToOem function to convert a Windows string in the edit-box control to OEM characters. This style is most useful for edit-box controls that contain filenames. Type: Bool. Default: False.

Want Return

Specifies that a carriage return be inserted when the user presses the ENTER key while entering text into a multiline edit-box control in a dialog box. If this style is not specified, pressing the ENTER key has the same effect as pressing the dialog box's default pushbutton. This style has no effect on a single-line edit-box control. Type: Bool. Default: False

Border

Creates a border around the edit box. Type: Bool. Default: True.

Uppercase

Converts all characters to uppercase as they are typed into the edit box. Type: Bool. Default: False.

Lowercase

Converts all characters to lowercase as they are typed into the edit box. Type: Bool. Default: False.

Read Only

Prevents the user from typing or editing text in the edit box. Type: Bool. Default: False.


Dialog: Group Box Properties  General
 Dialog: Group Box Properties — General

For a description of the following properties see »Dialog: Check Box Properties — General«:

ID
Caption
Visible
Disabled
Group
Tabstop (Default: False)


Dialog: List Box Properties  General
 Dialog: List Box Properties — General

For a description of the following properties see »Dialog: Check Box Properties — General«:

ID
Visible
Disabled
Group
Tabstop


Dialog: List Box Properties  Styles
 Dialog: List Box Properties — Styles

Selection

Determines how items in a list box can be selected. Possible values are as follows:

•	Single (default) — Only one item in a list box can be selected at a time.

•	Multiple — More than one list-box item can be selected, but the SHIFT and CTRL keys have no effect. Clicking or double-clicking an unselected item selects it. Clicking or double-clicking a selected item deselects it.

•	Extended — The SHIFT and CTRL keys can be used together with the mouse to select and deselect list-box items, select groups of items, and select non-adjacent items.

Owner Draw

Controls the owner-draw characteristics of the list box. Can be one of the following values:

•	No (default) — Turns off the owner-draw style. The list box contains strings.

•	Fixed — Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are the same height.

CWnd::OnMeasureItem is called when the list box is created and CWnd::OnDrawItem is called when a visual aspect of the list box has changed.

•	Variable — Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are variable in height.

CWnd::OnMeasureItem is called for each item in the list when the list box is created and CWnd::OnDrawItem is called when a visual aspect of the list box has changed.

Has Strings

Specifies that an owner-draw list box contains items consisting of strings. The list box maintains the memory and pointers for the strings so the application can use the LB_GETTEXT message to retrieve the text for a particular item. By default, all list boxes except owner-draw list boxes have this style. An application can create an owner-draw list box either with or without this style.

This style is only available if the Owner Draw property is set to either Fixed or Variable. If Owner Draw is set to No, the list box contains strings by default. Type: Bool. Default: True.

Border

Creates a list box with a border. Type: Bool. Default: True.

Sort

Sorts the contents of the list box alphabetically. Type: Bool. Default: True.

Notify

Notifies the parent window if a list item has been clicked or double-clicked. Type: Bool. Default: True.

Multicolumn

Specifies a multicolumn list box that is scrolled horizontally. The LB_SETCOLUMNWIDTH message sets the width of the columns. Type: Bool. Default: False.

Horiz. Scroll

Creates a list box with a horizontal scroll bar. Type: Bool. Default: False.

Vert. Scroll

Creates a list box with a vertical scroll bar. Type: Bool. Default: True.

No Redraw

Specifies that the list box's appearance is not updated when changes are made. This style can be changed at any time by sending a WM_SETREDRAW message or by calling CWnd::SetRedraw. Type: Bool. Default: False.

Use Tabstops

Allows a list box to recognize and expand tab characters when drawing its strings. The default tab positions are 32 dialog box units. Type: Bool. Default: False.

Want Key Input

Specifies that the owner of the list box receives WM_VKEYTOITEM or WM_CHARTOITEM messages whenever the user presses a key and the list box has the input focus. This allows an application to perform special processing on the keyboard input. If a list box uses the Has Strings style, the list box receives WM_VKEYTOITEM messages. If a list box does not use the Has Strings style, it receives WM_CHARTOITEM messages. Type: Bool. Default: False.

Disable No Scroll

Shows a disabled vertical scroll bar in the list box when the box does not contain enough items to scroll. Without this style, the scroll bar is hidden when the list box does not contain enough items. Type: Bool. Default: False.

No Integral Height

Specifies that the size of the list box is exactly the size specified by the application when it created the list box. Normally, Windows sizes a list box so that the list box does not display partial items. Type: Bool. Default: True.


Dialog: Picture Properties  General
 Dialog: Picture Properties — General

For a description of the following properties see »Dialog: Check Box Properties — General«:

ID
Visible
Disabled
Group
Tabstop (Default: False)

Static graphics have additional general properties:

Type

Sets the type of static graphic to display. One of the following:

•	Frame (Default) — Displays a frame. You set the color of the frame in the Color box. Use a frame to visually group controls.

•	Icon — Displays an icon in the dialog box. Use the Icon box to specify the identifier of the icon you want to display.

•	Rectangle — Displays a filled-in rectangle. You set the color of the rectangle in the Color box.

Icon

Sets the resource identifier of the icon to be displayed.

Color

Sets the color of a frame or rectangle to black, white, or gray. This property is not available when the picture type is icon. Default: Black.


Dialog: Pushbutton Properties  General
 Dialog: Pushbutton Properties — General

For a description of the following properties see »Dialog: Check Box Properties — General«:

ID
Caption
Visible
Disabled
Group
Tabstop

Pushbuttons have additional general properties:

Default Button

If True, the control is the default button in the dialog box. The default button is selected (drawn with a heavy black border) when the dialog box first appears and is executed if the user presses ENTER without choosing another command in the dialog box. Windows allows only one default button in a dialog box. Type: Bool. Default: False.

Owner Draw

Creates an owner-draw button. Use an owner-draw button when you need to customize the appearance of a control by providing your own OnDrawItem message handler in the owner-window procedure (usually a dialog-box procedure or class derived from the Microsoft Foundation classes CDialog or CFormView). You can also derive your own class from CButton and override CButton::DrawItem. See CWnd::OnDrawItem and CButton::OnDraw in the Class Library Reference for more information.

This property must be set to define a bitmap button in a dialog box using the CBitmapButton class. Type: Bool. Default: False


Dialog: Radio Button Properties  General
 Dialog: Radio Button Properties — General

For a description of the following properties see the »Dialog: Check Box Properties — General«:

ID
Caption
Visible
Disabled
Group
Tabstop (Default: False)

Radio buttons also have additional general properties:

Auto

When the user selects a radio button with this property, the radio button is automatically selected and any other radio buttons in the same group are cleared (deselected). You must set this property to True if you are using a group of check boxes with »Dialog Data Exchange«. Type: Bool. Default: True.

Left Text

Places the radio button's caption text on the left rather than the right. Type: Bool. Default: False.


Dialog: Scrollbar Properties  General
 Dialog: Scrollbar Properties — General

For a description of the following properties see the »Dialog: Check Box Properties — General«:

ID
Visible
Disabled
Group
Tabstop (Default: False)

Scroll bars have an additional general property:

Align

One of the following values:

•	None (Default) — No special alignment is performed. The size of the scroll bar is the size specified in App Studio.

•	Top/Left — Aligns the upper-left corner of the scroll bar with the upper-left corner of the containing window specified in App Studio.

•	Bottom/Right — Aligns the lower-right corner of the scroll bar with the lower-right corner of the containing window specified in App Studio.


Dialog: Text Properties  General
 Dialog: Text Properties — General

For a description of the following properties see »Dialog: Check Box Properties — General«:

ID
Caption
Visible
Disabled
Group (Default: True)
Tabstop (Default: False)

Static text controls have additional general properties:

No Prefix

Prevents ampersands (&) in the control's text from being interpreted as the mnemonic character. Normally a string containing an ampersand is displayed with the ampersand removed and the next character in the string underlined. The No Prefix style is most often used when filenames or other strings that may contain an ampersand need to be displayed.

No Wrap

Displays text left-aligned. Tabs are expanded but words are not wrapped. Text that extends past the end of a line is clipped. Type: Bool. Default: False.

Simple

Disables No Wrap and Text Align. Text in static text controls with this property set does not wrap and is not clipped. In addition, setting this property means that overriding WM_CTLCOLOR in the parent window has no effect on the control. Type: Bool. Default: False.

Text Align

Controls how text is aligned in the static-text control. Possible values are Left, Center, and Right. Set to Left when No Wrap is selected. Default: Left.


Dialog: User Control Properties  General
 Dialog: User Control Properties — General

For a description of the following properties see »Dialog: Check Box Properties — General«:

ID
Caption
Visible
Disabled
Group
Tabstop

User-defined controls have additional general properties:

Class

The name of the control's Windows class. This class must be registered before the dialog box containing the control is created.

Style

A 32-bit hexadecimal value specifying the control's style, primarily used to edit the lower 16 bits that make up a user control's sub-style.


Icon Properties  General
 Icon Properties — General

ID

The resource or resource object's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol, Integer, or Quoted String.

Filename

The name of the file containing the icon resource.

The following properties are displayed only and cannot be modified on the property page:

Width

Image width in pixels. This property is determined by the currently selected target-device definition.

Height

Image height in pixels. This property is determined by the currently selected target-device definition.

Colors

Monochrome (2) or 16. This property is determined by the currently selected target-device definition.


Menu Properties  General
 Menu Properties — General

ID

The resource or resource object's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol, Integer, or Quoted String.


Menu: Menu Item  General
 Menu: Menu Item — General

ID

The resource's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol or Integer.

Caption

The text that appears as part of the menu item to label it. To make one of the letters in the caption of a menu item the mnemonic key, precede it with an ampersand (&).

Separator

If True, the menu item is a separator. Type: Bool. Default: False.

Checked

If True, the menu item is initially checked. Type: Bool. Default: False.

Popup

If True, the menu item is a pop-up menu (a submenu). Type: Bool. Default: True for top-level menu items in a menu bar; otherwise False.

Grayed

If True, the menu item is initially grayed and inactive. Type: Bool. Default: False.

Inactive

If the Grayed property is True, then the Inactive property is always True. Otherwise Inactive determines whether the menu item is initially inactive. Type: Bool. Default: False.

Help

Right justifies the menu item in the menu bar at run time. Type: Bool. Default: False.

Break

Can be one of these values:

•	None (Default) — No break

•	Column — For static menu-bar items, places the item on a new line. For pop-up menus, places the item in a new column with no dividing line between the columns. Setting this property affects the appearance of the menu only at run time, not in the menu editor.

•	Bar — Same as Column except, for pop-up menus, separates the new column from the old column with a vertical line. Setting this property affects the appearance of the menu only at run time, not in the menu editor.

Prompt

Contains text to appear in the status bar when this menu item is highlighted. The text entered here is placed in the string table with the same identifier as the menu item. Available only in resource files with Microsoft Foundation Class Library support.


String Editor: String Properties  General
 String Editor: String Properties — General

ID

The resource or resource object's identifier. Usually the resource ID is a symbol supplied by App Studio and defined in the .H file that App Studio creates as part of your project. Type: Symbol or Integer.

Caption

A string of up to 255 bytes (single characters, escape sequences, or ASCII values). See »Editing a String's Properties« for more information about entering escape sequences and ASCII values as part of the string. Type: Text.


Initializing and Configuring App Studio
 Appendix A  Initializing and Configuring App Studio

With Windows NT, App Studio stores information about initialization and configuration within the system configuration registry. Most of the settings in the Registry are read-write: App Studio reads them at startup and writes them at the end of the session if they have changed. Other settings are "read-only": App Studio reads them at startup but never writes them. The only way that you can change this read-only information is to use the Registry Editor, REGEDT32.EXE. For more information on using the Registry Editor, refer to Windows NT Help.

The Registry is divided into keys, which are represented as folders in the Registry Editor. To modify the keys specific to App Studio, open the App Studio key, which can be found under HKEY_CURRENT_USER\Software\Microsoft. The App Studio key is further subdivided into keys.

This appendix describes the read-only settings you can use to customize App Studio's behavior. Each key contains one or more entries consisting of a value and a string or number, which are shown in the right-hand pane of the Registry Editor. The appendix shows both the key and the value. The Registry also requires that you provide the type for numbers and strings included in an entry. All numerical values within an entry (Booleans, levels, integers) should be of type REG_DWORD and that of strings should be REG_SZ.


 Setting the Default .RC File Type

Key Name: App Studio\General
Name: UseMFC
Type: REG_DWORD
Data: Bool

This entry is equivalent to the Use Microsoft Foundation Classes check box in the New dialog box. If Bool is 1, the check box is checked by default; if Bool is 0, the check box is cleared by default. If the check box is checked, App Studio creates a resource script (.RC) file that supports Microsoft Foundation Class Library features such as ClassWizard. If the check box is cleared, App Studio creates a standard resource script (.RC) file.


 Setting the Number of Undo Levels

Key Name: App Studio\General
Name: UndoLevels
Type: REG_DWORD
Data: levels

The number of undo operations is limited to the number specified by levels. If this entry does not appear in the Registry, the default of 10 is used.


 Using Default Dialog-Box Buttons

Key Name: App Studio\Dialog Editor
Name: Initial Buttons
Type: REG_DWORD
Data: Bool

If Bool is 1, dialog-box templates are created with the OK and Cancel buttons. If Bool is 0, they are not.


 Setting the Default Magnification Factor

Key Name: App Studio\Graphics Editor
Name: Default Zoom
Type: REG_DWORD
Data: int

Sets the default value for the ratio of magnified and actual-size views in the image editor window. The range is 2 to 10. If this entry does not appear in  the Registry, the default of 6 is used.


 Describing Cursor Devices

Key Name: App Studio\Cursor Devices
Name: name
Type: REG_SZ
Data: colors[,]width[,]height

Specifies the names of display devices and the attributes of their corresponding cursor images. The name of the device is specified by name. It appears in the New Cursor Image dialog box when you add an image to a cursor. The colors, width, and height entries specify the number of colors supported by the device (subject to App Studio's limit of 16 colors) and the image size in pixels. Windows currently supports only monochrome cursors.


 Describing Icon Devices

Key Name: App Studio\Icon Devices
Name: name
Type: REG_SZ
Data: colors[,]width[,]height

Specifies the names of display devices and the attributes of their corresponding icon images. The name of the device is specified by name. It appears in the New Cursor Image dialog box when you add an image to a cursor. The colors, width, and height entries specify the number of colors supported by the device (subject to App Studio's limit of 16 colors) and the image size in pixels.


Figure 5.1    Using the Accelerator Table Editor and Properties Window
1.	In the Type box, select Accelerator.

2.	In the Resources box, select an accelerator table to edit.

Figure 5.1    Selecting an Accelerator Table

»Next«


Figure 5.1    Using the Accelerator Table Editor and Properties Window
3.	In the Accelerator window, select an entry to modify.

Figure 5.1    Selecting an Accelerator Table Entry

»Next«     »Previous«


Figure 5.1    Using the Accelerator Table Editor and Properties Window
4.	Use the General property page to add or change values.

Figure 5.1    Using the Accelerator Table Properties Page

»Previous«


Figure 5.2    General Property Page for Accelerators


Figure 8.1    Binary Data Editor


Figure 9.1    Add Class Dialog Box


Figure 9.2    Import Class Dialog Box


Figure 9.3    Defining a Message or Command Handler


Figure 9.4    Add Variable Member Dialog Box


Figure 9.5    Dialog Data Validation


Figure 9.6    Password Dialog Box


Figure 9.7    DDX/DDV Example: Add Member Variable Dialog Box


Figure 9.8    DDX/DDV Example: Using Built-in DDV for a CString Variable


Figure 9.9    DDX/DDV Example Defining a DDX Control Variable


Figure 9.10    Repair Class Information Dialog Box


Figure 9.11    Select Files Dialog Box for Generating a New .CLW File


Figure 3.1    App Studio Controls


Figure 3.2    New Dialog Box
Figure 3.2    Dialog Editor Window and Control Palette

»Dialog Box Property Page«


Figure 3.2    New Dialog Box Property Page
Figure 3.2    Dialog Box Property Page

»Dialog Editor Window and Control Palette«


Figure 3.3    Dialog Editor Position Indicators


Figure 3.4    Dragging a Control from the Control Palette
1.	Click the radio-button button and drag the control
into the dialog box.

Figure 3.4    Dragging a Control from the Control Palette

»Next«


Figure 3.4    Dragging a Control from the Control Palette
2.	The cursor changes shape to show what you are dragging.

Figure 3.4    Dragging a Control to the Dialog Editor Window

»Next«     »Previous«


Figure 3.4    Dragging a Control from the Control Palette
3.	Release the mouse button to place the control.

Figure 3.4    Dropping a Control Into a Dialog Box

»Previous«


Figure 3.5    Selecting Multiple Controls


Figure 3.6    Sizing a Control›
Figure 3.6    Sizing a Control


Figure 3.7    Sizing the Drop-down Portion of a Combo Box


Figure 3.8    Setting Tab Order


Figure 3.9    Changing the Existing Tab Order


Figure 3.10    Dialog Editor Toolbar


Figure 3.11    Using Space Evenly Down
Figure 3.11    Before Using Space Evenly Down

»Next«


Figure 3.11    Using Space Evenly Down
Figure 3.11    After Using Space Evenly Down

»Previous«


Figure 3.12    Install Controls Dialog Box


Figure 3.13    General Property Page for a VBX Control


Figure 3.14    Styles Property Page for a VBX Control


Figure 3.15    General Property Page for a User-Defined Control
Figure 3.14    General Property Page for a User-Defined Control


Figure 2.1    Using Drag and Drop to Copy Resources Between Files


Figure 2.2    Set Includes Dialog Box


Figure 2.3    Symbol Browser


Figure 7.1    Image Editor Window and Graphics Palette
Figure 7.1    Image Editor Window

»Graphics Palette«


Figure 7.1    Image Editor Window and Graphics Palette
Figure 7.1    Graphics Palette

»Image Editor Window«


Figure 7.2    Cross hairs for Defining the Selection


Figure 7.3    Border Enclosing the Selected Area


Figure 7.4    Cropping, Extending, Shrinking, and Stretching a Bitmap
Figure 7.4    Original Bitmap

»Next«


Figure 7.4    Cropping, Extending, Shrinking, and Stretching a Bitmap

Figure 7.4    Cropped Bitmap

»Next«     »Previous«


Figure 7.4    Cropping, Extending, Shrinking, and Stretching a Bitmap
Figure 7.4    Extended Bitmap

»Next«     »Previous«


Figure 7.4    Cropping, Extending, Shrinking, and Stretching a Bitmap
Figure 7.4    Shrunken Bitmap

»Next«     »Previous«


Figure 7.4    Cropping, Extending, Shrinking, and Stretching a Bitmap
Figure 7.4    Stretched Bitmap

»Previous«


Figure 7.5    Moving the Image-Editor Pane Splitter


Figure 7.6    Zooming in on the Actual-Size View


Figure 7.7    New Icon Image Dialog Box


Figure 7.8    Selectors for Screen Color and Inverse Color


Figure 7.9    Typical Toolbar Graphic


Figure 7.10    Grid Settings Dialog Box


Figure 7.11    Image Editor Window with a Tile Grid


Figure 7.12    Resizing the Toolbar Bitmap


Figure 7.13    Selecting Button Images


Figure 7.14    Moving the Selected Button Images


Figure 7.15    Color Dialog Box


Figure 7.16    Custom-Colors Dialog Box


Figure 4.1    Menu Terminology


Figure 4.2    Menu Editor New-Item Boxes


Figure 4.3    Example: Moving a Cascading Menu to the Menu Bar
1.	Click on a menu item to select the whole menu.

Figure 4.3    Example: Making a Drop-Down Menu a Cascading Menu

»Next«


Figure 4.3    Example: Moving a Cascading Menu to the Menu Bar
2.	Drag the pointer over the destination menu item and down into the second menu.
The insertion guide shows where the cascading menu will be inserted.

Figure 4.3    Making a Drop-Down Menu...

»Next«»Previous«


Figure 4.3    Example: Moving a Cascading Menu to the Menu Bar
3.	Drop the cascading menu when the insertion guide shows the position you want.

Figure 4.3   ...a Cascading Menu

»Previous«


Figure 1.1    App Studio Workspace


Figure 1.2    App Studio Resource Browser


Figure 1.3    Dragging and Dropping


Figure 1.4    App Studio Properties Window


Figure 1.5    Dialog Editor


Figure 1.6    Menu Editor


Figure 1.7    Accelerator Table Editor


Figure 1.8    String Editor


Figure 1.9    Graphics Editor


Figure 1.10    Binary Data Editor


Figure 1.11    Symbol Browser


Figure 1.12    Using Class Wizard to Define a Message Handler


Figure 1.13    Menu Example


Figure 1.14    Toolbar Bitmap Generated by AppWizard


Figure 1.15    Cursor Example: Dragging a Radio Button


Figure 6.1    Using the String Editor
1.	In the Type box, select String Table.

2.	In the Resources box, select a string segment to edit.

Figure 6.1    Selecting a String Segment

»Next«


Figure 6.1    Using the String Editor
3.	In the String Editor window, select the string to modify.

Figure 6.1    Selecting a String

»Next«»Previous«


Figure 6.1    Using the String Editor
4.	Use the General property page to edit the string or its ID.

Figure 6.1    Using the String Editor Property Page

»Previous«


Figure 12.1 Macros Used for Serialization and Run-Time Information
	CObject::IsKindOf	CRuntimeClass:: CreateObject	CArchive::operator>> CArchive::operator<<
Basic CObject functionality	No	No	No
DECLARE_DYNAMIC	Yes	No	No
DECLARE_DYNCREATE	Yes	Yes	No
DECLARE_SERIAL	Yes	Yes	Yes
Figure 12.1    Macros Used for Serialization and Run-Time Information


Figure 5.1    The App Studio Resource Browser


Figure 5.2    The Menu Editor


Figure 5.3    A Property Page


Figure 5.4    Menu Editor for IDR_SCRIBTYPE


Figure 5.5    Property Page with ID


Figure 5.6    Adding the Clear All Menu Item


Figure 5.7    The Pen Menu Dragged into Position


Figure 5.8    The Completed Pen Menu


Figure 5.9    The Default Toolbar Bitmap


Figure 5.10    Scribble with Its Edited Toolbar


Figure 5.11    Bitmap Selection in the Resource Browser


Figure 5.12    The Bitmap Image Window


Figure 5.13    The Grid Settings Dialog Box


Figure 5.14    The Scrolled Bitmap


Figure 5.15    The Graphics Palette


Figure 5.16    The Bitmap Dragged to the Right


Figure 5.17    Bitmap for the Thick Line Button


Figure 5.18    The Edited Bitmap


Figure 6.1    ClassWizard Dialog Box


Figure 6.2    Command Architecture


Figure 6.3    Command Target Class Hierarchy


Figure 6.4    Searching Message Maps


Figure 6.5    Clear All in ClassWizard


Figure 6.6    The OnEditClearAll Function Template


Figure 6.7    Adding the Data Members


Figure 6.8    ClassWizard Selections for OnUpdateEditClearAll


Figure 6.9    Scribble Step 2


Figure 7.1    Scribble's Pen Widths Dialog Box


Figure 7.2    Designing the Pen Widths Dialog Box with App Studio


Figure 7.3    The Add Class Dialog Box


Figure 7.4    The ClassWizard Dialog Box


Figure 7.5    The Edit Member Variables Dialog Box


Figure 7.6    Scribble Version 3


Figure 3.1    Scribble in Action


Figure 3.2    Objects in Scribble


Figure 3.3    Document and View


Figure 3.4    Creating a Document


Figure 3.5    One Stroke in Scribble


Figure 3.6    Scribbles m_strokeList Data Structure


Figure 3.7    Serialization in Scribble


Figure 10.1    Selecting Context-Sensitive Help


Figure 10.2    The Main Index Screen in Compiled Help


Figure 10.3    The Main Index Screen in PEN.RTF


Figure 10.4    The Pen Menu Topic in the PEN.RTF File


Figure 10.5    The Pen Widths and Thick Line Topics in the PEN.RTF File


Figure 2.1    AppWizard Dialog Box


Figure 2.2    The Document Class in the Classes Dialog Box


Figure 2.3    The View Class in the Classes Dialog Box


Figure 2.4    AppWizard Options Dialog Box


Figure 2.5    Compiling in Visual Workbench


Figure 2.6    The Starter Application


Figure 1.1    Document and View


Figure 1.2    Your Code in the Application Framework


Figure 1.3    Scribble in Action


Figure 1.4    The Project Options Dialog Box


Figure 9.1    The Printing Loop


Figure 9.2    Scribble Version 5


Figure 8.1    Multiple Views on a Document Without Updating


Figure 8.2    A Scrollable View on a Document


Figure 8.3    Scribble with Scrolling Support


Figure 8.4    A Window with Two Views on a Document


Figure 8.5    Scribble Document Window Split into Two Panes


Figure 8.6    Scribble Version 4


Figure 4.1    The View and the Document


Figure 4.2    The Main ClassWizard Dialog Box


Figure 4.3    Available Windows Messages in ClassWizard


Figure 4.4    The Visual Workbench Editor


Figure 4.5    Scribble Step 1


Introduction
Class Library User's Guide

Introduction

This manual contains a tutorial for the Microsoft Foundation Class Library. The class library is a set of C++ classes that encapsulate the functionality of applications written for the Microsoft® Windows™ family of operating systems.

Among the features covered in Chapters 1 through 10 of the tutorial are the following:

•	Using AppWizard to create a skeletal starter application upon which to build your program.

•	Implementing a document class to manage your application's data and to write to and read from files.

•	Implementing a "view" class to display your document and manage all user interaction with it.

•	Using App Studio to create and edit your application's resources.

•	Using ClassWizard to connect user-interface objects, such as menu items, buttons, and accelerator keys, to handler functions in your source code.

•	Using App Studio to create dialog-template resources and ClassWizard to encapsulate those resources in dialog classes. Also, arranging for automatic transfer of data between the controls in a dialog box and member variables of the dialog class and for automatic validation of data that the user enters.

•	Implementing scrolling and splitter windows, enhancing the default printing capabilities, and adding context-sensitive help to your application.

Chapters 11 through 17 explore additional features of programming with the Microsoft Foundation Class Library:

•	Using the diagnostic and exception-handling facilities.

•	Working with files and the "serialization" of objects to and from persistent storage.

•	Using the collection classes: arrays, lists, and maps.

•	Using Object Linking and Embedding (OLE).


Class Library User's Guide


 Document Conventions

This book uses the following typographic conventions:

Example	Description
STDIO.H	Uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
char, _setcolor, __far	Bold type indicates C and C++ keywords, operators, language-specific characters, and library routines. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
	Many constants, functions, and keywords begin with either a single or double underscore. These are required as part of the name. For example, the compiler recognizes the __cplusplus manifest constant only when the leading double underscore is included. It may be difficult at first glance to distinguish a single underscore from a double underscore because the two run together on the screen. Therefore, the width of the character(s) is your guide. The sample term setcolor, in the left column above, has one underscore in front of it, while the term far has two underscores in front of it.
expression	Words in italics indicate placeholders for information you must supply, such as a filename. Italic type is also used occasionally for emphasis in the text.
[option]	Items inside square brackets are optional.
#pragma pack {1 | 2}	Braces and a vertical bar indicate a choice among two or more items. You must choose one of these items unless square brackets ([ ] ) surround the braces.
#include <io.h>	This font is used for examples, user input, program output, and error messages in text.
CL [option...]  file...	Three dots (an ellipsis) following an item indicate that more items having the same form may appear.
while() {  .  .  . }	A column or row of three dots tells you that part of an example program has been intentionally omitted.
CTRL+ENTER	Small capital letters are used to indicate the names of keys on the keyboard. When you see a plus sign (+) between two key names, you should hold down the first key while pressing the second.
	The carriage-return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
"argument"	Quotation marks enclose a new term the first time it is defined in text.
"C string"	Some C constructs, such as strings, require quotation marks.
Dynamic-Link Library (DLL)	The first time an acronym is used, it is usually spelled out.
see »Using Projects«.	Hypertext cross-references are enclosed in green double chevrons. Click the term enclosed in the chevrons to display the referenced information.
CEnterDlg;	The blue box adjoining the blue code indicates that it has been altered from a previous example, usually because you are being instructed to edit it.


 Chapter 1  Introducing the Class Library

In this tutorial, you'll learn about the class library features and functions by creating an application for Microsoft Windows called Scribble.

In this Chapter

The chapter begins with an overview of the Microsoft Foundation Class Library and its supporting tools. It also covers the following topics:

•	»Designing programs with the class library«

•	»Using the tutorial«

•	»Working with the incremental versions of the tutorial program«

In Chapters to Come

Use the first ten chapters as an introduction to the Microsoft Foundation Classes or as a step-by-step tour through the fundamentals of writing applications for Windows with the class library. Use the remaining chapters to deepen your knowledge and to learn specific programming techniques for such topics as:

•	»Managing memory«

•	»Deriving classes from the root base class,« CObject

•	»Accessing run-time information« about the class objects in your application

•	»Using collection classes for aggregates of data«

•	»Serializing files« to and from disk

•	»Using the facilities for diagnostics and robustness«

•	»Handling exceptions«

•	»Programming for Object Linking and Embedding« (OLE)

Use »Appendix A« for a survey of new features in the Microsoft Foundation Class Library, general instructions for installing the class library, and the locations of sample programs and technical notes.


 What You Need to Know

The tutorial assumes that you have some knowledge of C++ and of programming for Windows. If you've already programmed with the Microsoft Foundation Class Library, you should find the transition straightforward. For information about migrating from version 1 of the class library to version 2, see Technical Note 19 in MSVCNT\HELP\MFCNOTES.HLP. However, if you've programmed with Windows in C, or with another C++ environment for Windows, you may find a different program structure to get used to. But inside that structure much of what you do resembles what you've done before.

You may wish to consult texts on C++ and on Windows and Windows NT. Microsoft Visual C++™ includes the C++ Tutorial, and Microsoft Press® publishes Kaare Christian's Microsoft Guide to C++ Programming and Charles Petzold's Programming Windows 3.1 (third edition). Another good C++ text is Stanley B. Lippman's C++ Primer (Addison-Wesley, second edition).  For a deeper understanding of Windows NT, you may want to read Helen Custer's Inside Windows NT, also published by the Microsoft Press.

With that base of knowledge, you should be able to follow the Foundation Class Library tutorial, especially if you have some C-language background.

Beyond those fundamental texts, available shortly after the release of Visual C++ from Microsoft Press, is David J. Kruglinski's Microsoft Visual C/C++ Programming for Windows. That book supplements the tutorial in this manual and provides deeper coverage of programming with the Foundation classes.


 Guide to Related Documentation

For a quick overview of the process of using Microsoft Visual C++, see Presenting Visual C++: In Our Own Words.

For an overview of the class library, see Chapters 1 through 6 in the Class Library Reference.

For reference information about the classes, global functions, and macros that make up the class library, see the alphabetic reference in the Class Library Reference.

Programmers using the Microsoft Foundation Class Library rely on several key tools. AppWizard creates a starter application. App Studio lets you construct your user interface and edit resources. ClassWizard helps you connect user-interface objects such as menus to code.

•	For information about using AppWizard, see »Chapter 2« in this manual and Chapter 13 in the Visual Workbench User's Guide.

•	For information about using App Studio, see the App Studio User's Guide.

•	For information about using ClassWizard, see »Chapter 6« and »Chapter 7« in this manual, Chapter 9 in the App Studio User's Guide, and Chapter 13 in the Visual Workbench User's Guide.

For information about using the Visual C++ programming environment, see the Visual Workbench User's Guide.

For C++ and C run-time library reference information, see the C++ Language Reference, the C Language Reference, and the Run-Time Library Reference.


 The Class Library

The Microsoft Foundation Class Library enables C++ programmers to write applications for Microsoft Windows. The class library gives you a complete "application framework." The framework defines an architecture for integrating the user interface of an application for Windows with the rest of the application. It also provides implementations for a large set of the user-interface components described in The Windows Interface: An Application Design Guide, available from Microsoft Press.

For a summary of what's new in the class library since version 1, see »Appendix A.«

In the tutorial, you'll learn to:

•	Quickly construct a user interface that follows the Windows Design Guide.

•	Easily implement both single document interface (SDI) and multiple document interface (MDI) applications.

•	Implement features that until now were considered difficult or tedious, such as printing, toolbars, scrolling, splitter windows, print preview, and context-sensitive help.

•	Take advantage of the many built-in or reusable components of the class library.

This section lists the main features of the class library and introduces the application framework and its associated visually-oriented programming tools: App Studio, AppWizard, and ClassWizard.


 Class Library Features

The Microsoft Foundation Class Library has the following features:

•	Powerful, visual tools that simplify programming:

•	AppWizard, a tool for creating a skeleton starter application on which to build your application-specific functionality.

•	App Studio, a tool for constructing your user interface and editing your resources.

•	ClassWizard, a tool for connecting Windows messages and user-interface objects such as menus to code.

•	A flexible program framework based on document objects that manage data, and view objects that manage user interaction with their documents.

•	Classes that encapsulate the Windows API: windows, dialog boxes, device contexts, GDI drawing objects, controls, and more.

•	Implementations for standard menus, including the following commands and their associated standard dialog boxes:

•	File menu: New, Open, Save, Save As, Print, Print Setup, Print Preview, Exit commands. Also support for the most-recently-used list of files. Open, Save, and Save As are supported by the framework's standard serialization mechanism.

•	Edit menu: Paste, Paste Link, and Links commands for OLE. Also support for OLE verbs.

•	View menu: Commands to toggle the display of a toolbar and status bar.

•	Window menu: New Window, Tile, Cascade, Hide, Show commands for multiple document interface (MDI) applications.

•	Help menu: Standard Index and Using Help commands.

•	Support for routing commands from user-interface objects, such as menu items and toolbar buttons, to command handlers.

•	Support for toolbars and status bars.

•	Support for scroller and splitter windows.

•	Support for forms and text editing windows.

•	Support for printing and print preview.

•	A simple program interface for initializing, validating, and accessing the data in dialog-box controls.

•	Support for Object Linking and Embedding (OLE) integrated with the  document/view architecture and support for OLE user interfaces.

•	Support for context-sensitive help.

•	Diagnostic facilities and exception handling.

•	Collection classes for managing aggregates of data.

•	File classes.

•	Compatibility with version 1 of the Microsoft Foundation Class Library.

The tutorial demonstrates many of these features, and the Visual C++ environment makes them easy and productive to use. The features are embodied in the framework and the tools.


 The Framework

The Microsoft Foundation Class Library is a group of C++ classes collectively known as an application framework. These classes provide the framework and essential components of an application for the Windows graphical environment. The purpose of the framework is to reduce the effort required to design and implement applications for Windows. The framework embodies the accumulated wisdom of experienced programmers for the Windows graphical environment.

Note  In the documentation, you'll see the terms "application framework" and "framework" used interchangeably. The classes that make up the framework are listed and explained in the Class Library Reference. Chapters 1 through 6 of the Class Library Reference explain how the framework works.

The application framework supplied by the Microsoft Foundation Class Library is powerful and easy to reuse because the framework is an object-oriented class library. Instead of editing the framework's source code directly, you derive new, specialized classes from those in the library. The derived classes inherit all of the behavior and functionality of their base classes, but you can extend them by adding new member variables and functions and modify the existing behavior by overriding inherited member functions.


 Key Concepts

The following are central concepts in the application framework:

•	At the heart of your application for Windows is an "application object."

The application object manages a list of documents and dispatches commands to other objects in the program.

•	The unit of data that the user works with is a document.

The document maintains, loads, and stores its data.

•	The user interacts with a document through a "view" on the document.

A view is a window embedded in the client area of a frame window. It displays its document's data and takes mouse and keyboard input, which it translates into selection and editing actions.

•	Objects in the user interface, such as menus and buttons, send commands to the documents, views, and other objects in the application. Those objects carry out the commands.

»Figure 1.1« shows the relationship between a document and its view.


 Working with the Framework

Your main tasks in using the framework are:

•	Defining your application's data in its document class(es).

•	Defining how the user views and interacts with the data inside a window.

•	Connecting menus, buttons, and other user-interface objects to commands, then defining handler functions to carry out the commands.

The general process is to use:

•	AppWizard to create the files for a skeleton starter application.

The classes in these files are derived from classes in the class library. The files contain, in particular, a document class, a view class, a frame window class, and an application class. AppWizard also creates an initial resource file and other supporting files.

•	App Studio to construct the user interface by creating and editing resources.

•	ClassWizard to connect user-interface objects to message-handler functions.

•	The Microsoft Visual Workbench editor and browser to implement the message-handlers  —  such as for menu commands.

•	The Visual Workbench editor also to edit all of your classes and to control the development cycle.

•	ClassWizard to define automatic processing of dialog data.

The tools described above are summarized in Chapter 7 of the Visual Workbench User's Guide.


 The Partnership

Your work with the Microsoft Foundation Class Library is a partnership. The  source code you add is your part. This includes code to:

•	Declare and implement the data structure of a document.

•	Serialize the document's data so it persists from one work session to the next, typically by writing it to and reading it from a file.

•	Display the data in a view.

•	Process keyboard and mouse-related messages from Windows.

•	Handle commands from menus and toolbar buttons.

•	Enhance the printing, scrolling, and window-splitting capabilities you get from the framework.

In addition to the source code that implements your application's functionality, you're responsible for:

•	Using App Studio to create and edit resources that define the user-interface elements of your program.

•	Optionally, editing the Rich-Text Format (RTF) files containing help topics for context-sensitive help.

The role of the framework in this partnership is to provide all of the many features detailed earlier in this chapter.


 Benefits

The Microsoft Foundation Class Library provides a thorough foundation that allows you to spend most of your programming effort writing the code that handles your data rather than reinventing the graphical user interface. For more information about the application framework, see Chapters 2 through 6 in the Class Library Reference.

»Figure 1.2« shows schematically how your code fits into the framework.

Because the framework provides so much standard functionality, it's easy to write applications that follow the recommendations of The Windows Interface: An Application Design Guide. At the same time, the framework's flexibility and extensibility don't lock you into Windows Design Guide conformance, although deviating from the standard may take a little more work.


 Introducing Scribble

It's a time-honored programming practice to begin work with a new system or language compiler by writing a program that prints "Hello, World!" on the display. When you begin programming in a graphical user interface (GUI) environment such as Microsoft Windows, however, the traditional practice is hard to follow. There's a fair amount of programming overhead  —  well in excess of the few lines of "Hello, World!"  —  simply to get a minimal GUI application running.

Scribble, the application you build in the tutorial, is a tiny drawing program. Something like Scribble poses a more realistic trial run in the Windows programming environment than "Hello, World!" Instead of printing that little phrase so familiar to programmers, Scribble lets the user draw "Hello, World!" (or any free-hand drawing) using the mouse, and save the image in a file.

By the end of the tutorial, Scribble has custom menus, a dialog box with automatic initialization and validation, printing and print preview, scrolling, splitter windows, context-sensitive Windows Help, and more. That's a fitting list of features for a GUI "Hello, World!" And, as you'll see, it's still quick to implement, considering the challenge.

»Figure 1.3« shows what Scribble looks like on the screen.


 Using the Tutorial

Some readers may wish to read the tutorial and study the supplied source code before venturing on a first framework application of their own. Others may wish to learn by adding code as they go. The tutorial can be used in either way. For details on procedure, see »Read Along« or »Work Along«.

Important  You must complete a chapter of the tutorial before the version of Scribble developed in that chapter will run.


 Tutorial Conventions

The tutorial uses the following textual conventions:

•	The names of all classes, functions, macros, and other items supplied as part of the Microsoft Foundation Class Library appear in boldface print. For example:

CDocument

CDocument::OnOpenDocument

DECLARE_MESSAGE_MAP

•	The names of all classes, functions, and other items developed as part of the tutorial  —  and not supplied by the library  —  appear in monotype. For example:

CScribDoc

CScribDoc::DeleteContents

You'll often see these conventions used to distinguish items from the two domains.


 Project Makefiles and STEP Directories for Scribble

Source code files,  project files (also known as makefiles), and other necessary files for the tutorial are supplied in a group of subdirectories under the MFC\SAMPLES\SCRIBBLE directory. The tutorial develops the Scribble application in seven steps; there are seven subdirectories, named STEP0 through STEP6, representing these steps. Each subdirectory contains the files needed for one step. For convenience, Table 1.1 correlates chapters, steps, and chapter content. The second column gives the step completed by the end of the corresponding chapter. Each chapter begins where you left off in the previous step.

Table 1.1    Tutorial Steps

Chapter	Step Completed	Content
»2«	0	Starter application (AppWizard)
»3«		Scribble's document.
»4«	1	Scribble's view
»5«		Menus and toolbar (App Studio)
»6«	2	Handlers for commands (ClassWizard)
»7«	3	Dialog boxes (App Studio, ClassWizard)
»8«	4	Scrolling and splitting
»9«	5	Printing and print preview
»10«	6	Context-sensitive help
For each version of Scribble, the project file, called SCRIBBLE.MAK, is stored in the appropriate subdirectory for the step. Use Table 1.1 to locate the right subdirectory for each chapter.


 The Files You Work With

For both of the procedures that follow, you usually need to deal with only a few of the files:

•	Document class files: SCRIBDOC.H and SCRIBDOC.CPP

•	View class files: SCRIBVW.H and SCRIBVW.CPP

You may occasionally need to refer to (or edit) SCRIBBLE.H and SCRIBBLE.CPP, the application class files.

For chapters that use App Studio (5 − 7), you'll work with SCRIBBLE.RC, the application's resource file.

You may also occasionally want to examine the other files created by AppWizard and ClassWizard, but in most cases you won't need to alter them.

Note  For »Chapter 2,« simply follow instructions to create the skeleton starter application with AppWizard. You can do so easily even if you aren't planning to add the tutorial code yourself, and it's a good way to learn to use this tool.

Descriptions of the two alternative styles of using the tutorial follow.


 Read Along

Use the following procedure if you don't want to type in the code:

To read along without typing code

1.	Print out source files from the STEPn directory appropriate for the chapter.

For example, in Chapter 3, »Creating the Document,« print files for step 1 (see »Table 1.1«).

You can also examine the files by opening them with the Visual Workbench editor.

For comparison, you can look at the code for the previous step to see what it looked like before the current chapter's additions.

2.	As you read the chapter, examine the code that is added, replaced, or deleted in the chapter.

The chapters surround the pieces of code they discuss with enough context to help you locate them in the files.


 Work Along

Probably the most effective way to use the tutorial is to work along:

Work in your own subdirectory. You'll create this subdirectory  —  call it MYSCRIB  —  in »Chapter 2« by running AppWizard. You might, for example, make MYSCRIB a subdirectory of MFC\SAMPLES\SCRIBBLE. As you work along, you can compare your files in MYSCRIB with the files for the step you're doing in the appropriate STEPn subdirectory.

As you work on the code for each chapter, use the next two procedures. The first procedure explains how to use the Visual C++ project file for each Scribble step. The second procedure explains how to work with the Visual Workbench editor to add the tutorial code.

To open the Visual C++ project for a Scribble step

1.	Start Visual Workbench.

2.	Choose the Open command on the Project menu.

3.	Move to your MYSCRIB subdirectory and select the project file: SCRIBBLE.MAK. Choose the OK button.

4.	Open and edit files as needed, using the File menu and the editor in Visual Workbench. For more information about opening, editing, and saving files with Visual Workbench, see the Visual Workbench User's Guide.

To work along, typing in the code yourself

1.	Begin with the code files you developed in the previous step.

The idea is to begin with the code as it exists at the end of the step for the previous chapter and add the new chapter's code to it.

For example, as you begin »Chapter 3,« your files should match those in the STEP0 directory. When you finish the chapter, your code should be essentially identical to that in the STEP1 directory.

2.	As you read the chapter, type in all code as it appears in the text.

Be sure to type in all code exactly as it appears, unless you're instructed not to. Code to be added is marked in the left margin of the tutorial with the special symbol Û.  For example, you might be instructed to type the marked lines in the following function:

// OnOpenDocument, then ...

CStroke* CScribDoc::NewStroke( )

{

CStroke* pStrokeItem = new CStroke( m_nPenWidth );

m_StrokeList.AddTail( pStrokeItem );

return pStrokeItem;

}

Don't add code that isn't marked.

The comment above the function supplies contextual information to help you see where to put the new lines. You'll be told which file to add the lines to.

Sometimes the discussion following a piece of code explains that some lines were deleted or replaced rather than added. As part of the development of Scribble, observe why these changes occurred.

3.	Also perform all App Studio and ClassWizard steps.

In chapters that take you through the steps of using one of these tools, invoke the tool as instructed and follow all steps. Compare the resulting changes to your source code with the illustrative code in the text. Also, for example, compare the dialog box you create with the one shown in the tutorial.

These tools are an integral part of programming with the Microsoft Foundation Class Library.

4.	Complete the chapter (in most cases) by compiling the code you worked on as directed in Chapter 2 of the Visual Workbench User's Guide.

Note  This procedure also lets you selectively work on a step. You can begin with the previous step for any chapter. For example, to do your first work at step 2 (»Chapter 5« and »Chapter 6«), begin with the code for step 1, whether you did step 1 yourself or not.

Each chapter begins with a short reminder of these procedures.


 Scribble Build Information

This section explains a few things you'll need to know when you prepare to build Scribble. General procedures for compiling and linking framework programs in Visual C++ and running the executable program under Windows are given in Chapter 2 of the Visual Workbench User's Guide.

The Right Directory

If you're simply reading along with the tutorial without adding code, you can still compile Scribble at each step to see what it looks like and how it behaves. In this case, go to the STEP subdirectory for the step indicated at the beginning of a chapter. For example, in Chapter 4, »Creating the View«, go to the STEP1 subdirectory. Open the project from the Visual Workbench Project Open dialog box by double-clicking the file SCRIBBLE.MAK.

If you're working along, adding code as you read, compile the project in which you've been editing the files. You should already be in your MYSCRIB  subdirectory and have the project open.

Setting Options

For Scribble, you'll normally want to use the default debug-mode setting. However:

To select debug or release build options

1.	From the Options menu in Visual Workbench, choose Project.

2.	In the Build Mode group, choose either the Debug or Release radio button.

3.	Make sure the check box labeled "Use Foundation Classes" is checked.

4.	Choose OK.

Recall that the project type for Microsoft Foundation Class Library programs is "Windows Application." You can verify this in the Project Options dialog box. »Figure 1.4« shows the Project Options dialog box.

Once you've moved to the right directory and set your options (if needed), you're ready to build Scribble. Choose one of the Build commands on the Project menu in Visual Workbench.

»Chapter 2« begins the tutorial proper. You'll create a skeleton application with AppWizard. In later chapters, you'll build a more powerful Scribble application upon that skeleton.


 Chapter 2  Creating a New Application with AppWizard

Once you've completed your initial application design, you'll typically perform the following tasks to develop the application with the Microsoft Foundation Class Library:

•	Use AppWizard to create a skeleton application—a set of C++ starter files.

•	Use App Studio to construct the user interface.

•	Use ClassWizard and the Visual Workbench editor to add application-specific code to the starter files.

•	Use Visual Workbench to test and debug, then add more code.

To create a new Visual C++ project based on the Microsoft Foundation Class Library, you'll choose the AppWizard command from the Project menu in Visual Workbench.

AppWizard speeds your work in beginning a new project. In seconds it creates a set of Visual C++ files that declare skeletal versions of the classes that make up your application. Key parts of the code that implements these classes are supplied by AppWizard, based on the options you choose in the AppWizard dialog box. These files comprise a starter application that you can compile and run immediately. The starter application contains all the code required to display the windows in which users will interact with your application.

Once you've created the starter application with AppWizard, you'll complete the rest of the steps listed above using App Studio to construct the menus and other user-interface objects, ClassWizard to make connections between those objects and the code you write to respond to them, and Visual Workbench to edit, compile, browse, and debug your source-code files.

The steps tend to be iterative—you'll probably weave back and forth between editing the user interface and writing code all through the development process, and you may do the steps in a different order, depending on your working style.

This chapter shows you how to create a set of starter files for the Scribble application that is developed throughout the tutorial. These files contain skeletal code for several C++ classes—an "application class," a "document class," a "view class," and a "frame window class." The concepts behind these classes are discussed fully in Chapter 2, "Using the Classes to Write Applications for Windows," in the Class Library Reference. You'll also learn more about them in »Chapter 3« and »Chapter 4« of this manual. Details about the created files are available in a text file, README.TXT, that is created along with the starter files. The contents of the starter files are discussed in later chapters as needed. For additional information about the starter files, see Chapter 13 in the Visual Workbench User's Guide.

Without adding a line of code, you can compile the starter application you created with AppWizard and run the resulting program, which exhibits much of the standard functionality you expect from a program written for the Windows operating system. The steps needed to compile and run the program are given in the section »Compile the Starter Files« and »Run the Starter Application«.

»Chapter 3« and »Chapter 4« show you how to add the application-specific code for Scribble, the sample application developed in the rest of the tutorial. »Chapter 5« shows you how to construct Scribble's user interface with App Studio. From »Chapter 6« and the chapters that follow, you'll iteratively add more features to Scribble, then test, revisit App Studio, and so on.

This chapter covers step 0 of the tutorial. If you're working along, adding code as you read, follow all directions in this chapter. When you finish, you'll have a full set of starter files in your own subdirectory. On the other hand, if you're reading along without adding any code, it's still a good idea to work through this chapter to familiarize yourself with AppWizard. If you prefer, however, you can simply study the set of files in the MFC\SAMPLES\SCRIBBLE\STEP0 subdirectory, which are identical to those created by AppWizard .


 Create the Starter Application for Scribble

This section shows you how to use AppWizard to create the starter application that forms the beginnings of Scribble. AppWizard lets you specify a number of options. Then it creates a set of source-code files based on these options from which you develop your application. This saves a great deal of time and effort and lets you focus on the application-specific parts of your program.

The following procedure describes how to enter the correct values for Scribble. This procedure  applies equally to your own applications. Just change the names and other values as needed.

To create starter files for Scribble

1.	Start Visual Workbench by double-clicking its icon in the Windows Program Manager.

2.	On the Project menu in Visual Workbench, choose the AppWizard command.

Complete the AppWizard dialog box as described below (and as illustrated in »Figure 2.1«).

3.	In the Project Name text box, type scribble

The application's project file will be given this name: in this case, SCRIBBLE.MAK.

4.	In the New Subdirectory text box, delete "scribble" and type myscrib

This names the directory that will contain the project's files.

AppWizard will create this directory if it doesn't exist. For Scribble, MYSCRIB is a new directory.

5.	Specify the path to the project's subdirectory.

Use the list box provided to navigate through the directories on the selected drive.

As you navigate through the directory structure, the path listed in the dialog box changes to show where the named subdirectory (MYSCRIB) should be placed. When the path suits you, stop navigating.

For Scribble, navigate to MFC\SAMPLES\SCRIBBLE (relative to your Visual C++ installation). Assuming your Visual C++ installation is in directory MSVC on drive C, the path should look like this in the dialog box:

c:\msvc\mfc\samples\scribble\myscrib\scribble.mak

AppWizard creates a new MYSCRIB subdirectory in the SCRIBBLE directory.

6.	Choose the Classes button to check and modify class names and filenames.

The Classes dialog box lets you edit the names of your program's classes and the files they're in. The dialog box is shown for two different classes, the document class and the view class,  in »Figure 2.2« and »Figure 2.3.«

For Scribble, some of the class names must be changed from the defaults that AppWizard suggests. To edit the information for a class, select the class name in the drop-down list box at the top of the Classes dialog box.

7.	Select class "CScribbleDoc" and edit its information as follows:

•	Change the class name from "CScribbleDoc" to "CScribDoc."

•	Type the file extension scb (don't supply a period).

This is the extension that is appended by default to the names of files that the user saves with Scribble.

•	Change the Document Type Name from "Scribb" to "Scrib."

These are the characters (up to 6) used wherever Scribble's native document type is referred to. For example, the document type name is used to name the

default file, SCRIB1.SCB, the Windows shell registration name ("Scrib"), and constants referred to in the code created by AppWizard, such as IDR_SCRIBTYPE.

»Figure 2.2« shows the dialog box as it appears with the document class selected.

When you select a class, the available text boxes in the area at the bottom of the dialog box change to reflect the nature of the chosen class. For all classes, these extra text boxes include Class Name, Base Class, Header File, and Implementation File. For document classes, additional boxes specify a document File Extension and a Document Type Name.

You can edit any box whose contents are not dimmed (grayed).

The changes you type will make using the tutorial easier by keeping the names of your classes and files synchronized with those in the subdirectories provided for the Scribble steps. What you see on the screen as you work will also match the figures in the tutorial.

8.	Select class "CScribbleView" and edit its information as follows:

Change the class name from "CScribbleView" to "CScribView."

»Figure 2.3« shows the dialog box as it appears with the view class selected.

9.	Choose the OK button in the Classes dialog box when you finish.

AppWizard provides satisfactory defaults for classes CScribbleApp and CMainFrame. You don't have to edit them for Scribble — although you might want to edit them for another application.

10.	Accept the default options.

Scribble uses AppWizard's default options. To accept these options, do nothing.

With these options, AppWizard will add code for printing and print preview and to support a toolbar, and it will supply comments throughout the files it creates to help you understand where you need to add your own code. By default, the source code will also support the multiple document interface (MDI).

As an MDI application, Scribble lets the user open multiple documents at the same time. The alternative is a single document interface (SDI) application, which allows the user to open only one document at a time.

If you want to see what options are available, you can examine options by choosing the Options button. »Figure 2.4« shows the Options dialog box. For more information about the options, see Chapter 4 in the Visual Workbench User's Guide.

11.	Choose the OK button in the AppWizard dialog box.

12.	Choose the Create button in the New Application Information dialog box.

AppWizard creates the specified subdirectory if it doesn't exist. Then it creates all necessary files in the directory. It then opens the project in Visual Workbench.

The remaining sections of this chapter »Compile the Starter Files« and »Run the Starter Application« guide you through the process of compiling the starter application and running the resulting program to examine its capabilities.


 Compile the Starter Files

The starter application you created provides the skeleton of a working application for the Windows operating system. When you compile the starter files — without adding a single line of code — the result is an application that runs, opens and closes windows, and lets you perform other operations on the windows. Of course, at this stage the windows have nothing in them. So far, Scribble doesn't scribble.

At this point, Scribble should be the currently open project in Visual Workbench.

To compile the starter application

1.	Make sure you've set up the environment as explained in »Appendix A.«

2.	Build the application in Visual Workbench.

On the Project menu, choose Build or Rebuild All as shown in »Figure 2.5.«

3.	The starter application is built, producing the file SCRIBBLE.EXE in your new MYSCRIB subdirectory.


 Run the Starter Application

After you compile the starter application, you can run it from Visual Workbench, either with breakpoints set or not. You can also run the application from the Windows Program Manager.

To run Scribble for debugging (with breakpoints)

1.	From the Debug menu, choose the Breakpoints command and set any breakpoints you want in your code.

2.	From the Debug menu, choose Go to run Scribble.

To run Scribble without debugging

•	From the Project menu, choose the Execute Target command.

When the starter application runs, an MDI application window appears with a menu bar containing File, Edit, View, Window, and Help menus and a default toolbar. The application window contains one open document window, as shown in »Figure 2.6.«

The document window is empty, of course, because you've added no application-specific code yet. But you can move, resize, minimize, maximize, and close the document window and the application window. You can also use the New command on the File menu to open new windows. The Open, Save, and Save As commands are partially functional: at this point, they save empty files. You haven't added all of the code yet to support these commands. The About command on the Help menu brings up an About dialog box with default text in it. The default toolbar is partially functional too: the Open and Save/Save As buttons do the same things as the corresponding menus. And the status bar at the bottom of the application window displays a description string when you move the mouse pointer over any menu command.

This minimal application lays the foundation for Scribble and displays much of the standard behavior you expect in an MDI application written for the Windows operating system. The next two chapters, »Creating the Document« and »Creating the View,« use Scribble to show you how to develop the document and view classes that you created in this chapter, »Creating a New Application with AppWizard«.

You'll undoubtedly want to examine the source code files you created. To orient you, AppWizard also creates a text file, README.TXT, in your new application directory. This file explains the contents and uses of the other new files created by AppWizard.


 Chapter 3  Creating the Document

In this chapter and the next, you'll add code to the starter application you created in »Chapter 2« with AppWizard. By the end of »Chapter 4,« you can compile and run the Scribble program.

»Figure 3.1« shows what the Scribble application developed in the tutorial will look like at the end of Chapter 4 (see »Compile Scribble − Step 1 Version«).

This chapter introduces documents and develops Scribble's document class, an application-specific class derived from class CDocument, called CScribDoc. Chapter 4, »Creating the View,« introduces views and develops the view class. The two chapters together introduce many of the fundamental concepts of the framework: documents, serialization, views, drawing, and messages. Because documents and views are intimately related, you need to implement both before Scribble is fully functional.

In later chapters, you'll incrementally add new features to Scribble: menus, a working toolbar, a dialog box with automatic initialization and validation of its controls, scrolling, splitter windows, enhanced printing, and context-sensitive help.

Your tour of Scribble's code begins with the starter files created by AppWizard in the topic »Create the Starter Application for Scribble«. You'll add a lot of functionality to Scribble with a small amount of code. Among the things you'll develop in this chapter are:

•	»Scribble's data« — CStroke, a class that defines one "stroke" of a drawing.

•	»Scribble's document« — CScribDoc, a class to contain and manage a list of strokes.

•	»Scribble's serialization code« — code that implements writing and reading documents.

The code that you must add to fill out the framework in this chapter is in the following files: SCRIBBLE.H, SCRIBDOC.H, and SCRIBDOC.CPP.

This chapter, "Creating the Document," and Chapter 4, »Creating the View,« cover step 1 of Scribble. If you want to work along, adding the code as you go, begin with the files you created with AppWizard in your MYSCRIB subdirectory in »Create the Starter Application for Scribble« in Chapter 2. At this point, your files should consist entirely of the set of generic starter files that AppWizard created. As you read this chapter, add or change all lines of code marked with the [image] symbol in the left margin. At the end of Chapter 4, when you reach »Compile Scribble − Step 1 Version,« your files should essentially resemble those in the SCRIBBLE\STEP1 subdirectory.

If, on the other hand, you want to read along without adding code, you can print or examine the files in the SCRIBBLE\STEP1 subdirectory.

Note  If you have trouble locating the correct place to add code, try looking at the corresponding source files in the subdirectory for the completed step. For this chapter, "Creating the Document," and Chapter 4, »Creating the View,« use the SCRIBBLE\STEP1 subdirectory for this purpose.

If you want to preview Scribble, load the version in SCRIBBLE\STEP1 in Visual Workbench and choose the Build command on the Project menu. Run the program with the Execute Target command on the Project menu.


 Documents

At the heart of Scribble are its document and its view. This section explains the role of the document and introduces Scribble's document class and its members.

At run time, an application written with the Microsoft Foundation Class Library is a group of cooperating objects that communicate by sending and receiving Windows messages and by calling each other's member functions. Documents are created by document template objects and managed by an application object. Users interact with a document through a view object, which is framed by a document frame window object. »Figure 3.2« shows graphically the relationships between these key objects.

Table 3.1 shows how the document and other objects are created and managed in a framework application.

Table 3.1    Key Objects in an Application

Object	Primary Purpose	Relationships to Other Objects
Application	Manages all other framework objects.	Keeps a list of document templates.
Document template	Creates and manages documents.	Manages a list of open documents of a given type. Creates frame windows and views to provide a user interface to the document's data.
Document	Stores data.	Manages a list of views on its data.
View	Manages user interaction with a document.	Attached to a document. Owned by a frame window.
Frame window	Frames a view.	Owns a view that is attached to a document.


 Document Definition

A document is the unit of data that a user opens with the Open command on the File menu and saves with the Save command. The document is responsible for storing the data and for loading it from and storing it to persistent storage, usually a disk file. A document typically appears to the user inside a frame window through which the user manipulates the data.

»Figure 3.3« shows the general relationship between a document and its view and frame window.


 Documents in the Framework

In the framework, the data and the user's operations on it are managed by two separate objects. A document is an object that stores your data in its member variables and reads and writes it through a member function called Serialize. The user interacts with the document through a separate object called a view. The view fills the client area of a frame window, where it displays the data and accepts user input and editing operations. Documents know how to manage data; views know how to display it and accept operations on it. »Figure 3.3« shows this important relationship graphically.


 Document Creation

When the user opens a document — existing or new — the framework creates a document object and its associated frame window and view objects. If the document is associated with a file, the document reads the file and stores its data. The view obtains data from the document and displays it. »Figure 3.4« shows the general process of creating a new document and its view and frame window. For more details, see Chapters 2 and 4 in the Class Library Reference.


 Document/View Interaction

When the user modifies data through the view, the view notifies the document. In turn, the document tells all of its views (some documents have multiple views) to update their displays with the new information, and the views respond by redrawing all or part of the visible portion of the document. You'll learn more about the view's part in this process in »Chapter 4.«

In the Microsoft Foundation Class Library, documents are based on class CDocument. To use CDocument, you derive your own document class from it. For more detailed information about documents, see Chapters 2 through 4 and class CDocument in the Class Library Reference.


 You and the Document

Table 3.2 shows your responsibilities and those of the framework in implementing a document.

Table 3.2    Document Implementation Responsibilities

Your Job	The Framework's Job
Derive a document class from class CDocument.	Provides many document services through class CDocument.
Add data members to your class.
Implement application-specific initialization and cleanup of your document's data.	Calls the appropriate initialization and cleanup functions at the right times.
Override CDocument's Serialize member function to specify how your data is read and written.	Provides implementations of File Open, Save, and Save As that call your Serialize override to read and write your data.
Typically, you also add member functions to your derived document class through which other objects — mainly the view — can access the document's data.


 Scribble's Document: Class CScribDoc

Scribble is a simple drawing program. Documents in Scribble store the lines, or "strokes," that make up a drawing. Because a drawing is typically made up of many strokes, the document stores a list of all the strokes the user has drawn. »Figure 3.5« shows a single stroke drawn in a Scribble document's view.

Documents in Scribble are objects of class CScribDoc, which is derived from CDocument. CScribDoc has a member variable named m_strokeList for storing a list of strokes and member functions to manage the stroke list.

AppWizard writes a skeletal CScribDoc class for you, but you need to add a few things. In the following procedure, as in similar procedures throughout the tutorial, you'll add the indicated code to a named file, using the Visual Workbench editor. The files are those created by AppWizard. In the code listings below, the lines to add or change are always preceded by a few existing code lines or a comment to help you locate the right place in the files. To add code, start Visual Workbench, open the file named in the procedure, locate the place to add your lines, and type in the lines that are marked with the symbol Û. For more information about editing source files, see the Visual Workbench User's Guide.

To add member declarations to Scribble's document class

•	Complete the declaration of class CScribDoc (in file SCRIBDOC.H). If you're working along, add the marked lines, which contain new Scribble-specific code, to the file.

// Forward declaration of data structure class

class CStroke;

class CScribDoc : public CDocument

{

protected: // Create from serialization only

CScribDoc( );

DECLARE_DYNCREATE( CScribDoc )

// Attributes

protected:

CObList    m_strokeList;	// Each element is a CStroke

// The document keeps track of the current pen width on

// behalf of all views. We'd like the user interface of

// Scribble to be such that if the user chooses the Pen

// Thick Line command, it will apply to all views, not just

// the view that currently has the focus.

UINT    m_nPenWidth;	// Current user-selected width

CPen    m_penCur;	// Pen created according to

// user-selected pen style (width)

public:

CPen*   GetCurrentPen( ) { return &m_penCur; }

// Operations

public:

void DeleteContents( );

CStroke* NewStroke( );

POSITION GetFirstStrokePos( );

CStroke* GetNextStroke( POSITION& pos );

// Implementation

public:

virtual ~CScribDoc( );

virtual void Serialize( CArchive& ar );	// Overridden for

// document i/o

#ifdef _DEBUG

virtual   void AssertValid( ) const;

virtual   void Dump( CDumpContext& dc ) const;

#endif

protected:

void InitDocument( );

virtual BOOL OnNewDocument( );

virtual BOOL OnOpenDocument( const char* pszPathName );

// Generated message-map functions

protected:

//{{AFX_MSG(CScribDoc)

// NOTE - the ClassWizard will add and remove member

// functions here. DO NOT EDIT what you see in these

// blocks of AppWizard code !

//}}AFX_MSG

DECLARE_MESSAGE_MAP( )

};

This code declares a C++ class that defines Scribble's documents. The member variables and functions provide the typical functionality of a document — they define and manipulate the document's data, serialize the data to and from files, and provide diagnostic assistance when you compile a debug version. (Notice the forward declaration of class CStroke, the class used to define the document's data structure. CScribDoc needs to know about CStroke. You'll learn about CStroke later in the chapter in the section »The Document's Data Class CStroke«.)

Table 3.3 describes the member variables of class CScribDoc.

Table 3.3    CScribDoc Data Members

Member	Description
m_strokeList	A list of  strokes. Each item in the list is an object of class CStroke. The list itself is an object of class CObList, one of the collection classes supplied by the class library.
m_penCur	A CPen object used to do the drawing. Its main attribute is its width. The pen is created when the document is constructed and is used during the creation of new strokes.
m_nPenWidth	The current width of the lines drawn by the pen.
Note  By convention, class names begin with an uppercase "C" and member variable names begin with a lowercase "m_".

Table 3.4 describes the member functions.

Table 3.4    CScribDoc Member Functions

Member	Description
CScribDoc, ~CScribDoc	A default constructor and a virtual destructor. AppWizard creates placeholders for these functions. In Scribble, they remain empty.
DeleteContents	Deletes the contents of a document — the strokes that make up the drawing.
GetCurrentPen	Retrieves a pointer to the current pen object any time it's needed by the drawing code.
InitDocument, OnNewDocument,  OnOpenDocument	Called when a new document is created or an existing document is opened. Overriding versions of the CDocument member functions OnNewDocument and OnOpenDocument call InitDocument to initialize the new document.
NewStroke	Creates a new stroke object and adds it to the list of strokes in m_strokeList.
GetFirstStrokePos	Returns the position of the first stroke object in m_strokeList.
GetNextStroke	Returns a pointer to the next stroke object in the list.
Serialize	Overrides the Serialize member function of class CDocument. The override specifies how to serialize a list of stroke objects to and from a disk file. AppWizard creates this function for you in skeletal form.
AssertValid	Tests the validity of an object's internal state.
Dump	Dumps the contents of an object's members for examination during debugging.
You'll add code for most of these member functions in later sections of this chapter. You'll learn more about Serialize under »Serializing the Data«. For more information about AssertValid and Dump, see Chapter 15, »Diagnostics.« You won't add code to these functions for Scribble.


 The Document's Data: Class CStroke

In Scribble, a stroke consists of an array of points. As the user drags the mouse to draw, Scribble collects points and stores them as part of the current stroke. Points collected from the time the left mouse button is pressed to the time it's released form one stroke of a Scribble drawing. »Figure 3.6« shows Scribble's data structure schematically. Scribble uses an object of class CPen for drawing.

Each stroke is stored in an object of class CStroke, Scribble's primary data structure. The whole drawing is a list of CStroke objects. CStroke is a new class, so you'll have to add its entire declaration to Scribble's source files.

To add the CStroke class

•	If you're working along, add the code marked below. The declaration for class CStroke follows that for class CScribDoc in file SCRIBDOC.H. Here's the declaration for class CStroke:

// Declaration of class CScribDoc, then ...

class CStroke : public CObject

{

public:

CStroke( UINT nPenWidth );

protected:

CStroke( );

DECLARE_SERIAL( CStroke )

// Attributes

UINT   m_nPenWidth;  // One width applies to entire stroke

CDWordArray   m_pointArray;  // Series of connected points

// Operations

public:

void AddPoint( CPoint pt );

BOOL DrawStroke( CDC* pDC );

// Helper functions

protected:

CPoint GetPoint( int i ) const

{ return CPoint(m_pointArray[i]); }

public:

virtual void Serialize( CArchive& ar );

};

This code declares a C++ class of stroke objects. The member variables and functions define and manipulate the data of a stroke and serialize it when the document is serialized. You'll add the member function definitions in the next section.

Table 3.5 lists CStroke's member variables.

Table 3.5    CStroke Data Members

Member	Description
m_nPenWidth	Stores the width of the pen in effect at the time this stroke was drawn.
m_pointArray	Stores an array containing the points that define this stroke. These are used to redraw the stroke as needed.
Table 3.6 lists CStroke's member functions.

Table 3.6    CStroke Member Functions

Member	Description
CStroke	The class defines two constructors, one protected and one public.
AddPoint	Adds a new point to the stroke. The point is represented by a CPoint object that defines the coordinates of the mouse during drawing. Class CPoint is supplied by the class library.
DrawStroke	When the view object redraws the document's data, it calls upon each stroke object in the stroke list to draw itself by calling its DrawStroke member function.
GetPoint	Returns the CPoint object at a given index in the array of points that defines this stroke.
Serialize	To assist the document in making its data persistent, typically on disk, CStroke also overrides the Serialize member function of CObject to define how a single stroke serializes its points and other data. For more information about point serialization, see »Serializing the Data«.


 Building and Storing Strokes

Your next step is to add definitions for CStroke's member functions.

To add implementation code for the CStroke members

1.	Add the following definitions for CStroke's two empty constructors to the SCRIBDOC.CPP file:

// Last line of CScribDoc code, then ...

CStroke::CStroke()

{

// This empty constructor should be used by serialization only

}

CStroke::CStroke(UINT nPenWidth)

{

m_nPenWidth = nPenWidth;

}

The first constructor, declared protected in SCRIBDOC.H, is used only by the application framework during serialization of CStroke objects. Its parameter list and function body are empty. The second constructor is for public use, when you need to construct new stroke objects directly. When it constructs a new stroke object, the public constructor initializes the pen width. CStroke doesn't declare its own destructor — it relies on CObject to provide one by default.

2.	Add the AddPoint member function to the SCRIBDOC.CPP file. The function adds the latest mouse location to the current stroke's list of points:

// Constructor declarations, then ...

void CStroke::AddPoint( CPoint pt )

{

m_pointArray.Add( MAKELONG( pt.x, pt.y ) );

}

A CStroke object stores its array of points in the m_pointArray data member — an object of class CDWordArray, one of the collection classes supplied by the class library. A CDWordArray stores 32-bit doublewords. A CPoint stores its horizontal and vertical coordinates in two 16-bit words, so a CPoint fits into a doubleword. The AddPoint member function invokes a Windows macro, MAKELONG, to convert the coordinates of a point to a doubleword and passes the result to the Add member function of class CDWordArray. Add stores the point as a doubleword at the end of the array.

At this point, class CStroke is not quite complete. You'll add code for the two remaining member functions, GetPoint and DrawStroke, in »Chapter 5.« These member functions are used by the view object to draw the data.


 Managing the Document

Typically, you must write code to (a) initialize a document's data members and (b) deallocate memory allocated for the data, release system resources, and perform other cleanup chores. When a new Scribble document is created, CScribDoc must create a pen for drawing new strokes. When a document is closed, the document must delete the stroke objects it has stored up.


 Initializing and Cleaning Up

Because a document can be created with either the New command or the Open command on the File menu, CScribDoc overrides both the OnNewDocument and OnOpenDocument member functions of CDocument to perform necessary document initialization. However, for Scribble, both initializations are the same, so both overrides call the new member function InitDocument.

The framework automatically calls OnNewDocument when a new document is created or OnOpenDocument when a document is opened. AppWizard creates a skeletal version of OnNewDocument for you; you must supply OnOpenDocument yourself.

If you're working along, add the marked code lines below to the indicated file. Because the constructor and destructor created by AppWizard are empty, the code isn't shown here.

To implement initialization for Scribble's documents

1.	Add a definition for the InitDocument member function to file SCRIBDOC.CPP:

// Empty constructor and destructors, then ...

void CScribDoc::InitDocument( )

{

m_nPenWidth = 2;  // Default 2-pixel pen width

// Solid black pen

m_penCur.CreatePen( PS_SOLID, m_nPenWidth, RGB(0,0,0) );

}

InitDocument sets a default pen width and creates a pen object for drawing. Pen creation is done through the CPen object, m_penCur, by calling its CreatePen member function. The arguments specify a solid black pen 2 pixels wide.

2.	Add the following to the override of OnNewDocument created by AppWizard in file SCRIBDOC.CPP:

// InitDocument, then ...

BOOL CScribDoc::OnNewDocument( )

{

if( !CDocument::OnNewDocument( ) )

return FALSE;

InitDocument( );

return TRUE;

}

3.	Finally, add the following override of OnOpenDocument to file SCRIBDOC.CPP:

// OnNewDocument, then ...

BOOL CScribDoc::OnOpenDocument( const char* pszPathName )

{

if( !CDocument::OnOpenDocument( pszPathName ) )

return FALSE;

InitDocument( );

return TRUE;

}

The two overrides call the base-class version of the function before performing application-specific initialization of the document.

To implement document cleanup

•	In file SCRIBDOC.CPP, add the following definition for DeleteContents, which overrides the DeleteContents member function of CDocument:

// Empty constructor and destructors, then ...

void CScribDoc::DeleteContents( )

{

while( !m_strokeList.IsEmpty( ) )

{

delete m_strokeList.RemoveHead( );

}

}

DeleteContents provides the best place to destroy a document's data when you want to keep the document object around. The function is called automatically by the framework any time it's necessary to delete only the document's contents. It's called in response to the Close command on the File menu, when the user closes the document's last open window, and before creating or opening a document with the New and Open commands.

Scribble's override of DeleteContents iterates through the stroke list. For each stroke object, the function invokes the delete operator. This destroys the strokes. RemoveHead, a member function of class CObList, then clears the pointers in the list. Alternatively, this cleanup code could be placed in the destructor, but DeleteContents is reused later in other functions.


 Managing the Data

As the user works with documents, the document object must manage a pen and its list of strokes in the current drawing. GetCurrentPen is a helper function that gives restricted, type-safe public access to the protected data member m_penCur. NewStroke, GetFirstStrokePos, and GetNextStroke provide public access to the protected data structure in m_strokeList.

To implement document members for managing Scribble's data

1.	Here's the definition for GetCurrentPen (it's already defined inline in file SCRIBDOC.H, so don't add this code):

// Declaration of CPen m_penCur, then ...

public:

CPen*   GetCurrentPen( ) { return &m_penCur; }

GetCurrentPen simply returns a pointer to the current pen. Here a public member function is used to access the pen instead of making m_penCur public.

2.	Add the NewStroke member function to file SCRIBDOC.CPP. NewStroke creates a new stroke object and adds it to the stroke list:

// Dump member function, then ...

CStroke* CScribDoc::NewStroke( )

{

CStroke* pStrokeItem = new CStroke(m_nPenWidth);

m_strokeList.AddTail( pStrokeItem );

SetModifiedFlag( );	// Mark document as modified

// to confirm File Close.

return pStrokeItem;

}

NewStroke uses the C++ new operator to construct a new CStroke object dynamically, initializing it with the pen width. It uses the CObList member function AddTail to add the new stroke to the list. Then it calls the CDocument member function SetModifiedFlag to flag the changes to the document and returns a pointer to the stroke.

3.	Add the following definition for GetFirstStroke (file SCRIBDOC.CPP), which returns the index of the first stroke in m_strokeList:

// NewStroke, then ...

POSITION CScribDoc::GetFirstStrokePos( )

{

return m_strokeList.GetHeadPosition( );

}

GetFirstStrokePos calls the GetHeadPosition member function of class CObList and returns a pointer of type POSITION to the first stroke object in the list. POSITION  is defined in the class library.

4.	Finally, add this definition for GetNextStroke (file SCRIBDOC.CPP), which returns the stroke object at a given index in the stroke list:

// GetFirstStrokePos, then ...

CStroke* CScribDoc::GetNextStroke( POSITION& pos )

{

return (CStroke*)m_strokeList.GetNext( pos );

}

GetNextStroke calls the GetNext member function of CObList, which returns a pointer to a CObject. The pointer must be cast to a pointer to a CStroke object (CStroke is derived from CObject).

The purpose of providing GetFirstStrokePos and GetNextStroke is to make the stroke list easily accessible in a type-safe manner. These member functions mimic the interfaces of the class library's list classes. This makes it easy to iterate through the list of strokes with clean code like the following (don't add this code to Scribble):

POSITION pos = pScribDoc->GetFirstStrokePos( );

while( pos != NULL )

{

CStroke* pStroke = pScribDoc->GetNextStroke( pos );

// Do something with the stroke ...

}


 Serializing the Data

This section adds code to define file input/output for Scribble documents. The default I/O implementation in the Microsoft Foundation Class Library is called "serialization." It provides a mechanism for making a document's data persistent between work sessions with the program. Given the code added here, serialization is automatic when the user chooses the Open, Save, or Save As commands from the File menu.

Note  You don't have to write any code to process the Open, Save, and Save As commands on the File menu — such as putting up the dialog boxes. The framework supplies this code.

The CScribDoc class declaration in file SCRIBDOC.H begins with the following lines — the lines contain an important macro invocation needed for serialization (don't add this code):

class CScribDoc : public CDocument

{

protected: // Create from serialization only.

CScribDoc( );

DECLARE_DYNCREATE( CScribDoc )

// Other declarations ...

};

AppWizard wrote this code for you.

The DECLARE_DYNCREATE macro prepares the class so that document objects can be dynamically created by the framework.


 Serializing the Document

Serializing a document occurs in two stages. First, the framework calls the document's Serialize member function. Second, that Serialize function calls the Serialize function of the stroke list. If you're working along, add the marked lines to the indicated files.

To implement serialization for Scribble documents

•	Fill in the Serialize member function for class CScribDoc. The SCRIBDOC.CPP file defines a skeletal version of the function. Here's Serialize, with one marked line added to adapt the serialization mechanism to Scribble:

// OnOpenDocument, then ...

void CScribDoc::Serialize( CArchive& ar )

{

if ( ar.IsStoring( ) )

{

}

else

{

}

m_strokeList.Serialize( ar );

}

AppWizard creates the skeleton of the Serialize member function in class CScribDoc; you simply fill in the code shown. Later you'll add code in both branches of the if statement. AppWizard also generates comments of the form

// TODO: Add storing code here

You will typically remove these comments when the functionality has been implemented.

Serialization uses an object of class CArchive to manage the connection to a disk file or other storage. A CArchive object, ar, is passed in as an argument.

A call to the archive object's IsStoring member function determines whether this is a store or a load operation. If the archive is for storing (saving), the stroke-list object's own Serialize member function is called to store the stroke's data to disk. If the archive is for loading, its Serialize member function is called to load data from the disk file. This constructs new CStroke objects to fill the list. The stroke list for a document being read in from disk must already be empty.

Note that the stroke list already exists when Serialize reads data in. That's because it was declared as an embedded object, like this:

CObList m_strokeList;

rather than as a pointer, like this:

CObList* m_pStrokeList;

For a pointer, you'd use CArchive's extraction (>>) operator to read the data:

ar >> m_pStrokeList;	// Example of serializing to a

// referenced (non-embedded) object

But for an embedded object, as in Scribble, you call Serialize directly because you don't want to create a new CObList object and because you know the exact type of the object.


 Serializing Strokes

When the document responds to an Open, Save, or Save As command, it delegates the real serialization work to the strokes themselves. That is, the document tells the stroke list to serialize itself, and the stroke list, in turn, tells the individual strokes to serialize themselves. As a result, all strokes in the document are read from or written to a file.

To implement serialization for stroke objects

1.	Add the IMPLEMENT_SERIAL macro for CStroke.

Throughout the tutorial, Scribble is presented as a series of incremental versions. When you build successive versions that modify the structure of CStroke, they are incompatible with earlier versions. Attempts to read CStroke data stored by a previous version may fail because the serialization process expects a different structure. Each time you make such a modification of CStroke, it's valuable to tag the new version with a version number. The version or "schema" number is checked automatically during serialization. You can check the schema number in the serialization code to support backward compatibility, allowing you to read files created with earlier versions of your application.

// End of CScribDoc code in file SCRIBDOC.CPP

IMPLEMENT_SERIAL( CStroke, CObject, 1 )

If you're working along, add the IMPLEMENT_SERIAL macro for CStroke as shown. The third argument is the schema number, set to 1 for Scribble step 1.

The IMPLEMENT_SERIAL macro complements the DECLARE_SERIAL macro invoked in file SCRIBDOC.H. The two macros prepare a class for serialization.

2.	Add a Serialize override for class CStroke in the SCRIBDOC.CPP file. Like CScribDoc, CStroke also overrides the Serialize member function of its base class. When the stroke-list object is called to serialize itself, it calls each stroke object in turn to serialize itself. Here's the code for CStroke's version of Serialize:

// AddPoint, then ...

void CStroke::Serialize( CArchive& ar )

{

if( ar.IsStoring( ) )

{

ar << (WORD)m_nPenWidth;

m_pointArray.Serialize( ar );

}

else

{

WORD w;

ar >> w;

m_nPenWidth = w;

m_pointArray.Serialize( ar );

}

}

If the archive object is for storing, the stroke's pen-width value is stored in the archive, and then its array of points is stored. Notice that the CDWordArray object m_pointArray can serialize itself.

If the archive object is for loading, the stroke's data must be read in the same order it was written: first the pen width, then the array of points. The else branch of the if statement declares a local variable to receive the width, then copies that value to m_nPenWidth. It then calls upon the point array to load its data (see »Figure 3.7« ).

Note that the m_nPenWidth variable is cast to a WORD before it's inserted in the archive, ar:

ar << (WORD)m_nPenWidth;

The cast is necessary because m_nPenWidth is declared as type UINT (unsigned integer). The archive mechanism only supports saving types of fixed size.  UINT, for example, is 16 bits in the Windows version 3.1 operating system and 32 bits in the Windows NT operating system. Using the WORD cast makes the data files created by your application portable. To promote machine independence, class CArchive doesn't have an extraction operator for type int but does have one for type WORD.

Once this code is in place, serialization of Scribble's data is automatic.


 In the Next Chapter

In this chapter, you filled in the details of Scribble's document class by defining its data, providing useful functions through which to manipulate the data, and specifying how the data objects are written to and read from files. So far, the data can be initialized and cleaned up but not displayed or worked on by the user.

At this point, Scribble is about half ready to compile. In »Chapter 4,« you'll complete the basic Scribble application by developing a view on the document. The view displays strokes and manages all user input. At the end of that chapter, you'll compile and test Scribble.


 Chapter 4  Creating the View

In Chapter 3, "»Creating the Document,«" you completed Scribble's document class. In this chapter, you'll add a view class that provides a "view on the document." Scribble's view class displays the strokes of a drawing and accepts user input from the mouse. By the end of this chapter, you can compile and run Scribble.

Among the things you'll develop in this chapter are:

•	»Code to display Scribble's strokes« — in class CScribView.

•	»Code to handle Windows messages« as the user draws with the mouse.

You'll also get your first hands-on experience with ClassWizard. ClassWizard lets you map Windows messages to message-handler member functions in your classes. As you'll see in »Chapter 6,« it also lets you map the commands generated by user-interface objects such as menu items, toolbar buttons, and accelerator keys to message-handler functions.

The code that you must add to fill out the framework in this chapter is mainly in the following files: SCRIBVW.H and SCRIBVW.CPP. You'll also add two more member functions to class CStroke in SCRIBDOC.CPP.

This chapter and Chapter 3, »Creating the Document,« cover step 1 of Scribble. If you want to work along, adding the code as you go, begin with the files you worked on in Chapter 3 in your MYSCRIB subdirectory. At this point, your files should consist of the starter files you created with AppWizard in Chapter 2, »Creating a New Application with AppWizard,« and modified in Chapter 3. As you read this chapter, add all lines of code marked with the [image] symbol in the left margin. At the end of this chapter, your files should closely resemble those in the SCRIBBLE\STEP1 subdirectory.

If, on the other hand, you want to read along without adding code, you can print or examine the files in the SCRIBBLE\STEP1 subdirectory.

Instructions for compiling Scribble are given at the end of this chapter in »Compile Scribble − Step 1 Version«.


 Views

The document object defines, stores, and manages the application's data. But all user interaction with the document is managed through a view object attached to the document object. Scribble uses a view object to display a document on the screen or on a printer. This section explains the role of the view and introduces Scribble's view class and its members.

As you saw in Chapter 3 in »Document Creation«, when a new document is created in response to a New or Open command from the File menu, the framework also creates a "document frame window" and creates a view inside the frame window's client area as a child window. The view displays the document's data and responds to mouse actions, keystrokes, menu commands, and other actions as the user works on the document. It's your task to specify how the view draws your application-specific data and what it does in response to user actions.

»Figure 4.1« illustrates the view's role in relation to the document.


 View Definition

A view is an object derived from class CView (or from another CView-derived class, such as CScrollView) that manages user interaction with a document. The view is attached to a particular document and is a child window that typically fills the client area of a document frame window. In single document interface (SDI) applications, the view fills the main frame window. In multiple document interface (MDI) applications, the document frame window is in turn displayed inside the main frame window of the application.


 Views in the Framework

In the framework, the document manages data, but the view displays it and acts as intermediary between the user and the document for all input, selection, and editing in the document. Typically, a document has only one view, although it is possible for a document to have multiple views, as in the case of splitter windows. A given view is always associated with only one document. Each Scribble document uses only one view.


 View Creation

A view is created by its parent frame window when the framework creates the associated document. Both the document and frame objects are created by a document template object; then the frame window creates the view. Immediately after creation, the framework calls the view's OnInitialUpdate member function to initialize the view. You'll frequently override the OnInitialUpdate member function of class CView to initialize the view object. After creation, when the document's data changes, the view's OnUpdate member function is called. You will frequently override the OnUpdate member function to optimize what portion of the view is redrawn.


 Drawing the View's Contents

Each time the view needs to be redrawn, the framework calls its OnDraw member function. OnDraw does the actual drawing, obtaining the data to draw from its document. However, when more immediate drawing is required, a view can respond to mouse-related messages, such as WM_LBUTTONDOWN, to do mouse-driven drawing. You'll see both kinds of drawing in this chapter.

You'll always override the OnDraw member function of class CView to specify how your document's data is drawn.


 Document/View Interaction

A view can access the data stored in its document by calling the CView member function GetDocument, which returns a pointer to the document object. The view can call public member functions and access public data members of the document by using the pointer.

When the user changes data in the view, the view notifies the document and updates the data stored there. On such occasions, the document typically then calls its UpdateAllViews member function to cause any views attached to it to redraw themselves. For a document with multiple views, this mechanism ensures that all of them are updated properly.


 You and the View

Table 4.1 shows your responsibilities and those of the framework in implementing a view on a document.

Table 4.1    View Implementation Responsibilities

Your Job	The Framework's Job
Derive a view class from class CView.  For scrolling, use CScrollView instead. Other view classes are available as well.	AppWizard provides a skeletal view class for you. Class CView and its derived classes provide view services.
Implement your view's OnDraw member function.	The framework calls OnDraw at the appropriate times, passing it a device-context object into which it can draw.
Map Windows messages and commands to member functions of your view.	The framework calls your message-handler member functions in response to the corresponding Windows messages.
Other view classes include CFormView and CEditView. For more information about views, see Chapters 2 and 4 and class CView and its derived classes in the Class Library Reference.


 Scribble's View: Class CScribView

The view's job in Scribble is to render strokes as the user draws them with the mouse and to redraw the view as needed — for example, when the window is covered by another window and then uncovered.

Views in Scribble are objects of class CScribView, which is derived from class CView. CScribView knows how to access the document's stroke list and can tell the strokes stored there to draw themselves in the view.

AppWizard writes a skeletal CScribView class for you, but you need to implement the OnDraw member function and add a few other things. In the following procedure, as you did in Chapter 3 in »Scribble's Document: Class CScribDoc«, you'll add the indicated code to a named file. Add the lines marked with the [image] symbol in the left margin.

To define the working data used by the view

•	Add Scribble-specific lines to class CScribView. File SCRIBVW.H declares class CScribView. Lines are added to the code generated by AppWizard to define some Scribble-specific data items:

class CScribView : public CView

{

protected: // Create from serialization only

CScribView( );

DECLARE_DYNCREATE( CScribView )

// Attributes

public:

CScribDoc* GetDocument( );

protected:

CStroke*   m_pStrokeCur;	// The stroke in progress

CPoint     m_ptPrev;	// The last mouse pt in the stroke

// in progress

// Operations

public:

// Implementation

protected:

public:

virtual ~CScribView( );

virtual void OnDraw( CDC* pDC );	// Overridden to draw

// this view

#ifdef _DEBUG

virtual void AssertValid( ) const;

virtual void Dump( CDumpContext& dc ) const;

#endif

// Printing support

protected:

virtual BOOL OnPreparePrinting( CPrintInfo* pInfo );

virtual void OnBeginPrinting( CDC* pDC, CPrintInfo* pInfo );

virtual void OnEndPrinting( CDC* pDC, CPrintInfo* pInfo );

// Generated message-map functions

protected:

//{{AFX_MSG(CScribView)

// NOTE - the ClassWizard will add and remove member

// functions here. DO NOT EDIT what you see in these

// blocks of AppWizard code !

//}}AFX_MSG

DECLARE_MESSAGE_MAP( )

};

#ifndef _DEBUG   // Debug version in scribvw.cpp

inline CScribDoc* CScribView::GetDocument( )

    { return (CScribDoc*)m_pDocument; }

#endif

This code declares class CScribView, the view on the Scribble document's data. The added lines declare two new protected member variables.

Table 4.2 describes the member variables of class CScribView.

Table 4.2    CScribView Data Members

Member	Description
m_pStrokeCur	A pointer to the stroke currently being drawn.
m_ptPrev	A CPoint object containing the previous mouse coordinates, from which a line will be drawn to the current coordinates.
The view uses these members to store the information it needs in order to record the points of a stroke in progress.

Table 4.3 describes the member functions of class CScribView.

Table 4.3 CScribView Member Functions

Member	Description
CScribView, ~CScribView	With nothing to initialize and no data to destroy, the view's constructor and destructor are empty.
OnDraw	OnDraw updates the view by redrawing its contents. (It's used to draw both on the screen and on a printer.)
GetDocument	Defined inline in file SCRIBVW.H, GetDocument retrieves a type-safe pointer to the document attached to this view. The view uses the pointer to call document member functions, which it must do to access the data it displays.
AssertValid,        Dump	These diagnostic functions simply call the base-class functions they override.
OnPreparePrinting, OnBeginPrinting, OnEndPrinting	These virtual functions override the versions in CView to specify the application's printing behavior. See »Chapter 9« for more information about how Scribble prints.
AppWizard creates the constructor and destructor, GetDocument, AssertValid, Dump, OnPreparePrinting, OnBeginPrinting, and OnEndPrinting for you. You won't need to alter any of these functions for the tutorial, so they are not shown in this chapter.

Notice the inline definition of GetDocument after the class declaration above. The debug version of this member function calls the IsKindOf member function defined in class CObject and uses the RUNTIME_CLASS macro to retrieve the run-time class name of the document. For more information about those topics, see class CObject in the Class Library Reference and Chapter 12, »The CObject Class«.


 Redrawing the View

When the view, or some part of it, must be redrawn, the framework calls your override of the OnDraw member function.

To add implementation code for the view's OnDraw member function

•	Add OnDraw to file SCRIBVW.CPP, as defined below:

// Constructor and destructor, then ...

void CScribView::OnDraw( CDC* pDC )

{

CScribDoc* pDoc = GetDocument();

// The view delegates the drawing of individual strokes to

// CStroke::DrawStroke( ).

for( POSITION pos = pDoc->GetFirstStrokePos( );

pos != NULL; )

{

CStroke* pStroke = pDoc->GetNextStroke( pos );

pStroke->DrawStroke( pDC );

}

}

The view calls upon the individual stroke objects to draw themselves. To do this, the view needs access to the stroke data stored in the document, so the view's first task is to obtain a pointer to its document, using GetDocument. The view then uses the pointer to iterate through the stroke list, telling each stroke to draw itself. You saw the CStroke member functions GetFirstStrokePos and GetNextStroke in Chapter 3 in »Scribble's Document: Class CScribDoc«. When OnDraw calls DrawStroke for a given stroke object, it passes along the device-context object it received as a parameter. (Having the data draw itself is only one possible strategy.)

To complete Scribble's drawing, you must also add the DrawStroke member function to class CStroke.

To add drawing code for strokes

1.	Add the DrawStroke member function to file SCRIBDOC.CPP. Its declaration is already in place in SCRIBDOC.H. DrawStroke, called when the view redraws itself (as described above) looks like this:

// AddPoint, then ...

BOOL CStroke::DrawStroke( CDC* pDC )

{

CPen penStroke;

if( !penStroke.CreatePen(PS_SOLID, m_nPenWidth, RGB(0,0,0)))

return FALSE;

CPen* pOldPen = pDC->SelectObject( &penStroke );

pDC->MoveTo( GetPoint(0) );

for( int i=1; i < m_pointArray.GetSize(); i++ )

{

pDC->LineTo( GetPoint(i) );

}

pDC->SelectObject( pOldPen );

return TRUE;

}

DrawStroke is passed a pointer to an object of class CDC. CDC encapsulates a Windows device context. In programs written with the Microsoft Foundation Class Library, all graphics calls are made through a device-context object of class CDC or one of its derived classes. DrawStroke calls CDC member functions—SelectObject, MoveTo, LineTo—through the pointer to select a graphic device interface (GDI) pen into the device context and to move the pen and draw.

DrawStroke next constructs a new CPen object and initializes it with the current properties by calling the pen's CreatePen member function—note that this two-stage construction is typical of framework objects. Then DrawStroke calls SelectObject to select the pen into the device context (saving the existing pen as pOldPen) and calls MoveTo to position the pen. To initialize the pen position, DrawStroke calls the stroke object's GetPoint with an argument of 0. GetPoint returns the first point in the stroke's array.

DrawStroke then iterates through the array of points. It calls the device context's LineTo member function to connect the previous point with the next point.

Finally, DrawStroke restores the device context to its previous condition by reinstalling its old pen.

Important  Always restore the device context to its original state before releasing it to Windows. To do so, save the state before you change it. Storing the old pen in DrawStroke is an example of how to do this.

2.	The GetPoint member function called by DrawStroke (and already defined inline in file SCRIBDOC.H) is a helper function provided to retrieve points from the stroke's point array. It looks like this (don't add this code):

// Declaration of DrawStroke in class CStroke, then ...

protected:

   CPoint GetPoint( int i ) const

             { return CPoint(m_pointArray[i]); }

GetPoint retrieves the doubleword stored at a given index in the point array. It casts the doubleword to a CPoint.

The addition of DrawStroke completes Scribble's code for drawing in response to update requests from the framework. However, Scribble also draws in response to mouse actions, as discussed in the next section, »Handling Windows Messages in the View«.


 Handling Windows Messages in the View

To implement mouse-driven drawing in Scribble, it's necessary to write code that handles several Windows messages related to mouse activity. You will use ClassWizard to help write this message-handling code.

When the user presses the left mouse button while the pointer is in a Scribble window, Windows sends the window a WM_LBUTTONDOWN message. When the user subsequently releases the mouse button within the window, Windows sends the window a WM_LBUTTONUP message. Meanwhile, if the user moves the mouse—as in drawing—Windows sends a WM_MOUSEMOVE message.

How does Scribble handle these messages? They're sent to a window, in this case the currently active view. The view uses its "message map" to determine whether it has a member function that can handle the message. For example, on receiving a WM_LBUTTONDOWN message, the view finds that it has a "handler" associated with that message name and calls the handler. The handler is a member function of class CScribView.

It's appropriate that the view should handle mouse-drawing messages because it's in the view that Scribble's drawing takes place. The view represents that part of the document that can be seen at any one time.

What do the message-handler functions do? They track mouse activity, drawing in the view. They also call member functions of the document to update its data. As the user draws a stroke, the points that make up the stroke are stored in the document's stroke list.


 Connecting Messages to Code

This section takes you through the steps required to connect the three mouse-related messages needed in Scribble to message-handler member functions of class CScribView.

This step will be different from the previous ones. Instead of opening a file in the Visual Workbench editor and adding lines of code, you'll invoke ClassWizard and use it to make the connections between Windows messages and their handler functions. ClassWizard lets you make the connections and generate the handler functions with a few clicks of the mouse. ClassWizard writes an entry in the message map for class CScribView and writes a default member function definition in the SCRIBVW.CPP file for the handler function. You fill in the function's code.

You'll learn much more about ClassWizard, messages, message maps, and handler functions in Chapter 6, »Binding Visual Objects to Code Using ClassWizard.« For now, if you're working along, you'll invoke ClassWizard to connect the three mouse-related messages to handler names and to generate the handlers. Then you'll use the Visual Workbench editor to fill in the handler functions. If you're reading along instead, you can still try out ClassWizard on the starter code you created with AppWizard in Chapter 2, »Creating a New Application with AppWizard«. For more information about ClassWizard, see Chapter 6, »Binding Visual Objects to Code Using ClassWizard,« in this guide, Chapter 13 in the Visual Workbench User's Guide, and Chapter 9 in the App Studio User's Guide.

To connect the messages to Scribble's code

1.	With your Scribble project open in Visual Workbench, invoke ClassWizard by choosing the ClassWizard command from the Browse menu. The ClassWizard dialog box appears.

2.	In the Class Name edit box, make sure class CScribView is selected. The name "CScribView" and a number of predefined command IDs appear in the Object IDs list box. »Figure 4.2« shows ClassWizard's main dialog box.

3.	In the Object IDs list box, select the name "CScribView." A list of Windows messages that the view can receive appears in the Messages list box. »Figure 4.3« shows ClassWizard with the list of messages.

4.	In the Messages list box, select the name of a Windows message for which you want to define a handler. To begin, select WM_LBUTTONDOWN.

5.	To define a handler function for the message, choose the Add Function button.

The Member Functions list box now lists the member function name OnLButtonDown and the corresponding message-map macro name ON_WM_LBUTTONDOWN. A small hand-shaped icon next to the WM_LBUTTONDOWN message in the Messages list box shows that the connection has been made.

6.	Repeat steps 4 and 5 for each additional message: first WM_LBUTTONUP, then WM_MOUSEMOVE.

7.	Choose the OK button to close the main ClassWizard dialog box.

At this point, ClassWizard has done the following things to associate each of the three messages with its handler and to greatly simplify your work:

•	Added a function declaration for the handler to the CScribView class declaration in file SCRIBVW.H.

•	Added a "message-map entry" for the message-to-handler connection in CScribView's message map in file SCRIBVW.CPP.

•	Added a function definition with a default body — to file SCRIBVW.CPP. For example, the default function definition for OnLButtonDown looks like this (don't add this code):

void CScribView::OnLButtonDown( UINT nFlags, CPoint point )

{

    // TODO: Add your message handler code here

    // and/or call default

    CView::OnLButtonDown( nFlags, point );

}

Notice that ClassWizard embeds a comment reminding you what to do and adds a call to the OnLButtonDown member function of class CView, the base class of CScribView.

You'll learn more about message maps, message-handler functions, and their uses in Chapter 6, »Binding Visual Objects to Code Using ClassWizard.« For more information about these topics, see Chapter 3 in the Class Library Reference.


 Adding the Message-Handler Functions

With the connections made, it's time to fill in the bodies of the handler functions. If you're working along, add the marked lines of code.

To fill in Scribble's message-handler function bodies

1.	Choose the ClassWizard command from the Browse menu in Visual Workbench.

2.	To write the handler code for the WM_LBUTTONDOWN message, select the OnLButtonDown handler name in the Member Functions list box.

3.	Choose the Edit Code button. The Visual Workbench editor appears, scrolled to a function definition for OnLButtonDown. Its body is selected for editing. »Figure 4.4« shows OnLButtonDown in the editor.

ClassWizard creates the following default implementation, which you'll replace later:

void CScribView::OnLButtonDown(UINT nFlags, CPoint point)

{

    CView::OnLButtonDown( nFlags, point);

}

4.	Fill in the member functions as described in the procedures that follow.


 Initiate Stroke Drawing

The OnLButtonDown member function, shown below, is called via the message map when Windows sends a WM_LBUTTONDOWN message to the view object. The function begins a new stroke, adding the current location of the mouse to the stroke and adding the stroke to the document's stroke list. Then OnLButtonDown "captures" the mouse—until the left mouse button is released to end the stroke.

To add code for OnLButtonDown

1.	If you haven't already done so, use the Edit Code button in ClassWizard (or the Visual Workbench editor) to move to the function definition for OnLButtonDown.

2.	Replace the default implementation of the OnLButtonDown function body with the marked lines shown here:

void CScribView::OnLButtonDown( UINT nFlags, CPoint point )

{

// When the user presses the mouse button, she may be

// starting a new stroke, or selecting or de-selecting a

// stroke.

m_pStrokeCur = GetDocument( )->NewStroke( );

// Add first point to the new stroke

m_pStrokeCur->AddPoint( point );

SetCapture( );  // Capture the mouse until button up

m_ptPrev = point;	// Serves as the MoveTo( ) anchor point

// for the LineTo() the next point, as

// the user drags the mouse

return;

}

This version of OnLButtonDown doesn't include a call to the base class version. It completely replaces the inherited behavior.

3.	Remove the first parameter name, nFlags, from the declaration of OnLButtonDown in order to avoid a compiler warning stating that this parameter is not referenced.

void CScribView::OnLButtonDown( UINT, CPoint point )

Once in the editor, you can complete your other message handlers or return to ClassWizard and select another function.


 Terminate Stroke Drawing

The OnLButtonUp member function, shown below, ends the current stroke when the user releases the left mouse button. The function draws a line to connect the last point, then releases the mouse for use by other windows. The test at the beginning calls the Windows GetCapture function to determine whether the current window has control of the mouse. If not, the user is not currently drawing in this view.

To add code for OnLButtonUp

1.	Use the editor to scroll to the OnLButtonUp function definition in the same file.

2.	Replace the default implementation of the OnLButtonUp function body with the marked lines shown here:

// OnLButtonDown, then ...

void CScribView::OnLButtonUp( UINT nFlags, CPoint point )

{

// Mouse button up is interesting in the Scribble

// application only if the user is currently drawing a new

// stroke by dragging the captured mouse.

if( GetCapture( ) != this )

return;	// If this window (view) didn't capture the

// mouse, the user isn't drawing in this window.

CScribDoc* pDoc = GetDocument( );

CClientDC dc( this );

CPen* pOldPen = dc.SelectObject( pDoc->GetCurrentPen( ) );

dc.MoveTo( m_ptPrev );

dc.LineTo( point );

dc.SelectObject( pOldPen );

m_pStrokeCur->AddPoint( point );

ReleaseCapture( );	// Release the mouse capture established

// at the beginning of the mouse drag.

return;

}

3.	Remove the first parameter name, nFlags, from the declaration of OnLButtonUp in order to avoid a compiler warning that this parameter is not referenced.

void CScribView::OnLButtonUp( UINT, CPoint point )


 Draw While the Mouse Button Is Down

Between the time that the mouse button goes down and the time that it's released, Scribble tracks the mouse and draws a trace of its movements in the view. OnMouseMove, shown below, is called as the user moves the mouse while drawing the current stroke. The function connects the latest mouse location with its previous location and saves the new location as the previous point for the next time the function is called. To do the drawing, OnMouseMove constructs a local CClientDC object used to draw in the window's client area.

To add code for OnMouseMove

1.	Scroll to the OnMouseMove function definition in the same file.

2.	Replace the default implementation of the OnMouseMove function body with the marked lines shown here:

// OnLButtonUp, then ...

void CScribView::OnMouseMove( UINT nFlags, CPoint point )

{

// Mouse movement is interesting in the Scribble application

// only if the user is currently drawing a new stroke by

// dragging the captured mouse.

if( GetCapture( ) != this )

return;	// If this window (view) didn't capture the

// mouse, the user isn't drawing in this window.

CClientDC dc( this );

m_pStrokeCur->AddPoint( point );

// Draw a line from the previous detected point in the mouse

// drag to the current point.

CPen* pOldPen =

dc.SelectObject( GetDocument( )->GetCurrentPen( ) );

dc.MoveTo( m_ptPrev );

dc.LineTo( point );

dc.SelectObject( pOldPen );

m_ptPrev = point;

return;

}

3.	Remove the first parameter name, nFlags, from the declaration of OnMouseMove in order to avoid a compiler warning that this parameter is not referenced.

void CScribView::OnMouseMove( UINT, CPoint point )

Together, these three member functions handle the three phases of mouse drawing: beginning to track the mouse, tracking the mouse and connecting points, and ending mouse tracking.

For more information about the Microsoft Foundation Class Library classes mentioned in this section, see the Class Library Reference.


Compile Scribble  Step 1 Version
 Compile Scribble − Step 1 Version

In this section, if you've been working along, you'll compile your completed code and try out the program. If you're simply reading along, use the Scribble project supplied in your Visual C++ installation as described in step 2 following.

To try out your work in Chapters 3 and 4

1.	If you don't have Visual Workbench running, start it by choosing the Visual Workbench icon in the Program Manager.

2.	Open the SCRIBBLE.MAK project (if it's not already open) by choosing Open on the Project menu and completing the dialog box. The following describes where to find the appropriate version of the project:

If you're building Scribble after working through the chapter, use the SCRIBBLE.MAK file in your MYSCRIB directory.

 − or −

If you're simply previewing Scribble without adding code, use the SCRIBBLE.MAK file provided by Visual C++ in the MFC\SAMPLES\SCRIBBLE\STEP1 subdirectory.

3.	On the Project menu, choose Build to compile and link Scribble.

4.	If necessary, use the Visual Workbench debugging facilities to find and correct any errors you made.

For debugging information, see Chapter 11 in the Visual Workbench User's Guide.

After compiling Scribble, try out its features. When Scribble runs, an MDI application window appears with a menu bar containing File, Edit, View, Window and Help menus and a toolbar and status bar. It has one document window open as shown in »Figure 4.5.«

To give Scribble a try

1.	On the Visual Workbench Project menu, choose the Execute Target command to run Scribble.

2.	On the File menu, use the New command to create a new document.

3.	Move, resize, minimize, and maximize the document window.

4.	Draw "Hello, World!" (or anything) in the window. Then save the file as HELLO.SCB.

5.	Try the Print Preview and Print commands on the File menu.

Note  Your printout may show the strokes of your scribbling at a reduced size. This is because the current version of Scribble uses the MM_TEXT mapping mode instead of the MM_LOENGLISH mapping mode. Unlike MM_LOENGLISH, which Scribble will use at a later stage, MM_TEXT doesn't acknowledge that a pixel on the printer is much smaller than a pixel on the screen. Printing will improve later in the tutorial.

6.	Close HELLO.SCB and reopen it with the Open button on the toolbar.

7.	Create a new document with the New button on the toolbar and draw in the new document. (Save the new document if you like.)

8.	Exit Scribble.

Note  During drawing, Scribble samples points as fast as it can (as soon as the mouse moves). When Scribble's view redraws a stroke, the playback represents approximately the speed at which the stroke was originally drawn.

This concludes your quick introduction to Scribble. You've seen how to implement the document with serialization and the view with message handling. In Chapter 5, »Constructing the User Interface With App Studio«, you'll learn to construct some additional user-interface components with App Studio. Later chapters add more (and more interesting) code to Scribble.


 Chapter 5  Constructing the User Interface With App Studio

Now that you've implemented enough of Scribble by hand to see how it works, it's time to explore the tools that eliminate much of the handwork.

The next three chapters show how to use some of the powerful tools supplied with the Microsoft Foundation Class Library.

•	This chapter explains how to use App Studio to visually construct Scribble's menus and toolbar.

•	In Chapter 6, »Binding Visual Objects to Code Using ClassWizard,« you will use ClassWizard and Visual Workbench to bind menu items and toolbar buttons to commands and define message-handler functions to process the commands.

•	Chapter 7, »Adding a Dialog Box,« shows how to use both App Studio and ClassWizard to create a dialog box and connect it to a menu command.

App Studio, Class Wizard and Visual Workbench automatically add these new features to the resource and source files that AppWizard created in Chapter 2, »Creating a New Application with AppWizard,« and that you augmented in Chapter 3, »Creating the Document,« and Chapter 4, »Creating the View.«

This chapter and »Chapter 6« cover step 2 of Scribble. If you want to work along, adding the code as you go, begin with the files from Chapter 4 in your MYSCRIB directory. At this point, your files should be very similar to the files in the SCRIBBLE\STEP1 subdirectory. As you read this chapter, perform all App Studio steps. At the end, your resource file, SCRIBBLE.RC, should closely resemble the same file in the SCRIBBLE\STEP2 subdirectory. Also in Visual Workbench you'll make a small addition to the MAINFRM.CPP file. You can compile the new version of Scribble at the end of Chapter 6 in Compile Scribble − »Step 2 Version«.

If, on the other hand, you want to read along without adding code, you can print or examine the files in the SCRIBBLE\STEP2 subdirectory.

Even if you don't want to add code, however, it's a good idea to work along in this chapter to familiarize yourself with App Studio and the Visual C++ programming process. You can begin by making your own copy of the SCRIBBLE\STEP1 subdirectory.


 Edit Scribble's Menus

The first task in this chapter is to edit Scribble's menus using the menu editor in App Studio.

Thanks to AppWizard, Scribble starts out with a skeleton resource file with no effort on your part. You can look at the file SCRIBBLE.RC among the files generated in »Chapter 2« to see what's there.


 Default Menus

The menus AppWizard generates by default include:

•	A menu bar to display when Scribble, a multiple document interface (MDI) application, has no documents open.

They include a basic File menu, a View menu for toggling the visibility of Scribble's status bar and toolbar, and a basic Help menu.

•	A menu bar to display when a Scribble document is open.

They include, besides those above, more File menu commands, an Edit menu with standard commands, and a Window menu with standard commands (supplied only for MDI applications, like Scribble).

Note  Single document interface (SDI) applications have only one menu bar. The correct menu bars are generated when you choose between SDI and MDI in AppWizard.


 Scribble's New Menu Commands

The goal in this section is to add a new Clear All command to the Edit menu as well as a completely new Pen menu with two commands, Thick Line and Pen Widths. The Clear All command clears the current drawing and deletes its stroke data. The Thick Line command toggles the thickness of the lines used to draw subsequent strokes. They can be thick or thin. The Pen Widths command brings up a dialog box that lets the user set the thick and thin widths in pixels for subsequent drawing.

In the discussion that follows, you'll see how to create the new menu items with App Studio. In Chapter 6, »Binding Visual Objects to Code Using ClassWizard«, you'll see how to use ClassWizard to connect the menus to code. And in Chapter 7, »Adding a Dialog Box,« you'll see how to create the Pen Widths dialog box and connect it to the menu command.


 Adding the Menus

This section adds all of Scribble's new menus and demonstrates the fundamental techniques for editing menus with App Studio.


 Designing

Because App Studio is highly visual, it is easy for you to design your application's user interface. For example, you can drag menus around on the menu bar, drag and drop new controls on a dialog box, use tools to align the elements, and so on.

Beyond that, App Studio lets you test the behavior of your menus and dialog boxes. While you're editing menus, simply click the menu bar to see a menu drop down. While you're editing a dialog box, invoke App Studio's Test command to simulate the actions of the dialog box and its controls. You'll see the Test command in use in Chapter 7 in »Modifying the Controls' Properties«.


 Examining and Editing Resources

App Studio lets you work with many resource types: menus, dialog boxes, bitmaps, string tables, and more. Use the resource browser to select a particular resource type and then to select a specific resource of that type. The resource browser is the first window you see when you run App Studio — it's the upper window in »Figure 5.1.« The figure shows the Menu resource type selected in the Type list box.

In the resource browser, you can click a resource type to view a list of the specific resources of that type. Each resource has an ID and an icon that shows its type. Then you can click a resource ID and choose the Open button to invoke an editor for the selected resource. Or you can create a new resource of the selected type by choosing the New button.

When you select and open a specific resource, such as a menu, App Studio invokes an editor for that type. For example, the menu editor displays a menu bar showing all menus defined by the open menu resource. Although you're in editing mode, you can simulate menu operation by choosing a menu with the mouse (keyboard shortcuts are not available for a menu-in-progress). You can also drag menus to new locations, add new menus or menu items, and edit the properties of existing menus. »Figure 5.2« shows a menu-editor window with the Properties window directly below it.

As you work with the editor for a resource, the Properties window floats nearby, showing a "property page" for the resource. (To keep it there, use the "pushpin" control in the upper left corner, as shown in Figure 5.3.) »Figure 5.3« shows the property page for a menu resource. A property page displays information about the resource and lets you edit the information. For example, a menu's property page displays the ID of the command associated with the menu, the menu's caption as it appears when the menu drops down, and other properties that relate to the menu's visibility or status. The property page also shows a command-prompt string displayed when the user moves the mouse over the menu item. In framework programs, the prompt tells the user what the menu command does. Some resources have multiple property pages, which you can access through the drop-down list box in the upper-right corner of the Properties window.

Properties for a selected resource are displayed automatically in the Properties window. When you select the ID with a single click, check boxes for general properties appear — such as Preload, Moveable, Discardable, and Pure. Usually you can ignore these. When you open the resource to edit it and select a menu in the editor window, the property page reflects the properties of the chosen menu item. Typically, you'll edit these.

When you use App Studio to define a command ID for a menu, App Studio assigns each such ID a unique value and writes a #define line for it in the file you specify or RESOURCE.H by default. Automatic definition of such symbols is one of the advantages of using App Studio. If you enter a duplicate ID, App Studio alerts you so you can change it.

The command ID and a caption string are required menu properties. For more information about menu property pages, see the App Studio User's Guide.


 Add the Clear All Command to Scribble's Edit Menu

How App Studio handles menus is illustrated when you add the new menu item, the Clear All command, to Scribble. If you're working along, use the following procedure:

To add Scribble's Clear All Menu Command

1.	Start up App Studio: With your Scribble project open in Visual Workbench, open the resource file SCRIBBLE.RC by opening App Studio from the Tools Menu.

If you're working along, use the version of SCRIBBLE.RC in the directory MFC\SAMPLES\SCRIBBLE\MYSCRIB. If you're reading along, use the version in the directory MFC\SAMPLES\SCRIBBLE\STEP1.

This launches App Studio, which automatically uses the resource compiler to compile the file's resources. When the file has been compiled, the App Studio resource browser lists Scribble's resource types.

Important  Although you can run App Studio as a stand-alone program, it's best to run it from the Tools menu in Visual Workbench with your project already open. Or you can run App Studio by opening a .RC file from the Visual Workbench File menu. By default, opening a .RC file from the File menu opens the file as text. You can modify that behavior to open .RC files in App Studio. Use the Editor command in the Visual Workbench Options menu. Running App Studio from Visual Workbench in either of these ways allows Visual Workbench to pass useful information about the project to App Studio.

2.	Choose Menu from the Type list box of the resource browser.

Two menu IDs appear in the right-hand list box: IDR_MAINFRAME and IDR_SCRIBTYPE. IDR_MAINFRAME is the menu resource for the multiple document interface (MDI) frame window when no documents are displayed in its child windows. IDR_SCRIBTYPE is the menu resource for the frame window when a document in a child window has the focus. (Under the multiple document interface (MDI), the available menus vary depending on context.) This ID was defined for you by AppWizard. The ID name is based on the Document Type Name you supplied in AppWizard.

3.	Open the IDR_SCRIBTYPE menu resource.

Select the ID in the Resource list box and choose the Open button, or double-click the ID. A menu-editing window appears. You see the menus much as you would see them in the running application. If the Properties window does not appear, select Show Properties from the Window menu. The Properties window now shows the properties of this particular menu resource. »Figure 5.4« shows the menu editor and a general property page for the resource. Note the empty cells in the menu bar and Edit menu.

4.	Click the Edit menu.

The menu drops down as it would in the application. An empty cell outlined with a dotted line sits below the last menu item, as shown in »Figure 5.4.« The cell defines where you add the next menu item.

For a taste of what you can do with menus, see the topic »Drag and Drop«.

5.	Click the cell at the bottom of the Edit menu.

The cell is highlighted with a fuzzy gray outline. This is where you'll see the menu's caption after you type it in the Properties window.

6.	Type the caption Clear &All in the Caption edit box of the Properties window.

As soon as you start typing, the text you enter appears in the ragged-outlined cell on the menu. You don't have to select the Caption edit box first.

Type the ampersand character (&) in front of the letter to be used in an access key combination. As you type &A, for example, the letter A appears underlined in the menu.

Note  If you wanted to specify an accelerator or shortcut key for the menu item, you'd append its specifier after the caption. For example, to specify CTRL+O as the accelerator for an Open command, the caption string would read "Open...\tCTRL+O" where "\t" signifies a tab to align the column.

7.	Open the ID drop-down list in the Properties window and start typing the ID for the Clear All command: ID_EDIT_C.

As soon as you start typing the ID, the drop-down list box scrolls to the first ID that matches the letters you've typed so far. This behavior occurs because ID_EDIT_CLEAR_ALL is a command ID predefined by the class library. App Studio ensures that the ID you enter is unique.

Two IDs that begin with "ID_EDIT_C" appear in the list box. Select the second one: ID_EDIT_CLEAR_ALL.

»Figure 5.5« shows the property page after you've selected the ID.

You can define your own command IDs, of course. You'll see an example under »Add Scribble's Pen Menu«.

8.	As soon as you select the predefined ID, the following string appears in the Prompt edit box: "Erase everything". Change the wording to "Clears the drawing".

The prompt string is displayed in the status bar, if the application has one, when the user navigates up and down the menu using the keyboard.

AppWizard predefines this text for the ID_EDIT_CLEAR_ALL symbol. For an ID that isn't predefined, you should enter a descriptive prompt string. This context-sensitive menu information is essentially free, so take advantage of it.

That's it. You've added the Clear All command to the Edit menu. It appeared in the menu as soon as you started typing its caption. »Figure 5.6« shows the finished product.

Note  You don't have to press ENTER or click any buttons to conclude your menu editing. App Studio automatically stores the edited resource in the resource file.

The most important thing about defining the menu command is assigning it an ID. To the framework, the ID is the command. At some point, you have to specify what happens when the user chooses the Clear All menu command; which code will be  executed? You'll learn more about commands in the next chapter in »Using ClassWizard to Bind Commands«.


 Add Scribble's Pen Menu

Adding an entire new menu is similar to adding new commands to existing menus. If you're working along, use the following procedure:

To add Scribble's Pen menu

1.	With the menu-editor window still showing, click in the ragged-outlined cell at the right-hand end of the Scribble menu bar (after the Help menu).

This cell serves the same purpose for the top-level menus as the other ragged-outlined cell does for items within a pop-up menu.

2.	To position the menu entry, drag the ragged-outlined cell to the left and drop it between the Edit and View menus. (See the topic »Drag and Drop«.)

3.	Type the new menu's caption, &Pen, in the Caption edit box of the Properties window.

This is the only step needed to define the Pen menu as a whole. The next step is to define the menu items on the Pen menu.

»Figure 5.7« shows the new Pen menu after it has been dragged to its new location and the menu caption typed in.

4.	Press the ENTER key to advance to the first menu item or click the ragged-outlined cell that descends beneath the word "Pen."

5.	As you did for the Clear All command, type a caption for the Thick Line command in the Caption edit box: Thick &Line.

6.	Select the ID combo box and type a command ID: ID_PEN_THICK_OR_THIN.

7.	Type a command prompt string in the Prompt edit box: Toggles the line thickness between thin and thick.

No default string appeared because ID_PEN_THICK_OR_THIN is not a predefined command ID.

8.	Click the ragged-outlined cell at the bottom of the Pen menu, below "Thick Line."

9.	As you did for the Thick Line command, type a caption for the Pen Widths command: Pen &Widths....

The ampersand (&) appears before the character to be used as an access key. The ellipses (. . .) following a menu item's text lets the user know that the item brings up a dialog box.

10.	Type a command ID: ID_PEN_WIDTHS

11.	Type a command prompt string: Changes the size of the thin and thick pen

That's all it takes to create the Pen menu. »Figure 5.8« shows the completed menu as it appears in the menu editor.


 Drag and Drop

Drag and drop is a common technique in App Studio. You'll find it in the user interfaces of many of the resource editors. For example, in Chapter 7 in »Designing a Dialog Box«, you'll see it used to drag various kinds of controls from a controls palette and drop them into a dialog box in the dialog editor. Try experimenting in the menu editor: position the mouse over an outlined box under a menu item; press the left mouse button, and drag the box up or down the list and drop it where you like by releasing the mouse button. Notice that when you start to drag, an insertion point appears to orient you for dropping. You can also drag a whole menu to some other location in the menu structure, or you can drag a top-level menu to a lower level, to create a hierarchical menu. If you change your mind, drag the menu back or choose Undo from the Edit menu.


 Connect the Menus to Code

Typically, at this point you would invoke ClassWizard from App Studio's Resource menu and use it to bind the menu commands to message-handler functions. That step is postponed until the next chapter in order to keep this chapter focused on App Studio and constructing the user interface. If you like, you can skip ahead, perform the command-binding steps in Chapter 6 in »Binding Scribble's Commands« and then return to this chapter to edit Scribble's toolbar.


 Edit Scribble's Toolbar

The resource file that AppWizard gives you also includes a toolbar bitmap. »Figure 5.9« shows the toolbar bitmap. In this section you'll use App Studio's bitmap editor to add a new button to the bitmap for Scribble.

Earlier in the chapter in »Add Scribble's Pen Menu«, you added the Pen menu. One of its menu items is the Thick Line command. In this section, you'll add a Thick Line button to Scribble's toolbar. Then, in Chapter 6 in »Adding Handlers for Commands«, you'll use ClassWizard to connect both the Thick Line menu item and the Thick Line toolbar button to the same handler member function. Thus the Thick Line toolbar button will become an alternative user interface for the Thick Line menu item. That is, both user-interface objects will have the same command ID, so they generate the same command message, which invokes the same handler function.

When the user chooses either the menu item or the toolbar button, the chosen item sends a command message that toggles Scribble's drawing pen between thin and thick lines. »Figure 5.10« shows Scribble as it appears with the finished toolbar. The Thick Line button is the seventh button from the left.


 About the Toolbar

Some of the buttons on Scribble's toolbar already work, as you saw in Chapter 4 when you compiled Scribble (see »Compile Scribble − Step 1 Version«). The buttons for opening and saving files are already connected to handlers defined by the framework. All you had to do to make the file operations functional was write the Serialize functions for the document and the stroke data structure. The print button is supported by default.

The Cut, Copy, and Paste buttons on the toolbar will not be implemented for Scribble. The Help button will not be connected up until a later chapter in the tutorial.

Although this chapter simply shows you how to add one new button, you could easily add others or delete unused buttons from the toolbar bitmap.


 Add the Thick Line Button to Scribble's Toolbar Bitmap

You'll use App Studio's graphics editor for this task.

To edit Scribble's toolbar

1.	Start up App Studio from Visual Workbench.

You saw how to do this earlier in the chapter in »Add the Clear All Command to Scribble's Edit Menu«.

2.	In the resource browser, choose Bitmap in the type list box.

If the Properties window is not open, open it by choosing the Properties button in the resource browser window. Click the pushpin so the Properties window will remain open.

3.	Select the IDR_MAINFRAME resource ID in the Resources list box.

»Figure 5.11« shows the resource browser at this stage. In the Properties window, you see a Preview box with an actual-size image of the bitmap.

4.	Choose the Open button to Open the IDR_MAINFRAME bitmap resource.

An image window opens showing the bitmap. Below it is the Properties window. A graphics palette opens as well, showing the tool box, a color indicator, the color palette, and the option selector. »Figure 5.12« shows this configuration. You may see more or less of the image window than shown in the figure depending on your screen size.

You may want to drag the graphics palette out of the way on the left-hand side of the image window.

5.	Use the window's maximize button to enlarge the image window that shows the bitmap.

6.	From the Image menu choose Grid Settings.

7.	In the Grid Settings dialog box, set the Tile Grid checkbox and choose the OK button. (»Figure 5.13« shows the Grid Settings dialog box.) Leave Pixel Grid checked as well. The size boxes show a grid size of 16 pixels by 15 pixels. This is the size of a "tile" — one of the buttons on the toolbar.

Turning on the Tile Grid option places a thin blue rectangle, a guide, around each tile in the bitmap. These guides make it easier to select and work with a tile.

8.	Scroll the right-hand pane of the image window (which shows a zoomed image of the bitmap) until the right-hand end of the bitmap is visible in the center of the pane.

Notice that the bitmap is outlined by a selection rectangle. In the Properties window, the Width text box shows the bitmap's current width to be 144 pixels. Beyond the end of the bitmap is enough space to expand the bitmap by several tiles.

9.	Lengthen the bitmap by one tile: Drag the resizing handle on the right-hand end of the bitmap to the right by the width of one tile.

The bitmap grows a full tile at a time. Notice that as you drag your bitmap, the rightmost indicator on the App Studio status bar shows new bitmap dimensions of "160 x 15." This makes the bitmap wide enough to accommodate another button.

Beyond the current end of the bitmap you see a white area the size of a tile at the end, overlaid with the grid. »Figure 5.14« shows the bitmap as it appears after you've lengthened it, with the white space displayed at the end.

Notice that the Width text box in the Properties window now shows the new width of the toolbar bitmap to be 160 pixels.

10.	Enclose the three rightmost button images — a printer, a question mark, and an arrow next to a question mark — with the selection rectangle.

Click the selection tool in the upper-right corner of the graphics palette.

»Figure 5.15« shows the graphics palette and the three tools you'll be using: the selection tool, the pencil tool, and the fill tool.

Position the mouse pointer at the upper-left corner of the printer image and drag to the lower-right corner of the question-mark image. Place the lines of the crosshairs just inside the blue guides.

11.	Drag the selected images one tile to the right to open up a space for a new button.

»Figure 5.16« shows the bitmap after dragging.

12.	Choose the pencil tool from the graphics palette.

13.	Draw the bitmap shown in »Figure 5.17.« It doesn't have to be exact.

If you make a mistake, choose the eraser tool.

14.	Choose the paint-bucket fill tool from the graphics palette.

15.	Choose light gray from the color palette.

16.	Click the fill tool in the new button image to fill its background with the selected color.

»Figure 5.18« shows the completed bitmap as it appears in Scribble.

17.	From the File menu choose Save.

18.	Exit App Studio.

That completes the task of editing Scribble's toolbar bitmap. In order for the new button to work, it must be associated with a command ID. In this case, the Thick Line button will be bound to ID_PEN_THICK_OR_THIN. You defined that ID earlier in the property page for the Thick Line menu command, so App Studio has already written a #define for the ID in a file called RESOURCE.H. Your only task at this point is to associate the ID with the button. If you are working along, add lines of code marked with [image].

Note  If you had just created a new button for which there was no existing command ID, you'd use the App Studio symbol editor to define a symbol such as ID_PEN_THICK_OR_THIN. For information about the symbol editor, see Chapter 2 in the App Studio User's Guide.

To associate the button with its command ID

1.	Start up Visual Workbench if it's not open.

2.	From the File menu in the Visual Workbench editor, open the MAINFRM.CPP file.

3.	Scroll to the static array called "buttons." The code maps the buttons to their command IDs.

// Arrays of IDs used to initialize control bars

// Toolbar buttons - IDs are command buttons

static UINT BASED_CODE buttons[] =

{

// Same order as in the bitmap 'toolbar.bmp'

ID_FILE_NEW,

ID_FILE_OPEN,

ID_FILE_SAVE,

ID_SEPARATOR,

ID_EDIT_CUT,

ID_EDIT_COPY,

ID_EDIT_PASTE,

ID_SEPARATOR,

ID_PEN_THICK_OR_THIN,

ID_SEPARATOR,

ID_FILE_PRINT,

ID_APP_ABOUT,

};

This array definition provides a 1-to-1 mapping based on the positions of the button tiles in the toolbar bitmap. The ID_SEPARATOR entries denote small amounts of extra space used to group the button tiles.

4.	Save the file.

Now the Thick Line button generates precisely the same command as the Thick Line menu item. Because of this, the same handler function serves for both.


 Summary

Scribble's resource needs are simple, so this chapter introduced only a few of the things you can do with App Studio. For information about its many capabilities, see the App Studio User's Guide.

After editing your application's menus and toolbar with App Studio, the next step is to connect them to code using ClassWizard. That step is explained in »Chapter 6.«


 Chapter 6  Binding Visual Objects to Code Using ClassWizard

The version of Scribble you saw in »Chapter 3« and »Chapter 4« added a small amount of code to the skeleton starter files created by AppWizard — much less code than you would normally have to write to get a comparable application up and running without the framework. Considering the small amount of work, the program does quite a lot: drawing, saving, printing, even print preview.

Like all applications written for Windows, Scribble is "message driven." A keystroke, mouse click, or other event causes messages to be sent to some part of the application that can respond to the event. In Chapter 4 in »Adding the Message-Handler Functions«, for example, you saw how Scribble implements mouse drawing by detecting and responding to messages generated by mouse clicks and drags.

This chapter introduces a category of messages called "commands," which are messages to your application from menu items, toolbar buttons, and accelerator keys. The expanded version of Scribble developed in this chapter adds two menu items that generate commands to toggle the line thickness for drawing and to clear all strokes from the current document. The command that toggles line thickness is also duplicated by a button on Scribble's toolbar.

You created the resources for Scribble's new menu items and its new toolbar button in Chapter 5 in »Edit Scribble's Menus« and »Edit Scribble's Toolbar«. Now you can use ClassWizard to assign a user-interface object, such as a menu item, to a command and map the command to a function that handles it.

In this chapter, you will:

•	Learn the fundamentals of commands and how the framework routes them to various "command target" objects in the program for handling.

•	Extend your knowledge of ClassWizard, begun in »Chapter 4.«

•	Add new command-handling code for Scribble.

•	Connect a toolbar button and a menu item to the same command.

•	Learn how to keep your user-interface objects (menus and toolbar buttons) updated since a menu item may be enabled or disabled, a button checked or unchecked.

This chapter and the previous chapter cover step 2 of Scribble. If you want to work along, adding the code as you go, begin with the files from Chapter 5, »Constructing the User Interface with App Studio,« in your MYSCRIB directory. At this point, your files should be very similar to the files in the SCRIBBLE\STEP1 subdirectory, plus the resource changes you made in Chapter 5 with App Studio. As you read this chapter, perform all ClassWizard steps and add all lines of code marked in the left margin with the symbol [image]. At the end of the chapter, your files should closely resemble the files in the SCRIBBLE\STEP2 subdirectory.

If, on the other hand, you want to read along without adding code, you can print or examine the files in the SCRIBBLE\STEP2 subdirectory. However, even if you don't want to add code, it's a good idea to work along in this chapter to familiarize yourself with ClassWizard and the Visual C++ programming process. You can begin by making your own copy of the SCRIBBLE\STEP1 subdirectory.


 Using ClassWizard to Bind Commands

In the previous chapters, you created a working Scribble application. In Chapter 4 in »Connecting Messages to Code«, you used ClassWizard to make connections between several standard Windows messages related to mouse actions and the code that responds to those actions. Now you'll use ClassWizard to add new commands to Scribble.

In this chapter, you will use ClassWizard to connect menu items, toolbar buttons, and other user-interface objects to the code that responds when the user clicks them. In »Chapter 7,« you will use ClassWizard again to create new classes and perform other chores (see the following section, »What ClassWizard Can Do«).


 What ClassWizard Can Do

ClassWizard is one of the Visual C++ tools that you'll use most frequently. It helps you:

•	Connect standard Windows messages to message-handler functions.

•	Connect user-interface objects to message-handler functions.

•	Create new classes, such as dialogs and extra views, documents, or frame windows.

•	Add member variables to dialog classes and specify how those variables are to be initialized and validated when the dialog box is displayed.

For more information about the capabilities of ClassWizard, see Chapter 9 in the App Studio User's Guide.

When the ClassWizard dialog box appears, a drop-down list shows all of the classes in your program that can handle commands or Windows messages. When you select a class to which you want to map commands, a list box shows you all of the visual objects associated with that class:

•	Classes, such as dialogs, views, and frame windows, which can receive standard Windows messages.

•	Dialog-box controls, which can generate Windows control-notification messages.

•	Command IDs, which are associated with menu items, toolbar buttons, or accelerator keys.

When you select a visual object, a second list box displays a list of the Windows messages or commands to which you can connect the visual object.

To make a connection, you select one of the available messages or commands to connect the object to and choose the Add Function button. Another list box shows the message or command and the name of its handler function.

The resulting connection is called a "command binding." »Figure 6.1« shows the ClassWizard dialog box after a command has been connected to a handler. In some cases, a second dialog box appears to let you accept or modify a proposed function name.

After you create a message-handler function, ClassWizard writes an entry for the command in the chosen class's "message map" and adds a function declaration to the class. Also, ClassWizard writes a function template—a complete member function definition with an empty function body—in the source files that contain the class. ClassWizard then lets you jump directly to the Visual Workbench editor to fill in the function template. You'll learn more about message maps and message-handler functions later in this chapter in »Message Maps« and »Message Handlers«.

Note  ClassWizard automatically writes its changes to your files to disk. You need to save files explicitly only if you have edited them yourself, as for example when you use the Visual Workbench editor to fill in a handler's code.

You can also use ClassWizard to edit existing message maps and message-handler functions. ClassWizard follows a conservative set of rules in writing to your files, writing only a few kinds of code to predictable places, so it's safe and easy to use.

Warning  If you delete a command binding with ClassWizard, its message-map entry is deleted, but the message-handler function, and any references to it in your other code, are not deleted. You must edit those items by hand.

Because you may want to bind commands either while you're editing user-interface objects that generate commands or while you're editing code, you can invoke ClassWizard from the Resource menu in App Studio or from the Browse menu in Visual Workbench.

Typically, you will invoke ClassWizard from App Studio while you're editing menus, dialog boxes, and other user-interface objects. ClassWizard uses the current selection in App Studio to jump quickly to the appropriate class for the selected visual object.

You may want to work something like this: create several menu items or other user-interface objects, call up ClassWizard and connect the first object to a handler, and jump to the Visual Workbench editor to write the handler. Then return to ClassWizard and repeat the process for each of the other objects. Or you may prefer to create the user-interface objects, use ClassWizard to make all of the connections, and then jump to Visual Workbench to fill in all of the handler functions. The tools are flexible enough to support whichever working style you prefer.


 Adding Handlers for Commands

Once you've created the user-interface objects — such as menus, accelerators, and toolbar buttons — that generate commands, you must bind them to the code that carries out the commands. This section explains the fundamentals of commands in the framework and explains how to use ClassWizard to bind user-interface objects to commands and commands to code.


 Command Fundamentals

Before using ClassWizard to bind commands, you'll need to know more about the related concepts and terms. In addition to this section, you'll find more information about these concepts in Chapter 3 of the Class Library Reference.


 Command Concepts and Terms

»Figure 6.2« illustrates the concepts that make up the command architecture of the Microsoft Foundation Class Library. Among the concepts covered in this chapter are:

•	Commands, messages, and control notifications

A command is an instruction to your program to perform a certain action. Unlike a function call, a command is a "message" that is routed to various "command target" objects, each of which has an opportunity to carry out the instruction. Examples of commands include the Open, Save, and Save As commands on the File menu.

Important  To the class library, a command is identical to its ID. A menu item, toolbar button, or dialog box control is bound to a command by giving the item the same ID.

Commands are based on the WM_COMMAND Windows message. Commands can be sent to frame windows, documents, views, the application itself, and other kinds of objects. These objects are discussed as "command targets" on the next page. For more about commands and other Windows messages, see Chapter 3 in the Class Library Reference.

•	User-interface objects (command generators) and updating

Menu items, buttons, and similar elements of the user interface can cause Windows to generate commands. The framework routes commands to the other objects in your program that carry them out. Keep in mind that these user-interface objects are not C++ objects.

You can also use commands to update the visual state of menu items and buttons — for example, enabling them if they're available to the user in a given situation and disabling them if they're unavailable. For more information, see »Updating User-Interface Objects«.

•	Command targets

Many objects in your program can receive and respond to commands. These objects are called "command targets" and are derived from class CCmdTarget. Command-target objects contain their own message maps and message-handler functions. »Figure 6.3« shows most of the hierarchy of command-target classes in the class library. For a complete list see Class Library Reference, Chapter 1.

•	Command bindings

A binding associates two things, such as a menu item and the command it invokes. Commands are assigned at one end of the command routing to the user-interface objects that generate them. This is done, for example, by equating the command's ID with the ID of a menu item. At the other end of the routing, commands are mapped to the name of a message-handler function. This is done by connecting the command ID and the name of the function.

You normally do this task with ClassWizard, which you can invoke from either App Studio or Visual Workbench. Usually, you'll bind some commands as you construct the user interface with App Studio. Later, you'll probably revisit ClassWizard as you work with code in the Visual Workbench editor.

Note  You can assign a command ID to more than one user-interface object. Scribble binds its Thick Line command to both a menu item and a toolbar button. The same message-handler function and message-map entry work for both sources of the command.

•	Message maps

How does a command target know it can handle a command? For that matter, how does any object know it can handle a message? The answer is the message map of the object's class.

Each command-target object has a message map. Message maps are tables that connect commands with the names of the member functions that handle the commands. These functions are called "message handlers." When a command target object receives a message, the object's message map is used to determine which handler function to call for the message. Message maps are used in dispatching Windows messages.

You don't typically have to write message-map entries manually — ClassWizard does the job for you. For more information, see »Message Maps«.

•	Message handlers

Command-target classes have member functions designated to handle any com-mands to which the target can respond. These functions are called "message handlers." Message handlers are explained under »Message Handlers«. In this tutorial, the terms "handler," "message handler," and "message-handler function" are equivalent.

A considerable part of writing an application is writing message-handler functions that determine how a document, view, or other class responds to a command.

•	Command routing

The class library provides a standard mechanism for routing commands from the user-interface objects that generate them to the command targets that handle them. This standard routing ensures that your objects receive the commands they need to handle. For details, see »Command Routing«. »Table 6.1« illustrates the standard command routing.


 Message Maps

Each command-target class defines a message map that contains an entry for each command or other message that the target can handle. Here's a sample from Scribble's document class, CScribDoc (this is code that ClassWizard writes, as you'll see shortly):

BEGIN_MESSAGE_MAP( CScribDoc, CDocument )

    //{{AFX_MSG_MAP(CScribDoc)

    ON_COMMAND( ID_EDIT_CLEAR_ALL, OnEditClearAll )

    ON_COMMAND( ID_PEN_THICK_OR_THIN, OnPenThickOrThin )

    // ... More entries

    //}}AFX_MSG_MAP

END_MESSAGE_MAP( )

ClassWizard places this code in file SCRIBDOC.CPP. The BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros bracket the map and provide code that takes care of creating the map at run time. Between the bracketing macros are message-map entries, one per command that the document can handle.

The BEGIN_MESSAGE_MAP macro specifies two arguments: the name of the class that the message map belongs to (CScribDoc in the example) and the name of the base class from which that class is derived (CDocument in the example).

Notice the special comment lines:

   //{{AFX_MSG_MAP(CScribDoc)

   //}}AFX_MSG_MAP

The ClassWizard tool uses these comments to locate the message map of a class for which it is binding commands. All message-map entries are written between these comment lines.

Important  Use ClassWizard to create and edit all message-map entries. If you add them manually, you may not be able to edit them with ClassWizard later. If you add them outside the bracketing comments, ClassWizard can't edit them at all. You can use this feature to add entries you don't want ClassWizard to touch.

A message-map entry looks like this:

    ON_COMMAND( ID_PEN_THICK_OR_THIN, OnPenThickOrThin )

Each entry has three parts:

•	The ON_COMMAND macro.

•	The command ID; here it would be ID_PEN_THICK_OR_THIN.

•	The name of the message-handler function for the command; here it's OnPenThickOrThin.

The result of this macro is an entry in the message map whose parts connect the command ID to the handler.

When the target object receives a command message, it checks the message map. If the command matches an entry, the message-handler function, a member function of the target class, is called for that object.

The message map has one other required element. In addition to the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros in your .CPP file, you must use the DECLARE_MESSAGE_MAP macro in your class declaration in the .H file. It's a convention of the Microsoft Foundation Class Library to put DECLARE_MESSAGE_MAP at the end of the class declaration, but it can go anywhere. The macro is not sensitive to C++ access-control keywords. Message maps are always protected; you should specify the access control for any following sections. Keep in mind that AppWizard and ClassWizard do this work for you.

When you began your Scribble development project with AppWizard, all parts of your message maps and the macros listed above had already been created for you except the entries for specific commands such as ID_EDIT_CLEAR_ALL and ID_PEN_THICK_OR_THIN. You will add those with ClassWizard.


 Command Routing

How does a command from a menu or other user-interface object find its handler function? Commands are routed through a standard sequence of command-target objects, one of which is expected to have a handler for the command.

OnCmdMsg

To accomplish this routing, each command target calls the OnCmdMsg member function of the next command target in the sequence. Command targets use OnCmdMsg to determine whether they can handle a command and, if they can't, route it to another command target.

Each command-target class overrides the OnCmdMsg member function. The overrides let each class route commands to a particular next target. A frame window, for example, always routes commands to its current child window or view. »Table 6.1« shows the standard command routing for all command targets.

The default CCmdTarget implementation of OnCmdMsg uses the message map of the command-target class to search for a handler function for each command message it receives. If it finds a match, it calls the handler. Message map searching is explained in the section »Searching Message Maps«.

Different command-target classes check their own message maps at different times. Typically, a class routes the command to certain other objects to give them first chance at the command. If none of those objects handle the command, the original class checks its own message map. Then, if it can't supply a handler itself, it may route the command to yet more command targets. Table 6.1 shows how each of the classes structures this sequence. The general order in which a command target routes a command is:

1.	To its children

2.	To itself

3.	To other command targets

How expensive is this routing mechanism? Compared to what your handler does in response to a command, the cost of the routing is low. Bear in mind that commands are generated, and thus routed, only when the user chooses a menu or a button.

Table 6.1    Standard Command Route

When an object of this type receives a command . . .	. . . it gives itself and other command-target objects a chance to handle the command in this order:
Frame window	1.  Active child window or view 2.  This frame window 3.  Application (CWinApp object)
View	1.  This view 2.  Document attached to the view
Document	1.  This document 2.  Document template attached to the document
Dialog	1.  This dialog 2.  Window that owns the dialog 3.  Application (CWinApp object)
If the command is not handled by any object along the routing, the application object passes it to Windows for default processing.

An Example

To illustrate, consider a command message from the Clear All item in Scribble's Edit menu. In Scribble, the handler function for this command happens to be a member function of class CScribDoc. Here's how that command reaches its handler after the user chooses the menu item:

1.	The main frame receives the command message first.

2.	In the case of an MDI frame window, the main frame gives the currently active MDI child window a chance to handle the command.

3.	Because of the standard routing, the frame window now gives its view a chance to handle the command before checking its own message map.

4.	Unlike the frame, the view checks its own message map first.

5.	Finding no handler, the view next routes the command to its associated document.

6.	The document checks its message map and, in this case, does find a handler, which gets called — and the routing stops.

If the document did not have a handler, it would route the command next to its document template. Then the command would return to the view and then to the frame window. Finally, the child frame would check its message map. If that check failed as well, the command would be routed back to the MDI frame and then to the application object — the ultimate destination of unhandled commands.


 Searching Message Maps

The previous section, »Command Routing« focused on commands, a particular category of Windows messages. There are two other categories of messages: standard Windows messages (with the WM_ prefix) and control-notification messages (such as BN_CLICKED, which is sent by a button).

The OnCmdMsg routing mechanism uses message maps in command-target classes to search for a handler function for each command message. Message maps are also used to locate handlers for standard Windows messages and control-notification messages, the other categories of Windows messages. In Chapter 4 in »Connecting Messages to Code«, you saw how the view's message map is used to map three mouse-related Windows messages to their handlers in the view. This section explains how message maps are searched.

Windows Messages

Standard Windows messages and control-notification messages are sent only to windows. Messages in these categories are never routed like commands from one command target to another. Standard messages are sent to frame windows, dialog boxes, views, and other kinds of windows. Control-notification messages are sent from controls (child windows) to their parent windows.

All windows have message maps. (As do all command-target objects.) Windows can handle a wider variety of messages in their message maps then other command targets such as documents, document templates, and the application object.

The Search

When a window receives an incoming Windows message (not a command), it searches its message map for a corresponding handler function. However, the phrase "searches its own message map" needs a little clarification.

It's possible to make a window an object of class CWnd directly, without deriving a new class. But in most cases the window receiving a message is an object of some class derived from CWnd. For example, Scribble's main application window class, CMainFrame, is derived from CFrameWnd, which in turn is derived from CWnd. By the nature of C++ class derivation, a CMainFrame is a CFrameWnd. It also is a CWnd. Because of this, the handler functions for some of the messages that a CMainFrame receives might actually be defined in CFrameWnd or even CWnd.

How does a CMainFrame find a message handler defined not in CMainFrame itself but in one of its base classes? The answer is that part of the definition of any message map, including CMainFrame's, is the name of the immediate base class. Recall the way you use the BEGIN_MESSAGE_MAP macro:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

The base class named in the second argument gives the receiving window a way to locate the message map of the base class. That message map, in turn, provides the name of the next-higher base class, and so on.

Thus, when it receives a standard Windows message, a CMainFrame is able to search not only the CMainFrame message map but also the message maps defined for CFrameWnd and CWnd. »Figure 6.4« illustrates the search process.

There are a few exceptions to the rule that a window handles noncommand messages itself. Control-notification messages, scrolling messages, and a few WM_ messages are actually delegated to the control that sent the message or to the view for possible handling before the parent window checks its message map(s). This is done to support self-drawing controls and scrolling views.

Command-Target Message Maps

Because command-target classes other than windows also have message maps, you might expect them to be searched in the same way. Indeed they are. The difference, of course, is that the only messages being searched for in this case are commands. When the search will take place in a given command target depends on the standard command routing and how the command target's class implements its OnCmdMsg override. But the search still encompasses not only the message map of the command-target class but also of its base class(es).

For example, in Scribble, when a CScribDoc searches its message map — at the appropriate point in the routing, as shown in »Table 6.1« — it also searches the message map of CDocument, the base class of CScribDoc, if needed.


 Message Handlers

A message handler is a member function of a command-target class. Its purpose is to respond when called through the message map.

You declare message handlers as member functions of your classes. For example, in Chapter 4 in »Scribble's View: Class CScribView« you saw three message-handler functions for mouse actions: OnLButtonDown, OnMouseMove, and OnLButtonUp. These were declared as members of class CScribView, Scribble's view class. In this chapter, you'll see handlers for several commands, including the Clear All and Thick Line commands, declared as members of CScribDoc, the document class.

Chapter 3 in the Class Library Reference explains some rules for the names and parameter signatures of message-handler functions. In this chapter you'll see how to create message handlers from ClassWizard.

For more information about commands, messages, message maps, and the command architecture in the Microsoft Foundation Class Library, see Chapter 3 in the Class Library Reference.


 Binding Scribble's Commands

This section explains the issues and procedures involved in binding Scribble's Clear All and Thick Line commands to their handlers using ClassWizard. (The Pen Widths command is bound in Chapter 7, »Adding a Dialog Box«.)


 Which Command-Target Class Gets the Handler?

Before you can bind Scribble's Clear All command to a message-handler function in the document class, there's a problem to solve. Where should you put the handler for a command? Where should you put attributes, such as a line thickness value? In the document class? In the view class? Somewhere else?

Consider the specific case of Scribble first. Scribble has one document class (some applications might have several kinds of documents — such as text documents and graphics documents) and one view class (some documents might have more than one way to view their data — for example, as text or as an outline).

Scribble's Clear All command has two effects: it deletes data in the document and it causes the view to be redrawn with no strokes. Should the handler for Clear All be located in the document or the view? Scribble's CScribDoc class houses the application's data structure, the stroke list. Clear All's primary effect is to delete the data. Redrawing the view afterwards is secondary. Hence, it makes sense to locate the OnEditClearAll handler in the document.

Scribble's Thick Line command is more interesting. This command toggles the current value of a line thickness variable between thick and thin. Should the handler for Thick Line be located in the view because it affects how Scribble's data is drawn? This seems reasonable, but consider what happens when, in a later chapter in »Adding Splitter Windows«, Scribble gets splitter window functionality. In that case, each pane of the splitter window is really a new view on the same data. Should each of these views house its own line thickness information (and its own pen)? It seems a better solution to store that information in the document instead, where all of the views can access it. Keep in mind that this is a decision specific to Scribble's user interface, where it's desirable that the pen width commands apply to all views, not just the one with the current focus. You might choose to organize things differently in another application.

Now consider a hypothetical application with more than one view on a document and perhaps even more than one frame window for the same document. Should handlers and attributes be part of the document, one of the frame windows, or one of the views? Should an attribute be duplicated in more than one view or frame window?

Here are some guidelines that may help:

•	In general, put handlers in the command-target class where they have the greatest effect.

•	When attributes are shared by multiple views or frame windows, put them in the common document.

•	If attributes are not shared, put them in the view(s) or window(s) that use them.


 Bind Scribble's Clear All Command

As discussed in the previous section, »Which Command-Target Class Gets the Handler?,« Scribble's Clear All command is bound to the document class. If you're working along, use the following procedure:

To bind Scribble's Clear All command

1.	Invoke ClassWizard (from App Studio or from Visual Workbench).

2.	Use the Class Name list box in the ClassWizard dialog box to select the CScribDoc class.

If you invoke ClassWizard from App Studio, the currently selected object, such as a menu or dialog resource, is automatically selected in ClassWizard.

Recall the decision to handle the command from the document rather than the view. That's why the handler for Clear All will be placed in CScribDoc.

After you select a class, the Object IDs list box shows all of the visual objects managed by the class — the available items that can be mapped to functions. These might include controls (for a dialog resource) and commands from menus and accelerator tables. The list may also include class names.

3.	In the Object IDs list box, select the ID_EDIT_CLEAR_ALL command.

You see COMMAND and UPDATE_COMMAND_UI in the Messages list box. For commands, these are always the choices you see. In other cases, you might see other things listed — a list of Windows messages, for example, when the selected item is the name of a window or view class.

4.	In the Messages list box, select COMMAND.

Later in the chapter in »Update Menu Items«, you'll see how UPDATE_COMMAND_UI is used.

»Figure 6.5« shows the selections from steps 2, 3, and 4.

5.	Choose the Add Function button.

This brings up a dialog box with a proposed name for the new handler function.

6.	In the Add Member Function dialog box, accept the name OnEditClearAll by choosing the OK button.

Although you could change that name, don't. The name fits the handler's functionality and its connection to the menu item very well. The proposed name is synthesized from the command name and message type.

Several things are added to your source files when you add a member function:

•	A message-map entry is added to the class's message map (in the .CPP file for the class).

•	A member function declaration is added to the class declaration (in the .H file for the class).

•	A member function template definition is added to the .CPP file.

These changes are made to your source files after you finish editing the class.

After you add the function, its name appears in the Member Functions list box beside the ID to which it maps.

7.	In the ClassWizard dialog box, select the new handler's name, OnEditClearAll, from the Member Functions list box.

8.	Choose the Edit Code button.

The Visual Workbench editor opens file SCRIBDOC.CPP with the function template for OnEditClearAll displayed. »Figure 6.6« shows the function definition template.

9.	Fill in the OnEditClearAll message-handler function.

The function looks like this (you add the lines marked with [image]):

void CScribDoc::OnEditClearAll( )

{

DeleteContents( );

SetModifiedFlag();

UpdateAllViews( NULL );

}

SetModified Flag is a member function of class CDocument. It marks the document as changed so the framework will prompt the user to save the document when it closes.

10.	In the File menu choose the Save command to save changes to the SCRIBDOC.CPP file.

This is the only file you changed by adding the new member function.

How do the commands work? The new message handler first calls DeleteContents to destroy the document's stroke data. (This version of DeleteContents, from Chapter 4, overrides CDocument's DeleteContents member function. See »To implement document cleanup.«) Then OnEditClearAll calls the UpdateAllViews member function inherited from CDocument to cause all views of the data to be updated. The document's view is redrawn, this time with no data. UpdateAllViews takes a NULL argument because the document is modifying itself. The parameter is normally used to pass a pointer to the view that modified the document, but that doesn't apply here.

When you finish adding OnEditClearAll, you're still in the Visual Workbench editor. To continue binding commands, invoke ClassWizard again from Visual Workbench's Browse menu.


 Bind Scribble's Thick Line Command

Like the Clear All command, the Thick Line command will be handled by the document. Recall the discussion under »Which Command-Target Class Gets the Handler?«.

To bind Scribble's Thick Line command

1.	If you're not in ClassWizard, invoke it from Visual Workbench's Browse menu.

2.	Select the CScribDoc class.

3.	In the Object IDs list box, select the ID_PEN_THICK_OR_THIN command.

4.	In the Messages list box, select COMMAND.

5.	Choose the Add Function button.

6.	In the Add Member Function dialog box, accept the name OnPenThickOrThin by choosing the OK button.

7.	In the ClassWizard dialog box, choose the Edit Code button.

If Visual Workbench is not running, you get a warning. Start Visual Workbench from the Windows Program Manager.

8.	Fill in the OnPenThickOrThin message-handler function.

The function looks like this (you add the lines marked with [image]):

void CScribDoc::OnPenThickOrThin( )

{

// Toggle the state of the pen between thin and thick.

m_bThickPen = !m_bThickPen;

// Change the current pen to reflect the new width.

ReplacePen( );

}

The OnPenThickOrThin message handler first toggles the state of a Boolean variable, m_bThickPen. If the variable is now TRUE, the pen will be thick. Otherwise, it will be thin. Then the handler calls a helper function, ReplacePen, to reset the current pen to the new width.

9.	Next, use the Visual Workbench editor to add ReplacePen to file SCRIBDOC.CPP (ReplacePen is not a message handler, so you don't add it with ClassWizard). Here it is:

// OnPenThickOrThin, then ...

void CScribDoc::ReplacePen( )

{

m_nPenWidth = m_bThickPen ? m_nThickWidth : m_nThinWidth;

// Change the current pen to reflect the new width.

m_penCur.DeleteObject( );

m_penCur.CreatePen( PS_SOLID, m_nPenWidth, RGB(0,0,0) );

}

The ReplacePen member function uses the C++ conditional operator (?:) to determine the pen width and return its value. Then it calls the DeleteObject member function of the current pen object and creates a new solid black pen with CreatePen, setting its attributes, including its width.

10.	Besides adding the ReplacePen function definition to SCRIBDOC.CPP, you must also add a function prototype to the CScribDoc class declaration in file SCRIBDOC.H. If you're working along, you can open that file with Visual Workbench, locate the class declaration as partially shown immediately following, and add the marked line:

class CScribDoc : public CDocument

{

protected: // Create from serialization only.

...

// Attributes

...

// Operations

public:

void DeleteContents( );

...

// Implementation

protected:

void ReplacePen( );

...

};

11.	To add this improved way of updating the pen, locate the InitDocument member function in SCRIBDOC.CPP and change the function to match this code:

void CScribDoc::InitDocument()

{

ReplacePen();   // Initialize pen according to current width

}

To match the function as shown, besides adding the marked line you must delete the following lines (added in »Chapter 4«):

   m_nPenWidth = 2; // Default 2 pixel pen width

   // Solid, black pen

   m_penCur.CreatePen( PS_SOLID, m_nPenWidth, RGB( 0,0,0 ) );

The line you added calls ReplacePen to set up the pen with its new width.

12.	Choose the Save All command on Visual Workbench's File menu to save changes to both the SCRIBDOC.H and SCRIBDOC.CPP files.


 Bind the Toolbar Button to the Thick Line Command

Scribble's Thick Line command is now bound to the Thick Line toolbar button as well as to the Thick Line menu item. Either user-interface object generates precisely the same command. This duplication is accomplished simply by giving the menu item, as described in »Bind Scribble's Thick Line Command,« and the button (as in Chapter 5 in »Add the Thick Line Button to Scribble's Toolbar Bitmap«) the same ID as the command: ID_PEN_THICK_OR_THIN.


 Add New Member Variables to Scribble

In addition to storing the current pen width in m_nPenWidth, class CScribDoc needs to keep track of whether the pen is currently thick or thin and how "thick" and "thin" are defined (in pixels). In Chapter 7 in »Connecting a Class to a Dialog Box«, you will add code to allow the user to define these values with a dialog box. For now, defaults are hard coded.

To add the new data members, use the Visual Workbench editor, as shown in »Figure 6.7«

1.	Open the file SCRIBDOC.H.

2.	Find the class declaration for class CScribDoc.

It begins:

class CScribDoc : public CDocument

{ ...

Locate the section labeled "// Attributes:".

3.	Add the following marked lines after the protected keyword and the existing m_strokeList and m_nPenWidth declarations:

// Attributes:

public:

protected:

CObList    m_strokeList;   // Each member of list is a stroke

// ... comments ...

UINT    m_nPenWidth;	// Current user-selected pen width

BOOL    m_bThickPen;	// Thick currently selected or not

UINT    m_nThinWidth;	// Current definition of thin

UINT    m_nThickWidth;	// Current definition of thick

CPen    m_penCur;	// Pen created according to

// user-selected pen style (width)

// Additional code ...

4.	Add the following lines to InitDocument in SCRIBDOC.CPP:

void CScribDoc::InitDocument()

{

m_bThickPen = FALSE;

m_nThinWidth = 2;     // Default thin pen is 2 pixels wide

m_nThickWidth = 5;    // Default thick pen is 5 pixels wide

ReplacePen();   // Initialize pen according to current width

}

The added lines specify that the pen is initially thin and define the meanings of "thin" and "thick."

5.	Save files SCRIBDOC.H and SCRIBDOC.CPP.


 Library Support for Writing Message Handlers

To implement your handlers, call upon the many services and classes provided by the Microsoft Foundation Class Library.

The classes, supplemented by standard C run-time functions and Windows Application Programming Interface (API) functions that aren't encapsulated by the library, let you use object-oriented programming methods in your message handlers and customize the functionality to suit your needs. For more information about these classes, see Chapters 1 through 6 in the Class Library Reference. The general-purpose (non-Windows) classes are also covered in more detail in the later chapters of this guide, beginning with Chapter 11, »General Purpose Classes«.


 Updating User-Interface Objects

When a menu drops down in your application, the user expects to see some menu items enabled (available) and others dimmed (grayed to show they're unavailable) depending on the current context. Some menu items may have a check mark. Similarly, the user expects to see some toolbar buttons enabled and others disabled and perhaps checked (depressed). The framework provides a direct, command-based way to set the state of the menus and toolbar buttons as conditions in the program change.


 Update a Command's User Interface

To update a menu in traditional programming for Windows, you get a handle to the menu and call the Windows EnableMenuItem function. Under the Microsoft Foundation Class Library, however, you can use messages to let the most appropriate command-target object update the menu status automatically. This delegates the task of enabling and disabling menu items and buttons to the object that possesses the most contextual information relating to the menu or button.

The idea is to search the default command routing for objects that can enable or disable menu items before the user actually sees the menu. (Updating for buttons will be explained shortly in »Update Toolbar Buttons.«)

The command-routing mechanism is fast and costs you very little as long as the update handlers you write don't do a lot of calculation.


 Update Menu Items

When the user clicks the mouse in the menu bar, the framework — before showing the menu items — sends out command update messages to the command targets. A message is sent for each item on the menu. The important thing to realize is that all items on the menu are updated before the menu drops down and the user sees it.

»Figure 6.2« shows how menu items are updated and menu commands are carried out.

Messages to update user-interface objects are routed and handled like commands. The framework searches the standard command routing as if the command was actually being executed. If it finds a message-map entry for the initialization message, it passes a pointer to a CCmdUI object representing the menu item — or other user-interface object — to the command target. The target should use this pointer in its command user-interface handler to update the menu.

The items on a particular menu might be handled by one or several command-target objects. If you've mapped the items to handlers, the handlers will be found along the routing and called to update the items' state. Items with no handlers are not updated.

To have your application handle user-interface initialization messages, your command-target objects — application, windows, views, documents — in general must do two things:

1.	Use ClassWizard to include an ON_UPDATE_COMMAND_UI entry in their message maps with arguments for the command ID and the name of the message-handler function.

Usually you'll pair this message-map entry with one for carrying out the command. For example, Scribble's document includes message-map entries for

ON_UPDATE_COMMAND_UI( ID_PEN_THICK_OR_THIN, OnUpdatePenThickOrThin )

ON_COMMAND( ID_PEN_THICK_OR_THIN, OnPenThickOrThin )

and

ON_UPDATE_COMMAND_UI( ID_EDIT_CLEAR_ALL, OnUpdateEditClearAll )

ON_COMMAND( ID_EDIT_CLEAR_ALL, OnEditClearAll )

The way ON_UPDATE_COMMAND_UI is handled is almost identical for the Clear All and Thick Line commands except that for Clear All the menu item is enabled or disabled, while for Thick Line the menu item is checked or unchecked.

2.	Provide a message-handler function that does the menu updating.

The OnUpdatePenThickOrThin handler uses its pointer to a CCmdUI object to call an Enable member function. An object of class CCmdUI is associated with each menu item (and toolbar button). This object provides an interface through which to update the menu or button. The framework passes your update-handler function a pointer to the object.

Table 6.2 summarizes the command and message-handler naming conventions used in the source-code files of the class library and sample applications, including the conventions for user-interface updating.

Table 6.2    Command and Message-Handler Naming Conventions

Item	Convention	Example
Command ID	ID_XXX	ID_EDIT_CLEAR_ALL
Message handler	OnXxx	OnEditClearAll
Command UI handler	OnUpdateXxx	OnUpdateEditClearAll


 Update Toolbar Buttons

Like menus, toolbar buttons show their availability or status (some controls have more than two possible states) with some kind of visual feedback. You can use almost the same update mechanism to update these user-interface objects.

Menu initialization is automatic in the framework, occurring when the application receives a WM_INITMENUPOPUP message. For buttons, searching the command routing is done in the idle loop. When there are no pending messages in its message queue, a window enters an idle loop. During the idle loop, the command routing is searched for buttons in much the same way as for menus. (You can also do other useful processing in the idle loop. See "Idle Loop Processing" in Chapter 2 in the Class Library Reference and the OnIdle member function of class CWinApp.)


 The CCmdUI Structure

The CCmdUI structure defined by the class library supplies a common interface to both menus and controls. That is, for either kind of user-interface object, you can call the same member functions of CCmdUI to update the object.

This common program interface is one major advantage of initializing your user-interface objects with ON_UPDATE_COMMAND_UI. You can, for example, readily replace or duplicate a menu command with a command generated by a toolbar button. The same message-map entry and handler function in the command target will work.

Another major advantage of initializing user-interface objects using CCmdUI is that much of the process is automated and all commands are handled in a uniform way. The same object handles both the command and updating of the user-interface object.

Note  For advanced programmers: CCmdUI also works for indicators in status bars and normal buttons in dialog bars.


 Update Scribble's Clear All Menu Item

This section presents the steps you will take to prepare the code required to update the Clear All menu item on Scribble's Edit menu. This command is handled by the document object, which has the necessary information on whether there are any strokes in the current drawing to clear. If you're working along, the following procedure guides you through the process.

To add an update handler for Scribble's Clear All menu

1.	Invoke ClassWizard.

2.	Select class CScribDoc.

3.	In the Object IDs list box, select the ID_EDIT_CLEAR_ALL command.

4.	In the Messages list box, select UPDATE_COMMAND_UI.

»Figure 6.8« shows the selections made in steps 2, 3, and 4:

5.	Choose the Add Function button.

6.	In the Add Member Function dialog box, accept the name OnUpdateEditClearAll by choosing the OK button.

7.	In the ClassWizard dialog box, choose the Edit Code button.

8.	Fill in the OnUpdateEditClearAll update handler function when the Visual Workbench editor opens.

The function looks like this (you add the marked lines):

void CScribDoc::OnUpdateEditClearAll( CCmdUI* pCmdUI )

{

// Enable the user-interface object (menu item or tool-

// bar button) if the document is non-empty, i.e., has

// at least one stroke.

pCmdUI->Enable( !m_strokeList.IsEmpty( ) );

}

9.	Save changes to file SCRIBDOC.CPP.

Notice that the OnUpdateEditClearAll handler takes one argument, a pointer to a CCmdUI object that contains information about the Clear All menu item on the Edit menu.

The pointer to a CCmdUI object, pCmdUI, is used to access a CCmdUI member function, Enable. Enable takes one Boolean argument. In this code, the expression !m_strokeList.IsEmpty( ) evaluates to zero if the document has at least one stroke to clear. If the expression evaluates to nonzero (no strokes), the menu item is disabled (and dimmed or grayed).

Note  When the user pulls down a menu, the update handlers for all items on the menu are called before the user sees the menu displayed. It's important, then, to make your update handlers fast.

When you add an update command for the ClearAll menu item, ClassWizard also writes a message-map entry in the document's message map in file SCRIBDOC.CPP that looks like this:

BEGIN_MESSAGE_MAP( CScribDoc, CDocument )

   ON_UPDATE_COMMAND_UI( ID_EDIT_CLEAR_ALL, OnUpdateEditClearAll )

   // Other message-map entries

END_MESSAGE_MAP( )

The ON_UPDATE_COMMAND_UI macro resembles the ON_COMMAND macro that you saw earlier for the OnEditClearAll message handler.

In addition, ClassWizard adds a new member function declaration for OnUpdateEditClearAll to the CScribDoc class declaration in file SCRIBDOC.H. The function declaration looks like this:

afx_msg void OnUpdateEditClearAll( CCmdUI* pCmdUI );


 Update Scribble's Thick Line Menu Item

Updating the Thick Line menu is very similar to updating the Clear All menu. In this case, however, rather than enabling or disabling the menu item, the handler puts a check mark beside the item or removes an existing check mark. If you're working along, do the following procedure.

To add an update handler for the Thick Line menu

1.	Invoke ClassWizard.

2.	Select class CScribDoc.

3.	In the Object IDs list box, select the ID_PEN_THICK_OR_THIN command.

4.	In the Messages list box, select UPDATE_COMMAND_UI.

5.	Choose the Add Function button.

6.	In the Add Member Function dialog box, accept the name OnUpdatePenThickOrThin by choosing the OK button.

7.	In the ClassWizard dialog box, choose the Edit Code button.

8.	Fill in the OnUpdatePenThickOrThin update handler function when the Visual Workbench editor opens.

The function looks like this (you add the marked lines):

void CScribDoc::OnUpdatePenThickOrThin( CCmdUI* pCmdUI )

{

// Add check mark to Pen Thick Line menu item if the current

// pen width is "thick."

pCmdUI->SetCheck( m_bThickPen );

}

9.	Save changes to file SCRIBDOC.CPP.

Rather than enabling or disabling the menu command, this handler uses the pointer to a CCmdUI object to call the SetCheck member function. SetCheck puts a check mark in front of the menu item's text, "Thick Line," if its argument evaluates to TRUE, or unchecks the menu item if FALSE. In this case, the expression m_bThickPen is a member variable of CScribDoc. It evaluates TRUE if the line thickness is currently set to thick. Since the value of m_bThickPen is passed to SetCheck, the effect is to toggle the menu item's check mark on or off as the line thickness changes.

The ON_UPDATE_COMMAND_UI message-map entry and the OnUpdatePenThickOrThin message handler serve to update the state of the Thick Line button on the toolbar as well as the Thick Line menu item. The code line

pCmdUI->SetCheck( m_bThickPen );

adjusts the state of the toolbar button as well as updating the checked state of the menu item. For a toolbar button, "checked" means depressed.

In this example, the user would previously have reset the line thickness. The next time the user chooses the Pen menu (or the toolbar button), the user-interface update mechanism takes care of updating the check mark to match the current thickness. Similarly, the toolbar button's state toggles between a "pressed down" appearance and a normal appearance.

As with the update handler for Clear All, ClassWizard adds a message-map entry for OnUpdatePenThickOrThin to the document's message map in file SCRIBDOC.CPP:

BEGIN_MESSAGE_MAP( CScribDoc, CDocument )

 ON_UPDATE_COMMAND_UI(ID_PEN_THICK_OR_THIN,OnUpdatePenThickOrThin)

 // Other message-map entries

END_MESSAGE_MAP( )

ClassWizard also adds a member function declaration to the document class declaration in file SCRIBDOC.H:

afx_msg void OnUpdatePenThickOrThin( CCmdUI* pCmdUI );


Compile Scribble  Step 2 Version
 Compile Scribble − Step 2 Version

How does Scribble behave with these new commands in place? Compile the new step-2 version of Scribble and find out.

Run the new version of Scribble from the Project menu.

Draw some strokes with the default thin pen. Then change the line thickness with the Thick Line command on the Pen menu and draw some new strokes. Clear all strokes from the drawing with the Clear All command on the Edit menu. »Figure 6.9« shows this version of Scribble.

Exit Scribble.

This completes step 2 in the tutorial. You now have a basic understanding of commands. In later chapters you'll build on that foundation.

In Chapter 7, »Adding a Dialog Box,« you'll implement a command that invokes a dialog box and then processes the results in its message handler.


 Chapter 7  Adding a Dialog Box

»Chapter 5« and »Chapter 6« added new commands to Scribble in two steps: first, by using App Studio to add new menu items; and second, by using ClassWizard to define message handlers and bind them to the commands. Recall that in Chapter 5, you added menu items for three new commands: Edit Clear All, Thick Pen, and Pen Widths. In contrast, Chapter 6 discussed binding only the first two of these commands.

The reason for this omission is that the Pen Widths command is somewhat different from the other two commands. Both the Edit Clear All and Thick Pen commands execute to completion as soon as the user selects them. By contrast, the Pen Widths command requires more information from the user. The command invokes a dialog box, one that lets the user specify exactly how thin the Thin Pen should be and how thick the Thick Pen should be for subsequent drawing. Before you can write a message handler for this command, you have to design the dialog box that it invokes and define a new class to manage the dialog box. That's what you'll do in this chapter.

This chapter develops a modal dialog box using the same general procedure that »Chapter 5« and »Chapter 6«used for adding menu commands: first using App Studio to design the dialog box's appearance, and then using ClassWizard to define message handlers and bind them to the dialog box. Along the way, you'll see a feature of ClassWizard that greatly simplifies the process of gathering data from a dialog box and checking the data's validity.

This chapter describes the following topics:

•	»Designing a dialog box« using App Studio.

•	Using ClassWizard to »connect a class to a dialog box.«

•	»Invoking a dialog box« from your application.

This chapter covers step 3 of Scribble. If you want to work along, adding the code as you go, begin with the files from Chapter 6 in your SCRIBBLE\MYSCRIB subdirectory. At this point, these files should closely resemble those in the SCRIBBLE\STEP2 subdirectory. As you read the chapter, perform all ClassWizard steps and add all the code that's marked with the symbol [image]. At the end, your files should closely resemble the files in the SCRIBBLE\STEP3 subdirectory.

If, on the other hand, you want to read along without adding code, you can print or view the files in the SCRIBBLE\STEP3 subdirectory.


 Designing a Dialog Box

»Figure 7.1« shows the Pen Widths dialog box that you will create.

The Pen Width dialog box will have the following behavior: for either the Thin or Thick Pen width, the user can enter any number between 1 and 20. If the user enters a value outside of this range, Scribble displays a message box stating the legal range; after dismissing the message box, the user can enter new values. To reset the pen widths to their default values, the user chooses the Default button. To use the currently displayed widths for any subsequent drawing, the user chooses the OK button. To cancel the operation, the user chooses the Cancel button.


 Adding the Controls

App Studio provides a graphical editor for designing the appearance of a dialog box. This editor displays a palette of available controls (such as radio buttons, check boxes, and pushbuttons) and an empty dialog box, which is the starting point for the dialog box you're designing. You select controls from the palette and position them on your dialog box. You can move the controls around or resize them directly using the mouse.

There are two steps in designing a dialog box: the first is adding the controls you want, and the second is editing the captions, IDs, and other properties for the controls.

To add controls to the Pen Widths dialog box

1.	With your Scribble project open in Visual Workbench, choose the Open command from the File menu and load the resource file SCRIBBLE.RC. This launches App Studio, and a resource browser window appears.

2.	Choose the New button to create a new resource.

3.	Select Dialog from the list of resource types and choose OK. A dialog editor window appears displaying a dialog box that contains two buttons labeled OK and Cancel. The palette of the available controls appears nearby.

4.	Add two edit controls. You can add and reposition controls using the »drag and drop« method.

5.	Add two static text controls to contain the descriptions for the two edit controls. Again, you can use the drag and drop method.

6.	Add a third pushbutton to the ones already present.


 Modifying the Controls' Properties

To customize the captions and IDs for the controls you've added, you must open the App Studio property page for each control. In the topic »Examining and Editing Resources«, you saw that menus and individual menu items have property pages; in the same way, dialog boxes and dialog controls have property pages describing their attributes.

To edit the captions and IDs for the controls in the Pen Widths dialog box

1.	If the property page is not currently displayed, double-click the dialog box itself and then click the push-pin button on the property page to keep it open. If the property page is already displayed, click the dialog box to display its properties. Change its ID to IDD_PEN_WIDTHS and change its caption to "Pen Widths."

2.	Click the first edit box to display its property page. Change its ID to IDC_THIN_PEN_WIDTH. Then click the second edit box to display its property page. Change its ID to IDC_THICK_PEN_WIDTH.

3.	Click the first text box to display its property page. Change the caption of the text box to read "Thin Pen Width:". Then bring up the property page for the other text box, and change its caption to read "Thick Pen Width:". Resize each text box so that the entire caption is visible; you can do this by dragging on the sizing handles on the sides of the text box.

You won't have to refer to the IDs of the text boxes, so you can leave them with their default values (both have the value IDC_STATIC).

4.	Click the pushbutton you added to display its property page. Change its caption to "Default" and its ID to IDC_DEFAULT_PEN_WIDTHS.

Note that App Studio has predefined the OK and Cancel buttons. If you want to look at the property pages for these buttons, click on them in turn. They have IDOK and IDCANCEL, respectively, as their IDs. Notice that the OK button has the Default Button check box chosen; this makes the OK button the default if the user immediately presses the ENTER key.  »Figure 7.2« illustrates using App Studio to design the Pen Widths dialog box. In this illustration the central window is the dialog editor window. Below the dialog editor is the property page and the control palette is to the right.

You can clean up the dialog box's appearance by selecting one or more of the controls and using the commands on the Layout menu to align them, make them the same size, etc. If you want to see what the dialog box will look like when it's actually invoked, choose the Test command from the Resource menu. This displays the dialog box as it will appear in Scribble. Exit Test mode by choosing either the OK or Cancel button on the dialog box or by pressing the ESC key.

When you're satisfied with the way your dialog box looks, choose the File Save command. App Studio saves the template for your dialog box in the .RC file that you're working in, SCRIBBLE.RC in this case.

For more information about editing dialog boxes with App Studio, see Chapter 3 of the App Studio User's Guide.


 Connecting a Class to a Dialog Box

Once you've specified the appearance of your dialog box, you must specify its behavior. This requires deriving a class from CDialog that implements your dialog box and connecting the class to the resource you created in the previous section.

In general, to connect a class to a dialog box:

1.	Declare a class to represent the dialog box.

2.	Declare handler functions for the messages you want to handle.

3.	Map the controls to member variables of the dialog class and define what (if any) validation rules should be applied to each.

You could do all of this manually, but ClassWizard provides a graphical user interface that lets you do it quickly and easily. It generates a header and an implementation file for your dialog class complete with function prototypes, skeletal function definitions, a message map, and a data map.

The following sections show how these steps are accomplished for Scribble's Pen Widths dialog box.


 Declaring the Class

As you saw in Chapter 6 in »Using ClassWizard to Bind Commands«, ClassWizard lets you connect a graphical object (such as a menu command or a toolbar button) to a class. The commands described in that chapter are handled by the CScribDoc class, the document class generated by AppWizard.

AppWizard doesn't provide any classes for dialog boxes, so you must declare a new class to control the Pen Widths dialog box.

To declare a new dialog class

1.	At this point, the App Studio dialog editor window is still open, displaying the Pen Width dialog box. Pull down the Resource menu and select the ClassWizard command. The Add Class dialog box appears. ClassWizard knows that a class hasn't been defined yet, so it displays this dialog box to allow you to define one, as shown in »Figure 7.3.«

2.	For the class name, enter "CPenWidthsDlg." Notice that the class type is already set to "CDialog," which is the type ClassWizard assumes because you were using the dialog editor.

3.	For the header file, ClassWizard offers the candidate name "penwidth.h"; it has created this name based on the class name. Change the name to "pendlg.h."

4.	For the implementation file, change the name to "pendlg.cpp."

5.	Choose the Create Class button. The ClassWizard dialog box regains the focus, now displaying the name "CPenWidthsDlg" and the IDs for the controls in the Pen Widths dialog box, as shown in »Figure 7.4«.

In the previous chapters, you've been adding code to the SCRIBDOC.H/CPP and SCRIBVW.H/CPP files exclusively, which were created initially by AppWizard. In this chapter you will work with two new files: PENDLG.H and PENDLG.CPP, which you specified in the Add Class dialog box. ClassWizard automatically adds these files to the project.

Here's the initial version of PENDLG.H that ClassWizard generates once you've completed the Add Class dialog box:

class CPenWidthsDlg : public CDialog

{

// Construction

public:

CPenWidthsDlg(CWnd* pParent = NULL); 	// standard constructor

// Dialog Data

//{{AFX_DATA{CPenWidthsDlg)

enum { IDD = IDD_PEN_WIDTHS };

// NOTE: the ClassWizard will add data members here

//}}AFX_DATA

// Implementation

protected:

virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

// Generated message map functions

//{{AFX_MSG(CPenWidthsDlg)

// Note: the ClassWizard will add member functions here

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

This file contains a declaration for CPenWidthsDlg, the class that implements the Pen Widths dialog box. At this point, the class contains two member functions: a constructor and the DoDataExchange function, which is described later on.

As described in Chapter 6 in »Message Maps«, the file contains comment lines that begin //{{AFX_ and //}}AFX_. Recall that ClassWizard uses those comment lines to find the sections of code that it maintains. There are two such sections in the header file, each delimited by slightly different comments: the AFX_DATA section, containing the declarations of the dialog data members; and the AFX_MSG section, containing the declarations of the message handlers. In general, you shouldn't manually edit any declarations that appear in these sections.

Here's the initial version of PENDLG.CPP that ClassWizard generates once you've completed the Add Class dialog box:

#include "stdafx.h"

#include "scribble.h"

#include "pendlg.h"

#ifdef _DEBUG

#undef THIS_FILE

static char BASED_CODE THIS_FILE[] = __FILE__;

#endif

////////////////////////////////////////////////////////////////////

// CPenWidthsDlg dialog

CPenWidthsDlg::CPenWidthsDlg(CWnd* pParent /*=NULL*/ )

: CDialog(CPenWidthsDlg::IDD, pParent)

{

//{{AFX_DATA_INIT(CPenWidthsDlg)

// Note: the ClassWizard will add member initialization here

//}}AFX_DATA_INIT

}

void CPenWidthsDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CPenWidthsDlg)

// Note: the ClassWizard will add DDX and DDV calls here

//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CPenWidthsDlg, CDialog)

//{{AFX_MSG_MAP(CPenWidthsDlg)

// Note: the ClassWizard will add message map macros here

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

////////////////////////////////////////////////////////////////////

// CPenWidthsDlg message handlers

This file contains an empty message map and empty function definitions for the constructor and the DoDataExchange member function. The DoDataExchange function will be described later in this chapter in »Mapping the Controls to Member Variables«.

Notice that the constructor has a base initializer for CDialog. The CDialog constructor that it invokes creates a modal dialog box, and it takes two parameters: the ID of the dialog resource and a pointer to the parent window. For the first parameter ClassWizard has specified CPenWidthsDlg::IDD. This is an enumerated value that is defined in the AFX_DATA section in the class declaration. This enumerated value is equal to IDD_PEN_WIDTHS, the ID you specified in the section »Modifying the Controls' Properties«. Thus the dialog class is associated with the dialog resource you created.

Also notice that the implementation file, like the header file, contains sections delimited by //{{ and //}}, in which ClassWizard will insert code later.


 Declaring the Message-Handling Functions

The CDialog class defines default handlers for the OK and Cancel buttons. The Pen Widths dialog box contains a third pushbutton, the Default button. For CPenWidthsDlg to respond when the user chooses this button, you must define a new message handler and bind it to the Default pushbutton.

Binding a message handler to a control in a dialog box is essentially the same as binding a message handler to a menu command, which was described in Chapter 6 in »Using ClassWizard to Bind Commands«; both are accomplished by adding an entry to a class's message map using ClassWizard.

After completing the Add Class dialog box in the previous section, the ClassWizard dialog box is active. This is the same dialog box that was described in Chapter 6 in »What ClassWizard Can Do«, but notice the following differences:

•	The dialog class, not the document or view class, is the one that will handle the message. Consequently, the Class Name box displays "CPenWidthsDlg."

•	The Object IDs list box displays the IDs of all the controls in the dialog box, not the commands in a menu.

•	The message being handled is a Windows control notification message, not an application-specific command. As a result, the Message box displays more than just COMMAND and UPDATE_COMMAND_UI; it displays all the messages that can be sent by the object that's highlighted in the Object IDs box. For example, if IDC_THIN_PEN_WIDTH  —  which is the ID of the first edit box  —  is highlighted in the Object IDs box, the Message box displays all the control notification messages that an edit box can generate, such as EN_SETFOCUS, EN_KILLFOCUS, and EN_UPDATE.

Despite these differences, the procedure for adding a message handler is the same.

To add a message handler for the Default button

1.	In the Object IDs list box, highlight IDC_DEFAULT_PEN_WIDTHS ( as illustrated in »Figure 7.4.« Recall that this is the ID of the Default button. Notice that the Message list box shows all the notification messages that a pushbutton can send, that is, BN_CLICKED and BN_DOUBLECLICKED.

2.	In the Messages list box, highlight the BN_CLICKED message. Notice the description in the Description section of the dialog box: "Indicates the user clicked a button".

3.	Choose the Add Function button. The Add Member Function dialog box appears, displaying the candidate name, "OnClickedDefaultPenWidths." ClassWizard has synthesized this name based on the object's ID and the message name.

4.	Change the name to "OnDefaultPenWidths" and then choose the OK button. The name "OnDefaultPenWidths" appears in the Member Function list box and a hand-shaped icon appears next to the entry for BN_CLICKED in the Message box.

At this point, you could choose the Edit Code button to fill in the definition of the OnDefaultPenWidths message handler, the way you did with the message handlers for menu commands in Chapter 6 in »Adding Handlers for Commands«. However, the purpose of this function is to manipulate member variables of the dialog class. Right now the  CPenWidthsDlg class doesn't have any member variables defined; those members will be defined in the next section in »Mapping the Controls to Member Variables«. You will implement OnDefaultPenWidths later in the chapter in »Implementing the Message Handler«, after you've added the member variables.

Here are the changes that ClassWizard makes to PENDLG.H after you've defined the message handler (these changes are saved to the file when you close the ClassWizard dialog box):

class CPenWidthsDlg : public CDialog

{

// Construction

public:

CPenWidthsDlg(CWnd* pParent = NULL);

// Dialog Data

//{{AFX_DATA{CPenWidthsDlg)

enum { IDD = IDD_PEN_WIDTHS };

// Note: the ClassWizard will add data members here

//}}AFX_DATA

// Implementation

protected:

virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

// Generated message map functions

//{{AFX_MSG(CPenWidthsDlg)

afx_msg void OnDefaultPenWidths();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

Notice that ClassWizard has inserted a prototype for a member function named OnDefaultPenWidths.

ClassWizard makes the following changes to PENDLG.CPP after you've defined the message handler (these changes are saved to the file when you close the ClassWizard dialog box):

#include "stdafx.h"

#include "scribble.h"

#include "pendlg.h"

// ...

BEGIN_MESSAGE_MAP(CPenWidthsDlg, CDialog)

    //{{AFX_MSG_MAP(CPenWidthsDlg)

ON_BN_CLICKED(IDC_DEFAULT_PEN_WIDTHS, OnDefaultPenWidths)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

////////////////////////////////////////////////////////////////////

// CPenWidthsDlg message handlers

void CPenWidthsDlg::OnDefaultPenWidths()

{

// TODO: Add your control notification handler code here

}

Notice that ClassWizard has inserted an entry in the message map indicating that the member function OnDefaultPenWidths is a message handler that is invoked whenever the control IDC_DEFAULT_PEN_WIDTHS sends a BN_CLICKED message. ClassWizard has also generated an empty function definition for the message handler. You'll fill in the implementation for the function later in the chapter in »Implementing the Message Handler«.


 Mapping the Controls to Member Variables

Scribble must be able to retrieve the values that the user enters in the Thin Pen and Thick Pen edit boxes. The Microsoft Foundation Class Library defines a mechanism that automates the process of gathering values from a dialog box; this mechanism is called a "data map." In the same way that a message map binds a user-interface element with a member function, a data map binds a dialog-box control with a member variable. The value of the member variable reflects the status or the contents of the control. By adding entries to CPenWidthsDlg's data map, you can retrieve the values entered in the Thin Pen and Thick Pen edit boxes.

For Scribble, the widths of the thin and thick pens must be between 1 and 20. You can enforce these conditions by using the automated data validation that data maps provide. If the user enters values that fall outside this range, the application displays a message box stating the legal range and allows the user to enter new values.

At this point, the ClassWizard dialog box is still on the screen. Choose the Edit Variables button. The Edit Member Variables dialog box appears, as shown in »Figure 7.5.« This dialog box contains a list box displaying the mapping between controls and member variables. At the moment the box displays only the IDs for the controls, because you haven't yet specified which member variables the controls correspond to.

To map the controls of the Pen Widths dialog box to member variables

1.	Select IDC_THIN_PEN_WIDTH and then choose the Add Variable button. The Add Member Variable dialog box appears.

2.	In the Member name edit box, enter "m_nThinWidth."

3.	In the Variable Type list box, choose "int."

4.	Choose OK to add the member variable to the class. Notice that the member name and type you specified now appear in the Control list box and two new edit boxes appear to receive the validation parameters appropriate for an integer.

5.	In the Minimum and Maximum edit boxes, enter "1" and "20" respectively.

6.	Repeat steps 1 through 5 for the control IDC_THICK_PEN_WIDTH. Enter "m_nThickWidth" for the member name, choose "int," and enter lower and upper limits of 1 and 20.

7.	Choose the Close button to exit the Edit Member Variable dialog box.

You've now completed the data map connecting the Pen Widths dialog box to the PenWidthsDlg class.

ClassWizard makes the following changes to PENDLG.H after you've mapped the controls to member variables (these changes are saved to the file after you close the ClassWizard dialog box):

class CPenWidthsDlg : public CDialog

{

// Construction

public:

CPenWidthsDlg(CWnd* pParent = NULL);

// Dialog Data

//{{AFX_DATA{CPenWidthsDlg)

enum { IDD = IDD_PEN_WIDTHS };

int	 m_nThinWidth;

int	 m_nThickWidth;

//}}AFX_DATA

// Implementation

protected:

virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

// Generated message map functions

//{{AFX_MSG(CPenWidthsDlg)

afx_msg void OnDefaultPenWidths();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

Notice that ClassWizard has inserted declarations of member variables in the data map. These are the member variables you specified in the Add Member Variable dialog box.

ClassWizard makes the following changes to PENDLG.CPP after you've mapped the controls to member variables (these changes are saved to the file when you close the ClassWizard dialog box):

#include "stdafx.h"

#include "scribble.h"

#include "pendlg.h"

////////////////////////////////////////////////////////////////////

// CPenWidthsDlg Dialog

// ...

CPenWidthsDlg::CPenWidthsDlg(CWnd* pParent /*=NULL*/)

: CDialog(CPenWidthsDlg::IDD, pParent)

{

//{{AFX_DATA_INIT(CPenWidthsDlg)

m_nThinWidth = 0;

m_ThickWidth = 0;

//}}AFX_DATA_INIT

}

void CPenWidthsDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CPenWidthsDlg)

DDX_Text(pDX, IDC_THIN_PEN_WIDTH, m_nThinWidth);

DDV_MinMaxInt(pDX, m_nThinWidth, 1, 20);

DDX_Text(pDX, IDC_THICK_PEN_WIDTH, m_nThickWidth);

DDV_MinMaxInt(pDX, m_nThickWidth, 1, 20);

//}}AFX_DATA_MAP

}

// ...

Notice that ClassWizard has initialized the member variables in the constructor and provided an implementation for the DoDataExchange function. The framework calls DoDataExchange whenever values have to be moved between the member variables in the class and the controls in the dialog box on screen (for example, when first displaying the dialog box on the screen or when the user closes the dialog box by choosing OK).

The DoDataExchange function is implemented using DDX and DDV function calls. A DDX (for Dialog Data eXchange) function specifies which control in the dialog box corresponds to a particular member variable and transfers the data between the two. A DDV (for Dialog Data Validation) function specifies the validation parameters for a particular member variable, ensuring that its value is legal. The DDX and DDV function calls shown above reflect the mapping and validation parameters you specified with ClassWizard.

Notice that the DDV function call for a given member variable immediately follows the DDX function call for that variable. This is a rule you must follow if you choose to manually edit the contents of the data map.

For more information about ClassWizard, see Chapter 9 of the App Studio User's Guide.


 Implementing the Message Handler

Recall that ClassWizard provided an empty function definition for the OnDefaultPenWidths message handler, which is called when the user chooses the Default button. Now that the CPenWidthsDlg class contains the necessary member variables, it's time to fill in that function definition. This function sets the contents of the edit boxes to the default widths of the thin and thick pens.

To implement the message handler for the Default button

1.	From the ClassWizard dialog box, highlight "OnDefaultPenWidths" in the Member Functions list box and then choose the Edit Code button. (The Edit Code button may be disabled if you are running App Studio without running Visual Workbench; in this case, launching Visual Workbench will enable the button.) The Edit Code button transfers you to Visual Workbench, opens PENDLG.CPP, and displays the definition for OnDefaultPenWidths.

2.	Fill in the OnDefaultPenWidths function with the following code:

void CPenWidthsDlg::OnDefaultPenWidths()

{

m_nThinWidth = 2;

m_nThickWidth = 5;

UpdateData(FALSE);  // causes DoDataExchange()

// bSave=FALSE means don't save from screen, rather, write

// to screen

}

The function sets m_nThinWidth and m_nThickWidth to their default values and then calls UpdateData, a member function defined by CWnd (the base class of CDialog).

The UpdateData member function calls the DoDataExchange function to move values between the member variables and the controls displayed on the screen. The direction in which the data values are moved is specified by the argument to UpdateData. The default value of this argument is TRUE, which moves data from the controls to the member variables. A value of FALSE moves data from the member variables to the controls. The OnDefaultPenWidths member function passes FALSE, causing the default values to be displayed in the edit boxes on the screen.

3.	Save and close the file PENDLG.CPP and return to App Studio. The dialog editor window is still visible, displaying the Pen Widths dialog box you designed. Click on the push-pin button on the property page so that it is unpinned, then double-click the close box on the dialog editor window. Now only the App Studio resource browser window for SCRIBBLE.RC should be visible.


 Invoking the Dialog Box

By now you've specified almost everything about the Pen Widths dialog box: its appearance, the data map for its edit controls, and the message handlers for its pushbuttons. There's only one thing that remains to be specified: when the dialog box should be invoked.

At the moment there is no programmatic connection between the Pen Widths menu item and the Pen Widths dialog box; that is, the menu item and the dialog box are not bound together. You must explicitly bind them by invoking the Pen Widths dialog box from within the message handler for the Pen Widths command.

How do you invoke a dialog box? The first step is to declare a CPenWidthsDlg object. This doesn't display the dialog box on the screen, it just constructs the C++ object that manages the dialog box. To display the dialog box, you must call the DoModal member function defined by the CDialog class.

The Pen Widths dialog box is a "modal" dialog, which means that once invoked, it takes control of the application (it puts the program in a different "mode"). The user can do no other work in the application while the dialog box is displayed and must dismiss the dialog box, typically by choosing the OK or Cancel button, to continue with the application. The DoModal function continues executing as long as the dialog box is displayed on the screen. When the user chooses the OK or Cancel button, the DoModal function returns IDOK or IDCANCEL, respectively, and the application can continue.

Now you can write a message handler for the Pen Widths command. Which class should get the handler? Recall that in Chapter 6 in »Add New Member Variables to Scribble« you added declarations for the m_nThickWidth and m_nThinWidth member variables to the CScribDoc class, because the document needs to keep track of the widths of the thick and thin pens (this allows multiple views to share the same pen widths). Since the document class has to maintain those values, it should get the handler for the Pen Widths command.

To bind the Pen Widths command

1.	From the Type box in the App Studio resource browser window for SCRIBBLE.RC, choose Menu.

2.	Open the IDR_SCRIBTYPE menu resource (you edited this resource earlier in »Add the Clear All Command to Scribble's Edit Menu« in Chapter 5.

3.	From the Resource menu, choose the ClassWizard command. The ClassWizard dialog box appears.

4.	In the Class Name dropdown list, choose "CScribDoc."

5.	In the Object IDs box, highlight the ID_PEN_WIDTHS command.

6.	In the Messages box, highlight COMMAND.

7.	Choose the Add Function button.

8.	Choose the OK button to accept the candidate name "OnPenWidths."

9.	Choose the Edit Code button. This returns you to the Visual Workbench session and opens the file SCRIBDOC.CPP.

10.	Make the following additions to SCRIBDOC.CPP:

#include "stdafx.h"

#include "scribble.h"

#include "scribdoc.h"

#include "pendlg.h"

// ...

void CScribDoc::OnPenWidths()

{

CPenWidthsDlg dlg;

// Initialize dialog data

dlg.m_nThinWidth = m_nThinWidth;

dlg.m_nThickWidth = m_nThickWidth;

// Invoke the dialog box

if (dlg.DoModal() == IDOK)

{

// retrieve the dialog data

m_nThinWidth = dlg.m_nThinWidth;

m_nThickWidth = dlg.m_nThickWidth;

// Update the pen used by views when drawing new strokes

// to reflect the new pen widths for "thick" and "thin".

ReplacePen();

}

}

11.	Save SCRIBDOC.CPP. In App Studio, save SCRIBBLE.RC.

When modifying SCRIBDOC.CPP, it's necessary to include PENDLG.H, so that the message handler has access to the dialog class you've created. The OnPenWidths function declares a CPenWidthsDlg object and sets the values of the m_nThickWidth and m_nThinWidth member variables to the current widths of the thick and thin pens. Then the function calls the DoModal function, which displays the dialog box on the screen and takes control of the system until the user exits the dialog box. If the user exits the dialog box by choosing the OK button, the function changes the current thick and thin pen widths to the new values; if the user chooses the Cancel button, the old values are retained. Finally, the function calls the ReplacePen member function to make the document's pen use the current widths.

When does the application perform the data exchange and validation defined in the DoDataExchange function? Recall that DoDataExchange is called by the UpdateData member function. Just before the dialog box is first displayed on the screen, the framework calls the UpdateData function with an argument of FALSE, which sets the contents of the edit boxes to the values of the member variables. If the user exits the dialog box by choosing the OK button, the framework calls UpdateData with an argument of TRUE, which retrieves the contents of the edit boxes and sets the values of the member variables accordingly. (If the user exits by choosing the Cancel button, the framework doesn't call UpdateData.)

You don't have to handle the UPDATE_COMMAND_UI message for the Pen Widths menu item, because the menu item doesn't need to be updated. The command is never disabled, since it's always legal to change the widths of the pens, and there's no need to add or remove a check mark, because the command isn't a toggle.


Compile Scribble  Step 3 Version
 Compile Scribble − Step 3 Version

How does Scribble behave now that a dialog box has been added? Compile the new version of Scribble and find out.

To compile Scribble

•	From the Project menu in the Visual Workbench, choose the Build command.

Run the new version of Scribble. Draw some strokes with the default thick pen and the default thin pen. Then use the Pen Widths dialog to change the thickness of the pens and draw some new strokes. »Figure 7.6« illustrates the third version of Scribble with a variety of strokes drawn.

Exit Scribble.

This completes step 3 in the tutorial.

In Chapter 8, »Enhancing Views«, you'll implement the updating of multiple views, scrolling, and splitter windows.


 Chapter 8  Enhancing Views

In the previous chapters, you've seen how a view acts as an intermediary between a document and the user: the view displays a document on the screen and interprets mouse actions as operations on the document. You've also seen how a view cooperates with a frame window so that the frame window implements the generic window behavior while the view provides the application-specific functionality.

However, there are additional benefits to having a view class that is separate from the document and the frame window, benefits which Scribble hasn't demonstrated yet. This chapter describes how to take advantage of the division of labor between these classes to add special features to your application's user interface.

This chapter covers the following topics:

•	»Updating multiple views« on the same document.

•	»Scrolling a view.«

•	»Splitting a window.«

This chapter covers step 4 of Scribble. If you want to work along, adding the code as you go, begin with the files you worked on in Chapter 7, »Adding a Dialog Box,« in your SCRIBBLE\MYSCRIB subdirectory. At this point, these files should closely resemble those in the SCRIBBLE\STEP3 subdirectory. As you read the chapter, add all the code that's marked with the symbol [image]. At the end, your files should closely resemble the files in the SCRIBBLE\STEP4 subdirectory.

If, on the other hand, you want to read along without adding code, you can print or examine the files in the SCRIBBLE\STEP4 subdirectory.


 Updating Multiple Views

Suppose you have a drawing open in Scribble and you choose the New Window command on the Window menu. This action opens a new document window displaying the same drawing. The document object now has two view objects connected to it. Now consider what would happen if you added some new strokes in one of the document windows. Would the new strokes appear in the other window simultaneously? No, not as Scribble is currently implemented, because each window is unaware of what's happening in the other windows. (This is illustrated in »Figure 8.1.«) You would have to wait until the other window is repainted (for instance, if you minimized and then restored it). Then its OnDraw function would display the drawing again, including the new strokes.

How can you ensure that all the views attached to a document reflect changes to the document as soon as they are made? Each view must notify the other views whenever it has modified the document. The Microsoft Foundation Class Library provides a standard mechanism for notifying views of modifications to a document through the UpdateAllViews member function of the CDocument class.

The UpdateAllViews function traverses the list of views attached to the document. For each view in the list (except the one that made the modifications), it calls the OnUpdate member function of the CView class. The OnUpdate function is where the view responds to changes in the document; the default implementation of the function invalidates the client area of the view, causing it to be repainted. The simplest way for you to use this updating mechanism in your application is to call the document's UpdateAllViews function whenever a view modifies a document in response to a user action.

You can also perform more efficient repainting with this updating mechanism if you use the parameters of the UpdateAllViews function. Here is the declaration of UpdateAllViews:

virtual void UpdateAllViews(CView* pSender, LPARAM lHint = 0L,

                            CObject* pHint = NULL);

The first argument identifies the view that made the modifications to the document. This is specified to keep the UpdateAllViews function from performing a redundant notification; typically the view that made the modifications doesn't need to be told about them. The second two arguments are "hints." You can use these hints to describe the modifications that the view made.

The UpdateAllViews function gives the hints to every view attached to the document (except the one that made the modifications) by passing them as parameters to the OnUpdate member function. You can override OnUpdate to interpret those hints and update only the area of the display that corresponds to the modified portion of the document. Thus, if another view is displaying a completely different portion of the document, it doesn't have to perform any repainting at all.

To inform other views of modifications:

1.	Define a type of hint that describes a modification to a document.

2.	When a view modifies the document, create a hint describing the modification made and pass it to UpdateAllViews.

3.	Override OnUpdate to use the hint so that only the portion of the screen corresponding to the modification gets updated.

These steps are described in more detail in the following sections, using Scribble as an example.


 Define a Hint for Scribble

When a stroke is added to a drawing in Scribble, the rectangular region that contains the new stroke is the only area that needs to be updated; the remainder of the drawing can be left alone. Therefore, a logical choice for a hint in Scribble is the bounding rectangle of the new stroke.

To define bounding rectangles for strokes

1.	Instead of creating a separate class to represent the hint, it's more convenient to store the bounding rectangle for each stroke in the CStroke object itself. Accordingly, load the file SCRIBDOC.H in Visual WorkBench and add the following new member declarations to CStroke:

class CStroke : public CObject

{

// ...

protected:

// Attributes

// ...

CRect	m_rectBounding;	  // smallest rect that surrounds all

  // of the points in the stroke

public:

CRect& GetBoundingRect() { return m_rectBounding; }

// Operations

public:

void FinishStroke();

// ...

};

The protected member variable m_rectBounding is a CRect object storing the bounding rectangle, and the public member function GetBoundingRect allows the rectangle to be retrieved by the view. There is also a new helper function, the FinishStroke member function.

2.	Load SCRIBDOC.CPP and make the following modifications:

// Each time we change what gets serialized, we change

// the schema number.

IMPLEMENT_SERIAL( CStroke, CObject, 2 )

// ...

CStroke::CStroke(UINT nPenWidth)

{

m_nPenWidth = nPenWidth;

m_rectBounding.SetRectEmpty();

}

//...

void CStroke::Serialize(CArchive& ar)

{

if (ar.IsStoring())

{

ar << m_rectBounding;

ar << (WORD)m_nPenWidth;

m_pointArray.Serialize(ar);

}

else

{

ar >> m_rectBounding;

WORD w;

ar >> w;

m_nPenWidth = w;

m_pointArray.Serialize(ar);

}

}

The changes shown here are needed to manage the addition of the m_rectBounding member variable. The first change to be made is incrementing the schema number in the IMPLEMENT_SERIAL macro. This is necessary because this version of Scribble changes what's stored in a CStroke object by adding a new member variable. Changing the schema number distinguishes strokes saved by this version of Scribble from those of other versions.

The next change initializes the bounding rectangle to an empty rectangle in the CStroke constructor. The changes to the Serialize member function store and read the m_rectBounding member variable.

3.	The FinishStroke member function calculates the bounding rectangle for a stroke. Add the following function definition to the end of SCRIBDOC.CPP:

//////////////////////////////////////////////////////////////////

void CStroke::FinishStroke()

{

// Calculate the bounding rectangle.  It's needed for smart

// repainting.

if( m_pointArray.GetSize() == 0 )

{

m_rectBounding.SetRectEmpty();

return;

}

CPoint pt = GetPoint(0);

m_rectBounding = CRect( pt.x, pt.y, pt.x, pt.y );

for (int i=1; i < m_pointArray.GetSize(); i++)

{

// If the point lies outside of the accumulated bounding

// rectangle, then inflate the bounding rect to include it.

pt = GetPoint(i);

m_rectBounding.left   = min(m_rectBounding.left, pt.x);

m_rectBounding.right  = max(m_rectBounding.right, pt.x);

m_rectBounding.top    = min(m_rectBounding.top, pt.y);

m_rectBounding.bottom = max(m_rectBounding.bottom, pt.y);

}

// Add the pen width to the bounding rectangle.  This is needed

// to account for the width of the stroke when invalidating

// the screen.

m_rectBounding.InflateRect(CSize(m_nPenWidth, m_nPenWidth));

return;

}

In this function, the stroke object iterates through its array of points, testing each one's location; if a point falls outside the current bounding rectangle, the stroke object enlarges the bounding rectangle just enough to contain it. Then the bounding rectangle is expanded on each side by the width of the pen.


 Pass the Hint After Modifying the Document

The next step is to pass the hint to the document's UpdateAllViews member function. An appropriate time to pass a hint is each time a stroke is completed.

To pass the hint after modifying the document

•	The OnLButtonUp member function is called when a stroke is finished, so you should call UpdateAllViews from there. Load SCRIBVW.CPP and make the following modifications near the end of OnLButtonUp:

void CScribView::OnLButtonUp(UINT, CPoint point)

{

// ...

m_pStrokeCur->AddPoint( point );

// Tell the stroke item that we're done adding points to it.

// This is so it can finish computing its bounding rectangle.

m_pStrokeCur->FinishStroke();

// Tell the other views that this stroke has been added

// so that they can invalidate this stroke's area in their

// client area.

pDoc->UpdateAllViews(this, 0L, m_pStrokeCur);

ReleaseCapture();	// Release the mouse capture established at

// the beginning of the mouse drag.

return;

}

In this function, the view gets the hint information that it will send to the document. It does this by calling the FinishStroke member function for m_pStrokeCur; FinishStroke computes the bounding rectangle for the current stroke. Then the view calls UpdateAllViews, passing two arguments: the this pointer, which identifies this view as the one that performed the modification to the document; and m_pStrokeCur, whose bounding rectangle is the hint. (The function sends a pointer to the entire CStroke object rather than just the bounding rectangle because the hint must be a CObject pointer, and CRect isn't derived from CObject.) The view doesn't need to send any more hint information, so it doesn't pass anything in the LPARAM parameter.

The UpdateAllViews function iterates through the list of views attached to the document; for each view (except the one that performed the modification), the function calls its OnUpdate function and passes the hint as a parameter.


 Use the Hint for Efficient Repainting

The last step is to take advantage of the hint so the other views can repaint themselves more efficiently. This involves modifying the CScribView class to respond to any hint it receives.

To use the hint for efficient repainting

1.	From within Visual Workbench, load SCRIBVW.H and add the following function declaration:

class CScribView : public CView

{

// ...

// Implementation

public:

virtual void OnUpdate( CView* pSender, LPARAM lHint = 0L,

CObject* pHint = NULL);

// ...

};

This causes CScribView to override the OnUpdate function defined by the CView class.

2.	To define CScribView's version of OnUpdate, load SCRIBVW.CPP in Visual Workbench and add the following function definition to the end of the file:

//////////////////////////////////////////////////////////////////

void CScribView::OnUpdate(CView*, LPARAM, CObject* pHint)

{

// The document has informed this view that some data has changed.

if (pHint != NULL)

{

if (pHint->IsKindOf(RUNTIME_CLASS(CStroke)))

{

// The hint is that a stroke has been added (or changed).

// So, invalidate its rectangle.

CStroke* pStroke = (CStroke*)pHint;

CRect rectInvalid = pStroke->GetBoundingRect();

InvalidateRect(&rectInvalid);

return;

}

}

// We can't interpret the hint, so assume that anything might

// have been updated.

Invalidate();

return;

}

Recall that this function is called by the UpdateAllViews function of CScribDoc, which passes it a hint. In this function, the view checks if the hint is a CStroke object. If so, the view gets the bounding rectangle for the stroke and marks it as invalid. This rectangle marks the area that must be redrawn. If the hint isn't a CStroke object, the view doesn't know what area was modified, so it invalidates the entire client area as a precaution.

After a region has been invalidated, Windows sends a WM_PAINT message. The OnPaint member function defined by CView handles this message by calling the virtual OnDraw member function. Consequently, you must modify the OnDraw function to take advantage of the invalidated rectangle when redrawing.

3.	Make the following changes to the OnDraw member function in SCRIBVW.CPP:

void CScribView::OnDraw(CDC* pDC)

{

CScribDoc* pDoc = GetDocument();

// Get the invalidated rectangle of the view, or in the case

// of printing, the clipping region of the printer dc.

CRect rectClip;

CRect rectStroke;

pDC->GetClipBox(&rectClip);

//Note: CScrollView::OnPaint() will have already adjusted the

//viewpoint origin before calling OnDraw(), to reflect the

//currently scrolled position.

// The view delegates the drawing of individual strokes to

// CStroke::DrawStroke().

for (POSITION pos = pDoc->GetFirstStrokePos(); pos != NULL; )

{

CStroke* pStroke = pDoc->GetNextStroke(pos);

rectStroke = pStroke->GetBoundingRect();

if (!rectStroke.IntersectRect(&rectStroke, &rectClip))

continue;

pStroke->DrawStroke(pDC);

}

}

In this function, the view first calls the GetClipBox member function of CDC to get the invalidated portion of the client area. Then the view iterates through the list of strokes in the document, calling IntersectRect for each to determine if any part of the stroke lies in the invalidated region. If so, the view asks the stroke to draw itself. Any strokes that don't intersect the invalidated region don't have to be redrawn.


 Adding Scrolling

In the current version of Scribble, you cannot work on a drawing that is larger than the window. It would be more convenient if you could work on a large drawing no matter how small the window is; to do this, Scribble must support scrolling.

The addition of scrolling expands the conceptual role played by a view. Not only does a view produce a visual representation of a document's data, it also acts as a peephole to a document that may be too large to display all at once. This peephole can be moved across the document to reveal different portions of it. This is illustrated in »Figure 8.2.«

Implementing scrolling all by yourself is fairly complicated. However, since a lot of the scrolling code is the same for all applications, the Microsoft Foundation Class Library implements the common scrolling logic in a class called CScrollView.

The basic steps for adding scrolling to your application are as follows:

1.	Define a size for your documents. This can be a constant, a member stored in each document object, a value calculated at run time, etc.

2.	Derive your view class from CScrollView instead of CView.

3.	Pass the document's size to the SetScrollSizes member function of CScrollView whenever the size may change.

4.	Convert between logical coordinates and device coordinates if passing points between graphic device interface (GDI) and non-GDI functions.

The framework's responsibilities are as follows:

•	Handle all WM_HSCROLL and WM_VSCROLL messages, scroll the document in response, and move the scroll box accordingly.

The positions of the scroll boxes reflect where the currently displayed portion of the document resides relative to the rest of the document. If the user clicks on a scroll arrow at either end of the scroll bar, the document is scrolled one "line" (whose meaning depends on the document type). If the user clicks on either side of the scroll box, the document is scrolled one "page." If the user drags the scroll box itself, the document is scrolled accordingly.

•	Calculate a mapping between the lengths of the scroll bars and the height and width of the document, adjust this scaling factor when the window is resized or when the size of the document changes, and in turn remove or add scroll bars as needed.

The next section, »Add Scrolling to Scribble,« describes how to add scrolling to Scribble. »Figure 8.3« shows what Scribble looks like with scroll bars added.


 Add Scrolling to Scribble

To add scrolling support to Scribble

1.	First define the size of Scribble documents. You can do this by having each document store its dimensions. Launch Visual Workbench and load SCRIBDOC.H. Make the following changes to the declaration of the CScribDoc class:

class CScribDoc : public CDocument

{

// ...

protected:

CSize m_sizeDoc;

public:

CSize GetDocSize() { return m_sizeDoc; }

// Operations

// ...

};

The member variable m_sizeDoc stores the size of the document in a CSize object. This member is protected, so it cannot be accessed directly by the views attached to the document. To let the views retrieve the size of the document, you provide a public helper function named GetDocSize. The views base their scrolling limits on the document size.

2.	Load SCRIBDOC.CPP and make the following changes:

// ...

void CScribDoc::InitDocument()

{

// ...

// default document size is 800 x 900 screen pixels

m_sizeDoc = CSize(800,900);

}

// ...

// CScribDoc serialization

void CScribDoc::Serialize(CArchive& ar)

{

if (ar.IsStoring())

{

ar << m_sizeDoc;

}

else

{

ar >> m_sizeDoc;

}

m_strokeList.Serialize(ar);

}

The new code in the InitDocument member function initializes the m_sizeDoc member variable; recall that you use this function whenever a new document is created or an existing document is opened. All Scribble documents are the same size: 800 logical units in width and 900 logical units in height. For simplicity's sake, Scribble doesn't support documents of varying size to accommodate arbitrarily large drawings.

The changes to the Serialize member function store and read the m_sizeDoc member variable.

3.	Next, you must make the view set its scrolling limits according to the size of the document. Load SCRIBVW.H and make the following changes to the declaration of CScribView:

class CScribView : public CScrollView

{

// ...

// Implementation

public:

void OnInitialUpdate();

// ...

}

By changing the base class of CScribView from CView to CScrollView, you give CScribView scrolling functionality without having to implement any of it yourself.

In addition, the CScribView class overrides the OnInitialUpdate member function, which is called when the view is first attached to the document. By overriding this function, you can inform the view of the document's size as soon as possible.

4.	Recall that the Microsoft Foundation Class Library uses message maps as well as C++ inheritance. As a result, modifying the class declaration in the header file isn't enough to give CScribView all of CScrollView's functionality; you also have to modify the message-map macros in the implementation file. Load SCRIBVW.CPP and change the following lines:

IMPLEMENT_DYNCREATE( CScribView, CScrollView )

BEGIN_MESSAGE_MAP( CScribView, CScrollView )

//{{AFX_MSG_MAP( CScribView )

// ...

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

// ...

Notice that in the message map macro,  CScribView's name is now followed by CScrollView instead of CView. This instructs the framework to search CScrollView's message map if it can't find the message handler it needs in CScribView's message map.

5.	If you want to use the diagnostic features provided by the Microsoft Foundation Class Library, change the implementations of the Dump and AssertValid member functions of CScribView. These functions simply call their base class versions; change them to call the CScrollView versions rather than the CView versions.

6.	To provide a definition for OnInitialUpdate, add the following code at the end of SCRIBVW.CPP:

void CScribView::OnInitialUpdate()

{

SetScrollSizes( MM_TEXT, GetDocument()->GetDocSize() );

}

The SetScrollSizes member function is defined by CScrollView. Its first parameter is the mapping mode used to display the document. The mapping mode that the current version of Scribble uses is MM_TEXT; in Chapter 9, Scribble will use the MM_LOENGLISH mapping mode for better printing. (For more information on mapping modes, see »Enlarge the Printed Image« in Chapter 9, or see CDC::SetMapMode in the Class Library Reference).

The second parameter is the total size of the document, which is needed to determine the scrolling limits. The view uses the value returned by the document's GetDocSize member function for this parameter.

SetScrollSizes also has two other parameters, for which Scribble uses the default values. These are CSize values that represent the size of one "page" and one "line," the distances to be scrolled if the user clicks the scroll bar or a scroll arrow. The default values are 1/10th and 1/100th of the document size, respectively.

Since Scribble documents are fixed in size, there is no need to make any subsequent calls to SetScrollSizes. If your application supports documents of varying size, you should call SetScrollSizes immediately after the document's size changes. (You can do this from the OnUpdate member function of your view class.)

Notice that the addition of scrolling didn't require you to modify the OnDraw member function of CScribView. If the drawing function is unchanged, why does the window display different portions of the document depending on where the user has scrolled to? The reason is that the document is displayed using coordinates relative to an origin used by GDI. When this origin was fixed at the upper-left corner of the client area, the part of the document that was visible was always the same. By moving the origin used by GDI, CScrollView can adjust what portion of the document is shown in the client area of the window and what portions are hidden.

The origin used by GDI is a characteristic of a device context; it is used by the member functions of the CDC class. If you want to make adjustments to the CDC object used by your view, you can override the OnPrepareDC member function defined by CView. CScrollView overrides OnPrepareDC to move the device context's origin to reflect the currently scrolled position. OnPrepareDC is always called by the framework before it calls OnDraw; in Scribble, CScrollView's version of OnPrepareDC is called before CScribView's OnDraw is called. As a result, you don't have to make any changes to the OnDraw function to draw a properly scrolled document; all the work needed to do scrolling is done to the device context before OnDraw receives it.

It's important to note that changing the device context's origin doesn't affect the coordinates you receive with Windows messages such as WM_LBUTTONDOWN or WM_MOUSEMOVE; the points accompanying those messages are still specified in coordinates relative to the upper-left corner of the client area. This is because Windows messages are not part of a device context, so they are unaffected by changes to the GDI origin. Thus, CScribView must now deal with two types of coordinates:

•	The coordinates used for describing the points received with a mouse message. Those points are returned in "device coordinates."

•	The coordinates used for drawing with GDI. These are known as "logical coordinates."

When storing the coordinates of strokes, Scribble needs to know where the strokes are relative to the document, not relative to the client area. Consequently, CScribView must convert points from device coordinates (relative to the window origin) to logical coordinates (relative to the document origin) before storing them in CStroke objects.

To store the strokes using logical coordinates

1.	Make the following modifications to the OnLButtonDown member function of CScribView:

void CScribView::OnLButtonDown(UINT, CPoint point)

{

// CScrollView changes the viewport origin and mapping mode.

// It's necessary to convert the point from device coordinates

// to logical coordinates, such as are stored in the document.

CClientDC dc(this);

OnPrepareDC(&dc);

dc.DPtoLP(&point);

m_pStrokeCur = GetDocument()->NewStroke();

m_pStrokeCur->AddPoint(point); // add 1st point to the new stroke

SetCapture();	// Capture the mouse until button up.

m_ptPrev = point;	// Serves as the MoveTo() anchor for the

//   LineTo() the next point as the user

//   drags the mouse.

return;

}

In this function, the view receives a point specified in device coordinates. A device context is needed to find the GDI origin, so the function declares a CClientDC object, a CDC object for the client area of the view, and calls OnPrepareDC to adjust its origin. Then the function passes the point to the DPtoLP (Device Point to Logical Point) member function of CDC to perform the actual conversion. The point added to m_pStrokeCur is thus described in logical coordinates (that is, relative to the document origin).

2.	Make a similar modification to the OnMouseMove member function:

void CScribView::OnMouseMove(UINT, CPoint point)

{

// ...

if (GetCapture() != this)

return;	// If this window (view) didn't capture the mouse,

// then the user isn't drawing in this window.

CClientDC dc(this);

// CScrollView changes the viewport origin and mapping mode.

// It's necessary to convert the point from device coordinates

// to logical coordinates, such as are stored in the document.

OnPrepareDC(&dc);

dc.DPtoLP(&point);

m_pStrokeCur->AddPoint(point);

// ...

}

This function already has a device context for drawing the stroke in progress, so the only modifications needed are to call OnPrepareDC to move the viewport origin and then DPtoLP to convert the point before before adding it.

3.	Make the same modification to the OnLButtonUp member function:

void CScribView::OnLButtonUp(UINT, CPoint point)

{

// ...

if (GetCapture() != this)

return;	// If this window (view) didn't capture the mouse,

// then the user isn't drawing in this window.

CScribDoc* pDoc = GetDocument();

CClientDC dc(this);

// CScrollView changes the viewport origin and mapping mode.

// It's necessary to convert the point from device coordinates

// to logical coordinates, such as are stored in the document.

OnPrepareDC(&dc);  // set up mapping mode and viewport origin

dc.DPtoLP(&point);

CPen* pOldPen = dc.SelectObject(pDoc->GetCurrentPen());

// ...

}

Like OnMouseMove, this function already has a device context to complete drawing the stroke, so the only modifications needed are to call OnPrepareDC and then DPtoLP.

4.	Finally, you must modify the OnUpdate member function. Unlike the previous three functions, this function requires a conversion in the opposite direction, that is, from logical coordinates to device coordinates. Recall that OnUpdate retrieves the bounding rectangle of a stroke and invalidates that rectangle. The stroke's bounding rectangle is stored in logical coordinates. However, the rectangle passed to InvalidateRect must be specified in device coordinates (since InvalidateRect is not a GDI function).

Accordingly, a stroke's bounding rectangle must have its coordinates converted into device coordinates before it can be invalidated. Make the following modifications:

void CScribView::OnUpdate(CView*, LPARAM, CObject* pHint)

{

// The document has informed this view that some data has changed.

if (pHint != NULL)

{

if (pHint->IsKindOf(RUNTIME_CLASS(CStroke)))

{

// The hint is that a stroke as been added (or changed).

// So, invalidate its rectangle.

CStroke* pStroke = (CStroke*)pHint;

CClientDC dc(this);

OnPrepareDC(&dc);

CRect rectInvalid = pStroke->GetBoundingRect();

dc.LPtoDP(&rectInvalid);

InvalidateRect(&rectInvalid);

return;

}

}

// We can't interpret the hint, so assume that anything might

// have been updated.

Invalidate(TRUE);

return;

}

The function declares a CClientDC object and then calls the OnPrepareDC member function to move the viewport origin of the device context to reflect the currently scrolled position. The rectangle is then passed to the LPtoDP (Logical Point to Device Point) function of CDC to convert its points into device coordinates. (Both DPtoLP and LPtoDP are overloaded to accept rectangles as well as points.) Once it is converted, the rectangle can be invalidated.

For more information on CScrollView, see the Class Library Reference.


 Adding Splitter Windows

Scrolling lets you work on a document that is larger than the window, but by the same token it means that much of the document is hidden at any one time. Suppose the user needs to refer to two widely separated portions of a document at the same time. One way to do this is to open another window on the same document and scroll them to different locations. However, windows must be resized individually so that they don't overlap. A more convenient solution is to divide a window into separate "panes," each of which can display a different portion of the document. This is illustrated in »Figure 8.4.«

A window that can be divided into multiple panes is called a "splitter window." A splitter window contains split boxes at the top of the vertical scroll bar and at the left of the horizontal scroll bar. By double-clicking a split box, the user can divide a window vertically or horizontally into panes. The panes are separated by a "split bar"; each pane can be scrolled independently to display a different portion of the document. The user can also drag the split bar to resize both panes at once.

»Figure 8.5« shows what a Scribble window looks like when it is split into two panes.

Each pane in a splitter window represents a separate view object. In »Figure 8.5,« each pane is an instance of the CScribView class, but it's not necessary for the panes to use the same view class; you can use different classes for different panes. This is useful when, for example, you want one pane to display an outline of a document while the other pane displays the full text.

The Microsoft Foundation Class Library provides splitting functionality in a class called CSplitterWnd. By using this class, you can support splitting in your application with very little effort.

The basic steps for adding splitter windows to your application are as follows:

1.	Derive a frame window class from CMDIChildWnd if you are writing a Multiple Document Interface (MDI) application or CFrameWnd if you are writing a Single Document Interface (SDI) application. Give this class a member variable of type CSplitterWnd.

2.	Override the OnCreateClient member function of your frame window class to create a CSplitterWnd.

3.	When defining a document template, use the frame window class you derived instead of CMDIChildWnd or CFrameWnd.

The following section, »Add Splitter Windows to Scribble,« shows in detail how these steps are accomplished for Scribble.


 Add Splitter Windows to Scribble

To make it easy to add splitter windows to your application, ClassWizard provides an option that automatically derives a frame window class and overrides its OnCreateClient member function for you.

To add splitter windows to Scribble

1.	From Visual Workbench, pull down the Browse menu and choose the ClassWizard command. The ClassWizard dialog box appears.

2.	Choose the Add Class button. The Add Class dialog box appears.

3.	For the class name, enter "CScribFrame."

4.	For the class type, choose "splitter."

5.	For the header file, change the default name to "scribfrm.h."

6.	For the implementation file, change the default name to "scribfrm.cpp."

7.	Choose the Create Class button to generate the new class. The ClassWizard dialog box regains the focus.

8.	Choose the OK button to exit the ClassWizard dialog box. As before, the new files are automatically added to the project.

The file SCRIBFRM.H, which ClassWizard has generated, declares a new class called CScribFrame. Here's what the file looks like:

////////////////////////////////////////////////////////////////////

// CScribFrame frame with splitter

#ifndef _AFXEXT_H

#include <afxext.h>

#endif

class CScribFrame : public CMDIChildWnd

{

DECLARE_DYNCREATE( CScribFrame )

protected:

CScribFrame();  // protected constructor used by dynamic creation

// Attributes

protected:

CSplitterWnd  m_wndSplitter;

public:

// Operations

public:

// Implementation

public:

virtual ~CScribFrame();

virtual BOOL OnCreateClient( LPCREATESTRUCT lpcs,

CCreateContext* pContext );

// Generated message map functions

//{{AFX_MSG(CScribFrame)

// NOTE - ClassWizard will add and remove member functions here.

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

CScribFrame assumes the role that CMDIChildWnd previously played in Scribble. To understand CScribFrame's declaration, it's helpful to review how CMDIChildWnd is normally used. Until now, each time you opened a document window in Scribble, there were two objects cooperating to display the document: a CMDIChildWnd object, which manages the document window's frame, and a CScribView object, which manages the document window's client area. (These two classes were specified when AppWizard created the document template for CScribDoc objects.)

For Scribble to support splitting, this organization must change. Objects of three classes must cooperate to displaying a document: a CScribFrame object, which manages the document window's frame; a CSplitterWnd object, which manages the document window's client area; and one or more CScribView objects, each of which manages a pane in the window. The CSplitterWnd object is not visible as a distinct entity, but it is responsible for handling the CScribView objects as panes, managing their scroll bars, and drawing the split boxes and split bars.

This technique for managing splitter windows is similar to the way MDI is implemented. An MDI application's frame window has a client window managing its entire client area, or workspace. It is this client window that owns the child windows that display documents.

Now consider CScribFrame's declaration. The CScribFrame class is derived from CMDIChildWnd because Scribble is an MDI application; if Scribble were an SDI application, CScribFrame would be derived from CFrameWnd. The only constructor for CScribFrame is a protected one, because you don't need to explicitly create CScribFrame objects; the framework handles their creation for you.

The CScribFrame class defines one member variable: a CSplitterWnd object. This is the window that covers the frame window's client area. The class also overrides the OnCreateClient member function defined by CFrameWnd (the base class of CMDIChildWnd). The framework calls this function when it first creates the frame window.

The file SCRIBFRM.CPP, which ClassWizard has generated, contains the implementation of the member functions for CScribFrame. Here's what it looks like:

#include "stdafx.h"

#include "scribble.h"

#include "scribfrm.h"

#ifdef _DEBUG

#undef THIS_FILE

static char BASED_CODE THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////

// CScribFrame

IMPLEMENT_DYNCREATE(CScribFrame, CMDIChildWnd)

CScribFrame::CScribFrame()

{

}

CScribFrame::~CScribFrame()

{

}

BOOL CScribFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/,

 	CCreateContext* pContext )

{

return m_wndSplitter.Create( this,

2, 2, 	// TODO: adjust the number of rows, columns

CSize( 10, 10 ),   // TODO: adjust the minimum pane size

pContext );

}

BEGIN_MESSAGE_MAP(CScribFrame, CMDIChildWnd)

//{{AFX_MSG_MAP(CScribFrame)

   // NOTE - ClassWizard will add and remove mapping macros here.

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

//////////////////////////////////////////////////////////////////

// CScribFrame message handlers

In the OnCreateClient member function, the frame window creates the window that will cover its client area by calling the Create function of its CSplitterWnd member variable. The parameters passed to the Create function describe the panes that the splitter window will manage.

The first argument passed to Create specifies the parent window for the client window: the function passes the this pointer, making the CScribFrame window the parent of the CSplitterWnd object. The second and third parameters specify the maximum number of rows and columns that the splitter window can have; a value of two is used for each, so Scribble's splitter windows can have up to four panes. The fourth parameter specifies the minimum size of a pane: a square 10 logical units on a side.The fifth parameter is the CCreateContext structure that is passed to OnCreateClient. This structure is used to determine which view class should be used for each pane in the splitter window.

The Create function can also accept an additional two arguments; because Scribble doesn't pass any values for these, the default values are used. The sixth argument specifies the styles to be used for the splitter window. The default value specifies a visible child window with vertical and horizontal scroll bars that supports dynamic splitting. The seventh argument specifies the ID to be assigned to the splitter window. Its default value is AFX_IDW_PANE_FIRST, which is the ID of the first pane.

9.	Having defined a new frame window class, you must now use it when opening Scribble documents. Open the file SCRIBBLE.CPP and add the code following:

#include "stdafx.h"

#include "scribble.h"

#include "mainfrm.h"

#include "scribfrm.h"

#include "scribdoc.h"

#include "scribvw.h"

// ...

BOOL CScribbleApp::InitInstance()

{

// ...

AddDocTemplate(new CMultiDocTemplate(IDR_SCRIBTYPE,

RUNTIME_CLASS(CScribDoc),

RUNTIME_CLASS(CScribFrame),  // MDI child with splitter wnd

RUNTIME_CLASS(CScribView)));

// ...

}

First it's necessary to include the header file SCRIBFRM.H so you can access the declaration of the CScribFrame class. The major modification occurs in the InitInstance member function of CScribbleApp. This function calls AddDocTemplate to register the CScribDoc document type with the application. Recall that a document template connects a document class, a frame window class, and a view class. In previous versions of Scribble, CMDIChildWnd was the frame window class used for displaying CScribDoc objects. Now CScribFrame, which is derived from CMDIChildWnd, is the frame window class. As a result, the windows used for displaying Scribble's documents support splitting.

For more information on CSplitterWnd, see the Class Library Reference.


Compile Scribble  Step 4 Version
 Compile Scribble − Step 4 Version

How does Scribble behave with these new enhancements? Compile the new version and find out.

To compile Scribble

•	From the Project menu in Visual Workbench, choose the Build Command.

Run the new version of Scribble.

Draw some strokes, scroll to a new portion of the drawing, and draw some more strokes. Resize the window and scroll back and forth. Click the split box to split the window into two panes. With both panes displaying the same portion of the document, draw some strokes in one pane and see them reflected in the other one. »Figure 8.6« shows this version of Scribble.

Exit Scribble.

This completes step 4 of the tutorial. You now have a basic understanding of the view architecture provided by the Microsoft Foundation Class Library.

In Chapter 9, »Enhancing Printing«, you'll enhance Scribble's printing and print preview support.


 Chapter 9  Enhancing Printing

Scribble has supported printing and print preview ever since Chapter 4, »Creating the View,« when you first added application-specific code to the starter files created by AppWizard. All the printing and previewing functionality came essentially "for free." None of the code you added dealt specifically with printing; AppWizard and the framework did all the work for you.

While it's nice to get printing and print preview for free, Scribble's current printing support isn't perfect. For example, the printed image is smaller than you might like. In addition, the printed image is very plain; it doesn't include a header or footer. This chapter describes how to enlarge the printed image and implement printing enhancements in your application.

This chapter covers the following topics:

•	»The printing architecture« provided by the Microsoft Foundation Class Library.

•	»Using a metric mapping mode.«

•	»Dividing a document« into pages.

•	»Defining headers or footers.«

This chapter covers step 5 of Scribble. If you want to work along, adding the code as you go, begin with the files from Chapter 8, »Enhancing Views,« in your SCRIBBLE\MYSCRIB subdirectory. At this point, these files should closely resemble those in the SCRIBBLE\STEP4 subdirectory. As you read the chapter, add all the code that's marked with the symbol [image]. At the end, your files should closely resemble the files in the SCRIBBLE\STEP5 subdirectory.

If, on the other hand, you want to read along without adding code, you can print or examine the files in the SCRIBBLE\STEP5 subdirectory.


 How Default Printing Is Done

Recall how Scribble performs drawing on the screen. In Chapter 4 in »Scribble's View: Class CScribView« you saw that the CScribView class has a member function named OnDraw which contains all the drawing code. Notice that OnDraw takes a pointer to a CDC object as a parameter. That CDC object represents the device context to receive the image produced by OnDraw. When the window displaying the document receives a WM_PAINT message, the framework calls OnDraw and passes it a device context for the screen (a CPaintDC object, to be specific). Accordingly, OnDraw's output goes to the screen.

In programming for Windows, sending output to the printer is very similar to sending output to the screen. This is because the Windows graphics device interface (GDI) is hardware-independent; you can use the same GDI functions for screen display or for printing simply by using the appropriate device context. If the CDC object that OnDraw receives represents the printer, OnDraw's output goes to the printer.

This explains how Scribble can perform simple printing without requiring extra effort on your part. The framework takes care of displaying the Print dialog box and creating a device context for the printer. When you select the Print command from the File menu, the view passes this device context to OnDraw, which draws the document on the printer.

However, there are some significant differences between printing and screen display. When you print, you have to divide the document into distinct pages and display them one at a time, rather than display whatever portion is visible in a window. As a corollary, you have to be aware of the size of the paper (whether it's letter size, legal size, or an envelope). You may want to print in different orientations, such as landscape or portrait mode. The Microsoft Foundation Class Library can't predict how your application will handle these issues, so it provides a protocol for you to add these capabilities.


 The Printing Architecture

In an application built with the Microsoft Foundation Class Library, your view class and the framework cooperate in the printing process. Your view class has the following responsibilities:

•	Inform the framework how many pages are in the document.

•	When asked to print a specified page, draw that portion of the document.

•	Allocate and deallocate any fonts or other GDI resources needed for printing.

•	If necessary, send any escape codes needed to change the printer mode before printing a given page; for example, to change the printing orientation on a per-page basis.

The framework's responsibilities are as follows:

•	Display the Print dialog box.

•	Create a CDC object for the printer.

•	Call the StartDoc and EndDoc member functions of the CDC object.

•	Repeatedly call the StartPage member function of the CDC object, inform the view class which page should be printed, and call the EndPage member function of the CDC object.

•	Call overridables in the view at the appropriate times.

To print a multipage document, the framework and view interact in the following manner. First the framework displays the Print dialog box, creates a device context for the printer, and calls the StartDoc member function of the CDC object. Then, for each page of the document, the framework calls the StartPage member function of the CDC object, instructs the view object to print the page, and then calls the EndPage member function. If the printer mode must be changed before starting a particular page, the view object sends the appropriate escape code by calling the Escape member function of the CDC object. When the entire document has been printed, the framework calls the EndDoc member function.

The CView class defines several member functions that are called by the framework during printing. By overriding these functions in your view class, you provide the connections between the framework's printing logic and your view class's printing logic. The following table lists these member functions.

Table 9.1    CView's Overridables for Printing

Name	Reason for Overriding
OnPreparePrinting	To insert values in the Print dialog box, especially the length of the document.
OnBeginPrinting	To allocate fonts or other GDI resources.
OnPrepareDC	To adjust attributes of the device context for a given page, or to do print-time pagination.
OnPrint	To print a given page.
OnEndPrinting	To deallocate GDI resources.
You can do printing-related processing in other functions as well, but these functions are the ones that drive the printing process.

»Figure 9.1« illustrates the steps involved in the printing process and shows where each of CView's printing member functions are called. The following sections explain these steps in more detail.


 Pagination

The framework stores much of the information about a print job in an instance of the structure CPrintInfo. Several of the values in CPrintInfo pertain to pagination; these values are as shown in Table 9.2.

Table 9.2    Page Number Information Stored in CPrintInfo

Name(s)	Page Number Referenced
GetMinPage / SetMinPage	First page of document.
GetMaxPage / SetMaxPage	Last page of document.
GetFromPage	First page to be printed.
GetToPage	Last page to be printed.
m_nCurPage	Page currently being printing.
Page numbers start at 1; that is the first page is numbered 1, not 0. For more information about these and other members of CPrintInfo, see the Class Library Reference.

At the beginning of the printing process, the framework calls the view's OnPreparePrinting member function, passing a pointer to a CPrintInfo structure. AppWizard provides an implementation of OnPreparePrinting that calls DoPreparePrinting, another member function of CView. DoPreparePrinting is the function that displays the Print dialog box and creates a printer device context.

At this point the application doesn't know how many pages are in the document; it uses the default values 1 and 0xFFFF for the numbers of the first and last page of the document. If you know how many pages your document has, override OnPreparePrinting and call SetMaxPage for the CPrintInfo structure before you send it to DoPreparePrinting; this lets you specify the length of your document.

DoPreparePrinting then displays the Print dialog box; when it returns, the CPrintInfo structure contains the values specified by the user. If the user wishes to print only a selected range of pages, he or she can specify the starting and ending page numbers in the Print dialog box; the framework retrieves these values using the GetFromPage and GetToPage functions. If the user doesn't specify a page range, the framework calls GetMinPage and GetMaxPage and uses the values returned to print the entire document.

For each page of a document to be printed, the framework calls two member functions in your view class, OnPrepareDC and OnPrint, and passes each function two parameters: a pointer to a CDC object and a pointer to a CPrintInfo structure. Each time the framework calls OnPrepareDC and OnPrint, it passes a different value in the m_nCurPage member of the CPrintInfo structure. In this way the framework tells the view which page should be printed.

Recall that the OnPrepareDC member function is also used for screen display; it makes adjustments to the device context before drawing takes place. OnPrepareDC serves a similar role in printing, but there are a couple of differences: First, the CDC object represents a printer device context instead of a screen device context, and second, a CPrintInfo object is passed as a second parameter. (This parameter is NULL when OnPrepareDC is called for screen display.) Override OnPrepareDC to make adjustments to the device context based on which page is being printed; for example, you can move the viewport origin and the clipping region to ensure that the appropriate portion of the document gets printed.

The OnPrint member function performs the actual printing of the page. Earlier in this chapter, in the description of default printing in »How Default Printing Is Done«, you saw that the framework calls OnDraw with a printer device context to perform printing. More precisely, the framework calls OnPrint with a CPrintInfo structure and a device context, and OnPrint passes the device context to OnDraw. Override OnPrint to perform any rendering that should be done only during printing and not for screen display; for example, to print headers or footers (see "»Headers and Footers"« for more information). Then call OnDraw to do the rendering common to both screen display and printing.

The fact that OnDraw does the rendering for both screen display and printing means that your application is WYSIWYG: "What you see is what you get." However, suppose you aren't writing a WYSIWYG application. For example, consider a text editor that uses a bold font for printing but displays control codes to indicate bold text on the screen. In such a situation, you use OnDraw strictly for screen display. When you override OnPrint, substitute the call to OnDraw with a call to a separate drawing function. That function draws the document the way it appears on paper, using the attributes that you don't display on the screen.


 Printer Pages vs. Document Pages

When you refer to page numbers, it's sometimes necessary to distinguish between the printer's concept of a page and a document's concept of a page. From the point of view of the printer, a page is one sheet of paper. However, one sheet of paper doesn't necessarily equal one page of the document. For example, if you're printing a newsletter, where the sheets are to be folded, one sheet of paper might contain both the first and last pages of the document, side by side. Similarly, if you're printing a spreadsheet, the document doesn't consist of pages at all; instead, one sheet of paper might contain rows 1 through 20, columns 6 through 10.

All the page numbers in the CPrintInfo structure refer to printer pages, The framework calls OnPrepareDC and OnPrint once for each sheet of paper that will pass through the printer. When you override the OnPreparePrinting function to specify the length of the document, you must use printer pages. If there's a one-to-one correspondence (that is, one printer page equals one document page), then this is easy. If, on the other hand, document pages and printer pages do not directly correspond, you must translate between them. For example, consider printing a spreadsheet. When overriding OnPreparePrinting, you must calculate how many sheets of paper will be required to print the entire spreadsheet and then use that value when calling the SetMaxPage member function of CPrintInfo. Similarly, when overriding OnPrepareDC, you must translate m_nCurPage into the range of rows and columns that will appear on that particular sheet and then adjust the viewport origin accordingly.


 Print-Time Pagination

In some situations, your view class may not know in advance how long the document is until it has actually been printed. For example, suppose your application isn't WYSIWYG, so a document's length on the screen doesn't correspond to its length when printed.

This causes a problem when you override OnPreparePrinting for your view class: you can't pass a value to the SetMaxPage function of the CPrintInfo structure, because you don't know the length of a document. If the user doesn't specify a page number to stop at using the Print dialog box, the framework doesn't know when to stop the print loop. The only way to determine when to stop the print loop is to print out the document and see when it ends; your view class must check for the end of the document while it is being printed, and then inform the framework when the end is reached.

The framework relies on your view class's OnPrepareDC function to tell it when to stop. After each call to OnPrepareDC, the framework checks a member of the CPrintInfo structure called m_bContinuePrinting. Its default value is TRUE; as long as it remains so, the framework continues the print loop. If it is set to FALSE, the framework stops. To perform print-time pagination, override the OnPrepareDC to check whether the end of the document has been reached, and set  m_bContinuePrinting to FALSE when it has.

The default implementation of OnPrepareDC sets m_bContinuePrinting to FALSE if the current page is greater than 1. This means that if the length of the document wasn't specified, the framework assumes the document is one page long. One consequence of this is that you must be careful if you call the base class version of OnPrepareDC; do not assume that m_bContinuePrinting will be TRUE after calling the base class version.


 Headers and Footers

When looking at a document on the screen, the name of the document and your current location in the document are commonly displayed in a title bar and a status bar. When looking at a printed copy of a document, it's useful to have the name and page number shown in a header or footer. This is a common way in which even WYSIWYG programs differ in how they perform printing and screen display.

The OnPrint member function is the appropriate place to print headers or footers because it is called for each page, and because it is called only for printing, not for screen display. You can define a separate function to print a header or footer, and pass it the printer device context from OnPrint. You may need to adjust the window origin or extent before calling OnDraw to avoid having the body of the page overlap the header or footer. You might also have to modify OnDraw because the amount of the document that fits on the page could be reduced.

One way to compensate for the area taken by the header or footer is to use the m_rectDraw member of CPrintInfo. Each time a page is printed, this member is initialized with the usable area of the page. If you print a header or footer before printing the body of the page, you can reduce the size of the rectangle stored in m_rectDraw to account for the area taken by the header or footer. Then OnPrint can refer to m_rectDraw to find out how much area remains for printing the body of the page.

You cannot print a header, or anything else, from OnPrepareDC, because it is called before the StartPage member function of CDC has been called. At that point, the printer device context is considered to be at a page boundary. You can perform printing only from the OnPrint member function.


 Allocating GDI Resources for Printing

Suppose you need to use certain fonts, pens, or other GDI objects for printing, but not for screen display. Because of the memory they require, it's inefficient to allocate these objects when the application starts up; when the application isn't printing a document, that memory might be needed for other purposes. It's better to allocate them when printing begins, and then delete them when printing ends.

To allocate these GDI objects, override the OnBeginPrinting member function. This function is well suited to this purpose for two reasons: the framework calls this function once at the beginning of each print job and, unlike OnPreparePrinting, this function has access to the CDC object representing the printer device driver. You can store these objects for use during the print job by defining member variables in your view class that point to GDI objects (for example, CFont * members, etc.).

To use the GDI objects you've created, select them into the printer device context in the OnPrint member function. If you need different GDI objects for different pages of the document, you can examine the m_nCurPage member of the CPrintInfo structure and select the GDI object accordingly. If you need a GDI object for several consecutive pages, Windows requires that you select it into the device context each time OnPrint is called.

To deallocate these GDI objects, override the OnEndPrinting member function. The framework calls this function at the end of each print job, giving you the opportunity to deallocate printing-specific GDI objects before the application returns to other tasks.


 Enhance Scribble's Printing

Step 5 of Scribble adds the following printing capabilities to the program:

•	»Enlarging the printed image« to a more comfortable size.

•	»Paginating a Scribble document.«

•	»Adding a page header.«

The following sections describe these enhancements in detail.


 Enlarge the Printed Image

Recall from Chapter 8 in »Add Scrolling to Scribble« that when you specify a position for a GDI drawing function, you use logical coordinates. Chapter 8 described how CScrollView moves the origin of this coordinate system. You can also control the scale of this coordinate system, that is, the physical size of a logical unit. By default, GDI considers logical units to be equal to device units, meaning that 1 logical unit equals 1 pixel on the screen. This interpretation of logical units is called the MM_TEXT mapping mode.

Since Scribble uses the MM_TEXT mapping mode, it considers a stroke that is 100 units long to be 100 pixels long. The physical size of the stroke depends on the device that displays it. For example, a device unit on a typical laser printer is 1/300 of an inch, which is considerably smaller than a pixel on a typical screen. As a result, the images that Scribble produces on a printer are much smaller than those it displays on the screen.

To keep Scribble from producing tiny images on the printer, you need a mapping mode that ensures a drawing remains the same size no matter what device displays it. Windows provides several such mapping modes, known as "metric" mapping modes. In these modes, GDI considers logical units to be equal to real-world units (or "metrics"), such as millimeters or inches.

In step 5, Scribble changes to the MM_LOENGLISH mapping mode, which treats each logical unit as 0.01 inches. In this mode, a stroke that is 100 logical units long is drawn as 1 inch long, no matter which device is used; each device driver determines how many device units are needed to draw a 1-inch stroke.

Once Scribble uses the MM_LOENGLISH mode, all coordinates used for GDI drawing are in hundredths-of-an-inch, not pixels. As a result, the images that Scribble displays on the printer are the same size as the ones it displays on the screen. Recall that in Chapter 8 in »Add Scrolling to Scribble« a Scribble drawing was defined to be 800 logical units across and 900 logical units high; now a drawing is 8 inches across and 9 inches high.


 Specify the Mapping Mode

You must specify the mapping mode when you call the SetScrollSizes member function defined by CScrollView. Recall from Chapter 8 in »Add Scrolling to Scribble« that this function sets the view's scrolling limits. SetScrollSizes is called from the OnInitialUpdate member function of CScribView.

To specify the mapping mode

•	Launch the Visual Workbench and load the file SCRIBVW.CPP. Make the following modification:

void CScribView::OnInitialUpdate()

{

SetScrollSizes( MM_LOENGLISH, GetDocument()->GetDocSize() );

}

Recall that OnInitialUpdate is called immediately after the view is attached to the document. This lets the view set its mapping mode before OnDraw is called.


 Reversing the Sign of the Y-Coordinates

Another feature of the MM_LOENGLISH mode (as well as the other metric mapping modes) is that its y-axis runs in the opposite direction to that in MM_TEXT mode. In MM_TEXT mode, y-coordinates increase when you move down, but in all the metric mapping modes, y-coordinates increase when you move up.

Even though Scribble has changed the direction of the y-axis for drawing, most of the code doesn't require any modifications. This is because the DPtoLP function performs the conversion for you. Consider: when a point is received with a mouse message, its coordinates are converted by the DPtoLP function before being stored in a CStroke object. This means its y-coordinates are converted from a positive number of pixels to a negative number of inches. Those coordinates are then passed to the LineTo drawing function, and then it's up to the device driver for the screen to determine how many pixels are equivalent to the value that was passed in inches. You never have to directly examine the value of the coordinates.

However, there are some places where the reversal of the y-axis does have an impact. The mapping mode used by GDI is a characteristic of a device context; functions that don't use a device context are unaffected by the mapping mode. The member functions of the CRect class don't use the mapping mode; consequently, you must make some adjustments wherever Scribble uses CRect functions.

To compensate for the reversal of the y-axis

1.	First you must correct the way a bounding rectangle for a stroke is calculated. Load the file SCRIBDOC.CPP in Visual Workbench and make the following modifications to the FinishStroke member function of the CStroke class:

void CStroke::FinishStroke()

{

// ...

m_rectBounding = CRect(pt.x, pt.y, pt.x, pt.y);

for (int i=1; i < m_pointArray.GetSize(); i++)

{

// If the point lies outside of the accumulated bounding

// rectangle, then inflate the bounding rect to include it.

pt = GetPoint(i);

m_rectBounding.left 	= min(m_rectBounding.left, pt.x);

m_rectBounding.right	= max(m_rectBounding.right, pt.x);

m_rectBounding.top	= max(m_rectBounding.top, pt.y);

m_rectBounding.bottom	= min(m_rectBounding.bottom, pt.y);

}

// Add the pen width to the bounding rectangle.  This is needed

// to account for the width of the stroke when invalidating

// the screen.

m_rectBounding.InflateRect(CSize(m_nPenWidth,-(int)m_nPenWidth));

return;

}

When you inflate the top and bottom borders of the bounding rectangle to include each point, the direction in which the borders move is reversed. Also, the y-value of the pen width's sign is reversed before it is added to the bounding rectangle.

You also must make a correction when using the invalid rectangle. Recall that the OnDraw member function checks whether the invalid rectangle intersects the bounding rectangle for each stroke. The IntersectRect member function of CRect assumes that the bottom of a rectangle must have a larger y-coordinate than that of the top; it cannot find the intersection of two rectangles whose bottoms have smaller y-coordinates than their tops.

2.	In SCRIBVW.CPP, make the following modifications to the OnDraw member function of CScribView:

void CScribView::OnDraw(CDC* pDC)

{

CScribDoc* pDoc = GetDocument();

// Get the invalidated rectangle of the view, or in the case

// of printing, the clipping region of the printer dc.

CRect rectClip;

CRect rectStroke;

pDC->GetClipBox(&rectClip);

pDC->LPtoDP(&rectClip);

// Note: CScrollView::OnPaint() will have already adjusted the

// viewport origin before calling OnDraw(), to reflect the

// currently scrolled position.

// The view delegates the drawing of individual strokes to

// CStroke::DrawStroke().

for (POSITION pos = pDoc->GetFirstStrokePos(); pos != NULL; )

{

CStroke* pStroke = pDoc->GetNextStroke(pos);

rectStroke = pStroke->GetBoundingRect();

pDC->LPtoDP(&rectStroke);

if (!rectStroke.IntersectRect(&rectStroke, &rectClip))

continue;

pStroke->DrawStroke(pDC);

}

}

Both the invalidated rectangle and the bounding rectangle are converted to device coordinates (reversing the signs of their y-coordinates) before being tested for intersection.


 Paginate Scribble Documents

If Scribble allowed you to produce arbitrarily large drawings, it would make sense for the program to break up a drawing into pages by dividing it into a grid of m by n rectangles, the values of m and n being determined by the size of the drawing. However, Scribble supports drawings of only one size, and each one fits on a single page. To illustrate pagination, step 5 of Scribble prints each drawing as a two-page document: a title page, and the drawing itself.

To add pagination to Scribble

1.	Load the SCRIBVW.CPP file  in Visual Workbench and make the following additions to CScribView's OnPreparePrinting member function:

BOOL CScribView::OnPreparePrinting( CPrintInfo* pInfo )

{

pInfo->SetMaxPage(2);	// the document is two pages long:

// the first page is the title page

// the second page is the drawing

// default preparation

return DoPreparePrinting(pInfo);

}

This function specifies the length of the document by calling SetMaxPage for the pInfo parameter. Since all Scribble documents are two pages long, the function uses a numeric constant rather than a variable to represent the number of the last page of the document. The title page and the drawing page are numbered 1 and 2, respectively. Note that the function still retains a call to DoPreparePrinting at the end; this displays the Print dialog box and creates a device context for the printer.

2.	Load SCRIBVW.H in Visual Workbench and make the following changes to CScribView's class declaration:

class CScribView : public CScrollView

{

public:

// ...

virtual void OnUpdate( CView* pSender, LPARAM lHint = 0L,

CObject* pHint = NULL );

void PrintTitlePage(CDC* pDC, CPrintInfo* pInfo);

void PrintPageHeader(CDC* pDC, CPrintInfo* pInfo,

CString& strHeader);

virtual void OnPrint(CDC* pDC, CPrintInfo* pInfo);

// ...

}

To perform printing, CScribView overrides the OnPrint member function and defines two new helper functions: PrintTitlePage, which prints the title page, and PrintPageHeader, which prints a header on the drawing page.

3.	In SCRIBVW.CPP, after the OnEndPrinting member function, add the following definition of the OnPrint member function:

void CScribView::OnPrint(CDC* pDC, CPrintInfo* pInfo)

{

if (pInfo->m_nCurPage == 1)	 // page no. 1 is the title page

{

PrintTitlePage(pDC, pInfo);

return; // nothing else to print on page 1 but the page title

}

CString strHeader = GetDocument()->GetTitle();

PrintPageHeader(pDC, pInfo, strHeader);

// PrintPageHeader() subtracts out from the pInfo->m_rectDraw the

// amount of the page used for the header.

pDC->SetWindowOrg(pInfo->m_rectDraw.left,-pInfo->m_rectDraw.top);

// Now print the rest of the page

OnDraw(pDC);

}

The behavior of the OnPrint member function depends on which of the two pages is being printed. If the title page is being printed, OnPrint simply calls the PrintTitlePage function and then returns. If it's the drawing page, OnPrint calls PrintPageHeader to print the header and then calls OnDraw to do the actual drawing. Before calling OnDraw, OnPrint sets the window origin at the upper-left corner of the rectangle defined by m_rectDraw; this rectangle was reduced by PrintPageHeader to account for the size of the header. This keeps the drawing from overlapping the header.

Notice that the drawing itself isn't divided into multiple pages. Consequently, OnDraw never has to display just a portion of the drawing (for example, it never has to display the section that fits on a particular page without displaying the surrounding sections). Either the title page is being printed and OnDraw isn't called at all, or else the drawing page is being printed and OnDraw displays the entire drawing at once.

This also explains why CScribView doesn't override the OnPrepareDC member function: there's no need to adjust the viewport origin or clipping region depending on which page is being printed.

4.	In SCRIBVW.CPP, below your definition of OnPrint, define the PrintTitlePage member function as follows:

void CScribView::PrintTitlePage(CDC* pDC, CPrintInfo* pInfo)

{

// Prepare a font size for displaying the file name

LOGFONT logFont;

memset(&logFont, 0, sizeof(LOGFONT));

logFont.lfHeight = 75; //  3/4th inch high in MM_LOENGLISH

//  (1/100th inch)

CFont font;

CFont* pOldFont = NULL;

if (font.CreateFontIndirect(&logFont))

pOldFont = pDC->SelectObject(&font);

// Get the file name, to be displayed on title page

CString strPageTitle = GetDocument()->GetTitle();

// Display the file name 1 inch below top of the page,

// centered horizontally

pDC->SetTextAlign(TA_CENTER);

pDC->TextOut(pInfo->m_rectDraw.right/2, -100, strPageTitle);

if (pOldFont != NULL)

pDC->SelectObject(pOldFont);

}

The PrintTitlePage function uses m_rectDraw, which stores the usable drawing area of the page, as the rectangle in which the title should be centered.

Notice that PrintTitlePage declares a local CFont object to use when printing the title page. If you needed the font for the entire printing process, you could declare a CFont member variable in your view class, create the font in the OnBeginPrinting, and destroy it in EndPrinting. However, since Scribble uses the font for just the title page, the font doesn't have to exist beyond the PrintTitlePage function. When the function ends, the destructor is automatically called for the local CFont object.


 Add a Page Header

As mentioned earlier, CScribView defines the PrintPageHeader function, which is called by OnPrint before the drawing itself is printed.

To add a page header to the drawing

•	In SCRIBVW.CPP, define the PrintPageHeader member function as follows:

void CScribView::PrintPageHeader(CDC* pDC, CPrintInfo* pInfo,

CString& strHeader)

{

// Print a page header consisting of the name of

// the document and a horizontal line

pDC->TextOut(0,-25, strHeader);  // 1/4 inch down

// Draw a line across the page, below the header

TEXTMETRIC textMetric;

pDC->GetTextMetrics(&textMetric);

int y = -35 - textMetric.tmHeight;	// line 1/10th in. below text

pDC->MoveTo(0, y);	// from left margin

pDC->LineTo(pInfo->m_rectDraw.right, y); //  to right margin

// Subtract from the drawing rectangle the space used by header.

y -= 25; 	// space 1/4 inch below (top of) line

pInfo->m_rectDraw.top += y;

}

The PrintPageHeader member function prints the name of the document at the top of the page, and then draws a horizontal line separating the header from the drawing. It adjusts the m_rectDraw member of the pInfo parameter to account for the height of the header; recall that OnPrint uses this value to adjust the window origin before it calls OnDraw.


 The Print Preview Architecture

Print preview is somewhat different from screen display and printing because, instead of directly drawing an image on a device, the application must simulate the printer using the screen. To accommodate this, the Microsoft Foundation Class Library defines a special class derived from CDC, called CPreviewDC. All CDC objects contain two device contexts, but usually they are identical. In a CPreviewDC object, they are different: the first represents the printer being simulated, and the second represents the screen on which output is actually displayed.

When you select the Print Preview command from the File menu, the framework creates a CPreviewDC object. Whenever your application performs an operation that sets a characteristic of the printer device context, the framework also performs a similar operation on the screen device context. For example, if your application selects a font for printing, the framework selects a font for screen display that simulates the printer font. Whenever your application would send output to the printer, the framework instead sends the output to the screen.

Print preview also differs from printing in the order each draws the pages of a document. During printing, the framework continues a print loop until a certain range of pages have been rendered. During print preview, one or two pages are displayed at any time, and then the application waits; no further pages are displayed until the user responds. During print preview, the application must also respond to WM_PAINT messages, just as it does during ordinary screen display.

The OnPreparePrinting function is called when preview mode is invoked, just as it is at the beginning of a print job. The CPrintInfo structure passed to the function contains several members whose values you can set to adjust certain characteristics of the print preview operation. For example, you can set the m_nNumPreviewPages member to specify whether you want to preview the document in one-page or two-page mode.

If you know how long the document is and called SetMaxPage with the appropriate value, the framework can use this information in preview mode as well as during printing. Once the framework knows the length of the document, it can provide the preview window with a scroll bar, allowing the user to page back and forth through the document in preview mode. If you haven't set the length of the document, the framework cannot position the scroll box to indicate the current position, so the framework doesn't add a scroll bar. In this case, the user must use the Next Page and Previous Page buttons on the preview window's control bar to page through the document.

For print preview, you may find it useful to assign a value to the m_nCurPage member of CPrintInfo, even though you would never do so for ordinary printing. During ordinary printing, this member carries information from the framework to your view class; this is how the framework tells the view which page should be printed.

By contrast, when print preview mode is started, the m_nCurPage member carries information in the opposite direction: from the view to the framework. The framework uses the value of this member to determine which page should be previewed first. The default value of this member is 1, so the first page of the document is displayed initially. You can override OnPreparePrinting to set this member to the number of the page being viewed at the time the Print Preview command was invoked. This way, the application maintains the user's current position when moving from normal display mode to print preview mode.

Sometimes you may want OnPreparePrinting to perform different initialization depending on whether it is called for a print job or for print preview. You can determine this by examining the m_bPreview member variable in the CPrintInfo structure; this member is set to TRUE when print preview is invoked.

The CPrintInfo structure also contains a member named m_strPageDesc, which is used to format the strings displayed at the bottom of the screen in single-page and multiple-page modes. By default these strings are of the form "Page n" and "Pages n - m," but you can modify m_strPageDesc from within OnPreparePrinting and set the strings to something more elaborate. See CPrintInfo in the Class Library Reference for more information.


 Enhance Scribble's Print Preview

The default print preview capabilities are almost sufficient for Scribble's needs. To some extent, Scribble's print preview has already been enhanced when the printing capabilities were enhanced. Recall that in the override of OnPreparePrinting you called the SetMaxPages function to specify the length of Scribble documents. This allows the framework to add a scroll bar to the preview window.

Another enhancement you can make is to change the number of pages displayed when preview mode is invoked.

To set the number of pages displayed in preview mode

•	In SCRIBVW.CPP, add the following line to the OnPreparePrinting member function:

BOOL CScribView::OnPreparePrinting( CPrintInfo* pInfo )

{

pInfo->SetMaxPage(2);	//  the document is two pages long:

//  the first page is the title page

//  the second page is the drawing

BOOL bRet = DoPreparePrinting (pInfo);	  // default preparation

pInfo->m_nNumPreviewPages = 2;	//Preview 2 pages at a time

// Set this value after calling DoPreparePrinting to override

// value read from .INI file

return bRet:

}

The line added here assigns the value 2 to m_nNumPreviewPages. This causes Scribble to preview both pages of the document at once: the title page (page 1) and the drawing page (page 2). Note the value for m_nNumPreviewPages must be assigned after calling DoPreparePrinting, because DoPreparePrinting sets m_nNumPreviewPages to the number of preview pages used the last time the program was executed; this value is stored in the application's .INI file.


Compile Scribble  Step 5 Version
 Compile Scribble − Step 5 Version

What does Scribble's printing look like now? Compile the new version of Scribble and find out.

To compile Scribble

•	From the Project menu in Visual Workbench, choose the Build command.

Run the new version of Scribble. Draw some strokes, and then choose the File Print Preview command. Switch back and forth between one-page and two-page display mode, or move to the previous or next page. »Figure 9.2« shows this version of Scribble.

Exit Scribble.

This completes step 5 in the tutorial. You now have a basic understanding of the printing architecture provided by the Microsoft Foundation Class Library.

In Chapter 10, »Adding Context-Sensitive Help«, you'll add context-sensitive help to Scribble.


 Chapter 10  Adding Context-Sensitive Help

So far, thanks to the Microsoft Foundation Class Library, Scribble implements a number of common user-interface features, such as print preview and splitter windows. To conclude the tutorial, this chapter adds another such feature to Scribble: context-sensitive Windows Help.

Note  To complete this chapter, the Windows Help Compiler, which is shipped with Microsoft Visual C++ Professional Edition as an executable file, must be in your path.

Scribble already offers the user some help in the form of prompt strings displayed in the status bar. When the user navigates through a menu using the UP ARROW and DOWN ARROW keys, or uses the mouse to press a toolbar button, Scribble displays a brief description of the command's purpose in the status bar (if the status bar is visible). The framework easily supplies this level of information for commands predefined by the class library. And, as you did in Chapter 5 in »Examining and Editing Resources«, you can add prompts to the menu items you create in App Studio by filling in a field in the menu's property page. Since prompts are attached to command IDs, Scribble's toolbar buttons, which duplicate commands on the menus, automatically invoke the appropriate prompts.

The level of help described in this chapter, however, goes much further. The user can open Windows Help for your application from the Help menu or invoke context-sensitive help by pressing the F1 key or SHIFT+F1.

This chapter explains how to implement:

•	F1 help

•	SHIFT+F1 help mode

•	Help menu support

The next section, »Division of Labor«, describes the three kinds of help listed here, and explains which functions are provided by the framework and which you must implement.

For a quick preview of how easy it is to add context-sensitive help to your application, follow the instructions described in »See Context-Sensitive Help in Action«. In that section, you'll create a new application with AppWizard, build the application, and then run it to see the help features you get without adding a single line of code.

The chapter also shows how to add an AppWizard option to your program in »Adding Help After the Fact« if you didn't select the option when you originally created your application.

For an overview of the framework's help support, see Chapter 5 in the Class Library Reference.

Note  You can freely use the help files that AppWizard creates in your applications and freely ship the compiled help.

This chapter covers step 6 of Scribble. Unlike previous steps, the STEP6 subdirectory does not contain the complete source files for this step — it includes only a help source file named PEN.RTF. If you want to see the results of this step, you must follow the directions presented in this chapter, starting with the STEP5 source files.


 Division of Labor

To support help, the framework:

•	Handles F1 help.

With an active window, dialog box, or message box, or with a menu item or toolbar button selected, the user can press the F1 key to summon specific help about the selected item.

For menu items, help is summoned for the item currently highlighted. For toolbar buttons, the user can use the mouse to press the button and press F1 before letting the button up.

You can define a key other than F1 for help, but it is common among applications for Windows to use F1.

•	Handles SHIFT+F1 help mode.

At any time the application is active, the user can press SHIFT+F1 to put the application into a "help mode." The cursor changes to a help cursor: an arrow beside a question mark.

While the application is in help mode, clicking any window, dialog box, message box, menu item, or toolbar button summons specific help about the item. Selecting any item for help ends help mode and displays help. Pressing the ESCAPE key or switching to another application and back also ends help mode.

The standard toolbar provided by AppWizard also has a button through which the user can invoke help mode. The graphic on the button resembles the help cursor.

You can define a key combination other than SHIFT+F1, but it is common among applications for Windows to use SHIFT+F1.

•	Provides the Index and Using Help commands on the Help menu.

The Index command causes Windows Help to display an index to the available help topics. The Using Help command causes Windows Help to display information on using Windows Help.

•	Provides a starter set of files in Rich-Text Format (RTF) containing standard help topics.

These include commands on standard menus such as File and Edit, standard information on using help, standard keyboard shortcuts, a standard help index, and more.

To take advantage of this support for help:

•	Use the AppWizard Context-Sensitive Help option.

•	Write your application-specific help topics in the .RTF files.

Fill in application-specific details in these help topics, add new topics, and delete unused topics.

•	Provide finer-grained context-sensitive help, if desired.

Fine-tune help further by overriding portions of the class library to support more specific help contexts, such as individual controls in a dialog box. For more information about fine-tuning context-sensitive help, see Technical Note 28 in \MSVCNT\HELP\MFCNOTES.HLP.


 Implementing Context-Sensitive Help with AppWizard

Use AppWizard to enable the framework's support for context-sensitive help and the Help menu. The following sections explain how to select this support in AppWizard and what AppWizard creates as a result.


 The Context-Sensitive Help Option

When you first create a new application with AppWizard, be sure to select the Context-Sensitive Help option if you plan to support help.

To select context-sensitive help

1.	In AppWizard, choose the Options button.

2.	To select the Context-Sensitive Help option, click the Context-Sensitive Help check box.

»Figure 10.1« shows the Options dialog box in AppWizard with Context-Sensitive Help selected.

3.	Select any other options you need.

4.	Choose the OK button.

5.	Complete your AppWizard session and choose the OK button in the main AppWizard dialog box.

When AppWizard creates your skeleton application, it adds the following items:

•	Message-map entries in your derived application class for handler functions to handle Help menu items and F1 and SHIFT+F1 help. These handlers are predefined by the framework.

•	Index and Using Help items in the menu definitions.

•	Status-bar command prompts for the help items. These appear when the user clicks the mouse in one of the menu commands.

•	A batch file called MAKEHELP.BAT that you can use to compile your help.

•	A Windows Help project file with a .HPJ extension. It's named for your project.

•	One or more RTF-format files (.RTF extension) containing standard help contexts. Add application-specific help contexts to these files to customize your help. For more information, see »Editing Scribble's Help Topics«.

•	Several bitmap files (.BMP extension) used in the help files.

You can then use the items created by AppWizard, add a few extra steps, and build your help file. These steps are described in later sections.

Note  Help project files and Windows Help tools are explained in Programming Tools for the Microsoft Windows Operating System.


 The Message Map

To support the Help menu commands, F1 help, and SHIFT+F1 help, AppWizard adds five entries to the message map for your CWinApp-derived application class. This message map is in the .CPP file named for your project. When you complete the steps outlined in »Adding Help After the Fact«, the message map for class CScribbleApp will look like the following:

// CScribbleApp

BEGIN_MESSAGE_MAP(CScribbleApp, CWinApp)

//{{AFX_MSG_MAP(CScribbleApp)

ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

// NOTE - the ClassWizard will add and remove mapping macros here.

//	DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_MSG_MAP

// Standard file based document commands

ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)

ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

// Standard print setup command

ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)

// Global help commands

ON_COMMAND(ID_HELP_INDEX, CWinApp::OnHelpIndex)

ON_COMMAND(ID_HELP_USING, CWinApp::OnHelpUsing)

ON_COMMAND(ID_HELP, CWinApp::OnHelp)

ON_COMMAND(ID_CONTEXT_HELP, CWinApp::OnContextHelp)

ON_COMMAND(ID_DEFAULT_HELP, CWinApp::OnHelpIndex)

END_MESSAGE_MAP()

The five help-related message map entries follow the comment // Global help commands. Table 10.1 explains the purpose of each command ID used in these entries.

Table 10.1    Help-Related Command IDs

Command ID	Purpose
ID_HELP_INDEX	Responds to the Index item on the Help menu by displaying the Windows Help index.
ID_HELP_USING	Responds to the Using Help item on the Help menu by displaying information about using Windows Help.
ID_HELP	Responds to F1 by displaying a specific topic in Windows Help.
ID_CONTEXT_HELP	Responds to SHIFT+F1 by putting the application into help mode.
ID_DEFAULT_HELP	Used when a specific help context cannot be found.
Notice that all of these commands are mapped to member functions of class CWinApp. Unlike most of the other commands you place into the message map, these have handler functions predefined by the class library. Making the message-map entry enables the command.

The application's accelerator table defines F1 for ID_HELP and SHIFT+F1 for ID_CONTEXT_HELP. You can change the keys used for these help functions by using App Studio to change the key values in the accelerator table.


 The Help Project File

AppWizard also creates several help-related files in your project directory, including a help project file (.HPJ extension).

The help project file provides coordinating information used by the Windows Help Compiler. When you complete the steps outlined in »Adding Help After the Fact«, Scribble's help project file, SCRIBBLE.HPJ, will look like the following:

[OPTIONS]

CONTENTS=main_index

TITLE=SCRIBHLP Application Help

COMPRESS=true

WARNING=2

[FILES]

hlp\afxcore.rtf

hlp\afxprint.rtf

[BITMAPS]

; toolbar buttons for File commands

hlp\filenew.bmp

hlp\fileopen.bmp

hlp\fileprnt.bmp

hlp\filesave.bmp

; toolbar buttons for Edit commands

hlp\editcopy.bmp

hlp\editcut.bmp

hlp\editpast.bmp

hlp\editundo.bmp

...

[ALIAS]

HIDR_MAINFRAME = main_index

HIDR_SCRIBHTYPE = HIDR_DOC1TYPE

HIDD_ABOUTBOX = HID_APP_ABOUT

HID_HT_SIZE = HID_SC_SIZE

HID_HT_HSCROLL = scrollbars

HID_HT_VSCROLL = scrollbars

HID_HT_MINBUTTON = HID_SC_MINIMIZE

HID_HT_MAXBUTTON = HID_SC_MAXIMIZE

AFX_HIDP_INVALID_FILENAME   = AFX_HIDP_default

AFX_HIDP_FAILED_TO_OPEN_DOC = AFX_HIDP_default

...

[MAP]

#include <C:\MSVCNT\MFC\include\afxhelp.hm>

#include <hlp\scribble.hm>

This file describes options used by the Windows Help Compiler, topic files with the .RTF extension to be included in the help build, bitmap files to be included in the build, a mapping of context strings to context numbers, and more.

Of particular interest is the [MAP] section, which in this example points to two included files with the .HM (help mapping) extension. The next section, »The MAKEHELP.BAT File,« explains more about help-context mapping. For more information about Windows Help project files, see Programming Tools for the Microsoft Windows Operating System.


 The MAKEHELP.BAT File

In Windows Help, a "help context" consists of a string and a number. The help context string is what the help text author uses to identify help topics. The help context number is what the programmer uses to identify help topics. Help author and programmer come together in the [MAP] section of the .HPJ file, which associates the help context string and number. When your application calls Windows Help, Windows Help uses the context your application passes to locate and display the help topic denoted by that context. At run time, the framework manages supplying the appropriate help context.

To facilitate relating the windows, dialog boxes, and commands in your application to Windows Help contexts, the Microsoft Foundation Class Library provides the MAKEHM.EXE tool, which creates the information used in the [MAP] section of the .HPJ file.

AppWizard creates a MAKEHELP.BAT file that you'll use to compile your help. MAKEHELP.BAT calls MAKEHM.EXE and then the Windows Help Compiler.

When you use App Studio to create dialog-template resources, menu commands, and the like, App Studio writes #define statements in a file named RESOURCE.H (by default). For example, there might be #define statements for such symbols as IDD_MY_DIALOG and ID_PEN_WIDTHS. For more information about how App Studio adds symbols to RESOURCE.H and how you can view and manipulate them with App Studio's Symbol Browser, see Chapter 2 in the App Studio User's Guide.

When you run MAKEHELP.BAT from the MS-DOS® command line, it calls the MAKEHM tool to map the #define statements in RESOURCE.H to Windows Help strings in a .HM file. The MAKEHM tool collects #define statements from RESOURCE.H and uses an algorithm to map defined symbols to help strings in a .HM file. For the example IDs in the previous paragraph, it would create help strings such as HIDD_MY_DIALOG and HID_PEN_WIDTHS. These context strings are formed by prefixing an "H" to the symbol found in RESOURCE.H. The algorithm also maps the ID's numeric value to a corresponding number for the help context. An example is shown in section »Help Contexts in Scribble«.

When MAKEHELP.BAT then runs the Windows Help Compiler, the compiler uses the .HM files pointed to by the .HPJ file to set up the help contexts in your new help file. Once you finish compiling your .HLP file, you can use it from your application.

For more information about MAKEHELP.BAT and MAKEHM.EXE, see the section "Context-Sensitive Help" in Chapter 5 of the Class Library Reference.


 See Context-Sensitive Help in Action

It isn't necessary to follow the steps described in, »Adding Help After the Fact,« to try out the help support provided by the framework and AppWizard. You can try it out now.

To give the help support a try

1.	Run AppWizard with the help option selected.

When you run AppWizard, specify a project named MYHELP with a path of MFC\SAMPLES\SCRIBBLE\MYHELP. Select the Context-Sensitive Help option in the Options dialog box. AppWizard creates help-related files for the new application.

2.	Build the MYHELP application.

It's not necessary to modify any of the code created by AppWizard. Simply build the MYHELP application that AppWizard just created.

3.	Run MAKEHELP.BAT from the MS-DOS command line to build the .HLP file.

As the Windows Help Compiler runs, it prints a row of dots on the screen.

Run the MYHELP application and try out various help options. Here are some suggestions for what to try:

•	Choose Using Help from the Help menu. See the standard help provided by WINHELP's own help file.

•	Choose Index from the Help menu. See the standard main help topic that AppWizard has prepared. It describes the standard menus that the framework provides.

•	Click the help-mode button on the toolbar, which appears as an arrow beside a question mark. To get help for a menu item, drop down a menu and click a menu item with the mouse. Click the help-mode button again and then click another toolbar button. Finally, enter help mode again by pressing the SHIFT+F1 keys; then click the toolbar itself, or a window's title bar, or some other element of MyHelp's user interface.

•	Using the keyboard, drop down a menu and select a menu item using the DOWN ARROW key. Then press the F1 key to get help for the selected item.

Thanks to AppWizard and the framework, you — and your users — get all of this help essentially for free.


 Adding Help to Scribble

The normal way to add help to an application is to select the Context-Sensitive Help option when you first run AppWizard, as just described in »Implementing Context-Sensitive Help with AppWizard.« However, to simplify the previous chapters this was not done in Scribble step 0, so it's necessary to add the option after the fact.


 Adding Help After the Fact

This section explains how to add context-sensitive help at a later stage of program development. The general procedures apply to any AppWizard option.

Merging context-sensitive help support into Scribble at this late stage requires several general steps. Each step is explained in more detail below. The overall steps are:

The idea is to create a starter application as in Chapter 2 in »Create the Starter Application for Scribble« that this time has the help-related files and code.

2.	Copy resources from the MYHELP application to Scribble. See the procedure »To Copy Resources to Scribble« later in this section.

You'll use App Studio to copy the resources.

3.	Copy help-related code from the MYHELP application to Scribble. See the procedure »To Copy Help-Related Code to Scribble« later in this section.

You'll use the Visual Workbench editor (or any text editor) to copy the code.

4.	Copy help-related files from the MYHELP directory to your MYSCRIB directory. See the procedure »To Copy Help-Related Files to MYSCRIB« later in this section.

5.	Build the new version of Scribble and compile its help file. See the procedure »To Complete Scribble's Help« later in this section.

To create a new MYHELP application

•	If you haven't done so already, run AppWizard to create a new MYHELP application, as described in »See Context-Sensitive Help in Action«.

It's unnecessary to build the MYHELP application. You're about to borrow code and resources from this application for Scribble.

The Scribble end of this procedure begins with the files fromChapter 9 (step 5) in your MYSCRIB directory. If you have not done the tutorial step in »Chapter 9,« you can copy all of the files and subdirectories in the MFC\SAMPLES\SCRIBBLE\STEP5 subdirectory to your MYSCRIB directory.

To perform the steps in the next procedure, you'll use App Studio's menu, accelerator, and string editors. These editors are explained in Chapters 4, 5, and 6, respectively, in the App Studio User's Guide.

To copy resources to Scribble

1.	Run App Studio and open the resource files for both MYSCRIB and MYHELP.

You're about to copy menu items, accelerator keys, and status-bar prompt strings from MYHELP to MYSCRIB. As you do this, you'll not only learn about adding help to an application after the fact, you'll also learn how easy it is to copy resources from one resource file to another using App Studio. Note that because Scribble is an MDI application, it has two sets of menus, identified by the IDs IDR_MAINFRAME and IDR_SCRIBTYPE. You'll copy menus from both sets.

2.	Use the App Studio menu editor to open menus from both resource files.

Arrange the menu editor windows so they don't overlap.

3.	Drop down both Help menus.

4.	Click on the separator below the Using Help item in MYHELP's Help menu. Then hold down the SHIFT key and click on the Index and Using Help items. Release the SHIFT key.

This selects the separator and the two menu items.

5.	Hold down the CTRL key, click on the highlighted menu items, and drag them to the Help menu in MYSCRIB, above the About Scribble menu item. Release the mouse button and the CTRL key. Repeat steps 2 through 5 for the IDR_MAINFRAME menu resources. Copy the same menu items from MYHELP to MYSCRIB.

The menu items and the separator are copied to Scribble.

6.	Use the App Studio accelerator editor to copy the accelerator keys F1 and SHIFT+F1 for the ID_HELP command and the ID_CONTEXT_HELP command, respectively.

The copying procedure is similar to copying menus. To copy the two accelerators, hold down the SHIFT key while selecting them. Then hold down the CTRL key while dragging the accelerators to the new window.

7.	Use the App Studio string editor to (a) delete the existing AFX_IDS_IDLEMESSAGE string from string segment 0 in MYSCRIB, and (b) copy the following status-bar prompt strings to MYSCRIB: AFX_IDS_IDLEMESSAGE, AFX_IDS_HELPMODEMESSAGE, ID_HELP_INDEX, ID_CONTEXT_HELP, ID_HELP_USING, and ID_HELP.

The copying procedure is similar to the procedures for copying menus and accelerators. To delete a string, select it in the string editor and choose the Delete button. To copy several strings, hold the SHIFT key down while selecting the strings. Then hold the CTRL key down while dragging the selected strings to the new window.

For an application without help, AppWizard defines the default status-bar prompt to be "Ready". This is the string that is displayed in the status bar when no other command prompt is being displayed. This string is identified as AFX_IDS_IDLEMESSAGE.

The other strings are command prompts for the Index and Using Help commands on the Help menu and for F1 and SHIFT+F1 help.

8.	Save the MYSCRIB resource file, SCRIBBLE.RC. You can close App Studio if you wish.

To copy help-related code to Scribble

1.	Copy the help-related entries in the message map for class CMyhelpApp to the corresponding message map in class CScribbleApp.

Using the Visual Workbench editor, open MYHELP.CPP and SCRIBBLE.CPP. Copy the help-related lines, marked with the [image] symbol, from the message map in MYHELP.CPP and paste them into the same position in the message map in SCRIBBLE.CPP. The message map looks like the following:

// CMyHelpApp

BEGIN_MESSAGE_MAP(CMyhelpApp, CWinApp)

//{{AFX_MSG_MAP(CMyhelpApp)

ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

// NOTE - the ClassWizard will add and remove mapping

// macros here.

//	DO NOT EDIT what you see in these blocks of

//	generated code !

//}}AFX_MSG_MAP

// Standard file based document commands

ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)

ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

// Standard print setup command

ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)

// Global help commands

ON_COMMAND(ID_HELP_INDEX, CWinApp::OnHelpIndex)

ON_COMMAND(ID_HELP_USING, CWinApp::OnHelpUsing)

ON_COMMAND(ID_HELP, CWinApp::OnHelp)

ON_COMMAND(ID_CONTEXT_HELP, CWinApp::OnContextHelp)

ON_COMMAND(ID_DEFAULT_HELP, CWinApp::OnHelpIndex)

END_MESSAGE_MAP()

2.	Enable the help-mode toolbar button.

AppWizard includes a toolbar button for help mode in the toolbar bitmap regardless of whether you choose the help option. This button did not appear on the screen when you ran previous versions of Scribble because the button was not mapped to any command in the buttons array defined in the MAINFRM.CPP file. The help-mode button has the rightmost position in the toolbar. Up to now there was one less entry in the buttons array than there were buttons in the toolbar bitmap.

To expose the help-mode button, add the command ID_CONTEXT_HELP to the end of the list of commands in the buttons array in the MAINFRM.CPP file for Scribble. Add the line marked with the [image] symbol in the left margin, as shown in this code:

// toolbar buttons - IDs are command buttons

static UINT BASED_CODE buttons[] =

{

// same order as in the bitmap 'toolbar.bmp'

ID_FILE_NEW,

ID_FILE_OPEN,

ID_FILE_SAVE,

ID_SEPARATOR,

ID_EDIT_CUT,

ID_EDIT_COPY,

ID_EDIT_PASTE,

ID_SEPARATOR,

ID_PEN_THICK_OR_THIN,

ID_SEPARATOR,

ID_FILE_PRINT,

ID_APP_ABOUT,

ID_CONTEXT_HELP,

};

To copy help-related files to MYSCRIB

1.	Copy the MAKEHELP.BAT and MYHELP.HPJ files from the MYHELP directory to the MYSCRIB directory.

2.	In the MYSCRIB directory, rename MYHELP.HPJ as SCRIBBLE.HPJ.

3.	In the copy of MAKEHELP.BAT in the MYSCRIB directory, change all occurrences of the string "myhelp" to "scribble."

4.	In SCRIBBLE.HPJ, make the following changes:

•	Under the [FILES] section, add the line

hlp\pen.rtf

The source and purpose of the new file PEN.RTF is explained below.

•	Under the [OPTIONS] section, change "CONTENTS=main_index" to "CONTENTS=new_index."

The new help topic source file, PEN.RTF, will replace the main help topic that AppWizard originally created.

•	Under the [ALIAS] section, change the string "HIDR_MAINFRAME = main_index" to "HIDR_MAINFRAME = new_index."

•	Also under the [ALIAS] section, change "HIDR_MYHELPTYPE" to "HIDR_SCRIBTYPE."

•	Replace all occurrences of the string "myhelp" with "scribble."

5.	Create a subdirectory called HLP in your MYSCRIB directory. Copy all files in the directory MYHELP\HELP to your MYSCRIB\HLP directory. This includes several .RTF files and a number of .BMP files.

6.	Copy the PEN.RTF and README.TXT files from the MFC\SAMPLES\SCRIBBLE\STEP6 directory to MYSCRIB\HLP.

PEN.RTF and README.TXT contain help topics specific to Scribble's Pen menu. The remaining sections of this chapter show you some of the contents of this .RTF file and explain how you would author the help topics using a program that can edit .RTF files, such as Microsoft Word for Windows.

Note that the only file provided in the MFC\SAMPLES\SCRIBBLE\STEP6 directory is PEN.RTF.

To complete Scribble's help

1.	Run MAKEHELP.BAT to compile your help file.

2.	Compile Scribble and test its various help features.

Once you have successfully built Scribble and compiled its help file, run your new version of Scribble and try out its context-sensitive help.

To try out Scribble's help

1.	Press the SHIFT+F1 keys to enter help mode then click one of the items on Scribble's Pen menu.

You'll see the custom help that has been provided in PEN.RTF.

2.	Select the Index command on the Help menu to see Scribble's custom help index.

Now that you've seen Scribble's help, it's time to examine some of the elements that make it work.


 Help Contexts in Scribble

By step 6, Scribble has already defined a number of new IDs (symbols). The following lists Scribble's RESOURCE.H file at this stage:

//{{NO_DEPENDENCIES}}

// App Studio generated include file.

// Used by SCRIBBLE.RC

//

#define IDR_MAINFRAME                  1

#define IDR_SCRIBTYPE                  2

#define IDD_ABOUTBOX                   100

#define IDD_PEN_WIDTHS                 101

#define ID_PEN_THICK_OR_THIN           1001

#define ID_PEN_WIDTHS                  1002

#define IDC_THIN_PEN_WIDTH             1000

#define IDC_THICK_PEN_WIDTH            1001

#define IDC_DEFAULT_PEN_WIDTHS         1002

Newly defined symbols include IDR_SCRIBTYPE (Scribble's menus and other application-specific resources), IDD_PEN_WIDTHS (the Pen Widths dialog box added in »Modifying the Controls Properties« in Chapter 7), ID_PEN_THICK_OR_THIN (the Thick Line command added in »Add Scribble's Pen Menu« in Chapter 5), and so on. Notice that the ID_EDIT_CLEAR_ALL command ID doesn't appear in RESOURCE.H because it's a predefined ID in the class library.

MAKEHM will map these symbols to Windows help contexts when you run MAKEHELP.BAT. After you run MAKEHLP.BAT, the SCRIBBLE.HM file looks like the following:

// MAKEHELP.BAT generated Help Map file.  Used by scribble.HPJ.

// Commands (ID_* and IDM_*)

HID_PEN_THICK_OR_THIN    0x103E9

HID_PEN_WIDTHS           0x103EA

// Prompts (IDP_*)

// Resources (IDR_*)

HIDR_MAINFRAME           0x20001

HIDR_SCRIBTYPE           0x20002

// Dialogs (IDD_*)

HIDD_ABOUTBOX            0x20064

HIDD_PEN_WIDTHS          0x20065

// Frame Controls (IDW_*)

This file contains help contexts for two commands, two resources (menus and other application resources), and two dialog boxes.

Given these files and the framework's help support, the one task remaining is to edit Scribble's .RTF files to add these topics.


 Editing Scribble's Help Topics

The framework manages navigation from application user interfaces to help contexts. Implementing further navigation within the help file is the domain of help authoring rather than programming. The purpose of this section is to describe the general process of authoring and editing help topic files.

Editing the help topics for Scribble is too big a task to work through in just one chapter, however a few examples will help you get started. The examples in this chapter were edited with Microsoft Word for Windows, but you can use any application that can edit RTF-format files.

The .RTF files that AppWizard creates contain starter help topics for many elements of the Windows user interface. Some of them are fairly complete, while others are skeletal and must be filled out.

If you want to customize the help topics supplied by AppWizard, you must do the following, using all of the .RTF files in MYSCRIB\HLP:

•	Globally replace the string "<<YourApp>>" in the .RTF files with the name of the application: "Scribble". This string is a placeholder.

»Figure 10.2« shows one place where the string "<<YourApp>>" has been replaced by the string "Scribble".

•	From the help topics, remove any references to menu items absent in Scribble.

For example, file PEN.RTF contains a topic for the Edit Links command, which Scribble doesn't support.

•	Replace the helpful directives in the help topics with your own information. These directives are bracketed by << and >> symbols.

Notice that because the class library predefines ID_EDIT_CLEAR_ALL, file PEN.RTF already contains a help topic for the Clear All command that you added to the Edit menu as described in »Add the Clear All Command to Scribble's Edit Menu« in Chapter 5 and »Bind Scribble's Clear All Command« in Chapter 6. However, its skeletal directive, "<< Write application-specific help here. >>," needs to be replaced with a real description.

•	Add topics for Scribble's new commands and its dialog box.

Examine the listing of RESOURCE.H in the previous section, »Help Contexts in Scribble«. It lists the following help topics:

•	Two resource-related HIDs (HIDR_ ), for menus and related resources.

•	Two dialog-box HIDs (HIDD_ ), for the About and Pen Widths dialog boxes.

•	Two command HIDs (HID_ ), for the Thick Line and Pen Widths commands.

New help topics are needed for the Pen Widths dialog box (About already has a topic in PEN.RTF) and for the two commands.

Help topics in an .RTF file are separated by hard page breaks. Each topic has a name and a "footnote" symbol (#).

The footnote symbol # identifies context strings. Other possible footnote symbols identify keywords for searching (K) and topic names ($). Topic text can contain "popups" and "jumps." A popup displays a small window with extra information when its "hot spot" is clicked. A jump takes the user to another topic screen in the help system when its button is clicked. Hot spots for popups and jumps are text strings with special formatting. For more information, see Programming Tools for the Microsoft Windows Operating System. If you're using Word for Windows for .RTF files, you can examine the file PEN.RTF with hidden text displayed.


 Example Topics

To illustrate the process of adding topics, this section shows the structure needed for a user to jump from the main index screen in help to a screen showing general information about the new Pen menu, and from there to screens that describe the two Pen menu commands. These items are added to the PEN.RTF file.

The Main Index Screen

»Figure 10.2« shows the main index screen as it appears in compiled help. This is what the screen looks like after the Pen menu entry has been added.

»Figure 10.3« shows the help topic for the main index screen as it appears in Microsoft Word for Windows (with hidden text displayed). The screen contains entries for six menus: File, Edit, View, Pen, Window, and Help. The Pen menu is Scribble-specific, so this jump has been added. The others are created by AppWizard.

Each of the menu names on this screen is a "hot spot" that links to another topic. By clicking this hot spot, the user can jump to another screen in the help system. If you examine this screen in the PEN.RTF file using Word for Windows, you see that the menu names—such as "Pen Menu"— are formatted with double underlining. (This might be represented differently by another RTF editor.) Each menu name is followed immediately by a context name formatted as hidden text. For the Pen menu, this text reads "menu_pen."

The Pen Menu Screen

»Figure 10.4« shows the text in PEN.RTF for a help screen on the Pen Menu topic. The upper part of the figure shows the text of the file; the lower part shows footnote text. All formatting and hidden text are displayed.

The topic screen begins with a hard page break. The next line shows the footnote character, #, followed by the title to be displayed on the user's screen, "Pen menu commands." The rest of the screen contains descriptive text and two more hot spots for jumping to screens about the individual menu items.

The footnote text associated with the # footnote for the Pen menu is "menu_pen," which names the context — the destination of jumps to this screen of the help system.

Setting up this screen requires entering the hard page break and the footnote, then writing the text. In Word for Windows, for example, you'd use the Break command on the Insert menu to enter a hard page break. Then you'd use the Footnote entry on the Insert menu to specify a footnote with the special footnote character #.

Next, you'd type the footnote text in the footnote window. Finally, you'd type the descriptive text and format the hot spots.

The jumps to screens for individual menu items consist of:

•	Visible text, such as "Pen Widths," formatted as double underlined, to designate the hot spot on the screen for the jump.

•	Hidden text, such as "HID_PEN_WIDTHS," to designate the destination help topic.

In the RTF files that AppWizard supplies, tables (as in Word for Windows) are used to present groups of jumps, but help authors are not required to use tables.

A Screen for a Menu Item

»Figure 10.5« shows a screen for the Pen Widths and Thick Line menu items.

The screen is set up similarly to its parent screen for the Pen menu as a whole. Notice the text used for the footnotes in the lower part of »Figure 10.5.«

Once your help authoring is finished, you can compile your help file. If you've chosen to author Scribble's help files, use the following procedure to see the results.

To compile and test Scribble's help

1.	To compile help, run MAKEHELP.BAT from the MS-DOS command line.

The .HLP file is placed in your MYSCRIB directory.

2.	To prepare Scribble for testing your help, build Scribble from the Visual Workbench Project menu.

3.	To test help, run Scribble and try out the help features.

The section »See Context-Sensitive Help in Action« suggests how to try out the help features.


 Conclusion

This concludes the Scribble tutorial portion of the Class Library User's Guide. The remaining chapters explore other aspects of the Microsoft Foundation Class Library:

•	Memory management (»Chapter 11«)

•	General-purpose classes for dates, times, and strings (»Chapter 11«)

•	Class CObject, the root base class of the class library, which offers useful services to classes derived from it (»Chapter 12«)

•	Collection classes, such as arrays, lists, and maps (»Chapter 13«)

•	Files and serialization (»Chapter 14«)

•	Diagnostics (»Chapter 15«)

•	Exception-handling (»Chapter 16«)

•	Using Object Linking and Embedding (OLE) (»Chapter 17«)


 Chapter 11  General-Purpose Classes

The Microsoft Foundation Class Library provides services to make programming easier. These services range from general-purpose memory-management services to more advanced Windows facilities. This chapter describes how to take advantage of the general-purpose services related to memory management, time and date management, and string manipulation.


 Memory Management

Memory allocation can be divided into two main categories: frame allocations and heap allocations. One main difference between the two allocation techniques is that with frame allocation you typically work with the actual memory block itself, whereas with heap allocation you are always given a pointer to the memory block. Another major difference between the two schemes is that frame objects are automatically deleted, while heap objects must be explicitly deleted by the programmer.

The following sections describe how to use the capabilities of C and C++ to accomplish memory allocations on the frame and on the heap.


 Frame Allocation

Allocation on the frame takes its name from the "stack frame" that is set up whenever a function is called. The stack frame is an area of memory that temporarily holds the arguments to the function as well as any variables that are defined local to the function. Frame variables are often called "automatic" variables because the compiler automatically allocates the space for them.

There are two key characteristics of frame allocations. First, when you define a local variable, enough space is allocated on the stack frame to hold the entire variable, even if it is a large array or data structure. Second, frame variables are automatically deleted when they go out of scope. For local function variables, this scope transition happens when the function exits, but the scope of a frame variable can be smaller than a function if nested braces are used (or larger, in the case of global variables). This automatic deletion of frame variables is very important. In the case of simple primitive types (such as int or byte), arrays, or data structures, the automatic deletion simply reclaims the memory used by the variable. Since the variable has gone out of scope, it cannot be accessed anyway. In the case of C++ objects, however, the process of automatic deletion is a bit more complicated.

When an object is defined as a frame variable, its constructor is automatically invoked at the point where the definition is encountered. When the object goes out of scope, its destructor is automatically invoked before the memory for the object is reclaimed. This automatic construction and destruction can be very handy, but you must be aware of the automatic calls, especially to the destructor.

The key advantage of allocating objects on the frame is that they are automatically deleted. When you allocate your objects on the frame, you don't have to worry about forgotten objects causing memory leaks. (For details on memory leaks, see »Detecting Memory Leaks«.) A disadvantage of frame allocation is that frame variables cannot be used outside their scope. Another factor in choosing frame allocation vs. heap allocation is that for large structures and objects, it is often better to use the heap instead of the stack for storage since stack space is often limited.


 Heap Allocation

The heap is reserved for the memory allocation needs of the program. It is an area apart from the program code and from the stack. Typical C programs use the functions malloc and free to allocate and deallocate heap memory. The Debug version of the Microsoft Foundation Class Library provides modified versions of the C++ built-in operators new and delete to allocate and deallocate objects in heap memory. When you use new and delete instead of malloc and free you are able to take advantage of the Foundation's memory-management debugging enhancements, which can be useful in detecting memory leaks. When you build your program with the Release version of the Microsoft Foundation Class Library, new and delete still provide an efficient way to allocate and deallocate memory.


 Memory Allocation on the Frame and on the Heap

There are three typical kinds of memory allocations:

•	»An array of bytes«

•	»A data structure«

•	»An object«

The following sections describe how the Microsoft Foundation Class Library facilities perform frame allocation and heap allocation for each of these.


 Allocation of an Array of Bytes

To allocate an array of bytes on the frame

•	Define the array as shown by the following code. The array is automatically deleted and its memory reclaimed when the array variable exits its scope.

{
const int BUFF_SIZE = 128;

// Allocate on the frame
char myCharArray[BUFF_SIZE];
int myIntArray[BUFF_SIZE];
// Reclaimed when exiting scope
}

To allocate an array of bytes (or any primitive data type) on the heap

•	Use the new operator with the following array syntax:

const int BUFF_SIZE = 128;

// Allocate on the heap
char* myCharArray = new char[BUFF_SIZE];
int* myIntArray = new int[BUFF_SIZE];

To deallocate the arrays from the heap

•	Use the delete operator as follows:

delete [] myCharArray;
delete [] myIntArray;


 Allocation of a Data Structure

To allocate a data structure on the frame

•	Define the structure variable as follows:

struct MyStructType {...};
void SomeFunc(void)
{
// Frame allocation
MyStructType myStruct;

// Use the struct
myStruct.topScore = 297;

// Reclaimed when exiting scope
}

The memory occupied by the structure is reclaimed when it exits its scope.

To allocate data structures on the heap

•	Use new to allocate data structures on the heap and delete to deallocate them, as shown by the following examples:

// Heap allocation
MyStructType* myStruct = new MyStructType;

// Use the struct through the pointer ...
myStruct->topScore = 297;

delete myStruct;


 Allocation of an Object

To allocate an object on the frame

•	Declare the object as follows:

{
CPerson myPerson;     // Automatic constructor call here

myPerson.SomeMemberFunction();     // Use the object

}

The destructor for the object is automatically invoked when the object exits its scope.

To allocate an object on the heap

•	Use the new operator, which returns a pointer to the object, to allocate objects on the heap. Use the delete operator to delete them. The following heap and frame examples assume that the CPerson constructor takes no arguments.

// Automatic constructor call here
CPerson* myPerson = new CPerson;

myPerson->SomeMemberFunction();	// Use the object

delete myPerson;	// Destructor invoked during delete

If the argument for the CPerson constructor is a pointer to char, the statement for frame allocation is:

CPerson myPerson( "Joe Smith" );

The statement for heap allocation is:

CPerson* MyPerson = new CPerson( "Joe Smith" );


 Resizable Memory Blocks

The new and delete operators described above are good for allocating and deallocating fixed-size memory blocks and objects. Occasionally, your application may need resizable memory blocks. You must use the standard C run-time library functions malloc, realloc, and free to manage resizable memory blocks on the heap.

Mixing the new and delete operators with the resizable memory-allocation functions on the same memory block will result in corrupted memory in the Debug version of the Foundation Class Library. That is, do not allocate a memory block with new and deallocate it with free. Likewise, you should not use the C++ delete operator on a memory block allocated with malloc and you should not use realloc on a memory block allocated with new.


 Date and Time

The CTime class provides a way to represent date and time information easily. The CTimeSpan class represents elapsed time, such as the difference between two CTime objects.

Note  CTime objects cannot be used to represent dates earlier than January 1, 1980. CTime objects have a resolution of 1 second.

The first procedure in this section shows how to create a CTime object and initialize it with the current time. The next procedure shows how to calculate the difference between two CTime objects and get a CTimeSpan result.

To get the current time

1.	Allocate a CTime object, as follows:

CTime theTime;

Note  Uninitialized CTime objects are automatically set to an invalid time.

2.	Call the CTime::GetCurrentTime function to get the current time from the operating system. This function returns a CTime object that can be used to set the value of CTime, as follows:

theTime = CTime::GetCurrentTime();

Since GetCurrentTime is a static member function from the CTime class, you must qualify its name with the name of the class and the scope resolution operator (::), CTime::GetCurrentTime().

Of course, the two steps outlined previously could be combined into a single program statement as follows:

CTime theTime = CTime::GetCurrentTime();

To calculate elapsed time

•	Use the CTime and CTimeSpan objects to calculate the elapsed time, as follows:

CTime startTime = CTime::GetCurrentTime();

// ... perform time-consuming task ...

CTime endTime = CTime::GetCurrentTime();

CTimeSpan elapsedTime = endTime - startTime;

Once you have calculated elapsedTime, you can use the member functions of CTimeSpan to extract the components of the elapsed-time value.

To format a string representation of a time or elapsed time

•	Use the Format member function from either the CTime or CTimeSpan classes to create a character string representation of the time or elapsed time, as shown by the following example.

CTime t( 1991, 3, 19, 22, 15, 0 ); // 10:15PM March 19, 1991
CString s = t.Format( "%A, %B %d, %Y" );
// s == "Tuesday, March 19, 1991"


 Strings

The CString class provides support for manipulating strings. It is intended to replace and extend the functionality normally provided by the C run-time library string package.

A CString object represents a sequence of a variable number of characters. CString objects can be thought of as arrays of single-byte characters.

A CString object can store up to 32,766 characters. The normal C char data type is used to get or set individual characters inside a CString object. CString objects are automatically growable (that is, you don't have to worry about growing a CString object to fit longer strings). A CString object also can act like a literal
C-style string (a pointer to const char).


 Basic Operations

The CString class provides member functions and overloaded operators that duplicate and, in some cases, surpass the string services of the C run-time libraries (for example, strcat). The following sections describe some of the main operations of the CString class.

To create CString objects from standard C literal strings

•	Assign the value of a C literal string to a CString object:

CString myString = "This is a test";

•	Assign the value of one CString to another CString object:

CString oldString = "This is a test";
CString newString = oldString;

As explained more completely in the next section on using CString objects as values, the contents of a CString object are copied when one string is assigned to another CString object. Thus, the two strings do not share a reference to the actual characters that make up the string.

To access individual characters in a CString

•	You can access individual characters within a CString object with the GetAt and SetAt member functions. You can also use the array element operator ( [] ) instead of GetAt to get individual characters (this is similar to accessing array elements by index, as in standard C-style strings). Index values for CString characters are zero-based.

To concatenate two CStrings

•	Use the concatenation operators (+ or +=) as follows:

CString s1 = "This ";	//Cascading concatenation
s1 += "is a ";
CString s2 = "test";
CString message = s1 + "big " + s2;
//Message contains "This is a big test".

At least one of the arguments to the concatenation operators (+ or +=) must be a CString object, but you can use a constant character string (such as "big") or a char (such as 'x') for the other argument.

To compare two CStrings

•	While the overloaded equality operator (==) and the Compare member functions will determine if two CString objects are equivalent character for character, you can also use the CompareNoCase and Collate member functions to do comparisons that are case insensitive and national-language sensitive. The following table shows the three available CString comparison functions and their equivalent C run-time string functions.

CString Function	C Run-time Function
Compare	strcmp
CompareNoCase	stricmp
Collate	strcoll
The CString class overrides the relational operators (<, <=, >=, >, ==, and !=) to use the Compare function, so you can compare two CStrings using these operators, as shown here:

CString s1( "Tom" );
CString s2( "Jerry" );
if( s1 < s2 )
...


 CString Objects Are Values

Even though CString objects are dynamically growable objects, they act like built-in primitive types and simple classes. Each CString object represents a unique value. CString objects should be thought of as the actual strings rather than as pointers to strings.

The most obvious consequence of using CString objects as values is that the string contents are copied when you assign one CString to another. Thus, even though two CStrings objects may represent the same sequence of characters, they do not share those characters. Each CString has its own copy of the character data. When you modify one CString object, the copied CString object is not modified, as shown by the following example:

CString s1, s2;
s1 = s2 = "hi there";

if( s1 == s2 )	// TRUE - they are equal
...

s1.MakeUpper();	// Does not modify s2
if( s2[0] == 'h' )	// TRUE - s2 is still "hi there"

Notice in the example that the two CString objects are considered to be "equal" because they represent the same character string. The CString class overloads the equality operator (==) to compare two CString objects based on their value (contents) rather than their identity (address).

To specify CString formal parameters correctly

•	For most functions that need a string argument, it is best to specify the formal parameter in the function prototype as a pointer to const char (const char* or const char FAR*) instead of a CString. When a formal parameter is specified as a pointer to const char, you can pass either a pointer to a char array, a literal string ("hi there"), or a CString object. The CString object will be automatically converted to a pointer to const char. Any place you can use a pointer to char, you can also use a CString object.

•	You can also specify a formal parameter as a constant string reference (that is, const CString&) if the argument will not be modified. Drop the const modifier if the string will be modified by the function. If a default null value is desired, initialize it to the null string (""), as shown below:

void AddCustomer( const CString& name,
const CString& address,
const CString& comment = "" );

•	For most function results, you can simply return a CString object by value.


 Operations Related to C-Style Strings

It is often useful to be able to manipulate the contents of a CString object as if it were a C-style null-terminated string.

To convert to C-style null-terminated strings

•	In the simplest case, you can cast a CString object to be a pointer to const char. The const char* type conversion operator returns a read-only pointer to a C-style null-terminated string from a CString object.

The pointer to char returned by the implicit conversion shown above points into the data area used by the CString. If the CString goes out of scope and is automatically deleted or something else changes the contents of the CString,
the char pointer will no longer be valid. You should treat this pointer as a temporary read-only pointer. Do not directly modify the characters to which
it points.

•	You can use CString functions, such as SetAt, to modify individual characters in the string object. However, if you need a copy of a CString object's char-acters that you can modify directly, use strcpy to copy the CString object into a separate buffer where the characters can be safely modified, as shown by the following example:

CString theString( "This is a test" );
char* psz = new char[theString.GetLength()+1];
strcpy( psz,theString );
//... modify psz as much as you want

Note  The second argument to strcpy is declared as a constant pointer to char (const char*). The example above passes a CString for this argument. The C++ compiler automatically applies the conversion function defined for the CString class that converts a CString to a const char*. The ability to define casting operations from one type to another is one of the most useful features of C++.

To work with standard C-library string functions

•	In most situations, you should be able to find CString member functions to perform any string operation for which you might consider using the standard
C run-time library string functions, such as strcmp.

•	If you find that you must use the C run-time string functions, you can use the techniques described in the previous procedure to copy the CString object to an equivalent C-style string buffer, perform your operations on the buffer, and then assign the resulting C-style string back to a CString object.

To modify CString contents directly with GetBuffer and ReleaseBuffer

•	In most situations, you should use CString member functions to modify the contents of a CString object or to convert the CString to a C-style character string as described in the previous section.

•	However, there are certain situations, such as working with operating-system functions that require a character buffer, where it is advantageous to directly modify the CString contents.

The GetBuffer and ReleaseBuffer member functions allow you to gain access to the internal character buffer of a CString object and modify it directly. The following steps show how to use these functions for this purpose:

1.	Call GetBuffer for a CString object, specifying the length of the buffer you require.

2.	Use the pointer returned by GetBuffer to write characters directly into the CString object.

3.	Call ReleaseBuffer for the CString object to update all the internal CString state information (such as the length of the string). After modifying a CString object's contents directly, you must call ReleaseBuffer before calling any other CString member functions.

To use CString objects with variable argument functions

Some C functions take a variable number of arguments. A notable example is printf. Because of the way this kind of function is declared, the compiler cannot be sure of the type of the arguments and cannot determine which conversion operation to perform on the argument. Therefore, it is essential that you use an explicit-type cast when passing a CString object to a function that takes a variable number of arguments.

•	Explicitly cast the CString to a pointer to a constant char string, as shown here:

CString kindOfFruit = "bananas";
int	howmany = 25;
printf( "You have %d %s\n", howmany, (const char*)kindOfFruit );


 Chapter 12  The CObject Class

CObject is the root base class for most of the Microsoft Foundation Class Library. The CObject class contains many useful features that you may want to incorporate into your own program objects, including serialization support, run-time class information, and object diagnostic output. If you derive your class from CObject, your class can exploit these CObject features.

The cost of deriving your class from CObject is minimal. Your derived class will have the overhead of four virtual functions and a single CRuntimeClass object.


 Deriving a Class from CObject

This section describes the minimum steps necessary to derive a class from CObject. Other sections describe the steps needed to take advantage of specific CObject features, such as serialization and diagnostic debugging support.

In the discussions of CObject, the terms "interface file" and "implementation file" are used frequently. The interface file (often called the header file, or .H file) contains the class declaration and any other information needed to use the class. The implementation file (or .CPP file) contains the class definition as well the code that implements the class member functions. For example, for a class named CPerson, you would typically create an interface file named PERSON.H and an implementation file named PERSON.CPP. However, for some small classes that will not be shared among applications, it is sometimes easier to combine the interface and implementation into a single .CPP file.

There are four levels of functionality from which you can choose when deriving a class from CObject:

•	Basic functionality that does not include support for run-time class information or serialization but includes diagnostic memory management.

•	Basic functionality plus support for run-time class information.

•	Basic functionality plus support for run-time class information and dynamic creation.

•	Basic functionality plus support for run-time class information, dynamic creation, and serialization.

Classes designed for reuse (those that will later serve as base classes) should at least include run-time class support and serialization support, if any future serialization need is anticipated.

You choose the level of functionality by using specific declaration and implementation macros in the declaration and implementation of the classes you derive from CObject.

»Figure 12.1« shows the relationship among the macros used to support serialization and run-time information.

The following sections describe how to specify the level of functionality.

To use basic CObject functionality

•	Use the normal C++ syntax to derive your class from CObject (or from a class derived from CObject).

The following example shows the simplest case, the derivation of a class from CObject:

class CPerson : public CObject
{
// add CPerson-specific members and functions...
}

Typically, however, you may want to override some of CObject's member functions to handle the specifics of your new class. For example, you may usually want to override the Dump function of CObject to provide debugging output for the contents of your class. For details on how to override Dump, see »Dumping Object Contents«. You may also want to override the AssertValid function of CObject to provide customized testing to validate the consistency of the data members of class objects. For a description of how to override AssertValid, see the section on »Overriding the AssertValid Function«.

To add run-time class information

CObject supports run-time class information through the IsKindOf function, which allows you to determine if an object belongs to or is derived from a specified class. (For more detailed information, see Chapter 14, »Files and Serialization.«) This capability is not supported directly by the C++ language. The IsKindOf function permits you to do a typesafe cast down to a derived class.

Use the following steps to access run-time class information:

1.	Derive your class from CObject, as described in the previous section.

2.	Use the DECLARE_DYNAMIC macro in your class declaration, as shown here:

class CPerson : public CObject
{
DECLARE_DYNAMIC( CPerson )

// rest of class declaration follows...
};

3.	Use the IMPLEMENT_DYNAMIC macro in the implementation file (.CPP) of your class. This macro takes as arguments the name of the class and its base class, as follows:

IMPLEMENT_DYNAMIC( CPerson, CObject )

To better understand the relationships among the macros and the functions that support serialization and run-time, see »Figure 12.1«.

Note  Always put IMPLEMENT_DYNAMIC in the implementation file (.CPP) for your class. The IMPLEMENT_DYNAMIC macro should be evaluated only once during a compilation and therefore should not be used in an interface file (.H) that could potentially be included in more than one file.

To add dynamic creation support

CObject also supports dynamic creation, which is the process of creating an object of a specific class at run time. The object is created by the CreateObject member function of CRuntimeClass. Your document, view, and frame class should support dynamic creation because the framework (through the CDocTemplate class) needs to create them dynamically. Dynamic creation is not supported directly by the C++ language. To add dynamic creation, you must do the following:

1.	Derive your class from CObject.

2.	Use the DECLARE_DYNCREATE macro in the class declaration.

3.	Define a constructor with no arguments (a default constructor).

4.	Use the IMPLEMENT_DYNCREATE macro in the class implementation file.

To add serialization support

Serialization is the process of writing or reading the contents of an object to and from a file. The Microsoft Foundation Class Library uses an object of the CArchive class as an intermediary between the object to be serialized and the storage medium. The CArchive object uses overloaded insertion (<<) and extraction (>>) operators to perform writing and reading operations.

The following steps are required to support serialization in your classes:

1.	Derive your class from CObject.

2.	Override the Serialize member function.

If you call Serialize directly, that is, you do not want to serialize the object through a polymorphic pointer, omit these steps:

1.	Use the DECLARE_SERIAL macro in the class declaration.

2.	Define a constructor with no arguments (a default constructor).

3.	Use the IMPLEMENT_SERIAL macro in the class implementation file.

For more details on how to enable serialization when you derive your class from CObject, see »Serialization«. Each of the steps listed above is described in that section.


 Accessing Run-Time Class Information

If you have derived your class from CObject and used the DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC, the DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE, or the DECLARE_SERIAL and IMPLEMENT_SERIAL macros explained previously, the CObject class has the ability to determine the exact class of an object at run time.

The ability to determine the class of an object at run time is most useful when extra type checking of function arguments is needed and when you must write special-purpose code based on the class of an object. However, this practice is not usually recommended because it duplicates the functionality of virtual functions.

The CObject member function IsKindOf can be used to determine if a particular object belongs to a specified class or if it is derived from a specific class. The argument to IsKindOf is a CRuntimeClass object, which you can get using the RUNTIME_CLASS macro with the name of the class. The use of the RUNTIME_CLASS macro is shown in the following section.

To use the RUNTIME_CLASS macro

•	Use RUNTIME_CLASS with the name of the class, as shown here for the class CObject:

CRuntimeClass* pClass = RUNTIME_CLASS( CObject );

You will rarely need to access the run-time class object directly. A more common use is to pass the run-time class object to the IsKindOf function, as shown in the next section.

To use the IsKindOf function

The IsKindOf function tests an object to see if it belongs to a particular class. The following steps show how to use IsKindOf.

1.	Make sure the class has run-time class support. That is, the class must have been derived from CObject and used the DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC, the DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE, or the DECLARE_SERIAL and IMPLEMENT_SERIAL macros explained previously in »Deriving a Class from CObject«.

2.	Call the IsKindOf member function for objects of that class, using the RUNTIME_CLASS macro to generate the CRuntimeClass argument, as shown here:

// in .H file
class CPerson : public CObject
{
DECLARE_DYNAMIC( CPerson )
public:
CPerson(){};

// other declaration
};

// in .CPP file
IMPLEMENT_DYNAMIC( CPerson, CObject )

CObject* pMyObject = new CPerson;

if( myObject->IsKindOf( RUNTIME_CLASS( CPerson ) ) )
{
//if IsKindOf is true, then cast is all right
CPerson* pmyPerson = (CPerson*) pmyObject;
}

Note  IsKindOf returns TRUE if the object is a member of the specified class or of a class derived from the specified class. IsKindOf does not support multiple inheritance or virtual base classes, although you can use multiple inheritance for your Microsoft Foundation classes if necessary.

To dynamically create an object given its run-time class

•	Use the following code to dynamically create an object by using the CreateObject function of the CRuntimeClass:

CRuntimeClass* pRuntimeClass = RUNTIME_CLASS( CMyClass );
CObject* pObject = pRuntimeClass->CreateObject();
ASSERT( pObject->IsKindOf( RUNTIME_CLASS( CMyClass ) ) );

For more detailed information on serialization and run-time class information, see Chapter 14, »Files and Serialization.«


 Chapter 13  Collections

The Microsoft Foundation Class Library provides collection classes to manage groups of objects. A collection class is characterized by its "shape" and by the types of its elements. The shape refers to the way the objects are organized and stored by the collection. The Microsoft Foundation Class Library provides three basic collection shapes: lists, arrays, and maps (also known as dictionaries). You can pick the collection shape most suited to your particular programming problem.

Each of the three provided collection shapes is described briefly below, followed by Table 13.1, which compares the features of the shapes to help you decide which is best for your program. In the table, the term "ordered" means that the order of the items in the collection is determined by the order in which they were inserted and deleted. It does not mean that the items are sorted based on their contents. The term "indexed" means that the items in the collection can be retrieved by an integer index, much like a typical array structure.

•	List

The list class provides an ordered, nonindexed list of elements, implemented as a doubly linked list. A list has a "head" and a "tail," and adding or removing elements from the head or tail, or inserting or deleting elements in the middle,  is very fast.

•	Array

The array class provides a dynamically sized, ordered, and integer-indexed array of objects.

•	Map (also known as a dictionary)

A "map" is a collection that associates a key object with a value object.

Table 13.1    Shape Features

Shape	Ordered?	Indexed?	Insert an Element	Check for Specified Element	Duplicate Elements?
List	Yes	No	Fast	Slow	Yes
Array	Yes	By int	Slow	Slow	Yes
Map	No	By key	Fast	Fast	No (keys) Yes (values)


 How to Make a Type-Safe Collection

The Microsoft Foundation Class Library provides predefined type-safe collections that can be used to contain CObject, UINT, DWORD, and CString elements. You can use these predefined collections (such as CObList) to hold collections of any objects derived from CObject. The Microsoft Foundation Class Library also provides other predefined collections to hold primitive types such as UINT and void pointers (void*). In general, however, it is often useful to define your own type-safe collections to hold objects of a more specific class and its derivatives.

There are three main ways to use collections with the Microsoft Foundation Class Library, as described by the following sections.

To use predefined collections

•	The easiest way to use the Microsoft Foundation collection classes is to use a predefined collection type, such as CWordArray. You can create a CWordArray and add any 32-bit values to it and retrieve them. There is nothing more to do. You just use the predefined functionality.

•	You can also use a predefined collection, such as CObList, to hold objects that are derived from CObject. A CObList is defined to hold pointers to CObject. You can put any object that is derived from CObject into a CObList. When you retrieve an object from the list, you may have to cast the result to the proper type since the CObList functions return pointers to CObject. For example, if you store CPerson objects in a CObList, you have to cast a retrieved element to be a pointer to a CPerson object. The following example uses a CObList to hold CPerson objects:

class CPerson : public CObject {...};

CPerson* p1 = new CPerson(...);
CObList myList;

myList.AddHead( p1 );   // No cast needed
CPerson* p2 = ( CPerson* )myList.GetHead();

•	This technique of using a predefined collection type and casting as necessary may be adequate for many of your collection needs. If you need further functionality or more type safety, read the next section.

To derive and extend a collection

•	You can also derive your own collection class from one of the predefined collection classes provided with the Microsoft Foundation Class Library. When you derive your class, you can add type-safe wrapper functions to provide a type-safe interface to existing functions.

•	For example, if you derived a list from CObList to hold CPerson objects, you might add the wrapper functions AddHeadPerson and GetHeadPerson, as shown below.

class CPersonList : public CObList
{
public:
void AddHeadPerson( CPerson* person )
{AddHead( person );}

CPerson* GetHeadPerson()
{return (CPerson*)GetHead();}
};

These wrapper functions provide a type-safe way to add and retrieve CPerson objects from the derived list. You can see that for the GetHeadPerson function, you are simply encapsulating the casting seen in the previous section.

You can also add new functionality by defining new functions that extend the capabilities of the collection rather than just wrapping existing functionality in type-safe wrappers. For example, a later section describes a function to delete all the objects contained in a list. This function could be added to the derived class as a member function.

To use templates to create new collection classes

•	See Technical Note 4 in \MSVCNT\HELP\MFCNOTES.HLP which describes the Microsoft Foundation Class Library tool that you can use to create new type-safe collections from template files. These templates and the tool allow you to create a version of an existing collection shape that is customized to hold a specified data type or object type.

The TEMPLDEF tool is a template expander that uses a syntax similar to ANSI language syntax. You do not need to build TEMPLDEF.EXE; it is already provided in the \MSVCNT\BIN directory. A good way to get started is to examine the four .CTT template classes found in the MFC\SAMPLES\TEMPDEF subdirectory.


 Accessing All Members of a Collection

The Foundation collection classes use a position indicator to describe a given position within the collection. To access one or more members of a collection, first initialize the position indicator and then repeatedly pass that position to the collection and ask it to return the next element. The collection is not responsible for maintaining state information about the progress of the iteration. That information is kept in the position indicator. But, given a particular position, the collection is responsible for returning the next element.

The following examples show how to iterate over the three main types of collections provided with the Microsoft Foundation Class Library.

To iterate an array

•	Use sequential index numbers with the GetAt member function:

CObArray myArray;

for( int i = 0; i < myArray.GetSize();i++ )
{
CPerson* thePerson = (CPerson*)myArray.GetAt( i );
...
}

To iterate a list

•	Use the member functions GetHeadPosition and GetNext to work your way through the list:

CPersonList myList;

POSITION pos = myList.GetHeadPosition();
while( pos != NULL )
{
CPerson* thePerson = myList.GetNext( pos );
...
}

To iterate a map

•	Use GetStartPosition to get to the beginning of the map and GetNextAssociation to repeatedly get the next key and value from the map, as shown by the following example:

CMapStringToOb myMap;

POSITION pos = myMap.GetStartPosition();
while( pos != NULL )

{
CObject* pObject;
CPerson* pPerson;
CString string;
// Gets key ( string ) and value ( pObject )
myMap.GetNextAssoc( pos, string, pObject );
if( pObject->IsKindOf( RUNTIME_CLASS(CPerson) ) )
{
pPerson = (CPerson*)pObject;
//...
}
}


 How to Delete All Objects in a CObject Collection

To delete all the objects in a collection of CObjects (or of objects derived from CObject), you use one of the iteration techniques described in »Accessing All Members of a Collection« to delete each object in turn.

Note  Objects in collections can be shared. That is, the collection keeps a pointer to the object, but other parts of the program may also have pointers to the same object. You must be careful not to delete an object that is shared until all the parts have finished using the object.

To delete all objects in a CObList

1.	Use GetHeadPosition and GetNext to iterate through the list.

2.	Use the delete operator to delete each object as it is encountered in the iteration.

3.	Call the RemoveAll function to remove all elements from the list after the objects associated with those elements have been deleted.

The preceding technique deletes all objects in a CObList or a list derived from CObList.

The following example shows how to delete all objects from a list of
CPerson objects. Each object in the list is a pointer to a CPerson object that was originally allocated on the heap.

class CPersonList : public CObList {...};

CPersonList myList
POSITION pos = myList.GetHeadPosition();

while( pos != NULL )
{
delete myList.GetNext( pos );
}
myList.RemoveAll();

The last function call, RemoveAll, is a list member function that removes all elements from the list. The member function RemoveAt will remove a single element.

Notice the difference between deleting an element's object and removing the element itself. Removing an element from the list merely removes the list's reference to the object. The object still exists in memory. When you delete an object, its memory is reclaimed and it ceases to exist. Thus, it is important to remove an element immediately after the element's object has been deleted so that the list won't try to access objects that no longer exist.

To delete all elements in an array

1.	Use GetSize and integer index values to iterate through the array.

2.	Use the delete operator to delete each element as it is encountered in the iteration.

3.	Call the RemoveAll function to remove all elements from the array after they have been deleted.

The code for deleting all elements of an array is as follows:

CObArray myArray;

int i = 0;
while (i < myArray.GetSize() )
{
delete myArray.GetAt( i++ );
}

myArray.RemoveAll();

Like the list example, you can call RemoveAll to remove all elements in an array or RemoveAt to remove an individual element.

To delete all elements in a map

1.	Use GetStartPosition and GetNextAssociation to iterate through the array.

2.	Use the delete operator to delete the key and/or value for each map element as it is encountered in the iteration.

3.	Call the RemoveAll function to remove all elements from the map after they have been deleted.

The code for deleting all elements of a CMapStringToOb is as follows. Each element in the map has a string as the key and a CPerson object (derived from CObject) as the value.

CMapStringToOb myMap;
// ... Add some key-value elements ...
// Now delete the elements
pos = myMap.GetStartPosition();
while( pos != NULL )
{
CObject* pObject;
CString string;
// Gets key ( string ) and value ( pObject )
myMap.GetNextAssoc( pos, string, pObject );
delete pObject;
}
myMap.RemoveAll();

You can call RemoveAll to remove all elements in a map or RemoveKey to remove an individual element with the specified key.


 How to Create a Stack Collection

Because the standard list collection has both a head and a tail, it is easy to create a derived list collection that mimics the behavior of a last-in-first-out stack. A stack is like a stack of trays in a cafeteria. As trays are added to the stack, they go on top of the stack. The last tray added is the first to be removed. The list collection member functions AddHead and RemoveHead can be used to add and remove elements specifically from the head of the list; thus the most recently added element is the first to be removed.

To create a stack collection

•	Derive a new list class from one of the existing Foundation list classes and add more member functions to support the functionality of stack operations.

The following example shows you can add member functions to push elements on to the stack, peek at the top element of the stack, and pop the top element from the stack:

class CTray : public CObject { ... };

class CStack : public CObList
{
public:
// Add element to top of stack
void Push( CTray* newTray )
{ AddHead( newTray ); }

// Peek at top element of stack
CTray* Peek()
{ return IsEmpty() ? NULL : (CTray*)GetHead(); }

// Pop top element off stack
CTray* Pop()
{ return (CTray*)RemoveHead(); }
};


 How to Create a Queue Collection

Because the standard list collection has both a head and a tail, it is also easy to create a derived list collection that mimics the behavior of a first-in-first-out queue. A queue is like a line of people in a cafeteria. The first person in line is the first to be served. As more people come, they go to the end of the line to wait their turn. The list collection member functions AddTail and RemoveHead can be used to add and remove elements specifically from the head or tail of the list; thus the most recently added element is always the last to be removed.

To create a queue collection

•	Derive a new list class from one of the predefined list classes provided with the Microsoft Foundation Class Library and add more member functions to support the semantics of queue operations.

The following example shows how you can append member functions to add an element to the end of the queue and get the element from the front of the queue.

class CPerson : public CObject { ... };

class CQueue : public CObList
{
public:
// Go to the end of the line
void AddToEnd( CPerson* newPerson )
{ AddTail( newPerson ); }	// End of the queue

// Get first element in line
CPerson* GetFromFront()
{ return IsEmpty() ? NULL : (CPerson*)RemoveHead(); }
};


 Chapter 14  Files and Serialization

In the Microsoft Foundation Class Library, the CFile class handles normal file I/O operations. This chapter explains how to open and close files as well as read and write data to those files. You will also learn about file status operations. For a description of how to use the object-based serialization features of the Microsoft Foundation Class Library as an alternative way of reading and writing data in files, see »Serialization«.


 Files

The CFile class provides an interface for general-purpose binary file operations. The CStdioFile and CMemFile classes are derived from CFile to supply more specialized file services.

In the Microsoft Foundation Class Library, the most common way to open a file is a two-stage process.

To open a file

1.	Create the file object without specifying a path or permission flags.

You usually create a file object by declaring a CFile variable on the stack frame.

2.	Call the Open member function for the file object, supplying a path and permission flags.

The return value for Open will be nonzero if the file was opened successfully or 0 if the specified file could not be opened.

The open flags specify which permissions, such as read-only, you want for the file. The possible flag values are defined as enumerated constants within the CFile class, so they are qualified with "CFile::," as in CFile::modeRead. Use the CFile::modeCreate flag if you want to create the file.

The following example shows how to create a new file with read/write permission (replacing any previous file with the same path):

char* pszFileName = "\\test\\myfile.dat";
CFile myFile;

if ( ! myFile.Open( pszFileName,
CFile::modeCreate | CFile::modeReadWrite ) )
{
TRACE( "Can't open file %s\n",pszFileName );
}

You may pass an additional CFileException object if you require more detailed error reporting.

To read from and write to the file

•	Use the Read and Write member functions to read and write data in the file.

The Seek member function is also available for moving to a specific offset within the file.

Read takes a pointer to a buffer and a UINT specifying the number of bytes to read and returns a UINT with the actual number of bytes that were read. If the required number of bytes could not be read because end-of-file (EOF) is reached, the actual number of bytes read is returned. If any read error occurs, an exception is thrown. Write is similar to Read, but the number of bytes written is not returned. If a write error occurs, including not writing all the bytes specified, an exception is thrown. If you have a valid CFile object, you can read from it or write to it as shown in the following example:

char	szBuffer[256];
UINT	nActual = 0;

myFile.Write( szBuffer, sizeof( szBuffer ) );
myFile.Seek( 0, CFile::begin );
nActual = myFile.Read( szBuffer, sizeof( szBuffer ) );

To close a file

•	Use the Close member function. This function closes the file-system file and flushes buffers if necessary.

If you allocated the CFile object on the frame (as in the examples above), the object will automatically be closed and then destroyed when it goes out of scope. Note that deleting the CFile object does not delete the physical file in the file system.

To get file status

•	Use the CFile class to get and set information about a file. One useful application is to use the CFile static member function GetStatus to determine if a file exists. GetStatus will return 0 if the specified file does not exist.

Thus, you could use the result of GetStatus to determine whether to use the CFile::modeCreate flag when opening a file, as shown by the following example:

CFile theFile;
char* szFileName = "c:\\test\\myfile.dat";
BOOL bOpenOK;

CFileStatus status;
if( CFile::GetStatus( szFileName, status ) )
{
// Open the file without the Create flag
bOpenOK = theFile.Open( szFileName,
CFile::modeWrite );
}
else
{
// Open the file with the Create flag
bOpenOK = theFile.Open( szFileName,
CFile::modeCreate | CFile::modeWrite );
}


 Serialization (Object Persistence)

Serialization is the process of writing or reading an object to or from a persistent storage medium, such as a disk file. The Microsoft Foundation Class Library provides built-in support for serialization in the class CObject. Thus, all classes that are derived from CObject can take advantage of CObject's serialization protocol.

The basic idea of serialization is that an object should be able to write its current state, usually indicated by the value of its member variables, to persistent storage. Later, the object can be re-created by reading, or deserializing, the object's state from the storage. Serialization handles all the details of object pointers and circular references to objects that are used when you serialize an object. A key point is that the object itself is responsible for reading and writing its own state. Thus, for a class to be serializable, it must implement the basic serialization operations. As you will see in the following topics, it is easy to add this functionality to a class.

The Microsoft Foundation Class Library uses an object of the CArchive class as an intermediary between the object to be serialized and the storage medium. This object is always associated with a CFile object, from which it obtains the necessary information for serialization, including the filename and whether the requested operation is a read or write. The object that performs a serialization operation can use the CArchive object without regard to the nature of the storage medium.

A CArchive object uses overloaded insertion (<<) and extraction (>>) operators to perform writing and reading operations. For more information, see »Storing and Loading CObjects via an Archive«.

Note   Do not confuse the CArchive class with general-purpose iostream classes, which are for formatted text only. The CArchive class is for binary format serialized objects.

The following sections cover the two main tasks required for serialization:

•	»Making a serializable class.«

•	»Serializing an object« to and from a file object.


 Making a Serializable Class

There are five main steps required to make a class serializable. They are listed below and explained in the following sections:

1.	Derive your class from CObject (or from some class derived from CObject).

2.	Use the DECLARE_SERIAL macro in the class declaration.

3.	Override the Serialize member function.

4.	Define a constructor that takes no arguments.

5.	Use the IMPLEMENT_SERIAL macro in the implementation file for your class.

If you call Serialize directly rather than through the >> and << operators of CArchive, the last three steps are not required for serialization.


 Deriving Your Class from CObject andUsing the DECLARE_SERIAL Macro

The basic serialization protocol and functionality are defined in the CObject class. By deriving your class from CObject (or from a class derived from CObject), as shown in the following example code, you gain access to the serialization protocol and functionality of CObject.

The DECLARE_SERIAL macro is required in the declaration of classes that will support serialization, as shown here:

class CPerson : public CObject
{
DECLARE_SERIAL( CPerson )
// rest of declaration follows...
};


 Overriding the Serialize Member Function

The Serialize member function, which is defined in the CObject class, is responsible for actually serializing the data necessary to capture an object's current state. The Serialize function has a CArchive argument that it uses to read and write the object data. The CArchive object has a member function, IsStoring, which indicates whether Serialize is storing (writing data) or loading (reading data). Using the results of IsStoring as a guide, you either insert your object's data in the CArchive object with the insertion operator (<<) or extract data with the extraction operator (>>).

Consider a class that is derived from CObject and has two new member variables, a CString and a WORD. The following class declaration fragment shows the new member variables and the declaration for the overridden Serialize member function:

class CPerson : public CObject
{
public:
DECLARE_SERIAL( CPerson, )
// empty constructor is necessary
CPerson(){};

CString m_name;
WORD   m_number;

void Serialize( CArchive& archive );

// rest of class declaration
};

To override the Serialize member function

1.	Call your base class version of Serialize to make sure that the inherited portion of the object is serialized.

2.	Insert or extract the member variables that are specific to your class.

The insertion and extraction operators interact with the archive class to read and write the data. The following example shows how to implement Serialize for the CPerson class declared above:

void CPerson::Serialize( CArchive& archive )
{
// call base class function first
// base class is CObject in this case
CObject::Serialize( archive );

// now do the stuff for our specific class
if( archive.IsStoring() )
archive << m_name << m_number;
else
archive >> m_name >> m_number;
}

You can also use the CArchive::Read and CArchive::Write member functions to read and write large amounts of untyped data.


 Defining a Constructor with No Arguments

A default constructor is required by the Microsoft Foundation Class Library when it re-creates your objects as they are deserialized (loaded from disk.) The deserialization process will fill in all member variables with the values required to re-create the object.

This constructor can be declared public, protected, or private. If you make it protected or private, you ensure that it will only be used by the serialization functions. The constructor must put the object in a state that allows it to be safely deleted if necessary.

Note  If you forget to define a constructor with no arguments in a class that uses the DECLARE_SERIAL and IMPLEMENT_SERIAL macros, you will get a "no default constructor available" compiler warning on the line where the IMPLEMENT_SERIAL macro is used.


 Using the IMPLEMENT_SERIAL Macro in the Implementation File

The IMPLEMENT_SERIAL macro is used to define the various functions needed when you derive a serializable class from CObject. You use this macro in the implementation file (.CPP) for your class. The first two arguments to the macro are the name of the class and the name of its immediate base class.

The third argument to this macro is a schema number. The schema number is essentially a version number for objects of the class. Use an integer greater than or equal to 0 for the schema number.

The Microsoft Foundation Class Library serialization code checks the schema number when reading objects into memory. If the schema number of the object on disk does not match the schema number of the class in memory, then the library will throw a CArchiveException, preventing your program from reading an incorrect version of the object.

The following example shows how to use IMPLEMENT_SERIAL for a class, CPerson, that is derived from CObject:

IMPLEMENT_SERIAL( CPerson, CObject, 1 )


 Serializing an Object

The previous sections showed how to make a class serializable. Once you have a serializable class, you can serialize objects of that class to and from a file via a CArchive object. This section first describes a CArchive object. It then describes the two ways to create it: (1) let the framework create it for your serializable document or (2) explicitly create the CArchive object yourself. Finally, the section describes how to transfer data between a file and your serializable object by using the << and >> operators for CArchive or, in some cases, by calling the Serialize function of a CObject-derived class.


 What Is a CArchive Object?

A CArchive object provides a type-safe buffering mechanism for writing or reading serializable objects to or from a CFile object. Usually the CFile object represents a disk file; however, it can be also be a memory file (CMemFile object), perhaps representing the Clipboard.

A given CArchive object either stores (writes, serializes) data or loads (reads, deserializes) data, but never both. The life of a CArchive object is limited to one pass through writing objects to a file or reading objects from a file. Thus, two successively created CArchive objects are required to serialize data to a file and then deserialize it back from the file.

When an archive stores objects to a file, the archive attaches the CRuntimeClass name to the objects. Then, when another archive loads objects from a file to memory, the CObject-derived objects are dynamically reconstructed based on the CRuntimeClass of the objects. A given object may be referenced more than once as it is written to the file by the storing archive. The loading archive, however, will reconstruct the object only once.  The details about how an archive attaches CRuntimeClass information to objects and reconstructs objects, taking into account possible multiple references, is described in Technical Note 2, which can be found in \MSVCNT\HELP\MFCNOTES.HLP.

As data is serialized to an archive, the archive accumulates the data until its buffer is full. Then the archive writes its buffer to the CFile object pointed to by the CArchive object. Similarly, as you read data from an archive, it reads data from the file to its buffer and then from the buffer to your deserialized object. This buffering reduces the number of times a hard disk is physically read, thus improving your application's performance.


 Two Ways to Create a CArchive Object

There are two ways to create a CArchive object. The most common, and the easiest way is to let the framework create one for your document on behalf of the Save, Save As, and Open commands on the File menu. For example, here is what the framework does when the user of your application issues the Save As command from the File menu:

1.	The framework presents the File Save As dialog box and gets the filename from the user.

2.	The framework opens the file named by the user as a CFile object.

3.	The framework creates a CArchive object that points to this CFile object. In creating the CArchive object, the framework sets the mode to "store" (write, serialize), as opposed to "load" (read, deserialize).

4.	The framework calls the Serialize function defined in your CDocument-derived class, passing it a reference to the CArchive object.

5.	Your document's Serialize function writes data to the CArchive object, as explained shortly.

6.	Upon return from your Serialize function, the framework destroys the CArchive object and then the CFile object.

Thus, if you let the framework create the CArchive object for your document, all you have to do is implement the document's Serialize function that writes and reads to and from the archive. You also have to implement Serialize for any CObject-derived objects that the document's Serialize function in turn serializes directly or indirectly.

Besides serializing a document via the framework, there are other occasions when you may need a CArchive object. For example, you might want to serialize data to and from the Clipboard, represented by a CMemFile object. Or, you may want to use a user interface for saving a file that is different from the one offered by the framework. In this case, you can explicitly create a CArchive object. You do this the same way the framework does, using the following.

To explicitly create a CArchive object

1.	Construct a CFile object or an object derived from CFile.

2.	Pass the CFile object to the constructor for CArchive, as shown in the following example:

CFile theFile;
theFile.Open(..., CFile::modeWrite);
CArchive archive(&theFile, CArchive::store);

The second argument to the CArchive constructor is an enumerated value that specifies whether the archive will be used for storing or loading data to or from the file. The Serialize function of an object checks this state by calling the IsStoring function for the archive object.

When you are finished storing or loading data to or from the CArchive object, close it. Although the CArchive (and CFile) objects will automatically close the archive (and file), it is good practice to explicitly do so since it makes recovery from errors easier. For more information, see »Catching Exceptions«.

To close the CArchive object

•	The following example illustrates how to close the CArchive object:

archive.Close();
theFile.Close();


 Using the CArchive << and >> Operators

CArchive provides << and >> operators for writing and reading simple data types as well as CObjects to and from a file.

To store an object in a file via an archive

•	The following example shows how to store an object in a file via an archive:

CArchive ar(&theFile, CArchive::store);
WORD wEmployeeID;
...
ar << wEmployeeID;

To load an object from a value previously stored in a file

•	The following example shows how to load an object from a value previously stored in a file:

CArchive ar(&theFile, CArchive::load);
WORD wEmployeeID
...
ar >> wEmployeeID;

Usually, the places where you store and load data to and from a file via an archive are in the Serialize functions of CObject-derived classes, which you must have declared with the DECLARE_SERIALIZE macro. A reference to a CArchive object is passed to your Serialize function. You call the IsLoading function of the CArchive object to determine whether the Serialize function has been called to load data from the file or store data to the file.

The Serialize function of a serializable CObject-derived class typically has the following form:

void CPerson::Serialize(CArchive& ar)
{
CObject::Serialize(ar);
if (ar.IsStoring())
{
// TODO:  add storing code here
}
else
{
// TODO:  add loading code here
}
}

The above code template is exactly the same as the one that AppWizard creates for the Serialize function of the document (a class derived from CDocument). This code template helps you write code that is easier to review, because the storing code and the loading code should always be parallel, as in the following example:

void CPerson:Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_strName;
ar << m_wAge
}
else
{
ar >> m_strName;
ar >> m_wAge;
}
}

The library defines << and >> operators for CArchive as the first operand and the following data types and class types as the second operand:

CObject* (see topic following)	BYTE
WORD	LONG
DWORD	float
double	POINT and CPoint
SIZE and CSize	RECT and CRect
CString	CTime and CTimeSpan
The CArchive << and >> operators always return a reference to the CArchive object, which is the first operand. This enables you to chain the operators, as illustrated below:

BYTE bSomeByte;
WORD wSomeWord;
DWORD wSomeDoubleWord;
...
ar << bSomeByte << wSomeWord << wSomeDoubleWord;


 Storing and Loading CObjects via an Archive

Storing and loading CObjects via an archive requires extra consideration. In certain cases, you should call the Serialize function of the object, where the CArchive object is a parameter of the Serialize call, as opposed to using the << or >> operator of the CArchive. The important fact to keep in mind is that the CArchive >> operator constructs the CObject in memory based on CRuntimeClass information previously written to the file by the storing archive.

Therefore, whether you use the CArchive << and >> operators, versus call Serialize, depends on whether you need the loading archive to dynamically reconstruct the object based on previously stored CRuntimeClass information. Use the Serialize function in the following cases:

1.	When deserializing the object, you know the exact class of the object beforehand.

2.	When deserializing the object, you already have memory allocated for it.

Note  If you load the object using the Serialize function, then you must also store the object using the Serialize function. Don't store using the CArchive << operator and then load using the Serialize function, or store using the Serialize function and then load using CArchive >> operator.

The following example illustrates the cases:

class CMyObject : public CObject
{
// ...Member functions
CMyObject();
virtual void Serialize( CArchive& ar );

// Implementation
protected:
DECLARE_SERIAL( CMyObject )
};

class COtherObject : public CObject
{
// ...Member functions
COtherObject();
virtual void Serialize( CArchive& ar );

// Implementation
protected:
DECLARE_SERIAL( COtherObject )
};

class CCompoundObject : public CObject
{
// ...Member functions
CCompoundObject();
virtual void Serialize( CArchive& ar );

// Implementation
protected:
CMyObject m_myob;	// Embedded object
COtherObject* m_pOther;	// Object allocated in constructor
CObject* m_pObDyn;	// Dynamically allocated object
//..Other member data and implementation

DECLARE_SERIAL( CCompoundObject )

};

CCompoundObject::CCompoundObject()
{
m_pOther = new COtherObject; // Exact type known and object already
//allocated.
m_pObDyn = NULL;	// Will be allocated in another member function
// if needed, could be a derived class object.
}

void CCompundObject::Serialize( CArchive& ar )
{
CObject::Serialize( ar );	// Always call base class Serialize.
m_myob.Serialize( ar );	// Call Serialize on embedded member.
m_pOther->Serialize( ar );	// Call Serialize on objects of known
exact type.

// Serialize dynamic members and other raw data
if ( ar.IsStoring() )
{
ar << m_pObDyn;
// Store other members
}
else
{
ar >> m_pObDyn; // Polymorphic reconstruction of persistent
// object
//load other members
}
}

In summary, if your serializable class defines an embedded CObject as a member, then you should not use the CArchive << and >> operators for that object, but should call the Serialize function instead. Also, if your serializable class defines a pointer to a CObject as a member, but constructs this other object in its own constructor, then you should also call Serialize.


 Chapter 15  Diagnostics

The Microsoft Foundation Class Library contains many diagnostic features to help debug your program during development. These features, especially those that track memory allocations, will slow down your program. Others, such as assertion testing, will cause your program to halt when erroneous conditions are encountered.

In a commercial retail product, slow performance and program interruption are clearly unacceptable. For this reason, the Microsoft Foundation Class Library provides a method for turning the debugging and diagnostic features on or off. When you are developing your program, you typically build a debug version of your program and link with the Debug version of the Microsoft Foundation Class Library. Once the program is completed and debugged, you build a release version and link with the Release version of the Microsoft Foundation library.


 Debugging Features

The following features are included for all classes derived from CObject in the Debug version of the Microsoft Foundation Class Library:

•	Dump member function to dump object contents to debugging output

•	Trace output to print or display debugging output to evaluate argument validity

•	Assertions and AssertValid member function

•	Memory diagnostics to detect memory leaks

•	DEBUG_NEW macro to show where objects were allocated

To enable the debugging features

1.	Compile with the symbol _DEBUG defined. This is typically done by passing the /D_DEBUG flag on the compiler command line. To accomplish this in Visual C++, set the Debug option in the Project Options dialog box, which happens automatically when you turn on the Use Microsoft Foundation Class check box. When you define the _DEBUG symbol, sections of code delimited by #ifdef _DEBUG / #endif are compiled.

2.	Link with the Debug versions of the Microsoft Foundation Class Library. Setting the Debug option in Visual C++ ensures linking with the Debug libraries. The Debug versions of the library have a "D" at the end of the library name. For example, the medium-model Debug version of the Microsoft Foundation Class Library for Windows is named MAFXCWD.LIB, and the Release version (non-debug) is named MAFXCW.LIB.


 Dumping Object Contents

When deriving a class from CObject, you have the option to override the Dump member function and write a textual representation of the object's member variables to a dump context, which is similar to an I/O stream. Like an I/O stream, you can use the insertion (<<) operator to send data to a CDumpContext.

You do not have to override Dump when you derive a class from CObject. However, if you use other diagnostic features for debugging, providing the capa-bility for dumping an object and viewing its contents is very helpful and highly recommended.

To override the Dump member function

1.	Call the base class version of Dump to dump the contents of a base class object.

2.	Write a textual description and value for each member variable of your derived class.

The declaration of the Dump function in the class declaration looks like:

class CPerson : public CObject
{
public:
#ifdef _DEBUG
virtual void Dump( CDumpContext& dc ) const;
#endif

CString m_firstName;
CString m_lastName;
// etc. ...
};

Note  Since object dumping only makes sense when you are debugging your program, the declaration of the Dump function is bracketed with an #ifdef _DEBUG / #endif block.

In the following example from an implementation file for the class CPerson, the Dump function's first statement calls the Dump member function for its base class. It then writes a short description of each member variable along with the member's value to the diagnostic stream.

#ifdef _DEBUG
void CPerson::Dump( CDumpContext& dc ) const
{
// call base class function first
CObject::Dump( dc );

// now do the stuff for our specific class
dc	<< "last name: " << m_lastName << "\n"
<< "first name: " << m_firstName ;
}
#endif

Note  Again, notice that the definition of the Dump function is bracketed by #ifdef _DEBUG / #endif directives. If you refer to afxDump in a program linked with the nondebug libraries, you will get unresolved externals errors at link time.

To send Dump output to afxDump

•	You must supply a CDumpContext argument to specify where the dump output will go when you call the Dump function for an object. The Microsoft Foundation Class Library supplies a predefined CDumpContext object named afxDump that you will normally use for routine object dumping. The following example shows how to use afxDump:

CPerson pMyPerson = new CPerson;
// set some fields of the CPerson object...
//..
// now dump the contents
#ifdef _DEBUG
pMyPerson->Dump( afxDump );
#endif

In Windows, afxDump output is sent to the debugger, if present. In MS-DOS, afxDump output is sent to stderr.

Note  afxDump is defined only in the Debug version of the Microsoft Foundation Class Library.


 The TRACE Macro

The TRACE macro can be used during development to print or display debugging messages from a program. TRACE prints a string argument to the current diagnostic output device. For programs with character-based output in MS-DOS, the TRACE output will go to stderr. For Windows programs, the TRACE output will be directed to your debugger (or to the AUX port, which can be captured using DBWIN.EXE, found in \MSVCNT\BIN).

The TRACE macro can handle a variable number of arguments, similar to the way printf operates. Following are examples of different ways to use TRACE macros:

int x = 1;
int y = 16;
float z = 32.0;
TRACE( "This is a TRACE statement\n" );

TRACE( "The value of x is %d\n", x );

TRACE( "x = %d and y = %d\n", x, y );

TRACE( "x = %d and y = %x and z = %f\n", x, y, z );

The TRACE macro is active only in the Debug version of the library. After a program has been debugged, you can build a Release version to deactivate all TRACE calls in the program. For important information on the TRACE macro, see "Globals and Macros" in the Class Library Reference and Technical Note 7 in \MSVCNT\HELP\MFCNOTES.HLP.


 The ASSERT Macro

The most typical use of the ASSERT macro is to identify program errors used during development. The argument given to ASSERT should be chosen so that it holds true only if the program is operating as intended. The macro evaluates the argument; and if the argument expression is false (0), prints a diagnostic message and halts program execution. No action is taken if the argument is true (nonzero).

In MS-DOS, the diagnostic message is sent to afxDump and has the form:

assertion failed in file <name> in line <num>

where <name> is the name of the source file and <num> is the line number of the assertion that failed. In Windows, the following message box appears:

assertion failed in file <name> in line <num>
Abort Retry Ignore

If you choose Abort, program execution terminates. If you choose Retry, the debugger is activated. If you choose Ignore, program execution continues.

The following example shows how the ASSERT macro could be used to check the validity of a function's return value:

int x = SomeFunc(y);
ASSERT(x == 0);   //  Assertion fails if x not equal to 0

ASSERT can also be used in combination with the IsKindOf function to provide extra checking for function arguments, such as in the following example. (For a discussion of the IsKindOf function, see »Accessing Run-Time Class Information«).

ASSERT( pObject1->IsKindOf( RUNTIME_CLASS( CPerson ) ) );

The liberal use of assertions throughout your programs can catch errors during development. A good rule of thumb is that you should write assertions for any assumptions you make. For example, if you assume that an argument is not NULL, then you should use an assertion statement to check for that condition.

The ASSERT macro will catch errors only when you are using the Debug version of the Microsoft Foundation Class Library during development. It will be turned off (produce no code) when you build your program with the Release version of the library.

Note  The expression argument to ASSERT will not be evaluated in the release version of your program. If you want the expression to be evaluated in both debug and release environments, use the VERIFY macro instead of ASSERT. In debug versions, VERIFY simply passes its expression argument to ASSERT. In release environments, VERIFY evaluates the expression argument but does not check the result.


 The ASSERT_VALID Macro

Use the ASSERT_VALID macro to perform a run-time check of an object's internal consistency. The class of that object should override the AssertValid function of CObject as described in the next section. The ASSERT_VALID macro is a more robust way of accomplishing:

pObject->AssertValid();

Like the ASSERT macro, ASSERT_VALID is turned on in the debug version of your program, but turned off in the release version.


 Overriding the AssertValid Function

The AssertValid member function is provided in CObject to allow run-time checks of an object's internal state. AssertValid typically performs assertions on all the object's member variables to see if they contain valid values. For example, AssertValid can check that all pointer member variables are not NULL. If the object is invalid, AssertValid halts the program.

Although you are not required to override AssertValid when you derive your class from CObject, you can make your class safer and more reliable by doing so. The following example shows how to declare the AssertValid function in the class declaration:

class CPerson : public CObject
{
protected:
CString m_strName;
float   m_Salary;
public:
virtual void AssertValid() const    // Override

// ...
};

When you override AssertValid, first call AssertValid for the base class. Then use the ASSERT macro to check the validity of the members that are unique to your derived class, as shown by the following example:

void CPerson::AssertValid()
{
// call inherited AssertValid first
CObject::AssertValid()

// check CPerson members...
ASSERT( !m_strName.IsEmpty()); \\Must have a name.
ASSERT( m_Salary ! 0 ); \\Must have an income
}

If any of the member variables of your class store objects, you can use the ASSERT_VALID macro to test their internal validity (if their classes override AssertValid). The following example shows how this is done.

Consider a class CDataBase, which stores a CObList in one of its member variables. The CObList variable, m_DataList, stores a collection of CPerson objects. An abbreviated declaration of CDataBase looks like this:

class CDataBase : public CObject
{
// Constructor and other members ...
protected:
CObList * m_DataList;
// Other declarations ...
public:
virtual void AssertValid( ) const; // Override
// Etc. ...
};

The AssertValid override in CDataBase looks like this:

void CDataBase::AssertValid( )
{
// Call inherited AssertValid
CObject::AssertValid( );
// Check validity of CDataBase members
ASSERT_VALID( m_pDataList );
// ...

}

CDataBase uses the AssertValid mechanism to add validity tests for the objects stored in its data member to the validity test of the CDataBase object itself. The overriding AssertValid of CDataBase invokes the ASSERT_VALID macro for its own m_pDataList member variable.

The chain of validity testing might stop at this level, but in this case class CObList overrides AssertValid too, and the ASSERT_VALID macro causes it to be called. This override performs additional validity testing on the internal state of the list. If an assertion failure occurs, diagnostic messages are printed, and the program halts.

Thus a validity test on a CDataBase object leads to additional validity tests for the internal states of the stored CObList list object. With a little more work, the validity tests could include the CPerson objects stored in the list as well. You could derive a class CPersonList from CObList and override AssertValid. In the override, you would call CObject::AssertValid and then iterate through the list, calling AssertValid on each CPerson object stored in the list. CPerson already overrides AssertValid.

This is a powerful mechanism when you build for debugging, and when you subsequently build for release, the mechanism is turned off automatically.

Users of an AssertValid function of a given class should be aware of the limitations of this function. A triggered assertion indicates that the object is definitely bad and execution will halt. However, a lack of assertion only indicates that no problem was found, but the object isn't guaranteed to be good.


 Detecting Memory Leaks

A memory leak occurs when you allocate memory on the heap and never deallocate that memory to make it available for reuse, or if you mistakenly use memory that has already been allocated. This is a particular problem for programs that are intended to run for extended periods. In a long-lived program, even a small incremental memory leak can compound itself; eventually all available memory resources are exhausted and the program crashes. Traditionally, memory leaks have been very hard to detect.

The Microsoft Foundation Class Library provides classes and functions that you can use to detect memory leaks during development. Basically, these functions take a snapshot of all memory blocks before and after a particular set of operations. You can use these results to determine if all memory blocks allocated during the operation have been deallocated.

The size of the operation that you choose to bracket with these diagnostic functions is arbitrary. It can be as small as a single program statement, or it can span the entry and exit from the entire program. Either way, these functions will allow you to detect memory leaks and identify which memory blocks have not been deallocated properly.


 Memory Diagnostics

To enable or disable memory diagnostics

•	Call the global function AfxEnableMemoryTracking to enable or disable the diagnostic memory allocator. Since memory diagnostics are on by default in the Debug library, you will typically use this function to temporarily turn them off, which increases program execution speed and reduces diagnostic output.

To select specific memory diagnostic features with afxMemDF

•	If you want more precise control over the memory diagnostic features, you can selectively turn individual memory diagnostic features on and off by setting the value of the Microsoft Foundation Class Library global variable afxMemDF. This variable can have the following values as specified by the enumerated type AfxMemDF:

Value	Meaning
allocMemDF	Turn on debugging allocator (default).
delayFreeMemDF	Delay freeing memory when calling delete or free. This will cause maximum memory stress for your program.
checkAlwaysMemDF	Call AfxCheckMemory every time memory is allocated or freed.
These values can be used in combination by performing a logical-OR operation, as shown here:

afxMemDF |= delayFreeMemDF | checkAlwaysMemDF;


 Detecting a Memory Leak

The following instructions and examples show you how to detect a memory leak.

To detect a memory leak

1.	Create a CMemoryState object and call the Checkpoint member function to get the initial snapshot of memory.

2.	After you perform the memory allocation and deallocation operations, create another CMemoryState object and call Checkpoint for that object to get a current snapshot of memory usage.

3.	Create a third CMemoryState object, call the Difference member function, and supply the previous two CMemoryState objects as arguments. The return value for the Difference function will be nonzero if there is any difference between the two specified memory states, indicating that some memory blocks have not been deallocated.

The following example shows how to check for memory leaks:

// Declare the variables needed
#ifdef _DEBUG
CMemoryState oldMemState, newMemState, diffMemState;
#endif

#ifdef _DEBUG
oldMemState.Checkpoint();
#endif

// do your memory allocations and deallocations...
CString s = "This is a frame variable";
// the next object is a heap object
CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );

#ifdef _DEBUG
newMemState.Checkpoint();
if( diffMemState.Difference( oldMemState, newMemState ) )
{
TRACE( "Memory leaked !\n" );
}
#endif

Notice that the memory-checking statements are bracketed by
#ifdef _DEBUG / #endif blocks so that they are only compiled in debug versions of your program.


 Dumping Memory Statistics

The CMemoryState member function Difference determines the difference between two memory-state objects. It detects any objects that were not deallocated from the heap between the beginning and end memory-state snapshots.

To dump memory statistics

•	The following example (continuing the example from the previous section) shows how to call DumpStatistics to get information about the objects that have not been deallocated:

if( diffMemState.Difference( oldMemState, newMemState ) )
{
TRACE( "Memory leaked !\n" );
diffMemState.DumpStatistics();
}

A sample dump from the example above is shown here:

0 bytes in 0 Free Blocks
22 bytes in 1 Object Blocks
45 bytes in 4 Non-Object Blocks
Largest number used: 67 bytes
Total allocations: 67 bytes

•	The first line describes the number of blocks whose deallocation was delayed if afxMemDF was set to delayFreeMemDF. For a description of afxMemDF, see the procedure "To select specific memory diagnostic features with afxMemDF" presented under »Memory Diagnostics«.

•	The second line describes how many objects remain allocated on the heap.

•	The third line describes how many nonobject blocks (arrays or structures allocated with new) were allocated on the heap and not deallocated.

•	The fourth line gives the maximum memory used by your program at any one time.

•	The last line lists the total amount of memory used by your program.


 Dumping All Objects

DumpAllObjectsSince dumps out a description of all objects detected on the heap that have not been deallocated. As the name implies, DumpAllObjectsSince dumps all objects allocated since the last Checkpoint. However, if no Checkpoint has taken place, all objects and nonobjects currently in memory are dumped.

To dump all objects

•	Expanding on the previous example, the following code dumps all objects that have not been deallocated when a memory leak is detected:

if( diffMemState.Difference( oldMemState, newMemState ) )
{
TRACE( "Memory leaked !\n" );
diffMemState.DumpAllObjectsSince();
}

A sample dump from the preceding example is shown here:

Dumping objects ->

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

{1} strcore.cpp(80) : non-object block at $00A7516E, 25 bytes long

The numbers in braces at the beginning of most lines specify the order in which the objects were allocated. The most recently allocated object is displayed first. You can use these ordering numbers to help identify allocated objects.


 Interpreting an Object Dump

The preceding dump comes from the original memory checkpoint example in »Detecting a Memory Leak«. Remember that there were only two explicit allocations in that program — one on the frame and one on the heap:

// do your memory allocations and deallocations ...
CString s = "This is a frame variable";
// the next object is a heap object
CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );

Start with the CPerson object; its constructor takes three arguments that are pointers to char. The constructor uses these arguments to initialize CString member variables for the CPerson class. In the memory dump, you can see the CPerson object listed along with three nonobject blocks (3, 4, and 5) that hold the characters for the CString member variables. These memory blocks will be deleted when the destructor for the CPerson object is invoked.

Block number 2 represents the CPerson object itself. After the CPerson address listing, the contents of the object are displayed. This is a result of DumpAllObjectsSince calling the Dump member function for the CPerson object.

You can guess that block number 1 is associated with the CString frame variable because of its sequence number and its size, which match the number of characters in the frame CString variable. The allocations associated with frame variables are automatically deallocated when the frame variable goes out of scope.

In general, you shouldn't worry about heap objects associated with frame variables because they are automatically deallocated when the frame variables go out of scope. In fact, you should position your calls to Checkpoint so that they are outside the scope of frame variables to avoid clutter in your memory diagnostic dumps. For example, place scope brackets around the previous allocation code, as shown here:

oldMemState.Checkpoint();
{
// do your memory allocations and deallocations ...
CString s = "This is a frame variable";
// the next object is a heap object
CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
}
newMemState.Checkpoint();

With the scope brackets in place, the memory dump for this example is as follows:

Dumping objects ->

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

Notice that some allocation are objects (such as CPerson) and some are non-object allocations. "Non-object allocations" are allocations for objects not derived from CObject or allocations of primitive C types such as char, int, or long. If the CObject-derived class allocates additional space, such as for internal buffers, those objects will show both object and non-object allocations

Notice that the memory block associated with the CString frame variable has been deallocated automatically and does not show up as a memory leak. The automatic deallocation associated with scoping rules takes care of most memory leaks associated with frame variables.

For objects allocated on the heap, however, you must explicitly delete the object to prevent a memory leak. To clean up the last memory leak in the previous example, you can delete the CPerson object allocated on the heap, as follows:

{
// do your memory allocations and deallocations ...
CString s = "This is a frame variable";
// the next object is a heap object
CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
delete p;
}


 Using DEBUG_NEW to Aid Debugging

The Microsoft Foundation Class Library defines the macro DEBUG_NEW to assist you in locating memory leaks. You can use DEBUG_NEW everywhere in your program that you would ordinarily use the new operator.

When you compile a Debug version of your program, DEBUG_NEW keeps track of the filename and line number for each object that it allocates. Then, when you call DumpAllObjectsSince, as described in the previous section, each object allocated with DEBUG_NEW will be shown with the file and line number where it was allocated, thus allowing you to pinpoint the sources of memory leaks.

When you compile a Release version of your program, DEBUG_NEW resolves to a simple new operation without the filename and line number information. Thus, you pay no speed penalty in the Release version of your program.

To use DEBUG_NEW

•	Define a macro in your source files that replaces new with DEBUG_NEW, as shown here:

#define new DEBUG_NEW

You can then use new for all heap allocations. The preprocessor will substitute DEBUG_NEW when compiling your code. In the Debug version of the library, DEBUG_NEW will create debugging information for each heap block. In the Release version, DEBUG_NEW will resolve to a standard memory allocation without the extra debugging information.

Note  You must place the #define statement after all statements that call the IMPLEMENT_DYNCREATE or IMPLEMENT_SERIAL macros in your module, or you will get a compile-time error.


 Chapter 16  Exceptions

There are three categories of outcomes that can occur when a function is called during program execution: normal execution, erroneous execution, or abnormal execution. Each category is described below.

•	Normal execution

The function may execute normally and return. Some functions return a result code to the caller, which indicates the outcome of the function. The possible result codes are strictly defined for the function and represent the range of possible outcomes of the function. The result code can indicate success or failure or can even indicate a particular type of failure that is within the normal range of expectations. For example, a file-status function can return a code that indicates that the file does not exist. Note that the term "error code" is not used since a result code represents one of many expected outcomes.

•	Erroneous execution

The caller makes some mistake in passing arguments to the function or calls the function in an inappropriate context. This situation causes an error, and it should be detected by an assertion during program development. (For more information on assertions, see »The ASSERT Macro«.)

•	Abnormal execution

Abnormal execution includes situations where conditions outside the program's control are influencing the outcome of the function, such as low memory or I/O errors. Abnormal situations should be handled by catching and throwing exceptions.


 Microsoft Foundation Classes Exception Handling

The Microsoft Foundation Class Library uses an exception-handling scheme that is very similar to one proposed by the ANSI standards committee for C++ 2.1. You set up an exception handler before calling functions that you think might encounter abnormal situations. If your program does run into abnormal conditions, then it throws an exception. When an exception is thrown, program execution jumps to the exception handler and execution resumes there.

Exceptions are represented as objects derived from the abstract class CException. The Microsoft Foundation Class Library provides several predefined kinds of exceptions:

Exception Class	Meaning
CMemoryException	Out-of-memory
CFileException	File exception
CArchiveException	Archive/Serialization exception
CNotSupportedException	Response to request for unsupported service
CResourceException	Windows resource allocation exception
COleException	OLE exceptions
CUserException	Exception that alerts the user with a message box, then throws a generic CException
Since many parts of the Microsoft Foundation Class Library, especially those dealing with files and serialization, use exceptions to report abnormal conditions, you will find it useful to use the Microsoft Foundation exception-handling mechanism in the parts of your program that call those types of Microsoft Foundation Class Library functions. For a description of each Microsoft Foundation Class Library function and the exceptions that can possibly be thrown by that function, see the Class Library Reference. If you see that a function can throw an exception, you should probably surround it with an exception handler.


 Catching Exceptions

The following instructions and examples will show you how to catch exceptions.

To catch exceptions

•	Use the TRY macro to set up a TRY block. Execute any program statements that might throw an exception within a TRY block.

Use the CATCH macro to set up a CATCH block. Place exception handling code in a CATCH block. The code in the CATCH block is executed only if the code within the TRY block throws an exception of the type specified in the CATCH statement.

The following skeleton shows how TRY and CATCH blocks are normally arranged:

// Normal program statements
...

TRY
{
// Execute some code that might throw an exception.
}
CATCH( CException, e )
{
// Handle the exception here.
// "e" contains information about the exception
}
END_CATCH

// Other normal program statements
...

Note  The END_CATCH macro marks the end of the CATCH blocks.

The CATCH macro takes an exception-type parameter, allowing you to selectively handle different types of exceptions with sequential CATCH and AND_CATCH blocks as listed below:

TRY
{
// Execute some code that might throw an exception.
}
CATCH( CMemoryException, e )
{
// Handle the out-of-memory exception here.
}
AND_CATCH( CFileException, e )
{
// Handle the file exceptions here.
}
AND_CATCH( CException, e )
{
// Handle all other types of exceptions here.
}
END_CATCH


 Examining Exception Contents

The CATCH macro includes an argument that is used to hold a pointer to a CException object (or an object derived from CException, such as CMemoryException). Depending on the exact type of the exception, you can examine the data members of the exception object to gather information about the specific cause of the exception.

For example, the CFileException type has the m_cause data member that contains an enumerated type that specifies the cause of the file exception. Some examples of the possible return values are CFileException::fileNotFound and CFileException::readOnly.

To examine exception contents

•	The following example shows how to examine the contents of a CFileException. Other exception types can be examined in a similar way.

TRY
{
// Do something to throw a file exception.
}
CATCH( CFileException, theException )
{
if( theException->m_cause == CFileException::fileNotFound )
TRACE( "File not found\n" );
}
END_CATCH


 Freeing Objects in Exceptions

The exception-handling mechanism of the Microsoft Foundation Class Library can interrupt normal program flow. Thus, it is very important to keep close track of objects that have been created on the heap so that you can properly dispose of them in case an exception is thrown.

There are two primary methods to do this.

•	Handle exceptions locally using the TRY and CATCH macros, then destroy all objects with one statement.

•	Destroy any object in the CATCH block before the exception is thrown outside for further handling.

These two approaches are illustrated below as solutions to the following problematic example:

void SomeFunc()
{
CPerson* myPerson = new CPerson;

// Do something that might throw an exception.
myPerson->SomeFunc();

// Now destroy the object before exiting.
delete myPerson;
}

As written above, myPerson will not be deleted if an exception is thrown by SomeFunc. Execution jumps directly to the innermost exception handler, bypassing the normal function exit and the code that deletes the object. The pointer to the object goes out of scope when the exception leaves the function, and the memory occupied by the object will never be recovered as long as the program is running. This is known as a memory leak and would be detected by using the memory diagnostics.


 Handle the Exception Locally

The TRY/CATCH paradigm provides a defensive programming method for avoiding memory leaks and ensuring that your objects are destroyed when exceptions occur. For example, the previous example in the topic »Freeing Objects in Exceptions« could be rewritten as shown below:

void SomeFunc()
{
CPerson* myPerson = new CPerson;

TRY
{
// Do something that might throw an exception.
myPerson->SomeFunc();
}
CATCH( CException, e )
{
// Handle the exception locally.
}
END_CATCH

// Now destroy the object before exiting.
delete myPerson;
}

This new example sets up an exception handler to catch the exception and handle it locally. It then exits the function normally and destroys the object. The important aspect of this example is that a context to catch the exception is established with the TRY/CATCH blocks. Without a local exception frame, the function would never know that an exception had been thrown and would not have the chance to exit normally and destroy the object.


 Throw Exceptions After Destroying Objects

Another way to handle exceptions is to pass them on to the next outermost exception-handling context. In your CATCH block, you can do some cleanup of your locally allocated objects and then throw the exception on for further processing. The following example shows how this can be done:

void SomeFunc()
{
CPerson* myPerson = new CPerson;

TRY
{
// Do something that might throw an exception.
myPerson->SomeFunc();
}
CATCH( CException, e )
{
 // Destroy the object before passing exception on.
delete myPerson;
// Throw the exception to the next handler.
THROW_LAST( );
}
END_CATCH

// On normal exits, destroy the object.
delete myPerson;
}

If you call functions that can throw exceptions, you can use TRY/CATCH blocks to make sure that you catch the exceptions and have a chance to destroy any objects you have created. In particular, be aware that many Microsoft Foundation Class Library functions can throw exceptions.


 Throwing Exceptions from Your Own Functions

It is possible to use the Microsoft Foundation Class Library exception-handling paradigm solely to catch exceptions thrown by functions in the Microsoft Foundation Class Library or other libraries. In addition to catching exceptions thrown by library code, you can throw exceptions from your own code if you are writing functions that can encounter exceptional conditions.

To throw an exception

•	Use one of the Microsoft Foundation Class Library helper functions, such as AfxThrowMemoryException, listed in AFX.H. These functions throw a preallocated exception object of the appropriate type.

When an exception is thrown, execution of the current function is aborted and jumps directly to the CATCH block of the innermost exception frame. The exception mechanism bypasses the normal exit path from a function. Therefore, you must be sure to delete those memory blocks that would be deleted in a normal exit. In the following example, a function tries to allocate two memory blocks and throws an exception if either allocation fails:

{
char* p1 = malloc( SIZE_FIRST );
if( p1 == NULL )
AfxThrowMemoryException();
char* p2 = malloc( SIZE_SECOND );
if( p2 == NULL )
{
free( p1 );
AfxThrowMemoryException();
}

// ... Do something with allocated blocks ...

// In normal exit, both blocks are deleted.
free( p1 );
free( p2 );
}

If the first allocation fails, you can simply throw the memory exception. If the first allocation is successful but the second one fails, you must free the first allocation block before throwing the exception. If both allocations succeed, then you can proceed normally and free the blocks when exiting the function.


 Exceptions in Constructors

When throwing an exception in a constructor, clean up whatever objects and memory allocations you have made prior to throwing the exception, as explained in the previous section.

Throwing an exception in a constructor is tricky, however, because the memory for the object itself has already been allocated by the time the constructor is called. There is no simple way to deallocate the memory occupied by the object from within the constructor for that object. Thus, you will find that throwing an exception in a constructor will result in the object remaining allocated. For a discussion of how to detect objects in your program that have not been deallocated, see »Detecting Memory Leaks«.

If you are performing operations in your constructor that can fail, it might be a better idea to put those operations into a separate initialization function rather than throwing an exception in the constructor. That way, you can safely construct the object and get a valid pointer to it. Then, you can call the initialization function for the object. If the initialization function fails, you can delete the object directly.


 Frame Variables and Exceptions

Explicitly allocated heap objects must also be deallocated before an exception is thrown. With frame objects, the frame memory will be reclaimed automatically by the exception mechanism. Although the memory occupied by the frame object is reclaimed, the destructor for the frame object is not executed by the exception mechanism.

For most objects, the reclamation of frame space is sufficient to clean up the object. But, for objects that allocate memory in addition to the frame space they occupy, such as CString objects, the default exception handling is not sufficient to completely deallocate the object. In addition, objects whose destructors are an integral part of their operations need special handling during exceptions.

When a CString object is allocated on the frame, its constructor also allocates memory on the heap to hold the characters of the string. Thus, a CString occupies space on the frame and also on the heap. When a CString frame variable is destroyed normally, its destructor takes care of deallocating the heap space used by the object. When the normal destruction of the CString is bypassed by an exception, this heap space is not deallocated, even though the frame space occupied by the CString is reclaimed.

To avoid a CString memory leak

•	Call the Empty function for any CString frame variables when handling an exception. The following example shows how to do this:

{
CString s1 = "This is a test";

TRY
{
char* p1 = new char[ A_BIG_BLOCK ];
}
CATCH( CMemoryException,e )
{
// Deallocate heap space used by string.
s1.Empty();

// Now you can safely throw the exception.
THROW_LAST( );
}
END_CATCH
}

The need to explicitly deallocate heap resources for a frame-based object is not limited to CString objects. Since the destructors for frame objects are not automatically executed when an exception interrupts normal program flow, any frame-based object where the destructor performs significant tasks will need special attention during exception handling.


Chapter 18 OLE Support
 Chapter 17  OLE Support

Object Linking and Embedding (OLE) is a mechanism that allows users to create and edit documents containing data created by multiple applications. This allows a single document to contain text, graphics, spreadsheets, sound, or other types of data. By supporting OLE in your application, you can let users combine data that it creates with data created by other applications.

This chapter describes how to use the Microsoft Foundation Class Library to write an application that supports OLE.


 Overview of OLE

Before discussing how the Microsoft Foundation Class Library supports OLE, it's helpful to review the basic concepts involved in OLE. This section describes OLE from the user's point of view and then defines some common OLE terms. For a complete description of OLE, see the OLE Programmer's Reference or the documentation in the appropriate software development kit.


 Using OLE

As an example of how OLE changes the way applications work together, consider how you would use a drawing program and a text editor together. You can demonstrate this yourself by using the Paintbrush and Write applications included with Windows version 3.1. Suppose you want to insert a picture in a text document.

To insert a picture in a text document

1.	Open Paintbrush and draw a picture.

2.	Select a portion of the picture and copy it into the Clipboard.

3. 	Exit Paintbrush.

4.	Open Write and enter some text.

5.	Choose the Paste command. The portion of the picture you selected earlier is inserted into the document.

Now suppose that, after entering some more text, you want to modify the picture in the document. If Paintbrush and Write didn't support OLE, you would essentially have to repeat the entire process.

To modify a picture in a text document, without OLE

1.	Open Paintbrush again and reload the original picture (assuming you saved it; otherwise recreate it). Make the desired modifications.

2.	Repeat steps 2 through 5 above, replacing the original picture in the document.

However, the Windows 3.1 versions of Paintbrush and Write support OLE. As a result, the process is much simpler.

To modify a picture in a text document, using OLE

•	Double-click on the picture in the document from within Write.

Paintbrush is automatically invoked with the picture from your document. Modify the picture as desired and then exit the drawing program. Your document is still open in Write, but the picture has been updated. You can now continue entering text.

With OLE, Write and Paintbrush work together to produce a single document consisting of both text and graphics. You can edit the entire document as a single entity, rather than having to edit its components separately and combine them later. OLE allows you to invoke the appropriate application, as needed, whenever you work on a given portion of the document. A document that contains data created by different applications is called a "compound document."

While you use the Paste command in the same way in OLE and non-OLE applications, the command is clearly performing very different operations in each case. The difference can be clearly illustrated when you consider the action of pasting some cells from a worksheet into a text document. Compare what happens with a non-OLE spreadsheet application versus an OLE spreadsheet application, such as Microsoft Excel:

•	If you paste some cells from a non-OLE worksheet into a text document, what gets inserted is a textual representation of the numbers in the cells.

•	If you paste some cells from an Excel worksheet into a Write document, what gets inserted are the actual floating-point values used by Excel, plus any associated formulas. The textual representation is still used for display purposes, but when you double-click on those numbers while working within Write, the original floating-point values are sent back to Excel. This is what allows you to edit the cells again without re-entering the data.

In a non-OLE application, the Paste command inserts a representation of the original data using a format that the receiving application knows how to display. In an OLE application, the Paste command still inserts this "presentation" data, but this is used for display purposes only; the command also inserts the actual data used by the donor application. This data is called the "Native" data for the item.


 Embedded vs. Linked Items

Using the Paste command in an OLE application creates an "embedded item." An embedded item is stored as part of the compound document that contains it. In this way, a .WRI file for a Write document can contain not only text, but also bitmaps, floating-point numbers and formulas, or any other type of data.

OLE also provides another way to incorporate data from another application: creating a "linked item." The steps for creating a linked item are similar to those for creating an embedded item, except that instead of using the Paste command, you use the Paste Link command. The difference between a linked item and an embedded item is that with a linked item, the data is stored in a separate file.

For example, if you create a linked item of some cells from an Excel worksheet, the data for that item is stored in the .XLS file for that particular worksheet. The Write document contains only the information that specifies where the item can be found; that is, it contains a link to the item's .XLS file. When you double-click on those cells, Excel is launched and the original worksheet file is loaded in for editing.

A linked item has a couple of advantages over an embedded item:

•	The compound document is smaller, since it contains only a link rather than all the data for the item.

•	If the original document is updated, the linked item is also updated.

Every OLE item, whether embedded or linked, has a type associated with it; an item's type is based on the application that created it. For example, a Paintbrush item is one type of item, while an Excel item is another type. However, some applications can create more than one type of item; for example, Excel can create worksheet items, chart items, and macrosheet items.

Note  The Microsoft Windows Software Development Kit (SDK) refers to embedded and linked items as "objects" and refers to types of items as "classes." This chapter uses the term "item" to distinguish the OLE entity from the corresponding C++ object and the term "type" to distinguish the OLE category from the C++ class.

For more information on what kind of data is stored in embedded and linked items, see the OLE Programmer's Reference or the documentation in the appropriate software development kit.


 Clients and Servers

An application that can incorporate embedded or linked items into its own documents is called a "client application." An application that can create items for use by client applications is called a "server application." In the earlier examples, Write is the client application while Paintbrush and Excel are the server applications.

The documents managed by a client application must be able to store and display OLE items as well as data created by the application itself. A client application must also allow users to insert new items or edit existing items. The user-interface requirements of a client application are listed in »Implementing a Client Application«.

Some server applications, such as Paintbrush, support the creation of embedded items only, while others, such as Excel, support the creation of both embedded and linked items. All server applications must be able to be invoked by a client application when the user wants to edit an item. If a server application supports linked items, it must also be able to copy its data to the Clipboard so that client can use it to create OLE items. An application can be both a client and a server; that is, it can both incorporate items into its documents, and its data can be incorporated as items into other application's documents.

Clients and servers do not communicate directly. Instead, they communicate indirectly through the OLE system DLLs. These DLLs provide functions that clients and servers call, and the clients and servers define callback functions that the DLLs call.

This system of communication is designed so that a client doesn't need to know anything specific about a server application. This allows a client to accept items created by any server; a client does not have to define what types of servers it can work with. As a result, the user of a client application, such as Write, can take advantage of new applications and data formats created in the future. As long as those new applications are OLE servers, a Write document will be able to incorporate items created by those applications.


 Verbs

Double-clicking on an OLE item from within a client application typically launches the server application; this allows you to edit the item using the server. However, certain items don't behave this way. For example, double-clicking on an item created with the Sound Recorder application does not cause the server to be launched; instead it causes the sound to be played.

The reason for this difference in behavior is that Sound Recorder items have a different "primary verb." The primary verb is the action performed when the user double-clicks on an item. For most types of items, the primary verb is Edit, which launches the server that created the item. For some types of items, such as Sound Recorder items, the primary verb is Play.

Most types of items support only one verb, and Edit is the most common one. However, some types of items support multiple verbs. For example, Sound Recorder items support Edit as a secondary verb.

Any verbs other than the primary verb must be invoked through a menu command when the item is selected. For information on the typename Object command, see »Implementing a Client Application«.

The verbs that a server application supports are listed in the Windows registration database. Your server application's verbs should be registered when it is installed. See »Registering a Server Application«.


 The OLE Classes

The Microsoft Foundation Class Library provides nine classes that support OLE, which can be grouped into three categories: general classes, client classes and server classes.

The following are the general classes:

Name	Purpose
COleDocument	Provides generic functionality for a document containing OLE items; serves as base class for COleClientDoc and COleServerDoc.
CDocItem	Provides generic functionality for a document item; serves as base class for COleClientItem and COleServerItem.
COleException	Describes an error occurring during an OLE operation.
You do not use the COleDocument and CDocItem classes directly; they are abstract classes that define an interface for dealing with a document as a list of items. This interface is used by both COleClientDoc and COleServerDoc to their stored OLE items.

The COleException class is a special type of exception thrown during OLE operations. For more information on exception handling, see »Chapter 16« of this book and Chapter 6 in the overview of the Class Library Reference.

The classes that you will primarily use are the client classes and the server classes. The following are the client classes:

Name	Purpose
COleClientDoc	Document managed by a client application; able to contain COleClientItem objects as well as the client application's own data.
COleClientItem	Defines client interface to an embedded or linked item.
To write a client application, you need the following:

•	One document class for each type of document that your client application supports. Each class must be derived from COleClientDoc.

Your application needs one object of a document class for each open document.

•	One item class, which must be derived from COleClientItem. Note that only one item class is needed for embedded and linked items of all types.

Your application needs one object of the item class for each embedded or linked item.

When writing your client application, you do not have to write any code for managing the specific contents of embedded or linked items. For example, you do not have to write code that manages floating-point numbers in order to accept embedded worksheet items. The framework and the OLE system DLLs manage all of this data for you. This is what allows your client application to accept items from any server.

The following are the server classes:

Name	Purpose
COleServer	Creates and manages server documents of a specific type; used for servers that are only launched by clients.
COleTemplateServer	Creates and manages server documents using a CDocTemplate object; used for servers that are launched as stand-alone applications, as well as by clients.
COleServerDoc	Document managed by a server application; able to treat its contents as COleServerItem objects.
COleServerItem	Defines server interface to an OLE item.
To write a server application, you need the following:

•	One server class for each type of item your application supports. For example, if your application acts as a server for both worksheets and charts, you need two server classes. You can use either COleTemplateServer directly as a server class, or you can derive a class from COleServer.

Your application needs only one object of each server class.

•	One document class for each type of item your application supports. Each class must be derived from COleServerDoc.

Your application needs one object of a document class for each open document.

•	One item class for each type of item your application supports. Each class must be derived from COleServerItem.

Your application needs one object of an item class for each embedded or linked item that is open. However, you may also use objects of an item class for representing data that is not an embedded or linked item.

Note that the COleClientItem and COleServerItem classes do not represent two different categories of items; they represent different interfaces to the same item. Each OLE item has both a COleClientItem interface and a COleServerItem interface.

As described earlier in "»Clients and Servers,«" client and server applications interact through the OLE system DLLs. A client application never directly calls a member function of a server class, and similarly, a server application never directly calls a member function of a client class.

Most of the member functions of the client classes are operations; you call them directly from your client application's code. By comparison, most of the member functions of the server classes are overridables; they are called by the OLE system DLLs (via the framework) in response to requests from the client. You typically don't call them from your server application's code.


 Implementing a Client Application

A client application typically supports the following user-interface features:

•	The Insert New Object command.

The Insert New Object command typically appears on the Edit menu (though it may appear on the Insert menu, if your application has one). This command lets the user create an embedded item in a document in a more direct manner than the Paste command. When the user selects the Insert New Object command, the Insert Object dialog box appears. This dialog box displays a list of all the types of items available on the system. When the user chooses the type of item to embed, the appropriate server application is launched, allowing the user to create a new item. If the user chooses Update when exiting the server application, a new embedded item appears in the document.

•	The Paste command.

The Paste command appears on the Edit menu. It has the same behavior in OLE applications as it does in non-OLE applications, except that it can create an embedded item if the Clipboard contains data from a server application.

If the Clipboard doesn't contain all the data necessary to create an embedded item, the Paste command creates a "static" item. A static item cannot be edited.

•	The Paste Link command.

The Paste Link command appears on the Edit menu if the client application accepts linked items. It is the most common way to create a linked item. (You can also create linked items using the Paste Special command. However, the Paste Special command has a more complicated user interface than the Paste Link command and is not commonly implemented.)

•	Invoking a verb on an item.

There are two ways for the user to invoke a verb on an item: by double-clicking the item or by using the typename Object command.

When the user of the client application double-clicks an item, typically the item's primary verb is executed. The Edit verb launches the server application and displays the item for editing. The Play verb also launches the server application, but may not display anything (for example, if playing a sound item).

The typename Object command appears on the Edit menu. This command lets the user execute any of the verbs that an item supports. It differs from most other commands in that its appearance and behavior depend entirely on what type of OLE item is selected. The command has the following behavior:

1.	If nothing is currently selected, or if the item selected is not an OLE item, or if more than one OLE item is selected, the menu item reads "Object . . ." and is disabled.

2.	If an OLE item is selected, the caption on the menu item changes. If the selected item has an unnamed verb, the menu item becomes "typename Object."

3.	If the selected item has only one verb, the menu item becomes "verb typename Object."

4.	If the selected item has more than one verb, the menu item becomes "typename Object." Choosing the command opens a submenu listing all the supported verbs.

•	The Edit Links command.

The Edit Links command appears on the Edit menu if the client application accepts linked items. This command lets the user modify properties of the linked items in the document. When the user chooses the Edit Links command, the Links dialog box appears. This dialog box displays a list of all the linked items in the document (the information displayed for each linked item includes the type of the item, the document in which the item is stored, and the name that identifies the item within the document). The user can select one or more of the linked items and change the type of link updating (automatic or manual), update linked items immediately, cancel links, or repair broken links.

•	Cutting/copying an item to the Clipboard.

The basic steps in writing a client application are described in more detail in the following topics.


 Defining a Client Document Class

A client document class must be able to do everything a non-OLE document class does; it must interact with views and be able to handle commands. However, it must also be designed to accommodate objects of a COleClientItem-derived class as well as its own data.

To define a client document class

•	Derive your document class from COleClientDoc instead of CDocument.

•	Override the Serialize member function to enable the document to be stored to disk.

If you define CDocItem-derived classes to represent your non-OLE data, you can use the COleDocument list to store both your OLE and non-OLE data. Otherwise, you must manage your non-OLE data using your own data structures, as you would when implementing documents for a non-OLE application.

When a client document is created, the framework automatically registers the document with the OLE system DLL. This allows the DLL to identify the client documents.


 Defining a Client Item Class

As mentioned earlier, you do not have to write code that manages the specific contents of embedded or linked items, such as the floating-point numbers in an embedded worksheet item; the framework and the OLE system DLLs manage that for you. However, you may want to define member variables in your item class that store the item's size and position within the compound document.

To define a client item class

•	Derive a class from COleClientItem.

•	Implement the OnChange member function.

The OnChange function is called by the framework when the user of the server application modifies the item or saves or closes the document containing the item. You must implement this function to respond to changes in the item's state. Typically you update the item's appearance by invalidating the area in which the item is displayed.


 The Insert New Object Command

If you choose the OLE Client option, AppWizard adds the Insert New Object command to the Edit menu and gives it the ID_OLE_INSERT_NEW command ID. AppWizard also defines a member function in your view class named OnInsertObject, which acts as the message handler for this command.

AppWizard provides a skeletal definition of OnInsertObject; it declares a CString object and passes it to the global function AfxOleInsertDialog. This function displays the Insert Object dialog box and returns the type name selected by the user in the CString object. You must complete the implementation of OnInsertObject by creating an item of the specified type and insert it in your document.

To complete the implementation

•	Dynamically allocate a new instance of your COleClientItem-derived class; this creates the C++ object, but not the OLE item itself. Pass a pointer to the client document as the argument to the base class constructor — that is, the COleClientItem constructor. This constructor adds the item to the specified document.

•	Create the OLE item itself by calling the CreateNewObject member function, passing the name of the server specified by the user and a name that uniquely identifies the item being created.

This function launches the specified server application that allows the user to create a new item. In a server application written with the Microsoft Foundation Class Library, the OnCreateDoc member function of the server class is called at this point. For more information, see »Defining a Server Class«.

When CreateNewObject returns, the item is not displayed because it doesn't contain anything yet. When the user updates the item, the framework calls the OnChange function of the new item; the client application responds by displaying the item. See »Displaying an Embedded or Linked Item« for information on what you should do in your override of OnChange. If the user chooses not to update the item when exiting the server, no item is embedded.

For details on implementing the Insert New Object command, see the OCLIENT sample program in \MSVCNT\MFC\SAMPLES\OCLIENT.


 The Paste and Paste Link Commands

AppWizard provides the Paste command on the Edit menu and gives it the ID_EDIT_PASTE command ID. If you choose the OLE Client option when you run AppWizard, it also adds the Paste Link command to the Edit menu and gives it the ID_EDIT_PASTE_LINK command ID.

The Microsoft Foundation Class Library defines update handlers for the Paste or Paste Link commands (these are member functions of COleClientDoc). These functions enable or disable the Paste and Paste Link commands, respectively, based on the current contents of the Clipboard. The Paste command is enabled if either an embedded or a static item can be pasted. The Paste Link command is enabled if a linked item can be pasted.

To complete the implementation

•	Define a message handler in your view class. The message handler for the Paste command should be named OnPaste, and the one for the Paste Link command should be named OnPasteLink. Do the following steps in each message handler:

1.	Open the clipboard by calling the CWnd::OpenClipboard member function.

2.	Create an instance of your COleClientItem-derived class:

•	For the Paste command, call the CreateFromClipboard member 	function.

If the function call is unsuccessful, call the CreateStaticFromClipboard 	member function. This function creates a static item; such an item does 	not contain the Native data used by the server, only the presentation data 	for displaying the item. As a result, a static item can be displayed but not 	edited.

•	For the Paste Link command, call the CreateLinkFromClipboard 	member function.

3.	Insert the new item in your document at the current position. The specifics depend on your implementation of compound documents.

4.	Close the clipboard by calling the CWnd::CloseClipboard member function.

See the OCLIENT sample program in \MSVCNT\MFC\SAMPLES\OCLIENT for details on implementing the Paste and Paste Link commands.


 Invoking a Verb on an Item

If you want to invoke an item's primary verb when the user double-clicks the item, override the OnLButtonDblClick message handler of the view class that displays the item. In your override of the function, call the DoVerb member function defined by COleClientItem. Even if the selected item supports more than one verb, you should use the primary verb for consistency with other OLE applications. To specify the primary verb, pass OLEVERB_PRIMARY to DoVerb.

To implement the typename Object command if you choose the OLE Client option, AppWizard adds a command to the Edit menu with ID_OLE_VERB_FIRST as its command ID. The Microsoft Foundation Class Library defines both the update handler and the message handler for this command (these are member functions of COleClientDoc). The update handler enables/disables the menu item and adjusts its caption depending on what type of OLE item, if any, is currently selected. The OnCmdMsg member function of COleClientDoc handles the command by calling the DoVerb member function of the selected item.

To complete the implementation of the typename Object command

1.	Implement some form of item selection. The details of this will depend on your application.

2.	Override the IsSelected member function in your view class; this is needed for the menu command to be enabled properly.

When the user invokes a verb on an item, the server opens the item and then executes the verb. In a server application written with the Microsoft Foundation Class Library, a member function of the item class is called to execute the verb; the particular member function depends on the verb. See »Defining a Server Item Class« for information.

See the OCLIENT sample program in \MSVCNT\MFC\SAMPLES\OCLIENT for details on invoking verbs on embedded or linked items.


 The Edit Links Command

If you choose the OLE Client option, AppWizard adds the Edit Links command to the Edit menu and gives it the ID_OLE_EDIT_LINKS command ID. The Microsoft Foundation Class Library defines both the update handler and the message handler for this command (these are member functions of COleClientDoc). The update handler checks whether there are any linked items in the document and enables or disables the menu item accordingly. The message handler calls the global AfxOleLinksDialog function, which displays the Links dialog box. No further work is required.


 Displaying an Embedded or Linked Item

As described in »Defining a Client Item Class,« you are responsible for managing the size and position of embedded and linked items. Use this information when displaying items.

To display an item

1.	Override OnDraw in your view class.

2.	For each item, call the Draw member function defined by COleClientItem. This function renders an image of the item. If the item's server was written with the Microsoft Foundation Class Library, the function plays the metafile created by the OnDraw member function of COleServerItem. See »Defining a Server Item Class« for information.

To ensure that the items are displayed correctly when the server updates them, override the OnChange member function in your COleClientItem-derived class. This function is called in response to actions performed by the user while working in the server application. From this function, call the UpdateAllViews member function of the document. As described in "»Updating Multiple Views"« in Chapter 8, this function notifies all the views attached to the document to update their displays. The default behavior for each view is to invalidate their entire display area; this causes the OnDraw member function of the view to be called, redisplaying each item.

See the OCLIENT sample program in \MSVCNT\MFC\SAMPLES\OCLIENT for details on displaying embedded or linked items. The OCLIENT program allows resizing of items and optimizes drawing so that a change in one item does not force all items to be redrawn.


 Cutting or Copying Items to the Clipboard

To implement the Cut or Copy commands

1.	Implement some form of item selection. The details of this will depend on your application.

2.	Override the IsSelected member function in your view class; this is needed for the menu commands to be enabled properly.

3.	Define update handlers for the Cut and Copy commands in your view class. Enable those commands on the menu depending on whether anything in the document is selected.

4.	Define message handlers for the Cut and Copy commands in your view class. In the message handler, do the following:

a.	Open and empty the Clipboard.

b.	Call the CopyToClipboard member function defined by COleClientItem for the currently selected item.

c.	Close the clipboard.

d.	For the Cut operation, destroy the item.

If your application supports selection of more than one item at a time, or selection of non-OLE data with OLE data, you must define additional Clipboard formats and implement the Cut and Copy commands so they copy the multiple selections to the Clipboard.


 Loading/Saving a Compound Document

As described in previous chapters, the Microsoft Foundation Class Library provides a framework for creating, loading, and saving documents through the CDocument interface. Because COleClientDoc is derived indirectly from CDocument, client documents can be managed by the framework in the same way as ordinary documents; COleClientDoc overrides certain functions to perform the additional work needed for OLE client documents.

For example, when loading a client document, a client application must register the document with the OLE system DLL. COleClientDoc takes care of this by overriding OnNewDocument and OnOpenDocument to call the RegisterClientDoc member function. Similarly, a client application must notify the library when a document is saved; to do this, COleClientDoc overrides OnSaveDocument to call the NotifySaved member function.

To complete the implementation

1.	Override Serialize in your COleClientDoc-derived class. To save embedded or linked items, use the interface provided by COleDocument to iterate through the list of items contained in the document and call Serialize for each one. If you are using your own data structures as well, iterate through them and serialize their contents.

2.	Override Serialize in your COleClientItem-derived class. Serialize any information you store in your class, such as the position and size of the item. Then call the version of Serialize defined by COleClientItem; this serializes the data stored in the item itself. That is, for an embedded item, it stores the Native data and the type of the item, and for a linked item, it stores the type of the item and information that specifies where the item can be found.


 Implementing a Server Application

Support server functionality requires only minor changes to an application's user interface: when an embedded item is being edited, the Save command on the File menu is replaced by the Update command and the Save As command is replaced by the Save Copy As. This indicates that storing changes made to the document does not involve saving anything to disk, but instead involves updating the item stored in a compound document. The framework updates the menu captions automatically.


 Defining a Server Class

The class you use to implement your server depends on the type of server application you want to write.

Mini-Servers vs. Full Servers

There are two types of server applications: mini-servers and full servers. A mini-server can be launched only by a client. The MS-Draw and Graph servers are examples of mini-servers. A mini-server does not store documents as their own files on disk; instead, it reads its documents from and writes them to items in client documents. As a result, such an application can support only embedding, not linking.

A full server is a stand-alone application; it can either be run by itself or be launched by a client application. A full server supports storing documents on disk as their own files. Such an application can support embedding only, or it can support both embedding and linking. A full server typically supports the Cut and Copy commands; these allow the user of a client application to create an embedded item by choosing the Paste command or, in the case of the Copy command, to create a linked item by choosing the Paste Link command.

To define a class for a mini-server

1.	Derive a class from COleServer.

2.	Implement the OnCreateDoc member function. This is a pure virtual function, so you must provide an implementation.

The OnCreateDoc function is called when the user of a client application chooses the Insert New Object command. Return a document object from this function; this must be an object of your COleServerDoc-derived class.

3.	Implement the OnEditDoc member function. This is a pure virtual function, so you must provide an implementation.

The OnEditDoc function is called when the user of a client application edits an existing embedded item. Return a document object from this function; this must be an object of your COleServerDoc-derived class.

If you are writing a full server, you should use the class COleTemplateServer. COleTemplateServer is derived from COleServer and can be used directly. It provides definitions for the pure virtual functions defined by COleServer by using the document-creation facilities of a CDocTemplate object. This lets your server application take advantage of the document/view architecture provided by the Microsoft Foundation Class Library.

To use COleTemplateServer as a server class

1.	Create a CDocTemplate object, specifying a COleServerDoc-derived class
as the document class. Typically you pass this to the application's AddDocTemplate member function.

2.	Create a COleTemplateServer object; you can declare this as a member variable in your CWinApp-derived class. From within your application's InitInstance member function, call the RunEmbedded member function of the COleTemplateServer object, passing the CDocTemplate object.

For an example of a mini-server, see the MINSVR sample program in \MSVCNT\MFC\SAMPLES\MINSVR. For an example of a full server, see the HIERSVR sample program in \MSVCNT\MFC\SAMPLES\HIERSVR.

SDI Servers vs. MDI Servers

Another issue related to the mini- versus full-server question is whether your application should be a single document interface (SDI) or a multiple document interface (MDI) application. Mini-servers are always SDI applications. Full servers can be either, though they are typically MDI applications.

A server application must be able to support multiple clients simultaneously, in case more than one client wants to edit an embedded or linked item. If the server is an SDI application, it must be possible for multiple instances of the server to be running simultaneously. This allows a separate instance of the application to handle each client's requests.

If the server is an MDI application, it can simply create a new MDI child window each time a client needs to edit an item. In this way, a single instance of the application can support multiple clients.

Your server application must specify whether or not it supports multiple instances when it is first launched. This tells the OLE system DLL what to do if one instance of the server is already running when another client requests its services: whether it should launch a new instance of the server, or whether it should direct all clients' requests to one instance of the server.

The following table summarizes some characteristics of mini- and full servers:

Type of server	SDI/MDI	Number of items per document	Supports multiple instances	Number of documents per instance
Mini-server	SDI	1	Yes	1
Full server that supports embedding only	MDI	1	No	0 or more
Full server that supports embedding and linking	MDI	0 or more	No	0 or more
See »Launching a Server Application« for more information.


 Defining a Server Document Class

In a server document, there is not the same distinction between OLE items and the application's own data as there is in a client document. This is because an OLE item consists of data created by the server application itself. As a result, the design of your server document class and your server item class are interdependent.

The relationship between the document and item classes depends on whether your server supports embedding only, or linking as well. If your server supports only embedding, a server item is equivalent to a server document. Thus you will need only one object of your item class for each document.

If your server supports linking, designing your document and item classes is potentially more difficult. From the server's point of view, a linked item can be anything that can be selected. There are two basic types of selection: single selection, in which only one element in the document can be selected at a time, and multiple selection, in which an arbitrary number of elements in the document can be selected at a time.

The easiest way to support linking in a server is to allow only single selection. With this approach, you can use COleServerItem as the base class for an element in the document. Your document class can use the COleDocument list to store your document items. Whenever an element is copied to the Clipboard, you can simply call the CopyToClipboard member function for that item. The HIERSVR sample program allows only single selection.

Supporting multiple selection is much more difficult. You must design data structures that allow a COleServerItem object to represent an arbitrary number of the elements that make up a document. A full discussion of implementing multiple selection is beyond the scope of this chapter.

For more information, see »Defining a Server Item Class«.

To define a server document class

1.	Derive your document class from COleServerDoc instead of CDocument.

2.	Implement the OnGetEmbeddedItem member function. This is a pure virtual function, so you must provide an implementation.

OnGetEmbeddedItem is called when the user of a client application creates or edits an embedded item. Return an item representing the entire document. This should be an object of your COleServerItem-derived class.

3.	If you are implementing a full server, override the Serialize member function. If you are implementing a mini-server, the documents are never written to disk, so the Serialize member function is unnecessary.

The OnGetLinkedItem member function of COleServerDoc is called when the user of a client application edits a linked item. A default implementation of this function is provided. You need to override it only if you are implementing your own data structures for storing server items instead of using the COleDocument list.

When a server document is created, the framework automatically registers the document with the OLE system DLL. This allows the DLL to identify the server documents.


 Defining a Server Item Class

Most of the behavior of your server application lies in the item class. The item class contains the Native data that makes up an item; the item class also defines the appearance of the items and the actions taken when verbs are invoked.

To define a server item class

1.	Derive a class from COleServerItem.

2.	Implement the OnDraw member function. This is a pure virtual function, so you must provide an implementation.

The OnDraw function draws an image of the item to a metafile, allowing it to be displayed when a client application opens a compound document.

3.	Implement the Serialize member function. This is a pure virtual function, so you must provide an implementation.

The Serialize function reads and writes the Native data for an item, that is, all the information needed to describe it. This allows an embedded item to be transferred between the server and client applications.

4.	(Optional) Override the OnShow member function.

The OnShow function is called when an item is opened for editing. Override the function to scroll the view so that the item is visible and then select the item.

5.	(Optional) If the type of item supports more than one verb, override the OnExtraVerb member function to perform the desired action for each supported verb.

6.	(Optional) If you want to support CF_TEXT as a presentation format, override the OnGetTextData member function. A presentation format is a format in which the server can provide an image of an item. By default, servers written with the Microsoft Foundation Class Library provide images of items only as metafiles (that is, the only presentation format supported is CF_METAFILEPICT). If you want to provide a text representation of an item, override OnGetTextData to do so.

If you want to support other formats, override the OnEnumFormats member function to return the formats and override the OnGetData member function to provide the data in these formats.


 Registering a Server Application

Every server application installed on the system must have an entry in the Windows registration database indicating that it supports OLE. The registration database is a binary file named REG.DAT located in the Windows directory.

A server application's entry in the registration database contains several pieces of information: a name identifying the type of item that the application supports, the command line to execute to launch the application, the verbs that it supports, and whether an object-handler DLL exists for the application.

The framework and OLE system DLLs use this database to determine what servers are available on the system. For example, when the user of a client application executes the Insert New Object command, the list of servers that appears in the dialog box is constructed by querying the registration database. The OLE system DLLs also use this database to determine how to launch the server application when a linked or embedded object is activated.

You should register your server when it is first installed. You can also have the server update its registration every time it is executed as a stand-alone program. This keeps the registration database up-to-date if the server's executable file is moved.

If you want to register your application during installation, use the REGLOAD utility included with the SDK. If you include a setup program with your application, you should have the setup program run REGLOAD. Otherwise, instruct the user to run REGLOAD with the name of your server application.

To use REGLOAD, write a text file with the extension .REG for your server. Here is a sample .REG file:

REGEDIT

HKEY_CLASSES_ROOT\MySvr = My OLE Server

HKEY_CLASSES_ROOT\MySvr\protocol\StdFileEditing\server =
         C:\MYSERVER\MYSERVER.EXE

HKEY_CLASSES_ROOT\MySvr\protocol\StdFileEditing\verb\0 = Edit

HKEY_CLASSES_ROOT\MySvr\protocol\StdFileEditing\verb\1 = Play

HKEY_CLASSES_ROOT\.MYS = MySvr

The .REG file contains the following information:

•	An internal name for the item type. For example, "MySvr" is the internal name in the sample .REG file above. This name is for internal use only; try to pick a name that avoids collisions. This name should not contain spaces.

•	A user-visible name for the item type. For example, "My OLE Server" is the human-readable name in the sample .REG file above. This is the name that appears in the Insert Object dialog box, as well as in various other places. This name can contain spaces.

•	The path name of the server's executable file.

•	(Optional) A standard suffix for document files edited by the server. For example, ".MYS" is the suffix in the sample .REG file above.

•	All the verbs supported by the item type. The primary verb has the index 0, the secondary verb has the index 1, and so forth. If your server supports multiple verbs, you must specify those verbs here.

REGLOAD merges the contents of the .REG text file into the registration database. You can also use the REGEDIT program to view or modify the contents of the registration database.

If you want to register your server application each time it is executed as a stand-alone program, call the global function AfxOleRegisterServerName from the InitInstance member function of your CWinApp-derived class. AfxOleRegisterServerName takes two parameters: the internal and user-visible names for the type of item that the server supports. This function updates the path for the server's executable file. If there are no verbs registered for the item type, the function also adds Edit as the default primary verb.


 Launching a Server Application

When a server application is launched by a client application, the OLE system DLL adds the  "/Embedding" option to the server's command line. A server application's behavior differs depending on whether or not it was launched by a client, so the first thing an application should do when it begins execution is check for the "/Embedding" or "-Embedding" option on the command line.

If you are writing a mini-server, it will always be launched by a client, by definition. You should still parse the command line to check for the "/Embedding" option. The lack of a "/Embedding" option on the command line indicates that the user tried to launch the mini-server as a stand-alone application. In this case, you should register the server with the Windows registration database and then display a message box informing the user to launch the application from a client application.

Before running the server, you must perform instance registration. This operation does not add an entry to the registration database; instead, it informs the OLE system DLL that the server is active and ready to receive requests from clients. Register the server by calling the Register member function defined by COleServer. The Register function takes two parameters: the server's internal type name and a flag indicating whether the server supports multiple instances. A mini-server must be able to support multiple instances; that is, it must be possible for multiple instances of the server to run simultaneously, one for each client. Consequently, you should pass TRUE for this flag when launching a mini-server.

If you are writing a full server using COleTemplateServer, call the RunEmbedded to parse the command line. This function updates the server's entry in the Windows registration database and calls the Register member function for you, performing instance registration.

When you call RunEmbedded, you must pass a flag indicating whether the server supports multiple instances. A full server typically does not support multiple instances, because it is typically an MDI application; a single instance of the server can handle all clients. Consequently, you should pass FALSE for this flag when launching a full server.

If a server is launched by a client to edit a linked item, the OLE system DLL passes a filename on the command line following the "/Embedding" option; this is the name of the document that is the source of the linked item. The server should open this document immediately.


 Sequences of OLE Function Calls

This section outlines the major steps that occur during common OLE operations and lists the member functions called in each step. For more information on the OLE classes and their member functions, see the descriptions in the Class Library Reference.


 Inserting a New Embedded Item

The following list describes the scenario where the user chooses the Insert New Object command.

1.	Your client code calls COleClientItem::CreateNewObject.

2.	The OLE system DLL searches the Windows registration database to find the executable file for the server, and launches the server with the "/Embedding" option on the command line.

3.	COleClientItem::CreateNewObject returns at approximately this time, but the item is blank.

4.	If the server is a mini-server, your server code calls COleServer::Register. If it's a full server, COleTemplateServer calls it for you.

5.	COleServer::OnCreateDoc is called; it returns a document object.

6.	COleServerDoc::OnGetEmbeddedItem is called; it returns an item.

7.	COleServerItem::OnShow is called; it displays the item, allowing the user to edit it.

8.	The user chooses the Update command. The framework calls COleServerDoc::NotifySaved.

9.	COleServerItem::OnGetData is called to get the item's Native data. This function calls COleServerItem::Serialize to write the data.

10.	COleServerItem::OnGetData is called to get the item's metafile representation. This function calls COleServerItem::OnDraw to draw an image of the item to a metafile.

11.	COleClientItem::OnChange is called, notifying the client that the item was updated. At this point the item can be displayed.

12.	The user chooses the Exit command in the server application. If the server is a mini-server, your server code calls COleServer::BeginRevoke. If it's a full server, COleTemplateServer calls it for you (if there are no other documents open).

13.	COleClientItem::OnChange is called, notifying the client that the server has closed the document.


 Editing an Embedded Item

The following list describes the scenario where the user invokes the Edit verb on an embedded item, either by double-clicking the item or by using the typename Object command.

1.	Your client code calls COleClientItem::DoVerb, which in turn calls COleClientItem::Activate.

2.	The OLE system DLL searches the Windows registration database to find the executable file for the server, and launches the server with the "/Embedding" option on the command line.

3.	If the server is a mini-server, your server code calls COleServer::Register. If it's a full server, COleTemplateServer calls it for you.

4.	COleServer::OnEditDoc is called; it returns a document object.

5.	COleServerDoc::OnGetEmbeddedItem is called; it returns an object of the item class.

6.	COleServerItem::OnSetData is called to set the item's Native data; this function calls COleServerItem::Serialize to read the data.

7.	COleServerItem::OnShow is called; it displays the item, allowing the user to edit it.

8.	COleClientItem::DoVerb returns at approximately this time.

9.	Steps 8-13 of the »Inserting a New Embedded Item« procedure occur.


 Editing a Linked Item

The following list describes the scenario where the user invokes the Edit verb on a linked item, either by double-clicking the item or by using the typename Object command.

1.	Your client code calls COleClientItem::DoVerb, which in turn calls COleClientItem::Activate.

2.	The OLE system DLL searches the Windows registration database to find the executable file for the server, and launches the server with the "/Embedding filename" option on the command line.

3.	COleTemplateServer calls COleServer::Register for you.

4.	COleServer::OnOpenDoc is called, loading a file from disk; the function returns a document object.

5.	COleServerDoc::OnGetLinkedItem is called; it returns an object of the item class.

6.	COleServerItem::OnShow is called; it displays the item, allowing the user to edit it.

7.	COleClientItem::DoVerb returns at approximately this time.

8.	The user chooses the Save command. The framework saves the document and calls COleServer::NotifySaved.

9.	COleServerItem::OnGetData is called to get the item's metafile representation. This function calls COleServerItem::OnDraw to draw an image of the item to a metafile.

10.	COleClientItem::OnChange is called, notifying the client that the item was saved.

11.	The user chooses the Exit command in the server application. COleTemplateServer calls COleServer::BeginRevoke for you (if there are no other documents open).

12.	COleClientItem::OnChange is called, notifying the client that the server has closed the document.


 Appendix A  Getting Started

This appendix provides an overview of the new and changed functions and features in the current version of the Microsoft Foundation Class Library. It also provides information on installing the class library and locating its components.


 What's New in the Class Library

Among the new features in version 2 of the Microsoft Foundation Class Library are the following:

•	The class library is now integrated with the visual tools in the Visual C++ programming environment: AppWizard, App Studio, ClassWizard, and Visual Workbench.

•	The class library gives you a head start with the skeleton starter application created by AppWizard.

•	Managing Windows messages and commands from menus, buttons, and accelerator keys is greatly simplified when you use ClassWizard.

•	App Studio provides one-stop user-interface design and resource editing.

•	Visual Workbench lets you compile and debug your application and browse your class hierarchy.

•	At the heart of the class library is its document/view program structure. Documents manage your data. Views manage user interaction with a document.

•	The class library implements many standard user-interface elements:

•	standard menu items, such as the New, Open, Save, and Save As commands on the File menu

•	support for toolbars, status bars, and other control bars

•	support for scrolling and splitter windows

•	form-style user interfaces based on dialog templates

•	support for printing and print preview

•	support for context-sensitive help

•	You get a dialog-box interface that makes it easy to initialize and validate dialog-box data and to retrieve data from a dialog box.

•	Object Linking and Embedding (OLE) support is integrated with the document/view architecture, and the framework supports OLE user interfaces.

•	Complete support for dynamic link libraries (DLLs). This support is more extensive than the support in the previous version.

These and other features make the Microsoft Foundation Class Library more powerful and even easier to use. The current version of the class library is also compatible with the previous version.


 Installing the Class Library

For general information and installation instructions, see Chapter 1 in the Getting Started Guide.

On the main screen in the Setup program during installation, be sure the check boxes labeled "Microsoft Foundation Classes" and "Microsoft App Studio: Resource Editor" are selected (they are selected by default). You can also install these components at a later time. For information on installing Visual C++ components after your initial installation, see the Getting Started Guide.


 Additional Files

In addition to header files and libraries, the MFC directory and its subdirectories created when you install the Microsoft Foundation Class Library contain source code, sample programs, and technical notes.

Source Code

The full source code for the Microsoft Foundation Class Library is supplied on your distribution disks in the MFC\SRC subdirectory. You'll find the source code useful in a number of ways:

•	As an aid in debugging your own code when the failure is revealed, say, with an ASSERT inside a class in the class library.

•	As the ultimate reference if the documents don't answer all of your questions.

•	In very rare cases, you may want to modify the library class implementations, although this is generally not recommended.

Sample Programs

Sample programs are provided in the MFC\SAMPLES subdirectory. You'll find it instructive to compile and run them and to examine their source code for useful techniques. To install the samples, see "Samples" in Chapter 1 of the Getting Started Guide.

For a helpful overview of the sample programs and what they illustrate, see MFCSAMP.HLP, which you can reach through the main contents screen of MFC.HLP.

Technical Notes

Technical notes are provided to discuss porting issues and the architecture and advanced features of the Microsoft Foundation Class Library.

For easy access to the technical notes, see MFCNOTES.HLP, which you can find in \MSVCNT\HELP, or by double-clicking on the MFC Tech Notes icon displayed in the Visual C++ main screen.


Introduction
Build Tools User's Guide

Introduction

The Microsoft® Visual C++™ Development System for Windows™ and Windows NT™, 32-Bit Edition, represents an evolutionary step in the progress of high-performance program development tools for the Microsoft Windows NT™ operating system. Visual C++ uses fully integrated Windows-hosted development tools and a "visual" user-interface-driven paradigm to the traditional C/C++ development process. Visual C++ includes a full set of development tools for writing, compiling, and debugging your programs. You can build your programs within the Visual Workbench integrated environment by setting project options in dialog boxes. You can also use some of the tools on the command line to develop external projects.


Book Location
Build Tools User's Guide


About This User Guide‹
  About This User Guide

This User Guide includes information on using the build tools supplied with Visual C++. The following chapters are included:

•	»Chapter 1« summarizes the new features and functions of the build tools and describes how to use the tools to set project options.

•	»Chapter 2« describes how to use the Microsoft C and C++ compilers. This chapter includes tables that reference the CL options in Visual Workbench and on the command-line. This chapter also includes a complete alphabetical reference to the CL options.

•	»Chapter 3« describes how to use the Microsoft 32-Bit Library Manager (LIB.EXE) to create and manage a library of COFF object files.

•	»Chapter 4« describes how to use the Microsoft 32-Bit Executable Linker (LINK.EXE)to link Common Object File Format (COFF) object files and libraries to create a 32-bit executable file or dynamic-link library (DLL).

•	»Chapter 5« describes the Microsoft Program Maintenance Utility (NMAKE.EXE)

•	»Chapter 6« describes the Microsoft  Browser Database Maintenance Utility (BSCMAKE), the Microsoft COFF Binary File Dumper (DUMPBIN.EXE), and the Microsoft Resource Compiler (RC.EXE).


  Document Conventions

This book uses the following typographic conventions:

Example	Description
STDIO.H	Uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
char, _setcolor, __far	Bold type indicates C and C++ keywords, operators, language-specific characters, and library routines. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
	Many constants, functions, and keywords begin with either a single or double underscore. These are required as part of the name. For example, the compiler recognizes the __cplusplus manifest constant only when the leading double underscore is included. It may be difficult at first glance to distinguish a single underscore from a double underscore because the two run together on the screen. Therefore, the width of the character(s) is your guide. The sample term setcolor, in the left column above, has one underscore in front of it, while the term far has two underscores in front of it.
expression	Words in italics indicate placeholders for information you must supply, such as a filename. Italic type is also used occasionally for emphasis in the text.
[option]	Items inside square brackets are optional.
#pragma pack {1 | 2}	Braces and a vertical bar indicate a choice among two or more items. You must choose one of these items unless square brackets ([ ] ) surround the braces.
#include <io.h>	This font is used for examples, user input, program output, and error messages in text.
CL [option...]  file...	Three dots (an ellipsis) following an item indicate that more items having the same form may appear.
while() {  .  .  . }	A column or row of three dots tells you that part of an example program has been intentionally omitted.
CTRL+ENTER	Small capital letters are used to indicate the names of keys on the keyboard. When you see a plus sign (+) between two key names, you should hold down the first key while pressing the second.
	The carriage-return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
"argument"	Quotation marks enclose a new term the first time it is defined in text.
"C string"	Some C constructs, such as strings, require quotation marks.
Dynamic-Link Library (DLL)	The first time an acronym is used, it is usually spelled out.
see »Using Projects«	Hypertext cross-references are enclosed in green double chevrons. Click the term enclosed in the chevrons to display the referenced information.
CEnterDlg;	The blue box adjoining the blue code indicates that it has been altered from a previous example, usually because you are being instructed to edit it.


Chapter 1 Chapter 1 Using the 32-Bit Build Tools
  Chapter 1  Using the 32-Bit Build Tools

The build tools provided with the  Visual C++ development system for Windows NT include the compiler (CL), Library Manager (LIB) and Linker (LINK); the program maintenance utilities (NMAKE, BSCMAKE, EDITBIN and DUMPBIN; and the Resource Compiler (RC). This chapter summarizes the new features and functions of these tools and describes how to use the tools to set project options. The following topics are included:

•	»Changes to the Tools«

•	»Setting Tool Options for a Project«


  Changes to the Tools

The build tools include new features and functions that were not included in the versions released with the Visual C++ development system for Windows. These changes are described in the following paragraphs.


  Changes to CL

CL now uses 32-bit memory addresses instead of 16-bit memory addresses. Programs written with the Visual C++ development system for Windows NT can directly address the entire memory address space.

The options that supported 16-bit segment and offset addressing are no longer necessary. As a result, the following options are no longer provided:

•	/A option to specify the memory model.

•	/N option to name segments.

•	/G options for near and far data.

•	/G options to set up a function's epilog and prolog for Windows 3.x.

Other options are new or include new features. These options are as follows:

•	/O options include new features for optimizations.

•	/MD, /ML and /MT options specify whether or not a program uses multiple threads.

•	/LD option specifies that the executable file is a Dynamic Link Library (DLL).


   Changes to Link

The changes to the 32-bit Linker (LINK) include how LINK accepts input and produces output, and how command-line arguments are specified. The 32-bit LINK also includes new options.

LINK accepts only two types of input: 32-bit Common Object File Format (COFF) files produced by CL, and 32-bit Object Module Format (OMF) files. In addition, LINK produces only .EXE or .DLL files.

The method for specifying command-line arguments to LINK has also changed. Arguments are now separated by whitespace, instead of in fields separated by commas.

Some options in the 16-bit linker distributed with Visual C++ for Windows are no longer used in the 32-bit linker. »Table 4.1« in Chapter 4 summarizes these changes.


  Changes in Other Tools

Some of the tools provided with the Visual C++ development system for Windows NT have been updated to replace tools provided with the Visual C++ development system for Windows. Other tools are used differently. These differences are described below.

•	DUMPBIN and EDITBIN have replaced EXEHDR.

DUMPBIN examines the contents of the header for a file (.EXE, .DLL, .OBJ or .LIB).

EDITBIN modifies the contents of the header for a file  (.EXE, .DLL, .OBJ or .LIB).

•	LINK automatically produces an import library when it links an .EXE or a .DLL that contains exports.

When using the 32-bit LINK, you can create an import library using LIB with the /DEF option for the first in a series of .DLLs which call each other. You can then link the .DLLs using the import library created with LIB. This method replaces the use of IMPLIB.


  Setting Tool Options for a Project

You can set identical tool options for all the files in a project using the dialog boxes in Visual Workbench. You can access dialog boxes for the C/C++ compiler (CL) and the linker (LINK) from the Options menu. You can set options in related categories in each dialog box, using various types of controls: option buttons, check boxes and text boxes. Not all of the options available for these tools are represented by a separate control. In cases where there is no specific control to set an option, you use an alternative method within Visual Workbench. For compiler options, you can type the option in the Other Options text box in the Custom Options category. For the linker, you can type the option in the Other Options text box in the Miscellaneous category.

For more information on setting options in Visual Workbench, see »Reference to CL Options« in Chapter 3, "Using the 32-bit CL, and »Using Link with Visual Workbench« in Chapter 4, "Using the 32-bit LINK."

If you need to specify one set of options for some files in a project and other options for others, you need to create an external makefile for use with NMAKE. NMAKE then calls the command-line tools with the specified options for each file. For more information on using external makefiles, see »Chapter 5«, "Using NMAKE", or see Chapter 3, "Using Projects" in Visual Workbench User's Guide.


  Chapter 2  Using the 32-Bit CL

This chapter describes how to use the Microsoft C and C++ compilers. They are controlled by the compiler-driver program named CL.EXE. CL is a 32-bit tool that uses the compiler to produce Common Object File Format (COFF) object files. CL can also use the linker to produce executable files or dynamic-link libraries (DLLs).

Most of the CL options described in this chapter are available as settings in the C/C++ Compiler Options dialog box in Visual Workbench. Tables 2.5 through 2.13  show the command-line equivalents to the settings in the C/C++ Compiler Options dialog box.  (See Visual Workbench User's Guide for more information on Visual Workbench).


  Description of CL Syntax

The CL command line uses the following syntax:

CL [option...] file... [option | file]... [lib...] [@response-file] [/link link-opt...]

The following list describes input to the CL command:

Entry	Meaning
option	One or more CL options; see »Alphabetic Reference to CL Options«  for a list and descriptions.
file	The name of one or more source files, object files, or libraries. You must specify at least one filename. CL compiles source files and passes the names of the object files and libraries to the linker.
lib	One or more library names. CL passes the names of these libraries to the linker for processing.
link-opt	One or more of the linker options described in »Chapter 4«, "Using the 32-Bit Link." The CL command passes these options to the linker for processing.
response-file	A file that can contain multiple options and filenames which you would otherwise type on the command line or specify by using the CL environment variable. See »Response Files« for more information.
You can specify any number of options, filenames, and library names, as long as the number of characters on the command line does not exceed 1024, the limit dictated by the operating system.

Note  The input limit to a Windows NT command line of 1024 characters is not guaranteed to remain the same in future releases.


Filename Syntax (CL)
  Filename Syntax

CL will accept files with names that follow FAT, HPFS, or NTFS naming conventions. Any filename can include a full or partial path. A full path includes a drive name and one or more directory names separated by backslashes (\). A partial path omits the drive name, which CL assumes to be the current drive. If you don't specify a path, CL assumes the file is in the current directory.

The filename extension determines how files are processed. The filename extensions and the processes performed on the files are listed in Table 2.1.

Table 2.1    Processing Performed on Each Type of File

File Extension	File Type	Processing
.C	C source file	File is compiled.
.CXX, .CPP	C++ source file	File is compiled.
.OBJ	Object file	File is passed to the linker.
.LIB	Library	File is passed to the linker. The linker links this library with the object files CL created from source files and the object files given on the command line.
.DEF	Definition file	The file is passed to the linker.
Any other extension or no extension	Object file	The file is passed to the linker.


  Specifying CL Options

You can specify CL options on the command line, in response files, and in the CL environment variable. Options specified in the CL environment variable are used every time you invoke CL. If a response file is named in the CL environment variable or on the command line, the options specified in the response file are used. Unlike either the command line or the CL environment variable, a response file allows you to use multiple lines of options and filenames. See »CL Environment Variable« and »Response Files« for more information.

Options to the CL command consist of either a forward slash (/) or a dash ( − ) followed by one or more characters. Certain options take arguments; in some of these options, a space is allowed between the option and the argument; in others, no space is allowed. The spacing rules for the options are given in their descriptions. Options (except for the /HELP option) are case sensitive. For example, /C and /c are different options.


Order of Options (CL)
  Order of Options

With the exception of the /link option, which must occur last, options can appear anywhere on the CL command line. The compiler reads options from left to right. It begins with options specified in the CL environment variable and reads the content of response files when it encounters a @filename during its left-to-right scan of the command line. After gathering all options, the compiler applies each option to all files on the command line. If CL encounters conflicting options during its left-to-right scan, such as the /G3 option in the CL environment variable and the /G4 option on the command line, it uses the rightmost option—/G4, in this case.


  Using CL

You can use CL to compile specified source files into a COFF object file, or to compile and link specified source files, Microsoft Common Object Format (OMF) and/or COFF object files, and libraries into an executable file or a dynamic-link library (DLL).


Fast Compilation (CL)
  Fast Compilation

If you do not specify optimization options, CL uses the disable optimization option (/Od). This feature allows you to quickly compile code that is under development and reserve using optimization until it is needed.

You can also use the precompiled header options (/YX, /Yc, /Yd, /Yu, /Fp, and the hdrstop pragma) to speed compilation.


Compiling (CL)
  Compiling

CL compiles each source file, creating an object file for each. It automatically includes the options listed in the CL environment variable and any specified response files. CL places the name of the library specified by using »/MD«, »/ML« (the default), or »/MT« (the default if /LD is specified) in each object file unless the »/Zl« option is used.

You can use the "compile without linking" option (/c) to create only an object file. The »/c« option stops CL before it invokes LINK.


Linking (CL)
  Linking

CL automatically invokes the linker after compiling unless the /c option is used. CL gives the names of the object files created during compiling, and the names of any object files or libraries given on the command line to the linker. The linker uses the options listed in the LINK environment variable. If you use /link to specify linker options on the CL command line, these options apply as well. If conflicts occur, options that follow /link override those in the LINK environment variable. Table 2.2 lists the options that suppress linking.

Table 2.2    Options That Suppress Linking

Option	Description
/c	Compile without linking
/E, /EP, /P	Preprocess without compiling or linking
/Zg	Generate function prototypes
/Zs	Check syntax
Before it creates the executable file or a DLL, the linker resolves "external references" in the object files. An external reference is a function call in one object file that refers to a function defined in another object file or in a library. To resolve an external reference, the linker searches for the called function in the following locations in the following order:

1.	The object files passed by CL

2.	The libraries given on the CL command line, if any

3.	The libraries named in the object files

After all external references are resolved, the linker links the object files and libraries named by CL to create a single executable file or a DLL.

Example

Assume that you are compiling three C source files: MAIN.C, MOD1.C, and MOD2.C. Each file includes a call to a function defined in a different file:

•	MAIN.C calls the function named func1 in MOD1.C and the function named func2 in MOD2.C.

•	MOD1.C calls the standard library functions printf and scanf.

•	MOD2.C calls graphics functions named myline and mycircle, which are defined in a library named MYGRAPH.LIB.

First, compile with the following command line:

CL MAIN.C MOD1.C MOD2.C MYGRAPH.LIB

CL first compiles the C source files and creates the object files MAIN.OBJ, MOD1.OBJ, and MOD2.OBJ. The compiler places the name of the standard library in each object file. The name of the library, listed in Table 2.3, depends on whether you compile using /MD, /ML, or /MD.

Table 2.3    Libraries Specified with /MD, /ML, and /MT

Option	Library Name	Description
/MD	MSVCRT.LIB	Statically linked import library for the dynamically linked library MSVCRT10.DLL, which allows you to write multi-threaded code. Any program linked with MSVCRT.LIB must have run-time access to MSVCRT10.DLL.
/ML	LIBC.LIB	Single-thread, statically linked (default).
/MT	LIBCMT.LIB	Multi-thread, statically linked.
After placing the name of the standard library in each object file, CL passes the names of the object files to the linker. The linker then resolves the external references in the following order.

1.	In MAIN.OBJ, the reference to the function func1 is resolved using the definition in MOD1.OBJ; the reference to the function func2 is resolved using the definition in MOD2.OBJ.

2.	In MOD1.OBJ, the references to printf and scanf are resolved using the definitions in the library that the linker finds named within MOD1.OBJ.

3.	In MOD2.OBJ, the references to myline and mycircle are resolved using the definitions in MYGRAPH.LIB.


Response Files (CL)
  Response Files

A response file is an ASCII file that contains options and filenames you would otherwise type on the command line or specify using the CL environment variable. CL accepts a compiler response file as an argument in the CL environment variable or on the command line. Unlike either the command line or the CL environment variable, a response file allows you to use multiple lines of options and filenames.

The location of a response filename within the CL environment variable or on the command line, is the position of the options contained within the response file. An exception to this rule is the /link option. If /link appears in the response file, all options on the rest of the line are passed to the linker. Options in subsequent lines in the response file and options on the command line after the response file invocation are still accepted as compiler options. For more information on how the order of options affects their interpretation, see »Order of Options«.

A response file should not contain the CL command. Also, each option must begin and end on the same line; you cannot use the backslash (\) to combine an option across two lines.

To invoke a response file, type the at sign (@) followed by a filename; you can also specify a drive and path.

Examples

You could put the following command into a file named RESP:

/Og /link LIBC.LIB

CL uses these options in addition to any options you specify on the CL command line. If you specify the following CL command:

CL /Ob2 @RESP MYAPP.C

the command to CL is as follows:

CL /Ob2 /Og MYAPP.C /link LIBC.LIB

Note that the command line and the response file commands are combined.

You can use NMAKE to create a temporary response file for a single compilation step as shown in the following response file:

MYAPP.OBJ : MYAPP.C
CL @<< MYAPP.C
/DV100 /Og
<<


  CL Environment Variable

Use the CL environment variable to specify files and options without giving them on the command line. The environment variable has the following syntax:

SET CL=[ [option] ... [file] ...] [/link [ link-libinfo] ]

The CL environment variable is useful if you often specify a large number of files and options when you compile. You can define the files and options you use most often with the CL variable and give only the files and options you need for specific purposes on the command line. The number of characters that the CL environment variable will hold is the number of characters that the command-line of a Windows NT console will accept, currently 1024.

You cannot use CL to set options that use an equal sign (for example, the /D option). However, the /D option (define symbols and constants) accepts the number sign (#) as an equal sign (=). This allows you to use the CL environment variable to define preprocessor constants (for example, /Dname#string).

Examples

In the following example, the CL environment variable tells the CL command to use the /Zp, /Ox, and /I options during compilation and then to link with the object file \LIB\BINMODE.OBJ.

SET CL=/Zp2 /Ox /I\INCLUDE\MYINCLS \LIB\BINMODE.OBJ

Both the CL environment variable above and the CL command below specify structure packing on 2-byte boundaries, perform maximum optimizations, search for include files in the \INCLUDE\MYINCLS directory, and, with BINMODE.OBJ, suppress translation of carriage-return−linefeed character combinations for INPUT.C and for any program with which INPUT.C is linked.

CL /Zp2 /Ox /I\INCLUDE\MYINCLS \LIB\BINMODE.OBJ INPUT.C

In the following example, the CL environment variable instructs the CL command to compile the source files FILE1.C and FILE2.C and then link the object files FILE1.OBJ, FILE2.OBJ, and FILE3.OBJ:

SET CL=FILE1.C FILE2.C
CL FILE3.OBJ

The preceding environment variable and CL command line has the same effect as the following command line:

CL FILE1.C FILE2.C FILE3.OBJ


Function Calling Conventions(CL)
  Function Calling Conventions

The compiler provides four calling conventions: C, fastcall, standard call, and thiscall. Table 2.4 lists the calling conventions and the compiler options and keywords that control them.

Table 2.4    Calling Conventions With Associated Options and Keywords

Calling convention	Option	Keyword
C	/Gd	__cdecl
fastcall	/Gr	__fastcall
standard call	/Gz	__stdcall
thiscall	none	none
The /Gd, /Gr, and /Gz options apply the associated calling conventions to entire source files. The __cdecl, __fastcall, and __stdcall keywords apply the associated calling conventions to individual functions. Both the options and the keywords allow you to specify whether the calling or the called function pops the called function's parameters from the stack. You can use the /Gr option and the __fastcall keyword to store some function parameters in registers.

Note  The 32-bit compiler does not support the Pascal/FORTRAN (/Gc, __pascal, or __fortran) calling convention.


Default Calling Conventions (CL)
  Default Calling Conventions

All C and C++ functions use the C calling convention by default. This is also true of functions and member functions that take a variable number of parameters.

All C++ member functions that do not take a variable number of parameters use the thiscall calling convention by default. The thiscall calling convention performs the following actions:

•	Passes the this pointer in the ECX register

•	Pushes all other parameters on the stack from right to left

•	Causes a called member function to pop its own parameters from the stack

You have no direct control over the thiscall calling convention. However, a member function explicitly marked as __cdecl, _ _fastcall, or _ _stdcall uses the associated calling convention, and a member function that takes a variable number of parameters always uses the _ _cdecl calling convention.


Calling Conventions and Code Size (CL)
  Calling Conventions and Code Size

The C calling convention (/Gd) specifies that a calling function must pop the parameters of any function that it calls from the program stack. In this case, the code required to pop the parameters is part of every function call. The fastcall and standard call calling convention (/Gr and /Gz) specify that a called function pop its own parameters from the stack. In this case, the code required to pop the parameters appears only once, with the function's description. Because a typical program has more function calls than functions, the use of /Gr or /Gz can result in a slightly smaller, more efficient program than the use of /Gd. The /Gz option has no effect on C++ methods and functions. See the discussions of the __cdecl,  __fastcall, and  __stdcall keywords in either the C Language Reference or the C++ Language Reference for more information on the associated calling conventions.


  Reference to CL Options

Tables 2.5 through 2.13 list the CL options according to the option categories in the Visual Workbench C/C++ Compiler Options dialog box. You can set options in each dialog box using various kinds of controls: option buttons, check boxes and text boxes. Not all of the CL options are represented by a separate control. In cases where there is no specific control to set an option, you can type the option in the Other Options text box in the Custom Options category.

Note  You are responsible for the accuracy of any option you enter in the Other Options text box. If Visual Workbench recognizes an option as one that can be set using a dialog box control, it changes the dialog-box control to reflect the option and removes the option from the Other Options box. However, if the option is not recognized, it is left on the options string as is and passed to the compiler.


Code Generation Options Dialog Box (CL)
  Code Generation Options Dialog Box

Table 2.5    Code Generation Options Dialog Box

Visual Workbench	Command Line
CPU list box
80386	/G3
80486	/G4
Pentium	/G5
Calling Convention
C/C++ (_ _cdecl)	/Gd
C/C++ (_ _fastcall)	/Gr
C/C++ (_ _stdcall)	/Gz
Struct Member Byte Alignment
1 Byte	/Zp1
2 Bytes	/Zp2
4 Bytes	/Zp4
8 Bytes	/Zp8
16 Bytes	/Zp16


Custom Options Dialog Box (CL)
  Custom Options Dialog Box

Table 2.6    Custom Options Dialog Box

Visual Workbench	Command Line
Eliminate Duplicate Strings	/Gf
Enable Function-Level Linking	/Gy
Suppress Display of Sign-On Banner	/nologo
Warnings as Errors	/WX
Warning Level
None	/W0, /w
Level 1	/W1
Level 2	/W2
Level 3	/W3
Level 4	/W4
Disable Microsoft Language Extensions	/Za
None	/Ze
Other Options
Preserve comments during preprocessing	/C
Compile without linking	/c
Exclude #line directives from preprocessor output	/E
Add #line directives to preprocessor output	/EP
Set stack size	/Fnum
Process specified header file first	/FIfilename
Rename assember listing file	/Fa
Rename program database file	/Fd
Rename executable file	/Fe
Create map file	/Fm
Rename executable file	/Fo
Specify precompiled header filename	/Fp
Control stack checking	/Ge
Control stack checking	/Gs
Generate call to _ _penter in function calls	/Gh
Restrict length of external names	/H
List the compiler options	/HELP, /?
Change default char type	/J
Create a dynamic-link library	/LD
Linker-control options	/link
Override Improve float consistency	/Op−
Enable frame-pointer addressing	/Oy−
Create preprocessor-output file	/P
Specify C source file	/Tc
Specify C++ source file	/Tp
Set version string	/Vstring
Duplicate debugging information in all object files	/Yd
Generate function prototypes	/Zg
Remove default-library name from object file	/Zl
Check syntax only	/Zs


Custom Options (C++) Dialog Box (CL)
  Custom Options (C++) Dialog Box

Table 2.7    Custom Options (C++) Dialog Box

Visual Workbench	Command Line
Disable Construction Displacements	/vd1
C++ Pointer to Member Representation
Representation Method
Best-case always	/vmb
General-purpose always	/vmg
General-Purpose Representation
Point to any class	/vms
Point to multiple inheritance classes	/vmm
Point to virtual inheritance classes	/vmv


Debug Options (C++) Dialog Box (CL)
  Debug Options (C++) Dialog Box

Table 2.8    Debug Options (C++) Dialog Box

Visual Workbench	Command Line
Debug Information
None
Full (C7 Compatible)	/Z7
Partial (Line Numbers Only)	/Zd
Full (Using Program Database)	/Zi


Listing Files Dialog Box (CL)
  Listing Files Dialog Box

Table 2.9    Listing Files Dialog Box

Visual Workbench	Command Line
Assembly	/FA
Assembly + Include Machine Code	/FAc
Assembly + Include Source Code	/FAs
Assembly + Include Machine Code + Include Source Code	/FAcs
Browser Information + Include Local Variables	/FR
Browser Information - Include Local Variables	/Fr
Don't Pack Information	/Zn


Optimizations Dialog Box (CL)
  Optimizations Dialog Box

Table 2.10    Optimizations Dialog Box

Visual Workbench	Command Line
Default
Minimize size	/O1
Maximize speed	/O2
Disable (Debug)	/Od
Full	/Ox
Custom
Assume no aliasing	/Oa
Assume aliasing across function calls	/Ow
Global optimizations	/Og
Generate instrinsic functions	/Oi
Improve float consistency	/Op
Favor small code	/Os
Favor fast code	/Ot
Frame-pointer omission	/Oy
Full	/Ox
Inline Expansion of Functions
Disable *	/Ob0
Only _ _inline	/Ob1
Any suitable	/Ob2


Precompiled Headers Dialog Box (CL)
  Precompiled Headers Dialog Box

Table 2.11    Precompiled Headers Dialog Box

Visual Workbench	Command Line
Automatic use of precompiled headers	/YX
Precompile through header
C++ Files
Precompile through header	/Yc, /Yu
Precompile with source
C Files
Precompile through header	/Yc, /Yu
Precompile with source
Note  The Precompile through Header control is equivalent to placing a pragma pack directive in your source file.


Preprocessor Dialog Box (CL)
  Preprocessor Dialog Box

Table 2.12    Preprocessor Dialog Box

Visual Workbench	Command Line
Symbols and Macros to Define	/D
Individual Symbols to Undefine	/Uname
Undefine All Symbols	/u
Include Path	/I
Ignore Standard Places of Include Files	/X


Runtime Dialog Box (CL)
  Runtime Dialog Box

Table 2.13    Runtime Dialog Box

Visual Workbench	Command Line
Use Run-Time Library
Single Threaded (LIBC.LIB)	/MD
Multi threaded (LIBCMT.LIB)	/ML
Multi Threaded Using DLL (MSVCRT.DLL)	/MT


  Alphabetic Reference to CL Options

A complete, alphabetic reference to the CL options follows. If an option can take one or more arguments, its syntax is shown under a "Syntax" heading before its description.


/C (upper case) (CL)
  /C

The /C option preserves comments during preprocessing with the /E, /P, or /EP options. If you do not specify the /C option, the preprocessor does not pass source-file comments to its output file.

This option is valid only if the /E, /P, or /EP option is also used.

Example

The following example produces a listing named SAMPLE.I. The listing file contains the original source file, including comments, with all preprocessor directives expanded or replaced.

CL /P /C SAMPLE.C


/c (lower case) (CL)
  /c

The /c option instructs CL to compile all C source files given on the command line. Only object files are created. CL does not pass object files to the linker. No executable file or DLL is produced.

Example

The following example compiles FIRST.C, creating the object file FIRST.OBJ, and then compiles SECOND.C, creating the object file SECOND.OBJ. No processing is performed with THIRD.OBJ because CL stops the build process after compilation and before linking.

CL /c FIRST.C SECOND.C THIRD.OBJ


/D (CL)
  /D

Syntax

/Dname[= | # [{string | number}] ]

Use the /D option to define symbols or constants for your source file.

The name is the name of the symbol or constant. It can be defined as a string or as a number. No space can separate /D and name. Enclose the string in quotes if it includes spaces.

Note that with Microsoft Visual C++, you can substitute a number sign (#) for an equal sign (=) when setting the name to string | number. From either the MS-DOS® command line or from a batch file, you cannot set an environment variable, such as CL, to a string that contains an equal sign. Environment variables do, however, accept the number sign. Now that the CL driver allows the substitution of "#" for "=," you can use the CL environment variable to define preprocessor constants:

SET CL="/DTEST#0"

If you omit both the equal sign and the string or number, the identifier is assumed to be defined, and its value is set to 1. For example, entering /DSET defines a constant named SET with a value of 1. Note that the identifier argument is case sensitive. For example, the preceding /D option would have no effect on a constant named set that is defined in the source file.

Use the constants created by the compiler and the /D option in combination with either the #if or #ifdef directive to compile source files conditionally.

You can replace a keyword, identifier, or a numeric constant with no text in a source file. To do so, use the /D option with a keyword, identifier, or a numeric constant and append an equal sign followed by a space. For example, use the following command to remove all occurrences of RELEASE from TEST.C:

CL /DRELEASE= TEST.C

Similarly, use the following command to remove all occurrences of the keyword __far in TEST.C:

CL /D (--) far=  TEST.C

Defining symbols and constants with the /D option has the same effect as using a #define preprocessor directive at the beginning of your source file. The constant is defined until either an #undef directive in the source file removes the definition or the compiler reaches the end of the file.

If a constant defined in a /D option is also defined within the source file, CL uses the definition on the command line until it encounters a redefinition in the source file.

Example

The following code fragment calls a function to check the near heap unless the constant RELEASE is defined:

#if !defined(RELEASE)
     (-) heapchk();
#endif

While developing the program, you can leave RELEASE undefined and perform heap checking to find bugs. Assuming the program name is BIG.C, you would compile with the following command:

CL BIG.C

After you have found all of the bugs in the program, you can define RELEASE in a /D option so the program runs faster, as follows:

CL /DRELEASE BIG.C


/E (CL)
  /E

The /E option preprocesses the C source file and copies preprocessor output to the standard output device (usually your terminal). Unlike the /EP option, the /E option adds #line directives to the output. The #line directives are placed at the beginning and end of each included file and around lines removed by preprocessor directives that specify conditional compilation. You can use the »/EP« option to suppress the addition of #line to the output.

The output that the /E option generates is identical to the original source file except that all preprocessor directives are carried out, macro expansions are performed, and comments are removed. You usually use the /E option with the »/C« option which preserves comments in the preprocessed output.

Use the /E option when you want to resubmit the preprocessed listing for compilation. The #line directives renumber the lines of the preprocessed file so that errors generated during later stages of processing refer to the line numbers of the original source file rather than to the preprocessed file.

The /E option suppresses compilation; CL does not produce an object file, even if you specify the /Fo option on the CL command line. The /E option also suppresses production of the alternate output files that the /FA, /Fa, or /Fm option generates.

Example

The following command creates a preprocessed file with inserted #line directives from the source file ADD.C. The output is redirected to the file PREADD.C.

CL /E /C ADD.C > PREADD.C

Note  You cannot use precompiled headers with the /E option.


/EP (CL)
  /EP

The /EP option is similar to the /E option: It preprocesses the C source file and copies preprocessor output to the standard output device. Unlike the /E option, however, the /EP option does not add #line directives to the output.

Preprocessed output is identical to the original source file except that all preprocessor directives are carried out, macro expansions are performed, and comments are removed. You can use the /EP option with the »/C« option  which preserves comments in the preprocessor output file.

The /EP option suppresses compilation; CL does not produce an object file, even if you specify the /Fo option on the CL command line. The /EP option also suppresses production of the alternate output files that the /FA, /Fa, or /Fm option generates.

Example

The following command creates a preprocessed file from the source file ADD.C. It preserves comments but does not insert #line directives. The output appears on the screen.

CL /EP /C ADD.C


/F (CL)
  /F

Syntax

/F number

The /F option sets the program stack size to a specified number of bytes. If you don't specify this option, a stack size of 1 MB is used by default. The number argument can be a decimal, octal, or hexadecimal number. The argument can range from a lower limit of 1 to the maximum stack size accepted by your linker. Table 2.14 shows the prefixes to the number argument you use to specify the three different number systems.

Table 2.14    Prefixes and Number Systems

Prefix	Number system
none	Decimal
0	Octal
0x	Hexadecimal
You may want to increase the stack size if your program gets stack-overflow diagnostic messages.


/FA (CL)
  /FA

Syntax

/FA[string]

Use the /FA option to create a listing file containing source code, assembler code, and machine code. The generated file will always contain assembly code. The string argument controls the generation of source code and machine code. The string argument can be left blank, or it can be defined as c, s, or cs, as shown in Table 2.15.

Table 2.15    Listing-File Control

Letter	Action
c	Listing file contains machine code
s	Listing file contains source code
no letter	Listing file contains assembly code
The default extensions for listing files are listed in Table 2.16.

Table 2.16    Default File Extensions

Option	Extension
/FA	.ASM
/FAs	.ASM
/FAc	.COD
/FAsc	.COD
Example

In the following example, CL produces a combined source and machine-code listing called HELLO.COD. The object file has the default name HELLO.OBJ.

CL /FAsc HELLO.CPP


/Fd, /Fo, /Fe, /Fa, /Fm, /Fp, /FR, /Fr (CL)
  /Fd, /Fo, /Fe, /Fa, /Fm, /Fp, /FR, /Fr

Use these options to specify alternate names for output files. Table 2.17, which follows, summarizes each option. The following paragraphs describe how to use these options.

Table 2.17    Optional File Types

CL option	File type	Default filename	Default extension
/Fd	Program database	MSVC.PDB	.PDB
/Fo	Object	Base name of source file plus .OBJ	.OBJ
/Fe	Executable	Base name of source file plus .EXE  or .DLL	.EXE
/Fa	Assembly listing	Base name of source file plus .ASM	.ASM
/Fm	Linker map	Base name of executable file plus .MAP	.MAP
/Fp	Precompiled header	MSVC.PCH	.PCH
/FR	Source Browser file —  includes local variables	Base name of source file plus .SBR	.SBR
/Fr	Source Browser file —  excludes local variables	Base name of source file plus .SBR	.SBR


Path Specifications and Extensions (CL)
  Path Specifications and Extensions

The filename argument must follow the option with no intervening space. It can be a file specification, a drive name, or a path specification. If filename is a drive name or path specification, the CL command creates the specified file or files in the given location; the default name is listed in Table 2.17. If the filename argument is a path without a filename (that is, a directory), end the path with a backslash (\) or CL cannot differentiate the path from a filename.

You can give any name and extension for filename. If you give a filename without an extension, CL automatically appends the default extension. The results of adding filename, drive name, and/or path arguments to the listing options are described in the following paragraphs:

Filename  Creates a listing for every source file specified in the CL environment variable, on the command line, and in any response file. The file is given the default extension if an extension is not given.

Drive name or path  Creates listings in the specified location for every source file specified in the CL environment variable, on the command line, and in any response file. The listing is given the base name of the source file and an extension determined by the type of listing.

No argument  Creates listings in the current directory for every source file specified in the CL environment variable, on the command line, and in any response file. The listing is given the base name of the source file and an extension determined by the type of listing.


Combining Options (CL)
  Combining Options

The following list summarizes the interactions between options:

Option	Effect
/Fm and /c	Linking is suppressed; /Fm is ignored
/Fe and /c	Linking is suppressed; /Fe is ignored


Windows NT Device Names (CL)
  Windows NT Device Names

You can append the Windows NT device names AUX, CON, PRN, and NUL to the alternate output-file options and direct the resulting listing files to your terminal or printer. There can be no space between the option and the device name. For instance, the following command line generates assembly code for TEST.C and directs the output to the console:

CL /FaCON TEST.C

The following list summarizes the result when a device name is appended to an option:

Device name	Result
AUX	Sends the listing file to an auxiliary device
CON	Sends the listing file to the console
PRN	Sends the listing file to a printer
NUL	No file is created
Note  Do not append a colon (:) to the device names when you use them as arguments to the listing options. For example, use CON instead of CON: and PRN instead of PRN:.

Example

In the following example, CL sends an assembly-code listing to the printer:

CL /FaPRN HELLO.CPP


/Fa (CL)
  /Fa

Syntax

/Fa[ filename]

The /Fa option instructs the compiler to translate your C or C++ source code to assembly language. The new /FA option, with no argument, is the recommended way to generate an assembly file as an alternate output file. The /Fafilename option remains useful for renaming (or creating in a different directory) the assembly file generated by /FA. Without the use of the /Fafilename option, the default name of the assembly file is the base name of the C or C++ source file, specified on the CL command line, with an .ASM or a .COD extension. Example

The following example compiles, but does not link (/c), the source file QSORT.C and generates an assembly-listing file named QSORT.ASM in a directory named ASM. The compiler will not make a directory.

CL /c /FaASM\QSORT  QSORT.C


/Fd (CL)
  /Fd

Syntax

/Fdfilename

Use the /Fd option to specify a filename for a program database (PDB) other than the default name, MSVC.PDB, created by /Zi. No space is allowed between /Fd and filename.

If you do not specify an extension to filename, an extension of .PDB is used. Also, if filename ends in a backslash (to specify the name of a directory), the default filename (MSVC.PDB) is appended to filename. You can also use the filename argument to specify a directory. For more information on PDBs, see »/Zi«.

Example

The following command creates a .PDB file called DPROG.PDB that contains debugging information.

CL /DDEBUG /Zi /FdDPROG.PDB PROG.CPP


/Fe (CL)
  /Fe

Syntax

/Fefilename

By default, CL names the executable file with the base name of the first file (source or object) on the command line plus the extension .EXE (or .DLL if you use the /LD option to create a dynamic-link library). The /Fe option lets you give the executable file or DLL a different name or create it in a different directory.

The /Fe option applies only in the linking stage. If you specify the /c option to suppress linking, /Fe has no effect.

Examples

The following example compiles and links all source files with the extension .C in the current directory. The resulting executable file is named PROCESS.EXE and is created in the directory C: \BIN.

CL /FeC:\BIN\PROCESS *.C

The following example is similar to the first example except that the executable file is given the same base name as the first file compiled instead of being named PROCESS.EXE. The executable file is created in the directory C: \BIN.

CL /FeC:\BIN\ *.C


/Fm (CL)
  /Fm

Syntax

/Fm[ filename]

The /Fm option produces a map file. The map file contains a list of segments. The segments are listed in the order of their appearance within the load module. Unless you name the resulting file with the optional filename argument, it is given the base name of the C or C++ source file specified on the CL command line with a .MAP extension. You can also use the filename argument to specify a directory.

Global symbols in a map file usually have one or more leading underscores because the compiler adds an underscore to the beginning of variable names. Many of the global symbols that appear in the map file are symbols used internally by the compiler and the standard libraries.


/Fo (CL)
  /Fo

Syntax

/Fofilename

By default, CL gives each object file it creates the base name of the corresponding source file plus the extension .OBJ. The /Fo option lets you give different names to object files or create them in a different directory. No space is allowed between the option and filename. The /Fo option requires a filename argument.

You can give any name and extension you want for filename. However, it is recommended that you use the conventional .OBJ extension since the linker and the LIB library manager use .OBJ as the default extension when processing object files.

Example

In the following example, CL compiles the source file THIS.C and gives the resulting object file the name THIS.OBJ by default. The directory specification B:\OBJECT\ tells CL to create THIS.OBJ in the directory named \OBJECT on drive B.

CL /FoB:\OBJECT\ THIS.C


/Fp (CL)
  /Fp

Syntax

/Fpfilename

Use the /Fp option with the /YX, /Yc, and /Yu options to specify a .PCH filename (and path) that is different from the default. If you do not specify an extension to filename, an extension of .PCH is used. Also, if filename ends in a backslash (to specify the name of a directory), the default filename (MSVC.PCH) is appended to filename. See the  related options »/YX«, »/Yc«, »/Yd«, and »/Yu« for more information.

Examples

Use the following command to rename the default MSVC.PCH file created and used by the "automate precompiled header" option (/YX):

CL /YX /FpMYPCH.PCH PROG.CPP

This command causes the compiler to use a precompiled header named MYPCH.PCH. This command will also create the specified headerfile if it has not been created.

Use the following command if you want to create a precompiled header file for a debugging version of your program and you are compiling both header files and source code:

CL /DDEBUG /Zi /Yc /FpDPROG.PCH PROG.CPP

This command assumes the existence of a hdrstop pragma in PROG.CPP and creates a precompilation of all code up to the hdrstop pragma. The precompiled code is stored in a file called DPROG.PCH. If you need a release version in parallel, use the following command:

CL /Yc /FpRPROG.PCH PROG.CPP

This command creates a separate precompilation of all code up to the hdrstop pragma and stores it in RPROG.PCH.


/FR, /Fr (CL)
  /FR, /Fr

Syntax

/FR[filename]
/Fr[filename]

These options are used with the Microsoft Source Browser. Both options create a file with an .SBR extension. The Microsoft Browser Database Maintenance Utility (BSCMAKE) uses an .SBR file to create a database file with a .BSC extension. The .BSC file is used by the Source Browser.

An .SBR file contains symbolic information about your program. Using the /FR option creates an .SBR file with complete symbolic information. Using the /Fr option creates an .SBR file without information on local variables.

By default, both options generate a filename that uses the source file's base name and appends an .SBR extension. Use the filename argument to provide a name and directory other than the default; an .SBR extension is required. No space is allowed between either the /FR or the /Fr option and the filename argument.

The  option suppresses packing of the .SBR file.

For information about using the Source Browser and BSCMAKE, see »Using BSCMAKE« in Chapter 6 and see Chapter 4, "Using the Browser" in Visual Workbench User's Guide.

Example

The following command compiles and links the source file QSORT.C and generates a file named NEWSORT.SBR.

CL /FRNEWSORT  QSORT.C


/FI (CL)
  /FI

Syntax

/FIfilename

The /FI option causes the preprocessor to process the header file specified by filename. Each filename is included as if it were line 0 of any source file specified on the command line. The space between /FI and filename is optional. If multiple /FI options are used, the files are processed in the order they are found in the CL environment variable, on the command line, or in any response file. Files are included as if they were specified with " " in an #include directive.


/G3, /G4, /G5 (CL)
  /G3, /G4, /G5

You can use the /G3, /G4, or /G5 options to optimize the compiler's code generation for the 80386, 80486, or Pentium processors. Using these options optimizes the generated code for the target processor; it does not prevent the code from running on a lower-numbered processor. For example, compiling a program with /G5 optimizes the resulting code for a Pentium processor; the same code will run on an 80386 processor. On the other hand, compiling the same program with /G3 will produce code that runs a little faster on an 80836.

Note  You cannot use 80x86 or Pentium mnemonics as labels inside blocks of inline
_ _asm code.


Preprocessor Identifiers (CL)
  Preprocessor Identifiers

Table 2.18 lists the preprocessor identifiers generated by each compiler for each option. The compiler generates a value for the _M_IX86 preprocessor that reflects the processor option specified.

Table 2.18    Preprocessor Identifiers for /G3, /G4, and /G5

Option	Value
/G3	_M_IX86 = 300
/G4	_M_IX86 = 400 (Default)
/G5	_M_IX86 = 500


/Gd (CL)
  /Gd

The /Gd option specifies that all functions that are not C++ member functions or are not marked as __stdcall or __fastcall will use the C calling convention. That is, a called function's parameters are pushed onto the stack from right to left and the calling function must pop these parameters from the stack when control returns to the calling function. This option is the default.

For C, the /Gd naming convention (and __cdecl) uses the function name preceded by an underscore ( _ )—no case translation is done. Unless declared as extern "C", C++ methods and functions use a different name decorating scheme.

Note  By default, C++ member functions use a calling convention whereby the member function's this pointer is passed in the ECX register, all other parameters are pushed on the stack from right to left, and the called routine pops the member function's parameters from the stack. A member function that is explicitly marked as _ _cdecl, _ _fastcall, or _ _stdcall uses the specified calling convention. A member function that takes a variable number of parameters always uses the _ _cdecl calling convention.


/Ge (CL)
  /Ge

Syntax

/Ge

The /Ge option (and the /Gs option with a size of 0) activate stack probes for every function call that requires storage for local variables. This mechanism is useful only if you rewrite the functionality of the stack probe. We recommend that you use the /Gh option rather than rewriting the stack probe.


/Gs (CL)
  /Gs

Syntax

/Gssize

The /Gssize option is an advanced feature that allows you to control stack probes. A stack probe is a sequence of code that the compiler inserts into every function call. When activated, a stack probe reaches benignly into memory by the amount of space required to store the associated function's local variables.

If a function requires more than size stack space for local variables, its stack probe is activated. The default value of size is the size of one page (4K for Intel x86 processors). This value allows a carefully tuned interaction between a Win32™ application and the Windows NT virtual-memory manager to increase the amount of memory committed to the program stack at runtime.

Warning  The default value of size is carefully chosen to allow the program stack of Win32 applications to grow at run time. Do not change the default setting of /Gs unless you know exactly why you need to change it.

Some programs, such as virtual device drivers, do not require this default stack-growth mechanism. In such cases, the stack probes are not necessary. You can stop the compiler from generating stack probes by setting size to a value that is larger than any function will require for local variable storage.

The /Gs option with a size of 0 activate stack probes for every function call that requires storage for local variables. This mechanism is useful only if you rewrite the functionality of the stack probe. We recommend that you use the /Gh option rather than rewriting the stack probe.

You can turn stack probes on or off by using the check_stack pragma. Note that the /Gs option and the check_stack pragma have no effect on standard C library routines; they affect only the functions you compile. For more information on the check_stack pragma, see Preprocessor Reference.


/Gf (CL)
  /Gf

The /Gf option enables the compiler to place a single copy of identical strings into the executable file. Because identical strings are copied into a single memory location, programs compiled with the /Gf option can be smaller than those compiled without /Gf. This space optimization is sometimes called "string pooling." Use of /Gf does not guarantee string pooling in all cases. String pooling does, however, occur in most cases.

Example

When the following two source files:

// file1.c
char * sz = "String";
// file2.c
    printf( "String" );

are compiled and linked with the following command line:

cl /Gf file1.c file2.c

only one copy of "String" will exist in the resulting executable file.

When using /Gf, you must not write over strings that can be pooled.

Note  When using /Gf, you must not write over pooled strings.


/Gh (CL)
  /Gh

The /Gh option causes the compiler to generate a call to a function named _ _penter as the very first line of code in the body of every method or function. The libraries do not provide a _ _penter function. Rather, this call is a hook that you can use for your own purposes. You should use assembly language to write a _ _penter function. Unless you plan to explicitly call _ _penter, you do not need to provide a prototype. The _ _penter function must appear as if it had the following prototype:

void _ _cdecl _penter( void );

In other words, _ _penter must not modify the content of any register—it must push the content of all registers on entry and pop the unchanged content on exit. The compiler does not generate a call to _ _penter for methods or functions that it generates inline.


/Gr (CL)
  /Gr

The /Gr option specifies that all functions that are not C++ member functions or are not marked as __cdecl or __stdcall use the fastcall calling convention. All functions that use the fastcall calling convention must have prototypes.

For fastcall, some of a called function's actual parameters are passed in registers (ECX and EDX) and the rest are pushed onto the stack from right to left. The called routine must pop these parameters from the stack before it returns. Typically, /Gr decreases execution time.

Note  By default, C++ member functions use a calling convention that passes the member function's this pointer in the ECX register, all other parameters are pushed on the stack from right to left, and the calling routine pops the member function's parameters from the stack. A member function that is marked as _ _cdecl, _ _fastcall, or _ _stdcall uses the specified calling convention. A member function that takes a variable number of parameters always uses the _ _cdecl calling convention.

For C, the /Gr naming convention (and __fastcall) uses the function name preceded by an at sign (@). An at sign (@) followed by the size of the function's actual parameters in bytes is appended to the function name. No case translation is done. The compiler uses the following template for the naming convention:

@function_name@number

Unless declared as extern "C", C++ methods and functions use a different name decorating scheme.

Note  Microsoft does not guarantee the same implementation of the __fastcall calling convention between compiler releases. For example, the implementation differs between the 16- and 32-bit compilers.

When using the fastcall naming convention, make sure to use the standard include files. Otherwise, you get unresolved external references.

Important  Be careful when using the register calling convention for any function written in inline assembly language. Your use of registers in assembly language could conflict with the compiler's use of registers for storing parameters.


/Gy (CL)
  /Gy

The /Gy option enables linking on a function-by-function basis by creating packaged functions. Packaged functions are visible to the linker in the form of COMDAT records. Packaged functions have several uses:

•	You can exclude unreferenced packaged functions from the executable file by specifying the linker's /OPT:REF option. For more information see »/OPT« in Chapter 4.

•	You can place packaged functions in a specified order in the executable file by using passing the /ORDER option to the linker. For more information see »/ORDER« in Chapter 4.

Inline functions are always packaged if they are instantiated (e.g. if inlining is turned off or you take the function address). Also, C++ member functions defined within the class declaration are automatically packaged; other functions are not, and /Gy is required to compile them as packaged functions.


/Gz (CL)
  /Gz

The /Gz option specifies that all prototyped C functions that do not take a variable number of parameters and are not marked as __cdecl or __fastcall, use the standard-call (__stdcall) calling convention. All functions that use the standard call calling convention must have prototypes.

For standard call, a called function's actual parameters are pushed onto the stack from right to left and the called function must pop these parameters from the stack before it returns. The /Gz option has no effect on C++ methods and functions.

For C, the /Gz naming convention (and __stdcall) uses the function name preceded by an underscore ( _ ) and followed by an at sign (@) and the size of the function's parameters in bytes. No case translation is done. The compiler uses the following template for the naming convention:

_functionname@number

Unless declared as extern "C", C++ methods and functions use a different name decorating scheme.


/H (CL)
  /H

Syntax

/Hnumber

The /H option restricts the length of external (public) names. The number field accepts an integer specifying the maximum number of significant characters; the compiler considers only the first number characters of external names in the program. The program can contain external names longer than number characters,
but the extra characters are ignored.

Use the /H option with tools that impose limits on the length of external identifiers. Without the /H option, the compiler imposes no limit on the length of external identifiers. However, other tools that operate on the object files generated by the compiler, such as linkers, may impose limits. The limit on length includes any compiler-generated leading underscore (_) or at sign (@). The compiler adds a leading underscore to names modified by the __cdecl (default) and __stdcall calling conventions and a leading at sign to names modified by __fastcall calling conventions; it also appends argument size information to names modified by the __fastcall and __stdcall calling conventions and adds type information to C++ names.

You may find /H useful when creating mixed-language or portable programs.


/HELP (CL)
  /HELP

Syntax

/HELP
/help
/?

This option displays a multi-page, quick-reference listing of the compiler options to the standard output device.


/I (CL)
  /I

Syntax

/Idirectory

You can add to the list of directories searched for in include files by using the /I (for "include") option. The space between /I and directory is optional.

The search process for included files can involve three stages and begins with the #include directive. If the file specified to the #include directive contains a complete drive and path specification, that file is included without searching any directories. If the specified file is enclosed in double quotation marks, the directory of the file containing the #include directive is searched. If the current file is also an include file, the directory of the parent file is searched until the original source file's directory is searched.

The second stage uses the /I option. If the file is still not found or if it is specified to the #include directive in angle brackets, a directory specified by an /I command-line option is searched. To search more than one directory, give additional /I options on the CL command line — one /I option for each directory. Use a space to separate multiple /I options. Multiple directories are searched in order of their appearance on the command line. The directories are searched only until the specified include file is found.

The third and final stage involves the INCLUDE environment variable. If the file is not found in a directory specified by an /I option, a directory or path specified in the INCLUDE environment variable is used. This enables you to give a particular file special handling without changing the compiler environment you usually use. If the include file is not found, the compiler prints an error message and stops processing. When this occurs, you must restart compilation with a corrected directory specification.

Examples

In the following example, CL looks for the include files requested by MAIN.C in the following order: first in the directory \INCLUDE, then in the \MY\INCLUDE directory, and finally in the directory or directories assigned to the INCLUDE environment variable.

CL /I \INCLUDE /I\MY\INCLUDE MAIN.C

In the following example, the compiler looks for include files only in the \ALT\INCLUDE directory. The »/X« option tells CL to consider the list of standard places empty; the /I option causes CL to search only the specified directory.

CL /X /I \ALT\INCLUDE MAIN.C


/J (CL)
  /J

The /J option changes the default char type from signed char to unsigned char. This option is useful when you are working with character data that will eventually be translated into a language other than English. If a char value is explicitly declared signed, the /J option does not affect it, and the value is sign extended when widened to int type. With the /J option the char type is zero extended when widened to an int type.

When you specify /J, the compiler automatically defines the identifier _CHAR_UNSIGNED, which is used with #ifndef in the LIMITS.H include file to define the range of the default char type.

Neither ANSI C nor C++ requires a specific implementation of the char type.


/LD (CL)
  /LD

The /LD option allows you to compile and link a program as a dynamic-link library (DLL). The /LD option does the following:

•	Causes the compiler to pass the /DLL option to the linker. The compiler looks for, but does not require, a DllMain function. If you do not write a DllMain function, the compiler simply inserts a DllMain function that returns TRUE.

•	Causes the linker to link the DLL startup code.

•	Causes LIB to produce an import library, if an export file (.EXP) is not specified on the command line, to be linked to applications that call your DLL.

•	Interprets /Fe as naming a DLL rather than an executable file; the default program name becomes basename.DLL instead of basename.EXE.

•	Changes default run-time library support to /MT if you have not explicitly specified one of /MD, /ML, or /MT.

For more information on creating DLLs, see Programming Techniques.

Example

The following command line:

CL /LD FILE1.CXX FILE2.CXX

tells the compiler to pass the following commands to the linker:

/OUT:FILE1.DLL

/DLL

?*?/IMPLIB:FOO.LIB?*?

FILE1.OBJ FILE2.OBJ

The following command:

CL /LD FILE1.CXX FILE2.CXX FILE1.EXP

tells the compiler to pass the following commands to the linker:

/OUT:FILE1.DLL

/DLL

FILE1.OBJ FILE2.OBJ

FILE1.EXP

In this case, no import library (.LIB) is passed to the linker because LIB will create one from the export file (.EXP) that the compiler passes to the linker.

In both of the previous examples, the output from the linker is a DLL. Also, both the import library, FOO.LIB, and the DLL are placed in the same directory. This means that the following command line will create both DLL\FILE1.DLL and DLL\FILE1.LIB:

CL /LD /FeDLL\ FILE1.C

If your source code contains no exported functions, the linker will not generate an import library (.LIB).


/link (CL)
  /link

Syntax

/link [option]

This option passes the linker options specified by the option argument to LINK. The /link option and its associated linker options must appear after any source or object filenames and CL options. A space is required between /link and option.

For information about linker options, see »Chapter 4«.

The CL options shown in Table 2.19 also affect the linker:

Table 2.19    CL options that affect the linker

Option	Description
/F num	Resets stack size to specified number. This option is the same as passing the STACK option to LINK.
/Fm	Produces a map file.
/MD	Statically links with MSVCRT.LIB and defines _MT and _DLL. MSVCRT10.DLL must be available at run time.
/ML	Links with LIBC.LIB (default).
/MT	Links with LIBCMT.LIB and defines _MT (default with /LD).


/MD (CL)
  /MD

The /MD option causes the driver to define _MT and _DLL so that both multithread and DLL versions of the runtime routines are selected from the standard header files. It also causes the compiler to place the library name "MSVCRT.LIB" in the object file. Either /MD or /MT is required to create multithreaded programs.

Applications compiled with /MD are statically linked to MSVCRT.LIB. This library provides a layer of code that allows the linker to resolve external references. The actual working code is contained in MSVCRT10.DLL, which must be available at run time to applications linked with MSVCRT.LIB.


/ML (CL)
  /ML

The /ML option causes the compiler to place the library name "LIBC.LIB" in the object file so the linker will use LIBC.LIB to resolve external symbols. This is the compiler's default action. LIBC.LIB does not provide multithread support.


/MT (CL)
  /MT

The /MT option causes the driver to define _MT so that multithread versions of the runtime routines are selected from the standard header files. It also causes the compiler to place the library name "LIBCMT.LIB" in the object file so the linker will use LIBCMT.LIB to resolve external symbols. Either /MT or /MD is required to create multithreaded programs.


/nologo (CL)
  /nologo

The /nologo option suppresses the display of the sign-on banner when CL is invoked.


/O (CL)
  /O

Syntax

/Ostring

The /O options allow you to control the optimization applied to the code that the compiler generates for your program. Use the /Od option to disable optimization and speed compilation and simplify debugging. Use the /Og option to enable basic global optimizations.

The string argument is one or more letters, with no intervening spaces, from Table 2.20. The letters following the /O, including the number argument to /Obn and the minus arguments to /Op− and /Oy−, can appear in a continuous series in any order.

Table 2.20    Optimization Options

Letter	Optimizing procedure
/O1, /O2	Specify small or very fast code
/Oa	Assume no aliasing
/Ow	Assume aliasing across function calls
/Obn	Control inline expansion, where n is a digit from 0 through 2
/Og	Enable global optimization
/Od	Disable optimization
/Oi	Generate intrinsic functions
/Op, /Op−	Improve floating-point consistency
/Os	Specify short sequences of machine code
/Ot	Specify fast sequences of machine code (default)
/Ox	Use maximum optimization
/Oy, /Oy−	Omit or generate frame pointers on the program stack


/O1, /O2 (CL)
  /O1, /O2

The /O1 and /O2 options select a predefined set of options — not all are optimization (/O) options — that affect the size and speed of executable files. The /O1 option produces small executable files. The /O2 option produces very fast executable files. Both options are designed to produce executable files or DLLs that will run well on most machines. The result of using /O1 or /O2 is more extensive than that of using /Os or /Ot.

Table 2.21 shows the options that the optimizing compiler uses to implement /O1 and /O2.

Table 2.21    Implementation of /O1 and /O2

Option	Equivalent to	Comment
/O1	/Osgb1 /Gfy	Smallest code
/O2	/Ox /Gfy	Fastest code
You can use other options to improve the size or speed of many applications. For example, neither /O1 nor /O2 use a processor-selection option (/G3, /G4, or /G5) to produce code that is optimized for computers based on 80386, 80486, or Pentium processors.

Note  The use of the /O2 option implies the use of the "omit frame pointer" option (/Oy). If your project contains code requiring EBP-based addressing, you can specify the /Oy− option after the /O2 option or use the optimize pragma with the "y" and off arguments to gain maximum optimization with EBP-based addressing. The compiler detects most situations where EBP-based addressing is required (for instance, with the _alloca and setjmp functions and with structured exception handling.)


/Oa and /Ow (CL)
  /Oa and /Ow

The /Oa option tells the compiler that your program does not use more than one name for a memory location. A name used to refer to a memory location that is already referred to by a different name is called an "alias." Aliasing can slow your application by reducing both the extent to which a compiler can keep variables in registers and the types of loop optimizations it can perform.

Whereas the /Oa option tells the compiler that none of your code uses aliases, the /Ow option tells it that no aliasing occurs within function bodies but might occur across function calls. Therefore, after each function call, pointer variables must be reloaded from memory.

When you tell the compiler to assume that you are not doing aliasing, it expects that the rules in the following list are being followed for any variable not declared as volatile. In the list, the term "reference" means read or write; that is, whether a variable is on the left side of an assignment statement or the right side, you are still referring to it. In addition, any function calls that use a variable as a parameter reference that variable.

If the following aliasing rules are not followed, any use of /Oa or /Ow is ignored:

•	No pointer is used to reference a variable that is used directly.

•	No variable is used directly if a pointer to the variable is being used.

•	No variable is used directly if the address to the variable is taken within a function.

•	No pointer is used to access a memory location if another pointer is used to modify the same memory location.

For programs compiled with /Oa, aliasing bugs most frequently show up as corrupted data. If global or local variables are being assigned seemingly random values, take the following steps to determine if you have a problem with optimization and aliasing:

•	Compile the program with /Od (disable optimization).

•	If the program works when compiled with the /Od option, check your normal compile options for the /Oa option.

•	If you were using the /Oa option, change your compile options so that /Oa is not specified.

Note  You can instruct the compiler to disable optimizations around code that uses aliasing (for individual functions) by using the optimize pragma with the a or w option. For more information on the optimize pragma see Preprocessor Reference.


/Obn (CL)
  /Obn

Use the /Ob option to control the inline expansion of functions, where n is a digit from 0 through 2. Table 2.22 describes the action of each digit.

Table 2.22    Inline Expansion Control

Digit	Action
0	Disables inline expansion (default)
1	Expands only functions marked as inline or __inline or in a C++ member function defined within a class declaration (default with /O1, /O2, and /Ox)
2	Expands functions marked as inline or __inline and any other function that the compiler chooses (expansion occurs at compiler discretion — often referred to as "auto-inlining")
The /Ob0 option allows you to turn off inlining. The /Ob1, /Ob2, options and the inline and __inline keywords allow you to control the degree of inlining. The compiler treats these options and keywords as suggestions. There is no guarantee that functions will be inlined, and there is no control over the inlining of individual functions.


/Od (CL)
  /Od

The /Od option turns off all optimizations in the program and speeds compilation. This option is the default. Because /Od suppresses code movement, it simplifies the debugging process. For information on the compile-for-debugging options see »/Zi /Z7 and /Zd«.


/Og (CL)
  /Og

The /Og option enables the optimizing compiler to provide the following optimizations:

•	Local and global common subexpression allocation

•	Automatic register allocation of variables and subexpressions

•	Loop optimizations

Local and global common subexpression elimination

This optimization allows the compiler to calculate the value of a common subexpression once. For example, b + c is common to the following code. If the values of b and c do not change between the three expressions, the compiler can calculate the value of b + c once, assign the calculation to a temporary variable, and substitute the variable as appropriate.

a = b + c;
d = b + c;
e = b + c;

For local common subexpression optimization, the compiler examines short sections of code (basic blocks) for common subexpressions. For global common subexpression optimization, the compiler searches entire functions for common subexpressions.

Automatic register allocation

This optimization allows the compiler to store frequently used variables and subexpressions in registers; the register keyword is ignored.

Loop optimizations

Loop optimizations move or rewrite code so that it executes more quickly. Because loops involve sections of code that are executed repeatedly, they are excellent targets for optimization.

An optimal loop contains only expressions whose values change through each execution of the loop. Any subexpression with a constant value should be evaluated before the body of the loop is executed. Unfortunately, these subexpressions are not always readily apparent. The optimizer can remove many of them from the body of a loop at compile time. This example illustrates an expression that does not change in a loop:

i = -100;
while( i < 0 )
{
    i += x + y;
}

In the preceding example, the expression x + y does not change in the loop body. Loop optimization removes this subexpression from the body of the loop so that it is only executed once, not every time the loop body is executed. The optimizer changes the code to the following:

i = -100;
t = x + y;
while( i < 0 )
{
    i += t;
}

Loop optimization is much more effective when the compiler can assume no aliasing. While you can use loop optimization without the /Oa or /Ow option, use /Oa to ensure that the most options possible are used.

Here is a code fragment that could have an aliasing problem:

i = -100;
while( i < 0 )
{
    i += x + y;
    *p = i;
}

If you do not specify the /Oa option for the preceding code, the compiler must assume that either x or y could be modified by the assignment to *p. Therefore, the compiler cannot assume the subexpression x + y is constant for each loop iteration. If you specify that you are not doing any aliasing (with the /Oa option), the compiler assumes that modifying *p cannot affect either x or y, and that the subexpression is indeed constant and can be removed from the loop, as in the previous example. For more information see the  »/Oa and /Ow« options.

Note  You can enable or disable global optimization on a function-by-function basis using the optimize pragma with the g option.


/Oi (CL)
  /Oi

The /Oi option instructs the compiler to replace the following function calls with their intrinsic (inline) forms:

_disable	abs
_enable	fabs
_inp	labs
_inpw	memcp
_lrotl	memcpy
_lrotr	memset
_outp	strcat
_outpw	strcmp
_rotl	strcpy
_rotr	strlen
_strset
Programs that use intrinsic functions are faster because they do not include the overhead associated with function calls. However, they may also be larger due to the additional code generated.

Note  The _alloca and _setjmp functions are always generated inline; this behavior is not affected by /Oi.

The floating-point functions listed below do not have true intrinsic forms. Instead they have versions that pass arguments directly to the floating-point chip rather than pushing them onto the program stack:

acos	pow
asin	sinh
cosh	tanh
fmod
The floating-point functions listed below have true intrinsic forms when you specify both /Oi and /Og (or any option that includes /Og—/Ox, /O1, and /O2):

atan	log10
atan2	sin
cos	sqrt
exp	tan
log

The intrinsic floating-point functions do not perform any special checks on input values and so work in restricted ranges of input, and have different exception handling and boundary conditions than the library routines with the same name. Using the true intrinsic forms implies loss of IEEE exception handling, and loss of _matherr, and errno functionality; the latter implies loss of ANSI conformance.

You may use the /Op or /Za options to override generation of true intrinsic floating-point options. In this case, the functions are generated as library routines that pass arguments directly to the floating-point chip instead of pushing them onto the program stack.


/Op, /Op (CL)
  /Op, /Op

Use the /Op option to improve the consistency of floating-point tests for equality and inequality. The /Op option disables optimizations that could change the precision of floating-point calculations. Without the /Op option, the compiler uses the coprocessor's 80-bit registers to hold the intermediate results of floating-point calculations. This increases program speed and decreases program size. However, as the calculation involves floating-point data types that are represented in memory by less than 80 bits, carrying the extra bits of precision (80 bits minus the number of bits in a smaller floating-point type) through a lengthy calculation can produce inconsistent results.

Note  The /Op option disables inline generation of floating-point functions. The standard run-time library routines are used instead. For more information, see the »/Oi« option.

When you use the /Op option, the compiler loads data from memory prior to each floating-point operation and, if assignment occurs, writes the results back to memory upon completion. Loading the data prior to each operation guarantees that the data does not retain any significance greater than the capacity of its type. A program compiled with /Op may be slower and larger than one compiled without /Op.

Note  If you use the /Za (compile for ANSI compatibility) option, CL uses the /Op option to improve the consistency of floating-point tests for equality and inequality. This use of /Op with /Za is for strict ANSI conformance and is the only situation under which /Op is selected by default. The /Op− option is provided to override the default selection of /Op with /Za. Placing the /Op− option on the command line after the /Za option will disable /Op.


/Os and /Ot (CL)
  /Os and /Ot

The compiler can reduce many C and C++ constructs to different, but functionally similar, sequences of machine code. Occasionally these differences offer tradeoffs with respect to the size or the speed of the code. The "optimizing code generation" options (/Os and /Ot) allow you to specify a preference for either small machine code or fast machine code when the compiler recognizes the existence of such a choice; see the example that follows.

The /Os option minimizes the size of executable files and DLLs by instructing the compiler to favor size over speed; it produces smaller but possibly slower code. If you do not select this option, code may be larger and may be faster.

The /Ot option maximizes the speed of executable files and DLLs by instructing the compiler to favor speed over size; this option produces faster but possibly larger code. This is the default.

The /Ot option is implied by the /O2 option. The /O2 option combines several options to produce very fast code; it is described earlier in this chapter.

Note  The /Os and /Ot options have their greatest effect when used with the /Og option.

Example

Using either the /Os or the /Ot option can cause the compiler to generate functionally equivalent but different machine code from the same source code. Consider the implementation of a multiplication operator in the following source code:

/* differ.c

    Compile /Os to see multiply implemented explicitly

    as multiply (a short but slower sequence of code).

    Compile /Ot to do multiply implemented as a series of shift

    and LEA instructions (a fast but longer sequence of code).

 */

int differ(int x)

{

    return x * 71;

}

As shown in the fragment of machine code below, when DIFFER.C is compiled for size (/Os), the compiler implements the multiply expression in the return statement explicitly as a multiply to produce a short but slower sequence of code:

mov	eax, DWORD PTR _x$[ebp]

imul	eax, 71	; 00000047H

Alternatively, when DIFFER.C is compiled for speed (/Ot), the compiler implements the multiply expression in the return statement as a series of shift and LEA instructions to produce a fast but longer sequence of code:

mov	eax, DWORD PTR _x$[ebp]

mov	ecx, eax

shl	eax, 3

lea	eax, DWORD PTR [eax+eax*8]

sub	eax, ecx


/Ox (CL)
  Ox

The /Ox option is a shorthand way to combine optimizing options to produce the fastest possible program. The effect is the same as using the following options on the same command line:

/Ogityb1

Note  The use of the /Ox option implies the use of the "omit frame pointer" option (/Oy). If your project contains code requiring EBP-based addressing, you can specify the /Oy− option after the /Ox option or use the optimize pragma with the "y" and off arguments to gain maximum optimization with EBP-based addressing. The compiler detects most situations where EBP-based addressing is required (for instance, with the _alloca and setjmp functions and with structured exception handling.)

Example

The following command tells the compiler to use maximum optimizations to compile FILE.C with the options listed in Table 2.23.

CL /Ox FILE.C

Table 2.23    Implementation of the /Ox Option

Option	Action
/Ob1	Expand functions marked as inline or __inline or those in a C++ member function defined within a class declaration
/Og	Enable global optimizations
/Oi	Generate intrinsic functions
/Ot	Specify fast sequences of machine code
/Oy	Omit frame pointer


/Oy, /Oy (CL)
  /Oy, /Oy

Use the /Oy option to suppress the creation of frame pointers on the call stack. This option speeds function calls, since no frame pointers need be set up and removed. It also frees one more register, EBP, for storing frequently used variables and subexpressions. The /Oy option is implied by the »/Ox« and »/O2« options.


/P (CL)
   /P

The /P option writes preprocessor output to a file with the same base name as the source file but with the .I extension. This option adds #line directives to the output file. They are placed at the beginning and end of each included file and around lines removed by preprocessor directives that specify conditional compilation.

The preprocessed listing file is identical to the original source file except that all preprocessor directives are carried out and macro expansions are performed.

The /P option suppresses compilation; CL does not produce an object file, even if you specify the /Fo option on the CL command line. The /P option also suppresses production of the alternate output files that the /FA, /Fa, or /Fm option generates.

The /P option is similar to both the»/E« and the »/EP« options. Using /EP with /P suppresses placement of #line directives in the output file.

Example

The following command creates the preprocessed file MAIN.I from the source file MAIN.C:

CL /P MAIN.C


/Tc, /Tp (CL)
   /Tc, /Tp

Options

/Tcfilename
/Tpfilename

The /Tc option specifies that filename is a C source file, even if it doesn't have the extension .C. The /Tp option specifies that filename is a C++ source file, even if it doesn't have the extension .CPP or .CXX. For both options, the space between the option and the filename argument is optional.

If this option does not appear, CL assumes that files with the .C extension are C source files, files with the .CPP or the .CXX extension are C++ source files.

If you need to specify more than one source file with an extension other than the default (.C, .CPP), you must specify each file with the appropriate command-line option (/Tc or /Tp).

Example

The following CL command line specifies that MAIN.C, TEST.PRG, and COLLATE.PRG are all C source files.

CL MAIN.C /Tc TEST.PRG /Tc COLLATE.PRG PRINT.PRG


/U, /u (CL)
  /U, /u

Options

/Uname
/u

Both the /u and the /U options turn off previously-defined symbols. The /U option turns off the previously-defined symbols specified by name. The /u option turns off every predefined symbol listed in Table 2.24. Both /U and /u apply to the predefined symbols listed in Table 2.24 and to those you define with the /D option. Neither /U nor /u apply to symbols created with the #define directive.

The predefined symbols are useful in writing portable programs. For instance, they can be used with preprocessor directives to conditionally compile parts of a program, depending on the processor and operating system being used.

One or more spaces can separate /U and name. You can specify more than one /U option on the same command line.

Table 2.24    Previously Defined Symbols

Symbol	Function
_CHAR_UNSIGNED	Default char type is unsigned. Defined when /J is specified. Microsoft specific.
_DLL	Defined when /MD is specified. Microsoft specific.
_M_IX86	Defined as 300 for the 80386 processor (/G3 option), as 400 for the 80486 processor (/G4 option), and as 500 for the Pentium processor (/G5 option). Microsoft specific.
_MSC_VER	Defines the compiler version in the form: "ddd". Defined as 800 for Microsoft Visual C++ for Windows NT. Always defined. Microsoft specific.
_WIN32	Defined for WIN32 applications. Always defined. Microsoft specific.
_MT	Defined when /MD or /MT is specified. Microsoft specific.
Example

The following example removes the definitions of a predefined symbol.

CL /U_M_IX86 WORK.C


/V (CL)
  /V

Syntax

/Vstring

The /V option embeds a text string in the object file. This string can label an object file with a version number or a copyright notice. If the specified string contains white-space characters, it must be enclosed in double quotation marks (" "). A backslash (\) must precede any embedded double quotation marks. A space between /V and string is optional.


/vdn (CL)
  /vdn

Options

/vd{0|1}

The /vdn options, where n is 0 or 1, apply only to C++ code that uses virtual bases. If a derived class overrides a virtual function that it inherits from a virtual base class, and a constructor or a destructor for the derived base class calls that function using a pointer to the virtual base class, the compiler may introduce additional hidden "vtordisp" fields into the classes with virtual bases. The /vd0 option suppresses the addition of the hidden vtordisp constructor/destructor displacement member. The /vd1 option, the default, enables them where they are necessary. Turn off vtordisps only if you are sure that all class constructors and destructors call virtual functions virtually.

The /vd option affects an entire compilation module. Use the vtordisp pragma to suppress and then reenable vtordisp fields on a class-by-class basis.


/vmx (CL)
  /vmx

Microsoft Visual C++ supports pointers to members of any class. If you always declare a pointer to a member of a class after defining the class, you do not need to use any of the /vmx options. If you need to declare a pointer to a member of a class before defining the class, you must use either the /vmx options (where x is one of b, g, m, s, or v) or the related pointers_to_members pragma.

Before designing your code so that it declares a pointer to a member of a class before defining the class, consider the impact that such a declaration has on the size and speed of the resulting executable file. The number of bytes required to represent a pointer to a member of a class and the code required to interpret the representation vary considerably and may depend on whether the class is defined with no, single, multiple, or virtual inheritance. In general, the more complex the inheritance used by a class, the greater the number of bytes required to represent a pointer to a member of the class and the larger the code required to interpret the pointer.

All five /vmx options and the pointers_to_members pragma affect the entire translation module for which they are used. For information on using the
__single_inheritance, __multiple_inheritance, and __virtual_inheritance keywords to control the code generated on a per-class basis, see Chapter 7 in C++ Language Reference.


/vmb (CL)
  /vmb

Use the /vmb option if you always define a class before you declare a pointer to a member of the class. This is the compiler default.

When the compiler encounters the declaration of a pointer to a member of a class, it already knows the kind of inheritance used by the class. Thus, the compiler can use the smallest possible representation of a pointer and generate the smallest amount of code required to operate on the pointer for each kind of inheritance.

The compiler generates an error if it encounters the pointer declaration before the class definition. In this case, you must either reorganize your code, use the /vmg option with the /vms, /vmm, or /vmv option, or use the pointers_to_members pragma. You can also define the class using the __single_inheritance, __multiple_inheritance, or __virtual_inheritance keywords, thus allowing control of the code generated on a per-class basis. For information on the use of these keywords, see Chapter 7 "Declarators" in C++ Language Reference.

The corresponding argument to the pointers_to_members pragma is best_case.


/vmg (CL)
  /vmg

Use the /vmg option if you need to declare a pointer to a member of a class before defining the class. You may need this option if you define members in two different classes that reference each other. For such mutually referencing classes, one class must be referenced before it is defined. The compiler uses the most general representation for the pointer to the member.

If you use the /vmg option, you must also use either the /vms (single inheritance), /vmm (multiple inheritance), or /vmv (virtual inheritance) option to indicate the inheritance model of the not-yet-encountered class definition.

The corresponding argument to the pointers_to_members pragma is full_generality.


/vms (CL)
  /vms

Use the /vms option with the /vmg option. The /vms option specifies the most general representation of a pointer to a member of a class to be one that uses either no inheritance or single inheritance. This is the smallest possible representation of a pointer to a member of a class. If the inheritance model of a class definition for which a pointer to a member is declared is multiple or virtual, the compiler generates an error.

The corresponding argument to the pointers_to_members pragma is single_inheritance.


/vmm (CL)
  /vmm

Use the /vmm option with the /vmg option. The /vmm option specifies the most general representation of a pointer to a member of a class to be one that uses multiple inheritance. This representation is larger than that required for single inheritance.

If the inheritance model of a class definition for which a pointer to a member is declared is virtual, the compiler generates an error.

The corresponding argument to the pointers_to_members pragma is multiple_inheritance.


/vmv (CL)
  /vmv

Use the /vmv option with the /vmg option. The /vmv option specifies the most general representation of a pointer to a member of a class to be one that uses virtual inheritance. This option will require a larger pointer and additional code to interpret the pointer than the other options. This option, however, never causes an error and is the default.

The corresponding argument to the pointers_to_members pragma is virtual_inheritance.


/W, /w (CL)
  /W, /w

Options

/W{0 | 1 | 2 | 3 | 4 | X}

/w

You can control the number of warning messages produced by the compiler by using the /w, /W0, /W1, /W2, /W3, /W4, or /WX option. A space between /W and 0, 1, 2, 3, 4, or X is optional. Compiler warning messages are any messages beginning with C4. Help has descriptions of these warnings and indicates each warning's level. Warnings indicate potential problems (rather than actual coding errors) with statements that may not compile as you intend. The /W options affect only source files named on the command line; they do not apply to object files.

Table 2.25 describes the warning-level options. W1 warnings are the most serious and W4 warnings are the least serious:

Table 2.25    Warning levels

Option	Description
/w	Turns off all warning messages. Use this option when you compile programs that deliberately include questionable statements.
/W0	The same as /w.
/W1	Displays severe warning messages. This is the default.
/W2	Displays an intermediate level of warning messages. Level 2 includes warnings such as the following:
	• Use of functions with no declared return type.
	• Failure to put return statements in functions with nonvoid return types.
	• Data conversions that would cause loss of data or precision.
/W3	Displays a less severe level of warning messages, including warnings about function calls that precede their function prototypes in the source code.
/W4	Displays the least severe level of warning messages, including warnings about the use of non-ANSI features and extended keywords.
/WX	Treats all warnings as errors. If there are any warning messages, an error message is emitted and compilation continues.
Example

The following command enables all possible warning messages when the source files CRUNCH.C and PRINT.C are compiled. Microsoft Visual C++ provides a pragma to control warning messages.

CL /W4 CRUNCH.C PRINT.C


/X (CL)
   /X

You can prevent the compiler from searching the standard places for include files by using the /X (for "exclude") option. When CL sees the /X option, it does not search any directories specified in the INCLUDE environment variable.

You can use this option with the /I option to define the location of include files that have the same names as include files found in other directories but that contain different definitions. See the »/I« option for an example of /X used with /I.


/YX or /Yc and /Yu (CL)
  /YX or /Yc and /Yu

The Microsoft C and C++ compilers provide options for precompiling any C or C++ code, including inline code. This feature allows you to compile a stable body of code, store the compiled state of the code (including debugging information) in a file, and, during subsequent compilations, combine the precompiled code with code that is still under development. The time for each subsequent compilation is reduced since the stable code is not recompiled.

You can precompile C or C++ code automatically or manually as described below:

•	Automatically precompiled headers. Use the /YX option and let the compiler decide when to create and use precompiled headers.

•	Manually precompiled headers. Use the /Yc and /Yu options when your source files use common sets of header files but do not include them in the same order, or when you want to include source code in your precompilation.

Using automatically precompiled headers is quick and easy. Using manually precompiled headers requires you to invest a small amount of project-management time, but offers faster compilations and allows you to precompile code other than simple header files.

You can use the »/YX«, »/Yc« and »/Yu« options, to create and use precompiled headers. These options can be used with the hdrstop pragma. For more information on the hdrstop pragma, see Preprocessor Reference. You can use the »/Fp« option to specify a precompiled header filename.


/YX (CL)
  /YX

The /YX option instructs the compiler to use a precompiled header file with a default name of MSVC.PCH if one exists or to create one if none exists. The file is created in the current directory. You can use the /Fp option to change the default name (and placement) of the precompiled header.

Example

The following command line uses /YX to create or use a precompiled header named MSVC.PCH:

CL /YX MYPROG.CPP

The following command line creates a precompiled header named MYPROG.PCH and places it in the \PROJPCH directory:

CL /YX /Fp\PROJPCH\MYPROG.PCH MYPROG.CPP

/YX Precompiles Header Files

Using the /YX option limits precompilation to header files only. The precompiled header is created when the compiler encounters the first declaration, definition, hrdstop pragma, or #line directive that occurs in the source file. In a subsequent compilation, the precompiled header is used at the point in a source file where the compiler makes its final consistency check.

The actual set of header files precompiled with /YX is determined by the compiler, which may elect to use a subset of header files available to try and improve the number of cases where the resulting precompiled header can be used.

Although it is usually best to let the compiler determine which header files to use, you can selectively precompile header files by placing a hdrstop pragma in the source file between two #include directives. All header files before the hdrstop pragma are precompiled; those after are not. When used with /YX, any filename specified with the hdrstop pragma is ignored. If any subsequent compilation using the precompiled header does not contain an identical hdrstop pragma at the same point in the source file, the compiler builds a new precompiled header. For more information on the hdrstop pragma see  Preprocessor Reference.

Use of the /YX option implies use of the /Yd option (duplicate debugging information in all object files).

Consistency Rules for the /YX Option

If a precompiled header file exists (either MSVC.PCH or one specified by /Fp), it is compared to the current compilation for consistency. The following requirements must be met; otherwise, a new precompiled header file is created, and the new file overwrites the old:

•	The current compiler options must match those specified when the precompiled header was created.

•	The current working directory must match that specified when the precompiled header was created.

•	The order and values of all #include and #pragma preprocessor directives must match those specified when the precompiled header was created. These, along with #define directives, are checked as they appear during subsequent compilations that use the precompiled header. The #pragma directives must be nearly identical—multiple spaces outside of strings are treated as a single space to allow for different programming styles.

•	The values of #define directives must match. However, a group of #define directives in sequence need not occur in exactly the same order since there are no semantic order dependencies for #define directives.

•	The value and order of include paths specified on the command line with /I options must match those specified when the precompiled header was created.

•	The timestamps of all the header files (all files specified with #include directives) used to build the precompiled header must match those that existed when the precompiled header was created.


/Yc (CL)
  /Yc

Syntax

/Yc[filename]

The /Yc option instructs the compiler to create a precompiled header (.PCH) file that represents the state of compilation at a certain point. No space is allowed between /Yc and filename.

Using /Yc with a Filename

If you specify a filename with the /Yc option, the compiler compiles all code up to and including the specified file for subsequent use with the /Yu option (use precompiled header). The precompiled code is saved in a file with a name created from the base name of the file specified with the /Yc option and a .PCH extension. You can also use the /Fp option, described earlier in this chapter, to specify a name for the resulting precompiled header file.

Example

Consider the following code:

#include <afxwin.h>   // Include header for class library
#include "resource.h" // Include resource definitions
#include "myapp.h"    // Include information specific to this app
...

When this code is compiled with the command

CL /YcMYAPP.H PROG.CPP

the compiler saves all the preprocessing for AFXWIN.H, RESOURCE.H, and MYAPP.H in a precompiled header file called MYAPP.PCH.

Using /Yc Without a Filename

If you specify the /Yc option without a filename, the resulting precompiled header saves the compilation state at the end of the base source file, or, if the base file contains a hdrstop pragma, at the place where the hdrstop pragma occurs.

The resulting .PCH file has the same base name as your base source file unless you specify a different filename using the hdrstop pragma.

Note  If the options /Ycfilename and /Yufilename occur on the same command line and both reference, or imply, the same filename, /Ycfilename takes precedence. This feature simplifies the writing of makefiles.


/Yu (CL)
  /Yu

Syntax

/Yu[filename]

The /Yu option instructs the compiler to use an existing precompiled header in the current compilation. No space is allowed between the option and the filename.

Using /Yu with a Filename

The filename argument is the name of a header file, which is included in the source file using an #include preprocessor directive. The include file's name must be the same for both the /Yc option that creates the precompiled header and any subsequent /Yu option indicating use of the precompiled header.

For /Yc, filename specifies the point at which precompilation stops; the compiler precompiles all code through filename and names the resulting precompiled header using the base name of the include file and an extension of .PCH. For /Yu, the compiler assumes that all code occurring before filename is precompiled. The compiler skips to the specified #include directive, uses the code contained in the precompiled header file, and then compiles all code after filename.

Examples

If the following code:

#include <afxwin.h>   // Include header for class library
#include "resource.h" // Include resource definitions
#include "myapp.h"    // Include information specific to this app
...

is compiled with the command line:

CL /YuMYAPP.H PROG.CPP

the compiler does not process the three include statements but uses precompiled code from MYAPP.PCH, thereby saving the time involved in preprocessing all three of the files (and any files they might include).

You can use the /Fp option with the /Yu option to specify the name of the .PCH file if the name is different from either the filename argument to /Yc or the base name of the source file, as in the following:

CL /YuMYAPP.H /FpMYPCH.PCH PROG.CPP

This command specifies a precompiled header file named MYPCH.PCH. The compiler uses its contents to restore the precompiled state of all header files up to and including MYAPP.H. The compiler then compiles the code that occurs after the MYAPP.H include statement.

Using /Yu Without a Filename

When you specify the /Yu option without a filename, your source program must contain a hdrstop pragma that specifies the filename. The compiler skips to the location of that pragma, restores the compiled state from the precompiled header file specified by the pragma, and then compiles only code that follows the pragma. If the hdrstop pragma does not specify a filename, the compiler looks for a file with a name derived from the base name of the source file with a .PCH extension.

If you specify the /Yu option without a filename and fail to specify a hdrstop pragma, an error message is generated and the compilation is unsuccessful.

Note  If the options /Ycfilename and /Yufilename occur on the same command line and both reference, or imply, the same filename, /Ycfilename takes precedence. This feature simplifies the writing of makefiles.


/Yd (CL)
  /Yd

Use the /Yd option with the /Z7 option (generate Microsoft C/C++ version 7.0 debugging information) to place complete debugging information in object files that are created from a precompiled header (.PCH) file. The /Yd option takes no argument.

Note  The /Yd option is obsolete with the new action of the /Zi option, which creates program database (.PDB) files. The /Yd option is compatible with Microsoft C/C++ version 7.0 and simplifies the distribution of libraries that contain debugging information. For more information, see »/Zi /Z7 and /Zd«.

Storing complete debugging information in every object file, including that which describes the .PCH file, is sometimes convenient, but slows compilation and requires considerable disk space. In contrast, when /Yc and /Z7 are used without /Yd, the compiler stores debugging information describing the .PCH file in the first object file created from the .PCH file. The compiler does not insert this common debugging information into object files subsequently created from the .PCH file; rather, it inserts cross-references to the debugging information. Therefore, no matter how many object files use the .PCH file, only one object file contains the common debugging information.

Although this default behavior results in faster build times and reduces disk-space demands, it is undesirable if a small change requires rebuilding the object file containing the common debugging information. In this case, the compiler must rebuild all object files containing cross-references to the original object file. Also, if a common .PCH file is used by different projects, reliance on cross-references to a single object file is difficult.

Note  The /Yd option is implied with use of the /YX option (automate precompiled header).


/Ze, /Za (CL)
  /Ze, /Za

The Microsoft C compiler supports the ANSI C standard. In addition, it offers a number of features beyond those specified in the ANSI C standard. These features are available when the /Ze option is specified and are not available when the /Za option is specified (/Ze is the default). Descriptions of the Microsoft extensions follow.


Keywords (CL)
  Keywords

The following keywords are Microsoft specific:

The __based, __cdecl, __except, __fastcall, __finally, __leave, __stdcall, __try, and __declspec(extended-declaration-modifier-list) keywords.


Casts (CL)
  Casts

The Microsoft compiler supports the following two non-ANSI casts. ANSI compliant methods of coding these casts are given:

1.	Use of non-ANSI casts to produce l-values (numlist):

char *p;
(( int * ) p )++;

The preceding example could be rewritten to conform with the ANSI C standard as follows:

p = ( char * )(( int * )p + 1 );

2.	Non-ANSI Casting of a function pointer to a data pointer:

int ( * pfunc ) ();
int *pdata;

pdata = ( int * ) pfunc;

To perform the same cast while maintaining ANSI compatibility, you must cast the function pointer to an int before casting it to a data pointer:

pdata = ( int * ) (int) pfunc;


Variable Length Argument Lists (CL)
  Variable-Length Argument Lists

The following conventions are Microsoft specific:

•	Use of trailing commas (,) rather than an ellipsis (...) in function declarations to indicate variable-length argument lists:

int printf( char *, );

•	Previous function declarator specifies a variable number of arguments, but the function definition provides a type instead:

void myfunc( int x, ... );

void myfunc( int x, char * c )
{ }


Single Line Comments (CL)
  Single-Line Comments

The Microsoft C Compiler supports single-line comments, which are introduced with two (//) slash characters:

// This is a single-line comment.


Scope (CL)
  Scope

The Microsoft C compiler supports the following scope related features:

•	Redefinitions of extern items as static:

extern int foo();
static int foo()
{}

•	Use of benign typedef redefinitions within the same scope:

typedef int INT;
typedef int INT;

•	Function declarators have file scope:

void func1()
{
    extern int func2( double );
}

void main( void )
{
    func2( 4 );    //  /Ze passes 4 as type double
}                  //  /Za passes 4 as type int

•	Use of block scope variables initialized with nonconstant expressions:

int foo( int );
int bar( int );

void main( void )
{
    int array[2] = { foo( 2 ), bar( 4 ) };
}

int foo( int x )
{
    return x;
}

int bar( int x )
{
    return x;
}


Data Declarations and Definitions (CL)
  Data Declarations and Definitions

The following data declaration and definition features are supported by the Microsoft C compiler:

•	Use of mixed character and string constants in an initializer:

char arr[5] = {'a', 'b', "cde"};

•	Use of bit fields with base types other than unsigned int or signed int.

•	Use of declarators without either a storage class or a type:

x;

void main( void )
{
    x = 1;
}

•	Use of zero-sized arrays as last field in structures and union:

struct zero
{
    char *c;
    int zarray[];
};


Intrinsic Floating-Point Functions (CL)
  Intrinsic Floating-Point Functions

The Microsoft compiler supports the inline generation of the atan, atan2, cos, exp, log, log10, sin, sqrt, and tan functions when the /Oi option is specified. ANSI conformance is lost when these intrinsics are used as they do not set the errno variable.

Use the /Za option if you plan to port your program to other environments. The /Za option tells the compiler to treat extended keywords as simple identifiers and to disable the other extensions listed above.

When you specify /Za, the compiler automatically defines the __STDC__ identifier. In the include files provided with the C run-time libraries, this identifier is used with #ifndef to control use of the __cdecl keyword on library function prototypes. For an example of this conditional compilation, see the file STDIO.H.

Note  If you use the /Za (compile for ANSI compatibility) option, CL uses the /Op option to improve the consistency of floating-point tests for equality and inequality. This use of /Op with /Za is for strict ANSI conformance and is the only situation under which /Op is selected by default. The /Op −  option is provided to override the default selection of /Op with /Za. Placing the /Op −  option on the command line with the /Za option will disable /Op.


/Zg (CL)
  /Zg

The /Zg option generates a function prototype for each function defined in the source file but does not compile the source file.

The function prototype includes the function return type and an argument-type list. The argument-type list is created from the types of the formal parameters of the function. Any function prototypes already present in the source file are ignored.

The generated list of prototypes is written to the standard output. You may find this list helpful to verify that actual arguments and formal parameters of a function are compatible. You can save the list by redirecting standard output to a file. Then you can use #include to make the list of function prototypes a part of your source file. Doing so causes the compiler to perform argument type checking.

If you use the /Zg option and your program contains formal parameters that have structure, enumeration, or union type (or pointers to such types), the prototype for each structure, enumeration, or union type must have a tag.


/Zi, /Z7, and /Zd (CL)
  /Zi, /Z7, and /Zd

CL offers three options, /Zi, /Z7, and /Zd, that cause the compiler to generate debugging information.

You can use the /Zi or the /Z7 option to generate complete debugging information. This provides the CodeView debugger and the Visual Workbench debugger with a detailed view of your source code. Complete debugging information includes information on each module: its associated name, line numbers, types, variables, and function names with their return types. It also includes full symbol-table information.

It is recommended that you use /Zi unless you need /Z7 to simplify shipping libraries that contain debugging information. The /Zi option places the generated debugging information in a program database (PDB); a PDB speeds linking during the debugging process.

The following table summarizes results obtained from using the /Zi, /Z7, and /Yd options in combination with /Yc or /Yu.

Option	Result
/Zi	Debugging information for both the precompiled header and the rest of the source code is placed in a .PDB file.
/Zi /Yd	/Yd is ignored. Debugging information for both the precompiled header and the rest of the source code is placed in a .PDB file.
/Z7	Debugging information for both the precompiled header and the rest of the source code is placed in the first object file created using the precompiled header.
/Z7 /Yd	Debugging information for both the precompiled header and the rest of the source code is placed in every object file created using the precompiled header.


/Zi (CL)
  /Zi

The /Zi option causes the compiler to generate complete debugging information, placing some of it in the .PDB file and the rest in the object file. If you do not use the "compile without linking" option (/c), CL passes the /DEBUGoption to the linker, causing the linker to place all debugging information in the executable file for use with both the CodeView and Visual Workbench debuggers. See »Chapter 4« for more information on the /DEBUG linker option.

Program Database

The /Zi option starts a program database (PDB) file of debugging information generated by the compiler and used by LINK and CodeView. The .PDB file is named MSVC.PDB by default. You can use the /Fd option to provide an alternate name.

Compared to the method of storing debugging information used by the /Z7 option, use of a PDB provides two benefits:

•	It decreases the size of all object files compiled with /Zi by factoring common debugging information into the PDB.

•	It speeds the linking step by reducing the amount of redundant type information the linker must deal with.

The linker combines the code, data, and debugging information found in object files with the debugging information in the .PDB file to create an executable file that can be debugged using either CodeView or the Visual Workbench debugger.

Object files that are created using the /Zi option contain the name of the associated .PDB file. The named PDB must be available at link time to create an executable file.

PDBs and Libraries Containing Debugging Information

If you want to distribute a library that contains debugging information, you must distribute the .PDB file along with the library and its source code. Without the associated PDB, the library cannot be used in subsequent linking processes. If you don't need the faster link times that PDBs provide, see Table 2.26 for other ways to include debugging information in libraries that you want to distribute.

Table 2.26    Including Debugging Information

Procedure	Desired location of debugging information
Compile with /Z7 and /Yc	In the first object file created when using the /Yc and /Yu options
Compile with /Z7 and /Yd	In all object files created when using the /Yc and /Yu options
Compile with /YX	In an object file when using the /YX option
Compile with /Z7	In an object file when not using precompiled headers
The first technique in the above list — compile with /Z7 and /Yc — eliminates most duplicate type information and, thus, creates a significantly smaller library. To use this technique, however, you must provide a public symbol in the object that contains the type information for the .PCH file. You must then reference that public symbol using an extern in order to link the PCH type information.

The /YX option implies the /Yd option. The /Yd option places the debugging information generated by /Z7 into every object file created from the associated precompiled header file. The options /Yc and /Yu (create or use precompiled header), /YX (automate precompiled header), and /Yd (duplicate debugging information in all object files) are all discussed earlier in this chapter.

Speed the Build Process

A .PCH file created using the precompiled header options (/YX or /Yc and /Yu) speeds compilation. A .PDB file created using /Zi speeds linking during the debugging process. Use the precompiled header options with /Zi to speed up debug builds.

Example

The following command produces a .PDB file named MSVC.PDB and an executable file named TEST.EXE containing full debugging information for use with the CodeView and Visual Workbench debuggers.

CL /Zi TEST.C


/Z7 (CL)
  /Z7

The /Z7 option causes the compiler to generate complete debugging information and to place all of it in the object file. If you do not use the "compile without linking" option (/c), CL causes the linker to place all debugging information in the executable file for use with both the CodeView and Visual Workbench debuggers.


/Zd (CL)
  /Zd

The /Zd option produces an object file with only line-number and public-symbol information.


/Zl (CL)
  /Zl

Ordinarily, CL puts the name of the library in the object file so the linker can use the correct library to link with the object file. For more information on the default library, see the »/MD«, »/ML«, and »/MT« options.

The /Zl option tells the compiler not to place the default-library name in the object file. As a result, the object file is slightly smaller. Use the /Zl option when you are using the LIB utility to build a library. (The LIB utility is described in "Using the 32-Bit LIB.") You can use /Zl to compile the object files you plan to put in your library, thereby omitting the default-library names from your object modules. Although the /Zl option saves only a small amount of space for a single object file, the total amount of space saved is significant in a library containing many object modules.


/Zn (CL)
  /Zn

Use the /Zn option with either the /FR or /Fr option to turn off packing of browser files. The /FR or /Fr option creates an .SBR file, which CL packs by default. Both options are described earlier in this chapter.

The Microsoft Browser Database Maintenance Utility (BSCMAKE) uses the .SBR file to generate a .BSC file that you can examine with the Microsoft Source Browser. Packing allows BSCMAKE to run faster and also saves disk space. However, BSCMAKE's /Iu option requires an unpacked .SBR file in order to include unreferenced symbols. Use /Zn only if you need to include unreferenced symbols or if compilation time is critical.

Example

The following example compiles and links the source file QSORT.C and generates a file called QSORT.SBR. The /Zn option ensures that CL does not pack the file.

CL /FR /Zn QSORT.C


/Zp (CL)
  /Zp

Syntax

/Zp[{1|2|4|8|16}]

The /Zp option allows you to control the alignment of structure members and global variables. Ordinarily, when /Zp is not specified, the allocation of storage for structure members and global variables is aligned on the smaller of two sizes: the size of the type or 8 bytes (/Zp8).

Note  Although applications written for Windows 3.x require one-byte structure-member alignment, applications written using the Win32 API do not. The default value of 8 bytes, when /Zp is not specified, provides maximum portability when using the Win32 API to develop applications for Windows NT.

To conserve space or to conform to existing data structures, you may want to store structures more or less compactly. The /Zp option and the pack pragma control how structure data are packed into memory.

Use the /Zp option to specify the same packing for all structures in a module. When you give the /Zpn option, where n is 1, 2, 4, 8, or 16, each structure member after the first is stored on the smaller of the size of the member type or n-byte boundaries. If you use the /Zp option without an argument, structure members are packed on 1-byte boundaries. No space is allowed between /Zp and its argument.

Use the pack pragma in your source code to pack particular structures on boundaries different from the packing specified on the command line. Give the pack(n) pragma, where n is 1, 2, 4, 8, or 16, before structures that you want to pack differently. To reinstate the packing given on the command line, give the pack() pragma with no arguments. See Preprocessor Reference for more information on the pack pragma.

Example

The following command causes all structures in the program PROG.C to be stored one-byte boundaries.

CL /Zp PROG.C


/Zs (CL)
  /Zs

The /Zs option tells the compiler to check only the syntax of the source files on the command line. This option provides a quick way to find and correct syntax errors before you try to compile and link a source file.

When you give the /Zs option, the compiler does not generate code or produce object files, object listings, or executable files. The compiler, however, does display error messages if the source file has syntax errors.

Example

The following command instructs the compiler to perform a syntax check on all source files in the current working directory that begin with TEST and end with the .C extension. The compiler displays messages for any errors found.

CL /Zs TEST*.C


  Chapter 3  Using the 32-Bit LIB

This chapter describes the Microsoft 32-Bit Library Manager (LIB.EXE) version 1.00. LIB is a 32-bit tool that creates and manages a library of COFF object files. LIB can also be used to create exports files and import libraries to reference exported definitions.

LIB creates standard libraries, import libraries, and exports files that you can use with LINK when building a 32-bit program. (LINK is described in »Chapter 4«, "Using the 32-Bit LINK.") LIB runs from a command prompt. Visual Workbench does not provide controls for LIB.

You can use LIB in the following modes:

•	»Building or modifying a COFF library«

•	»Extracting a member object to a file«

•	»Creating an exports file and an import library«

These modes are mutually exclusive, you can use LIB in one mode at a time.


  LIB Input Files

The input files expected by LIB depend on the mode in which it is used, as follows:

Mode	Input
Default (building or modifying a library)	COFF object (.OBJ) files, COFF libraries (.LIB), 32-bit OMF object (.OBJ) files
Extracting a member with /EXTRACT	COFF library (.LIB)
Building an exports file and import library with /DEF	Module-definition (.DEF) file, COFF object (.OBJ) files, COFF libraries (.LIB), 32-bit OMF object (.OBJ) files
Note  OMF libraries created by the 16-bit version of LIB cannot be used as input to the 32-bit LIB.


  LIB Output Files

The output files produced by LIB depend on the mode it is used in as shown in the following table:

Mode	Output
Default (building or modifying a library)	COFF library (.LIB)
Extracting a member with /EXTRACT	Object (.OBJ) file
Building an exports file and import library with /DEF	Import library (.LIB) and exports (.EXP) file


  Other LIB Output

In the default mode, you can use the /LIST option to display information about the resulting library. You can redirect this output to a file.

LIB displays a copyright and version message and echoes command files unless the /NOLOGO option is used.

When you type lib with no other input, LIB displays a usage statement that summarizes its options.

Error and warning messages issued by LIB have the form LNKnnnn. This error prefix and range of numbers is also used by LINK and DUMPBIN. Documentation on these errors is available in Help.


Structure of a Library (LIB)
  Structure of a Library

A library contains COFF objects. Objects in a library contain functions and data that can be referenced externally by other objects in a program. An object in a library is sometimes referred to as a library member.

You can get additional information about the contents of a library by running the DUMPBIN tool with the /LINKERMEMBER option. For more information, see »Using DUMPBIN« in Chapter 6.


  Running LIB

This section presents information on running LIB in any mode. It describes the LIB command line, discusses the use of command files, and gives general rules for using options.


  LIB Command Line

To run LIB, type the command lib followed by the options and filenames for the task you are using LIB to perform. LIB also accepts command-line input in command files, which are described in the following section. LIB does not use an environment variable.

Note  If you are accustomed to the LINK32.EXE and LIB32.EXE tools provided with the Microsoft Win32 Software Development Kit for Windows NT, you may have been using either the command link32 -lib or the command lib32 for managing libraries and creating import libraries. Be sure to change your makefiles and batch files to use the d command instead.


  LIB Command Files

Command-line arguments can be passed to LIB in a command file. A command file is a text file that contains options and filenames specified in the same form as you specify them on the command line.

To specify a command file to LIB, use the following syntax:

LIB @commandfile

The commandfile is the name of the text file. No space or tab is allowed between the at sign (@) and the filename. There is no default extension; you must specify the full filename including any extension. Wildcard characters cannot be used. You can specify an absolute or relative path with the filename.

In the command file, arguments can be separated by spaces or tabs as they can on the command line, and they can also be separated by newline characters. Use a semicolon (;) to mark a comment in a command file. LIB ignores all text from the semicolon to the end of the line.

You can specify either all or part of the command line in a command file, and you can use more than one command file in a LIB command. LIB accepts the command-file input as if it were specified in that location on the command line. Command files cannot be nested. LIB echoes the contents of command files unless the /NOLOGO option is used.


  Using LIB Options

An option consists of an option specifier, which is either a dash (-) or a forward slash (/), followed by the name of the option. Option names cannot be abbreviated. Some options take an argument, specified after a colon (:). No spaces or tabs are allowed within an option specification. Option names and their keyword or filename arguments are not case sensitive, but identifiers used as arguments are case sensitive. LIB processes options in the order specified on the command line and in command files. If an option is repeated with different arguments, the last one to be processed takes precedence.

The /NOLOGO option can be used with any LIB mode. Use /NOLOGO to suppress display of the LIB copyright message and version number. This option also prevents echoing of command files.

Other options apply only to specific modes of LIB. These options are discussed in the sections describing each mode.


Managing a Library (LIB)
  Managing a Library

The default mode for LIB is to build or modify a library of COFF objects. LIB runs in this mode when you do not specify /EXTRACT (to copy an object to a file) or /DEF (to build an import library).

To build a library from objects and/or libraries, use the following syntax:

LIB [options...] files...

This command creates a library from one or more input files. The files can be COFF object files, 32-bit OMF object files, and existing COFF libraries. LIB creates one library that contains all objects in the specified files. If an input file is a 32-bit OMF object file, LIB converts it to COFF before building the library. LIB cannot accept a 32-bit OMF object that is in a library created by the 16-bit version of LIB. You must first use the 16-bit LIB to extract the object, then you can use the extracted object file as input to the 32-bit LIB. The 16-bit version of LIB is not provided with the Visual C++ development system for Windows NT.

By default, LIB names the output file using the base name of the first object or library file and the extension .LIB. If a file already exists with the same name, the output file overwrites the existing file. To preserve an existing library, use the /OUT option to specify a name for the output file.

The following options apply to building and modifying a library:

/LIST

Displays information about the output library to standard output. The output can be redirected to a file. You can use /LIST to determine the contents of an existing library without modifying it.

/OUT:filename

Overrides the default output filename. By default, the output library has the base name of the first library or object on the command line and the extension .LIB.

/REMOVE:object

Omits the specified object from the output library. LIB creates an output library by first combining all objects (whether in object files or libraries), then deleting any objects specified with /REMOVE.

/SUBSYSTEM

Tells the operating system how to run a program created by linking to the output library. For more information see »/SUBSYSTEM« in Chapter 4, "Using the 32-Bit LINK."

You can use LIB to perform the following tasks:

•	To add objects to a library, specify the filename for the existing library and the filenames for the new objects.

•	To combine libraries, specify the library filenames. You can add objects and combine libraries in a single LIB command.

•	To replace a library member with a new object, specify the library containing the member object to be replaced and the filename for the new object (or the library that contains it). When an object that has the same name exists in more than one input file, LIB puts the last object specified in the LIB command into the output library. When you replace a library member, be sure to specify the new object or library after the library that contains the old object.

•	To delete a member from a library, use the /REMOVE option. LIB processes any specifications of /REMOVE after combining all input objects, regardless of command-line order.

Note  You cannot both delete a member and extract it to a file in the same step. You must first extract the member object using /EXTRACT, then run LIB again using /REMOVE. This behavior differs from that of the 16-bit LIB (for OMF libraries) provided in other Microsoft products.


Extracting a Member (LIB)
  Extracting a Member

You can use LIB to create an object (.OBJ) file that contains a copy of a member of an existing library. To extract a copy of a member, use the following syntax:

LIB library /EXTRACT:member /OUT:objectfile

This command creates an .OBJ file called objectfile that contains a copy of a member of a library. The member name is case sensitive. You can extract only one member in a single command. The /OUT option is required; there is no default output name. If a file called objectfile already exists in the specified directory (or current directory, if no directory is specified with objectfile), the extracted objectfile overwrites the existing file.


  Import Libraries and Exports Files

You can use LIB with the /DEF option to create an import library and an exports file. LINK uses the exports file to build a program that contains exports (usually a DLL), and it uses the import library to resolve references to those exports in other programs.

In most situations, you do not need to use LIB to create your import library. When you link a program (either an executable file or a DLL) that contains exports, LINK automatically creates an import library that describes the exports. Later, when you link a program that references those exports, you specify the import library.

When a DLL exports to a program that it also imports from, whether directly or indirectly, you must use LIB to create one of the import libraries. When LIB creates an import library, it also creates an exports file. You must use the exports file when linking one of the DLLs.


  Building an Import Library and Exports Files

To build an import library and exports file, use the following syntax:

LIB /DEF[:deffile] [/EXPORT:name...] [/OUT:import] [objfiles] [libraries]

LIB creates the output files from export specifications that are passed in the LIB command. There are three methods for specifying exports, listed in recommended order of use:

•	A __declspec(dllexport) definition in one of the objfiles or libraries

•	A specification of /EXPORT:definition on the LIB command line

•	A definition in an EXPORTS statement in a deffile

These are the same methods you use to specify exports when linking an exporting program. A program can use more than one method. You can specify parts of the LIB command (such as multiple objfiles or /EXPORTS specifications) in a command file in the LIB command, just as you can in a LINK command.

For details about /EXPORT, see »Chapter 4«, "Using the 32-Bit LINK".

You can use the /OUT option to specify a name for the import library being created. When /OUT is not specified, the default name is the base name of the first object file or library in the LIB command and the extension .LIB. The exports file is given the same base name as the import library and the extension .EXP.


  Using an Import Library and Exports File

When a program (either an executable file or a DLL) exports to another program that it also imports from, or if more than two programs both export to and import from each other, the commands to link these programs must accommodate the circular exports.

In a situation without circular exports, when you link a program that uses exports from another program, you must specify the import library for the exporting program. The import library for the exporting program is created when you link that exporting program. This requires that you link the exporting program before the importing program. For example, if TWO.DLL imports from ONE.DLL, you must first link ONE.DLL and get the import library ONE.LIB. You then specify ONE.LIB when you link TWO.DLL. When the linker creates TWO.DLL, it also creates its import library, TWO.LIB. You use TWO.LIB when linking programs that import from TWO.DLL.

However, in a circular export situation, it is not possible to link all of the interdependent programs using import libraries from the other programs. In the example discussed earlier, if TWO.DLL also exports to ONE.DLL, the import library for TWO.DLL won't exist yet when ONE.DLL is linked. When circular exports exist, you must use LIB to create an import library and exports file for one of the programs.

To begin, choose one of the programs on which to run LIB. In the LIB command, list all objects and libraries for the program and specify /DEF. If the program uses a .DEF file or /EXPORTS specifications, specify these as well.

After you create the import library (.LIB) and the export file (.EXP) for the program, you then use the import library when linking the other program or programs. LINK creates an import library for each exporting program it builds. For example, if you ran LIB on the objects and exports for ONE.DLL, you created ONE.LIB and ONE.EXP. You can now use ONE.LIB when linking TWO.DLL; this step also creates the import library TWO.LIB.

Finally, link the program you began with. In the LINK command, specify the objects and libraries for the program, the .EXP file that LIB created for the program, and the import library or libraries for the exports used by the program. In the continuing example, the LINK command for ONE.DLL contains ONE.EXP and TWO.DLL, as well as the objects and libraries that go into ONE.DLL. Do not specify the .DEF file and /EXPORTS specifications in the LINK command; these are not needed, because the exports definitions are contained in the .EXP file. When you link using an .EXP file, LINK does not create an import library, because it assumes that one was created when the .EXP file was created.


  Chapter 4  Using the 32-Bit LINK

This chapter describes the Microsoft 32-Bit Executable Linker (LINK.EXE). You can use LINK to link Common Object File Format (COFF) object files and libraries and create a 32-bit executable file or dynamic-link library (DLL). The program created by LINK is sometimes called an image file.


  LINK Input Files

You provide the linker with files that contain objects, import and standard libraries, resources, module definitions, and command input. LINK does not use file extensions to make assumptions about the contents of a file. Instead, LINK examines each input file to determine what kind of file it is.


  .OBJ files

LINK accepts object files that are either COFF (Common Object File Format) or 32-bit OMF (Object Module Format). The CL compiler provided with Visual C++ for Windows NT creates COFF object files. LINK automatically converts 32-bit OMF objects to COFF.


  .LIB files

LINK accepts standard COFF libraries and COFF import libraries, both of which usually have the extension .LIB. Standard libraries contain objects and are created by the LIB tool. Import libraries contain information about exports in other programs and are created either by LINK when it builds a program that contains exports or by the LIB tool. For information on using LIB to create standard or import libraries, see »Chapter 3«, "Using the 32-Bit LIB." For details on using LINK to create an import library, see »/DLL«.

A library is specified to LINK as either a filename argument or a default library. LINK resolves external references by searching first in libraries specified on the command line, then in default libraries specified with the /DEFAULTLIB option, then in default libraries named in object files. If a path is specified with the library name, LINK looks for the library in that directory. If no path is specified, LINK looks first in the directory that LINK is running from, then in any directories specified with the LIB environment variable.

LINK cannot link a library of 32-bit OMF objects created by the 16-bit version of LIB. To use an OMF library, you must first use the 16-bit LIB (not provided in Visual C++ for Windows NT) to extract the objects. You can then either link the OMF objects or use the 32-bit LIB to convert them to COFF and put them in a library.


  .EXP files

Export (.EXP) files contain information about exported functions and data items. When LIB creates an import library, it also creates an export (.EXP) file. You use the .EXP file when you link a program that both exports to and imports from another program, either directly or indirectly. If you link with an .EXP file, LINK does not produce an import library because it assumes that one was already created by LIB. For details about .EXP files and import libraries, see »Import Libraries and Exports Files« in Chapter 3, "Using the 32-Bit LIB."


  .DEF files

Module-definition (.DEF) files provide the linker with information about exports, attributes, and other information about the image to be linked. Use the /DEF option to specify the .DEF filename. Because LINK provides options and other features that can be used instead of module-definition statements, .DEF files are generally not necessary.


  .PDB files

Object files that were compiled using the /Zi option contain the name of a program database (PDB). You do not specify the PDB filename to the linker, but LINK looks for the PDB if it is needed. For more information on how LINK uses PDBs, see »/DEBUG«.


  .RES files

You can specify a resource (.RES) file when linking a program. The .RES file is created by RC. For information about RC, see »Using the Resource Compiler« in Chapter 6, "Using Other Tools". LINK automatically converts .RES files to COFF.


  .EXE files

The /STUB option specifies the name of an executable file that runs under MS-DOS. LINK examines the specified file to be sure that it is a valid MS-DOS program.


  .TXT files

LINK expects various text files as additional input. The command-file specifier (@) and the options /BASE, /DEF, and /ORDER all specify text files. These files can have any extension, not just .TXT.


  LINK Output

Link output includes executable files, DLLs, mapfiles, and messages.


  Output Files

The default output file from LINK is an executable (.EXE) file. If the /DLL option is specified, LINK builds a DLL. You can control the output filename by using the /OUT option. You can put debugging information in the output file by using the /DEBUG option. When LINK creates a program (usually a DLL) that contains exports, it also builds an import library (.LIB file), unless an .EXP file was used in the build. You can control the import library filename by using the /IMPLIB option. If the /MAP option is specified, LINK creates a mapfile.


  Other Output

LINK displays a copyright and version message and echoes command-file input, unless the /NOLOGO option is used. You can use the /VERBOSE option to display additional details about the build. The information is displayed to standard output and can be redirected to a file. When you type link without any other command-line input, LINK displays a usage statement that summarizes its options. Error and warning messages issued by the 32-bit LINK have the form LNKnnnn. This error prefix and range of numbers is also used by the 32-bit LIB and DUMPBIN. Documentation on these errors is available in Help. You can control the display of warnings by using the /WARN option.


  A Comparison of LINK to Other Linkers

This section describes the differences between the version of LINK provided with the Visual C++ development system for Windows NT, the 16-bit LINK.EXE provided with other Microsoft language products, and the LINK32.EXE provided with the Microsoft Win32 Software Development Kit (SDK) for Windows NT. Make sure you change the commands in your makefiles or batch files so that the 32-bit linker is invoked correctly.


  Differences Between 32-Bit LINK and 16-Bit LINK

The following table summarizes the differences between the 32-bit linker and the 16-bit linker. Both linkers are named LINK.EXE.

Table 4.1    Differences Between 16-Bit and 32-Bit LINK

Feature	16-Bit LINK	32-Bit LINK
Targets	Real-mode MS-DOS .EXE or .COM, overlaid MS-DOS .EXE, 16-bit .EXE or .DLL for Windows	.EXE or .DLL for Win32
Arguments	In fields; separated by commas	No fields; separated by whitespace
Command files	At most one response file	Can have multiple command files
Prompts	Prompts for empty fields	No prompts
Object files input	16-bit OMF object files	COFF object files, COFF libraries, 32-bit OMF object files
Libraries input	OMF libraries created by 16-bit LIB	COFF libraries created by 32-bit LIB
Load libraries	Links all modules of a library specified in the objects field	The /INCLUDE:symbol option forces linking with object that contains symbol
.DEF file input	Command-line field	/DEF option
.DEF file content	Required for specifying attributes, ordering functions, building a DLL, attaching stub, and other uses	Not required; statements duplicated by command-line features
Options	Specify with a slash (/); can be abbreviated	Specify with a dash (-) or a slash (/); no abbreviations
Case sensitivity of symbols	Off by default; control with /NOI	On by default; no control
Resources	Added by RC after build	Accepted as LINK input
Output if unresolved externals occur	Creates a main output file (with error bit set) despite unresolved externals; suppress with /ONERROR:NOEXE	No image file if errors occur during linking; /FORCE creates an image file despite unresolved externals
Modifying binaries	EXEHDR.EXE (.EXE/.DLL only)	EDITBIN.EXE (.EXE, .DLL, .OBJ)
Examining binaries	EXEHDR.EXE (.EXE/.DLL only)	DUMPBIN.EXE (.EXE, .DLL, .OBJ, .LIB)
In addition, many options that are valid for one of the linkers are invalid for the other. Also, some module-definition statements are relevant only for 16-bit or 32-bit builds.


  Differences Between LINK and LINK32

The 32-bit LINK provided with the Visual C++ development system for Windows NT is similar to the LINK32.EXE utility provided with the Microsoft Win32 SDK for Windows NT. While they have both use many of the same options, there are some differences you should be aware of when you are converting a build from LINK32 to LINK. These differences are as follows:

•	The following options are supported by LINK and are invalid for LINK32:  /COMMENT, /DEF, /DEFAULTLIB, /EXPORT, /IMPLIB, /NODEFAULTLIB, /NOLOGO, /OPT, /WARN.

•	The following options are supported by LINK32 and are invalid for LINK: /GPSIZE, /HEAP, /IGNORE, /ROM, /STUB.

•	LINK uses the environment variables described in »LINK Environment Variables«. LINK32 uses only the LIB environment variable.

•	The mapfiles produced by each linker have different formats.


  Using LINK with Visual Workbench

You can use the Linker Options dialog box in Visual Workbench to set LINK options. To get to this dialog box, choose Project Options from the Project menu and then choose Linker in the Build Options dialog box. Linker options in Visual Workbench are summarized in Chapter 10, "Build Options Reference," in Visual Workbench User's Guide.

Table 4.2 describes the Linker Options categories in Visual Workbench and the dialog-box controls in each category, along with the equivalent command-line options. For details about each command-line option, see »LINK Options«.

Table 4.2     Linker Options Categories and Equivalent Command-Line Options

Visual Workbench	Command Line
Debug Category
Generate Mapfile check box	/MAP
Mapfile Name text box	/MAP:filename
Debugging Information check box	/DEBUG
Debugging Information Type buttons	/DEBUGTYPE:{CV|COFF|BOTH}
Image Attributes Category
Stack Allocations text boxes	/STACK:reserve,commit
Base Address text box	/BASE:address
Entry-Point Symbol text box	/ENTRY:function
Input Category
Object/Library Modules text box	filename on command line
Ignore All Default Libraries check box	/NODEFAULTLIB
Ignore Specific Libraries text box	/NODEFAULTLIB:library
Include Symbols text box	/INCLUDE:symbol
Name of .DEF File text box	/DEF:filename
MS-DOS Stub Filename text box	/STUB:filename
Miscellaneous Category
Version Information text boxes	/VERSION:major.minor
Verbose check box	/VERBOSE
Suppress Display of Sign-On Banner text box	/NOLOGO
Other Options text box	Any option except /DLL
Output Category
Force File Output check box	/FORCE
Name of Output File text box	/OUT:filename


  Using CL to Control LINK

The CL compiler automatically calls LINK when you do not specify the /c option. CL provides some control over the linker through command-line options and arguments. Table 4.3 summarizes the features in CL that affect linking.

Table 4.3  Methods Used by CL to Control LINK

CL Command-Line Specification	CL Action That Affects LINK
Any filename other than .C, .CXX, .CPP, or .DEF	Passes filename as input to LINK
filename.DEF	Passes /DEF:filename.DEF
/Fnumber	Passes /STACK:number
/Fe filename	Passes /OUT:filename
/Fm filename	Passes /MAP:filename
/Gy	Creates packaged functions (COMDATs), enables function-level linking
/LD	Passes /DLL
/link	Passes remainder of command line to LINK
/MD, /ML, or /MT	Places a default library name in the object file
/nologo	Passes /NOLOGO
/Zd	Passes /DEBUG /DEBUGTYPE:COFF
/Zi or /Z7	Passes /DEBUG /DEBUGTYPE:CV
/Zl	Omits default library name from object file


 Running LINK on the Command Line

This section discusses how to run LINK at a command prompt. The following topics are included:

•	»Link Command Line«

•	»Link Command Files«

•	»Link Environment Variables«


  LINK Command Line

To run LINK, use the following command syntax:

LINK arguments

The arguments include options and filenames and can be specified in any order. Options are processed first, then files. Use one or more spaces or tabs to separate arguments.

To pass a file to the linker, specify the filename on the command line after the LINK command. If you specify a filename without an extension, LINK determines the type of file by examining it and processes it accordingly. You can specify an absolute or relative path with the filename, and you can use wildcards in the filename. If you omit the dot and filename extension, LINK assumes .OBJ for the purpose of finding the file. LINK does not use filename extensions or the lack of them to make assumptions about the contents of files.


  LINK Command Files

You can pass command-line arguments to LINK in the form of a command file. A command file is a text file that contains options and filenames specified in the same form as you specify them on the command line.

To specify a command file to the linker, use the following syntax:

LINK @commandfile

The commandfile is the name of the text file. No space or tab is allowed between the at sign (@) and the filename. There is no default extension; you must specify the full filename including any extension. Wildcard characters cannot be used. You can specify an absolute or relative path with the filename. LINK does not use an environment variable to search for the file.

In the command file, arguments can be separated by spaces or tabs (as on the command line) and by newline characters. Use a semicolon (;) to mark a comment in a command file. LINK ignores all text from the semicolon to the end of the line.

You can specify all or part of the command line in a command file. You can use more than one command file in a LINK command. LINK accepts the command-file input as if it were specified in that location on the command line. Command files cannot be nested. LINK echoes the contents of command files, unless the /NOLOGO option is specified.

Example

The following command to build a DLL passes the names of object files and libraries in separate command files and uses a third command file for specifications of the /EXPORTS option:

link /dll @objlist.txt @liblist.txt @exports.txt


  LINK Environment Variables

LINK uses environment variables as follows:

•	If LINK variable is defined, LINK processes arguments defined in the variable before it processes the command line. The LINK environment variable can contain any arguments to the linker.

•	If LIB is defined, LINK uses the LIB path when it searches for a file (such as an object or library) specified on the LINK command line or with the /BASE option, or for a PDB file named in an object. The LIB environment variable can contain one or more path specifications, separated by semicolons (;). You can set the LIB variable in Visual Workbench by choosing Directories from the Options menu.

•	If the /DEBUG option is used, LINK uses the PATH environment variable to look for CVPACK.

•	LINK uses the directory specified in the TMP environment variable when linking OMF or .RES files.


  LINK Options

An option consists of an option specifier, either a dash (-) or a forward slash (/), followed by the name of the option. Option names cannot be abbreviated. Some options take an argument, specified after a colon (:). No spaces or tabs are allowed within an option specification, except within a quoted string in the /COMMENT option. Specify numeric arguments in decimal or C-language notation. Option names and their keyword or filename arguments are not case sensitive, but identifiers as arguments are case sensitive.

LINK first processes options specified in the LINK environment variable. Link next processes options in the order they are specified on the command line and in command files. If an option is repeated with different arguments, the last one to be processed by LINK takes precedence.

Options apply to the entire build; no options can be applied to specific input files. Descriptions of each LINK option follow.


/ALIGN (LINK)
  /ALIGN

Syntax

/ALIGN:number

Category

Miscellaneous: Other Options

This option specifies the alignment of each section within the linear address space of the image file. The number argument is in bytes and must be a multiple of 512. The default is 4K. The linker generates a warning if the alignment produces an invalid image.


/BASE (LINK)
  /BASE

Syntax

/BASE:{address|@filename,key}

Category

Image Attributes: Base Address

This option sets a base address for the image, overriding the default location for an executable file (at 0x10000) or a DLL (at 0x400000). The operating system will first attempt to load the image at the specified base address. If sufficient space is not available there, the system will relocate the image. To prevent relocation, use the /FIXED option.

The address argument specifies the preferred base address. LINK rounds the specified number up to the nearest multiple of 64K.

Another way to specify the base address is by using a filename, preceded by an at sign (@), and a key into the file. The filename is a text file that contains the locations and sizes of all DLLs that your program will use. LINK looks for filename in either the specified path or, if no path is specified, in directories specified in the LIB environment variable. Each line in filename represents one DLL and has the following syntax:

key address size ;comment

The key is a string of alphanumeric characters and is not case sensitive. It is usually the name of a DLL but it need not be. The key is followed by a base address in C-notation hexadecimal or decimal and a maximum size. All three arguments are separated by spaces or tabs. LINK issues a warning if the specified size is less than the virtual address space required by the image. A comment is specified by a semicolon (;) and can be on the same or a separate line. LINK ignores all text from the semicolon to the end of the line. An example of part of such a file is as follows:

main   0x00010000    0x08000000    ; for PROJECT.EXE

one    0x28000000    0x00100000    ; for DLLONE.DLL

two    0x28100000    0x00300000    ; for DLLTWO.DLL

If the file is called DLLS.TXT, the following example command applies this information:

link dlltwo.obj /dll /base:dlls.txt,two

You can reduce paging and improve performance of your program by assigning base addresses so that DLLs do not overlap in the address space.

An alternate way to set the base address is with the BASE argument in a NAME or LIBRARY statement. The /BASE and /DLL options together are equivalent to the LIBRARY statement.


/COMMENT (LINK)
  /COMMENT

Syntax

/COMMENT:["]comment["]

Category

Miscellaneous: Other Options

This option inserts a comment string into the header of an image file, after the array of section headers. The type of operating system determines whether the string is loaded into memory. This comment string, unlike the comment specified with the DESCRIPTION statement in a .DEF file, is not inserted into the data section. Comments are useful for embedding copyright and version information.

To specify a comment that contains spaces or tabs, enclose it in double quotation marks ("). LINK removes the quotation marks before inserting the string. If more than one /COMMENT option is specified, LINK concatenates the strings and places a null byte at the end of each string.


/DEBUG (LINK)
  /DEBUG

Syntax

/DEBUG

Category

Debug: Debugging Information

This option adds debugging information to the main output file. Debugging information must exist in the object files; use the /Zi, /Zd, or /Z7 option when compiling with CL. If an object was compiled with /Zi, or if a library contains an object that was compiled with /Zi, debugging information is stored in a program database (PDB). The object contains the name and location of the PDB. LINK looks for the PDB in the following locations in this order:

1.	The absolute path written in the object

2.	The directory that LINK is running from

3.	Any directories specified in the LINK environment variable

LINK does not look in the directory that contains the object file or library that uses the PDB. You cannot specify a PDB's filename or location on the LINK command line.

When /DEBUG is used, LINK calls the CVPACK tool after linking the program. CVPACK.EXE must be in the same directory as LINK.EXE or in a directory specified in the PATH environment variable.

Note  When LINK is run using /DEBUG, it calls the CVPACK tool. The file CVPACK.EXE must be either in the same directory as LINK.EXE or in a directory specified in the PATH environment variable.

The /DEBUG option changes the default for the /OPT option from REF to NOREF.


/DEBUGTYPE (LINK)
  /DEBUGTYPE

Syntax

/DEBUGTYPE:{CV|COFF|BOTH}

Category

Debug: Debugging Information Type

This option determines the type of debugging information to be included in the image file. Specify one of the following keywords:

Keyword	Format of debugging information
CV	Microsoft Symbolic Debugging Information, used by CodeView, Visual Workbench, and some other debuggers
COFF	Common Object File Format, used by other COFF debuggers
BOTH	Both CV and COFF formats
If no option is specified, the default is CV. If more than one option is specified, both formats are put into the image file. LINK ignores /DEBUGTYPE if /DEBUG is not specified.


/DEF (LINK)
  /DEF

Syntax

/DEF:filename

Category

Input: Name of .DEF File

This option passes a module-definition (.DEF) file to the linker. Only one .DEF file can be specified to LINK. For details about .DEF files, see »Module-Definition Files for 32-Bit Programs«


/DEFAULTLIB (LINK)
  /DEFAULTLIB

Syntax

/DEFAULTLIB:library[,library...]

Category

Miscellaneous: Other Options

This option adds a library to the list of libraries that LINK searches when resolving references. The library is searched after libraries specified on the command line and before default libraries named in object files.

If the /NODEFAULTLIB option is specified, either with no filename or with the same filename as given with /DEFAULTLIB, the /DEFAULTLIB option is ignored.


/DLL (LINK)
  /DLL

Syntax

/DLL

Category

This option is set when you choose Dynamic Link Library (DLL) in the Project Type drop-down list box in the Project Options dialog box. Do not specify this option in Other Options in the Miscellaneous category.

This option builds a DLL as the main output file. A DLL usually contains exports that can be used by another program. There are three methods for specifying exports, listed in recommended order of use:

•	The __declspec(dllexport) keyword in the source code

•	An /EXPORT specification in a LINK command

•	An EXPORTS statement in a .DEF file

A program can use more than one method.

An alternate way to build a DLL is with the LIBRARY module-definition statement. The /BASE and /DLL options together are equivalent to the LIBRARY statement.


/ENTRY (LINK)
  /ENTRY

Syntax

/ENTRY:function

Category

Image Attributes: Entry-Point Symbol

This option sets the starting address for an executable file or DLL. Specify a function that is defined with the __stdcall calling convention. The function parameters and return value must be defined as documented in the Win32 API for WinMain (for an .EXE) or DllEntryPoint (for a DLL). It is recommended that you let LINK set the entry point so that the C run-time library is initialized correctly and C++ constructors for static objects are executed.

By default, the starting address is a function name from the C run-time library. LINK selects it according to the attributes of the image, as follows:

Function name	Default for
_mainCRTStartup	Application using /SUBSYSTEM:CONSOLE; calls main
_WinMainCRTStartup	Application using /SUBSYSTEM:WINDOWS; calls WinMain (which must be defined with __stdcall)
__DllMainCRTStartup	DLL; calls DllMain (which must be defined with __stdcall) if it exists
If /DLL or /SUBSYSTEM is not specified, LINK selects a subsystem and entry point depending on whether main or WinMain is defined.

The functions main, WinMain, and DllMain are the three forms of the user-defined entry point.


/EXPORT (LINK)
  /EXPORT

Syntax

/EXPORT:entryname[=internalname][,@ordinal[,NONAME]][,DATA]

Category

Miscellaneous: Other Options

This option lets you export a function from your program to allow other programs to call the function. You can also export data. Exports are usually defined in a DLL.

The entryname is the name of the function or data item as it is to be used by the calling program. You can optionally specify the internalname as the function known in the defining program; by default, internalname is the same as entryname. The ordinal specifies an index into the exports table in the range 1 − 65535; if you do not specify ordinal, LINK assigns one. The NONAME keyword exports the function only as an ordinal, without an entryname.

The DATA keyword specifies that the exported item is a data item. The data item in the client program must be declared using extern __declspec(dllimport). The CONSTANT keyword is supported for compatibility but is not recommended.

There are three methods for exporting a definition, listed in recommended order of use:

•	The __declspec(dllexport) keyword in the source code

•	An /EXPORT specification in a LINK command

•	An EXPORTS statement in a .DEF file

All three methods can be used in the same program. When LINK builds a program that contains exports, it also creates an import library, unless an .EXP file is used in the build.

LINK uses decorated forms of identifiers. CL decorates an identifier when it creates the object file. If entryname or internalname is specified to the linker in its undecorated form as it appears in the source code, LINK attempts to match the name. If it cannot find a unique match, LINK issues an error. Use the DUMPBIN tool to get the decorated form of an identifier when you need to specify it to the linker.


/FIXED (LINK)
  /FIXED

Syntax

/FIXED

Category

Miscellaneous: Other Options

This option tells the operating system to load the image file only at its preferred base address. If the preferred base address is unavailable, the operating system will not load the file. For more information on base addresses, see »/BASE«.

When /FIXED is specified, LINK does not generate a relocation section in the image file. At run time, if the operating system is unable to load the image at that address, it issues an error and does not load the program.

Some Win32 operating systems, especially those that coexist with MS-DOS, frequently must relocate an image.


/FORCE (LINK)
  /FORCE

Syntax

/FORCE

Category

Output: Force File Output

This option tells LINK to create a valid image file even if a symbol is referenced but not defined. LINK issues a warning for each undefined symbol. By default, LINK does not generate an image file when an unresolved external is found.

A file created with /FORCE may not run as expected if there are undefined symbols.


/IMPLIB (LINK)
  /IMPLIB

Syntax

/IMPLIB:filename

Category

Miscellaneous: Other Options

This option overrides the default name for the import library that LINK creates when it builds a program that contains exports. The default name is formed from the base name of the main output file and the extension .LIB. A program contains exports if one or more of the following are specified:

•	The __declspec(dllexport) keyword in the source code

•	An /EXPORT specification in a LINK command

•	An EXPORTS statement in a .DEF file

LINK ignores /IMPLIB when an import library is not being created. If no exports are specified, LINK does not create an import library. If an export (.EXP) file is used in the build, LINK assumes an import library already exists and it does not create one. For information on import libraries and export files, see »Chapter 3«, "Using the 32-Bit LIB."


/INCLUDE (LINK)
  /INCLUDE

Syntax

/INCLUDE:symbol

Category

Input: Include Symbols

This option tells LINK to add the specified symbol to the symbol table. LINK then resolves symbol by adding the object that contains the symbol definition to the image file. This is useful for including a library object that otherwise would not have been linked to the program.

An /INCLUDE:symbol specification overrides the removal of that symbol by /OPT:REF.


/MAP (LINK)
  /MAP

Syntax

/MAP[:filename]

Category

Debug: Generate Mapfile
Debug: Mapfile Name

This option tells LINK to generate a mapfile, which is a text file that contains information about the image file. The mapfile can be read by tools such as MAPSYM (not provided in this product).

When /MAP is specified, LINK names the mapfile with the base name of the image file and the extension .MAP. To override the default name, specify a colon (:) followed by filename.

A mapfile contains the following information:

•	The module name, which is the base name of the file

•	The timestamp from the image file header (not from the file system)

•	A list of groups in the image, with each group's start address (as section:offset), length, group name, and class

•	A list of public symbols, with each address (as section:offset), symbol name, flat address, and object file where the symbol is defined

•	The entry point (as section:offset)

•	A list of fixups


/NODEFAULTLIB (LINK)
  /NODEFAULTLIB

Syntax

/NODEFAULTLIB[:library[,library...]]

Category

Input: Ignore All Default Libraries
Input: Ignore Specific Libraries

This option tells LINK to remove some or all default libraries from the list of libraries it searches when resolving externals. LINK resolves references to external definitions by searching first in libraries specified on the command line, then in default libraries specified with the /DEFAULTLIB option, then in default libraries named in object files.

To suppress the search in all default libraries, specify /NODEFAULTLIB with no arguments. To suppress the search in a specific library, specify a colon (:) and the library name. You can specify multiple libraries by typing a comma (,) between the library names.

If the /NODEFAULTLIB option is specified with no filename or with the same library as given with the /DEFAULTLIB option, LINK does not search the library specified with /DEFAULTLIB.


/NOLOGO (LINK)
  /NOLOGO

Syntax

/NOLOGO

Category

Miscellaneous: Suppress Display of Sign-On Banner

This option tells LINK not to display the copyright message and version number that it sends to standard output. This option also prevents echoing of command files.


/OPT (LINK)
  /OPT

Syntax

/OPT:{REF|NOREF}

Category

Miscellaneous: Other Options

This option controls the kind of optimizations that LINK performs during a build. Optimizations generally decrease the image size and increase the program speed, at a cost of increased link time.

By default, LINK removes unreferenced packaged functions (COMDATs). An object contains packaged functions if it has been compiled with the /Gy option. This optimization is called transitive COMDAT elimination. To override this default and keep unused packaged functions in the program, specify /OPT:NOREF. You can use the /INCLUDE option to override the removal of a specific symbol.

If the /DEBUG option is specified, the default for /OPT changes from REF to NOREF and all functions are preserved in the image. To override this default and optimize a debugging build, specify /OPT:REF.


/ORDER (LINK)
  /ORDER

Syntax

/ORDER:@filename

Category

Miscellaneous: Other Options

This option lets you perform optimization by telling LINK to place certain packaged functions into the image in a predetermined order. LINK places the functions in the specified order within each section in the image.

Specify the order in filename, which is a text file that lists the packaged functions in the order you want to link them. Each line in filename contains the name of one packaged function. An object contains packaged functions if it has been compiled with the /Gy option. Function names are case sensitive. A comment is specified by a semicolon (;) and can be on the same or a separate line. LINK ignores all text from the semicolon to the end of the line.

LINK uses decorated forms of identifiers. CL decorates an identifier when it creates the object file. If the name of the packaged function is specified to the linker in its undecorated form as it appears in the source code, LINK attempts to match the name. If it cannot find a unique match, LINK issues an error. Use the DUMPBIN tool to get the decorated form of an identifier when you need to specify it to the linker.

If more than one /ORDER specification is used, the last one specified takes effect.

Ordering allows you to optimize your program's paging behavior through swap tuning. Group a function with the functions it calls. You can also group frequently called functions together. These techniques increase the probability that a called function is in memory when it is needed and will not have to be paged from disk.


/OUT (LINK)
  /OUT

Syntax

/OUT:filename

Category

Output: Name of Output File

This option overrides the default name and location of the image file that LINK creates. By default, LINK forms the filename using the base name of the first file specified and the appropriate extension (.EXE or .DLL).

The /OUT option controls the default base name for a mapfile or import library. For details, see the descriptions of /MAP and /IMPLIB.


/SECTION (LINK)
  /SECTION

Syntax

/SECTION:name,attributes

Category

Miscellaneous: Other Options

This option changes the attributes of a section, overriding the attributes set when the object file for the section was compiled.

Specify a colon (:) and a section name. The name is case sensitive.

Specify one or more attributes for the section. The attribute characters are E, R, W, and S and are not case sensitive. You must specify all attributes that you want the section to have; an omitted attribute character causes that attribute bit to be turned off. Attribute characters have the following meanings:

Character	Attribute	Meaning
E	execute	Allows code to be executed
R	read	Allows read operations on data
W	write	Allows write operations on data
S	shared	Shares the section among all processes that load the image
Note that Win32s™ operating systems load all DLL data sections as "shared" even if that attribute is not set.

A section that does not have E, R, or W set is probably invalid.


/STACK (LINK)
  /STACK

Syntax

/STACK:reserve[,commit]

Category

Image Attributes: Stack Allocations

This option sets the size of the stack in bytes and takes arguments in decimal or C-language notation.

The reserve specifies the total stack allocation in virtual memory. The default stack size is 1MB. LINK rounds up the specified value to the nearest 4 bytes.

The optional commit argument is subject to interpretation by the operating system. In Windows NT, commit specifies the amount of physical memory to allocate at a time. Committed virtual memory causes space to be reserved in the paging file. A higher commit value saves time when the application needs more stack space but increases the memory requirements and possibly startup time.

An alternate way to set the stack is with the STACKSIZE statement in a .DEF file. STACKSIZE overrides /STACK if both are specified. You can change the stack after the executable file is built by using the EDITBIN tool.


/STUB (LINK)
  /STUB

Syntax

/STUB:filename

Category

Output: MS-DOS Stub Filename

This option attaches an MS-DOS stub program to a Win32 image file. A stub program is invoked if the file is executed in MS-DOS. Usually, it displays an appropriate message; however, any valid MS-DOS application can be a stub program.

Specify a colon (:) and the filename for the stub program. LINK checks filename to be sure that it is a valid MS-DOS executable file and issues an error if the file is not valid.

If /STUB is not used, LINK attaches a default stub program that generates the following message:

This program cannot be run in MS-DOS mode.


/SUBSYSTEM (LINK)
  /SUBSYSTEM

Syntax

/SUBSYSTEM:{CONSOLE|WINDOWS}[,major[.minor]]

Category

Miscellaneous: Other Options (not recommended)

This option tells the operating system how to run the executable file. The subsystem is set as follows:

•	The CONSOLE subsystem is for a character-mode application that runs with Windows NT. Console applications are given a console by the operating system. If main is defined, CONSOLE is the default.

•	The WINDOWS subsystem applies to an application that does not require a console, probably because it creates its own windows for interaction with the user. Win32s operating systems can run only WINDOWS applications. If WinMain is defined, WINDOWS is the default.

The optional major and minor version numbers specify the minimum required version of the subsystem. The arguments are decimal numbers in the range 0 − 65535. The default is version 3.10.

The choice of subsystem affects the default starting address for the program. For more information, see /ENTRY.


/VERBOSE (LINK)
  /VERBOSE

Syntax

/VERBOSE

Category

Miscellaneous: Verbose

This option tells LINK to display details about the build process to standard output. The output can be redirected to a file.

The displayed information includes the library search process and lists each library and object name (with full path), the symbol being resolved from the library, and the list of objects that reference the symbol.


/VERSION (LINK)
  /VERSION

Syntax

/VERSION:major[.minor]

Category

Miscellaneous: Version Information

This option tells LINK to put a version number in the header of the executable file or DLL. The major and minor arguments are decimal numbers in the range 0 − 65535. The default is version 0.0.

An alternate way to insert a version number is with the VERSION module-definition statement.


/WARN (LINK)
  /WARN

Syntax

/WARN[:level]

Category

Miscellaneous: Other Options

This option lets you determine the output of LINK warnings. Specify the level as one of the following:

level	Meaning
0	Suppress all warnings.
1	Default if /WARN:level is not used; displays most warnings. Overrides a /WARN:level specified earlier on the LINK command line or in the LINK environment variable
2	Default if /WARN is specified without level; displays additional warnings.


Module-Definition Files for 32-Bit Programs (LINK)
  Module-Definition Files for 32-Bit Programs

A module-definition (.DEF) files is a text file that contains statements for defining an executable file or DLL. This section describes the statements in a .DEF file.

Because LINK provides equivalent command-line options for most module-definition statements, a typical 32-bit program for Win32 does not usually require a .DEF file. In contrast, 16-bit programs for Windows almost always must be linked using a .DEF file. The descriptions in this section give the command-line equivalent for each statement.


Rules for Module-Definition Statements (LINK)
  Rules for Module-Definition Statements

The following syntax rules apply to all statements in a .DEF file. Other rules that apply to specific statements are described with each statement.

•	Statements and attribute keywords are not case sensitive. User-specified identifiers are case sensitive.

•	Use one or more spaces, tabs, or newline characters to separate a statement keyword from its arguments and to separate statements from each other. A colon (:) or equal sign (=) that designates an argument is surrounded by zero or more spaces, tabs, or newline characters.

•	A NAME or LIBRARY statement, if used, must precede all other statements.

•	Most statements appear at most once in the .DEF file and accept one specification of arguments. The specification follows the statement keyword on the same or subsequent line(s). If the statement is repeated with different arguments later in the file, the later statement overrides the earlier one.

•	The SECTIONS and EXPORTS statements can appear more than once in the .DEF file. Each statement can take multiple specifications, which must be separated by one or more spaces, tabs, or newline characters. The statement keyword must appear once before the first specification and can be repeated before each additional specification..

•	Many statements have an equivalent LINK command-line option. ??See the description of the LINK option for additional details.

•	Comments in the .DEF file are designated by a semicolon (;) at the beginning of each comment line. A comment cannot share a line with part or all of a statement, but it can appear between specifications in a multiline statement. (SECTIONS and EXPORTS are multiline statements.)

•	Numeric arguments are specified in decimal or in C-language notation.

•	If a string argument matches a reserved word, it must be enclosed in double quotation marks (").


NAME (LINK)
  NAME

Syntax

NAME [application][BASE=address]

This statement specifies a name for the main output file. An equivalent way to specify an output filename is with the /OUT option, and an equivalent way to set the base address is with the /BASE option. If both are specified, /OUT overrides NAME. See the descriptions of /OUT and /BASE for details about output filenames and base addresses.


LIBRARY (LINK)
  LIBRARY

Syntax

LIBRARY [library][BASE=address]

This statement tells LINK to create a DLL. At the same time LINK also creates an import library, unless an .EXP file is used in the build.

The library argument specifies the DLL filename. If both the /OUT option and the LIBRARY statement are specified, /OUT overrides LIBRARY.

An equivalent way to specify a DLL build is with the /DLL option, and an equivalent way to set the base address is with the /BASE option. See »/DLL«, »/BASE«, and »/OUT« for more information.


DESCRIPTION (LINK)
  DESCRIPTION

Syntax

DESCRIPTION "text"

This statement writes a string into the data section with a "read" attribute. Enclose the specified text in single or double quotation marks (' or "). To use a literal quotation mark (either single or double) in the string, enclose the string with the other type of mark.

This feature differs from the comment specified with the /COMMENT option.


STACKSIZE (LINK)
  STACKSIZE

Syntax

STACKSIZE reserve[,commit]

This statement sets the size of the stack in bytes. An equivalent way to set the stack is with the /STACK option. See/STACK for more information.


CODE (LINK)
  CODE

Syntax

CODE attributes

This statement sets the default attributes for all code sections in the image file. You can override the defaults for specific sections by using individual /SECTION specifications or SECTIONS statements.

The attributes are one or more of the following: EXECUTE, READ, SHARED, and WRITE. The default attributes for code sections are EXECUTE and READ.


DATA (LINK)
  DATA

Syntax

DATA attributes

This statement sets the default attributes for all data sections in the image file. You can override the defaults for specific sections by using individual /SECTION specifications or SECTIONS statements.

The attributes are one or more of the following: EXECUTE, READ, SHARED, and WRITE. The default attributes for data sections are READ and WRITE. Data sections in DLLs for Win32s and Windows NT must be SHARED.


SECTIONS (LINK)
  SECTIONS

Syntax

SECTIONS definitions

This statement sets attributes for one or more sections in the image file. It can be used to override the default attributes for each type of section.

SECTIONS marks the beginning of a list of section definitions. Each definition must be on a separate line. The SECTIONS keyword can be on the same line as the first definition or on a preceding line. The .DEF file can contain one or more SECTIONS statements. The SEGMENTS keyword is supported as a synonym for SECTIONS.

The syntax for a section definition is:

section [CLASS 'classname'] attributes

The section name is case sensitive. The CLASS keyword is supported for compatibility but is ignored. The attributes are one or more of the following: EXECUTE, READ, SHARED, and WRITE.

An equivalent way to specify section attributes is with the /SECTION option.


EXPORTS (LINK)
  EXPORTS

Syntax

EXPORTS definitions

This statement makes one or more definitions available as exports to other programs.

EXPORTS marks the beginning of a list of export definitions. Each definition must be on a separate line. The EXPORTS keyword can be on the same line as the first definition or on a preceding line. The .DEF file can contain one or more EXPORTS statements.

The syntax for an export definition is:

entryname[=internalname] [@ordinal[ NONAME]] [DATA]

For information on the  entryname, internalname, ordinal, NONAME, and DATA arguments see  »/EXPORT«. The CONSTANT keyword is supported for compatibility but is not recommended.

There are three methods for exporting a definition, listed in recommended order of use:

•	The __declspec(dllexport) keyword in the source code

•	An /EXPORT specification in a LINK command

•	An EXPORTS statement in a .DEF file

All three methods can be used in the same program. When LINK builds a program that contains exports, it also creates an import library, unless an .EXP file is used in the build.


VERSION (LINK)
  VERSION

Syntax

VERSION major[.minor]

This statement tells LINK to put a number in the header of the executable file or DLL. The major and minor arguments are decimal numbers in the range 0 − 65535. The default is version 0.0.

An equivalent way to specify a version number is with the /VERSION option.


Reserved Words (LINK)
  Reserved Words

The following words are reserved by the linker. These names can be used as arguments in module-definition statements only if the name is enclosed in double quotation marks (").

APPLOADER	INVALID	PHYSICAL
BASE	IOPL	PRELOAD
CLASS	LIBRARY	PRIVATELIB
CODE	LOADONCALL	PROTMODE
CONFORMING	LONGNAMES	PURE
CONSTANT	MAXVAL	READONLY
CONTIGUOUS	MIXED1632	READWRITE
DATA	MOVABLE	REALMODE
DESCRIPTION	MOVEABLE	RESIDENT
DEV386	MULTIPLE	RESIDENTNAME
DEVICE	NAME	SECTIONS
DISCARDABLE	NEWFILES	SEGMENTS
DYNAMIC	NODATA	SHARED
EXECUTE-ONLY	NOEXPANDDOWN	SINGLE
EXECUTEONLY	NOIOPL	STACKSIZE
EXECUTEREAD	NONAME	STUB
EXETYPE	NONCONFORMING	SUBSYSTEM
EXPANDDOWN	NONDISCARDABLE	SWAPPABLE
EXPORTS	NONE	TERMINSTANCE
FIXED	NONPERMANENT	UNKNOWN
FUNCTIONS	NONSHARED	VERSION
HEAPSIZE	NOTWINDOWCOMPAT	VIRTUAL
HUGE	NULL	WINDOWAPI
IMPORTS	OBJECTS	WINDOWCOMPAT
IMPURE	OLD	WINDOWS
INCLUDE	OVERLAY	WINDOWSCHAR
INITGLOBAL	OVL
INITINSTANCE	PERMANENT


Chapter 5 NMAKE
  Chapter 5  Using NMAKE

NMAKE is a sophisticated command processor that saves time and simplifies project management. Once you specify which project files depend on others, NMAKE automatically builds your project without recompiling files that haven't changed since the last build.

If you are using Visual Workbench to build your project, the development environment handles the build process for you. You may want to read this information if you intend to build your program outside of Visual Workbench, if you want to understand existing makefiles, or if you want to use an external project in Visual Workbench.


New Features (NMAKE)
  New Features

This chapter describes NMAKE version 1.40. This version is a 32-bit tool that runs in Windows NT.

NMAKE versions 1.30 and later have the following new or updated features:

•	NMAKE's behavior during recursion has changed. Recursive calls to NMAKE do not differ from the original call. The MAKEFLAGS macro is no longer passed automatically. There is no special inheritance of macros or options. The /N option no longer displays commands in recursive calls to NMAKE.

•	The /HELP option now gives the same result as the /? option.

•	The /M and /V options are no longer supported.

The following features are new in NMAKE versions 1.20 and later:

•	New options: /B and /K

•	New options: /M and /V (removed in NMAKE version 1.30)

•	Addition of .CPP and .CXX to the .SUFFIXES list.

•	Predefined macros for C++ programs: CPP, CXX, CPPFLAGS, and CXXFLAGS

•	Predefined inference rules for C++ programs

•	The !MESSAGE directive

•	Two preprocessing operators: DEFINED and EXIST

•	Three keywords for use with the !ELSE directive: IF, IFDEF, and IFNDEF

•	New directives: !ELSEIF, !ELSEIFDEF, and !ELSEIFNDEF


Overview (NMAKE)
  Overview

NMAKE works by looking at the "time stamp" of a file. A time stamp is the time and date the file was last modified. Time stamps are assigned by most operating systems in 2-second intervals. NMAKE compares the time stamps of a "target" file and its "dependent" files. A target is usually a file you want to create, such as an executable file, though it could be a label for a set of commands you want to execute. A dependent is usually a file from which a target is created, such as a source file. A target is "out-of-date" if any of its dependents has a later time stamp than the target or if the target does not exist. (For information on how the 2-second interval affects your build, see the /B option in »Command Line Options«.)

Warning  For NMAKE to work properly, the date and time setting on your system must be consistent relative to previous settings. If you set the date and time each time you start the system, be careful to set it accurately. If your system stores a setting, be certain that the battery is working.

When you run NMAKE, it reads a "makefile" that you supply. A makefile (sometimes called a description file) is a text file containing a set of instructions that NMAKE uses to build your project. The instructions consist of description blocks, macros, directives, and inference rules. Each description block typically lists a target (or targets), the target's dependents, and the commands that build the target. NMAKE compares the time stamp on the target file with the time stamp on the dependent files. If the time stamp of any dependent is the same as or later than the time stamp of the target, NMAKE updates the target by executing the commands listed in the description block.

It is possible to run NMAKE without a makefile. In this case, NMAKE uses predefined macros and inference rules along with instructions given on the command line or in TOOLS.INI.

NMAKE's main purpose is to help you build programs quickly and easily. However, NMAKE is not limited to compiling and linking; it can run other types of programs and can execute operating system commands. You can use NMAKE to prepare backups, move files, and perform other project-management tasks that you ordinarily do at the operating-system prompt.

This chapter uses the term "build," as in building a target, to mean evaluating the time stamps of a target and its dependent and, if the target is out-of-date, executing the commands associated with the target. The term "build" has this meaning whether or not the commands actually create or change the target file.


  Running NMAKE

You invoke NMAKE with the following syntax:

NMAKE [options] [macros] [targets]

The options field lists NMAKE options, which are described in the following section, "Command-Line Options."

The macros field lists macro definitions, which allow you to change text in the makefile. The syntax for macros is described in »User-Defined Macros«.

The targets field lists targets to build. NMAKE builds only the targets listed on the command line. If you don't specify a target, NMAKE builds only the first target in the first dependency in the makefile. (You can use a pseudotarget to tell NMAKE to build more than one target. See »Pseudotargets«.)

NMAKE uses the following priorities to determine how to conduct the build:

1.	If the /F option is used, NMAKE searches the current or specified directory for the specified makefile. NMAKE halts and displays an error message if the file does not exist.

2.	If you do not use the /F option, NMAKE searches the current directory for a file named MAKEFILE.

3.	If MAKEFILE does not exist, NMAKE checks the command line for target files and tries to build them using inference rules (either defined in TOOLS.INI or predefined). This feature lets you use NMAKE without a makefile as long as NMAKE has an inference rule for the target.

4.	If a makefile is not used and the command line does not specify a target, NMAKE halts and displays an error message.

Example

The following command specifies an option ( /S ) and a macro definition ("program=sample") and tells NMAKE to build two targets (sort.exe and search.exe). The command does not specify a makefile, so NMAKE looks for MAKEFILE or uses inference rules.

NMAKE /S "program=sample" sort.exe search.exe


Command-Line Options (NMAKE)
  Command-Line Options

NMAKE accepts options for controlling the NMAKE session. Options are not case sensitive and can be preceded by either a slash ( / ) or a dash (-). You can specify some options in the makefile or in TOOLS.INI. For more information see »TOOLS.INI«. The NMAKE options are described in the following paragraphs.

/A

Forces NMAKE to build all evaluated targets, even if the targets are not out-of-date with respect to their dependents. This option does not force NMAKE to build unrelated targets.

/B

Tells NMAKE to execute a dependency even if time stamps are equal. Most operating systems assign time stamps with a resolution of 2 seconds. If your commands execute quickly, NMAKE may conclude that a file is up-to-date when in fact it is not. This option may result in some unnecessary build steps but is recommended when running NMAKE on very fast systems.

/C

Suppresses default NMAKE output, including nonfatal NMAKE error or warning messages, time stamps, and the NMAKE copyright message. If both /C and /K are specified, /C suppresses the warnings issued by /K.

/D

Displays information during the NMAKE session. The information is interspersed in NMAKE's default output to the screen. NMAKE displays the time stamp of each target and dependent evaluated in the build and issues a message when a target does not exist. Dependents for a target precede the target and are indented. The /D and /P options are useful for debugging a makefile.To set or clear /D for part of a makefile, use the !CMDSWITCHES directive; see »Preprocessing Directives«.

/E

Causes environment variables to override macro definitions in the makefile. See Environment-Variable Macros.

/F filename

Specifies filename as the name of the makefile. Zero or more spaces or tabs precede filename. If you supply a dash (-) instead of a filename, NMAKE gets makefile input from the standard input device. (End keyboard input with either F6 or CTRL+Z.) NMAKE accepts more than one makefile; use a separate /F specification for each makefile input. If you omit /F, NMAKE searches the current directory for a file called MAKEFILE (with no extension) and uses it as the makefile. If MAKEFILE doesn't exist, NMAKE uses inference rules for the command-line targets.

/HELP

Displays a brief summary of NMAKE command-line syntax.

/I

Ignores exit codes from all commands listed in the makefile. NMAKE processes the whole makefile even if errors occur. To ignore exit codes for part of a makefile, use the dash (-) command modifier or the .IGNORE directive. For more information see »Command Modifiers« and »Dot Directives«. To set or clear /I for part of a makefile, use the !CMDSWITCHES directive; see »Preprocessing Directives«. To ignore errors for unrelated parts of the build, use the /K option; /I overrides /K if both are specified.

/K

Continues the build for unrelated parts of the dependency tree if a command terminates with an error. By default, NMAKE halts if any command returns a nonzero exit code. If this option is specified and a command returns a nonzero exit code, NMAKE ceases to execute the block containing the command. It does not attempt to build the targets that depend on the results of that command; instead, it issues a warning and builds other targets. When /K is specified and the build is not complete, NMAKE returns an exit code of 1. This differs from the /I option, which ignores exit codes entirely; /I overrides /K if both are specified. The /C option suppresses the warnings issued by /K.

/N

Displays but does not execute the commands that would be executed by the build. Preprocessing commands are executed. Commands in recursive calls to NMAKE are not automatically displayed. This option is useful for debugging makefiles and checking which targets are out-of-date. To set or clear /N for part of a makefile, use the !CMDSWITCHES directive; see »Preprocessing Directives«.

/NOLOGO

Suppresses the NMAKE copyright message.

/P

Displays NMAKE information to the standard output device, including all macro definitions, inference rules, target descriptions, and the .SUFFIXES list, before running the NMAKE session. If /P is specified without a makefile or command-line target, NMAKE displays the information and does not issue an error. The /P and /D options are useful for debugging a makefile.

/Q

Checks time stamps of targets that would be updated by the build but does not run the build. NMAKE returns a zero exit code if the targets are up-to-date and a nonzero exit code if any target is out-of-date. Only preprocessing commands in the makefile are executed. This option is useful when running NMAKE from a batch file.

/R

Clears the .SUFFIXES list and ignores inference rules and macros that are defined in the TOOLS.INI file or that are predefined.

/S

Suppresses the display of all executed commands. To suppress the display of commands in part of a makefile, use the @ command modifier or the .SILENT directive; see »Command Modifiers« »Dot Directives«. To set or clear /S for part of a makefile, use the !CMDSWITCHES directive; see »Preprocessing Directives«.

/T

Changes time stamps of command-line targets (or first target in the makefile if no command-line targets are specified) to the current time and executes preprocessing commands but does not run the build. Contents of target files are not modified.

/X filename

Sends all NMAKE error output to filename, which can be a file or a device. Zero or more spaces or tabs can precede filename. If you supply a dash (-) instead of a filename, NMAKE sends its error output to standard output. By default, NMAKE sends errors to standard error. This option does not affect output that is sent to standard error by commands in the makefile.

/?

Displays a brief summary of NMAKE command-line syntax.

Example

The following command line specifies two NMAKE options:

NMAKE /F sample.mak /C targ1 targ2

The /F option tells NMAKE to read the makefile SAMPLE.MAK. The /C option tells NMAKE not to display nonfatal error messages and warnings. The command specifies two targets (targ1 and targ2) to update.


  NMAKE Command File

You can place a sequence of command-line arguments in a text file and pass the file's name as a command-line argument to NMAKE. NMAKE opens the command file and reads the arguments. You can use a command file to overcome the limit on the length of a command line in the operating system (128 characters in MS-DOS).

To provide input to NMAKE with a command file, type

NMAKE @commandfile

The commandfile is the name of a text file containing the information NMAKE expects on the command line. Precede the name of the command file with an at sign (@). You can specify a path with the filename.

NMAKE treats the file as if it were a single set of arguments. It replaces each line break with a space. Macro definitions that contain spaces must be enclosed in quotation marks. See »Where to Define Macros«for more information.

You can split input between the command line and a command file. Specify @commandfile on the command line at the place where the file's information is expected. Command-line input can precede and/or follow the command file. You can specify more than one command file.

Examples

If a file named UPDATE contains the line

/S "program = sample" sort.exe search.exe

you can start NMAKE with the command

NMAKE @update

The effect is the same as if you entered the following command line:

NMAKE /S "program = sample" sort.exe search.exe

The following is another version of the UPDATE file:

/S "program \
= sample" sort.exe search.exe

The backslash ( \ ) allows the macro definition to span two lines.

If the command file called UPDATE contains the line

/S "program = sample" sort.exe

you can start NMAKE with the command

NMAKE @update search.exe


The TOOLS.INI File (NMAKE)
  The TOOLS.INI File

You can customize NMAKE by placing commonly used information in the TOOLS.INI initialization file. Settings for NMAKE must follow a line that begins with the tag [NMAKE]. The tag is not case sensitive. This section of the initialization file can contain any makefile information. NMAKE uses this information in every session, unless you run NMAKE with the /R option. NMAKE looks for TOOLS.INI first in the current directory and then in the directory specified by the INIT environment variable.

You can use the !CMDSWITCHES directive to specify command-line options in TOOLS.INI. An option specified this way is in effect for every NMAKE session. This serves the same purpose as does an environment variable, which is a feature available in other utilities. For more information on !CMDSWITCHES, see »Preprocessing Directives«.

Macros and inference rules appearing in TOOLS.INI can be overridden. See »Precedence Among Macro Definitions«and »Precedence Among Inference Rules« for more information.

NMAKE reads information in TOOLS.INI before it reads makefile information. For example, a description block appearing in TOOLS.INI acts as the first description block in the makefile; this is true for every NMAKE session, unless /R is specified.

To place a comment in TOOLS.INI, specify the comment on a separate line beginning with a semicolon ( ; ). You can also specify comments with a number sign ( # ) as you can in a makefile; for more information, see »Comments«.

Example

The following is an example of text in a TOOLS.INI file:

[NMAKE]
; macros
CC     = qcl
CFLAGS = /Gc /Gs /W3 /Oat
; inference rule
.c.obj:
    $(CC) /Zi /c $(CFLAGS) $*.c

NMAKE reads and applies the lines following [NMAKE]. The example redefines the macro CC to invoke the Microsoft QuickC Compiler, defines the macro CFLAGS, and redefines the inference rule for making .OBJ files from .C sources. These NMAKE features are explained throughout this chapter.


Contents of a Makefile (NMAKE)
  Contents of a Makefile

An NMAKE makefile contains description blocks, macros, inference rules, and directives. This section presents general information about writing makefiles.

The following topics are included:

»Using Special Characters as Literals«

»Wildcards«

»Comments«

»Long Filenames«


Using Special Characters as Literals (NMAKE)
  Using Special Characters as Literals

You may need to specify as a literal character one of the characters that NMAKE uses for a special purpose. These characters are:

:  ;  #  (  )  $  ^  \  {  }  !  @  —

To use one of these characters without its special meaning, place a caret ( ^ ) in front of it. NMAKE ignores carets that precede characters other than the special characters listed previously. A caret within a quoted string is treated as a literal caret character.

You can also use a caret at the end of a line to insert a literal newline character in a string or macro. The caret tells NMAKE to interpret the newline character as part of the macro, not a line break. Note that this effect differs from using a backslash ( \ ) to continue a line in a macro definition. A newline character that follows a backslash is replaced with a space. For more information, see »User-Defined Macros«.

In a command, a percent symbol (%) can represent the beginning of a file specifier. (See »Filename-Parts Syntax«.) NMAKE interprets %s as a filename, and it interprets the character sequence of %| followed by d, e, f, p, or F as part or all of a filename or path. If you need to represent these characters literally in a command, specify a double percent sign (%%) in place of a single one. In all other situations, NMAKE interprets a single % literally. However, NMAKE always interprets a double %% as a single %. Therefore, to represent a literal %%, you can specify either three percent signs, %%%, or four percent signs, %%%%.

To use the dollar sign ($) as a literal character in a command, you must specify two dollar signs ($$); this method can also be used in other situations where ^$ also works.

For information on literal characters in macro definitions, see »Special Characters in Macros«.


Wildcards (NMAKE)
  Wildcards

You can use MS-DOS wildcards (* and ?) to specify target and dependent names. NMAKE expands wildcards that appear on dependency lines. A wildcard specified in a command is passed to the command; NMAKE does not expand it.

Example

In the following description block, the wildcard * is used twice:

project.exe : *.c
    cl *.c /Feproject.exe

NMAKE expands the *.c in the dependency line and looks at all files having the .C extension in the current directory. If any .C file is out-of-date, the CL command expands the *.c and compiles and links all files.


Comments (NMAKE)
  Comments

To place a comment in a makefile, precede it with a number sign ( # ). If the entire line is a comment, the number sign must appear at the beginning of the line. Otherwise, the number sign follows the item being commented. NMAKE ignores all text from the number sign to the next newline character.

Command lines cannot contain comments; this is true even for a command that is specified on the same line as a dependency line or inference rule. This is because NMAKE does not parse a command; instead, it passes the entire command to the operating system. However, a comment can appear between lines in a commands block. To comment out a command, insert a number sign at the beginning of the command line.

You can use comments in the following situations:

# Comment on line by itself

OPTIONS = /MAP  # Comment on macro definition line

all.exe : one.obj two.obj  # Comment on dependency line
    link one.obj two.obj
# Comment in commands block
    copy one.exe \release
# Command turned into comment:
#   copy *.obj \objects

.obj.exe:  # Comment in inference rule

To specify a literal number sign, precede it with a caret ( ^ ), as in the following:

DEF = ^#define  #Macro representing a C preprocessing directive

Comments can also appear in a TOOLS.INI file. TOOLS.INI allows an additional form of comment using a semicolon ( ; ). See »The TOOLS.INI File«.


Long Filenames (NMAKE)
  Long Filenames

You can use long filenames if they are supported by your file system. However, you must enclose the name in double quotation marks, as in the following dependency line:

all : "VeryLongFileName.exe"


Description Blocks (NMAKE)
  Description Blocks

Description blocks form the heart of the makefile. The following is a typical NMAKE description block:

myapp.exe : myapp.obj another.obj myapp.def
    link myapp another /DEF:myapp.def
    copy myapp.exe c:\project

The first line in a description block is the "dependency line." In this example, the dependency contains one "target" and three "dependents." The dependency is followed by a commands block that lists one or more commands. The following sections discuss dependencies, targets, and dependents.

The following topics are included:

•	»Dependency Line«

•	»Targets«

•	»Dependents«


Dependency Line (NMAKE)
  Dependency Line

A description block begins with a "dependency line." A dependency line specifies one or more "target" files and then lists zero or more "dependent" files. If a target does not exist, or if its time stamp is earlier than that of any dependent, NMAKE executes the commands block for that target. The following is an example of a dependency line:

myapp.exe : myapp.obj another.obj myapp.def

This dependency line tells NMAKE to rebuild the MYAPP.EXE target whenever MYAPP.OBJ, ANOTHER.OBJ, or MYAPP.DEF has changed more recently than MYAPP.EXE.

The dependency line must not be indented (it cannot start with a space or tab). The first target must be specified at the beginning of the line. Targets are separated from dependents by a single colon, except as described in »Using Targets in Multiple Description Blocks«. The colon can be preceded or followed by zero or more spaces or tabs. The entire dependency must appear on one line; however, you can extend the line by placing a backslash ( \ ) after a target or dependent and continuing the dependency on the next line.

Before executing any commands, NMAKE moves through all dependencies and applicable inference rules to build a "dependency tree" that specifies all the steps required to fully update the target. NMAKE checks to see if dependents themselves are targets in other dependency lists, if any dependents in those lists are targets elsewhere, and so on. After it builds the dependency tree, NMAKE checks time stamps. If it finds any dependents in the tree that are newer than the target, NMAKE builds the target.


Targets (NMAKE)
  Targets

The targets section of the dependency line lists one or more target names. At least one target must be specified. Separate multiple target names with one or more spaces or tabs. You can specify a path with the filename. Targets are not case sensitive. A target (including path) cannot exceed 256 characters.

If the name of the last target before the colon ( : ) is a single character, you must put a space between the name and the colon; otherwise, NMAKE interprets the letter-colon combination as a drive specifier.

Usually a target is the name of a file to be built using the commands in the description block. However, a target can be any valid filename, or it can be a pseudotarget.

NMAKE builds targets specified on the NMAKE command line. If a command-line target is not specified, NMAKE builds the first target in the first dependency in the makefile.

The example in the previous section tells NMAKE how to build a single target file called MYAPP.EXE if it is missing or out-of-date.

This section includes the following topics:

•	»Using Targets in Multiple Description Blocks«

•	»Accumulating Targets in Dependencies«

•	»Pseudotargets«


Using Targets in Multiple Description Blocks (NMAKE)
  Using Targets in Multiple Description Blocks

A target can appear in only one description block when specified using the single-colon ( : ) syntax to separate the target from the dependent. To update a target using more than one description block, specify two consecutive colons (::) between targets and dependents. One use for this feature is for building a complex target that contains components created with different commands.

Example

The following makefile updates a library:

target.lib :: one.asm two.asm three.asm
    ML one.asm two.asm three.asm
    LIB target one.obj two.obj three.obj
target.lib :: four.c five.c
    CL /c four.c five.c
    LIB target four.obj five.obj

If any of the assembly-language files have changed more recently than the library, NMAKE assembles the source files and updates the library. Similarly, if any of the C-language files have changed, NMAKE compiles the C files and updates the library.


Accumulating Targets in Dependencies (NMAKE)
  Accumulating Targets in Dependencies

Dependency lines are cumulative when the same target appears more than once in a single description block.

Example

bounce.exe : jump.obj
bounce.exe : up.obj
    echo Building bounce.exe...

is evaluated by NMAKE as

bounce.exe : jump.obj up.obj
    echo Building bounce.exe...

This evaluation has several effects. Because NMAKE builds the dependency tree based on one target at a time, the lines can contain other targets, as in:

bounce.exe leap.exe : jump.obj
bounce.exe climb.exe : up.obj
    echo Building bounce.exe...

NMAKE evaluates a dependency for each of the three targets as if each were specified in a separate description block. If bounce.exe or climb.exe is out-of-date, NMAKE runs the given command. If leap.exe is out-of-date, the given command does not apply, and NMAKE tries to use an inference rule.

If the same target is specified in two single-colon dependency lines in different locations in the makefile, and if commands appear after only one of the lines, NMAKE interprets the dependency lines as if they were adjacent or combined. This can cause an unwanted side effect: NMAKE does not invoke an inference rule for the dependency that has no commands. See . Rather, it assumes that the dependencies belong to one description block and executes the commands specified with the other dependency.

Example

The following makefile is interpreted in the same way as the preceding examples:

bounce.exe : jump.obj
    echo Building bounce.exe...
.
.
.
bounce.exe : up.obj

This effect does not occur if the colons are doubled (::) after the duplicate targets. A double-colon dependency with no commands block invokes an inference rule, even if another double-colon dependency containing the same target is followed by a commands block.


Pseudotargets (NMAKE)
  Pseudotargets

A "pseudotarget" is a target that doesn't specify a file but instead names a label for use in executing a group of commands. NMAKE interprets the pseudotarget as a file that does not exist and thus is always out-of-date. When NMAKE evaluates a pseudotarget, it always executes its commands block. Be sure that the current directory does not contain a file with a name that matches the pseudotarget.

A pseudotarget name must follow the syntax rules for filenames. Like a filename target, a pseudotarget name is not case sensitive. However, if the name does not have an extension (that is, it does not contain a period), it can exceed the 8-character limit for filenames and can be up to 256 characters long.

A pseudotarget can be listed as a dependent. A pseudotarget used this way must appear as a target in another dependency; however, that dependency does not need to have a commands block.

A pseudotarget used as a target has an assumed time stamp that is the most recent time stamp of all its dependents. If a pseudotarget has no dependents, the assumed time stamp is the current time. NMAKE uses the assumed time stamp if the pseudotarget appears as a dependent elsewhere in the makefile.

Pseudotargets are useful when you want NMAKE to build more than one target automatically. NMAKE builds only those targets specified on the NMAKE command line, or, when no command-line target is specified, it builds only the first target in the first dependency in the makefile. To tell NMAKE to build multiple targets without having to list them on the command line, write a description block with a dependency containing a pseudotarget and list as its dependents the targets you want to build. Either place this description block first in the makefile or specify the pseudotarget on the NMAKE command line.

Examples

In the following example, UPDATE is a pseudotarget.

UPDATE : *.*
    !COPY $** a:\product

If UPDATE is evaluated, NMAKE copies all files in the current directory to the specified drive and directory.

In the following makefile, the pseudotarget all builds both PROJECT1.EXE and PROJECT2.EXE if either all or no target is specified on the command line. The pseudotarget setenv changes the LIB environment variable before the .EXE files are updated:

all : setenv project1.exe project2.exe

project1.exe : project1.obj
    LINK project1

project2.exe : project2.obj
    LINK project2

setenv :
    set LIB=\project\lib


Dependents (NMAKE)
  Dependents

The dependents section of the dependency line lists zero or more dependent names. Usually a dependent is a file used to build the target. However, a dependent can be any valid filename, or it can be a pseudotarget. You can specify a path with the filename. Dependents are not case sensitive. Separate each dependent name with one or more spaces or tabs. A single or double colon (: or ::) separates it from the targets section.

Along with dependents you explicitly list in the dependency line, NMAKE can assume an "inferred dependent." An inferred dependent is derived from an inference rule. For more information, see »Inference Rules«. NMAKE considers an inferred dependent to appear earlier in a dependents list than explicit dependents. It builds inferred dependents into the dependency tree. It is important to note that when an inferred dependent in a dependency is out-of-date with respect to a target, NMAKE invokes the commands block associated with the dependency, just as it does with an explicit dependent.

NMAKE uses the dependency tree to make sure that dependents themselves are updated before it updates their targets. If a dependent file doesn't exist, NMAKE looks for a way to build it; if it already exists, NMAKE looks for a way to make sure it is up-to-date. If the dependent is listed as a target in another dependency, or if it is implied as a target in an inference rule, NMAKE checks that the dependent is up-to-date with respect to its own dependents; if the dependent file is out-of-date or doesn't exist, NMAKE executes the commands block for that dependency.

Example

The following example lists three dependents after MYAPP.EXE:

myapp.exe : myapp.obj another.obj myapp.def

Specifying Search Paths for Dependents

You can specify the directories in which NMAKE should search for a dependent. The syntax for a directory specification is:

{directory[;directory...]}dependent

Enclose one or more directory names in braces ( { } ). Separate multiple directories with a semicolon ( ; ). No spaces are allowed. You can use a macro to specify part or all of a search path. NMAKE searches the current directory first, then the directories in the order specified. A search path applies only to a single dependent.

Example

The following dependency line contains a directory specification:

forward.exe : {\src\alpha;d:\proj}pass.obj

The target FORWARD.EXE has one dependent, PASS.OBJ. The directory list specifies two directories. NMAKE first searches for PASS.OBJ in the current directory. If PASS.OBJ isn't there, NMAKE searches the \ SRC \ ALPHA directory, then the D:\ PROJ directory.


Commands (NMAKE)
  Commands

The commands section of a description block or inference rule lists the commands that NMAKE must run if the dependency is out-of-date. You can specify any command or program that can be executed from an MS-DOS command line (with a few exceptions, such as PATH). Multiple commands can appear in a commands block. Each appears on its own line (except as noted in the next section). If a description block doesn't contain any commands, NMAKE looks for an inference rule that matches the dependency. See »Inference Rules«. The following example shows two commands following a dependency line:

myapp.exe : myapp.obj another.obj myapp.def
    link myapp another /DEF:myapp.def
    copy myapp.exe c:\project

NMAKE displays each command line before it executes it, unless you specify the /S option , the .SILENT directive , the !CMDSWITCHES directive , or the @ modifier .

The following topics are included:

•	»Command Syntax«

•	»Command Modifiers«

•	»Exit Codes from Commands«

•	»Filename-Parts Syntax«


Command Syntax (NMAKE)
  Command Syntax

A command line must begin with one or more spaces or tabs. NMAKE uses this indentation to distinguish between a dependency line and a command line.

Blank lines cannot appear between the dependency line and the commands block. However, a line containing only spaces or tabs can appear; this line is interpreted as a null command, and no error occurs. Blank lines can appear between command lines.

A long command can span several lines if each line ends with a backslash ( \ ). A backslash at the end of a line is interpreted as a space on the command line. For example, the LINK command shown in previous examples in this chapter can be expressed as:

    link myapp\
another /DEF:myapp.def

NMAKE passes the continued lines to the operating system as one long command. A command continued with a backslash must still be within the operating system's limit on the length of a command line. If any other character, such as a space or tab, follows the backslash, NMAKE interprets the backslash and the trailing characters literally.

You can also place a single command at the end of a dependency line, whether or not you specify other commands in the indented commands block. Use a semicolon ( ; ) to separate the command from the rightmost dependent, as in:

project.obj : project.c project.h ; cl /c project.c


Command Modifiers (NMAKE)
  Command Modifiers

Command modifiers provide extra control over the commands in a description block. You can use more than one modifier for a single command. Specify a command modifier preceding the command being modified, optionally separated by spaces or tabs. Like a command, a modifier cannot appear at the beginning of a line. It must be preceded by one or more spaces or tabs.

Descriptions of the three NMAKE command modifiers follow:

@command

Prevents NMAKE from displaying the command. Any results displayed by commands are not suppressed. Spaces and tabs can appear before the command. By default, NMAKE echoes all makefile commands that it executes. The /S option suppresses display for the entire makefile; the .SILENT directive  suppresses display for part of the makefile.

−[number ]command

Turns off error checking for the command. Spaces and tabs can appear before the command. By default, NMAKE halts when any command returns an error in the form of a nonzero exit code. This modifier tells NMAKE to ignore errors from the specified command. If the dash is followed by a number, NMAKE stops if the exit code returned by the command is greater than that number. No spaces or tabs can appear between the dash and the number. At least one space or tab must appear between the number and the command. (For more information on using this number, see »Exit Codes from Commands«.) The /I option  turns off error checking for the entire makefile; the .IGNORE directive  turns off error checking for part of the makefile.

!command

Executes the command for each dependent file if the command preceded by the exclamation point uses the predefined macros $** or $?. See »Filename Macros«. Spaces and tabs can appear before the command. The $** macro represents all dependent files in the dependency line. The $? macro refers to all dependent files in the dependency line that have a later time stamp than the target.

Examples

In the following example, the at sign (@) suppresses display of the ECHO command line:

sort.exe : sort.obj
    @ECHO Now sorting...

The output of the ECHO command is not suppressed.

In the following description block, if the program sample returns a nonzero exit code, NMAKE does not halt; if sort returns an exit code that is greater than 5, NMAKE stops:

light.lst : light.txt
    -sample light.txt
    -5 sort light.txt

The description block

print : one.txt two.txt three.txt
    !print $** lpt1:

generates the following commands:

print one.txt lpt1:
print two.txt lpt1:
print three.txt lpt1:


Exit Codes from Commands (NMAKE)
  Exit Codes from Commands

NMAKE stops execution if a command or program executed in the makefile encounters an error and returns a nonzero exit code. The exit code is displayed in an NMAKE error message.

You can control how NMAKE behaves when a nonzero exit code occurs by using the /I or /K option, the .IGNORE directive, the !CMDSWITCHES directive, or the dash (-) command modifier.

Another way to use exit codes is during preprocessing. You can run a command or program and test its exit code using the !IF preprocessing directive.


Filename-Parts Syntax (NMAKE)
Filename-Parts Syntax

NMAKE provides a syntax that you can use in commands to represent components of the name of the first dependent file. This file is generally the first file listed to the right of the colon in a dependency line. However, if a dependent is implied from an inference rule, NMAKE considers the inferred dependent to be the first dependent file, ahead of any explicit dependents. If more than one inference rule applies, the .SUFFIXES list determines which dependent is first. The filename components are the file's drive, path, base name, and extension as you have specified it, not as it exists on disk.

You can represent the complete filename with the following syntax:

%s

For example, if a description block contains

sample.exe : c:\project\sample.obj
    LINK %s

NMAKE interprets the command as

LINK c:\project\sample.obj

You can represent parts of the complete filename with the following syntax:

%|[parts]F

where parts can be zero or more of the following letters, in any order:

Letter	Description
No letter	Complete name
d	Drive
p	Path
f	File base name
e	File extension
Using this syntax, you can represent the full filename specification by %|F or by %|dpfeF, as well as by %s.

Example

The following description block uses filename-parts syntax:

sample.exe : c:\project\sample.obj
    LINK %s /OUT:a:%|pfF.exe

NMAKE interprets the first representation as the complete filename of the dependent. It interprets the second representation as a filename with the same path and base name as the dependent but on the specified drive and with the specified extension. It executes the following command:

    LINK c:\project\sample.obj /OUT:a:\project\sample.exe

Note  For another way to represent components of a filename, see Modifying Filename Macros in »Filename Macros«.


Inline Files (NMAKE)
  Inline Files

NMAKE can create "inline files" in the commands section of a description block or inference rule. An inline file is created on disk by NMAKE and contains text you specify in the makefile. The name of the inline file can be used in commands in the same way as any filename. NMAKE creates the inline file only when it executes the command in which the file is created.

One way to use an inline file is as a command file for another utility such as LINK or LIB. Command files avoid operating system limits on the maximum length of a command line and automate the specification of input to a utility. Inline files eliminate the need to maintain a separate command file. They can also be used to pass a list of commands to the operating system.

Specifying an Inline File

The syntax for specifying an inline file in a command is:

    <<[filename]

Specify the double angle brackets (<<) on the command line at the location where you want a filename to appear. Because command lines must be indented, the angle brackets cannot appear at the beginning of a line. The angle bracket syntax must be specified literally; it cannot be represented by a macro expansion.

When NMAKE executes the description block, it replaces the inline file specification with the name of the inline file being created. The effect is the same as if a filename was literally specified in the commands section.

The filename supplies a name for the inline file. It must immediately follow the angle brackets; no space is permitted. You can specify a path with the filename. No extension is required or assumed. If a file by the same name already exists, NMAKE overwrites it; such a file is deleted if the inline file is temporary.

A name is optional; if you don't specify filename, NMAKE gives the inline file a unique name. If filename is specified, NMAKE places the file in the directory specified with the name or in the current directory if no path is specified. If filename is not specified, NMAKE places the inline file in the directory specified by the TMP environment variable or in the current directory if TMP is not defined. You can reuse a previous inline filename; NMAKE overwrites the previous file.

Creating an Inline File

The instructions for creating the inline file begin on the first line after the command. The syntax to create the inline file is:

inlinetext
.
.
.
<<[KEEP | NOKEEP]

The set of angle brackets marking the end of the inline file must appear at the beginning of a separate line in the makefile. All inlinetext before the delimiting angle brackets is placed in the inline file. The text can contain macro expansions and substitutions. Directives and comments are not permitted in an inline file; NMAKE treats them as literal text. Spaces, tabs, and newline characters are treated literally.

The inline file can be temporary or permanent. To retain the file after the end of the NMAKE session, specify KEEP immediately after the closing set of angle brackets. If you don't specify a preference, or if you specify NOKEEP (the default), the file is temporary. KEEP and NOKEEP are not case sensitive. The temporary file exists for the duration of the NMAKE session.

It is possible to specify KEEP for a file that you do not name; in this case, the NMAKE-generated filename appears in the appropriate directory after the NMAKE session.

Example

The following makefile uses a temporary inline file to clear the screen and then display the contents of the current directory:

COMMANDS = cls ^
dir
showdir :
    <<showdir.bat
$(COMMANDS)
<<

In this example, the name of the inline file serves as the only command in the description block. This command has the same effect as running a batch file named SHOWDIR.BAT that contains the same commands as those listed in the macro definition.

Reusing an Inline File

After an inline file is created, you can use it more than once. To reuse an inline file in the command in which it is created, you must supply a filename for the file where it is defined and first used. You can then reuse the name later in the same command.

You can also reuse an inline file in subsequent commands in the same description block or elsewhere in the makefile. Be sure that the command that creates the inline file executes before all commands that use the file. Regardless of whether you specify KEEP or NOKEEP, NMAKE keeps the file for the duration of the NMAKE session.

Example

The following makefile creates a temporary command file named LIB.LRF, which is used to run the 16-bit LIB tool:

OBJECTS = add.obj sub.obj mul.obj div.obj
math.lib : $(OBJECTS)
    LIB math.lib @<<lib.lrf
-+$(?: = &^
-+)
listing;
<<
    copy lib.lrf \projinfo\lib.lrf

The resulting response file tells LIB which library to use, the commands to execute, and the name of the listing file to produce:

-+add.obj &
-+sub.obj &
-+mul.obj &
-+div.obj
listing;

The second command in the descripton block tells NMAKE to copy the response file to another directory.

Using Multiple Inline Files

You can specify more than one inline file in a single command line. For each inline specification, specify one or more lines of inline text followed by a closing line containing the delimiter. Begin the second file's text on the line following the delimiting line for the first file.

Example

The following example creates two inline files:

target.abc : depend.xyz
    copy <<file1 + <<file2 both.txt
I am the contents of file1.
<<
I am the contents of file2.
<<KEEP

This is equivalent to specifying

copy file1 + file2 both.txt

to concatenate two files, where FILE1 contains

I am the contents of file1.

and FILE2 contains

I am the contents of file2.

The KEEP keyword tells NMAKE not to delete FILE2. After the NMAKE session, the files FILE2 and BOTH.TXT exist in the current directory.


Macros (NMAKE)
  Macros

Macros offer a convenient way to replace a particular string in the makefile with another string. You can define your own macros or use predefined macros. Macros are useful for a variety of tasks, such as:

•	Creating a single makefile that works for several projects. You can define a macro that replaces a dummy filename in the makefile with the specific filename for a particular project.

•	Controlling the options NMAKE passes to the compiler or linker. When you specify options in a macro, you can change options throughout the makefile in a single step.

•	Specifying paths in an inference rule. (For an example, see User-Defined Inference Rules.)

This section describes user-defined macros, shows how to use a macro, and discusses the macros that have special meaning for NMAKE.

The following topics are included:

»User-Defined Macros«

»Using Macros«

»Special Macros«

»Substitution Within Macros«

»Substitution Within Predefined Macros«

»Environment Variable Macros«

»Macros in Recursion«

»Precedence Among Macro Definitions«


User-Defined Macros (NMAKE)
  User-Defined Macros

To define a macro, use the following syntax:

macroname=string

The macroname can be any combination of letters, digits, and the underscore ( _ ) character, up to 1024 characters. Macro names are case sensitive; NMAKE interprets MyMacro and MYMACRO as different macro names. The macroname can contain a macro invocation. If macroname consists entirely of an invoked macro, the macro being invoked cannot be null or undefined.

The string can be any sequence of zero or more characters (limited only by virtual memory). A string of zero characters is called a null string. A string consisting only of spaces, tabs, or both is also considered a null string.

Other syntax rules, such as the use of spaces, apply depending on where you specify the macro; see »Where to Define Macros«. The string can contain a macro invocation.

Example

The following specification defines a macro named DIR and assigns to it a string that represents a directory.

DIR=c:\objects


Special Characters in Macros (NMAKE)
  Special Characters in Macros

Certain characters have special meaning within a macro definition. You use these characters to perform specific tasks. If you want one of these characters to have a literal meaning, you must specify it using a special syntax.

•	To specify a comment with a macro definition, place a number sign ( # ) and the comment after the definition, as in:

LINKCMD = link /DEBUG  # Prepare for debugging

NMAKE ignores the number sign and all characters up to the next newline character. To specify a literal number sign in a macro, use a caret ( ^ ), as in ^#.

•	To extend a macro definition to a new line, end the line with a backslash ( \ ). The newline character that follows the backslash is replaced with a space when the macro is expanded, as in the following example:

LINKCMD = link myapp\
another /DEF:myapp.def

When this macro is expanded, a space separates myapp and another.

To specify a literal backslash at the end of the line, precede it with a caret ( ^ ), as in:

exepath = c:\bin^\

You can also make a backslash literal by following it with a comment specifier
( # ). NMAKE interprets a backslash as literal if it is followed by any other character.

•	To insert a literal newline character into a macro, end the line with a caret ( ^ ). The caret tells NMAKE to interpret the newline character as part of the macro, not as a line break ending the macro definition. The following example defines a macro composed of two operating-system commands separated by a newline character:

CMDS = cls^
dir

For an illustration of how this macro can be used, see the first example under »Inline Files«.

•	To specify a literal dollar sign ($) in a macro definition, use two dollar signs ($$). NMAKE interprets a single dollar sign as the specifier for invoking a macro; see »Using Macros«.

For information on how to handle other special characters literally, regardless of whether they appear in a macro, see »Using Special Characters as Literals«.


Where to Define Macros (NMAKE)
  Where to Define Macros

You can define macros in the makefile, on the command line, in a command file, or in TOOLS.INI. Each macro defined in the makefile or in TOOLS.INI must appear on a separate line. The line cannot start with a space or tab.

When you define a macro in the makefile or in TOOLS.INI, NMAKE ignores any spaces or tabs on either side of the equal sign. The string itself can contain embedded spaces. You do not need to enclose string in quotation marks (if you do, they become part of the string). The macro name being defined must appear at the beginning of the line. Only one macro can be defined per line. For example, the following macro definition can appear in a makefile or TOOLS.INI:

LINKCMD = LINK /MAP

Slightly different rules apply when you define a macro on the NMAKE command line or in a command file. The command-line parser treats spaces and tabs as argument delimiters. Therefore, spaces must not precede or follow the equal sign. If string contains embedded spaces or tabs, either the string itself or the entire macro must be enclosed in double quotation marks (" "). For example, either form of the following command-line macro is allowed:

NMAKE "LINKCMD = LINK /MAP"
NMAKE LINKCMD="LINK /MAP"

However, the following form of the same macro is not permitted. It contains spaces that are not enclosed by quotation marks:

NMAKE LINKCMD = "LINK /MAP"


Null Macros and Undefined Macros (NMAKE)
  Null Macros and Undefined Macros

An undefined macro is not the same thing as a macro defined to be null. Both kinds of macros expand to a null string. However, a macro defined to be null is still considered to be defined when used with preprocessing directives such as !IFDEF. See »Preprocessing Directives«. A macro name can be "undefined" in a makefile by using the !UNDEF preprocessing directive.

To define a macro to be null:

•	In a makefile or TOOLS.INI, specify zero or more spaces between the equal sign (=) and the end of the line, as in the following:

LINKOPTIONS =

•	On the command line or in a command file, specify zero or more spaces enclosed in double quotation marks (" "), or specify the entire null definition enclosed in double quotation marks, as in either of the following:

LINKOPTIONS=""
"LINKOPTIONS ="

To undefine a macro, use !UNDEF, as in:

!UNDEF LINKOPTIONS


Using Macros (NMAKE)
  Using Macros

To use a macro (defined or not), enclose its name in parentheses preceded by a dollar sign ($), as follows:

$(macroname)

No spaces are allowed. For example, you can use the LINKCMD macro defined as

LINKCMD = LINK /MAP

by specifying

$(LINKCMD)

NMAKE replaces the specification $(LINKCMD) with LINK /MAP.

If the name you use as a macro has never been defined, or was previously defined but is now undefined, NMAKE treats that name as a null string. No error occurs.

The parentheses are optional if macroname is a single character. For example, $L is equivalent to $(L). However, parentheses are recommended for consistency and to avoid possible errors.

Example

The following makefile defines and uses three macros:

program = sample
L       = LINK
OPTIONS =

$(program).exe : $(program).obj
    $(L) $(OPTIONS) $(program).obj

NMAKE interprets the description block as

sample.exe : sample.obj
    LINK sample.obj

NMAKE replaces every occurrence of $(program) with sample, every instance of $(L) with LINK, and every instance of $(OPTIONS) with a null string.


Special Macros (NMAKE)
  Special Macros

NMAKE provides several special macros to represent various filenames and commands. One use for these macros is in the predefined inference rules. (For more information, see »Predefined Inference Rules«.) Like user-defined macro names, special macro names are case sensitive. For example, NMAKE interprets CC and cc as different macro names.

The following sections describe the four categories of special macros. The file-name macros offer a convenient representation of filenames from a dependency line. The recursion macros allow you to call NMAKE from within your makefile. The command macros and options macros make it convenient for you to invoke the Microsoft language compilers.


Filename Macros (NMAKE)
  Filename Macros

NMAKE provides macros that are predefined to represent filenames. The filenames are as you have specified them in the dependency line and not the full specification of the filenames as they exist on disk. As with all one-character macros, these do not need to be enclosed in parentheses. (The $$@ and $** macros are exceptions to the parentheses rule for macros; they do not require parentheses even though they contain two characters.)

$@

The current target's full name (path, base name, and extension), as currently specified.

$$@

The current target's full name (path, base name, and extension), as currently specified. This macro is valid only for specifying a dependent in a dependency line.

$*

The current target's path and base name minus the file extension.

$**

All dependents of the current target.

$?

All dependents that have a later time stamp than the current target.

$<

The dependent file that has a later time stamp than the current target. You can use this macro only in commands in inference rules.

Examples

The following example uses the $? macro, which represents all dependents that have changed more recently than the target. The ! command modifier causes NMAKE to execute a command once for each dependent in the list. As a result, the LIB command is executed up to three times, each time replacing a module with a newer version.

trig.lib : sin.obj cos.obj arctan.obj
    !LIB trig.lib $?

In the next example, NMAKE updates a file in another directory by replacing it with a file of the same name from the current directory. The $@ macro is used to represent the current target's full name.

# File in objects directory depends on version in current directory
DIR = c:\objects
$(DIR)\a.obj : a.obj
    COPY a.obj $@

Modifying Filename Macros

You can append one of the modifiers in the following table to any of the filename macros to extract part of a filename. If you add one of these modifiers to the macro, you must enclose the macro name and the modifier in parentheses.

Modifier	Resulting filename part
D	Drive plus directory
B	Base name
F	Base name plus extension
R	Drive plus directory plus base name
Examples

Assume that $@ represents the target C:\SOURCE\PROG\SORT.OBJ. The following table shows the effect of combining each modifier with $@:

Macro reference	Value
$(@D)	C:\SOURCE\PROG
$(@F)	SORT.OBJ
$(@B)	SORT
$(@R)	C:\SOURCE\PROG\SORT
If $@ has the value SORT.OBJ without a preceding directory, the value of $(@R) is SORT, and the value of $(@D) is a period ( . ) to represent the current directory.

The following example uses the F modifier to specify a file of the same name in the current directory:

# Files in objects directory depend on versions in current directory
DIR = c:\objects
$(DIR)\a.obj $(DIR)\b.obj $(DIR)\c.obj : $$(@F)
    COPY $(@F) $@

Note  For another way to represent components of a filename, see »Filename-Parts Syntax«.


Recursion Macros (NMAKE)
  Recursion Macros

There are three macros that you can use when you want to call NMAKE recursively from within a makefile. These macros can make recursion more efficient.

MAKE

Defined as the name that you specified to the operating system when you ran NMAKE; this name is NMAKE unless you have renamed the utility file. Use this macro to call NMAKE recursively. It is recommended that you do not redefine MAKE.

MAKEDIR

Defined as the current directory when NMAKE was called.

MAKEFLAGS

Defined as the NMAKE options currently in effect. To pass these options when you call NMAKE recursively, specify /$(MAKEFLAGS) with the NMAKE call. You cannot redefine MAKEFLAGS. To change the /D, /I, /N, and /S options within a makefile, use the preprocessing directive !CMDSWITCHES. (See »Preprocessing Directives«.) To add other options to the ones already in effect for NMAKE when recursing, specify them as part of the recursion command.

Calling NMAKE Recursively

In a commands block, you can specify a call to NMAKE itself and start a new NMAKE session. Either invoke the MAKE macro as $(MAKE) or specify NMAKE literally. The called NMAKE session is independent from the original session.

Environment-variable macros and information in TOOLS.INI are available to the recursive session. For information on making macros available to the called NMAKE, see »Macros in Recursion«.

Inference rules defined in the makefile are not passed to the called NMAKE session. Settings for .SUFFIXES and .PRECIOUS are also not inherited. However, you can make .SUFFIXES, .PRECIOUS, and all inference rules available to the recursive call either by specifying them in TOOLS.INI or by placing them in a file that is specified in an !INCLUDE directive in the makefile for each NMAKE session.

Example

The MAKE macro is useful for building different versions of a program. The following makefile calls NMAKE recursively to build targets in the \VERS1 and \VERS2 directories.

all : vers1 vers2

vers1 :
    cd \vers1
    $(MAKE) /$(MAKEFLAGS)
    cd ..

vers2 :
    cd \vers2
    $(MAKE) /$(MAKEFLAGS) /F vers2.mak
    cd ..

If the dependency containing vers1 as a target is executed, NMAKE performs the commands to change to the \VERS1 directory and call itself recursively using the MAKEFILE in that directory. If the dependency containing vers2 as a target is executed, NMAKE changes to the \VERS2 directory and calls itself using the file VERS2.MAK in that directory.


Command Macros (NMAKE)
  Command Macros

NMAKE predefines several macros to represent commands for Microsoft products. You can use these macros as commands in either a description block or an inference rule; they are automatically used in NMAKE's predefined inference rules. (See »Inference Rules«.) You can redefine these macros to represent part or all of a command line, including options.

AS

Defined as ml, the command to run the Microsoft Macro Assembler

BC

Defined as bc, the command to run the Microsoft Basic Compiler

CC

Defined as cl, the command to run the Microsoft C Compiler

COBOL

Defined as cobol, the command to run the Microsoft COBOL Compiler

CPP

Defined as cl, the command to run the Microsoft C++ Compiler

CXX

Defined as cl, the command to run the Microsoft C++ Compiler

FOR

Defined as fl, the command to run the Microsoft FORTRAN Compiler

PASCAL

Defined as pl, the command to run the Microsoft Pascal Compiler

RC

Defined as rc, the command to run the Microsoft Resource Compiler

Options Macros

The following macros represent options to be passed to the commands for invoking the Microsoft language compilers. These macros are used automatically in the predefined inference rules. (See »Predefined Inference Rules«.) By default, these macros are undefined. You can define them to mean the options you want to pass to the compilers, and you can use these macros in commands in description blocks and inference rules. As with all macros, the options macros can be used even if they are undefined; a macro that is undefined or defined to be a null string generates a null string where it is used.

AFLAGS

Passes options to the Microsoft Macro Assembler

BFLAGS

Passes options to the Microsoft Basic Compiler

CFLAGS

Passes options to the Microsoft C Compiler

COBFLAGS

Passes options to the Microsoft COBOL Compiler

CPPFLAGS

Passes options to the Microsoft C++ Compiler

CXXFLAGS

Passes options to the Microsoft C++ Compiler

FFLAGS

Passes options to the Microsoft FORTRAN Compiler

PFLAGS

Passes options to the Microsoft Pascal Compiler

RFLAGS

Passes options to the Microsoft Resource Compiler


Substitution Within Macros (NMAKE)
  Substitution Within Macros

Just as macros allow you to substitute text in a makefile, you can also substitute text within a macro itself. The substitution applies only to the current use of the macro and does not modify the original macro definition. To substitute text within a macro, use the following syntax:

$(macroname:string1=string2)

Every occurrence of string1 is replaced by string2 in the macro macroname. Do not put any spaces or tabs before the colon. Spaces that appear after the colon are interpreted as part of the string in which they occur. If string2 is a null string, all occurrences of string1 are deleted from the macroname macro.

Macro substitution is literal and case sensitive. This means that the case as well as the characters in string1 must match the target string in the macro exactly, or the substitution is not performed. This also means that string2 is substituted exactly as it is specified. Because substitution is literal, the strings cannot contain macro expansions.

Examples

The following makefile illustrates macro substitution:

SOURCES = project.c one.c two.c

project.exe : $(SOURCES:.c=.obj)
    LINK $**

The predefined macro $** stands for the names of all the dependent files (See »Filename Macros«.) When this makefile is run, NMAKE executes the following command:

LINK project.obj one.obj two.obj

The macro substitution does not alter the SOURCES macro definition; if it is used again elsewhere in the makefile, SOURCES has its original value as it was defined.

If the macro OBJS is defined as

OBJS = ONE.OBJ TWO.OBJ THREE.OBJ

you can replace each space in the defined value of OBJS with a space, followed by a plus sign, followed by a newline character, by using

$(OBJS: = +^
)

The caret ( ^ ) tells NMAKE to treat the end of the line as a literal newline character. The expanded macro after substitution is:

ONE.OBJ +
TWO.OBJ +
THREE.OBJ

This example is useful for creating response files.


Substitution Within Predefined Macros (NMAKE)
  Substitution Within Predefined Macros

You can also substitute text in any predefined macro (except $$@) using the same syntax as for other macros.

The command in the following description block makes a substitution within the predefined macro $@, which represents the full name of the current target. Note that although $@ is a single-character macro, when it is used in a substitution, it must be enclosed in parentheses.

target.abc : depend.xyz
    echo $(@:targ=blank)

NMAKE substitutes blank for targ in the target, resulting in the string blanket.abc. If dependent depend.xyz has a later time stamp than target target.abc, then NMAKE executes the command

echo blanket.abc


Environment-Variable Macros (NMAKE)
  Environment-Variable Macros

When NMAKE executes, it inherits macro definitions equivalent to every environment variable that existed before the start of the NMAKE session. If a variable such as LIB or INCLUDE has been set in the operating-system environment, you can use its value as if you had specified an NMAKE macro with the same name and value. The inherited macro names are converted to uppercase. Inheritance occurs before preprocessing. The /E option causes macros inherited from environment variables to override any macros with the same name in the makefile.

You can redefine environment-variable macros the same way that you define or redefine other macros. Changing a macro does not change the corresponding environment variable; to change the variable, use a SET command. Also, using the SET command to change an environment variable in an NMAKE session does not change the corresponding macro; to change the macro, use a macro definition.

If an environment variable has not been set in the operating-system environment, it cannot be set using a macro definition. However, you can use a SET command in the NMAKE session to set the variable. The variable is then in effect for the rest of the NMAKE session unless redefined or cleared by a later SET command. A SET definition that appears in a makefile does not create a corresponding macro for that variable name; if you want a macro for an environment variable that is created during an NMAKE session, you must explicitly define the macro in addition to setting the variable.

If an environment variable is defined as a string that would be syntactically incorrect in a makefile, NMAKE does not create a macro from that variable. No warning is generated.

Warning  If an environment variable contains a dollar sign ($), NMAKE interprets it as the beginning of a macro invocation. The resulting macro expansion can cause unexpected behavior and possibly an error.

Example

The following makefile redefines the environment-variable macro called LIB:

LIB = c:\tools\lib

sample.exe : sample.obj
    LINK sample

No matter what value the environment variable LIB had before, it has the value c:\tools\lib when NMAKE executes the LINK command in this description block. Redefining the inherited macro does not affect the original environment variable; when NMAKE terminates, LIB still has its original value.

If LIB is not defined before the NMAKE session, the LIB macro definition in the preceding example does not set a LIB environment variable for the LINK command. To do this, use the following makefile:

sample.exe : sample.obj
    SET LIB=c:\tools.lib
    LINK sample


Macros in Recursion (NMAKE)
  Macros in Recursion

When NMAKE is called recursively, the only macros that are inherited by the called NMAKE are those defined on the command line or in environment variables. Macros defined in the makefile are not inherited when NMAKE is called recursively. There are several ways to pass macros to a recursive NMAKE session:

•	Use the SET command before the recursive call to set an environment variable before the called NMAKE session.

•	Define a macro on the command line for the recursive call.

•	Define a macro in the TOOLS.INI file. Each time NMAKE is recursively called, it reads TOOLS.INI.


Precedence Among Macro Definitions (NMAKE)
  Precedence Among Macro Definitions

If you define the same macro name in more than one place, NMAKE uses the macro with the highest precedence. The precedence from highest to lowest is as follows:

1.	A macro defined on the command line

2.	A macro defined in a makefile or include file

3.	An inherited environment-variable macro

4.	A macro defined in the TOOLS.INI file

5.	A predefined macro, such as CC and AS

The /E option causes macros inherited from environment variables to override any macros with the same name in the makefile. The !UNDEF directive in a makefile overrides a macro defined on the command line.


Inference Rules (NMAKE)
  Inference Rules

Inference rules are templates that define how a file with one extension is created from a file with another extension. NMAKE uses inference rules to supply commands for updating targets and to infer dependents for targets. In the dependency tree, inference rules cause targets to have inferred dependents as well as explicitly specified dependents; see »Inferred Dependents«. The .SUFFIXES list determines priorities for applying inference rules; see »Dot Directives«.Inference rules provide a convenient shorthand for common operations. For instance, you can use an inference rule to avoid repeating the same command in several description blocks. You can define your own inference rules or use predefined inference rules. Inference rules can be specified in the makefile or in TOOLS.INI.

Inference rules can be used in the following situations:

•	If NMAKE encounters a description block that has no commands, it checks the .SUFFIXES list and the files in the current or specified directory and then searches for an inference rule that matches the extensions of the target and an existing dependent file with the highest possible .SUFFIXES priority.

•	If a dependent file doesn't exist and is not listed as a target in another description block, NMAKE looks for an inference rule that shows how to create the missing dependent from another file with the same base name.

•	If a target has no dependents and its description block has no commands, NMAKE can use an inference rule to create the target.

•	If a target is specified on the command line and there is no makefile (or no mention of the target in the makefile), inference rules are used to build the target.

If a target is used in more than one single-colon dependency, an inference rule might not be applied as expected; see »Accumulating Targets in Dependencies«.

The following topics are included in this section:

•	»Inference Rule Syntax«

•	»Inference Rule Search Paths«

•	»User-Defined Inference Rules«

•	»Predefined Inference Rules«

•	»Inferred Dependents«

•	»Precedence Among Inference Rules«


Inference Rule Syntax (NMAKE)
  Inference Rule Syntax

To define an inference rule, use the following syntax:

.fromext.toext:
commands

The first line lists two extensions: fromext represents the extension of a dependent file, and toext represents the extension of a target file. Extensions are not case sensitive. Macros can be invoked to represent fromext and toext; the macros are expanded during preprocessing.

The period ( . ) preceding fromext must appear at the beginning of the line. The colon ( : ) can be preceded by zero or more spaces or tabs; it can be followed only by spaces or tabs, a semicolon ( ; ) to specify a command, a number sign
( # ) to specify a comment, or a newline character. No other spaces are allowed.

The rest of the inference rule gives the commands to be run if the dependency is out-of-date. Use the same rules for commands in inference rules as in description blocks. (See »Commands«.)

An inference rule can be used only when a target and dependent have the same base name. You cannot use a rule to match multiple targets or dependents. For example, you cannot define an inference rule that replaces several modules in a library because all but one of the modules must have a different base name from the target library.

Inference rules can exist only for dependents with extensions that are listed in the .SUFFIXES directive. (For information on .SUFFIXES, see .) If an out-of-date dependency does not have a commands block, and if the .SUFFIXES list contains the extension of the dependent, NMAKE looks for an inference rule matching the extensions of the target and of an existing file in the current or specified directory. If more than one rule matches existing dependent files, NMAKE uses the order of the .SUFFIXES list to determine which rule to invoke. Priority in the list descends from left to right. NMAKE may invoke a rule for an inferred dependent even if an explicit dependent is specified; for more information, see »Inferred Dependents«.

Inference rules tell NMAKE how to build a target specified on the command line if no makefile is provided or if the makefile does not have a dependency containing the specified target. When a target is specified on the command line and NMAKE cannot find a description block to run, it looks for an inference rule to tell it how to build the target. You can run NMAKE without a makefile if the inference rules that are predefined or defined in TOOLS.INI are all you need for your build.


Inference Rule Search Paths (NMAKE)
  Inference Rule Search Paths

The inference-rule syntax described previously tells NMAKE to look for the specified files in the current directory. You can also specify directories to be searched by NMAKE when it looks for files. An inference rule that specifies paths has the following syntax:

{frompath}.fromext{topath}.toext:
commands

No spaces are allowed. The frompath directory must match the directory specified for the dependent file; similarly, topath must match the target's directory specification. For NMAKE to apply an inference rule to a dependency, the paths in the dependency line must match the paths specified in the inference rule exactly. For example, if the current directory is called PROJ, the inference rule

{..\proj}.exe{..\proj}.obj:

does not apply to the dependency

project1.exe : project1.obj

If you use a path on one extension in the inference rule, you must use paths on both. You can specify the current directory by either a period ( . ) or an empty pair of braces ( { } ).

You can specify only one path for each extension in an inference rule. To specify more than one path, you must create a separate inference rule for each path.

Macros can be invoked to represent frompath and topath; the macros are expanded during preprocessing.


User-Defined Inference Rules (NMAKE)
  User-Defined Inference Rules

The following examples illustrate several ways to write inference rules.

Examples

The following makefile contains an inference rule and a minimal description block:

.c.obj:
    cl /c $<

sample.obj :

The inference rule tells NMAKE how to build a .OBJ file from a .C file. The predefined macro $< represents the name of a dependent that has a later time stamp than the target. The description block lists only a target, SAMPLE.OBJ; there is no dependent or command. However, given the target's base name and extension, plus the inference rule, NMAKE has enough information to build the target.

After checking to be sure that .c is one of the extensions in the .SUFFIXES list, NMAKE looks for a file with the same base name as the target and with the .C extension. If SAMPLE.C exists (and no files with higher-priority extensions exist), NMAKE compares its time to that of SAMPLE.OBJ. If SAMPLE.C has changed more recently, NMAKE compiles it using the CL command listed in the inference rule:

    cl /c sample.c

The following inference rule compares a .C file in the current directory with the corresponding .OBJ file in another directory:

{.}.c{c:\objects}.obj:
    cl /c $<;

The path for the .C file is represented by a period. A path for the dependent extension is required because one is specified for the target extension.

This inference rule matches a dependency line containing the same combination of paths, such as:

c:\objects\test.obj : test.c

This rule does not match a dependency line such as:

test.obj : test.c

In this case, NMAKE uses the predefined inference rule for .c.obj when building the target.

The following inference rule uses macros to specify paths in an inference rule:

C_DIR = proj1src
OBJ_DIR = proj1obj
{$(C_DIR)}.c{$(OBJ_DIR)}.obj:
    cl /c $

If the macros are redefined, NMAKE uses the definition that is current at that point during preprocessing. To reuse an inference rule with different macro definitions, you must repeat the rule after the new definition:

C_DIR = proj1src
OBJ_DIR = proj1obj
{$(C_DIR)}.c{$(OBJ_DIR)}.obj:
    cl /c $<
C_DIR = proj2src
OBJ_DIR = proj2obj
{$(C_DIR)}.c{$(OBJ_DIR)}.obj:
    cl /c $<


Predefined Inference Rules (NMAKE)
  Predefined Inference Rules

NMAKE provides predefined inference rules containing commands for creating object, executable, and resource files. Table 5.1 describes the predefined inference rules.

Table 5.1    Predefined Inference Rules

Rule	Command	Default action
.asm.exe	$(AS) $(AFLAGS) $*.asm	ML $*.ASM
.asm.obj	$(AS) $(AFLAGS) /c $*.asm	ML /c $*.ASM
.c.exe	$(CC) $(CFLAGS) $*.c	CL $*.C
.c.obj	$(CC) $(CFLAGS) /c $*.c	CL /c $*.C
.cpp.exe	$(CPP) $(CPPFLAGS) $*.cpp	CL $*.CPP
.cpp.obj	$(CPP) $(CPPFLAGS) /c $*.cpp	CL /c $*.CPP
.cxx.exe	$(CXX) $(CXXFLAGS) $*.cxx	CL $*.CXX
.cxx.obj	$(CXX) $(CXXFLAGS) /c $*.cxx	CL /c $*.CXX
.bas.obj	$(BC) $(BFLAGS) $*.bas;	BC $*.BAS;
.cbl.exe	$(COBOL) $(COBFLAGS) $*.cbl, $*.exe;	COBOL $*.CBL, $*.EXE;
.cbl.obj	$(COBOL) $(COBFLAGS) $*.cbl;	COBOL $*.CBL;
.for.exe	$(FOR) $(FFLAGS) $*.for	FL $*.FOR
.for.obj	$(FOR) /c $(FFLAGS) $*.for	FL /c $*.FOR
.pas.exe	$(PASCAL) $(PFLAGS) $*.pas	PL $*.PAS
.pas.obj	$(PASCAL) /c $(PFLAGS) $*.pas	PL /c $*.PAS
.rc.res	$(RC) $(RFLAGS) /r $*	RC /r $*
For example, assume you have the following makefile:

sample.exe :

This description block lists a target without any dependents or commands. NMAKE looks at the target's extension (.EXE) and searches for an inference rule that describes how to create an .EXE file. Table 0.1 shows that more than one inference rule exists for building an .EXE file. NMAKE uses the order of the extensions appearing in the .SUFFIXES list to determine which rule to invoke. It then looks in the current or specified directory for a file that has the same base name as the target sample and one of the extensions in the .SUFFIXES list; it checks the extensions one by one until it finds a matching dependent file in the directory.

For example, if a file called SAMPLE.FOR exists, NMAKE applies the .for.exe inference rule. If both SAMPLE.C and SAMPLE.FOR exist, and if .c appears before .for in the .SUFFIXES list, NMAKE instead uses the .c.exe inference rule to compile SAMPLE.C and links the resulting file SAMPLE.OBJ to create SAMPLE.EXE.

Note  By default, the options macros (AFLAGS, CFLAGS, and so on) are undefined. As explained in »Using Macros«, this causes no problem; NMAKE replaces an undefined macro with a null string. Because the predefined options macros are included in the inference rules, you can define these macros and have their assigned values passed automatically to the predefined inference rules.


Inferred Dependents (NMAKE)
  Inferred Dependents

NMAKE can assume an "inferred dependent" for a target if there is an applicable inference rule. An inference rule is applicable if:

•	The toext in the rule matches the extension of the target being evaluated.

•	The fromext in the rule matches the extension of a file that has the same base name as the target and that exists in the current or specified directory.

•	The fromext is in the .SUFFIXES list.

•	No other fromext in a matching rule is listed in .SUFFIXES with a higher priority.

•	No explicitly specified dependent has a higher priority extension.

If an existing dependent matches an inference rule and has an extension with a higher .SUFFIXES priority, NMAKE does not infer a dependent.

NMAKE does not necessarily execute the commands block in an inference rule for an inferred dependent. If the target's description block contains commands, NMAKE executes the description block's commands and not the commands in the inference rule. The effect of an inferred dependent is illustrated in the following example:

project.obj :
    cl /Zi /c project.c

If a makefile contains this description block and if the current directory contains a file named PROJECT.C and no other files, NMAKE uses the predefined inference rule for .c.obj to infer the dependent project.c. It does not execute the predefined rule's command, cl /c project.c. Instead, it runs the command specified in the makefile.

Inferred dependents can cause unexpected side effects. In the following examples, assume that both PROJECT.ASM and PROJECT.C exist and that .SUFFIXES contains the default setting. If the makefile contains

project.obj : project.c

NMAKE infers the dependent project.asm ahead of project.c because .SUFFIXES lists .asm before .c and because a rule for .asm.obj exists. If either PROJECT.ASM or PROJECT.C is out-of-date, NMAKE executes the commands in the rule for .asm.obj.

However, if the dependency in the preceding example is followed by a commands block, NMAKE executes those commands and not the commands in the inference rule for the inferred dependent.

Another side effect occurs because NMAKE builds a target if it is out-of-date with respect to any of its dependents, whether explicitly specified or inferred. For example, if PROJECT.OBJ is up-to-date with respect to PROJECT.C but not with respect to PROJECT.ASM, and if the makefile contains

project.obj : project.c
    cl /Zi /c project.c

NMAKE infers the dependent project.asm and updates the target using the command specified in this description block.


Precedence Among Inference Rules (NMAKE)
  Precedence Among Inference Rules

If the same inference rule is defined in more than one place, NMAKE uses the rule with the highest precedence. The precedence from highest to lowest is as follows:

1.	An inference rule defined in the makefile. If more than one rule is defined, the last rule applies.

2.	An inference rule defined in the TOOLS.INI file. If more than one rule is defined, the last rule applies.

3.	A predefined inference rule.

User-defined inference rules always override predefined inference rules. NMAKE uses a predefined inference rule only if no user-defined inference rule exists for a given target and dependent.

If two inference rules match a target's extension and a dependent is not specified, NMAKE uses the inference rule whose dependent's extension appears first in the .SUFFIXES list.


Directives (NMAKE)
  Directives

NMAKE provides several ways to control the NMAKE session through dot directives and preprocessing directives. Directives are instructions to NMAKE that are placed in the makefile or in TOOLS.INI. NMAKE interprets dot directives and preprocessing directives and applies the results to the makefile before processing dependencies and commands.

This section includes the following topics:

•	»Dot Directives«

•	»Preprocessing Directives«

•	»Expressions in Preprocessing«


Dot Directives (NMAKE)
  Dot Directives

Dot directives must appear outside a description block and must appear at the beginning of a line. Dot directives begin with a period ( . ) and are followed by a colon ( : ). Spaces and tabs can precede and follow the colon. These directive names are case sensitive and must be uppercase.

.IGNORE :

Ignores nonzero exit codes returned by programs called from the makefile. By default, NMAKE halts if a command returns a nonzero exit code. This directive affects the makefile from the place it is specified to the end of the file. To turn it off again, use the !CMDSWITCHES preprocessing directive. To ignore the exit code for a single command, use the dash (-) command modifier. To ignore exit codes for an entire file, invoke NMAKE with the /I option.

.PRECIOUS : targets

Tells NMAKE not to delete targets if the commands that build them are interrupted. This directive has no effect if a command is interrupted and handles the interrupt by deleting the file. Separate the target names with one or more spaces or tabs. By default, NMAKE deletes the target if building was interrupted by CTRL+C or CTRL+BREAK. Multiple specifications are cumulative; each use of .PRECIOUS applies to the entire makefile.

.SILENT :

Suppresses display of the command lines as they are executed. By default, NMAKE displays the commands it invokes. This directive affects the makefile from the place it is specified to the end of the file. To turn it off again, use the !CMDSWITCHES preprocessing directive. To suppress display of a single command line, use the @ command modifier. To suppress the command display for an entire file, invoke NMAKE with the /S option.

.SUFFIXES : list

Lists file suffixes (extensions) for NMAKE to try to match when it attempts to apply an inference rule. (For details about using .SUFFIXES, see »Inference Rules«.) The list is predefined as follows:

.SUFFIXES : .exe .obj .asm .c .cpp .cxx .bas .cbl .for .pas .res .rc

To add additional suffixes to the end of the list, specify

.SUFFIXES : suffixlist

where suffixlist is a list of the additional suffixes, separated by one or more spaces or tabs. To clear the list, specify

.SUFFIXES :

without extensions. To change the list order or to specify an entirely new list, you must clear the list and specify a new setting. To see the current setting, run NMAKE with the /P option.


Preprocessing Directives (NMAKE)
  Preprocessing Directives

NMAKE preprocessing directives are similar to compiler preprocessing directives. You can use several of the directives to conditionally process the makefile. With other preprocessing directives you can display error messages, include other files, undefine a macro, and turn certain options on or off. NMAKE reads and executes the preprocessing directives before processing the makefile as a whole.

Preprocessing directives begin with an exclamation point ( ! ), which must appear at the beginning of the line. Zero or more spaces or tabs can appear between the exclamation point and the directive keyword; this allows indentation for readability. These directives (and their keywords and operators) are not case sensitive.

!CMDSWITCHES {+| −}opt...

Turns on or off one or more options.  Specify an operator, either a plus sign ( + ) to turn options on or a minus sign (-) to turn options off, followed by one or more letters representing options. Letters are not case sensitive. Do not specify the slash ( / ). Separate the directive from the operator by one or more spaces or tabs; no space can appear between the operator and the options. To turn on some options and turn off other options, use separate specifications of the !CMDSWITCHES directives.

All options with the exception of /F, /HELP, /NOLOGO, /X, and /? can appear in !CMDSWITCHES specifications in TOOLS.INI. In a makefile, only the letters D, I, N, and S can be specified. If !CMDSWITCHES is specified within a description block, the changes do not take effect until the next description block. This directive updates the MAKEFLAGS macro; the changes are inherited during recursion if MAKEFLAGS is specified.

!ERROR text

Displays text to standard error in the message for error U1050, then stops the NMAKE session. This directive stops the build even if /K, /I, .IGNORE, !CMDSWITCHES, or the dash (-) command modifier is used. Spaces or tabs before text are ignored.

!MESSAGE text

Displays text to standard output, then continues the NMAKE session. Spaces or tabs before text are ignored.

!INCLUDE [<]filename[>]

Reads and evaluates the file filename as a makefile before continuing with the current makefile. NMAKE first looks for filename in the current directory if filename is specified without a path; if a path is specified, NMAKE looks in the specified directory. Next, if the !INCLUDE directive is itself contained in a file that is included, NMAKE looks for filename in the parent file's directory; this search is recursive, ending with the original makefile's directory. Finally, if filename is enclosed by angle brackets (< >), NMAKE searches in the directories specified by the INCLUDE macro. The INCLUDE macro is initially set to the value of the INCLUDE environment variable.

!IF constantexpression

Processes the statements between the !IF and the next !ELSE or !ENDIF if constantexpression evaluates to a nonzero value.

!IFDEF macroname

Processes the statements between the !IFDEF and the next !ELSE or !ENDIF if macroname is defined. NMAKE considers a macro with a null value to be defined.

!IFNDEF macroname

Processes the statements between the !IFNDEF and the next !ELSE or !ENDIF if macroname is not defined.

!ELSE [IF constantexpression | IFDEF macroname | IFNDEF macroname]

Processes the statements between the !ELSE and the next !ENDIF if the preceding !IF, !IFDEF, or !IFNDEF statement evaluated to zero. The optional keywords give further control of preprocessing.

!ELSEIF

Synonym for !ELSE IF.

!ELSEIFDEF

Synonym for !ELSE IFDEF.

!ELSEIFNDEF

Synonym for !ELSE IFNDEF.

!ENDIF

Marks the end of an !IF, !IFDEF, or !IFNDEF block. Anything following !ENDIF on the same line is ignored.

!UNDEF macroname

Undefines a macro by removing macroname from NMAKE's symbol table. (For more information, see »Null Macros and Undefined Macros«.)

Example

The following set of directives

!IF
!ELSE
!   IF
!   ENDIF
!ENDIF

is equivalent to the set of directives

!IF
!ELSE IF
!ENDIF


Expressions in Preprocessing (NMAKE)
  Expressions in Preprocessing

The constantexpression used with the !IF or !ELSE IF directives can consist of integer constants, string constants, or program invocations. You can group expressions by enclosing them in parentheses. NMAKE treats numbers as decimals unless they start with 0 (octal) or 0x (hexadecimal).

Expressions in NMAKE use C-style signed long integer arithmetic; numbers are represented in 32-bit two's-complement form and are in the range −2147483648 to 2147483647.

Two unary operators evaluate a condition and return a logical value of true (1) or false (0):

DEFINED (macroname)

Evaluates to true if macroname is defined. In combination with the !IF or !ELSE IF directives, this operator is equivalent to the !IFDEF or !ELSE IFDEF directives. However, unlike these directives, DEFINED can be used in complex expressions using binary logical operators.

EXIST (path)

Evaluates to true if path exists. EXIST can be used in complex expressions using binary logical operators. If path contains spaces (allowed in some file systems), enclose it in double quotation marks.

Integer constants can use the unary operators for numerical negation (-), one's complement ( ~ ), and logical negation ( ! ).

Constant expressions can use any binary operator listed in Table 5.2. To compare two strings, use the equality (==) operator and the inequality (!=) operator. Enclose strings in double quotation marks.

Table 5.2 Binary Operators for Preprocessing

Operator	Description
+	Addition
−	Subtraction
*	Multiplication
/	Division
%	Modulus
&	Bitwise AND
|	Bitwise OR
^	Bitwise XOR
&&	Logical AND
||	Logical OR
<<	Left shift
>>	Right shift
==	Equality
!=	Inequality
<	Less than
>	Greater than
<=	Less than or equal to
>=	Greater than or equal to
Example

The following example shows how preprocessing directives can be used to control whether the linker inserts debugging information into the .EXE file:

!INCLUDE <infrules.txt>
!CMDSWITCHES +D
winner.exe : winner.obj
!IF DEFINED(debug)
!    IF "$(debug)"=="y"
         LINK /DEBUG winner.obj
!    ELSE
         LINK winner.obj
!    ENDIF
!ELSE
!    ERROR Macro named debug is not defined.
!ENDIF

In this example, the !INCLUDE directive inserts the INFRULES.TXT file into the makefile. The !CMDSWITCHES directive sets the /D option, which displays the time stamps of the files as they are checked. The !IF directive checks to see if the macro debug is defined. If it is defined, the next !IF directive checks to see if it is set to y. If it is, NMAKE reads the LINK command with the /CO option; otherwise, NMAKE reads the LINK command without /CO. If the debug macro is not defined, the !ERROR directive prints the specified message and NMAKE stops.

Executing a Program in Preprocessing

You can invoke a program or command from within NMAKE and use its exit code during preprocessing. NMAKE executes the command during preprocessing, and it replaces the specification in the makefile with the command's exit code. A nonzero exit code usually indicates an error. You can use this value in an expression to control preprocessing.

Specify the command, including any arguments, within brackets ( [ ] ). You can use macros in the command specification; NMAKE expands the macro before executing the command.

Example

The following part of a makefile tests the space on disk before continuing the NMAKE session:

!IF [c:\util\checkdsk] != 0
!    ERROR Not enough disk space; NMAKE terminating.
!ENDIF


  Sequence of NMAKE Operations

When you write a complex makefile, it can be helpful to know the sequence in which NMAKE performs operations. This section describes those operations and their order.

When you run NMAKE from the command line, NMAKE's first task is to find the makefile:

1.	If the /F option is used, NMAKE searches for the filename specified in the option. If NMAKE cannot find that file, it returns an error.

2.	If the /F option is not used, NMAKE looks for a file named MAKEFILE in the current directory. If there are targets on the command line, NMAKE builds them according to the instructions in MAKEFILE. If there are no targets on the command line, NMAKE builds only the first target it finds in MAKEFILE.

3.	If NMAKE cannot find MAKEFILE, NMAKE looks for target files on the command line and attempts to build them using inference rules (either defined by the user in TOOLS.INI or predefined by NMAKE). If no target is specified, NMAKE returns an error.

NMAKE then assigns macro definitions with the following precedence (highest to lowest):

1.	Macros defined on the command line

2.	Macros defined in a makefile or include file

3.	Inherited macros

4.	Macros defined in the TOOLS.INI file

5.	Predefined macros (such as CC and RFLAGS)

Macro definitions are assigned first in order of priority and then in the order in which NMAKE encounters them. For example, a macro defined in an include file overrides a macro with the same name from the TOOLS.INI file. Note that a macro within a makefile can be redefined; a macro is valid from the point it is defined until it is redefined or undefined.

NMAKE also assigns inference rules, using the following precedence (highest to lowest):

1.	Inference rules defined in a makefile or include file

2.	Inference rules defined in the TOOLS.INI file

3.	Predefined inference rules (such as .c.obj)

You can use command-line options to change some of these priorities:

•	The /E option allows macros inherited from the environment to override macros defined in the makefile.

•	The /R option tells NMAKE to ignore macros and inference rules that are defined in TOOLS.INI or are predefined.

Next, NMAKE evaluates any preprocessing directives. If an expression for conditional preprocessing contains a program in brackets ( [ ] ), the program is invoked during preprocessing and the program's exit code is used in the expression. If an !INCLUDE directive is specified for a file, NMAKE preprocesses the included file before continuing to preprocess the rest of the makefile. Preprocessing determines the final makefile that NMAKE reads.

NMAKE is now ready to update the targets. If you specified targets on the command line, NMAKE updates only those targets. If you did not specify targets on the command line, NMAKE updates only the first target in the makefile. If you specify a pseudotarget, NMAKE always updates the target. If you use the /A option, NMAKE always updates the target, even if the file is not out-of-date.

NMAKE updates a target by comparing its time stamp to the time stamp of each dependent of that target. A target is out-of-date if any dependent has a later time stamp; if the /B option is specified, a target is out-of-date if any dependent has a later or equal time stamp.

If the dependents of the targets are themselves out-of-date or do not exist, NMAKE updates them first. If the target has no explicit dependent, NMAKE looks for an inference rule that matches the target. If a rule exists, NMAKE updates the target using the commands given with the inference rule. If more than one rule applies to the target, NMAKE uses the priority in the .SUFFIXES list to determine which inference rule to use.

NMAKE normally stops processing the makefile when a command returns a nonzero exit code. In addition, if NMAKE cannot tell whether the target was built successfully, it deletes the target. The /I command-line option, .IGNORE directive, !CMDSWITCHES directive, and dash (-) command modifier all tell NMAKE to ignore error codes and attempt to continue processing. The /K option tells NMAKE to continue processing unrelated parts of the build if an error occurs. The .PRECIOUS directive prevents NMAKE from deleting a partially created target if you interrupt the build with CTRL+C or CTRL+BREAK. You can document errors by using the !ERROR directive to print descriptive text. The directive causes NMAKE to print some text and then stop the build.


  NMAKE Exit Codes

NMAKE returns an exit code to the operating system or the calling program. A value of 0 indicates execution of NMAKE with no errors. Warnings return exit code 0.

Code	Meaning
0	No error
1	Incomplete build (issued only when /K is used)
2	Program error, possibly due to one of the following:
	• A syntax error in the makefile
	• An error or exit code from a command
	• An interruption by the user
4	System error—out of memory
255	Target is not up-to-date (issued only when /Q is used)


Using Other Tools
  Chapter 6  Using Other Tools

This chapter describes the Microsoft Browser Database Maintenance Utility (BSCMAKE) version 2.51, the Microsoft COFF Binary File Dumper (DUMPBIN.EXE) version 1.00, and the Microsoft Resource Compiler (RC.EXE) version 3.20. Each of these tools are used with the Visual C++ development system for Windows NT.

The following topics are included:

•	»Using BSCMAKE«

•	»Using DUMPBIN«

•	»Using the Resource Compiler«


  Using BSCMAKE

BSCMAKE builds a browser database (.BSC file) from .SBR files created during compilation. You use a browser database with the Microsoft Source Browser, a feature of Visual Workbench. As a navigation tool, the browser gives you the means to move around quickly in a large project and find pieces of code in your source and include files. As an interactive program database, the browser can answer questions about where functions are invoked or where variables and types are used. The browser can also generate useful outlines, call trees, and cross-reference tables.

You can let Visual Workbench automatically create  a browser database or you can run BSCMAKE to build a database outside of Visual Workbench. When you tell Visual Workbench to create a browser database (.BSC file) for your program, Visual Workbench automatically calls BSCMAKE. You do not need to know how to run BSCMAKE if you create your database in Visual Workbench. However, you may want to read this section to understand the Browser Information choices available to modify the database. For information on how to create and use a browser database in Visual Workbench, see Chapter 4, "Using the Browser," in Visual Workbench User's Guide. If you build your program outside of Visual Workbench, you can still create a custom browser database that you can examine with the browser. Run BSCMAKE on the .SBR files that you created during compilation.


Building a Database (BSCMAKE)
  Building a Database

BSCMAKE can build a new database from newly created .SBR files. It can also maintain an existing database using .SBR files for object files that have changed since the last build. The following paragraphs describe how to create .SBR files and build a database.

This section includes the following topics:

•	»Preparing to Build a Database«

•	»How BSCMAKE Builds a Database«

•	»Methods for Increasing Efficiency«


Preparing to Build a Database (BSCMAKE)
  Preparing to Build a Database

The input files for BSCMAKE are .SBR files that you create when you compile or assemble your source files. When you build or update your browser database, all .SBR files for your project must be available on disk.

To create an .SBR file, specify the /FR or /Fr option to the CL compiler. The /FR option puts all possible information into the .SBR file. The /Fr option omits local symbols from the .SBR file. (If the .SBR file was created with all possible information, you can still omit local symbols by using BSCMAKE's /El option, described later in this chapter.) You can create an .SBR file without performing a full compile. For example, you can specify the /Zs option to CL to perform a syntax check and still generate an .SBR file if you specify /FR or /Fr.

Database building can be more efficient if the .SBR files are first packed to remove unreferenced definitions. The CL compiler automatically packs .SBR files. An unpacked .SBR file is required if you want to use the /Iu option with BSCMAKE to include unreferenced symbols in the browser database. If you want to prevent packing, specify CL's /Zn option.


How BSCMAKE Builds a Database (BSCMAKE)
  How BSCMAKE Builds a Database

BSCMAKE builds or rebuilds a database in the most efficient way it can. To avoid potential problems, it is important to understand the database-building process.

When BSCMAKE builds a database, it truncates the .SBR files to zero length. During a subsequent build of the same database, a zero-length (or empty) .SBR file tells BSCMAKE that the .SBR file has no new contribution to make. It lets BSCMAKE know that an update of that part of the database is not required and an incremental build will be sufficient. During every build (unless the /n option is specified), BSCMAKE first attempts to update the database incrementally by using only those .SBR files that have changed.

BSCMAKE looks for a .BSC file that has the name specified with the /o option. If /o is not specified, BSCMAKE looks for a file that has the base name of the first .SBR file and a .BSC extension. If the database exists, BSCMAKE performs an incremental build of the database using only the contributing .SBR files. If the database does not exist, BSCMAKE performs a full build using all .SBR files. The rules for builds are as follows:

•	For a full build to succeed, all specified .SBR files must exist and must not be truncated. If an .SBR file is truncated, you must rebuild it (by recompiling or assembling) before running BSCMAKE.

•	For an incremental build to succeed, the .BSC file must exist. All contributing .SBR files, even empty files, must exist and must be specified on the BSCMAKE command line. If you omit an .SBR file from the command line, BSCMAKE removes its contribution from the database.


Methods for Increasing Efficiency (BSCMAKE)
  Methods for Increasing Efficiency

The database-building process can require large amounts of time, memory, and disk space. However, you can reduce these requirements by creating a smaller database and by avoiding unreferenced definitions.

Making a Smaller Database

Smaller databases take less time to build, use less disk space, reduce the risk of BSCMAKE running out of memory, and run faster in the browser. You can use the following methods to create a smaller database:

•	Use BSCMAKE options to exclude information from the database.

•	Omit local symbols in one or more .SBR files when compiling or assembling.

•	If an object file does not contain information that you need for your current stage of debugging, omit its .SBR file when rebuilding the database.

Saving Build Time and Disk Space

Unreferenced definitions cause .SBR files to take up more disk space and cause BSCMAKE to run less efficiently. The CL compiler automatically packs .SBR files to remove unreferenced definitions. The /Zn option prevents this packing. You can increase efficiency of disk space and BSCMAKE speed by not using /Zn and allowing CL to pack the .SBR files.


  BSCMAKE Command Line

To run BSCMAKE, use the following command line:

BSCMAKE [options] sbrfiles

Options can appear only in the options field on the command line.

The sbrfiles field specifies one or more .SBR files created by a compiler or assembler. If you specify more than one file, separate the names with spaces or tabs. You must specify the extension; there is no default. You can specify a path with the filename, and you can use operating-system wildcards (* and ?).

During an incremental build, you can specify new .SBR files that were not part of the original build. If you want all contributions to remain in the database, you must specify all .SBR files (including truncated files) that were originally used to create the database. If you omit an .SBR file, that file's contribution to the database is removed.

Do not specify a truncated .SBR file for a full build. A full build requires contributions from all specified .SBR files. Before you perform a full build, recompile the project and create a new .SBR file for each empty file.

Example

The following command runs BSCMAKE to build a file called MAIN.BSC from three .SBR files:

BSCMAKE main.sbr file1.sbr file2.sbr


  BSCMAKE Command File

You can provide part or all of the command-line input in a command file, which is a text file that contains options and/or filenames. Specify the command file using the following syntax:

BSCMAKE @filename

Only one command file is allowed. You can specify a path with filename. Precede filename with an at sign (@). BSCMAKE does not assume an extension. You can specify additional sbrfiles on the command line after filename.In the command file, specify the input to BSCMAKE in the same order as you would on the command line. Separate the command-line arguments with one or more spaces, tabs, or newline characters.

Example

The following command calls BSCMAKE using a command file:

BSCMAKE @prog1.txt

The following is a sample command file:

/n /v /o main.bsc /El
/S (
toolbox.h
verdate.h c:\src\inc\screen.h
)
/Er ( HWND HpOfSbIb
LONG LPSTR
NEAR NULL
PASCAL
VOID
WORD
)
file1.sbr file2.sbr file3.sbr file4.sbr


  BSCMAKE Options

This section describes the options available for controlling BSCMAKE. Several options control the content of the database by excluding or including certain information. The exclusion options can allow BSCMAKE to run faster and may result in a smaller .BSC file. Option names are case sensitive (except for /HELP and /NOLOGO).

/Ei (filename...)

This option excludes the contents of the specified include files from the database. To specify multiple files, separate the names with spaces and enclose the list in parentheses. Parentheses are not necessary if you specify only one filename. Use /Ei along with the /Es option to exclude files not excluded by /Es.

/El

This option excludes local symbols. The default is to include local symbols in the database. For more information about local symbols, see »Preparing to Build a Database«.

/Em

This option excludes symbols in the body of macros. Use /Em to include only the names of macros in the database. The default is to include both the macro names and the result of the macro expansions.

/Er (symbol...)

This option excludes the specified symbols from the database. To specify multiple symbol names, separate the names with spaces and enclose the list in parentheses. Parentheses are not necessary if you specify only one symbol.

/Es

This option excludes from the database every include file specified with an absolute path or found in an absolute path specified in the INCLUDE environment variable. (Usually, these are the system include files, which contain a lot of information that you may not need in your database.) This option does not exclude files specified without a path or with relative paths or found in a relative path in INCLUDE. You can use the /Ei option along with /Es to exclude files that /Es does not exclude. If you want to exclude only some of the files that /Es excludes, use /Ei instead of /Es and list the files you want to exclude.

/HELP

Setting this option causes a summary of the BSCMAKE command-line syntax to display.

/Iu

This option includes unreferenced symbols. By default, BSCMAKE does not record any symbols that are defined but not referenced. If an .SBR file has been packed, this option has no effect for that input file because CL has already removed the unreferenced symbols.

/n

This option forces a nonincremental build. Use /n to force a full build of the database whether or not a .BSC file exists and to prevent .SBR files from being truncated.

/NOLOGO

This option suppresses the BSCMAKE copyright message.

/o filename

This option specifies a name for the database file. By default, BSCMAKE assumes that the database file has the base name of the first .SBR file and a .BSC extension.

/S (filename...)

This option tells BSCMAKE to process the specified include file the first time it is encountered and to exclude it otherwise. Use this option to save processing time when a file (such as a header, or .H, file for a .C source file) is included in several source files but is unchanged by preprocessing directives each time. You may also want to use this option if a file is changed in ways that are unimportant for the database you are creating. To specify multiple files, separate the names with spaces and enclose the list in parentheses. Parentheses are not necessary if you specify only one filename. If you want to exclude the file every time it is included, use the /Ei or /Es option.

/v

This option provides verbose output, which includes the name of each .SBR file being processed and information about the complete BSCMAKE run.

/?

This option displays a brief summary of BSCMAKE command-line syntax.

Example

The following command line tells BSCMAKE to do a full build of MAIN.BSC from three .SBR files. It also tells BSCMAKE to exclude duplicate instances of TOOLBOX.H:

BSCMAKE /n /S toolbox.h /o main.bsc file1.sbr file2.sbr file3.sbr


  BSCMAKE Exit Codes

BSCMAKE returns an exit code (also called return code or error code) to the operating system or the calling program. You can use the exit code to control the operation of batch files or makefiles. The exit codes are listed in Table 6.1.

Table 6.1    BSCMAKE Exit Codes

Code	Meaning
0	No error
1	Command-line error
4	Fatal error during database build


  Using DUMPBIN

DUMPBIN is a 32-bit tool that displays information about 32-bit Common Object File Format (COFF) binary files. DUMPBIN runs only from a command prompt. Visual Workbench does not provide controls for DUMPBIN. You can use DUMPBIN to examine the following kinds of COFF files: object files, standard libraries of COFF objects, executable files, and Dynamic-link libraries (DLLs).

The following topics are included in this section:

•	»DUMPBIN Command Line«

•	»DUMPBIN Options«


  DUMPBIN Command Line

To run DUMPBIN, use the following syntax:

DUMPBIN [options] files...

Specify one or more binary files, along with any options required to control the information. DUMPBIN displays the information to standard output. You can either redirect it to a file or use the /OUT option to specify a filename for the output.

When you run DUMPBIN on a file without specifying an option, DUMPBIN displays the /SUMMARY output.

When you type the command dumpbin without any other command-line input, DUMPBIN displays a usage statement that summarizes its options.


  DUMPBIN Options

An option consists of an option specifier, which is either a dash (-) or a forward slash (/), followed by the name of the option. Option names cannot be abbreviated. Some options take arguments, specified after a colon (:). No spaces or tabs are allowed within an option specification. Option names and their keyword or filename arguments are not case sensitive. Most options apply to all binary files; a few apply only to certain types of files. DUMPBIN has the following options:

/ALL

Setting this option causes DUMPBIN to display all available information except code disassembly. Use /DISASM to display disassembly. You can use /RAWDATA:NONE with /ALL to omit the raw binary details of the file.

/ARCHIVEMEMBERS

Setting this option causes DUMPBIN to display minimal information about member objects in a library.

/DISASM

Setting this option causes DUMPBIN to show disassembly of code sections, using symbols if present in the file.

/EXPORTS

This option causes DUMPBIN to list all definitions exported from an executable file or DLL.

/HEADERS

Setting this option causes DUMPBIN to display the file header and the header for each section. When used with a library, displays the header for each member object.

/IMPORTS

This option causes DUMPBIN to list all definitions imported to an executable file or DLL.

/LINENUMBERS

Setting this option causes DUMPBIN to show COFF line numbers. Line numbers exist in an object file if it was compiled with /Zi. An executable file or DLL contains COFF line numbers if it was linked with /DEBUG and /DEBUGTYPE:COFF.

/LINKERMEMBER[:{1|2}]

Setting this option causes DUMPBIN to list public symbols defined in a library. Specify the 1 argument to display symbols in object order, along with their offsets. Specify the 2 argument to display offsets and index numbers of objects, then list the symbols in alphabetical order along with the object index for each. To get both outputs, specify /LINKERMEMBER without the number argument.

/OUT:filename

This option specifies a filename for the output. By default, DUMPBIN displays the information to standard output.

/RAWDATA[:{BYTES|SHORTS|LONGS|NONE}[,number]]

Setting this option causes DUMPBIN to display the raw contents of each section in the file. The arguments control the format of the display, as follows:

Argument	Result
BYTES	The default. Contents are displayed in hexadecimal bytes, and also as ASCII if they have a printed representation.
SHORTS	Contents are displayed in hexadecimal words.
LONGS	Contents are displayed in hexadecimal longwords.
NONE	Raw data is suppressed. This is useful to control the output of /ALL.
number	Displayed lines are set to a width that holds number values per line.
/RELOCATIONS

Setting this option causes DUMPBIN to display any relocations in the object or image.

/SECTION:section

This option restricts the output to information on the specified section.

/SUMMARY

Setting this option causes DUMPBIN to display minimal information about sections, including total size .This option is the default if no other option is specified in a DUMPBIN command.

/SYMBOLS

Setting this option causes DUMPBIN to display the COFF symbol table. Symbol tables exist in all object files. A COFF symbol table appears in an image file only if it is linked with /DEBUG /DEBUGTYPE:COFF

/UNDECORATE

Setting this option causes DUMPBIN to display all symbols as they appear in source code before decoration. By default, DUMPBIN displays symbols in their decorated form. CL decorates symbols when it creates object files.


  Using the Resource Compiler

This section describes how to create a resource-definition (script) file, and how to compile your application's resources and add them to the application's executable file.

The following topics are included:

•	»Including Resources in An  Application«

•	»Creating a Resource Definition File«

•	»The RC Command Line«

•	»Common Statement Parameters«


Including Resources in an Application (RC)
  Including Resources in an Application

To include resources in your application

1.	Use the resource creation tools in the AppStudio to create individual resource files for cursors, icons, bitmaps, dialog boxes, and fonts. See AppStudio User's Guide for more information on how to do this.

2.	Create a resource-definition file (script) that describes all the resources used by the application.

3.	Compile the script into a resource (.RES) file with RC.

4.	Link the compiled resource files into the application's executable file.

You do not use RC to include compiled resources into the executable file or to mark the file as a Windows application. The linker recognizes the compiled resource files and links them to the executable file.


Creating a Resource-Definition File (RC)
  Creating a Resource-Definition File

After creating individual resource files for your application's icon, cursor, font, bitmap, and dialog-box resources, you create a resource-definition file, or script. A script is a text file with the extension .RC.

The script lists every resource in your application and describes some types of resources in great detail. For a resource that exists in a separate file, such as an icon or cursor, the script names the resource and the file that contains it. For some resources, such as a menu, the entire definition of the resource exists within the script.

A script file can contain the following information:

•	Preprocessing directives, which instruct RC to perform actions on the script before compiling. Directives can also assign values to names.

•	Statements, which name and describe resources.

The following sections describe directives and statements you can use in a script.


Preprocessing Directives (RC)
  Preprocessing Directives

The directives listed in Table 6.2 can be used in the script to instruct RC to perform actions or assign values to names. The syntax and semantics for the RC preprocessor is the same as for a C compiler.

Table 6.2    Preprocessing Directives

Directive	Description
define	Defines a specified name by assigning it a given value.
elif	Marks an optional clause of a conditional-compilation block.
else	Marks the last optional clause of a conditional-compilation block.
endif	Marks the end of a conditional-compilation block.
if	Conditionally compiles the script if a specified expression is true.
ifdef	Conditionally compiles the script if a specified name is defined.
ifndef	Conditionally compiles the script if a specified name is not defined.
include	Copies the contents of a file into the resource-definition file.
undef	Removes the definition of the specified name.


Single-Line  (RC)
  Single-Line Statements

A single-line statement can begin with any of the following keywords:

Keyword	Description
BITMAP	Defines a bitmap by naming it and specifying the name of the file that contains it. (To use a particular bitmap, the application requests it by name.)
CURSOR	Defines a cursor by naming it and specifying the name of the file that contains it. (To use a particular cursor, the application requests it by name.)
FONT	Specifies the name of a file that contains a font.
ICON	Defines an icon by naming it and specifying the name of the file that contains it. (To use a particular icon, the application requests it by name.)
LANGUAGE	Sets the language for all resources up to the next LANGUAGE statement or to the end of the file. When the LANGUAGE statement appears before the BEGIN in an ACCELERATORS, DIALOG, MENU, RCDATA, or STRINGTABLE resource definition, the specified language applies only to that resource.
MESSAGETABLE	Defines a message table by naming it and specifying the name of the file that contains it. The file is a binary resource file generated by the Message Compiler.


Multiline Statements (RC)
  Multiline Statements

A multiline statement can begin with any of the following keywords:

Keyword	Description
ACCELERATORS	Defines menu accelerator keys.
DIALOG	Defines a template that an application can use to create dialog boxes.
MENU	Defines the appearance and function of a menu.
RCDATA	Defines data resources. Data resources let you include binary data in the executable file.
STRINGTABLE	Defines string resources. String resources are Unicode strings that can be loaded from the executable file.
Each of these multiline statements allows you to specify zero or more optional statements before the BEGIN ... END block that defines the resource. You can specify the following statements:

Statement	Description
CHARACTERISTICS dword	User-defined information about the resource that can be used by tools that read and write resource files. The value appears in the compiled resource file, it is not stored in the executable file and is not used by Windows.
LANGUAGE language, sublanguage	Specifies the language for the resource. The parameters are constants from WINNLS.H.
VERSION dword	User-defined version number for the resource that can be used by tools that read and write resource files. The value appears in the compiled resource file, it is not stored in the executable file and is not used by Windows.


Sample Script File (RC)
  Sample Script File

The following example shows a script file that defines the resources for an application named Shapes:

#include "SHAPES.H"

ShapesCursor  CURSOR  SHAPES.CUR
ShapesIcon    ICON    SHAPES.ICO

ShapesMenu    MENU
    BEGIN
        POPUP "&Shape"
            BEGIN
                MENUITEM "&Clear", ID_CLEAR
                MENUITEM "&Rectangle", ID_RECT
                MENUITEM "&Triangle", ID_TRIANGLE
                MENUITEM "&Star", ID_STAR
                MENUITEM "&Ellipse", ID_ELLIPSE
            END
    END

The CURSOR statement names the application's cursor resource ShapesCursor and specifies the cursor file SHAPES.CUR, which contains the image for that cursor.

The ICON statement names the application's icon resource ShapesIcon and specifies the icon file SHAPES.ICO, which contains the image for that icon.

The MENU statement defines an application menu named ShapesMenu, a pop-up menu with five menu items.

The menu definition, enclosed by the BEGIN and END keywords, specifies each menu item and the menu identifier that is returned when the user selects that item. For example, the first item on the menu, Clear, returns the menu identifier ID_CLEAR when the user selects it. The menu identifiers are defined in the application header file, SHAPES.H.


  The RC Command-line

To start RC, use the following command-line syntax:

RC [options] script-file

The options parameter can include one or more of the following options:

/?

This option causes a display of a list of RC command-line options.

/d

This option defines a symbol for the preprocessor that you can test with the #ifdef directive.

/foresname

This option uses resname for the name of the .RES file.

/h

This option causes a display of a list of RC command-line options.

/i

This option causes RC to search the specified directory before searching the directories specified by the INCLUDE environment variable.

/r

Ignored. Provided for compatibility with existing makefiles.

/v

This option causes displays of messages that report on the progress of the compiler.

/x

This option prevents RC from checking the INCLUDE environment variable when searching for header files or resource files.

Options are not case-sensitive, and a hyphen (-) can be used in place of a slash (/). You can combine single-letter options if they do not require additional parameters. For example, the following commands are equivalent:

RC /V /X SAMPLE.RC

rc -vz sample.rc

The script-file parameter specifies the name of the resource-definition script that contains the names, types, filenames, and descriptions of the resources to be compiled.


Defining Names for the Preprocessor (RC)
  Defining Names for the Preprocessor

You can use  the /d option to specify conditional compilation in a script, based on whether a name is defined on the RC command line. You can also use the  #define directive to specify conditional compilation in the file or an include file.

For example, suppose your application has a pop-up menu, the Debug menu, that should appear only with debugging versions of the application. When you compile the application for normal use, the Debug menu is not included. The following example shows the statements that can be added to the resource-definition file to define the Debug menu:

MainMenu MENU
BEGIN
  . . .
#ifdef DEBUG
        POPUP "&Debug"
        BEGIN
                MENUITEM "&Memory usage", ID_MEMORY
                MENUITEM "&Walk data heap", ID_WALK_HEAP
        END
#endif
END

When compiling resources for a debugging version of the application, you could include the Debug menu by using the following RC command:

rc -d DEBUG myapp.rc

To compile resources for a normal version of the application—one that does not include the Debug menu—you could use the following RC command:

rc myapp.rc


Naming the Compiled Resource File (RC)
  Naming the Compiled Resource File

By default, when compiling resources, RC names the compiled resource (.RES) file with the base name of the .RC file and places it in the same directory as the .RC file. The following example compiles MYAPP.RC and creates a compiled resource file named MYAPP.RES in the same directory as MYAPP.RC:

rc myapp.rc

The /fo option lets you give the resulting .RES file a name that differs from the name of the corresponding .RC file. For example, to name the resulting .RES file NEWFILE.RES, you would use the following command:

rc -fo newfile.res myapp.rc

The /fo option can also place the .RES file in a different directory. For example, the following command places the compiled resource file MYAPP.RES in the directory C:\SOURCE\RESOURCE:

rc -fo c:\source\resource\myapp.res myapp.rc


Searching for Files (RC)
  Searching for Files

By default, RC searches for header files and resource files (such as icon and cursor files) first in the current directory and then in the directories specified by the INCLUDE environment variable. (The PATH environment variable has no effect on which directories RC searches.)

Adding a Directory to Search

You can use the /i option to add a directory to the list of directories RC searches. The compiler then searches the directories in the following order:

1.	The current directory

2.	The directory or directories you specify by using the /i option, in the order in which they appear on the RC command line

3.	The list of directories specified by the INCLUDE environment variable, in the order in which the variable lists them, unless you specify the /x option

The following example compiles the resource-definition file MYAPP.RC:

rc /i c:\source\stuff /i d:\resources myapp.rc

When compiling the script MYAPP.RC, RC searches for header files and resource files first in the current directory, then in C:\SOURCE\STUFF and D:\RESOURCES, and then in the directories specified by the INCLUDE environment variable.

Suppressing the INCLUDE Environment Variable

You can prevent RC from using the INCLUDE environment variable when determining the directories to search. To do so, use the /x option. The compiler then searches for files only in the current directory and in any directories you specify by using the /i option.

The following example compiles the script file MYAPP.RC:

rc /x /i c:\source\stuff myapp.rc

When compiling the script MYAPP.RC, RC searches for header files and resource files first in the current directory and then in C:\SOURCE\STUFF. It does not search the directories specified by the INCLUDE environment variable.


Displaying Progress Messages (RC)
  Displaying Progress Messages

You can use the /v option to specify that RC is to display progress messages. The following example causes RC to display progress messages as it compiles the resource-definition script SAMPLE.RC and creates the compiled resource file SAMPLE.RES:

rc /v sample.rc


Common Statement Parameters (RC)
  Common Statement Parameters

The following paragraphs list parameters in common among the resource or control statements. Occasionally, a certain statement will use a parameter differently, or may ignore a parameter. The statement-specific variation is described with the statement in the alphabetical reference.


Common Control Parameters (RC)
  Common Control Parameters

The syntax for a control definition is as follows:

control [text,] id, x, y, width, height [, style [, extended-style]]

Horizontal dialog units are 1/4 of the dialog base width unit. Vertical units are 1/8 of the dialog base height unit. The current dialog base units are computed from the height and width of the current system font. The GetDialogBaseUnits function returns the dialog base units in pixels. The coordinates are relative to the origin of the dialog box.

The parameters are described in the following paragraphs:

control

This parameters specifies the keyword that indicates the type of control being defined, such as PUSHBUTTON or CHECKBOX.

text

This parameters specifies text that is displayed with the control. The text is positioned within the control's specified dimensions, or adjacent to the control.

This parameter must contain zero or more characters enclosed in double quotation marks.  Strings are automatically null-terminated and converted to Unicode in the resulting resource file, except for strings specified in raw-data statements. (raw-data can be specified in RCDATA and user-defined resources.) To specify a Unicode string in raw-data, explicitly qualify the string as a wide-character string by using the L prefix.

By default, the characters listed between the double quotation marks are ANSI characters and escape sequences are interpreted as byte escape sequences. If the string is preceded by the L prefix, the string is a wide-character string and escape sequences are interpreted as two-byte escape sequences that specify Unicode characters. If a double quotation mark is required in the text, you must include the double quotation mark twice or use the \" escape sequence.

An ampersand (&) character in the text indicates that the following character is used as a mnemonic character for the control. When the control is displayed, the ampersand is not shown, but the mnemonic character is underlined. The user can choose the control by pressing the key corresponding to the underlined mnemonic character. To use the ampersand as a character in a string, insert two ampersands (&&).

id

This parameter specifies the control identifier. This value must be a 16-bit unsigned integer in the range 0 through 65,535 or a simple arithmetic expression that evaluates to a value in that range.

x

This parameter specifies the x-coordinate of the left side of the control relative to the left side of the dialog box. This value must be a 16-bit unsigned integer in the range 0 through 65,535. The coordinate is in dialog units and is relative to the origin of the dialog box, window, or control containing the specified control.

y

This parameter specifies the y-coordinate of the top side of the control relative to the top of the dialog box. This value must be a 16-bit unsigned integer in the range 0 through 65,535. The coordinate is in dialog units relative to the origin of the dialog box, window, or control containing the specified control.

width

This parameters specifies the width of the control. This value must be a 16-bit unsigned integer in the range 1 through 65,535. The width is in 1/4-character units.

height

This parameter specifies the height of the control. This value must be a 16-bit unsigned integer in the range 1 through 65,535. The height is in 1/8-character units.

style

This parameter specifies the control styles. Use the bitwise OR (|) operator to combine styles.

extended-style

This parameter specifies extended (WS_EX_xxx) styles. You must specify a style to specify an extended-style. .


Common Resource Attributes (RC)
  Common Resource Attributes

All resource-definition statements include a load-mem option that specifies the loading and memory characteristics of the resource. These options include load attributes and memory attributes. The only attribute that is used by Win32 is the DISCARDABLE attribute. The remaining attribute specifiers are allowed in the script for compatibility with existing scripts, but are ignored.

Load Attributes

The load attributes specify when the resource is to be loaded. The load parameter must be one of the following:

•	PRELOAD

Ignored. In 16-bit Windows, the resource is loaded with the executable file.

•	LOADONCALL

Ignored. In 16-bit Windows, the resource is loaded when called.


Memory Attributes (RC)
  Memory Attributes

The memory attributes specify whether the resource is fixed or movable, whether it is discardable, and whether it is pure. The memory parameter can be one or more of the following:

•	FIXED

Ignored. In 16-bit Windows, the resource remains at a fixed memory location.

•	MOVEABLE

Ignored. In 16-bit Windows, the resource can be moved if necessary in order to compact memory.

•	DISCARDABLE

Resource can be discarded if no longer needed.

•	PURE

Ignored. Accepted for compatibility with existing resource scripts.

•	IMPURE

Ignored. Accepted for compatibility with existing resource scripts.

The default is DISCARDABLE for cursor, icon, and font resources.


Introduction
Run-Time Library Reference

Introduction

The Microsoft® run-time library is a set of more than 550 ready-to-use functions and macros designed for use in C and C++ programs. The run-time library makes programming easier by providing fast and efficient routines to perform common programming tasks (such as string manipulation), sparing you the time and effort needed to write such routines and providing reliable methods of performing operating-system functions (such as opening and closing files). The run-time library is important because it provides basic functions not provided by the C and C++ languages themselves. These functions include input and output, memory allocation, process control, graphics, and many others.

This book describes the run-time library routines included with this product. These comprise all of the routines formerly included with Microsoft C/C++ version 7.0 and earlier, as well as new routines.


Run-Time Library Reference


  About This Book

This book provides a guide to the run-time library provided with this product. It has two parts. Part 1, "Overview," introduces the Microsoft run-time library. It describes general rules for using the library and summarizes the main categories of library routines. Part 1 contains the following chapters:

•	Chapter 1, "Using the Run-Time Library," gives general rules for understanding and using library routines and mentions special considerations that apply to certain routines. It is recommended that you read this chapter before using the run-time library; you may also want to turn to Chapter 1 when you have questions about library procedures.

•	Chapter 2, "Run-Time Routines by Category," lists the library routines by category and discusses considerations that apply to each category. This chapter makes it easy to locate routines by task. Once you find the routine you want, turn to the reference page in Part 2 for a detailed description.

•	Chapter 3, "Global Variables and Standard Types," describes variables and types that are used by library routines. Global variables and standard types are also described in the reference descriptions of the routines that use them.

Part 2, "Run-Time Functions," describes the library routines in alphabetical order. Once you are familiar with the run-time library rules and procedures, you will probably use this part most often.

Note  For information on Microsoft product support, see "Using Microsoft Support Services" in the Introduction to Getting Started.


  Other Books of Interest

The following books cover a variety of topics that you may find useful. They are listed only for your convenience. With the exception of its own publications, Microsoft does not endorse these books or recommend them over others on the same subject.

•	Barkakati, Nabajyoti. The Waite Group's Microsoft C Bible. Indianapolis, IN: Howard W. Sams, 1988. A topical guide to the Microsoft C run-time library. A similar volume is available for the Microsoft QuickC® product.

•	Campbell, Joe. C Programmer's Guide to Serial Communications. Indianapolis, IN: Howard W. Sams & Company, 1987. A comprehensive guide to the specialized area of serial communication programming in C.

•	Christian, Kaare. C++ Programming. Redmond, WA: Microsoft Press, 1992. An introduction to object-oriented programming concepts, C++ fundamentals, and programming for Windows with the Microsoft Foundation Class Library.

•	Harbison, Samuel P., and Guy L. Steele, Jr. C: A Reference Manual, 3d ed. Englewood Cliffs, NJ: Prentice Hall, 1991. A comprehensive guide to the C language and the standard library.

•	Kernighan, Brian W., and Dennis M. Ritchie. The C Programming Language, 2d ed. Englewood Cliffs, NJ: Prentice Hall, 1988. The first edition of this book is the classic definition of the C language. The second edition includes new information on the ANSI C standard.

•	Lafore, Robert. Microsoft C Programming for the IBM. Indianapolis, IN: Howard W. Sams & Company, 1987. The first half of this book teaches C. The second half concentrates on specifics of the PC environment, such as basic input/output system (BIOS) calls, memory, and video displays.

•	Mark Williams Company. ANSI C: A Lexical Guide. Englewood Cliffs, NJ: Prentice Hall, 1988. A dictionary-style guide to the ANSI C standard.

•	Plauger, P. J., and Jim Brodie. ANSI and ISO Standard C: A Guide for Programmers. Redmond, WA: Microsoft Press, 1992. A reference to the ANSI and ISO C implementation by the secretary and chairman of the ANSI- and ISO-authorized C Programming Language Standards Committee.

•	Plum, Thomas. Reliable Data Structures in C. Cardiff, NJ: Plum Hall, 1985. An intermediate-level look at data structures using the C language.

•	Plum, Thomas, and Jim Brodie. Efficient C. Cardiff, NJ: Plum Hall, 1985. A guide to techniques for increasing the efficiency of C programs.

•	Press, William H., Brian P. Flannery, Saul A. Teukolsky, and William T. Vetterling. Numerical Recipes in C: The Art of Scientific Computing. New York: Cambridge University Press, 1988. A comprehensive look at numerical techniques using the C language.

•	Schustack, Steve. Variations in C: Building Professional Applications with Microsoft C. Second Edition. Redmond, WA: Microsoft Press, 1989. An intermediate-level guide to developing business applications in C.

•	Ward, Robert. Debugging C. Indianapolis, IN: Que Corporation, 1986. An advanced guide to the theory and practice of debugging C programs.

•	Wilton, Richard. Programmer's Guide to PC and PS/2 Video Systems: Maximum Video Performance from the EGA, VGA, HGC, & MCGA. Redmond, WA: Microsoft Press, 1987. An advanced guide to all the PC and PS/2 video modes.


  Document Conventions

This book uses the following typographic conventions:

Example	Description
STDIO.H	Uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
char, _setcolor, __far	Bold type indicates C and C++ keywords, operators, language-specific characters, and library routines. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
	Many constants, functions, and keywords begin with either a single or double underscore. These are required as part of the name. For example, the compiler recognizes the __cplusplus manifest constant only when the leading double underscore is included. It may be difficult at first glance to distinguish a single underscore from a double underscore because the two run together on the screen. Therefore, the width of the character(s) is your guide. The sample term setcolor, in the left column above, has one underscore in front of it, while the term far has two underscores in front of it.
expression	Words in italics indicate placeholders for information you must supply, such as a filename. Italic type is also used occasionally for emphasis in the text.
[option]	Items inside square brackets are optional.
#pragma pack {1 | 2}	Braces and a vertical bar indicate a choice among two or more items. You must choose one of these items unless square brackets ([ ] ) surround the braces.
#include <io.h>	This font is used for examples, user input, program output, and error messages in text.
CL [option...]  file...	Three dots (an ellipsis) following an item indicate that more items having the same form may appear.
while() {  .  .  . }	A column or row of three dots tells you that part of an example program has been intentionally omitted.
CTRL+ENTER	Small capital letters are used to indicate the names of keys on the keyboard. When you see a plus sign (+) between two key names, you should hold down the first key while pressing the second.
	The carriage-return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
"argument"	Quotation marks enclose a new term the first time it is defined in text.
"C string"	Some C constructs, such as strings, require quotation marks.
Dynamic-Link Library (DLL)	The first time an acronym is used, it is usually spelled out.
see »Using Projects«.	Hypertext cross-references are enclosed in green double chevrons. Click the term enclosed in the chevrons to display the referenced information.
CEnterDlg;	The blue box adjoining the blue code indicates that it has been altered from a previous example, usually because you are being instructed to edit it.


About the Microsoft Run-Time Library
  About the Microsoft® Run-Time Library

The Microsoft run-time library contains routines and features that support American National Standards Institute (ANSI) C and UNIX C compatibility, MS-DOS® and programming for the Microsoft Windows™ operating system, programming for the Microsoft Windows NT™ operating system, and sophisticated graphics programming.

To ease the task of transporting programs between operating systems and compilers, the description of each run-time library routine includes a compatibility section. A routine with full compatibility has the following entries:

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

(In this book, references to UNIX systems also encompass XENIX® and other UNIX-like systems.) If a routine is incompatible with any of the previous standards, its compatibility section shows that standard as struck through. For example, following is a section showing ANSI and UNIX incompatibility:

ANSI     MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


  ANSI C Compatibility

The run-time library routines are designed for compatibility with the ANSI C standard, which the Microsoft C and C++ compilers support. Functions that are ANSI C compatible are marked as ANSI in the compatibility section.


  Type Checking

The major innovation of ANSI C is to permit argument-type lists in function prototypes (declarations). Given the information in the function prototype, the compiler can check later references to the function to make sure that the references use the correct number and type of arguments and the correct return value.

To take advantage of the compiler's type-checking ability, the include files that accompany the run-time library have been expanded. In addition to the definitions and declarations required by library routines, the include files now contain function declarations with argument-type lists. Several new include files have also been added. The names of these files are chosen to maximize compatibility with the ANSI C standard and with UNIX and XENIX names.


  Underscores and OLDNAMES.LIB

All Microsoft-specific run-time functions, constants, variables, type definitions, structures, and macros (such as, respectively, _open, _VRES16COLOR, _cpumode, _HEAPINFO, _heapinfo, and __isascii) are ANSI compatible. The Microsoft-specific run-time functions, constants, variables, type definitions, and structures begin with a single underscore; Microsoft-specific run-time macros and keywords begin with two underscores.

For compatibility with Microsoft C/C++ version 7.0 and earlier, a library named OLDNAMES.LIB is provided that contains alias records mapping the names to the new names. For instance, open is mapped to _open.

You have to link with OLDNAMES.LIB to link programs created with this product with object files created by Microsoft C/C++ version 7.0 and earlier. However, by default the compiler emits a library search record—the only time you must link explicitly with OLDNAMES.LIB is under one of the following situations:

•	Compiling with a combination of the default /Ze option (use Microsoft extensions) and the /Zl option (omit default library name from object file)

•	Compiling with the default /Ze option (use Microsoft extensions) and a combination of the /link option (linker-control) and the /NOD option (no default-library search)

For more information on the CL command-line options, see the Build Tools User's Guide.

Note  The compiler views a structure with both an old name and a new name as two different types; you cannot copy from an old type to a new type. Also, old prototypes that take struct pointers use the old struct names in the prototype. So, you must be consistent—match the old names for routines with the old names for the parameters and be similarly consistent with the new routine names and parameters.


Programming for the MS-DOS, Microsoft Windows NT, and Microsoft Windows Operating Systems
  Programming for the MS-DOS™, Microsoft Windows NT™, and Microsoft Windows™ Operating Systems

Microsoft run-time library routines are designed to maintain maximum compatibility between MS-DOS, the Windows operating system, Windows NT, and UNIX or XENIX systems. The run-time library offers a number of operating-system interface routines that make it possible for you to take advantage of specific MS-DOS, Windows, and Windows NT features. Functions that are MS-DOS and Windows operating system compatible are marked, respectively, as MS-DOS and WIN in the compatibility section. Note that for Windows the compatibility section also contains information on dynamic-link library (DLL) compatibility. Functions that are 32-bit compatible (with the Windows NT operating system) are marked as WIN32 in the compatibility section. Functions that are compatible with the Win32s environment are marked as WIN32S in the compatibility section. In some cases, functions that are WIN32 compatible are not WIN32s compatible (for example, _beginthread and _endthread).


QuickWin
  QuickWin (16-Bit Specific)

The Microsoft 16-bit run-time library now contains several QuickWin functions that make it possible to compile MS-DOS programs that are not compatible with Windows as simple as text-only applications for Windows. MS-DOS programs compiled with the /Mq compiler option have a limited Windows user interface, including a standard menu bar, standard Help (for the QuickWin features), and a client (or application) window with a child (document) window for the C input/output streams stdin, stdout, and stderr. You can also add other child windows of your own. QuickWin applications support the Windows Clipboard, and you can use standard C functions to write to and read from a QuickWin application's windows, which behave as streams. Note that the QuickWin functions are not supported by the 32-bit run-time libraries. Functions that are QuickWin compatible are marked as QWIN in the compatibility section.


  UNIX C Compatibility

Most of the functions in the Microsoft run-time library are compatible with like-named UNIX routines. For additional compatibility, the math library functions have been extended to provide exception handling in the same manner as the UNIX System V math functions. Functions that are UNIX and XENIX compatible are marked as UNIX in the compatibility section.


Expanded Graphics Library
  Expanded Graphics Library (16-Bit Specific)

The Microsoft 16-bit MS-DOS run-time library contains more than 100 graphics routines. The core of this library consists of several dozen low-level graphics routines that allow your programs to select video modes, set points, draw lines, change colors, and draw shapes such as rectangles and ellipses. You can display real-valued data, such as floating-point values, within windows of different sizes by using various coordinate systems.

The graphics library includes presentation graphics and fonts. The presentation-graphics library provides powerful tools for adding presentation-quality graphics to your programs. These routines can display data as a variety of graphs, including pie charts, bar and column charts, line graphs, and scatter diagrams. The fonts library allows your programs to display various styles and sizes of text in graphics images or charts. You can use font-manipulation routines with any graphics routines that display text, including presentation graphics.


Using the Run-Time Library
  Chapter 1  Using the Run-Time Library

This chapter provides basic information about how to use the Microsoft run-time library routines. It also describes some special rules, such as path and filename conventions, that apply to particular routines. You should read this chapter before you begin to use the run-time library routines, and you may also want to refer back to it if you have questions about library procedures.


Calling Library Routines
  1.1  Calling Library Routines

To use a library routine, simply call it in your program, just as if it is defined there. For instance, suppose you write the following program and name it SAMPLE.C:

#include <stdio.h>
void main( void )
{
   printf( "cats and dogs\n" );
}

The program prints cats and dogs by calling the printf routine, which is part of the run-time library. Calling a library routine normally involves two groups of files:

•	Header ("include") files that contain declarations, constants, and type definitions required by library routines

•	Library files that contain the library routines in compiled form

Header files and library files are both included with this product. Header files are used when compiling, and library files are used when linking.

You include the necessary header files in your program source code with #include directives. The description of each library routine in Part 2, "Run-Time Functions," tells you what header file the routine requires. Because printf requires the STDIO.H header file, the SAMPLE.C program contains the following line:

#include <stdio.h>

This line causes the compiler to insert the contents of STDIO.H into the source file SAMPLE.C.

After you compile the source file, you link the resulting object (.OBJ) file with the appropriate library (.LIB) file to create an executable (.EXE) file. Your object file contains the name of every routine that your program calls, including library routines. If a routine is not defined in your program, the linker searches for its code in a library file and includes that code in the executable file.

Usually, the code for standard library routines is contained in the "default library" that you create when installing this product. Because the linker automatically searches the default library, you do not need to specify that library's name when linking your program. If you call a library routine that is not contained in the default library, you must give the linker the name of the library file that contains the routine. For instance, if your program uses a Microsoft graphics routine, you link the program using a line that includes GRAPHICS.LIB.

For more information about linking, see Build Tools User's Guide (in this product's documentation set) or consult the installation documentation for your compiler.


Using Header Files
  1.2  Using Header Files

As stated in the previous section, you should include header files when using library routines. The reasons why header files are required are described in the following sections.


  Including Necessary Definitions

Many run-time library routines use macros, constants, or type definitions defined in a header file. To use the routine, you must include the header file containing the needed definition(s). The following list gives examples:

•	Macro: If a library routine is implemented as a macro, the macro definition appears in a header file. For instance, the toupper macro is defined in the header file CTYPE.H.

•	Manifest constant: Many library routines refer to constants that are defined in header files. For instance, the _open routine uses constants such as _O_CREAT, which is defined in the header file FCNTL.H.

•	Type definition: Some library routines return a structure or take a structure as an argument. For example, stream input/output routines use a structure of type FILE, which is defined in STDIO.H.


  Including Function Declarations

The run-time library header files also contain function declarations for every function in the run-time library. These declarations are in the style recommended by the ANSI C standard. Given these declarations, the compiler can perform "type checking" on every reference to a library function, making sure that you have used the correct return type and arguments. Function declarations are sometimes called "prototypes," because the declaration serves as a prototype or template for every subsequent reference to the function.

A function declaration lists the name of the function, its return type, and the number and type of its arguments. For instance, this is the declaration of the pow library function from the header file MATH.H:

double pow( double x, double y );

The example declares that pow returns a value of type double and takes two arguments of type double. Given this declaration, the compiler can check every reference to pow in your program to ensure that the reference passes two double arguments to pow and takes a return value of type double.

The compiler can perform type checking only for function references that appear after the function declaration. Because of this, function declarations usually appear near the beginning of the source file, prior to any use of the functions they declare. Function declarations are especially important for functions that return a value of some type other than int, which is the default. For example, the pow function returns a double value. If you do not declare such a function, the compiler treats its return value as int, which can cause unexpected results.

It is also a good practice to provide declarations for functions that you write. If you do not want to type the declarations by hand, you can generate them automatically by using the /Zg compiler option. This option causes the compiler to generate ANSI-standard function declarations for every function defined in the current source file. Redirect this output to a file, then insert the file near the beginning of your source file.

Your program can contain more than one declaration of the same function, as long as the declarations do not conflict. This is important if you have old programs whose function declarations do not contain argument-type lists. For instance, if your program contains the declaration

char *calloc( );

you can later include the following declaration:

char *calloc(unsigned, unsigned);

Because the two declarations are compatible, even though they are not identical, no conflict occurs. The second declaration simply gives more information about function arguments than the first. A conflict arises, however, if the declarations give a different number of arguments or give arguments of different types.

Some library functions can take a variable number of arguments. For instance, the printf function can take one argument or several. The compiler can perform only limited type checking on such functions, a factor that affects the following library functions:

•	In calls to _cprintf, _cscanf, printf, and scanf, only the first argument (the format string) is type checked.

•	In calls to fprintf, fscanf, _snprintf, sprintf, and sscanf, only the first two arguments (the file or buffer and the format string) are type checked.

•	In calls to _open, only the first two arguments (the path and the _open flag) are type checked.

•	In calls to _sopen, only the first three arguments (the path, the _open flag, and the sharing mode) are type checked.

•	In calls to _execl, _execle, _execlp, and _execlpe, only the first two arguments (the path and the first argument pointer) are type checked.

•	In calls to _spawnl, _spawnle, _spawnlp, and _spawnlpe, only the first three arguments (the mode flag, the path, and the first argument pointer) are type checked.


Paths and Filenames
  1.3  Paths and Filenames

Many library routines take strings representing paths and filenames as arguments. If you plan to transport your programs to the UNIX (or XENIX/POSIX) operating system, you should remember that UNIX uses path and filename conventions that are different from those used by MS-DOS and Windows NT. If you do not plan to transport your programs to UNIX, you can skip this section.


  Case Sensitivity

The File Allocation Table (FAT) file system in MS-DOS and Windows NT is not case sensitive (it does not distinguish between uppercase and lowercase letters). Thus, SAMPLE.C and Sample.C refer to the same file. In Windows NT, the installable NT File System (NTFS) preserves case for directory listings, but ignores case in file searches and other system operations. However, the UNIX operating system (as well as the POSIX subsystem in Windows NT) is case sensitive. In POSIX and UNIX, SAMPLE.C and Sample.C refer to different files. To transport programs to UNIX (or POSIX), choose paths and filenames that work correctly in UNIX, because either case works in MS-DOS and Windows NT. For instance, the following directives are identical in MS-DOS and Windows NT, but only the second works in UNIX:

#include <STDIO.H>
#include <stdio.h>


  Subdirectory Conventions

With UNIX, certain header files are usually placed in a subdirectory named SYS. In this product, this convention is followed to ease the process of transporting programs to UNIX. If you do not plan to transport your programs, you can place the SYS header files elsewhere.


Path Delimiters

UNIX uses the slash mark (/) in paths, while MS-DOS and Windows NT use the backslash (\). To transport programs to UNIX, it is advantageous to use path delimiters that are compatible with UNIX whenever possible.


Choosing Between Functions and Macros
  1.4  Choosing Between Functions and Macros

This book uses the words "routine" and "function" interchangeably. However, the term "routine" actually encompasses both functions and macros. Because functions and macros have different properties, you should pay attention to which form you are using. The descriptions in the reference section indicate whether routines are implemented as functions or as macros.

Most routines in the Microsoft run-time library are functions. They consist of compiled C code or assembled Microsoft Macro Assembler (MASM) code.

However, a few library routines are implemented as macros that behave like functions. You can pass arguments to library macros and invoke them in the same way you invoke functions.

The main benefit of using macros is faster execution time. Every library macro is defined with a #define directive in a header file. A macro is expanded (replaced by its definition) during preprocessing, creating inline code. Thus, macros do not have the overhead associated with function calls. On the other hand, each use of a macro inserts the same code in your program, whereas a function definition occurs only once regardless of how many times it is called. Functions and macros thus offer a trade-off between speed and size.

Apart from speed and size issues, macros and functions have some other important differences:

•	Some macros treat arguments with side effects incorrectly when the macro evaluates its arguments more than once (see the example that follows this list). Not every macro has this effect. To determine if a macro handles side effects as desired, examine its definition in the appropriate header file.

•	A function name evaluates to an address, but a macro name does not. Thus, you cannot use a macro name in contexts requiring a function pointer. For instance, you can declare a pointer to a function, but you cannot declare a pointer to a macro.

•	You can declare functions, but you cannot declare macros. Thus, the compiler cannot perform type checking of macro arguments as it does of function arguments. However, the compiler can detect when you pass the wrong number of arguments to a macro.

The following example demonstrates how some macros can produce unwanted side effects. It uses the toupper routine.

#include <ctype.h>

int a = 'm';
a = toupper(a++);

The example increments a when passing it as an argument to the toupper routine, which is implemented as a macro. It is defined in CTYPE.H:

#define toupper(c) ( (islower(c)) ? _toupper(c) : (c) )

The definition uses the conditional operator (? :). The conditional expression evaluates the argument c twice: once to check if it is lowercase and again to create the result. This macro evaluates the argument a++ twice, increasing a by 2 instead of 1. As a result, the value operated on by islower differs from the value operated on by _toupper.

Like some other library routines, toupper is provided in both macro and function versions. The header file CTYPE.H not only declares the toupper function but also defines the toupper macro. Choosing between the macro version and function version of such routines is easy. If you wish to use the macro version, you can simply include the header file that contains the macro definition. Because the macro definition of the routine always appears after the function declaration, the macro definition usually takes precedence. Thus, if your program includes CTYPE.H and then calls toupper, the compiler uses the toupper macro:

#include <ctype.h>

int a = 'm';
a = toupper(a);

You can force the compiler to use the function version of a routine by enclosing the routine's name in parentheses:

#include <ctype.h>

int a = 'm';
a = (toupper) (a);

Because the name toupper is not immediately followed by a left parenthesis, the compiler cannot interpret it as a macro name. It must use the toupper function.

A second way to do this is to "undefine" the macro definition with the #undef directive:

#include <ctype.h>
#undef toupper

Because the macro definition no longer exists, subsequent references to toupper use the function version.

A third way, not generally recommended, to make sure the compiler uses the function version is to declare the function explicitly:

#include <ctype.h>
int toupper(int _c);

Because this function declaration appears after the macro definition in CTYPE.H, it causes the compiler to use the toupper function.


Stack Checking on Entry
  1.5  Stack Checking on Entry (16-Bit Specific)

For certain 16-bit library routines, the compiler performs stack checking on entry. (The "stack" is a memory area used for temporary storage.) Upon entry to such a routine, the stack is checked to determine if it has enough room for the local variables used by that routine. If it does, space is allocated by adjusting the stack pointer. Otherwise, a "stack overflow" run-time error occurs. If stack checking is disabled, the compiler assumes there is enough stack space; if there is not, you might overwrite memory locations in the data segment and receive no warning—unpredictable program behavior may result.

Typically, stack checking is enabled only for functions with large local-variable requirements (more than about 150 bytes), because there is enough free space between the stack and data segments to handle functions with smaller requirements. If the function is called many times, stack checking slows execution slightly. Stack checking is enabled for the following library functions:

_execvp	_spawnvp	vfprintf
_execvpe	_spawnvpe	vprintf
fprintf	sprintf	vsprintf
fscanf	_snprintf	_vsnprintf
printf	sscanf	_write
scanf	system
You can enable or disable stack checking with the /Gs and /Ge compiler options (see the Build Tools User's Guide) or the check_stack pragma (see the Preprocessor Reference). Both books are in the documentation set for this product.


Handling Errors
  1.6  Handling Errors

Many library routines return a value that indicates an error condition. To avoid unexpected results, your code should always check such error values and handle all of the possible error conditions. The description of each library routine in the reference section lists the routine's return value(s).

Some library functions do not have a set error return. These include functions that return nothing and functions whose range of return values makes it impossible to return a unique error value.

To aid in error handling, some functions set the value of a global variable named errno. If the reference description of a routine states that it sets the errno variable, you can use errno in two ways:

•	Compare errno to the values defined in the header file ERRNO.H.

•	Handle errno with the perror or strerror library routine. The perror routine prints a system error message to the standard error (stderr). The strerror routine stores the same information in a string for later use.

When you use errno, perror, and strerror, remember that the value of errno reflects the error value for the last call that set errno. To avoid confusion, you should always test the return value to verify that an error actually occurred. Once you determine that an error has occurred, use strerror or perror immediately. Otherwise, the value of errno may be changed by intervening calls.

Library math routines set errno by calling the »_matherr« or »_matherrl« library routine; both are described in the reference section. If you wish to handle math errors differently from these routines, you can write your own routine and name it _matherr or _matherrl. Your routine must follow the rules listed in the _matherr reference description.

The ferror library routine makes it possible for you to check for errors in stream input/output (I/O) operations. This routine checks if an error indicator has been set for a given stream. Closing or rewinding the stream automatically clears the error indicator. You can also reset the error indicator by calling the clearerr library routine.

The feof library routine tests for end of file on a given stream. An end-of-file condition in low-level input and output can be detected with the _eof routine or when a _read operation returns 0 as the number of bytes read.

The _grstatus library routine makes it possible for you to check for errors after calling certain graphics library operations. For details, see the reference page on the »_grstatus« function.


Operating-System Considerations
  1.7  Operating-System Considerations

The library routines listed in this section behave differently under different operating-system versions. For more information on an individual routine, see the description of that routine in the reference section.

Routine	Restrictions
»_locking,«  »_sopen,«  »_fsopen«	These routines are effective only in MS-DOS versions 3.0 and later and in Windows NT.
»_dosexterr«	This routine provides error handling for system call 0x59 (get extended error) in MS-DOS versions 3.0 and later and in Windows NT.
»_dup,«  »_dup2«	These routines can cause unexpected results in MS-DOS versions earlier than 3.0. If you use them to create a duplicate file handle for stdin, stdout, stderr, _stdaux, or _stdprn, calling the _close function with one handle causes errors in later I/O operations that use the other handle. This anomaly does not occur in MS-DOS versions 3.0 and later or in Windows NT.
»_exec,«  »_spawn«	When using these families of functions under MS-DOS versions earlier than 3.0, the value of the arg0 argument (or argv[0] to the child process) is not available; a null string ( "" ) is stored in that position instead. In MS-DOS versions 3.0 and later and in Windows NT, the arg0 argument contains the complete command path.
This product defines global variables that indicate the version of the current operating system. You can use these to determine the operating-system version in which a program is executing. For more information, see Chapter 3, »Global Variables and Standard Types.«


Floating-Point Support
  1.8  Floating-Point Support

Microsoft math library routines require floating-point support to perform calculations with real numbers (numbers that can contain fractions). This support can be provided by the floating-point libraries that accompany your compiler software or by an 8087, 80287, or 80387 coprocessor. The names of the functions that require floating-point support are listed following:

acos	_chgsign	_fabsl	_hypot	_scalb
acosl	_clear87	_fcvt	_hypotl	sin
asin	_control87	_fieeetomsbin	_isnan	sinl
asinl	_copysign	_finite	ldexp	sinh
atan	cos	floor	_ldexpl	sinhl
atanl	cosl	floorl	log	sqrt
atan2	cosh	fmod	_logb	sqrtl
atan2l	coshl	fmodl	logl	_status87
atof	_dieeetomsbin	_fmsbintoieee	log10	strtod
_atold	difftime	_fpclass	log10l	_strtold
Bessel routines	_dmsbintoieee	_fpieee_flt	modf	tan
_cabs	_ecvt	_fpreset	_modfl	tanl
_cabsl	exp	frexp	_nextafter	tanh
ceil	expl	_frexpl	pow	tanhl
ceill	fabs	_gcvt	powl
Note that the Bessel routine does not correspond to a single function, but to 12 functions named _j0, _j1, _jn, _y0, _y1, _yn, _j0l, _j1l, _jnl, _y0l, _y1l, and _ynl. Also note that the _clear87 and _control87 functions are not available with the /FPa compiler option.

Also requiring floating-point support is the printf family of functions (_cprintf, fprintf, printf, _snprintf, sprintf, vfprintf, vprintf, _vsnprintf, and vsprintf). These functions require support for floating-point input and output if used to print floating-point values.

The compiler tries to detect whether floating-point values are used in a program so that supporting functions are loaded only if required. This behavior saves a considerable amount of space for programs that do not require floating-point support.

When you use a floating-point type specifier in the format string for a printf or scanf call, make sure you specify floating-point values or pointers to floating-point values in the argument list. These values or pointers must correspond to any floating-point type specifiers in the format string. The presence of floating-point arguments allows the compiler to detect that floating-point support code is required. If a floating-point type specifier is used to print an integer argument, for example, floating-point values will not be detected because the compiler does not actually read the format string used in the printf and scanf functions. For instance, the following program produces an error at run time:

void main( void )  /* This example causes an error */
{
    long f = 10L;
    printf("%f", f);
}

In the preceding example, the functions for floating-point support are not loaded because no floating-point arguments are given in the call to printf and no floating-point values are used elsewhere in the program.

As a result, this error occurs: Floating point not loaded. Here is a corrected version of the previous call to printf in which the long integer value is cast to double:

void main( void )  /* This example works correctly */
{
    long f = 10L;
    printf("%f", (double) f);
}


Using Huge Arrays
1.9  [image]  Using Huge Arrays with Library Functions (16-Bit Specific)

In 16-bit programs that use small, compact, medium, and large memory models, the compiler makes it possible for you to use arrays exceeding the 64 kilobyte (K) limit of physical memory in these models by explicitly declaring the arrays as __huge. However, generally, you cannot pass huge pointers as arguments to run-time library functions. In the compact-model library used by compact-model programs and in the large-model library used by both large-model and huge-model programs, only the functions listed following use pointer arithmetic that works with huge items:

»bsearch«	»fread«	»memcmp«
»_fmemccpy«	»fwrite«	»memcpy«
»_fmemchr«	»_halloc«	»_memicmp«
»_fmemcmp«	»_hfree«	»memmove«
»_fmemcpy«	»_lfind«	»memset«
»_fmemicmp«	»_lsearch«	»qsort«
»_fmemmove«	»_memccpy«
»_fmemset«	»memchr«
With this set of functions, you can read from, write to, search, sort, copy, initialize, compare, or dynamically allocate and free huge arrays; the huge array can be passed without difficulty to any of these functions in a compact-, large-, or huge-model program. The model-independent routines in the previous list (those beginning with _f) are available in all memory models.

The memset, memcpy, and memcmp library routines are available in two versions: as C functions and as intrinsic (inline) code. The function versions of these routines support huge pointers in compact and large memory models, but the intrinsic versions do not support huge pointers. (The function version of such routines generates a call to a library function, whereas the intrinsic version inserts inline code into your program. For information on how to select the intrinsic versions of library routines, either see the discussion of the /Oi option in the Build Tools User's Guide in the documentation set for this product, or consult your compiler documentation.)


Run-Time Routines by Category
  CHAPTER 2  Run-Time Routines by Category

Microsoft run-time library routines handle various kinds of tasks. If you know the type of task you need done but don't know exactly which routine to use, the categorized lists of routines in this chapter can help. The descriptions here are intended only to give you a brief overview of the capabilities of the run-time library. For a complete description of the behavior, syntax, and use of each routine, see Part 2, "Run-Time Functions."

The main categories of library routines are:

Buffer manipulation	Process and environment control
Character classification and conversion	QuickWin
Data conversion	Searching and sorting
Directory control	String manipulation
File handling	System calls
Generic text	Time
Graphics	Variable-length argument lists
Input and output	Virtual memory allocation
Internationalization	32-Bit specific
Math	Wide-character
Memory allocation


Buffer Manipulation Routines
  2.1  Buffer Manipulation

The buffer-manipulation routines are useful for working with areas of memory on a byte-by-byte basis. A "buffer" is an array of bytes, similar to a character string. However, unlike strings, buffers are not usually terminated with a null character ('\0') and can contain data that is not in American Standard Code for Information Interchange (ASCII) format. Therefore, the buffer-manipulation routines always take a length or count argument. Function declarations for the buffer-manipulation routines are given in the include files MEMORY.H and STRING.H, except for the _swab function, which appears in STDLIB.H.

Use the following routines to perform these tasks. Routines beginning with _f are 16-bit specific and model independent; the _f stands for far. These routines are useful in writing mixed-model programs because they can be called from any 16-bit program, regardless of the memory model being used.

»_memccpy,« »_fmemccpy«

Copy characters from one buffer to another until a given character or a given number of characters has been copied

»memchr,« »_fmemchr«

Return a pointer to the first occurrence, within a specified number of characters, of a given character in the buffer

»memcmp,« »_fmemcmp«

Compare a specified number of characters from two buffers

»memcpy,« »_fmemcpy«

Copy a specified number of characters from one buffer to another

»_memicmp,« »_fmemicmp«

Compare a specified number of characters from two buffers without regard to the case of the letters (uppercase and lowercase treated as equivalent)

»memmove,« »_fmemmove«

Copy a specified number of characters from one buffer to another

»memset,« »_fmemset«

Use a given character to initialize a specified number of bytes in the buffer

»_swab«

Swaps bytes of data and stores them at the specified location

When the source and target areas overlap, only the memmove and _fmemmove functions are guaranteed to copy the full source properly. (The memcpy and _fmemcpy routines do not always copy the full source in such cases.)


Character Classification and Conversion Routines
  2.2  Character Classification and Conversion

The character classification and conversion routines make it possible for you to test individual characters in a variety of ways and to convert between uppercase and lowercase characters:

»isalnum,« »iswalnum«

Test for alphanumeric character

»isalpha,« »iswalpha«

Test for alphabetic character

»__isascii,« »__iswascii«

Test for ASCII character

»iscntrl,« »__iswcntrl«

Test for control character

»__iscsym«

Tests for letter, underscore, or digit

»__iscsymf«

Tests for letter or underscore

»isdigit,« »iswdigit«

Test for decimal digit

»isgraph,« »iswgraph«

Test for printable character except space

»isleadbyte«

Tests for multibyte character

»islower,« »iswlower«

Test for lowercase character

»isprint,« »iswprint«

Test for printable character

»ispunct,« »iswpunct«

Test for punctuation character

»isspace,« »iswspace«

Test for white-space character

»isupper,« »iswupper«

Test for uppercase character

»isxdigit,« »iswxdigit«

Test for hexadecimal digit

»__toascii«

Converts character to ASCII code

»tolower,« »towlower«

Test character and convert to lowercase if uppercase

»_tolower«

Converts character to lowercase (unconditional)

»toupper,« »towupper«

Test character and convert to uppercase if lowercase

»_toupper«

Converts character to uppercase (unconditional)

The classification routines identify characters by finding them in a table of classification codes. Using these routines to classify characters is generally faster than writing a test expression such as the following:

if ((c >= 0) || (c <= 0x7f))

All of these routines are implemented in two versions: as functions and as macros. The function prototypes and macro definitions appear in CTYPE.H. »Choosing Between Functions and Macros« explains how to choose the appropriate version. The toupper and tolower functions are also declared in the STDLIB.H header file.


Data Conversion Routines
  2.3  Data Conversion

The data-conversion routines convert numbers to strings of ASCII characters and vice versa. These routines are implemented as functions, all of which are declared in the include file STDLIB.H. The atof function is also declared in MATH.H.

»abs«

Finds absolute value of integer

»atof«

Converts string to float

»atoi«

Converts string to int

»atol«

Converts string to long

»_atold«

Converts string to long double

»_ecvt«

Converts double to string

»_fcvt«

Converts floating-point number to string

»_gcvt«

Converts floating-point number to string and stores it in a buffer

»_itoa«

Converts int to string

»labs«

Finds absolute value of long integer

»_ltoa«

Converts long to string

»strtod,« »wcstod«

Convert string to double

»strtol,« »wcstol«

Converts string to a long integer

»_strtold«

Converts string to long double

»strtoul,« »wcstoul«

Convert string to an unsigned long integer

»_ultoa«

Converts unsigned long to string


Directory Control Routines
  2.4  Directory Control

The directory-control routines let a program access, modify, and obtain information about the directory structure. These routines are functions and are declared in DIRECT.H.

»_chdir«

Changes current working directory

»_chdrive«

Changes current drive

»_getcwd«

Gets current working directory for the default drive

»_getdcwd«

Gets current working directory for the specified drive

»_getdrive«

Gets current (default) drive

»_mkdir«

Makes a new directory

»_rmdir«

Removes a directory

»_searchenv«

Searches for a given file on specified paths


File Handling Routines
  2.5  File Handling

Using the file-handling routines, you can create, manipulate, and delete files. These routines also set and check file-access permissions. They work on a file designated by a path or by a "file handle," an integer assigned by the operating system that identifies an open file; they modify or give information about the designated file. Most of them are declared in the include file IO.H, with the exceptions being the _fstat and _stat functions (declared in SYS\STAT.H), the _fullpath routine (declared in DIRECT.H), and the remove and rename functions (also declared in STDIO.H).

»_access«

Checks file-permission setting

»_chmod«

Changes file-permission setting

»_chsize«

Changes file size

»_filelength«

Gets file length

»_fstat«

Gets file-status information on handle

»_fullpath«

Makes an absolute path from a relative path

»_get_osfhandle«

Returns the operating system file handle associated with an existing C run-time stream FILE pointer.

»_isatty«

Checks for character device

»_locking«

Locks areas of file (available with MS-DOS versions 3.0 and later)

»_makepath«

Merges path components into a single, full path

»_mktemp«

Creates a unique filename

»_open_osfhandle«

Associates a C run-time file handle with an existing operating system file handle.

»remove«

Deletes a file

»rename«

Renames a file

»_setmode«

Sets the file-translation mode

»_splitpath«

Splits a path into component pieces

»_stat«

Gets file-status information on the named file

»_umask«

Sets the default-permission mask

»_unlink«

Deletes a file

The _access, _chmod, _fullpath, _makepath, remove, rename, _splitpath, _stat, and _unlink routines operate on files specified by a path or filename. The _chsize, _filelength, _fstat, _isatty, _locking, and _setmode routines work with files designated by a file handle.

The _mktemp and _umask routines have functions that are slightly different from the other routines. The _mktemp routine creates a unique filename; you can use _mktemp to create unique filenames that do not conflict with the names of existing files. The _umask routine sets the default permission mask for any new files created in a program. The mask can override the permission setting given in the _open or _creat call for the new file.


  2.6  Generic Text

A "generic-text" function name maps to a single-byte character version or a wide-character version of a function, depending upon whether the constant _UNICODE has been defined using the #define directive. Generic-text function names provide this versatility for many functions in the categories of character classification and conversion, input and output, and string manipulation. Note that generic-text function names are Microsoft extensions that should not be used when ANSI compatibility is desired. The generic-text function names map as listed in Table 2.1.

Table 2.1    Generic-text Function Name Mappings

Generic-text Function Name	_UNICODE Not Defined	_UNICODE  Defined
_ftprintf	fprintf	fwprintf
_ftscanf	fscanf	fwscanf
_istalnum	isalnum	iswalnum
_istalpha	isalpha	iswalpha
_istascii	isascii	iswascii
_istcntrl	iscntrl	iswcntrl
_istdigit	isdigit	iswdigit
_istgraph	isgraph	iswgraph
_istlower	islower	iswlower
_istprint	isprint	iswprint
_istpunct	ispunct	iswpunct
_istspace	isspace	iswspace
_istupper	isupper	iswupper
_istxdigit	isxdigit	iswxdigit
_sntprintf	_snprintf	_snwprintf
_stprintf	sprintf	swprintf
_stscanf	sscanf	swscanf
_totlower	tolower	towlower
_totupper	toupper	towupper
_vftprintf	vfprintf	vfwprintf
_vsntprintf	_vsnprintf	_vsnwprintf
_vstprintf	vsprintf	vswprintf
_vtprintf	vprintf	vwprintf
_tcscat	strcat	wcscat
_tcschr	strchr	wcschr
_tcscmp	strcmp	wcscmp
_tcscoll	strcoll	wcscoll
_tcscpy	strcpy	wcscpy
_tcscspn	strcspn	wcscspn
_tcsdup	_strdup	_wcsdup
_tcsicmp	_stricmp	_wcsicmp
_tcsicoll	_stricoll	_wcsicoll
_tcslen	strlen	wcslen
_tcslwr	_strlwr	_wcslwr
_tcsncat	strncat	wcsncat
_tcsncmp	strncmp	wcsncmp
_tcsncpy	strncpy	wcsncpy
_tcsnicmp	_strnicmp	_wcsnicmp
_tcsnset	_strnset	_wcsnset
_tcspbrk	strpbrk	wcspbrk
_tcsrchr	strrchr	wcsrchr
_tcsrev	_strrev	_wcsrev
_tcsset	_strset	_wcsset
_tcsspn	strspn	wcsspn
_tcsstr	strstr	wcsstr
_tcstod	strtod	wcstod
_tcstok	strtok	wcstok
_tcstol	strtol	wcstol
_tcstoul	strtoul	wcstoul
_tcsupr	_strupr	_wcsupr
_tcsxfrm	strxfrm	wcsxfrm
_tprintf	printf	wprintf
_tscanf	scanf	wscanf


  2.7  Graphics (16-bit Specific)

The Microsoft 16-bit run-time library includes a set of graphics routines that offer a wide variety of graphics functions, low-level graphics primitives, font functions, and presentation graphics (displays such as graphs and pie charts). Note that these functions are not supported in Windows NT. Graphics functions are supplied in two libraries that must be explicitly linked with your program. The GRAPHICS.LIB library provides support for low-level graphics and character-font routines. The PGCHART.LIB library supports presentation-graphics routines.


Graphics Routines
  Low-Level Graphics and Character-Font (16-bit Specific)

The low-level graphics and font functions are declared in the include file GRAPH.H. The library can be divided into eight categories, which correspond to different tasks involved in creating and manipulating graphic objects. The following sections explain each of these categories.


Configuring Mode and Environment Routines
  Configuring Mode and Environment

The following routines configure the mode and environment, establish the graphics or text mode of operation, determine the current graphics environment, and control the display of the cursor:

»_clearscreen«

Erases the screen and fills it with the current background color

»_getactivepage«

Gets the current active page number

»_getbkcolor«

Returns the current background color

»_getvideoconfig«

Obtains the status of current graphics environment

»_getvisualpage«

Gets the current visual page number

»_grstatus«

Returns the status of the most recent graphics function call

»_setactivepage«

Sets the memory area for the active page for writing images

»_setbkcolor«

Sets the current background color

»_settextrows«

Sets the number of text rows

»_setvideomode«

Selects an operating mode for the display screen

»_setvideomoderows«

Sets the video mode and the number of rows for text operations

»_setvisualpage«

Sets memory area for the current visual page


Setting Coordinates Routines
  Setting Coordinates

The "set coordinates" routines set the current text or graphics position and convert pixel coordinates between the various graphics coordinate systems. The Microsoft graphics functions recognize three sets of coordinates:

•	Fixed physical coordinates

•	View coordinates defined by the application

•	Window coordinates that can include floating-point values

The functions in this category establish window and view coordinate systems and translate between physical, view, and window coordinate systems:

»_getcurrentposition«

Determines the current position in view coordinates

»_getcurrentposition_w«

Determines the current position in window coordinates

»_getphyscoord«

Converts view coordinates to physical coordinates

»_getviewcoord«

Converts physical coordinates to view coordinates

»_getviewcoord_w«

Converts window coordinates to view coordinates

»_getviewcoord_wxy«

Converts window coordinates in _wxycoord structure to view coordinates

»_getwindowcoord«

Converts view coordinates to window coordinates

»_setcliprgn«

Limits graphic output to a region of the screen

»_setvieworg«

Positions the view-coordinate origin

»_setviewport«

Limits graphics output to a region of the screen and positions the view-coordinate origin to the upper-left corner of that region

»_setwindow«

Defines a floating-point window coordinate system

The default view coordinate system is identical to the physical screen coordinate system. The physical origin (0,0) is always in the upper-left corner of the display. The x-axis extends in the positive direction left to right, while the y-axis extends in the positive direction top to bottom.

The physical horizontal and vertical dimensions depend on the hardware display configuration and the selected mode. These values are accessible at run time by examining the numxpixels and numypixels fields of the _videoconfig structure returned by the _getvideoconfig routine, listed in the previous section, »Configuring Mode and Environment.« Using the _setvieworg function, you can move the viewport origin to a new position relative to the physical screen. (The "viewport" is an alternative drawing surface with an arbitrary coordinate system that can be mapped to the screen and that "clips," or excludes, areas beyond its boundaries.)

Routines that refer to coordinates on the physical screen or viewport require integer values. However, in real-world graphing applications, you might want to use floating-point values, such as stock prices or average rainfall. Using the window coordinate system, you can display graphics using floating-point values instead of integers.

Using the _getcurrentposition and _getcurrentposition_w routines, you can determine the location of the current graphics-output point. The _setcliprgn function defines a restricted active display area on the screen. The _setviewport function does the same thing and also resets the viewport origin to the upper-left corner of the restricted active display area.

The physical coordinates of any view-coordinate point can be determined with the _getphyscoord function, and the view coordinates of any physical point can be determined with the _getviewcoord function. The view coordinates of any window coordinate can be determined with the _getviewcoord_w and _getviewcoord_wxy functions. The window coordinates of any view coordinate can be determined with the _getwindowcoord function. The _setwindow function defines the current viewport as a real-coordinate window bound by the specified floating-point values.


Setting Low-Level Palette Routines
  Setting Low-Level Graphics Palettes

Use the low-level palette routines to select or remap color palettes:

»_remapallpalette«

Changes all color indexes in the current palette

»_remappalette«

Changes a single color index in the current palette

»_selectpalette«

Selects a predefined palette

Some video modes support a "color palette," which is a table of the color values that can be displayed together on the screen at any given time. A "color value" is a long integer representing a color that can be displayed on your system.

In CGA color graphics modes, you can use the _selectpalette routine to choose one of several predefined palettes. On EGA, MCGA, VGA, and SVGA video systems, you can "remap" (change) the palette using the _remappalette or _remapallpalette routines. For instance, the EGA _ERESCOLOR mode offers a total of 64 color values, of which 16 can be displayed at a time. In this mode, the palette contains 16 "color indices," or slots to which you can assign color values.

The _remappalette routine changes a single color index to a specified color value. The _remapallpalette routine changes all of the available palette entries simultaneously.


Setting Attributes Routines
  Setting Attributes

The low-level output functions that draw lines, arcs, ellipses, and other basic figures do not specify color or line-style information. Instead, the low-level graphics functions rely on a set of attributes that are set independently by the following functions:

»_getarcinfo«

Determines the endpoints in viewport coordinates of the most recently drawn arc or pie

»_getcolor«

Gets the color

»_getfillmask«

Gets the fill mask

»_getlinestyle«

Gets the line-style mask

»_getwritemode«

Gets the logical write mode

»_setcolor«

Sets the color

»_setfillmask«

Sets the fill mask

»_setlinestyle«

Sets the line-style mask

»_setwritemode«

Sets the logical write mode for line drawing

The _getcolor and _setcolor functions get or set the current color index for graphics and font output. The _getbkcolor and _setbkcolor functions get or set the current background color. (The _getbkcolor and _setbkcolor functions are listed in »Configuring Mode and Environment.«) The _getfillmask and _setfillmask functions get or set the current fill mask. The mask is an 8-by-8-bit template array, with each bit representing a pixel. If a bit is 0, the pixel in memory is left untouched, as the mask is transparent to that pixel. If a bit is 1, the pixel is assigned the current color value. The template is repeated as necessary over the entire fill area.

The _getlinestyle and _setlinestyle functions get or set the current line style. The line style is determined by a 16-bit template buffer with each bit corresponding to a pixel. If a bit is 1, the pixel is set to the current color. If a bit is 0, the pixel is not changed. The template is repeated for the length of the line.

The _getwritemode and _setwritemode functions get or set the logical write mode for straight-line drawing. The default mode, _GPSET, causes lines to be drawn in the current graphics color. Other modes combine the current graphics color and the original screen image using various logical operations.


Creating Graphics Output Routines
  Creating Graphics Output

The graphics output functions use a set of specified coordinates and draw various figures. They use the current or default attributes for line-style mask, fill mask, write mode, background color, and foreground color. The name of each function announces its task or the figure it draws, as the following list indicates:

»_arc,« »_arc_w,« »_arc_wxy«

Draw an arc

»_ellipse,« »_ellipse_w,« »_ellipse_wxy«

Draw an ellipse or circle

»_floodfill,« »_floodfill_w«

Flood-fill an area of the screen with the current color

»_getpixel,« »_getpixel_w«

Obtain a pixel's color

»_lineto,« »_lineto_w«

Draw a line from the current graphic-output position to a specified point

»_moveto,« »_moveto_w«

Move the current graphic-output position to a specified point

»_pie,« »_pie_w,« »_pie_wxy«

Draw a pie-slice-shaped figure

»_polygon,« »_polygon_w,« »_polygon_wxy«

Draw or scan-fill a polygon

»_rectangle,« »_rectangle_w,« »_rectangle_wxy«

Draw or scan-fill a rectangle

»_setpixel,« »_setpixel_w«

Set a pixel's color

Most of these routines are available in several forms, which are indicated by their names. Output functions without a suffix use the view coordinate system. Functions that end with _w take double values as arguments and use the window coordinate system. Functions that end with _wxy use _wxycoord structures to define the coordinates and use the window coordinate system.

Circular figures, such as arcs and ellipses, are centered within a "bounding rectangle" specified by two points that define the diagonally opposed corners of the rectangle. The center of the rectangle becomes the center of the figure, and the rectangle's borders determine the size of the figure.


Creating Text Output Routines
  Creating Text Output

The next group of routines provides text output in both graphics and text modes. Unlike the standard console I/O library routines, these functions recognize text-window boundaries and use the current text color.

»_displaycursor«

Sets the cursor on or off upon exit from a graphics routine

»_gettextcolor«

Gets the text color

»_gettextcursor«

Returns the cursor attribute (text modes only)

»_gettextposition«

Obtains the text-output position

»_gettextwindow«

Gets the text window boundaries

»_outmem«

Prints text of a specified length from a memory buffer

»_outtext«

Prints a text string to the screen at the text position

»_scrolltextwindow«

Scrolls the text window up or down

»_settextcolor«

Sets the text color

»_settextcursor«

Sets the cursor attribute (text modes only)

»_settextposition«

Relocates the text position

»_settextwindow«

Defines the text-display window

»_wrapon«

Enables or disables line wrap

The _outtext and _outmem routines provide no formatting. If you want to output integer or floating-point values, you must convert the values into a string variable (using the sprintf function) before calling these routines. The _outtext routine recognizes the \n (newline character) and \r (carriage return) sequences. The _outmem routine treats these sequences as printable graphics characters.


Transferring Images Routines
  Transferring Images

The functions in this category transfer screen images between memory and the screen, using a buffer allocated by the application, or determine the size in bytes of the buffer needed to store a given image. The functions that end with _w or _wxy use window coordinates; the other functions in this set use view coordinates.

»_getimage,« »_getimage_w,« »_getimage_wxy«

Store a screen image in memory

»_imagesize,« »_imagesize_w,« »_imagesize_wxy«

Return the size (in bytes) of the buffer needed to store the image

»_putimage,« »_putimage_w«

Retrieve an image from memory and display it

In some cases, the buffer needed to store an image with the _getimage functions must be larger than 64K (65,534) bytes. Use the _halloc routine to allocate a buffer larger than 64K.


Displaying Fonts Routines
  Displaying Fonts

The functions listed in this section control the display of font-based characters on the screen:

»_getfontinfo«

Obtains the current font characteristics

»_getgtextextent«

Determines the width in pixels of specified text in the font

»_getgtextvector«

Gets orientation of font text output

»_outgtext«

Outputs text in the current font to the screen at the specified pixel position

»_registerfonts«

Initializes the font library

»_setfont«

Finds a single font that matches a specified set of characteristics and makes this font the current font for use by the _outgtext function

»_setgtextvector«

Sets the orientation for font text output

»_unregisterfonts«

Frees memory allocated by _registerfonts


Presentation-Graphics Functions
  Presentation-Graphics Functions (16-bit Specific)

The presentation-graphics functions are declared in the PGCHART.H include file. The library can be divided into the three categories listed, corresponding to the different tasks involved in creating and manipulating graphic objects.


  Displaying Presentation Graphics

The routines listed in this section initialize the presentation-graphics library and display the specified graph type.

Because the _pg_initchart routine initializes the presentation-graphics library, it must be called before any other function in the presentation-graphics library. The _pg_defaultchart function initializes the variables in the chart environment. The other routines in this category display the specified graph. The single-series versions plot one set of data, and the multiseries versions (those ending with an ms suffix) plot several sets of data in the same chart style.

Presentation-graphics programs can display text in different font sizes by taking advantage of font-based characters (see the section "Displaying Fonts," previous). Call the _registerfonts and _setfont routines to select a font before calling the _pg_initchart routine. Subsequent charts use the selected font. You can later call the _unregisterfonts routine to restore the default character font and free the memory previously allocated for fonts.

Note  If your program uses the alternate math package—if it is compiled with /FPa—it cannot use the PGCHART.LIB module.

Specific presentation-graphics functions' uses:

»_pg_chart«

Displays a single-series bar, column, or line chart

»_pg_chartms«

Displays a multiseries bar, column, or line chart

»_pg_chartpie«

Displays a pie chart

»_pg_chartscatter«

Displays a scatter diagram for a single series of data

»_pg_chartscatterms«

Displays a scatter diagram for more than one series of data

»_pg_defaultchart«

Initializes all variables in the chart environment that are necessary for a specified chart type

»_pg_initchart«

Initializes the presentation-graphics library


Analyzing Presentation Graphic Data Routines
  Analyzing Presentation Graphics Charts

Presentation graphic data routines calculate default values for the specified graph type but do not display the chart.

»_pg_analyzechart«

Analyzes a single series of data for a bar, column, or line chart

»_pg_analyzechartms«

Analyzes a multiseries of data for a bar, column, or line chart

»_pg_analyzepie«

Analyzes data for a pie chart

»_pg_analyzescatter«

Analyzes a single series of data for a scatter diagram

»_pg_analyzescatterms«

Analyzes a multiseries of data for a scatter diagram


Manipulating Presentation Graphics Structures Routines
  Manipulating Presentation Graphics Structures

These functions control low-level aspects of the presentation-graphics package:

»_pg_getchardef«

Retrieves the 8-by-8-pixel bitmap for a specified character

»_pg_getpalette«

Retrieves colors, line styles, fill patterns, and plot characters for all presentation-graphics palettes

»_pg_getstyleset«

Retrieves the contents of the styleset

»_pg_hlabelchart«

Writes text horizontally on the screen

»_pg_resetpalette«

Sets current colors, line styles, fill patterns, and plot characters to the default values for the current screen mode

»_pg_resetstyleset«

Resets the contents of the current styleset to the default value for the current screen mode

»_pg_setchardef«

Sets the 8-by-8-pixel bitmap for a specified character

»_pg_setpalette«

Sets current colors

»_pg_setstyleset«

Sets the contents of the styleset

»_pg_vlabelchart«

Writes text vertically on the screen


Input and Output (I/O) Routines
  2.8  Input and Output

The input and output (I/O) routines make it possible for you to read and write data to and from files and devices. In C, there are no predefined file structures; all data items are treated as sequences of bytes. Three types of I/O functions are available:

•	Stream

•	Low-level

•	Console and Port

The stream I/O functions treat data as a stream of individual characters. By choosing among the many stream functions available, you can process data in different sizes and formats, from single characters to large data structures. Stream I/O also provides buffering, which can significantly improve performance.

The low-level I/O routines do not perform buffering and formatting. Instead, they invoke the operating system's input and output capabilities directly. Using these routines, you can access files and peripheral devices at a more basic level than the stream functions.

The console and port I/O routines make it possible for you to read or write directly to a console (keyboard and screen) or an I/O port (such as a printer port). The port I/O routines simply read and write data in bytes. With console I/O routines, some additional options are available, such as detecting whether a character has been typed at the console. You can also choose between echoing characters to the screen as they are read or reading characters without echoing.

The run-time library also provides a number of direct MS-DOS I/O system-call routines. These are for MS-DOS application programs only, and are described in »System Calls.«

You can perform file I/O operations in two modes: text and binary. The following section describes these modes and their uses. You can also ensure that the fflush and _flushall routines write data to storage media rather than to just the operating system's buffers. For more information, see »Stream Routines.«

Warning  Because stream routines are buffered and low-level routines are not, the two types of routines are generally incompatible. You should use either stream or low-level routines consistently for processing a given file.


  Text and Binary Modes

Many C and C++ programs use data files for input and output; data files are usually processed in text mode. In this mode, each carriage-return − linefeed (CR-LF) combination is translated into a single linefeed character during input. During output, each linefeed character is translated into a CR-LF combination. Sometimes you may want to process a file without making those translations. In these cases you use binary mode, which suppresses CR-LF translations.

When the wide character stream input/output functions (the fwprintf and fwscanf family) are used on a stream operating in text mode, the external file is assumed to be a sequence of multibyte characters. Therefore, in addition to the carriage-return − linefeed translation, the wide character stream input functions convert multibyte characters to wide characters (as if by a call to the mbtowc function), and the wide character stream output functions convert wide characters to multibyte characters (as if by a call to the wctomb function). When the wide character stream input/output functions (the fwprintf and fwscanf family) are used on a stream operating in binary mode, the external file is assumed to be a sequence of wide characters, and no translation or conversion occurs during input or output.

You can control the file translation mode in the following ways:

•	To process a few selected files in binary mode, while retaining the default text mode for most files, you can specify binary mode when you open the selected files. The fopen routine opens a file in binary mode when you specify the letter b in the access-mode string for the file. The _open routine opens a file in binary mode when you specify the _O_BINARY flag in the oflag argument. For more information about fopen and _open, see the reference description of each routine.

•	To process most or all files in binary mode, you can change the default mode to binary. The global variable _fmode controls the default translation mode, which is usually text. If you set _fmode to _O_BINARY, the default mode is binary except for _stdaux and _stdprn, which are opened in binary mode by default.

You can change the value of _fmode in two ways:

•	Link with the file BINMODE.OBJ (supplied with this product). Linking with this file changes the initial setting of _fmode to the _O_BINARY flag, causing all files except stdin, stdout, and stderr to be opened in binary mode.

•	Change the value of _fmode directly by setting it to the _O_BINARY flag in your program. This has the same effect as linking with BINMODE.OBJ.

You can still override the default mode (now binary) for a particular file by opening it in text mode. Specify the letter t when using fopen, or specify the _O_TEXT flag when using _open.

By default, the stdin, stdout, and stderr files are opened in text mode, and the _stdaux and _stdprn files are opened in binary mode. Using the _setmode routine, you can change these defaults or change the mode of a file after it has been opened. For details, see the reference description of _setmode.


  Stream Routines

Stream I/O functions handle data as a continuous stream of characters. To use the stream functions, you must include the file STDIO.H in your program. This file defines constants, types, and structures used in the stream functions and contains function declarations and macro definitions for the stream routines.

When a file is opened for I/O using the stream functions, the opened file is associated with a structure of type FILE (defined in STDIO.H) containing basic information about the file. A pointer to the FILE structure is returned when the stream is opened. Subsequent operations use this pointer (also called the "stream pointer," or just "stream") to refer to the file.

The stream functions provide for buffered, formatted, or unformatted input and output. When a stream is buffered, data that is read from or written to the stream is collected in an intermediate storage location called a "buffer." In write operations, the output buffer's contents are written to the appropriate final location when the buffer is full, the stream is closed, or the program terminates normally. The buffer is said to be "flushed" when this occurs. In read operations, a block of data is placed in the input buffer. When the input buffer is empty, the next block of data is transferred into the buffer. Buffering produces efficient I/O because the system can transfer a large block of data in a single operation rather than performing an I/O operation each time a data item is read from or written to a stream. However, if a program terminates abnormally, output buffers may not be flushed, resulting in loss of data.

You can use the fflush and _flushall routines to ensure that the buffer associated with the specified file or all of the open buffers are flushed to the operating system. If a file was opened with fopen or _fdopen and the c flag, or if the program is linked with COMMODE.OBJ, the contents of a flushed buffer are written to disk.

Some of the constants defined in STDIO.H may be useful in your program. The manifest constant EOF is defined to be the value returned at end of file. NULL is the null pointer. FILE is the structure that maintains information about a stream. In the 16-bit run-time libraries only, BUFSIZ defines the default size of stream buffers, in bytes (in the 32-bit run-time libraries, BUFSIZ is not used to define this default size; the default size of stream buffers is 4K).

»clearerr«

Clears the error indicator for a stream

»fclose«

Closes a stream

»_fcloseall«

Closes all open streams

»_fdopen«

Associates a stream with an open file handle

»feof«

Tests for end-of-file on a stream

»ferror«

Tests for error on a stream

»fflush«

Flushes a stream

»fgetc«

Reads a character from a stream (function version)

»_fgetchar«

Reads a character from stdin (function version)

»fgetpos«

Gets the position indicator of a stream

»fgets«

Reads a string from a stream

»_fileno«

Gets the file handle associated with a stream

»_flushall«

Flushes all streams

»fopen«

Opens a stream

»fprintf,« »fwprintf«

Write formatted data to a stream

»fputc«

Writes a character to a stream (function version)

»_fputchar«

Writes a character to stdout (function version)

»fputs«

Writes a string to a stream

»fread«

Reads unformatted data from a stream

»freopen«

Reassigns a FILE pointer to a new file

»fscanf,« »fwscanf«

Read formatted data from a stream

»fseek«

Moves file position to a given location

»fsetpos«

Sets the position indicator of a stream

»_fsopen«

Opens a stream with file sharing

»ftell«

Gets current file position

»fwrite«

Writes unformatted data items to a stream

»getc«

Reads a character from a stream

»getchar«

Reads a character from stdin

»gets«

Reads a line from stdin

»_getw«

Reads a binary int item from a stream

»printf,« »wprintf«

Write formatted data to stdout

»putc«

Writes a character to a stream

»putchar«

Writes a character to stdout

»puts«

Writes a line to a stream

»_putw«

Writes a binary int item to a stream

»rewind«

Moves file position to the beginning of a stream

»_rmtmp«

Removes temporary files created by tmpfile

»scanf,« »wscanf«

Read formatted data from stdin

»setbuf«

Controls stream buffering

»setvbuf«

Controls stream buffering and buffer size

»_snprintf,« »_snwprintf«

Write formatted data of a specified length to a string

»sprintf,« »swprintf«

Write formatted data to a string

»sscanf,« »swscanf«

Read formatted data from a string

»_tempnam«

Generates a temporary filename in given directory

»tmpfile«

Creates a temporary file

»tmpnam«

Generates a temporary filename

»ungetc«

Places a character in the buffer

»vfprintf,« »vfwprintf«

Write formatted data to a stream

»vprintf,« »vwprintf«

Write formatted data to stdout

»_vsnprintf,« »_vsnwprintf«

Write formatted data of a specified length to a string

»vsprintf,« »vswprintf«

Write formatted data to a string


  Opening a Stream

A stream must be opened using the _fdopen, fopen, freopen, or _fsopen function before input and output can be performed on that stream. When opening a stream, the named stream can be opened for reading, writing, or both, and it can be opened in either text or binary mode.

The _fdopen, fopen, freopen, and _fsopen functions return a FILE pointer. You usually assign the pointer value to a variable and use the variable to refer to the opened stream. For instance, if your program contains the lines

FILE *infile
infile = fopen ("test.dat", "r");

you can use the FILE pointer variable infile to refer to the stream.


  Using Predefined Stream Pointers

When a program begins execution, the startup code automatically opens several streams: standard input, standard output, and standard error. By default, the standard input, standard output, and standard error streams are directed to the console (keyboard and screen). This means that when a program expects input from the "standard input," it receives that input from the console. Similarly, a program that writes to the "standard output" prints its data to the console. Error messages generated by the library routines are sent to the "standard error," meaning that error messages appear on the user's console.

With MS-DOS, two additional streams are opened: standard auxiliary and standard print. The assignment of standard auxiliary and standard print depends on the machine configuration. These streams usually refer to the first serial port and a printer port, but those ports may not be available on some systems. Be sure to check your machine configuration before using these streams.

You can refer to the standard streams with the following predefined stream pointers:

•	stdin    Points to the standard input stream

•	stdout    Points to the standard output stream

•	stderr    Points to the standard error stream

•	_stdaux    Points to the standard auxiliary stream (MS-DOS only)

•	_stdprn    Points to the standard print stream (MS-DOS only)

You can use these pointers in any function that requires a stream pointer as an argument. Some functions, such as getchar and putchar, are designed to use stdin or stdout automatically. The pointers stdin, stdout, stderr, _stdaux, and _stdprn are constants, not variables; do not try to assign them a new stream pointer value.

You can redirect a program's standard input and standard output at the operating-system command line. For a complete discussion of redirection, see your operating-system user's manual.

Within your program, you can use the freopen routine to redirect stdin, stdout, stderr, _stdaux, or _stdprn so that it refers to a disk file or to a device. For more information, see the reference description of freopen.


  Controlling Stream Buffering

As mentioned earlier, stream routines can use in-memory buffers to speed I/O operations. Files opened using the stream routines are buffered by default, except for _stdaux and _stdprn, which are usually unbuffered. The stdout and stderr streams are flushed whenever they are full or, if you are writing to a character device, after each library call.

By using the setbuf or setvbuf function, you can cause a stream to be unbuffered or you can associate a buffer with an unbuffered stream. Buffers allocated by the system are not accessible to you, but buffers allocated with setbuf or setvbuf refer to arrays in your program and can be manipulated. Buffers can be any size up to INT_MAX bytes, in powers of 2. This size is set by the manifest constant BUFSIZ in STDIO.H if you use seftbuf; if you use setvbuf, you can set the size of the buffer yourself. (For details, see the descriptions of setbuf and setvbuf in the reference section.)

Note  These routines affect only buffers created by the run-time library routines. They have no effect on buffers created by the operating system.


  Committing Buffer Contents to Disk

Usually, both the fflush and the _flushall functions pass the contents of a program buffer to the operating system, which can cache data before writing it to disk. In the case of a system failure, data cached by the operating system is lost. The commit-to-disk feature ensures that the flushed contents of a buffer are written to storage media. There are two ways to commit buffer contents to disk:

•	Link with the file COMMODE.OBJ (provided with this product) to set a global commit flag. The default setting of the global flag is "no-commit."

•	Set the c "commit" flag with fopen or _fdopen to open the file in commit mode. The n flag specifies the "no-commit" mode.

COMMODE.OBJ allows existing code to use the commit feature. Any file specifically opened with either the c or the n flag behaves according to the flag, regardless of the state of the global commit/no-commit flag. Thus, some files can be opened with committing contents to disk and some without.


  Closing Streams

The fclose and _fcloseall functions close a stream or streams. The fclose routine closes a single specified stream; _fcloseall closes all open streams except stdin, stdout, stderr, _stdaux, and _stdprn. If your program does not explicitly close a stream, the stream is automatically closed when the program terminates. However, it is a good practice to close a stream when your program is finished with it, as the number of streams that can be open at a given time is limited.


  Reading and Writing Data

Using the stream functions, you can transfer data in a variety of ways. You can read and write binary data (a sequence of bytes) or specify reading and writing by characters, lines, or more complicated formats.

Reading and writing operations on streams always begin at the current position of the stream, known as the "file pointer" for the stream. The file pointer is changed to reflect the new position after a read or write operation takes place. For example, if you read a single character from a stream, the file pointer is increased by one byte so that the next operation begins with the first unread character. If a stream is opened for appending, the file pointer is automatically positioned at the end of the file before each write operation.

When switching directly between output and input, there must be an intervening call to the fflush function or to a file-positioning function (fseek, fsetpos, or rewind). Input can be directly followed by output without an intervening call to a file-positioning function if the input operation encounters the end of the file.

Using the fseek and fsetpos functions, you can position the file pointer anywhere in a file. The next operation occurs at the position you specified. The rewind routine positions the file pointer at the beginning of the file. Use the ftell or fgetpos routine to determine the current position of the file pointer. The feof macro detects an end-of-file condition on a stream; once the end-of-file indicator is set, it remains set until the file is closed, or until clearerr, fseek, fsetpos, or rewind is called.

Streams associated with a character-oriented device (such as a console) do not have file pointers. Data coming from or going to a console cannot be accessed randomly. Routines that set or get the file-pointer position (such as fseek, fgetpos, fsetpos, ftell, or rewind) have undefined results if used on a stream associated with a character-oriented device.


  Detecting Errors

When an error occurs in a stream operation, an error indicator for the stream is set. You can use the ferror macro to test the error indicator and determine whether an error has occurred. Once an error has occurred, the error indicator for the stream remains set until the stream is closed, or until you explicitly clear the error indicator by calling clearerr or rewind.


  Low-Level Routines

Low-level input and output calls do not buffer or format data. Declarations for the low-level functions are given in the include files IO.H, FCNTL.H, SYS\TYPES.H, and SYS\STAT.H. Unlike the stream functions, low-level functions do not require the include file STDIO.H. However, some common constants are defined in STDIO.H; for example, the end-of-file indicator (EOF) may be useful. If your program requires these constants, you must include STDIO.H.

»_close«

Closes a file

»_commit«

Flushes a file to disk

»_creat«

Creates a file

»_dup«

Creates a second handle for a file

»_dup2«

Reassigns a handle to a file

»_eof«

Tests for end-of-file

»_lseek«

Repositions file pointer to a given location

»_open«

Opens a file

»_read«

Reads data from a file

»_sopen«

Opens a file for file sharing

»_tell«

Gets current file-pointer position

»_umask«

Sets the default-permission mask

»_write«

Writes data to a file


  Opening a File

You must open a file before performing I/O functions on it. The _open function opens a file; it can also create the file when opening it. With Windows NT and MS-DOS versions 3.0 and later, you can use _sopen to open a file with file-sharing attributes. The _creat function can create and open a file.

The file can be opened for reading, writing, or both, and it can be opened in either text or binary mode (for more information, see »Text and Binary Modes«). The include file FCNTL.H must be included when opening a file, as it contains definitions for flags used in _open. In some cases, the files SYS\TYPES.H and SYS\STAT.H must also be included; for more information, see the reference description for the »_open« function.

These functions return a file handle, which is usually assigned to an integer variable. You use the variable to refer to the opened file.


  Reading and Writing Data

Use the _read and _write routines to read and write to files. These operations begin at the current position in the file. The current position is updated each time a read or write operation occurs.

Use the _lseek function to place the file pointer anywhere in the file. The next operation occurs at the position you specified. The _tell function indicates the current position of the file pointer. The _eof routine tests for the end of the file. Character-oriented devices, such as the console, do not have file pointers. The _lseek and _tell routines have undefined results if used on a handle associated with a device. Low-level I/O routines set the errno variable when an error occurs. For more information on errno, see Chapter 3, »Global Variables and Standard Types.«


  Closing Files

The _close function closes an open file. Open files are automatically closed when a program terminates. However, it is a good practice to close a file when your program is finished with it, as there is a limit to the number of files that can be open at one time.


  Using Predefined Handles

When a program begins execution, five files are automatically opened: standard input, standard output, standard error, standard auxiliary, and standard print. Low-level routines can access these files using the following predefined handles:

Stream	Handle
stdin	0
stdout	1
stderr	2
_stdaux (MS-DOS only)	3
_stdprn (MS-DOS only)	4
You can use these file handles without previously opening the files. The files are opened and the handles are assigned when the program starts. Using the _dup and _dup2 routines, you can assign multiple handles for the same file. These routines are typically used to associate the predefined file handles with different files.

You can redirect the standard input and standard output at the operating-system command line. For a complete discussion of redirection, see your operating-system user's manual.


Increasing the Maximum Number of File Handles and Streams (16-bit Specific)

You can change the maximum number of file handles and streams that your 16-bit MS-DOS, QuickWin, or Windows-hosted program can handle. The process is simple and involves changing some constants in the startup source files, which are provided with this product, and then compiling and linking the new startup code with your program. The following sections describe the process.

Note  You must have MASM version 6.0 or later to increase the maximum number of file handles or streams.


  Increasing File Handles

MS-DOS, Windows, and QuickWin use the value of the constant _NFILE_ to establish the maximum number of available file handles. To increase the number of file handles, edit the startup source file CRT0DAT.ASM and change the line

_NFILE_ = 20

so that _NFILE_ is set to the desired maximum. For example, to increase the maximum number of available file handles to 40, change the line as shown here:

_NFILE_ = 40

CRT0DAT.ASM contains a section of conditional code that is automatically enabled when you change the value of _NFILE_.

QuickWin uses the constant _WFILE_ to establish the maximum number of available text child windows. You can edit CRT0DAT.ASM to change _WFILE_. Change the line

_WFILE_ = 20

so that _WFILE_ is set to the desired maximum. For example, to increase the maximum number of available text child windows to 40, change the line as shown here:

_WFILE_ = 40

Note  Increasing the number of file handles makes it possible for you to use low-level I/O functions, such as _open and _read, with more files. However, it does not affect the number of stream-level I/O files (that is, the number of FILE * streams).


  Increasing Streams

To increase the maximum number of streams, edit one or more of the following source files and constants:

System	Source file	Constant
MS-DOS	_FILE.C	_NFILE_
Windows and QuickWin	FILE.ASM	_NFILE_
QuickWin	WFILE.ASM	_WFILE_
For MS-DOS, Windows, and QuickWin, change the line

_NFILE_ equ 20

to set _NFILE_ to the desired maximum. For example, to allow a maximum of 40 streams, change the line as shown here:

_NFILE_ equ 40

In addition, you can change the value of the constant _WFILE_, found in WFILE.ASM, to increase the maximum number of available QuickWin text child windows. Increasing the number of streams makes it possible for you to use stream-level I/O functions, such as fopen and fread, with more files.

Note  The number of low-level file handles must be greater than or equal to the number of stream-level files. For example, if you increase the value of _NFILE_ in the module _FILE.C, you must also increase the value of _NFILE_ in the module CRT0DAT.ASM. Similarly, if you increase the value of _WFILE_ in the module WFILE.ASM, you must also increase the value of _WFILE_ in the module CRT0DAT.ASM.


  Increasing the System Limit

To use more than 20 files at a time, you must increase the file limit imposed on your process by the operating system. To increase the systemwide limit, increase the number of files available on your system as a whole by editing your system configuration file (CONFIG.SYS). For example, to allow 50 open files at a time on your system, put this statement in the configuration file:

FILES=50


  Using the Modified Startup Files

After you modify one or more of the startup source files, you need to recompile the file(s) using the batch file CSTARTUP.BAT. Be sure to read the file README.TXT, which is located in the same directory as CSTARTUP.BAT, before running the batch file.

To use a new object file, either explicitly link your program with it or replace it in the appropriate model of the run-time library. For example, after you assemble CRT0DAT.ASM, the object file is CRT0DAT.OBJ.


Console and Port I/O Routines
  Console and Port I/O

These functions perform reading and writing operations on your console or on the specified port. The _cgets, _cscanf, _getch, _getche, and _kbhit routines take input from the console, while _cprintf, _cputs, _putch, and _ungetch write to the console. The input or output of these functions can be redirected. The console and port I/O routines are implemented as functions and are declared in the include file CONIO.H.

»_cgets«

Reads a string from the console

»_cprintf«

Writes formatted data to the console

»_cputs«

Writes a string to the console

»_cscanf«

Reads formatted data from the console

»_getch«

Reads a character from the console

»_getche«

Reads a character from the console and echoes it

»_inp«

Reads one byte from the specified I/O port

»_inpd«

Reads a double word from the specified I/O port

»_inpw«

Reads a two-byte word from the specified I/O port

»_kbhit«

Checks for a keystroke at the console

»_outp«

Writes a one byte to the specified I/O port

»_outpd«

Writes one byte to the specified I/O port

»_outpw«

Writes a double word to the specified I/O port

»_putch«

Writes a character to the console

»_ungetch«

"Ungets" the last character read from the console so that it becomes the next character read

Note  Programs that need only run under MS-DOS can also use a number of direct MS-DOS I/O system calls ( _dos_open, _dos_read, _dos_close, etc.). For more information, see »MS-DOS System Calls.« These are described in detail in »System Calls.«

The console or port does not have to be opened or closed before I/O is performed, so there are no open or close routines in this category. The port I/O routines _inp and _outp read or write one byte at a time from the specified port. The _inpw and _outpw routines read and write 2-byte words, respectively. The _inpd and _outpd functions read and write 4-byte double words, respectively, and are not available in MS-DOS.

The console I/O routines make possible reading and writing of strings (_cgets and _cputs), formatted data (_cscanf and _cprintf), and characters. Several options are available when reading and writing characters. The _putch routine writes a single character to the console. The _getch and _getche routines read a single character from the console: _getche echoes the character back to the console, while _getch does not. The _ungetch routine "ungets" the last character read; the next read operation on the console begins with the "ungotten" character.

In MS-DOS, the output from the console I/O routines can be redirected at the operating system command line. In Windows NT, the output from these functions cannot be redirected; they always write to the console.

The _kbhit routine determines whether a key has been struck at the console. Using this routine, you can test for keyboard input before you attempt to read from the console.

Note  The console I/O routines are not compatible with stream or low-level library routines and should not be used with them.


Internationalization Routines
  2.9  Internationalization

Internationalization routines are useful for creating different versions of a program for international markets. These routines are declared in the header file LOCALE.H, except for strftime, which is declared in TIME.H:

»localeconv«

Sets a structure with appropriate values for formatting numeric quantities

»mblen,« »_fmblen«

Get the length and determine the validity of a multibyte character

»_mbslen«

Gets the number of multibyte characters in a multibyte wide-character string

»mbstowcs,« »_fmbstowcs«

Convert a sequence of multibyte characters to a corresponding sequence of wide characters

»mbtowc,« »_fmbtowc«

Convert a multibyte character to the corresponding wide character

»setlocale«

Selects the appropriate locale for the program

»strcoll,« »wcscoll«

Compare strings using locale-specific information

»_stricoll,« »_wcsicoll«

Compare strings using locale-specific information (case-insensitive)

»strftime,« »wcsftime«

Format a date and time string

»strxfrm,« »wcsxfrm«

Transform a string based on locale-specific information

»wcstombs,« »_fwcstombs«

Convert a sequence of wide characters to a corresponding sequence of multibyte characters

»wctomb,« »fwctomb«

Convert a wide character to the corresponding multibyte character


Math Routines
  2.10  Math

Using the math routines, you can perform common mathematical calculations. All math routines work with floating-point values and therefore require floating-point support (for more information, see »Floating-Point Support.«)

The math library provides two versions of some routines. The first version of the routine supports double arguments and return values. The second version supports an 80-bit data type, allowing the routine to take long double arguments and return a long double value. The second version usually has the same name with the suffix l. For instance, the acos routine supports double arguments and return values, while acosl supports long double arguments and return values.

Routines which support long double values are not available when you compile with the /FPa (alternate math) compiler option. The same is true of the _clear87, _control87, and _status87 routines.

Most math declarations are in the include file MATH.H. However, the _clear87, _control87, _fpreset, and _status87 routines are defined in FLOAT.H; the abs and labs functions are defined in MATH.H and STDLIB.H; and the div and ldiv routines are declared in STDLIB.H.

»acos,« »acosl«

Calculate the arccosine

»asin,« »asinl«

Calculate the arcsine

»atan,« »atanl«

Calculate the arctangent

»atan2,« »atan2l«

Calculate the arctangent

»Bessel«

Calculates Bessel functions

»_cabs,« »_cabsl«

Find the absolute value of a complex number

»ceil,« »ceill«

Find the integer ceiling

»_chgsign«

Reverses the sign of its double-precision floating-point argument

»_clear87,« »_clearfp«

Gets and clears the floating-point status word

»_control87,« »_controlfp«

Gets the old floating-point control word and sets a new control-word value

»_copysign«

Returns x with the sign of y

»cos,« »cosl«

Calculate the cosine

»cosh,« »coshl«

Calculate the hyperbolic cosine

»_dieeetomsbin«

Converts IEEE double-precision number to Microsoft (MS) binary format

»div«

Divides one integer by another, returning the quotient and remainder

»_dmsbintoieee«

Converts Microsoft binary double-precision number to IEEE format

»exp,« »expl«

Calculate the exponential function

»fabs,« »fabsl«

Find the absolute value

»_fieeetomsbin«

Converts IEEE single-precision number to Microsoft binary format

»_finite«

Tests a given double-precision floating-point value to determine whether it is finite

»floor,« »floorl«

Find the largest integer less than or equal to the argument

»fmod,« »fmodl«

Find the floating-point remainder

»_fmsbintoieee«

Converts Microsoft binary single-precision number to IEEE format

»_fpclass«

Returns a status word containing information on the floating-point class

»_fpieee_flt«

Invokes a user-defined trap handler for IEEE floating-point exceptions

»_fpreset«

Reinitializes the floating-point-math package

»frexp,« »frexpl«

Calculate an exponential value

»_hypot,« »_hypotl«

Calculate the hypotenuse of a right triangle

»_isnan«

Tests whether a given double-precision floating-point value is not a number (NAN)

»ldexp,« »ldexpl«

Calculate the product of the argument and 2**3

»ldiv«

Divides one long integer by another, returning the quotient and remainder

»log,« »logl«

Calculate the natural logarithm

»log10,« »log10l«

Calculate the base-10 logarithm

»_logb«

Extracts the exponential value of its double-precision floating-point argument

»_lrotl,« »_lrotr«

Shift an unsigned long int item left (_lrotl) or right (_lrotr)

»_matherr,« »_matherrl«

Handle math errors

»__max,« »__min«

Return the larger or smaller of two values

»modf,« »modfl«

Split the argument into integer and fractional parts

»_nextafter«

Returns the next representable neighbor

»pow,« »powl«

Calculate a value raised to a power

»rand«

Gets a pseudorandom number

»_rotl,« »_rotr«

Shift an unsigned int item left (_rotl) or right (_rotr)

»_scalb«

Scale argument by a power of 2

»sin,« »sinl«

Calculate the sine

»sinh,« »sinhl«

Calculate the hyperbolic sine

»sqrt,« »sqrtl«

Find the square root

»srand«

Initializes a pseudo-random series

»_status87,« »_statusfp«

Gets the floating-point status word

»tan,« »tanl«

Calculate the tangent

»tanh,« »tanhl«

Calculate the hyperbolic tangent

The Bessel routine does not correspond to a single function, but to 12 functions named _j0, _j1, _jn, _y0, _y1, _yn, _j0l, _j1l, _jnl, _y0l, _y1l, and _ynl.

The _matherr and _matherrl routines are invoked by the math functions when errors occur. The _matherr routine handles math functions that return a double value, and _matherrl handles routines that return a long double. You are not required to supply a definition for the _matherr routines. If no definition is present, the default error returns for each routine are used. (For a description of a routine's error returns, see the reference description of that routine.) The routines that the _matherr function handles are defined in the library, but you can redefine them for different error handling. The user-defined function, if given, must follow the rules given in the reference description of _matherr and _matherrl.


Memory Allocation Routines
  2.11  Memory Allocation

Using the memory-allocation functions, you can allocate, free, and reallocate blocks of memory. Memory-allocation math routines are declared in the include file MALLOC.H. The C++ _set_new_handler functions allow you to redefine the action of the C++ new operator and are declared in the include file NEW.H.

»_alloca«

Allocates a block of memory from the program's stack

»_bfreeseg«

Frees a based heap (16-bit specific)

»_bheapseg«

Allocates a based heap (16-bit specific)

»calloc,« »_bcalloc« (16-bit specific), »_fcalloc« (16-bit specific), »_ncalloc« (16-bit specific)

Allocate storage for an array

»_expand,« »_bexpand« (16-bit specific), »_fexpand« (16-bit specific), »_nexpand« (16-bit specific)

Expand or shrink a block of memory without moving its location

»free,« »_bfree« (16-bit specific), »_ffree« (16-bit specific), »_nfree« (16-bit specific)

Free an allocated block

»_freect«

Returns approximate number of items of given size that could be allocated in the near heap (16-bit specific)

»_halloc«

Allocates storage for huge array (16-bit specific)

»_heapadd,« »_bheapadd«

Add memory to a heap (16-bit specific)

»_heapchk,« »_bheapchk,« »_fheapchk,« »_nheapchk«

Check a heap for consistency (16-bit specific)

»_heapmin,« »_bheapmin,« »_fheapmin,« »_nheapmin«

Release unused memory in a heap (16-bit specific)

»_heapset,« »_bheapset,« »_fheapset,« »_nheapset«

Fill free heap entries with a specified value (16-bit specific)

»_heapwalk,« »_bheapwalk,« »_fheapwalk,« »_nheapwalk«

Return information about each entry in a heap (16-bit specific)

»_hfree«

Frees a block allocated by _halloc (16-bit specific)

»malloc,« »_bmalloc« (16-bit specific), »_fmalloc« (16-bit specific), »_nmalloc« (16-bit specific)

Allocate a block of memory

»_memavl«

Returns approximate number of bytes available for allocation in the near heap (16-bit specific)

»_memmax«

Returns size of largest contiguous free block in the near heap (16-bit specific)

»_msize,« »_bmsize« (16-bit specific), »_fmsize« (16-bit specific), »_nmsize« (16-bit specific)

Return size of an allocated block

»realloc,« »_brealloc« (16-bit specific), »_frealloc« (16-bit specific), »_nrealloc« (16-bit specific)

Reallocate a block to a new size

»_set_new_handler,« »_set_bnew_handler,« »_set_fnew_handler,« »_set_hnew_handler,« »_set_nnew_handler«

Enable an error-handling mechanism

»_stackavail«

Returns size of stack space available for allocation with _alloca (16-bit specific)

Some memory-management routines, such as malloc, are available in different versions that begin with _b, _f, or _n. These variations are 16-bit specific, and are described in the following section.

The malloc and free routines allocate and free memory space, respectively, while a program runs. The malloc routine allocates memory from the "heap," which is a pool of memory not otherwise used by your program. In 16-bit tiny-, small-, and medium-model programs, the heap consists of unused memory in your program's default data segment. In 16-bit compact-, large-, and huge-model programs, it is unused memory outside the default data segment. The malloc and free routines satisfy the memory-allocation requirements of most programs. More specialized memory-management routines are discussed in following sections.

The realloc and _expand routines can expand or shrink an allocated memory block. They behave differently in cases in which there is not enough room to expand the block in its current location. In these cases, realloc moves the block as needed, but _expand does not.

The calloc routine allocates memory for an array and initializes every byte in the allocated block to 0. The _halloc routine is similar to calloc, except that it can allocate memory for a huge array (one that exceeds 64K in size), and is 16-bit specific. This routine is useful when you need a very large data object, or if you need to return allocated memory to the operating system for subsequent calls to the _spawn family of functions.


  Near and Far Heaps (16-bit Specific)

As mentioned in the previous section, heap memory can reside inside or outside your program's default data segment, depending on what memory model your program uses. When heap memory lies inside the default data segment, the heap is called the "near heap," because it can be accessed with near pointers. The "far heap" is memory that spans one or more segments outside the default data segment. The far heap can be accessed only with far pointers.

In various memory models, malloc automatically allocates memory from the near heap or far heap, as appropriate. The run-time library also includes near and far versions of malloc, free, and other memory-management routines, using which you can specify the near and far heaps explicitly. These have the same names as standard memory routines but are preceded by _n (for near) or _f (for far). For instance, the _nmalloc routine always allocates memory from the near heap and returns a near pointer, no matter which memory model your program uses. (Use _nfree to release memory allocated with _nmalloc.) Similarly, _fmalloc always allocates memory from the far heap and returns a far pointer, regardless of memory model. Use the _ffree routine to release memory allocated with _fmalloc.


  Based Heaps (16-bit Specific)

You can also allocate memory from a "based heap," which is a single segment that lies outside the default data segment. Based-heap routines generally use the same names as standard memory routines but begin with _b. For instance, _bmalloc allocates a memory block from the based heap and _bfree frees the block. Based heaps offer the following advantages:

•	Localized data. Using based heaps, you can group related data in a single segment. This can simplify the management of related data.

•	Faster pointer arithmetic. Although the based heap lies in the far data segment, pointers to its data items are the same size as near pointers. Thus, pointer arithmetic on items in a based heap is faster than pointer arithmetic on items in the far heap.

The _bheapseg routine allocates a based heap segment, from which you can then allocate blocks of memory. You can call _bheapseg more than once to allocate as many based-heap segments as needed (within the confines of available memory). The _bfreeseg routine frees a based-heap segment. This routine frees every block in the based-heap segment, whether or not you previously freed the blocks individually.

Note  Near- , far- , and based-heap calls are not ANSI or Win32 compatible and make your program less portable.


Process and Environment Control Routines
  2.12  Process and Environment Control

Using the process-control routines, you can start, stop, and manage processes from within a program. Using the environment-control routines, you can get and change information about the operating-system environment.

A "process" is a program being executed by the operating system. It consists of the program's code and data, plus information about the process, such as the number of open files. Whenever you execute a program at the operating-system level, you start a process. All process-control functions except signal are declared in the include file PROCESS.H. The signal function is declared in SIGNAL.H. The abort, exit, and system functions are also declared in the STDLIB.H include file. The environment-control routines (getenv and _putenv) are declared in STDLIB.H.

»abort«

Aborts a process without flushing buffers or calling functions registered by atexit and _onexit

»assert«

Tests for logic error

»_beginthread«

Begins thread in Windows NT process.

»atexit«

Schedules routines for execution at program termination

»_cexit«

Performs the exit termination procedures (such as flushing buffers) and returns control to the calling program

»_c_exit«

Performs the _exit termination procedures and returns control to the calling program

»_cwait«

Waits until the child process terminates.

»_endthread«

Terminates a Windows NT thread.

»_execl«

Executes a child process with an argument list

»_execle«

Executes a child process with an argument list and the given environment

»_execlp«

Executes a child process using the PATH variable and an argument list

»_execlpe«

Executes a child process using the PATH variable, the given environment, and an argument list

»_execv«

Executes a child process with an argument array

»_execve«

Executes a child process with an argument array and the given environment

»_execvp«

Executes a child process using the PATH variable and an argument array

»_execvpe«

Executes a child process using the PATH variable, the given environment, and an argument array

»exit«

Calls functions registered by atexit and _onexit, then flushes all buffers and closes all open files before terminating the process

»_exit«

Terminates process without processing atexit or _onexit functions or flushing buffers

»_fatexit«

Schedules routines for execution at program termination (memory-model independent)

»_fonexit«

Schedules routines for execution at program termination (memory-model independent)

»getenv«

Gets the value of an environment variable

»_getpid«

Gets process ID number

»longjmp«

Restores a saved stack environment

»_onexit«

Schedules routines for execution at program termination

»_pclose«

Waits for a child command and closes the stream on the associated pipe

»_pipe«

Creates a pipe for reading and writing

»_popen«

Creates a pipe and executes a command

»perror«

Prints an error message

»_putenv«

Adds or changes the value of an environment variable

»raise«

Sends a signal to the calling process

»setjmp«

Saves a stack environment

»signal«

Handles an interrupt signal

»_spawnl«

Executes a child process with an argument list

»_spawnle«

Executes a child process with an argument list and the given environment

»_spawnlp«

Executes a child process using the PATH variable and an argument list

»_spawnlpe«

Executes a child process using the PATH variable, the given environment, and argument list

»_spawnv«

Executes a child process with an argument array

»_spawnve«

Executes a child process with an argument array and the given environment

»_spawnvp«

Executes a child process using the PATH variable and an argument array

»_spawnvpe«

Executes a child process using the PATH variable, the given environment, and an argument array

»system«

Executes an operating-system command

The atexit and _onexit routines create a list of functions to be executed when the calling program terminates. The only difference between the two is that atexit is part of the ANSI standard. The _onexit function is offered for compatibility with Microsoft C/C++ version 7.0 and earlier. The _exit routine terminates a process immediately, whereas exit terminates the process only after flushing buffers and calling any functions previously registered by atexit and _onexit. The _cexit and _c_exit routines are identical to exit and _exit, respectively, except that they return control to the calling program without terminating the process.

The setjmp and longjmp routines save and restore a stack environment. Using these routines, you can execute a nonlocal goto.

The _exec and _spawn routines start a new process, sometimes called the "child" process. In Windows NT, there is no such "parent-child" relationship; thus, the child process should be referred to as the "new" process. In Windows NT, the spawned process is equivalent to the spawning process, and the OS/2 wait function (which allows a parent process to wait for its children to terminate) is not available. Instead, the _cwait function can be used by any process to wait for any other process (provided the process handle is known).

The difference between the _exec and _spawn routines is that the _spawn routines are capable of returning control from the new process to its caller (the "parent" or "calling" process). Both the calling process and the new process are present in memory (unless _P_OVERLAY is specified). In the _exec routines, the new process overlays the calling process, so returning control to the calling process is impossible (unless an error occurs when attempting to start execution of the new process).

There are eight forms each of the _exec and _spawn routines (see Table 2.2). The differences among the forms involve the method of locating the file to be executed as the new process, the method for passing arguments to the new process, and the method of setting the environment.

Passing an argument list means that the arguments to the new process are listed separately in the _exec or _spawn call. Passing an argument array means that the arguments are stored in an array, and a pointer to the array is passed to the new process. The argument-list method is typically used when the number of arguments is constant or is known at compile time. The argument-array method is useful when the number of arguments must be determined at run time.

Table 2.2    Forms of the _spawn and _exec Routines

Routines	Locating the file	Argument-passing convention	Envrionment settings
_execl, _spawnl	Do not use PATH	Argument list	Inherited from calling process
_execle, _spawnle	Do not use PATH	Argument list	Pointer to environment table for new process passed as last argument
_execlp, _spawnlp	Use PATH	Argument list	Inherited from calling process
_execlpe, _spawnlpe	Use PATH	Argument list	Pointer to environment table for new process passed as last argument
_execv, _spawnv	Do not use PATH	Argument array	Inherited from calling process
_execve, _spawnve	Do not use PATH	Argument array	Pointer to environment table for new process passed as last argument
_execvp, _spawnvp	Use PATH	Argument array	Inherited from calling process
_execvpe, _spawnvpe	Use PATH	Argument array	Pointer to environment table for new process passed as last argument
The assert macro is typically used to test for logic errors. It prints a message when a given "assertion" fails to hold true. Defining the identifier NDEBUG to any value causes occurrences of assert to be removed from the source file; thus, you can turn off assertion checking without modifying the source file.


QuickWin Routines
  2.13  QuickWin (16-bit Specific)

The QuickWin functions make it possible to compile non-Windows MS-DOS programs as simple text-only Windows applications. MS-DOS programs compiled with the /Mq compiler option have a limited Windows user interface, including a standard menu bar, standard Help (for the QuickWin features), and a client (or application) window with a child (document) window for the I/O streams stdin, stdout, and stderr. You can also add other child windows of your own. QuickWin applications support the Windows Clipboard, and you can use standard C and C++ functions to write to and read from a QuickWin application's windows, which behave as streams. QuickWin also supports the graphics functions provided in the GRAPHICS.LIB run-time library.

Unless you use the functions covered in this section, you do not need to alter your program's source code. However, by using these functions in your source, you can take advantage of enhanced capabilities in your QuickWin programs.

Some restrictions exist on the kinds of MS-DOS programs that can be compiled with QuickWin. Programs that spawn processes or that use console or serial port I/O cannot take advantage of QuickWin. In addition, some run-time functions work differently in QuickWin than in MS-DOS; these functions are identified in the documentation. Also, QuickWin programs cannot be run in real mode.

QuickWin uses Windows libraries and the QWIN.LIB library. QuickWin constants, structures, and functions are declared in the Windows version of IO.H and STDIO.H. The /Mq compiler option defines the _WINDOWS constant, declared in the Windows version of STDIO.H.

»_fwopen«

Opens a new window stream

»_inchar«

Reads a single character from the keyboard

»_wabout«

Sets the string that appears in the About dialog box

»_wclose«

Closes a window's file handle

»_wgclose«

Closes an existing graphics child window

»_wgetexit«

Gets a QuickWin program's current exit behavior setting

»_wgetfocus«

Returns a file handle to the window with the input focus

»_wgetscreenbuf«

Gets a window's current screen-buffer size

»_wgetsize«

Gets a window's current size and position on the screen

»_wggetactive«

Returns a file handle to the active graphics child window

»_wgopen«

Opens a graphics child window

»_wgsetactive«

Makes a graphics child window active

»_wmenuclick«

Chooses a menu command

»_wopen«

Opens a window, returning a file handle to it

»_wsetexit«

Sets the way a QuickWin program behaves when exit is called

»_wsetfocus«

Makes a window the active window (sets its focus)

»_wsetscreenbuf«

Sets a window's screen-buffer size

»_wsetsize«

Sets a window's size and position on the screen

»_wyield«

Yields processor time to Windows for queue servicing


Searching and Sorting Routines
  2.14  Searching and Sorting

Search and sort routines provide binary-search, linear-search, and quick-sort capabilities. They are all declared in SEARCH.H.

»bsearch«

Performs a binary search

»_lfind«

Performs a linear search for a given value

»_lsearch«

Performs a linear search for a given value, which is added to an array if not found

»qsort«

Performs a quick sort


String Manipulation Routines
  2.15  String Manipulation

The string functions are declared in the include file STRING.H. Using these functions, you can compare strings, copy them, search for strings and characters, and perform various other operations. Routines beginning with _f are 16-bit specific model-independent versions of the corresponding routines and are useful in mixed-model programs. These routines can be called from any point in the program, regardless of which model is being used.

»strcat,« »wcscat,« »_fstrcat«

Append one string to another

»strchr,« »wcsrchr,« »_fstrchr«

Find first occurrence of a given character in a string

»strcmp,« »wcscmp,« »_fstrcmp«

Compare two strings

»strcpy,« »wcscpy,« »_fstrcpy«

Copy one string to another

»strcspn,« »wcscspn,« »_fstrcspn«

Find first occurrence of a character from a given character set in a string

»_strdup,« »_wcsdup,« »_fstrdup,« »_nstrdup«

Duplicate a string

»strerror«

Maps an error number to a message string

»_strerror«

Maps a user-defined error message to a string

»_stricmp,« »_wcsicmp,« »_fstricmp«

Compare two strings without regard to case

»strlen,« »wcslen,« »_fstrlen«

Find length of string

»_strlwr,« »wcslwr,« »_fstrlwr«

Convert string to lowercase

»strncat,« »wcsncat,« »_fstrncat«

Append characters of a string

»strncmp,« »wcsncmp,« »_fstrncmp«

Compare characters of two strings

»strncpy,« »wcsncpy,« »_fstrncpy«

Copy characters of one string to another

»_strnicmp,« »_wcsnicmp,« »_fstrnicmp«

Compare characters of two strings without regard to case

»_strnset,« »_wcsnset,« »_fstrnset«

Set characters of a string to a given character

»strpbrk,« »wcspbrk,« »_fstrpbrk«

Find first occurrence of a character from one string in another

»strrchr,« »wcsrchr,« »_fstrrchr«

Find last occurrence of a given character in string

»_strrev,« »_wcsrev,« »_fstrrev«

Reverse a string

»_strset,« »wcsset,« »_fstrset«

Set all characters of a string to a given character

»strspn,« »wcsspn,« »_fstrspn«

Find first substring from a given character set in a string

»strstr,« »wcsstr,« »_fstrstr«

Find first occurrence of a given string in another string

»strtok,« »wcstok,« »_fstrtok«

Find next token in a string

»_strupr,« »_wcsupr,« »_fstrupr«

Convert a string to uppercase

All string functions work on null-terminated character strings. When working with character arrays that do not end with a null character, you can use the buffer-manipulation routines, described in »Buffer Manipulation.«


  2.16  System Calls

The following routines give access to IBM-PC BIOS interrupts and MS-DOS and Windows NT operating system calls.


System Calls: BIOS Interface
  BIOS Interface (16-bit Specific)

The functions in this category provide direct access to the BIOS interrupt services. These routines are for MS-DOS application programs only.They are all declared in BIOS.H.

»_bios_disk«

Issues service requests for both hard and floppy disks, using INT 0x13

»_bios_equiplist«

Performs an equipment check, using INT 0x11

»_bios_keybrd«

Provides access to keyboard services, using INT 0x16

»_bios_memsize«

Obtains information about available memory, using INT0x12

»_bios_printer«

Performs printer output services, using INT 0x17

»_bios_serialcom«

Performs serial communications tasks, using INT 0x14

»_bios_timeofday«

Provides access to system clock, using INT 0x1A

Note  BIOS routines are hardware dependent. Some of them may not work as expected on machines whose hardware differs from the IBM PC.


System Calls: Windows NT Interface
  Windows NT Interface

The following routines are only available in the 32-bit run-time libraries, and are declared in IO.H:

»_findclose«

Releases resources from previous find operations

»_findfirst«

Finds the file with the specified attributes

»_findnext«

Finds the next file with the specified attributes


System Calls: MS-DOS Interface
  MS-DOS Interface (16-bit Specific)

Except for _FP_OFF, _FP_SEG, and _MK_FP, all these routines are implemented as functions; they are declared in DOS.H. These routines are for MS-DOS application programs only.

»_bdos«

Invokes MS-DOS system call; uses only DX and AL registers

»_chain_intr«

Chains one interrupt handler to another

»_disable«

Disables interrupts

»_dos_allocmem«

Allocates a block of memory, using MS-DOS system call 0x48

»_dos_close«

Closes a file, using MS-DOS system call 0x3E

»_dos_commit«

Flushes a file to disk, using MS-DOS system call 0x68

»_dos_creat«

Creates a new file and erases any existing file having the same name, using MS-DOS system call 0x3C

»_dos_creatnew«

Creates a new file and returns an error if a file having the same name exists, using MS-DOS system call 0x5B

»_dos_findfirst«

Finds first occurrence of a given file, using MS-DOS system call 0x4E

»_dos_findnext«

Finds subsequent occurrences of a given file, using MS-DOS system call 0x4F

»_dos_freemem«

Frees a block of memory, using MS-DOS system call 0x49

»_dos_getdate«

Gets the system date, using MS-DOS system call 0x2A

»_dos_getdiskfree«

Gets information on a disk volume, using MS-DOS system call 0x36

»_dos_getdrive«

Gets the current default drive, using MS-DOS system call 0x19

»_dos_getfileattr«

Gets current attributes of a file or directory, using MS-DOS system call 0x43

»_dos_getftime«

Gets the date and time a file was last written, using MS-DOS system call 0x57

»_dos_gettime«

Gets the current system time, using MS-DOS system call 0x2C

»_dos_getvect«

Gets the current value of a specified interrupt vector, using MS-DOS system call 0x35

»_dos_keep«

Installs terminate-and-stay-resident (TSR) programs using MS-DOS system call 0x31

»_dos_lock«

Synchronizes files and records in a mutitasking environment or network

»_dos_open«

Opens an existing file, using MS-DOS system call 0x3D

»_dos_read«

Reads a file, using MS-DOS system call 0x3F

»_dos_seek«

Moves a file pointer to a specified position in an open file, using MS-DOS system call 0x42

»_dos_setblock«

Changes the size of a previously allocated block, using MS-DOS system call 0x4A

»_dos_setdate«

Sets the current system date, using MS-DOS system call 0x2B

»_dos_setdrive«

Sets the default disk drive, using MS-DOS system call 0x0E

»_dos_setfileattr«

Sets the current attributes of a file, using MS-DOS system call 0x43

»_dos_setftime«

Sets the date and time that the specified file was last written, using MS-DOS system call 0x57

»_dos_settime«

Sets the system time, using MS-DOS system call 0x2D

»_dos_setvect«

Sets a new value for the specified interrupt vector, using MS-DOS system call 0x25

»_dos_write«

Sends output to a file, using MS-DOS system call 0x40

»_dosexterr«

Obtains in-depth error information from MS-DOS system call 0x59

»_enable«

Enables interrupts

»_FP_OFF«

Returns offset portion of a far pointer

»_FP_SEG«

Returns segment portion of a far pointer

»_harderr«

Establishes a hardware error handler

»_hardresume«

Returns to MS-DOS after a hardware error

»_hardretn«

Returns to the application after a hardware error

»_int86«

Invokes MS-DOS interrupts

»_int86x«

Invokes MS-DOS interrupts with segment register values

»_intdos«

Invokes MS-DOS system call

»_intdosx«

Invokes MS-DOS system call with segment register values

»_MK_FP«

Makes a far pointer from the segment value and the offset value

»_segread«

Returns current values of segment registers

The _dosexterr function obtains and stores the error information returned by MS-DOS system call 0x59 (extended error handling). This function is provided for use with MS-DOS versions 3.0 and later.

The _bdos routine is useful for invoking MS-DOS calls that use either or both of the DX (DH/DL) and AL registers for arguments. However, _bdos should not be used to invoke system calls that return an error code in AX if the carry flag is set; because your program cannot detect whether the carry flag is set, it cannot determine whether the value in AX is a legitimate value or an error value. In this case, the _intdos routine should be used instead, because it allows the program to detect whether the carry flag is set. The _intdos routine can also be used to invoke MS-DOS calls that use registers other than DX and AL.

The _intdosx routine is similar to the _intdos routine but is used when ES is required by the system call, when DS must contain a value other than the default data segment (for instance, when a far pointer is used), or when making the system call in a large-model program. When calling _intdosx, give an argument that specifies the segment values to be used in the call.

The _int86 routine can be used to invoke any interrupt. The _int86x routine is similar; however, like the _intdosx routine, it is designed to work with large-model programs and far items, as described in the preceding paragraph.

The _FP_OFF and _FP_SEG routines make possible easy access to the segment and offset portions of a far pointer value. The _MK_FP routine builds a far pointer from segment and offset values. _FP_OFF, _FP_SEG, and _MK_FP are implemented as macros and defined in DOS.H. The argument to _FP_SEG and _FP_OFF must be a far pointer variable. It cannot be an array name, or a near pointer cast to a far pointer.

The _segread routine returns the current values of the segment registers. This routine is typically used with the _intdosx and _int86x routines to obtain the correct segment values.

The _chain_intr routine is useful for chaining interrupt handlers together. The _enable routine enables interrupts, while the _disable routine disables interrupts.

The routines prefixed with _dos_ are all direct system interfaces that use the system calls noted above. More detailed information on these system calls can be found in the MS-DOS Encyclopedia (Duncan, Ray, ed.; Redmond, WA: Microsoft Press, 1988) or the Programmer's PC Sourcebook 2d ed. (Hogan, Thom; Redmond, WA: Microsoft Press, 1991).

Note  The MS-DOS interface I/O routines are generally incompatible with console, low-level, and stream I/O routines. Do not mix different types of I/O routines in the same source file.


Time Routines
  2.17  Time

Using the time functions, you can obtain the current time, then convert and store it according to your particular needs. The current time is always taken from the system time.

»asctime«

Converts time from type struct tm to a character string

»clock«

Returns the elapsed CPU time for a process

»ctime«

Converts time from type time_t to a character string

»difftime«

Computes the difference between two times

»_ftime«

Puts current system time in variable of type struct _timeb

»_futime«

Sets the modification time on an open file.

»gmtime«

Converts time from type time_t to struct tm

»localtime«

Converts time from type time_t to struct tm with local correction

»mktime«

Converts time to a calendar value

»_strdate«

Returns the current system date as a string

»_strtime«

Returns the current system time as a string

»time«

Gets current system time as type time_t

»_tzset«

Sets external time variables from the environment time variable

»_utime«

Sets file-modification time

The time and _ftime functions return the current time as the number of seconds elapsed since midnight on January 1, 1970, Universal coordinated time (also known as Greenwich mean time or GMT). This value can be converted, adjusted, and stored in a variety of ways by using the asctime, ctime, gmtime, localtime, and mktime functions. The _utime function sets the modification time for a specified file, using either the current time or a time value stored in a structure.

Note  In versions of Microsoft C/C++ prior to 7.0, and in this product, the time and _ftime functions return the current time as the number of seconds elapsed since midnight on January 1, 1970. However, in Microsoft C/C++ version 7.0, the time and _ftime functions returned the current time as the number of seconds elapsed since midnight on December 31, 1899.

The clock function returns the elapsed CPU time for the calling process.

The _ftime function requires two files: SYS\TYPES.H and SYS\TIMEB.H. It is declared in SYS\TIMEB.H. The _utime function also requires two include files: SYS\TYPES.H and SYS\UTIME.H. It is declared in SYS\UTIME.H. The remainder of the time functions are declared in the include file TIME.H. When you want to use _ftime or localtime to make adjustments for local time, you must define an environment variable named TZ. For more information on TZ and the global variables _daylight, _timezone, and _tzname, refer to »_daylight, _timezone, and _tzname.« TZ is also described on the »_tzset« reference page in Part 2 of this book.

The _strdate and _strtime routines return strings containing the current date and time, respectively, in the MS-DOS and Windows date and time format rather than in the UNIX-style formats. The strftime function is useful for creating international versions of a program. See »Internationalization.«


Variable-Length Argument Lists
  2.18  Variable-Length Argument Lists

The va_arg, va_end, and va_start routines are macros that provide a portable way to access the arguments to a function when the function takes a variable number of arguments. Two versions of the macros are available: the macros defined in the VARARG.H include file, which are compatible with the UNIX System V definition, and the macros defined in STDARG.H, which conform to the ANSI C standard.

»va_arg«

Retrieves argument from list

»va_end«

Resets pointer

»va_start«

Sets pointer to beginning of argument list


Virtual Memory Allocation Routines
  2.19  Virtual Memory Allocation

Using the virtual memory functions, you can allocate, free, reallocate, lock, and unlock blocks of memory. The virtual memory functions are declared in the include file VMEMORY.H.

»_vfree«

Frees an allocated block of virtual memory

»_vheapinit«

Initializes the virtual memory manager

»_vheapterm«

Terminates the virtual memory manager

»_vload«

Loads an allocated block of virtual memory

»_vlock«

Locks an allocated block of virtual memory

»_vlockcnt«

Returns the number of locks held on a block of virtual memory

»_vmalloc«

Allocates a block of virtual memory

»_vmsize«

Returns the size of an allocated block of virtual memory

»_vrealloc«

Reallocates a block of virtual memory to a new size

»_vunlock«

Unlocks a locked block of virtual memory

The _vheapinit function specifies how much MS-DOS memory the virtual memory manager can use and whether it should use expanded memory, extended memory, or disk storage. You must call this function before calling any of the other virtual memory functions. The _vmalloc function returns a handle of type _vmhnd_t, which is used to refer to a block of virtual memory. The _vfree, _vrealloc, _vload, _vlock, _vunlock, _vlockcnt, and _vmsize functions work on blocks of virtual memory specified by handles of type _vmhnd_t. The _vheapterm function frees all the resources used by the virtual memory manager. You must call this function after you have finished using virtual memory.


  2.20  Wide Character

A wide character is a 16-bit multilingual character code. Any character in use in modern computing worldwide, including technical symbols and special publishing characters, can be represented according to the Unicode specification as a wide character. Whereas a single-byte character is of type char, a wide character is of type wchar_t. Because every wide character is always represented in a fixed size of 16 bits, using wide characters simplifies programming with international character sets.

The following functions are wide-character versions of standard single-byte character functions. Each of these functions is described in the section that describes its counterpart single-byte character function.

»iswalnum«

Tests for alphanumeric character

»iswalpha«

Tests for alphabetic character

»__iswascii«

Tests for ASCII character

»__iswcntrl«

Tests for control character

»iswdigit«

Tests for decimal digit

»iswgraph«

Tests for printable character except space

»iswlower«

Tests for lowercase character

»iswprint«

Tests for printable character

»iswpunct«

Tests for punctuation character

»iswspace«

Tests for white-space character

»iswupper«

Tests for uppercase character

»iswxdigit«

Tests for hexadecimal digit

»_mbslen,« »_fmbslen«

Gets the number of multibyte characters in a multibyte wide-character string

»towlower«

Test character and convert to lowercase if uppercase

»towupper«

Test character and convert to uppercase if lowercase

»wcscat«

Appends one wide-character string to another

»wcschr«

Finds first occurrence of a given wide character in a string

»wcschr«

Compare two wide-character strings

»_wcsicoll«

Compares wide-character strings using locale-specific information (case-insensitive)

»_wcsdup«

Duplicates a wide-character string

»_wcsicmp«

Compares two wide-character strings without regard to case

»_wcslwr«

Converts wide-character string to lowercase

»_wcsnicmp«

Compares characters of two wide-character strings without regard to case

»_wcsnset«

Sets characters of a wide-character string to a given character

»_wcsupr«

Converts a wide-character string to uppercase

»_wcsrev«

Reverses a wide-character string

»_wcsset«

Sets all characters of a wide-character string to a given character


32-bit only Run-Time Functions
  2.21  32-Bit Specific

The following routines are only available in the 32-bit run-time libraries:

»_beginthread«

Begins thread in Windows NT process

»_cwait«

Waits until the spawned process terminates

»_endthread«

Terminates a Windows NT thread

»_findclose«

Releases resources from previous find operations

»_findfirst«

Finds the file with the specified attributes

»_findnext«

Finds the next file with the specified attributes

»_futime«

Sets the modification time on an open file

»_get_osfhandle«

Returns the operating system file handle associated with an existing C run-time stream FILE pointer

»_open_osfhandle«

Associates a C run-time file handle with an existing operating system file handle

»_pclose«

Waits for a new process command and closes the stream on the associated pipe

»_pipe«

Creates a pipe for reading and writing

»_popen«

Creates a pipe and executes a command


Global Variables and Standard Types
  Chapter 3  Global Variables and Standard Types

The Microsoft run-time library contains definitions for a number of variables and standard types used by library routines. You can access these variables and types by including in your program the files in which they are declared, or by giving appropriate declarations in your program, as shown in the following sections.


_amblksiz Variable
  3.1  _amblksiz Variable

The _amblksiz variable controls memory heap granularity. It is declared in the MALLOC.H include file as follows:

extern unsigned int _amblksiz;

The value of _amblksiz is used to control how memory is obtained from the operating system for the heap. The initial requested size for a segment of memory for the heap manager is based on the amount of current allocation request plus overhead for the heap manager's bookkeeping chores—that is, just enough to satisfy the allocation request at hand (for example, a malloc or calloc). However, when the heap manager grows a segment, it does so in multiples of _amblksiz. The value of _amblksiz represents a trade-off between the number of times the operating system must be called to grow a segment to its maximum size (no more than 640K for MS-DOS) and the amount of memory potentially wasted (available but not used) at the end of the heap.

The default value of _amblksiz is 8K. The value can be changed by direct assignment in your program. For example:

_amblksiz = 2048;

The actual value used internally by the heap manager will be the given value, rounded up to the nearest whole power of 2 (so an _amblksiz value of 4K−1 is the same as a value of 4K).

Note that adjusting the value of _amblksiz affects allocation in the near, far, and based heaps. The value of _amblksiz has no effect on huge memory blocks (those allocated with _halloc and similar functions).


_daylight, _timezone, and _tzname Variables
  3.2  _daylight, _timezone, and _tzname

The _daylight, _timezone, and _tzname variables are global time-zone variables used in time functions. They are declared in the TIME.H include file as follows:

extern int _daylight;

extern long _timezone;

extern char *_tzname[2];

Some time and date routines use the _daylight, _timezone, and _tzname variables to make local-time adjustments. Whenever a program calls the _ftime, localtime, or _tzset function, the values of _daylight, _timezone, and _tzname are determined from the value of the TZ environment variable. If you do not explicitly set the value of TZ, the default value of "PST8PDT" is used. The following list shows each variable and its value:

_daylight    Nonzero if a daylight-saving-time zone (DST) is specified in TZ; otherwise, 0. The default value is 1.

_timezone    The difference in seconds between Universal coordinated time and the local time. The default value is 28,800.

_tzname[0]    A three-letter time-zone name derived from the TZ environment variable. The default value is "PST" (Pacific standard time).

_tzname[1]    A three-letter daylight-saving-time zone name derived from the TZ environment variable. The default value is "PDT" (Pacific daylight time). If the DST zone is omitted from TZ, _tzname[1] is an empty string.


_doserrno, errno, sys_errlist, and sys_nerr Variables
  3.3  _doserrno, errno, _sys_errlist, and _sys_nerr Variables

The _doserrno, errno, _sys_errlist, and _sys_nerr variables contain error codes and are used by the perror and strerror routines to print error information. These variables are declared in the STDLIB.H include file. Manifest constants for the errno variables are declared in the ERRNO.H include file as follows:

extern int _doserrno;

extern int errno;

extern char *_sys_errlist[ ];

extern int _sys_nerr;

The errno variable is set to an integer value to reflect the type of error that has occurred in a system-level call. Each errno value is associated with an error message, which can be printed with the perror routine or stored in a string with the strerror routine. Note that only some routines set the errno variable. If a routine sets errno, the description of the routine in the reference section says so explicitly.

The value of errno reflects the error value for the last call that set errno. However, this value is not necessarily reset by later successful calls. To avoid confusion, test for errors immediately after a call.

The include file ERRNO.H contains the definitions of the errno values. However, not all of the definitions given in ERRNO.H are used in MS-DOS and Windows NT. Some of the values in ERRNO.H are present to maintain compatibility with the UNIX (and XENIX) operating system. The errno values in MS-DOS and Windows NT are a subset of the values for errno in XENIX systems. Thus, the errno value is not necessarily the same as the actual error code returned by an MS-DOS or Windows NT system call. To access the actual operating system error code, use the _doserrno variable, which contains this value. In general, you should use _doserrno only for error detection in operations involving input and output, since the errno values for input and output errors have operating system error-code equivalents. In other cases, the value of _doserrno is undefined.

The _sys_errlist variable is an array; the perror and strerror routines use it to process error information. The _sys_nerr variable tells how many elements the _sys_errlist array contains.

Table 3.1, following, gives the errno values for MS-DOS and Windows NT, the system error message for each value, and the value of each constant. Note that only the ERANGE and EDOM constants are specified in the ANSI standard.

Table 3.1    errno Values and Their Meanings

Constant	Meaning	Value
E2BIG	Argument list too long	7
EACCES	Permission denied	13
EBADF	Bad file number	9
EDEADLOCK	Resource deadlock would occur	36
EDOM	Math argument	33
EEXIST	File exists	17
EINVAL	Invalid argument	22
EMFILE	Too many open files	24
ENOENT	No such file or directory	2
ENOEXEC	Exec format error	8
ENOMEM	Not enough memory	12
ENOSPC	No space left on device	28
ERANGE	Result too large	34
EXDEV	Cross-device link	18


environ Variable
  3.4  _environ Variable

The _environ variable is a pointer to the strings in the process environment. It is declared in the STDLIB.H include file as follows:

extern char **_environ;

The _environ variable is a pointer to an array of pointers to the strings that constitute the process environment. The environment consists of one or more entries of the form

NAME=string

where NAME is the name of an environment variable and string is the value of that variable. The string can be empty. The initial environment settings are taken from the operating-system environment at the time of program execution.

The »getenv« and »_putenv« routines use the _environ variable to access and modify the environment table. When _putenv is called to add or delete environment settings, the environment table changes size; its location in memory may also change, depending on the program's memory requirements. The _environ variable is adjusted in these cases and always points to the correct table location.


_fileinfo Variable
  3.5  _fileinfo Variable

The _fileinfo variable determines whether or not a process's open file information, in the form of the _C_FILE_INFO entry in the environment, will be passed to child processes. It is declared in the STDLIB.H include file as follows:

extern int _fileinfo;

If _fileinfo is 0, the _C_FILE_INFO information is not passed to the child processes. If _fileinfo is not 0, the _C_FILE_INFO information is passed to child processes. By default, _fileinfo is 0 and thus the _C_FILE_INFO information is not passed to child processes. There are two ways to modify the default value of _fileinfo:

•	Link the supplied object file FILEINFO.OBJ into your program. Use the /NOE LINK option to avoid multiple symbol definitions.

•	Set the _fileinfo variable to a nonzero value directly within your program.


_fmode Variable
  3.6  _fmode Variable

The _fmode variable controls the default file-translation mode. It is declared in the STDLIB.H include file as follows:

extern int _fmode;

By default, the value of _fmode is _O_TEXT, causing files to be translated in text mode (unless specifically opened or set to binary mode). When _fmode is set to _O_BINARY, the default mode is binary. You can set _fmode to the flag _O_BINARY by linking with BINMODE.OBJ or by assigning _fmode the _O_BINARY value.


Locale Macros
  3.7  Locale Macros

The two ANSI macros, MB_LEN_MAX and MB_CUR_MAX, are useful when writing portable programs for international markets. The MB_LEN_MAX macro, defined in LIMITS.H, gives the maximum number of bytes in a multibyte character. The MB_CUR_MAX macro, defined in STDLIB.H, expands to the maximum number of bytes in a multibyte character of the current locale.


_Operating System Variables
  3.8  Operating System Variables

The _osmajor, _osminor, _osver, _winmajor, _winminor, _winver, _osversion, _osmode, and _cpumode variables specify the version number of the operating system or the current mode of operation. They are declared in the STDLIB.H include file, except _osversion, which is declared in DOS.H. Their declarations are as follows:

extern unsigned char _osmajor;	// 16-bit specific

extern unsigned char _osminor;	// 16-bit specific

extern unsigned int _osver;

extern unsigned char _winmajor;

extern unsigned char _winminor;

extern unsigned int _winver;

extern unsigned int _osversion;	// 16-bit specific

extern unsigned char _osmode;	// 16-bit specific

extern unsigned char _cpumode;	// 16-bit specific

The _osmajor, _osminor, and _osversion variables specify the version number of MS-DOS in use. The _osmajor variable holds the "major" version number, and the _osminor variable stores the "minor" version number. Thus, under MS-DOS version 6.0, _osmajor is 6 and _osminor is 0. The _osver variable holds both values: its high byte contains the major version number and its low byte contains the minor version number. The _osversion variable also holds both values, but in reverse order. The _osver variable is generally more useful for testing the MS-DOS version because it has the two bytes in the correct order for comparison.

The _winmajor, _winminor, and _winver variables specify the version of Windows in use. These variables are not available in the MS-DOS libraries. The _winmajor variable holds the major version number, and the _winminor variable holds the minor version number. Thus, under Windows 3.10 (also called Windows 3.1), _winmajor is 3 and _winminor is 10.

The _osver and _winver variables contain the version numbers in the order that makes sense for comparison, not in the order returned by the system calls that get the version numbers. Note also that MS-DOS and Windows minor version numbers are sometimes specified without a trailing 0. For example, "MS-DOS 3.3" means version 3.30, and "Windows 3.1" means 3.10.

These variables are useful for creating programs that run in different versions of MS-DOS and Windows. For example, you can test the _osmajor variable before making a call to _sopen; if the major version number is earlier (less) than 3, _open should be used instead of _sopen.

The _osmode variable indicates the currently running operating system: _DOS_MODE or _WIN_MODE. The _cpumode variable indicates the mode of the currently running operating system: _REAL_MODE or _PROT_MODE.


_psp Variable
  3.9  _psp Variable

The _psp variable contains the segment address of the program segment prefix (PSP) for the process. It is declared in the STDLIB.H include file as follows:

extern unsigned int _psp;

The PSP contains execution information about the process, such as a copy of the command line that invoked the process and the return address on process termination or interrupt. The _psp variable can be used to form a long pointer to the PSP, where _psp is the segment value and 0 is the offset value. Note that the _psp variable is supported only in MS-DOS.


_pgmptr Variable
  3.10  _pgmptr Variable

The _pgmptr variable is automatically initialized at startup and points to a string that contains a copy of the path of the just-started program; _pgmptr will contain whatever the program that spawns it passes as argv[0]. The command interpreter (COMMAND.COM) will pass a full path; other programs may pass a filename, a relative path, or a full path. The _pgmptr variable is declared in the STDLIB.H include file as follows:

extern char __far *_pgmptr;

It is defined as a global variable in the run-time library and declared in CRT0DAT.ASM, which is part of the startup code. This code is linked to any module that contains a main function. The following program demonstrates the use of _pgmptr:

#include <stdio.h>
#include <stdlib.h>
void main( void )
{
   printf("The full path of the executing program is : %Fs\n",
          _pgmptr);
}

In MS-DOS versions 3.0 and later, argv[0] also contains a pointer to the full path of the executing program.


  3.11  Standard Types

A number of library routines use values whose types are defined in include files. The following list describes these types and gives the include files where they are defined:

_BYTEREGS

Defined in DOS.H, this structure stores byte register values for the _REGS union to be passed to and returned from calls to the MS-DOS interface functions. (16-bit specific)

clock_t

Defined in TIME.H, this type stores time values. It is used by the clock function.

_complex, _complexl

Defined in MATH.H, this structure stores the real and imaginary parts of complex numbers. It is used by the _cabs function.

_dev_t

Defined in SYS\TYPES.H, this is the type for representing device handles.

_diskfree_t

Defined in DOS.H, this structure stores disk information used by the _dos_getdiskfree routine. (16-bit specific)

_diskinfo_t

Defined in BIOS.H, this structure records information about disk drives returned by the _bios_disk routine. (16-bit specific)

div_t, ldiv_t

Defined in STDLIB.H, these structures store the values returned by the div and ldiv functions, respectively.

_dosdate_t

Defined in DOS.H, this structure records the current system date used in the _dos_getdate and _dos_setdate routines. (16-bit specific)

_DOSERROR

Defined in DOS.H, this structure stores values returned by MS-DOS system call 59H (available with MS-DOS versions 3.0 and later). (16-bit specific)

_dostime_t

Defined in DOS.H, this structure records the current system time used in the _dos_gettime and _dos_settime routines. (16-bit specific)

_exception, _exceptionl

Defined in MATH.H, these structure store error information for math routines. They are used by the _matherr and _matherrl routines, respectively.

FILE

Defined in STDIO.H, this is the structure used in all stream input and output operations. The fields of the FILE structure store information about the current state of the stream.

_find_t

Defined in DOS.H, this structure stores file-attribute information returned by the _dos_findfirst and _dos_findnext routines. (16-bit specific)

_finddata_t

Defined in IO.H, this structure stores file-attribute information returned by the findfirst and findnext routines.

_FPIEEE_RECORD

Defined in FPIEEE.H, this structure contains information pertaining to an IEEE floating-point exception. It is passed to the user-defined trap handler by the _fpieee_flt function.

fpos_t

The fgetpos and fsetpos functions use the fpos_t object type, defined in STDIO.H, to record all the information necessary to uniquely specify every position within the file.

_HEAPINFO

Defined in MALLOC.H, this structure contains information about the next heap entry for the _heapwalk function.

jmp_buf

Defined in SETJMP.H, this is an array type rather than a structure type. A buffer of this type is used by the setjmp and longjmp routines to save and restore the program environment.

lconv

Defined in LOCALE.H, this type is a structure containing formatting rules for numeric values in different countries.

_off_t    Defined in SYS\TYPES.H, this is the type for representing a file offset value.

_onexit_t, _fonexit    Declared in STDLIB.H, the _onexit routine is declared as an _onexit_t pointer type and returns an _onexit_t pointer. The _fonexit routine is declared as an _fonexit_t pointer type and returns an _fonexit_t pointer.

ptrdiff_t

This type is used for the signed integral result of the subtraction of two pointers.

_REGS

Defined in DOS.H, this union stores byte and word register values to be passed to and returned from calls to the MS-DOS interface functions. (16-bit specific)

sig_atomic_t

Defined in SIGNAL.H, this type is the integral type of an object that can be modified as an atomic entity, even in the presence of asynchronous interrupts. It is used in conjunction with the signal routine.

size_t

Defined in STDDEF.H and several other include files, this type is the unsigned integral result of the sizeof operator.

_SREGS

Defined in DOS.H, this structure stores the values of the ES, CS, SS, and DS registers. This structure is used by the MS-DOS interface functions that require segment register values (_int86x, _intdosx, and _segread). (16-bit specific)

_stat

Defined in SYS\STAT.H, this structure contains file-status information returned by the _stat and _fstat routines.

time_t

Defined in TIME.H, this type represents time values in the mktime and time routines.

_timeb

Defined in SYS\TIMEB.H, this structure is used by the _ftime routine to store the current system time.

tm

Defined in TIME.H, this structure is used by the asctime, gmtime, localtime, mktime, and strftime functions to store and retrieve time information.

_utimbuf

Defined in SYS\UTIME.H, this structure stores file access and modification times used by the _utime function to change file-modification dates.

va_list

Defined in STDARG.H, this array type is used to hold information needed by the va_arg macro and the va_end routine. The called function declares a variable of type va_list, which can be passed as an argument to another function.

_vmhnd_t

Defined in VMEMORY.H, this type represents the handles to blocks of virtual memory. Handles of this type are returned by the _vmalloc routine and used by the virtual memory routines.

wchar_t

Defined in STDDEF.H and STDLIB.H, this type is the internal type of a wide character. It is required by the ANSI standard for the C language and is useful when writing portable programs for international markets.

wctype_t

Defined in STDDEF.H and STDLIB.H, this is the integral type that can represent all characters of any national character set.

wint_t

Defined in WCHAR.H, this is an integral type of a data object that can hold any wide character or wide end-of-file value.

_wopeninfo

Defined in IO.H, this type is a structure containing information needed to open a new QuickWin window. (16-bit specific)

_WORDREGS

Defined in DOS.H, this structure stores word register values for the _REGS union to be passed to and returned from calls to the MS-DOS interface functions. (16-bit specific)

_wsizeinfo

Defined in IO.H, this type is a structure containing information needed to initialize the size of a new QuickWin window, to examine the size of an existing QuickWin window, or to resize an existing QuickWin window. (16-bit specific)


  About the Run-Time Reference

The following pages describe, in alphabetical order, the functions and macros in the Microsoft run-time library. In some cases, related routines are clustered in the same description. For example, the based, near, and far versions of _heapwalk are discussed in the same place, as are the regular and long double versions of the math functions, such as acos and atan, and the regular and wide-character versions of printf. Differences are noted where appropriate. To locate any function that does not appear in the expected position within the alphabetical reference, refer to Chapter 2, »Run-Time Routines by Category.«

The discussion of each routine (or group of routines) includes a section that names the include file(s) containing its declaration, illustrates the routine's syntax, and briefly describes its arguments. This is followed by these sections:

•	Remarks giving a more detailed description of the routine and how it is used.

•	Return Value describing the value returned by the routine.

•	See Also naming related routines.

•	Compatibility telling whether the routine is compatible with ANSI C, MS-DOS, QuickWin, UNIX, the Microsoft Windows operating system, the Windows dynamic-link library (DLL), the Microsoft Windows 32-bit operating system, and the Microsoft Windows 32-bit operating system subset.

•	Example giving a complete program that shows the use of the routine.

•	Output showing the output from the example program.


Description: abort
  abort

#include <process.h>    Use either PROCESS.H or STDLIB.H

#include <stdlib.h>

void abort( void );

Remarks

The abort function prints the message abnormal program termination to stderr, then calls raise(SIGABRT). The action taken in response to the SIGABRT signal depends on what action has been defined for that signal in a prior call to the signal function. The default SIGABRT action is for the calling process to terminate with exit code 3, returning control to the parent process or operating system.

In Windows, the abort function does not call raise(SIGABRT). Instead, it terminates the process with an "Abnormal Program Termination" pop-up message. In Windows multithread libraries, the abort function does not call raise(SIGABRT). Instead, it terminates the process with exit code 3. The abort function does not flush stream buffers or do atexit/_onexit processing.

Return Value

The abort function does not return control to the caller. Rather, it terminates the process and, by default, returns an exit code of 3 to the parent process.

See Also

»_exec functions,« »exit,« »_exit,« »raise,« »signal,« »_spawn functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ABORT.C:  This tries to open a file and
 * aborts if the attempt fails.
 */

#include  <stdio.h>
#include  <stdlib.h>

void main( void )
{
   FILE *stream;

   if( (stream = fopen( "NOSUCHF.ILE", "r" )) == NULL )
   {
      perror( "Couldn't open file" );
      abort();
   }
   else
      fclose( stream );
}

Output

Couldn't open file: No such file or directory

abnormal program termination


Description: abs
  abs

#include <stdlib.h>    Use STDLIB.H OR MATH.H

#include <math.h>

int abs( int n );

n    Integer value

Remarks

The abs function returns the absolute value of its integer parameter n.

Return Value

The abs function returns the absolute value of its parameter. There is no error return.

See Also

»_cabs,« »fabs,« »labs«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ABS.C: This program computes and displays
 * the absolute values of several numbers.
 */

#include  <stdio.h>
#include  <math.h>
#include  <stdlib.h>

void main( void )
{
   int    ix = -4, iy;
   long   lx = -41567L, ly;
   double dx = -3.141593, dy;

   iy = abs( ix );
   printf( "The absolute value of %d is %d\n", ix, iy);

   ly = labs( lx );
   printf( "The absolute value of %ld is %ld\n", lx, ly);

   dy = fabs( dx );
   printf( "The absolute value of %f is %f\n", dx, dy );
}

Output

The absolute value of -4 is 4
The absolute value of -41567 is 41567
The absolute value of -3.141593 is 3.141593


Description: _access
   _access

#include <io.h>

#include <errno.h>    Required for definition of errno constants

int _access( const char *path, int mode );

path    File or directory path

mode    Permission setting

Remarks

With files, the _access function determines whether the specified file exists and can be accessed in mode. The possible mode values and their meanings in the _access call are as follows:

00    Check for existence only

02    Check for write permission

04    Check for read permission

06    Check for read and write permission

With directories, _access determines only whether the specified directory exists; in MS-DOS, all directories have read and write access.

Return Value

The _access function returns the value 0 if the file has the given mode. A return value of − 1 indicates that the named file does not exist or is not accessible in the given mode, and errno is set to one of the following values:

EACCES    Access denied: the file's permission setting does not allow the specified access.

ENOENT    File or path not found.

See Also

»_chmod,« »_fstat,« »_open,« »_stat«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _access for compatibility with ANSI naming conventions of non-ANSI functions. Use access and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* ACCESS.C: This example uses _access to check the
 * file named "ACCESS.C" to see if it exists and if
 * writing is allowed.
 */

#include  <io.h>
#include  <stdio.h>
#include  <stdlib.h>

void main( void )
{
   /* Check for existence */
   if( (_access( "ACCESS.C", 0 )) != -1 )
   {
      printf( "File ACCESS.C exists\n" );

      /* Check for write permission */
      if( (_access( "ACCESS.C", 2 )) != -1 )
         printf( "File ACCESS.C has write permission\n" );
   }
}

Output

File ACCESS.C exists


Description: acos Functions
   acos Functions

#include <math.h>

#include <errno.h>    Required for definition of errno constant

double acos( double x );

long double acosl( long double x );

x    Value whose arccosine is to be calculated

Remarks

The acos functions return the arccosine of x in the range 0 to π radians. The value of x must be between − 1 and 1. The acosl function is the 80-bit counterpart, which uses an 80-bit, 10-byte coprocessor form of parameters and return values. See the »long double functions« for more details on this data type.

Return Value

The acos functions return the arccosine result. If x is less than − 1 or greater than 1, the function sets errno to EDOM, prints a _DOMAIN error message to stderr, and returns 0. Error handling can be modified with the _matherr (or _matherrl) routine.

See Also

»asin functions,« »atan functions,« »cos functions,« »_matherr,« »sin functions,« »tan functions«

Compatibility

acos:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

acosl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ASINCOS.C: This program prompts for a value in the range
 * -1 to 1. Input values outside this range will produce
 * _DOMAIN error messages.If a valid value is entered, the
 * program prints the arcsine and the arccosine of that value.
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void main( void )
{
   double x, y;

   printf( "Enter a real number between -1 and 1: " );
   scanf( "%lf", &x );
   y = asin( x );
   printf( "Arcsine of %f = %f\n", x, y );
   y = acos( x );
   printf( "Arccosine of %f = %f\n", x, y );
}

Output

Enter a real number between -1 and 1: .32696
Arcsine of 0.326960 = 0.333085
Arccosine of 0.326960 = 1.237711


Description: _alloca
   _alloca

#include <malloc.h>

void *_alloca( size_t size );

size    Bytes to be allocated from stack

Remarks

The _alloca routine allocates size bytes from the program's stack. The allocated space is automatically freed when the calling function is exited.

In the 32-bit version of the compiler, the _alloca function is implemented as an inline intrinsic. This will have little or no effect on the size of the generated code. However, note that the 16-bit version of _alloca makes assumptions about the layout of the stack frame which may, under certain circumstances, be incorrect.

Observe the following restrictions when using _alloca:

•	For 16-bit programs only, when you compile with optimization on (either by default or by using one of the /O options), the stack pointer may not be restored properly in functions that have no local variables and that also reference the _alloca function. (This restriction does not apply to 32-bit operating system targets, such as Windows NT.) The following program demonstrates the problem:

/* Compile with CL /AM /Ox /Fc */
#include <malloc.h>

void main( void )
{
   func( 10 );
}
void func( register int i )
{
   _alloca( i );
}

To ensure that the stack pointer is properly restored in 16-bit programs, make sure that any function referencing _alloca declares at least one local variable. This requirement does not apply to 32-bit operating systems.

•	The pointer value returned by _alloca must not be passed as an argument to free, since the allocated space is automatically freed when the calling function is exited.

•	In 16-bit programs only, the _alloca function should never be used in an expression that is an argument to a function.

Return Value

The _alloca routine returns a void pointer to the allocated space, which is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than char, use a type cast on the return value. In 16-bit operating systems, the return value is NULL if the space cannot be allocated. In 32-bit operating systems, a stack overflow exception is generated if the space cannot be allocated.

See Also

»calloc functions,« »malloc functions,« »realloc functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _alloca for compatibility with ANSI naming conventions of non-ANSI functions. For 16-bit targets, use alloca and link with OLDNAMES.LIB for UNIX compatibility. For 32-bit targets, use alloca and compile with /Ze (enable Microsoft language extensions) for UNIX compatibility.

Example

/* Note: MS-DOS ONLY
 *
 * ALLOCA.C: This program checks the stack
 * space available before and after using the
 * _alloca function to allocate space on the stack.
 */

#include <malloc.h>
#include <stdio.h>

void main( void )
{
   char *buffer;

   printf( "Bytes available on stack: %u\n", _stackavail() );

   /* Allocate memory for string. */
   buffer = _alloca( 120 * sizeof( char ) );
   printf( "The _alloca function just allocated" );
   printf( " memory from the program stack.\n" );

   printf( "Enter a string: " );
   gets( buffer );
   printf( "\"%s\" was stored in the program stack.\n", buffer );
   printf( "Bytes available on stack: %u\n", _stackavail() );
}

Output

Bytes available on stack: 1720
The _alloca function just allocated memory from the program stack.
Enter a string: Store this on the stack.
"Store this on the stack." was stored in the program stack.
Bytes available on stack: 1590


Description: _arc Functions
   _arc Functions

#include <graph.h>

short __far _arc( short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4 );

short __far _arc_w( double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4 );

short __far _arc_wxy( struct _wxycoord __far *pwxy1, struct _wxycoord __far *pwxy2, struct _wxycoord __far *pwxy3, struct _wxycoord __far *pwxy4 );

x1, y1    Upper-left corner of bounding rectangle

x2, y2    Lower-right corner of bounding rectangle

x3, y3     Second point of start vector (center of bounding rectangle is first point)

x4, y4     Second point of end vector (center of bounding rectangle is first point)

pwxy1    Upper-left corner of bounding rectangle

pwxy2     Lower-right corner of bounding rectangle

pwxy3    Second point of start vector (center of bounding rectangle is first point)

pwxy4     Second point of end vector (center of bounding rectangle is first point)

Remarks

The _arc functions draw elliptical arcs. The center of the arc is the center of the bounding rectangle, which is defined by points (x1, y1) and (x2, y2) for _arc and _arc_w and by points pwxy1 and pwxy2 for _arc_wxy. The arc starts where it intersects an imaginary line extending from the center of the arc through (x3, y3) for _arc and _arc_w and through pwxy3 for _arc_wxy. It is drawn counterclockwise about the center of the arc, ending where it intersects an imaginary line extending from the center of the arc through (x4, y4) for _arc and _arc_w and through pwxy4 for _arc_wxy.

The _arc routine uses the view coordinate system. The _arc_w and _arc_wxy functions use the real-valued window coordinate system. In each case, the arc is drawn using the current color. Because an arc does not define a closed area, it is not filled.

Return Value

These functions return a nonzero value if the arc is successfully drawn; otherwise, they return 0.

See Also

»_ellipse functions,« »_lineto functions,« »_pie functions,« »_rectangle functions,« »_setcolor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * ARC.C: This program draws a simple arc.
 *
 */

#include <graph.h>
#include <stdlib.h>
#include <conio.h>

void main( void )
{
   short x, y;
   struct _xycoord xystart, xyend, xyfill;

   /* Find a valid graphics mode */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   /* Draw arcs         */
   x = 100; y = 100;
   _arc( x - 60, y - 60, x, y, x - 30, y - 60, x - 60, y - 30 );
   _arc( x + 60, y + 60, x, y, x, y + 30, x + 30, y );

   /* Get endpoints of second arc and enclose the figure, then
    * fill it.
    */
   _getarcinfo( &xystart, &xyend, &xyfill );
   _moveto( xystart.xcoord, xystart.ycoord );
   _lineto( xyend.xcoord,   xyend.ycoord );
   _floodfill( xyfill.xcoord, xyfill.ycoord, _getcolor() );

   _getch();
   _setvideomode( _DEFAULTMODE );
}


Description: asctime
   asctime

#include <time.h>

char *asctime( const struct tm *timeptr );

timeptr    Time/date structure

Remarks

The asctime function converts a time stored as a structure to a character string. The timeptr value is usually obtained from a call to gmtime or localtime, both of which return a pointer to a tm structure, defined in TIME.H. The fields of the structure type tm store the following values, each of which is an int:

tm_sec    Seconds after the minute (0 − 59)

tm_min     Minutes after the hour (0 − 59)

tm_hour     Hours since midnight (0 − 23)

tm_mday     Day of the month (1 − 31)

tm_mon     Month (0 − 11; January = 0)

tm_year    Year (current year minus 1900)

tm_wday    Day of week (0 − 6; Sunday = 0)

tm_yday    Day of year (0 − 365; January 1 = 0)

tm_isdst    Nonzero if daylight saving time is in effect, otherwise 0

The string result produced by asctime contains exactly 26 characters and has the form of the following example: Wed Jan 02 02:03:55 1980\n\0. A 24-hour clock is used. All fields have a constant width. The newline character (\n) and the null character ('\0') occupy the last two positions of the string. The asctime function uses a single statically allocated buffer to hold the return string. Each call to this routine destroys the result of the previous call.

Return Value

The asctime function returns a pointer to the character string result. There is no error return.

See Also

»ctime,« »_ftime,« »gmtime,« »localtime,« »time,« »_tzset«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ASCTIME.C: This program places the system time
 * in the long integer aclock, translates it into the
 * structure newtime and then converts it to string
 * form for output, using the asctime function.
 */

#include <time.h>
#include <stdio.h>

struct tm *newtime;
time_t aclock;

void main( void )
{
   time( &aclock );                 /* Get time in seconds */

   newtime = localtime( &aclock );  /* Convert time to struct */
                                    /* tm form */

   /* Print local time as a string */
   printf( "The current date and time are: %s", asctime( newtime ) );
}

Output

The current date and time are: Mon Mar 22 15:46:05 1993


Description: asin Functions
   asin Functions

#include <math.h>

#include <errno.h>

double asin( double x );

long double asinl( long double x );

x    Value whose arcsine is to be calculated

Remarks

The asin functions calculate the arcsine of x in the range − π/2 to π/2 radians. The value of x must be between − 1 and 1. The asinl function is the 80-bit counterpart, which uses an 80-bit, 10-byte coprocessor form of parameters and return values. See the »long double functions« for more details on this data type.

Return Value

The asin functions return the arcsine result. If x is less than − 1 or greater than 1, asin sets errno to EDOM, prints a _DOMAIN error message to stderr, and returns 0. Error handling can be modified by using the _matherr (or _matherrl) routine.

See Also

»acos functions,« »atan functions,« »cos functions,« »_matherr,« »sin functions,« »tan functions«

Compatibility

asin:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

asinl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »acos.«


Description: assert
  assert

#include <assert.h>

#include <stdio.h>

void assert( int expression );

expression    C expression specifying assertion being tested

Remarks

The assert routine prints a diagnostic message and calls the abort routine if expression is false (0). The diagnostic message has the form Assertion failed: expression, file filename, line linenumber where filename is the name of the source file and linenumber is the line number of the assertion that failed in the source file. No action is taken if expression is true (nonzero). In Windows, the diagnostic message appears in an "Assertion Failed" pop-up window.

The assert routine is typically used in program development to identify program logic errors. The given expression should be chosen so that it holds true only if the program is operating as intended. After a program has been debugged, the special "no debug" identifier NDEBUG can be used to remove assert calls from the program. If NDEBUG is defined (by any value) with a /D command-line option or with a #define directive, the C preprocessor removes all assert calls from the program source. If NDEBUG is defined with a #define directive, it must appear before inclusion of ASSERT.H. The assert routine is implemented as a macro.

Return Value

None.

See Also

»abort,« »raise,« »signal«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ASSERT.C: In this program, the analyze_string function uses
 * the assert function to test several conditions related to
 * string and length. If any of the conditions fails, the program
 * prints a message indicating what caused the failure.
 */

#include <stdio.h>
#include <assert.h>
#include <string.h>

void analyze_string( char *string );   /* Prototype */

void main( void )
{
   char  test1[] = "abc", *test2 = NULL, test3[] = "";

   printf ( "Analyzing string '%s'\n", test1 );
   analyze_string( test1 );
   printf ( "Analyzing string '%s'\n", test2 );
   analyze_string( test2 );
   printf ( "Analyzing string '%s'\n", test3 );
   analyze_string( test3 );
}

/* Tests a string to see if it is NULL, */
/*   empty, or longer than 0 characters */
void analyze_string( char * string )
{
   assert( string != NULL );        /* Cannot be NULL */
   assert( *string != '\0' );       /* Cannot be empty */
   assert( strlen( string ) > 2 );  /* Length must exceed 2 */
}

Output

Assertion failed: string != NULL, file assert.c, line 24

abnormal program termination


Description: atan Functions
  atan Functions

#include <math.h>

double atan( double x );

double atan2( double y, double x );

long double atanl( long double x );

long double atan2l( long double y, long double x );

x, y     Any number

Remarks

The atan family of functions calculates the arctangent of x, and the atan2 family of functions calculates the arctangent of y/x. The atan group returns a value in the range − π/2 to π/2 radians, and the atan2 group returns a value in the range − π to π radians. The atan2 functions use the signs of both parameters to determine the quadrant of the return value. The atan2 functions are well defined for every point other than the origin, even if x equals 0 and y does not equal 0.

Return Value

The atan family of functions returns the arctangent result. If both parameters of atan2 or atan2l are 0, the function sets errno to EDOM, prints a _DOMAIN error message to stderr, and returns 0. Error handling can be modified by using the _matherr (or _matherrl) routine.

See Also

»acos functions,« »asin functions,« »cos functions,« »_matherr,« »sin functions,« »tan functions«

Compatibility

atan, atan2:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

atanl, atan2l:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ATAN.C: This program calculates
 * the arctangent of 1 and -1.
 */

#include <math.h>
#include <stdio.h>
#include <errno.h>

void main( void )
{
   double x1, x2, y;

   printf( "Enter a real number: " );
   scanf( "%lf", &x1 );
   y = atan( x1 );
   printf( "Arctangent of %f: %f\n", x1, y );
   printf( "Enter a second real number: " );
   scanf( "%lf", &x2 );
   y = atan2( x1, x2 );
   printf( "Arctangent of %f / %f: %f\n", x1, x2, y );
}

Output

Enter a real number: -862.42
Arctangent of -862.420000: -1.569637
Enter a second real number: 78.5149
Arctangent of -862.420000 / 78.514900: -1.480006


Description: atexit, _fatexit
  atexit, _fatexit

#include <stdlib.h>

int atexit( void ( __cdecl *func )( void ) );

int __far _fatexit( void ( __cdecl __far *func )( void ) );

func    Function to be called

Remarks

The atexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to atexit create a register of functions that are executed in LIFO (last-in-first-out) order. With MS-DOS only, no more than 32 functions can be registered with atexit or _onexit. The functions passed to atexit cannot take parameters. In Windows NT, atexit and _onexit use the heap to hold the "register of functions." Thus, the number of functions that can be registered is limited only by heap memory. The _fatexit function is a far version of atexit; it can be used with any memory model.

Return Value

Both atexit and _fatexit return 0 (EXIT_SUCCESS) if successful, or a nonzero value (EXIT_FAILURE) if an error occurs (e.g., if there are already 32 exit functions defined in a 16-bit application). Use the ANSI-standard atexit function (rather than the similar _onexit function) whenever ANSI portability is desired.

See Also

»abort,« »exit,« »_exit,« »_onexit«

Compatibility

atexit:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fatexit:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ATEXIT.C: This program pushes four functions onto
 * the stack of functions to be executed when atexit
 * is called. When the program exits, these programs
 * are executed on a "last in, first out" basis.
 */

#include <stdlib.h>
#include <stdio.h>

void fn1( void ), fn2( void ), fn3( void ), fn4( void );

void main( void )
{
   atexit( fn1 );
   atexit( fn2 );
   atexit( fn3 );
   atexit( fn4 );
   printf( "This is executed first.\n" );
}

void fn1()
{
   printf( "next.\n" );
}

void fn2()
{
   printf( "executed " );
}

void fn3()
{
   printf( "is " );
}

void fn4()
{
   printf( "This " );
}

Output

This is executed first.
This is executed next.


Description: atof, atoi, atol, _atold
  atof, atoi, atol, _atold

#include<math.h>    atof, _atold

#include <stdlib.h>    atof, _atold, atoi, atol

double atof( const char *string );

long double _atold( const char *string );

int atoi( const char *string );

long atol( const char *string );

string    String to be converted

Remarks

These functions convert a character string to a double-precision floating-point value (atof), an integer value (atoi), a long integer value (atol), or a long double value (_atold). The input string is a sequence of characters that can be interpreted as a numerical value of the specified type. The output value is affected by the setting of the LC_NUMERIC category in the current locale. The string size that can be handled by the atof or _atold function is limited to 100 characters. The function stops reading the input string at the first character that it cannot recognize as part of a number. This character may be the null character ('\0') terminating the string.

The atof and _atold functions expect string to have the following form:

[whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]

A whitespace consists of space and/or tab characters, which are ignored; sign is either plus (+) or minus ( − ); and digits are one or more decimal digits. If no digits appear before the decimal point, at least one must appear after the decimal point. The decimal digits may be followed by an exponent, which consists of an introductory letter ( d, D, e, or E) and an optionally signed decimal integer.

The atoi and atol functions do not recognize decimal points or exponents. The string argument for these functions has the form

[whitespace] [sign]digits

where whitespace, sign, and digits are exactly as described above for atof.

Return Value

Each function returns the double, long double, int, or long value produced by interpreting the input characters as a number. The return value is 0 (for atoi), 0L (for atol), and 0.0 (for atof and _atold) if the input cannot be converted to a value of that type. The return value is undefined in case of overflow.

See Also

»_ecvt,« »_fcvt,« »_gcvt,« »setlocale,« »strtod«

Compatibility

atof, atoi, atol:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_atold:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ATOF.C: This program shows how numbers stored
 * as strings can be converted to numeric values
 * using the atof, atoi, and atol functions.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char *s; double x; int i; long l;

   s = "  -2309.12E-15";    /* Test of atof */
   x = atof( s );
   printf( "atof test: ASCII string: %s\tfloat:  %e\n", s, x );

   s = "7.8912654773d210";  /* Test of atof */
   x = atof( s );
   printf( "atof test: ASCII string: %s\tfloat:  %e\n", s, x );

   s = "  -9885 pigs";      /* Test of atoi */
   i = atoi( s );
   printf( "atoi test: ASCII string: %s\t\tinteger: %d\n", s, i );

   s = "98854 dollars";     /* Test of atol */
   l = atol( s );
   printf( "atol test: ASCII string: %s\t\tlong: %ld\n", s, l );
}

Output

atof test:  ASCII string:   -2309.12E-15   float:     -2.309120e-012
atof test:  ASCII string: 7.8912654773d210   float:     7.891265e+210
atoi test:  ASCII string:   -9885 pigs      integer: -9885
atol test:  ASCII string: 98854 dollars      long:    98854


Description: _bdos
_bdos

#include <dos.h>

int _bdos( int dosfunc, unsigned int dosdx, unsigned int dosal );

dosfunc    Function number

dosdx    DX register value

dosal    AL register value

Remarks

The _bdos function invokes the MS-DOS system call specified by dosfunc after placing the values specified by dosdx and dosal in the DX and AL registers, respectively. The _bdos function executes an INT 21H instruction to invoke the system call. When the system call is complete, _bdos returns the contents of the AX register. The _bdos function is intended to be used to invoke MS-DOS system calls that either take no parameters or take parameters only in the DX (DH, DL) and/or AL registers.

Do not use the _bdos function to call interrupts that modify the DS register. Instead, use the _intdosx or _int86x function.

This call should not be used to invoke system calls that indicate errors by setting the carry flag. Because C programs do not have access to this flag, your program cannot determine whether the return value is an error code. The _intdos function should be used in these cases.

Return Value

The _bdos function returns the value of the AX register after the system call has completed.

See Also

»_intdos,« »_intdosx«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BDOS.C: This example calls DOS function 0x9 (display
 * string) to display a $-terminated string.
 */

#include <dos.h>

/* Function 0x09 assumes that DS will contain segment of the
 * string. This will be true for all memory models if the
 * string is declared near.
 */
char __near str[] = "Hello world!\r\n$";

void main( void )
{
   /* Offset of string must be in DX, segment in DS. AL is not
    * needed, so 0 is used.
    */
    _bdos( 0x09, (int)str, 0 );
}

Output

Hello world!


Description: _beginthread
_beginthread

#include <process.h>

unsigned long _beginthread( void( *start_address )( void * ), unsigned stack_size, void *arglist );

start_address    Starting address

stack_size    Stack size for thread

arglist    Argument list for thread

Remarks

The _beginthread function creates a thread that begins execution of a routine at start_address. When the thread returns from that routine, it is terminated automatically. However, it is recommended that you always call _endthread to terminate threads created with _beginthread. Doing so reduces the risk of memory leaks which can result from improper cleanup of resources allocated at the time the thread is created.

Windows NT handles the allocation of the stack when the _beginthread routine is called. You do not need to pass the address of the thread stack to _beginthread. The stack_size argument can be 0, in which case Windows NT will use the same value as the stack specified for the main thread.

The arglist is a parameter, the size of a pointer, to be passed to the newly created thread. Typically it is the address of a data item, such as a character string, to be passed to the new thread. The arglist may be NULL if not needed, but _beginthread must be provided with some value to pass to the child thread. All threads are terminated if any thread calls abort, exit, _exit, or ExitThread.

To use the _beginthread function, you must link with one of the multi-threaded C run-time libraries, rather than the default run-time library.

Return Value

If successful, _beginthread returns a handle to the newly created thread. A return value of − 1 indicates an error, and errno is set to one of the following values:

EAGAIN    Too many threads

EINVAL    Invalid argument, bad stack size

See Also

»_endthread«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* BEGTHRD.C illustrates multiple threads using functions:
 *
 *      _beginthread            _endthread
 *
 *
 * This program requires the multithreaded library. For example,
 * compile with the following command line:
 *     CL /MT /D "_X86_" BEGTHRD.C
 *
 * If you are using the Visual C++ development environment, select the
 * Multi-Threaded runtime library in the compiler Project Options
 * dialog box.
 *
 */

#include <windows.h>
#include <process.h>    /* _beginthread, _endthread */
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>

void Bounce( void *ch );
void CheckKey( void *dummy );

/* GetRandom returns a random integer between min and max. */
#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - \
                              (min))) + (min))

BOOL repeat = TRUE;     /* Global repeat flag and video variable */
HANDLE hStdOut;         /* Handle for console window */
CONSOLE_SCREEN_BUFFER_INFO csbi;    /* Console information structure */

void main()
{
    CHAR    ch = 'A';

    hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

    /* Get display screen's text row and column information. */
   GetConsoleScreenBufferInfo( hStdOut, &csbi );

    /* Launch CheckKey thread to check for terminating keystroke. */
    _beginthread( CheckKey, 0, NULL );

    /* Loop until CheckKey terminates program. */
    while( repeat )
    {
        /* On first loops, launch character threads. */
        _beginthread( Bounce, 0, (void *) (ch++)  );

        /* Wait one second between loops. */
        Sleep( 1000L );
    }
}

/* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */
void CheckKey( void *dummy )
{
    _getch();
    repeat = 0;    /* _endthread implied */
}

/* Bounce - Thread to create and and control a colored letter that moves
 * around on the screen.
 *
 * Params: ch - the letter to be moved
 */
void Bounce( void *ch )
{
    /* Generate letter and color attribute from thread argument. */
    char    blankcell = 0x20;
    char    blockcell = (char) ch;
    BOOL    first = TRUE;
   COORD   oldcoord, newcoord;
   DWORD   result;

    /* Seed random number generator and get initial location. */
    srand( _threadid );
    newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );
    newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );
    while( repeat )
    {
        /* Pause between loops. */
        Sleep( 100L );

        /* Blank out our old position on the screen,
         * and draw new letter.
         */
        if( first )
            first = FALSE;
        else
            WriteConsoleOutputCharacter( hStdOut, &blankcell, 1,
                                         oldcoord, &result);
            WriteConsoleOutputCharacter( hStdOut, &blockcell, 1,
                                         newcoord, &result);

        /* Increment the coordinate for next placement of the block. */
        oldcoord.X = newcoord.X;
        oldcoord.Y = newcoord.Y;
        newcoord.X += GetRandom( -1, 1 );
        newcoord.Y += GetRandom( -1, 1 );

        /* Correct placement (and beep) if about to go
         * off the screen.
         */
        if( newcoord.X < 0 )
            newcoord.X = 1;
        else if( newcoord.X == csbi.dwSize.X )
            newcoord.X = csbi.dwSize.X - 2;
        else if( newcoord.Y < 0 )
            newcoord.Y = 1;
        else if( newcoord.Y == csbi.dwSize.Y )
            newcoord.Y = csbi.dwSize.Y - 2;

        /* If not at a screen border, continue, otherwise beep. */
        else
            continue;
        Beep( ((char) ch - 'A') * 100, 175 );
    }
    /* _endthread given to terminate */
    _endthread();
}


Description: Bessel Functions
Bessel Functions

#include <math.h>

double _j0( double x );

double _j1( double x );

double _jn( int n, double x );

double _y0( double x );

double _y1( double x );

double _yn( int n, double x );

long double _j0l( long double x );

long double _jnl( int n, long double x );

long double _j1l( long double x );

long double _y0l( long double x );

long double _y1l( long double x );

long double _ynl( int n, long double x );

x    Floating-point value

n    Integer order

Remarks

The _j0, _j1, and _jn routines return Bessel functions of the first kind: orders 0, 1, and n, respectively. The _y0, _y1, and _yn routines return Bessel functions of the second kind: orders 0, 1, and n, respectively. The parameter x must be positive. The long double versions of these functions are the 80-bit counterparts and use the 80-bit, 10-byte coprocessor form of parameters and return values. See the »long double functions« for more details on this data type.

The Bessel functions are explained more fully in most mathematics reference books, such as the Handbook of Mathematical Functions (Abramowitz and Stegun; Washington: U.S. Government Printing Office, 1964). These functions are commonly used in the mathematics of electromagnetic wave theory.

Return Value

These functions return the result of a Bessel function of x.

For _y0, _y1, or _yn, if x is negative, the routine sets errno to EDOM , prints a _DOMAIN error message to stderr, and returns _HUGE_VAL.

Error handling can be modified by using the _matherr (or _matherrl) routine.

See Also

»_matherr«

Compatibility

_j0, _j1, _jn, _y0, _y1, _yn:

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_j0l, _j1l, _jnl, _y0l, _y1l, _ynl:

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _j0, _j1, _jn, _y0, _y1, and _yn for compatibility with ANSI naming conventions of non-ANSI functions. Use j0, j1, jn, y0, y1, and yn and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* BESSEL.C: This program illustrates Bessel functions,
 * including:    _j0   _j1   _jn   _y0   _y1   _yn
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 2.387;
   int n = 3, c;

   printf( "Bessel functions for x = %f:\n", x );
   printf( " Kind\t\tOrder\tFunction\tResult\n\n" );
   printf( " First\t\t0\t_j0( x )\t%f\n", _j0( x ) );
   printf( " First\t\t1\t_j1( x )\t%f\n", _j1( x ) );
   for( c = 2; c < 5; c++ )
      printf( " First\t\t%d\t_jn( n, x )\t%f\n", c, _jn( c, x ) );

   printf( " Second\t0\t_y0( x )\t%f\n", _y0( x ) );
   printf( " Second\t1\t_y1( x )\t%f\n", _y1( x ) );
   for( c = 2; c < 5; c++ )
      printf( " Second\t%d\t_yn( n, x )\t%f\n", c, _yn( c, x ) );
}

Output

Bessel functions for x = 2.387000:
  Kind      Order   Function   Result

  First      0   _j0( x )   0.009288
  First      1   _j1( x )   0.522941
  First      2   _jn( n, x )   0.428870
  First      3   _jn( n, x )   0.195734
  First      4   _jn( n, x )   0.063131
  Second   0   _y0( x )   0.511681
  Second   1   _y1( x )   0.094374
  Second   2   _yn( n, x )   -0.432608
  Second   3   _yn( n, x )   -0.819314
  Second   4   _yn( n, x )   -1.626833


Description: _bfreeseg
_bfreeseg

#include <malloc.h>

int _bfreeseg( __segment seg );

seg    Segment selected

Remarks

The _bfreeseg function frees a based heap. The seg parameter is a based heap returned by an earlier call to _bheapseg. It specifies the based heap to be freed. The specified segment is freed completely regardless of whether the blocks it contains are free or allocated. After a _bfreeseg call, the seg value is invalid and should not be used.

Return Value

The _bfreeseg function returns 0 if successful and − 1 in the case of an error.

See Also

»_bheapseg,« »calloc functions,« »free functions,« »malloc functions,« »realloc functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_bheapseg.«


Description: _bheapseg
_bheapseg

#include <malloc.h>

__segment _bheapseg( size_t size );

size     Segment size to allocate

Remarks

The _bheapseg function allocates a based-heap segment of at least size bytes. (The block may be larger than size bytes because of space required for alignment and for maintenance information.) The value returned by _bheapseg is the identifier of the based-heap segment. This value should be saved and used in subsequent calls to other based-heap functions. If the original block of memory is depleted (that is, by calls to _bmalloc and _brealloc), the run-time code will try to enlarge the heap as necessary. The _bheapseg function can be called repeatedly. For each call, the run-time library will allocate a new based-heap segment.

Return Value

The _bheapseg function returns the newly allocated segment selector; save this value for use in subsequent based-heap functions. A return value of _NULLSEG indicates failure. Always check the return from the _bheapseg function (especially when it is used in real mode), even if the amount of memory requested is small.

See Also

»_bfreeseg,« »calloc functions,« »free functions,« »malloc functions,« »realloc functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BHEAPSEG.C: This program C illustrates dynamic
 * allocation of based memory using functions
 * _bheapseg, _bfreeseg, _bmalloc, and _bfree.
 */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>

void main( void )
{
   __segment seg;
   char __based( seg ) *outstr, __based( seg ) *instr;
   char __based( seg ) *pout,   __based( seg ) *pin;
   char tmpstr[80];
   int  len;

   printf( "Enter a string: " );
   gets( tmpstr );

   /* Request a based heap. Use based so that memory won't be
    * taken from near heap.
    */
   if( (seg = _bheapseg( 1000 )) == _NULLSEG )
      exit( 1 );

   /* Allocate based memory for two strings. */
   len = strlen( tmpstr );
   if( ((instr  = _bmalloc( seg, len + 1 )) == _NULLOFF) ||
       ((outstr = _bmalloc( seg, len + 1 )) == _NULLOFF) )
       exit( 1 );

   /* Copy a lowercased string to dynamic memory. The based memory
    * is far when addressed as a whole.
    */
   _fstrlwr( _fstrcpy( (char __far *)instr,
           (char __far *)tmpstr ) );

    /* Copy input string to output string in reversed order. When
     * reading and writing individual characters from a based
     * heap, the compiler will try to process them as near, thus
     * speeding up the processing.
     */
    for( pin = instr + len - 1, pout = outstr;
            pout < outstr + len; pin--, pout++ )
      *pout = *pin;
      *pout = '\0';

   /* Display strings. Again, strings as a whole are far. */
   printf( "Input:  %Fs\n", (char __far *)instr );
   printf( "Output: %Fs\n", (char __far *)outstr );

   /* Free blocks and release based heap. */
   _bfree( seg, instr );
   _bfree( seg, outstr );
   _bfreeseg( seg );
}

Output

Enter a string: Was I god
Input:  was i god
Output: dog i saw


Description: _bios_disk
_bios_disk

#include <bios.h>

unsigned _bios_disk( unsigned service, struct _diskinfo_t *diskinfo );

service    Disk function desired

diskinfo    Disk parameters

Remarks

The _bios_disk routine uses INT 0x13 to provide several disk-access functions. The service parameter selects the function desired, while the diskinfo structure provides the necessary parameters. Note that the low-level disk operations allowed by the _bios_disk routine are very dangerous to use because they perform direct manipulation of the disk. The diskinfo structure provides the following fields:

unsigned drive    Drive number

unsigned head    Head number

unsigned track     Track number

unsigned sector    Starting sector number

unsigned nsectors    Number of sectors to read, write, or compare

void far *buffer    Memory location to write to, read from, or compare

The service parameter can be set to one of the following manifest constants:

_DISK_FORMAT    Formats the track specified by diskinfo. The head and track fields indicate the track to format. Only one track can be formatted in a single call. The buffer field points to a set of sector markers. The format of the markers depends on the type of disk drive; see a technical reference to the PC BIOS to determine the marker format. The high-order byte (AH) of the return value contains the status of the call; 0 equals success. If there is an error, the high-order byte will contain a set of status flags, as defined below under Return Value.

_DISK_READ    Reads one or more disk sectors into memory. This service uses all fields of the structure pointed to by diskinfo, as defined earlier in this section. If no error occurs, the function returns 0 in the high-order byte and the number of sectors read in the low-order byte. If there is an error, the high-order byte (AH) will contain a set of status flags, as defined below under Return Value.

_DISK_RESET    Forces the disk controller to do a hard reset, preparing for floppy-disk I/O. This is useful after an error occurs in another operation, such as a read. If this service is specified, the diskinfo parameter is ignored. Status is returned in the 8 high-order bits (AH) of the return value. If there is an error, the high-order byte will contain a set of status flags, as defined below under Return Value.

_DISK_STATUS    Obtains the status of the last disk operation. If this service is specified, the diskinfo parameter is ignored. Status is returned in the 8 low-order bits (AL) of the return value. If there is an error, the low-order byte (AL) will contain a set of status flags, as defined below under Return Value.

_DISK_VERIFY    Checks the disk to be sure the specified sectors exist and can be read. It also runs a CRC (cyclic redundancy check) test. This service uses all fields (except buffer) of the structure pointed to by diskinfo, as defined earlier in this section. If no error occurs, the function returns 0 in the high-order byte (AH) and the number of sectors compared in the low-order byte (AL). The error status flags are listed below under Return Value.

_DISK_WRITE    Writes data from memory to one or more disk sectors. This service uses all fields of the structure pointed to by diskinfo, as defined earlier in this section. If no error occurs, the function returns 0 in the high-order byte (AH) and the number of sectors written in the low-order byte (AL). If there is an error, the high-order byte will contain a set of status flags, as defined below under Return Value.

Return Value

The _bios_disk function returns the value in the AX register after the BIOS interrupt. The following bits have these meanings:

0x00     No error

0x01    Invalid request or a bad command

0x02    Address mark not found

0x03    Disk write protected

0x04    Sector not found

0x05    Reset failed

0x06    Floppy disk removed

0x07    Drive parameter activity failed

0x08    Direct Memory Access (DMA) overrun

0x09    DMA crossed 64K boundary

0x0A    Bad sector flag detected

0x0B    Bad track flag detected

0x0C    Media type not found

0x0D    Invalid number of sectors on format

0x0E    Control data access mark detected

0x0F    DMA arbitration level out of range

0x10    Data read (CRC or ECC) error

0x11    Corrected data read (ECC) error

0x20    Controller failure

0x40    Seek error

0x80    Disk timed out or failed to respond

0xAA    Drive not ready

0xBB    Undefined error

0xCC    Write fault on drive

0xE0    Status error

0xFF    Sense operation failed

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BDISK.C: This program first attempts to verify a
 * disk by using an invalid disk head number. After
 * printing the return value error code, the program
 * verifies the disk by using a valid disk head code.
 */

#include <conio.h>
#include <stdio.h>
#include <bios.h>

void main( void )
{
   unsigned status = 0;
   struct _diskinfo_t disk_info;

   disk_info.drive    = 0;
   disk_info.head     = 10;   /* Invalid head number */
   disk_info.track    = 1; disk_info.sector   = 2;
   disk_info.nsectors = 8;
   printf( "Insert disk in drive A: and press any key\n" );
   _getch();
   status = _bios_disk( _DISK_VERIFY, &disk_info );
   printf( "Return value: 0x%.4x\n", status );
   if( status & 0xff00 )      /* Error if high byte is 0 */
      printf( "Seek error\n" );
    else
      printf( "No seek error\n" );
   printf( "Press any key\n" );
   _getch(); disk_info.head = 0;        /* Valid head number */
   status = _bios_disk( _DISK_VERIFY, &disk_info );
   printf( "Return value: 0x%.4x\n", status );
   if( status & 0xff00 )      /* Error if high byte is 0 */
      printf( "Seek error\n" );
   else
      printf( "No seek error\n" );
}

Output

Insert disk in drive A: and press any key
Return value: 0x0600
Seek error
Press any key
Return value: 0x0008
No seek error


Description: _bios_equiplist
_bios_equiplist

#include <bios.h>

unsigned _bios_equiplist( void );

Remarks

The _bios_equiplist routine uses INT 0x11 to determine what hardware and peripherals are currently installed on the machine.

Return Value

The function returns the AX value, which is a set of bits indicating what equipment is installed, as defined below:

0    True (1) if disk drive(s) installed

1    True (1) if math coprocessor installed

2−3    System RAM in 16K blocks (16 − 64K)

4−5    Initial video mode:
00 = Reserved
01 = 40 x 25 color
10 = 80 x 25 color
11 = 80 x 25 monochrome

6−7    Number of floppy-disk drives installed (00 = 1, 01 = 2, and so forth.)

8    False (0) if and only if a direct memory access (DMA) chip is installed

9−11    Number of RS232 serial ports installed

12    True (1) if and only if a game adapter is installed

13    True (1) if and only if an internal modem is installed

14−15    Number of printers installed

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BEQUIPLI.C: This program checks for the presence of diskettes.
 */

#include <bios.h>
#include <stdio.h>

void main( void )
{
   unsigned equipment;

   equipment = _bios_equiplist();
   printf( "Equipment bits: 0x%.4x\n", equipment );
   if( equipment & 0x1000 )      /* Check for game adapter bit */
      printf( "Game adapter installed\n" );
   else
      printf( "No game adapter installed\n" );
}

Output

Equipment bits: 0xc463
No game adapter installed


Description: _bios_keybrd
_bios_keybrd

#include <bios.h>

unsigned _bios_keybrd( unsigned service );

service    Keyboard function desired

Remarks

The _bios_keybrd routine uses INT 0x16 to access the keyboard services. The service parameter can be any of the following manifest constants:

_KEYBRD_READ, _NKEYBRD_READ    Reads the next character from the keyboard. If no character has been typed, the call will wait for one. If the low-order byte of the return value is nonzero, the call contains the ASCII value of the character typed. The high-order byte contains the keyboard scan code for the character. The _NKEYBRD_READ constant is used with enhanced keyboards to obtain the scan codes for function keys F11 and F12 and the cursor control keys.

_KEYBRD_READY, _NKEYBRD_READY    Checks whether a keystroke is waiting to be read and, if so, reads it. The return value is 0 if no keystroke is waiting, or it is the character waiting to be read, in the same format as the _KEYBRD_READ or _NKEYBRD_READ return. This service does not remove the waiting character from the input buffer, as does the _KEYBRD_READ or _NKEYBRD_READ service. The _NKEYBRD_READY constant is used with enhanced keyboards to obtain the scan codes for function keys F11 and F12 and the cursor control keys.

_KEYBRD_SHIFTSTATUS, _NKEYBRD_SHIFTSTATUS    Returns the current SHIFT-key status. _KEYBRD_SHIFTSTATUS returns only low byte. The _NKEYBRD_SHIFTSTATUS constant is used to get a full 16-bit status value. Any combination of the following bits may be set:

00H    Rightmost SHIFT key pressed

01H    Leftmost SHIFT key pressed

02H    Either CTRL key pressed

03H    Either ALT key pressed

04H    SCROLL LOCK on

05H    NUM LOCK on

06H    CAPS LOCK on

07H    In insert mode (INS)

08H    Left CTRL key pressed

09H    Left ALT key pressed

0AH    Right CTRL key pressed

0BH    Right ALT key pressed

0CH    SCROLL LOCK key pressed

0DH    NUM LOCK key pressed

0EH    CAPS LOCK key pressed

0FH    SYS REQ key pressed

Return Value

With the ...READ and ...SHIFTSTATUS parameters, the _bios_keybrd function returns the contents of the AX register after the BIOS call. With the ...READY parameter, _bios_keybrd returns 0 if there is no key. If there is a key, _bios_keybrd returns the key waiting to be read (i.e., the same value as _KEYBRD_READ). With the ...READ and the ...READY parameters, the _bios_keybrd function returns − 1 if CTRL+BREAK has been pressed and is the next keystroke to be read.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BKEYBRD.C: This program prints a message on the
 * screen until the right SHIFT key is pressed.
 */

#include <bios.h>
#include <stdio.h>

void main( void )
{
   while( !(_bios_keybrd( _KEYBRD_SHIFTSTATUS ) & 0001) )
      printf( "Use the right SHIFT key to stop this message\n" );
   printf( "Right SHIFT key pressed\n" );
}

Output

Use the right SHIFT key to stop this message
Use the right SHIFT key to stop this message
Use the right SHIFT key to stop this message
Use the right SHIFT key to stop this message
Right SHIFT key pressed


Description: _bios_memsize
_bios_memsize

#include <bios.h>

unsigned _bios_memsize( void );

Remarks

The _bios_memsize routine uses INT 0x12 to determine the total amount of conventional main memory installed.

Return Value

The routine returns the total amount of installed memory in 1K blocks. The maximum return value is 640, representing 640K of conventional main memory.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BMEMSIZE.C: This program displays the amount of
 * memory installed.
 */

#include <bios.h>
#include <stdio.h>

void main( void )
{
   unsigned memory;

   memory = _bios_memsize();
   printf ( "The amount of memory installed is: %dK\n", memory );
}

Output

The amount of memory installed is: 640K


Description: _bios_printer
_bios_printer

#include <bios.h>

unsigned _bios_printer( unsigned service, unsigned printer, unsigned data );

service    Printer function desired

printer    Target printer port

data    Output data

Remarks

The _bios_printer routine uses INT 0x17 to perform printer output services for parallel printers. The printer parameter specifies the affected printer, where 0 is LPT1, 1 is LPT2, and so forth. Some printers do not support the full set of signals. As a result, the "Out of Paper" condition, for example, may not be returned to your program. The service parameter can be any of the following manifest constants:

_PRINTER_INIT    Initializes the selected printer. The data parameter is ignored.

_PRINTER_STATUS    Returns the printer status. The data parameter is ignored.

_PRINTER_WRITE    Sends the low-order byte of data to the printer specified by printer.

Return Value

The _bios_printer function returns the value in the AX register after the BIOS interrupt. The high-order byte (AH) of the return value indicates the printer status after the operation, as defined below:

Bit	Meaning if True
0	Printer timed out
1	Not used
2	Not used
3	I/O error
4	Printer selected
5	Out of paper
6	Acknowledge
7	Printer not busy
Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BPRINTER.C: This program checks the status
 * of the printer attached to LPT1 when it is
 * off line, then initializes the printer.
 */

#include <bios.h>
#include <conio.h>
#include <stdio.h>

#define LPT1 0

void main( void )
{
   unsigned status;

   printf ( "Place printer off line and press any key\n" );
   _getch();

   status = _bios_printer( _PRINTER_STATUS, LPT1, 0 );
   printf( "Status with printer off line: 0x%.4x\n\n", status );
   printf( "Put the printer on line and then\n" );
   printf( "Press any key to initialize printer\n" );
   _getch();

   status = _bios_printer( _PRINTER_INIT, LPT1, 0 );
   printf( "Status after printer initialized: 0x%.4x\n", status );
}

Output

Place printer off line and press any key
Status with printer off line: 0x0038

Put the printer on line and then
Press any key to initialize printer
Status after printer initialized: 0x0038


Description: _bios_serialcom
_bios_serialcom

#include <bios.h>

unsigned _bios_serialcom( unsigned service, unsigned serial_port, unsigned data );

service    Communications service

serial_port     Serial port to use

data    Port configuration bits

Remarks

The _bios_serialcom routine uses INT 0x14 to provide serial communications services. The serial_port parameter is set to 0 for COM1, to 1 for COM2, and so on. The _bios_serialcom routine may not be able to establish reliable communications at baud rates in excess of 1,200 baud (_COM_1200) due to the overhead associated with servicing computer interrupts. Faster data communication rates are possible with more direct programming of serial-port controllers. See C Programmer's Guide to Serial Communications for more details on serial-communications programming in C. (More information on this book is found under »Other Books of Interest.«)

The service parameter can be set to one of the following manifest constants:

_COM_INIT    Sets the port to the parameters specified in the data parameter

_COM_SEND    Transmits the data characters over the selected serial port

_COM_RECEIVE    Accepts an input character from the selected serial port

_COM_STATUS    Returns the current status of the selected serial port

The data parameter is ignored if service is set to _COM_RECEIVE or _COM_STATUS. The data parameter for _COM_INIT is created by combining (with the OR operator) one or more of the following constants:

_COM_CHR7    7 data bits

_COM_CHR8    8 data bits

_COM_STOP1    1 stop bit

_COM_STOP2     2 stop bits

_COM_NOPARITY    No parity

_COM_EVENPARITY    Even parity

_COM_ODDPARITY    Odd parity

_COM_110    110 baud

_COM_150    150 baud

_COM_300    300 baud

_COM_600     600 baud

_COM_1200     1200 baud

_COM_2400     2400 baud

_COM_4800     4800 baud

_COM_9600     9600 baud

The default value of data is 1 stop bit, no parity, and 110 baud.

Return Value

The function returns a 16-bit integer whose high-order byte contains status bits. The meaning of the low-order byte varies, depending on the service value. The high-order bits have the following meanings:

15    Timed out

14    Transmission-shift register empty

13    Transmission-hold register empty

12    Break detected

11    Framing error

10    Parity error

9    Overrun error

8    Data ready

When service is _COM_SEND, bit 15 will be set if data could not be sent. When service is _COM_RECEIVE, the byte read will be returned in the low-order bits if the call is successful. If an error occurs, any of the bits 9, 10, 11, or 15 will be set. When service is _COM_INIT or _COM_STATUS, the low-order bits are defined as follows:

7    Receive-line signal detected

6    Ring indicator

5    Data set ready

4    Clear to send

3    Change in receive-line signal detected

2    Trailing-edge ring indicator

1    Change in data-set-ready status

0     Change in clear-to-send status

Note that this function works only with IBM personal computers and true compatibles.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BSERIALC.C: This program checks the
 * status of serial port COM1.
 */

#include <bios.h>
#include <stdio.h>

void main( void )
{
   unsigned com1_status;

   com1_status =  _bios_serialcom( _COM_STATUS, 0, 0 );
   printf ( "COM1 status: 0x%.4x\n", com1_status );
}

Output

COM1 status: 0x6000


Description: _bios_timeofday
_bios_timeofday

#include <bios.h>

unsigned _bios_timeofday( unsigned service, long *timeval );

service    Time function desired

timeval    Clock count

Remarks

The _bios_timeofday routine uses INT 0x1A to get or set the clock count. The service parameter can be either of two following manifest constants. The _TIME_GETCLOCK constant copies the current value of the clock count to the location pointed to by timeval. If midnight has not passed since the last time the system clock was read or set, the function returns 0; otherwise, the function returns 1. The _TIME_SETCLOCK constant sets the current value of the system clock to the value in the location pointed to by timeval. There is no return value.

Return Value

The _bios_timeofday function returns the value in the AX register after the BIOS interrupt.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * BTIMEOFD.C: This program gets the current system
 * clock count before and after a "do-nothing" loop
 * and displays the difference.
 */

#include <bios.h>
#include <stdio.h>

void main( void )
{
   long i, begin_tick, end_tick;

   _bios_timeofday( _TIME_GETCLOCK, &begin_tick );
   printf( "Beginning tick count: %lu\n", begin_tick );
   for( i = 1; i <= 900000; i++ )
      ;
   _bios_timeofday( _TIME_GETCLOCK, &end_tick );
   printf( "Ending tick count:    %lu\n", end_tick );
   printf( "Elapsed ticks:        %lu\n", end_tick - begin_tick );
}

Output

Beginning tick count: 839102
Ending tick count:    839113
Elapsed ticks:        11


Description: bsearch
bsearch

#include <stdlib.h>    Required for ANSI compatibility

#include <search.h>

void *bsearch( const void *key, const void *base, size_t num, size_t width, int ( __cdecl *compare )( const void *elem1, const void *elem2 ) );

key    Object to search for

base    Pointer to base of search data

num    Number of elements

width    Width of elements

compare    Function that compares two elements: elem1 and elem2

elem1    Pointer to the key for the search

elem2    Pointer to the array element to be compared with the key

Remarks

The bsearch function performs a binary search of a sorted array of num elements, each of width bytes in size. The base value is a pointer to the base of the array to be searched, and key is the value being sought. The compare parameter is a pointer to a user-supplied routine that compares two array elements and returns a value specifying their relationship. The bsearch function calls the compare routine one or more times during the search, passing pointers to two array elements on each call. The routine compares the elements, then returns one of the following values:

value < 0    elem1 less than elem2

value = 0    elem1 identical to elem2

value > 0    elem1 greater than elem2

If the array you are searching is not in ascending sort order, bsearch does not work properly. If the array contains duplicate records with identical keys, there is no way to predict which of the duplicate records will be located by bsearch.

Return Value

The bsearch function returns a pointer to an occurrence of key in the array pointed to by base. If key is not found, the function returns NULL.

See Also

»_lfind,« »_lsearch,« »qsort«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* BSEARCH.C: This program reads the command-line
 * parameters, sorting them with qsort, and then
 * uses bsearch to find the word "cat."
 */

#include <search.h>
#include <string.h>
#include <stdio.h>

int compare( char **arg1, char **arg2 ); /* Declare a function
                                            for compare */

void main( int argc, char **argv )
{
   char **result;
   char *key = "cat";
   int i;

   /* Sort using Quicksort algorithm: */
   qsort( (void *)argv, (size_t)argc, sizeof( char * ), (int (*)(const void*, const void*))compare );

   for( i = 0; i < argc; ++i )    /* Output sorted list */
      printf( "%s ", argv[i] );

   /* Find the word "cat" using a binary search algorithm: */
   result = (char **)bsearch( (char *) &key, (char *)argv, argc,
                              sizeof( char * ), (int (*)(const void*, const void*))compare );
   if( result )
      printf( "\n%s found at %Fp\n", *result, result );
   else
      printf( "\nCat not found!\n" );
}

int compare( char **arg1, char **arg2 )
{
   /* Compare all of both strings: */
   return _strcmpi( *arg1, *arg2 );
}

Output

[C:\work]bsearch dog pig horse cat human rat cow goat
bsearch cat cow dog goat horse human pig rat
cat found at 002D0008


Description: _cabs, _cabsl
  _cabs, _cabsl

#include <math.h>

double _cabs( struct _complex z );

long double _cabsl( struct _complexl z );

z    Complex number

Remarks

The _cabs and _cabsl functions calculate the absolute value of a complex number, which must be a structure of type _complex (or _complexl). The structure z is composed of a real component x and an imaginary component y. A call to one of the _cabs routines is equivalent to: sqrt( z.x*z.x + z.y*z.y ). The _cabsl function is the 80-bit counterpart, and it uses the 80-bit, 10-byte coprocessor form of parameters and return values. See the »long double functions« for more details on this data type.

Return Value

These functions return the absolute value if successful, or HUGE_VAL on overflow (_LHUGE_VAL for _cabsl). The errno variable is set to ERANGE on overflow. Error handling can be changed with the _matherrl function.

See Also

»abs,« »fabs,« »labs«

Compatibility

_cabs:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_cabsl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _cabs for compatibility with ANSI naming conventions of non-ANSI functions. Use cabs and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* CABS.C: Using _cabs, this program calculates
 * the absolute value of a complex number.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   struct _complex number = { 3.0, 4.0 };
   double d;

   d = _cabs( number );
   printf( "The absolute value of %f + %fi is %f\n",
           number.x, number.y, d );
}

Output

The absolute value of 3.000000 + 4.000000i is 5.000000


Description: calloc Functions
  calloc Functions

#include <stdlib.h>    For ANSI compatibility (calloc only)

#include <malloc.h>

void *calloc( size_t num, size_t size );

void __based( void ) *_bcalloc( __segment seg, size_t num, size_t size );

void __far *_fcalloc( size_t num, size_t size );

void __near *_ncalloc( size_t num, size_t size );

num    Number of elements

size    Length in bytes of each element

seg    Segment selector

Remarks

The calloc family of functions allocates storage space for an array of num elements, each of length size bytes. Each element is initialized to 0. In large data models (compact-, large-, and huge-model programs), calloc maps to _fcalloc. In small data models (tiny-, small-, and medium-model programs), calloc maps to _ncalloc. The various calloc functions allocate storage space in the data segments shown in the list below:

calloc    Depends on data model of program

_bcalloc    Based heap, specified by seg segment selector

_fcalloc    Far heap (outside default data segment)

_ncalloc    Near heap (inside default data segment)

Return Value

The calloc functions return a pointer to the allocated space. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value. The _fcalloc and _ncalloc functions return NULL if there is insufficient memory available. The _bcalloc function returns _NULLOFF in this case.

See Also

»free functions,« »_halloc,« »_hfree,« »malloc functions,« »realloc functions«

Compatibility

calloc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bcalloc, _fcalloc, _ncalloc:

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CALLOC.C: This program uses calloc to allocate space for
 * 40 long integers. It initializes each element to zero.
 */

#include <stdio.h>
#include <malloc.h>

void main( void )
{
   long *buffer;

   buffer = (long *)calloc( 40, sizeof( long ) );
   if( buffer != NULL )
      printf( "Allocated 40 long integers\n" );
   else
      printf( "Can't allocate memory\n" );
   free( buffer );
}

Output

Allocated 40 long integers


Description: ceil, ceill
  ceil, ceill

#include <math.h>

double ceil( double x );

long double ceill( long double x );

x    Floating-point value

Remarks

The ceil and ceill functions return a double (or long double) value representing the smallest integer that is greater than or equal to x. The ceill function is the 80-bit counterpart, and it uses the 80-bit, 10-byte coprocessor form of parameters and return values. See the »long double functions« for more details on this data type.

Return Value

These functions return the double or long double result. There is no error return.

See Also

»floor,« »fmod«

Compatibility

ceil:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

ceill:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »floor.«


Description: _cexit, _c_exit__
  _cexit, _c_exit

#include <process.h>

void _cexit( void );

void _c_exit( void );

Remarks

The _cexit function calls, in LIFO ("last in, first out") order, the functions registered by atexit and _onexit. Then the _cexit function flushes all I/O buffers and closes all open streams before returning. The _c_exit function is the same as the _exit function but returns to the calling process without processing atexit or _onexit or flushing stream buffers. The behavior of the exit, _exit, _cexit, and _c_exit functions is described in the following list:

exit    Performs complete C library termination procedures, terminates the process, and exits with the supplied status code

_exit    Performs "quick" C library termination procedures, terminates the process, and exits with the supplied status code

_cexit    Performs complete C library termination procedures and returns to caller, but does not terminate the process

_c_exit    Performs "quick" C library termination procedures and returns to caller, but does not terminate the process

Return Value

None.

See Also

»abort,« »atexit,« »_exec functions,« »exit,« »_onexit,« »_spawn functions,« »system«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _cgets
  _cgets

#include <conio.h>

char *_cgets( char *buffer );

buffer    Storage location for data

Remarks

The _cgets function reads a string of characters directly from the console and stores the string and its length in the location pointed to by buffer. The buffer parameter must be a pointer to a character array. The first element of the array, buffer[0], must contain the maximum length (in characters) of the string to be read. The array must contain enough elements to hold the string, a terminating null character ('\0'), and two additional bytes. The _cgets function continues to read characters until a carriage-return − line-feed (CR-LF) combination is read, or the specified number of characters is read. The string is stored starting at str[2]. If a CR-LF combination is read, it is replaced with a null character ('\0') before being stored. The _cgets function then stores the actual length of the string in the second array element, buffer [1]. Because all MS-DOS editing keys are active when you call _cgets, pressing F3 repeats the last entry.

Return Value

The _cgets function returns a pointer to the start of the string, at buffer[2]. There is no error return.

See Also

»_getch,« »_getche«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CGETS.C: This program creates a buffer and initializes
 * the first byte to the size of the buffer: 2. Next, the
 * program accepts an input string using _cgets and displays
 * the size and text of that string.
 */

#include <conio.h>
#include <stdio.h>

void main( void )
{
   char buffer[82] = { 80 };  /* Maximum characters in 1st byte */
   char *result;

   printf( "Input line of text, followed by carriage return:\n");
   result = _cgets( buffer );  /* Input a line of text */
   printf( "\nLine length = %d\nText = %s\n", buffer[1], result );
}

Output

Input line of text, followed by carriage return:
This is a line of text.

Line length = 23
Text = This is a line of text.


Description: _chain_intr
  _chain_intr

#include <dos.h>

void _chain_intr( void( __cdecl __interrupt __far *target )( ));

target    Target interrupt routine

Remarks

The _chain_intr routine passes control from one interrupt handler to another. The stack and the registers of the first routine are passed to the second, allowing the second routine to return as if it had been called directly. The _chain_intr routine is generally used when a user-defined interrupt handler begins processing, then chains to the original interrupt handler to finish processing. Chaining is one of two techniques, listed below, that can be used to transfer control from a new interrupt routine to an old one:

•	Call _chain_intr with the interrupt routine as an argument. Do this if your routine is finished and you want the second interrupt routine to terminate the interrupt call.

void __interrupt new _int(unsigned _es, unsigned _ds,
   unsigned _di, unsigned _si,... )
{
   ++_di;                  /* Initial processing here */
   _chain_intr( old_int ); /* New DI passed to old_int */
   --_di;                  /* This is never executed */
}

•	Call the interrupt routine (after casting it to an interrupt function if necessary). Do this if you need to do further processing after the second interrupt routine finishes.

void __interrupt new _int(unsigned _es, unsigned _ds,
   unsigned _di, unsigned _si,... )
{
 ++_di;              /* Initial processing here */
   (*old_int)();     /* New DI passed to old_int */
   __asm mov _di, di /* Put real DI from old_int */
                     /* into _di for return */
}

Note that the real registers set by the old interrupt function are not automatically set to the pseudoregisters of the new routine. Use the _chain_intr function when you do not want to replace the default interrupt handler, but you do need to see its input. An example is a TSR (terminate-and-stay-resident) program that checks all keyboard input for a particular "hot key" sequence.

The _chain_intr function should be used only with C functions that have been declared with __interrupt. The __interrupt declaration ensures that the procedure's entry/exit sequence is appropriate for an interrupt handler.

Return Value

The _chain_intr function does not return to the caller.

See Also

»_dos_getvect,« »_dos_keep,« »_dos_setvect«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _chdir
  _chdir

#include <direct.h>

#include <errno.h>    Required for errno constants

int _chdir( const char *dirname );

dirname    Path of new working directory

Remarks

The _chdir function changes the current working directory to the directory specified by dirname. The dirname parameter must refer to an existing directory. This function can change the current working directory on any drive. In MS-DOS, _chdir cannot be used to change the default drive itself. However, in Windows NT, this function will change the default working drive. For example, if A: is the default drive and \BIN is the current working directory, the following call changes the current working directory for drive C:

_chdir("c:\\temp");

In Windows NT, this call changes the default drive to C:. In MS-DOS, the default drive remains unchanged. Notice that you must place two backslashes (\\) in a C string in order to represent a single backslash (\); the backslash is the escape character for C strings and therefore requires special handling.

If _chdir is called to change the directory on a drive other than the default drive, this function call may have no apparent immediate effect. However, when the _chdrive function is called to change the default drive to C:, the current working directory becomes C:\TEMP. With MS-DOS and Windows NT, the new directory set by the program becomes the new current working directory.

Return Value

The _chdir function returns a value of 0 if the working directory is successfully changed. A return value of −1 indicates an error, in which case errno is set to ENOENT, indicating that the specified path could not be found.

See Also

»_dos_setdrive,« »_mkdir,« »_rmdir,« »system«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _chdir for compatibility with ANSI naming conventions of non-ANSI functions. Use chdir and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* CHGDIR.C: This program uses the _chdir function to verify
 * that a given directory exists.
 */

#include <direct.h>
#include <stdio.h>
#include <stdlib.h>

void main( int argc, char *argv[] )
{
   if( _chdir( argv[1] )   )
      printf( "Unable to locate the directory: %s\n", argv[1] );
   else
      system( "dir *.c" );
}

Output

 Volume in drive C is CDRIVE
 Volume Serial Number is 1966-6F27

 Directory of C:\msvc\samples\generic

GENERIC  C                11463 01-28-93  01:03AM
               1 File(s)      11463 bytes
                           12763136 bytes free


Description: _chdrive
  _chdrive

#include <direct.h>

int _chdrive( int drive );

drive    Number of new working drive

Remarks

The _chdrive function changes the current working drive to the drive specified by drive. The drive parameter uses an integer to specify the new working drive (1=A, 2=B, etc.). This function changes only the working drive; the _chdir function changes the working directory. With MS-DOS, the new drive set by the program becomes the new working drive.

Return Value

The _chdrive function returns a value of 0 if the working drive is successfully changed. A return value of −1 indicates an error.

See Also

»_chdir,« »_dos_setdrive,« »_fullpath,« »_getcwd,« »_getdrive,« »_mkdir,« »_rmdir,« »system«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getdrive.«


Description: _chmod
  _chmod

#include    <sys\types.h>

#include    <sys\stat.h>

#include    <errno.h>

#include <io.h>

int _chmod( const char *filename, int pmode );

filename    Name of existing file

pmode    Permission setting for file

Remarks

The _chmod function changes the permission setting of the file specified by filename. The permission setting controls read and write access to the file. The constant expression pmode contains one or both of the manifest constants _S_IWRITE and _S_IREAD, defined in SYS\STAT.H. Any other values for pmode are ignored. When both constants are given, they are joined with the bitwise-OR operator ( | ). The meaning of the pmode parameter is as follows:

_S_IWRITE    Writing permitted

_S_IREAD    Reading permitted

_S_IREAD | _S_IWRITE    Reading and writing permitted

If write permission is not given, the file is read-only. Note that all files are always readable; it is not possible to give write-only permission. Thus the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent.

Return Value

The _chmod function returns the value 0 if the permission setting is successfully changed. A return value of −1 indicates an error; in this case, errno is set to ENOENT, indicating that the specified file could not be found.

See Also

»_access,« »_creat,« »_fstat,« »_open,« »_stat«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _chmod for compatibility with ANSI naming conventions of non-ANSI functions. Use chmod and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* CHMOD.C: This program uses _chmod to
 * change the mode of a file to read-only.
 * It then attempts to modify the file.
 */

#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   /* Make file read-only: */
   if( _chmod( "CHMOD.C", _S_IREAD ) == -1 )
      perror( "File not found\n" );
   else
      printf( "Mode changed to read-only\n" );
   system( "echo /* End of file */ >> CHMOD.C" );

   /* Change back to read/write: */
   if( _chmod( "CHMOD.C", _S_IWRITE ) == -1 )
      perror( "File not found\n" );
   else
      printf( "Mode changed to read/write\n" );
}

Output

Mode changed to read-only
Mode changed to read/write


Description: _chgsign
  _chgsign

#include <float.h>

double _chgsign( double x );

x    Double-precision floating-point value to be changed

Remarks

The _chgsign function reverses the sign of its double-precision floating-point argument x.

Return Value

The _chgsign function returns a value equal to its argument x, but with its sign reversed. There is no error return.

See Also

»fabs,« »_copysign«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _chsize
  _chsize

#include <io.h>

#include <errno.h>

int _chsize( int handle, long size );

handle    Handle referring to open file

size    New length of file in bytes

Remarks

The _chsize function extends or truncates the file associated with handle to the length specified by size. The file must be open in a mode that permits writing. Null characters ('\0') are appended if the file is extended. If the file is truncated, all data from the end of the shortened file to the original length of the file is lost. In MS-DOS and Windows, the directory update is done when a file is closed. Consequently, while a program is running, requests to determine the amount of free disk space may receive inaccurate results.

Return Value

The _chsize function returns the value 0 if the file size is successfully changed. A return value of −1 indicates an error, and errno is set to one of the following values:

EACCES    Specified file is locked against access.

EBADF    Specified file is read-only or an invalid file handle.

ENOSPC    No space is left on device.

See Also

»_close,« »_creat,« »_open«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _chsize for compatibility with ANSI naming conventions of non-ANSI functions. Use chsize and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* CHSIZE.C: This program uses _filelength to report the size
 * of a file before and after modifying it with _chsize.
 */

#include <io.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <stdio.h>

void main( void )
{
   int fh, result;
   unsigned int nbytes = BUFSIZ;

   /* Open a file */
   if( (fh = _open( "data", _O_RDWR | _O_CREAT, _S_IREAD
                   | _S_IWRITE ))  != -1 )
   {
      printf( "File length before: %ld\n", _filelength( fh ) );
      if( ( result = _chsize( fh, 329678 ) ) == 0 )
         printf( "Size successfully changed\n" );
      else
         printf( "Problem in changing the size\n" );
      printf( "File length after:  %ld\n", _filelength( fh ) );
      _close( fh );
   }
}

Output

File length before: 0
Size successfully changed
File length after:  329678


Description: _clear87, _clearfp
  _clear87, _clearfp

#include <float.h>

unsigned int _clear87( void );

unsigned int _clearfp( void );

Remarks

The _clear87 function clears the exception flags in the floating-point status word, sets the busy bit to 0, and returns the status word. The floating-point status word is a combination of the 8087/80287 status word and other conditions detected by the 8087/80287 exception handler, such as floating-point stack overflow and underflow.

The _clearfp function is a platform independent, portable version of the _clear87 routine. It is identical to the _clear87 function on Intel (x86) platforms and is also supported by the MIPS platform. If you want to ensure that your floating-point code is portable to MIPS, you should use the _clear87 function. If you are only targeting x86 platforms, you can use either _clear87 or _clearfp.

Return Value

The bits in the value returned indicate the floating-point status. See the FLOAT.H include file for a complete definition of the bits returned by _clear87. Many of the math library functions modify the 8087/80287 status word, with unpredictable results. Return values from _clear87 and _status87 become more reliable as fewer floating-point operations are performed between known states of the floating-point status word.

See Also

»_control87,« »_controlfp,« »_status87,« »_statusfp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CLEAR87.C: This program creates various floating-point
 * problems, then uses _clear87 to report on these problems.
 * Compile this program with Optimizations disabled (/Od).
 * Otherwise the optimizer will remove the code associated with
 * the unused floating-point values.
 */

#include <stdio.h>
#include <float.h>

void main( void )
{
   double a = 1e-40, b;
   float x, y;

   printf( "Status: %.4x - clear\n", _clear87()  );

   /* Store into y is inexact and underflows: */
   y = a;
   printf( "Status: %.4x - inexact, underflow\n", _clear87() );

   /* y is denormal: */
   b = y;
   printf( "Status: %.4x - denormal\n", _clear87() );
}

Output

Status: 0000 - clear
Status: 0003 - inexact, underflow
Status: 80000 - denormal


Description: clearerr
  clearerr

#include <stdio.h>

void clearerr( FILE *stream );

stream    Pointer to FILE structure

Remarks

The clearerr function resets the error indicator and end-of-file indicator for stream. Error indicators are not automatically cleared; once the error indicator for a specified stream is set, operations on that stream continue to return an error value until clearerr, fseek, fsetpos, or rewind is called.

Return Value

None.

See Also

»_eof,« »feof,« »ferror,« »perror«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CLEARERR.C: This program creates an error
 * on the standard input stream, then clears
 * it so that future reads won't fail.
 */

#include <stdio.h>

void main( void )
{
   int c;

   /* Create an error by writing to standard input. */
   putc( 'c', stdin );
   if( ferror( stdin ) )
   {
      perror( "Write error" );
      clearerr( stdin );
   }

   /* See if read causes an error. */
   printf( "Will input cause an error? " );
   c = getc( stdin );
   if( ferror( stdin ) )
   {
      perror( "Read error" );
      clearerr( stdin );
   }
}

Output

Write error: Error 0
Will input cause an error? n


Description: _clearscreen
  _clearscreen

#include <graph.h>

void __far _clearscreen( short area );

area    Target area

Remarks

The _clearscreen function erases the target area, filling it with the current background color. The area parameter can be one of the following manifest constants (defined in GRAPH.H):

_GCLEARSCREEN    Clears and fills the entire screen

_GVIEWPORT    Clears and fills only within the current view port

_GWINDOW    Clears and fills only within the current text window

Return Value

None.

See Also

»_getbkcolor,« »_setbkcolor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * CLRSCRN.C
 *
 */

#include <conio.h>
#include <graph.h>
#include <stdlib.h>

void main( void )
{
   short xhalf, yhalf, xquar, yquar;
   struct _videoconfig vc;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );
   _getvideoconfig( &vc );
   xhalf = vc.numxpixels / (short)2;
   yhalf = vc.numypixels / (short)2;
   xquar = xhalf / (short)2;
   yquar = yhalf / (short)2;

   _setviewport( 0, 0, xhalf - (short)1, yhalf - (short)1 );
   _rectangle( _GBORDER, 0,  0, xhalf - (short)1,
        yhalf - (short)1 );
   _ellipse( _GFILLINTERIOR, xquar/(short)4, yquar/(short)4,
        xhalf - (xquar/(short)4), yhalf - (yquar/(short)4) );
   _getch();
   _clearscreen( _GVIEWPORT );

   _getch();
   _setvideomode( _DEFAULTMODE );
}


Description: clock
  clock

#include <time.h>

clock_t clock( void );

Remarks

The clock function tells how much processor time has been used by the calling process. The time in seconds is approximated by dividing the clock return value by the value of the CLOCKS_PER_SEC constant. In other words, the clock function returns the number of processor timer ticks that have elapsed. A timer tick is approximately equal to 1/CLOCKS_PER_SEC seconds. In versions of Microsoft C prior to version 6.0, the CLOCKS_PER_SEC constant was called CLK_TCK.

Return Value

The clock function returns the product of the time in seconds and the value of the CLOCKS_PER_SEC constant. If the processor time is not available, the function returns the value −1, cast as clock_t. In MS-DOS, clock returns the time elapsed since the process started. This may not be equal to the actual processor time used by the process.

See Also

»difftime,« »time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CLOCK.C: This example prompts for how long
 * the program is to run and then continuously
 * displays the elapsed time for that period.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void sleep( clock_t wait );

void main( void )
{
   long    i = 600000L;
   clock_t start, finish;
   double  duration;

   /* Delay for a specified time. */
   printf( "Delay for three seconds\n" );
   sleep( (clock_t)3 * CLOCKS_PER_SEC );
   printf( "Done!\n" );

   /* Measure the duration of an event. */
   printf( "Time to do %ld empty loops is ", i );
   start = clock();
   while( i-- )
      ;
   finish = clock();
   duration = (double)(finish - start) / CLOCKS_PER_SEC;
   printf( "%2.1f seconds\n", duration );
}

/* Pauses for a specified number of microseconds. */
void sleep( clock_t wait )
{
   clock_t goal;
   goal = wait + clock();
   while( goal > clock() )
      ;
}

Output

Delay for three seconds
Done!
Time to do 600000 empty loops is 0.2 seconds


Description: _close
  _close

#include <io.h>

#include <errno.h>

int _close( int handle );

handle    Handle referring to open file

Remarks

The _close function closes the file associated with handle.

Return Value

The _close function returns 0 if the file was successfully closed. A return value of −1 indicates an error, and errno is set to EBADF, indicating an invalid file-handle parameter.

See Also

»_chsize,« »_creat,« »_dup,« »_dup2,« »_open,« »_unlink«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _close for compatibility with ANSI naming conventions of non-ANSI functions. Use close and link with OLDNAMES.LIB for UNIX compatibility.

Example

See the example for »_open.«


Description: _commit
  _commit

#include <io.h>

#include <errno.h>

int _commit( int handle );

handle    Handle referring to open file

Remarks

The _commit function forces the operating system to write the file associated with handle to disk. This call ensures that the specified file is flushed immediately, not at the operating system's discretion.

Return Value

The _commit function returns 0 if the file was successfully flushed to disk. A return value of −1 indicates an error, and errno is set to EBADF, indicating an invalid file-handle parameter.

See Also

»_creat,« »_open,« »_read,« »_write«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* COMMIT.C illustrates low-level file I/O functions including:
 *
 *     _close    _commit    memset    _open    _write
 *
 * This is example code; to keep the code simple and readable
 * return values are not checked.
 */

#include <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <memory.h>

#define MAXBUF 32

int log_receivable( int );

void main( void )
{
    int fhandle;
    fhandle = _open( "TRANSACT.LOG", _O_APPEND | _O_CREAT |
                                     _O_BINARY | _O_RDWR );
    log_receivable( fhandle );
    _close( fhandle );
}

int log_receivable( int fhandle )
{
/* The log_receivable function prompts for a name and a monetary
 * amount and places both values into a buffer (buf). The _write
 * function writes the values to the operating system and the
 * _commit function ensures that they are written to a disk file.
 */

    int i;
    char  buf[MAXBUF];

    memset( buf, '\0', MAXBUF );
    /* Begin Transaction. */
    printf( "Enter name: " );
    gets( buf );
    for( i = 1; buf[i] != '\0'; i++ );
    /* Write the value as a '\0' terminated string. */
    _write( fhandle, buf, i+1 );
    printf( "\n" );

    memset( buf, '\0', MAXBUF );
    printf( "Enter amount: $" );
    gets( buf );
    for( i = 1; buf[i] != '\0'; i++ );
    /* Write the value as a '\0' terminated string. */
    _write( fhandle, buf, i+1 );
    printf( "\n" );

    /* The _commit function ensures that two important pieces of
     * data are safely written to disk. The return value of the
     * _commit function is returned to the calling function.
     */
    return _commit( fhandle );
}


Description: _control87, _controlfp
  _control87, _controlfp

#include <float.h>

unsigned int _control87( unsigned int new, unsigned int mask );

unsigned int _controlfp( unsigned int new, unsigned int mask );

new    New control-word bit values

mask    Mask for new control-word bits to set

Remarks

The _control87 function gets and sets the floating-point control word. The floating-point control word allows the program to change the precision, rounding, and infinity modes in the floating-point-math package. Floating-point exceptions can also be masked or unmasked using the _control87 function. If the value for mask is equal to 0, then _control87 gets the floating-point control word. If mask is nonzero, then a new value for the control word is set in the following manner: for any bit that is on (equal to 1) in mask, the corresponding bit in new is used to update the control word. To put it another way, fpcntrl = ((fpcntrl & ~mask) | (new & mask)) where fpcntrl is the floating-point control word.

The _controlfp function is a platform independent, portable version of the _control87 routine. It is identical to the _control87 function on Intel (x86) platforms and is also supported by the MIPS platform. If you want to ensure that your floating-point code is portable to MIPS, you should use the _control87 function. If you are only targeting x86 platforms, you can use either _control87 or _controlfp.

The possible values for the mask constant (mask) and new control values (new) are shown in Table R.1.

Table R.1    Hexadecimal Values

Mask	Hexadecimal value	Constant	Hexadecimal  value
MCW_EM  (Interrupt exception)	0x003F	_EM_INVALID _EM_DENORMAL _EM_ZERODIVIDE _EM_OVERFLOW _EM_UNDERFLOW _EM_INEXACT	0x0001 0x0002 0x0004 0x0008 0x0010 0x0020
MCW_IC  (Infinity  control)	0x1000	_IC_AFFINE _IC_PROJECTIVE	0x1000 0x0000
MCW_RC  (Rounding  control)	0x0C00	RC_CHOP RC_UP _RC_DOWN _RC_NEAR	0x0C00 0x0800  0x0400  0x0000
MCW_PC  (Precision  control)	0x0300	_PC_24 (24 bits) _PC_53 (53 bits) _PC_64 (64 bits)	0x0000  0x0200  0x0300
Return Value

The bits in the value returned indicate the floating-point control state. See the FLOAT.H include file for a complete definition of the bits returned by _control87.

See Also

»_clear87,« »_clearfp,« »_status87,« »_statusfp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CNTRL87.C: This program uses _control87 to output the control
 * word, set the precision to 24 bits, and reset the status to
 * the default.
 */

#include <stdio.h>
#include <float.h>

void main( void )
{
   double a = 0.1;

   /* Show original control word and do calculation. */
   printf( "Original: 0x%.4x\n", _control87( 0, 0 ) );
   printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );

   /* Set precision to 24 bits and recalculate. */
   printf( "24-bit:   0x%.4x\n", _control87( _PC_24, MCW_PC ) );
   printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );

   /* Restore to default and recalculate. */
   printf( "Default:  0x%.4x\n",
          _control87( CW_DEFAULT, 0xffff ) );
   printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );
}

Output

Original: 0x8001f
0.1 * 0.1 = 1.000000000000000e-002
24-bit:   0xa001f
0.1 * 0.1 = 9.999999776482582e-003
Default:  0xa001f
0.1 * 0.1 = 9.999999776482582e-003


Description: _copysign
  _copysign

#include <float.h>

double _copysign( double x, double y );

x    Double-precision floating-point value to be changed

y    Double-precision floating-point value

Remarks

The _copysign function returns its double-precision floating point argument x with the same sign as its double-precision floating point argument y.

Return Value

The _copysign function returns its argument x with the same sign as its argument y. There is no error return.

See Also

»fabs,« »_chgsign«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: cos Functions
  cos Functions

#include <math.h>

double cos( double x );

double cosh( double x );

long double cosl( long double x );

long double coshl( long double x );

x    Angle in radians

Remarks

The cos and cosh functions return the cosine and hyperbolic cosine, respectively, of x. The cosl and coshl functions are the 80-bit counterparts and use the 80-bit, 10-byte coprocessor form of parameters and return values. See the »long double functions« for more details on this data type.

Return Value

If x is greater than or equal to 2 raised to the power of 27, a partial loss of significance in the result may occur in a call to cos, in which case the function generates a _PLOSS error. If x is greater than or equal to 2 raised to the power of 31, significance is completely lost, and cos prints a _TLOSS message to stderr and returns 0. In both cases, errno is set to ERANGE. If the result is too large in a cosh call, the functions return HUGE_VAL (_LHUGE_VAL for coshl) and set errno to ERANGE. This behavior can be changed with _matherr.

See Also

»acos functions,« »asin functions,« »atan functions,« »_matherr,« »sin functions,« »tan functions«

Compatibility

cos, cosh:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

cosl, coshl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »sin.«


Description: _cprintf
  _cprintf

#include <conio.h>

int _cprintf( const char *format [, argument] ... );

format    Format control string

argument    Optional parameters

Remarks

The _cprintf function formats and prints a series of characters and values directly to the console, using the _putch function to output characters. Each argument (if any) is converted and output according to the corresponding format specification in format. The format has the same form and function as the format parameter for the »printf« function. Note that unlike the fprintf, printf, and sprintf functions, _cprintf does not translate linefeed characters into carriage-return − linefeed (CR-LF) combinations on output.

Return Value

The _cprintf function returns the number of characters printed.

See Also

»_cscanf,« »fprintf,« »printf,« »sprintf,« »vfprintf«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CPRINTF.C: This program displays
 * some variables to the console.
 */

#include <conio.h>

void main( void )
{
   int      i = -16, h = 29;
   unsigned u = 62511;
   char     c = 'A';
   char     s[] = "Test";

   /* Note that console output does not translate \n as
    * standard output does. Use \r\n instead.
    */
   _cprintf( "%d  %.4x  %u  %c %s\r\n", i, h, u, c, s );
}

Output

-16  001d  62511  A Test


Description: _cputs
  _cputs

#include <conio.h>

int _cputs( const char *string );

string    Output string

Remarks

The _cputs function writes the null-terminated string pointed to by string directly to the console. Note that a carriage-return−linefeed (CR-LF) combination is not automatically appended to the string.

Return Value

If successful, _cputs returns a 0. If the function fails, it returns a nonzero value.

See Also

»_putch«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CPUTS.C: This program first displays
 * a string to the console.
 */

#include <conio.h>

void main( void )
{
   /* String to print at console.
    * Note the \r (return) character.
    */
   char *buffer = "Hello world (courtesy of _cputs)!\r\n";

   _cputs( buffer );
}

Output

Hello world (courtesy of _cputs)!


Description: _creat
  _creat

#include <sys\types.h>

#include <sys\stat.h>

#include <errno.h>

#include <io.h>

int _creat( const char *filename, int pmode );

filename    Name of new file

pmode    Permission setting

Remarks

The _creat function either creates a new file or opens and truncates an existing file. If the file specified by filename does not exist, a new file is created with the given permission setting and is opened for writing. If the file already exists and its permission setting allows writing, _creat truncates the file to length 0, destroying the previous contents, and opens it for writing. The permission setting, pmode, applies to newly created files only. The new file receives the specified permission setting after it is closed for the first time. The integer expression pmode contains one or both of the manifest constants _S_IWRITE and _S_IREAD, defined in SYS\STAT.H. When both of the constants are given, they are joined with the bitwise-OR operator ( | ). The pmode parameter is set to one of the following values:

_S_IWRITE    Writing permitted

_S_IREAD    Reading permitted

_S_IREAD | _S_IWRITE    Reading and writing permitted

If write permission is not given, the file is read-only. Note that all files are always readable; it is not possible to give write-only permission. Thus, the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent. With MS-DOS versions 3.0 and later, files opened using _creat are always opened in compatibility mode (see »_sopen«). With Windows NT, the files are always opened with _SH_DENYNO.

The _creat function applies the current file-permission mask to pmode before setting the permissions (see »_umask«). Note that the _creat routine is provided primarily for compatibility with previous libraries. A call to _open with _O_CREAT and _O_TRUNC in the oflag parameter is equivalent to _creat and is preferable for new code.

Return Value

If successful, _creat returns a handle for the created file. Otherwise, it returns −1 and sets errno to one of the following constants:

EACCES    The filename specifies an existing read-only file or specifies a directory instead of a file

EMFILE    No more handles available (too many open files)

ENOENT    File not found

See Also

»_chmod,« »_chsize,« »_close,« »_dup,« »_dup2,« »_open,« »_sopen,« »_umask«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _creat for compatibility with ANSI naming conventions of non-ANSI functions. Use creat and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* CREAT.C: This program uses _creat to create
 * the file (or truncate the existing file)
 * named data and open it for writing.
 */

#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int fh;

   fh = _creat( "data", _S_IREAD | _S_IWRITE );
   if( fh == -1 )
      perror( "Couldn't create data file" );
   else
   {
      printf( "Created data file.\n" );
      _close( fh );
   }
}

Output

Created data file.


Description: _cscanf
  _cscanf

#include <conio.h>

int _cscanf( const char *format [, argument] ... );

format    Format-control string

argument    Optional parameters

Remarks

The _cscanf function reads data directly from the console into the locations given by argument. The _getche function is used to read characters. Each optional parameter must be a pointer to a variable with a type that corresponds to a type specifier in format. The format controls the interpretation of the input fields and has the same form and function as the format parameter for the »scanf« function. While _cscanf normally echoes the input character, it will not do so if the last call was to _ungetch.

Return Value

The _cscanf function returns the number of fields that were successfully converted and assigned. The return value does not include fields that were read but not assigned. The return value is EOF for an attempt to read at end-of-file. This may occur when keyboard input is redirected at the operating system command-line level. A return value of 0 means that no fields were assigned.

See Also

»_cprintf,« »fscanf,« »scanf,« »sscanf«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CSCANF.C: This program prompts for a string
 * and uses _cscanf to read in the response.
 * Then _cscanf returns the number of items
 * matched, and the program displays that number.
 */

#include <stdio.h>
#include <conio.h>

void main( void )
{
   int   result, i[3];

   _cprintf( "Enter three integers: ");
   result = _cscanf( "%i %i %i", &i[0], &i[1], &i[2] );
   _cprintf( "\r\nYou entered " );
   while( result-- )
      _cprintf( "%i ", i[result] );
   _cprintf( "\r\n" );
}

Output

Enter three integers: 1  2  3
You entered 3 2 1


Description: ctime
  ctime

#include <time.h>

char *ctime( const time_t *timer );

timer    Pointer to stored time

Remarks

The ctime function converts a time stored as a time_t value to a character string. The timer value is usually obtained from a call to time, which returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, Universal coordinated time (UCT). The string result produced by ctime contains exactly 26 characters and has the form of the following example:

Wed Jan 02 02:03:55 1980\n\0

A 24-hour clock is used. All fields have a constant width. The newline character ('\n') and the null character ('\0') occupy the last two positions of the string.

Calls to the ctime function modify the single statically allocated buffer used by the gmtime and the localtime functions. Each call to one of these routines destroys the result of the previous call. The ctime function also shares a static buffer with the asctime function. Thus, a call to ctime destroys the results of any previous call to asctime, localtime, or gmtime.

Return Value

The ctime function returns a pointer to the character string result. If time represents a date before midnight, January 1, 1970, Universal coordinated time, ctime returns NULL.

See Also

»asctime,« »_ftime,« »gmtime,« »localtime,« »time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CTIME.C: This program gets the current
 * time in time_t form, then uses ctime to
 * display the time in string form.
 */

#include <time.h>
#include <stdio.h>

void main( void )
{
   time_t ltime;

   time( &ltime );
   printf( "The time is %s\n", ctime( &ltime ) );
}

Output

The time is Mon Mar 22 16:35:42 1993


Description: _cwait
  _cwait

#include <process.h>

int _cwait( int *termstat, int procid, int action );

termstat    Address for termination status code

procid    Process ID of new process

action    Action code

Remarks

The _cwait funtion suspends the calling process until the specified new process terminates. If not NULL, termstat points to a buffer where _cwait places the termination-status word and the return code of the terminated process. The termination-status word indicates whether the called process terminated normally by calling the Windows NT ExitProcess API. (Programs that terminate with exit or by "falling off the end of main" use ExitProcess internally.) If the process did terminate normally, the low-order and high-order bytes of the termination-status word are as follows:

High order    Contains the low-order byte of the result code that the new process code passed to ExitProcess. The ExitProcess function is called if the new process called exit or _exit, returned from main, or reached the end of main. The low-order byte of the result code is either the low-order byte of the argument to _exit or exit, the low-order byte of the return value from main, or a random value if the called process reached the end of main.

Low order    0 (normal termination)

If the called process terminates without calling ExitProcess, the high-order and low-order bytes of the termination-status word are as follows:

High order	0

Low order	Termination code:
1 = Hard-error abort
2 = Trap operation
3 = SIGTERM signal not intercepted

The procid argument specifies which new-process termination to wait for. This value is returned by the call to the spawn function that started the new process. If the specified spawned process terminates before _cwait is called, the function returns immediately.

The action argument specifies when the calling process resumes execution. This argument is ignored in Windows NT, but it is accepted for compatibility with OS/2®. In Windows NT, there is no parent-child relationship, as in OS/2. Therefore, the OS/2 wait function, which allowed a parent process to wait for any of its immediate children to terminate, is not available in Windows NT. The _cwait function can be used by any process to wait for any other process (if the process ID is known). The action argument can be one of the following values:

_WAIT_CHILD    The parent process waits until the specified child process has ended.

_WAIT_GRANDCHILD    The parent process waits until the specified child process and all child processes of that child process have ended.

The _WAIT_CHILD and _WAIT_GRANDCHILD action codes are defined in PROCESS.H.

Return Value

If the _cwait function returns after normal termination of the new process, it returns the process ID of the new process. If the _cwait function returns after abnormal termination of the new process, it returns −1 and sets errno to EINTR. Otherwise, the cwait function returns −1 immediately and sets errno to one of the following error codes:

ECHILD    No new process exists, or invalid process ID

EINVAL    Invalid action code

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* CWAIT.C: This program launches several processes and waits
 * for a specified process to finish.
 *
 * If compiling from the command prompt, use the following command line:
 *     CL /D "_X86_" CWAIT.C
 *
 */

#include <windows.h>
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

/* Macro to get a random integer within a specified range */
#define getrandom( min, max ) (( rand() % (int)((( max ) + 1 ) - \
                              ( min ))) + ( min ))

struct PROCESS
{
        int     nPid;
        char    name[40];

} process[4] = { { 0, "Ann" }, { 0, "Beth" }, { 0, "Carl" },
                 { 0, "Dave" } };

void main( int argc, char *argv[] )
{

   int termstat, c;

   srand( (unsigned)time( NULL ) );    /* Seed randomizer */
   /* If no arguments, this is the calling process */
   if( argc == 1 )
   {
      /* Spawn processes in numeric order */
      for( c = 0; c < 4; c++ ){
         _flushall();
         process[c].nPid = spawnl( _P_NOWAIT, argv[0], argv[0],
                                                  process[c].name, NULL );
      }

      /* Wait for randomly specified process, and respond when done */
      c = getrandom( 0, 3 );
      printf( "Come here, %s\n", process[c].name );
      _cwait( &termstat, process[c].nPid, _WAIT_CHILD );
      printf( "Thank you, %s\n", process[c].name );
   }

   /* If there are arguments, this must be a spawned process */
   else
   {
      /* Delay for a period determined by process number */
      Sleep( (argv[1][0] - 'A' + 1) * 1000L );
      printf( "Hi, Dad. It's %s.\n", argv[1] );
   }

}

Output

Hi, Dad. It's Ann.
Come here, Ann
Thank you, Ann
Hi, Dad. It's Beth.
Hi, Dad. It's Carl.
Hi, Dad. It's Dave.


Description: _dieeetomsbin, _dmsbintoieee
  _dieeetomsbin, _dmsbintoieee

#include <math.h>

int _dieeetomsbin( double *src8, double *dst8 );

int _dmsbintoieee( double *src8, double *dst8 );

src8    Buffer containing value to convert

dst8    Buffer to store converted value

Remarks

The _dieeetomsbin routine converts a double-precision number in IEEE (Institute of Electrical and Electronic Engineers) format to Microsoft (MS) binary format. The routine _dmsbintoieee converts a double-precision number in MS binary format to IEEE format. These routines allow C programs (which store floating-point numbers in the IEEE format) to use numeric data in random-access data files created with those versions of Microsoft Basic that store floating-point numbers in MS binary format, and vice versa. The parameter src8 is a pointer to the double value to be converted. The result is stored at the location given by dst8. These routines do not handle IEEE NANs ("not a number") and infinities. IEEE denormals are treated as 0 in the conversions.

Return Value

These functions return 0 if the conversion is successful and 1 if the conversion causes an overflow.

See Also

»_fieeetomsbin,« »_fmsbintoieee«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: difftime
  difftime

#include <time.h>

double difftime( time_t timer1, time_t timer0 );

timer0     Beginning time

timer1     Ending time

Remarks

The difftime function computes the difference between the supplied time values, timer0 and timer1.

Return Value

The difftime function returns, in seconds, the elapsed time from timer0 to timer1. The value returned is a double-precision floating-point number.

See Also

»time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* DIFFTIME.C: This program calculates the amount of time
 * needed to do a floating-point multiply 10 million times.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void main( void )
{
   time_t   start, finish;
   long loop;
   double   result, elapsed_time;

   printf( "This program will do a floating point multiply ");
   printf( "10,000,000 times\n" );
   printf( "Working...\n" );

   time( &start );
   for( loop = 0; loop < 10000000; loop++ )
      result = 3.63 * 5.27;
   time( &finish );

   elapsed_time = difftime( finish, start );
   printf( "\nProgram takes %6.0f seconds.\n", elapsed_time );
}

Output

This program will do a floating point multiply 10,000,000 times
Working...

Program takes      5 seconds.


Description: _disable
  _disable

#include <dos.h>

void _disable( void );

Remarks

The _disable routine disables interrupts by executing an 8086 CLI machine instruction. Use _disable before modifying an interrupt vector.

Return Value

None.

See Also

»_enable«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _displaycursor
  _displaycursor

#include <graph.h>

short __far _displaycursor( short flag );

flag    Cursor state

Remarks

Upon entry into each graphic routine, the screen cursor is turned off. The _displaycursor function determines whether the cursor will be turned back on when programs exit graphic routines. If flag is set to _GCURSORON, the cursor will be restored on exit. If flag is set to _GCURSOROFF, the cursor will be left off.

Return Value

The function returns the previous value of flag. There is no error return.

See Also

»_gettextcursor,« »_settextcursor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DISCURS.C: This program changes the cursor
 * shape using _gettextcursor and _settextcursor,
 * and hides the cursor using _displaycursor.
 */

#include <conio.h>
#include <graph.h>

void main( void )
{
   short oldcursor;
   short newcursor = 0x007;        /* Full block cursor */

   /* Save old cursor shape and make sure cursor is on */
   oldcursor = _gettextcursor();
   _clearscreen( _GCLEARSCREEN );
   _displaycursor( _GCURSORON );
   _outtext( "\nOld cursor shape: " );
   _getch();

   /* Change cursor shape */
   _outtext( "\nNew cursor shape: " );
   _settextcursor( newcursor );
   _getch();

   /* Restore original cursor shape */
   _outtext( "\n" );
   _settextcursor( oldcursor );
}


Description: div
  div

#include <stdlib.h>

div_t div( int numer, int denom );

numer    Numerator

denom    Denominator

Remarks

The div function divides numer by denom, computing the quotient and the remainder. The div_t structure contains int quot, the quotient, and int rem, the remainder. The sign of the quotient is the same as that of the mathematical quotient. Its absolute value is the largest integer that is less than the absolute value of the mathematical quotient. If the denominator is 0, the program will terminate with an error message.

Return Value

The div function returns a structure of type div_t, comprising both the quotient and the remainder. The structure is defined in STDLIB.H.

See Also

»ldiv«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* DIV.C: This example takes two integers as command-line
 * arguments and displays the results of the integer
 * division. This program accepts two arguments on the
 * command line following the program name, then calls
 * div to divide the first argument by the second.
 * Finally, it prints the structure members quot and rem.
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

void main( int argc, char *argv[] )
{
   int x,y;
   div_t div_result;

   x = atoi( argv[1] );
   y = atoi( argv[2] );

   printf( "x is %d, y is %d\n", x, y );
   div_result = div( x, y );
   printf( "The quotient is %d, and the remainder is %d\n",
           div_result.quot, div_result.rem );
}

Output

x is 876, y is 13
The quotient is 67, and the remainder is 5


Description: _dos_allocmem
  _dos_allocmem

#include <dos.h>

#include <errno.h>

unsigned _dos_allocmem( unsigned size, unsigned *seg );

size    Block size to allocate

seg    Return buffer for segment descriptor

Remarks

The _dos_allocmem function uses MS-DOS service 0x48 to allocate a block of memory size paragraphs long. (A paragraph is 16 bytes.) Allocated blocks are always paragraph aligned. The segment descriptor for the initial segment of the new block is returned in the word that seg points to. If the request cannot be satisfied, the maximum possible size (in paragraphs) is returned in this word instead.

Return Value

If successful, the _dos_allocmem function returns 0. Otherwise, it returns the
MS-DOS error code and sets errno to ENOMEM, indicating insufficient memory or invalid arena (memory area) headers.

See Also

»_alloca,« »calloc functions,« »_dos_freemem,« »_dos_setblock,« »_halloc,« »malloc functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DALOCMEM.C: This program allocates 20 paragraphs
 * of memory, increases the allocation to 40
 * paragraphs, and then frees the memory space.
 */

#include <dos.h>
#include <stdio.h>

void main( void )
{
   unsigned segment;
   unsigned maxsize;

   /* Allocate 20 paragraphs */
   if( _dos_allocmem( 20, &segment ) != 0 )
      printf( "allocation failed\n" );
   else
      printf( "allocation successful\n" );

   /* Increase allocation to 40 paragraphs */
   if( _dos_setblock( 40, segment, &maxsize ) != 0 )
      printf( "allocation increase failed\n" );
   else
      printf( "allocation increase successful\n" );

   /* free memory */
   if( _dos_freemem( segment ) != 0 )
      printf( "free memory failed\n" );
   else
      printf( "free memory successful\n" );
}

Output

allocation successful
allocation increase successful
free memory successful


Description: _dos_close
  _dos_close

#include <dos.h>

#include <errno.h>

unsigned _dos_close( int handle );

handle    Target file handle

Remarks

The _dos_close function uses system call 0x3E to close the file indicated by handle. The file's handle parameter is returned by the call that created or last opened the file.

Return Value

The function returns 0 if successful. Otherwise, it returns the MS-DOS error
code and sets errno to EBADF, indicating an invalid file handle. Do not use the MS-DOS interface I/O routines with the console, low-level, or stream I/O routines.

See Also

»_close,« »_creat,« »_dos_close,« »_dos_creat functions,« »_dos_open,« »_dos_read,« »_dos_write,« »_dup,« »_open«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for _dos_open.


Description: _dos_commit
  _dos_commit

#include <dos.h>

#include <errno.h>

unsigned _dos_commit( int handle );

handle    Target file handle

Remarks

The _dos_commit function uses system call 0x68 to flush to disk the MS-DOS buffers associated with the file indicated by handle. It also forces an update on the corresponding disk directory and the file allocation table. System call 0x68 ensures that the specified file is flushed directly to disk and not flushed at the operating system's discretion.

The system call used to implement _dos_commit is only available in MS-DOS versions 3.3 and later. Using _dos_commit in earlier versions of MS-DOS results in undefined behavior. Do not use the MS-DOS interface I/O routines with the console, low-level, or stream I/O routines.

Return Value

The function returns 0 if successful. Otherwise, it returns the MS-DOS error code and sets errno to EBADF, indicating an invalid file handle.

See Also

»_close,« »_creat,« »_dos_creat functions,« »_dos_open,« »_dos_read,« »_dos_write,« »_dup,« »_open«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DCOMMIT.C illustrates MS-DOS file I/O functions including:
 *      _dos_commit     _dos_creatnew     _dos_write
 *      _dos_creat      _dos_close
 *
 */

#include <dos.h>
#include <errno.h>
#include <conio.h>

void main()
{
   char saveit[] = "Straight to disk. ",
      prompt[] = "File exists, overwrite? [y|n] ",
      err[] = "Error occurred. ",
      newline[] = "\n\r";
   int hfile, ch;
   unsigned count;

   /* Open file and create, overwriting if necessary. */
   if( _dos_creatnew( "COMMIT.LOG", _A_NORMAL, &hfile ) != 0 )
   {
      if( errno == EEXIST )
      {
         /* Use _dos_write to display prompts. Use _bdos to call
          * function 1 to get and echo keystroke.
          */
         _dos_write( 1, prompt, sizeof( prompt ) - 1, &count );
         ch = _bdos( 1, 0, 0 ) & 0x00ff;
         if( (ch == 'y') || (ch == 'Y') )
            _dos_creat( "COMMIT.LOG", _A_NORMAL, &hfile );
         _dos_write( 1, newline, sizeof( newline ) - 1, &count );
      }
   }

   /* Write to file; output passes through
    * operating system's buffers.
    */
   if( _dos_write( hfile, saveit, sizeof( saveit ), &count ) != 0 )
   {
      _dos_write( 1, err, sizeof( err ) - 1, &count );
      _dos_write( 1, newline, sizeof( newline ) - 1, &count );
   }

   /* Write directly to file with no intermediate buffering */
   if( _dos_commit( hfile ) != 0 )
   {
      _dos_write( 1, err, sizeof( err ) - 1, &count );
      _dos_write( 1, newline, sizeof( newline ) - 1, &count );
   }

   /* Close file. */
   if( _dos_close( hfile ) != 0 )
   {
      _dos_write( 1, err, sizeof( err ) - 1, &count );
      _dos_write( 1, newline, sizeof( newline ) - 1, &count );
   }
}


Description: _dos_creat Functions
  _dos_creat Functions

#include <dos.h>

#include <errno.h>

unsigned _dos_creat( const char *filename, unsigned attrib, int *handle );

unsigned _dos_creatnew( const char *filename, unsigned attrib, int *handle );

filename    Name of new file

attrib    File attributes

handle    Handle return buffer

Remarks

The _dos_creat and _dos_creatnew routines create and open a new file named filename; this new file has the access attributes specified in the attrib parameter. The new file's handle is copied into the integer location pointed to by handle. The file is opened for both read and write access. If file sharing is installed, the file is opened in compatibility mode. The _dos_creat routine uses system call 0x3C, and the _dos_creatnew routine uses system call 0x5B. If the file already exists, _dos_creat erases its contents and leaves its attributes unchanged; however, the _dos_creatnew routine fails if the file already exists.

Return Value

If successful, both routines return 0. Otherwise, they return the MS-DOS error code and set errno to one of the following values:

EACCES    Access denied because the directory is full or, for _dos_creat only, the file exists and cannot be overwritten

EEXIST    File already exists (_dos_creatnew only)

EMFILE    Too many open file handles

ENOENT    Path or file not found

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DCREAT.C: This program creates a file using the _dos_creat
 * function. The program cannot create a new file using the
 * _dos_creatnew function because it already exists.
 */

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>

void main( void )
{
   int fh1, fh2;
   int result;

   if( ( result = _dos_creat( "data", _A_NORMAL, &fh1 ) ) != 0 )
      printf( "Couldn't create data file\n" );
   else
   {
      printf( "Created data file.\n" );

      /* If _dos_creat is successful, the _dos_creatnew call
       * will fail since the file exists
       */
      if( ( result = _dos_creatnew( "data", _A_RDONLY,
                                            &fh2 ) ) != 0 )
         printf( "Couldn't create data file\n" );
      else
      {
         printf( "Created data file.\n" );
        _dos_close( fh2 );
      }
      _dos_close( fh1 );
   }
}

Output

Created data file.
Couldn't create data file


Description: _dos_find Functions
  _dos_find Functions

#include <dos.h>

#include <errno.h>

unsigned _dos_findfirst( const char *filename, unsigned attrib, struct _find_t *fileinfo );

unsigned _dos_findnext( struct _find_t *fileinfo );

filename    Target filename

attrib    Target attributes

fileinfo    File-information buffer

Remarks

The _dos_findfirst routine uses system call 0x4E to return information about the first instance of a file whose name and attributes match filename and attrib. The filename parameter may use wildcards (* and ?). The attrib parameter can be any of the following manifest constants:

_A_ARCH    Archive. Set whenever the file is changed, and cleared by the MS-DOS BACKUP command.

_A_HIDDEN    Hidden file. Cannot be found with the MS-DOS DIR command. Returns information about normal files as well as about files with this attribute.

_A_NORMAL    Normal. File can be read or written without restriction.

_A_RDONLY    Read-only. File cannot be opened for writing, and a file with the same name cannot be created. Returns information about normal files as well as about files with this attribute.

_A_SUBDIR    Subdirectory. Returns information about normal files as well as about files with this attribute.

_A_SYSTEM    System file. Cannot be found with the MS-DOS DIR command. Returns information about normal files as well as about files with this attribute.

_A_VOLID    Volume ID. Only one file can have this attribute, and it must be in the root directory.

Multiple constants can be combined (with the OR operator), using the vertical-bar
( | ) character. If the attrib parameter to either of these functions is _A_RDONLY, _A_HIDDEN, _A_SYSTEM, or _A_SUBDIR, the function also returns any normal attribute files that match the filename parameter. That is, a normal file does not have a read-only, hidden, system, or directory attribute. Information is returned in a _find_t structure, defined in DOS.H. The _find_t structure contains the following elements:

char reserved[21]    Reserved for use by MS-DOS

char attrib    Attribute byte for matched path

unsigned wr_time    Time of last write to file

unsigned wr_date    Date of last write to file

long size    Length of file in bytes

char name[13]    Null-terminated name of matched file/directory, without the path

The formats for the wr_time and wr_date elements are in MS-DOS format and are not usable by any other C run-time function. The time format is shown below; the listed bits have the given contents:

0−4    Number of 2-second increments (0−29)

5−10    Minutes (0−59)

11−15    Hours (0−23)

The date format is shown below; the listed bits have the given contents:

0−4    Day of month (1−31)

5−8    Month (1−12)

9−15    Year (relative to 1980)

Do not alter the contents of the buffer between a call to _dos_findfirst and a subsequent call to the _dos_findnext function. Also, the buffer should not be altered between calls to _dos_findnext.

The _dos_findnext routine uses system call 0x4F to find the next name, if any, that matches the filename and attrib parameters specified in a prior call to _dos_findfirst. The fileinfo parameter must point to a structure initialized by a previous call to _dos_findfirst. The contents of the structure will be altered as described above if a match is found.

Return Value

If successful, both functions return 0. Otherwise, they return the MS-DOS error code and set errno to ENOENT, indicating that filename could not be matched.

See Also

»_findfirst,« »_findnext«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DFIND.C: This program finds and prints all files
 * in the current directory with the .c extension.
 */

#include <stdio.h>
#include <dos.h>

void main( void )
{
   struct _find_t  c_file;

   /* find first .c file in current directory */
   _dos_findfirst( "*.c", _A_NORMAL, &c_file );

   printf( "Listing of .c files:\n\n" );
   printf( "File: %s is %ld bytes\n", c_file.name, c_file.size );

   /* Find the rest of the .c files */
   while( _dos_findnext( &c_file ) == 0 )
      printf( "File: %s is %ld bytes\n", c_file.name,
                                         c_file.size );
}

Output

Listing of .c files:

File: DFIND.C is 586 bytes


Description: _dos_freemem
  _dos_freemem

#include <dos.h>

#include <errno.h>

unsigned _dos_freemem( unsigned seg );

seg    Block to be released

Remarks

The _dos_freemem function uses system call 0x49 to release a block of memory previously allocated by _dos_allocmem. The seg parameter is a value returned by a previous call to _dos_allocmem. The freed memory may no longer be used by the application program.

Return Value

If successful, _dos_freemem returns 0. Otherwise, it returns the MS-DOS error code and sets errno to ENOMEM, indicating a bad segment value (one that does not correspond to a segment returned by a previous _dos_allocmem call) or invalid arena (memory area) headers.

See Also

»_dos_allocmem,« »_dos_setblock,« »free functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for _dos_allocmem.


Description: _dos_getdate
  _dos_getdate

#include <dos.h>

void _dos_getdate( struct _dosdate_t *date );

date    Current system date

Remarks

The _dos_getdate routine uses system call 0x2A to obtain the current system date. The date is returned in a _dosdate_t structure, defined in DOS.H. The _dosdate_t structure contains the following elements:

unsigned char day    1−31

unsigned char month    1−12

unsigned int year    1980−2099

unsigned char dayofweek    0−6 (0 = Sunday)

Return Value

None.

See Also

»_dos_gettime,« »_dos_setdate,« »_dos_settime,« »gmtime,« »localtime,« »mktime,« »_strdate,« »_strtime,« »time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for _dos_gettime.


Description: _dos_getdiskfree
  _dos_getdiskfree

#include <dos.h>

#include <errno.h>

unsigned _dos_getdiskfree( unsigned drive, struct _diskfree_t * diskspace );

drive    Drive number (default is 0)

diskspace    Buffer to hold disk information

Remarks

The _dos_getdiskfree routine uses system call 0x36 to obtain information on the disk drive specified by drive. The default drive is 0, drive A is 1, drive B is 2, and so on. Information is returned in the _diskfree_t structure (defined in DOS.H) pointed to by diskspace. The struct _diskfree_t structure contains the following elements:

unsigned total_clusters    Total clusters on disk

unsigned avail_clusters    Available clusters on disk

unsigned sectors_per_cluster    Sectors per cluster

unsigned bytes_per_sector    Bytes per sector

Return Value

If successful, the function returns 0. Otherwise, it returns a nonzero value and sets errno to EINVAL, indicating that an invalid drive was specified.

See Also

»_dos_getdrive,« »_dos_setdrive«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DGDISKFR.C: This program displays information
 * about the default disk drive.
 */

#include <stdio.h>
#include <dos.h>

void main( void )
{
   struct _diskfree_t drive;

   /* Get information on default disk drive 0 */
   _dos_getdiskfree( 0, &drive );
   printf( "total clusters: %u\n", drive.total_clusters );
   printf( "available clusters: %u\n", drive.avail_clusters );
   printf( "sectors per cluster: %u\n",
                                 drive.sectors_per_cluster );
   printf( "bytes per sector: %u\n", drive.bytes_per_sector );
}

Output

total clusters: 41319
available clusters: 1437
sectors per cluster: 16
bytes per sector: 512


Description: _dos_getdrive
  _dos_getdrive

#include <dos.h>

void _dos_getdrive( unsigned *drive );

drive    Current-drive return buffer

Remarks

The _dos_getdrive routine uses system call 0x19 to obtain the current disk drive. The current drive is returned in the word that drive points to: 1 = drive A, 2 = drive B, and so on.

Return Value

None.

See Also

»_dos_getdiskfree,« »_dos_setdrive,« »_getdrive«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DGDRIVE.C: This program prints the letter of
 * the current drive, changes the default drive
 * to A, then returns the number of disk drives.
 */

#include <stdio.h>
#include <dos.h>

void main( void )
{
   unsigned olddrive, newdrive;
   unsigned number_of_drives;

   /* Print current default drive information */
   _dos_getdrive( &olddrive );
   printf( "The current drive is: %c\n", 'A' + olddrive - 1 );

   /* Set default drive to be drive A */
   printf( "Changing default drive to A\n");
   _dos_setdrive( 1, &number_of_drives );

   /* Get new default drive information
    * and total number of drives
    */
   _dos_getdrive( &newdrive );
   printf( "The current drive is: %c\n", 'A' + newdrive - 1 );
   printf( "Number of logical drives: %d\n", number_of_drives );

   /* Restore default drive */
   _dos_setdrive( olddrive, &number_of_drives );
}

Output

The current drive is: C
Changing default drive to A
The current drive is: A
Number of logical drives: 26


Description: _dos_getfileattr
  _dos_getfileattr

#include <dos.h>

#include <errno.h>

unsigned _dos_getfileattr( const char *path, unsigned *attrib );

path    Full path of target file/directory

attrib    Word to store attributes in

Remarks

The _dos_getfileattr routine uses system call 0x43 to obtain the current attributes of the file or directory pointed to by path. The attributes are copied to the low-order byte of the attrib word. Attributes are represented by manifest constants; the following constants have the given meanings:

_A_ARCH    Archive. Set whenever the file is changed, or cleared by the MS-DOS BACKUP command.

_A_HIDDEN    Hidden file. Cannot be found by a directory search.

_A_NORMAL    Normal. File can be read or written without restriction.

_A_RDONLY    Read-only. File cannot be opened for a write, and a file with the same name cannot be created.

_A_SUBDIR    Subdirectory.

_A_SYSTEM    System file. Cannot be found by a directory search.

_A_VOLID    Volume ID. Only one file can have this attribute, and it must be in the root directory.

Return Value

If successful, the function returns 0. Otherwise, it returns the MS-DOS error code and sets errno to ENOENT, indicating that the target file or directory could not be found.

See Also

»_access,« »_chmod,« »_dos_setfileattr,« »_umask«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DGFILEAT.C: This program creates a file with the
 * specified attributes, then prints this information
 * before changing the file attributes back to normal.
 */

#include <stdio.h>
#include <dos.h>

void main( void )
{
   unsigned oldattrib, newattrib;

   /* Get and display file attribute */
   _dos_getfileattr( "DGFILEAT.C", &oldattrib );
   printf( "Attribute: 0x%.4x\n", oldattrib );
   if( ( oldattrib & _A_RDONLY ) != 0 )
      printf( "Read only file\n" );
   else
      printf( "Not a read only file.\n" );

   /* Reset file attribute to normal file */
   _dos_setfileattr( "DGFILEAT.C", _A_RDONLY );
   _dos_getfileattr( "DGFILEAT.C", &newattrib );
   printf( "Attribute: 0x%.4x\n", newattrib );

   /* Restore file attribute */
   _dos_setfileattr( "DGFILEAT.C", oldattrib );
   _dos_getfileattr( "DGFILEAT.C", &newattrib );
   printf( "Attribute: 0x%.4x\n", newattrib );
}

Output

Attribute: 0x0021
Read only file
Attribute: 0x0001
Attribute: 0x0021


Description: _dos_getftime
  _dos_getftime

#include <dos.h>

#include <errno.h>

unsigned _dos_getftime( int handle, unsigned *date, unsigned *time );

handle    Target file

date    Date-return buffer

time    Time-return buffer

Remarks

The _dos_getftime routine uses system call 0x57 to get the date and time that
the specified file was last written. The file must have been opened with a call to _dos_open or _dos_creat prior to calling _dos_getftime. The date and time are returned in the words pointed to by date and time. The values appear in the
MS-DOS date and time format: The time bits have these meanings:

0−4    Number of 2-second increments (0−29)

5−10    Minutes (0−59)

11−15    Hours (0−23)

The date bits have these meanings:

0−4    Day of month (1−31)

5−8    Month (1−12)

9−15    Year (relative to 1980)

Return Value

If successful, the function returns 0. Otherwise, it returns the MS-DOS error code and sets errno to EBADF, indicating that an invalid file handle was passed.

See Also

»_dos_setftime,« »_fstat,« »_stat«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DGFTIME.C: This program displays and modifies
 * the date and time fields of a file.
 */

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>

void main( void )
{
                               /* FEDC BA98 7654 3210           */
   unsigned new_date = 0x26cf; /* 0010 0110 1100 1111  12/15/99 */
   unsigned new_time = 0x48e0; /* 0100 1000 1110 0000  9:07 AM  */
   unsigned old_date, old_time;

   int fh;

  /* Open file with _dos_open function */
   if( _dos_open( "dgftime.obj", _O_RDONLY, &fh ) != 0 )
      exit( 1 );

   /* Get file date and time */
   _dos_getftime( fh, &old_date, &old_time );
   printf( "Old date field: 0x%.4x\n", old_date );
   printf( "Old time field: 0x%.4x\n", old_time );
   system( "dir dgftime.obj" );

   /* Modify file date and time */
   if( !_dos_setftime( fh, new_date, new_time ) )
   {
      _dos_getftime( fh, &new_date, &new_time );
      printf( "New date field: 0x%.4x\n", new_date );
      printf( "New time field: 0x%.4x\n", new_time );
      system( "dir dgftime.obj" );

      /* Restore date and time */
      _dos_setftime( fh, old_date, old_time );
   }
   _dos_close( fh );
}

Output

 Volume in drive C is DRIVE
 Volume Serial Number is 1966-6F27
 Directory of C:\CODE

DGFTIME  OBJ       865 03-24-93   2:03p
        1 file(s)        865 bytes
                    11730944 bytes free

 Volume in drive C is DRIVE
 Volume Serial Number is 1966-6F27
 Directory of C:\CODE

DGFTIME  OBJ       865 06-15-99   9:07a
        1 file(s)        865 bytes
                    11730944 bytes free
Old date field: 0x1a78
Old time field: 0x706c
New date field: 0x26cf
New time field: 0x48e0


Description: _dos_gettime
  _dos_gettime

#include <dos.h>

void _dos_gettime( struct _dostime_t *time );

time     Current system time

Remarks

The _dos_gettime routine uses system call 0x2C to obtain the current system time. The time is returned in a _dostime_t structure, defined in DOS.H. The dostime_t structure contains the following elements:

unsigned char hour    0−23

unsigned char minute    0−59

unsigned char second    0−59

unsigned char hsecond    1/100 second; 0−99

Return Value

None.

See Also

»_dos_getdate,« »_dos_setdate,« »_dos_settime,« »gmtime,« »localtime,« »_strtime«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DGTIME.C: This program gets and displays
 * current date and time values.
 */

#include <stdio.h>
#include <dos.h>

void main( void )
{
   struct _dosdate_t date;
   struct _dostime_t time;

   /* Get current date and time values */
   _dos_getdate( &date );
   _dos_gettime( &time );

   printf( "Today's date is %d-%d-%d\n", date.month,
           date.day, date.year );
   printf( "The time is %02d:%02d\n", time.hour, time.minute );
}

Output

Today's date is 3-24-1993
The time is 14:04


Description: _dos_getvect
  _dos_getvect

#include <dos.h>

void ( __cdecl __interrupt __far *_dos_getvect( unsigned intnum))( );

intnum    Target interrupt vector

Remarks

The _dos_getvect routine uses system call 0x35 to get the current value of the interrupt vector specified by intnum. This routine is typically used in conjunction with the _dos_setvect function. To replace an interrupt vector, first save the current vector of the interrupt using _dos_getvect. Then set the vector to your own interrupt routine with _dos_setvect. The saved vector can later be restored, if necessary, using _dos_setvect. The user-defined routine may also need the original vector in order to call that vector or chain to it with _chain_intr.

Return Value

The function returns a far pointer for the intnum interrupt to the current handler, if there is one.

See Also

»_chain_intr,« »_dos_keep,« »_dos_setvect«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _dos_keep
  _dos_keep

#include <dos.h>

void _dos_keep( unsigned retcode, unsigned memsize );

retcode    Exit status code

memsize    Allocated resident memory (in 16-byte paragraphs)

Remarks

The _dos_keep routine installs TSRs (terminate-and-stay-resident programs) in memory, using system call 0x31. The routine first exits the calling process, leaving it in memory. It then returns the low-order byte of retcode to the parent of the calling process. Before returning execution to the parent process, _dos_keep sets the allocated memory for the now-resident process to memsize 16-byte paragraphs. Any excess memory is returned to the system.

The _dos_keep function calls the same internal routines called by exit. It therefore takes the following actions:

•	Calls any functions that have been registered by atexit or _onexit calls.

•	Flushes all file buffers.

•	Restores interrupt vectors replaced by the C startup code. The primary one is interrupt 0 (divide by zero). If the emulator math library is used and there is no coprocessor, interrupts 0x34 through 0x3D are restored. If there is a coprocessor, interrupt 2 is restored.

Do not use the emulator math library in TSRs unless you are familiar with the startup code and the coprocessor. Use the alternate math package if the TSR must do floating-point math. The _dos_keep function should not be used in any program that shells out to an MS-DOS command line, since doing so causes subsequent memory problems. The Microsoft Programmer's WorkBench (PWB) environment is an example of such a program.

Return Value

None.

See Also

»_cexit,« »_chain_intr,« »_dos_getvect,« »_dos_setvect,« »_exit«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _dos_lock
  _dos_lock

#include <dos.h>

#include <errno.h>

unsigned _dos_lock( int handle, int mode, unsigned long origin, unsigned long length );

handle    Target file handle

mode    Lock or unlock region

origin    Start of region to be locked or unlocked

length    Length of region to be locked or unlocked

Remarks

The _dos_lock routine is used to synchronize files and records in a multitasking environment or network. The routine uses MS-DOS system call 0x5C to lock or unlock a region of the file specified by handle. The region is defined with the origin argument, which indicates where the region starts, and the length argument, which indicates the length of the region. If mode is 0, the specified region is to be locked; if mode is 1, the specified region is to be unlocked. The region to be locked can extend beyond the end of file. File sharing must be installed to use this routine. (See your system documentation for detailed information about file sharing.) To determine the status of a region, use _dos_lock to lock the region, then examine the return value.

Return Value

If successful, the _dos_lock routine returns 0. Otherwise, it returns the MS-DOS error code and sets errno as follows:

EBADF    This error code is set if handle is invalid.

EACCESS    This error code is set if all or part of the specified region is already locked or if the specified region to be unlocked is not identical to a region previously locked, or if another program tries to read from or write to a locked region.

EINVAL    This error code is set if file sharing is not installed or if mode is invalid.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _dos_open
  _dos_open

#include <dos.h>

#include <errno.h>

#include <fcntl.h>    Access mode constants

#include <share.h>    Sharing mode constants

unsigned _dos_open( const char *filename, unsigned mode, int *handle );

filename    Path to an existing file

mode    Permissions

handle    Pointer to integer

Remarks

The _dos_open routine uses system call 0x3D to open the existing file pointed to by filename. The handle for the opened file is copied into the integer pointed to by handle. The mode parameter specifies the file's access, sharing, and inheritance modes by combining (with the OR operator) manifest constants from the three groups shown below. At most, one access mode and one sharing mode can be specified at a time.

Constant	Mode	Meaning
_O_RDONLY	Access	Read-only
_O_WRONLY	Access	Write-only
_O_RDWR	Access	Both read and write
_SH_COMPAT	Sharing	Compatibility
_SH_DENYRW	Sharing	Deny reading and writing
_SH_DENYWR	Sharing	Deny writing
_SH_DENYRD	Sharing	Deny reading
_SH_DENYNO	Sharing	Deny neither
_O_NOINHERIT	Inheritance by the child process	File is not inherited
Do not use the MS-DOS interface I/O routines in conjunction with the console, low-level, or stream I/O routines.

Return Value

If successful, the function returns 0. Otherwise, it returns the MS-DOS error code and sets errno to one of the following manifest constants:

EACCES    Access denied (possible reasons include specifying a directory or volume ID for filename, or opening a read-only file for write access)

EINVAL    Sharing mode specified when file sharing not installed, or access-mode value is invalid

EMFILE    Too many open file handles

ENOENT    Path or file not found

See Also

»_dos_close,« »_dos_read,« »_dos_write«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DOPEN.C: This program uses MS-DOS I/O functions
 * to open and close a file. If the file does not
 * exist, display appropriate message.
 */

#include <fcntl.h>
#include <stdio.h>
#include <dos.h>

void main( void )
{
   int fh;

   /* Open file with _dos_open function */
   if( _dos_open( "data1", _O_RDONLY, &fh ) != 0 )
      perror( "Open failed on input file" );
   else
   {
      printf( "Open succeeded on input file\n" );

      /* Close file with _dos_close function */
      if( _dos_close( fh ) != 0 )
         perror( "Close failed" );
      else
         printf( "File successfully closed\n" );
   }
}

Output

Open succeeded on input file
File successfully closed


Description: _dos_read
  _dos_read

#include <dos.h>

unsigned _dos_read( int handle, void __far *buffer, unsigned count, unsigned *numread );

handle    File to read

buffer    Buffer to write to

count    Number of bytes to read

numread    Number of bytes actually read

Remarks

The _dos_read routine uses system call 0x3F to read count bytes of data from the file specified by handle. The routine then copies the data to the buffer pointed to by buffer. The integer pointed to by numread will show the number of bytes actually read, which may be less than the number requested in count. If the number of bytes actually read is 0, it means the routine tried to read at end-of-file. Do not use the MS-DOS interface I/O routines in conjunction with the console, low-level, or stream I/O routines.

Return Value

If successful, the function returns 0. Otherwise, it returns the MS-DOS error code and sets errno to EACCES, which means that access is denied (handle is not open for read access), or EBADF, which means that file handle is invalid.

See Also

»_dos_close,« »_dos_open,« »_dos_write,« »_read«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DREAD.C: This program uses the MS-DOS I/O
 * operations to read the contents of a file.
 */

#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>

void main( void )
{
   int fh; char buffer[50];
   unsigned number_read;

   /* Open file with _dos_open function */
   if( _dos_open( "dread.c", _O_RDONLY, &fh ) != 0 )
      perror( "Open failed on input file\n" );
   else
      printf( "Open succeeded on input file\n" );

   /* Read data with _dos_read function */
   _dos_read( fh, buffer, 50, &number_read );
   printf( "First 40 characters are: %.40s\n\n", buffer );

   /* Close file with _dos_close function */
   _dos_close( fh );
}

Output

Open succeeded on input file
First 40 characters are:
/* DREAD.C: This program uses the MS-DOS


Description: _dos_seek
  _dos_seek

#include <dos.h>

#include <errno.h>

unsigned long _dos_seek( int handle, unsigned long offset, int origin );

handle    Target file handle

offset    Offset of new position relative to origin

origin    Position in target file to begin seeking

Remarks

The _dos_seek routine uses MS-DOS system call 0x42 to move the file pointer to the specified position in the open file specified by handle. The file pointer is maintained by the system; it points to the next byte to be read from a file or to the next position in the file to receive a byte. The offset specifies the number of bytes to move the file pointer. The origin specifies the origin of the move; to move the pointer from the beginning of the file, set origin to 0; to move the pointer from the current position, set origin to 1; to move the pointer from the end of the file, set origin to 2.

A program should never move the file pointer to a position before the beginning of the file. Although this does not generate an error during the move, it generates an error on a subsequent read or write operation. However, a program can move the file pointer past the end of file. A subsequent write operation writes data to the given position in the file, filling the gap between the previous end of file and the given position with undefined data. This is a common way to reserve file space without writing to the file.

Return Value

If successful, the routine returns the offset, in bytes, from the beginning of the file. Otherwise, it returns a value of  − 1L for offset, and sets errno to EBADF if handle is invalid, or to EINVAL if the value proivded for origin is invalid.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _dos_setblock
  _dos_setblock

#include <dos.h>

unsigned _dos_setblock( unsigned size, unsigned seg, unsigned *maxsize );

size    New segment size

seg    Target segment

maxsize    Maximum-size buffer

Remarks

The _dos_setblock routine uses system call 0x4A to change the size of seg, previously allocated by _dos_allocmem, to size paragraphs. If the request cannot be satisfied, the maximum possible segment size is copied to the buffer pointed to by maxsize.

Return Value

The function returns 0 if successful. If the call fails, it returns the MS-DOS error code and sets errno to ENOMEM, indicating a bad segment value was passed. A bad segment value is one that does not correspond to a segment returned from a previous _dos_allocmem call, or one that contains invalid arena headers.

See Also

»_dos_allocmem,« »_dos_freemem,« »realloc functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for _dos_allocmem.


Description: _dos_setdate
  _dos_setdate

#include <dos.h>

unsigned _dos_setdate( struct _dosdate_t *date );

date    New system date

Remarks

The _dos_setdate routine uses system call 0x2B to set the current system date. The date is stored in the _dosdate_t structure pointed to by date, defined in DOS.H. The _dosdate_t structure contains the following elements:

unsigned char day    1−31

unsigned char month    1−12

unsigned int year    1980− 2099

unsigned char dayofweek    0−6 (0 = Sunday)

Return Value

If successful, the function returns 0. Otherwise, it returns a nonzero value and sets errno to EINVAL, indicating an invalid date was specified.

See Also

»_dos_getdate,« »_dos_gettime,« »_dos_settime,« »gmtime,« »localtime,« »mktime,« »_strdate,« »_strtime,« »time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for _dos_settime.


Description: _dos_setdrive
  _dos_setdrive

#include <dos.h>

void _dos_setdrive( unsigned drive, unsigned *numdrives );

drive    New default drive

numdrives    Total drives available

Remarks

The _dos_setdrive routine uses system call 0x0E to set the current default drive to the drive parameter: 1 = drive A, 2 = drive B, and so on. The numdrives parameter indicates the total number of logical drives in the system, including network drives. If this value is 4, for example, it does not mean the drives are designated A, B, C, and D; it means only that four drives are in the system.

Return Value

There is no return value. If an invalid drive number is passed, the function fails without indication. Use the _dos_getdrive routine to verify whether the desired drive has been set.

See Also

»_dos_getdiskfree,« »_dos_getdrive«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for _dos_getdrive.


Description: _dos_setfileattr
  _dos_setfileattr

#include <dos.h>

unsigned _dos_setfileattr( const char *path, unsigned attrib );

path    Full path of target file or directory

attrib    New attributes

Remarks

The _dos_setfileattr routine uses system call 0x43 to set the attributes of the file or directory pointed to by path. The actual attributes are contained in the low-order byte of the attrib word. Attributes are represented by manifest constants, as described below:

_A_ARCH    Archive. Set whenever the file is changed, or cleared by the MS-DOS BACKUP command.

_A_HIDDEN    Hidden file. Cannot be found by a directory search.

_A_NORMAL    Normal. File can be read or written to without restriction.

_A_RDONLY    Read-only. File cannot be opened for writing, and a file with the same name cannot be created.

_A_SUBDIR    Subdirectory.

_A_SYSTEM     System file. Cannot be found by a directory search.

_A_VOLID     Volume ID. Only one file can have this attribute, and it must be in the root directory.

Return Value

The function returns 0 if successful. Otherwise, it returns the MS-DOS error code and sets errno to one of two manifest constants. The EACCES constant means that access is denied (you cannot change the volume ID or the subdirectory); the ENOENT constant means that no file or directory matching the target was found.

See Also

»_dos_getfileattr«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for _dos_getfileattr.


Description: _dos_setftime
  _dos_setftime

#include <dos.h>

unsigned _dos_setftime( int handle, unsigned date, unsigned time );

handle    Target file

date    Date of last write

time    Time of last write

Remarks

The _dos_setftime routine uses system call 0x57 to set the date and time at which the file identified by handle was last written to. These values appear in the MS-DOS date and time format. The time bits have these meanings:

0−4    Number of two-second increments (0−29)

5−10    Minutes (0−59)

11−15    Hours (0−23)

The date bits have these meanings:

0−4    Day (1−31)

5−8    Month (1−12)

9−15    Year since 1980 (for example, 1994 is stored as 14)

Return Value

If successful, the function returns 0. Otherwise, it returns the MS-DOS error code and sets errno to EBADF, indicating that an invalid file handle was passed.

See Also

»_dos_getftime,« »_fstat,« »_stat«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for _dos_getftime.


Description: _dos_settime
  _dos_settime

#include <dos.h>

unsigned _dos_settime( struct _dostime_t *time );

time    New system time

Remarks

The _dos_settime routine uses system call 0x2D to set the current system time to the value stored in the _dostime_t structure that time points to, as defined in DOS.H. The _dostime_t structure contains the following elements:

unsigned char hour    0−23

unsigned char minute    0−59

unsigned char second    0−59

unsigned char hsecond    Hundredths of a second; 0−99

Return Value

If successful, the function returns 0. Otherwise, it returns a nonzero value and sets errno to EINVAL, indicating an invalid time was specified.

See Also

»_dos_getdate,« »_dos_gettime,« »_dos_setdate,« »gmtime,« »localtime,« »mktime,« »_strdate,« »_strtime«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DSTIME.C: This program changes the time and date
 * values and displays the new date and time values.
 */

#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>

void main( void )
{
   struct _dosdate_t olddate, newdate = { { 4 }, { 7 },
                                          { 1999 } };
   struct _dostime_t oldtime, newtime = { { 3 }, { 45 },
                                          { 30 }, { 0 } };
   char   datebuf[40], timebuf[40];

   /* Get current date and time values */
   _dos_getdate( &olddate );
   _dos_gettime( &oldtime );
   printf( "%s    %s\n" , _strdate( datebuf ),
                          _strtime( timebuf ) );

   /* Modify date and time structures */
   _dos_setdate( &newdate ); _dos_settime( &newtime );
   printf( "%s    %s\n" , _strdate( datebuf ),
                          _strtime( timebuf ) );

   /* Restore old date and time */
   _dos_setdate( &olddate );
   _dos_settime( &oldtime );
}

Output

03/24/93    16:23:47
07/04/99    03:45:29


Description: _dos_setvect
  _dos_setvect

#include <dos.h>

void _dos_setvect( unsigned intnum, void( __cdecl __interrupt __far *handler)( ));

intnum    Target-interrupt vector

handler    Interrupt handler for which to assign intnum

Remarks

The _dos_setvect routine uses system call 0x25 to set the current value of the interrupt vector intnum to the function pointed to by handler. Subsequently, whenever the intnum interrupt is generated, the handler routine will be called. If handler is a C function, it must have been previously declared with the interrupt attribute. Otherwise, you must make sure that the function satisfies the requirements for an interrupt-handling routine. For example, if handler is an assembler function, it must be a far routine that returns with an IRET instead of a RET. The interrupt attribute indicates that the function is an interrupt handler. The compiler generates appropriate entry and exit sequences for the interrupt-handling function, including saving and restoring all registers and executing an IRET instruction to return.

The _dos_setvect routine is generally used with the _dos_getvect function. To replace an interrupt vector, first save the current vector of the interrupt using _dos_getvect. Then set the vector to your own interrupt routine with _dos_setvect. The saved vector can later be restored, if necessary, using _dos_setvect. The user-defined routine may also need the original vector in order to call it or to chain to it with _chain_intr.

Registers and Interrupt Functions

When you call an interrupt function, the DS register is initialized to the C data segment. This allows you to access global variables from within an interrupt function. In addition, all registers except SS are saved on the stack. You can access these registers within the function if you declare a function parameter list containing a formal parameter for each saved register. The following example illustrates such a declaration:

void __interrupt __far int_handler( unsigned _es, unsigned _ds,
                                     unsigned _di, unsigned _si,
                                     unsigned _bp, unsigned _sp,
                                     unsigned _bx, unsigned _dx,
                                     unsigned _cx, unsigned _ax,
                                     unsigned _ip, unsigned _cs,
                                     unsigned _flags )
{
.
.
.
}

The formal parameters must appear in the opposite order from which they are pushed onto the stack. You can omit parameters from the end of the list in a declaration, but not from the beginning. For example, if your handler needs to use only DI and SI, you must still provide ES and DS, but not necessarily BX or DX. You can pass additional parameters if your interrupt handler will be called directly from C rather than by an INT instruction. To do this, you must declare all register parameters and then declare your parameter at the end of the list.

The compiler always saves and restores registers in the same, fixed order. Thus, no matter what names you use in the formal parameter list, the first parameter in the list refers to ES, the second refers to DS, and so on. If your interrupt routines will use inline assembler, you should distinguish the parameter names so that they will not be the same as the real register names.

If you change any of the register parameters of an interrupt function while the function is executing, the corresponding register contains the changed value when the function returns. For example:

void __interrupt __far int_handler( unsigned _es, unsigned _ds,
                                     unsigned _di, unsigned _si )
{
   _di = -1;
}

This code causes the DI register to contain −1 when the handler function returns. It is not a good idea to modify the values of the parameters representing the IP and CS registers in interrupt functions. If you must modify a particular flag (such as the carry flag for certain MS-DOS and BIOS interrupt routines), use the OR operator ( | ) so that other bits in the flag register are not changed.

When an interrupt function is called by an INT instruction, the interrupt-enable flag is cleared. If your interrupt function needs to do significant processing, you should use the _enable function to set the interrupt flag so that interrupts can be handled.

Precautions for Interrupt Functions

Because MS-DOS is not reentrant (an MS-DOS interrupt cannot be called from inside an MS-DOS interrupt), it is usually not safe to call from inside an interrupt function any standard library function that calls DOS INT 21H. Similar precautions apply to many BIOS functions. Functions that rely on INT 21H calls include I/O functions and the _dos family of functions. Functions that rely on the machine's BIOS include graphics functions and the _bios family of functions. It is usually safe to use functions that do not rely on INT 21H or BIOS, such as string-handling functions. Before using a standard library function in an interrupt function, be sure that you are familiar with the action of the library function.

Return Value

None.

See Also

»_chain_intr,« »_dos_getvect,« »_dos_keep«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _dos_write
  _dos_write

#include <dos.h>

unsigned _dos_write( int handle, void __far *buffer, unsigned count, unsigned *numwrt );

handle    File to write to

buffer    Buffer to write from

count    Number of bytes to write

numwrt    Number of bytes actually written

Remarks

The _dos_write routine uses system call 0x40 to write data to the file that handle references; count bytes of data from the buffer to which buffer points are written to the file. The integer pointed to by numwrt will be the number of bytes actually written, which may be less than the number requested. Do not use the MS-DOS interface routines with the console, low-level, or stream I/O routines.

Return Value

If successful, the function returns 0. Otherwise, it returns the MS-DOS error code and sets errno to one of two manifest constants, EACCES, which means access denied (handle references a file not open for write access), or EBADF, which means invalid file handle.

See Also

»_dos_close,« »_dos_open,« »_dos_read,« »_write«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * DWRITE.C: This program uses MS-DOS I/O
 * functions to write to a file.
 */

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>

void main( void )
{
   char out_buffer[] = "Hello";
   int  fh;
   unsigned n_written;

   /* Open file with _dos_creat function */
   if( _dos_creat( "data", _A_NORMAL, &fh ) == 0 )
   {
      /* Write data with _dos_write function */
      _dos_write( fh, out_buffer, 5, &n_written );
      printf( "Number of characters written: %d\n", n_written );

      _dos_close( fh );
      printf( "Contents of file are:\n" );
      _flushall();
      system( "type data" );
   }
}

Output


Description: _dosexterr
  _dosexterr

#include <dos.h>

int _dosexterr( struct _DOSERROR *errorinfo );

errorinfo    Extended MS-DOS error information

Remarks

The _dosexterr function obtains the extended error information returned by MS-DOS system call 0x59 and stores the values in the structure pointed to by errorinfo. This function is useful when making system calls with MS-DOS versions 3.0 and later, which offer extended error handling. The structure type _DOSERROR is defined in DOS.H. The _DOSERROR structure contains the following elements:

int exterror    AX register contents

char errclass    BH register contents

char action    BL register contents

char locus    CH register contents

Giving a NULL pointer parameter causes _dosexterr to return the value in AX without filling in the structure fields. See MS-DOS Encyclopedia (Duncan, ed.; Redmond, WA: Microsoft Press, 1988) or Programmer's PC Sourcebook 2nd ed. (Hogan; Redmond, WA: Microsoft Press, 1991) for more information on the register contents.

Return Value

The _dosexterr function returns the value in the AX register (identical to the value in the exterror structure field). The _dosexterr function should be used only with MS-DOS version 3.0 or later.

See Also

»perror«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

 //+(all)
/* Note: MS-DOS ONLY
 *
 * DOSEXERR.C: This program tries to open the file test.dat.
 * If the attempted open operation fails, the program uses
 * _dosexterr to display extended error information.
 */

#include <dos.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>

void main( void )
{
   struct _DOSERROR doserror;
   int fd;

   /* Attempt to open a non-existent file */
   if( (fd = _open( "TEST.DAT", _O_RDONLY )) == -1 )
   {
      _dosexterr( &doserror );
      printf( "Error: %d  Errclass: %d  Action: %d  Locus: %d\n",
               doserror.exterror, doserror.errclass,
               doserror.action,   doserror.locus );
   }
   else
   {
      printf( "Open succeeded so no extended information printed\n" );
      _close( fd );
   }
}

Output

Open succeeded so no extended information printed


Description: _dup, _dup2
  _dup, _dup2

#include <io.h>

int_dup( int handle );

int _dup2( int handle1, int handle2 );

handle, handle1    Handle referring to open file

handle2    Any handle value

Remarks

The _dup and _dup2 functions cause a second file handle to be associated with a currently open file. Operations on the file can be carried out using either file handle. The type of access allowed for the file is unaffected by the creation of a new handle. The _dup function returns the next available file handle for the given file. The _dup2 function forces handle2 to refer to the same file as handle1. If handle2 is associated with an open file at the time of the call, that file is closed.

Both _dup and _dup2 accept file handles as parameters. If you want to pass a stream (FILE *) to either of these functions, use the _fileno function. This function associates a stream with a file handle. The following example shows how to associate stderr (defined as FILE * in STDIO.H) with a handle:

cstderr = _dup( _fileno( stderr ));

Note that in a QuickWin application, you cannot use either _dup or _dup2 with _fileno on the stdin, stdout, or stderr streams. You can, however, use the combination of the _dup functions and the _fileno function on other streams.

Return Value

The _dup function returns a new file handle. The _dup2 function returns 0 to indicate success. Both functions return  − 1 if an error occurs and set errno to either EBADF, which means invalid file handle, or EMFILE, which means no more file handles are available (too many open files).

See Also

»_close,« »_creat,« »_open«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _dup and _dup2 for compatibility with ANSI naming conventions of non-ANSI functions. Use dup and dup2 and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* DUP.C: This program uses the variable old to save
 * the original stdout. It then opens a new file named
 * new and forces stdout to refer to it. Finally, it
 * restores stdout to its original state.
 */

#include <io.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int old;
   FILE *new;

   old = _dup( 1 );   /* "old" now refers to "stdout" */
                      /* Note:  file handle 1 == "stdout" */
   if( old == -1 )
   {
      perror( "_dup( 1 ) failure" );
      exit( 1 );
   }
   write( old, "This goes to stdout first\r\n", 27 );
   if( ( new = fopen( "data", "w" ) ) == NULL )
   {
      puts( "Can't open file 'data'\n" );
      exit( 1 );
   }

   /* stdout now refers to file "data" */
   if( -1 == _dup2( _fileno( new ), 1 ) )
   {
      perror( "Can't _dup2 stdout" );
      exit( 1 );
   }
   puts( "This goes to file 'data'\r\n" );

   /* Flush stdout stream buffer so it goes to correct file */
   fflush( stdout );
   fclose( new );

   /* Restore original stdout */
   _dup2( old, 1 );
   puts( "This goes to stdout\n" );
   puts( "The file 'data' contains:" );
   system( "type data" );
}

Output

This goes to stdout first
This goes to file 'data'

This goes to stdout

The file 'data' contains:

This goes to file 'data'


Description: _ecvt
  _ecvt

#include <stdlib.h>

char *_ecvt( double value, int count, int *dec, int *sign );

value    Number to be converted

count    Number of digits stored

dec    Stored decimal-point position

sign    Sign of converted number

Remarks

The _ecvt function converts a floating-point number to a character string. The value parameter is the floating-point number to be converted. The _ecvt function stores up to count digits of value as a string and appends a null character ('\0'). If the number of digits in value exceeds count, the low-order digit is rounded. If there are fewer than count digits, the string is padded with zeros.

Only digits are stored in the string. The position of the decimal point and the sign of value can be obtained from dec and sign after the call. The dec parameter points to an integer value giving the position of the decimal point with respect to the beginning of the string. A 0 or negative integer value indicates that the decimal point lies to the left of the first digit. The sign parameter points to an integer indicating the sign of the converted number. If the integer value is 0, the number is positive. Otherwise, the number is negative.

The _ecvt and _fcvt functions use a single statically allocated buffer for the conversion. Each call to one of these routines destroys the result of the previous call.

Return Value

The _ecvt function returns a pointer to the string of digits. There is no error return.

See Also

»atof,« »atoi,« »atol,« »_fcvt,« »_gcvt«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _ecvt for compatibility with ANSI naming conventions of non-ANSI functions. Use ecvt and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* ECVT.C: This program uses _ecvt to convert a
 * floating-point number to a character string.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int     decimal,   sign;
   char    *buffer;
   int     precision = 10;
   double  source = 3.1415926535;

   buffer = _ecvt( source, precision, &decimal, &sign );
   printf( "source: %2.10f   buffer: '%s'  decimal: %d  sign: %d\n",
           source, buffer, decimal, sign );
}

Output

source: 3.1415926535   buffer: '3141592654'  decimal: 1   sign: 0


Description: _ellipse Functions
  _ellipse Functions

#include <graph.h>

short __far _ellipse( short control, short x1, short y1, short x2, short y2 );

short __far _ellipse_w( short control, double wx1, double wy1, double wx2, double wy2 );

short __far _ellipse_wxy( short control, struct _wxycoord __far *pwxy1 , struct _wxycoord __far *pwxy2 );

control    Fill flag

x1, y1    Upper-left corner of bounding rectangle

x2, y2    Lower-right corner of bounding rectangle

wx1, wy1    Upper-left corner of bounding rectangle

wx2, wy2    Lower-right corner of bounding rectangle

pwxy1    Upper-left corner of bounding rectangle

pwxy2    Lower-right corner of bounding rectangle

Remarks

The _ellipse functions draw ellipses or circles. The borders are drawn in the current color. In the _ellipse function, the center of the ellipse is the center of the bounding rectangle defined by the view-coordinate points (x1, y1) and (x2, y2). In the _ellipse_w function, the center of the ellipse is the center of the bounding rectangle defined by the window-coordinate points (wx1, wy1) and (wx2, wy2). In the _ellipse_wxy function, the center of the ellipse is the center of the bounding rectangle defined by the window-coordinate points (pwxy1) and (pwxy2). If the bounding-rectangle arguments define a point or a vertical or horizontal line, no figure is drawn.

The control parameter can be one of two manifest constants, _GFILLINTERIOR, which uses _floodfill to fill the ellipse using the current fill mask, or _GBORDER, which does not fill the ellipse. The control option given by _GFILLINTERIOR is equivalent to a subsequent call to the _floodfill function, using the center of the ellipse as the starting point and the current color (set by _setcolor) as the boundary color.

Return Value

The _ellipse functions return a nonzero value if the ellipse is drawn successfully; otherwise, they return 0.

See Also

»_arc functions,« »_floodfill,« »_grstatus,« »_lineto functions,« »_pie functions,« »_polygon functions,« »_rectangle functions,« »_setcolor,« »_setfillmask«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * ELLIPSE.C: This program draws a simple ellipse.
 *
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

void main( void )
{
   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   _ellipse( _GFILLINTERIOR, 80, 50, 240, 150 );

   /* Strike any key to clear screen. */
   _getch();
   _setvideomode( _DEFAULTMODE );
}


Description: _enable
  _enable

#include <dos.h>

void _enable( void );

Remarks

The _enable routine enables interrupts by executing an 8086 STI machine instruction.

Return Value

None.

See Also

»_disable«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description_endthread
  _endthread

#include <process.h>    Multithread version of PROCESS.H

void _endthread( void );

Remarks

The _endthread function terminates a thread created by _beginthread. It is recommended that you always call _endthread to terminate threads created with _beginthread. Doing so reduces the risk of memory leaks which can result from improper cleanup of resources allocated at the time the thread is created.

Return Value

None.

See Also

»_beginthread«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _eof
  _eof

#include <io.h>

int _eof( int handle );

handle    Handle referring to open file

Remarks

The _eof function determines whether the end of the file associated with handle has been reached.

Return Value

The _eof function returns the value 1 if the current position is end-of-file, or 0 if it is not. A return value of −1 indicates an error; in this case, errno is set to EBADF, indicating an invalid file handle.

See Also

»clearerr,« »feof,« »ferror,« »perror«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* EOF.C: This program reads data from a file
 * ten bytes at a time until the end of the
 * file is reached or an error is encountered.
 */
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
void main( void )
{
   int  fh, count, total = 0;
   char buf[10];
   if( (fh = _open( "_eof.c", _O_RDONLY )) == - 1 )
   {
        perror( "Open failed");
        exit( 1 );
   }
   /* Cycle until end of file reached: */
   while( !_eof( fh ) )
   {
      /* Attempt to read in 10 bytes: */
      if( (count = _read( fh, buf, 10 )) == -1 )
      {
         perror( "Read error" );
         break;
      }
      /* Total up actual bytes read */
      total += count;
   }
   printf( "Number of bytes read = %d\n", total );
   _close( fh );
}

Output

Number of bytes read = 777


Description: _exec Functions
  _exec Functions

#include <process.h>

int _execl( const char *cmdname, const char *arg0, ... const char *argn, NULL );

int _execle( const char *cmdname, const char *arg0, ... const char *argn, NULL, const char * const *envp );

int _execlp( const char *cmdname, const char *arg0, ... const char *argn, NULL );

int _execlpe( const char *cmdname, const char *arg0, ... const char *argn, NULL, const char * const *envp );

int _execv( const char *cmdname, const char *const *argv );

int _execve( const char *cmdname, const char *const *argv, const char * const *envp );

int _execvp( const char *cmdname, const char *const *argv );

int _execvpe( const char *cmdname, const char *const *argv, const char * const *envp );

cmdname    Path of file to be executed

arg0, ... argn    List of pointers to parameters

argv    Array of pointers to parameters

envp    Array of pointers to environment settings

Remarks

The _exec functions load and execute new processes. When the call is successful in MS-DOS or Windows NT, the new process is placed in the memory previously occupied by the calling process. Sufficient memory must be available for loading and executing the new process. All of the _exec functions use the same operating system function. The letter(s) at the end of the function name determine the specific variation, as shown in the following list:

e    An array of pointers to environment parameters is explicitly passed to the child process.

l    Command-line arguments are passed individually to the _exec function.

p    Uses the PATH environment variable to find the file to be executed.

v    Command-line arguments are passed to the _exec function as an array of pointers.

The cmdname parameter specifies the file to be executed as the new process. It can specify a full path (from the root), a partial path (from the current working directory), or just a filename. If cmdname does not have a filename extension or does not end with a period (.), the _exec function searches for the named file; if the search is unsuccessful, it tries the same base name, first with the extension .COM, then the .EXE extension, then the .BAT extension, and finally the .CMD extension (in Windows NT only). If cmdname has an extension, only that extension is used in the search. If cmdname ends with a period, the _exec calls search for cmdname with no extension. The _execlp, _execlpe, _execvp, and _execvpe routines search for cmdname (using the same procedures) in the directories specified by the PATH environment variable. If cmdname contains a drive specifier or any slashes (that is, if it is a relative path), the _exec call searches only for the specified file; the path is not searched. Note that the MS-DOS APPEND command cannot be used with the _exec functions.

Parameters are passed to the new process by giving one or more pointers to character strings as parameters in the _exec call. These character strings form the parameter list for the new process. The combined length of the strings forming the parameter list for the new process must not exceed 128 bytes (in MS-DOS) or 1024 bytes (in Windows NT). The terminating null character ('\0') for each string is not included in the count, but space characters (inserted automatically to separate the parameters) are counted.

The argument pointers can be passed as separate parameters (_execl, _execle, _execlp, and _execlpe) or as an array of pointers (_execv, _execve, _execvp, and _execvpe). At least one parameter, arg0, must be passed to the new process; this parameter is argv[0] of the new process. Usually, this parameter is a copy of the cmdname parameter. (A different value will not produce an error.) With versions of MS-DOS earlier than 3.0, the passed value of arg0 is not available for use in the child process. However, with MS-DOS versions 3.0 and later, cmdname is available as arg0.

The _execl, _execle, _execlp, and _execlpe calls are typically used when the number of parameters is known in advance. The parameter arg0 is usually a pointer to cmdname. The parameters arg1 through argn point to the character strings forming the new parameter list. A null pointer must follow argn to mark the end of the parameter list.

The _execv, _execve, _execvp, and _execvpe calls are useful when the number of parameters to the new process is variable. Pointers to the parameters are passed as an array, argv. The parameter argv[0] is usually a pointer to cmdname. The parameters argv[1] through argv[n] point to the character strings forming the new parameter list. The parameter argv[n+1] must be a NULL pointer to mark the end of the parameter list.

Files that are open when an _exec call is made remain open in the new process. In the _execl, _execlp, _execv, and _execvp calls, the new process inherits the environment of the calling process. The _execle, _execlpe, _execve, and _execvpe calls allow the user to alter the environment for the new process by passing a list of environment settings through the envp parameter. The parameter envp is an array of character pointers, each element of which (except for the final element) points to a null-terminated string defining an environment variable. Such a string usually has the form NAME=value where NAME is the name of an environment variable and value is the string value to which that variable is set. (Note that value is not enclosed in double quotation marks.) The final element of the envp array should be NULL. When envp itself is NULL, the new process inherits the environment settings of the calling process.

A program executed with one of the _exec family of functions is always loaded into memory as if the "maximum allocation" field in the program's .EXE file header is set to the default value of 0xFFFFH. You can use the EXEHDR utility to change the maximum allocation field of a program; however, such a program invoked with one of the _exec functions may behave differently from a program invoked directly from the operating-system command line or with one of the _spawn functions. Note that in MS-DOS, COMMAND.COM checks the first two bytes of a file to determine whether it is an .EXE file or a .COM file — you can execute a file named by any extension, as long as its content is truly executable.

The _exec calls do not preserve the translation modes of open files. If the new process must use files inherited from the calling process, the »_setmode« routine should be used to set the translation mode of these files to the desired mode. You must explicitly flush (using fflush or _flushall) or close any stream prior to the _exec function call. Signal settings are not preserved in new processes that are created by calls to _exec routines. The signal settings are reset to the default in the new process.

Return Value

The _exec functions do not normally return to the calling process. If an _exec function returns, an error has occurred and the return value is −1. The errno variable is set to one of the following values:

E2BIG    The parameter list exceeds 128 bytes (in MS-DOS) or 1024 bytes (in Windows NT), or the space required for the environment information exceeds 32K.

EACCES    The specified file has a locking or sharing violation (MS-DOS version 3.0 or later).

EMFILE    Too many files open (the specified file must be opened to determine whether it is executable).

ENOENT    File or path not found.

ENOEXEC    The specified file is not executable or has an invalid executable-file format.

ENOMEM    Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process process was not allocated properly.

See Also

»abort,« »atexit,« »exit,« »_exit,« »_onexit,« »_spawn functions,« »system«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _exec for compatibility with ANSI naming conventions of non-ANSI functions. Use exec and link with OLDNAMES.LIB for UNIX compatibility.

Because of differences in MS-DOS versions 2.0 and 2.1, new processes generated by the _exec family of functions (or by the equivalent _spawn functions with the _P_OVERLAY parameter) may cause fatal system errors when they exit. If you are running MS-DOS 2.0 or 2.1, you must upgrade to MS-DOS version 3.0 or later to use these functions.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to child by the",
   "SPAWN=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}


Description: exit, _exit
  exit, _exit

#include <process.h>

#include <stdlib.h>    Use either PROCESS.H or STDLIB.H.

void exit( int status );

void _exit( int status );

status    Exit status

Remarks

The exit and _exit functions terminate the calling process. The exit function first calls, in LIFO (last-in-first-out) order, the functions registered by atexit and _onexit, then flushes all file buffers before terminating the process. The _exit function terminates the process without processing atexit or _onexit functions or flushing stream buffers. The status value is typically set to 0 to indicate a normal exit and set to some other value to indicate an error.

Although the exit and _exit calls do not return a value, the low-order byte of status is made available to the waiting parent process, if one exists, after the calling process exits. The status value is available to the operating-system batch command ERRORLEVEL, and is represented by one of two constants: EXIT_SUCCESS, which represents a value of 0, or EXIT_FAILURE, which represents a value of 1. The behavior of the exit, _exit, _cexit, and _c_exit functions is as follows:

exit    Performs complete C library termination procedures, terminates the process, and exits with the supplied status code.

_exit    Performs "quick" C library termination procedures, terminates the process, and exits with the supplied status code.

_cexit    Performs complete C library termination procedures and returns to caller, but does not terminate the process.

_c_exit    Performs "quick" C library termination procedures and returns to caller, but does not terminate the process.

Return Value

None.

See Also

»abort,« »atexit,« »_cexit,« »_exec functions,« »_onexit,« »_spawn functions,« »system«

Compatibility

exit:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_exit:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* EXITER.C: This program prompts the user for a yes
 * or no and returns an exit code of 1 if the
 * user answers Y or y; otherwise it returns 0. The
 * error code could be tested in a batch file.
 */

#include <conio.h>
#include <stdlib.h>

void main( void )
{
   int ch;

   _cputs( "Yes or no? " );
   ch = _getch();
   _cputs( "\r\n" );
   if( toupper( ch ) == 'Y' )
      exit( 1 );
   else
      exit( 0 );
}


Description: exp, _expl
  exp, expl

#include <math.h>

double exp( double x );

long double expl( long double x );

x    Floating-point value

Remarks

The exp and expl functions return the exponential function of their floating-point parameters (x). The expl function is the 80-bit counterpart; it uses an 80-bit, 10-byte coprocessor form of parameters and return values. See the »long double functions« for more details on this data type.

Return Value

These functions return the exponential value of x if successful. On overflow, exp and expl return _LHUGE_VAL. On underflow, they return 0. The errno variable is set to ERANGE on overflow but is not set on underflow.

See Also

»log functions«

Compatibility

exp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

expl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

/* EXP.C */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 2.302585093, y;

   y = exp( x );
   printf( "exp( %f ) = %f\n", x, y );
}

Output

exp( 2.302585 ) = 10.000000


Description: _expand Functions
  _expand Functions

#include <malloc.h>

void *_expand( void *memblock, size_t size );

void __based( void ) *_bexpand( __segment seg, void __based( void ) *memblock, size_t size );

void __far *_fexpand( void __far *memblock, size_t size );

void __near *_nexpand( void __near *memblock, size_t size );

memblock    Pointer to previously allocated memory block

size    New size in bytes

seg    Value of base segment

Remarks

The _expand family of functions changes the size of a previously allocated memory block by attempting to expand or contract the block without moving its location in the heap. The memblock parameter points to the beginning of the block. The size parameter gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes. The memblock parameter can also point to a block that has been freed, as long as there has been no intervening call to calloc, _expand, malloc, or realloc. If memblock points to a freed block, the block remains free after a call to one of the _expand functions. The seg parameter is the segment address of the __based heap.

In large data models (compact-, large-, and huge-model programs), _expand maps to _fexpand. In small data models (tiny-, small-, and medium-model programs), _expand maps to _nexpand. The various _expand functions change the size of the storage block in the data segments shown in the list below:

_expand    Depends on data model of program

_bexpand    Based heap specified by seg, or in all based heaps if seg is zero

_fexpand    Far heap (outside default data segment)

_nexpand    Near heap (inside default data segment)

Return Value

The _expand family of functions returns a void pointer to the reallocated memory block. Unlike realloc, _expand cannot move a block to change its size. This means the memblock parameter to _expand is the same as the return value if there is sufficient memory available to expand the block without moving it.

With the exception of the _bexpand function, these functions return NULL if there is insufficient memory available to expand the block to the given size without moving it. The _bexpand function returns _NULLOFF if insufficient memory is available. The item pointed to by memblock will have been expanded as much as possible in its current location.

The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. The new size of the item can be checked with one of the _msize functions. To get a pointer to a type other than void, use a type cast on the return value.

See Also

»calloc functions,« »free functions,« »malloc functions,« »_msize functions,« »realloc functions«

Compatibility

_expand:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bexpand, _fexpand, _nexpand:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* EXPAND.C */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

void main( void )
{
   char *bufchar;

   printf( "Allocate a 512 element buffer\n" );
   if( (bufchar = (char *)calloc( 512, sizeof( char ) )) == NULL )
      exit( 1 );
   printf( "Allocated %d bytes at %Fp\n",
         _msize( bufchar ), (void __far *)bufchar );
   if( (bufchar = (char *)_expand( bufchar, 1024 )) == NULL )
      printf( "Can't expand" );
   else
      printf( "Expanded block to %d bytes at %Fp\n",
            _msize( bufchar ), (void __far *)bufchar );

   /* Free memory */
   free( bufchar );
   exit( 0 );
}

Output

Allocate a 512 element buffer
Allocated 512 bytes at 2480:0F5C
Expanded block to 1024 bytes at 2480:0F5C


Description: fabs, fabsl
  fabs, fabsl

#include <math.h>

double fabs( double x );

long double fabsl( long double x );

x    Floating-point value

Remarks

The fabs and fabsl functions calculate the absolute value of their floating-point parameters. The fabsl function is the 80-bit counterpart; it uses an 80-bit, 10-byte coprocessor form of parameters and return values. See the reference page on the »long double functions« for more details on this data type.

Return Value

These functions return the absolute value of their arguments. There is no error return.

See Also

»abs,« »_cabs,« »labs«

Compatibility

fabs:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

fabsl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »abs.«


Description: fclose, _fcloseall
  fclose, _fcloseall

#include <stdio.h>

int fclose( FILE *stream );

int _fcloseall( void );

stream    Pointer to FILE structure

Remarks

The fclose function closes stream. The _fcloseall function closes all open streams except stdin, stdout, stderr (and in MS-DOS, _stdaux and _stdprn). It also closes and deletes any temporary files created by tmpfile. In both functions, all buffers associated with the stream are flushed prior to closing. System-allocated buffers are released when the stream is closed. Buffers assigned by the user with setbuf and setvbuf are not automatically released.

Return Value

The fclose function returns 0 if the stream is successfully closed. The _fcloseall function returns the total number of streams closed. Both functions return EOF to indicate an error.

See Also

»_close,« »_fdopen,« »fflush,« »fopen,« »freopen«

Compatibility

fclose:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fcloseall:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »fopen.«


Description: _fcvt
  _fcvt

#include <stdlib.h>

char *_fcvt( double value, int count, int *dec, int *sign );

value    Number to be converted

count    Number of digits after decimal point

dec    Pointer to stored decimal-point position

sign    Pointer to stored sign indicator

Remarks

The _fcvt function converts a floating-point number to a null-terminated character string. The value parameter is the floating-point number to be converted. The _fcvt function stores the digits of value as a string and appends a null character ('\0'). The count parameter specifies the number of digits to be stored after the decimal point. Excess digits are rounded off to count places. If there are fewer than count digits of precision, the string is padded with zeros.

Only digits are stored in the string. The position of the decimal point and the sign of value can be obtained from dec and sign after the call. The dec parameter points to an integer value; this integer value gives the position of the decimal point with respect to the beginning of the string. A zero or negative integer value indicates that the decimal point lies to the left of the first digit. The parameter sign points to an integer indicating the sign of value. The integer is set to 0 if value is positive and is set to a nonzero number if value is negative.

The _ecvt and _fcvt functions use a single statically allocated buffer for the conversion. Each call to one of these routines destroys the results of the previous call.

Return Value

The _fcvt function returns a pointer to the string of digits. There is no error return.

See Also

»atof,« »atoi,« »atol,« »_ecvt,« »_gcvt«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _fcvt for compatibility with ANSI naming conventions of non-ANSI functions. Use fcvt and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* FCVT.C: This program converts the constant
 * 3.1415926535 to a string and sets the pointer
 * *buffer to point to that string.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int  decimal, sign;
   char *buffer;
   double source = 3.1415926535;

   buffer = _fcvt( source, 7, &decimal, &sign );
   printf( "source: %2.10f   buffer: '%s'   decimal: %d   sign: %d\n",
            source, buffer, decimal, sign );
}

Output

source: 3.1415926535   buffer: '31415927'   decimal: 1   sign: 0


Description: _fdopen
  _fdopen

#include <stdio.h>

FILE *_fdopen( int handle, const char *mode );

handle    Handle referring to open file

mode    Type of access permitted

Remarks

The _fdopen function associates an input/output stream with the file identified by handle, thus allowing a file opened for low-level I/O to be buffered and formatted. The mode character string specifies the type of access requested for the file, as shown below. The following list gives the mode string used in the fopen and _fdopen functions and the corresponding oflag arguments used in the _open and _sopen functions. A complete description of the mode string argument is given in the "Remarks" section of the »fopen« function.

Type string	Equivalent value for _open/_sopen
"r"	_O_RDONLY
"w"	_O_WRONLY (usually _O_WRONLY | _O_CREAT | _O_TRUNC)
"a"	_O_WRONLY | _O_APPEND (usually _O_WRONLY | _O_CREAT | _O_APPEND)
"r+"	_O_RDWR
"w+"	_O_RDWR (usually _O_RDWR | _O_CREAT | _O_TRUNC)
"a+"	_O_RDWR | _O_APPEND (usually _O_RDWR | _O_APPEND | _O_CREAT )
If t or b is not given in the mode string, the translation mode is defined by the default-mode variable _fmode.

In addition to the values listed above, one of the following characters can be included in the mode string to specify the translation mode for new lines. These characters correspond to the constants used in the _open and _sopen functions, as shown below:

Mode	Equivalent value for _open/_sopen
t	_O_TEXT
b	_O_BINARY
If t or b is not given in the mode string, the translation mode is defined by the default-mode variable _fmode.

In addition to the file attribute and the text or binary mode listed above, the mode string accepts either c or n to specify commit to disk or do not commit to disk, respectively. These characters have no correspondence to constants used in the _open and _sopen functions. For more information on the commit feature, see »Committing Buffer Contents to Disk.« If c or n is not given in the mode string, n is the default mode.

Return Value

The _fdopen function returns a pointer to the open stream. A null pointer value indicates an error.

See Also

»_dup,« »_dup2,« »fclose,« »_fcloseall,« »fopen,« »freopen,« »_open«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _fdopen for compatibility with ANSI naming conventions of non-ANSI functions. Use fdopen and link with OLDNAMES.LIB for UNIX compatibility. The t, c, and n options are not part of the ANSI standard for fopen and _fdopen but are instead Microsoft extensions and should not be used where ANSI portability is desired.

Example

/* _FDOPEN.C: This program opens a file using low-
 * level I/O, then uses _fdopen to switch to stream
 * access. It counts the lines in the file.
 */

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>

void main( void )
{
   FILE *stream;
   int  fh, count = 0;
   char inbuf[128];

   /* Open a file handle. */
   if( (fh = _open( "_fdopen.c", _O_RDONLY )) == -1 )
      exit( 1 );

   /* Change handle access to stream access. */
   if( (stream = _fdopen( fh, "r" )) == NULL )
      exit( 1 );

   while( fgets( inbuf, 128, stream ) != NULL )
      count++;

   /* After _fdopen, close with fclose, not _close. */
   fclose( stream );
   printf( "Lines in file: %d\n", count );
}

Output

Lines in file: 30


Description: feof
  feof

#include <stdio.h>

int feof( FILE *stream );

stream    Pointer to FILE structure

Remarks

The feof routine (implemented both as a function and as a macro) determines whether the end of stream has been reached. Once the end of the file is reached, read operations return an end-of-file indicator until the stream is closed or until rewind, fsetpos, fseek, or clearerr is called against it.

Return Value

The feof function returns a nonzero value after the first read operation that attempts to read past the end of the file. It returns 0 if the current position is not end-of-file. There is no error return.

See Also

»clearerr,« »_eof,« »ferror,« »perror«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FEOF.C: This program uses feof to indicate when
 * it reaches the end of the file FEOF.C. It also
 * checks for errors with ferror.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int  count, total = 0;
   char buffer[100];
   FILE *stream;

   if( (stream = fopen( "feof.c", "r" )) == NULL )
      exit( 1 );

   /* Cycle until end of file reached: */
   while( !feof( stream ) )
   {
      /* Attempt to read in 10 bytes: */
      count = fread( buffer, sizeof( char ), 100, stream );
      if( ferror( stream ) )      {
         perror( "Read error" );
         break;
      }

      /* Total up actual bytes read */
      total += count;
   }
   printf( "Number of bytes read = %d\n", total );
   fclose( stream );
}

Output

Number of bytes read = 697


Description: ferror
  ferror

#include <stdio.h>

int ferror( FILE *stream );

stream    Pointer to FILE structure

Remarks

The ferror routine (implemented both as a function and as a macro) tests for a reading or writing error on the file associated with stream. If an error has occurred, the error indicator for the stream remains set until the stream is closed or rewound, or until clearerr is called against it.

Return Value

If no error has occurred on stream, ferror returns 0. Otherwise, it returns a nonzero value.

See Also

»clearerr,« »_eof,« »feof,« »perror,« »fopen«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »feof.«


Description: fflush
  fflush

#include <stdio.h>

int fflush( FILE *stream );

stream    Pointer to FILE structure

Remarks

The fflush function flushes a stream. If the file associated with stream is open for output, fflush writes to that file the contents of the buffer associated with the stream. If the stream is open for input, fflush clears the contents of the buffer. The fflush function negates the effect of any prior call to ungetc against stream.

Buffers are automatically flushed when they are full, when the stream is closed, or when a program terminates normally without closing the stream. Also, fflush(NULL) flushes all streams opened for output.The stream remains open after the call. The fflush function has no effect on an unbuffered stream.

Return Value

The fflush function returns the value 0 if the buffer was successfully flushed. The value 0 is also returned in cases in which the specified stream has no buffer or is open for reading only. A return value of EOF indicates an error.

Note  If fflush returns EOF, data may have been lost because of a failed write. When setting up a critical error handler, it is safest to turn buffering off with the setvbuf function or to use low-level I/O routines such as _open, _close, and _write instead of the stream I/O functions.

See Also

»fclose,« »_flushall,« »setbuf«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FFLUSH.C */

#include <stdio.h>
#include <conio.h>

void main( void )
{
   int integer;
   char string[81];

   /* Read each word as a string. */
   printf( "Enter a sentence of four words with scanf: " );
   for( integer = 0; integer < 4; integer++ )
   {
      scanf( "%s", string );
      printf( "%s\n", string );
   }

   /* You must flush the input buffer before using gets. */
   fflush( stdin );
   printf( "Enter the same sentence with gets: " );
   gets( string );
   printf( "%s\n", string );
}

Output

Enter a sentence of four words with scanf: This is a test
This
is
a
test
Enter the same sentence with gets: This is a test
This is a test


Description: fgetc, _fgetchar
  fgetc, _fgetchar

#include <stdio.h>

int fgetc( FILE *stream );

int _fgetchar( void );

stream    Pointer to FILE structure

Remarks

The fgetc function reads a single character from the current position of the file associated with stream. The character is converted and returned as an int. The function then increments the associated file pointer (if any) to point to the next character. The _fgetchar function is equivalent to fgetc(stdin). The fgetc and _fgetchar routines are identical to getc and getchar, but they are functions rather than macros.

Return Value

The fgetc and _fgetchar functions return the character read. They return EOF to indicate an error or end-of-file. Use feof or ferror to distinguish between an error and an end-of-file condition.

See Also

»fputc,« »_fputchar,« »getc,« »getchar«

Compatibility

fgetc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fgetchar:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FGETC.C: This program uses getc to read the first
 * 80 input characters (or until the end of input)
 * and place them into a string named buffer.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   FILE *stream;
   char buffer[81];
   int  i, ch;

   /* Open file to read line from: */
   if( (stream = fopen( "fgetc.c", "r" )) == NULL )
      exit( 0 );

   /* Read in first 80 characters and place them in "buffer": */
   ch = fgetc( stream );
   for( i=0; (i < 80 ) && ( feof( stream ) == 0 ); i++ )
   {
      buffer[i] = (char)ch;
      ch = fgetc( stream );
   }

   /* Add null to end string */
   buffer[i] = '\0';
   printf( "%s\n", buffer );
   fclose( stream );
}

Output

/* FGETC.C: This program uses getc to read the first
 * 80 input characters (or


Description: fgetpos
  fgetpos

#include <stdio.h>

int fgetpos( FILE *stream, fpos_t *pos );

stream    Target stream

pos    Position-indicator storage

Remarks

The fgetpos function gets the current value of the stream argument's file-position indicator and stores it in the object pointed to by pos. The fsetpos function can later use information stored in pos to reset the stream argument's pointer to its position at the time fgetpos was called. The pos value is stored in an internal format and is intended for use only by the fgetpos and fsetpos functions.

Return Value

If successful, the fgetpos function returns 0. On failure, it returns a nonzero value and sets errno to one of the following manifest constants (defined in STDIO.H): EBADF, which means the specified stream is not a valid file handle or is not accessible, or EINVAL, which means the stream value is invalid.

See Also

»fsetpos«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FGETPOS.C: This program opens a file and reads
 * bytes at several different locations.
 */

#include <stdio.h>

void main( void )
{
   FILE   *stream;
   fpos_t pos;
   char   buffer[20];

   if( (stream = fopen( "fgetpos.c", "rb" )) == NULL )
      printf( "Trouble opening file\n" );
   else
   {
      /* Read some data and then check the position. */
      fread( buffer, sizeof( char ), 10, stream );
      if( fgetpos( stream, &pos ) != 0 )
         perror( "fgetpos error" );
      else
      {
         fread( buffer, sizeof( char ), 10, stream );
         printf( "10 bytes at byte %ld: %.10s\n", pos, buffer );
      }

   /* Set a new position and read more data */
   pos = 140;
   if( fsetpos( stream, &pos ) != 0 )
      perror( "fsetpos error" );

   fread( buffer, sizeof( char ), 10, stream );
   printf( "10 bytes at byte %ld: %.10s\n", pos, buffer );
   fclose( stream );
   }
}

Output

10 bytes at byte 10: .C: This p
10 bytes at byte 140:
{
   FIL


Description: fgets
  fgets

#include <stdio.h>

char *fgets( char *string, int n, FILE *stream );

string    Storage location for data

n    Maximum number of characters to read

stream    Pointer to FILE structure

Remarks

The fgets function reads a string from the input stream argument and stores it in string. Characters are read from the current stream position up to and including the first newline character ('\n'), up to the end of the stream, or until the number of characters read is equal to n −1, whichever comes first. The result is stored in string, and a null character ('\0') is appended. The newline character, if read, is included in the string. The fgets function is similar to the gets function; however, gets replaces the newline character with NULL.

Return Value

If successful, the fgets function returns string. It returns NULL to indicate either an error or end-of-file condition. Use feof or ferror to determine whether an error occurred.

See Also

»fputs,« »gets,« »puts«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FGETS.C: This program uses fgets to display
 * a line from a file on the screen.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char line[100];

   if( (stream = fopen( "fgets.c", "r" )) != NULL )
   {
      if( fgets( line, 100, stream ) == NULL)
         printf( "fgets error\n" );
      else
         printf( "%s", line);
      fclose( stream );
   }
}

Output

/* FGETS.C: This program uses fgets to display


Description: _fieeetomsbin, _fmsbintoieee
  _fieeetomsbin, _fmsbintoieee

#include <math.h>

int _fieeetomsbin( float *src4, float *dst4 );

int _fmsbintoieee( float *src4, float *dst4 );

scr4    Value to be converted

dst4    Converted value

Remarks

The _fieeetomsbin routine converts a single-precision floating-point number in IEEE (Institute of Electrical and Electronic Engineers) format to Microsoft (MS) binary format. The _fmsbintoieee routine converts a floating-point number in Microsoft binary format to IEEE format. These routines allow C programs (which store floating-point numbers in the IEEE format) to use numeric data in random-access data files created with Microsoft Basic (which stores floating-point numbers in the Microsoft binary format), and vice versa.

These routines do not handle IEEE NANs ("not a number") and infinities. IEEE denormals are treated as 0 in the conversions.

The argument src4 points to the float value to be converted. The result is stored at the location given by dst4.

Return Value

These functions return 0 if the conversion is successful and 1 if the conversion causes an overflow.

See Also

»_dieeetomsbin,« »_dmsbintoieee«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _filelength
  _filelength

#include <io.h>

long _filelength( int handle );

handle    Target file handle

Remarks

The _filelength function returns the length, in bytes, of the target file associated with handle.

Return Value

The _filelength function returns the file length in bytes. A return value of −1L indicates an error, and an invalid handle sets errno to EBADF.

See Also

»_chsize,« »_fileno,« »_fstat,« »_stat«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_chsize.«


Description: _fileno
  _fileno

#include <stdio.h>

int _fileno( FILE *stream );

stream    Pointer to FILE structure

Remarks

The _fileno routine returns the file handle currently associated with stream. This routine is implemented both as a function and as a macro.

Return Value

The _fileno routine returns the file handle. There is no error return. The result is undefined if stream does not specify an open file.

See Also

»_fdopen,« »_filelength,« »fopen,« »freopen«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _fileno for compatibility with ANSI naming conventions of non-ANSI functions. Use fileno and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* FILENO.C: This program uses _fileno to obtain
 * the file handle for some standard C streams.
 */

#include <stdio.h>

void main( void )
{
   printf( "The file handle for stdin is %d\n", _fileno( stdin ) );
   printf( "The file handle for stdout is %d\n", _fileno( stdout ) );
   printf( "The file handle for stderr is %d\n", _fileno( stderr ) );
}

Output

The file handle for stdin is 0
The file handle for stdout is 1
The file handle for stderr is 2


Description: _find Functions
  _find Functions

#include <io.h>

long _findfirst( char *filespec, struct _finddata_t *fileinfo );

int _findnext( long handle, struct _finddata_t *fileinfo );

int _findclose( long handle );

filespec    Target file specification (may include wildcards)

handle    Search handle returned by a previous call to _findfirst

fileinfo    File information buffer

Remarks

The _findfirst function provides information about the first instance of a filename that matches the file specified in the filespec argument. Wildcards (* and ?) can be used in the filespec argument. Any wildcard combination supported by the host operating system can be used. File information is returned in a _finddata_t structure, defined in IO.H. The _finddata_t structure includes the following elements:

unsigned attrib    File attribute

time_t time_create    Time of file creation ( −1L for FAT file systems)

time_t time_access    Time of last file access (−1L for FAT file systems)

time_t time_write    Time of last write to file

_fsize_t size    Length of file in bytes

char name[_MAX_FNAME]    Null-terminated name of matched file/directory, without the path

In file systems that do not support the creation and last access times of a file, such as the File Allocation Table (FAT) system supported by MS-DOS, the time_create and time_access fields will always be −1L.

_MAX_FNAME is defined in STDLIB.H and is equal to 256 bytes.

You cannot specify target attributes ( such as _A_RDONLY) by which to limit the find operation. This attribute is returned in the attrib field of the _finddata_t structure and can have the following values (defined in IO.H):

_A_ARCH    Archive. Set whenever the file is changed, and cleared by the BACKUP command. Value: 0x20

_A_HIDDEN    Hidden file. Not normally seen with the DIR command, unless the /AH option is used. Returns information about normal files as well as files with this attribute. Value: 0x02

_A_NORMAL    Normal. File can be read or written to without restriction. Value: 0x00

_A_RDONLY    Read-only. File cannot be opened for writing, and a file with the same name cannot be created. Value: 0x01

_A_SUBDIR    Subdirectory. Value: 0x10

_A_SYSTEM    System file. Not normally seen with the DIR command, unless the /AS option is used. Value: 0x04

The _findnext function finds the next name, if any that matches the filespec argument specified in a prior call to _findfirst. The fileinfo argument should point to a structure initialized by a previous call to _findfirst. The contents of the structure will be altered as described above if a match is found. The _findclose routine closes the specified search handle and releases associated resources.

The _find functions allow nested calls. For example, if the file found by a call to _findfirst or _findnext is a subdirectory, a new search can be initiated with another call to _findfirst or _findnext.

Return Value

If successful, the _findfirst function returns a unique search handle identifying the file or group of files matching the filespec specification, which can be used in a subsequent call to _findnext or _findclose. Otherwise, it returns −1 and sets errno to one of the following values:

ENOENT    File specification that could not be matched

EINVAL    Invalid filename specification

If successful, the _findnext and _findclose functions return 0. Otherwise, they return −1 and set errno to ENOENT, indicating that no more matching files could be found.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FFIND.C: This program uses the 32-bit _find functions to print
 * a list of all files (and their attributes) with a .C extension
 * in the current directory.
 */

#include <stdio.h>
#include <io.h>
#include <time.h>

void main( void )
{
    struct _finddata_t c_file;
    long hFile;

    /* Find first .c file in current directory */
    if( (hFile = _findfirst( "*.c", &c_file )) == -1L )
       printf( "No *.c files in current directory!\n" );
   else
   {
            printf( "Listing of .c files\n\n" );
            printf( "\nRDO HID SYS ARC  FILE         DATE %25c SIZE\n", ' ' );
            printf( "--- --- --- ---  ----         ---- %25c ----\n", ' ' );
            printf( ( c_file.attrib & _A_RDONLY ) ? " Y  " : " N  " );
            printf( ( c_file.attrib & _A_SYSTEM ) ? " Y  " : " N  " );
            printf( ( c_file.attrib & _A_HIDDEN ) ? " Y  " : " N  " );
            printf( ( c_file.attrib & _A_ARCH )   ? " Y  " : " N  " );
            printf( " %-12s %.24s  %9ld\n",
               c_file.name, ctime( &( c_file.time_write ) ), c_file.size );

            /* Find the rest of the .c files */
            while( _findnext( hFile, &c_file ) == 0 )
            {
                printf( ( c_file.attrib & _A_RDONLY ) ? " Y  " : " N  " );
                printf( ( c_file.attrib & _A_SYSTEM ) ? " Y  " : " N  " );
                printf( ( c_file.attrib & _A_HIDDEN ) ? " Y  " : " N  " );
                printf( ( c_file.attrib & _A_ARCH )   ? " Y  " : " N  " );
                printf( " %-12s %.24s  %9ld\n",
                   c_file.name, ctime( &( c_file.time_write ) ), c_file.size );
            }

       _findclose( hFile );
   }

}

Output

Listing of .c files

RDO HID SYS ARC  FILE         DATE                           SIZE
--- --- --- ---  ----         ----                           ----
 N   N   N   Y   CWAIT.C      Tue Jun 01 04:07:26 1993       1611
 N   N   N   Y   SPRINTF.C    Thu May 27 04:59:18 1993        617
 N   N   N   Y   CABS.C       Thu May 27 04:58:46 1993        359
 N   N   N   Y   BEGTHRD.C    Tue Jun 01 04:00:48 1993       3726


Description: _finite
  _finite

#include <float.h>

int _finite( double x );

x    Double-precision floating-point value

Remarks

The _finite function tests a given double-precision floating-point value x, returning a nonzero value (TRUE) if x is not infinite; that is, −INF < x < +INF. Note that if x is a NaN, _finite returns 0 (FALSE), even though x is not infinite. Otherwise, it returns 0.

Return Value

The  _finite function returns a nonzero value (TRUE) if the argument x is not infinite, and 0 (FALSE) if x is infinite or a NaN.

See Also

»_isnan,« »_fpclass«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _floodfill, _floodfill_w
  _floodfill, _floodfill_w

#include <graph.h>

short __far _floodfill( short x, short y, short boundary );

short __far _floodfill_w( double wx, double wy, short boundary );

x, y    Start point

wx, wy    Start point

boundary    Boundary color of area to be filled

Remarks

The functions in the _floodfill family fill an area of the display, using the current color and fill mask. The _floodfill routine begins filling at the view-coordinate point (x, y). The _floodfill_w routine begins filling at the window-coordinate point (wx, wy). If this point lies inside the figure, the interior is filled; if it lies outside the figure, the background is filled. The point must be inside or outside the figure to be filled, not on the figure boundary itself. Filling occurs in all directions, stopping at the color of boundary.

Return Value

The _floodfill functions return a nonzero value if the fill is successful. They return 0 if the fill could not be completed, the starting point lies on the boundary color, or the start point lies outside the clipping region.

See Also

»_ellipse functions,« »_getcolor,« »_getfillmask,« »_grstatus,« »_pie functions,« »_setfillmask,« »_setcliprgn,« »_setcolor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * FLOODFIL.C: This program draws a series of
 * nested rectangles in different colors,
 * constantly changing the background color.
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

void main( void )
{
   int loop;
   short xvar, yvar;

   /* find a valid graphics mode */
   if( !_setvideomode( _MAXCOLORMODE ) ) exit( 1 );

   for( xvar = 163, loop = 0; xvar < 320; loop++, xvar += 3 )
   {
      _setcolor( (short)(loop % 16) );
      yvar = (short)(xvar * 5 / 8);
      _rectangle( _GBORDER, 320-xvar, 200-yvar, xvar, yvar );
      _setcolor( (short)(rand() % 16) );
      _floodfill( 0, 0, (short)(loop % 16) );
   }
   _getch();
   _setvideomode( _DEFAULTMODE );
}


Description: floor, floorl
  floor, floorl

#include <math.h>

double floor( double x );

long double floorl( long double x );

x    Floating-point value

Remarks

The floor and floorl functions return a floating-point value representing the largest integer that is less than or equal to x. The floorl function is the 80-bit counterpart, and it uses the 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

Return Value

These functions return the double or long double result. There is no error return.

See Also

»ceil,« »fmod«

Compatibility

floor:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

floorl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FLOOR.C: This example displays the largest integers
 * less than or equal to the floating-point values 2.8
 * and -2.8. It then shows the smallest integers greater
 * than or equal to 2.8 and -2.8.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double y;

   y = floor( 2.8 );
   printf( "The floor of 2.8 is %f\n", y );
   y = floor( -2.8 );
   printf( "The floor of -2.8 is %f\n", y );

   y = ceil( 2.8 );
   printf( "The ceil of 2.8 is %f\n", y );
   y = ceil( -2.8 );
   printf( "The ceil of -2.8 is %f\n", y );
}

Output

The floor of 2.8 is 2.000000
The floor of -2.8 is -3.000000
The ceil of 2.8 is 3.000000
The ceil of -2.8 is -2.000000


Description: _flushall
  _flushall

#include <stdio.h>

int _flushall( void );

Remarks

The _flushall function writes to its associated files the contents of all buffers associated with open output streams. All buffers associated with open input streams are cleared of their current contents. The next read operation (if there is one) then reads new data from the input files into the buffers. All streams remain open after the call to _flushall.

Buffers are automatically flushed when they are full, when streams are closed, or when a program terminates normally without closing streams.

Return Value

The _flushall function returns the number of open streams (input and output). There is no error return.

See Also

»fflush«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FLUSHALL.C: This program uses _flushall
 * to flush all open buffers.
 */

#include <stdio.h>

void main( void )
{
   int numflushed;

   numflushed = _flushall();
   printf( "There were %d streams flushed\n", numflushed );
}

Output

There were 3 streams flushed


Description: fmod, fmodl
  fmod, fmodl

#include <math.h>

double fmod( double x, double y );

long double fmodl( long double x, long double y );

x, y    Floating-point values

Remarks

The fmod and fmodl functions calculate the floating-point remainder f of x / y such that x = i * y + f, where i is an integer, f has the same sign as x, and the absolute value of f is less than the absolute value of y. The fmodl function is the 80-bit counterpart; it uses the 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

Return Value

These functions return the floating-point remainder. If y is 0, the function returns 0.

See Also

»ceil,« »fabs,« »floor«

Compatibility

fmod:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

fmodl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FMOD.C: This program displays a
 * floating-point remainder.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = -10.0, y = 3.0, z;

   z = fmod( x, y );
   printf( "The remainder of %.2f / %.2f is %f\n", x, y, z );
}

Output

The remainder of -10.00 / 3.00 is -1.000000


Description: fopen
  fopen

#include <stdio.h>

FILE *fopen( const char *filename, const char *mode );

filename    Filename

mode    Type of access permitted

Remarks

The fopen function opens the file specified by filename. The character string mode specifies the type of access requested for the file, as follows:

"r"    Opens for reading. If the file does not exist or cannot be found, the fopen call will fail.

"w"    Opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"    Opens for writing at the end of the file (appending); creates the file first if it doesn't exist.

"r+"    Opens for both reading and writing. (The file must exist.)

"w+"    Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

"a+"    Opens for reading and appending; creates the file first if it doesn't exist.

When a file is opened with the "a" or "a+" access type, all write operations occur at the end of the file. Although the file pointer can be repositioned using fseek or rewind, the file pointer is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten. When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for "update"). However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired.

In addition to the values listed above, the following characters can be included in mode to specify the translation mode for newline characters:

t    Open in text (translated) mode. In this mode, carriage-return−linefeed (CR-LF) combinations are translated into single linefeeds (LF) on input and LF characters are translated to CR-LF combinations on output. Also , CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing, fopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using the fseek and ftell functions to move within a file that ends with a CTRL+Z may cause fseek to behave improperly near the end of the file.

b    Open in binary (untranslated) mode; the above translations are suppressed.

c    Enable the commit flag for the associated filename so that the contents of the file buffer are written directly to disk if either fflush or _flushall is called.

n    Reset the commit flag for the associated filename to "no-commit." This is the default. It will also override the global commit flag if you have linked your program with COMMODE.OBJ. The global commit flag default is "no-commit" unless you explicitly link your program with COMMODE.OBJ.

If t or b is not given in mode, the translation mode is defined by the default-mode variable _fmode. If t or b is prefixed to the argument, the function will fail and return NULL.

For a discussion of text and binary modes, see »Input and Output.«

Return Value

The fopen function returns a pointer to the open file. A null pointer value indicates an error.

See Also

»fclose,« »_fcloseall,« »_fdopen,« »ferror,« »_fileno,« »freopen,« »_open,« »_setmode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Note that the c, n, and t options are not part of the ANSI standard for fopen; they are Microsoft extensions and should not be used where ANSI portability is desired.

Example

/* FOPEN.C: This program opens files named "data"
 * and "data2".It  uses fclose to close "data" and
 * _fcloseall to close all remaining files.
 */

#include <stdio.h>

FILE *stream, *stream2;

void main( void )
{
   int numclosed;

   /* Open for read (will fail if 'data does not exist) */
   if( (stream  = fopen( "data", "r" )) == NULL )
      printf( "The file 'data' was not opened\n" );
   else
      printf( "The file 'data' was opened\n" );

   /* Open for write */
   if( (stream2 = fopen( "data2", "w+" )) == NULL )
      printf( "The file 'data2' was not opened\n" );
   else
      printf( "The file 'data2' was opened\n" );

   /* Close stream */
   if( fclose( stream ) )
      printf( "The file 'data' was not closed\n" );

   /* All other files are closed: */
   numclosed = _fcloseall( );
   printf( "Number of files closed by _fcloseall: %u\n", numclosed );
}

Output

The file 'data' was opened
The file 'data2' was opened
Number of files closed by _fcloseall: 1


Description: _FP_OFF, _FP_SEG
  _FP_OFF, _FP_SEG

#include <dos.h>

unsigned _FP_OFF( void __far *address );

unsigned _FP_SEG( void __far *address );

address    Far pointer to memory address

Remarks

The _FP_OFF and _FP_SEG macros can be used to set or get the offset and segment, respectively, of the far pointer at address. The argument to _FP_OFF and _FP_SEG must be a far pointer variable. It cannot be an array name, or a near pointer cast to a far pointer.

Return Value

The _FP_OFF macro returns an offset. The _FP_SEG macro returns a segment address.

See Also

»_MK_FP«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * _FP_SEG.C: This program uses _FP_SEG and _FP_OFF to
 * obtain the segment and offset of the long pointer p.
 */

#include <dos.h>
#include <malloc.h>
#include <stdio.h>

void main( void )
{
   void __far *p;
   unsigned int seg_val;
   unsigned int off_val;

   p = _fmalloc( 100 );      /* Points pointer at something */

   seg_val = _FP_SEG( p );      /* Gets address pointed to */
   off_val = _FP_OFF( p );

   printf( "Segment is %.4X; Offset is %.4X\n", seg_val, off_val );
}

Output

Segment is 3478; Offset is 0016


Description: _fpclass
  _fpclass

#include <float.h>

int    _fpclass( double x );

x    Double-precision floating-point value

Remarks

The _fpclass function returns a status word containing information on the floating-point class of its double-precision floating-point argument x.

Return Value

The _fpclass function returns an integer value which indicates the floating-point class of its argument x. The class word has the following values, defined in FLOAT.H:

Value	Meaning
_FPCLASS_SNAN	Signaling NAN
_FPCLASS_QNAN	Quiet NAN
_FPCLASS_NINF	Negative infinity ( −INF)
_FPCLASS_NN	Negative normalized non-zero
_FPCLASS_ND	Negative denormalized
_FPCLASS_NZ	Negative zero ( −0)
_FPCLASS_PZ	Positive 0 (+0)
_FPCLASS_PD	Positive denormalized
_FPCLASS_PN	Positive normalized non-zero
_FPCLASS_PINF	Positive infinity (+INF)
See Also

»_isnan«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _fpieee_flt
  _fpieee_flt

#include <fpieee.h>

int _fpieee_flt( unsigned long exc_code, struct _EXCEPTION_POINTERS *exc_info, int handler(_FPIEEE_RECORD *) );

exc_code    exception code

exc_inf    pointer to the NT Exception Information structure

handler    pointer to user's IEEE trap handler routine

Remarks

The _fpieee_flt function invokes a user-defined trap handler for IEEE floating-point exceptions and provides it with all relevant information. This routine serves as an exception filter in the Structured Exception Handling (SEH) mechanism, which invokes your own IEEE exception handler when necessary.

The _FPIEEE_RECORD structure, defined in FPIEEE.H, contains information pertaining to an IEEE floating-point exception. This structure is passed to the user-defined trap handler by the _fpieee_flt function, and contains the following fields:

unsigned int RoundingMode, unsigned int Precision    These fields contain information on the floating-point environment at the time the exception occurred.

unsigned int Operation    Indicates the type of operation which caused the trap. If the type is a comparison (_FpCodeCompare), you can supply one of the special _FPIEEE_COMPARE_RESULT values (as defined in FPIEEE.H) in the Result.Value field. The conversion type (_FpCodeConvert) indicates that the trap occurred during a floating-point conversion operation. You can look at the Operand1 and Result types to determine the type of conversion being attempted.

_FPIEEE_VALUE Operand1, _FPIEEE_VALUE Operand2, _FPIEEE_VALUE Result    These structures indicate the types and values of the proposed result and operands:

•	OperandValid    This flag indicates if the corresponding value is valid.

•	Format    This field indicates the data type of the corresponding value. Note that the format type may be returned even if the corresponding value is not valid.

•	Value    This field contains the result or operand data value.

Return Value

The return value of the _fpieee_flt function is the value returned by handler. As such, the IEEE filter routine may be used in the except clause of an SEH mechanism.

See Also

»_controlfp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FPIEEE.C: This program demonstrates the implementation of
 * a user-defined floating-point exception handler using the
 * _fpieee_flt function.
 */

#include <fpieee.h>
#include <excpt.h>
#include <float.h>

int fpieee_handler( _FPIEEE_RECORD * );

int fpieee_handler( _FPIEEE_RECORD *pieee )
{
   // user-defined ieee trap handler routine:
   // there is one handler for all
   // IEEE exceptions

   // Assume the user wants all invalid
   // operations to return 0.

   if ((pieee->Cause.InvalidOperation) &&
       (pieee->Result.Format == _FpFormatFp32))
   {
        pieee->Result.Value.Fp32Value = 0.0F;
        return EXCEPTION_CONTINUE_EXECUTION;
   }
   else
      return EXCEPTION_EXECUTE_HANDLER;
}

#define _EXC_MASK    \
    _EM_UNDERFLOW  + \
    _EM_OVERFLOW   + \
    _EM_ZERODIVIDE + \
    _EM_INEXACT

void main( void )
{
   // ...

   __try {
      // unmask Invalid operation Exception
      _controlfp(_EXC_MASK, _MCW_EM);

      // code that may generate
      // fp exceptions goes here
   }
   __except ( _fpieee_flt( GetExceptionCode(),
                GetExceptionInformation(),
                fpieee_handler ) ){

      // code that gets control
      // if fpieee_handler returns
      // EXCEPTION_EXECUTE_HANDLER goes here
   }

   // ...
}


Description: _fpreset
  _fpreset

#include <float.h>

void _fpreset( void );

Remarks

The _fpreset function reinitializes the floating-point-math package. This function is usually used in conjunction with signal, system, or the _exec or _spawn functions. If a program traps floating-point error signals (SIGFPE) with signal, it can safely recover from floating-point errors by invoking _fpreset and using longjmp.

In MS-DOS versions prior to 3.0, a child process executed by _exec, _spawn, or system may affect the floating-point state of the parent process if an 8087, 80287, or 80387 coprocessor is used. If you are using either coprocessor, the following precautions are recommended:

•	The _exec, _spawn, and system functions should not be called during the evaluation of a floating-point expression.

•	The _fpreset function should be called after these routines if there is a possibility of the child process performing any floating-point operations.

Return Value

None.

See Also

»_exec functions,« »signal,« »_spawn functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FPRESET.C: This program uses signal to set up a
 * routine for  handling floating-point errors.
 */

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <string.h>

jmp_buf mark;              /* Address for long jump to jump to */
int     fperr;             /* Global error number */

void __cdecl fphandler( int sig, int num );   /* Prototypes */
void fpcheck( void );

void main( void )
{
   double n1, n2, r;
   int jmpret;

   /* Set up floating-point error handler. The compiler
    * will generate a warning because it expects
    * signal-handling functions to take only one argument.
    */
   if( signal( SIGFPE, fphandler ) == SIG_ERR )
   {
      fprintf( stderr, "Couldn't set SIGFPE\n" );
      abort();
   }

   /* Save stack environment for return in case of error. First
    * time through, jmpret is 0, so true conditional is executed.
    * If an error occurs, jmpret will be set to -1 and false
    * conditional will be executed.
    */
   jmpret = setjmp( mark );
   if( jmpret == 0 )
   {
      printf( "Test for invalid operation - " );
      printf( "enter two numbers: " );
      scanf( "%lf %lf", &n1, &n2 );
      r = n1 / n2;
      /* This won't be reached if error occurs. */
      printf( "\n\n%4.3g / %4.3g = %4.3g\n", n1, n2, r );
      r = n1 * n2;
      /* This won't be reached if error occurs. */
      printf( "\n\n%4.3g * %4.3g = %4.3g\n", n1, n2, r );
   }
   else
      fpcheck();
}

/* fphandler handles SIGFPE (floating-point error) interrupt. Note
 * that this prototype accepts two arguments and that the
 * prototype for signal in the run-time library expects a signal
 * handler to have only one argument.
 *
 * The second argument in this signal handler allows processing of
 * _FPE_INVALID, _FPE_OVERFLOW, _FPE_UNDERFLOW, and
 * _FPE_ZERODIVIDE all of which are Microsoft-specific symbols
 * that augment the information provided by SIGFPE. The compiler
 * will generate a warning, which is harmless and expected.
 */
void fphandler( int sig, int num )
{
   /* Set global for outside check since we don't want
    * to do I/O in the handler.
    */
   fperr = num;

   /* Initialize floating-point package. */
   _fpreset();
   /* Restore calling environment and jump back to setjmp. Return
    * -1 so that setjmp will return false for conditional test.
    */
   longjmp( mark, -1 );
}

void fpcheck( void )
{
   char fpstr[30];
   switch( fperr )
   {
   case _FPE_INVALID:
       strcpy( fpstr, "Invalid number" );
       break;
   case _FPE_OVERFLOW:
       strcpy( fpstr, "Overflow" );
       break;
   case _FPE_UNDERFLOW:
       strcpy( fpstr, "Underflow" );
       break;
   case _FPE_ZERODIVIDE:
       strcpy( fpstr, "Divide by zero" );
       break;
   default:
       strcpy( fpstr, "Other floating point error" );
       break;
   }
   printf( "Error %d: %s\n", fperr, fpstr );
}

Output

Test for invalid operation - enter two numbers: 5 0
Error 131: Divide by zero


Description: fprintf, fwprintf
  fprintf, fwprintf

#include <stdio.h>    For fprintf

#include <wchar.h>    For fwprintf use either WCHAR.H (for ANSI compatibility) or STDIO.H

int fprintf( FILE *stream, const char *format [, argument ]...);

int fwprintf( FILE *stream, const wchar_t *format [, argument ]...);

stream    Pointer to FILE structure

format    Format-control string

argument    Optional arguments

Remarks

The fprintf function formats and prints a series of characters and values to the output stream. Each function argument (if any) is converted and output according to the corresponding format specification in format. For fprintf, the format argument has the same syntax and use that it has in the printf function.

The fwprintf function is a wide-character version of fprintf; in fwprintf, the format is a wide-character string. The fwprintf and fprintf functions behave identically otherwise.

For more information on format and argument, see the "Remarks" section for the »printf« function.

Return Value

The fprintf function returns the number of bytes written. The fwprintf function returns the number of wide characters written. Each of these functions returns a negative value instead when an output error occurs.

See Also

»_cprintf,« »fscanf,« »printf,« »sprintf«

Compatibility

fprintf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

fwprintf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FPRINTF.C: This program uses fprintf to format various
 * data and print them to the file named FPRINTF.OUT. It
 * then displays FPRINTF.OUT on the screen using the system
 * function to invoke the operating system TYPE command.
 */

#include <stdio.h>
#include <process.h>

FILE *stream;

void main( void )
{
   int    i = 10;
   double fp = 1.5;
   char   s[] = "this is a string";
   char   c = '\n';

   stream = fopen( "fprintf.out", "w" );
   fprintf( stream, "%s%c", s, c );
   fprintf( stream, "%d\n", i );
   fprintf( stream, "%f\n", fp );
   fclose( stream );
   system( "type fprintf.out" );
}

Output

this is a string
10
1.500000


Description: fputc, _fputchar
  fputc, _fputchar

#include <stdio.h>

int fputc( int c, FILE *stream );

int _fputchar( int c );

c    Character to be written

stream    Pointer to FILE structure

Remarks

The fputc function writes the single character c to the output stream at the current position. The _fputchar function is equivalent to fputc(c, stdout). The fputc and _fputchar routines are similar to putc and putchar but are functions rather than macros.

Return Value

The fputc and _fputchar functions return the character written. A return value of EOF indicates an error.

See Also

»fgetc,« »_fgetchar,« »putc,« »putchar«

Compatibility

fputc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fputchar:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FPUTC.C: This program uses fputc and _fputchar
 * to send a character array to stdout.
 */

#include <stdio.h>

void main( void )
{
   char strptr1[] = "This is a test of fputc!!\n";
   char strptr2[] = "This is a test of _fputchar!!\n";
   char *p;

   /* Print line to stream using fputc. */
   p = strptr1;
   while( (*p != '\0') && fputc( *(p++), stdout ) != EOF ) ;

   /* Print line to stream using _fputchar. */
   p = strptr2;
   while( (*p != '\0') && _fputchar( *(p++) ) != EOF )
      ;
}

Output

This is a test of fputc!!
This is a test of _fputchar!!


Description: fputs
  fputs

#include <stdio.h>

int fputs( const char *string, FILE *stream );

string    String to be output

stream    Pointer to FILE structure

Remarks

The fputs function copies string to the output stream at the current position. The terminating null character ('\0') is not copied.

Return Value

The fputs function returns a nonnegative value if it is successful. If an error occurs, it returns EOF.

See Also

»fgets,« »gets,« »puts«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FPUTS.C: This program uses fputs to write
 * a single line to the stdout stream.
 */

#include <stdio.h>

void main( void )
{
   fputs( "Hello world from fputs.\n", stdout );
}

Output

Hello world from fputs.


Description: fread
  fread

#include <stdio.h>

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

buffer    Storage location for data

size    Item size in bytes

count    Maximum number of items to be read

stream    Pointer to FILE structure

Remarks

The fread function reads up to count items of size bytes from the input stream and stores them in buffer. The file pointer associated with stream (if there is one) is increased by the number of bytes actually read. If the given stream is opened in text mode, carriage-return − linefeed pairs are replaced with single linefeed characters. The replacement has no effect on the file pointer or the return value. The file-pointer position is indeterminate if an error occurs. The value of a partially read item cannot be determined.

Return Value

The fread function returns the number of full items actually read, which may be less than count if an error occurs or if the file end is encountered before reaching count. The feof or ferror function should be used to distinguish a read error from an end-of-file condition. If size or count is 0, fread returns 0 and the buffer contents are unchanged.

See Also

»fwrite,« »_read«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FREAD.C: This program opens a file named FREAD.OUT and
 * writes 25 characters to the file. It then tries to open
 * FREAD.OUT and read in 25 characters. If the attempt succeeds,
 * the program displays the number of actual items read.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char list[30];
   int  i, numread, numwritten;

   /* Open file in text mode: */
   if( (stream = fopen( "fread.out", "w+t" )) != NULL )
   {
      for ( i = 0; i < 25; i++ )
         list[i] = (char)('z' - i);
      /* Write 25 characters to stream */
      numwritten = fwrite( list, sizeof( char ), 25, stream );
      printf( "Wrote %d items\n", numwritten );
      fclose( stream );
   }
   else
      printf( "Problem opening the file\n" );

   if( (stream = fopen( "fread.out", "r+t" )) != NULL )
   {
      /* Attempt to read in 25 characters */
      numread = fread( list, sizeof( char ), 25, stream );
      printf( "Number of items read = %d\n", numread );
      printf( "Contents of buffer = %.25s\n", list );
      fclose( stream );
   }
   else
      printf( "Was not able to open the file\n" );
}

Output

Wrote 25 items
Number of items read = 25
Contents of buffer = zyxwvutsrqponmlkjihgfedcb


Description: free Functions
  free Functions

#include <stdlib.h>    For ANSI compatibility (free only)

#include <malloc.h>

void free( void *memblock );

void _bfree( __segment seg, void __based( void ) *memblock );

void _ffree( void __far *memblock );

void _nfree( void __near *memblock );

memblock    Allocated memory block

seg    Based-heap segment selector

Remarks

The free family of functions deallocates a memory block. The argument memblock points to a memory block previously allocated through a call to calloc, malloc, or realloc. The number of bytes freed is the number of bytes specified when the block was allocated (or reallocated, in the case of realloc). After the call, the freed block is available for allocation. The seg argument specifies the based heap containing the memory block to be freed by the _bfree function. Attempting to free an invalid pointer may affect subsequent allocation and cause errors. An invalid pointer is one not allocated with the appropriate call.

Blocks allocated with calloc, malloc, and realloc should be freed with free. Blocks allocated with _bcalloc, _bmalloc, and _brealloc should be freed with _bfree. Blocks allocated with _fcalloc, _fmalloc, and _frealloc should be freed with _ffree. Blocks allocated with _ncalloc, _nmalloc, and _nrealloc should be freed with _nfree. A NULL pointer argument is ignored.

In large data models (compact-, large-, and huge-model programs), free maps to _ffree. In small data models (tiny-, small-, and medium-model programs), free maps to _nfree. The various free functions deallocate a memory block in the segments shown in the list following:

free    Depends on data model of program

_bfree    Based heap specified by seg value

_ffree    Far heap (outside default data segment)

_nfree    Near heap (inside default data segment)

Return Value

None.

See Also

»calloc functions,« »malloc functions,« »realloc functions«

Compatibility

free:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bfree, _ffree, _nfree:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »malloc.«


Description: _freect
  _freect

#include <malloc.h>

unsigned int _freect( size_t size );

size    Item size in bytes

Remarks

The _freect function tells you how much memory is available for dynamic memory allocation in the near heap. It does so by returning the approximate number of times your program can call _nmalloc (or malloc in small data models) to allocate an item size bytes long in the near heap (default data segment).

Return Value

The _freect function returns the number of calls as an unsigned integer.

See Also

»calloc functions,« »_expand functions,« »malloc functions,« »_memavl,« »_msize functions,« »realloc functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * FREECT.C: This program determines how much free
 * space is available for integers in the default
 * data segment. Then it allocates space for 1000
 * integers and checks the space again, using _freect.
 */

#include <malloc.h>
#include <stdio.h>

void main( void )
{
   int i;

   /* First report on the free space: */
   printf( "Integers (approximate) available on heap: %u\n\n",
      _freect( sizeof(int) ) );

   /* Allocate space for 1000 integers:\n */
   for( i = 0;   i < 1000;   ++i )
      malloc( sizeof( int ) );

   /* Report again on the free space: */
   printf( "After allocating space for 1000 integers:\n" );
   printf( "Integers (approximate) available on heap: %u\n\n",
      _freect( sizeof(int) ) );
}

Output

Integers (approximate) available on heap: 15520

After allocating space for 1000 integers:
Integers (approximate) available on heap: 14391


Description: freopen
  freopen

#include <stdio.h>

FILE *freopen( const char *path, const char *mode, FILE *stream );

path    Path of new file

mode    Type of access permitted

stream    Pointer to FILE structure

Remarks

The freopen function closes the file currently associated with stream and reassigns stream to the file specified by path. The freopen function is typically used to redirect the pre-opened files stdin, stdout, and stderr to files specified by the user. The new file associated with stream is opened with mode, which is a character string specifying the type of access requested for the file, as follows:

"r"    Opens for reading. If the file does not exist or cannot be found, the freopen call fails.

"w"    Opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"    Opens for writing at the end of the file (appending); creates the file first if it does not exist.

"r+"    Opens for both reading and writing. (The file must exist.)

"w+"    Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

"a+"    Opens for reading and appending; creates the file first if it does not exist.

Use the "w" and "w+" types with care, as they can destroy existing files.

When a file is opened with the "a" or "a+" access type, all write operations take place at the end of the file. Although the file pointer can be repositioned using fseek or rewind, the file pointer is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten. When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for "update"). However, when you switch between reading and writing, there must be an intervening fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired. In addition to the values listed above, one of the following characters may be included in the mode string to specify the translation mode for new lines.

t    Open in text (translated) mode; carriage-return−linefeed (CR-LF) combinations are translated into single linefeed (LF) characters on input; LF characters are translated to CR-LF combinations on output. Also, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading, or writing and reading, the run-time library checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using the fseek and ftell functions to move within a file may cause fseek to behave improperly near the end of the file.

b    Open in binary (untranslated) mode; the above translations are suppressed.

If t or b is not given in the mode string, the translation mode is defined by the default mode variable _fmode.

For a discussion of text and binary modes, see »Input and Output.«

Return Value

The freopen function returns a pointer to the newly opened file. If an error occurs, the original file is closed and the function returns a NULL pointer value.

See Also

»fclose,« »_fcloseall,« »_fdopen,« »_fileno,« »fopen,« »_open,« »_setmode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

The t option is not part of the ANSI standard for freopen; it is a Microsoft extension that should not be used where ANSI portability is desired.

Example

/* FREOPEN.C: This program reassigns _stdaux to the file
 * named FREOPEN.OUT and writes a line to that file.
 */

#include <stdio.h>
#include <stdlib.h>

FILE *stream;

void main( void )
{
   /* Reassign "_stdaux" to "freopen.out": */
   stream = freopen( "freopen.out", "w", _stdaux );

   if( stream == NULL )
      fprintf( stdout, "error on freopen\n" );
   else
   {
      fprintf( stream, "This will go to the file 'freopen.out'\n" );
      fprintf( stdout, "successfully reassigned\n" );
      fclose( stream );
   }
   system( "type freopen.out" );
}

Output

This will go to the file 'freopen.out'
successfully reassigned


Description: frexp, frexpl
  frexp, frexpl

#include <math.h>

double frexp( double x, int *expptr );

long double frexpl( long double x, int *expptr );

x    Floating-point value

expptr     Pointer to stored integer exponent

Remarks

The frexp and frexpl functions break down the floating-point value (x) into a mantissa (m) and an exponent (n), such that the absolute value of m is greater than or equal to 0.5 and less than 1.0, and x equals m times (2 raised to the power of n). The integer exponent n is stored at the location pointed to by expptr. The frexpl function is the 80-bit counterpart and uses an 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

Return Value

These functions return the mantissa. If x is 0, the function returns 0 for both the mantissa and the exponent. There is no error return.

See Also

»ldexp functions,« »modf«

Compatibility

frexp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

frexpl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FREXP.C: This program calculates frexp( 16.4, &n )
 * then displays y and n.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x, y;
   int n;

   x = 16.4;
   y = frexp( x, &n );
   printf( "frexp( %f, &n ) = %f, n = %d\n", x, y, n );
}

Output

frexp( 16.400000, &n ) = 0.512500, n = 5


Description: fscanf, fwscanf
  fscanf, fwscanf

#include <stdio.h>    For fscanf

#include <wchar.h>    For fwscanf use either WCHAR.H (for ANSI compatibility) or STDIO.H

int fscanf( FILE *stream, const char *format [, argument ]... );

int fwscanf( FILE *stream, const wchar_t *format [, argument ]... );

stream    Pointer to FILE structure

format     Format-control string

argument    Optional arguments

Remarks

The fscanf function reads data from the current position of stream into the locations given by argument (if any). Each argument must be a pointer to a variable of a type that corresponds to a type specifier in format. The format controls the interpretation of the input fields and has the same form and function as the format argument for the scanf function; see »scanf« for a description of format. If copying takes place between strings that overlap, the behavior is undefined.

The fwscanf function is a wide-character version of fscanf; the format argument to fwscanf is a wide-character string. The fwscanf and fscanf functions behave identically otherwise.

Return Value

Each of the fscanf and fwscanf functions returns the number of fields successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. In the case of an error or if the end of the file stream is reached before the first conversion, the return value is EOF for fscanf or WEOF for fwscanf.

See Also

»_cscanf,« »fprintf,« »scanf,« »sscanf,« »swscanf,« »wscanf«

Compatibility

fscanf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

fwscanf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FSCANF.C: This program writes formatted
 * data to a file. It then uses fscanf to
 * read the various data back from the file.
 */

#include <stdio.h>

FILE *stream;

void main( void )
{
   long l;
   float fp;
   char s[81];
   char c;

   stream = fopen( "fscanf.out", "w+" );
   if( stream == NULL )
      printf( "The file fscanf.out was not opened\n" );
   else
   {
      fprintf( stream, "%s %ld %f%c", "a-string",
               65000, 3.14159, 'x' );

      /* Set pointer to beginning of file: */
      fseek( stream, 0L, SEEK_SET );

      /* Read data back from file: */
      fscanf( stream, "%s", s );
      fscanf( stream, "%ld", &l );
      fscanf( stream, "%f", &fp );
      fscanf( stream, "%c", &c );

      /* Output data read: */
      printf( "%s\n", s );
      printf( "%ld\n", l );
      printf( "%f\n", fp );
      printf( "%c\n", c );

      fclose( stream );
   }
}

Output

a-string
65000
3.141590
x


Description: fseek
  fseek

#include <stdio.h>

int fseek( FILE *stream, long offset, int origin );

stream    Pointer to FILE structure

offset    Number of bytes from origin

origin    Initial position

Remarks

The fseek function moves the file pointer (if any) associated with stream to a new location that is offset bytes from origin. The next operation on the stream takes place at the new location. On a stream open for update, the next operation can be either a read or a write. The argument origin must be one of the following constants defined in STDIO.H:

SEEK_CUR    Current position of file pointer

SEEK_END    End of file

SEEK_SET    Beginning of file

The fseek function can be used to reposition the pointer anywhere in a file. The pointer can also be positioned beyond the end of the file. An attempt to position the pointer before the beginning of the file causes an error only if you explicitly link with LSEEKCHK.OBJ. The fseek function clears the end-of-file indicator and negates the effect of any prior ungetc calls against stream.

When a file is opened for appending data, the current file position is determined by the last I/O operation, not by where the next write would occur. If no I/O operation has yet occurred on a file opened for appending, the file position is the start of the file.

For streams opened in text mode, fseek has limited use because carriage-return − linefeed translations can cause fseek to produce unexpected results. The only fseek operations guaranteed to work on streams opened in text mode are seeking with an offset of 0 relative to any of the origin values and seeking from the beginning of the file with an offset value returned from a call to ftell.

Return Value

If successful, fseek returns 0. Otherwise, it returns a nonzero value. On devices incapable of seeking, the return value is undefined.

See Also

»ftell,« »_lseek,« »rewind«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FSEEK.C: This program opens the file FSEEK.OUT and
 * moves the pointer to the file's beginning.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char line[81];
   int  result;

   stream = fopen( "fseek.out", "w+" );
   if( stream == NULL )
      printf( "The file fseek.out was not opened\n" );
   else
   {
      fprintf( stream, "The fseek begins here: "
                       "This is the file 'fseek.out'.\n" );
      result = fseek( stream, 23L, SEEK_SET);
      if( result )
         perror( "Fseek failed" );
      else
      {
         printf( "File pointer is set to middle of first line.\n" );
         fgets( line, 80, stream );
         printf( "%s", line );
      }
      fclose( stream );
  }
}

Output

File pointer is set to middle of first line.
This is the file 'fseek.out'.


Description: fsetpos
  fsetpos

#include <stdio.h>

int fsetpos( FILE *stream, const fpos_t *pos );

stream    Target stream

pos    Position-indicator storage

Remarks

The fsetpos function sets the file-position indicator for stream to the value of pos, which is obtained in a prior call to fgetpos against stream. The function clears the end-of-file indicator and undoes any effects of the ungetc function on stream. After calling fsetpos, the next operation on stream may be either input or output.

Return Value

If successful, the fsetpos function returns 0. On failure, the function returns a nonzero value and sets errno to one of the following manifest constants (defined in ERRNO.H): EBADF, which means the object that stream points to is not a valid file handle, or the file is not accessible, or EINVAL, which means an invalid stream value was passed.

See Also

»fgetpos«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »fgetpos.«


Description: _fsopen
  _fsopen

#include <stdio.h>

#include <share.h>    shflag constants

FILE *_fsopen( const char *filename, const char *mode, int shflag );

filename    Name of file to open

mode    Type of access permitted

shflag    Type of sharing allowed

Remarks

The _fsopen function opens the file specified by filename as a stream and prepares the file for subsequent shared reading or writing, as defined by the mode and shflag arguments. The character string mode specifies the type of access requested for the file, as follows:

"r"    Opens for reading. If the file does not exist or cannot be found, the _fsopen call will fail.

"w"    opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"    Opens for writing at the end of the file (appending); creates the file first if it does not exist.

"r+"    Opens for both reading and writing. (The file must exist.)

"w+"    Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

"a+"    Opens for reading and appending; creates the file first if it does not exist.

Use the "w" and "w+" types with care, as they can destroy existing files.

When a file is opened with the "a" or "a+" access type, all write operations occur at the end of the file. Although the file pointer can be repositioned using fseek or rewind, the file pointer is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten. When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for "update"). However, when switching between reading and writing, there must be an intervening fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired. In addition to the values listed above, one of the following characters can be included in mode to specify the translation mode for new lines:

t    Opens a file in text (translated) mode. In this mode, carriage-return−linefeed (CR-LF) combinations are translated into single linefeeds (LF) on input and LF characters are translated to CR-LF combinations on output. Also, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading or reading/writing, _fsopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using the fseek and ftell functions to move within a file that ends with a CTRL+Z may cause fseek to behave improperly near the end of the file.

b    Opens a file in binary (untranslated) mode; the above translations are suppressed.

If t or b is not given in mode, the translation mode is defined by the default-mode variable _fmode. If t or b is prefixed to the argument, the function will fail and will return NULL. For a discussion of text and binary modes, see »Input and Output.«

The argument shflag is a constant expression consisting of one of the following manifest constants, defined in SHARE.H. If SHARE.COM (or SHARE.EXE for some versions of MS-DOS) is not installed, MS-DOS ignores the sharing mode. (See your system documentation for detailed information about sharing modes.)

_SH_COMPAT    Sets compatibility mode

_SH_DENYNO    Permits read and write access

_SH_DENYRD    Denies read access to file

_SH_DENYRW    Denies read and write access to file

_SH_DENYWR    Denies write access to file

The _fsopen function should be used only under MS-DOS versions 3.0 and later. Under earlier versions of MS-DOS, the shflag argument is ignored.

Return Value

The _fsopen function returns a pointer to the stream. A NULL pointer value indicates an error.

See Also

»fclose,« »_fcloseall,« »_fdopen,« »ferror,« »_fileno,« »fopen,« »freopen,« »_open,« »_setmode,« »_sopen«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FSOPEN.C:
 */

#include <stdio.h>
#include <stdlib.h>
#include <share.h>

void main( void )
{
   FILE *stream;

   /* Open output file for writing. Using _fsopen allows us to
    * ensure that no one else writes to the file while we are
    * writing to it.
    */
   if( (stream = _fsopen( "outfile", "wt", _SH_DENYWR )) != NULL )
   {
      fprintf( stream, "No one else in the network can write "
                       "to this file until we are done.\n" );
      fclose( stream );
   }
   /* Now others can write to the file while we read it. */
   system( "type outfile" );
}

Output

No one else in the network can write to this file until we are done.


Description: _fstat
  _fstat

#include <sys\types.h>

#include <sys\stat.h>

int _fstat( int handle, struct _stat *buffer );

handle    Handle of open file

buffer    Pointer to structure to store results

Remarks

The _fstat function obtains information about the open file associated with handle and stores it in the structure pointed to by buffer. The structure, whose type _stat is defined in SYS\STAT.H, contains the following fields with the listed values:

st_atime    Time of last access of file.

st_ctime    Time of creation of file.

st_dev    Either handle in the case of a device, or the drive number of the disk containing the file if the drive number is available (MS-DOS only); otherwise 0.

st_mode    Bit mask for file-mode information. The _S_IFCHR bit is set if handle refers to a device. The _S_IFREG bit is set if handle refers to an ordinary file. The read/write bits are set according to the file's permission mode. (_S_IFCHR and other constants are defined in SYS\STAT.H.)

st_mtime    Time of last modification of file.

st_nlink    Always 1.

st_rdev    Either handle in the case of a device, or the drive number of the disk containing the file if the drive number is available (MS-DOS only); otherwise 0.

st_size    Size of the file in bytes.

In the File Allocation Table (FAT) file system supported by MS-DOS, the creation and last access times of a file are not kept separately. Therefore, st_atime, st_ctime, and st_mtime are always the same. These fields have different values under UNIX. Note that if handle refers to a device, the size and time fields in the _stat structure are not meaningful. Also, because STAT.H uses the _dev_t type, which is defined in TYPES.H, you must include TYPES.H before STAT.H in your code.

Return Value

The _fstat function returns the value 0 if the file-status information is obtained. A return value of −1 indicates an error; in this case, errno is set to EBADF, indicating an invalid file handle.

See Also

»_access,« »_chmod,« »_filelength,« »_stat«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _fstat for compatibility with ANSI naming conventions of non-ANSI functions. Use fstat and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* FSTAT.C: This program uses _fstat to report
 * the size of a file named FSTAT.OUT.
 */

#include <io.h>
#include <fcntl.h>
#include <time.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main( void )
{
   struct _stat buf;
   int fh, result;
   char buffer[] = "A line to output";

   if( (fh = _open( "f_stat.out", _O_CREAT | _O_WRONLY |
                                  _O_TRUNC )) ==  -1 )
      exit( 1 );
   _write( fh, buffer, strlen( buffer ) );

   /* Get data associated with "fh": */
   result = _fstat( fh, &buf );

   /* Check if statistics are valid: */
   if( result != 0 )
      printf( "Bad file handle\n" );
   else
   {
      printf( "File size     : %ld\n", buf.st_size );
      printf( "Drive number  : %d\n", buf.st_dev );
      printf( "Time modified : %s", ctime( &buf.st_atime ) );
   }
   _close( fh );
}

Output

File size     : 16
Drive number  : 0
Time modified : Mon Mar 22 17:53:38 1993


Description: ftell
  ftell

#include <stdio.h>

long ftell( FILE *stream );

stream     Target FILE structure

Remarks

The ftell function gets the current position of the file pointer (if any) associated with stream. The position is expressed as an offset relative to the beginning of the stream.

Note that when a file is opened for appending data, the current file position is determined by the last I/O operation, not by where the next write would occur. For example, if a file is opened for an append and the last operation was a read, the file position is the point where the next read operation would start, not where the next write would start. (When a file is opened for appending, the file position is moved to end-of-file before any write operation.) If no I/O operation has yet occurred on a file opened for appending, the file position is the beginning of the file.

Return Value

The ftell function returns the current file position. The value returned by ftell may not reflect the physical byte offset for streams opened in text mode, because text mode causes carriage-return−linefeed translation. Use ftell in conjunction with the fseek function to return to file locations correctly. On error, the function returns −1L and errno is set to one of two constants, defined in ERRNO.H. The EBADF constant means the stream argument is not a valid file-handle value or does not refer to an open file. The EINVAL constant means an invalid stream argument was passed to the function. On devices incapable of seeking (such as terminals and printers), or when stream does not refer to an open file, the return value is undefined.

See Also

»fgetpos,« »fseek,« »_lseek,« »_tell«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FTELL.C: This program opens a file named FTELL.C
 * for reading and tries to read 100 characters. It
 * then uses ftell to determine the position of the
 * file pointer and displays this position.
 */

#include <stdio.h>

FILE *stream;

void main( void )
{
   long position;
   char list[100];
   if( (stream = fopen( "ftell.c", "rb" )) != NULL )
   {
      /* Move the pointer by reading data: */
      fread( list, sizeof( char ), 100, stream );
      /* Get position after read: */
      position = ftell( stream );
      printf( "Position after trying to read 100 bytes: %ld\n",
              position );
      fclose( stream );
   }
}

Output

Position after trying to read 100 bytes: 100


Description: _ftime
  _ftime

#include <sys\types.h>

#include <sys\timeb.h>

void _ftime( struct _timeb *timeptr );

timeptr    Pointer to structure defined in SYS\TIMEB.H

Remarks

The _ftime function gets the current time and stores it in the structure pointed to by timeptr. The _timeb structure is defined in SYS\TIMEB.H. It contains four fields, following, which have the listed values:

dstflag    Nonzero if daylight saving time is currently in effect for the local time zone. (See the reference page on »_tzset« for an explanation of how daylight saving time is determined.)

millitm    Fraction of a second in milliseconds. The last digit is always 0 because millitm is incremented to the nearest one-hundredth of a second.

time    Time in seconds since midnight (00:00:00), January 1, 1970, Universal coordinated time (UCT).

timezone    Difference in minutes, moving westward, between Universal coordinated time and local time. The value of timezone is set from the value of the global variable _timezone (see »_tzset«).

Return Value

The _ftime function gives values to the fields in the structure pointed to by timeptr. It does not return a value.

See Also

»asctime,« »ctime,« »gmtime,« »localtime,« »time,« »_tzset«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FTIME.C: This program uses _ftime to obtain the current
 * time and then stores this time in timebuffer.
 */

#include <stdio.h>
#include <sys\timeb.h>
#include <time.h>

void main( void )
{
   struct _timeb timebuffer;
   char *timeline;

   _ftime( &timebuffer );
   timeline = ctime( & ( timebuffer.time ) );

   printf( "The time is %.19s.%hu %s", timeline, timebuffer.millitm, &timeline[20] );
}

Output

The time is Mon Mar 22 17:55:22.585 1993


Description: _fullpath
  _fullpath

#include <stdlib.h>

char *_fullpath( char *buffer, const char *pathname, size_t maxlen );

buffer    Full path buffer

path    Relative pathname

maxlen    Length of the buffer pointed to by buffer

Remarks

The _fullpath routine converts the partial path stored in path to a fully qualified path that is stored in buffer. Unlike _makepath, the _fullpath routine can be used with .\ and ..\ in the path. If the length of the fully qualified path is greater than the value of maxlen, then NULL is returned; otherwise, the address of buffer is returned. If the buffer is NULL, _fullpath will allocate a buffer of _MAX_PATH size using malloc and the maxlen argument is ignored. It is the caller's responsibility to deallocate this buffer (using free) as appropriate. If the path argument specifies a disk drive, the current directory of this drive is combined with the path. If the path argument specifies a disk drive, the current directory of this drive is combined with the path. If the drive is not valid, _fullpath returns NULL.

Return Value

The _fullpath function returns a pointer to the buffer containing the absolute path (buffer). If there is an error, _fullpath returns NULL.

See Also

»_getcwd,« »_getdcwd,« »_makepath,« »_splitpath«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FULLPATH.C: This program demonstrates how _fullpath
 * creates a full path from a partial path.
 */

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <direct.h>

char full[_MAX_PATH], part[_MAX_PATH];

void main( void )
{
   while( 1 )
   {
      printf( "Enter partial path or ENTER to quit: " );
      gets( part );
      if( part[0] == 0 )
         break;

      if( _fullpath( full, part, _MAX_PATH ) != NULL )
         printf( "Full path is: %s\n", full );
      else
         printf( "Invalid path\n" );
   }
}

Output

Enter partial path or ENTER to quit: ..
Full path is: C:\msvcnt\c32
Enter partial path or ENTER to quit: c:\include
Full path is: c:\include
Enter partial path or ENTER to quit: m:
Full path is: m:\
Enter partial path or ENTER to quit: generic
Full path is: C:\msvcnt\c32\samples\generic
Enter partial path or ENTER to quit:


Description: _futime
  _futime

#include <sys\utime.h>

int _futime( int handle, struct _utimbuf *filetime );

handle    Handle to open file

filetime    Pointer to structure containing new modification date

Remarks

The _futime routine sets the modification date and the access time on the open file associated with handle. It is identical to the _utime function, except that its argument is the handle to an open file, rather than the name of a file or a path to a file. The _utimbuf structure contains fields for the new modification date and access time. Both fields must contain valid values.

Return Value

The _futime function returns 0 if successful. A return value of −1 indicates an error; in this case, errno is set to EBADF, indicating an invalid file handle.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* FUTIME.C: This program uses _futime to set the
 * file-modification time to the current time.
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <sys\utime.h>

void main( void )
{

   int hFile;

   /* Show file time before and after. */
   system( "dir futime.c" );

   hFile = _open("futime.c", _O_RDWR);

   if( _futime( hFile, NULL ) == -1 )
      perror( "_futime failed\n" );
   else
      printf( "File time modified\n" );
   system( "dir futime.c" );
}

Output

 Volume in drive C is CDRIVE
 Volume Serial Number is 1966-6F27

 Directory of C:\code

FUTIME   C                  606 04-16-93  05:04PM
               1 File(s)        606 bytes
                           23822336 bytes free
 Volume in drive C is CDRIVE
 Volume Serial Number is 1966-6F27

 Directory of C:\code

FUTIME   C                  606 04-17-93  01:04AM
               1 File(s)        606 bytes
                           23822336 bytes free
File time modified


Description: _fwopen
  _fwopen

#include <stdio.h>

FILE * _fwopen( struct _wopeninfo *wopeninfo, struct _wsizeinfo *wsizeinfo, const char *mode );

wopeninfo    Pointer to a _wopeninfo structure

wsizeinfo    Pointer to a _wsizeinfo structure

mode    Type of access permitted

Remarks

The _fwopen function is a high-level call that opens a new QuickWin window, returning a file-stream pointer. This routine is used only in QuickWin programs; it is not part of the Windows API. For details about QuickWin, see Programming Techniques. The _wopeninfo and _wsizeinfo structures, declared in STDIO.H, are used to pass window initialization information, including the window's initial size and position on the screen. You can pass NULL for these arguments to accept QuickWin defaults or declare variables of these two structure types and fill in their fields. If you declare _wopeninfo and _wsizeinfo variables, assign the _QWINVER macro to the _version field. _QWINVER is the current QuickWin version, defined in STDIO.H.

For the _wopeninfo variable, assign a null-terminated string to the _title field containing the desired window title. You can also optionally set the size of the window's screen buffer in the _wbufsize field. The default is 2,048 bytes, but you can pass some other number or the value _WINBUFINF. This causes the buffer to be reallocated continually so that all window output is retained for scrolling. For the _wsizeinfo variable, assign one of the following values to the _type field:

_WINSIZEMIN    Minimize the window

_WINSIZEMAX    Maximize the window

_WINSIZECHAR    Use character coordinates for the window size

If the type is _WINSIZECHAR, you must supply the _x, _y, _h, and _w values in the remainder of the structure. They specify the upper-left corner and the height and width of the window (in characters).

The mode argument is a pointer to the stream I/O mode. The _fwopen function accepts the same mode values as the STDIO.H fopen function:

"r"    Opens for reading

"w"    Opens for writing

"r+"    Opens for both reading and writing

"w+"    Opens for both reading and writing

In addition to the values listed above, one of the following characters can be included in mode to specify the translation mode for newline characters. To open the file in text (translated) mode, use t. Top open in binary (untranslated) mode, use b. If t or b is not given in mode, the translation mode is defined by the default-mode variable _fmode. If t or b is prefixed to the argument, the function fails and returns NULL. For a discussion of text and binary modes, see »Input and Output.«

If _fwopen is successful, the returned stream can be passed to standard STDIO.H functions such as fread, fwrite, and fprintf. If you write to a stream and then read from it, or if you read from a stream and then write to it, call the STDIO.H rewind function between the I/O calls. To close an open window stream, call the STDIO.H function fclose. If you have opened a window with _fwopen, you can use the _fileno macro to obtain a file handle, which you can then pass to other QuickWin calls, such as _wsetscreenbuf or _wsetsize.

Return Value

If successful, the _fwopen function returns a stream pointer (FILE *) to the new window. A return value of NULL indicates an error.

See Also

»fclose,« »_fileno,« »_wabout,« »_wclose,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * FWOPEN.C - Demonstrate opening QuickWin windows
 * with _fwopen
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define OPENFLAGS "w"              /* Access permission */

void main()
{
    struct _wopeninfo wininfo;     /* Open information */
    char wintitle[32]="QuickWin "; /* Title for window */
    FILE *wp;                      /* FILE ptr to window */
    int nRes;                      /* I/O result */

    /* Set up window info structure for _fwopen */
    wininfo._version = _QWINVER;
    wininfo._title = wintitle;
    wininfo._wbufsize = _WINBUFDEF;

    /* Check current 'exit behavior' setting */
    /* Test should be true, since default is _WINEXITPERSIST */
    /* So set new behavior to prompt user */
    if( _wgetexit() == _WINEXITPERSIST )
       _wsetexit( _WINEXITPROMPT );

    /* Create a new window */
    /* NULL second argument accepts default size/position */
    wp = _fwopen( &wininfo, NULL, OPENFLAGS );
    if( wp == NULL )
    {
        printf( "***ERROR: _fwopen\n" );
        exit( -1 );
    }

    /* Write in the window */
    nRes = fprintf( wp, "Hello, QuickWin!\n" );

    /* Close the window */
    nRes = fclose( wp );

    /* On exiting anywhere, user is prompted
     * to keep window on screen or not
     */
    exit( 0 );

}


Description: fwrite
  fwrite

#include <stdio.h>

size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

buffer    Pointer to data to be written

size    Item size in bytes

count    Maximum number of items to be written

stream    Pointer to FILE structure

Remarks

The fwrite function writes up to count items, of length size each, from buffer to the output stream. The file pointer associated with stream (if there is one) is incremented by the number of bytes actually written. If stream is opened in text mode, each carriage return is replaced with a carriage-return−linefeed pair. The replacement has no effect on the return value.

Return Value

The fwrite function returns the number of full items actually written, which may be less than count if an error occurs. Also, if an error occurs, the file-position indicator cannot be determined.

See Also

»fread,« »_write«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »fread.«


Description: _gcvt
  _gcvt

#include <stdlib.h>

char *_gcvt( double value, int digits, char *buffer );

value    Value to be converted

digits    Number of significant digits stored

buffer    Storage location for result

Remarks

The _gcvt function converts a floating-point value to a character string (which includes a decimal point and a possible sign byte) and stores the string in buffer. The buffer should be large enough to accommodate the converted value plus a terminating null character ('\0'), which is appended automatically. If a buffer size of significant digits + 1 is used, the function will overwrite the end of the buffer. This is because the converted string includes a decimal point and can contain sign and exponent information. There is no provision for overflow. The _gcvt function attempts to produce digits significant digits in decimal format. If this is not possible, it produces digits significant digits in exponential format. Trailing zeros may be suppressed in the conversion.

Return Value

The _gcvt function returns a pointer to the string of digits. There is no error return.

See Also

»atof,« »atoi,« »atol,« »_ecvt,« »_fcvt«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _gcvt for compatibility with ANSI naming conventions of non-ANSI functions. Use gcvt and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* _GCVT.C: This program converts -3.1415e5
 * to its string representation.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char buffer[50];
   double source = -3.1415e5;

   _gcvt( source, 7, buffer );
   printf( "source: %f  buffer: '%s'\n", source, buffer );
   _gcvt( source, 7, buffer );
   printf( "source: %e  buffer: '%s'\n", source, buffer );
}

Output

source: -314150.000000  buffer: '-314150.'
source: -3.141500e+005  buffer: '-314150.'


Description: _getactivepage
  _getactivepage

#include <graph.h>

short __far _getactivepage( void );

Remarks

The _getactivepage function returns the number of the current active page. This function works differently in QuickWin applications.

Return Value

The function returns the number of the current active video page. All hardware combinations support at least one page (page number 0).

See Also

»_getvideoconfig,« »_getvisualpage,« »_grstatus,« »_setactivepage,« »_setvideomode,« »_setvisualpage«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * PAGE.C illustrates video page functions including:
 *  _getactivepage  _getvisualpage
 *  _setactivepage  _setvisualpage
 */

#include <conio.h>
#include <graph.h>
#include <stdlib.h>

void main( void )
{
   short  oldvpage, oldapage, page;
   struct _videoconfig vc;

   _getvideoconfig( &vc );
   if( vc.numvideopages < 4 )
      exit( 1 );              /* Fail for or monochrome. */
   oldapage  = _getactivepage();
   oldvpage  = _getvisualpage();
   _displaycursor( _GCURSOROFF );

   /* Draw arrows in different place on each page. */
   for( page = 0; page < vc.numvideopages; page++ )
   {
      _setactivepage( page );
      _setvisualpage( page );
      _clearscreen( _GCLEARSCREEN );
      _settextposition( 12, 10 * page );
      _outtext( ">>>>>>>>>>>" );
   }
   while( !_kbhit() )
      /* Cycle through pages 1 to 3 to show moving image. */
      for( page = 0; page < vc.numvideopages; page++ )
         _setvisualpage( page );
   _getch();
   /* Restore original page (normally 0) to restore screen. */
   _setactivepage( oldapage );
   _setvisualpage( oldvpage );
   _displaycursor( _GCURSORON );
}


Description: _getarcinfo
  _getarcinfo

#include <graph.h>

short __far _getarcinfo( struct _xycoord __far *start, struct _xycoord __far *end, struct _xycoord __far *fillpoint );

start    Starting point of arc

end    Ending point of arc

fillpoint    Point at which pie fill will begin

Remarks

The _getarcinfo function determines the endpoints in viewport coordinates of the most recently drawn arc or pie. If successful, the _getarcinfo function updates the start and end _xycoord structures to contain the endpoints (in viewport coordinates) of the arc drawn by the most recent call to one of the _arc or _pie functions. In addition, fillpoint specifies a point from which a pie can be filled. This is useful for filling a pie in a color different from the border color. After a call to _getarcinfo, change colors using the _setcolor function. Use the color, along with the coordinates in fillpoint, as arguments for the _floodfill function.

Return Value

The _getarcinfo function returns a nonzero value if successful. If neither the _arc nor the _pie function has been successfully called since the last time the screen was cleared or a new graphics mode or viewport was selected, the _getarcinfo function returns 0.

See Also

»_arc functions,« »_floodfill,« »_getvideoconfig,« »_grstatus,« »_pie functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_arc.«


Description: _getbkcolor
  _getbkcolor

#include <graph.h>

long __far _getbkcolor( void );

Remarks

The _getbkcolor function returns the current background color. The default is 0.

In a color text mode such as _TEXTC80, _setbkcolor accepts, and _getbkcolor returns, a color index. For example, _setbkcolor(2L) sets the background color to color index 2. The actual color displayed depends on the palette mapping for color index 2. The default for color index 2 is green in a color text mode.

In a color graphics mode such as _ERESCOLOR, _setbkcolor accepts, and _getbkcolor returns, a color value (as used in _remappalette). The value for the simplest background colors is given by the manifest constants defined in the GRAPH.H include file. For example, _setbkcolor( _GREEN) sets the background color in a graphics mode to green. These manifest constants are provided as a convenience in defining and manipulating the most common colors. In general, the actual range of colors is much greater.

In most cases, whenever a color argument is long, it refers to a color value, and whenever it is short, it refers to a color index. The two exceptions are _setbkcolor and _getbkcolor, described above. For a more complete discussion of colors, see the reference page for »_remappalette.«

Return Value

The function returns the current background color. There is no error return.

See Also

»_remappalette,« »_setbkcolor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outtext.«


Description: getc, getchar
  getc, getchar

#include <stdio.h>

int getc( FILE *stream );

int getchar( void );

stream    Current stream

Remarks

The getc routine reads a single character from the stream position and increments the associated file pointer (if there is one) to point to the next character. The getchar routine is identical to getc(stdin). The getc and getchar routines are similar to »fgetc« and »_fgetchar,« respectively, but are implemented both as macros and functions.

Return Value

Both getc and getchar return the character read. A return value of EOF indicates an error or end-of-file condition. Use ferror or feof to determine whether an error or end-of-file occurred.

See Also

»fgetc,« »_fgetchar,« »_getch,« »_getche,« »putc,« »putchar,« »ungetc«

Compatibility

getc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

getchar:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* GETC.C: This program uses getchar to read a single line
 * of input from stdin, places this input in buffer, then
 * terminates the string before printing it to the screen.
 */

#include <stdio.h>

void main( void )
{
   char buffer[81];
   int i, ch;

   printf( "Enter a line: " );

   /* Read in single line from "stdin": */
   for( i = 0; (i < 80) &&  ((ch = getchar()) != EOF)
                        && (ch != '\n'); i++ )
      buffer[i] = (char)ch;

   /* Terminate string with null character: */
   buffer[i] = '\0';
   printf( "%s\n", buffer );
}

Output

Enter a line: This is a test
This is a test


Description: _getch, _getche
  _getch, _getche

#include <conio.h>

int _getch( void );

int _getche( void );

Remarks

The _getch function reads a single character from the console without echoing. The _getche function reads a single character from the console and echoes the character read. Neither function can be used to read CTRL+C. Neither function can be used with QuickWin programs. When reading a function key or cursor-moving key, the _getch and _getche functions must be called twice; the first call returns 0 or 0xE0, and the second call returns the actual key code.

Return Value

Both the _getch and _getche functions return the character read. There is no error return.

See Also

»_cgets,« »getchar,« »_ungetch«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* GETCH.C: This program reads characters from
 * the keyboard until it receives a 'Y' or 'y'.
 */

#include <conio.h>
#include <ctype.h>

void main( void )
{
   int ch;

   _cputs( "Type 'Y' when finished typing keys: " );
   do
   {
      ch = _getch();
      ch = toupper( ch );
   } while( ch != 'Y' );

   _putch( ch );
   _putch( '\r' );    /* Carriage return */
   _putch( '\n' );    /* Line feed       */
}

Output

Type 'Y' when finished typing keys: Y


Description: _getcolor
  _getcolor

#include <graph.h>

short __far _getcolor( void );

Remarks

The _getcolor function returns the current graphics color index. The default is the highest legal index in the current palette.

Return Value

The _getcolor function returns the current color index.

See Also

»_setcolor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outtext.«


Description: _getcurrentposition Functions
  _getcurrentposition Functions

#include <graph.h>

struct _xycoord __far _getcurrentposition( void );

struct _wxycoord __far _getcurrentposition_w( void );

Remarks

The _getcurrentposition functions return the coordinates of the current graphics output position. The _getcurrentposition function returns the position as an _xycoord structure, defined in GRAPH.H. The _xycoord structure contains short xcoord, the x coordinate, and short ycoord, the y coordinate.

The _getcurrentposition_w function returns the position as a _wxycoord structure, defined in GRAPH.H. The _wxycoord structure contains double wx, the window x coordinate, and double wy, the window y coordinate.

The current position can be changed by the _lineto, _moveto, and _outgtext functions. The default position, set by _setvideomode, _setvideomoderows, or _setviewport, is the center of the viewport. Only graphics output starts at the current position; these functions do not affect text output, which begins at the current text position. (See the reference page for »_settextposition« for more information.)

Return Value

The _getcurrentposition functions return the coordinates of the current graphics output position. There is no error return.

See Also

»_grstatus,« »_lineto functions,« »_moveto functions,« »_outgtext«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * GCURPOS.C: This program sets a random current location,
 * then gets that location with _getcurrentposition.
 */

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <graph.h>

char   buffer[255];

void main( void )
{
   struct _videoconfig vc;
   struct _xycoord position;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );
   _getvideoconfig( &vc );

   /* Move to random location and report that location. */
   _moveto( rand() % vc.numxpixels, rand() % vc.numypixels );
   position = _getcurrentposition();
   sprintf( buffer, "x = %d, y = %d", position.xcoord,
                                      position.ycoord );
   _settextposition( 1, 1 );
   _outtext( buffer );

   _getch();
   _setvideomode( _DEFAULTMODE );
}


Description: _getcwd
  _getcwd

#include <direct.h>

char *_getcwd( char *buffer, int maxlen );

buffer    Storage location for path

maxlen    Maximum length of path

Remarks

The _getcwd function gets the full path of the current working directory for the default drive and stores it at buffer. The integer argument maxlen specifies the maximum length for the path. An error occurs if the length of the path (including the terminating null character) exceeds maxlen. The buffer argument can be NULL; a buffer of at least size maxlen (more only if necessary) will automatically be allocated, using malloc, to store the path. This buffer can later be freed by calling free and passing it the _getcwd return value (a pointer to the allocated buffer).

Note that _getcwd returns a string that represents the path of the current working directory. If the current working directory is set to the root, the string will end with a backslash ( \ ). If the current working directory is set to a directory other than the root, the string will end with the name of the directory and not with a backslash.

Return Value

The _getcwd function returns a pointer to buffer. A NULL return value indicates an error, and errno is set either to ENOMEM, indicating there is insufficient memory to allocate maxlen bytes (when a NULL argument is given as buffer), or ERANGE, indicating the path is longer than maxlen characters.

See Also

»_chdir,« »_mkdir,« »_rmdir«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _getcwd for compatibility with ANSI naming conventions of non-ANSI functions. Use getcwd and link with OLDNAMES.LIB for UNIX compatibility.

Example

// GETCWD.C
/* This program places the name of the current directory in the
 * buffer array, then displays the name of the current directory
 * on the screen. Specifying a length of _MAX_PATH leaves room
 * for the longest legal path name.
 */

#include <direct.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char buffer[_MAX_PATH];

   /* Get the current working directory: */
   if( _getcwd( buffer, _MAX_PATH ) == NULL )
      perror( "_getcwd error" );
   else
      printf( "%s\n", buffer );
}

Output

C:\code


Description: _getdcwd
  _getdcwd

#include <direct.h>

char *_getdcwd( int drive, char *buffer, int maxlen );

drive    Disk drive

buffer    Storage location for path

maxlen    Maximum length of path

Remarks

The _getdcwd function gets the full path of the current working directory on the specified drive and stores it at buffer. The argument maxlen specifies the maximum length for the path. An error occurs if the length of the path (including the terminating null character) exceeds maxlen. The drive argument specifies the drive (0 = default drive, 1 = A, 2 = B, and so on). The buffer argument can be NULL; a buffer of at least size maxlen (more only if necessary) will automatically be allocated, using malloc, to store the path. This buffer can later be freed by calling free and passing it the _getdcwd return value (a pointer to the allocated buffer).

Note that _getdcwd returns a string that represents the path of the current working directory. If the current working directory is set to the root, the string will end with a backslash (\). If the current working directory is set to a directory other than the root, the string will end with the name of the directory and not with a backslash.

Return Value

The _getdcwd function returns buffer. A NULL return value indicates an error, and errno is set either to ENOMEM, indicating there is insufficient memory to allocate maxlen bytes (when a NULL argument is given as buffer), or ERANGE, indicating the path is longer than maxlen characters.

See Also

»_chdir,« »_getcwd,« »_getdrive,« »_mkdir,« »_rmdir«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getdrive.«


Description: _getdrive
  _getdrive

#include <direct.h>

int _getdrive( void );

Remarks

The _getdrive function returns the current (default) drive (1 = A, 2 = B, and so on).

Return Value

The return value is stated above. There is no error return.

See Also

»_chdrive,« »_dos_getdrive,« »_dos_setdrive,« »_getcwd,« »_getdcwd«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* GETDRIVE.C illustrates drive functions including:
 *      _getdrive       _chdrive        _getdcwd
 */

#include <stdio.h>
#include <conio.h>
#include <direct.h>
#include <stdlib.h>
#include <ctype.h>

void main( void )
{
   int ch, drive, curdrive;
   static char path[_MAX_PATH];

   /* Save current drive. */
   curdrive = _getdrive();

   printf( "Available drives are: \n" );

   /* If we can switch to the drive, it exists. */
   for( drive = 1; drive <= 26; drive++ )
      if( !_chdrive( drive ) )
         printf( "%c: ", drive + 'A' - 1 );

   while( 1 )
   {
      printf( "\nType drive letter to check or ESC to quit: " );
      ch = _getch();
      if( ch == 27 )
         break;
      if( isalpha( ch ) )
         _putch( ch );
      if( _getdcwd( toupper( ch ) - 'A' + 1, path, _MAX_PATH ) != NULL )
         printf( "\nCurrent directory on that drive is %s\n", path );
   }

   /* Restore original drive.*/
   _chdrive( curdrive );
   printf( "\n" );
}

Output

Available drives are:
A: B: C: L: M: O: U: V:
Type drive letter to check or ESC to quit: c
Current directory on that drive is C:\CODE

Type drive letter to check or ESC to quit: m
Current directory on that drive is M:\

Type drive letter to check or ESC to quit:


Description: getenv
  getenv

#include <stdlib.h>

char *getenv( const char *varname );

varname    Name of environment variable

Remarks

The getenv function searches the list of environment variables for an entry corresponding to varname. Environment variables define the environment in which a process executes. (For example, the LIB environment variable defines the default search path for libraries to be linked with a program.) Because the getenv function is case sensitive in MS-DOS, the varname variable should match the case of the environment variable. In Windows NT, the getenv function is not case sensitive. (For example, in Windows NT, LIB is the same as lib or Lib.)

The getenv function returns a pointer to an entry in the environment table. It is, however, only safe to retrieve the value of the environment variable using the returned pointer. To modify the value of an environment variable, use the _putenv function. The getenv and _putenv functions use the copy of the environment pointed to by the global variable »_environ« to access the environment. Programs that use the envp argument to main and the _putenv function may retrieve invalid information. The safest programming practice is to use getenv and _putenv.

The getenv function operates only on the data structures accessible to the run-time library and not on the environment "segment" created for the process by the operating system.

Return Value

The getenv function returns a pointer to the environment table entry containing the current string value of varname. The return value is NULL if the given variable is not currently defined.

See Also

»_putenv«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* GETENV.C: This program uses getenv to retrieve
 * the LIB environment variable and then uses
 * _putenv to change it to a new value.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char *libvar;

   /* Get the value of the LIB environment variable. */
   libvar = getenv( "LIB" );

   if( libvar != NULL )
      printf( "Original LIB variable is: %s\n", libvar );

   /* Attempt to change path. Note that this only affects the
    * environment variable of the current process. The command
    * processor's environment is not changed.
    */
   _putenv( "LIB=c:\\mylib;c:\\yourlib" );

   /* Get new value. */
   libvar = getenv( "LIB" );

   if( libvar != NULL )
      printf( "New LIB variable is: %s\n", libvar );
}

Output

Original LIB variable is: C:\MSVCNT\C32\LIB;C:\MSVCNT\MFC\LIB
New LIB variable is: c:\mylib;c:\yourlib


Description: _getfillmask
  _getfillmask

#include <graph.h>

unsigned char __far * __far _getfillmask( unsigned char __far *mask );

mask    Mask array

Remarks

Some graphics routines (_ellipse, _floodfill, _pie, _polygon, and _rectangle) can fill part or all of the screen with the current color. The fill mask controls the pattern used for filling. The _getfillmask function returns the current fill mask. The mask is an 8-by-8-bit array, in which each bit represents a pixel. If the bit is 1, the corresponding pixel is set to the current color; if the bit is 0, the pixel is left unchanged. The mask is repeated over the entire fill area. If no fill mask is set, or if mask is NULL, a solid (unpatterned) fill is performed using the current color.

Return Value

If no mask is set, the function returns NULL. Otherwise, it returns the current fill mask.

See Also

»_ellipse functions,« »_floodfill,« »_pie functions,« »_polygon functions,« »_rectangle functions,« »_setfillmask«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * GFILLMSK.C: This program illustrates
 * _getfillmask and _setfillmask
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

void ellipsemask( short x1, short y1, short x2, short y2,
   const unsigned char __far *newmask );

unsigned char mask1[8] =
   { 0x43, 0x23, 0x7c, 0xf7, 0x8a, 0x4d, 0x78,  0x39 };
unsigned char mask2[8] =
   { 0x18, 0xad, 0xc0, 0x79, 0xf6, 0xc4, 0xa8,  0x23 };
char oldmask[8];

void main( void )
{
   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   /* Set first fill mask and draw rectangle. */
   _setfillmask( mask1 );
   _rectangle( _GFILLINTERIOR, 20, 20, 100, 100 );
   _getch();

   /* Call routine that saves and restores mask. */
   ellipsemask( 60, 60, 150, 150, mask2 );
   _getch();

   /* Back to original mask. */
   _rectangle( _GFILLINTERIOR, 120, 120, 190, 190 );
   _getch();

   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}

/* Draw an ellipse with a specified fill mask. */
void ellipsemask( short x1, short y1, short x2, short y2,
   const unsigned char __far *newmask )
{
   unsigned char savemask[8];

   _getfillmask( savemask );                    /* Save mask        */
   _setfillmask( newmask );                     /* Set new mask     */
   _ellipse( _GFILLINTERIOR, x1, y1, x2, y2 );  /* Use new mask     */
   _setfillmask( savemask );                    /* Restore original */
}


Description: _getfontinfo
  _getfontinfo

#include <graph.h>

short __far _getfontinfo( struct _fontinfo __far *fontbuffer );

fontbuffer    Buffer to hold font information

Remarks

The _getfontinfo function gets the current font characteristics and stores them in a _fontinfo structure, defined in GRAPH.H. The _fontinfo structure contains the following elements:

int type    Specifies vector (1) or bitmapped (0) font

int ascent    Specifies pixel distance from top to baseline

int pixwidth    Specifies the character width in pixels; 0 indicates a proportional font

int pixheight    Specifies the character height in pixels

int avgwidth    Specifies the average character width in pixels

char filename [81]    Specifies the filename, including the path

char facename [32]    Specifies the font name

If you have used the _setfont function to load and scale a vector font, the _getfontinfo function may return unexpected values for the ascent, pixheight, and avgwidth elements. This is because _getfontinfo reads from the current font's .FON file, which _setfont does not update. The _getfontinfo function works differently in QuickWin applications.

Return Value

The _getfontinfo function returns a negative number if a font has not been registered or loaded.

See Also

»_getgtextextent,« »_outgtext,« »_registerfonts,« »_setfont,« »_setgtextvector,« »_unregisterfonts«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outgtext.«


Description: _getgtextextent
  _getgtextextent

#include <graph.h>

short __far _getgtextextent( const char __far *text );

text    Text to be analyzed

Remarks

The _getgtextextent function returns the width in pixels that would be required to print the text string using _outgtext with the current font. This function is particularly useful for determining the size of text that uses proportionally spaced fonts.

Return Value

The _getgtextextent function returns the width in pixels. It returns −1 if a font has not been registered.

See Also

»_getfontinfo,« »_outgtext,« »_registerfonts,« »_setfont,« »_unregisterfonts«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outgtext.«


Description: _getgtextvector
  _getgtextvector

#include <graph.h>

struct _xycoord __far _getgtextvector( void );

Remarks

The _getgtextvector function gets the current orientation for font text output. The current orientation is used in calls to the _outgtext function. The text-orientation vector, which determines the direction of font-text rotation on the screen, is returned in a structure of type _xycoord. The xcoord and ycoord members of the structure describe the vector. The text-rotation options are shown below:

(1,0)    Horizontal text (default)

(0,1)    Rotated 90 degrees counterclockwise

(−1,0)    Rotated 180 degrees

(0,−1)    Rotated 270 degrees counterclockwise

Return Value

The _getgtextvector function returns the current text-orientation vector in a structure of type _xycoord.

See Also

»_getgtextextent,« »_grstatus,« »_outgtext,« »_setfont,« »_setgtextvector«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _getimage Functions
  _getimage Functions

#include <graph.h>

void __far _getimage( short x1, short y1, short x2, short y2, char __huge *image );

void __far _getimage_w( double wx1, double wy1, double wx2, double wy2, char __huge *image );

void __far _getimage_wxy( struct_wxycoord __far *pwxy1, struct_wxycoord __far *pwxy2, char __huge *image );

x1, y1    Upper-left corner of bounding rectangle

x2, y2    Lower-right corner of bounding rectangle

wx1, wy1    Upper-left corner of bounding rectangle

wx2, wy2    Lower-right corner of bounding rectangle

pwxy1    Upper-left corner of bounding rectangle

pwxy2    Lower-right corner of bounding rectangle

image    Storage buffer for screen image

Remarks

The _getimage functions store the screen image defined by a specified bounding rectangle into the buffer pointed to by image. The _getimage function defines the bounding rectangle with the view coordinates (x1, y1) and (x2, y2). The _getimage_w function defines the bounding rectangle with the window coordinates (wx1, wy1) and (wx2, wy2). The _getimage_wxy function defines the bounding rectangle with the window-coordinate pairs pwxy1 and pwxy2. The buffer must be large enough to hold the image.

Return Value

None. Use _grstatus to check success.

See Also

»_grstatus,« »_imagesize functions,« »_putimage functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * GIMAGE.C: This example illustrates animation routines,
 *  including:   _imagesize     _getimage     _putimage
 */

#include <conio.h>
#include <stddef.h>
#include <stdlib.h>
#include <malloc.h>
#include <graph.h>

short action[5]  = { _GPSET, _GPRESET, _GXOR, _GOR, _GAND };
char *descrip[5] = { "PSET", "PRESET", "XOR", "OR", "AND" };

void exitfree( char __huge *buffer );

void main( void )
{
   char  __huge *buffer;   /* Far pointer (with _fmalloc) */
                           /*   could be used.            */
   long  imsize;
   short i, x, y = 30;
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   /* Measure the image to be drawn and allocate memory for it. */
   imsize = (size_t)_imagesize( -16, -16, +16, +16 );
   buffer = _halloc( imsize, sizeof( char ) );
   if ( buffer == (char __far *)NULL )
      exit( 1 );

   _setcolor( 3 );
   for ( i = 0; i < 5; i++ )
   {
      /* Draw ellipse at new position and get a copy of it. */
      x = 50; y += 40;
      _ellipse( _GFILLINTERIOR, x - 15, y - 15, x + 15, y + 15 );
      _getimage( x - 16, y - 16, x + 16, y + 16, buffer );
      if( _grstatus() ) exitfree( buffer );  /* Quit on error */

      /* Display action type and copy a row  */
      /*   of ellipses with that type.       */
      _settextposition( 1, 1 );
      _outtext( descrip[i] );
      while( x < 260 )
      {
         x += 5;
         _putimage( x - 16, y - 16, buffer, action[i] );
         if( _grstatus() < 0 )      /* Ignore warnings,  */
                                    /*   quit on errors. */
            exitfree( buffer );
      }
      _getch();
   }
   exitfree( buffer );
}

void exitfree( char __huge *buffer )
{
   _hfree( buffer );
   exit( !_setvideomode( _DEFAULTMODE ) );
}


Description: _getlinestyle
  _getlinestyle

#include <graph.h>

unsigned short __far _getlinestyle( void );

Remarks

Some graphics routines (_lineto, _polygon, and _rectangle) output straight lines to the screen. The type of line can be controlled with the current line-style mask. The _getlinestyle function returns the current line-style mask. The mask is a 16-bit array in which each bit represents a pixel in the line being drawn. If the bit is 1, the corresponding pixel is set to the color of the line (the current color). If the bit is 0, the corresponding pixel is left unchanged. The mask is repeated over the length of the line. The default mask is 0xFFFF (a solid line).

Return Value

If no mask has been set, _getlinestyle returns the default mask.

See Also

»_lineto functions,« »_polygon functions,« »_rectangle functions,« »_setlinestyle,« »_setwritemode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * GLINESTY.C: This program illustrates
 * _setlinestyle and _getlinestyle.
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

void zigzag( short x1, short y1, short size );

void main( void )
{
   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXCOLORMODE ) )
      exit( 1 );

   /* Set line style and draw rectangle. */
   _setlinestyle( 0x4d );
   _rectangle( _GBORDER, 10, 10, 60, 60 );
   _getch();

   /* Draw figure with function that     */
   /*   changes and restores line style. */
   zigzag( 100, 100, 90 );
   _getch();

   /* Original style reused. */
   _rectangle( _GBORDER, 190, 190, 130, 130 );
   _getch();

   _setvideomode( _DEFAULTMODE );
}

/* Draw box with changing line styles. Restore original style. */
void zigzag( short x1, short y1, short size )
{
   short x, y, oldcolor;
   unsigned short oldstyle;
   unsigned short style[16] = { 0x0001, 0x0003, 0x0007, 0x000f,
                                0x001f, 0x003f, 0x007f, 0x00ff,
                                0x01ff, 0x03ff, 0x07ff, 0x0fff,
                                0x1fff, 0x3fff, 0x7fff, 0xffff };

   oldcolor = _getcolor();
   oldstyle = _getlinestyle();  /* Save old line style.   */
   for( x = 3, y = 3; x < size; x += 3, y += 3 )
   {
      _setcolor( x % 16 );
      _setlinestyle( style[x % 16] ); /* Set and use new line styles */
      _rectangle( _GBORDER, x1 - x, y1 - y, x1 + x, y1 + y );
   }
   _setlinestyle( oldstyle );   /* Restore old line style. */
   _setcolor( oldcolor );
}


Description: _get_osfhandle
  _get_osfhandle

#include <io.h>

long _get_osfhandle (int filehandle);

filehandle    User file handle

Return Value

If successful, the _get_osfhandle routine returns an operating system file handle, corresponding to filehandle. Otherwise, it returns −1 and sets errno to EBADF, indicating an invalid file handle.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _getphyscoord
  _getphyscoord

#include <graph.h>

struct _xycoord __far _getphyscoord( short x, short y );

x, y    View coordinates to translate

Remarks

The _getphyscoord function translates the view coordinates (x, y) to physical coordinates and returns them in an _xycoord structure, defined in GRAPH.H. The _xycoord structure contains short xcoord, the x coordinate, and short ycoord, the y coordinate.

Return Value

None.

See Also

»_getviewcoord functions,« »_grstatus,« »_setvieworg,« »_setviewport«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_setwindow.«


Description: _getpid
  _getpid

#include <process.h>

int _getpid( void );

Remarks

The _getpid function returns the process ID, an integer that uniquely identifies the calling process. In the MS-DOS environment, the process ID is usually considered to be the address of the program segment prefix, or PSP. However, in environments with multiple MS-DOS sessions, such as Windows, this value is often not unique. Therefore, the value returned by _getpid() in the MS-DOS libraries is a value based on a combination of the program segment prefix and the system time at the moment when _getpid is called for the first time.

Return Value

The _getpid function returns the process ID. There is no error return.

See Also

»_mktemp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _getpid for compatibility with ANSI naming conventions of non-ANSI functions. Use getpid and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* GETPID.C: This program uses _getpid to obtain
 * the process ID and then prints the ID.
 */

#include <stdio.h>
#include <process.h>

void main( void )
{
   /* If run from command line, shows different ID for
    * command line than for operating system shell.
    */
   printf( "\nProcess id: %d\n", _getpid() );
}

Output

Process id: 193


Description: _getpixel Functions
  _getpixel Functions

#include <graph.h>

short __far _getpixel( short x, short y );

short __far _getpixel_w( double wx, double wy );

x, y    Pixel position

wx, wy    Pixel position

Remarks

The functions in the _getpixel family return the pixel value (a color index) at a specified location. The _getpixel function uses the view coordinate (x, y). The _getpixel_w function uses the window coordinate (wx, wy). The range of possible pixel values is determined by the current video mode. The color translation of pixel values is determined by the current palette.

Return Value

If successful, the function returns the color index. If the function fails (for example, the point lies outside the clipping region, or the program is in a text mode), it returns −1.

See Also

»_getvideoconfig,« »_grstatus,« »_remapallpalette,« »_remappalette,« »_selectpalette,« »_setpixel functions,« »_setvideomode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * GPIXEL.C: This program assigns different
 * colors to randomly selected pixels.
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

void main( void )
{
   short xvar, yvar;
   struct _videoconfig vc;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXCOLORMODE ) )
      exit( 1 );
   _getvideoconfig( &vc );

   /* Draw filled ellipse to turn on certain pixels. */
   _ellipse( _GFILLINTERIOR, vc.numxpixels / 6, vc.numypixels / 6,
                             vc.numxpixels / 6 * 5,
                             vc.numypixels / 6 * 5 );

   /* Draw random pixels in random colors... */
   while( !_kbhit() )
   {
      /* but only if they are already on (inside the ellipse). */
      xvar = rand() % vc.numxpixels;
      yvar = rand() % vc.numypixels;
      if( _getpixel( xvar, yvar ) != 0 )
      {
         _setcolor( rand() % 16 );
         _setpixel( xvar, yvar );
      }
   }

   _getch();          /* Throw away the keystroke. */
   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: gets
  gets

#include <stdio.h>

char *gets( char *buffer );

buffer     Storage location for input string

Remarks

The gets function reads a line from the standard input stream stdin and stores it in buffer. The line consists of all characters up to and including the first newline character ('\n'). The gets function then replaces the newline character with a null character ('\0') before returning the line. In contrast, the fgets function retains the newline character.

Return Value

If successful, the gets function returns its argument. A NULL pointer indicates an error or end-of-file condition. Use ferror or feof to determine which one has occurred.

See Also

»fgets,« »fputs,« »puts«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* GETS.C */

#include <stdio.h>

void main( void )
{
   char line[81];

   printf( "Input a string: " );
   gets( line );
   printf( "The line entered was: %s\n", line );
}

Output

Input a string: Hello!
The line entered was: Hello!


Description: _gettextcolor
  _gettextcolor

#include <graph.h>

short __far _gettextcolor( void );

Remarks

The _gettextcolor function returns the color index of the current text color. The text color is set by the _settextcolor function and affects text output with the _outtext and _outmem functions only. The _setcolor function sets the color for font text output using the _outgtext function. The default is 7 in text modes; it is the highest legal color index of the current palette in graphics modes.

Return Value

The _gettextcolor function returns the color index of the current text color.

See Also

»_getvideoconfig,« »_outmem,« »_outtext,« »_remappalette,« »_selectpalette,« »_setcolor,« »_settextcolor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outtext.«


Description: _gettextcursor
  _gettextcursor

#include <graph.h>

short __far _gettextcursor( void );

Remarks

The _gettextcursor function returns the current cursor attribute (that is, the shape). This function works only in text video modes.

Return Value

The function returns the current cursor attribute, or −1 if an error occurs (such as a call to the function in a graphics mode).

See Also

»_displaycursor,« »_grstatus,« »_settextcursor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_displaycursor.«


Description: _gettextposition
  _gettextposition

#include <graph.h>

struct _rccoord __far _gettextposition( void );

Remarks

The _gettextposition function returns the current text position as an _rccoord structure, defined in GRAPH.H. The _rccoord structure contains short row, the row coordinate element, and short col, the column coordinate element. The text position given by the coordinates (1,1) is defined as the upper-left corner of the text window.

Text output from the _outtext and _outmem functions begins at the current text position. Font text is not affected by the current text position. Font text output begins at the current graphics output position, which is a separate position. Use the _moveto function to set the graphics output position. Standard console routines such as printf do not use or maintain information about the display, such as current text position, which is contained in the graphics library. Therefore, you cannot use standard console routines to output graphics text.

Return Value

The function returns the current text position as an _rccoord structure, defined in GRAPH.H.

See Also

»_getcurrentposition functions,« »_moveto functions,« »_outmem,« »_outtext,« »_settextposition,« »_settextwindow,« »_wrapon«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outtext.«


Description: _gettextwindow
  _gettextwindow

#include <graph.h>

void __far _gettextwindow( short __far *r1, short __far *c1, short __far *r2, short __far *c2 );

r1    Top row of current text window

c1    Leftmost column of current text window

r2    Bottom row of current text window

c2    Rightmost column of current text window

Remarks

The _gettextwindow function finds the boundaries of the current text window. The text window is the region of the screen to which output from the _outtext and _outmem functions is limited. By default, this is the entire screen, unless it has been redefined by the _settextwindow function. The window defined by _settextwindow has no effect on output from the _outgtext function. Text displayed with _outgtext is limited to the current viewport.

Return Value

None.

See Also

»_gettextposition,« »_outmem,« »_outtext,« »_scrolltextwindow,« »_settextposition,« »_settextwindow,« »_wrapon«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_scrolltextwindow.«


Description: _getvideoconfig
  _getvideoconfig

#include <graph.h>

struct _videoconfig __far * __far _getvideoconfig( struct _videoconfig __far *config );

config    Configuration information

Remarks

The _getvideoconfig function returns the current graphics environment configuration in a _videoconfig structure, defined in GRAPH.H. The values returned reflect the currently active video adapter and monitor, as well as the current video mode. The _videoconfig structure contains the following members, each of which is of type short:

numxpixels     Number of pixels on the x axis

numypixels      Number of pixels on the y axis

numtextcols     Number of text columns available

numtextrows     Number of text rows available

numcolors     Number of color indices

bitsperpixel     Number of bits per pixel

numvideopages    Number of available video pages

adapter     Active display adapter

mode     Current video mode

monitor      Active display monitor

memory      Adapter video memory in kilobytes

The values for the adapter member of the _videoconfig structure are given by the manifest constants shown in the list below. For any applicable adapter (_CGA, _EGA, or _VGA), the corresponding Olivetti adapter (_OCGA, _OEGA, or _OVGA) represents a superset of graphics capabilities.

_CGA     Color Graphics Adapter

_EGA     Enhanced Graphics Adapter

_HGC      Hercules Graphics Card

_MCGA      Multicolor Graphics Array

_MDPA     Monochrome Display Printer Adapter

_OCGA     Olivetti (AT&T) Color Graphics Adapter

_OEGA     Olivetti (AT&T) Enhanced Graphics Adapter

_OVGA      Olivetti (AT&T) Video Graphics Array

_VGA     Video Graphics Array

_SVGA     Super Video Graphics Array (VESA)

The values for the monitor member of the _videoconfig structure are given by the manifest constants listed below:

_ANALOG    Analog monochrome and color

_ANALOGCOLOR    Analog color only

_ANALOGMONO    Analog monochrome only

_COLOR    Color (or enhanced monitor emulating a color monitor)

_ENHCOLOR    Enhanced color

_MONO    Monochrome monitor

In every text mode, including monochrome, the _getvideoconfig function returns the value 32 for the number of available colors. The value 32 indicates the range of values (0−31) accepted by the _settextcolor function. This includes 16 normal colors (0−15) and 16 blinking colors (16−31). Blinking is selected by adding 16 to the normal color index. Because monochrome text mode has fewer unique display attributes, some color indices are redundant. However, because blinking is selected in the same manner, monochrome text mode has the same range (0−31) as other text modes.

Return Value

The _getvideoconfig function returns the video configuration information in a structure, as noted above. There is no error return.

See Also

»_setvideomode,« »_setvideomoderows«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * GVIDCFG.C: This program displays information
 * about the current video configuration.
 */

#include <stdio.h>
#include <graph.h>

void main( void )
{
   struct _videoconfig vc;
   short  c;
   char   b[500];               /* Buffer for string */

   _getvideoconfig( &vc );

   /* Write all information to a string, then output string. */
   c  = sprintf( b,     "X pixels:     %d\n", vc.numxpixels );
   c += sprintf( b + c, "Y pixels:     %d\n", vc.numypixels );
   c += sprintf( b + c, "Text columns: %d\n", vc.numtextcols );
   c += sprintf( b + c, "Text rows:    %d\n", vc.numtextrows );
   c += sprintf( b + c, "Colors:       %d\n", vc.numcolors );
   c += sprintf( b + c, "Bits/pixel:   %d\n", vc.bitsperpixel );
   c += sprintf( b + c, "Video pages:  %d\n", vc.numvideopages );
   c += sprintf( b + c, "Mode:         %d\n", vc.mode );
   c += sprintf( b + c, "Adapter:      %d\n", vc.adapter );
   c += sprintf( b + c, "Monitor:      %d\n", vc.monitor );
   c += sprintf( b + c, "Memory:       %d\n", vc.memory );
   _outtext( b );
}

Output

X pixels:     0
Y pixels:     0
Text columns: 80
Text rows:    43
Colors:       32
Bits/pixel:   0
Video pages:  4
Mode:         3
Adapter:      8
Monitor:      24
Memory:       256


Description: _getviewcoord Functions
  _getviewcoord Functions

#include <graph.h>

struct _xycoord __far _getviewcoord( short x, short y );

struct _xycoord __far _getviewcoord_w( double wx, double wy );

struct _xycoord __far _getviewcoord_wxy( struct _wxycoord __far *pwxy1 );

x, y    Physical point to translate

wx, wy    Window point to translate

pwxy1    Window point to translate

Remarks

The _getviewcoord routines translate the specified coordinates (x, y) from one coordinate system to view coordinates and then return them in an _xycoord structure, defined in GRAPH.H. The _xycoord structure contains short xcoord, the x coordinate, and short ycoord, the y coordinate.

The various _getviewcoord routines translate in the following manner:

_getviewcoord    Physical coordinates (x, y) to view coordinates

_getviewcoord_w    Window coordinates (wx, wy) to view coordinates

_getviewcoord_wxy    Window coordinates structure (pwxy1) to view coordinates

In Microsoft C version 5.1, the function _getviewcoord was called _getlogcoord.

Return Value

The _getviewcoord function returns the coordinates as noted above. There is no error return.

See Also

»_getphyscoord,« »_getwindowcoord,« »_grstatus«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_setwindow.«


Description: _getvisualpage
  _getvisualpage

#include <graph.h>

short __far _getvisualpage( void );

Remarks

The _getvisualpage function returns the current visual page number. This function works differently in QuickWin applications.

Return Value

The function returns the number of the current visual page. All hardware combinations support at least one page (page number 0).

See Also

»_getactivepage,« »_gettextcolor,« »_gettextposition,« »_outtext,« »_setactivepage,« »_settextcolor,« »_settextposition,« »_settextwindow,« »_setvideomode,« »_setvisualpage,« »_wrapon«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getactivepage.«


Description: _getw
  _getw

#include <stdio.h>

int _getw( FILE *stream );

stream    Pointer to FILE structure

Remarks

The _getw function reads the next binary value of type int from the file associated with stream and increments the associated file pointer (if there is one) to point to the next unread character. The _getw function does not assume any special alignment of items in the stream.

Return Value

The _getw function returns the integer value read. A return value of EOF may indicate an error or end-of-file. However, because the EOF value is also a legitimate integer value, feof or ferror should be used to verify an end-of-file or error condition.

See Also

»_putw«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _getw for compatibility with ANSI naming conventions of non-ANSI functions. Use getw and link with OLDNAMES.LIB for UNIX compatibility. The _getw function is provided primarily for compatibility with previous libraries. Note that portability problems may occur with _getw, because the size of the int type and the ordering of bytes within the int type differ across systems.

Example

/* GETW.C: This program uses _getw to read a word
 * from a stream, then performs an error check.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   FILE *stream;
   int i;

   if( (stream = fopen( "getw.c", "rb" )) == NULL )
      printf( "Couldn't open file\n" );
   else
   {
      /* Read a word from the stream: */
      i = _getw( stream );

      /* If there is an error... */
      if( ferror( stream ) )
      {
         printf( "_getw failed\n" );
         clearerr( stream );
      }
      else
         printf( "First data word in file: 0x%.4x\n", i );
      fclose( stream );
   }
}

Output

First data word in file: 0x282b2f2f


Description: _getwindowcoord
  _getwindowcoord

#include <graph.h>

struct _wxycoord __far _getwindowcoord( short x, short y );

x, y    Viewport coordinate to translate

Remarks

The _getwindowcoord function translates the view coordinates (x, y) to window coordinates and returns them in the _wxycoord structure, defined in GRAPH.H. The _wxycoord structure contains the following elements:

double wx    x coordinate

double wy    y coordinate

Return Value

The function returns the coordinates in the _wxycoord structure. There is no error return.

See Also

»_getphyscoord,« »_getviewcoord functions,« »_moveto functions,« »_setwindow«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_setwindow.«


Description: _getwritemode
  _getwritemode

#include <graph.h>

short __far _getwritemode( void );

Remarks

The _getwritemode function returns the current logical write mode, which is used when drawing lines with the _lineto, _polygon, and _rectangle functions. The default value is _GPSET, which causes lines to be drawn in the current graphics color. The other possible return values are _GXOR, _GAND, _GOR, and _GPRESET. See the reference page for »_putimage« for more details on these manifest constants.

Return Value

The _getwritemode function returns the current logical write mode, or −1 if not in graphics mode.

See Also

»_grstatus,« »_lineto functions,« »_putimage functions,« »_rectangle functions,« »_setcolor,« »_setlinestyle,« »_setwritemode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * GWRMODE.C: This program illustrates
 * getwritemode _and _setwritemode.
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

short wmodes[5]  = { _GPSET, _GPRESET, _GXOR, _GOR, _GAND };
char *wmstr[5]   = { "PSET", "PRESET", "XOR", "OR", "AND" };

void box( short x, short y, short size, short writemode,
          short  fillmode );

void main( void )
{
   short i, x, y;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXCOLORMODE ) )
      exit( 1 );

   x = y = 70;
   box( x, y, 50, _GPSET, _GFILLINTERIOR );
   _setcolor( 2 );
   box( x, y, 40, _GPSET, _GFILLINTERIOR );
   for( i = 0; i < 5; i++ )

   {
      _settextposition( 1, 1 );
      _outtext( wmstr[i] );
      box( x += 12, y += 12, 50, wmodes[i], _GBORDER );
      _getch();
    }
    _setvideomode( _DEFAULTMODE );
    exit( 0 );
}

void box( short x, short y, short size, short writemode,
          short  fillmode )
{
   short wm;

   wm = _getwritemode();    /* Save write mode and set new. */
   _setwritemode( writemode );
   _rectangle( fillmode, x - size, y - size, x + size, y + size );
   _setwritemode( wm );     /* Restore original write mode. */
}


Description: gmtime
  gmtime

#include <time.h>

struct tm *gmtime( const time_t *timer );

timer    Pointer to stored time

Remarks

The gmtime function converts the timer value to a structure. The timer argument represents the seconds elapsed since midnight (00:00:00), January 1, 1970, Universal coordinated time. This value is usually obtained from a call to the time function. The gmtime function breaks down the timer value and stores it in a structure of type tm, defined in TIME.H. The structure result reflects Universal coordinated time, not local time. The fields of the structure type tm store the following values, each of which is an int:

tm_sec    Seconds after the minute (0−59)

tm_min    Minutes after the hour (0−59)

tm_hour    Hours since midnight (0−23)

tm_mday    Day of month (1−31)

tm_mon    Month (0−11; January = 0)

tm_year    Year (current year minus 1900)

tm_wday    Day of week (0−6; Sunday = 0)

tm_yday    Day of year (0−365; January 1 = 0)

tm_isdst    Always 0 for gmtime

The gmtime, mktime, and localtime functions use a single statically allocated structure to hold the result. Each call to one of these routines destroys the result of any previous call. If timer represents a date before midnight, January 1, 1970, gmtime returns NULL.

Note  The target environment should attempt to determine whether daylight saving time is in effect.

Return Value

The gmtime function returns a pointer to the structure result. There is no error return.

See Also

»asctime,« »ctime,« »_ftime,« »localtime,« »time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* GMTIME.C: This program uses gmtime to convert a long-
 * integer representation of Universal Coordinated Time
 * to a structure named  newtime, then uses asctime to
 * convert this structure to an output string.
 */

#include <time.h>
#include <stdio.h>

void main( void )
{
   struct tm *newtime;
   long ltime;

   time( &ltime );

   /* Obtain Universal Coordinated Time: */
   newtime = gmtime( &ltime );
   printf( "Universal Coordinated Time is %s\n",
                               asctime( newtime ) );
}

Output

Universal Coordinated Time is Tue Mar 23 02:00:56 1993


Description: _grstatus
  _grstatus

#include <graph.h>

short __far _grstatus( void );

Remarks

The _grstatus function returns the status of the most recently used graphics function. The _grstatus function can be used immediately following a call to a graphics routine to determine if errors or warnings were generated. Return values less than 0 are errors, and values greater than 0 are warnings. The following manifest constants are defined in the GRAPH.H header file for use with the _grstatus function:

Value	Constant	Meaning
0	_GROK	Success.
−1	_GRERROR	Graphics error.
−2	_GRMODENOTSUPPORTED	Requested video mode not supported.
−3	_GRNOTINPROPERMODE	Requested routine only works in certain video modes.
− 4	_GRINVALIDPARAMETER	One or more arguments invalid.
−5	_GRFONTFILENOTFOUND	No matching font file found.
− 6	_GRINVALIDFONTFILE	One or more font files invalid.
−7	_GRCORRUPTEDFONTFILE	One or more font files inconsistent.
− 8	_GRINSUFFICIENTMEMORY	Not enough memory to allocate buffer or to complete a _floodfill operation.
−9	_GRINVALIDIMAGEBUFFER	Image buffer data inconsistent.
1	_GRNOOUTPUT	Nothing drawn.
2	_GRCLIPPED	Output was clipped to the viewport.
3	_GRPARAMETERALTERED	One or more input arguments was altered to be within range, or pairs of arguments were interchanged to be in the proper order.
After a graphics call, use an if statement to compare the return value of _grstatus to _GROK. For example:

if( _grstatus < _GROK )
   /*handle graphics error*/ ;

The functions listed below cannot cause errors, and they all set _grstatus to _GROK:

_displaycursor

_getactivepage

_getbkcolor

_getgtextvector

_gettextcolor

_gettextposition

_gettextwindow

_getvideoconfig

_getvisualpage

_outmem

_outtext

_unregisterfonts

_wrapon

See the list below for the graphics functions that affect _grstatus. The list shows error or warning messages that can be set by the graphics function. In addition to the error codes listed, any of these functions can produce the _GRERROR error code.

Function	Possible _grstatus error codes	Possible _grstatus warning codes
_arc functions	_GRNOTINPROPERMODE, _GRINVALIDPARAMETER	_GRNOOUTPUT, _GRCLIPPED
_clearscreen	_GRNOTINPROPERMODE, _GRINVALIDPARAMETER
_ellipse functions	_GRNOTINPROPERMODE, _GRINVALIDPARAMETER, _GRINSUFFICIENTMEMORY	_GRNOOUTPUT, _GRCLIPPED
_floodfill functions	_GRNOTINPROPERMODE, _GRINVALIDPARAMETER, _GRINSUFFICIENTMEMORY	_GRNOOUTPUT
_getarcinfo	_GRNOTINPROPERMODE
_getcurrentposition functions	_GRNOTINPROPERMODE
_getfontinfo	( _GRERROR only)
_getgtextextent	( _GRERROR only)
_getgtextvector	_GRPARAMETERALTERED
_getimage functions	_GRNOTINPROPERMODE	_GRPARAMETERALTERED
_getphyscoord	_GRNOTINPROPERMODE
_getpixel functions	_GRNOTINPROPERMODE
_gettextcursor	_GRNOTINPROPERMODE
_getviewcoord functions	_GRNOTINPROPERMODE
_getwindowcoord	_GRNOTINPROPERMODE
_getwritemode	_GRNOTINPROPERMODE
_imagesize functions	_GRNOTINPROPERMODE
_lineto functions	_GRNOTINPROPERMODE	_GRNOOUTPUT, _GRCLIPPED
_moveto functions	_GRNOTINPROPERMODE
_outgtext	_GRNOTINPROPERMODE	_GRCLIPPED, _GRNOOUTPUT
_pie functions	_GRNOTINPROPERMODE, _GRINVALIDPARAMETER, _GRINSUFFICIENTMEMORY	_GRNOOUTPUT, _GRCLIPPED
The _grstatus function works differently in QuickWin applications.

Return Value

The _grstatus function returns the status of the most recently used graphics function.

See Also

»_arc functions,« »_ellipse functions,« »_floodfill functions,« »_lineto functions,« »_pie functions,« »_remapallpalette,« »_setactivepage,« »_setbkcolor,« »_setcolor,« »_setpixel functions,« »_settextcolor,« »_settextcursor,« »_setvisualpage,« »_setwindow,« »_setwritemode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _halloc
  _halloc

#include <malloc.h>

void __huge *_halloc( long num, size_t size );

num    Number of elements

size    Length in bytes of each element

Remarks

The _halloc function allocates a huge array from the operating system consisting of num elements, each of which is size bytes long. Each element is initialized to 0. If the size of the array is greater than 128K (131,072 bytes), the size of an array element must then be a power of 2. Use the _hfree function to deallocate a block of memory returned by halloc.

Return Value

The _halloc function returns a void huge pointer to the allocated space, which is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void huge, use a type cast on the return value. If the request cannot be satisfied, the return value is NULL.

See Also

»calloc functions,« »free functions,« »_hfree,« »malloc functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * HALLOC.C: This program uses _halloc to allocate space for
 * 30,000 long integers, then uses _hfree to deallocate the memory.
 */

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

void main( void )
{
   long __huge *hbuf;

   /* Allocate huge buffer */
   hbuf = (long __huge *)_halloc( 30000L, sizeof( long ) );
   if ( hbuf == NULL )
      printf( "Insufficient memory available\n" );
   else
      printf( "Memory successfully allocated\n" );

   /* Free huge buffer */
   _hfree( hbuf );
}

Output

Memory successfully allocated


Description: _hard Functions
  _hard Functions

#include <dos.h>

void _harderr( void( __far *handler )( ));

void _hardresume( int result );

void _hardretn( int error );

handler ( )    New INT 0x24 handler

result    Handler return argument

error    Error to return from

Remarks

These three functions are used to handle critical error conditions that use MS-DOS interrupt 0x24. The _harderr function installs a new critical-error handler for interrupt 0x24. When a critical error occurs, control is passed to the function specified in the _harderr call. The _hardresume and _hardretn functions control how the program will return from the critical error handler. The _hardresume function returns to MS-DOS the code that encountered the critical error. The _hardretn function returns directly to the application program that issued the INT 0x21 MS-DOS system call, which, in turn, encountered the critical error.

The _harderr function does not directly install the handler pointed to by handler; instead, _harderr installs a handler that calls the function referenced by handler. The handler calls the function with the following arguments:

handler(unsigned deverror, unsigned errcode, unsigned __far *devhdr);

The deverror argument is the device error code. It contains the AX register value passed by MS-DOS to the INT 0x24 handler. The errcode argument is the DI register value that MS-DOS passes to the handler. The low-order byte of errcode can be one of the following values:

0    Attempt to write to a write-protected disk

1    Unknown unit

2    Drive not ready

3    Unknown command

4    Cyclic-redundancy-check error in data

5    Bad drive-request structure length

6    Seek error

7    Unknown media type

8    Sector not found

9    Printer out of paper

10    Write fault

11    Read fault

12    General failure

The devhdr argument is a far pointer to a device header that contains descriptive information about the device on which the error occurred. The user-defined handler must not change the information in the device-header control block.

Errors on Disk Devices

If the error occurred on a disk device, the high-order bit (bit 15) of the deverror argument is set to 0, and the deverror argument indicates the following:

Bit	Meaning
15	Disk error if false (0).
14	Not used.
13	"Ignore" response not allowed if false (0).
12	"Retry" response not allowed if false (0).
11	"Fail" response not allowed if false (0). Note that MS-DOS changes "fail" to "abort".
10, 9	See table following.
8	Read error if false; write error if true.
For bits 10 and 9, the error code given indicates a location:

Code	Location
00	MS-DOS
01	File allocation table
10	Directory
11	Data area
The low-order byte of deverror indicates the drive in which the error occurred (0 = drive A, 1 = drive B, and so on).

Errors on Other Devices

If the error occurs on a device other than a disk drive, the high-order bit (bit 15) of the deverror argument is 1. The attribute word located at offset 4 in the device-header block indicates the type of device that had the error. If bit 15 of the attribute word is 0, the error is a bad memory image of the file allocation table. If the bit is 1, the error occurred on a character device and bits 0 − 3 of the attribute word indicate the type of device, as shown in the following list:

0    Current standard input

1    Current standard output

2    Current null device

3    Current clock device

Restrictions on Handler Functions

The user-defined handler function can issue only system calls 0x01 through 0x0C, or 0x59. Thus, many of the standard C run-time functions (such as the I/O and _heap functions) cannot be used in a hardware error handler. System call 0x59 can be used to obtain further information about the error that occurred.

Using _hardresume and _harderr

If the handler returns, it can do so in several different ways:

•	Via the return statement

•	By calling the _hardresume function

•	By calling the _hardretn function

If the handler returns from _hardresume or from a return statement, control returns to MS-DOS. The _hardresume function should be called only from within the user-defined hardware error-handler function. The result supplied to _hardresume must be one of the following constants:

_HARDERR_ABORT    Aborts the program by issuing INT 0x24

_HARDERR_FAIL     Fails the system call that is in progress (this is not supported on MS-DOS 2.x)

_HARDERR_IGNORE    Ignores the error

_HARDERR_RETRY    Retries the operation

The _hardretn function allows the user-defined hardware error handler to return directly to the application program rather than returning to MS-DOS. The application resumes at the point just after the failing I/O function request. The _hardretn function should be called only from within a user-defined hardware error-handler function.

The error argument of _hardretn should be an MS-DOS error code, as opposed to the XENIX-style error code that is available in errno. Refer to MS-DOS Encyclopedia (Duncan, ed.; Redmond, WA: Microsoft Press, 1988) or Programmer's PC Sourcebook 2nd ed. (Hogan; Redmond, WA: Microsoft Press, 1991) for information about the MS-DOS error codes that may be returned by a given MS-DOS function call.

If the failing I/O function request is an INT 0x21 function greater than or equal to function 0x38, _hardretn will then return to the application with the carry flag set and the AX register set to the _hardretn error argument. If the failing INT 0x21 function request is less than function 0x38 and the function can return an error, the AL register will be set to 0xFF on return to the application. If the failing INT 0x21 does not have a way of returning an error condition (which is true of certain INT 0x21 functions below 0x38), the error argument of _hardretn is not used, and no error code is returned to the application.

Return Value

None.

See Also

»_chain_intr,« »_dos_getvect,« »_dos_setvect«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _heapadd Functions
  _heapadd Functions

#include <malloc.h>

int _heapadd( void __far *memblock, size_t size );

int _bheapadd( __segment seg, void __based (void) *memblock, size_t size );

seg    Based-heap segment selector

memblock    Pointer to heap memory

size    Size in bytes of memory to add

Remarks

The _heapadd and _bheapadd functions add an unused piece of memory to the heap. The _bheapadd function adds the memory to the based heap specified by seg. The _heapadd function looks at the segment value and, if it is DGROUP, adds the memory to the near heap. Otherwise, _heapadd adds the memory to the far heap.

Return Value

These functions return 0 if successful, or −1 if an error occurred.

See Also

»free functions,« »_halloc,« »_hfree,« »malloc functions,« »realloc functions«

Compatibility

_heapadd:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bheapadd:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_heapmin.«


Description: _heapchk Functions
  _heapchk Functions

#include <malloc.h>

int _heapchk( void );

int _bheapchk( __segment seg );

int _fheapchk( void );

int _nheapchk( void );

seg    Specified base heap

Remarks

The _heapchk routines help to debug heap-related problems by checking for minimal consistency of the heap. Each function checks a particular heap, as listed below:

_heapchk     Depends on data model of program

_bheapchk    Based heap specified by seg value

_fheapchk     Far heap (outside the default data segment)

_nheapchk     Near heap (inside the default data segment)

In large data models (that is, compact-, large-, and huge-model programs), _heapchk maps to _fheapchk. In small data models (tiny-, small-, and medium-model programs), _heapchk maps to _nheapchk. For _heapchk, if the seg value is _NULLSEG, all based heap segments are checked; otherwise, only the specified one is checked.

Return Value

All four routines return an integer value that is one of the following manifest constants (defined in MALLOC.H):

_HEAPBADBEGIN    Initial header information cannot be found, or it is bad.

_HEAPBADNODE    Bad node has been found, or the heap is damaged.

_HEAPEMPTY    Heap has not been initialized.

_HEAPOK    Heap appears to be consistent.

See Also

»_heapset functions,« »_heapwalk functions«

Compatibility

_heapchk:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bheapchk, _fheapchk:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_nheapchk:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* HEAPCHK.C: This program checks the heap for
 * consistency and prints an appropriate message.
 */

#include <malloc.h>
#include <stdio.h>

void main( void )
{
   int  heapstatus;
   char *buffer;

   /* Allocate and deallocate some memory */
   if( (buffer = (char *)malloc( 100 )) != NULL )
      free( buffer );

   /* Check heap status */
   heapstatus = _heapchk();
   switch( heapstatus )
   {
   case _HEAPOK:
      printf(" OK - heap is fine\n" );
      break;
   case _HEAPEMPTY:
      printf(" OK - heap is empty\n" );
      break;
   case _HEAPBADBEGIN:
      printf( "ERROR - bad start of heap\n" );
      break;
   case _HEAPBADNODE:
      printf( "ERROR - bad node in heap\n" );
      break;
   }
}

Output

 OK - heap is fine


Description: _heapmin Functions
  _heapmin Functions

#include <malloc.h>

int _heapmin( void );

int _bheapmin( __segment seg );

int _fheapmin( void );

int _nheapmin( void );

seg    Specified based-heap selector

Remarks

The _heapmin functions minimize the heap by releasing unused heap memory to the operating system. The various _heapmin functions release unused memory in these heaps:

_heapmin    Depends on data model of program.

_bheapmin    Based heap specified by seg value; _NULLSEG specifies all based heaps.

_fheapmin    Far heap (outside default data segment).

_nheapmin    Near heap (inside default data segment).

In large data models (that is, compact-, large-, and huge-model programs), _heapmin maps to _fheapmin. In small data models (tiny-, small-, and medium-model programs), _heapmin maps to _nheapmin. For _heapmin, if the supplied seg value is _NULLSEG, all based heap segments are minimized; otherwise, only the specified one is minimized. Based-heap segments are never freed (i.e., unlinked from the based heap list and released back to the operating system) by the _bheapmin function. The »_bfreeseg« function is used for that purpose.

Return Value

The _heapmin functions return 0 if the function completed successfully, or −1 in the case of an error.

See Also

»_bfreeseg,« »free functions,« »malloc functions«

Compatibility

_heapmin:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bheapmin, _fheapmin, _nheapmin:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * HEAPMIN.C: This program illustrates heap
 * management using _heapadd and _heapmin.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>
#include <malloc.h>

void heapdump( char *msg );     /* Prototype */

char s1[] = { "Here are some strings that we use at first, then don't\n"  };
char s2[] = { "need any more. We'll give their space to the heap.\n" };

void main( void )
{
   int *p[3], i;

   printf( "%s%s", s1, s2 );
   heapdump( "Initial heap" );

   /* Give space of used strings to heap. */
   if ( _heapadd( s1, sizeof( s1 )) == -1 )
      printf("Error.\n");
   if ( _heapadd( s2, sizeof( s2 )) == -1 )
      printf("Error.\n");
   heapdump( "After adding used strings" );

   /* Allocate some blocks. Some may use
    * string blocks from _heapadd.
    */
   for( i = 0; i < 2; i++ )
      if( (p[i] = (int *)calloc( 10 * (i + 1),
           sizeof( int ) )) == NULL )
      {
         --i;
         break;
      }
   heapdump( "After allocating memory" );

   /* Free some of the blocks. */
   free( p[1] );
   free( p[2] );
   heapdump( "After freeing memory" );

   /* Minimize heap. */
   _heapmin();
   heapdump( "After compacting heap" );
}

/* Walk through heap entries, displaying
 * information about each block.
 */
void heapdump( char *msg )
{
   _HEAPINFO hi;

   printf( "%s\n", msg );
   hi._pentry = NULL;
   while( _heapwalk( &hi ) == _HEAPOK )
      printf( "\t%s block at %Fp of size %u\t\n",
              hi._useflag == _USEDENTRY ? "USED" : "FREE",
              hi._pentry, hi._size );
   printf("Press any key.\n");
   _getch();
}

Output

Here are some strings that we use at first, then don't
need any more. We'll give their space to the heap.
Initial heap
   USED block at 24BE:0CDC of size 306
   USED block at 24BE:0E10 of size 24
   USED block at 24BE:0E2A of size 512
   FREE block at 24BE:102C of size 4050
After adding used strings
   FREE block at 24BE:0044 of size 52
   FREE block at 24BE:007A of size 50
   USED block at 24BE:00AE of size 3116
   USED block at 24BE:0CDC of size 306
   USED block at 24BE:0E10 of size 24
   USED block at 24BE:0E2A of size 512
   FREE block at 24BE:102C of size 4050
After allocating memory
   USED block at 24BE:0044 of size 20
   USED block at 24BE:005A of size 40
   FREE block at 24BE:0084 of size 40
   USED block at 24BE:00AE of size 3116
   USED block at 24BE:0CDC of size 306
   USED block at 24BE:0E10 of size 24
   USED block at 24BE:0E2A of size 512
   FREE block at 24BE:102C of size 4050
After freeing memory
        USED block at 24BE:0044 of size 20
   FREE block at 24BE:005A of size 40
   FREE block at 24BE:0084 of size 40
   USED block at 24BE:00AE of size 3116
   USED block at 24BE:0CDC of size 306
   USED block at 24BE:0E10 of size 24
   USED block at 24BE:0E2A of size 512
   FREE block at 24BE:102C of size 4050
After compacting heap
        USED block at 24BE:0044 of size 20
   FREE block at 24BE:005A of size 82
   USED block at 24BE:00AE of size 3116
   USED block at 24BE:0CDC of size 306
   USED block at 24BE:0E10 of size 24
   USED block at 24BE:0E2A of size 512
   FREE block at 24BE:102C of size 2


Description: _heapset Functions
  _heapset Functions

#include <malloc.h>

int _heapset( unsigned int fill );

int _bheapset( __segment seg, unsigned int fill );

int _fheapset( unsigned int fill );

int _nheapset( unsigned int fill );

fill    Fill character

seg    Specified based-heap segment selector

Remarks

The _heapset family of routines helps debug heap-related problems in programs by showing free memory locations or nodes unintentionally overwritten.

The _heapset routines first check for minimal consistency on the heap in a manner identical to that of the »_heapchk« functions. In addition, the _heapset functions set each byte of the heap's free entries to the fill value. This known value shows which memory locations of the heap contain free nodes and which locations contain data that were unintentionally written to freed memory. The various _heapset functions check and fill these heaps:

_heapset    Depends on data model of program.

_bheapset    Based heap specified by seg value; _NULLSEG specifies all based heaps.

_fheapset    Far heap (outside default data segment).

_nheapset    Near heap (inside default data segment).

In large data models (that is, compact-, large-, and huge-model programs), _heapset maps to _fheapset. In small data models (tiny-, small-, and medium-model programs), _heapset maps to _nheapset. For _heapset, if the seg value is _NULLSEG, all based heap segments are checked; otherwise, only the specified one is checked.

Return Value

All four routines return an int whose value is one of the following manifest constants (defined in MALLOC.H):

_HEAPBADBEGIN    Initial header information cannot be found, or it is invalid.

_HEAPBADNODE    Bad node has been found, or the heap is damaged.

_HEAPEMPTY    Heap has not been initialized.

_HEAPOK    Heap appears to be consistent.

See Also

»_heapchk functions,« »_heapwalk functions«

Compatibility

_heapset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bheapset, _fheapset:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_nheapset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* HEAPSET.C: This program checks the heap and
 * fills in free entries with the character 'Z'.
 */

#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int heapstatus;
   char *buffer;

   if( (buffer = malloc( 1 )) == NULL ) /* Make sure heap is */
      exit( 0 );                        /*    initialized    */
   heapstatus = _heapset( 'Z' );        /* Fill in free entries */
   switch( heapstatus )
   {
   case _HEAPOK:
      printf( "OK - heap is fine\n" );
      break;
   case _HEAPEMPTY:
      printf( "OK - heap is empty\n" );
      break;
   case _HEAPBADBEGIN:
      printf( "ERROR - bad start of heap\n" );
      break;
   case _HEAPBADNODE:
      printf( "ERROR - bad node in heap\n" );
      break;
   }
   free( buffer );
}

Output

OK - heap is fine


Description: _heapwalk Functions
  _heapwalk Functions

#include <malloc.h>

int _heapwalk( _HEAPINFO *entryinfo );

int _bheapwalk( __segment seg, _HEAPINFO *entryinfo );

int _fheapwalk( _HEAPINFO *entryinfo );

int _nheapwalk( _HEAPINFO *entryinfo );

entryinfo    Buffer to contain heap information

seg    Based-heap segment selector

Remarks

The _heapwalk family of routines helps debug heap-related problems in programs. The _heapwalk routines walk through the heap, traversing one entry per call, and return a pointer to a structure of type _HEAPINFO that contains information about the next heap entry. The _HEAPINFO type, defined in MALLOC.H, contains the following elements:

int far *_pentry    Heap entry pointer

size_t _size    Size of heap entry

int _useflag    Entry "in use" flag

A call to _heapwalk that returns _HEAPOK stores the size of the entry in the _size field and sets the _useflag field to either _FREEENTRY or _USEDENTRY (both are constants defined in MALLOC.H). To obtain this information about the first entry in the heap, pass the _heapwalk routine a pointer to a _HEAPINFO structure whose _pentry member is NULL. The various _heapwalk functions walk through and gather information on these heaps:

_heapwalk    Depends on data model of program.

_bheapwalk    Based heap specified by seg value; _NULLSEG specifies all based heaps.

_fheapwalk    Far heap (outside default data segment).

_nheapwalk    Near heap (inside default data segment).

In large data models (that is, compact-, large-, and huge-model programs), _heapwalk maps to _fheapwalk. In small data models (tiny-, small-, and medium-model programs), _heapwalk maps to _nheapwalk. For _heapwalk, if the seg value is _NULLSEG, all based heap segments will be traversed; otherwise, only the specified based heap is walked.

Return Value

All four routines return one of the following manifest constants (defined in MALLOC.H):

_HEAPBADBEGIN    The initial header information cannot be found, or it is invalid.

_HEAPBADNODE    A bad node has been found, or the heap is damaged.

_HEAPBADPTR     The _pentry field of the _HEAPINFO structure does not contain a valid pointer into the heap.

_HEAPEND     The end of the heap has been reached successfully.

_HEAPEMPTY    The heap has not been initialized.

_HEAPOK     No errors so far; the _HEAPINFO structure contains information about the next entry.

See Also

»_heapchk functions,« »_heapset functions«

Compatibility

_heapwalk:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bheapwalk, _fheapwalk:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_nheapwalk:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* HEAPWALK.C: This program "walks" the heap, starting
 * at the beginning (_pentry = NULL). It prints out each
 * heap entry's use, location, and size. It also prints
 * out information about the overall state of the heap as
 * soon as _heapwalk returns a value other than _HEAPOK.
 */

#include <stdio.h>
#include <malloc.h>

void heapdump( void );

void main( void )
{
   char *buffer;

   heapdump();
   if( (buffer = malloc( 59 )) != NULL )
   {
      heapdump();
      free( buffer );
   }
   heapdump();
}

void heapdump( void )
{
   _HEAPINFO hinfo;
   int heapstatus;
   hinfo._pentry = NULL;
   while( ( heapstatus = _heapwalk( &hinfo ) ) == _HEAPOK )
   { printf( "%6s block at %Fp of size %4.4X\n",
        ( hinfo._useflag == _USEDENTRY ? "USED" : "FREE" ),
          hinfo._pentry, hinfo._size );
   }

   switch( heapstatus )
   {
   case _HEAPEMPTY:
      printf( "OK - empty heap\n" );
      break;
   case _HEAPEND:
      printf( "OK - end of heap\n" );
      break;
   case _HEAPBADPTR:
      printf( "ERROR - bad pointer to heap\n" );
      break;
   case _HEAPBADBEGIN:
      printf( "ERROR - bad start of heap\n" );
      break;
   case _HEAPBADNODE:
      printf( "ERROR - bad node in heap\n" );
      break;
   }
}

Output

  USED block at 2486:0C3C of size 0132
  USED block at 2486:0D70 of size 0018
  USED block at 2486:0D8A of size 0200
  FREE block at 2486:0F8C of size 0072
OK - end of heap
  USED block at 2486:0C3C of size 0132
  USED block at 2486:0D70 of size 0018
  USED block at 2486:0D8A of size 0200
  USED block at 2486:0F8C of size 003C
  FREE block at 2486:0FCA of size 0034
OK - end of heap
  USED block at 2486:0C3C of size 0132
  USED block at 2486:0D70 of size 0018
  USED block at 2486:0D8A of size 0200
  FREE block at 2486:0F8C of size 003C
  FREE block at 2486:0FCA of size 0034
OK - end of heap


Description: _hfree
  _hfree

#include <malloc.h>

void _hfree( void __huge *memblock );

memblock    Pointer to allocated memory block

Remarks

The _hfree function deallocates a memory block; the freed memory is returned to the operating system. The memblock argument points to a memory block previously allocated through a call to _halloc. The number of bytes freed is the number of bytes specified when the block was allocated.

Note that attempting to free an invalid memblock argument (one not allocated with _halloc) may affect subsequent allocation and cause errors.

Return Value

None.

See Also

»_halloc«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_halloc.«


Description: _hypot, _hypotl
  _hypot, _hypotl

#include <math.h>

double _hypot( double x, double y );

long double _hypotl( long double x, long double y );

x, y    Floating-point values

Remarks

The _hypot and _hypotl functions calculate the length of the hypotenuse of a right triangle, given the length of the two sides x and y (or xl and yl ). A call to _hypot is equivalent to the square root of  (x squared + y squared). The _hypotl function uses the 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

Return Value

These functions return the length of the hypotenuse if successful or HUGE_VAL (_LHUGE_VAL for _hypotl) on overflow. The errno variable is set to ERANGE on overflow.

See Also

»_cabs«

Compatibility

_hypot:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_hypotl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _hypot for compatibility with ANSI naming conventions of non-ANSI functions. Use hypot and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* HYPOT.C: This program prints the
 * hypotenuse of a right  triangle.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 3.0, y = 4.0;

   printf( "If a right triangle has sides %2.1f and %2.1f, "
           "its hypotenuse is %2.1f\n", x, y, _hypot( x, y ) );
}

Output

If a right triangle has sides 3.0 and 4.0, its hypotenuse is 5.0


Description: _imagesize Functions
  _imagesize Functions

#include <graph.h>

long __far _imagesize( short x1, short y1, short x2, short y2 );

long __far _imagesize_w( double wx1, double wy1, double wx2, double wy2 );

long __far _imagesize_wxy( struct _wxycoord __far *pwxy1, struct _wxycoord __far *pwxy2 );

x1, y1    Upper-left corner of bounding rectangle

x2, y2    Lower-right corner of bounding rectangle

wx1, wy1    Upper-left corner of bounding rectangle

wx2, wy2    Lower-right corner of bounding rectangle

pwxy1    Upper-left corner of bounding rectangle

pwxy2    Lower-right corner of bounding rectangle

Remarks

The functions in the _imagesize family return the number of bytes needed to store the image defined by the bounding rectangle and specified by the coordinates given in the function call. The _imagesize function defines the bounding rectangle in terms of view-coordinate points (x1, y1) and (x2, y2). The _imagesize_w function defines the bounding rectangle in terms of window-coordinate points (x1, y1) and (x2, y2). The _imagesize_wxy function defines the bounding rectangle in terms of the window-coordinate pairs pwxy1 and pwxy2.

Return Value

The function returns the storage size of the image in bytes. There is no error return.

See Also

»_getimage functions,« »_getvideoconfig,« »_putimage functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getimage.«


Description: _inchar
  _inchar

#include <stdio.h>

#include <graph.h>

short __far char __cdecl _inchar( void );

Remarks

The _inchar routine reads a single character from the keyboard and returns the ASCII value of that character without any buffering. A graphics child window must have focus when this routine is called for the key to be accepted. The _inchar routine must be called before a character can be read. This function does not echo its input.

Return Value

This function returns an ASCII key code.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * INCHAR.C - Illustrates the QuickWin graphics
 * routine for character input: _inchar
 */

#include <stdio.h>
#include <graph.h>

void main()
{
   int status = 0, key = 0;
   char buffer[80];

   /* Open a graphics child window and set font to Times Roman*/
   status = _setvideomode( _MAXRESMODE );
   status = _registerfonts( "dummy string" );
   status = _setfont( "t'roman'" );
   status = _setcolor( 11 );
   status = _settextcolor( 14 );
   _clearscreen( _GCLEARSCREEN );

   /* Execute this loop until user enters a 'q' to quit*/
   while( key != 'q' )
   {
      /* Prompt user and read a key*/
      _settextposition( 1, 1 );
      _outtext( "this window must have focus for _inchar to work!" );
      _settextposition( 6, 1 );
      _outtext( "Enter a key ('q' to quit):" );
      key = _inchar();
      _clearscreen( _GCLEARSCREEN );
      _settextposition( 8, 1 );
      sprintf( buffer, "ASCII code = %d\n", key );
      _outtext( buffer );
      _moveto( 30, 30 );
      sprintf( buffer, "%d", key);
      _outgtext( buffer );
   }

   _settextposition( 10, 1 );
   _outtext( "Program finished." );
   _unregisterfonts();
}


Description: _inp, _inpw, _inpd
  _inp, _inpw, _inpd

#include <conio.h>

int _inp( unsigned short port );

unsigned short _inpw( unsigned short port );

unsigned long _inpd( unsigned short port );

port     Port number

Remarks

The _inp, _inpw, and _inpd functions read a byte, a word and a double word, respectively, from the specified input port. The input value can be any unsigned short integer in the range 0 − 65,535.

Return Value

The functions return the byte, word, or double word read from port. There is no error return.

See Also

»_outp,« »_outpd,« »_outpw«

Compatibility

_inp, _inpw: ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_inpd: ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outp.«


Description: _int86
  _int86

#include <dos.h>

int _int86( int intnum, union _REGS *inregs, union _REGS *outregs );

intnum    Interrupt number

inregs    Register values on call

outregs    Register values on return

Remarks

The _int86 function executes the 8086-processor-family interrupt specified by the interrupt number intnum. Before executing the interrupt, _int86 copies the contents of inregs to the corresponding registers. After the interrupt returns, the function copies the current register values to outregs. It also copies the status of the system carry flag to the cflag field in the outregs argument. The inregs and outregs arguments are unions of type _REGS. The _REGS type is defined in the include file DOS.H.

Do not use the _int86 function to call interrupts that modify the DS or ES registers. Instead, use the _int86x function. (The _int86x function loads the DS and ES registers from the segregs argument and also stores the DS and ES registers into segregs after the function call.)

Return Value

The return value is the value in the AX register after the interrupt returns. If the cflag field in outregs is nonzero, an error has occurred; in such cases, the _doserrno variable is also set to the corresponding error code.

See Also

»_bdos,« »_int86x,« »_intdos,« »_intdosx«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * INT86.C: This program uses _int86 to call the BIOS video
 * service (INT 10H) to get information about the cursor.
 */

#include <dos.h>
#include <stdio.h>

void main( void )
{
   union _REGS inregs, outregs;

   /* Set up to get cursor information. */
   inregs.h.ah = 3;     /* Get cursor position function */
   inregs.h.bh = 0;     /* Page 0 */

   /* Execute video interrupt: */
   _int86( 0x10, &inregs, &outregs );

   /* Display results. */
   printf( "Cursor position\n\tRow: %d\n\tColumn: %d\n",
           outregs.h.dh, outregs.h.dl );
   printf( "Cursor shape\n\tStart: %d\n\tEnd: %d\n",
           outregs.h.ch, outregs.h.cl );
}

Output

Cursor position
   Row: 42
   Column: 0
Cursor shape
   Start: 4
   End: 7


Description: _int86x
  _int86x

#include <dos.h>

int _int86x( int intnum, union _REGS *inregs, union _REGS *outregs, struct _SREGS *segregs );

intnum    Interrupt number

inregs    Register values on call

outregs    Register values on return

segregs    Segment-register values on call

Remarks

The _int86x function executes the 8086-processor-family interrupt specified by the interrupt number intnum. Unlike the _int86 function, _int86x accepts segment-register values in segregs, enabling programs that use large-model data segments or far pointers to specify which segment or pointer should be used during the system call.

Before executing the specified interrupt, _int86x copies the contents of inregs and segregs to the corresponding registers. Only the DS and ES register values in segregs are used. After the interrupt returns, the function copies the current register values to outregs, copies the current ES and DS values to segregs, and restores DS. It also copies the status of the system carry flag to the cflag field in outregs. The _REGS and _SREGS types are defined in the include file DOS.H. Segment values for the segregs argument can be obtained by using either the _segread function or the _FP_SEG macro.

Return Value

The return value is the value in the AX register after the interrupt returns. If the cflag field in outregs is nonzero, an error has occurred; in such cases, the _doserrno variable is also set to the corresponding error code.

See Also

»_bdos,« »_FP_SEG,« »_int86,« »_intdos,« »_intdosx,« »_segread«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * INT86X.C: In this program, _int86x executes an INT 21H
 * instruction to invoke MS-DOS system call 43H (change file
 * attributes). The  program uses _int86x because the file, which is
 * referenced with a far pointer, may be in a segment other than the
 * default data segment. Thus, the program must explicitly set the
 * DS register with the _SREGS structure.
 */

#include <signal.h>
#include <dos.h>
#include <stdio.h>
#include <process.h>

char __far *filename = "int86x.c";

void main( void )
{
   union  _REGS inregs, outregs;
   struct _SREGS segregs;
   int    result;

   inregs.h.ah = 0x43;   /* MS-DOS function to change attributes */
   inregs.h.al = 0;      /* Subfunction 0 to get attributes      */
   inregs.x.dx = _FP_OFF( filename ); /* DS:DX points to filename */
   segregs.ds  = _FP_SEG( filename );
   result = _int86x( 0x21, &inregs, &outregs, &segregs );
   if( outregs.x.cflag )
      printf( "Can't get file attributes; error no. %d\n", result);
   else
      printf( "Attribs = 0x%.4x\n", outregs.x.cx );
}

Output

Attribs = 0x0020


Description: _intdos
  _intdos

#include <dos.h>

int _intdos( union _REGS *inregs, union _REGS *outregs );

inregs    Register values on call

outregs    Register values on return

Remarks

The _intdos function invokes the MS-DOS system call specified by register values defined in inregs and returns the effect of the system call in outregs. The inregs and outregs arguments are unions of type _REGS. The _REGS type is defined in the include file DOS.H. To invoke a system call, _intdos executes an INT 21H instruction. Before executing the instruction, the function copies the contents of inregs to the corresponding registers. After the INT instruction returns, _intdos copies the current register values to outregs. It also copies the status of the system carry flag to the cflag field in outregs. A nonzero cflag field indicates the flag was set by the system call and also indicates an error condition.

The _intdos function is used to invoke MS-DOS system calls that take arguments for input or output in registers other than DX (DH/DL) and AL. The _intdos function is also used to invoke system calls that indicate errors by setting the carry flag. Under any other conditions, the _bdos function can be used. Do not use the _intdos function to call interrupts that modify the DS or ES registers. Instead, use the _intdosx or _int86x function. (The __intdosx and int86x functions load the DS and ES registers from the segregs argument and also store the DS and ES registers into segregs after the function call.)

Return Value

The _intdos function returns the value of the AX register after the system call is completed. If the cflag field in outregs is nonzero, an error has occurred and _doserrno is also set to the corresponding error code.

See Also

»_bdos,« »_intdosx«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * INTDOS.C: This program uses _intdos to invoke
 * MS-DOS system call 2AH (gets the current date).
 */

#include <dos.h>
#include <stdio.h>

void main( void )
{
   union _REGS inregs, outregs;

   inregs.h.ah = 0x2a;          /* DOS Get Date function: */
   _intdos( &inregs, &outregs );
   printf( "Date: %d/%d/%d\n", outregs.h.dh,
                               outregs.h.dl, outregs.x.cx );
}

Output

Date: 3/25/1993


Description: _intdosx
  _intdosx

#include <dos.h>

int _intdosx( union _REGS *inregs, union _REGS *outregs, struct _SREGS *segregs );

inregs    Register values on call

outregs    Register values on return

segregs    Segment-register values on call

Remarks

The _intdosx function invokes the MS-DOS system call specified by register values defined in inregs and returns the results of the system call in outregs. Unlike the _intdos function, _intdosx accepts segment-register values in segregs, enabling programs that use large-model data segments or far pointers to specify which segment or pointer should be used during the system call. The _REGS and _SREGS types are defined in the include file DOS.H. To invoke a system call, _intdosx executes an INT 21H instruction. Before executing the instruction, the function copies the contents of inregs and segregs to the corresponding registers. Only the DS and ES register values in segregs are used. After the INT instruction returns, _intdosx copies the current register values to outregs and restores DS. It also copies the status of the system carry flag to the cflag field in outregs. A nonzero cflag field indicates the flag was set by the system call and also indicates an error condition.

The _intdosx function is used to invoke MS-DOS system calls that take an argument in the ES register or that take a DS register value different from the default data segment. Segment values for the segregs argument can be obtained by using either the _segread function or the _FP_SEG macro.

Return Value

The _intdosx function returns the value of the AX register after the system call is completed. If the cflag field in outregs is nonzero, an error has occurred; in such cases, _doserrno is also set to the corresponding error code.

See Also

»_bdos,« »_FP_SEG,« »_intdos,« »_segread«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * INTDOSX.C Sends a $-terminated string
 * to the standard output device
 */

#include <dos.h>
#include <stdio.h>

char __far *buffer = "Dollar-sign terminated string\n\r\n\r$";

void main( void )
{
   union  _REGS inregs, outregs;
   struct _SREGS segregs;

   /* Print a $-terminated string on the screen
   /* using MS-DOS function 0x09.
    */
   inregs.h.ah = 0x9;
   inregs.x.dx = _FP_OFF( buffer );
   segregs.ds  = _FP_SEG( buffer );
   _intdosx( &inregs, &outregs, &segregs );
}

Output

Dollar-sign terminated string


Description: is Functions
  is, isw Functions

#include <ctype.h>     For is functions

#include <wchar.h>    For isw functions use either WCHAR.H (for ANSI compatibility) or CTYPE.H

int isalnum( int c );

int isalpha( int c );

int __isascii( int c );

int iscntrl( int c );

int __iscsym( int c );

int __iscsymf( int c );

int isdigit( int c );

int isgraph( int c );

int isleadbyte( int c );

int islower( int c );

int isprint( int c );

int ispunct( int c );

int isspace( int c );

int isupper( int c );

int isxdigit( int c );

int iswalnum( wint_t c );

int iswalpha( wint_t c );

int iswascii( wint_t c );

int iswcntrl( wint_t c );

int iswctype( wint_t c, wctype_t desc );

int iswdigit( wint_t c );

int iswgraph( wint_t c );

int iswlower( wint_t c );

int iswprint( wint_t c );

int iswpunct( wint_t c );

int iswspace( wint_t c );

int iswupper( wint_t c );

int iswxdigit( wint_t c );

c    Integer to test

desc    Property to test for

Remarks

The is routines produce meaningful results for any integer argument from −1 (EOF) to UCHAR_MAX (0xFF), inclusive. For the is routines, note that the expected argument type is int; if a signed character is passed, it may be converted to an integer by sign extension, which may yield unpredictable results.

The isw routines produce meaningful results for any integer value from −1 (WEOF) to 0xFFFF, inclusive. The wint_t data type, defined in WCHAR.H, is an integer type that can hold any wide character or the wide-character end-of-file (WEOF) value. With the exception of iswctype, which is implemented only as a function, each of these routines is implemented both as a function and as a macro.

For each of the is routines except isdigit and isxdigit, the result of the test for the specified condition is dependent upon the LC_CTYPE category of the current locale; see the »setlocale« function for more information. In the "C" locale, the test conditions for the is functions are as follows:

isalnum    Alphanumeric (A−Z, a−z, or 0−9)

isalpha    Letter (A−Z or a−z)

__isascii    ASCII character (0x00−0x7F)

iscntrl    Control character (0x00−0x1F or 0x7F)

__iscsym    Letter, underscore, or digit

__iscsymf    Letter or underscore

isdigit    Digit (0−9)

isgraph    Printable character except space ( )

isleadbyte    First byte of a multibyte character

islower    Lowercase letter (a−z)

isprint    Printable character (0x20−0x7E)

ispunct    Punctuation character

isspace    White-space character (0x09−0x0D or 0x20)

isupper    Uppercase letter (A−Z)

isxdigit    Hexadecimal digit (A−F, a−f, or 0−9)

For the isw routines, the result of the test for the specified condition is independent of locale. The test conditions for the isw functions are as follows:

iswalnum    iswalpha or iswdigit

iswalpha    Any wide character that is one of an implementation-defined set for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. In the "C" locale, iswalpha returns true only for wide characters for which iswupper or iswlower is true.

iswascii    Wide-character representation of ASCII character (0x0000 − 0x007F)

iswcntrl    Control wide character

iswctype    Character has property specified by the desc argument. For each valid value of the desc argument in iswctype, there is an equivalent wide-character testing function, as shown in Table R.2:

Table R.2    Equivalence of iswctype( c, desc ) to Other isw Testing Functions

iswctype( c, desc ) Equivalent	Value of desc
iswalpha( c )	_ALPHA
iswalnum( c )	_ALPHA | _DIGIT
iswcntrl( c )	_CONTROL
iswdigit( c )	_DIGIT
iswgraph( c )	_ALPHA | _DIGIT | _PUNCT
iswlower( c )	_LOWER
iswprint( c )	_ALPHA | _BLANK | _DIGIT | _PUNCT
iswpunct( c )	_PUNCT
iswspace( c )	_SPACE
iswupper( c )	_UPPER
iswxdigit( c )	_HEX
iswdigit    Wide character corresponding to a decimal-digit character

iswgraph    Printable wide character except space wide character (L' ')

iswlower    Lowercase letter, or one of an implementation-defined set of wide characters for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. In the "C" locale, iswlower returns true only for wide characters that correspond to lowercase letters.

iswprint    Printable wide character, including space wide character (L' ')

iswpunct    Printable wide character that is neither the space wide character (L' ') nor a wide character for which iswalnum is true

iswspace    Wide character that corresponds to a standard white-space character or is one of an implementation-defined set of wide characters for which iswalnum is false. The standard white-space characters are: space (L' '), formfeed (L'\f'), newline (L'\n'), carriage return (L'\r'), horizontal tab (L'\t'), and vertical tab (L'\v'). In the "C" locale, iswspace returns true only for the standard white-space wide characters.

iswupper    Wide character that is uppercase or is one of an implementation-defined set of wide characters for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. In the "C" locale, iswupper returns true only for wide characters that correspond to uppercase characters.

iswxdigit    Wide character that corresponds to a hexadecimal-digit character

Return Value

Each of the is and isw routines returns a nonzero value if the integer satisfies the test condition or 0 if it does not. In the "C" locale and in Single Byte Character Set (SBCS) locales, isleadbyte always returns 0.

See Also

»setlocale,« »__toascii,« »tolower,« »toupper «

Compatibility

isalnum, isalpha, iscntrl, isdigit, isgraph, islower, isprint, ispunct, isspace, isupper, isxdigit:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

__isascii:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

__iscsym, __iscsymf:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

isleadbyte, iswalnum, iswalpha, iswcntrl, iswctype, iswdigit, iswgraph, iswlower, iswprint, iswpunct, iswspace, iswupper, iswxdigit:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

__iswascii:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use __isascii for compatibility with ANSI naming conventions of non-ANSI functions. Use isascii and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* ISFAM.C: This program tests all characters between 0x0
 * and 0x7F, then displays each character with abbreviations
 * for the character-type codes that apply.
 */

#include <stdio.h>
#include <ctype.h>

void main( void )
{
   int ch;

   for( ch = 0; ch <= 0x7F; ch++ )
   {
      printf( "%.2x  ", ch );
      printf( " %c", isprint( ch )  ? ch   : '\0' );
      printf( "%4s", isalnum( ch )  ? "AN" : "" );
      printf( "%3s", isalpha( ch )  ? "A"  : "" );
      printf( "%3s", __isascii( ch )  ? "AS" : "" );
      printf( "%3s", iscntrl( ch )  ? "C"  : "" );
      printf( "%3s", __iscsym( ch )  ? "CS "  : "" );
      printf( "%3s", __iscsymf( ch )  ? "CSF"  : "" );
      printf( "%3s", isdigit( ch )  ? "D"  : "" );
      printf( "%3s", isgraph( ch )  ? "G"  : "" );
      printf( "%3s", islower( ch )  ? "L"  : "" );
      printf( "%3s", ispunct( ch )  ? "PU" : "" );
      printf( "%3s", isspace( ch )  ? "S"  : "" );
      printf( "%3s", isprint( ch )  ? "PR" : "" );
      printf( "%3s", isupper( ch )  ? "U"  : "" );
      printf( "%3s", isxdigit( ch ) ? "X"  : "" );
      printf( "\n" );
   }
}

Output

00
01
02
.
.
.

20            AS                       S PR
21   !        AS              G    PU    PR
22   "        AS              G    PU    PR
23   #        AS              G    PU    PR
.
.
.


Description: _isatty
  _isatty

#include <io.h>

int _isatty( int handle );

handle    Handle referring to device to be tested

Remarks

The _isatty function determines whether handle is associated with a character device (a terminal, console, printer, or serial port).

Return Value

The _isatty function returns a nonzero value if the device is a character device. Otherwise, the return value is 0.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _isatty for compatibility with ANSI naming conventions of non-ANSI functions. Use isatty and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* ISATTY.C: This program checks to see whether
 * stdout has been redirected to a file.
 */

#include <stdio.h>
#include <io.h>

void main( void )
{
   if( _isatty( _fileno( stdout ) ) )
      printf( "stdout has not been redirected to a file\n" );
   else
      printf( "stdout has been redirected to a file\n");
}

Output

stdout has been redirected to a file


Description: _isnan
  _isnan

#include <float.h>

int    _isnan( double x );

x    Double-precision floating-point value

Remarks

The _isnan function tests a given double-precision floating-point value x, returning a nonzero value if x is a NAN. Otherwise, it returns 0.

Return Value

The  _isnan function returns a nonzero value (TRUE) if the argument x is a NAN, and 0 (FALSE) if x is not a NAN.

See Also

»_finite,« »_fpclass«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _itoa
  _itoa

#include <stdlib.h>

char *_itoa( int value, char *string, int radix );

value    Number to be converted

string    String result

radix    Base of value

Remarks

The _itoa function converts the digits of the given value argument to a null-terminated character string and stores the result (up to 17 bytes) in string. The radix argument specifies the base of value; it must be in the range 2−36. If radix equals 10 and value is negative, the first character of the stored string is the minus sign (−).

Return Value

The _itoa function returns a pointer to string. There is no error return.

See Also

»_ltoa,« »_ultoa«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ITOA.C: This program converts integers of various
 * sizes to strings in various radixes.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char buffer[20];
   int  i = 3445;
   long l = -344115L;
   unsigned long ul = 1234567890UL;

   _itoa( i, buffer, 10 );
   printf( "String of integer %d (radix 10): %s\n", i, buffer );
   _itoa( i, buffer, 16 );
   printf( "String of integer %d (radix 16): 0x%s\n", i, buffer );
   _itoa( i, buffer, 2  );
   printf( "String of integer %d (radix 2): %s\n", i, buffer );

   _ltoa( l, buffer, 16 );
   printf( "String of long int %ld (radix 16): 0x%s\n", l,
                                                    buffer );

   _ultoa( ul, buffer, 16 );
   printf( "String of unsigned long %lu (radix 16): 0x%s\n", ul,
                                                    buffer );
}

Output

String of integer 3445 (radix 10): 3445
String of integer 3445 (radix 16): 0xd75
String of integer 3445 (radix 2): 110101110101
String of long int -344115 (radix 16): 0xfffabfcd
String of unsigned long 1234567890 (radix 16): 0x499602d2


Description: _kbhit
  _kbhit

#include <conio.h>

int _kbhit( void );

Remarks

The _kbhit function checks the console for a recent keystroke. If the function returns a nonzero value, a keystroke is waiting in the buffer. The program can then call _getch or _getche to get the keystroke.

Return Value

The _kbhit function returns a nonzero value if a key has been pressed. Otherwise, it returns 0.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* KBHIT.C: This program loops until the user
 * presses a key. If _kbhit returns nonzero, a
 * keystroke is waiting in the buffer. The program
 * can call _getch or _getche to get the keystroke.
 */

#include <conio.h>
#include <stdio.h>

void main( void )
{
   /* Display message until key is pressed. */
   while( !_kbhit() )
      _cputs( "Hit me!! " );

   /* Use _getch to throw key away. */
   printf( "\nKey struck was '%c'\n", _getch() );
   _getch();
}

Output

Hit me!! Hit me!! Hit me!! Hit me!! Hit me!! Hit me!! Hit me!!
Key struck was 'q'


Description: labs
  labs

#include <stdlib.h>

#include <math.h>

long labs( long n );

n    Long-integer value

Remarks

The labs function produces the absolute value of its long-integer argument n.

Return Value

The labs function returns the absolute value of its argument. There is no error return.

See Also

»abs,« »_cabs,« »fabs«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »abs.«


Description: ldexp, _ldexpl
  ldexp, ldexpl

#include <math.h>

double ldexp( double x, int exp );

long double ldexpl( long double x, int exp );

x    Floating-point value

exp    Integer exponent

Remarks

The ldexp and ldexpl functions calculate the value of x * (2 raised to the power of exp).

Return Value

These functions return an exponential value if successful. On overflow (depending on the sign of x), ldexp returns +/− HUGE_VAL, and ldexpl returns +/−_LHUGE_VAL; the errno variable is set to ERANGE. The ldexpl function uses the 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

See Also

»frexp,« »modf«

Compatibility

ldexp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

ldexpl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* LDEXP.C */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 4.0, y;
   int p = 3;

   y = ldexp( x, p );
   printf( "%2.1f times two to the power of %d is %2.1f\n", x, p, y );
}

Output

4.0 times two to the power of 3 is 32.0


Description: ldiv
  ldiv

#include <stdlib.h>

ldiv_t ldiv ( long int numer, long int denom );

numer    Numerator

denom    Denominator

Remarks

The ldiv function divides numer by denom, computing the quotient and the remainder. The sign of the quotient is the same as that of the mathematical quotient. Its absolute value is the largest integer that is less than the absolute value of the mathematical quotient. If the denominator is 0, the program will terminate with an error message. The ldiv function is similar to the div function, with the difference being that the arguments and the members of the returned structure are all of type long int.

The ldiv_t structure, defined in STDLIB.H, contains long int quot, the quotient, and long int rem, the remainder.

Return Value

The ldiv function returns a structure of type ldiv_t, that comprises both the quotient and the remainder.

See Also

»div«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* LDIV.C: This program takes two long integers
 * as command-line arguments and displays the
 * results of the integer division.
 */

#include <stdlib.h>
#include <math.h>
#include <stdio.h>

void main( void )
{
   long x = 5149627, y = 234879;
   ldiv_t div_result;

   div_result = ldiv( x, y );
   printf( "For %ld / %ld, the quotient is ", x, y );
   printf( "%ld, and the remainder is %ld\n",
            div_result.quot, div_result.rem );
}

Output

For 5149627 / 234879, the quotient is 21, and the remainder is 217168


Description: _lfind
  _lfind

#include <search.h>

void *_lfind( const void *key, const void *base, unsigned int *num, unsigned int width, int ( __cdecl *compare )( const void *elem1, const void *elem2 ) );

key    Object to search for

base    Pointer to base of search data

num    Number of array elements

width    Width of array elements

compare( )    Pointer to comparison routine

elem1    Pointer to the key for the search

elem2    Pointer to the array element to be compared with the key

Remarks

The _lfind function performs a linear search for the value key in an array of num elements; each element is width bytes in size. (Unlike bsearch, _lfind does not require the array to be sorted.) The base argument is a pointer to the base of the array to be searched. The compare argument is a pointer to a user-supplied routine that compares two array elements and then returns a value specifying their relationship. The _lfind function calls the compare routine one or more times during the search, passing pointers to two array elements on each call. This routine must compare the elements, then return nonzero, meaning the elements are different, or 0, meaning the elements are identical.

Return Value

If the key is found, _lfind returns a pointer to the element of the array at base that matches key. If the key is not found, _lfind returns NULL.

See Also

»bsearch,« »_lsearch,« »qsort«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _lfind for compatibility with ANSI naming conventions of non-ANSI functions. Use lfind and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* LFIND.C: This program uses _lfind to search for
 * the word "hello" in the command-line arguments.
 */

#include <search.h>
#include <string.h>
#include <stdio.h>

int compare( const void *arg1, const void *arg2 );

void main( unsigned int argc, char **argv )
{
   char **result;
   char *key = "hello";

   result = (char **)_lfind( &key, argv,
                      &argc, sizeof(char *), compare );
   if( result )
      printf( "%s found\n", *result );
   else
      printf( "hello not found!\n" );
}

int compare(const void *arg1, const void *arg2 )
{
   return( _stricmp( * (char**)arg1, * (char**)arg2 ) );
}

Output

[C:\code]lfind Hello World
Hello found


Description: _lineto Functions
  _lineto Functions

#include <graph.h>

short __far _lineto( short x, short y );

short __far _lineto_w( double wx, double wy );

x, y    End point

wx, wy    End point

Remarks

The functions in the _lineto family draw a line from the current graphics position up to and including the destination point. The destination point for the _lineto function is given by the view-coordinate point (x, y). The destination point for the _lineto_w function is given by the window-coordinate point (wx, wy). The line is drawn using the current color, logical write mode, and line style. If no error occurs, _lineto sets the current graphics position to the view-coordinate point (x, y); _lineto_w sets the current position to the window-coordinate point (wx, wy). If you use _floodfill to fill in a closed figure drawn with _lineto calls, the figure must be drawn with a solid line-style pattern.

Return Value

The _lineto and _lineto_w routines return a nonzero value if anything is drawn; otherwise, they return 0.

See Also

»_getcurrentposition functions,« »_moveto functions,« »_setlinestyle«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_moveto.«


Description: localeconv
  localeconv

#include <locale.h>

struct lconv *localeconv( void );

Remarks

The localeconv function gets detailed information on the locale-specific settings for numeric formatting of the program's current locale. This information is stored in a structure of type lconv. The lconv structure, defined in LOCALE.H, contains the following members:

char *decimal_point    Decimal-point character for nonmonetary quantities.

char *thousands_sep    Character used to separate groups of digits to the left of the decimal point for nonmonetary quantities.

char *grouping    Size of each group of digits in nonmonetary quantities.

char *int_curr_symbol    International currency symbol for the current locale. The first three characters specify the alphabetic international currency symbol as defined in the ISO 4217 Codes for the Representation of Currency and Funds standard. The fourth character (immediately preceding the null character) is used to separate the international currency symbol from the monetary quantity.

char *currency_symbol    Local currency symbol for the current locale.

char *mon_decimal_point    Decimal-point character for monetary quantities.

char *mon_thousands_sep    Separator for groups of digits to the left of the decimal place in monetary quantities.

char *mon_grouping    Size of each group of digits in monetary quantities.

char *positive_sign    String denoting sign for nonnegative monetary quantities.

char *negative_sign    String denoting sign for negative monetary quantities.

char int_frac_digits    Number of digits to the right of the decimal point in internationally formatted monetary quantities.

char frac_digits    Number of digits to the right of the decimal point in formatted monetary quantities.

char p_cs_precedes    Set to 1 if the currency symbol precedes the value for a nonnegative formatted monetary quantity. Set to 0 if the symbol follows the value.

char p_sep_by_space    Set to 1 if the currency symbol is separated by a space from the value for a nonnegative formatted monetary quantity. Set to 0 if there is no space separation.

char n_cs_precedes    Set to 1 if the currency symbol precedes the value for a negative formatted monetary quantity. Set to 0 if the symbol succeeds the value.

char n_sep_by_space    Set to 1 if the currency symbol is separated by a space from the value for a negative formatted monetary quantity. Set to 0 if there is no space separation.

char p_sign_posn    Position of positive sign in nonnegative formatted monetary quantities.

char n_sign_posn    Position of positive sign in negative formatted monetary quantities.

The char * members of the structure are pointers to strings. Any of these (other than char *decimal_point) that equals "" is either of zero length or is not supported in the current locale. The char members of the structure are nonnegative numbers. Any of these that equals CHAR_MAX is not supported in the current locale.

The elements of grouping and mon_grouping are interpreted according to the following rules:

CHAR_MAX    No further grouping is to be performed.

0    The previous element is to be repeatedly used for the remainder of the digits.

n    The integer value n is the number of digits that make up the current group. The next element is examined to determine the size of the next group of digits before the current group.

The values for p_sign_posn and n_sign_posn are interpreted according to the following rules:

0    Parentheses surround the quantity and currency symbol

1    Sign string precedes the quantity and currency symbol

2    Sign string follows the quantity and currency symbol

3    Sign string immediately precedes the currency symbol

4    Sign string immediately follows the currency symbol

Return Value

The localeconv function returns a pointer to a filled-in object of type struct lconv. The values contained in the object can be overwritten by subsequent calls to localeconv and do not directly modify the object. Calls to the setlocale function with category values of LC_ALL, LC_MONETARY, or LC_NUMERIC will overwrite the contents of the structure.

See Also

»setlocale,« »strcoll,« »strftime,« »strxfrm«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: localtime
  localtime

#include <time.h>

struct tm *localtime( const time_t *timer );

timer    Pointer to stored time

Remarks

The localtime function converts a time stored as a time_t value and stores the result in a structure of type tm. The long value timer represents the seconds elapsed since midnight (00:00:00), January 1, 1970, Universal coordinated time. This value is usually obtained from the time function. The fields of the structure type tm store the following values, each of which is an int:

tm_sec    Seconds after the minute (0−59)

tm_min     Minutes after the hour (0−59)

tm_hour    Hours since midnight (0−23)

tm_mday     Day of month (1−31)

tm_mon     Month (0−11; January = 0)

tm_year     Year (current year minus 1900)

tm_wday     Day of week (0−6; Sunday = 0)

tm_yday     Day of year (0−365; January 1 = 0)

tm_isdst    Positive value if daylight saving time is in effect; 0 if daylight saving time is not in effect; negative value if status of daylight saving time is unknown

Note that the gmtime, mktime, and localtime functions use a single statically allocated tm structure for the conversion. Each call to one of these routines destroys the result of the previous call.

The localtime function makes corrections for the local time zone if the user first sets the environment variable TZ. When TZ is set, three other environment variables (_timezone, _daylight, and _tzname) are automatically set as well. See the reference page for »_tzset« for a description of these variables. The TZ variable is not part of the ANSI standard definition of localtime but is a Microsoft extension.

Note  The target environment should attempt to determine whether daylight saving time is in effect.

Return Value

The localtime function returns a pointer to the structure result. If the value in timer represents a date before midnight, January 1, 1970, the function returns NULL.

See Also

»asctime,« »ctime,« »_ftime,« »gmtime,« »time,« »_tzset«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* LOCALTIM.C: This program uses time to get the current time
 * and then uses localtime to convert this time to a structure
 * representing the local time. The program converts the result
 * from a 24-hour clock to a 12-hour clock and determines the
 * proper extension (AM or PM).
 */

#include <stdio.h>
#include <string.h>
#include <time.h>

void main( void )
{
        struct tm *newtime;
        char am_pm[] = "AM";
        time_t long_time;

        time( &long_time );            /* Get time as long integer. */
        newtime = localtime( &long_time ); /* Convert to local time. */

        if( newtime->tm_hour > 12 )        /* Set up extension. */
                strcpy( am_pm, "PM" );
        if( newtime->tm_hour > 12 )        /* Convert from 24-hour */
                newtime->tm_hour -= 12;    /*   to 12-hour clock.  */
        if( newtime->tm_hour == 0 )    /*Set hour to 12 if midnight. */
                newtime->tm_hour = 12;

        printf( "%.19s %s\n", asctime( newtime ), am_pm );
}

Output

Tue Mar 23 11:28:17 AM


Description: _locking
  _locking

#include <sys\locking.h>

#include <io.h>

int _locking( int handle, int mode, long nbytes );

handle    File handle

mode    File-locking mode

nbytes    Number of bytes to lock

Remarks

The _locking function locks or unlocks nbytes bytes of the file specified by handle. Locking bytes in a file prevents access to those bytes by other processes. All locking or unlocking begins at the current position of the file pointer and proceeds for the next nbytes bytes. It is possible to lock bytes past the end of the file.

The mode argument specifies the locking action to be performed. It must be one of the following manifest constants:

_LK_LOCK    Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error.

_LK_NBLCK    Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.

_LK_NBRLCK    Same as _LK_NBLCK.

_LK_RLCK    Same as _LK_LOCK.

_LK_UNLCK    Unlocks the specified bytes. (The bytes must have been previously locked.)

More than one region of a file can be locked, but no overlapping regions are allowed. When a region of a file is being unlocked, it must correspond to a region that was previously locked. The _locking function does not merge adjacent regions; if two locked regions are adjacent, each region must be unlocked separately. Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.

The _locking function should be used only with MS-DOS versions 3.0 and later; it has no effect under earlier versions of MS-DOS. Also, file sharing must be loaded to use the _locking function. Note that with MS-DOS versions 3.0 and 3.1, the files locked by parent processes may become unlocked when child processes exit.

Return Value

The _locking function returns 0 if successful. A return value of −1 indicates failure, and errno is set to one of the following values:

EACCES    Locking violation (file already locked or unlocked).

EBADF    Invalid file handle.

EDEADLOCK    Locking violation. This is returned when the _LK_LOCK or _LK_RLCK flag is specified and the file cannot be locked after 10 attempts.

EINVAL    An invalid argument was given to the function.

Use _locking for compatibility with ANSI naming conventions of non-ANSI functions. Use locking and link with OLDNAMES.LIB for UNIX compatibility.

See Also

»_creat,« »_open«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * LOCKING.C: This program opens a file with sharing. It locks
 * some bytes before reading them, then unlocks them. Note that the
 * program works correctly only if the following conditions are met:
 *    - The file exists
 *    - The program is run with MS-DOS version 3.0 or later
 *      with file sharing installed (SHARE.COM or SHARE.EXE), or
 *      if a Microsoft Networks compatible network is running
 */

#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <sys\locking.h>
#include <share.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int  fh, numread;
   char buffer[40];

   /* Quit if can't open file or system doesn't
    * support sharing.
    */
   fh = _sopen( "locking.c", _O_RDWR, _SH_DENYNO,
                 _S_IREAD | _S_IWRITE );
   if( (fh == -1) || (_osmajor < 3) )
      exit( 1 );

   /* Lock some bytes and read them. Then unlock. */
   if( _locking( fh, LK_NBLCK, 30L ) != -1 )
   {
      printf( "No one can change these bytes " );
      printf( "while I'm reading them\n" );
      numread = _read( fh, buffer, 30 );
      printf( "%d bytes read: %.30s\n", numread, buffer );
      lseek( fh, 0L, SEEK_SET );
      _locking( fh, LK_UNLCK, 30L );
      printf( "Now I'm done. Do what you will with them\n" );
   }
   else
      perror( "Locking failed\n" );

   _close( fh );
}

Output

No one can change these bytes while I'm reading them
29 bytes read: //+(all)
/* LOCKING.C: This pp
Now I'm done. Do what you will with them


Description: log Functions
  log Functions

#include <math.h>

double log( double x );

double log10( double x );

long double logl( long double x );

long double log10l( long double x );

x    Value whose logarithm is to be found

Remarks

The log and log10 functions calculate the natural logarithm and the base-10 logarithm, respectively, of x. The logl and log10l functions are the 80-bit counterparts and use the 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

Return Value

The log functions return the logarithm of x if successful. If x is negative, the functions print a _DOMAIN error message to stderr, return the value −HUGE_VAL (−_LHUGE_VAL for the long double functions), and set errno to EDOM. If x is 0, they print a _SING error message to stderr, and set errno to ERANGE. Error handling can be modified by using the _matherr or _matherrl routine.

See Also

»exp,« »_matherr,« »pow functions«

Compatibility

log, log10:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

logl, log10l:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* LOG.C: This program uses log and log10
 * to calculate the natural logarithm and
 * the base-10 logarithm of 9,000.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 9000.0;
   double y;

   y = log( x );
   printf( "log( %.2f ) = %f\n", x, y );
   y = log10( x );
   printf( "log10( %.2f ) = %f\n", x, y );
}

Output

log( 9000.00 ) = 9.104980
log10( 9000.00 ) = 3.954243


Description: _logb
  _logb

#include <float.h>

double _logb( double x );

x    Double-precision floating-point value

Remarks

The _logb function extracts the exponential value of its double-precision floating-point argument x, as though x were represented with infinite range. If the argument x is denormalized, it is treated as if it were normalized.

Return Value

The _logb function returns the unbiased exponential value of x.

See Also

»frexp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: long double Functions
  long double Functions

The 8087 family of numeric coprocessor chips supports the 80-bit precision floating-point data type. Beginning with Microsoft C version 6.0, the long double functions, whose names end with l, map the C long double type into this 80-bit, 10-byte form. Unlike the regular floating-point functions (such as acos), which return values of type double, these long double functions (such as acosl) return values of type long double. The long double functions also return their values on the coprocessor stack for all calling conventions. The long double type is also supported by the addition of the "L" prefix for a floating-point format specification in the printf and scanf family of functions.

In Windows NT, the long double data type is equivalent to the double data type. Therefore, the long double versions of the functions below are identical to their regular counterparts. The MATH.H header file uses macros to map the long double function declarations directly to their double-precision equivalents.

The long double versions are described on the reference pages for their regular counterparts. These are the regular run-time math functions with corresponding long double equivalents:

Function	Long double form	Function	Long double form
acos	acosl	frexp	frexpl
asin	asinl	_hypot	_hypotl
atan	atanl	ldexp	ldexpl
atan2	atan2l	log	logl
atof	_atold	log10	log10l
_cabs	_cabsl	_matherr	_matherrl
ceil	ceill	modf	modfl
cos	cosl	pow	powl
cosh	coshl	sin	sinl
exp	expl	sinh	sinhl
fabs	fabsl	sqrt	sqrtl
floor	floorl	tan	tanl
fmod	fmodl	tanh	tanhl


Description: longjmp
  longjmp

#include <setjmp.h>

void longjmp( jmp_buf env, int value );

env    Variable in which environment is stored

value    Value to be returned to setjmp call

Remarks

The longjmp function restores a stack environment and execution locale previously saved in env by setjmp. The setjmp and longjmp functions provide a way to execute a nonlocal goto; they are typically used to pass execution control to error handling or recovery code in a previously called routine without using the normal call and return conventions.

A call to setjmp causes the current stack environment to be saved in env. A subsequent call to longjmp restores the saved environment and returns control to the point immediately following the corresponding setjmp call. Execution resumes as if value had just been returned by the setjmp call. The values of all variables (except register variables) that are accessible to the routine receiving control contain the values they had when longjmp was called. The values of register variables are unpredictable. The value returned by setjmp must be nonzero. If value is passed as 0, the value 1 is substituted in the actual return.

The longjmp function must be called before the function that called setjmp returns. If longjmp is called after the function calling setjmp returns, unpredictable program behavior results.

Observe the following four restrictions when using longjmp:

•	Do not assume that the values of the register variables will remain the same. The values of register variables in the routine calling setjmp may not be restored to the proper values after longjmp is executed.

•	Do not use longjmp to transfer control from within one overlay to within another. The overlay manager keeps the overlay in memory after a call to longjmp.

•	Do not use longjmp to transfer control out of an interrupt-handling routine unless the interrupt is caused by a floating-point exception. In this case, a program may return from an interrupt handler via longjmp if it first reinitializes the floating-point math package by calling _fpreset.

•	Do not use longjmp or setjmp from a C++ program.

Return Value

None.

See Also

»setjmp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_fpreset.«


Description: _lrotl, _lrotr
  _lrotl, _lrotr

#include <stdlib.h>

unsigned long _lrotl( unsigned long value, int shift );

unsigned long _lrotr( unsigned long value, int shift );

value    Value to be rotated

shift    Number of bits to shift

Remarks

The _lrotl and _lrotr functions rotate value by shift bits. The _lrotl function rotates the value left. The _lrotr function rotates the value right. Both functions "wrap" bits rotated off one end of value to the other end.

Return Value

Both functions return the rotated value. There is no error return.

See Also

»_rotl,« »_rotr«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* LROT.C */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   unsigned long val = 0x0fac35791;

   printf( "0x%8.8lx rotated left eight times is 0x%8.8lx\n",
            val, _lrotl( val, 8 ) );
   printf( "0x%8.8lx rotated right four times is 0x%8.8lx\n",
            val, _lrotr( val, 4 ) );
}

Output

0xfac35791 rotated left eight times is 0xc35791fa
0xfac35791 rotated right four times is 0x1fac3579


Description: _lsearch
  _lsearch

#include <search.h>

void *_lsearch( const void *key, void *base, unsigned int *num, unsigned int width, int ( __cdecl *compare )( const void *elem1, const void *elem2 ) );

key    Object to search for

base    Pointer to base of search data

num    Number of elements

width    Width of elements

compare    Pointer to comparison routine

elem1    Pointer to the key for the search

elem2    Pointer to the array element to be compared with the key

Remarks

The _lsearch function performs a linear search for the value key in an array of num elements, each of width bytes in size. (Unlike bsearch, _lsearch does not require the array to be sorted.) The base argument is a pointer to the base of the array to be searched. If key is not found, _lsearch adds it to the end of the array and increments num.

The compare argument is a pointer to a user-supplied routine that compares two array elements and returns a value specifying their relationship. The _lsearch function calls the compare routine one or more times during the search, passing pointers to two array elements on each call. This routine must compare the elements, then return either nonzero, meaning the elements are different, or 0, meaning the elements are identical.

Return Value

If the key is found, _lsearch returns a pointer to the element of the array at base that matches key. If the key is not found, _lsearch returns a pointer to the newly added item at the end of the array.

See Also

»bsearch,« »_lfind«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _lsearch for compatibility with ANSI naming conventions of non-ANSI functions. Use lsearch and link with OLDNAMES.LIB for UNIX compatibility.

Example

See the example for »_lfind.«


Description: _lseek
  _lseek

#include <io.h>

#include <stdio.h>

long _lseek( int handle, long offset, int origin );

handle    Handle referring to open file

offset    Number of bytes from origin

origin    Initial position

Remarks

The _lseek function moves the file pointer associated with handle to a new location that is offset bytes from origin. The next operation on the file occurs at the new location. The origin argument must be one of the following constants, which are defined in STDIO.H:

SEEK_SET    Beginning of file

SEEK_CUR    Current position of file pointer

SEEK_END    End of file

The _lseek function can be used to reposition the pointer anywhere in a file. The pointer can also be positioned beyond the end of the file. An attempt to position the pointer before the beginning of the file causes an error only if you explicitly link with LSEEKCHK.OBJ.

Return Value

The _lseek function returns the offset, in bytes, of the new position from the beginning of the file. The function returns −1L to indicate an error and sets errno to either EBADF, meaning the file handle is invalid, or EINVAL, meaning the value for origin is invalid or the position specified by offset is before the beginning of the file. On devices incapable of seeking (such as terminals and printers), the return value is undefined.

See Also

»fseek,« »_tell«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _lseek for compatibility with ANSI naming conventions of non-ANSI functions. Use lseek and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* LSEEK.C: This program first opens a file named LSEEK.C.
 * It then uses _lseek to find the beginning of the file,
 * to find the current position in the file, and to find
 * the end of the file.
 */

#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int fh;
   long pos;               /* Position of file pointer */
   char buffer[10];

   fh = _open( "lseek.c", _O_RDONLY );

   /* Seek the beginning of the file: */
   pos = _lseek( fh, 0L, SEEK_SET );
   if( pos == -1L )
      perror( "_lseek to beginning failed" );
   else
      printf( "Position for beginning of file seek = %ld\n", pos );

   /* Move file pointer a little */
    _read( fh, buffer, 10 );

   /* Find current position: */
   pos = _lseek( fh, 0L, SEEK_CUR );
   if( pos == -1L )
      perror( "_lseek to current position failed" );
   else
      printf( "Position for current position seek = %ld\n", pos );

   /* Set the end of the file: */
   pos = _lseek( fh, 0L, SEEK_END );
   if( pos == -1L )
      perror( "_lseek to end failed" );
   else
      printf( "Position for end of file seek = %ld\n", pos );

   _close( fh );
}

Output

Position for beginning of file seek = 0
Position for current position seek = 10
Position for end of file seek = 1207


Description: _ltoa
  _ltoa

#include <stdlib.h>

char *_ltoa( long value, char *string, int radix );

value    Number to be converted

string    String result

radix    Base of value

Remarks

The _ltoa function converts the digits of value to a null-terminated character string and stores the result (up to 33 bytes) in string. The radix argument specifies the base of value, which must be in the range 2−36. If radix equals 10 and value is negative, the first character of the stored string is the minus sign (−).

Return Value

The _ltoa function returns a pointer to string. There is no error return.

See Also

»_itoa,« »_ultoa«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_itoa.«


Description: _makepath
  _makepath

#include <stdlib.h>

void _makepath( char *path, const char *drive, const char *dir, const char *fname, const char *ext );

path    Full path buffer

drive    Drive letter

dir    Directory path

fname    Filename

ext    File extension

Remarks

The _makepath routine creates a single path, composed of a drive letter, directory path, filename, and filename extension. The path argument should point to an empty buffer large enough to hold the complete path. The constant _MAX_PATH, defined in STDLIB.H, specifies the maximum size path that the _makepath function can handle. The other arguments point to buffers containing the path elements:

drive    The drive argument contains a letter (A, B, and so on) corresponding to the desired drive and an optional trailing colon. The _makepath routine will insert the colon automatically in the composite path if it is missing. If drive is a null character or an empty string, no drive letter and colon will appear in the composite path string.

dir    The dir argument contains the path of directories, not including the drive designator or the actual filename. The trailing slash is optional, and either forward slashes (\) or backslashes (/) or both may be used in a single dir argument. If a trailing slash ( / or \ ) is not specified, it will be inserted automatically. If dir is a null character or an empty string, no slash is inserted in the composite path string.

fname    The fname argument contains the base filename without any extensions. If fname is NULL or points to an empty string, no filename is inserted in the composite path string.

ext    The ext argument contains the actual filename extension, with or without a leading period (.). The _makepath routine will insert the period automatically if it does not appear in ext. If ext is a null character or an empty string, no period is inserted in the composite path string.

There are no size limits on any of the above four fields. However, the composite path must be no larger than the _MAX_PATH constant. The _MAX_PATH limit permits a path much larger than current operating-system versions will handle.

Return Value

None.

See Also

»_fullpath,« »_splitpath«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MAKEPATH.C */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char path_buffer[_MAX_PATH];
   char drive[_MAX_DRIVE];
   char dir[_MAX_DIR];
   char fname[_MAX_FNAME];
   char ext[_MAX_EXT];

   _makepath( path_buffer, "c", "\\sample\\crt\\", "makepath", "c" );
   printf( "Path created with _makepath: %s\n\n", path_buffer );
   _splitpath( path_buffer, drive, dir, fname, ext );
   printf( "Path extracted with _splitpath:\n" );
   printf( "  Drive: %s\n", drive );
   printf( "  Dir: %s\n", dir );
   printf( "  Filename: %s\n", fname );
   printf( "  Ext: %s\n", ext );
}

Output

Path created with _makepath: c:\sample\crt\makepath.c

Path extracted with _splitpath:
  Drive: c:
  Dir: \sample\crt\
  Filename: makepath
  Ext: .c


Description: malloc Functions
  malloc Functions

#include <stdlib.h>    For ANSI compatibility (malloc only)

#include <malloc.h>

void *malloc( size_t size );

void __based(void) *_bmalloc( __segment seg, size_t size );

void __far *_fmalloc( size_t size );

void __near *_nmalloc( size_t size );

size    Bytes to allocate

seg    Based heap segment selector

Remarks

Functions in the malloc family allocate a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information. If size is 0, each of these functions allocates a zero-length item in the heap and returns a valid pointer to that item.

The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

In large data models (compact-, large-, and huge-model programs), malloc maps to _fmalloc. In small data models (tiny-, small-, and medium-model programs), malloc maps to _nmalloc. The _fmalloc function allocates a memory block of at least size bytes in the far heap, which is outside the default data segment. The bmalloc function allocates a memory block of at least size bytes in the based heap segment specified by the segment selector seg.

The malloc functions allocate memory in the heap segment specified below:

malloc    Depends on data model of program

_bmalloc    Based heap segment specified by seg value

_fmalloc    Far heap (outside default data segment)

_nmalloc    Near heap (within default data segment)

The functions listed below call the malloc family of routines. In addition, the startup code uses malloc to allocate storage for the environ/envp and argv strings and arrays. The following routines call malloc:

_brealloc

calloc

_execl

_execle

_execlp

_execlpe

_execv

_execve

_execvp

_execvpe

fgetc

_fgetchar

fgets

fprintf

fputc

_fputchar

fputs

fread

_frealloc

fscanf

fseek

fsetpos

_fullpath

fwrite

getc

getchar

_getcwd

_getdcwd

gets

_getw

_nrealloc

_popen

printf

putc

putchar

_putenv

puts

_putw

scanf

_searchenv

setvbuf

_spawnl

_spawnle

_spawnlp

_spawnlpe

_spawnv

_spawnve

_spawnvp

_spawnvpe

_strdup

system

_tempnam

ungetc

vfprintf

vprintf

The following routines call _nmalloc:

_nrealloc	_nrealloc	_nstrdup	realloc
			(in small data models)
The following routines call _fmalloc:

frealloc	fcalloc	fstrdup	realloc
			(in large data models)
In Microsoft C version 5.1, the _fmalloc function retried allocating within the default data segment (that is, in the near heap) if sufficient memory was not available outside the default data segment. Since version 6.0, _fmalloc returns NULL under these conditions.

The _freect, _memavl, and _memmax functions called malloc in Microsoft C version 5.1 but do not do so in versions 6.0, 7.0, and this product.

Return Value

The malloc function returns a void pointer to the allocated space. The _nmalloc function returns a ( void __near * ) and _fmalloc returns a ( void __far * ). The _bmalloc function returns a ( void __based( void ) * ).

The _malloc, _fmalloc, and _nmalloc functions return NULL if there is insufficient memory available. The _bmalloc function returns _NULLOFF if there is insufficient memory available.

Always check the return from the malloc function, even if the amount of memory requested is small.

See Also

»calloc functions,« »free functions,« »realloc functions«

Compatibility

malloc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bmalloc, _fmalloc, _nmalloc:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MALLOC.C: This program allocates memory with
 * malloc, then frees the memory with free.
 */

#include <stdlib.h>         /* Definition of _MAX_PATH */
#include <stdio.h>
#include <malloc.h>

void main( void )
{
   char *string;

   /* Allocate space for a path name */
   string = malloc( _MAX_PATH );
   if( string == NULL )
      printf( "Insufficient memory available\n" );
   else
      printf( "Memory space allocated for path name\n" );
   free( string );
   printf( "Memory freed\n" );
}

Output

Memory space allocated for path name
Memory freed


Description: _matherr, _matherrl
  _matherr, _matherrl

#include <math.h>

int _matherr( struct _exception *except );

int _matherrl( struct _exceptionl *except );

except    Pointer to structure containing error information

Remarks

The _matherr functions process errors generated by the functions of the math library. The math functions call the appropriate _matherr routine whenever an error is detected. The _matherrl function uses the 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

The user can provide a different definition of the _matherr or _matherrl function to carry out special error handling.

When an error occurs in a math routine, _matherr is called with a pointer to an _exception type structure (defined in MATH.H) as an argument. The _exception structure contains the following elements:

int type    Exception type

char *name    Name of function where error occurred

double arg1, arg2    First and second (if any) argument to function

double retval    Value to be returned by function

The type specifies the type of math error. It is one of the following values, defined in MATH.H:

_DOMAIN    Argument domain error

_SING    Argument singularity

_OVERFLOW    Overflow range error

_PLOSS    Partial loss of significance

_TLOSS    Total loss of significance

_UNDERFLOW    The result is too small to be represented. (This condition is not currently supported.)

The structure member name is a pointer to a null-terminated string containing the name of the function that caused the error. The structure members arg1 and arg2 specify the values that caused the error. (If only one argument is given, it is stored in arg1.)

The default return value for the given error is retval. If you change the return value, remember that the return value must specify whether an error actually occurred. If the _matherr function returns 0, an error message can be displayed and errno is set to an appropriate error value. If _matherr returns a nonzero value, no error message is displayed, and errno remains unchanged.

Return Value

The _matherr functions should return 0 to indicate an error, and a nonzero value to indicate successful corrective action.

Use _matherr for compatibility with ANSI naming conventions of non-ANSI functions. Use matherr and link with OLDNAMES.LIB for UNIX compatibility.

See Also

»acos functions,« »asin functions,« »atan functions,« »Bessel functions,« »_cabs,« »cos functions,« »exp,« »_hypot,« »log functions,« »pow,« »sin functions,« »sqrt,« »tan functions«

Compatibility

_matherr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_matherrl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MATHERR.C illustrates writing an error routine for math
 * functions. The error function must be:
 *      _matherr
 *
 * To use _matherr, you must turn on the No Extended Dictionary
 * option within the development environment or use the /NOE
 * linker option outside the environment. For example:
 *      CL matherr.c /link /NOE
 */

#include <math.h>
#include <string.h>
#include <stdio.h>

void main()
{
    /* Do several math operations that cause errors. The _matherr
     * routine handles _DOMAIN errors, but lets the system handle
     * other errors normally.
     */
    printf( "log( -2.0 ) = %e\n", log( -2.0 ) );
    printf( "log10( -5.0 ) = %e\n", log10( -5.0 ) );
    printf( "log( 0.0 ) = %e\n", log( 0.0 ) );
}

/* Handle several math errors caused by passing a negative argument
 * to log or log10 (_DOMAIN errors). When this happens, _matherr
 * returns the natural or base-10 logarithm of the absolute value
 * of the argument and suppresses the usual error message.
 */
int _matherr( struct _exception *except )
{
    /* Handle _DOMAIN errors for log or log10. */
    if( except->type == _DOMAIN )
    {
        if( strcmp( except->name, "log" ) == 0 )
        {
            except->retval = log( -(except->arg1) );
            printf( "Special: using absolute value: %s: _DOMAIN "
                     "error\n", except->name );
            return 1;
        }
        else if( strcmp( except->name, "log10" ) == 0 )
        {
            except->retval = log10( -(except->arg1) );
            printf( "Special: using absolute value: %s: _DOMAIN "
                     "error\n", except->name );
            return 1;
        }
    }
    else
    {
        printf( "Normal: " );
        return 0;    /* Else use the default actions */
    }
}

Output

Special: using absolute value: log: _DOMAIN error
log( -2.0 ) = 6.931472e-001
Special: using absolute value: log10: _DOMAIN error
log10( -5.0 ) = 6.989700e-001
Normal: log( 0.0 ) = -1.#INF00e+000


Description: __max
  __max

#include <stdlib.h>

type __max( type a, type b );

type    Any numeric data type

a, b    Values of any numeric type to be compared

Remarks

The __max macro compares two values and returns the value of the larger one. The arguments can be of any numeric data type, signed or unsigned. Both arguments and the return value must be of the same data type.

Return Value

The macro returns the larger of the two arguments.

See Also

»__min«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »__min.«


Description: mblen, _fmblen
  mblen, _fmblen

#include <stdlib.h>

int mblen( const char *mbstr, size_t count );

int __far _fmblen(const char __far *mbstr, size_t count );

mbstr    The address of a sequence of bytes (a multibyte character)

count    The number of bytes to check

Remarks

The mblen function returns the length in bytes of a valid multibyte character. It examines count or fewer bytes contained in mbstr. It will not examine more than MB_CUR_MAX bytes. The _fmblen function is a 16-bit model-independent (large-model) form of the mblen function.

Return Value

If mbstr is not NULL, both mblen and _fmblen return the length, in bytes, of the multibyte character. If mbstr is NULL, or the object that it points to is the wide-character null character ('\0'), both functions return 0. If the object that mbstr points to does not form a valid multibyte character within the first count characters, both functions return −1.

See Also

»mbstowcs,« »mbtowc,« »wcstombs,« »wctomb,« »MB_CUR_MAX,« »MB_LEN_MAX«

Compatibility

mblen:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmblen:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MBLEN.CPP illustrates the behavior of the mblen function
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
    int      i;
    char    *pmbc = (char *)malloc( sizeof( char ) );
    wchar_t  wc   = L'a';

    printf( "Convert a wide character to multibyte character:\n" );
    i = wctomb( pmbc, wc );
    printf( "\tCharacters converted: %u\n", i );
    printf( "\tMultibyte character: %x\n\n", pmbc );

    printf( "Find length--in bytes--of multibyte character:\n" );
    i = mblen( pmbc, MB_CUR_MAX );
    printf( "\tLength--in bytes--of multibyte character: %u\n", i );
    printf( "\tWide character: %x\n\n", pmbc );

    printf( "Attempt to find length of a NULL pointer:\n" );
    pmbc = NULL;
    i = mblen( pmbc, MB_CUR_MAX );
    printf( "\tLength--in bytes--of multibyte character: %u\n", i );
    printf( "\tWide character: %x\n\n", pmbc );

    printf( "Attempt to find length of a wide-character NULL:\n" );
    wc = L'\0';
    wctomb( pmbc, wc );
    i  = mblen( pmbc, MB_CUR_MAX );
    printf( "\tLength--in bytes--of multibyte character: %u\n", i );
    printf( "\tWide character: %x\n", pmbc );
}

Output

Convert a wide character to multibyte character:
   Characters converted: 1
   Multibyte character: 2d02d4

Find length--in bytes--of multibyte character:
   Length--in bytes--of multibyte character: 1
   Wide character: 2d02d4

Attempt to find length of a NULL pointer:
   Length--in bytes--of multibyte character: 0
   Wide character: 0

Attempt to find length of a wide-character NULL:
   Length--in bytes--of multibyte character: 0
   Wide character: 0


Description: mbslen
  _mbslen

#include <stdlib.h>

size_t _mbslen( const char *mbstr );

mbstr    The address of a multibyte character string

Remarks

The _mbslen function returns the number of multibyte characters in a multibyte string, excluding the terminal NULL. The multibyte character sequences recognized are determined by the LC_CTYPE category of the current locale.

Return Value

The _mbslen function returns the number of multibyte characters in a multibyte string.

See Also

»mbstowcs,« »mbtowc,« »setlocale,« »wcstombs,« »wctomb,« »MB_CUR_MAX,« »MB_LEN_MAX«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MBSLEN.C illustrates the behavior of the _mbslen function
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
    int      i;
    char     *pmbc = (char *)malloc( sizeof( char ) );
    wchar_t  *ws   = L"widestring";

    printf( "Convert a wide character string to multibyte "
            "character string:\n" );
    i = wcstombs( pmbc, ws, MB_CUR_MAX );
    printf( "\tNumber of bytes converted: %u\n", i );
    printf( "\tMultibyte character: %s\n\n", pmbc );

    printf( "Find number of multibyte characters:\n" );
    i = _mbslen( (const unsigned char *)pmbc );
    printf( "\tNumber of multibyte characters in multibyte "
            "string: %u\n", i );
    printf( "\tMultibyte character: %x\n\n", pmbc );
}

Output

Convert a wide character string to multibyte character string:
   Number of bytes converted: 1
   Multibyte character: w

Find number of multibyte characters:
   Number of multibyte characters in multibyte string: 1
   Multibyte character: 2d026c


Description: mbstowcs, _fmbstowcs
  mbstowcs, _fmbstowcs

#include <stdlib.h>

size_t mbstowcs( wchar_t *wcstr, const char *mbstr, size_t count );

size_t __far _fmbstowcs(wchar_t __far *wcstr, const char __far *mbstr, size_t count );

wcstr    The address of a sequence of wide characters

mbstr    The address of a sequence of multibyte characters

count    The number of multibyte characters to convert

Remarks

The mbstowcs function converts count or fewer multibyte characters pointed to by mbstr to a string of corresponding wide characters that are determined by the current locale. It stores the resulting wide-character string at the address represented by wcstr. The result is similiar to a series of calls to the mbtowc function. If mbstowcs encounters the null character ('\0') either before or when count occurs, it converts the null character to a wide-character null character (L'\0') and stops. Thus, the wide-character string at wcstr is null-terminated only if a null character is encountered during conversion. If the sequences pointed to by wcstr and mbstr overlap, the behavior is undefined.

If the wcstr argument is NULL, the mbstowcs function returns the required size of the destination string.

The _fmbstowcs function is a 16-bit model-independent (large-model) form of the mbstowcs function. It can be called from any point in any program.

Return Value

If mbstowcs or (_fmbstowcs) successfully converts the source string, it returns the number of converted multibyte characters. If the wcstr argument is NULL, these functions return the required size of the destination string. If either function encounters an invalid multibyte character, it returns −1. If the return value is count, the wide-character string is not null-terminated.

See Also

»mblen,« »mbtowc,« »wcstombs,« »wctomb,« »MB_CUR_MAX,« »MB_LEN_MAX«

Compatibility

mbstowcs:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmbstowcs:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MBSTOWCS.CPP illustrates the behavior of the mbstowcs function
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
    int i;
    char    *pmbnull  = NULL;
    char    *pmbhello = (char *)malloc( MB_CUR_MAX );
    wchar_t *pwchello = L"Hi";
    wchar_t *pwc      = (wchar_t *)malloc( sizeof( wchar_t ));

    printf( "Convert to multibyte string:\n" );
    i = wcstombs( pmbhello, pwchello, MB_CUR_MAX );
    printf( "\tCharacters converted: %u\n", i );
    printf( "\tHex value of first" );
    printf( " multibyte character: %#.4x\n\n", pmbhello );

    printf( "Convert back to wide-character string:\n" );
    i = mbstowcs( pwc, pmbhello, MB_CUR_MAX );
    printf( "\tCharacters converted: %u\n", i );
    printf( "\tHex value of first" );
    printf( " wide character: %#.4x\n\n", pwc );

    printf( "Attempt to convert a wide-character NULL pointer:\n" );
    i = mbstowcs( pwc, pmbnull, MB_CUR_MAX );
    printf( "\tCharacters converted: %u\n", i );
}

Output

Convert to multibyte string:
   Characters converted: 1
   Hex value of first multibyte character: 0x0e1a

Convert back to wide-character string:
   Characters converted: 1
   Hex value of first wide character: 0x0e1e

Attempt to convert a wide-character NULL pointer:
   Characters converted: 65535


Description: mbtowc, _fmbtowc
  mbtowc, _fmbtowc

#include <stdlib.h>

int mbtowc( wchar_t *wchar, const char *mbchar, size_t count );

int __far _fmbtowc( wchar_t __far *wchar, const char __far *mbchar, size_t count );

wchar    The address of a wide character (type wchar_t)

mbchar    The address of a sequence of bytes (a multibyte character)

count    The number of bytes to check

Remarks

The mbtowc function converts count or fewer bytes pointed to by mbchar, if mbchar is not NULL, to a corresponding wide character that is determined by the current locale. It stores the resulting wide character at wchar, if wchar is not NULL. It will not examine more than MB_CUR_MAX bytes. The _fmbtowc function is a 16-bit model-independent (large-model) form of the mbtowc function.

Return Value

If mbchar is not NULL and if the object that mbchar points to forms a valid multibyte character, both mbtowc and _fmbtowc return the length in bytes of the multibyte character. If mbchar is NULL or the object that it points to is a wide-character null character (L'\0'), both functions return 0. If the object that mbchar points to does not form a valid multibyte character within the first count characters, they return −1.

See Also

»mblen,« »mbtowc,« »wcstombs,« »wctomb,« »MB_CUR_MAX,« »MB_LEN_MAX«

Compatibility

mbtowc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmbtowc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MBTOWC.CPP illustrates the behavior of the mbtowc function
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
    int      i;
    char    *pmbc    = (char *)malloc( sizeof( char ) );
    wchar_t  wc      = L'a';
    wchar_t *pwcnull = NULL;
    wchar_t *pwc     = (wchar_t *)malloc( sizeof( wchar_t ) );

    printf( "Convert a wide character to multibyte character:\n" );
    i = wctomb( pmbc, wc );
    printf( "\tCharacters converted: %u\n", i );
    printf( "\tMultibyte character: %x\n\n", pmbc );

    printf( "Convert multibyte character back to a wide "
            "character:\n" );
    i = mbtowc( pwc, pmbc, MB_CUR_MAX );
    printf( "\tBytes converted: %u\n", i );
    printf( "\tWide character: %x\n\n", pwc );

    printf( "Attempt to convert when target is NULL\n" );
    printf( "  returns the length of the multibyte character:\n" );
    i = mbtowc( pwcnull, pmbc, MB_CUR_MAX );
    printf( "\tLength of multibyte character: %u\n\n", i );

    printf( "Attempt to convert a NULL pointer to a" );
    printf( " wide character:\n" );
    pmbc = NULL;
    i = mbtowc( pwc, pmbc, MB_CUR_MAX );
    printf( "\tBytes converted: %u\n", i );
}

Output

Convert a wide character to multibyte character:
   Characters converted: 1
   Multibyte character: 2d02d4

Convert multibyte character back to a wide character:
   Bytes converted: 1
   Wide character: 2d02dc

Attempt to convert when target is NULL
  returns the length of the multibyte character:
   Length of multibyte character: 1

Attempt to convert a NULL pointer to a wide character:
   Bytes converted: 0


Description: _memavl
  _memavl

#include <malloc.h>

size_t _memavl( void );

Remarks

The _memavl function returns the approximate size, in bytes, of the memory available for dynamic memory allocation in the near heap (default data segment). The _memavl function can be used with calloc, malloc, or realloc in tiny, small, and medium memory models and with _ncalloc, _nmalloc or _nrealloc in any memory model. The number returned by the _memavl function may not be the number of contiguous bytes. Consequently, a call to malloc requesting allocation of the size returned by _memavl may not succeed. Use the _memmax function to find the size of the largest available contiguous block of memory.

Return Value

The _memavl function returns the size in bytes as an unsigned integer.

See Also

»calloc functions,« »_freect,« »malloc functions,« »_memmax,« »realloc functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * MEMAVL.C: This program uses _memavl to determine the amount
 * of memory available for dynamic allocation. It then uses
 * malloc to allocate space for 5,000 long integers and uses
 * _memavl again to determine the new amount of available memory.
 */

#include <malloc.h>
#include <stdio.h>

void main( void )
{
   long __near *longptr;

   printf( "Memory available before _nmalloc = %u\n", _memavl() );
   if( (longptr = _nmalloc( 5000 * sizeof( long ) )) != NULL )
   {
      printf( "Memory available after _nmalloc = %u\n", _memavl() );
      _nfree( longptr );
   }
}

Output

Memory available before _nmalloc = 62146
Memory available after _nmalloc = 41630


Description: _memccpy, _fmemccpy
  _memccpy, _fmemccpy

#include <memory.h>    Use either STRING.H or MEMORY.H

#include <string.h>

void *_memccpy( void *dest, const void *src, int c, unsigned int count );

void __far * __far _fmemccpy( void __far *dest, const void __far *src, int c, unsigned int count );

dest    Pointer to destination

src    Pointer to source

c    Last character to copy

count    Number of characters

Remarks

The _memccpy and _fmemccpy functions copy 0 or more bytes of src to dest, halting when the character c has been copied or when count bytes have been copied, whichever comes first. The _fmemccpy function is a 16-bit model-independent (large-model) form of the _memccpy function. It can be called from any point in any program.

Return Value

If the character c is copied, _memccpy or _fmemccpy returns a pointer (or far pointer) to the byte in dest that immediately follows the character. If c is not copied, both return NULL.

See Also

»memchr,« »memcmp,« »memcpy,« »memset«

Compatibility

_memccpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmemccpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _memccpy for compatibility with ANSI naming conventions of non-ANSI functions. Use memccpy and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* MEMCCPY.C */

#include <memory.h>
#include <stdio.h>
#include <string.h>

char string1[60] = "The quick brown dog jumps over the lazy fox";

void main( void )
{
   char buffer[61];
   char *pdest;

   printf( "Function:\t_memccpy 60 characters or to character 's'\n" );
   printf( "Source:\t\t%s\n", string1 );
   pdest = _memccpy( buffer, string1, 's', 60 );
   *pdest = '\0';
   printf( "Result:\t\t%s\n", buffer );
   printf( "Length:\t\t%d characters\n\n", strlen( buffer ) );
}

Output

Function:   _memccpy 60 characters or to character 's'
Source:      The quick brown dog jumps over the lazy fox
Result:      The quick brown dog jumps
Length:      25 characters


Description: memchr, _fmemchr
  memchr, _fmemchr

#include <memory.h>    Use either STRING.H (for ANSI compatibility) or MEMORY.H

#include <string.h>

void *memchr( const void *buf, int c, size_t count );

void __far * __far _fmemchr( const void __far *buf, int c, size_t count );

buf    Pointer to buffer

c    Character to look for

count    Number of characters

Remarks

The memchr and _fmemchr functions look for the first occurrence of c in the first count bytes of buf. They stop when they find c or when they have checked the first count bytes. The _fmemchr function is a 16-bit model-independent (large-model) form of the memchr function. It can be called from any point in any program.

Return Value

If successful, memchr or _fmemchr returns a pointer (or a far pointer) to the first location of c in buf. Otherwise, they return NULL.

See Also

»_memccpy,« »memcmp,« »memcpy,« »memset,« »strchr«

Compatibility

memchr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmemchr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MEMCHR.C */

#include <memory.h>
#include <stdio.h>

int  ch = 'r';
char str[] =    "lazy";
char string[] = "The quick brown dog jumps over the lazy fox";
char fmt1[] =   "         1         2         3         4         5";
char fmt2[] =   "12345678901234567890123456789012345678901234567890";

void main( void )
{
   char *pdest;
   int result;

   printf( "String to be searched:\n\t\t%s\n", string );
   printf( "\t\t%s\n\t\t%s\n\n", fmt1, fmt2 );

   printf( "Search char:\t%c\n", ch );
   pdest = memchr( string, ch, sizeof( string ) );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "Result:\t\t%c found at position %d\n\n", ch, result );
   else
      printf( "Result:\t\t%c not found\n" );
}

Output

String to be searched:
      The quick brown dog jumps over the lazy fox
               1         2         3         4         5
      12345678901234567890123456789012345678901234567890

Search char:   r
Result:      r found at position 12


Description: memcmp, _fmemcmp
  memcmp, _fmemcmp

#include <memory.h>    Use either STRING.H (for ANSI compatibility) or MEMORY.H

#include <string.h>

int memcmp( const void *buf1, const void *buf2, size_t count );

int __far _fmemcmp( const void __far *buf1, const void __far *buf2, size_t count );

buf1    First buffer

buf2    Second buffer

count    Number of characters

Remarks

The memcmp and _fmemcmp functions compare the first count bytes of buf1 and buf2 and return a value indicating their relationship, as follows:

value < 0    buf1 less than buf2

value = 0    buf1 identical to buf2

value > 0    buf1 greater than buf2

The _fmemcmp function is a 16-bit model-independent (large-model) form of the memcmp function. It can be called from any point in a program.

There is a semantic difference between the function version of memcmp and its intrinsic version. The function version supports huge pointers in compact-, large-, and huge-model programs, but the intrinsic version does not.

Return Value

The memcmp and _fmemcmp functions return an integer value, as described above.

See Also

»_memccpy,« »memchr,« »memcpy,« »memset,« »strcmp,« »strncmp«

Compatibility

memcmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmemcmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MEMCMP.C: This program uses memcmp to compare
 * the strings named first and second. If the first
 * 19 bytes of the strings are equal, the program
 * considers the strings to be equal.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char first[]  = "12345678901234567890";
   char second[] = "12345678901234567891";
   int result;

   printf( "Compare '%.19s' to '%.19s':\n", first, second );
   result = memcmp( first, second, 19 );
   if( result < 0 )
      printf( "First is less than second.\n" );
   else if( result == 0 )
      printf( "First is equal to second.\n" );
   else if( result > 0 )
      printf( "First is greater than second.\n" );
   printf( "Compare '%.20s' to '%.20s':\n", first, second );
   result = memcmp( first, second, 20 );
   if( result < 0 )
      printf( "First is less than second.\n" );
   else if( result == 0 )
      printf( "First is equal to second.\n" );
   else if( result > 0 )
      printf( "First is greater than second.\n" );
}

Output

Compare '1234567890123456789' to '1234567890123456789':
First is equal to second.
Compare '12345678901234567890' to '12345678901234567891':
First is less than second.


Description: memcpy, _fmemcpy
  memcpy, _fmemcpy

#include <memory.h>    Use either STRING.H (for ANSI compatibility) or MEMORY.H

#include <string.h>

void *memcpy( void *dest, const void *src, size_t count );

void __far * __far _fmemcpy( void __far *dest, const void __far *src, size_t count );

dest    New buffer

src    Buffer to copy from

count    Number of characters to copy

Remarks

The memcpy and _fmemcpy functions copy count bytes of src to dest. If the source and destination overlap, these functions do not ensure that the original source bytes in the overlapping region are copied before being overwritten. Use memmove to handle overlapping regions. The _fmemcpy function is a 16-bit model-independent (large-model) form of memcpy. It can be called from any point in any program.

There is a semantic difference between the function version of memcpy and its intrinsic version. The function version supports huge pointers in compact-, large-, and huge-model programs, but the intrinsic version does not.

Return Value

The memcpy and _fmemcpy functions return the value of dest.

See Also

»_memccpy,« »memchr,« »memcmp,« »memmove,« »memset,« »strcpy,« »strncpy«

Compatibility

memcpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmemcpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MEMCPY.C: Illustrate overlapping copy: memmove
 * handles it correctly; memcpy does not.
 */

#include <memory.h>
#include <string.h>
#include <stdio.h>

char string1[60] = "The quick brown dog jumps over the lazy fox";
char string2[60] = "The quick brown fox jumps over the lazy dog";
/*                           1         2         3         4         5
 *                  12345678901234567890123456789012345678901234567890
 */

void main( void )
{
   printf( "Function:\tmemcpy without overlap" );
   printf( "Source:\t\t%s\n", string1 + 40 );
   printf( "Destination:\t%s\n", string1 + 16 );
   memcpy( string1 + 16, string1 + 40, 3 );
   printf( "Result:\t\t%s\n", string1 );
   printf( "Length:\t\t%d characters\n\n", strlen( string1 ) );

   /* Restore string1 to original contents */
   memcpy( string1 + 16, string2 + 40, 3 );

   printf( "Function:\tmemmove with overlap\n" );
   printf( "Source:\t\t%s\n", string2 + 4 );
   printf( "Destination:\t%s\n", string2 + 10 );
   memmove( string2 + 10, string2 + 4, 40 );
   printf( "Result:\t\t%s\n", string2 );
   printf( "Length:\t\t%d characters\n", strlen( string2 ) );

   printf( "Function:\tmemcpy with overlap\n" );
   printf( "Source:\t\t%s\n", string1 + 4 );
   printf( "Destination:\t%s\n", string1 + 10 );
   memcpy( string1 + 10, string1 + 4, 40 );
   printf( "Result:\t\t%s\n", string1 );
   printf( "Length:\t\t%d characters\n\n", strlen( string1 ) );
}

Output

Function:   memcpy without overlapSource:      fox
Destination:   dog jumps over the lazy fox
Result:      The quick brown fox jumps over the lazy fox
Length:      43 characters

Function:   memmove with overlap
Source:      quick brown fox jumps over the lazy dog
Destination:   brown fox jumps over the lazy dog
Result:      The quick quick brown fox jumps over the lazy dog
Length:      49 characters
Function:   memcpy with overlap
Source:      quick brown dog jumps over the lazy fox
Destination:   brown dog jumps over the lazy fox
Result:      The quick quick brown dog jumps over the lazy fox
Length:      49 characters


Description: _memicmp, _fmemicmp
  _memicmp, _fmemicmp

#include <memory.h>    Use either STRING.H for ANSI compatibility) or MEMORY.H

#include <string.h>

int _memicmp( const void *buf1, const void *buf2, unsigned int count );

int __far _fmemicmp( const void __far *buf1, const void __far *buf2, unsigned int count );

buf1    First buffer

buf2    Second buffer

count    Number of characters

Remarks

The _memicmp and _fmemicmp functions compare the first count characters of the two buffers buf1 and buf2 byte by byte. The comparison is made without regard to the case of letters in the two buffers; that is, uppercase and lowercase letters are considered equivalent. The _memicmp and _fmemicmp functions return a value indicating the relationship of the two buffers, as follows:

value < 0    buf1 less than buf2

value = 0    buf1 identical to buf2

value > 0    buf1 greater than buf2

The _fmemicmp function is a 16-bit model-independent (large-model) form of the _memicmp function. It can be called from any point in any program.

Return Value

The _memicmp and _fmemicmp functions return an integer value, as described above.

See Also

»_memccpy,« »memchr,« »memcmp,« »memcpy,« »memset,« »_stricmp,« »_strnicmp«

Compatibility

_memicmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmemicmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _memicmp for compatibility with ANSI naming conventions of non- ANSI functions. Use memicmp and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* MEMICMP.C: This program uses _memicmp to compare
 * the first 29 letters of the strings named first and
 * second without regard to the case of the letters.
 */

#include <memory.h>
#include <stdio.h>
#include <string.h>

void main( void )
{
   int result;
   char first[] = "Those Who Will Not Learn from History";
   char second[] = "THOSE WHO WILL NOT LEARN FROM their mistakes";
   /* Note that the 29th character is right here ^ */

   printf( "Compare '%.29s' to '%.29s'\n", first, second );
   result = _memicmp( first, second, 29 );
   if( result < 0 )
      printf( "First is less than second.\n" );
   else if( result == 0 )
      printf( "First is equal to second.\n" );
   else if( result > 0 )
      printf( "First is greater than second.\n" );
}

Output

Compare 'Those Who Will Not Learn from' to 'THOSE WHO WILL NOT LEARN FROM'
First is equal to second.


Description: _memmax
  _memmax

#include <malloc.h>

size_t _memmax( void );

Remarks

The _memmax function returns the size (in bytes) of the largest contiguous block of memory that can be allocated from the near heap (i.e., the default data segment). Calling _nmalloc with the value returned by the _memmax function will succeed as long as _memmax returns a nonzero value.

Return Value

The function returns the block size, if successful. Otherwise, it returns 0, indicating that nothing more can be allocated from the near heap.

See Also

»malloc functions,« »_msize functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * MEMMAX.C: This program uses _memmax and _nmalloc to allocate
 * the largest block of memory available in the near heap.
 */

#include <stddef.h>
#include <malloc.h>
#include <stdio.h>

void main( void )
{
   size_t contig;
   char *p;

   /* Determine contiguous memory size */
   contig = _memmax();
   printf( "Largest block of available memory is %u bytes long\n",
            contig  );
   if( contig )
   {
      p = _nmalloc( contig * sizeof( int ) );
      if( p == NULL )
         printf( "Error with malloc (should never occur)\n" );
      else
      {
         printf( "Maximum allocation succeeded\n" );
         free( p );
      }
   }
   else
      printf( "Near heap is already full\n" );
}

Output

Largest block of available memory is 62068 bytes long
Maximum allocation succeeded


Description: memmove, _fmemmove
  memmove, _fmemmove

#include <string.h>

void *memmove( void *dest, const void *src, size_t count );

void __far * __far _fmemmove( void __far *dest, const void __far *src, size_t count );

dest    Destination object

src    Source object

count    Number of characters to copy

Remarks

The memmove and _fmemmove functions copy count characters from the source (src) to the destination (dest). If some regions of the source area and the destination overlap, the memmove and _fmemmove functions ensure that the original source bytes in the overlapping region are copied before being overwritten. The _fmemmove function is a 16-bit model-independent (large-model) form of the memmove function. It can be called from any point in any program.

Return Value

The memmove and _fmemmove functions return the value of dest.

See Also

»_memccpy,« »memcpy,« »strcpy,« »strncpy«

Compatibility

memmove:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmemmove:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »memcpy.«


Description: memset, _fmemset
  memset, _fmemset

#include <memory.h>    Use either STRING.H (for ANSI compatibility) or MEMORY.H

#include <string.h>

void *memset( void *dest, int c, size_t count );

void __far * __far _fmemset( void __far *dest, int c, size_t count );

dest    Pointer to destination

c    Character to set

count    Number of characters

Remarks

The memset and _fmemset functions set the first count bytes of dest to the character c. The _fmemset function is a 16-bit model-independent (large-model) form of the memset function. It can be called from any point in any program.

There is a semantic difference between the function version of memset and its intrinsic version. The function version supports huge pointers in compact-, large-, and huge-model programs, but the intrinsic version does not.

Return Value

The memset and _fmemset functions return the value of dest.

See Also

»_memccpy,« »memchr,« »memcmp,« »memcpy,« »_strnset«

Compatibility

memset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fmemset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MEMSET.C: This program uses memset to
 * set the first four bytes of buffer to "*".
 */

#include <memory.h>
#include <stdio.h>

void main( void )
{
   char buffer[] = "This is a test of the memset function";

   printf( "Before: %s\n", buffer );
   memset( buffer, '*', 4 );
   printf( "After:  %s\n", buffer );
}

Output

Before: This is a test of the memset function
After:  **** is a test of the memset function


Description: __min
  __min

#include <stdlib.h>

type __min( type a, type b );

type    Any numeric data type

a, b    Values of any numeric type to be compared

Remarks

The __min macro compares two values and returns the value of the smaller one. The arguments can be of any numeric data type, signed or unsigned. Both arguments and the return value must be of the same data type.

Return Value

The macro returns the smaller of the two arguments.

See Also

»__max«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MINMAX.C */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int a = 10;
   int b = 21;

   printf( "The larger of %d and %d is %d\n",  a, b, __max( a, b ) );
   printf( "The smaller of %d and %d is %d\n", a, b, __min( a, b ) );
}

Output

The larger of 10 and 21 is 21
The smaller of 10 and 21 is 10


Description: _mkdir
  _mkdir

#include <direct.h>

int _mkdir( const char *dirname );

dirname    Path for new directory

Remarks

The _mkdir function creates a new directory with the specified dirname. Only one directory can be created at a time, so only the last component of dirname can name a new directory. The _mkdir function does not do any translation of path delimiters. All operating systems accept either " \" or "/ " internally as valid delimiters within paths.

Return Value

The _mkdir function returns the value 0 if the new directory was created. A return value of −1 indicates an error, and errno is set to one of two values. EACCES means a directory was not created; the given name is the name of an existing file, directory, or device. ENOENT means a path was not found.

See Also

»_chdir,« »_rmdir«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MAKEDIR.C */

#include <direct.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   if( _mkdir( "\\testtmp" ) == 0 )
   {
      printf( "Directory '\\testtmp' was successfully created\n" );
      system( "dir \\testtmp" );
      if( _rmdir( "\\testtmp" ) == 0 )
        printf( "Directory '\\testtmp' was successfully removed\n"  );
      else
         printf( "Problem removing directory '\\testtmp'\n" );
   }
   else
      printf( "Problem creating directory '\\testtmp'\n" );
}

Output

 Volume in drive C is CDRIVE
 Volume Serial Number is 1966-6F27

 Directory of C:\testtmp

.             <DIR>             03-23-93  11:32AM
..            <DIR>             03-23-93  11:32AM
               2 File(s)          0 bytes
                           17358848 bytes free
Directory '\testtmp' was successfully created
Directory '\testtmp' was successfully removed


Description: _MK_FP
  _MK_FP

#include <dos.h>

void __far *_MK_FP( unsigned seg, unsigned offset );

seg    Segment value for pointer

offset    Offset value for pointer

Remarks

The _MK_FP macro makes a far pointer from the segment value, seg, and the offset value, offset.

Return Value

The _MK_FP macro returns the resulting far pointer.

See Also

»_FP_OFF,« »_FP_SEG«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _mktemp
  _mktemp

#include <io.h>

char *_mktemp( char *template );

template    Filename pattern

Remarks

The _mktemp function creates a unique filename by modifying the given template argument. The template argument has the form: baseXXXXXX where base is the part of the new filename that you supply, and the X's are placeholders for the part supplied by _mktemp; _mktemp preserves base and replaces the six trailing X's with an alphanumeric character followed by a five-digit value. The five-digit value is a unique number identifying the calling process. The alphanumeric character is 0 ('0') the first time _mktemp is called with a given template.

In subsequent calls from the same process with copies of the same template, _mktemp checks to see if previously returned names have been used to create files. If no file exists for a given name, _mktemp returns that name. If files exist for all previously returned names, _mktemp creates a new name by replacing the alphanumeric character in the name with the next available lowercase letter. For example, if the first name returned is t012345 and this name is used to create a file, the next name returned will be ta12345. When creating new names, _mktemp uses, in order, '0' and then the lowercase letters 'a' through 'z'.

Note that the original template is modified by the first call to _mktemp. If you then call the _mktemp function again with the same template (i.e., the original one), you will get an error.

The _mktemp function generates unique filenames but does not create or open files.

Return Value

The _mktemp function returns a pointer to the modified template. The return value is NULL if the template argument is badly formed or no more unique names can be created from the given template.

See Also

»fopen,« »_getpid,« »_open,« »_tempnam,« »tmpfile«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _mktemp for compatibility with ANSI naming conventions of non-ANSI functions. Use mktemp and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* MKTEMP.C: The program uses _mktemp to create
 * five unique filenames. It opens each filename
 * to ensure that the next name is unique.
 */

#include <io.h>
#include <string.h>
#include <stdio.h>

char *template = "fnXXXXXX";
char *result;
char names[5][9];

void main( void )
{
   int i;
   FILE *fp;

   for( i = 0; i < 5; i++ )
   {
      strcpy( names[i], template );

      /* Attempt to find a unique filename: */
      result = _mktemp( names[i] );
      if( result == NULL )
         printf( "Problem creating the template" );
      else
      {
         if( (fp = fopen( result, "w" )) != NULL )
            printf( "Unique filename is %s\n", result );
         else
            printf( "Cannot open %s\n", result );
         fclose( fp );
      }
   }
}

Output

Unique filename is fn000182
Unique filename is fna00182
Unique filename is fnb00182
Unique filename is fnc00182
Unique filename is fnd00182


Description: mktime
  mktime

#include <time.h>

time_t mktime( struct tm *timeptr );

timeptr    Pointer to time structure

Remarks

The mktime function converts the supplied time structure (possibly incomplete) pointed to by timeptr into a fully defined structure with "normalized" values and then converts it to a time_t calendar time value. The structure for the tm is described in the reference page for »asctime.« The converted time has the same encoding as the values returned by the time function. The original values of the tm_wday and tm_yday components of the timeptr structure are ignored, and the original values of the other components are not restricted to their normal ranges.

If successful, mktime sets the values of tm_wday and tm_yday appropriately, and sets the other components to represent the specified calendar time, but with their values forced to the normal ranges; the final value of tm_mday is not set until tm_mon and tm_year are determined. When specifying a tm structure time, the tm_isdst field must be set to 0 to indicate that standard time is in effect, a value greater than 0 to indicate daylight savings time is in effect, or a value less than zero to have the C run-time library code compute whether standard time or daylight savings time is in effect. The tm_isdst is a required field. If it is not set, its value will be undefined and the resulting return value from mktime will be unpredictable. Note that if timeptr points to a tm structure returned by a previous call to a function such as asctime, gmtime, or localtime, the tm_isdst field will contain the correct value.

The mktime function handles dates in any time zone from midnight, January 1, 1970, to midnight, February 5, 2036. If timeptr references a date before midnight, January 1, 1970, mktime returns −1 cast to type time_t.

Note that the gmtime and localtime functions use a single statically allocated buffer for the conversion. If you supply this buffer to mktime, the previous contents will be destroyed.

Return Value

The mktime function returns the specified calendar time encoded as a value of type time_t. If the calendar time cannot be represented, the function returns the value −1 cast to type time_t.

See Also

»asctime,« »gmtime,« »localtime,« »time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MKTIME.C: The example takes a number of days
 * as input and returns the time, the current
 * date, and the specified number of days.
 */

#include <time.h>
#include <stdio.h>

void main( void )
{
   struct tm when;
   time_t now, result;
   int    days;

   time( &now );
   when = *localtime( &now );
   printf( "Current time is %s\n", asctime( &when ) );
   printf( "How many days to look ahead: " );
   scanf( "%d", &days );

   when.tm_mday = when.tm_mday + days;
   if( (result = mktime( &when )) != (time_t)-1 )
      printf( "In %d days the time will be %s\n",
              days, asctime( &when ) );
   else
      perror( "mktime failed" );
}

Output

Current time is Tue Mar 23 15:52:11 1993

How many days to look ahead: 23
In 23 days the time will be Thu Apr 15 16:52:11 1993


Description: modf, _modfl
  modf, modfl

#include <math.h>

double modf( double x, double *intptr );

long double modfl( long double x, long double *intptr );

x    Floating-point value

intptr    Pointer to stored integer portion

Remarks

The modf functions break down the floating-point value x into fractional and integer parts, each of which has the same sign as x. The signed fractional portion of x is returned. The integer portion is stored as a floating-point value at intptr. The modfl function uses the 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

Return Value

The modf and modfl functions return the signed fractional portion of x. There is no error return.

See Also

»frexp,« »ldexp«

Compatibility

modf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

modfl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* MODF.C */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x, y, n;

   x = -14.87654321;      /* Divide x into its fractional */
   y = modf( x, &n );     /* and integer parts            */

   printf( "For %f, the fraction is %f and the integer is %.f\n",
           x, y, n );
}

Output

For -14.876543, the fraction is -0.876543 and the integer is -14


Description: _movedata
  _movedata

#include <memory.h>    Use either STRING.H or MEMORY.H

#include <string.h>

void _movedata( unsigned int srcseg, unsigned int srcoff, unsigned int destseg, unsigned int destoff, unsigned int count );

srcseg    Segment address of source

srcoff    Segment offset of source

destseg    Segment address of destination

destoff    Segment offset of destination

count    Number of bytes

Remarks

The _movedata function copies count bytes from the source address specified by srcseg:srcoff to the destination address specified by destseg:destoff.

The _movedata function was intended to move far data in small-model programs. The newer 16-bit model-independent _fmemcpy and _fmemmove functions should be used instead of the _movedata function. In large-model programs, the memcpy and memmove functions can also be used. Segment values for the srcseg and destseg arguments can be obtained by using either the _segread function or the _FP_SEG macro. The _movedata function does not handle all cases of overlapping moves correctly. These occur when part of the destination is the same memory area as part of the source. The memmove function correctly handles overlapping moves.

Return Value

None.

See Also

»_FP_OFF,« »_FP_SEG,« »memcpy,« »memmove,« »_segread«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * MOVEDATA.C
 *
 */

#include <memory.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include <malloc.h>

char __far *src = "This is a test.";

void main( void )
{
   char __far *dest;

   if( (dest = _fmalloc( 80 )) != NULL )
   {
      _movedata( _FP_SEG( src ),  _FP_OFF( src ),
                 _FP_SEG( dest ), _FP_OFF( dest ),
                 _fstrlen( src ) + 1 );
      printf( "The source data at %Fp is '%Fs'\n", src, src );
      printf( "The destination data at %Fp is '%Fs'\n", dest, dest );
      _ffree( dest );
   }
}

Output

The source data at 2488:0042 is 'This is a test.'
The destination data at 3489:0016 is 'This is a test.'


Description: _moveto Functions
  _moveto Functions

#include <graph.h>

struct _xycoord __far _moveto( short x, short y );

struct _wxycoord __far _moveto_w( double wx, double wy );

x, y    View-coordinate point

wx, wy    Window-coordinate point

Remarks

The _moveto functions move the current position to the specified point. The _moveto function uses the view-coordinate point (x, y) as the current position. The _moveto_w function uses the window-coordinate point (wx, wy) as the current position. No drawing takes place.

The _moveto function operates only in graphics video modes (e.g., _MRES4COLOR). Because it is a graphics function, the color of text is set by the _setcolor function, not by the _settextposition function.

Return Value

The function returns the coordinates of the previous position. The _moveto function returns the coordinates in an _xycoord structure. The _xycoord structure, defined in GRAPH.H, contains short xcoord, the x-coordinate, and short ycoord, the y-coordinate. The _moveto_w function returns the coordinates in a _wxycoord structure, defined in GRAPH.H. The _wxycoord structure contains double wx, the x window coordinate, and double wy, the y window coordinate.

See Also

»_lineto functions,« »_outgtext«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * MOVETO.C: This program draws line
 * segments of different colors.
 */

#include <graph.h>
#include <stdlib.h>
#include <conio.h>

void main( void )
{
   short x, y, xinc, yinc, color = 1;
   struct _videoconfig v;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXCOLORMODE ) )
      exit( 1 );
   _getvideoconfig( &v );
   xinc = v.numxpixels / 50;
   yinc = v.numypixels / 50;

   for( x = 0, y = v.numypixels - 1; x < v.numxpixels;
        x += xinc, y -=  yinc )
   {
      _setcolor( color++ % 16 );
      _moveto( x, 0 );
      _lineto( 0, y );
   }
   _getch();

   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _msize Functions
  _msize Functions

#include <malloc.h>

size_t _msize( void *memblock );

size_t _bmsize( __segment seg, void __based( void ) *memblock );

size_t _fmsize( void __far *memblock );

size_t _nmsize( void __near *memblock );

memblock    Pointer to memory block

seg    Based-heap segment selector

Remarks

The _msize family of functions returns the size, in bytes, of the memory block allocated by a call to the appropriate version of the calloc, malloc, or realloc functions. In large data models (compact-, large-, and huge-model programs), _msize maps to _fmsize. In small data models (tiny-, small-, and medium-model programs), _msize maps to _nmsize. The _nmsize function returns the size (in bytes) of the memory block allocated by a call to _nmalloc, and the _fmsize function returns the size (in bytes) of the memory block allocated by a call to _fmalloc or _frealloc. The _bmsize function returns the size of a block allocated in segment seg by a call to _bmalloc, _bcalloc, or _brealloc.

The location of the memory block is indicated below:

_msize    Depends on data model of program

_bmsize    Based heap segment specified by seg value

_fmsize    Far heap segment (outside default data segment)

_nmsize    Default data segment (inside near heap)

Return Value

All four functions return the size (in bytes) as an unsigned integer.

See Also

»calloc functions,« »_expand functions,« »malloc functions,« »realloc functions«

Compatibility

_msize:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_bmsize, _fmsize, _nmsize:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »realloc.«


Description: _nextafter
  _nextafter

#include <float.h>

double _nextafter( double x, double y );

x    Double-precision floating-point value

y    Double-precision floating-point value

Remarks

The _nextafter function returns the closest representable neighbor of x in the direction toward y.

Return Value

If x=y, the _nextafter function returns x, with no exception triggered. If either x or y is a quiet NAN, then the return value is one or the other of the input NANs.

See Also

»_isnan«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


  offsetof Macro

#include <stddef.h>

size_t offsetof( struct-name, member-name );

Remarks

The macro offsetof takes a structure name and a member name as arguments. Types can be specified using the struct keyword.

Note  offsetof is not a function and cannot be described using a C prototype.

Return Value

This macro returns the offset in bytes of member-name from the beginning of the structure. It is undefined for bit fields.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _onexit, _fonexit
  _onexit, _fonexit

#include <stdlib.h>

_onexit_t _onexit( _onexit_t func );

_fonexit_t __far _fonexit( _fonexit_t func );

func    Pointer to function to be called at exit

Remarks

The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that is executed in LIFO (last-in-first-out) order. With MS-DOS, no more than 32 functions can be registered with _onexit; _onexit returns the value NULL if the number of functions exceeds 32. With Windows NT, more than 32 functions can be registered. The functions passed to _onexit cannot take parameters. The _fonexit function is a far version of _onexit; it can be used with any memory model.

Neither _onexit nor _fonexit is part of the ANSI definition; instead, both are Microsoft extensions. The ANSI-standard atexit function does the same thing as _onexit and should be used instead of _onexit when ANSI portability is desired.

Return Value

Both _onexit and _fonexit return 0 (EXIT_SUCCESS) if successful, or a nonzero value (EXIT_FAILURE) if an error occurs (e.g., if there are already 32 exit functions defined in a 16-bit application).

See Also

»atexit,« »exit«

Compatibility

_onexit:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fonexit:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _onexit for compatibility with ANSI naming conventions of non-ANSI functions. Use onexit and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* ONEXIT.C */

#include <stdlib.h>
#include <stdio.h>

/* Prototypes */
int fn1(void), fn2(void), fn3(void), fn4 (void);

void main( void )
{
   _onexit( fn1 );
   _onexit( fn2 );
   _onexit( fn3 );
   _onexit( fn4 );
   printf( "This is executed first.\n" );
}

int fn1()
{
   printf( "next.\n" );
   return 0;
}

int fn2()
{
   printf( "executed " );
   return 0;
}

int fn3()
{
   printf( "is " );
   return 0;
}

int fn4()
{
   printf( "This " );
   return 0;
}

Output

This is executed first.
This is executed next.


Description: _open
  _open

#include <fcntl.h>

#include <sys\types.h>

#include <sys\stat.h>

#include <io.h>

int _open( const char *filename, int oflag [, int pmode] );

filename    Filename

oflag    Type of operations allowed

pmode    Permission mode

Remarks

The _open function opens the file specified by filename and prepares the file for subsequent reading or writing, as defined by oflag. The oflag argument is an integer expression formed from one or more of the manifest constants defined in FCNTL.H (listed below). When two or more manifest constants are used to form the oflag argument, the constants are combined with the bitwise-OR operator ( | ). For more information, see »Text and Binary Modes.«

The FCNTL.H file defines the following manifest constants:

_O_APPEND    Repositions the file pointer to the end of the file before every write operation.

_O_BINARY    Opens file in binary (untranslated) mode.

_O_CREAT    Creates and opens a new file for writing; this has no effect if the file specified by filename exists.

_O_EXCL    Returns an error value if the file specified by filename exists. This flag must be used with _O_CREAT; otherwise, it is ignored.

_O_RDONLY    Opens file for reading only; if this flag is given, neither _O_RDWR nor _O_WRONLY can be given.

_O_RDWR    Opens file for both reading and writing; if this flag is given, neither _O_RDONLY nor _O_WRONLY can be given.

_O_TEXT    Opens file in text (translated) mode.

_O_TRUNC     Opens and truncates an existing file to zero length; the file must have write permission. The contents of the file are destroyed. If this flag is given, you cannot specify _O_RDONLY. When used with _O_CREAT, this flag opens a file which either does or does not exist.

_O_WRONLY    Opens file for writing only; if this flag is given, neither _O_RDONLY nor _O_RDWR can be given.

Warning  Use the _O_TRUNC flag with care, as it destroys the complete contents of an existing file.

Either _O_RDONLY, _O_RDWR, or _O_WRONLY must be given to specify the access mode. There is no default value for the access mode.

The pmode argument is required only when _O_CREAT is specified. If the file exists, pmode is ignored. Otherwise, pmode specifies the file's permission settings, which are set when the new file is closed for the first time. The pmode is an integer expression containing one or both of the manifest constants _S_IWRITE and _S_IREAD, defined in SYS\STAT.H. When both constants are given, they are joined with the bitwise-OR operator ( | ). The meaning of the pmode argument is as follows:

_S_IWRITE    Writing permitted

_S_IREAD    Reading permitted

_S_IREAD | _S_IWRITE    Reading and writing permitted

If write permission is not given, the file is read-only. With MS-DOS, all files are readable; it is not possible to give write-only permission. Thus the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent.

The _open function applies the current file-permission mask to pmode before setting the permissions (for more information, see the reference page on »_umask«).

The filename argument used in the _open function is affected by the MS-DOS APPEND command. Note that with MS-DOS versions 3.0 and later, a problem occurs when SHARE is installed and a new file is opened with oflag set to _O_CREAT | _O_RDONLY or _O_CREAT | _O_WRONLY and pmode set to _S_IREAD. Under these conditions, the operating system prematurely closes the file during system calls made within _open. To work around the problem, open the file with the pmode argument set to _S_IWRITE. Then close the file and use _chmod to change the access mode back to _S_IREAD. Another workaround is to open the file with pmode set to _S_IREAD and oflag set to _O_CREAT | _O_RDWR.

Return Value

The _open function returns a file handle for the opened file. A return value of −1 indicates an error, and errno is set to one of the following values:

EACCES    Given path is a directory; or an attempt was made to open a read-only file for writing; or a sharing violation occurred (the file's sharing mode does not allow the specified operations).

EEXIST    The _O_CREAT and _O_EXCL flags are specified, but the named file already exists.

EINVAL    An invalid oflag or pmode argument was given.

EMFILE    No more file handles available (too many open files).

ENOENT    File or path not found.

See Also

»_chmod,« »_close,« »_creat,« »_dup,« »_dup2,« »fopen,« »_sopen,« »_umask«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _open for compatibility with ANSI naming conventions of non-ANSI functions. Use open and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* OPEN.C: This program uses _open to open a file
 * named OPEN.C for input and a file named OPEN.OUT
 * for output. The files are then closed.
 */

#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <stdio.h>

void main( void )
{
   int fh1, fh2;

   fh1 = _open( "OPEN.C", _O_RDONLY );
   if( fh1 == -1 )
      perror( "open failed on input file" );
   else
   {
      printf( "open succeeded on input file\n" );
      _close( fh1 );
   }

   fh2 = _open( "OPEN.OUT", _O_WRONLY | _O_CREAT, _S_IREAD |
                            _S_IWRITE );
   if( fh2 == -1 )
      perror( "open failed on output file" );
   else
   {
      printf( "open succeeded on output file\n" );
      _close( fh2 );
   }
}

Output

open succeeded on input file
open succeeded on output file


Description: _open_osfhandle
  _open_osfhandle

#include <io.h>

int _open_osfhandle ( long osfhandle, int flags );

osfhandle    Operating system file handle

flags    Type of operations allowed

Remarks

The _open_osfhandle routine allocates a C run-time file handle and sets it to point to the operating system file handle specified by osfhandle. The flags argument is an integer expression formed from one or more of the manifest constants defined in FCNTL.H and listed below. When two or more manifest constants are used to form the flags argument, the constants are combined with the bitwise-OR operator ( | ).

The FCNTL.H file defines the following manifest constants:

_O_APPEND    Repositions the file pointer to the end of the file before every write operation.

_O_RDONLY    Opens file for reading only.

_O_TEXT    Opens file in text (translated) mode.

Return Value

If successful, the _open_osfhandle function returns a C run-time file handle. Otherwise, it returns −1.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _outgtext
  _outgtext

#include <graph.h>

void __far _outgtext( const char __far *text );

text    Text string to output

Remarks

The _outgtext function outputs on the screen the null-terminated string that text points to. The text is output using the current font at the current graphics position and in the current color. No formatting is provided, in contrast to the standard console I/O library routines such as printf. After it outputs the text, _outgtext updates the current graphics position.

The _outgtext function operates only in graphics video modes (e.g., _MRES4COLOR). Because it is a graphics function, the color of text is set by the _setcolor function, not by the _settextcolor function. Similarly, the position is affected by the _moveto function, not by the _settextposition function.

The _outgtext function operates differently in QuickWin applications.

Return Value

None.

See Also

»_moveto functions,« »_setcolor,« »_setfont«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * OUTGTXT.C illustrates font output using functions:
 *   _registerfonts     _setfont       _outgtext
 *   _unregisterfonts   _getfontinfo   _getgtextextent
 *   _setgtextvector
 */

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <graph.h>

#define NFONTS 4

unsigned char *face[NFONTS] =
{
   "Courier", "Modern", "Script", "Roman"
};
unsigned char *options[NFONTS] =
{
   "courier", "modern", "script", "roman"
};

void main( void )
{
   unsigned char list[20];
   char fondir[_MAX_PATH];
   struct _videoconfig vc;
   struct _fontinfo fi;
   short fontnum, x, y;

   /* Read header info from all .FON files in current or
    * given directory.
    */
   if( _registerfonts( "*.FON" ) <= 0 )
   {
      _outtext( "Enter full path where .FON files are located: " );
      gets( fondir );
      strcat( fondir, "\\*.FON" );
      if( _registerfonts( fondir ) <= 0 )
      {
         _outtext( "Error: can't register fonts" );
         exit( 1 );
      }
   }

   /* Set highest available graphics mode and get configuration. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );
   _getvideoconfig( &vc );

   /* Display each font name centered on screen. */
   for( fontnum = 0; fontnum < NFONTS; fontnum++ )
   {
      /* Build options string. */
      strcat( strcat( strcpy( list, "t'" ),
                      options[fontnum] ), "'");
      strcat( list, "h30w24b" );
      _clearscreen( _GCLEARSCREEN );
      if( _setfont( list ) >= 0 )
      {
         /* Use length of text and height of font to center text. */
         x = (vc.numxpixels / 2) -
             (_getgtextextent( face[fontnum] ) / 2);
         y = (vc.numypixels / 2) +
             (_getgtextextent( face[fontnum] ) / 2);
         if( _getfontinfo( &fi ) )
         {
            _outtext( "Error: Can't get font information" );
            break;
         }
         _moveto( x, y );
         if( vc.numcolors > 2 )
            _setcolor( fontnum + 2 );

         /* Rotate and display text. */
         _setgtextvector( 1, 0 );
         _outgtext( face[fontnum] );
         _setgtextvector( 0, 1 );
         _outgtext( face[fontnum] );
         _setgtextvector( -1, 0 );
         _outgtext( face[fontnum] );
         _setgtextvector( 0, -1 );
         _outgtext( face[fontnum] );
      }
      else
      {
         _outtext( "Error: Can't set font: " );
         _outtext( list );
      }
      _getch();
   }
   _unregisterfonts();
   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _outmem
  _outmem

#include <graph.h>

void __far _outmem( const char __far *text, short length );

text    Text string to output

length    Length of string to output

Remarks

The _outmem function outputs the string that text points to. The length argument specifies the number of characters to output. Unlike _outtext, the _outmem function prints all characters literally, including ASCII 10, 13, and 0 as the equivalent graphics characters. No formatting is provided. Text is printed using the current text color, starting at the current text position. To output text using special fonts, you must use the _outgtext function.

Standard console routines such as printf do not use or maintain information about the display, such as current text position, which is contained in the graphics library. Therefore, you cannot use standard console routines to output graphics text.

Return Value

None.

See Also

»_outtext,« »_settextcolor,« »_settextposition,« »_settextwindow«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * OUTMEM.C illustrates:
 *    _outmem
 */

#include <stdio.h>
#include <graph.h>

void main( void )
{
   int  i, len;
   char tmp[10];

   _clearscreen( _GCLEARSCREEN );
   for( i = 0; i < 256; i++ )
   {
      _settextposition( (i % 24) + 1, (i / 24) * 7 );
      len = sprintf( tmp, "%3d %c", i, i );
      _outmem( tmp, len );
   }
   _settextposition( 24, 1 );
}


Description: _outp, _outpw, _outpd
  _outp, _outpw, _outpd

#include <conio.h>

int _outp( unsigned short port, int databyte );

unsigned short _outpw( unsigned short port, unsigned short dataword );

unsigned long _outpd( unsigned short port, unsigned long dataword );

port    Port number

databyte    Output value

dataword    Output value

Remarks

The _outp, _outpw, and _outpd functions write a byte, a word, and a double word, respectively, to the specified output port. The port argument can be any unsigned integer in the range 0−65,535; databyte can be any integer in the range 0−255; and dataword can be any value in the range 0−65,535.

Return Value

The functions return the data output. There is no error return.

See Also

»_inp,« »_inpd,« »_inpw«

Compatibility

_outp, _outpw: ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_outpd: ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* OUTP.C: This program uses _inp and _outp
 * to make sound of variable tone and duration.
 */

#include <conio.h>
#include <stdio.h>
#include <time.h>

void Beep( unsigned duration, unsigned frequency );
void Sleep( clock_t _wait );

void main( void )
{
   Beep( 698, 700 );
   Beep( 523, 500 );
}

/* Sounds the speaker for a time specified in microseconds
 * by duration at a pitch specified in hertz by frequency.
 */
void Beep( unsigned frequency, unsigned duration )
{
   int control;

   /* If frequency is 0, Beep doesn't try to make a sound. */
   if( frequency )
   {
      /* 75 is about the shortest reliable duration of a sound. */
      if( duration < 75 )
         duration = 75;

      /* Prepare timer by sending 10111100 to port 43. */
      _outp( 0x43, 0xb6 );

      /* Divide input frequency by timer ticks per
       * second and write (byte by byte) to timer.
       */
      frequency = (unsigned)(1193180L / frequency);
      _outp( 0x42, (char)frequency );
      _outp( 0x42, (char)(frequency >> 8) );

      /* Save speaker control byte. */
      control = _inp( 0x61 );
      /* Turn on the speaker (with bits 0 and 1). */
      _outp( 0x61, control | 0x3 );
   }

   Sleep( (clock_t)duration );

   /* Turn speaker back on if necessary. */
   if( frequency )
      _outp( 0x61, control );
}

/* Pauses for a specified number of microseconds. */
void Sleep( clock_t _wait )
{
   clock_t goal;

   goal = _wait + clock();
   while( goal > clock() )
      ;
}


Description: _outtext
  _outtext

#include <graph.h>

void __far _outtext( const char __far *text );

text    Text string to output

Remarks

The _outtext function outputs the null-terminated string that text points to. No formatting is provided, in contrast to the standard console I/O library routines such as printf. This function will work in any screen mode. Text output begins at the current text position. To output text using special fonts, you must use the »_outgtext« function.

The _outtext function operates differently in QuickWin applications.

Standard console routines such as printf do not use or maintain information about the display, such as current text position, which is contained in the graphics library. Therefore, you cannot use standard console routines to output graphics text.

Return Value

None.

See Also

»_outmem,« »_settextcolor,« »_settextposition,« »_settextwindow,« »_wrapon«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * OUTTXT.C: This example illustrates text output functions:
 *   _gettextcolor  _getbkcolor  _gettextposition  _outtext
 *   _settextcolor  _setbkcolor  _settextposition
 */

#include <conio.h>
#include <stdio.h>
#include <graph.h>

char buffer [80];

void main( void )
{
   /* Save original foreground, background, and text position */
   short blink, fgd, oldfgd;
   long  bgd, oldbgd;
   struct _rccoord oldpos;

   /* Save original foreground, background, and text position. */
   oldfgd = _gettextcolor();
   oldbgd = _getbkcolor();
   oldpos = _gettextposition();
   _clearscreen( _GCLEARSCREEN );

   /* First time no blink, second time blinking. */
   for( blink = 0; blink <= 16; blink += 16 )
   {
      /* Loop through 8 background colors. */
      for( bgd = 0; bgd < 8; bgd++ )
      {
         _setbkcolor( bgd );
         _settextposition( (short)bgd + ((blink / 16) * 9) + 3, 1 );
         _settextcolor( 7 );
         sprintf(buffer, "Back: %d Fore:", bgd );
         _outtext( buffer );

         /* Loop through 16 foreground colors. */
         for( fgd = 0; fgd < 16; fgd++ )
         {
            _settextcolor( fgd + blink );
            sprintf( buffer, " %2d ", fgd + blink );
            _outtext( buffer );
         }
      }
   }
   _getch();

   /* Restore original foreground, background, and text position. */
   _settextcolor( oldfgd );
   _setbkcolor( oldbgd );
   _clearscreen( _GCLEARSCREEN );
   _settextposition( oldpos.row, oldpos.col );
}


Description: _pclose
  _pclose

#include <stdio.h>

int _pclose( FILE *stream );

stream    File stream returned by previous call to _popen

Remarks

The _pclose function waits for a child command and closes the stream on the associated pipe. The argument stream is the return value from a previous call to _popen. The _pclose function looks up the process ID of the child command started by the associated _popen call, closes the stream, executes a _cwait call on the child command, and returns the exit status of the child command. See the reference page on »_pipe« for a general discussion of pipes in Windows NT.

Return Value

The _pclose function returns the exit status of the child command. The format of the return value is the same as that for _cwait, with the exception that the low-order and high-order bytes are swapped. If an error occurs, −1 is returned.

See Also

»_popen«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: perror
  perror

#include <stdio.h>

void perror( const char *string );

string    String message to print

Remarks

The perror function prints an error message to stderr. The string argument is printed first, followed by a colon, then by the system error message for the last library call that produced the error, and finally by a newline character. If string is a null pointer or a pointer to a null string, perror prints only the system error message.

The actual error number is stored in the variable errno (defined in ERRNO.H). The system error messages are accessed through the variable _sys_errlist, which is an array of messages ordered by error number. The perror function prints the appropriate error message by using the errno value as an index to _sys_errlist. The value of the variable _sys_nerr is defined as the maximum number of elements in the _sys_errlist array.

To produce accurate results, perror should be called immediately after a library routine returns with an error. Otherwise, the errno value may be overwritten by subsequent calls.

Under MS-DOS, some of the errno values listed in ERRNO.H are not used. These additional errno values are reserved for UNIX use. See »_doserrno, errno, _sys_errlist, _sys_nerr« for a list of errno values used in MS-DOS and the corresponding error messages. The perror function prints an empty string for any errno value not used under the operating system.

Return Value

None.

See Also

»clearerr,« »ferror,« »strerror«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* PERROR.C: This program attempts to open a file named
 * NOSUCHF.ILE. Because this file probably doesn't exist,
 * an error message is displayed. The same message is
 * created using perror, strerror, and _strerror.
 */

#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void main( void )
{
   int  fh;

   if( (fh = _open( "NOSUCHF.ILE", _O_RDONLY )) == -1 )
   {
      /* Three ways to create error message: */
      perror( "perror says open failed" );
      printf( "strerror says open failed: %s\n", strerror( errno ) );
      printf( _strerror( "_strerror says open failed" ) );
   }
   else
   {
      printf( "open succeeded on input file\n" );
      _close( fh );
   }
}

Output

perror says open failed: No such file or directory

strerror says open failed: No such file or directory
_strerror says open failed: No such file or directory


Description: _pg_analyzechart Functions
  _pg_analyzechart Functions

#include <pgchart.h>

short __far _pg_analyzechart( _chartenv __far *env, const char __far * const __far *categories, const float __far *values, short n );

short __far _pg_analyzechartms( _chartenv __far *env, const char __far * const __far *categories, const float __far *values, short nseries, short n, short arraydim, const char __far * const __far *serieslabels );

env    Chart environment variable

categories    Array of category variables

values    Array of data values

nseries    Number of series to chart

n    Number of data values to chart

arraydim    Row dimension of data array

serieslabels    Array of labels for series

Remarks

The _pg_analyzechart routines analyze a single or multiple series of data without actually displaying the presentation-graphic image.

The _pg_analyzechart function fills the chart environment with default values for a single-series bar, column, or line chart, depending on the type specified by the call to the _pg_defaultchart function. The variables calculated by _pg_analyzechart reflect the data given in the arguments categories and values. All arguments are the same as those used with the »_pg_chart« function.

The _pg_analyzechartms function fills the chart environment with default values for a multiseries bar, column, or line chart, depending on which type is specified in the _pg_defaultchart function. The variables calculated by _pg_analyzechartms reflect the data given in the arguments categories and values. All arguments are the same as those used with the »_pg_chartms« function.

Boolean flags in the chart environment, such as AUTOSCALE and LEGEND, should be set to TRUE before calling either _pg_analyzechart function. This will ensure that the function will calculate all defaults.

Return Value

The _pg_analyzechart and _pg_analyzechartms functions return 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_chart functions,« »_pg_defaultchart,« »_pg_initchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * PGACHART.C: This example illustrates presentation-
 * graphics analyze functions. The example uses:
 *      _pg_analyzechartms
 * The same principles apply for
 *      _pg_analyzepie        _pg_analyzechart
 *      _pg_analyzescatter    _pg_analyzescatterms
 */

#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <graph.h>
#include <pgchart.h>

#define FALSE  0
#define TRUE   1

/* Note data declared as a single-dimension array. The
 * multiseries chart functions expect only one dimension.
 * See _pg_chartms example for an alternate method using
 * multidimension array.
 */

#define TEAMS  4
#define MONTHS 3
float __far values[TEAMS * MONTHS] = { .435f,   .522f,   .671f,
                                       .533f,   .431f,   .590f,
                                       .723f,   .624f,   .488f,
                                       .329f,   .226f,   .401f  };
char __far *months[MONTHS] =         { "May",   "June",  "July" };
char __far *teams[TEAMS] = { "Reds", "Sox", "Cubs", "Mets" };

void main( void )
{
   _chartenv env;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   _pg_initchart();                    /* Initialize chart system.  */
   /* Default multiseries bar chart */
   _pg_defaultchart( &env, _PG_BARCHART, _PG_PLAINBARS );
    strcpy( env.maintitle.title, "Little League Records - Default" );
   _pg_chartms( &env, months, values, TEAMS, MONTHS, MONTHS, teams );
   _getch();
   _clearscreen( _GCLEARSCREEN );

   /* Analyze multiseries bar chart with autoscale. This sets all
    * default scale values. We want y axis values to be automatic.
    */
   _pg_defaultchart( &env, _PG_BARCHART, _PG_PLAINBARS );
   strcpy( env.maintitle.title, "Little League Records - Customized" );
   env.xaxis.autoscale = TRUE;
   _pg_analyzechartms( &env, months, values, TEAMS, MONTHS, MONTHS,
                       teams );

   /* Now customize some of the x axis values. Then draw the chart.  */
   env.xaxis.autoscale = FALSE;
   env.xaxis.scalemax = 1.0f;        /* Make scale show 0.0 to 1.0.   */
   env.xaxis.ticinterval = 0.2f;     /* Don't make scale too crowded. */
   env.xaxis.ticdecimals = 3;        /* Show three decimals.          */
   strcpy( env.xaxis.scaletitle.title, "Win/Loss Percentage" );
   _pg_chartms( &env, months, values, TEAMS, MONTHS, MONTHS, teams );
   _getch();

   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _pg_analyzepie
  _pg_analyzepie

#include <pgchart.h>

short __far _pg_analyzepie( _chartenv __far *env, const char __far * const __far *categories, const float __far *values, const short __far *explode, short n );

env    Chart environment variable

categories    Array of category variables

values    Array of data values

explode    Array of explode flags

n   Number of data values to chart

Remarks

The _pg_analyzepie function analyzes a single series of data without actually displaying the graphic image. The _pg_analyzepie function fills the chart environment for a pie chart using the data contained in the array values. All arguments are the same as those used in the »_pg_chartpie« function.

Return Value

The _pg_analyzepie function returns 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_chartpie,« »_pg_defaultchart,« »_pg_initchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_analyzechart.«


Description: _pg_analyzescatter Functions
  _pg_analyzescatter Functions

#include <pgchart.h>

short __far _pg_analyzescatter( _chartenv __far *env, float __far *xvalues, float __far *yvalues, short n );

short __far _pg_analyzescatterms( _chartenv __far *env, const float __far *xvalues, const float __far *yvalues, short nseries, short n, short rowdim, const char __far * const __far *serieslabels );

env    Chart environment structure

xvalues    Array of x-axis data values

yvalues    Array of y-axis data values

n    Number of data values to chart

nseries    Number of series to chart

rowdim    Row dimension of data array

serieslabels    Array of labels for series

Remarks

The _pg_analyzescatter set of routines analyzes a single or multiple series of data without actually displaying the graphic image.

The _pg_analyzescatter function fills the chart environment for a single-series scatter diagram. The variables calculated by this function reflect the data given in the arguments xvalues and yvalues. All arguments are the same as those used in the »_pg_chartscatter« function.

The _pg_analyzescatterms function fills the chart environment for a multiseries scatter diagram. The variables calculated by _pg_analyzescatterms reflect the data given in the arguments xvalues and yvalues. All arguments are the same as those used in the »_pg_chartscatterms« function.

Boolean flags in the chart environment, such as AUTOSCALE and LEGEND, should be set to TRUE before calling _pg_analyzescatterms; this ensures that the function will calculate all defaults.

Return Value

The _pg_analyzescatter and _pg_analyzescatterms functions return 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_chartscatter functions,« »_pg_defaultchart,« »_pg_initchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_analyzechart.«


Description: _pg_chart Functions
  _pg_chart Functions

#include <pgchart.h>

short __far _pg_chart( _chartenv __far *env, const char __far * const __far *categories, const float __far *values, short n );

short __far _pg_chartms( _chartenv __far *env, const char __far * const __far *categories, const float __far *values, short nseries, short n, short arraydim, const char __far * const __far *serieslabels );

env    Chart environment variable

categories    Array of category variables

values    Array of data values

n    Number of data values to chart

nseries    Number of series to chart

arraydim    Row dimension of data array

serieslabels    Array of labels for series

Remarks

The _pg_chart function displays a single-series bar, column, or line chart, depending on the type specified in the chart environment variable (env). The _pg_chartms function displays a multiseries bar, column, or line chart, depending on the type specified in the chart environment. All the series must contain the same number of data points, specified by the argument n.

The array values is a two-dimensional array containing all value data for every series to be plotted on the chart. Each column of values represents a single series. The parameter arraydim is the integer value used to dimension rows in the array declaration for values. For example, the following code fragment declares the identifier values to be a two-dimensional floating-point array with 20 rows and 10 columns:

#define ARRAYDIM 20
float values [ARRAYDIM][10];
short rowdim = ARRAYDIM;

Note that the number of columns in the values array cannot exceed 10, the maximum number of data series on a single chart. Note also that rowdim must be greater than or equal to the argument n, and the column dimension in the array declaration must be greater than or equal to the argument nseries. If n and nseries are set to values less than the full dimensional size of the values array, only part of the data contained in values will be plotted.

The array serieslabels holds the labels used in the chart legend to identify each series.

For a discussion of the chart environment and related topics, see »Presentation-Graphics Functions.«

Return Value

The _pg_chart and _pg_chartms functions return 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_analyzechart functions,« »_pg_defaultchart,« »_pg_initchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * PGCHART.C: This example illustrates presentation-graphics
 * support routines and single-series chart routines, including
 *  _pg_initchart  _pg_defaultchart  _pg_chart  _pg_chartpie
 */

#include <conio.h>
#include <graph.h>
#include <string.h>
#include <stdlib.h>
#include <pgchart.h>

#define COUNTRIES 5

float __far value[COUNTRIES] =    { 42.5f, 14.3f, 35.2f, 21.3f, 32.6f };
char __far *category[COUNTRIES] = { "Cuba", "France", "USA", "UK",
                                    "Other" };
short __far explode[COUNTRIES] =  { 0, 1, 0, 1, 0 };

void main( void )
{
   _chartenv env;
   short mode = _VRES16COLOR;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   _pg_initchart();                 /* Initialize chart system. */

   /* Single-series bar chart */
   _pg_defaultchart( &env, _PG_BARCHART, _PG_PLAINBARS );
   strcpy( env.maintitle.title, "Widget Production" );
   _pg_chart( &env, category, value, COUNTRIES );
   _getch();
   _clearscreen( _GCLEARSCREEN );

   /* Single-series column chart */
   _pg_defaultchart( &env, _PG_COLUMNCHART, _PG_PLAINBARS );
   strcpy( env.maintitle.title, "Widget Production" );
   _pg_chart( &env, category, value, COUNTRIES );
   _getch();
   _clearscreen( _GCLEARSCREEN );

   /* Pie chart */
   _pg_defaultchart( &env, _PG_PIECHART, _PG_PERCENT );
   strcpy( env.maintitle.title, "Widget Production" );
   _pg_chartpie( &env, category, value, explode, COUNTRIES );
   _getch();

   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _pg_chartpie
  _pg_chartpie

#include <pgchart.h>

short __far _pg_chartpie( _chartenv __far *env, const char __far * const __far *categories, const float __far *values, const short __far * explode, short n );

env    Chart environment structure

categories    Array of category labels

values    Array of data values

explode    Array of explode flags

n    Number of data values to chart

Remarks

The _pg_chartpie function displays a pie chart for the data contained in the array values. Pie charts are formed from a single series of data; there is no multiseries version of pie charts as there is for other chart types.

The array explode must be dimensioned so that its length is greater than or equal to the argument n. All entries in explode are either 0 or 1. If an entry is 1, the corresponding pie slice is displayed slightly removed from the rest of the pie. For example, if the explode array is initialized as short explode[5] = {0, 1, 0, 0, 0}; the pie slice corresponding to the second entry of the categories array will be displayed "exploded" from the other four slices.

For a discussion of the chart environment and related topics, see »Presentation-Graphics Functions.«

Return Value

The _pg_chartpie function returns 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_analyzepie,« »_pg_defaultchart,« »_pg_initchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_chart.«


Description: _pg_chartscatter Functions
  _pg_chartscatter Functions

#include <pgchart.h>

short __far _pg_chartscatter( _chartenv __far *env, float __far *xvalues, float __far *yvalues, short n );

short __far _pg_chartscatterms( _chartenv __far *env, const float __far *xvalues, const float __far *yvalues, short nseries, short n, short rowdim, const char __far * const __far *serieslabels );

env    Chart environment structure

xvalues    Array of x-axis data values

yvalues    Array of y-axis data values

n    Number of data values to chart

nseries    Number of series to chart

rowdim    Row dimension of data array

serieslabels    Array of labels for series

Remarks

The _pg_chartscatter function displays a scatter diagram for a single series of data. The _pg_chartscatterms function displays a scatter diagram for more than one series of data.

The arguments xvalues and yvalues are two-dimensional arrays containing data for the x axis and y axis, respectively. Columns for each array hold data for individual series; thus the first columns of xvalues and yvalues contain plot data for the first series, the second columns contain plot data for the second series, and so forth. The n, rowdim, nseries, and serieslabels arguments fulfill the same purposes as those used in the _pg_chartms function. See the reference page on »_pg_chartms« for an explanation of these arguments.

For a discussion of the chart environment and related topics, see »Presentation-Graphics Functions.«

Return Value

The _pg_chartscatter and _pg_chartscatterms functions return 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_analyzescatter functions,« »_pg_defaultchart,« »_pg_initchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_chart.«


Description: _pg_defaultchart
  _pg_defaultchart

#include <pgchart.h>

short __far _pg_defaultchart( _chartenv __far *env, short charttype, short chartstyle );

env    Chart environment structure

charttype   Chart type

chartstyle    Chart style

Remarks

The _pg_defaultchart function initializes all necessary variables in the chart environment for the chart type by the variable charttype. All title fields in the environment structure are blanked. Titles should be set in the proper fields after calling _pg_defaultchart. The charttype variable can be set to one of the following manifest constants:

_PG_BARCHART    Bar chart

_PG_COLUMNCHART    Column chart

_PG_LINECHART    Line chart

_PG_PIECHART    Pie chart

_PG_SCATTERCHART    Scatter chart

The chartstyle variable specifies the style of the chart with either the number "1" or the number "2." Each of the five types of presentation-graphics charts can appear in two different chart styles, as described following:

Chart type	Chart style 1	Chart style 2
Bar	Side by side	Stacked
Column	Side by side	Stacked
Line	Points with lines	Points only
Pie	Percent	No percent
Scatter	Points with lines	Points only
In a pie chart, the pieces are "exploded" according to the explode array argument in the _pg_chartpie function. In the "percent" format, percentages are printed next to each slice. Bar and column charts have only one style when displaying a single series of data. The styles "side by side" and "stacked" are applicable only when more than one series appears on the same chart. The first style arranges the bars or columns for the different series side by side, showing relative heights or lengths. The stacked style emphasizes relative sizes between bars and columns.

Return Value

The _pg_defaultchart function returns 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_getchardef,« »_pg_getpalette,« »_pg_getstyleset,« »_pg_hlabelchart,« »_pg_initchart,« »_pg_resetpalette,« »_pg_resetstyleset,« »_pg_setchardef,« »_pg_setpalette,« »_pg_setstyleset,« »_pg_vlabelchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_chart.«


Description: _pg_getchardef
  _pg_getchardef

#include <pgchart.h>

short __far _pg_getchardef( short charnum, unsigned char __far *chardef );

charnum    ASCII number of character

chardef    Pointer to 8-by-8 bitmap array

Remarks

The _pg_getchardef function retrieves the current 8-by-8 pixel bitmap for the character having the ASCII number charnum. The bitmap is stored in the chardef array.

Return Value

The _pg_getchardef function returns 0 if there are no errors. A nonzero value indicates an error.

See Also

»_pg_defaultchart,« »_pg_initchart,« »_pg_setchardef«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _pg_getpalette
  _pg_getpalette

#include <pgchart.h>

short __far _pg_getpalette( _paletteentry __far *palette );

palette    Pointer to first palette structure in array

Remarks

The _pg_getpalette function retrieves palette colors, line styles, fill patterns, and plot characters for all palettes. The pointer palette points to an array of palette structures that will contain the desired palette values. The palette used by the presentation-graphics routines is independent of the palette used by the low-level graphics routines.

Return Value

The function _pg_getpalette returns 0 if there are no errors, and it returns the value _BADSCREENMODE if current palettes have not been initialized by a previous call to _pg_setpalette.

See Also

»_pg_defaultchart,« »_pg_initchart,« »_pg_resetpalette,« »_pg_setpalette«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * PGGPAL.C: This example illustrates presentation-graphics
 * palettes and the routines that modify them, including
 *    _pg_getpalette    _pg_resetpalette    _pg_setstyleset
 *    _pg_getstyleset   _pg_resetstyleset   _pg_vlabelchart
 *    _pg_hlabelchart   _pg_setpalette
 */

#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <graph.h>
#include <pgchart.h>

#define TEAMS  2
#define MONTHS 3

float __far values[TEAMS][MONTHS] =   { { .435f,  .522f,  .671f },
                                        { .533f,  .431f,  .401f } };
char __far *months[MONTHS] =            { "May", "June", "July" };
char __far *teams[TEAMS] = { "Cubs", "Reds" };

_fillmap fill1 = { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc };
_fillmap fill2 = { 0x99, 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33 };
_styleset styles;
_palettetype pal;

void main( void )
{
   _chartenv env;
   short mode = _VRES16COLOR;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   _pg_initchart();                 /* Initialize chart system.  */

   /* Modify global set of line styles used for borders, grids, and
    * data connectors. Note that this change is used before
    * _pg_defaultchart, which will use the style set.
    */
   _pg_getstyleset( styles );       /* Get styles and modify       */
   styles[1] = 0x5555;              /*   style 1 (used for         */
   _pg_setstyleset( styles );       /*   borders)-then set new.    */

   _pg_defaultchart( &env, _PG_BARCHART, _PG_PLAINBARS );

   /* Modify palette for data lines, colors, fill patterns, and
    * characters. Note that the line styles are set in the palette, not
    * in the style set, so that only data connectors will be affected.
    */
   _pg_getpalette( pal );           /* Get default palette.        */
   pal[1].plotchar = 16;            /* Set to ASCII 16 and 17.     */
   pal[2].plotchar = 17;
   memcpy( pal[1].fill, fill1, 8 ); /* Copy fill masks to palette. */
   memcpy( pal[2].fill, fill2, 8 );
   pal[1].color = 3;                /* Change palette colors.      */
   pal[2].color = 4;
   pal[1].style = 0xfcfc;           /* Change palette line styles. */
   pal[2].style = 0x0303;
   _pg_setpalette( pal );           /* Put modified palette.       */

   /* Multiseries bar chart */
   strcpy( env.maintitle.title, "Little League Records - Customized" );
   _pg_chartms( &env, months, (float __far *)values,
                TEAMS, MONTHS, MONTHS, teams );
   _getch();
   _clearscreen( _GCLEARSCREEN );

   /* Multiseries line chart */
   _pg_defaultchart( &env, _PG_LINECHART, _PG_POINTANDLINE );
   strcpy( env.maintitle.title, "Little League Records - Customized" );
   _pg_chartms( &env, months, (float __far *)values,
                TEAMS, MONTHS, MONTHS, teams );

   /* Print labels. */
   _pg_hlabelchart( &env, (short)(env.chartwindow.x2 * .75),
                          (short)(env.chartwindow.y2 * .10),
                          12, "Up and up!" );
   _pg_vlabelchart( &env, (short)(env.chartwindow.x2 * .75),
                          (short)(env.chartwindow.y2 * .45),
                          13, "Sliding down!" );
   _getch();
   _clearscreen( _GCLEARSCREEN );

   _pg_resetpalette();                /* Restore default palette   */
   _pg_resetstyleset();               /*   and style set.          */

   /* Multiseries bar chart */
   _pg_defaultchart( &env, _PG_BARCHART, _PG_PLAINBARS );
   strcpy( env.maintitle.title, "Little League Records - Default" );
   _pg_chartms( &env, months, (float __far *)values,
                TEAMS, MONTHS, MONTHS, teams );
   _getch();
   _clearscreen( _GCLEARSCREEN );

   /* Multiseries line chart */
   _pg_defaultchart( &env, _PG_LINECHART, _PG_POINTANDLINE );
   strcpy( env.maintitle.title, "Little League Records - Default" );
   _pg_chartms( &env, months, (float __far *)values,
                TEAMS, MONTHS, MONTHS, teams );
   _getch();

   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _pg_getstyleset
  _pg_getstyleset

#include <pgchart.h>

void __far _pg_getstyleset( unsigned short __far *styleset );

styleset    Pointer to current styleset array

Remarks

The _pg_getstyleset function retrieves the contents of the current styleset array.

Return Value

None.

See Also

»_pg_defaultchart,« »_pg_initchart,« »_pg_resetstyleset,« »_pg_setstyleset«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_getpalette.«


Description: _pg_hlabelchart
  _pg_hlabelchart

#include <pgchart.h>

short __far _pg_hlabelchart( _chartenv __far *env, short x, short y, short color, const char __far *label );

env    Chart environment structure

x    x-coordinate for text

y    Pixel y-coordinate for text

color    Color code for text

label    Label text

Remarks

The _pg_hlabelchart function writes text horizontally on the screen. The arguments x and y are pixel coordinates for the beginning location of text relative to the upper-left corner of the chart window.

Return Value

The _pg_hlabelchart functions return 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_defaultchart,« »_pg_initchart,« »_pg_vlabelchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_getpalette.«


Description: _pg_initchart
  _pg_initchart

#include <pgchart.h>

short __far _pg_initchart( void );

Remarks

The _pg_initchart function initializes the presentation-graphics package. It initializes the color and style pools, resets the chart-line styleset, builds default palette modes, and reads the presentation-graphics font definition from the disk. This function is required in all programs that use presentation graphics. The _pg_initchart function must be called before any of the other functions in the presentation-graphics library. Also, _pg_initchart must be called after each change of the video mode. The _pg_initchart function assumes a valid graphics mode has been established. Therefore, it must be called only after a successful call to the library function »_setvideomode.«

Note  The _pg_initchart function can only be called after using the _setvideomode function to establish the video mode. Also, _pg_initchart must be called after each change of the video mode.

Return Value

The _pg_initchart functions return 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_defaultchart,« »_pg_getchardef,« »_pg_getpalette,« »_pg_getstyleset,« »_pg_hlabelchart,« »_pg_resetpalette,« »_pg_resetstyleset,« »_pg_setchardef,« »_pg_setpalette,« »_pg_setstyleset,« »_pg_vlabelchart,« »_setvideomode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_chart.«


Description: _pg_resetpalette
  _pg_resetpalette

#include <pgchart.h>

short __far _pg_resetpalette( void );

Remarks

The _pg_resetpalette function sets the palette colors, line styles, fill patterns, and plot characters for the palette to the default for the current screen mode. The palette used by the presentation-graphics routines is independent of the palette used by the low-level graphics routines.

Return Value

The _pg_resetpalette function returns 0 if there are no errors. If the screen mode is not valid, the value _BADSCREENMODE is returned.

See Also

»_pg_defaultchart,« »_pg_getpalette,« »_pg_initchart,« »_pg_setpalette«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_getpalette.«


Description: _pg_resetstyleset
  _pg_resetstyleset

#include <pgchart.h>

void __far _pg_resetstyleset( void );

Remarks

The _pg_resetstyleset function reinitializes the styleset to the default values for the current screen mode.

Return Value

None.

See Also

»_pg_defaultchart,« »_pg_getstyleset,« »_pg_initchart,« »_pg_setstyleset«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_getpalette.«


Description: _pg_setchardef
  _pg_setchardef

#include <pgchart.h>

short __far _pg_setchardef( short charnum, unsigned char __far *chardef );

charnum    ASCII number of character

chardef    Pointer to an 8-by-8 bitmap array for the character

Remarks

The _pg_setchardef function sets the 8-by-8 pixel bitmap for the character with the ASCII number charnum. The bitmap is stored in the chardef array.

Return Value

The _pg_setchardef function returns 0 if there is no error. A nonzero value indicates an error.

See Also

»_pg_defaultchart,« »_pg_getchardef,« »_pg_initchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _pg_setpalette
  _pg_setpalette

#include <pgchart.h>

short __far _pg_setpalette( _paletteentry __far *palette );

palette    Pointer to first palette structure in array

Remarks

The _pg_setpalette function sets palette colors, line styles, fill patterns, and plot characters for all palettes. The pointer palette points to an array of palette structures that contain the desired palette values. The palette used by the presentation-graphics routines is independent of the palette used by the low-level graphics routines.

Return Value

The _pg_setpalette function returns 0 if there are no errors. If the new palettes are not valid, the value _BADSCREENMODE is returned.

See Also

»_pg_defaultchart,« »_pg_getpalette,« »_pg_initchart,« »_pg_resetpalette«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_getpalette.«


Description: _pg_setstyleset
  _pg_setstyleset

#include <pgchart.h>

void __far _pg_setstyleset( unsigned short __far *styleset );

styleset    Pointer to new styleset

Remarks

The _pg_setstyleset function sets the current styleset.

Return Value

None.

See Also

»_pg_defaultchart,« »_pg_getstyleset,« »_pg_initchart,« »_pg_resetstyleset«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_getpalette.«


Description: _pg_vlabelchart
  _pg_vlabelchart

#include <pgchart.h>

short __far _pg_vlabelchart( _chartenv __far *env, short x, short y, short color, const char __far *label );

env    Chart environment structure

x    Pixel x coordinate for text

y    Pixel y coordinate for text

color    Color code for text

label    Label text

Remarks

The _pg_vlabelchart function writes text vertically on the screen. The arguments x and y are pixel coordinates for the beginning location of text relative to the upper-left corner of the chart window.

Return Value

The _pg_vlabelchart function returns 0 if there are no errors. A nonzero value indicates a failure.

See Also

»_pg_defaultchart,« »_pg_hlabelchart,« »_pg_initchart«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_pg_getpalette.«


Description: _pie Functions
  _pie Functions

#include <graph.h>

short __far _pie( short control, short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4 );

short __far _pie_w( short control, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4 );

short __far _pie_wxy( short control, struct _wxycoord __far *pwxy1, struct _wxycoord __far *pwxy2, struct _wxycoord __far *pwxy3, struct _wxycoord __far *pwxy4 );

control     Fill-control constant

x1, y1    Upper-left corner of bounding rectangle

x2, y2    Lower-right corner of bounding rectangle

x3, y3    Second point of start vector (center of bounding rectangle is first point)

x4, y4    Second point of end vector (center of bounding rectangle is first point)

pwxy1    Upper-left corner of bounding rectangle

pwxy2    Lower-right corner of bounding rectangle

pwxy3    Second point of start vector (center of bounding rectangle is first point)

pwxy4    Second point of end vector (center of bounding rectangle is first point)

Remarks

The _pie functions draw a pie-shaped wedge by drawing an elliptical arc whose center and two endpoints are joined by lines. The center of the pie is the center of the bounding rectangle, which is defined by points (x1, y1) and (x2, y2) for _pie and _pie_w and by points pwxy1 and pwxy2 for _pie_wxy. The pie starts where it intersects an imaginary line extending from the center of the arc through (x3, y3) for _pie and _pie_w and through pwxy3 for _pie_wxy. It is drawn counterclockwise about the center of the arc, ending where it intersects an imaginary line extending from the center of the arc through (x4, y4) for _pie and _pie_w and through pwxy4 for _pie_wxy.

The _pie routine uses the view coordinate system. The _pie_w and _pie_wxy functions use the real-valued window coordinate system. The arc is drawn using the current color. Because an arc does not define a closed area, it is not filled.

The _wxycoord structure is defined in GRAPH.H and contains double wx, the window x coordinate, and double wy, the window y coordinate.

The wedge is drawn using the current color moving in a counterclockwise direction. The control parameter can be one of two manifest constants, _GFILLINTERIOR, which fills the figure using the current color and fill mask, or _GBORDER, which does not fill the figure. The control option given by _GFILLINTERIOR is equivalent to a subsequent call to the _floodfill function using the approximate center of the pie as the starting point and the current color (set by _setcolor) as the boundary color. Use the _getarcinfo function to find the exact starting point.

Return Value

These functions return a nonzero value if successful; otherwise, they return 0.

See Also

»_arc functions,« »_ellipse functions,« »_floodfill,« »_getarcinfo,« »_getcolor,« »_lineto functions,« »_rectangle functions,« »_setcolor,« »_setfillmask«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * PIE.C: This program draws a pie-shaped figure.
 *
 */

#include <stdlib.h>
#include <conio.h>
#include <graph.h>

void main( void )
{
   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   _pie( _GBORDER, 80, 50, 240, 150, 240, 12, 0, 150 );
   _getch();

   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _pipe
   _pipe

#include <fcntl.h>    For _O_BINARY and _O_TEXT definitions

#include <errno.h>    errno definitions

#include <io.h>    Prototype declaration

int _pipe( int *phandles, unsigned int psize, int textmode );

phandles[2]    Array to hold read and write handles

psize    Amount of memory to reserve

textmode    File mode

Remarks

A pipe is an artificial I/O channel that a program can create and use to pass information to other programs. A pipe is similar to a file in that it has a file pointer or a file descriptor, or both, and can be read from or written to using the input and output functions of the standard library. However, a pipe does not represent a specific file or device. Instead, a pipe represents temporary storage in memory that is independent of the program's own memory and is controlled entirely by the operating system.

Pipes may be used to pass information between programs. For example, the command processor in Windows NT creates a pipe when executing a command such as

PROGRAM1 | PROGRAM2

The standard output handle of PROGRAM1 is attached to the pipe's write handle. The standard input handle of PROGRAM2 is attached to the pipe's read handle. This eliminates the need for creating temporary files to pass information to other programs.

The _pipe function creates a pipe. This function is similar to _open but opens the pipe for both reading and writing, returning two file handles instead of one. The program can either use both sides of the pipe or close the one it does not need. This function typically opens a pipe in preparation for linking it to a child process.

The _pipe function opens a pipe and returns two handles to the pipe in the phandles argument. The element phandles[0] contains the read handle, and the element phandles[1] contains the write handle. Pipe file handles are used in the same way as other file handles. (The low-level input and output functions _read and _write can read from and write to a pipe.) To detect the end-of-pipe condition, check for a _read request that returns 0 as the number of bytes read.

The psize argument specifies the amount of memory, in bytes, to reserve for the pipe. The textmode argument specifies the translation mode for the pipe. The manifest constant _O_TEXT specifies a text translation, and the constant _O_BINARY specifies binary translation. (See the reference page on »fopen« for a description of text and binary modes.) If the textmode argument is 0, the _pipe function uses the default translation mode specified by the default-mode variable _fmode.

In multithreaded programs, no locking is performed. The handles returned are newly opened and should not be referenced by any thread until after the _pipe call is complete.

In Windows NT, a pipe is destroyed when all of its handles have been closed. (If all read handles on the pipe have been closed, writing to the pipe will cause an error.) All read and write operations on the pipe wait until there is enough data or enough buffer space to complete the I/O request.

Return Value

The _pipe function returns 0 if successful. A return value of −1 indicates an error, and errno is set to one of two values: EMFILE, which means no more file handles available (too many open files), or ENFILE, which means a system file table overflow.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* PIPE.C: This program uses the _pipe function to pass streams of
 * text to spawned processes.
 */

#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <process.h>
#include <math.h>

enum PIPES { READ, WRITE }; /* Constants 0 and 1 for READ and WRITE */
#define NUMPROBLEM 8

void main( int argc, char *argv[] )
{

   int hpipe[2];
   char hstr[20];
   int pid, problem, c;
   int termstat;

   /* If no arguments, this is the spawning process */
   if( argc == 1 )
   {
      setvbuf( stdout, NULL, _IONBF, 0 );

      /* Open a set of pipes */
      if( _pipe( hpipe, 256, O_BINARY ) == -1 )
          exit( 1 );

      /* Convert pipe read handle to string and pass as argument
       * to spawned program. Program spawns itself (argv[0]).
       */
      itoa( hpipe[READ], hstr, 10 );
      if( ( pid = spawnl( P_NOWAIT, argv[0], argv[0],
            hstr, NULL ) ) == -1 )
          printf( "Spawn failed" );

      /* Put problem in write pipe. Since spwaned program is
       * running simultaneously, first solutions may be done
       * before last problem is given.
       */
      for( problem = 1000; problem <= NUMPROBLEM * 1000;
           problem += 1000)
      {
         printf( "Son, what is the square root of %d?\n", problem );
         write( hpipe[WRITE], (char *)&problem, sizeof( int ) );
      }

      /* Wait until spawned program is done processing. */
      _cwait( &termstat, pid, WAIT_CHILD );
      if( termstat & 0x0 )
         printf( "Child failed\n" );

      close( hpipe[READ] );
      close( hpipe[WRITE] );
   }

   /* If there is an argument, this must be the spawned process. */
   else
   {
      /* Convert passed string handle to integer handle. */
      hpipe[READ] = atoi( argv[1] );

      /* Read problem from pipe and calculate solution. */
      for( c = 0; c < NUMPROBLEM; c++ )
      {
        read( hpipe[READ], (char *)&problem, sizeof( int ) );
        printf( "Dad, the square root of %d is %3.2f.\n",
                 problem, sqrt( ( double )problem ) );
      }
   }
}


Description: _polygon Functions
  _polygon Functions

#include <graph.h>

short __far _polygon( short control, const struct _xycoord __far * points, short numpoints );

short __far _polygon_w( short control, const double __far *points, short numpoints );

short __far _polygon_wxy( short control, const struct _wxycoord __far *points, short numpoints );

control    Fill flag

points    Pointer to an array of structures or doubles defining the polygon

numpoints    Number of points

Remarks

The _polygon functions draw polygons. The border of the polygon is drawn in the current color and line style. The _polygon routine uses the view coordinate system (expressed in _xycoord structures), and the _polygon_wxy and _polygon_w routines use real-valued window coordinates (expressed in _wxycoord structures and in pairs of double-precision floating-point values, respectively).

The argument points is an array of _xycoord or _wxycoord structures or pairs of doubles, each of which specifies one of the polygon's vertices. (For _polygon_w, points[0] and points[1] specify the x and y coordinates, respectively, of the first point.) If the first point does not equal the last point, the _polygon functions use them to provide a closing edge. The argument numpoints indicates the number of elements (the number of vertices) in the points array. The minimum number of points is 3; the maximum is 16,381. The control argument can be one of two manifest constants, _GFILLINTERIOR, which fills the polygon with the current fill mask using a scan fill, or _GBORDER, which does not fill the polygon.

The _setwritemode, _setlinestyle, and _setfillmask functions all affect the output from the _polygon functions. If you try to fill the polgon with the _floodfill function, the polygon must be bordered by a solid line-style pattern.

Return Value

The _polygon functions return a nonzero value if the arc is successfully drawn; otherwise, they return 0.

See Also

»_ellipse functions,« »_floodfill,« »_lineto functions,« »_pie functions,« »_rectangle functions,« »_setcolor,« »_setfillmask,« »_setlinestyle,« »_setwritemode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * POLYGON.C: This program draws a star-shaped polygon.
 *
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>
#include <math.h>
#include <stdlib.h>

#define PI 3.1415

void main( void )
{
   short  side, radius = 90, x = 0, y = 0;
   double radians;
   struct _xycoord polyside[5];
   struct _videoconfig vc;
   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );
   _getvideoconfig( &vc );
   _setvieworg( (short)(vc.numxpixels / 2),
                (short)(vc. numypixels / 2) );

   /* Calculate points of star every 144 degrees, then connect them. */
   for( side = 0;side < 5;side++ )
   {
      radians = 144 * PI / 180;
      polyside[side].xcoord = x + (short)(cos( side * radians )
                                * radius);
      polyside[side].ycoord = y + (short)(sin( side * radians )
                                * radius);
   }
   _polygon( _GFILLINTERIOR, polyside, 5 );
   _getch();
   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _popen
  _popen

#include <stdio.h>

FILE *_popen( char *command, char *mode );

command    Command to be executed

mode    Mode of returned stream

Remarks

The _popen function creates a pipe and asynchronously executes a child copy of the command processor with the specified string command. See »_pipe« for a general discussion of pipes in Windows NT. The character string mode specifies the type of access requested, as follows:

"r"    The calling process can read the child command's standard output via the returned stream.

"w"    The calling process can write to the child command's standard input via the returned stream.

"b"    Open in binary mode.

"t"    Open in text mode.

Return Value

The _popen function returns a stream associated with one end of the created pipe. The other end of the pipe is associated with the child command's standard input or standard output. If an error occurs, NULL is returned.

See Also

»_pclose«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* POPEN.C: This program uses _popen and _pclose to receive a
 * stream of text from a system process.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{

   char   psBuffer[128];
   FILE   *chkdsk;

   /* Run DIR so that it writes its output to a pipe. Open this
    * pipe with read text attribute so that we can read it
    * like a text file.
    */
   if( (chkdsk = _popen( "dir *.c /on /p", "rt" )) == NULL )
      exit( 1 );

   /* Read pipe until end of file. End of file indicates that
    * CHKDSK closed its standard out (probably meaning it
    * terminated).
    */
   while( !feof( chkdsk ) )
   {
      if( fgets( psBuffer, 128, chkdsk ) != NULL )
         printf( psBuffer );
   }

   /* Close pipe and print return value of CHKDSK. */
   printf( "\nProcess returned %d\n", _pclose( chkdsk ) );
}

Output

 Volume in drive C is CDRIVE
 Volume Serial Number is 1966-6F27

 Directory of C:\libref\code

PIPE     C                 2225 04-16-93  10:25AM
POPEN    C                  801 04-16-93  04:20PM
POW      C                  216 04-06-93  12:09PM
PRINTF   C                 1202 04-09-93  10:03AM
PUTC     C                  474 04-06-93  12:09PM
PUTS     C                  180 04-06-93  12:09PM
PUTW     C                  672 04-06-93  12:09PM
QSORT    C                  792 04-06-93  12:09PM

Process returned 0


Description: pow Functions
  pow Functions

#include <math.h>

double pow( double x, double y );

long double powl( long double x, long double y );

x    Number to be raised

y    Power of x

Remarks

The pow and powl functions compute x raised to the power of y. The powl function is the 80-bit counterpart, and it uses an 80-bit, 10-byte coprocessor form of arguments and return values. See the reference page on the »long double functions« for more details on this data type.

Return Value

The pow and powl functions return the value of xy. If x is not 0.0 and y is 0.0, pow and powl return the value 1. If x is 0.0 and y is negative, pow and powl set errno to EDOM and return 0.0. If both x and y are 0.0, or if x is negative and y is not an integer, the function prints a _DOMAIN error message to stderr, sets errno to EDOM, and returns 0.0. If an overflow results, the function sets errno to ERANGE and returns HUGE_VAL. No message is printed on overflow or underflow.

The pow function does not recognize integral floating-point values greater than 2 raised to the power of 64, such as 1.0E100.

See Also

»exp,« »log functions,« »sqrt«

Compatibility

pow:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

powl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* POW.C
 *
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 2.0, y = 3.0, z;

   z = pow( x, y );
   printf( "%.1f to the power of %.1f is %.1f\n", x, y, z );
}

Output

2.0 to the power of 3.0 is 8.0


Description: printf, wprintf
  printf, wprintf

#include <stdio.h>    For printf

#include <wchar.h>    For wprintf use either WCHAR.H (for ANSI compatibility) or STDIO.H

int printf( const char *format [, argument]... );

int wprintf( const wchar_t *format [, argument]... );

format    Format control

argument    Optional arguments

Remarks

The printf function formats and prints a series of characters and values to the standard output stream, stdout. If arguments follow the format string, the format string must contain specifications that determine the output format for the arguments. The printf and »fprintf« functions behave identically except that printf writes output to stdout rather than to a destination of type FILE.

The wprintf function is a wide-character version of printf; the format is a wide-character string. The wprintf and printf functions behave identically otherwise.

The format argument consists of ordinary characters, escape sequences, and (if arguments follow format) format specifications. The ordinary characters and escape sequences are copied to stdout in order of their appearance. For example, the line printf("Line one\n\t\tLine two\n"); produces the output

Line one
Line two

»Format specifications« always begin with a percent sign (%) and are read left to right. When the first format specification (if any) is encountered, the value of the first argument after format is converted and output accordingly. The second format specification causes the second argument to be converted and output, and so on. If there are more arguments than there are format specifications, the extra arguments are ignored. The results are undefined if there are not enough arguments for all the format specifications.

Format Specification Fields

A format specification, which consists of optional and required fields, has the following form:

%[flags] [width] [.precision] [{F | N}] [{h | l | L}]type

Each field of the format specification is a single character or a number signifying a particular format option. The simplest format specification contains only the percent sign and a type character (for example, %s). If a percent sign is followed by a character that has no meaning as a format field, the character is copied to stdout. For example, to print a percent-sign character, use %%.

The optional fields, which appear before the type character, control other aspects of the formatting, as follows:

type    Required character that determines whether the associated argument is interpreted as a character, a string, or a number. (See »Type Field Characters.«)

flags    Optional character or characters that control justification of output and printing of signs, blanks, decimal points, and octal and hexadecimal prefixes. (See »Flag Directives.«) More than one flag can appear in a format specification.

width    Optional number that specifies minimum number of characters output. (See »Width Specification.«)

precision    Optional number that specifies maximum number of characters printed for all or part of the output field, or minimum number of digits printed for integer values. (See »Precision specification.«)

F | N, h | l | L    Optional characters that specify the "distance" or the size of the argument. (See »Size and Distance Specification.«)

Type Field Characters

The type character is the only required format field for the printf function; it appears after any optional format fields. The type character determines whether the associated argument is interpreted as a character, string, or number (see Table R.3).

Table R.3    Type Characters for printf

Character	Type	Output format
c	int or  wint_t	When used with printf, specifies a single-byte character; when used with wprintf, specifies a wide character.
C	wint_t or  int	When used with printf, specifies a wide character; when used with wprintf, specifies a single-byte character.
d	int	Signed decimal integer.
i	int	Signed decimal integer.
o	int	Unsigned octal integer.
u	int	Unsigned decimal integer.
x	int	Unsigned hexadecimal integer, using "abcdef."
X	int	Unsigned hexadecimal integer, using "ABCDEF."
e	double	Signed value having the form [ − ]d.dddd e [sign]ddd, where d is a single decimal digit, dddd is one or more decimal digits, ddd is exactly three decimal digits, and sign is + or −.
E	double	Identical to the e format except that E rather than e introduces the exponent.
f	double	Signed value having the form [ − ]dddd.dddd, where dddd is one or more decimal digits. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision.
g	double	Signed value printed in f or e format, whichever is more compact for the given value and precision. The e format is used only when the exponent of the value is less than − 4 or greater than or equal to the precision argument. Trailing zeros are truncated, and the decimal point appears only if one or more digits follow it.
G	double	Identical to the g format, except that E, rather than e, introduces the exponent (where appropriate).
n	Pointer to integer	Number of characters successfully written so far to the stream or buffer; this value is stored in the integer whose address is given as the argument.
p	Pointer to void	Prints the address pointed to by the argument in the form xxxx:yyyy, where xxxx is the segment and yyyy is the offset, and the digits x and y are uppercase hexadecimal digits; %hp indicates a near pointer and prints only the offset of the address.
s	String	When used with printf, specifies a single-byte-character string; when used with wprintf, specifies a wide-character string. Characters are printed up to the first null character or until the precision value is reached.
S	String	When used with printf, specifies a wide-character string; when used with wprintf, specifies a single-byte-character string. Characters are printed up to the first null character or until the precision value is reached.
The types c, C, s, and S are Microsoft extensions that should not be used if ANSI portability is desired. Note that for both printf and wprintf, %hC is equivalent to %hc, %lC is equivalent to %lc, %hS is equivalent to %hs, and %lS is equivalent to %ls. That is, prefixing h or l to the type character c, C, s, or S reverses the single-byte character or wide character meaning of that type character as given in Table R.3. (See »Size and Distance Specification« for more information about the use of h and l.)

Flag Directives

The first optional field of the format specification is flag. A flag directive is a character that justifies output and prints signs, blanks, decimal points, and octal and hexadecimal prefixes. More than one flag directive may appear in a format specification.

Table R.4    Flag Characters for printf

Flag	Meaning	Default
−	Left justify the result within the given field width.	Right justify.
+	Prefix the output value with a sign (+ or −) if the output value is of a signed type.	Sign appears only for negative signed values (−).
0	If width is prefixed with 0, zeros are added until the minimum width is reached. If 0 and − appear, the 0 is ignored. If 0 is specified with an integer format (i, u, x, X, o, d) the 0 is ignored.	No padding.
blank (' ')	Prefix the output value with a blank if the output value is signed and positive; the blank is ignored if both the blank and + flags appear.	No blank appears.
#	When used with the o, x, or X format, the # flag prefixes any nonzero output value with 0, 0x, or 0X, respectively.	No blank appears.
	When used with the e, E, or f format, the # flag forces the output value to contain a decimal point in all cases.	Decimal point appears only if digits follow it.
	When used with the g or G format, the # flag forces the output value to contain a decimal point in all cases and prevents the truncation of trailing zeros.	Decimal point appears only if digits follow it. Trailing zeros are truncated.
	Ignored when used with c, d, i, u, or s.
Width Specification

The second optional field of the format specification is the width specification. The width argument is a nonnegative decimal integer controlling the minimum number of characters printed. If the number of characters in the output value is less than the specified width, blanks are added to the left or the right of the values — depending on whether the − flag (for left justification) is specified — until the minimum width is reached. If width is prefixed with 0, zeros are added until the minimum width is reached (not useful for left-justified numbers).

The width specification never causes a value to be truncated. If the number of characters in the output value is greater than the specified width, or width is not given, all characters of the value are printed (subject to the »precision« specification).

The width specification may be an asterisk (*), in which case an int argument from the argument list supplies the value. The width argument must precede the value being formatted in the argument list. A nonexistent or small field width does not cause a truncation of a field; if the result of a conversion is wider than the field width, the field expands to contain the conversion result.

Precision Specification

The third optional field of the format specification is the precision specification. It specifies a nonnegative decimal integer, preceded by a period (.), which specifies the number of characters to be printed, the number of decimal places, or the number of significant digits. (See Table R.5.) Unlike the width specification, the precision specification can cause truncation of the output value, or rounding in the case of a floating-point value. If precision is specified as zero and the value to be converted is zero, the result is no characters output, as shown below:

printf( "%.0d", 0 );      /* No characters output */

The precision specification may be an asterisk (*), in which case an int argument from the argument list supplies the value. The precision argument must precede the value being formatted in the argument list.

The interpretation of the precision value and the default when precision is omitted depend on the type, as shown in Table R.5.

Table R.5    How printf Precision Values Affect Type

Type	Meaning	Default
c, C	The precision has no effect.	Character is printed.
d  i  u  o  x  X	The precision specifies the minimum number of digits to be printed. If the number of digits in the argument is less than precision, the output value is padded on the left with zeros. The value is not truncated when the number of digits exceeds precision.	Default precision is 1.
e  E	The precision specifies the number of digits to be printed after the decimal point. The last printed digit is rounded.	Default precision is 6; if precision is 0 or the period (.) appears without a number following it, no decimal point is printed.
f	The precision value specifies the number of digits after the decimal point. If a decimal point appears, at least one digit appears before it. The value is rounded to the appropriate number of digits.	Default precision is 6; if precision is 0, or if the period (.) appears without a number following it, no decimal point is printed.
g  G	The precision specifies the maximum number of significant digits printed.	Six significant digits are printed, with any trailing zeros truncated.
s, S	The precision specifies the maximum number of characters to be printed. Characters in excess of precision are not printed.	Characters are printed until a null character is encountered.
If the argument corresponding to a floating-point specifier is infinite, indefinite, or not a number (NAN), the printf function gives the following output:

Value	Output
+ infinity	1.#INFrandom-digits
− infinity	−1.#INFrandom-digits
Indefinite	digit.#INDrandom-digits
NAN	digit.#NANrandom-digits
Size and Distance Specification

The format-specification characters F and N specify the "distance" to the argument (far or near); the characters h, l, and L specify the "size" of the argument. These format-specification characters are used with type-characters in printf or wprintf to specify interpretation of arguments as follows:

Table R.6    Size and Distance Prefixes for printf and wprintf Format Types

To Specify	Use	With Type
far	F	all types
near	N	all types
16-bit (near) pointer	h	p
32-bit (far) pointer	l	p
long double	L	e, E, f, g, G
long int	l	d, i, o, x, X
long unsigned int	l	u
short int	h	d, i, o, x, X
short unsigned int	h	u
single-byte character with printf function	h	c, C
single-byte character with wprintf function	h	c, C
wide-character with printf function	l	c, C
wide-character with wprintf function	l	c, C
single-byte character string with printf function	h	s, S
single-byte character string with wprintf function	h	s, S
wide-character string with printf function	l	s, S
wide-character string with wprintf function	l	s, S
The type prefixes F, N, h, l and L are Microsoft extensions that should not be used if ANSI portability is desired. Note that for both printf and wprintf, %hC is equivalent to %hc, %lC is equivalent to %lc, %hS is equivalent to %hs, and %lS is equivalent to %ls. That is, prefixing h or l to the type character c, C, s, or S reverses the single-byte character or wide character meaning of that type character as given in Table R.3.

Following are examples of the use of F, N, h, and l:

printf ("%Ns");    Print near string

printf ("%Fs");    Print far string

printf ("%Nn");    Store char count in near int

printf ("%Fn");    Store char count in far int

printf ("%hp");    Print a 16-bit pointer (xxxx)

printf ("%lp");    Print a 32-bit pointer (xxxx:xxxx)

printf ("%Nhn");     Store char count in near short int

printf ("%Nln");    Store char count in near long int

printf ("%Fhn");    Store char count in far short int

printf ("%Fln");    Store char count in far int

printf("%hs");    Print single-byte character string

printf("%lc");    Print wide-character

wprintf("%hs");    Print wide-character string

wprintf("%lC");    Print single-byte character

The specifications "%Np" and "%Fp" are aliases for "%hp" and "%lp" for compatibility with Microsoft C version 4.0.

Return Value

Each of these functions returns the number of characters printed, or a negative value if an error occurs.

See Also

»fopen,« »fprintf,« »scanf,« »sprintf,« »vfprintf,« »vprintf,« »vsprintf«

Compatibility

printf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wprintf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* PRINTF.C: This program uses the printf and wprintf functions
 * to produce formatted output.
 */

#include <stdio.h>

void main( void )
{
   char   ch = 'h', *string = "computer";
   int    count = -9234;
   double fp = 251.7366;
   wchar_t wch = L'w', *wstring = L"Unicode";

   /* Display integers. */
   printf( "Integer formats:\n"
           "\tDecimal: %d  Justified: %.6d  Unsigned: %u\n",
           count, count, count, count );

   printf( "Decimal %d as:\n\tHex: %Xh  C hex: 0x%x  Octal: %o\n",
            count, count, count, count );

   /* Display in different radixes. */
   printf( "Digits 10 equal:\n\tHex: %i  Octal: %i  Decimal: %i\n",
            0x10, 010, 10 );

   /* Display characters. */

   printf( "Characters in field (1):\n%10c%5hc%5C%5lc\n",
           ch, ch, wch, wch );
   wprintf( L"Characters in field (2):\n%10C%5hc%5c%5lc\n",
            ch, ch, wch, wch );

   /* Display strings. */

   printf( "Strings in field (1):\n%25s\n%25.4hs\n\t%S%25.3ls\n",
           string, string, wstring, wstring );
   wprintf( L"Strings in field (2):\n%25S\n%25.4hs\n\t%s%25.3ls\n",
            string, string, wstring, wstring );

   /* Display real numbers. */
   printf( "Real numbers:\n\t%f %.2f %e %E\n", fp, fp, fp, fp );

   /* Display pointer. */
   printf( "\nAddress as:\t%p\n", &count );

   /* Count characters printed. */
   printf( "\nDisplay to here:\n" );
   printf( "1234567890123456%n78901234567890\n", &count );
   printf( "\tNumber displayed: %d\n\n", count );
}

Output

Integer formats:
   Decimal: -9234  Justified: -009234  Unsigned: 4294958062
Decimal -9234 as:
   Hex: FFFFDBEEh  C hex: 0xffffdbee  Octal: 37777755756
Digits 10 equal:
   Hex: 16  Octal: 8  Decimal: 10
Characters in field (1):
         h    h    w    w
Characters in field (2):
         h    h    w    w
Strings in field (1):
                 computer
                     comp
   Unicode                      Uni
Strings in field (2):
                 computer
                     comp
   Unicode                      Uni
Real numbers:
   251.736600 251.74 2.517366e+002 2.517366E+002

Address as:   0013FFA8

Display to here:
123456789012345678901234567890
   Number displayed: 16


Description: putc, putchar Functions
  putc, putchar

#include <stdio.h>

int putc( int c, FILE *stream );

int putchar( int c );

c    Character to be written

stream    Pointer to FILE structure

Remarks

The putc routine writes the single character c to the output stream at the current position. The putchar routine is identical to putc(c, stdout). These routines are implemented as both macros and functions. For a discussion of how to select between the macro and function forms, see »Choosing Between Functions and Macros.«

Return Value

The putc and putchar routines return the character written, or EOF in the case of an error. Any integer can be passed to putc, but only the lower 8 bits are written.

See Also

»fputc,« »_fputchar,« »getc,« »getchar«

Compatibility

putc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

putchar:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* PUTC.C: This program uses putc to write buffer
 * to a stream. If an error occurs, the program
 * will stop before writing the entire buffer.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char *p, buffer[] = "This is the line of output\n";
   int  ch;

   /* Make standard out the stream and write to it. */
   stream = stdout;
   for( p = buffer; (ch != EOF) && (*p != '\0'); p++ )
      ch = putc( *p, stream );
}

Output

This is the line of output


Description: _putch Function
  _putch

#include <conio.h>

int _putch( int c );

c    Character to be output

Remarks

The _putch function writes the character c directly (without buffering) to the console.

Return Value

The function returns c if successful, and EOF if not.

See Also

»_cprintf,« »_getch,« »_getche«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getch.«


Description: _putenv Function
  _putenv

#include <stdlib.h>

int _putenv( const char *envstring );

envstring    Environment-string definition

Remarks

The _putenv function adds new environment variables or modifies the values of existing environment variables. Environment variables define the environment in which a process executes (for example, the default search path for libraries to be linked with a program).

The envstring argument must be a pointer to a string with the form varname=string where varname is the name of the environment variable to be added or modified and string is the variable's value. If varname is already part of the environment, its value is replaced by string; otherwise, the new varname variable and its string value are added to the environment. A variable can be removed from the environment by specifying an empty string—that is, by specifying only varname=.

This function affects only the environment that is local to the currently running process; it cannot be used to modify the command-level environment. When the currently running process terminates, the environment reverts to the level of the parent process (in most cases, the operating system level). However, the environment affected by _putenv can be passed to any child processes created by _spawn, _exec, or system, and these child processes get any new items added by _putenv. Never free a pointer to an environment entry, because the environment variable will then point to freed space. A similar problem can occur if you pass _putenv a pointer to a local variable, then exit the function in which the variable is declared.

The _putenv function operates only on data structures accessible to the run-time library and not on the environment "segment" created for a process by the operating system.

Note that environment-table entries must not be changed directly. If an entry must be changed, use _putenv. To modify the returned value without affecting the environment table, use _strdup or strcpy to make a copy of the string.

The getenv and _putenv functions use the global variable _environ to access the environment table. The _putenv function may change the value of _environ, thus invalidating the envp argument to the main function. Therefore, it is safer to use the _environ variable to access the environment information.

Return Value

The _putenv function returns 0 if it is successful. A return value of −1 indicates an error.

See Also

»getenv,« »_searchenv«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _putenv for compatibility with ANSI naming conventions of non-ANSI functions. Use putenv and link with OLDNAMES.LIB for UNIX compatibility.

Example

See the example for »getenv.«


Description: _putimage Functions
  _putimage Functions

#include <graph.h>

void __far _putimage( short x, short y, const char __huge *image, short action );

void __far _putimage_w( double wx, double wy, const char __huge *image , short action );

x, y    Position of upper-left corner of image

image    Stored image buffer

action    Interaction with existing screen image

wx, wy    Position of upper-left corner of image

Remarks

The _putimage function transfers to the screen the image stored in the buffer that image points to. In the _putimage function, the upper-left corner of the image is placed at the view coordinate point (x, y). In the _putimage_w function, the upper-left corner of the image is placed at the window coordinate point (wx, wy).

The action argument defines the interaction between the stored image and the one that is already on the screen. It may be any one of the following manifest constants (defined in GRAPH.H):

_GAND    Transfers the image over an existing image on the screen. The resulting image is the logical-AND product of the two images: points that had the same color in both the existing image and the new one will remain the same color, while points that have different colors are joined by logical-AND.

_GOR    Superimposes the image onto an existing image. The new image does not erase the previous screen contents.

_GPRESET    Transfers the data point-by-point onto the screen. Each point has the inverse of the color attribute it had when it was taken from the screen by _getimage, producing a negative image.

_GPSET    Transfers the data point-by-point onto the screen. Each point has the exact color attribute it had when it was taken from the screen by _getimage.

_GXOR    Causes the points on the screen to be inverted where a point exists in the image buffer. This behavior is like that of the cursor: when an image is put against a complex background twice, the background is restored unchanged. This allows you to move an object around without erasing the background. The _GXOR constant is a special mode often used for animation.

Return Value

None. Use the _grstatus function to check the result of a call to the _putimage functions.

See Also

»_getimage« , »_grstatus,« »_imagesize«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getimage.«


Description: puts Function
  puts

#include <stdio.h>

int puts( const char *string );

string    String to be output

Remarks

The puts function writes string to the standard output stream stdout, replacing the string's terminating null character ('\0') with a newline character (\n) in the output stream.

Return Value

The puts function returns a nonnegative value if it is successful. If the function fails, it returns EOF.

See Also

»fputs,« »gets«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* PUTS.C: This program uses puts
 * to write a string to stdout.
 */

#include <stdio.h>

void main( void )
{
   puts( "Hello world from puts!" );
}

Output

Hello world from puts!


Description: _putw Function
  _putw

#include <stdio.h>

int _putw( int binint, FILE *stream );

binint    Binary integer to be output

stream    Pointer to FILE structure

Remarks

The _putw function writes a binary value of type int to the current position of stream. The _putw function does not affect the alignment of items in the stream, nor does it assume any special alignment. The _putw function is provided primarily for compatibility with previous libraries. Note that portability problems may occur with _putw, since the size of an int and ordering of bytes within an int differ across systems.

Return Value

The _putw function returns the value written. A return value of EOF may indicate an error. Since EOF is also a legitimate integer value, ferror should be used to verify an error.

See Also

»_getw«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _putw for compatibility with ANSI naming conventions of non-ANSI functions. Use putw and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* PUTW.C: This program uses _putw to write a
 * word to a stream, then performs an error check.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   FILE *stream;
   unsigned u;
   if( (stream = fopen( "data.out", "wb" )) == NULL )
      exit( 1 );
   for( u = 0; u << 10; u++ )
   {
      _putw( u + 0x2132, stdout );
      _putw( u + 0x2132, stream );   /* Write word to stream. */
      if( ferror( stream ) )         /* Make error check. */
      {
         printf( "_putw failed" );
         clearerr( stream );
         exit( 1 );
      }
   }
   printf( "\nWrote ten words\n" );
   fclose( stream );
}

Output

Wrote ten words


Description: qsort Function
  qsort

#include <stdlib.h>    For ANSI compatibility

#include <search.h>

void qsort( void *base, size_t num, size_t width, int( __cdecl *compare ) ( const void *elem1, const void *elem2 ) );

base    Start of target array

num    Array size in elements

width    Element size in bytes

compare    Comparison function

elem1    Pointer to the key for the search

elem2    Pointer to the array element to be compared with the key

Remarks

The qsort function implements a quick-sort algorithm to sort an array of num elements, each of width bytes. The argument base is a pointer to the base of the array to be sorted. The qsort function overwrites this array with the sorted elements. The argument compare is a pointer to a user-supplied routine that compares two array elements and returns a value specifying their relationship. The qsort function calls the compare routine one or more times during the sort, passing pointers to two array elements on each call:

compare( (void *) elem1, (void *) elem2 );

The routine must compare the elements, then return one of the following values:

value < 0    elem1 less than elem2

value = 0    elem1 equivalent to elem2

value > 0    elem1 greater than elem2

The array is sorted in increasing order, as defined by the comparison function. To sort an array in decreasing order, reverse the sense of "greater than" and "less than" in the comparison function.

Return Value

None.

See Also

»bsearch,« »_lsearch«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* QSORT.C: This program reads the command-line
 * parameters and uses qsort to sort them. It
 * then displays the sorted arguments.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int compare( const void *arg1, const void *arg2 );

void main( int argc, char **argv )
{
   int i;
   /* Eliminate argv[0] from sort: */
   argv++;
   argc--;

   /* Sort remaining args using Quicksort algorithm: */
   qsort( (void *)argv, (size_t)argc, sizeof( char * ), compare );

   /* Output sorted list: */
   for( i = 0; i < argc; ++i )
      printf( "%s ", argv[i] );
   printf( "\n" );
}

int compare( const void *arg1, const void *arg2 )
{
   /* Compare all of both strings: */
   return _stricmp( * ( char** ) arg1, * ( char** ) arg2 );
}

Output

[C:\code]qsort every good boy deserves favor
boy deserves every favor good


Description: raise
  raise

#include <signal.h>

int raise( int sig );

sig    Signal to be raised

Remarks

The raise function sends sig to the executing program. If a signal-handling routine for sig has been installed by a prior call to signal, raise causes that routine to be executed. If no handler routine has been installed, the default action (as listed below) is taken. The signal value sig can be one of the following manifest constants:

Signal	Meaning	Default
SIGABRT	Abnormal termination.	Terminates the calling program with exit code 3.
SIGFPE	Floating-point error.	Terminates the calling program.
SIGILL	Illegal instruction. This signal is not generated by MS-DOS, but is supported for ANSI compatibility.	Terminates the calling program.
SIGINT	CTRL+C interrupt.	Issues INT 23H.
SIGSEGV	Illegal storage access. This signal is not generated by MS-DOS, but is supported for ANSI compatibility.	Terminates the calling program.
SIGTERM	Termination request sent to the program. This signal is not generated by MS-DOS, but is supported for ANSI compatibility.	Ignores the signal.
Return Value

If successful, the raise function returns 0. Otherwise, it returns a nonzero value.

See Also

»abort,« »signal«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »signal.«


Description: rand
  rand

#include <stdlib.h>

int rand( void );

Remarks

The rand function returns a pseudorandom integer in the range 0 to RAND_MAX. The srand routine can be used to seed the pseudorandom-number generator before calling rand.

Return Value

The rand function returns a pseudorandom number, as described above. There is no error return.

See Also

»srand«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* RAND.C: This program seeds the random-number generator
 * with the time, then displays 10 random integers.
 */

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

void main( void )
{
   int i;

   /* Seed the random-number generator with current time so that
    * the numbers will be different every time we run.
    */
   srand( (unsigned)time( NULL ) );

   /* Display 10 numbers. */
   for( i = 0;   i < 10;i++ )
      printf( "  %6d\n", rand() );
}

Output

    6929
    8026
   21987
   30734
   20587
    6699
   22034
   25051
    7988
   10104


Description: _read
  _read

#include <io.h>

int _read( int handle, void *buffer, unsigned int count );

handle    Handle referring to open file

buffer    Storage location for data

count    Maximum number of bytes

Remarks

The _read function attempts to read count bytes into buffer from the file associated with handle. The read operation begins at the current position of the file pointer associated with the given file. After the read operation, the file pointer points to the next unread character.

Return Value

The _read function returns the number of bytes actually read, which may be less than count if there are fewer than count bytes left in the file, or if the file was opened in text mode (see below). The return value 0 indicates an attempt to read at end-of-file. The return value −1 indicates an error, and errno is set to the value EBADF, meaning the given handle is invalid; the file is not open for reading; or (with MS-DOS versions 3.0 and later) the file is locked.

For 16-bit platforms, if you are reading more than 32K (the maximum size for type int) from a file, the return value should be of type unsigned int (see the example that follows). However, the maximum number of bytes that can be read from a file in one operation is 65,534, because 65,535 (or 0xFFFF) is indistinguishable from −1, and therefore cannot be distinguished from an error return.

If the file was opened in text mode, the return value may not correspond to the number of bytes actually read. When text mode is in effect, each carriage-return−linefeed (CR-LF) pair is replaced with a single linefeed character. Only the single linefeed character is counted in the return value. The replacement does not affect the file pointer.

Note that when files are opened in text mode, a CTRL+Z character is treated as an end-of-file indicator. When the CTRL+Z is encountered, the read terminates, and the next read returns 0 bytes. The _lseek function will clear the end-of-file indicator.

See Also

»_creat,« »fread,« »_open,« »_write«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _read for compatibility with ANSI naming conventions of non-ANSI functions. Use read and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* READ.C: This program opens a file named
 * READ.C and tries to read 60,000 bytes from
 * that file using read. It then displays the
 * actual number of bytes read from READ.C.
 */

#include <fcntl.h>      /* Needed only for _O_RDWR definition */
#include <io.h>
#include <stdlib.h>
#include <stdio.h>

char buffer[60000];

void main( void )
{
   int fh;
   unsigned int nbytes = 60000, bytesread;

   /* Open file for input: */
   if( (fh = _open( "read.c", _O_RDONLY )) == -1 )
   {
      perror( "open failed on input file" );
      exit( 1 );
   }

   /* Read in input: */
   if( ( bytesread = _read( fh, buffer, nbytes ) ) <= 0 )
      perror( "Problem reading file" );
   else
      printf( "Read %u bytes from file\n", bytesread );

   _close( fh );
}

Output

Read 775 bytes from file


Description: realloc Functions
  realloc Functions

#include <stdlib.h>    For ANSI compatibility (realloc only)

#include <malloc.h>

void *realloc( void *memblock, size_t size );

void __based( void ) *_brealloc( __segment seg, void __based( void ) *memblock, size_t size );

void __far *_frealloc( void __far *memblock, size_t size );

void __near *_nrealloc( void __near *memblock, size_t size );

memblock    Pointer to previously allocated memory block

size    New size in bytes

seg    Segment selector

Remarks

The realloc family of functions changes the size of a previously allocated memory block. The memblock argument points to the beginning of the memory block. If memblock is NULL (_NULLOFF for _brealloc), realloc functions in the same way as malloc and allocates a new block of size bytes. If memblock is not NULL (_NULLOFF for _brealloc), it should be a pointer returned by a prior call to calloc, malloc, or realloc.

The size argument gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block may be in a different location. Because the new block can be in a new memory location, the pointer returned by the realloc functions is not guaranteed to be the pointer passed through the memblock argument.

In large data models (that is, compact-, large-, and huge-model programs), realloc maps to _frealloc. In small data models (tiny-, small-, and medium-model programs), realloc maps to _nrealloc. The various realloc functions reallocate memory in the heap as specified in the following list:

realloc    Depends on data model of program

_brealloc    Based heap specified by seg value

_frealloc    Far heap (outside default data segment)

_nrealloc    Near heap (inside default data segment)

Return Value

The realloc functions return a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL (_NULLOFF for _brealloc) if the size is zero and the buffer argument is not NULL (_NULLOFF for _brealloc), or if there is not enough available memory to expand the block to the given size. In the first case, the original block is freed. In the second, the original block is unchanged. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

See Also

»calloc functions,« »free functions,« »malloc functions«

Compatibility

realloc:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_brealloc, _frealloc, _nrealloc:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* REALLOC.C: This program allocates a block of memory for
 * buffer and then uses _msize to display the size of that
 * block. Next, it uses realloc to expand the amount of
 * memory used by buffer and then calls _msize again to
 * display the new amount of memory allocated to buffer.
 */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

void main( void )
{
   long *buffer;
   size_t size;

   if( (buffer = (long *)malloc( 1000 * sizeof( long ) )) == NULL )
      exit( 1 );

   size = _msize( buffer );
   printf( "Size of block after malloc of 1000 longs: %u\n", size );

   /* Reallocate and show new size: */
   if( (buffer = realloc( buffer, size + (1000 * sizeof( long )) ))
        ==  NULL )
      exit( 1 );
   size = _msize( buffer );
   printf( "Size of block after realloc of 1000 more longs: %u\n",
            size );

   free( buffer );
   exit( 0 );
}

Output

Size of block after malloc of 1000 longs: 4000
Size of block after realloc of 1000 more longs: 8000


Description: _rectangle Functions
  _rectangle Functions

#include <graph.h>

short __far _rectangle( short control, short x1, short y1, short x2, short y2 );

short __far _rectangle_w( short control, double wx1, double wy1, double wx2, double wy2 );

short __far _rectangle_wxy( short control, struct _wxycoord __far * pwxy1, struct _wxycoord __far *pwxy2 );

control    Fill flag

x1, y1    Upper-left corner

x2, y2    Lower-right corner

wx1, wy1    Upper-left corner

wx2, wy2    Lower-right corner

pwxy1    Upper-left corner

pwxy2    Lower-right corner

Remarks

The _rectangle functions draw a rectangle with the current line style. The _rectangle function uses the view coordinate system. The view coordinate points (x1, y1) and (x2, y2) are the diagonally opposed corners of the rectangle. The _rectangle_w function uses the window coordinate system. The window coordinate points (wx1, wy1) and (wx2, wy2) are the diagonally opposed corners of the rectangle. The _rectangle_wxy function uses the window coordinate system. The window coordinate points (pwxy1) and (pwxy2) are the diagonally opposed corners of the rectangle. The coordinates for the _rectangle_wxy routine are given in terms of a _wxycoord structure (defined in GRAPH.H), which contains double wx, the window x coordinate, and double wy, the window y coordinate.

The control parameter can be one of two manifest constants. The _GFILLINTERIOR constant fills the figure, using a scan-fill algorithm, with the current color using the current fill mask. The _GBORDER constant does not fill the rectangle.

If the current fill mask is NULL, no mask is used. Instead, the rectangle is filled with the current color. If you try to fill the rectangle with the _floodfill function, the rectangle must be bordered by a solid line-style pattern.

Return Value

The function returns a nonzero value if the rectangle is drawn successfully, or 0 if not.

See Also

»_arc functions,« »_ellipse functions,« »_floodfill,« »_getcolor,« »_lineto functions,« »_pie functions,« »_polygon,« »_setcolor,« »_setfillmask«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * RECT.C: This program draws a rectangle.
 *
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

void main( void )
{
   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );
   _rectangle( _GBORDER, 80, 50, 240, 150 );
   _getch();
   _setvideomode( _DEFAULTMODE );
}


Description: _registerfonts
  _registerfonts

#include <graph.h>

short __far _registerfonts( const char __far *pathname );

path    Path specifying .FON files to be registered

Remarks

The _registerfonts function initializes the fonts graphics system. Font files must be registered with the _registerfonts function before any other font-related library function (_getgtextextent, _outgtext, _setfont, _unregisterfonts) can be used. The _registerfonts function reads the specified files and loads font header information into memory. Each font header takes up about 140 bytes of memory. The path argument is the path specification and filename of valid .FON files. The path can contain standard MS-DOS wildcards. The font functions affect only the output from the font output function _outgtext; no other run-time output functions are affected by font usage.

The _registerfonts function works differently in QuickWin applications.

Return Value

The _registerfonts function returns a positive value that indicates the number of fonts successfully registered. A negative return value indicates failure. The following negative values may be returned:

−1    No such file or directory.

−2    One or more of the .FON files was not a valid, binary .FON file.

−3    One or more of the .FON files is damaged.

See Also

»_getfontinfo,« »_getgtextextent,« »_grstatus,« »_outgtext,« »_setfont,« »_unregisterfonts«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outgtext.«


Description: _remapallpalette, _remappalette
  _remapallpalette, _remappalette

#include <graph.h>

short __far _remapallpalette( long __far *colors );

long __far _remappalette( short index, long color );

colors    Color value array

index    Color index to reassign

color    Color value to assign color index to

Remarks

The _remapallpalette function remaps the entire color palette simultaneously to the colors given in the colors array. The colors array is an array of long integers where the size of the array varies from 16 to 64 to 256, depending on the video mode. The number of colors mapped depends on the number of colors supported by the current video mode. The _remapallpalette function works in all video modes (except _ORESCOLOR mode), but only with EGA, MCGA, VGA, or SVGA hardware.

The default color values for color text or a 16-color graphics mode are shown following:

Number	Color	Number	Color
0	Black	8	Dark gray
1	Blue	9	Light blue
2	Green	10	Light green
3	Cyan	11	Light cyan
4	Red	12	Light red
5	Magenta	13	Light magenta
6	Brown	14	Yellow
7	White	15	Bright white
The first array element specifies the new color value to be associated with color index 0 (the background color in graphics modes). After the call to _remapallpalette, calls to _setcolor will index into the new array of colors. The mapping done by _remapallpalette affects the current display immediately. The colors array can be larger than the number of colors supported by the current video mode, but only the first n elements are used, where n is the number of colors supported by the current video mode, as indicated by the numcolors element of the _videoconfig structure.

The long color value is defined by specifying three bytes of data representing the three component colors: red, green, and blue. Each of the three bytes represents the intensity of one of the red, green, or blue component colors, and must be in the range 0−63. In other words, the low-order six bits of each byte specify the component's intensity and the high-order two bits should be zero. The fourth (high-order) byte in the long is unused and should be set to zero. The diagram below shows the ordering of bytes within the long value. For example, to create a lighter shade of blue, start with lots of blue, add some green, and maybe a little bit of red. The three-byte color value would be:

blue byte            green byte        red byte

00011111             00101111          00011111

high ----------------->  low order

Manifest constants are defined in GRAPH.H for the default color values corresponding to color indices 0−15 in color text modes and 16-color graphics modes, as shown following:

Index	Constant	Index	Constant
0	_BLACK	8	_GRAY
1	_BLUE	9	_LIGHTBLUE
2	_GREEN	10	_LIGHTGREEN
3	_CYAN	11	_LIGHTCYAN
4	_RED	12	_LIGHTRED
5	_MAGENTA	13	_LIGHTMAGENTA
6	_BROWN	14	_YELLOW
7	_WHITE	15	_BRIGHTWHITE
The VGA supports a palette of 262,144 (256K) colors in color modes, and the EGA supports a palette of only 64 different colors. Color values for EGA are specified in exactly the same way as with the VGA; however, the low-order four bits of each byte are simply ignored.

The _remappalette function assigns a new color value color to the color index given by index. This remapping affects the current display immediately. The _remappalette function works in all graphics modes, but only with EGA, MCGA, VGA, or SVGA hardware. An error results if the function is called while using any other configuration. The color value used in _remappalette is defined and used exactly as noted above for _remapallpalette. The range of color indices used with _remappalette depends on the number of colors supported by the video mode. The _remapallpalette and _remappalette functions do not affect the presentation-graphics "palettes," which are manipulated with the _pg_getpalette, _pg_setpalette, and _pg_resetpalette functions.

If a VGA or MCGA adapter is connected to an analog monochrome monitor, the color value is transformed into its gray-scale equivalent, based on the weighted sum of its red, green, and blue components (30 percent red + 50 percent green + 11 percent blue).

Return Value

If successful, _remapallpalette returns nonzero value (short). In case of an error, _remapallpalette returns 0 (short). If successful, _remappalette returns the color value previously assigned to index, or −1 if the function is inoperative (not EGA, VGA, SVGA, or MCGA), or if the color index is out of range. Note that _remapallpalette returns a short value and _remappalette returns a long value.

See Also

»_getvideoconfig,« »_selectpalette,« »_setbkcolor,« »_setvideomode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * RMPALPAL.C: This example illustrates functions
 * for assigning color values to color indices.
 * Functions illustrated include:
 *    _remappalette         _remapallpalette
 */

#include <graph.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>

/* Macro for mixing Red, Green, and Blue elements of color */
#define RGB(r,g,b) (((long) ((b) << 8 | (g)) << 8) | (r))

long tmp, pal[256];

void main( void )
{
   short  red, blue, green;
   short  inc, i, mode, cells, x, y, xinc, yinc;
   char   buf[40];
   struct _videoconfig vc;

   /* Make sure all palette numbers are valid. */
   for( i = 0; i < 256; i++ )
      pal[i] = _BLACK;

   /* Loop through each graphics mode that supports palettes. */
   for( mode = _MRES4COLOR;mode <= _MRES256COLOR;mode++ )
   {
      if( mode == _ERESNOCOLOR )
         mode++;
      if( !_setvideomode( mode ) )
         continue;

      /* Set variables for each mode. */
      _getvideoconfig( &vc );
      switch( vc.numcolors )
      {
      case 256:          /* Active bits in this order:          */
         cells = 13;
         inc = 12;      /* ???????? ??bbbbbb ??gggggg ??rrrrrr  */
         break;
      case  16:
         cells = 4;
         if( (vc.mode == _ERESCOLOR) || (vc.mode == _VRES16COLOR) )
            inc = 16;   /* ???????? ??bb???? ??gg???? ??rr????  */
         else
            inc = 32;   /* ???????? ??Bb???? ??Gg???? ??Rr????  */
         break;
      case   4:
         cells = 2;
         inc = 32;      /* ???????? ??Bb???? ??Gg???? ??Rr????  */
         break;
      default:
         continue;
      }
      xinc = vc.numxpixels / cells;
      yinc = vc.numypixels / cells;

      /* Fill palette arrays in BGR order. */
      for( i = 0, blue = 0; blue < 64; blue += inc )
         for( green = 0; green < 64; green += inc )
            for( red = 0; red < 64; red += inc )
            {
               pal[i] = RGB( red, green, blue );
               /* Special case of using 6 bits to represent 16 colors.
                * If both bits are on for any color, intensity is set.
                * If one bit is set for a color, the color is on.
                */
               if( inc == 32 )
                  pal[i + 8] = pal[i] | (pal[i] >> 1);
               i++;
            }

      /* If palettes available, remap all palettes at once. */
      if( !_remapallpalette( pal ) )
      {
         _setvideomode( _DEFAULTMODE );
         _outtext( "Palettes not available with this adapter" );
         exit( 1 );
      }

      /* Draw colored squares. */
      for( i = 0, x = 0; x < ( xinc * cells ); x += xinc )
         for( y = 0; y < ( yinc * cells); y += yinc )
         {
            _setcolor( i++ );
            _rectangle( _GFILLINTERIOR, x, y, x + xinc, y + yinc );
         }

      /* Note that for 256-color mode, not all colors are shown. The
       * number of colors from mixing three base colors can never be
       * the same as the number that can be shown on a two-dimensional
       * grid.
       */
      sprintf( buf, "Mode %d has %d colors", vc.mode, vc.numcolors );
      _setcolor( (short)(vc.numcolors / 2) );
      _outtext( buf );
      _getch();

      /* Change each palette entry separately in GRB order. */
      for( i = 0, green = 0; green < 64; green += inc )
         for( red = 0; red < 64; red += inc )
            for(blue = 0; blue < 64; blue += inc )
            {
               tmp = RGB( red, green, blue );
               _remappalette( i, tmp );
               if( inc == 32 )
                  _remappalette( (short)(i + 8),
                                 (long)(tmp | (tmp >> 1)) );
               i++;
            }
      _getch();
   }
   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: remove
  remove

#include <stdio.h>    Required for ANSI compatibility

#include <io.h>    Use either IO.H or STDIO.H

int remove( const char *path );

path    Path of file to be removed

Remarks

The remove function deletes the file specified by path.

Return Value

The function returns 0 if the file is successfully deleted. Otherwise, it returns −1 and sets errno either to EACCES, meaning the path specifies a read-only file, or ENOENT, meaning the filename or path is not found, or the path specifies a directory.

See Also

»_unlink«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* REMOVE.C: This program uses remove to delete REMOVE.OBJ. */

#include <stdio.h>

void main( void )
{
   if( remove( "remove.obj" ) == -1 )
      perror( "Could not delete 'REMOVE.OBJ'" );
   else
      printf( "Deleted 'REMOVE.OBJ'\n" );
}

Output

Deleted 'REMOVE.OBJ'


Description: rename
  rename

#include <stdio.h>    Required for ANSI compatibility

#include <io.h>    Use either IO.H or STDIO.H

int rename( const char *oldname, const char *newname );

oldname    Pointer to old name

newname    Pointer to new name

Remarks

The rename function renames the file or directory specified by oldname to the name given by newname. The old name must be the path of an existing file or directory. The new name must not be the name of an existing file or directory. The rename function can be used to move a file from one directory to another by giving a different path in the newname argument. In MS-DOS only, files cannot be moved from one device to another (for example, from drive A to drive B). Directories can only be renamed, not moved.

Return Value

The rename function returns 0 if it is successful. On an error, it returns a nonzero value and sets errno to one of the following values:

EACCES    File or directory specified by newname already exists or could not be created (invalid path); or oldname is a directory and newname specifies a different path.

ENOENT    File or path specified by oldname not found.

EXDEV    Attempt to move a file to a different device (in MS-DOS only).

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* RENAMER.C: This program attempts to rename a file
 * named RENAMER.OBJ to RENAMER.JBO. For this operation
 * to succeed, a file named RENAMER.OBJ must exist and
 * a file named RENAMER.JBO must not exist.
 */

#include <stdio.h>

void main( void )
{
   int  result;
   char old[] = "RENAMER.OBJ", new[] = "RENAMER.JBO";

   /* Attempt to rename file: */
   result = rename( old, new );
   if( result != 0 )
      printf( "Could not rename '%s'\n", old );
   else
      printf( "File '%s' renamed to '%s'\n", old, new );
}

Output

File 'RENAMER.OBJ' renamed to 'RENAMER.JBO'


Description: rewind
  rewind

#include <stdio.h>

void rewind( FILE *stream );

stream    Pointer to FILE structure

Remarks

The rewind function repositions the file pointer associated with stream to the beginning of the file. A call to rewind is equivalent to

(void) fseek( stream, 0L, SEEK_SET );

except that rewind clears the error indicators for the stream, and »fseek« does not. Both rewind and fseek clear the end-of-file indicator. Also, fseek returns a value that indicates whether the pointer was successfully moved, but rewind does not return any value.

You can also use the rewind function to clear the keyboard buffer. Use the rewind function with the stream stdin, which is associated with the keyboard by default.

Return Value

The rewind function has no return value.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* REWIND.C: This program first opens a file named
 * REWIND.OUT for input and output and writes two
 * integers to the file. Next, it uses rewind to
 * reposition the file pointer to the beginning of
 * the file and reads the data back in.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   int data1, data2;

   data1 = 1;
   data2 = -37;

   if( (stream = fopen( "rewind.out", "w+" )) != NULL )
   {
      fprintf( stream, "%d %d", data1, data2 );
      printf( "The values written are: %d and %d\n", data1, data2 );
      rewind( stream );
      fscanf( stream, "%d %d", &data1, &data2 );
      printf( "The values read are: %d and %d\n", data1, data2 );
      fclose( stream );
   }
}

Output

The values written are: 1 and -37
The values read are: 1 and -37


Description: _rmdir
  _rmdir

#include <direct.h>

int _rmdir( const char *dirname );

dirname    Path name of directory to be removed

Remarks

The _rmdir function deletes the directory specified by dirname. The directory must be empty, and it must not be the current working directory or the root directory.

Return Value

The _rmdir function returns the value 0 if the directory is successfully deleted. A return value of −1 indicates an error, and errno is set to one of two values. ENOTEMPTY means that the given path is not a directory; or the directory is not empty; or the directory is the current working directory or the root directory. ENOENT means that the path is not found.

See Also

»_chdir,« »_mkdir«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_mkdir.«


Description: _rmtmp
  _rmtmp

#include <stdio.h>

int _rmtmp( void );

Remarks

The _rmtmp function is used to clean up all the temporary files in the current directory. The function removes only those files created by tmpfile and should be used only in the same directory in which the temporary files were created.

Return Value

The _rmtmp function returns the number of temporary files closed and deleted.

See Also

»_flushall,« »tmpfile,« »tmpnam«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »tmpfile.«


Description: _rotl, _rotr
  _rotl, _rotr

#include <stdlib.h>

unsigned int _rotl( unsigned int value, int shift );

unsigned int _rotr( unsigned int value, int shift );

value    Value to be rotated

shift    Number of bits to shift

Remarks

The _rotl and _rotr functions rotate the unsigned value by shift bits. The _rotl function rotates the value left. The _rotr function rotates the value right. Both functions "wrap" bits rotated off one end of value to the other end.

Return Value

Both functions return the rotated value. There is no error return.

See Also

»_lrotl,« »_lrotr«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* ROT.C: This program uses _rotr and _rotl with
 * different shift values to rotate an integer.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   unsigned val = 0x0fd93;
   printf( "0x%4.4x rotated left three times is 0x%4.4x\n",
           val, _rotl( val, 3 ) );
   printf( "0x%4.4x rotated right four times is 0x%4.4x\n",
           val, _rotr( val, 4 ) );
}

Output

0xfd93 rotated left three times is 0x7ec98
0xfd93 rotated right four times is 0x30000fd9


Description: _scalb
  _scalb

#include <float.h>

double _scalb( double x, long exp );

x    Double-precision floating-point value

exp    Long integer exponent

Remarks

The _scalb function calculates the value of x * (2 raised to the power of exp).

Return Value

This function returns an exponential value if successful. On overflow (depending on the sign of x), ldexp returns +/−HUGE_VAL; the errno variable is set to ERANGE.

See Also

»ldexp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: scanf, wscanf
  scanf, wscanf

#include <stdio.h>    For scanf

#include <wchar.h>    For wscanf use either WCHAR.H (for ANSI compatibility) or STDIO.H

int scanf( const char *format [,argument]... );

int wscanf( const wchar_t *format [,argument]... );

format    Format control string

argument    Optional arguments

Remarks

The scanf function reads data from the standard input stream stdin and writes the data into the location given by argument. Each argument must be a pointer to a variable of a type that corresponds to a type specifier in format. If copying takes place between strings that overlap, the behavior is undefined.

The wscanf function is a wide-character version of scanf; the format argument to wscanf is a wide-character string. The wscanf and scanf functions behave identically otherwise.

The format argument specifies the interpretation of the input, and can contain one or more of the following:

•	White-space characters: blank (' '); tab ('\t'); or newline ('\n'). A white-space character causes scanf to read, but not store, all consecutive white-space characters in the input up to the next non-white-space character. One white-space character in the format matches any number (including 0) and combination of white-space characters in the input.

•	Non-white-space characters, except for the percent sign (%). A non-white-space character causes scanf to read, but not store, a matching non-white-space character. If the next character in stdin does not match, scanf terminates.

•	Format specifications, introduced by the percent sign (%). A format specification causes scanf to read and convert characters in the input into values of a specified type. The value is assigned to an argument in the argument list.

The format is read from left to right. Characters outside format specifications are expected to match the sequence of characters in stdin; the matching characters in stdin are scanned but not stored. If a character in stdin conflicts with the format specification, scanf terminates. The character is left in stdin as if it had not been read.

When the first format specification is encountered, the value of the first input field is converted according to this specification and stored in the location that is specified by the first argument. The second format specification causes the second input field to be converted and stored in the second argument, and so on through the end of the format string.

An input field is defined as all characters up to the first white-space character (space, tab, or newline), or up to the first character that cannot be converted according to the format specification, or until the field width (if specified) is reached. If there are too many arguments for the given specifications, the extra arguments are evaluated but ignored. The results are unpredictable if there are not enough arguments for the format specification.

A format specification has the following form:

%[*] [width] [{F | N}] [{h | l | L}]type

Each field of the format specification is a single character or a number signifying a particular format option. The type character, which appears after the last optional format field, determines whether the input field is interpreted as a character, a string, or a number. The simplest format specification contains only the percent sign and a type character (for example, %s).

Each field of the format specification is discussed in detail below. If a percent sign (%) is followed by a character that has no meaning as a format-control character, that character and the following characters (up to the next percent sign) are treated as an ordinary sequence of characters, that is, a sequence of characters that must match the input. For example, to specify that a percent-sign character is to be input, use %%.

An asterisk (*) following the percent sign suppresses assignment of the next input field, which is interpreted as a field of the specified type. The field is scanned but not stored.

The width is a positive decimal integer controlling the maximum number of characters to be read from stdin. No more than width characters are converted and stored at the corresponding argument. Fewer than width characters may be read if a white-space character (space, tab, or newline) or a character that cannot be converted according to the given format occurs before width is reached.

The optional prefixes F and N allow the user to specify whether the argument is far or near, respectively. F is to be prefixed to an argument pointing to a far object, while N is to be prefixed to an argument pointing to a near object.

The optional prefixes h, l, and L indicate the "size" of the argument (long or short, single-byte character or wide character, depending upon the type character that they modify). These format-specification characters are used with type-characters in scanf or wscanf to specify interpretation of arguments as described in Table R.7.

Table R.7    Size and Distance Prefixes for scanf and wscanf Format Types

To Specify	Use	With Type
far	F	all types
near	N	all types
16-bit (near) pointer	h	p
32-bit (far) pointer	l	p
double	l	e, E, f, g, G
long double	L	e, E, f, g, G
long int	l	d, i, o, x, X
long unsigned int	l	u
short int	h	d, i, o, x, X
short unsigned int	h	u
single-byte character with scanf function	h	c, C
single-byte character with wscanf function	h	c, C
wide-character with scanf function	l	c, C
wide-character with wscanf function	l	c, C
single-byte character string with scanf function	h	s, S
single-byte character string with wscanf function	h	s, S
wide-character string with scanf function	l	s, S
wide-character string with wscanf function	l	s, S
The type prefixes F, N, h, l, and L are Microsoft extensions that should not be used if ANSI portability is desired. Note that for both scanf and wscanf, %hC is equivalent to %hc, %lC is equivalent to %lc, %hS is equivalent to %hs, and %lS is equivalent to %ls. That is, prefixing h or l to the type character c, C, s, or S reverses the single-byte character or wide character meaning of that type character as given in Table R.8 below.

Following are examples of the use of F, N, h, and l with scanf and wscanf:

scanf( "%Fs", &x );    Read a string into far memory

scanf( "%Ns", &x );    Read a string into near memory

scanf( "%Nd", &x );    Read an int into near memory

scanf( "%Fd", &x );    Read an int into far memory

scanf( "%Nld", &x );    Read a long int into near memory

scanf( "%FLe", &x );    Read a long double into far memory

scanf( "%Nhp", &x );    Read a 16-bit pointer into near memory

scanf( "%Nlp", &x );    Read a 32-bit pointer into near memory

scanf( "%Fhp", &x );    Read a 16-bit pointer into far memory

scanf( "%Flp", &x );    Read a 32-bit pointer into far memory

scanf( "%ls", &x );    Read a wide-character string

wscanf( "%lC", &x );    Read a single-byte character

The type characters and their meanings are described in Table R.8.

To read strings not delimited by space characters, a set of characters in brackets ([ ]) can be substituted for the s (string) type character. The corresponding input field is read up to the first character that does not appear in the bracketed character set. If the first character in the set is a caret (^), the effect is reversed: the input field is read up to the first character that does appear in the rest of the character set.

Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]. This is a common scanf extension, but note that it is not required by the ANSI standard.

To store a string without storing a terminating null character ('\0'), use the specification %nc, where n is a decimal integer. In this case, the c type character indicates that the argument is a pointer to a character array. The next n characters are read from the input stream into the specified location, and no null character ('\0') is appended. If n is not specified, the default value for it is 1.

The scanf function scans each input field, character by character. It may stop reading a particular input field before it reaches a space character for a variety of reasons:

•	The specified width has been reached;

•	The next character cannot be converted as specified;

•	The next character conflicts with a character in the control string that it is supposed to match; or

•	The next character fails to appear in a given character set.

For whatever reason, when scanf stops reading an input field, the next input field is considered to begin at the first unread character. The conflicting character, if there is one, is considered unread and is the first character of the next input field or the first character in subsequent read operations on stdin.

Table R.8    Type Characters for scanf

Character	Type of Input Expected	Type of Argument
c	When used with scanf, specifies a single-byte character; when used with wscanf, specifies a wide character. White-space characters that are ordinarily skipped are read when c is specified. To read the next non-white-space single-byte character, use %1s; to read the next non-white-space wide character, use %1ws.	Pointer to char when used with scanf; pointer to wchar_t when used with wscanf.
C	When used with scanf, specifies a wide character; when used with wscanf, specifies a single-byte character. White-space characters that are ordinarily skipped are read when C is specified. To read the next non-white-space single-byte character, use %1s; to read the next non-white-space wide character, use %1ws.	Pointer to wchar_t when used with scanf; pointer to char when used with wscanf.
d	Decimal integer.	Pointer to int.
i	Decimal, hexadecimal, or octal integer.	Pointer to int.
o	Octal integer.	Pointer to int.
u	Unsigned decimal integer.	Pointer to unsigned int.
x	Hexadecimal integer.	Pointer to int.
e, E f  g, G	Floating-point value consisting of an optional sign (+ or −), a series of one or more decimal digits containing a decimal point, and an optional exponent ("e" or "E") followed by an optionally signed integer value.	Pointer to float.
n	No input read from stream or buffer.	Pointer to int, into which is stored the number of characters successfully read from the stream or buffer up to that point in the current call to scanf or wscanf.
p	Value in the form xxxx:yyyy, where the digits x and y are uppercase hexadecimal digits.	Pointer to far pointer to void.
s	String	When used with scanf, signifies a single-byte character array; when used with wscanf, signifies a wide-character array. In either case, character array must be large enough for input field plus terminating null character, which is automatically appended.
S	String.	When used with scanf, signifies a wide-character array; when used with wscanf, signifies a single-byte-character array. In either case, character array must be large enough for input field plus terminating null character, which is automatically appended.
The types c, C, s, and S are Microsoft extensions that should not be used if ANSI portability is desired. Note that for both scanf and wscanf, %hC is equivalent to %hc, %lC is equivalent to %lc, %hS is equivalent to %hs, and %lS is equivalent to %ls. That is, prefixing h or l to the type character c, C, s, or S reverses the single-byte character or wide character meaning of that type character as given in Table R.8. (See Table R.7 for more information about the use of h and l.)

Return Value

Each of the scanf and wscanf functions returns the number of fields successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. The return value is EOF for an error or if the end-of-file character or end-of-string character is encountered in the first attempt to read a character.

»fscanf,« fwscanf, »printf,« »sscanf,« »swscanf,« »vfprintf,« »vprintf,« »vsprintf«

Compatibility

scanf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wscanf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SCANF.C: This program uses the scanf and wscanf

 * functions to read formatted input.

 */

#include <stdio.h>

void main( void )

{

   int   i, result;

   float fp;

   char  c, s[81];

   wchar_t wc, ws[81];

   printf( "\n\nEnter an int, a float, two chars and two

strings\n");

   result = scanf( "%d %f %c %C %s %S", &i, &fp, &c, &wc, s, ws );

   printf( "\nThe number of fields input is %d\n", result );

   printf( "The contents are: %d %f %c %C %s %S\n",

           i, fp, c, wc, s, ws);

   wprintf( L"\n\nEnter an int, a float, two chars and two

strings\n");

   result = wscanf( L"%d %f %hc %lc %S %ls", &i, &fp, &c, &wc, s,

ws );

   wprintf( L"\nThe number of fields input is %d\n", result );

   wprintf( L"The contents are: %d %f %C %c %hs %s\n",

            i, fp, c, wc, s, ws);

}

Output

Enter an int, a float, two chars and two strings
71
98.6
h
z
Byte characters

The number of fields input is 6
The contents are: 71 98.599998 h z Byte characters

Enter an int, a float, two chars and two strings
36
92.3
y
n
Wide characters

The number of fields input is 6
The contents are: 456 92.300003 y n Wide characters


Description: _scrolltextwindow
  _scrolltextwindow

#include <graph.h>

void __far _scrolltextwindow( short lines );

lines    Number of lines to scroll

Remarks

The _scrolltextwindow function scrolls a text window (previously defined by the _settextwindow function). The lines argument specifies the number of lines to scroll. A positive value of lines scrolls the window up (the usual direction); a negative value scrolls the window down. Specifying a number larger than the height of the current text window is equivalent to calling _clearscreen( GWINDOW ). A value of 0 for lines has no effect on the text.

Return Value

None.

See Also

»_gettextposition,« »_outmem,« »_outtext,« »_settextposition,« »_settextwindow«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SCRTXWIN.C: This program displays text in text
 * windows and then scrolls, inserts, and deletes lines.
 */

#include <stdio.h>
#include <conio.h>
#include <graph.h>

void deleteline( void );
void insertline( void );
void status( char *msg );

void main( void )
{
   short row;
   char  buf[40];

   /* Set up screen for scrolling, and put text window around
   scroll  area. */ _settextrows( 25 );
   _clearscreen( _GCLEARSCREEN );

   for( row = 1; row <= 25; row++ )
   {
      _settextposition( row, 1 );
      sprintf( buf, "Line %c             %2d", row + 'A' - 1, row );
      _outtext( buf );
   }
   _getch();
   _settextwindow( 1, 1, 25, 10 );

   /* Delete some lines. */ _settextposition( 11, 1 );
   for( row = 12; row < 20; row++ )
      deleteline();
   status( "Deleted 8 lines" );

   /* Insert some lines. */ _settextposition( 5, 1 );
   for( row = 1; row < 6; row++ )
      insertline();
   status( "Inserted 5 lines" );

   /* Scroll up and down. */
   _scrolltextwindow( -7 );
   status( "Scrolled down 7 lines" );
   _scrolltextwindow( 5 );
   status( "Scrolled up 5 lines" );
   _setvideomode( _DEFAULTMODE );
}

/* Delete lines by scrolling them off the top of the current text
 * window. Save and restore original window.
 */
void deleteline()
{
   short left, top, right, bottom;
   struct _rccoord rc;

   _gettextwindow( &top, &left, &bottom, &right );
   rc = _gettextposition();
   _settextwindow( rc.row, left, bottom, right );
   _scrolltextwindow( _GSCROLLUP );
   _settextwindow( top, left, bottom, right );
   _settextposition( rc.row, rc.col );
}

/* Insert some lines by scrolling in blank lines from the top of the
 * current text window. Save and restore original window.
 */
 void insertline()
{
   short left, top, right, bottom;
   struct _rccoord rc;

   _gettextwindow( &top, &left, &bottom, &right );
   rc = _gettextposition();
   _settextwindow( rc.row, left, bottom, right );
   _scrolltextwindow( _GSCROLLDOWN );
   _settextwindow( top, left, bottom, right );
   _settextposition( rc.row, rc.col );
}

/* Display and clear status in its own window. */
void status( char *msg )
{
   short left, top, right, bottom;

   _gettextwindow( &top, &left, &bottom, &right );
   _settextwindow( 1, 50, 2, 80 );
   _outtext( msg );
   _getch();
   _clearscreen( _GWINDOW );
   _settextwindow( top, left, bottom, right );
}


Description: _searchenv
  _searchenv

#include <stdlib.h>

void _searchenv( const char *filename, const char *varname, char *pathname );

filename    Name of file to search for

varname    Environment to search

path    Buffer to store complete path

Remarks

The _searchenv routine searches for the target file in the specified domain. The varname variable can be any environment variable that specifies a list of directory paths, such as PATH, LIB, INCLUDE, or other user-defined variables. The _searchenv function is case-sensitive, so the varname variable should match the case of the environment variable.

The routine first searches for the file in the current working directory. If it doesn't find the file, it next looks through the directories specified by the environment variable. If the target file is found in one of the directories, the newly created path is copied into the buffer pointed to by path. You must ensure that there is sufficient space for the constructed path. If the filename file is not found, path will contain an empty null-terminated string.

Return Value

The _searchenv function does not return a value.

See Also

»getenv,« »_putenv«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SEARCHEN.C: This program searches for a file in
 * a directory specified by an environment variable.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char pathbuffer[_MAX_PATH];
   char searchfile[] = "CL.EXE";
   char envvar[] = "PATH";

   /* Search for file in PATH environment variable: */
   _searchenv( searchfile, envvar, pathbuffer );
   if( *pathbuffer != '\0' )
      printf( "Path for %s: %s\n", searchfile, pathbuffer );
   else
      printf( "%s not found\n", searchfile );
}

Output

Path for CL.EXE: C:\msvcnt\c32\bin\CL.EXE


Description: _segread
  _segread

#include <dos.h>

void _segread( struct _SREGS *segregs );

segregs    Segment-register values

Remarks

The _segread function fills the structure pointed to by segregs with the current contents of the segment registers. The _SREGS union is described in the reference section for »_int86x.« This function is intended to be used with the _intdosx and _int86x functions to retrieve segment-register values for later use.

Return Value

None.

See Also

»_FP_SEG,« »_intdosx,« »_int86x«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SEGREAD.C: This program gets the
 * current segment values with _segread.
 */

#include <dos.h>
#include <stdio.h>

void main( void )
{
   struct   _SREGS segregs;
   unsigned cs, ds, es, ss;

   /* Read the segment register values */ _segread( &segregs );
   cs = segregs.cs;
   ds = segregs.ds;
   es = segregs.es;
   ss = segregs.ss;
   printf( "CS = 0x%.4x    DS = 0x%.4x    ES = 0x%.4x    SS = 0x%.4x\n",
           cs, ds, es, ss );
}

Output

CS = 0x231d    DS = 0x246a    ES = 0x22f6    SS = 0x246a


Description: _selectpalette
  _selectpalette

#include <graph.h>

short __far _selectpalette( short number );

number    Palette number

Remarks

The _selectpalette function works only under the video modes _MRES4COLOR, _MRESNOCOLOR, and _ORESCOLOR. A CGA palette consists of a selectable background color (Color 0) and three set colors. Under the _MRES4COLOR mode, the number argument selects one of the four predefined palettes shown in Table R.9.

Table R.9    _MRES4COLOR Palette Colors

Palette Number	Color 1	Color 2	Color 3
0	Green	Red	Brown
1	Cyan	Magenta	White
2	Light green	Light red	Yellow
3	Light cyan	Light magenta	Bright white
The _MRESNOCOLOR video mode is used with black-and-white displays, producing palettes consisting of various shades of gray. It will also produce color when used with a color display. The number of palettes available depends upon whether a CGA or EGA hardware package is employed. Under a CGA configuration, only the palettes shown in Table R.10 are available. Note that although four palette numbers are listed, palettes 0 and 1 are identical, as are palettes 2 and 3.

Table R.10    _MRESNOCOLOR Mode CGA Palette Colors

Palette Number	Color 1	Color 2	Color 3
0	Blue	Red	White
1	Blue	Red	White
2	Light blue	Light red	Bright white
3	Light blue	Light red	Bright white
Under the EGA configuration, the three palettes shown in Table R.11 are available in the _MRESNOCOLOR video mode. Note that although four palette numbers are listed, palettes 1 and 3 are identical.

Table R.11    _MRESNOCOLOR Mode EGA Palette Colors

Palette Number	Color 1	Color 2	Color 3
0	Green	Red	Brown
1	Cyan	Magenta	White
2	Light green	Light red	Yellow
3	Cyan	Magenta	White
You can use the _ORESCOLOR high resolution video mode for the Olivetti graphics adapters found in most Olivetti computers and in the AT&T 6300 series computers. In _ORESCOLOR mode, an argument number in the range 0 − 15 selects one of the colors listed in Table R.12. The background color is always black in this mode.

Table R.12    _ORESCOLOR Mode Colors

Index	Color	Index	Color
0	Black	8	Dark Grey
1	Blue	9	Light. Blue
2	Green	10	Light Green
3	Cyan	11	Light Cyan
4	Red	12	Light Red
5	Magenta	13	Light Magenta
6	Brown	14	Yellow
7	White	15	Bright White
The _selectpalette function works differently in QuickWin applications.

Return Value

The function returns the value of the previous palette. There is no error return.

See Also

»_getvideoconfig,« »_remappalette,« »_setbkcolor,« »_setvideomode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SELPAL.C: This program changes the current CGA palette.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <graph.h>

long bkcolor[8] = { _BLACK,  _BLUE,     _GREEN,  _CYAN,
                    _RED,    _MAGENTA,  _BROWN,  _WHITE };
char *bkname [] = { "BLACK", "BLUE",    "GREEN", "CYAN",
                    "RED",   "MAGENTA", "BROWN", "WHITE" };

void main( void )
{
   short i, j, k;

   if ( !_setvideomode( _MRES4COLOR ) )
   {
      printf( "No palettes available" );
      exit( 1 );
   }
   for( i = 0; i < 4; i++ )          /* Palette loop        */
   {
      _selectpalette( i );
      for( k = 0; k < 8; k++ )       /* Background color  loop */
      {
         _clearscreen( _GCLEARSCREEN );
         _setbkcolor( bkcolor[k] );
         _settextposition( 1, 1 );
         printf( "Background: %s\tPalette: %d", bkname[k], i );
         for( j = 1; j < 4; j++ )       /* Foreground color loop  */
         {
            _setcolor( j );
            _ellipse( _GFILLINTERIOR, 100, j * 30, 220, 80 +
                      (j * 30) );
         }
         _getch();
      }
   }
    _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _setactivepage
  _setactivepage

#include <graph.h>

short __far _setactivepage( short page );

page    Memory page number

Remarks

For hardware and mode configurations with enough memory to support multiple screen pages, _setactivepage specifies the area in memory in which output is written. The page argument selects the current active page. The default page number is 0.

Screen animation can be done by alternating the graphics pages displayed. Use the _setvisualpage function to display a completed graphics or text page while executing graphics statements in another active page. These functions can also be used to control text output if you use the text functions _gettextcursor, _settextcursor, _outtext, _settextposition, _gettextposition, _settextcolor, _gettextcolor, _settextwindow, and _wrapon instead of the standard C-language I/O functions.

The CGA hardware configuration has only 16K of RAM available to support multiple video pages, and only in the text mode. The EGA and VGA configurations may be equipped with up to 256K of RAM for multiple video pages in graphics mode.

The _setactivepage function works differently in QuickWin applications.

Return Value

If successful, the function returns the page number of the previous active page. If the function fails, it returns a negative value.

See Also

»_getactivepage,« »_getvisualpage,« »_setvisualpage«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getactivepage.«


Description: _setbkcolor
  _setbkcolor

#include <graph.h>

long __far _setbkcolor( long color );

color    Desired color

Remarks

The _setbkcolor function sets the current background color to the color value color.

In a color text mode (such as _TEXTC80), _setbkcolor accepts (and _getbkcolor returns) a color index. The value for the default colors is given in a table in the description of the »_settextcolor« function. For example, _setbkcolor(2L) sets the background color to color index 2. The actual color displayed depends on the palette mapping for color index 2. The default is green in a color text mode.

In a color graphics mode (such as _ERESCOLOR), _setbkcolor accepts (and _getbkcolor returns) a color value. The value for the background color is given by the manifest constants defined in the GRAPH.H include file. For example, _setbkcolor(_GREEN) sets the background color in a graphics mode to green. These manifest constants are provided as a convenience in defining and manipulating the most common colors. The actual range of colors is, in general, much greater.

In general, whenever a color argument is long, it refers to a color value, and whenever it is short, it refers to a color index. The two exceptions are _setbkcolor and _getbkcolor.

Because the background color is color index 0, the _remappalette function will act identically to the _setbkcolor function. Unlike _remappalette, however, _setbkcolor does not require an EGA or VGA environment. In a text mode, the _setbkcolor function does not affect anything already appearing on the display; only the subsequent output is affected. In a graphics mode, it immediately changes all background pixels.

This function works differently in QuickWin applications.

Return Value

In text modes, _setbkcolor returns the color index of the old background color. In graphics modes, _setbkcolor returns the old color value of color index 0. There is no error return. Use the _grstatus function to check the status after a call to _setbkcolor.

See Also

»_getbkcolor,« »_grstatus,« »_remappalette,« »_selectpalette«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outtext.«


Description: setbuf
  setbuf

#include <stdio.h>

void setbuf( FILE *stream, char *buffer );

stream    Pointer to FILE structure

buffer    User-allocated buffer

Remarks

The setbuf function allows the user to control buffering for stream. The stream argument must refer to an open file that has not been read or written. If the buffer argument is NULL, the stream is unbuffered. If not, the buffer must point to a character array of length BUFSIZ, where BUFSIZ is the buffer size as defined in STDIO.H. The user-specified buffer, instead of the default system-allocated buffer for the given stream, is used for I/O buffering. The stderr and (in MS-DOS only) _stdaux streams are unbuffered by default, but can be assigned buffers with setbuf.

The setbuf function has been subsumed by the »setvbuf« function, which should be the preferred routine for new code. The setbuf function is retained for compatibility with existing code.

Return Value

None.

See Also

»fclose,« »fflush,« »fopen,« »setvbuf«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SETBUF.C: This program first opens files named DATA1 and
 * DATA2. Then it uses setbuf to give DATA1 a user-assigned
 * buffer and to change DATA2 so that it has no buffer.
 */

#include <stdio.h>

void main( void )
{
   char buf[BUFSIZ];
   FILE *stream1, *stream2;

   if( ((stream1 = fopen( "data1", "a" )) != NULL) &&
       ((stream2 = fopen( "data2", "w" )) != NULL) )
   {
      /* "stream1" uses user-assigned buffer: */
      setbuf( stream1, buf );
      printf( "stream1 set to user-defined buffer at: %Fp\n", buf );

      /* "stream2" is unbuffered              */
      setbuf( stream2, NULL );
      printf( "stream2 buffering disabled\n" );
      _fcloseall();
   }
}

Output

stream1 set to user-defined buffer at: 0013FDA0
stream2 buffering disabled


Description: _setcliprgn
  _setcliprgn

#include <graph.h>

void __far _setcliprgn( short x1, short y1, short x2, short y2 );

x1, y1    Upper-left corner of clip region

x2, y2    Lower-right corner of clip region

Remarks

The _setcliprgn function limits the display of subsequent graphics output and font text output to an area of the screen called the "clipping region." The physical points (x1, y1) and (x2, y2) are the diagonally opposed sides of a rectangle that defines the clipping region. This function does not change the view coordinate system. Rather, it merely masks the screen. Note that the _setcliprgn function affects graphics and font text output only. To mask the screen for text output, use the »_settextwindow« function.

Return Value

None.

See Also

»_settextwindow,« »_setvieworg,« »_setviewport,« »_setwindow«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SCLIPRGN.C
 *
 */

#include <stdlib.h>
#include <conio.h>
#include <graph.h>

void main( void )
{
   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   /* Set clip region, then draw an ellipse larger than the region. */
   _setcliprgn( 0, 0, 200, 125 );
   _ellipse( _GFILLINTERIOR, 80, 50, 240, 190 );

   _getch();
   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _setcolor
  _setcolor

#include <graph.h>

short __far _setcolor( short color );

color    Desired color index

Remarks

The _setcolor function sets the current color index to color. The color parameter is masked but always within range. The following graphics functions use the current color: _arc, _ellipse, _floodfill, _lineto, _outgtext, _pie, _polygon, _rectangle, and _setpixel. The _setcolor function accepts a short value as an argument. It is a color index. The default color index is the highest numbered color index in the current palette. Note that the _setcolor function does not affect the output of the presentation-graphics functions.

Return Value

This function returns the previous color. If the function fails (e.g., if used in a text mode), it returns −1.

See Also

»_arc functions,« »_ellipse functions,« »_floodfill,« »_getcolor,« »_lineto functions,« »_outgtext,« »_pie functions,« »_polygon functions,« »_rectangle functions,« »_selectpalette,« »_setpixel functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getpixel.«


Description: _setfillmask
  _setfillmask

#include <graph.h>

void __far _setfillmask( unsigned char __far *mask );

mask    Mask array

Remarks

The _setfillmask function sets the current fill mask, which determines the fill pattern. The mask is an 8-by-8 array of bits in which each bit represents a pixel. A 1 bit sets the corresponding pixel to the current color, while a 0 bit leaves the pixel unchanged. The pattern is repeated over the entire fill area. If no fill mask is set (mask is NULL—the default), a solid (unpatterned) fill is performed using the current color.

The _setfillmask function works differently in QuickWin applications.

Return Value

None.

See Also

»_ellipse functions,« »_floodfill,« »_getfillmask,« »_pie functions,« »_polygon functions,« »_rectangle functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getfillmask.«


Description: _setfont
  _setfont

#include <graph.h>

short __far _setfont( const char __far *options );

options    String describing font characteristics

Remarks

The _setfont function finds a single font, from the set of registered fonts, that has the characteristics specified by the options string. If a font is found, it is made the current font. The current font is used in all subsequent calls to the _outgtext function. There can be only one active font at any time.

The options string is a set of characters that specifies the desired characteristics of the font. The _setfont function searches the list of registered fonts for a font matching the specified characteristics. The characteristics that may be specified in the options string are shown in the list below. Characteristics specified in the options string are not case-sensitive or position-sensitive.

t'fontname'    Typeface.

hx    Character height, where x is the number of pixels.

wy    Character width, where y is the number of pixels.

f    Find only a fixed-space font (should not be used with the p characteristic).

p    Find only a proportionally spaced font (should not be used with the f characteristic).

v    Find only a vector font (should not be used with the r characteristic).

r    Find only a raster-mapped (bitmapped) font (should not be used with the v characteristic).

b    Select a best fit font.

nx    Select font number x, where x is less than or equal to the value returned by the _registerfonts function. Use this option to "step through" an entire set of fonts or to save or restore a previously set font.

You can request as many options as desired, except with nx, which should be used alone. If mutually exclusive options are requested (such as the pair f/p or r/v), the _setfont function ignores them. There is no error detection for incompatible parameters used with nx. Options can be separated by blanks in the options string. Any other character is ignored by _setfont.

The t (the typeface specification) in options is specified as a "t" followed by fontname in single quotation marks.

A b in the options field causes the _setfont routine to automatically select the "best fit" font that matches the other characteristics you have specified. If the b parameter is specified and at least one font is registered, _setfont will always be able to set a font and will return 0 to indicate success. You can also specify a pixel width and height for fonts. If a nonexistent value is chosen for either, and the b option is specified, the _setfont function will choose the closest match. A smaller font size has precedence over a larger size. For example, if _setfont requests Courier 12 with best fit, and only Courier 10 and Courier 14 are available, _setfont will select Courier 10.

In selecting a font, the _setfont routine uses the following precedence, rated from first to last: pixel height, typeface, pixel width, and fixed or proportional font.

If a nonexistent value is chosen for pixel height and width, the _setfont function will apply a magnification factor to a vector-mapped font to obtain a suitable font size. This automatic magnification does not apply if the r (raster-mapped font) option is specified, or if a specific typeface is requested and no best fit (b) option is specified.

If you specify the nx parameter, _setfont will ignore any other specified options and supply only the font number corresponding to x.

Note that the font functions affect only the output from the font output function _outgtext; no other run-time output functions are affected by font usage.

Return Value

The _setfont function returns an index that is suitable for use with nx to indicate success or a negative value to indicate an error. An error occurs if a request for a specific font fails and the b option was not specified, or if fonts have not yet been registered.

See Also

»_getfontinfo,« »_getgtextextent,« »_outgtext,« »_registerfonts,« »_unregisterfonts«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outgtext.«


Description: _setgtextvector
  _setgtextvector

#include <graph.h>

struct _xycoord __far _setgtextvector( short x, short y );

x, y    Integers specifying font rotation

Remarks

The _setgtextvector function sets the current orientation for font text output to the vector specified by x and y. The current orientation is used in calls to the _outgtext function. The values of x and y define the vector that determines the direction of rotation of font text on the screen. The text-rotation options are shown below:

(0, 0)     Unchanged

(1, 0)    Horizontal text (default)

(0, 1)     Rotated 90 degrees counterclockwise

(−1, 0)     Rotated 180 degrees

(0, −1)    Rotated 270 degrees counterclockwise

If other values are input, only the sign of the input is used. For example, (−3, 0) is interpreted as (−1, 0).

This function works differently in QuickWin applications.

Return Value

The _setgtextvector function returns the previous vector in a structure of _xycoord type. If you pass the _setgtextvector function the values (0, 0), the function returns the current vector values in the _xycoord structure.

See Also

»_getfontinfo,« »_getgtextextent,« »_grstatus,« »_outgtext,« »_registerfonts,« »_setfont,« »_unregisterfonts«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outgtext.«


Description: _setjmp
  _setjmp

#include <setjmp.h>

int _setjmp( jmp_buf env );

env    Variable in which environment is stored

Remarks

The _setjmp function saves a stack environment that can be subsequently restored using longjmp. Used together this way, _setjmp and longjmp provide a way to execute a "non-local goto." They are typically used to pass execution control to error-handling or recovery code in a previously called routine without using the normal calling or return conventions.

A call to _setjmp causes the current stack environment to be saved in env. A subsequent call to longjmp restores the saved environment and returns control to the point just after the corresponding _setjmp call. All variables (except register variables) accessible to the routine receiving control contain the values they had when longjmp was called.

Warning  Neither the _setjmp nor the longjmp function is compatible with the C++ language.

Return Value

The _setjmp function returns 0 after saving the stack environment. If _setjmp returns as a result of a longjmp call, it returns the value argument of longjmp, or if the value argument of longjmp is 0, setjmp returns 1. There is no error return.

See Also

»longjmp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_fpreset.«


Description: _setlinestyle
  _setlinestyle

#include <graph.h>

void __far _setlinestyle( unsigned short mask );

mask     Desired line-style mask

Remarks

Some graphics routines (_lineto, _polygon, and _rectangle) draw straight lines on the screen. The type of line is controlled by the current line-style mask. The _setlinestyle function selects the mask used for line drawing. The mask argument is a 16-bit array, where each bit represents a pixel in the line being drawn. If a bit is 1, the corresponding pixel is set to the color of the line (the current color). If a bit is 0, the corresponding pixel is left unchanged. The template is repeated for the entire length of the line. The default mask is 0xFFFF (a solid line).

This function works differently in QuickWin applications.

Return Value

None.

See Also

»_getlinestyle,« »_lineto functions,« »_polygon functions,« »_rectangle functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getlinestyle.«


Description: setlocale
  setlocale

#include <locale.h>

char *setlocale( int category, const char *locale );

category    Category affected by locale

locale    Name of the locale that will control the specified category

Remarks

The setlocale function sets the categories specified by category to the locale specified by locale. The "locale" refers to the locality (country and language) for which certain aspects of your program can be customized. Some locale-dependent aspects include the formatting of dates and the display format for monetary values.

The setlocale function is used to set, change, or query the program's current entire locale or simply portions of the locale information. The category argument specifies which portion of a program's locale information will be affected. The macros used for the category argument and the parts of the program they affect are listed below:

LC_ALL    All categories listed below.

LC_COLLATE    The strcoll, _stricoll, wcscoll, _wcsicoll, and strxfrm functions.

LC_CTYPE    The character-handling functions (except for isdigit, isxdigit, mbstowcs, and mbtowc, which are unaffected).

LC_MONETARY    Monetary formatting information returned by the localeconv function.

LC_NUMERIC    Decimal point character for the formatted output routines (such as printf), for the data conversion routines, and for the nonmonetary formatting information returned by the localeconv function.

LC_TIME     The strftime and wcsftime functions.

The locale argument is a pointer to a string that specifies the name of the locale. If locale points to an empty string, the locale is the implementation-defined native environment. A value of "C" specifies the minimal ANSI conforming environment for C translation. The "C" locale assumes that all char data types are one byte, and that their value is always less than 256. This is the only locale supported in Microsoft C version 6.0, Microsoft C/C++ version 7.0, and Microsoft Visual C++ version 1.0. At program startup, the equivalent of the following statement is executed:

setlocale( LC_ALL, "C" );

The locale argument can be composed of any combination of three separate string options: language, country, and code page. The locale argument takes the following form:

locale :: "lang[_country[.code_page]]"

| ".code_page"

| ""

| NULL

The set of available languages, countries, and code pages includes all those supported by the Win32 NLS API. The set of language and country codes supported by the setlocale function is included in »Appendix A.«

If the locale argument is a null pointer, setlocale returns a pointer to the string associated with the category of the program's locale. The program's current locale setting is not changed. The null pointer is a special directive that tells setlocale to query rather than set the international environment. For example,

setlocale( LC_ALL, NULL );

returns the string associated with category.

Note the following examples:

setlocale( LC_ALL, "" );

Sets the locale to the default specified by the operating system.

setlocale( LC_ALL, "[lang_ctry.cp]" );

Sets the locale to the language, country, and code page indicated in the [lang_ctry.cp] string. Any combination of language, country, and code page can be used. For example:

setlocale( LC_ALL, "Portuguese_Canada.437" );

setlocale( LC_ALL, "[lang_ctry]" );

Sets the locale to the language and country indicated, using the specified country's default code page (as defined by the host operating system).

setlocale( LC_ALL, "[lang]" );

Sets the locale to the country indicated, using the default country for the language specified , and the default code page for that country, as defined by the host operating system. For example, the following two calls to setlocale are functionally equivalent:

setlocale( LC_ALL, "English" );

setlocale( LC_ALL, "English_United States.437" );

setlocale( LC_ALL, "[.code_page]" );

Sets the code page to the value indicated, using the default country and language (as defined by the host operating system) for the specified code page. Note that the category must be either LC_ALL or LC_CTYPE to effect a change of code page. For example, if the host operating system default country and language are "United States" and "English," the following two calls to setlocale are functionally equivalent:

setlocale( LC_ALL, ".850" );

setlocale( LC_ALL, "English_United States.850");

Return Value

If a valid locale and category are given, setlocale returns a pointer to the string associated with the specified category for the new locale. If the locale or category is invalid, the setlocale function returns a null pointer and the program's current locale settings are not changed. The return string indicates the current locale. For example, the following call

setlocale( LC_ALL, "English" );

will return "English_USA.437," since all categories are set. If all categories are not explicitly set, setlocale returns a string indicating the current setting of each of the categories, separated by semicolons. For example, the following sequence of calls:

setlocale( LC_ALL, "English" );   // Set all categories and
                                  //   return "English_USA.437"

setlocale( LC_MONETARY, "French" ); // Set only the LC_MONETARY
                                    //  category and return
                                    //  "French_France.850"

setlocale( LC_ALL, NULL );

returns "LC_COLLATE=English_USA.437;LC_CTYPE=English_USA.437; LC_MONETARY=French_France.850;LC_NUMERIC=English_USA.437; LC_TIME=English_USA.437."

The pointer to a string returned by setlocale can be used in subsequent calls to restore that part of the program's locale information, assuming that your program does not alter the pointer or the string. Later calls to setlocale will overwrite the string; you can use the _strdup function to save a specific locale string.

 See Also

»localeconv,« »mblen,« »_mbslen,« »mbstowcs,« »mbtowc,« »strcoll,« »strftime,« »strxfrm,« »wcstombs,« »wctomb«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* LOCALE.C: Sets the current locale to "Germany" using the
 * setlocale function and demonstrates its effect on the strftime
 * function. In MS-DOS, this program will have no effect on the
 * current locale setting, since only the default "C" locale is
 * supported at this time.
 */

#include <stdio.h>
#include <locale.h>
#include <time.h>

void main(void)
{
       time_t ltime;
       struct tm *thetime;
       unsigned char str[100];

       setlocale(LC_ALL, "German");
       time (&ltime);
       thetime = gmtime(&ltime);

       /* %#x is the long date representation, appropriate to
        * the current locale
        */
       if (!strftime((char *)str, 100, "%#x",
                     (const struct tm *)thetime))
               printf("strftime failed!\n");
       else
               printf("In German locale, strftime returns '%s'\n",
                      str);

       /* Set the locale back to the default environment */
       setlocale(LC_ALL, "C");
       time (&ltime);
       thetime = gmtime(&ltime);

       if (!strftime((char *)str, 100, "%#x",
                     (const struct tm *)thetime))
               printf("strftime failed!\n");
       else
               printf("In 'C' locale, strftime returns '%s'\n",
                      str);
}

Output

In German locale, strftime returns 'Donnerstag, 22. April 1993'
In 'C' locale, strftime returns 'Thursday, April 22, 1993'


Description: _setmode
  _setmode

#include <fcntl.h>

#include <io.h>

int _setmode ( int handle, int mode );

handle    File handle

mode    New translation mode

Remarks

The _setmode function sets to mode the translation mode of the file given by handle. The mode must be one of two manifest constants, _O_TEXT or _O_BINARY. The _O_TEXT constant sets text (translated) mode. Carriage-return−linefeed (CR-LF) combinations are translated into a single linefeed (LF) character on input. Linefeed characters are translated into CR-LF combinations on output. The _O_BINARY constant sets binary (untranslated) mode. The previously mentioned translations are suppressed.

The _setmode function is typically used to modify the default translation mode of stdin, stdout, stderr, _stdaux, and _stdprn, but can be used on any file. If _setmode is applied to the file handle for a stream, the _setmode function should be called before any input or output operations are performed on the stream.

Return Value

If successful, _setmode returns the previous translation mode. A return value of −1 indicates an error, and errno is set to either EBADF, meaning invalid file handle, or EINVAL, meaning invalid mode argument (neither _O_TEXT nor _O_BINARY).

See Also

»_creat,« »fopen,« »_open«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SETMODE.C: This program uses _setmode to change
 * stdin from text mode to binary mode.
 */

#include <stdio.h>
#include <fcntl.h>
#include <io.h>

void main( void )
{
   int result;

   /* Set "stdin" to have binary mode: */
   result = _setmode( _fileno( stdin ), _O_BINARY );
   if( result == -1 )
      perror( "Cannot set mode" );
   else
      printf( "'stdin' successfully changed to binary mode\n" );
}

Output

'stdin' successfully changed to binary mode


Description: _set_new_handler Functions
  _set_new_handler Functions

#include <new.h>

_PNH _set_new_handler( _PNH pNewHandler );

_PNH _set_nnew_handler( _PNH pNewHandler );

_PNH _set_fnew_handler( _PNH pNewHandler );

_PNHH _set_hnew_handler( _PNHH pNewHandler );

_PNHB _set_bnew_handler( _PNHB pNewHandler );

pNewHandler     Pointer to a function that you write

Remarks

Use the C++ _set_new_handler function to gain control if the new operator fails to allocate memory. The run-time system automatically calls _set_new_handler when new fails. To use _set_new_handler, you must write an exception-handling function and then pass it as an argument to _set_new_handler. To facilitate the easy declaration of this new handler, three pointer-to-function types, _PNH, _PNHH, and _PNHB, are defined in NEW.H:

_PNH    Pointer to a function that returns type int and takes an argument of type size_t. Use size_t to specify the amount of space to be allocated.

_PNHH    Pointer to a function that returns type int and takes two arguments — the type unsigned long and the type size_t arguments specified to the huge new operator.

_PNHB    Pointer to a function that returns type int and takes two arguments — the type __segment and the type size_t arguments specified to the based new operator. Your function must ensure the correct binding of the segment variable to its return value.

Basically, _set_new_handler is a garbage collection scheme. The run-time system retries allocation each time your function returns a nonzero value and fails new if your function returns 0.

An occurrence of one of the _set_new_handler functions in a program registers the exception-handling function specified in the argument list with the run-time system:

#include <new.h>
int handle_program_memory_depletion( size_t )
{
   // Your code
}
void main( void )
{
   _set_new_handler( handle_program_memory_depletion );
   int *pi = new int[BIG_NUMBER];
}

You can save the function address that was last passed to the _set_new_handler function and then reinstate it at a later time:

_PNH old_handler = _set_new_handler( my_handler );
   // Code that requires my_handler
   _set_new_handler( old_handler )
   // Code that requires old_handler

The _set_new_handler function is defined in five different forms that allow you to manage the heap for five different memory models:

_PNH _set_new_handler( _PNH );    Default new handler

_PNH _set_nnew_handler( _PNH );    Manages the near heap

_PNH _set_fnew_handler( _PNH );    Manages the far heap

_PNHH _set_hnew_handler( _PNHH );    Manages the huge heap

_PNHB _set_bnew_handler( _PNHB );    Manages based heaps

The _set_new_handler function automatically maps to either the _set_nnew_handler or the _set_fnew_handler function, depending on the default data model. If the default memory model is either small or medium, you can call _set_fnew_handler to manage the far heap. If the default memory model is either compact or large, you can call _set_nnew_handler to manage the near heap. You can explicitly call the _set_hnew_handler and the _set_bnew_handler functions to manage both the huge and based heaps.

In a multithreaded environment, handlers are maintained separately for each process and thread. Each new process lacks installed handlers. Each new thread gets a copy of its parent thread's new handlers. Thus, each process and thread is in charge of its own free-store error handling.

Return Value

The _set_new_handler function returns a pointer to the allocated program memory if successful. It returns a 0 if it's unsuccessful.

For more information on the new and delete operators, see the C++ Language Reference (in this product's documentation set).

See Also

»_bfreeseg,« »_bheapseg,« »calloc,« »free,« »malloc,« »realloc«

Compatibility

_set_new_handler:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_set_bnew_handler, _set_fnew_handler, _set_hnew_handler, _set_nnew_handler:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* HANDLER.CPP: This program uses _set_new_handler to
 * print an error message if the new operator fails.
 */

#include <stdio.h>
#include <new.h>

/* Allocate memory in chunks of size MemBlock. */
const size_t MemBlock = 1024;

/* Allocate a memory block for the printf function to use in case
 * of memory allocation failure; the printf function uses malloc.
 * The failsafe memory block must be visible globally because the
 * handle_program_memory_depletion function can take one
 * argument only.
 */
char * failsafe = new char[128];

/* Declare a customized function to handle memory-allocation failure.
 * Pass this function as an argument to _set_new_handler.
 */
int handle_program_memory_depletion( size_t );

void main( void )
{
   // Register existence of a new memory handler.
   _set_new_handler( handle_program_memory_depletion );
   size_t *pmemdump = new size_t[MemBlock];
   for( ; pmemdump != 0; pmemdump = new size_t[MemBlock] );
}

int handle_program_memory_depletion( size_t size )
{
   // Release character buffer memory.
   delete failsafe;
   printf( "Allocation failed, " );
   printf( "%u bytes not available.\n", size );
   // Tell new to stop allocation attempts.
   return 0;
}


Description: _setpixel Functions
  _setpixel Functions

#include <graph.h>

short __far _setpixel( short x, short y );

short __far _setpixel_w( double wx, double wy );

x, y    Target pixel

wx, wy    Target pixel

Remarks

The _setpixel and the _setpixel_w functions set a pixel at a specified location to the current color. The _setpixel function sets the pixel at the view-coordinate point (x, y) to the current color. The _setpixel_w function sets the pixel at the window-coordinate point (wx, wy) to the current color.

Return Value

The function returns the previous value of the target pixel. If the function fails (for example, the point lies outside of the clipping region), it will return −1.

See Also

»_getpixel functions,« »_setcolor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getpixel.«


Description: _settextcolor
  _settextcolor

#include <graph.h>

short __far _settextcolor( short index );

index    Desired color index

Remarks

The _settextcolor function sets the current text color to the color index specified by index. The default text color is the same as the maximum color index for the current video mode. The _settextcolor routine sets the color for the _outtext and _outmem functions only. It does not affect the color of the printf function or the color of text output with the _outgtext font routine. Use the _setcolor function to change the color of font output.

In text color mode, you can specify a color index in the range 0 − 31. The colors in the range 0 − 15 are interpreted as normal (non-blinking). The normal color range is defined below:

Index	Color	Index	Color
0	Black	8	Dark gray
1	Blue	9	Light blue
2	Green	10	Light green
3	Cyan	11	Light cyan
4	Red	12	Light red
5	Magenta	13	Light magenta
6	Brown	14	Yellow
7	White	15	Bright white
Blinking is selected by adding 16 to the normal color value.

In every text mode, including monochrome, _getvideoconfig returns the value 32 for the number of available colors. The value 32 indicates the range of values (0−31) accepted by the _settextcolor function. This includes sixteen normal colors (0−15) and sixteen blinking colors (16−31). Monochrome text mode has fewer unique display attributes, so some color values are redundant. However, because blinking is selected in the same manner, monochrome text mode has the same range (0−31) as other text modes.

This function works differently in QuickWin applications.

Return Value

The function returns the color index of the previous text color. There is no error return. Use the _grstatus function to check the status after a call to _settextcolor.

See Also

»_gettextcolor,« »_grstatus,« »_outmem,« »_outtext«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outtext.«


Description: _settextcursor
  _settextcursor

#include <graph.h>

short __far _settextcursor( short attr );

attr    Cursor attribute

Remarks

The _settextcursor function sets the cursor attribute (i.e., the shape) to the value specified by attr. The high-order byte of attr determines the top line of the cursor within the character cell. The low-order byte of attr determines the bottom line of the cursor.

The _settextcursor function uses the same format as the BIOS routines in setting the cursor. Typical values for the cursor attribute are listed below:

0x0707    Underline

0x0007    Full block cursor

0x0607    Double underline

0x2000    No cursor

Note that this function works only in text video modes.

This function works differently in QuickWin applications.

Return Value

The function returns the previous cursor attribute, or −1 if an error occurs (such as calling the function in a graphics screen mode).

See Also

»_displaycursor,« »_gettextcursor«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_displaycursor.«


Description: _settextposition
  _settextposition

#include <graph.h>

struct _rccoord __far _settextposition( short row, short column );

row, column     New output start position

Remarks

The _settextposition function sets the current text position to the display point (row, column). The _outtext and _outmem functions (and standard console I/O routines, such as printf) output text at that point. Note that _settextposition does not affect the text position for the _outgtext function; use the _moveto function instead.

The _rccoord structure, defined in GRAPH.H, contains short row, the row coordinate, and short col, the column coordinate.

Standard console routines such as printf do not use or maintain information about the display, such as current text position, which is contained in the graphics library. Therefore, you cannot use standard console routines to output graphics text.

Return Value

The function returns the previous text position in an _rccoord structure, defined in GRAPH.H.

See Also

»_gettextposition,« »_moveto,« »_outmem,« »_outtext,« »_settextwindow«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outtext.«


Description: _settextrows
  _settextrows

#include <graph.h>

short __far _settextrows( short rows );

rows    Number of text rows

Remarks

The _settextrows function specifies the number of screen rows to be used in text modes. If the constant _MAXTEXTROWS is specified for the rows argument, the _settextrows function will choose the maximum number of rows available. In text modes, this is 50 rows on VGA, 43 on EGA, and 25 on others. In graphics modes that support 30 or 60 rows, _MAXTEXTROWS specifies 60 rows. In SVGA modes, _MAXTEXTROWS specifies the vertical resolution (as returned in a _videoconfig struct by the _getvideoconfig function) divided by 8.

This function works differently in QuickWin applications.

Return Value

This function returns the numbers of rows set. The function returns 0 if an error occurs (such as calling the function in a graphics screen mode).

See Also

»_getvideoconfig,« »_outtext,« »_setvideomode,« »_setvideomoderows«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * STXTROWS.C: This program attempts to set the screen
 * height. It returns an errorlevel code of 1 (fail) or
 * 0 (success) that could be tested in a batch file.
 */

#include <graph.h>
#include <stdlib.h>

void main( int argc, char **argv )
{
   short rows;

   if( (rows = (short)atoi( argv[1] )) != 0 )
   {
      _outtext( "\nSyntax: STXTROWS [ 25 | 43 | 50 ]\n" );
      exit( 1 );
   }

   /* Make sure new rows are the same as requested rows. */
   if( _settextrows( rows ) != rows )
   {
      _outtext( "\nInvalid rows\n" );
      exit( 1 );
   }
   else
      exit( 0 );
}


Description: _settextwindow
  _settextwindow

#include <graph.h>

void __far _settextwindow( short r1, short c1, short r2, short c2 );

r1, c1    Upper-left corner of window

r2, c2    Lower-right corner of window

Remarks

The _settextwindow function specifies a window in row and column coordinates where the text output to the screen by the _outtext or _outmem function is displayed. The arguments (r1, c1) specify the upper-left corner of the text window, and the arguments (r2, c2) specify the lower-right corner of the text window. Text is output from the top of the text window down. When the text window is full, the uppermost line scrolls up out of it.

Note that this function does not affect the output of presentation-graphics text (e.g., labels, axis marks, etc.), the output of the font display routine _outgtext, or the output of the standard I/O routine printf. Use the _setviewport function to control the display area for presentation graphics or fonts.

Return Value

None. Use the _grstatus function to check conditions of success or failure.

See Also

»_gettextposition,« »_gettextwindow,« »_grstatus,« »_outmem,« »_outtext,« »_scrolltextwindow,« »_settextposition«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_scrolltextwindow.«


Description: setvbuf
  setvbuf

#include <stdio.h>

int setvbuf( FILE *stream, char *buffer, int mode, size_t size );

stream    Pointer to FILE structure

buffer    User-allocated buffer

mode    Mode of buffering

size    Size of buffer

Remarks

The setvbuf function allows the program to control both buffering and buffer size for stream. The stream must refer to an open file that has not been read from or written to since it was opened. The array pointed to by buffer is used as the buffer, unless it is NULL, and an automatically allocated buffer size bytes long is used.

The mode must be _IOFBF, _IOLBF, or _IONBF. If mode is _IOFBF or _IOLBF, then size is used as the size of the buffer. If mode is _IONBF, the stream is unbuffered and size and buffer are ignored. Values for mode and their meanings are:

_IOFBF    Full buffering; that is, buffer is used as the buffer and size is used as the size of the buffer. If buffer is NULL, an automatically allocated buffer size bytes long is used.

_IOLBF    With MS-DOS, the same as _IOFBF.

_IONBF    No buffer is used, regardless of buffer or size.

The legal values for size are powers of 2, greater than 0 and less than 32,768.

Return Value

The return value for setvbuf is 0 if successful, and a nonzero value if an illegal type or buffer size is specified.

See Also

»fclose,« »fflush,« »fopen,« »setbuf«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SETVBUF.C: This program opens two streams named stream1
 * and stream2. It then uses setvbuf to give stream1 a
 * user-defined buffer of 1024 bytes and stream2 no buffer.
 */

#include <stdio.h>

void main( void )
{
   char buf[1024];
   FILE *stream1, *stream2;

   if( ((stream1 = fopen( "data1", "a" )) != NULL) &&
       ((stream2 = fopen( "data2", "w" )) != NULL) )
   {
      if( setvbuf( stream1, buf, _IOFBF, sizeof( buf ) ) != 0 )
         printf( "Incorrect type or size of buffer for stream1\n" );
      else
         printf( "'stream1' now has a buffer of 1024 bytes\n" );
      if( setvbuf( stream2, NULL, _IONBF, 0 ) != 0 )
         printf( "Incorrect type or size of buffer for stream2\n" );
      else
         printf( "'stream2' now has no buffer\n" );
      _fcloseall();
   }
}

Output

'stream1' now has a buffer of 1024 bytes
'stream2' now has no buffer


Description: _setvideomode
  _setvideomode

#include <graph.h>

short __far _setvideomode( short mode );

mode    Desired mode

Remarks

The _setvideomode function selects a screen mode appropriate for a particular hardware/display configuration. The mode argument can be one of the manifest constants shown in Tables R.13 and R.14 and defined in GRAPH.H. Table R.13 describes only standard hardware; however, display hardware that is strictly compatible with IBM, Hercules, or Olivetti hardware should also work as described.

Table R.13    Manifest Constants for Screen Mode

Mode	Type1	Size2	Colors3	Adapter4
_DEFAULTMODE	Mode existing at startup
_MAXRESMODE	Highest resolution in graphics mode
_MAXCOLORMODE	Maximum colors in graphics mode
_TEXTBW40	BW/T	40 columns	32	CGA
_TEXTC40	C/T	40 columns	32	CGA
_TEXTBW80	BW/T	80 columns	32	CGA
_TEXTC80	C/T	80 columns	32	CGA
_MRES4COLOR	C/G	320 ×  200	4	CGA
_MRESNOCOLOR	BW/G	320 × 200	4	CGA
_HRESBW	BW/G	640 × 200	2	CGA
_TEXTMONO	M/T	80 columns	32	MDPA
_HERCMONO5	M/G/Hercules graphics	720 ×  348	2	HGC
_MRES16COLOR	C/G	320 × 200	16	EGA
_HRES16COLOR	C/G	640 ×  200	16	EGA
_ERESNOCOLOR	M/G	640 ×  350	4	EGA
_ERESCOLOR	C/G	640 ×  350	16/4	EGA
_VRES2COLOR	C/G	640 ×  480	2	VGA
_VRES16COLOR	C/G	640 ×  480	16	VGA
_MRES256COLOR	C/G	320 ×  200	256	VGA
_ORESCOLOR	C/G	640 ×  400	1 of 16	OGA
1 Type: M indicates monochrome, BW indicates monochrome, C indicates color output, T indicates text, and G indicates graphics generation. 2 Size: For text modes, size is given in characters (number of columns). For graphics modes, size is given in pixels (horizontal × vertical). 3 Colors: For monochrome displays, the number of colors is the number of attributes or shades of gray. 4 Adapters: Adapters are the IBM (and compatible) Monochrome Adapter (MDPA), Color Graphics Adapter (CGA), Enhanced Graphics Adapter (EGA), Video Graphics Array (VGA), Hercules-compatible adapter (HGC), and Olivetti-compatible adapter (OGA). 5 In HERCMONO mode, the text dimensions are 80 columns by 25 rows, with a 9 by 14 character box. The bottom two scan lines of row 25 are not visible.
Super VGA Support

"Super VGA" (SVGA) does not describe a standard display adapter. Instead, it refers to any VGA-compatible video adapter that also provides higher resolution modes. SVGA adapters made by different manufacturers may support different extended resolution modes.

To allow your programs to use different SVGA adapters, the graphics libraries support the Video Electronics Standards Association (VESA) interface. This standard interface accesses the extended features of different SVGA adapters. The interface is widely supported by video hardware manufacturers, which allows your graphics program to run with virtually any VESA-compliant adapter.

The _setvideomode function supports eight extended resolution modes. Some or all are available on VESA-compliant SVGA adapters: _ORES256COLOR, _VRES256COLOR, _SRES16COLOR, _SRES256COLOR, _XRES16COLOR, _XRES256COLOR, _ZRES16COLOR and _ZRES256COLOR. (These modes represent BIOS numbers 0x0100 through 0x0107, respectively, in the VESA standard.) Consult the owner's manual to see which modes your adapter supports.

Having an SVGA adapter does not suffice for using one of these extended modes. You must have a display monitor that supports the higher resolution. Only the first two extended modes can be displayed on a standard VGA analog monitor. The other extended modes require special monitors.

You can use _setvideomode to select a nonstandard graphics mode specific to a particular manufacturer's adapter, if the adapter is VESA-compliant. Consult your adapter's owner's manual for the BIOS number of a given mode, and pass that number as the argument to _setvideomode. The BIOS number must be between 0x15 and 0x7F. Typically, these additional modes differ from the eight modes listed above only in resolution, not in number of colors. The _setvideomode function may not support all of an adapter's extended modes.

VESA TSRs

Some SVGA adapters provide the VESA interface in ROM. Other adapters require that you install a TSR (terminate-and-stay resident) program. Microsoft C/C++ includes TSRs for several adapters (see the file PACKING.LST for a list of TSRs supplied). If the TSR for your adapter is not included, contact your dealer or video adapter manufacturer.

These TSRs are executable programs with names of the form xxxVESA.COM or xxxVESA.EXE. You install the TSR by running the program. You must install the TSR before you run a graphics program that uses one of the VESA extended modes. If you don't install the TSR, your SVGA adapter behaves like a standard VGA adapter.

Warning  These drivers are provided on an as-is, unsupported basis, without any claim as to their correctness or suitability. Neither Microsoft nor the TSR vendor makes any representations or warranties regarding the capabilities or performance of the TSR software. Should you want to distribute any of the supplied TSRs with a software program developed using Microsoft C/C++, it is your responsibility to obtain permission from VESA and/or the TSR vendor.

Limitations of VESA Support

The graphics libraries may not work with all hardware and TSR combinations. Furthermore, VESA support has the following limitations:

•	Version 1.0 of the VESA Super VGA Standard (#VS891001) is supported.

•	Only color graphics modes are supported.

•	Super VGA BIOS functions 2, 3, 6, 7, and 9 must be supported. See section 6 of the VESA Super VGA Standard for more information.

•	Three types of hardware windows are supported: single window systems with a readable/writable 64K window beginning at A000h, dual overlapping 64K windows beginning at A000h, and dual adjacent 32K readable/writable windows beginning at A000h and A800h. See section 5.2.1 of the VESA Super VGA Standard for more information.

•	The only window size (WinSize) supported is 64K. Some adapters have an option of using either a 64K single-window, or a 32K double-window mode. Your adapter must be configured for 64K mode.

•	The window granularity (WinGranularity) must be a power of 2.

•	The memory model must be either 4-plane planar (16-color) or packed pixel (256-color).

Consult the VESA Super VGA Standard and your adapter's owner's manual for details. For a copy of the Super VGA Standard, write to the Video Electronics Standards Association (VESA) in San Jose, California.

Table R.14 lists the manifest constants that support the Super VGA screen modes specified by VESA. Other nonstandard Super VGA modes may also be supported. Note that some, or all, of these manifest constants may be supported by graphics cards that support the VESA Super Video standard VS891001. Other modes may also be supported; a TSR driver may be required.

Table R.14    VESA Manifest Constants for Screen Mode

Mode	VESA no.	Type1	Size	Colors	Adapter
_ORES256COLOR	0x0100	C/G	640 ×  400	256	SVGA
_VRES256COLOR	0x0101	C/G	640 ×  480	256	SVGA
_SRES16COLOR2	0x0102	C/G	800 ×  600	16	SVGA
_SRES256COLOR2	0x0103	C/G	800 ×  600	256	SVGA
_XRES16COLOR3	0x0104	C/G	1024 ×  768	16	SVGA
_XRES256COLOR3	0x0105	C/G	1024 ×  768	256	SVGA
_ZRES16COLOR4	0x0106	C/G	1280 ×  1024	16	SVGA
_ZRES256COLOR4	0x0107	C/G	1280 ×  1024	256	SVGA
1 C indicates color output, and G indicates graphics generation. 2 Requires NEC MultiSync 3D or equivalent or better. 3 Requires NEC MultiSync 4D or equivalent or better. 4 Requires NEC MultiSync 5D or equivalent or better.
Warning  Do not attempt to set _SRES16COLOR, _SRES256COLOR, _XRES16COLOR, _XRES256COLOR, _ZRES16COLOR, or _ZRES256COLOR without ensuring that your monitor can safely handle that resolution. Otherwise, you may risk damaging your display monitor! Consult your owner's manual for details.

_MAXRESMODE and _MAXCOLORMODE

The special mode _MAXRESMODE selects the highest resolution available with the current hardware. _MAXCOLORMODE selects the greatest number of colors available with the current hardware. These modes fail for adapters that do not support graphics modes. They never select _SRES, _XRES, or _ZRES mode. Table R.15 lists the video mode selected for different adapter and monitor combinations when _MAXRESMODE or _MAXCOLORMODE is specified.

Table R.15    Modes Selected by _MAXRESMODE and _MAXCOLORMODE

Adapter/Monitor	_MAXRESMODE	_MAXCOLORMODE
MDPA	fails	fails
HGC	_HERCMONO	_HERCMONO
CGA color1	_HRESBW	_MRES4COLOR
CGA noncolor1	_HRESBW	_MRESNOCOLOR
OCGA	_ORESCOLOR	_MRES4COLOR
OEGA color	_ORESCOLOR	_ERESCOLOR
EGA color 256K	_HRES16COLOR	_HRES16COLOR
EGA color 64K	_HRES16COLOR	_HRES16COLOR
EGA ecd 256K2	_ERESCOLOR	_ERESCOLOR
EGA ecd 64K2	_ERESCOLOR	_HRES16COLOR
EGA mono	_ERESNOCOLOR	_ERESNOCOLOR
MCGA	_VRES2COLOR	_MRES256COLOR
VGA	_VRES16COLOR	_MRES256COLOR
OVGA	_VRES16COLOR	_MRES256COLOR
SVGA	_VRES256COLOR3	_VRES256COLOR2
1 Color monitor is assumed if the startup text mode was _TEXTC80 or _TEXTC40 or if the startup mode was graphics mode. Composite or other noncolor CGA monitor is assumed if startup mode was _TEXTBW80 or _TEXTBY40. 2 The abbreviation "ecd" indicates Enhanced Color Display. 3 If _VRES256COLOR is supported by the adapter and monitor combination. If not, _MAXCOLORMODE is either _ORES256COLOR (if supported) or _MRES256COLOR and _MAXRESMODE is _VRES16COLOR.
Hercules Support

You must install the Hercules driver MSHERC.COM before running your program. Type MSHERC to load the driver. This can be automated by adding a line to your AUTOEXEC.BAT file. If you have both a Hercules monochrome card and a color video card, you should install MSHERC.COM with the /H (/HALF) option. The /H option causes the driver to use one instead of two graphics pages. This prevents the two video cards from attempting to use the same memory. You do not need to use the /H option if you have only a Hercules card. See your Hercules hardware manuals for more details on compatibility.

To use a mouse, you must follow special instructions for Hercules cards in Microsoft Mouse Programmer's Reference Guide. (This is sold separately; it is not supplied with either this product or the mouse package.)

This function works differently in QuickWin applications.

Return Value

The function returns the number of text rows if the function is successful. If an error is encountered (that is, the mode selected is not supported by the current hardware configuration), the function returns 0.

See Also

»_getvideoconfig,« »_settextrows,« »_setvideomoderows«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SVIDMODE.C: This program sets a video mode
 * from a string given on the command line.
 */

#include <graph.h>
#include <stdlib.h>
#include <string.h>

short modes[] = { _TEXTBW40,     _TEXTC40,      _TEXTBW80,
                  _TEXTC80,      _MRES4COLOR,   _MRESNOCOLOR,
                  _HRESBW,       _TEXTMONO,     _HERCMONO,
                  _MRES16COLOR,  _HRES16COLOR,  _ERESNOCOLOR,
                  _ERESCOLOR,    _VRES2COLOR,   _VRES16COLOR,
                  _MRES256COLOR, _ORESCOLOR
                };
char *names[] = { "TEXTBW40",    "TEXTC40",     "TEXTBW80",
                  "TEXTC80",     "MRES4COLOR",  "MRESNOCOLOR",
                  "HRESBW",      "TEXTMONO",    "HERCMONO",
                  "MRES16COLOR", "HRES16COLOR", "ERESNOCOLOR",
                  "ERESCOLOR",   "VRES2COLOR",  "VRES16COLOR",
                  "MRES256COLOR","ORESCOLOR" };

void error( char *msg );

void main( int argc, char *argv[] )
{
   short i, num = sizeof( modes ) / sizeof( short );

   if( argc < 2 )
      error( "No argument given" );

   /* If matching name found, change to corresponding mode. */
   for( i = 0; i < num; i++ )
   {
      if( !_strcmpi( argv[1], names[i] ) )
      {
         _setvideomode( modes[i] );
         _outtext( "New mode is: " );
         _outtext( names[i] );
         exit( 0 );
      }
   }
   error( "Invalid mode string" );
}

void error( char *msg )
{
   _outtext( msg );
   exit( 1 );
}


Description: _setvideomoderows
  _setvideomoderows

#include <graph.h>

short __far _setvideomoderows( short mode, short rows );

mode    Desired mode

rows    Number of text rows

Remarks

The _setvideomoderows function selects a screen mode for a particular hardware/display combination. The manifest constants for the screen mode are given in the description of »_setvideomode.« The _setvideomoderows function also specifies the number of text rows to be used in a text mode. If the constant _MAXTEXTROWS is specified for the rows argument, the _setvideomoderows function will choose the maximum number of rows available. In text modes, this is 50 rows on VGA, 43 on EGA, and 25 on others. In graphics modes that support 30 or 60 rows, _MAXTEXTROWS specifies 60 rows. In SVGA modes, _MAXTEXTROWS specifies the vertical resolution (as returned in a _videoconfig struct by the _getvideoconfig function) divided by 8.

This function works differently in QuickWin applications.

Return Value

The _setvideomoderows function returns the numbers of rows set. The function returns 0 if an error occurs (e.g., if the mode is not supported).

See Also

»_getvideoconfig,« »_settextrows,« »_setvideomode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SVMROWS.C
 *
 */

#include <stdlib.h>
#include <conio.h>
#include <graph.h>

void main( void )
{
   struct _videoconfig config;

   /* Set 43-line graphics mode if available. */
   if( !_setvideomoderows( _ERESCOLOR, 43 ) )
   {
      _outtext( "EGA or VGA required" );
      exit( 1 );
   }
   _getvideoconfig( &config );

   /* Set logical origin to center and draw a rectangle. */
   _setlogorg( (short)(config.numxpixels / 2 - 1),
               (short)(config.numypixels / 2 - 1) );
   _rectangle( _GBORDER, -80, -50, 80, 50 );

   _getch();
   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _setvieworg
_setvieworg

#include <graph.h>

struct _xycoord __far _setvieworg( short x, short y );

x, y    New origin point

Remarks

The _setvieworg function moves the view-coordinate origin (0, 0) to the physical point (x, y). It replaces the _setlogorg function of Microsoft C version 5.1.

Return Value

The function returns the physical coordinates of the previous view origin in an _xycoord structure, defined in GRAPH.H. The _xycoord structure contains short xcoord, the x coordinate, and short ycoord, the y coordinate.

See Also

»_getphyscoord,« »_getviewcoord,« »_getwindowcoord,« »_setcliprgn,« »_setviewport«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SVORG.C: This program sets the view origin
 * to the center of the screen, then draws a
 * rectangle using the new origin.
 */

#include <stdlib.h>
#include <conio.h>
#include <graph.h>

void main( void )
{
   struct _videoconfig config;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );
   _getvideoconfig( &config );

   /* Set view origin to the center of the screen. */
   _setvieworg( (short)(config.numxpixels / 2),
                (short)(config.numypixels / 2) );
   _rectangle( _GBORDER, -80, -50, 80, 50 );

   _getch();
   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _setviewport
  _setviewport

#include <graph.h>

void __far _setviewport( short x1, short y1, short x2, short y2 );

x1, y1    Upper-left corner of viewport

x2, y2    Lower-right corner of viewport

Remarks

The _setviewport function redefines the graphics viewport. The _setviewport function defines a clipping region in exactly the same manner as _setcliprgn, and then sets the view-coordinate origin to the upper-left corner of the region. The physical points (x1, y1) and (x2, y2) are the diagonally opposed corners of the rectangular clipping region. Any window transformation done with the _setwindow function applies only to the viewport and not to the entire screen. The default viewport is the entire screen.

Return Value

None. Use the _grstatus function to check for conditions of success or failure.

See Also

»_grstatus,« »_setcliprgn,« »_setvieworg,« »_setwindow«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SVIEWPRT.C: This program sets a viewport and then
 * draws a rectangle around it and an ellipse in it.
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

void main( void )
{
   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );

   _setviewport( 100, 100, 200, 200 );
   _rectangle( _GBORDER, 0, 0, 100, 100 );
   _ellipse( _GFILLINTERIOR, 10, 10, 90, 90 );

   _getch();
   _setvideomode( _DEFAULTMODE );
   exit( 0 );
}


Description: _setvisualpage
  _setvisualpage

#include <graph.h>

short __far _setvisualpage( short page );

page    Visual page number

Remarks

For hardware configurations that have enough memory to support multiple-screen pages, the _setvisualpage function selects the current visual page. The page argument specifies the current visual page. The default page number is 0.

This function works differently in QuickWin applications.

Return Value

The function returns the number of the previous visual page. If the function fails, it returns a negative value.

See Also

»_getactivepage,« »_getvisualpage,« »_setactivepage,« »_setvideomode«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getactivepage.«


Description: _setwindow
  _setwindow

#include <graph.h>

short __far _setwindow( short finvert, double wx1, double wy1, double wx2, double wy2 );

finvert    Invert flag

wx1, wy1    Upper-left corner of window

wx2, wy2    Lower-right corner of window

Remarks

The _setwindow function defines a window viewport. The arguments ( wx1, wy1) specify the upper-left corner of the window, and the arguments (wx2, wy2) specify the lower-right corner of the window. The finvert argument specifies the direction of the coordinates. If finvert is TRUE, the y axis increases from the screen bottom to the screen top (Cartesian coordinates). If finvert is FALSE, the y axis increases from the screen top to the screen bottom (screen coordinates). Any window transformation done with the _setwindow function applies only to the viewport and not to the entire screen. If wx1 equals wx2 or wy1 equals wy2, the function will fail.

Note that this function only affects output functions suffixed with _w or _wxy.

Return Value

The function returns a nonzero value if successful. If the function fails (e.g., if it is not in a graphics mode), it returns 0.

See Also

»_arc functions,« »_ellipse functions,« »_getwindowcoord,« »_lineto functions,« »_pie functions,« »_setviewport,« functions suffixed with _w or _wxy: »floodfill_w,« _»getcurrentposition_w,« »_getimage_w and _wxy,« »_getpixel_w,« »_getviewcoord_w and _wxy,« »_imagesize_w and _wxy,« »_moveto_w,« »_polygon_w and _wxy,« »_putimage_w,« »_rectangle_w and _wxy,« »_setpixel_w«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SWINDOW.C: This program illustrates translation
 * between window, view, and physical coordinates.
 * Functions used include:
 *     _setwindow        _getwindowcoord
 *     _getphyscoord     _getviewcoord_wxy
 */

#include <conio.h>
#include <stdlib.h>
#include <graph.h>

enum boolean { FALSE, TRUE };
enum display { MOVE, DRAW, ERASE };

void main( void )
{
   struct _xycoord view, phys;
   struct _wxycoord oldwin, newwin;
   struct _videoconfig vc;
   double xunit, yunit, xinc, yinc;
   short color, fintersect = FALSE, fdisplay = TRUE;
   int key;

   /* Find a valid graphics mode. */
   if( !_setvideomode( _MAXRESMODE ) )
      exit( 1 );
   _getvideoconfig( &vc );

   /* Set a window using real numbers. */
   _setwindow( FALSE, -125.0, -100.0, 125.0, 100.0 );
   /* Calculate the size of one pixel in window coordinates.
    * Then get the current window coordinates and color.
    */
   oldwin = _getwindowcoord( 1, 1 );
   newwin = _getwindowcoord( 2, 2 );
   xunit = xinc = newwin.wx - oldwin.wx;
   yunit = yinc = newwin.wy - oldwin.wy;
   newwin = oldwin = _getcurrentposition_w();
   color = _getcolor();

   while( 1 )
   {
      /* Set flag according to whether current pixel is on, then
       * turn pixel on.
       */
      if( _getpixel_w( oldwin.wx, oldwin.wy ) == color )
         fintersect = TRUE;
      else
         fintersect = FALSE;
      _setcolor( color );
      _setpixel_w( oldwin.wx, oldwin.wy );

      /* Get and test key. */
      key = _getch();
      switch( key )
      {
      case 27:                     /* ESC Quit */
         _setvideomode( _DEFAULTMODE );
         exit( 0 );
      case 32:                     /* SPACE Move no color   */
         fdisplay = MOVE;
         continue;
      case 0:                      /* Extended code - get next */
         key = _getch();
         switch( key )
         {
         case 72:                  /* UP       -y */
            newwin.wy -= yinc;
            break;
         case 77:                  /* RIGHT    +x */
            newwin.wx += xinc;
            break;
         case 80:                  /* DOWN     +y */
            newwin.wy += yinc;
            break;
         case 75:                  /* LEFT     -x */
            newwin.wx -= xinc;
            break;
         case 82:                  /* INS      Draw white */
            fdisplay = DRAW;
            continue;
         case 83:                  /* DEL      Draw black */
            fdisplay = ERASE;
            continue;
         }
         break;
      }

      /* Translate window coordinates to view, view to physical.
       * Then check physical to make sure we're on screen.
       * Update screen and position if we are. Ignore if not.
       */
      view = _getviewcoord_wxy( &newwin );
      phys = _getphyscoord( view.xcoord, view.ycoord );
      if( (phys.xcoord >= 0) && (phys.xcoord < vc.numxpixels) &&
          (phys.ycoord >= 0) && (phys.ycoord < vc.numypixels) )
      {
         /* If display on, draw to new position, else move to new. */
         if( fdisplay != MOVE )
         {
            if( fdisplay == ERASE )
               _setcolor( 0 );
            _lineto_w( newwin.wx, newwin.wy );
         }

         else
         {
            _setcolor( 0 );
            _moveto_w( newwin.wx, newwin.wy );
            /* If there was no intersect, erase old pixel. */
            if( !fintersect )
               _setpixel_w( oldwin.wx, oldwin.wy );
         }
         oldwin = newwin;
      }
      else
         newwin = oldwin;
   }
   exit( 0 );
}


Description: _setwritemode
  _setwritemode

#include <graph.h>

short __far _setwritemode( short action );

action    Interaction with existing screen image

Remarks

The _setwritemode function sets the current logical write mode, which is used when drawing lines with the _lineto, _polygon, and _rectangle functions. The action argument defines the write mode. The possible values are _GAND, _GOR, _GPRESET, _GPSET, and _GXOR. See the description of the »_putimage functions« for more details on these manifest constants.

Return Value

The _setwritemode function returns the previous write mode, or −1 if an error occurs.

See Also

»_getwritemode,« »_grstatus,« »_lineto functions,« »_polygon functions,« »_putimage functions,« »_rectangle functions,« »_setcolor,« »_setlinestyle«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_getwritemode.«


Description: signal
  signal

#include <signal.h>

void ( __cdecl *signal( int sig, void( __cdecl *func ) ( int sig [, int subcode ] ) ) ) ( int sig );

sig    Signal value

func    Function to be executed

subcode    Optional subcode to the signal number

Remarks

The signal function allows a process to choose one of several ways to handle an interrupt signal from the operating system. The signal function takes two arguments: sig and func.

The sig argument is the interrupt for which you want the signal function to respond; it must be one of the manifest constants (defined in SIGNAL.H) described in Table R.16.

Table R.16    Signals and Responses

Value	Mode	Meaning	Default Action
SIGABRT	Real	Abnormal termination	Terminates the calling program with exit code 3
SIGFPE	Real	Floating-point error	Terminates the calling program with exit code 3
SIGILL	Real	Illegal instruction	Terminates the calling program with exit code 3
SIGINT	Real	CTRL+C signal	Terminates the calling program with exit code 3
SIGSEGV	Real	Illegal storage access	Terminates the calling program with exit code 3
SIGTERM	Real	Termination request	Terminates the calling program with exit code 3
The func argument is either an address to s signal handler that you write or it is one of the manifest constants defined in SIGNAL.H, SIG_DFL or SIG_IGN.

If func is a function, it is installed as the signal handler for the given signal. The signal handler's prototype requires one formal argument, sig, of type int. The operating system provides the actual argument through sig when an interrupt occurs; the argument will be the signal that generated the interrupt. Thus, you can use the six manifest constants (SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, and SIGTERM) inside your signal handler to determine which interrupt occurred and take appropriate action. For example, you could call the signal function twice to assign the same handler to two different signals, then test the sig argument inside the handler to take different actions based on the signal received.

If you are testing for floating-point exceptions (SIGFPE), the function pointed to by func takes an optional second argument that is one of several manifest constants of the form FPE_xxx (defined in FLOAT.H). When a SIGFPE signal occurs, you can test the value of the second argument to determine the type of floating-point exception and then take appropriate action. This argument and its possible values are Microsoft extensions.

For floating-point exceptions, the value of func is not reset upon receiving the signal. To recover from floating-point exceptions, use setjmp in conjunction with longjmp. If the function returns, the calling process resumes execution with the floating-point state of the process left undefined.

If the signal handler returns, the calling process resumes execution immediately following the point at which it received the interrupt signal. This is true regardless of the type of signal or operating mode.

Before the specified function is executed under MS-DOS version 3.x or earlier, the value of func is set to SIG_DFL. The next interrupt signal is treated as described for SIG_DFL, unless an intervening call to signal specifies otherwise. This allows the user to reset signals in the called function if desired.

Because signal-handler routines are usually called asynchronously when an interrupt occurs, it is possible that your signal-handler function will get control when a run-time operation is incomplete and in an unknown state. There are certain restrictions as to which functions you can use in your signal-handler routine. The list below summarizes these restrictions:

•	Do not issue low-level or STDIO.H I/O routines (e.g., printf, fread).

•	Do not call heap routines or any routine that uses the heap routines (e.g., malloc, _freect, _strdup, _putenv). See »malloc« for more information.

•	Do not use any function that generates a system call (e.g., _getcwd, time).

•	Do not use the longjmp function unless the interrupt is caused by a floating-point exception (i.e., sig is SIGFPE). In this case, the program should first reinitialize the floating-point package by means of a call to _fpreset.

•	Do not use any overlay routines.

Under MS-DOS, a program must contain floating-point code if it is to trap the SIGFPE exception with the signal function. If your program does not have floating-point code and it requires the run-time library's signal-handling code, simply declare a volatile double and initialize it to zero:

volatile double d = 0.0f;

The SIGILL, SIGSEGV, and SIGTERM signals are not generated under MS-DOS. They are included for ANSI compatibility. Thus, you can set signal handlers for these signals via signal, and you can also explicitly generate these signals by calling raise.

Signal settings are not preserved in child processes created by calls to _exec or _spawn. The signal settings are reset to the default in the child process.

Return Value

The signal function returns the previous value of func associated with the given signal. For example, if the previous value of func was SIG_IGN, the return value will be SIG_IGN. A return value of SIG_ERR indicates an error, and errno is set to EINVAL.

See Also

»abort,« »_exec functions,« »exit,« »_exit,« »_fpreset,« »_spawn functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * SIGNAL.C illustrates setting up signal interrupt routines.
 * Functions illustrated include signal and raise.
 *
 * Because C I/O functions are not safe inside signal routines,
 * the code uses conditionals to use system-level MS-DOS
 * services. Another option is to set global flags and do any
 * I/O operations outside the signal handler.
 */

#include <stdio.h>
#include <conio.h>
#include <signal.h>
#include <process.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>

void ctrlchandler( int sig );         /* Prototypes */
void safeout( char *str );
int  safein( void );

void main( void )
{
   int ch;

   /* Install signal handler to modify CTRL+C behavior. */
   if( signal( SIGINT, ctrlchandler ) == SIG_ERR )
   {
      fprintf( stderr, "Couldn't set SIGINT\n" );
      abort();
   }

   /* Loop prints message to screen asking user to
    * enter Cntl+C--at which point the ctrlchandler
    * signal handler takes control.
    */
   do
   {
      printf( "Press Ctrl+C to enter handler.\n" );
   }
   while( ch = _getch());   /* Discard keystokes */
}

/* A signal handler must take a single argument. The argument can be
 * tested within the handler and thus allows a single signal handler
 * to handle several different signals. In this case, the parameter
 * is included to keep the compiler from generating a warning but is
 * ignored because this signal handler only handles one interrupt:
 * SIGINT (Ctrl+C).
 */
void ctrlchandler( int sig )
{
   int c;
   char str[] = " ";

   /* Disallow CTRL+C during handler. */
   signal( SIGINT, SIG_IGN );
   safeout( "User break - abort processing (y|n)? " );
   c = safein();
   str[0] = (char)c;
   safeout( str );
   safeout( "\r\n" );
   if( (c == 'y') || (c == 'Y') )
      abort();
   else
   {
      /* The CTRL+C interrupt must be reset to our handler because
       * by default it is reset to the system handler.
       */
      signal( SIGINT, ctrlchandler );
      safeout( "Press Ctrl+C to enter handler.\r\n" );
   }
}

/* Outputs a string using system level calls. */
void safeout( char *str )
{
   union _REGS inregs, outregs;

   inregs.h.ah = 0x0e;
   while( *str )
   {
      inregs.h.al = *str++;
      _int86( 0x10, &inregs, &outregs );
   }
}

/* Inputs a character using system level calls. */
int safein()
{
   return _bios_keybrd( _KEYBRD_READ ) & 0xff;
}

Output

Press Ctrl+C to enter handler.
^C
User break - abort processing (y|n)? y

abnormal program termination


Description: sin Functions
  sin Functions

#include <math.h>

double sin( double x );

double sinh( double x );

long double sinl( long double x );

long double sinhl( long double x );

x    Angle in radians

Remarks

The sin and sinh functions find the sine and hyperbolic sine of x, respectively. The sinl and sinhl functions are the 80-bit counterparts and use an 80-bit, 10-byte coprocessor form of arguments and return values. In Windows NT, since the 80-bit long double data type is synonymous with the 64-bit double data type, sinl is equivalent to sin, and sinhl is equivalent to sinh. See the reference page on the »long double functions« for more details on this data type.

Return Value

The sin functions return the sine of x. If x is greater than or equal to 2 raised to the power of 27, a partial loss of significance in the result may occur, and sin generates a _PLOSS error. If x is greater than or equal to 2 raised to the power of 31, significance is completely lost, and the sin function prints a _TLOSS message to stderr and returns 0. In both cases, errno is set to ERANGE.

The sinh function returns the hyperbolic sine of x. If the result is too large, sinh sets errno to ERANGE and returns ±HUGE_VAL (±_LHUGE_VAL for the long double functions). Error handling can be changed with the _matherr function.

See Also

»acos functions,« »asin functions,« »atan functions,« »cos functions,« »tan functions«

Compatibility

sin, sinh:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

sinl, sinhl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SINCOS.C: This program displays the sine, hyperbolic
 * sine, cosine, and hyperbolic cosine of pi / 2.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double pi = 3.1415926535;
   double x, y;

   x = pi / 2;
   y = sin( x );
   printf( "sin( %f ) = %f\n", x, y );
   y = sinh( x );
   printf( "sinh( %f ) = %f\n",x, y );
   y = cos( x );
   printf( "cos( %f ) = %f\n", x, y );
   y = cosh( x );
   printf( "cosh( %f ) = %f\n",x, y );
}

Output

sin( 1.570796 ) = 1.000000
sinh( 1.570796 ) = 2.301299
cos( 1.570796 ) = 0.000000
cosh( 1.570796 ) = 2.509178


Description: _sopen
  _sopen

#include <fcntl.h>

#include <sys\types.h>

#include <sys\stat.h>

#include <share.h>

#include <io.h>

int _sopen( const char *filename, int oflag, int shflag [, int pmode ] );

filename    Filename

oflag    Type of operations allowed

shflag    Type of sharing allowed

pmode    Permission setting

Remarks

The _sopen function opens the file specified by filename and prepares the file for subsequent shared reading or writing, as defined by oflag and shflag. The integer expression oflag is formed by combining one or more of the following manifest constants, defined in the file FCNTL.H. When two or more constants are used to form the argument oflag, the constants are combined with the bitwise-OR operator
( | ).

_O_APPEND    Repositions the file pointer to the end of the file before every write operation.

_O_BINARY    Opens file in binary (untranslated) mode. (See »fopen« for a description of binary mode.)

_O_CREAT    Creates and opens a new file. This has no effect if the file specified by filename exists.

_O_EXCL    Returns an error value if the file specified by filename exists. This applies only when used with _O_CREAT.

_O_RDONLY    Opens file for reading only. If this flag is given, neither the _O_RDWR flag nor the _O_WRONLY flag can be given.

_O_RDWR    Opens file for both reading and writing. If this flag is given, neither _O_RDONLY nor _O_WRONLY can be given.

_O_TEXT    Opens file in text (translated) mode. (See »fopen« for a description of text mode.)

_O_TRUNC    Opens and truncates an existing file to 0 bytes. The file must have write permission; the contents of the file are destroyed.

_O_WRONLY    Opens file for writing only. If this flag is given, neither _O_RDONLY nor _O_RDWR can be given.

The argument shflag is a constant expression consisting of one of the following manifest constants, defined in SHARE.H. If SHARE.COM (or SHARE.EXE for some versions of MS-DOS) is not installed, MS-DOS ignores the sharing mode. (See your system documentation for detailed information about sharing modes.) In Windows NT, the sharing mode is never ignored.

_SH_COMPAT (MS-DOS only)    Sets compatibility mode. This is the sharing mode used in the _open function in MS-DOS.

_SH_DENYRW    Denies read and write access to file.

_SH_DENYWR    Denies write access to file.

_SH_DENYRD    Denies read access to file.

_SH_DENYNO    Permits read and write access.

The _sopen function should be used only with Windows NT and MS-DOS version 3.0 and later. Under earlier versions of MS-DOS, the shflag argument is ignored.

The pmode argument is required only when _O_CREAT is specified. If the file does not exist, pmode specifies the file's permission settings, which are set when the new file is closed for the first time. Otherwise, the pmode argument is ignored. The pmode argument is an integer expression that contains one or both of the manifest constants _S_IWRITE and _S_IREAD, defined in SYS\STAT.H. When both constants are given, they are combined with the bitwise-OR operator ( | ). The meaning of the pmode argument is as follows:

_S_IWRITE    Writing permitted

_S_IREAD    Reading permitted

_S_IREAD | _S_IWRITE    Reading and writing permitted

If write permission is not given, the file is read-only. With MS-DOS, all files are readable; it is not possible to give write-only permission. Thus, the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent.

Note that with MS-DOS versions 3.x with SHARE installed, a problem occurs when opening a new file with _sopen under the following sets of conditions:

•	With oflag set to _O_CREAT | _O_RDONLY or _O_CREAT | _O_WRONLY, pmode set to _S_IREAD, and shflag set to _SH_COMPAT.

•	With oflag set to any combination that includes _O_CREAT | _O_RDWR, pmode set to _S_IREAD, and shflag set to anything other than _SH_COMPAT.

In either case, the operating system will prematurely close the file during system calls made within _sopen, or the system will generate a sharing violation (INT 24H). To avoid the problem, open the file with pmode set to _S_IWRITE. After closing the file, call _chmod and change the mode back to _S_IREAD. Another solution is to open the file with pmode set to _S_IREAD, oflag set to _O_CREAT | _O_RDWR, and shflag set to _SH_COMPAT.

The _sopen function applies the current file-permission mask to pmode before setting the permissions (see »_umask«).

Return Value

The _sopen function returns a file handle for the opened file. A return value of −1 indicates an error, and errno is set to one of the following values:

EACCES    Given path is a directory, or the file is read-only but an open for writing was attempted, or a sharing violation occurred (the file's sharing mode does not allow the specified operations; MS-DOS versions 3.0 and later only).

EEXIST    The _O_CREAT and _O_EXCL flags are specified, but the named file already exists.

EINVAL    An invalid oflag or shflag argument was given.

EMFILE    No more file handles available (too many open files).

ENOENT    File or path not found.

See Also

»_close,« »_creat,« »fopen,« »_fsopen,« »_open,« »_umask«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_locking.«


Description: _spawn Functions
  _spawn Functions

#include <stdio.h>

#include <process.h>

int _spawnl( int mode, const char *cmdname, const char *arg0, const char *arg1, ... const char *argn, NULL );

int _spawnle( int mode, const char *cmdname, const char *arg0, const char *arg1, ... const char *argn, NULL, const char * const *envp );

int _spawnlp( int mode, const char *cmdname, const char *arg0, const char *arg1, ... const char *argn, NULL );

int _spawnlpe( int mode, const char *cmdname, const char *arg0, const char *arg1, ... const char *argn, NULL, const char * const *envp );

int _spawnv( int mode, const char *cmdname, const char * const *argv );

int _spawnve( int mode, const char *cmdname, const char * const *argv, const char * const *envp );

int _spawnvp( int mode, const char *cmdname, const char * const *argv );

int _spawnvpe( int mode, const char *cmdname, const char * const *argv, const char * const *envp );

mode    Execution mode for parent process

cmdname    Path of file to be executed

arg0, ... argn    List of pointers to arguments

argv    Array of pointers to arguments

envp    Array of pointers to environment settings

Remarks

The _spawn family of functions creates and executes a new process. Enough memory must be available for loading and executing the new process. The mode argument determines the action taken by the calling process before and during _spawn. The following values for mode are defined in PROCESS.H:

_P_OVERLAY    Overlays calling process with new process, destroying the calling process (same effect as _exec calls).

_P_WAIT    Suspends calling process until execution of new process is complete (synchronous _spawn).

_P_NOWAIT or _P_NOWAITO    Continues to execute calling process concurrently with new process (asynchronous _spawn, valid only in Windows NT).

_P_DETACH    Continues to execute the calling process; new process is run in the background with no access to the console or keyboard. Calls to _cwait against the new process will fail. This is an asynchronous _spawn and is valid only in Windows NT.

The cmdname argument specifies the file that is executed as the new process and can specify a full path (from the root), a partial path (from the current working directory), or just a filename. If cmdname does not have a filename extension or does not end with a period (.), the _spawn function first tries the .COM extension, then the .EXE extension, then the .BAT extension, and finally the .CMD extension (in Windows NT only). This ability to spawn batch files is new beginning with Microsoft C version 6.0.

If cmdname has an extension, only that extension is used. If cmdname ends with a period, the _spawn calls search for cmdname with no extension. The _spawnlp, _spawnlpe, _spawnvp, and _spawnvpe routines search for cmdname (using the same procedures) in the directories specified by the PATH environment variable.

If cmdname contains a drive specifier or any slashes (that is, if it is a relative path), the _spawn call searches only for the specified file and no path searching is done.

Note  To ensure proper overlay initialization and termination, do not use the setjmp or longjmp function to enter or leave an overlay routine.

Arguments for the Child Process

Arguments are passed to the new process by giving one or more pointers to character strings as arguments in the _spawn call. These character strings form the argument list for the spawned process. The combined length of the strings forming the argument list for the new process must not exceed 128 bytes (in MS-DOS) or 1024 bytes (in Windows NT). The terminating null character ('\0') for each string is not included in the count, but space characters (automatically inserted to separate arguments) are included.

The argument pointers may be passed as separate arguments (_spawnl, _spawnle, _spawnlp, and _spawnlpe) or as an array of pointers (_spawnv, _spawnve, _spawnvp, and _spawnvpe). At least one argument, arg0 or argv[0], must be passed to the spawned process. By convention, this argument is the name of the program as it might be typed on the command line by the user. (A different value does not produce an error.) In real mode, the argv[0] value is supplied by the operating system and is the fully qualified path of the executing program. In protected mode, it is usually the program name as it would be typed on the command line.

The _spawnl, _spawnle, _spawnlp, and _spawnlpe calls are typically used in cases where the number of arguments is known in advance. The arg0 argument is usually a pointer to cmdname. The arguments arg1 through argn are pointers to the character strings forming the new argument list. Following argn, there must be a NULL pointer to mark the end of the argument list.

The _spawnv, _spawnve, _spawnvp, and _spawnvpe calls are useful when the number of arguments to the new process is variable. Pointers to the arguments are passed as an array, argv. The argument argv[0] is usually a pointer to a path in real mode or to the program name in protected mode, and argv[1] through argv[n] are pointers to the character strings forming the new argument list. The argument argv[n +1] must be a NULL pointer to mark the end of the argument list.

Environment of the Spawned Process

Files that are open when a _spawn call is made remain open in the new process. In the _spawnl, _spawnlp, _spawnv, and _spawnvp calls, the new process inherits the environment of the calling process. The _spawnle, _spawnlpe, _spawnve, and _spawnvpe calls make it possible for the user to alter the environment for the new process by passing a list of environment settings through the envp argument. The argument envp is an array of character pointers, each element of which (except for the final element) points to a null-terminated string defining an environment variable. Such a string usually has the form NAME=value where NAME is the name of an environment variable and value is the string value to which that variable is set. (Note that value is not enclosed in double quotation marks.) The final element of the envp array should be NULL. When envp itself is NULL, the spawned process inherits the environment settings of the parent process.

The _spawn functions can pass the new process all information about open files, including the translation mode, through the C_FILE_INFO entry in the environment that is passed in real mode. The startup code normally processes this entry and then deletes it from the environment. However, if a _spawn function spawns a non-C process, this entry remains in the environment. Printing the environment shows graphics characters in the definition string for this entry, because the environment information is passed in binary form in real mode. It should not have any other effect on normal operations. In protected mode, the environment information is passed in text form and therefore contains no graphics characters.

You must explicitly flush (using fflush or _flushall) or close any stream prior to the _spawn function call.

With this product, as well as with Microsoft C version 6.0 and Microsoft C/C++ version 7.0, you can control whether or not the open file information of a process is passed to its spawned processes. The external variable _fileinfo (declared in STDLIB.H) controls the passing of C_FILE_INFO information. If _fileinfo is 0, the C_FILE_INFO information is not passed to the new processes. If _fileinfo is not 0, C_FILE_INFO is passed to new processes. By default, _fileinfo is 0 and thus the C_FILE_INFO information is not passed to new processes. There are two ways to modify the default value of _fileinfo. You can link the supplied object file FILEINFO.OBJ into your program, using the /NOE option to avoid multiple symbol definitions, or you can set the _fileinfo variable to a nonzero value directly within your C program.

Return Value

The return value from a synchronous _spawn (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawn (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. The exit status can be set to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of −1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG    In MS-DOS, the argument list exceeds 128 bytes, or the space required for the environment information exceeds 32K. In Windows NT, the argument list exceeds 1024 bytes.

EINVAL     The mode argument is invalid.

ENOENT    The file or path is not found.

ENOEXEC    The specified file is not executable or has an invalid executable-file format.

ENOMEM    Not enough memory is available to execute the new process.

Note that signal settings are not preserved in new processes created by calls to _spawn routines. The signal settings are reset to the default in the spawned process.

See Also

»abort,« »atexit,« »_exec functions,« »exit,« »_exit,« »_flushall,« »_onexit,« »system«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of  the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;
   switch (argv[1][0])   /* Based on first letter of argument */

   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}


Description: _splitpath
  _splitpath

#include <stdlib.h>

void _splitpath( const char *path, char *drive, char *dir, char *fname, char *ext );

path    Full path

drive    Drive letter

dir    Directory path

fname    Filename

ext    File extension

Remarks

The _splitpath routine breaks a full path into its four components. The path argument should point to a buffer containing the complete path. The maximum size necessary for each buffer is specified by the manifest constants _MAX_DRIVE, _MAX_DIR, _MAX_FNAME, and _MAX_EXT, defined in STDLIB.H. The other arguments point to the buffers used to store the path elements:

drive    Contains the drive letter followed by a colon (:) if a drive is specified
in path.

dir    Contains the path of subdirectories, if any, including the trailing slash. Forward slashes ( / ), backslashes ( \ ), or both may be present in path.

fname    Contains the base filename without any extensions.

ext    Contains the filename extension, if any, including the leading period (.).

The return parameters will contain empty strings for any path components not found in path. You can pass a NULL pointer to _splitpath for any component you don't wish to receive.

Return Value

None.

See Also

»_fullpath,« »_makepath«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_makepath.«


Description: sprintf, _snprintf, _snwprintf, swprintf
  sprintf, _snprintf, _snwprintf, swprintf

#include <stdio.h>    For sprintf and _snprintf

#include <wchar.h>    For swprintf and _snwprintf use either WCHAR.H (for ANSI compatibility) or STDIO.H

int sprintf( char *buffer, const char *format [, argument] ... );

int _snprintf( char *buffer, size_t count, const char *format [, argument] ... );

int _snwprintf( wchar_t *buffer, size_t count, const wchar_t *format [, argument] ... );

int swprintf( wchar_t *buffer, const wchar_t *format [, argument] ... );

argument    Optional arguments

buffer    Storage location for output

count    Maximum number of characters to store

format    Format-control string

Remarks

The sprintf function formats and stores a series of characters and values in buffer. Each argument (if any) is converted and output according to the corresponding format specification in format. The format consists of ordinary characters and has the same form and function as the format argument for the printf function. (See »printf« for a description of the format and arguments.) A null character is appended after the last character written. If copying occurs between strings that overlap, the behavior is undefined.

The _snprintf function differs from sprintf in that _snprintf writes no more than count characters to buffer, including a terminating null character, which is always appended unless count is zero.

The swprintf function is a wide-character version of sprintf; the pointer arguments to swprintf are wide-character strings. The detection of encoding errors in swprintf may differ from that in sprintf. The swprintf and fwprintf functions behave identically except that swprintf writes output to a string rather than to a destination of type FILE.

The _snwprintf function differs from swprintf in that no more than count wide characters are written to buffer, including a terminating null wide character, which is always appended unless count is zero.

Return Value

The sprintf and _snprintf functions return the number of bytes stored in buffer, not counting the terminating null character. For _snprintf, if the number of bytes required to store the data exceeds count, then count bytes of data are stored in buffer and a negative value is returned. The swprintf and _snwprintf functions return the number of wide characters stored in buffer, not counting the terminating null wide character. For _snwprintf, if the storage required to store the data exceeds count wide characters, then count wide characters are stored in buffer and a negative value is returned.

See Also

»fprintf,« »fwprintf,« »fwscanf,« »printf,« »scanf,« »sscanf,« »swscanf,« »vfprintf,« »vfwprint,« »vprintf,« »vsprintf,« »vswprintf,« »vwprintf,« »wprintf«

Compatibility

sprintf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_snprintf, _snwprintf:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

swprintf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SPRINTF.C: This program uses sprintf to format various
 * data and place them in the string named buffer.
 */

#include <stdio.h>

void main( void )
{
   char  buffer[200], s[] = "computer", c = 'l';
   int   i = 35, j;
   float fp = 1.7320534f;

   /* Format and print various data: */
   j  = sprintf( buffer,     "\tString:    %s\n", s );
   j += sprintf( buffer + j, "\tCharacter: %c\n", c );
   j += sprintf( buffer + j, "\tInteger:   %d\n", i );
   j += sprintf( buffer + j, "\tReal:      %f\n", fp );

   printf( "Output:\n%s\ncharacter count = %d\n", buffer, j );
}

Output

Output:
   String:    computer
   Character: l
   Integer:   35
   Real:      1.732053

character count = 71


Description: sqrt, sqrtl
  sqrt, sqrtl

#include <math.h>

double sqrt( double x );

long double sqrtl( long double x );

x    Nonnegative floating-point value

Remarks

The sqrt functions calculate the square root of x. The sqrtl function is the 80-bit counterpart and uses an 80-bit, 10-byte coprocessor form of arguments and return values. In Windows NT, since the 80-bit long double data type is synonymous with the 64-bit double data type, sqrtl is equivalent to sqrt.

Return Value

The sqrt functions return the square-root result. If x is negative, the function prints a _DOMAIN error message to stderr, sets errno to EDOM, and returns 0. Error handling can be modified by using the _matherr or _matherrl routine.

See Also

»exp,« »log,« »_matherr,« »pow«

Compatibility

sqrt:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

sqrtl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SQRT.C: This program calculates a square root. */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   double question = 45.35, answer;

   answer = sqrt( question );
   if( errno == EDOM )
      printf( "Domain error\n" );
   else
      printf( "The square root of %.2f is %.2f\n", question, answer );
}

Output

The square root of 45.35 is 6.73


Description: srand
  srand

#include <stdlib.h>

void srand( unsigned int seed );

seed    Seed for random-number generation

Remarks

The srand function sets the starting point for generating a series of pseudorandom integers. To reinitialize the generator, use 1 as the seed argument. Any other value for seed sets the generator to a random starting point. The rand function is used to retrieve the pseudorandom numbers that are generated. Calling rand before any call to srand will generate the same sequence as calling srand with seed passed as 1.

Return Value

None.

See Also

»rand«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »rand.«


Description: sscanf, swscanf
  sscanf, swscanf

#include <stdio.h>    For sscanf

#include <wchar.h>    For swscanf use either WCHAR.H (for ANSI compatibility) or STDIO.H

int sscanf( const char *buffer, const char *format [, argument ] ... );

int swscanf( const wchar_t *buffer, const wchar_t *format [, argument ] ... );

buffer    Stored data

format    Format-control string

argument    Optional arguments

Remarks

The sscanf function reads data from buffer into the locations given by each argument. Every argument must be a pointer to a variable with a type that corresponds to a type specifier in format. The format argument controls the interpretation of the input fields and has the same form and function as the format argument for the scanf function; see »scanf« for a complete description of format. If copying takes place between strings that overlap, the behavior is undefined.

The swscanf function is a wide-character version of sscanf; the arguments to swscanf are wide-character strings. The swscanf and sscanf functions behave identically otherwise.

Return Value

Each of these functions returns the number of fields successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. The return value is EOF for an error or if the end of the string is reached before the first conversion.

See Also

»fscanf,« »fwscanf,« »scanf,« »sprintf,« »swprintf,« »wscanf«

Compatibility

sscanf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

swscanf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SSCANF.C: This program uses sscanf to read data items
 * from a string named tokenstring, then displays them.
 */

#include <stdio.h>

void main( void )
{
   char  tokenstring[] = "15 12 14...";
   char  s[81];
   char  c;
   int   i;
   float fp;

   /* Input various data from tokenstring: */
   sscanf( tokenstring, "%s", s );
   sscanf( tokenstring, "%c", &c );
   sscanf( tokenstring, "%d", &i );
   sscanf( tokenstring, "%f", &fp );

   /* Output the data read */
   printf( "String    = %s\n", s );
   printf( "Character = %c\n", c );
   printf( "Integer:  = %d\n", i );
   printf( "Real:     = %f\n", fp );
}

Output

String    = 15
Character = 1
Integer:  = 15
Real:     = 15.000000


Description: _stackavail
  _stackavail

#include <malloc.h>

size_t _stackavail( void );

Remarks

The _stackavail function returns the approximate size (in bytes) of the stack space available for dynamic memory allocation with _alloca.

Return Value

The _stackavail function returns the size in bytes as an unsigned integer value.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_alloca.«


Description: _stat
  _stat

#include <sys\types.h>

#include <sys\stat.h>

int _stat( const char *pathname, struct _stat *buffer );

path    Path of existing file

buffer    Pointer to structure that receives results

Remarks

The _stat function obtains information about the file or directory specified by path and stores it in the structure pointed to by buffer. The _stat structure, defined in the file SYS\STAT.H, includes the following fields:

st_atime    Time of last access of file.

st_ctime    Time of creation of file.

st_dev    Drive number of the disk containing the file (same as st_rdev), for 16-bit libraries only.

st_mode    Bit mask for file-mode information. The _S_IFDIR bit is set if pathname specifies a directory; the _S_IFREG bit is set if path specifies an ordinary file or a device. User read/write bits are set according to the file's permission mode; user execute bits are set according to the filename extension.

st_mtime    Time of last modification of file.

st_nlink    Always 1.

st_rdev    Drive number of the disk containing the file (same as st_dev), for 16-bit libraries only.

st_size    Size of the file in bytes.

Note that if path refers to a device, the size, time, _dev, and _rdev fields in the _stat structure are meaningless. Also, as STAT.H uses the _dev_t type, which is defined in TYPES.H, you must include TYPES.H before STAT.H in your code.

Return Value

The _stat function returns 0 if the file-status information is obtained. A return value of −1 indicates an error; also, errno is set to ENOENT, indicating that the filename or path could not be found.

See Also

»_access,« »_fstat«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _stat for compatibility with ANSI naming conventions of non-ANSI functions. Use stat and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* STAT.C: This program uses the _stat function to
 * report information about the file named STAT.C.
 */

#include <time.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <stdio.h>

void main( void )
{
   struct _stat buf;
   int result;
   char buffer[] = "A line to output";

   /* Get data associated with "stat.c": */
   result = _stat( "stat.c", &buf );

   /* Check if statistics are valid: */
   if( result != 0 )
      perror( "Problem getting information" );
   else
   {
      /* Output some of the statistics: */
      printf( "File size     : %ld\n", buf.st_size );
      printf( "Drive         : %c:\n", buf.st_dev + 'A' );
      printf( "Time modified : %s", ctime( &buf.st_atime ) );
   }
}

Output

File size     : 759
Drive         : C:
Time modified : Fri Mar 19 14:41:56 1993


Description: _status87, _statusfp
  _status87, _statusfp

#include <float.h>

unsigned int _status87( void );

unsigned int _statusfp( void );

Remarks

The _status87 function gets the floating-point status word. The status word is a combination of the 8087/80287/80387 status word and other conditions detected by the 8087/80287/80387 exception handler, such as floating-point stack overflow and underflow. Unmasked exceptions are checked for before returning the contents of the status word. This means that the caller will be informed of any pending exceptions.

The _statusfp function is a platform independent, portable version of the _status87 routine. It is identical to the _status87 function on Intel (x86) platforms and is also supported by the MIPS platform. If you want to ensure that your floating-point code is portable to MIPS, you should use the _status87 function. If you are only targeting x86 platforms, you can use either _status87 or _statusfp.

Return Value

The bits in the value returned indicate the floating-point status. See the FLOAT.H include file for a complete definition of the bits returned by _status87.

Note that many of the math library functions modify the 8087/80287 status word, with unpredictable results. Return values from _clear87 and _status87 become more reliable as fewer floating-point operations are performed between known states of the floating-point status word.

See Also

»_clear87,« »_clearfp,« »_control87,« »_controlfp«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STATUS87.C: This program creates various floating-point errors and
 * then uses _status87 to display messages indicating these problems.
 * Compile this program with optimizations disabled (/Od). Otherwise,
 * the optimizer removes the code related to the unused floating-
 * point values.
 */

#include <stdio.h>
#include <float.h>

void main( void )
{
   double a = 1e-40, b;
   float  x, y;

   printf( "Status = %.4x - clear\n",_status87() );

   /* Assignment into y is inexact & underflows: */
   y = a;
   printf( "Status = %.4x - inexact, underflow\n", _status87() );

   /* y is denormal: */
   b = y;
   printf( "Status = %.4x - inexact underflow, denormal\n",
           _status87() );

   /* Clear user 8087: */
   _clear87();
}

Output

Status = 0000 - clear
Status = 0003 - inexact, underflow
Status = 80003 - inexact underflow, denormal


Description: strcat, wcscat, _fstrcat
  strcat, wcscat, _fstrcat

#include <string.h>    Required only for strcat and _fstrcat

#include <wchar.h>    For wcscat use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strcat( char *string1, const char *string2 );

wchar_t *wcscat( wchar_t *string1, const wchar_t *string2 );

char __far * __far _fstrcat( char __far *string1, const char __far * string2 );

string1    Null-terminated destination string

string2    Null-terminated source string

Remarks

The strcat function appends string2 to string1 and terminates the resulting string with a null character ('\0'). Each of the arguments to strcat is expected to be null-terminated. The initial character of string2 overwrites the terminating null character of string1. No overflow checking is performed when strings are copied or appended. The behavior of strcpy is undefined if the source and destination strings overlap.

The wcscat function is a wide-character version of strcat; the arguments of wcscat are wide-character strings. The wcscat and strcat functions behave identically otherwise.

The _fstrcat function is a 16-bit model-independent (large-model) version of the strcat function. The arguments and return value of _fstrcat are far pointers. The _fstrcat and strcat functions behave identically otherwise.

Return Value

Each of these functions returns the destination string (string1). No return value is reserved to indicate an error.

See Also

»strncat,« »strncmp,« »strncpy,« »_strnicmp,« »strrchr,« »strspn«

Compatibility

strcat:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcscat:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrcat:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »strcpy.«


Description: strchr, wcschr, _fstrchr
  strchr, wcschr, _fstrchr

#include <string.h>    For strchr and _fstrchr

#include <wchar.h>    For wcschr use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strchr( const char *string, int c );

wchar_t *wcschr( const wchar_t *string, wint_t c );

char __far * __far _fstrchr( const char __far *string, int c );

string    Null-terminated source string

c    Character to be located

Remarks

The strchr function returns a pointer to the first occurrence of c (converted to a variable of type char) in string, or it returns NULL if c is not found. The string argument to strchr is expected to contain a null character ('\0') marking the end of the string. The converted character c may be the null character, which is included in the search.

The wcschr function is a wide-character version of strchr; the string argument and return value of wcschr are wide-character pointers. The wcschr and strchr functions behave identically otherwise.

The _fstrchr function is a 16-bit model-independent (large-model) version of the strchr function. The arguments and return value of _fstrchr are far pointers. The _fstrchr and strchr functions behave identically otherwise.

Return Value

The return values for these functions are described above.

See Also

»strcspn,« »strncat,« »strncmp,« »strncpy,« »_strnicmp,« »strpbrk,« »strrchr,« »strspn,« »strstr«

Compatibility

strchr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcschr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrchr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRCHR.C: This program illustrates searching for a character
 * with strchr (search forward) or strrchr (search backward).
 */

#include <string.h>
#include <stdio.h>

int  ch = 'r';

char string[] = "The quick brown dog jumps over the lazy fox";
char fmt1[] =   "         1         2         3         4         5";
char fmt2[] =   "12345678901234567890123456789012345678901234567890";

void main( void )
{
   char *pdest;
   int result;

   printf( "String to be searched: \n\t\t%s\n", string );
   printf( "\t\t%s\n\t\t%s\n\n", fmt1, fmt2 );
   printf( "Search char:\t%c\n", ch );

   /* Search forward. */
   pdest = strchr( string, ch );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "Result:\tfirst %c found at position %d\n\n",
              ch, result );
   else
      printf( "Result:\t%c not found\n" );

   /* Search backward. */
   pdest = strrchr( string, ch );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "Result:\tlast %c found at position %d\n\n", ch, result );
   else
      printf( "Result:\t%c not found\n" );
}

Output

String to be searched:
      The quick brown dog jumps over the lazy fox
               1         2         3         4         5
      12345678901234567890123456789012345678901234567890

Search char:   r
Result:   first r found at position 12

Result:   last r found at position 30


Description: strcmp, wcscmp, _fstrcmp
  strcmp, wcscmp, _fstrcmp

#include <string.h>    For strcmp and _fstrcmp

#include <wchar.h>    For wcscmp use either WCHAR.H (for ANSI compatibility) or STRING.H

int strcmp( const char *string1, const char *string2 );

int wcscmp( const wchar_t *string1, const wchar_t *string2 );

int __far _fstrcmp( const char __far *string1, const char __far *string2 );

string1    Null-terminated string to compare

string2    Null-terminated string to compare

Remarks

The strcmp function compares string1 and string2 lexicographically and returns a value indicating their relationship. Each of the arguments to strcmp is expected to contain a null character ('\0') marking the end of the string. The strcmp function differs from strcoll in that the strcmp comparison is not affected by locale, whereas the manner of comparison performed by the strcoll function is determined by the LC_COLLATE category of the current locale. For more information on the LC_COLLATE category, see the »setlocale« function.

In the "C" locale, the order of the characters in the character set (that is, in the ASCII character set) is the same as the lexicographic order of the characters. However, in other locales, the order of characters in the character set may differ from the lexicographic character order. For example, in certain European locales, the character 'a' (value 0x61) precedes the character 'ä' (value 0xE4) in the character set, but the character 'ä' precedes the character 'a' lexicographically.

In locales for which the character set and the lexicographic character order differ, strcoll rather than strcmp should be used for lexicographic comparison of strings according to the LC_COLLATE category setting of the current locale. Thus in the above example, strcoll rather than strcmp should be used for a lexicographic comparison, as strcoll would sort a string beginning with the character 'ä' before a string beginning with the character 'a'. Alternatively, using strxfrm on the original strings to be compared, and then using strcmp on the resulting strings, would also yield the appropriate lexicographic sort.

The wcscmp function is a wide-character version of strcmp; the arguments of wcscmp are wide-character strings. The wcscmp and strcmp functions behave identically otherwise.

The _fstrcmp function is a 16-bit model-independent (large-model) version of the strcmp function. The arguments of _fstrcmp are far pointers. The _fstrcmp and strcmp functions behave identically otherwise.

The »_stricmp,« »fstricmp,« »_wcsicmp,« and the »_strcmpi« functions compare strings by first converting them to their lowercase forms.

Note that two strings containing characters located between 'Z' and 'a' in the ASCII table ('[', '\', ']', '^', '_', and '`') compare differently depending on their case. For example, the two strings, "ABCDE" and "ABCD^", compare one way if the comparison is lowercase ("abcde" > "abcd^") and compare the other way ("ABCDE" < "ABCD^") if it is uppercase.

These functions are not affected by the current locale setting.

Return Value

The return value for each of these functions indicates the lexicographic relation of string1 to string2, as follows:

value < 0    string1 less than string2

value = 0    string1 identical to string2

value > 0    string1 greater than string2

See Also

»memcmp,« »_memicmp,« »strcoll,« »strncmp,« »_strnicmp,« »strrchr,« »strspn,« »strxfrm«

Compatibility

strcmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcscmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrcmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRCMP.C */

#include <string.h>
#include <stdio.h>

char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown dog jumps over the lazy fox";

void main( void )
{
   char tmp[20];
   int result;

   /* Case sensitive */
   printf( "Compare strings:\n\t%s\n\t%s\n\n", string1, string2 );
   result = strcmp( string1, string2 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "\tstrcmp:   String 1 is %s string 2\n", tmp );

   /* Case insensitive (could use equivalent _stricmp) */
   result = _stricmp( string1, string2 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "\t_stricmp:  String 1 is %s string 2\n", tmp );
}

Output

Compare strings:
   The quick brown dog jumps over the lazy fox
   The QUICK brown dog jumps over the lazy fox

   strcmp:   String 1 is greater than string 2
   _stricmp:  String 1 is equal to string 2


Description: strcoll, wcscoll,_stricoll, _wcsicoll
  strcoll, wcscoll, _stricoll, _wcsicoll

#include <string.h>    For strcoll and _stricoll

#include <wchar.h>    For wcscoll and _wcsicoll use either WCHAR.H (for ANSI compatibility) or STRING.H

int strcoll( const char *string1, const char *string2 );

int wcscoll( const wchar_t *string1, const wchar_t *string2 );

int stricoll( const char *string1, const char *string2 );

int _wcsicoll( const wchar_t *string1, const wchar_t *string2 );

string1, string2    Null-terminated strings to compare

Remarks

The strcoll function compares null-terminated strings string1 and string2 in a manner determined by the LC_COLLATE category of the current locale. Each of the string arguments to strcoll is expected to contain a null character ('\0') marking the end of the string. The strcoll function differs from the strcmp function in that strcoll uses locale-specific information that provides collating sequences. For more information on the LC_COLLATE category, see the »setlocale« function.

In the "C" locale, the order of the characters in the character set (that is, in the ASCII character set) is the same as the lexicographic order of the characters. However, in other locales, the order of characters in the character set may differ from the lexicographic character order. For example, in certain European locales, the character 'a' (value 0x61) precedes the character 'ä' (value 0xE4) in the character set, but the character 'ä' precedes the character 'a' lexicographically.

In locales for which the character set and the lexicographic character order differ, strcoll rather than strcmp should be used for lexicographic comparison of strings according to the LC_COLLATE category setting of the current locale. Thus in the above example, strcoll rather than strcmp should be used for a lexicographic comparison, as strcoll would sort a string beginning with the character 'ä' before a string beginning with the character 'a'. Alternatively, using strxfrm on the original strings to be compared, and then using strcmp on the resulting strings, would also yield the appropriate lexicographic sort.

The wcscoll function is a wide-character version of strcoll. The _stricoll function is a case-insensitive version of strcoll. The _wcsicoll function is a wide-character version of _stricoll.

Return Value

Each of these functions returns a value indicating the relationship of string1 to string2, as follows:

value < 0    string1 less than string2

value = 0    string1 identical to string2

value > 0    string1 greater than string2

The wcscoll function may fail if either of its arguments, string1 or string2, contains wide character codes outside the domain of the collating sequence. On error, wcscoll may set errno to [EINVAL], but no return value is reserved to indicate an error. Because of this, an application wishing to check for an error on a call to wcscoll should set errno to 0, then call wcscoll, then check errno.

See Also

»localeconv,« »setlocale,« »strcmp,« »strncmp,« »strxfrm«

Compatibility

strcoll:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_stricoll:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcscoll, _wcsicoll:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: strcpy, wcscpy, _fstrcpy
  strcpy, wcscpy, _fstrcpy

#include <string.h>    For strcpy and _fstrcpy

#include <wchar.h>    For wcscpy use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strcpy( char *string1, const char *string2 );

wchar_t *wcscpy( wchar_t *string1, const wchar_t *string2 );

char __far * __far _fstrcpy( char __far *string1, const char __far * string2 );

string1    Destination string

string2    Null-terminated source string

Remarks

The strcpy function copies string2, including the terminating null character ('\0'), to the location specified by string1. No overflow checking is performed when strings are copied or appended. The behavior of strcpy is undefined if the source and destination strings overlap.

The wcscpy function is a wide-character version of strcpy; the arguments and return value of wcschr are wide-character strings. The wcscpy and strcpy functions behave identically otherwise.

The _fstrcpy function is a 16-bit model-independent (large-model) version of the strcpy function. The arguments to _fstrcpy are far pointers. The _fstrcpy and strcpy functions behave identically otherwise.

Return Value

Each of these functions returns the destination string. No return value is reserved to indicate an error.

See Also

»strcat,« »strcmp,« »strncat,« »strncmp,« »strncpy,« »_strnicmp,« »strrchr,« »strspn«

Compatibility

strcpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcscpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrcpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRCPY.C: This program uses strcpy
 * and strcat to build a phrase.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[80];

   strcpy( string, "Hello world from " );
   strcat( string, "strcpy " );
   strcat( string, "and " );
   strcat( string, "strcat!" );
   printf( "String = %s\n", string );
}

Output

String = Hello world from strcpy and strcat!


Description: strcspn, wcscspn, _fstrcspn
  strcspn, wcscspn, _fstrcspn

#include <string.h>    For strcspn and _fstrcspn

#include <wchar.h>    For wcscspn use either WCHAR.H (for ANSI compatibility) or STRING.H

size_t strcspn( const char *string1, const char *string2 );

size_t wcscspn( const wchar_t *string1, const wchar_t *string2 );

size_t __far _fstrcspn( const char __far *string1, const char __far * string2 );

string1    Null-terminated searched string

string2    Null-terminated character set

Remarks

The strcspn function returns the index of the first character in string1 that belongs to the set of characters in string2. The index value is equivalent to the length of the initial segment of string1 that consists entirely of characters not in string2. If string1 begins with a character that is in string2, strcspn returns 0. Each string argument to the strcspn function is expected to contain a null character ('\0') marking the end of the string. Terminating null characters are not included in the search.

The wcscspn function is a wide-character version of strcspn; the arguments of wcscspn are wide-character strings.The wcscspn and strcspn functions behave identically otherwise.

The _fstrcspn function is a 16-bit model-independent (large-model) version of the strcspn function. The arguments and return value of _fstrcspn are far pointers. The _fstrcspn and strcspn functions behave identically otherwise.

Return Value

The return value for each of these functions is the index of the first character in string1 that belongs to the set of characters in string2. No return value is reserved to indicate an error.

See Also

»strncat,« »strncmp,« »strncpy,« »_strnicmp,« »strrchr,« »strspn«

Compatibility

strcspn:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcscspn:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrcspn:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRCSPN.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[] = "xyzabc";
   int  pos;

   pos = strcspn( string, "abc" );
   printf( "First a, b or c in %s is at character %d\n",
           string, pos );
}

Output

First a, b or c in xyzabc is at character 3


Description: _strdate
  _strdate

#include <time.h>

char *_strdate( char *datestr );

datestr    Current date

Remarks

The _strdate function copies the date to the buffer pointed to by datestr, formatted mm/dd/yy where mm is two digits representing the month, dd is two digits representing the day of the month, and yy is the last two digits of the year. For example, the string 12/05/99 represents December 5, 1999. The buffer must be at least nine bytes long.

Return Value

The _strdate function returns a pointer to the resulting text string datestr.

See Also

»asctime,« »ctime,« »gmtime,« »localtime,« »mktime,« »time,« »_tzset«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_strtime.«


Description: _strdup Functions
  _strdup, _nstrdup, _wcsdup, _fstrdup

#include <string.h>    For _strdup, _nstrdup, and _fstrdup

#include <wchar.h>    For _wcsdup use either WCHAR.H (for ANSI compatibility) or STRING.H

char *_strdup( const char *string );

char __near * __far _nstrdup( const char __far *string );

wchar_t * _wcsdup( const wchar_t *string );

char __far * __far _fstrdup( const char __far *string );

string    Null-terminated source string

Remarks

The _strdup function calls malloc to allocate storage space for a copy of string and then copies string to the allocated space. A null character ('\0') must mark the end of string. The space for the copy of string is allocated from the heap specified by the memory model in use. In large data models (that is, compact-, large-, and huge-model 16-bit programs), _strdup allocates space from the far heap. In small data models (tiny-, small-, and medium-model programs), _strdup allocates space from the near heap.

The _wcsdup function is a wide-character version of _strdup; the string argument and return value of _wcsdup are wide-character pointers. The _wcsdup and _strdup functions behave identically otherwise.

The _fstrdup and _nstrdup functions are 16-bit model-independent versions of the _strdup function. These functions provide control over the heap used for string duplication. The argument and return value of _fstrdup are far pointers; the argument and return value of _nstrdup are far pointers. Otherwise, the _fstrchr and _nstrdup functions behave identically to _strdup.

Return Value

The _strdup function returns a pointer to the storage location for the copied string or NULL if storage cannot be allocated. The _fstrdup function returns a far pointer to a copy of the string allocated in far memory (the far heap). The _nstrdup function returns a near pointer to a copy of the string allocated in the near heap (in the default data segment).

See Also

»memset,« »strcat,« »strcmp,« »strncat,« »strncmp,« »strncpy,« »_strnicmp,« »strrchr,« »strspn«

Compatibility

_strdup:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_wcsdup:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrdup, _nstrdup:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRDUP.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char buffer[] = "This is the buffer text";
   char *newstring;

   printf( "Original: %s\n", buffer );
   newstring = _strdup( buffer );
   printf( "Copy:     %s\n", newstring );
}

Output

Original: This is the buffer text
Copy:     This is the buffer text


Description: strerror, _strerror
  strerror, _strerror

#include <string.h>

char *strerror( int errnum );

char *_strerror( const char *string );

errnum    Error number

string    User-supplied message

Remarks

The strerror function maps errnum to an error-message string, returning a pointer to the string. The function itself does not actually print the message; for that, you need to call an output function such as »fprintf:«

if (( _access( "datafile",2 )) == -1 )
   fprintf( stderr, strerror(NULL) );

If string is passed as NULL, _strerror returns a pointer to a string containing the system error message for the last library call that produced an error. The error-message string is terminated by the newline character ('\n'). If string is not equal to NULL, then _strerror returns a pointer to a string containing (in order) your string message, a colon, a space, the system error message for the last library call producing an error, and a newline character. Your string message can be a maximum of 94 bytes long.

Unlike perror, _strerror alone does not print any messages. To print the message returned by _strerror to stderr, your program will need an fprintf statement, as shown in the following lines:

if (( _access( "datafile",2 )) == -1 )
   fprintf( stderr, _strerror(NULL) );

The actual error number for _strerror is stored in the variable errno. The system error messages are accessed through the variable _sys_errlist, which is an array of messages ordered by error number. The _strerror function accesses the appropriate error message by using the errno value as an index to the variable _sys_errlist. The value of the variable _sys_nerr is defined as the maximum number of elements in the _sys_errlist array. To produce accurate results, _strerror should be called immediately after a library routine returns with an error. Otherwise, the errno value may be overwritten by subsequent calls.

Note that the _strerror function under Microsoft C version 5.0 is identical to the version 4.0 strerror function. The name was altered to permit the inclusion in Microsoft C version 5.0 of the ANSI-conforming strerror function. The _strerror function is not part of the ANSI definition but is instead a Microsoft extension to it; it should not be used where portability is desired. For ANSI compatibility, use strerror instead.

Return Value

The strerror and _strerror functions return a pointer to the error-message string. The string can be overwritten by subsequent calls to strerror or _strerror, respectively.

See Also

»clearerr,« »ferror,« »perror«

Compatibility

strerror:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_strerror:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »perror.«


Description: strftime, wcsftime
  strftime, wcsftime

#include <time.h>    For strftime

#include <wchar.h>    For wcsftime use either WCHAR.H (for ANSI compatibility) or TIME.H

size_t strftime( char *string, size_t maxsize, const char *format, const struct tm *timeptr );

size_t wcsftime( wchar_t *string, size_t maxsize, const char *format, const struct tm *timeptr );

string    Output string

maxsize    Maximum length of string

format    Format control string

timeptr    tm data structure

Remarks

The strftime and wcsftime functions format the tm time value in timeptr according to the supplied format argument and store the result in the buffer string. At most, maxsize characters are placed in the string. The wcsftime function is equivalent to the strftime function, except that the string argument points to a wide character string.

The format argument consists of one or more codes; as in printf, the formatting codes are preceded by a % sign. Characters that do not begin with a % sign are copied unchanged to string. The LC_TIME category of the current locale affects the output formatting of strftime. The formatting codes for strftime are listed below:

%a    Abbreviated weekday name

%A    Full weekday name

%b    Abbreviated month name

%B    Full month name

%c    Date and time representation appropriate for the locale

%d    Day of the month as a decimal number (01−31)

%H    Hour in 24-hour format (00−23)

%I    Hour in 12-hour format (01−12)

%j    Day of the year as a decimal number (001−366)

%m    Month as a decimal number (01−12)

%M    Minute as a decimal number (00−59)

%p    Current locale's AM/PM indicator for a 12-hour clock

%S    Second as a decimal number (00−59)

%U    Week of the year as a decimal number, with Sunday as the first day of the week (00−51)

%w    Weekday as a decimal number (0−6; Sunday is 0)

%W    Week of the year as a decimal number, with Monday as the first day of the week (00−51)

%x    Date representation for current locale

%X    Time representation for current locale

%y    Year without the century as a decimal number (00−99)

%Y    Year with the century as a decimal number

%z, %Z    Time zone name or abbreviation; no characters if time zone is unknown

%%    Percent sign

As in the printf function, the # flag may prefix any formatting code. In that case, the meaning of the format code is changed as follows:

Format Code	Meaning
%#a, %#A, %#b, %#B, %#p, %#X, %#z, %#Z, %#%	The # flag is ignored
%#c	The long date and time representation, appropriate for the current locale. For example: "Tuesday, March 16, 1993, 12:41:29"
%#x	The long date representation, appropriate to the current locale. For example: "Tuesday, March 16, 1993"
%#d, %#H, %#I, %#j, %#m, %#M, %#S, %#U, %#w, %#W, %#y, %#Y	Removes leading zeros (if any)
Return Value

The strftime function returns the number of characters placed in string if the total number of resulting characters, including the terminating null, is not more than maxsize. The wcsftime function returns the corresponding number of wide characters. Otherwise, the functions return 0, and the contents of the string are indeterminate.

See Also

»localeconv,« »setlocale,« »strcoll,« »strxfrm«

Compatibility

strftime:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcsftime:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »time.«


Description: _stricmp, _wcsicmp, _fstricmp
  _stricmp, _wcsicmp, _fstricmp

#include <string.h>    For _stricmp and _fstricmp

#include <wchar.h>    For_wcsicmp use either WCHAR.H (for ANSI compatibility) or STRING.H

int _stricmp( const char *string1, const char *string2 );

int _wcsicmp(const wchar_t *string1, const wchar_t *string2 );

int __far _fstricmp( const char __far *string1, const char __far *string2 );

string1    Null-terminated string to compare

string2    Null-terminated string to compare

Remarks

The _stricmp function performs a lexicographical comparison of lowercase versions of string1 and string2 and returns a value indicating their relationship. Each of the arguments to _stricmp is expected to contain a null character ('\0') marking the end of the string. The _stricmp function differs from _stricoll in that the _stricmp comparison is not affected by locale, whereas the manner of comparison performed by the _stricoll function is determined by the LC_COLLATE category of the current locale. For more information on the LC_COLLATE category, see the »setlocale« function.

The _wcsicmp function is a wide-character version of _stricmp; the arguments of wcsicmp are wide-character strings. The _wcsicmp and _stricmp functions behave identically otherwise.

The _wcsicmp and wcscmp functions behave identically except that wcscmp does not convert its arguments to lowercase before comparing them.

The _fstricmp function is a 16-bit model-independent (large-model) version of the _stricmp function. The arguments of _fstricmp are far pointers. The _fstricmp and _stricmp functions behave identically otherwise.

The _fstricmp and _fstrcmp functions behave identically except that _fstrcmp does not convert its arguments to lowercase before comparing them.

Return Value

The return values indicating the relation of string1 to string2 are as follows:

value < 0    string1 less than string2

value = 0    string1 identical to string2

value > 0    string1 greater than string2

See Also

»memcmp,« »_memicmp,« »strcmp,« »strcoll,« »strncmp,« »_strnicmp,« »strrchr,« »_strset,« »strspn«

Compatibility

_stricmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_wcsicmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstricmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »strcmp.«


Description: strlen, wcslen, _fstrlen
  strlen, wcslen, _fstrlen

#include <string.h>    For strlen and _fstrlen

#include <wchar.h>    For wcslen use either WCHAR.H (for ANSI compatibility) or STRING.H

size_t strlen( const char *string );

size_t wcslen( const wchar_t *string );

size_t _fstrlen( const char __far *string );

string    Null-terminated string

Remarks

The strlen function returns the length in bytes of string, not including the terminating null character ('\0'). The wcslen function is a wide-character version of strlen; the argument of wcslen is a wide-character pointer. The wcschr and strchr functions behave identically otherwise. The _fstrlen function is a 16-bit model-independent (large-model) version of strlen. The argument to _fstrlen is a far pointer. The _fstrlen and strlen functions behave identically otherwise.

Return Value

Each of the strlen and _fstrlen functions returns the number of bytes in string. The wcslen function returns the number of wide characters in string. No return value is reserved to indicate an error.

See Also

»strcat,« »strcmp,« »strcoll,« »strcpy,« »strncat,« »strncmp,« »_strnicmp,« »strncpy,« »strrchr,« »_strset,« »strspn«

Compatibility

strlen:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcslen:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrlen:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/*  STRLEN.C */

#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>

void main( void )
{
   char buffer[61] = "How long am I?";
   int  len;

   len = strlen( buffer );
   printf( "'%s' is %d characters long\n", buffer, len );
}

Output

'How long am I?' is 14 characters long


Description: _strlwr, _wcslwr, _fstrlwr
  _strlwr, _wcslwr, _fstrlwr

#include <string.h>    For _strlwr and _fstrlwr only

#include <wchar.h>    For _wcslwr use either WCHAR.H (for ANSI compatibility) or STRING.H

char *_strlwr( char *string );

wchar_t * _wcslwr( wchar_t *string );

char __far * __far _fstrlwr( char __far *string );

string    Null-terminated string to be converted

Remarks

The _strlwr function converts any uppercase letters in string to lowercase in a manner determined by the LC_CTYPE category setting of the current locale. Other characters are not affected. For more information on the LC_CTYPE category, see the reference page on the »setlocale« function.

The _wcslwr function is a wide-character version of _strlwr; the string argument and return value of _wcslwr are wide-character pointers. The _wcslwr and _strlwr functions behave identically otherwise.

The _fstrlwr function is a 16-bit model-independent (large-model) version of the _strlwr function. The arguments and return value of _fstrlwr are far pointers. The _fstrlwr and _strlwr functions behave identically otherwise.

Return Value

Each of these functions returns a pointer to the converted string. Because the modification is done in place, the pointer returned is the same as the pointer passed as the input argument. No return value is reserved to indicate an error.

See Also

»_strupr«

Compatibility

_strlwr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_wcslwr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrlwr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRLWR.C: This program uses _strlwr and _strupr to create
 * uppercase and lowercase copies of a mixed-case string.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100] = "The String to End All Strings!";
   char *copy1, *copy2;

   copy1 = _strlwr( _strdup( string ) );
   copy2 = _strupr( _strdup( string ) );
   printf( "Mixed: %s\n", string );
   printf( "Lower: %s\n", copy1 );
   printf( "Upper: %s\n", copy2 );
}

Output

Mixed: The String to End All Strings!
Lower: the string to end all strings!
Upper: THE STRING TO END ALL STRINGS!


Description: strncat, wcsncat, _fstrncat
  strncat, wcsncat, _fstrncat

#include <string.h>    For strncat and _fstrncat

#include <wchar.h>    For wcsncat use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strncat( char *string1, const char *string2, size_t count );

wchar_t *wcsncat( wchar_t *string1, const wchar_t *string2, size_t count );

char __far * __far _fstrncat( char __far *string1, const char __far * string2, size_t count );

string1    Null-terminated destination string

string2    Null-terminated source string

count    Number of characters to append

Remarks

The strncat function appends, at most, the first count characters of string2 to string1. Each of the string arguments to strncat is expected to be null-terminated. The initial character of string2 overwrites the terminating null character ('\0') of string1. If a null character appears in string2 before count characters are appended, strncat appends all characters from string2 up to the null character. If count is greater than the length of string2, the length of string2 is used in place of count. The resulting string is terminated with a null character. If copying takes place between strings that overlap, the behavior is undefined.

The wcsncat function is a wide-character version of strncat; the string argument and return value of wcsncat are wide-character pointers. The wcsncat and strncat functions behave identically otherwise.

The _fstrncat function is a 16-bit model-independent (large-model) version of the strncat function. The string arguments and return value of _fstrncat are far pointers. The _fstrncat and strncat functions behave identically otherwise.

Return Value

Each of these functions returns a pointer to the destination string. No return value is reserved to indicate an error.

See Also

»strcat,« »strcmp,« »strcpy,« »strncmp,« »strncpy,« »_strnicmp,« »strrchr,« »_strset,« »strspn«

Compatibility

strncat:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcsncat:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrncat:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRNCAT.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[80] = "This is the initial string!";
   char suffix[] = " extra text to add to the string...";

   /* Combine strings with no more than 19 characters of suffix: */
   printf( "Before: %s\n", string );
   strncat( string, suffix, 19 );
   printf( "After:  %s\n", string );
}

Output

Before: This is the initial string!
After:  This is the initial string! extra text to add


Description: strncmp, wcsncmp, _wcsnicmp, _fstrncmp
  strncmp, wcsncmp, _wcsnicmp, _fstrncmp

#include <string.h>    For strncmp and _fstrncmp

#include <wchar.h>    For wcsncmp use either WCHAR.H (for ANSI compatibility) or STRING.H

int strncmp( const char *string1, const char *string2, size_t count );

int wcsncmp( const wchar_t *string1, const wchar_t *string2, size_t count );

int _wcsnicmp( const wchar_t *string1, const wchar_t *string2, size_t count );

int __far _fstrncmp( const char __far *string1, const char __far * string2, size_t count );

string1    String to compare

string2    String to compare

count    Number of characters to compare

Remarks

The strncmp function lexicographically compares, at most, the first count characters in each of the strings string1 and string2 and returns a value indicating the relationship between the substrings. The strncmp function is a case-sensitive version of »_strnicmp.« Unlike the comparison performed by the strcoll function, which is determined by the LC_COLLATE category of the current locale, the strncmp function is not affected by locale. For more information on the LC_COLLATE category, see the »setlocale« function.

The wcsncmp function is a wide-character version of strncmp; the string arguments of wcsncmp are wide-character strings. The wcsncmp and strncmp functions behave identically otherwise. The _wcsnicmp function is a case-insensitive version of wcsncmp.

The _fstrncmp function is a 16-bit model-independent (large-model) version of the strncmp function. The string arguments of _fstrncmp are far pointers. The _fstrncmp and strncmp functions behave identically otherwise.

Return Value

The return values indicating the relation of the substrings of string1 and string2 are as follows:

value < 0    string1 less than string2

value = 0    string1 identical to string2

value > 0    string1 greater than string2

See Also

»strcmp,« »strcoll,« »strrchr,« »_strset,« »strspn«

Compatibility

strncmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcsncmp _wcsnicmp:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrncmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRNCMP.C */

#include <string.h>
#include <stdio.h>

char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown fox jumps over the lazy dog";

void main( void )
{
   char tmp[20];
   int result;

   printf( "Compare strings:\n\t\t%s\n\t\t%s\n\n", string1, string2 );

   printf( "Function:\tstrncmp (first 10 characters only)\n" );
   result = strncmp( string1, string2 , 10 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "Result:\t\t1 is %s string 2\n\n", tmp );

   printf( "Function:\tstrnicmp _strnicmp " );
   printf( "(first 10 characters only)\n" );
   result = _strnicmp( string1, string2, 10 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
}

Output

Compare strings:
      The quick brown dog jumps over the lazy fox
      The QUICK brown fox jumps over the lazy dog

Function:   strncmp (first 10 characters only)
Result:      1 is greater than string 2

Function:   strnicmp _strnicmp (first 10 characters only)
Result:      String 1 is equal to string 2


Description: strncpy, wcsncpy, _fstrncpy
  strncpy, wcsncpy, _fstrncpy

#include <string.h>    For strncpy and _fstrncpy

#include <wchar.h>    For wcsncpy use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strncpy( char *string1, const char *string2, size_t count );

char *wcsncpy( wchar_t *string1, const wchar_t *string2, size_t count );

char __far * __far _fstrncpy( char __far *string1, const char __far * string2, size_t count );

string1    Destination string

string2    Source string

count    Number of characters to be copied

Remarks

The strncpy function copies the initial count characters of string2 to string1 and returns string1. If count is less than or equal to the length of string2, a null character ('\0') is not appended automatically to the copied string. If count is greater than the length of string2, the destination string is padded with null characters up to length count. The behavior of strncpy is undefined if the source and destination strings overlap.

The wcsncpy function is a wide-character version of strncpy; the string arguments and return value of wcsncpy are wide-character pointers. The wcsncpy and strncpy functions behave identically otherwise.

The _fstrncpy function is a 16-bit model-independent (large-model) version of the strncpy function. The string arguments to _fstrcpy are far pointers. The _fstrncpy and strncpy functions behave identically otherwise.

Return Value

Each of these functions returns string1. No return value is reserved to indicate an error.

See Also

»strcat,« »strcmp,« »strcpy,« »strncat,« »strncmp,« »_strnicmp,« »strrchr,« »_strset,« »strspn«

Compatibility

strncpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcsncpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrncpy:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRNCPY.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100] = "Cats are nice usually";

   printf("Before: %s\n", string );
   strncpy( string, "Dogs", 4 );
   strncpy( string + 9, "mean", 4 );
   printf("After:  %s\n", string );
}

Output

Before: Cats are nice usually
After:  Dogs are mean usually


Description: _strnicmp, _wcsnicmp, _fstrnicmp
  _strnicmp, _wcsnicmp, _fstrnicmp

#include <string.h>    For _strnicmp and _fstrnicmp

#include <wchar.h>    For _wcsnicmp use either WCHAR.H (for ANSI compatibility) or STRING.H

int _strnicmp( const char *string1, const char *string2, size_t count );

int _wcsnicmp( const wchar_t *string1, const wchar_t *string2, size_t count );

int __far _fstrnicmp( const char __far *string1, const char __far *string2, size_t count );

string1    Null-terminated string to compare

string2    Null-terminated string to compare

count    Number of characters to compare

Remarks

The _strnicmp function lexicographically compares, at most, the first count characters of string1 and string2. The comparison is performed without regard to case; the »strncmp« function is a case-sensitive version of _strnicmp. The comparison ends if a terminating null character ('\0') is reached in either string before count characters are compared. If the strings are equal when a terminating null character ('\0') is reached in either string before count characters are compared, the shorter string is lesser. The comparison performed by the _strnicmp function is not affected by the current locale.

Note that two strings containing characters located between 'Z' and 'a' in the ASCII table ([, \, ], ^, _, and `) compare differently depending on their case. For example, the two strings, "ABCDE" and "ABCD^", compare one way if the comparison is lowercase ("abcde" > "abcd^") and compare the other way ("ABCDE" < "ABCD^") if it is uppercase.

The _wcsnicmp function is a wide character form of _strnicmp; the string arguments and return value of _wcsnicmp are wide-character pointers. The _wcsnicmp and _strnicmp functions behave identically otherwise.

The _fstrnicmp function is a 16-bit model-independent (large-model) version of _strnicmp. The string arguments and return value of _fstrnicmp are far pointers. The _fstrnicmp and _fstrnicmp functions are otherwise identical.

These functions are not affected by the current locale setting.

Return Value

Each of these functions returns a value indicating the relationship between the substrings, as listed below:

value < 0    string1 less than string2

value = 0    string1 identical to string2

value > 0    string1 greater than string2

See Also

»strcat,« »strcmp,« »strcpy,« »strncat,« »strncpy,« »strrchr,« »_strset,« »strspn«

Compatibility

_strnicmp:   ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_wcsnicmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrnicmp:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »strncmp.«


Description: _strnset, _wcsnset, _fstrnset
  _strnset, _wcsnset, _fstrnset

#include <string.h>    For _strnset and _fstrnset

#include <wchar.h>    For _wcsnset use either WCHAR.H (for ANSI compatibility) or STRING.H

char *_strnset( char *string, int c, size_t count );

wchar_t * _wcsnset( wchar_t *string, wchar_t c, size_t count );

char __far * __far _fstrnset( char __far *string, int c, size_t count );

string    String to be altered

c    Character setting

count    Number of characters to be set

Remarks

The _strnset function sets, at most, the first count characters of string to c (converted to char). If count is greater than the length of string, the length of string is used instead of count.

The _wcsnset function is a wide character version of _strnset; the string argument and return value of _wcsnset are wide-character pointers. The _wcsnset and _strnset functions behave identically otherwise.

The _fstrnset function is a 16-bit model-independent (large-model) version of the _strnset function. The argument and return value of _fstrnset are far pointers. The _fstrnset and strnset functions behave identically otherwise.

Return Value

Each of these functions returns a pointer to the altered string.

See Also

»strcat,« »strcmp,« »strcpy,« »_strset«

Compatibility

_strnset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_wcsnset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrnset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRNSET.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[15] = "This is a test";

   /* Set not more than 4 characters of string to be *'s */
   printf( "Before: %s\n", string );
   _strnset( string, '*', 4 );
   printf( "After:  %s\n", string );
}

Output

Before: This is a test
After:  **** is a test


Description: strpbrk, wcspbrk, _fstrpbrk
  strpbrk, wcspbrk, _fstrpbrk

#include <string.h>    For strpbrk and _fstrpbrk

#include <wchar.h>    For wcspbrk use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strpbrk( const char *string1, const char *string2 );

wchar_t *wcspbrk( const wchar_t *string1, const wchar_t *string2 );

char __far * __far _fstrpbrk( const char __far *string1, const char __far *string2 );

string1    Null-terminated source string

string2    Null-terminated character set

Remarks

The strpbrk function finds the first occurrence in string1 of any character from string2. The terminating null character ('\0') is not included in the search.

The wcspbrk function is a wide-character version of strpbrk; the string argument and return value of wcspbrk are wide-character pointers. The wcspbrk and strpbrk functions behave identically otherwise.

The _fstrpbrk function is a 16-bit model-independent (large-model) version of the strpbrk function. The arguments and return value of _fstrbrk are far pointers. The _fstrpbrk and strpbrk functions behave identically otherwise.

Return Value

Each of these functions returns a pointer to the first occurrence of any character from string2 in string1, or a NULL pointer if the two string arguments have no characters in common.

See Also

»strchr,« »strrchr,« »wcschr,« »wcsrchr«

Compatibility

strpbrk:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcspbrk:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrpbrk:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRPBRK.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100] = "The 3 men and 2 boys ate 5 pigs\n";
   char *result;

   /* Return pointer to first 'a' or 'b' in "string" */
   printf( "1: %s\n", string );
   result = strpbrk( string, "0123456789" );
   printf( "2: %s\n", result++ );
   result = strpbrk( result, "0123456789" );
   printf( "3: %s\n", result++ );
   result = strpbrk( result, "0123456789" );
   printf( "4: %s\n", result );
}

Output

1: The 3 men and 2 boys ate 5 pigs

2: 3 men and 2 boys ate 5 pigs

3: 2 boys ate 5 pigs

4: 5 pigs


Description: strrchr, wcsrchr, _fstrrchr
  strrchr, wcsrchr, _fstrrchr

#include <string.h>    For strrchr and _fstrrchr

#include <wchar.h>    For wcsrchr use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strrchr( const char *string, int c );

char *wcsrchr( const wchar_t *string, int c );

char __far * __far _fstrrchr( const char __far *string, int c );

string    Searched null-terminated string

c    Character to be located

Remarks

The strrchr function finds the last occurrence of c (converted to char) in string. The terminating null character ('\0') of string is included in the search. Use »strchr« to find the first occurrence of c in string.

The wcsrchr function is a wide-character version of strrchr; the string argument and return value of wcsrchr are wide-character pointers. The wcsrchr and strrchr functions behave identically otherwise.

The _fstrrchr function is a 16-bit model-independent (large-model) version of the strrchr function. The arguments and return value of _fstrrchr are far pointers. The _fstrrchr and strrchr functions behave identically otherwise.

Return Value

Each of these functions returns a pointer to the last occurrence of c in string, or a NULL pointer if c is not found.

See Also

»strchr,« »strcspn,« »_strnicmp,« »strpbrk,« »strspn«

Compatibility

strrchr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcsrchr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrrchr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »strchr.«


Description: _strrev, _wcsrev, _fstrrev
  _strrev, _wcsrev, _fstrrev

#include <string.h>    For _strrev and _fstrrev

#include <wchar.h>    For _wcsrev use either WCHAR.H (for ANSI compatibility) or STRING.H

char *_strrev( char *string );

wchar_t * _wcsrev( wchar_t *string );

char __far * __far _fstrrev( char __far *string );

string    Null-terminated string to be reversed

Remarks

The _strrev function reverses the order of the characters in string. The terminating null character ('\0') remains in place. The _wcsrev function is a wide-character version of _strrev; the string argument and return value of _wcsrev are wide-character pointers. The _wcsrev and _strrev functions behave identically otherwise. The _fstrrev function is a 16-bit model-independent (large-model) version of the _strrev function. The arguments and return value of _fstrrev are far pointers. The _fstrrev and _strrev functions behave identically otherwise.

Return Value

Each of these functions returns a pointer to the altered string. No return value is reserved to indicate an error.

See Also

»strcpy,« »_strset«

Compatibility

_strrev:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_wcsrev:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

fstrrev:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRREV.C: This program checks an input string to
 * see whether it is a palindrome: that is, whether
 * it reads the same forward and backward.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100];
   int result;

   printf( "Input a string and I will tell you ");
   printf( "if it is a palindrome:\n" );
   gets( string );

   /* Reverse string and compare (ignore case): */
   result = _strcmpi( string, _strrev( _strdup( string ) ) );
   if( result == 0 )
      printf( "The string \"%s\" is a palindrome\n\n", string );
   else
      printf( "The string \"%s\" is not a palindrome\n\n", string );
}

Output

Input a string and I will tell you if it is a palindrome:
Able was I ere I saw Elba
The string "Able was I ere I saw Elba" is a palindrome


Description: _strset, _wcsset, _fstrset
  _strset, _wcsset, _fstrset

#include <string.h>    For _strset and _fstrset

#include <wchar.h>    For _wcsset use either WCHAR.H (for ANSI compatibility) or STRING.H

char *_strset( char *string, int c );

wchar_t * _wcsset( wchar_t *string, wchar_t c );

char __far * __far _fstrset( char __far *string, int c );

string    Null-terminated string to be set

c    Character setting

Remarks

The _strset function sets all of the characters of string to c (converted to char), except the terminating null character ('\0'). The _wcsset function is a wide-character version of _strset; the string argument and return value of wcsset are wide-character pointers. The _wcsset and _strset functions behave identically otherwise. The _fstrset function is a 16-bit model-independent (large-model) form of the _strset function. The string argument and return value of _fstrset are far pointers. The _fstrset and_strset functions behave identically otherwise.

Return Value

Each of these functions returns a pointer to the altered string. No return value is reserved to indicate an error.

See Also

»memset,« »strcat,« »strcmp,« »strcpy,« »_strnset«

Compatibility

_strset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_wcsset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrset:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRSET.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[] = "Fill the string with something";

   printf( "Before: %s\n", string );
   _strset( string, '*' );
   printf( "After:  %s\n", string );
}

Output

Before: Fill the string with something
After:  ******************************


Description: strspn, wcsspn, _fstrspn
  strspn, wcsspn, _fstrspn

#include <string.h>    For strspn and _fstrspn

#include <wchar.h>    For wcsspn use either WCHAR.H (for ANSI compatibility) or STRING.H

size_t strspn( const char *string1, const char *string2 );

size_t wcsspn( const wchar_t *string1, const wchar_t *string2 );

size_t __far _fstrspn( const char __far *string1, const char __far * string2 );

string1    Null-terminated string to search

string2    Null-terminated character set

Remarks

The strspn function returns the index of the first character in string1 that does not belong to the set of characters in string2. The index value is equivalent to the length of the initial substring of string1 that consists entirely of characters in string2. Each string argument to the strspn function is expected to contain a null character ('\0') marking the end of the string. Terminating null characters are not included in the search.

The wcsspn function is a wide-character version of strspn; the arguments of wcsspn are wide-character pointers. The wcsspn and strspn functions behave identically otherwise.

The _fstrspn function is a 16-bit model-independent (large-model) version of the strspn function. The arguments and return value of _fstrspn are far pointers. The _fstrspn and strspn functions behave identically otherwise.

Return Value

Each of these functions returns an integer value specifying the length of the substring in string1 consisting entirely of characters in string2. If string1 begins with a character not in string2, the function returns 0. No return value is reserved to indicate an error.

See Also

»strcspn,« »strncat,« »strncmp,« »strncpy,« »_strnicmp,« »strrchr«

Compatibility

strspn:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcsspn:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrspn:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRSPN.C: This program uses strspn to determine
 * the length of the segment in the string "cabbage"
 * consisting of a's, b's, and c's. In other words,
 * it finds the first non-abc letter.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[] = "cabbage";
   int result;

   result = strspn( string, "abc" );
   printf( "The portion of '%s' containing only a, b, or c "
           "is %d bytes long\n", string, result );
}

Output

The portion of 'cabbage' containing only a, b, or c is 5 bytes long


Description: strstr, wcsstr, _fstrstr
  strstr, wcsstr, _fstrstr

#include <string.h>    For strstr and _fstrstr

#include <wchar.h>    For wcscspn use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strstr( const char *string1, const char *string2 );

wchar_t *wcsstr( const wchar_t *string1, const wchar_t *string2 );

char __far * __far _fstrstr( const char __far *string1, const char __far *string2 );

string1    Null-terminated string to search

string2    String to search for

Remarks

The strstr function returns a pointer to the first occurrence of string2 in string1. Each argument is expected to be terminated by a null character ('\0'), but the terminating null characters are not included in the search. The wcsstr function is a wide-character version of strstr; the string argument and return value of wcsstr are wide-character pointers. The wcsstr and strstr functions behave identically otherwise. The _fstrstr function is a 16-bit model-independent (large-model) version of the strstr function. The arguments of _fstrstr are far pointers. The _fstrstr and strstr functions behave identically otherwise.

Return Value

Each of these functions returns either a pointer to the first occurrence of string2 in string1, or NULL if it does not find the string. If string2 points to a string of zero length, the function returns string1.

See Also

»strcspn,« »strcmp,« »strpbrk,« »strrchr,« »strspn«

Compatibility

strstr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcsstr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrstr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRSTR.C */

#include <string.h>
#include <stdio.h>

char str[] =    "lazy";
char string[] = "The quick brown dog jumps over the lazy fox";
char fmt1[] =   "         1         2         3         4         5";
char fmt2[] =   "12345678901234567890123456789012345678901234567890";

void main( void )
{
   char *pdest;
   int  result;

   printf( "String to be searched:\n\t%s\n", string );
   printf( "\t%s\n\t%s\n\n", fmt1, fmt2 );
   pdest = strstr( string, str );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "%s found at position %d\n\n", str, result );
   else
      printf( "%s not found\n", str );
}

Output

String to be searched:
   The quick brown dog jumps over the lazy fox
            1         2         3         4         5
   12345678901234567890123456789012345678901234567890

lazy found at position 36


Description: _strtime
  _strtime

#include <time.h>

char *_strtime( char *timestr );

timestr    Time string

Remarks

The _strtime function copies the current time into the buffer pointed to by timestr. The time is formatted as hh:mm:ss where hh is two digits representing the hour in 24-hour notation, mm is two digits representing the minutes past the hour, and ss is two digits representing seconds. For example, the string 18:23:44 represents 23 minutes and 44 seconds past 6 PM. The buffer must be at least nine bytes long.

Return Value

The _strtime function returns a pointer to the resulting text string timestr.

See Also

»asctime,« »ctime,« »gmtime,« »localtime,« »mktime,« »time,« »_tzset«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRTIME.C */

#include <time.h>
#include <stdio.h>

void main( void )
{
   char dbuffer [9];
   char tbuffer [9];

   _strdate( dbuffer );
   printf( "The current date is %s \n", dbuffer );
   _strtime( tbuffer );
   printf( "The current time is %s \n", tbuffer );
}

Output

The current date is 03/23/93
The current time is 13:40:40


Description: strtod, wcstod, strtol, wcstol, _strtold, strtoul, wcstoul
  strtod, wcstod, strtol, wcstol, _strtold, strtoul, wcstoul

#include <stdlib.h>    For strtod, strtol, _strtold, and strtoul

#include <wchar.h>    For wcstod, wcstol, and wcstoul use either WCHAR.H (for ANSI compatibility) or STRING.H

double strtod( const char *nptr, char **endptr );

double wcstod( const wchar_t *nptr, wchar_t **endptr );

long strtol( const char *nptr, char **endptr, int base );

long wcstol( const wchar_t *nptr, wchar_t **endptr, int base );

long double _strtold( const char *nptr, char **endptr );

unsigned long strtoul( const char *nptr, char **endptr, int base );

unsigned long wcstoul( const wchar_t *nptr, wchar_t **endptr, int base );

nptr    String to convert

endptr    Pointer to character that stops scan

base    Number base to use

Remarks

The strtod, _strtold, strtol, and strtoul functions convert the character string nptr to a double-precision value, a long-double value, a long-integer value, or an unsigned long-integer value, respectively. The input string is a sequence of characters that can be interpreted as a numerical value of the specified type. Each of these functions stops reading the string nptr at the first character it cannot recognize as part of a number. This may be the null character ('\0') at the end of the string. For strtol or strtoul, this terminating character can also be the first numeric character greater than or equal to base. For all seven functions in the strtod group, recognition of the radix character in nptr is determined by the setting of the LC_NUMERIC category of the current locale; for more information, see the setlocale function. If endptr is not NULL, a pointer to the character that stopped the scan is stored at the location pointed to by endptr. If no conversion can be performed (no valid digits were found or an invalid base was specified), the value of nptr is stored at the location pointed to by endptr.

The strtod and _strtold functions expect nptr to point to a string of the following form:

[whitespace] [sign] [digits] [.digits] [ {d | D | e | E}[sign]digits]

A whitespace consists of space and tab characters, which are ignored; sign is either plus (+) or minus (−); and digits are one or more decimal digits. If no digits appear before the radix character, at least one must appear after the radix character. The decimal digits can be followed by an exponent, which consists of an introductory letter (d, D, e, or E) and an optionally signed integer. If neither an exponent part nor a radix character appears, a radix character is assumed to follow the last digit in the string. The first character that does not fit this form stops the scan.

The strtol and strtoul functions expect nptr to point to a string of the following form:

[whitespace] [{+ | −}] [0 [{ x | X }]] [digits]

If base is between 2 and 36, then it is used as the base of the number. If base is 0, the initial characters of the string pointed to by nptr are used to determine the base. If the first character is 0 and the second character is not 'x' or 'X', then the string is interpreted as an octal integer; otherwise, it is interpreted as a decimal number. If the first character is '0' and the second character is 'x' or 'X', then the string is interpreted as a hexadecimal integer. If the first character is '1' through '9', then the string is interpreted as a decimal integer. The letters 'a' through 'z' (or 'A' through 'Z') are assigned the values 10 through 35; only letters whose assigned values are less than base are permitted. The strtoul function allows a plus (+) or minus (−) sign prefix; a leading minus sign indicates that the return value is negated.

The wcstod, wcstol, and wcstoul functions are wide-character versions of strtod, strtol, and strtoul, respectively; the nptr argument to each of these wide-character functions is a wide-character string. Otherwise, each of these wide-character functions behaves identically to its single-byte-character function counterpart.

Return Value

The strtod and _strtold functions return the value of the floating-point number, except when the representation would cause an overflow, in which case the functions return +/−HUGE_VAL. The sign of HUGE_VAL matches the sign of the value that cannot be represented. Each of these functions returns 0 if no conversion can be performed or an underflow occurs.

The strtol function returns the value represented in the string nptr, except when the representation would cause an overflow, in which case it returns LONG_MAX or LONG_MIN. The strtoul function returns the converted value, if any, or ULONG_MAX on overflow. Each of these functions returns 0 if no conversion can be performed.

The wcstod, wcstol, and wcstoul functions return values analogously to strtod, strtol, and strtoul, respectively.

For all seven functions in this group, errno is set to ERANGE if overflow or underflow occurs.

See Also

»atof,« »atol,« »localeconv,« »setlocale«

Compatibility

strtod, strtol:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

strtold:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

strtoul:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcstod, wcstol, wcstoul:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRTOD.C: This program uses strtod to convert a
 * string to a double-precision value; strtol to
 * convert a string to long integer values; and strtoul
 * to convert a string to unsigned long-integer values.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char   *string, *stopstring;
   double x;
   long   l;
   int    base;
   unsigned long ul;

   string = "3.1415926This stopped it";
   x = strtod( string, &stopstring );
   printf( "string = %s\n", string );
   printf("   strtod = %f\n", x );
   printf("   Stopped scan at: %s\n\n", stopstring );

   string = "-10110134932This stopped it";
   l = strtol( string, &stopstring, 10 );
   printf( "string = %s", string );
   printf("   strtol = %ld", l );
   printf("   Stopped scan at: %s", stopstring );

   string = "10110134932";
   printf( "string = %s\n", string );
   /* Convert string using base 2, 4, and 8: */
   for( base = 2; base <= 8; base *= 2 )
   {
      /* Convert the string: */
      ul = strtoul( string, &stopstring, base );
      printf( "   strtol = %ld (base %d)\n", ul, base );
      printf( "   Stopped scan at: %s\n", stopstring );
   }
}

Output

string = 3.1415926This stopped it
   strtod = 3.141593
   Stopped scan at: This stopped it

string = -10110134932This stopped it   strtol = -2147483647   Stopped scan at: This stopped itstring = 10110134932
   strtol = 45 (base 2)
   Stopped scan at: 34932
   strtol = 4423 (base 4)
   Stopped scan at: 4932
   strtol = 2134108 (base 8)
   Stopped scan at: 932


Description: strtok, wcstok, _fstrtok
  strtok, wcstok, _fstrtok

#include <string.h>    For strtok and _fstrtok

#include <wchar.h>    For wcstok use either WCHAR.H (for ANSI compatibility) or STRING.H

char *strtok( char *string1, const char *string2 );

wchar_t *wcstok( wchar_t *string1, const wchar_t *string2 );

char __far * __far _fstrtok( char __far *string1, const char __far * string2 );

string1    String containing token(s)

string2    Set of delimiter characters

Remarks

The strtok function finds the next token in a string. The set of characters in string2 specifies possible delimiters of the token to be found in string1 on the current call.

On the first call to strtok, the function skips leading delimiters and returns a pointer to the first token in string1, terminating the token with a null character ('\0'). More tokens can be broken out of the remainder of string1 by a series of calls to strtok. Each call to strtok modifies string1 by inserting a null character in string1 after the token returned by that call. To read the next token from string1, call strtok with a NULL value for the string1 argument. The NULL string1 argument causes strtok to search for the next token in the modified string1. The string2 argument can take any value from one call to the next so that the set of delimiters may vary.

The wcstok function is a wide-character version of strtok; the arguments of wcstok are wide-character strings. The wcstok and strtok functions behave identically otherwise.

The _fstrtok function is a 16-bit model-independent (large-model) version of strtok. The arguments and return value of _fstrtok are far pointers. The _fstrtok and strtok functions behave identically otherwise.

Return Value

The first time that any of these functions is called, the function returns a pointer to the first token in string1. In each subsequent call on the same token string, the function returns a pointer to the next token in the string. The function returns a NULL pointer when there are no more tokens. All tokens are null-terminated.

See Also

»strcspn,« »strspn,« »setlocale«

Compatibility

strtok:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcstok:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrtok:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* STRTOK.C: In this program, a loop uses strtok
 * to print all the tokens (separated by commas
 * or blanks) in the string named "string".
 */

#include <string.h>
#include <stdio.h>

char string[] = "A string\tof ,,tokens\nand some  more tokens";
char seps[]   = " ,\t\n";
char *token;

void main( void )
{
   printf( "%s\n\nTokens:\n", string );

   /* Establish string and get the first token: */
   token = strtok( string, seps );
   while( token != NULL )
   {
      /* While there are tokens in "string" */
      printf( " %s\n", token );
      /* Get next token: */
      token = strtok( NULL, seps );
   }
}

Output

A string   of ,,tokens
and some  more tokens

Tokens:
 A
 string
 of
 tokens
 and
 some
 more
 tokens


Description: _strupr, _wcsupr, _fstrupr
  _strupr, _wcsupr, _fstrupr

#include <string.h>    For _strupr and _fstrupr

#include <wchar.h>    For _wcsupr use either WCHAR.H (for ANSI compatibility) or STRING.H

char *_strupr( char *string );

wchar_t * _wcsupr( wchar_t *string );

char __far * __far _fstrupr( char __far *string );

string    String to capitalize

Remarks

The _strupr function converts each lowercase letter in string to uppercase in a manner determined by the LC_CTYPE category of the current locale. Other characters are not affected. For more information on the LC_CTYPE category, see the »setlocale« function.

The _wcsupr function is a wide-character version of _strupr; the string argument and return value of _wcsupr are wide-character pointers. The _wcsupr and _strupr functions behave identically otherwise.

The _fstrupr function is a 16-bit model-independent (large-model) version of the _strupr function. The arguments and return value of _fstrchr are far pointers. The _fstrchr and strchr functions behave identically otherwise.

Return Value

Each of these functions returns a pointer to the converted string. Because the modification is done in place, the pointer returned by these functions is the same as the pointer passed as the input argument. There is no return value reserved to indicate an error.

See Also

»_strlwr«

Compatibility

_strupr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_wcsupr:     ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fstrupr:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_strlwr.«


Description: strxfrm, wcsxfrm
  strxfrm, wcsxfrm

#include <string.h>    For strxfrm

#include <wchar.h>    For wcsxfrm include either WCHAR.H (for ANSI compatibility) or STRING.H

size_t strxfrm( char *string1, const char *string2, size_t count );

size_t wcsxfrm( wchar_t *string1, const wchar_t *string2, size_t count );

string1    Destination string

string2    Source string

count    Maximum number of characters to place in string1

Remarks

The strxfrm function transforms the string pointed to by string2 into a new collated form that is stored in string1. No more than count characters, including the null character, are transformed and placed into the resulting string. The transformation is made using the locale-specific information in the LC_COLLATE category of the current locale. After the transformation, a call to strcmp with the two transformed strings will yield identical results to a call to strcoll applied to the original two strings. For more information on the LC_COLLATE category, see the »setlocale« function.

In the "C" locale, the order of the characters in the character set (that is, in the ASCII character set) is the same as the lexicographic order of the characters. However, in other locales, the order of characters in the character set may differ from the lexicographic character order. For example, in certain European locales, the character 'a' (value 0x61) precedes the character 'ä' (value 0xE4) in the character set, but the character 'ä' precedes the character 'a' lexicographically.

In locales for which the character set and the lexicographic character order differ, using strxfrm on the original strings and then strcmp on the resulting strings produces a lexicographic string comparison according to the LC_COLLATE category setting of the current locale. Thus for a lexicographic comparison in the above example, using strxfrm on the original strings to be compared, and then using strcmp on the resulting strings, would sort a string beginning with the character 'ä' before a string beginning with the character 'a'. Alternatively, using strcoll rather than strcmp on the original strings would also yield the appropriate lexicographic sort.

The value of the following expression is the size of the array needed to hold the strxfrm transformation of the source string:

1 + strxfrm( NULL, string, 0 )

In the "C" locale only, strxfrm is equivalent to the following:

strncpy( _string1, _string2, _count );
return( strlen( _string1 ) );

The wcsxfrm function is a wide-character version of strxfrm; the string arguments of wcsxfrm are wide-character pointers. For wcsxfrm, after the string transformation, a call to wcscmp with the two transformed strings yields identical results to a call to wcscoll applied to the original two strings. The wcsxfrm and strxfrm functions behave identically otherwise.

Return Value

Each of these functions returns the length of the transformed string, not counting the terminating null character. If the return value is greater than or equal to count, the content of string1 is unpredictable. On an error, each of the functions sets errno and returns (size_t) −1.

See Also

»localeconv,« »setlocale,« »strcmp,« »strncmp,« »strcoll«

Compatibility

strxfrm:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

wcsxfrm:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s


Description: _swab
  _swab

#include <stdlib.h>

void _swab( char *src, char *dest, int n );

src    Data to be copied and swapped

dest    Storage location for swapped data

n    Number of bytes to be copied and swapped

Remarks

The _swab function copies n bytes from src, swaps each pair of adjacent bytes, and stores the result at dest. The integer n should be an even number to allow for swapping. The _swab function is typically used to prepare binary data for transfer to a machine that uses a different byte order.

Return Value

None.

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _swab for compatibility with ANSI naming conventions of non-ANSI functions. Use swab and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* SWAB.C illustrates:
 *      _swab
 */

#include <stdlib.h>
#include <stdio.h>

char from[] = "BADCFEHGJILKNMPORQTSVUXWZY";
char to[] =   "..........................";

void main()
{
    printf( "Before:\t%s\n\t%s\n\n", from, to );
    _swab( from, to, sizeof( from ) );
    printf( "After:\t%s\n\t%s\n\n", from, to );
}

Output

Before:   BADCFEHGJILKNMPORQTSVUXWZY
   ..........................

After:   BADCFEHGJILKNMPORQTSVUXWZY
   ABCDEFGHIJKLMNOPQRSTUVWXYZ


Description: system
  system

#include <process.h>

#include <stdlib.h>    Use STDLIB.H for ANSI compatibility

int system( const char *command );

command    Command to be executed

Remarks

The system function passes command to the command interpreter, which executes the string as an operating-system command. The system function refers to the COMSPEC and PATH environment variables that locate the command-interpreter file (the file named COMMAND.COM in MS-DOS or CMD.EXE in Windows NT). If command is a pointer to an empty string, the function simply checks to see whether or not the command interpreter exists.

You must explicitly flush (using fflush or _flushall) or close any stream prior to the system function call.

Return Value

If command is NULL and the command interpreter is found, the function returns a nonzero value. If the command interpreter is not found, it returns the value 0 and sets errno to ENOENT. If command is not NULL, the system function returns the value 0 if the command interpreter is successfully started. A return value of −1 indicates an error, and errno is set to one of the following values:

E2BIG    In MS-DOS, the argument list exceeds 128 bytes, or the space required for the environment information exceeds 32K.

ENOENT    The command interpreter cannot be found.

ENOEXEC    The command-interpreter file has an invalid format and is not executable.

ENOMEM    Not enough memory is available to execute the command; the available memory has been corrupted; or an invalid block exists, indicating that the process making the call was not allocated properly.

See Also

»_exec functions,« »exit,« »_exit,« »_flushall,« »_spawn functions«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* SYSTEM.C: This program uses
 * system to TYPE its source file.
 */

#include <process.h>

void main( void )
{
   system( "type system.c" );
}

Output

/* SYSTEM.C: This program uses
 * system to TYPE its source file.
 */
#include <process.h>
void main( void )
{
   system( "type system.c" );
}


Description: tan Functions
  tan Functions

#include <math.h>

double tan( double x );

double tanh( double x );

long double tanl( long double x );

long double tanhl( long double x );

x    Angle in radians

Remarks

The tan functions return the tangent or hyperbolic tangent of their arguments. The list below describes the differences between the various tangent functions:

tan     Calculates tangent of x

tanh    Calculates hyperbolic tangent of x

tanl     Calculates tangent of x (80-bit version)

tanhl    Calculates hyperbolic tangent of x (80-bit version)

The tanl and tanhl functions are the 80-bit counterparts and use an 80-bit, 10-byte coprocessor form of arguments and return values. In Windows NT, since the 80-bit long double data type is synonymous with the 64-bit double data type, tanl is equivalent to tan, and tanhl is equivalent to tanh. See the reference page on the »long double functions« for more details on this data type.

Return Value

The tan function returns the tangent of x. If x is greater than or equal to 2 raised to the power of 27, a partial loss of significance in the result may occur; in this case, tan sets errno to ERANGE and generates a _PLOSS error. If x is greater than or equal to 2 raised to the power of 31, significance is totally lost, tan prints a _TLOSS error message to stderr, sets errno to ERANGE, and returns 0. Error handling can be modified by using the _matherr function. There is no error return for tanh.

See Also

»acos functions,« »asin functions,« »atan functions,« »cos functions,« »sin functions«

Compatibility

tan, tanh:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

tanl, tanhl:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* TAN.C:  This program displays the tangent of pi / 4
 * and the hyperbolic tangent of the result.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double pi = 3.1415926535;
   double x, y;

   x = tan( pi / 4 );
   y = tanh( x );
   printf( "tan( %f ) = %f\n", x, y );
   printf( "tanh( %f ) = %f\n", y, x );
}

Output

tan( 1.000000 ) = 0.761594
tanh( 0.761594 ) = 1.000000


Description: tell
  _tell

#include <io.h>

long _tell( int handle );

handle    Handle referring to open file

Remarks

The _tell function gets the current position of the file pointer (if any) associated with the handle argument. The position is expressed as the number of bytes from the beginning of the file.

Return Value

A return value of −1L indicates an error, and errno is set to EBADF to indicate an invalid file-handle argument. On devices incapable of seeking, the return value is undefined.

See Also

»ftell,« »_lseek«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* TELL.C:  This program uses _tell to tell the
 * file pointer position after a file read.
 */

#include <io.h>
#include <stdio.h>
#include <fcntl.h>

void main( void )
{
   int  fh;
   char buffer[500];

   if( (fh = _open( "tell.c", _O_RDONLY )) != -1 )
   {
      if( _read( fh, buffer, 500 ) > 0 )
         printf( "Current file position is: %d\n", _tell( fh ) );
      _close( fh );
   }
}

Output

Current file position is: 434


_Description: tempnam, tmpnam
  _tempnam, tmpnam

#include <stdio.h>

char *_tempnam( char *dir, char *prefix );

char *tmpnam( char *string );

string    Pointer to temporary name

dir    Target directory to be used if TMP not defined

prefix    Filename prefix

Remarks

The tmpnam function generates a temporary filename that can be used to open a temporary file without overwriting an existing file. This name is stored in string. If string is NULL, then tmpnam leaves the result in an internal static buffer. Thus, any subsequent calls destroy this value. If string is not NULL, it is assumed to point to an array of at least L_tmpnam bytes (the value of L_tmpnam is defined in STDIO.H). The function will generate unique filenames for up to TMP_MAX calls.

The character string that tmpnam creates consists of the path prefix, defined by the entry P_tmpdir in the file STDIO.H, followed by a sequence consisting of the digit characters '0' through '9'; the numerical value of this string can range from 1 to 65,535. Changing the definitions of L_tmpnam or P_tmpdir in STDIO.H does not change the operation of tmpnam.

The _tempnam function allows the program to create a temporary filename for use in another directory. This filename will be different from that of any existing file. The prefix argument is the prefix to the filename. The _tempnam function uses malloc to allocate space for the filename; the program is responsible for freeing this space when it is no longer needed. The _tempnam function looks for the file with the given name in the following directories, listed in order of precedence:

Directory Used	Conditions
Directory specified by TMP	TMP environment variable is set, and directory specified by TMP exists.
dir argument to _tempnam	TMP environment variable is not set, or directory specified by TMP does not exist.
P_tmpdir in STDIO.H	The dir argument is NULL, or dir is name of nonexistent directory.
Current working directory	P_tmpdir does not exist.
If the search through the locations listed above fails, _tempnam returns the value NULL.

Return Value

The tmpnam and _tempnam functions both return a pointer to the name generated, unless it is impossible to create this name or the name is not unique. If the name cannot be created or if a file with that name already exists, tmpnam and _tempnam return the value NULL.

See Also

»tmpfile«

Compatibility

_tempnam:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _tempnam for compatibility with ANSI naming conventions of non-ANSI functions. Use tempnam and link with OLDNAMES.LIB for UNIX compatibility.

tmpnam:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* TEMPNAM.C: This program uses tmpnam to create a unique
 * filename in the current working directory, then uses
 * _tempnam to create a unique filename with a prefix of stq.
 */

#include <stdio.h>

void main( void )
{
   char *name1, *name2;

   /* Create a temporary filename for the current working directory: */
   if( ( name1 = tmpnam( NULL ) ) != NULL )
      printf( "%s is safe to use as a temporary file.\n", name1 );
   else
      printf( "Cannot create a unique filename\n" );

   /* Create a temporary file name in temporary directory with the
    * prefix "stq". The actual destination directory may vary
    * depending on the state of the TMP environment variable and
    * the global variable P_tmpdir.
    */
   if( ( name2 = _tempnam( "c:\\tmp", "stq" ) ) != NULL )
      printf( "%s is safe to use as a temporary file.\n", name2 );
   else
      printf( "Cannot create a unique filename\n" );
}

Output

\s5d. is safe to use as a temporary file.
C:\temp\stq2 is safe to use as a temporary file.


Description: time
  time

#include <time.h>

time_t time( time_t *timer );

timer    Storage location for time

Remarks

The time function returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, Universal coordinated time, according to the system clock. The system time is adjusted according to the _timezone system variable, which is explained under »_tzset.« The return value is stored in the location given by timer. This parameter may be NULL, in which case the return value is not stored.

Return Value

The time function returns the time in elapsed seconds. There is no error return.

See Also

»asctime,« »_ftime,« »gmtime,« »localtime,« »_tzset,« »_utime«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* TIMES.C illustrates various time and date functions including:
 *      time            _ftime          ctime       asctime
 *      localtime       gmtime          mktime      _tzset
 *      _strtime        _strdate        strftime
 *
 * Also the global variable:
 *      _tzname
 */

#include <time.h>
#include <stdio.h>
#include <sys\types.h>
#include <sys\timeb.h>
#include <string.h>

void main()
{
    char tmpbuf[128], ampm[] = "AM";
    time_t ltime;
    struct _timeb tstruct;
    struct tm *today, *gmt, xmas = { 0, 0, 12, 25, 11, 93 };

    /* Set time zone from TZ environment variable. If TZ is not set,
     * PST8PDT is used (Pacific standard time, daylight savings).
     */
    _tzset();

    /* Display MS-DOS-style date and time. */
    _strtime( tmpbuf );
    printf( "MS-DOS time:\t\t\t\t%s\n", tmpbuf );
    _strdate( tmpbuf );
    printf( "MS-DOS date:\t\t\t\t%s\n", tmpbuf );

    /* Get UNIX-style time and display as number and string. */
    time( &ltime );
    printf( "Time in seconds since UCT 1/1/70:\t%ld\n", ltime );
    printf( "UNIX time and date:\t\t\t%s", ctime( &ltime ) );

    /* Display UCT. */
    gmt = gmtime( &ltime );
    printf( "Universal coordinated time:\t\t%s", asctime( gmt ) );

    /* Convert to time structure and adjust for PM if necessary. */
    today = localtime( &ltime );
    if( today->tm_hour > 12 )
    {
   strcpy( ampm, "PM" );
   today->tm_hour -= 12;
    }
    if( today->tm_hour == 0 )  /* Adjust if midnight hour. */
   today->tm_hour = 12;

    /* Note how pointer addition is used to skip the first 11
     * characters and printf is used to trim off terminating
     * characters.
     */
    printf( "12-hour time:\t\t\t\t%.8s %s\n",
       asctime( today ) + 11, ampm );

    /* Print additional time information. */
    _ftime( &tstruct );
    printf( "Plus milliseconds:\t\t\t%u\n", tstruct.millitm );
    printf( "Zone difference in seconds from UCT:\t%u\n",
             tstruct.timezone );
    printf( "Time zone name:\t\t\t\t%s\n", _tzname[0] );
    printf( "Daylight savings:\t\t\t%s\n",
             tstruct.dstflag ? "YES" : "NO" );

    /* Make time for noon on Christmas, 1993. */
    if( mktime( &xmas ) != (time_t)-1 )
   printf( "Christmas\t\t\t\t%s\n", asctime( &xmas ) );

    /* Use time structure to build a customized time string. */
    today = localtime( &ltime );

    /* Use strftime to build a customized time string. */
    strftime( tmpbuf, 128,
         "Today is %A, day %d of %B in the year %Y.\n", today );
    printf( tmpbuf );
}

Output

MS-DOS time:            15:39:57
MS-DOS date:            03/26/93
Time in seconds since UCT 1/1/70:   733189197
UNIX time and date:         Fri Mar 26 15:39:57 1993
Universal coordinated time:      Fri Mar 26 23:39:57 1993
12-hour time:            03:39:57 PM
Plus milliseconds:         160
Zone difference in seconds from UCT:   480
Time zone name:            PST
Daylight savings:         NO
Christmas            Sat Dec 25 12:00:00 1993

Today is Friday, day 26 of March in the year 1993.


Description: tmpfile
  tmpfile

#include <stdio.h>

FILE *tmpfile( void );

Remarks

The tmpfile function creates a temporary file and returns a pointer to that stream. If the file cannot be opened, tmpfile returns a NULL pointer. This temporary file is automatically deleted when the file is closed, when the program terminates normally, or when _rmtmp is called, assuming that the current working directory does not change. The temporary file is opened in w+b (binary read/write) mode.

Return Value

If successful, the tmpfile function returns a stream pointer. Otherwise, it returns a NULL pointer.

See Also

»_rmtmp,« »_tempnam,« »tmpnam«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* TMPFILE.C: This program uses tmpfile to create a
 * temporary file, then deletes this file with _rmtmp.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char tempstring[] = "String to be written";
   int  i;

   /* Create temporary files. */
   for( i = 1; i <= 10; i++ )
   {
      if( (stream = tmpfile()) == NULL )
         perror( "Could not open new temporary file\n" );
      else
         printf( "Temporary file %d was created\n", i );
   }

   /* Remove temporary files. */
   printf( "%d temporary files deleted\n", _rmtmp() );
}

Output

Temporary file 1 was created
Temporary file 2 was created
Temporary file 3 was created
Temporary file 4 was created
Temporary file 5 was created
Temporary file 6 was created
Temporary file 7 was created
Temporary file 8 was created
Temporary file 9 was created
Temporary file 10 was created
10 temporary files deleted


Description: __toascii, tolower, toupper Functions
  __toascii, tolower, _tolower, towlower, toupper, _toupper, towupper

#include <ctype.h>    For single-byte character to functions (__toascii, tolower, _tolower, toupper, and _toupper)

#include <wchar.h>    For tow functions use either WCHAR.H (for ANSI compatibility) or CTYPE.H

int __toascii( int c );

int tolower( int c );

int _tolower( int c );

int towlower( wint_t c );

int toupper( int c );

int _toupper( int c );

int towupper( wint_t c );

c    Character to convert

Remarks

Each of the to functions and its associated macro, if any, converts a single character, as described in the following table:

Function	Macro	Description
__toascii	__toascii	Converts c to ASCII character
tolower	tolower	Converts c to lowercase if appropriate
_tolower	_tolower	Converts c to lowercase
towlower	None	Converts c to corresponding wide-character lowercase letter
toupper	toupper	Converts c to uppercase if appropriate
_toupper	_toupper	Converts c to uppercase
towupper	None	Converts c to corresponding wide-character uppercase letter
The function versions of the to routines that are also defined as macros can be used by removing the macro definitions with #undef directives or by not including CTYPE.H. Declarations of the tolower and toupper functions are in STDLIB.H. If the /Za compile option is used, the macro form of toupper or tolower is not used because each of these functions evaluates its argument more than once, and arguments with side effects may produce bad results.

The __toascii routine sets all but the low-order 7 bits of c to 0, so that the converted value represents a character in the ASCII character set. If c already represents an ASCII character, c is unchanged.

The tolower routine, because it calls isupper, is dependent on the LC_CTYPE category of the current locale. The tolower routine converts c to lowercase if c represents an uppercase letter in the current locale and a corresponding lowercase letter exists for that locale. Otherwise, c is unchanged. The _tolower routine is a locale-independent, much faster version of tolower, and is to be used only when both isascii(c) and isupper(c) are true. The result of _tolower is undefined if c is not an ASCII uppercase letter.

The toupper routine, because it calls islower, is dependent on the LC_CTYPE category of the current locale. The toupper routine converts c to uppercase if c represents a lowercase letter in the current locale and a corresponding uppercase letter exists for that locale. Otherwise, c is unchanged. The _toupper routine is a locale-independent, much faster version of toupper, and is to be used only when both isascii(c) and islower(c) are true. The result of _toupper is undefined if c is not an ASCII lowercase letter.

Return Value

If c is a wide character for which iswupper is true and there is a corresponding wide character for which islower is true, the towlower function returns the corresponding wide character; otherwise, the argument is returned unchanged.

If c is a wide character for which iswlower is true and there is a corresponding wide character for which isupper is true, the towupper function returns the corresponding wide character; otherwise, the argument is returned unchanged.

Each of the other to routines returns the changed or unchanged character c, as described previously. For all of the to routines, there is no return value reserved to indicate an error.

See Also

»is functions«

Compatibility

__toascii, _tolower, _toupper:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

tolower, toupper:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

towlower, towupper
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use __toascii for compatibility with ANSI naming conventions of non-ANSI functions. Use toascii and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* TOUPPER.C: This program uses toupper and tolower to
 * analyze all characters between 0x0 and 0x7F. It also
 * applies _toupper and _tolower to any code in this
 * range for which these functions make sense.
 */

#include <conio.h>
#include <ctype.h>
#include <string.h>

char msg[] = "Some of THESE letters are Capitals\r\n";
char *p;

void main( void )
{
   _cputs( msg );

   /* Reverse case of message. */
   for( p = msg; p < msg + strlen( msg ); p++ )
   {
      if( islower( *p ) )
         _putch( _toupper( *p ) );
      else if( isupper( *p ) )
         _putch( _tolower( *p ) );
      else
         _putch( *p );
   }
}

Output

Some of THESE letters are Capitals
sOME OF these LETTERS ARE cAPITALS


Description: _tzset
  _tzset

#include <time.h>

void _tzset( void );

int _daylight    Global variables set by function
long _timezone
char *_tzname[2]

Remarks

The _tzset function uses the current setting of the environment variable TZ to assign values to three global variables: _daylight, _timezone, and _tzname. These variables are used by the _ftime and localtime functions to make corrections from Universal coordinated time (UCT) to local time, and by time to compute UCT from system time. Use the following syntax to set the TZ environment variable:

set TZ=tzn[+ | −]hh[:mm[:ss] ][dzn]

The tzn must be a three-letter time-zone name, such as PST, followed by an optionally signed number, hh, giving the difference in hours between UCT and local time. To specify the exact local time, the hours can be followed by minutes, :mm; seconds, :ss; and a three-letter daylight-saving-time zone, dzn, such as PDT. Separate hours, minutes, and seconds with colons (:). If daylight saving time is never in effect, as is the case in certain states and localities, set TZ without a value for dzn. If the TZ value is not currently set, the default is PST8PDT, which corresponds to the Pacific time zone. The tzn can be any value, but it is the programmer's responsibility to ensure that the correct offset from UCT is specified. Once the correct offset has been specified via the TZ environment variable, _tzset will return the correct value.

For example, to set the TZ environment variable to correspond to the current time zone in Germany, you can use either one of the following forms:

set TZ=GST1GDT

set TZ=GST+1GDT

This uses the letters "GST" to indicate German Standard Time, though you can use any combination of three letters. This syntax assumes that Germany is one hour ahead of UCT, and that daylight savings time is in effect.

Based on the TZ environment variable value, the following values are assigned to the variables _daylight, _timezone, and _tzname when _tzset is called:

_daylight    Nonzero value if a daylight-saving-time zone is specified in the TZ setting; otherwise, 0

_timezone    Difference in seconds between UCT and local time

_tzname[0]    String value of the three-letter time-zone name from the TZ environmental variable

_tzname[1]    String value of the daylight-saving-time zone, or an empty string if the daylight-saving-time zone is omitted from the TZ environmental variable

The default for _daylight is 1; for _timezone, 28,800; for _tzname[0], PST; and for _tzname[1], PDT. This corresponds to "PST8PDT." If the DST zone is omitted from the TZ environmental variable, the _daylight variable will be 0 and the _ftime, gmtime, and localtime functions will return 0 for their DST flags.

Return Value

None.

See Also

»asctime,« »_ftime,« »gmtime,« »localtime,« »time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _tzset for compatibility with ANSI naming conventions of non-ANSI functions. Use tzset and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* TZSET.C: This program first sets up the time zone by
 * placing the variable named TZ=EST5 in the environment
 * table. It then uses _tzset to set the global variables
 * named _daylight, _timezone, and _tzname.
 */

#include <time.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   if( _putenv( "TZ=EST5EDT" ) == -1 )
   {
      printf( "Unable to set TZ\n" );
      exit( 1 );
   }
   else
   {
      _tzset();
      printf( "_daylight = %d\n", _daylight );
      printf( "_timezone = %ld\n", _timezone );
      printf( "_tzname[0] = %s\n", _tzname[0] );
   }
   exit( 0 );
}

Output

_daylight = 1
_timezone = 18000
_tzname[0] = EST


Description: _ultoa
  _ultoa

#include <stdlib.h>

char *_ultoa( unsigned long value, char *string, int radix );

value    Number to be converted

string    String result

radix    Base of value

Remarks

The _ultoa function converts value to a null-terminated character string and stores the result (up to 33 bytes) in string. No overflow checking is performed. The radix argument specifies the base of value; it must be in the range 2−36.

Return Value

The _ultoa function returns a pointer to string. There is no error return.

See Also

»_itoa,« »_ltoa«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_itoa.«


Description: _umask
  _umask

#include    <sys\types.h>

#include    <sys\stat.h>

#include <io.h>

int _umask( int pmode );

pmode    Default permission setting

Remarks

The _umask function sets the file-permission mask of the current process to the mode specified by pmode. The file-permission mask is used to modify the permission setting of new files created by _creat, _open, or _sopen. If a bit in the mask is 1, the corresponding bit in the file's requested permission value is set to 0 (disallowed). If a bit in the mask is 0, the corresponding bit is left unchanged. The permission setting for a new file is not set until the file is closed for the first time.

The argument pmode is a constant expression containing one or both of the manifest constants _S_IREAD and _S_IWRITE, defined in SYS.H. When both constants are given, they are joined with the bitwise-OR operator ( | ). If the pmode argument is _S_IREAD, reading is not allowed (the file is write-only). If the pmode argument is _S_IWRITE, writing is not allowed (the file is read-only). For example, if the write bit is set in the mask, any new files will be read-only. Note that with MS-DOS, all files are readable; it is not possible to give write-only permission. Therefore, setting the read bit with _umask has no effect on the file's modes.

Return Value

The _umask function returns the previous value of pmode. There is no error return.

See Also

»_chmod,« »_creat,« »_mkdir,« »_open«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _umask for compatibility with ANSI naming conventions of non-ANSI functions. Use umask and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* UMASK.C: This program uses _umask to set
 * the file-permission mask so that all future
 * files will be created as read-only files.
 * It also displays the old mask.
 */

#include <sys\stat.h>
#include <sys\types.h>
#include <io.h>
#include <stdio.h>

void main( void )
{
   int oldmask;

   /* Create read-only files: */
   oldmask = _umask( _S_IWRITE );
   printf( "Oldmask = 0x%.4x\n", oldmask );
}

Output

Oldmask = 0x0000


Description: ungetc
  ungetc

#include <stdio.h>

int ungetc( int c, FILE *stream );

c    Character to be pushed

stream    Pointer to FILE structure

Remarks

The ungetc function pushes the character c back onto stream and clears the end-of-file indicator. The stream must be open for reading. A subsequent read operation on the stream starts with c. An attempt to push EOF onto the stream using ungetc is ignored. The ungetc function returns an error value if nothing has yet been read from stream or if c cannot be pushed back.

Characters placed on the stream by ungetc may be erased if fflush, fseek, fsetpos, or rewind is called before the character is read from the stream. The file-position indicator will have the same value it had before the characters were pushed back. On a successful ungetc call against a text stream, the file-position indicator is unspecified until all the pushed-back characters are read or discarded. On each successful ungetc call against a binary stream, the file-position indicator is stepped down; if its value was 0 before a call, the value is undefined after the call.

Results are unpredictable if the ungetc function is called twice without a read operation between the two calls. After a call to the fscanf function, a call to ungetc may fail unless another read operation (such as the getc function) has been performed. This is because the fscanf function itself calls the ungetc function.

Return Value

The ungetc function returns the character argument c. The return value EOF indicates a failure to push back the specified character.

See Also

»getc,« »getchar,« »putc,« »putchar«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* UNGETC.C: This program first converts a character
 * representation of an unsigned integer to an integer. If
 * the program encounters a character that is not a digit,
 * the program uses ungetc to replace it in the  stream.
 */

#include <stdio.h>
#include <ctype.h>

void main( void )
{
   int ch;
   int result = 0;

   printf( "Enter an integer: " );

   /* Read in and convert number: */
   while( ((ch = getchar()) != EOF) && isdigit( ch ) )
      result = result * 10 + ch - '0';    /* Use digit. */
   if( ch != EOF )
      ungetc( ch, stdin );                /* Put nondigit back. */
   printf( "Number = %d\nNextcharacter in stream = '%c'",
            result, getchar() );
}

Output

Enter an integer: 521a
Number = 521
Nextcharacter in stream = 'a'


Description: _ungetch
  _ungetch

#include <conio.h>

int _ungetch( int c );

c    Character to be pushed

Remarks

The _ungetch function pushes the character c back to the console, causing c to be the next character read by _getch or _getche. The _ungetch function fails if it is called more than once before the next read. The c argument may not be EOF.

Return Value

The _ungetch function returns the character c if it is successful. A return value of EOF indicates an error.

See Also

»_cscanf,« »_getch,« »_getche«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* UNGETCH.C: In this program, a white-space delimited
 * token is read from the keyboard. When the program
 * encounters a delimiter, it uses _ungetch to replace
 * the character in the keyboard buffer.
 */

#include <conio.h>
#include <ctype.h>
#include <stdio.h>

void main( void )
{
   char buffer[100];
   int count = 0;
   int ch;

   ch = _getche();
   while( isspace( ch ) )      /* Skip preceding white space. */
      ch = _getche();
   while( count < 99 )         /* Gather token. */
   {
      if( isspace( ch ) )      /* End of token. */
         break;
      buffer[count++] = (char)ch;
      ch = _getche();
   }
   _ungetch( ch );            /* Put back delimiter. */
   buffer[count] = '\0';      /* Null terminate the token. */
   printf( "\ntoken = %s\n", buffer );
}

Output

White
token = White


Description: _unlink
  _unlink

#include <io.h>

#include <stdio.h>

int _unlink( const char *filename );

filename    Name of file to remove

Remarks

The _unlink function deletes the file specified by filename.

Return Value

If successful, _unlink returns 0; otherwise, it returns −1 and sets errno to one of two constants, EACCES, which means the path specifies a read-only file, or ENOENT, which means the file or path is not found or the path specified a directory.

See Also

»_close,« »remove«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _unlink for compatibility with ANSI naming conventions of non-ANSI functions. Use unlink and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* UNLINK.C: This program uses _unlink to delete UNLINK.OBJ. */

#include <stdio.h>

void main( void )
{
   if( _unlink( "unlink.obj" ) == -1 )
      perror( "Could not delete 'UNLINK.OBJ'" );
   else
      printf( "Deleted 'UNLINK.OBJ'\n" );
}

Output

Deleted 'UNLINK.OBJ'


Description: _unregisterfonts
  _unregisterfonts

#include <graph.h>

void __far _unregisterfonts( void );

Remarks

The _unregisterfonts function frees memory previously allocated and used by the _registerfonts function. The _unregisterfonts function removes the header information for all fonts and unloads the currently selected font data from memory. Any attempt to use the _setfont function or the _outgtext function after calling _unregisterfonts results in an error.

Return Value

None.

See Also

»_getfontinfo,« »_getgtextextent,« »_outgtext,« »_registerfonts,« »_setfont«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_outgtext.«


Description: _utime
  _utime

#include <sys\types.h>

#include <sys\utime.h>

int _utime( char *filename, struct _utimbuf *times );

filename    Filename

times    Pointer to stored time values

Remarks

The _utime function sets the modification time for the file specified by filename. The process must have write access to the file; otherwise, the time cannot be changed. Although the _utimbuf structure contains a field for access time, only the modification time is set with MS-DOS. If times is a NULL pointer, the modification time is set to the current time. Otherwise, times must point to a structure of type _utimbuf, defined in SYS\UTIME.H. The modification time is set from the modtime field in this structure.

Return Value

The _utime function returns the value 0 if the file-modification time was changed. A return value of −1 indicates an error, and errno is set to one of the following values:

EACCES    Path specifies directory or read-only file

EINVAL     Invalid argument; the times argument is invalid

EMFILE    Too many open files (the file must be opened to change its modification time)

ENOENT     Filename or path not found

See Also

»asctime,« »ctime,« »_fstat,« »_ftime,« »gmtime,« »localtime,« »_stat,« »time«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _utime for compatibility with ANSI naming conventions of non-ANSI functions. Use utime and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* UTIME.C: This program uses _utime to set the
 * file-modification time to the current time.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys\types.h>
#include <sys\utime.h>

void main( void )
{
   /* Show file time before and after. */
   system( "dir utime.c" );
   if( _utime( "utime.c", NULL ) == -1 )
      perror( "_utime failed\n" );
   else
      printf( "File time modified\n" );
   system( "dir utime.c" );
}

Output

 Volume in drive C is CDRIVE
 Volume Serial Number is 1966-6F27

 Directory of C:\ajax\print\lang\libref\code

UTIME    C                  469 03-19-93  02:42PM
               1 File(s)        469 bytes
                           12083200 bytes free
 Volume in drive C is CDRIVE
 Volume Serial Number is 1966-6F27

 Directory of C:\ajax\print\lang\libref\code

UTIME    C                  469 03-19-93  02:42PM
               1 File(s)        469 bytes
                           12083200 bytes free


Description: va_arg, va_end, va_start
  va_arg, va_end, va_start

#include <stdarg.h>    Required for ANSI compatibility

#include <varargs.h>    Required for UNIX V compatibility

#include <stdio.h>

type va_arg( va_list arg_ptr, type );

void va_end( va_list arg_ptr );

void va_start( va_list arg_ptr );    (UNIX version)

void va_start( va_list arg_ptr, prev_param );    (ANSI)

arg_ptr    Pointer to list of arguments

prev_param    Parameter preceding first optional argument (ANSI only)

type    Type of argument to be retrieved

Remarks

The va_arg, va_end, and va_start macros provide a portable way to access the arguments to a function when the function takes a variable number of arguments. Two versions of the macros are available: the macros defined in STDARG.H conform to the ANSI C standard, and the macros defined in VARARGS.H are compatible with the UNIX System V definition. The macros are listed following:

va_alist    Name of parameter to called function (UNIX version only)

va_arg    Macro to retrieve current argument

va_dcl    Declaration of va_alist (UNIX version only)

va_end    Macro to reset arg_ptr

va_list    The typedef for the pointer to list of arguments

va_start    Macro to set arg_ptr to beginning of list of optional arguments (UNIX version only)

Both versions of the macros assume that the function takes a fixed number of required arguments, followed by a variable number of optional arguments. The required arguments are declared as ordinary parameters to the function and can be accessed through the parameter names. The optional arguments are accessed through the macros in STDARG.H or VARARGS.H, which set a pointer to the first optional argument in the argument list, retrieve arguments from the list, and reset the pointer when argument processing is completed.

The ANSI C standard macros, defined in STDARG.H, are used as follows:

1.	All required arguments to the function are declared as parameters in the usual way. The va_dcl macro is not used with the STDARG.H macros.

2.	The va_start macro sets arg_ptr to the first optional argument in the list of arguments passed to the function. The argument arg_ptr must have va_list type. The argument prev_param is the name of the required parameter immediately preceding the first optional argument in the argument list. If prev_param is declared with the register storage class, the macro's behavior is undefined. The va_start macro must be used before va_arg is used for the first time.

3.	The va_arg macro retrieves a value of type from the location given by arg_ptr and increments arg_ptr to point to the next argument in the list, using the size of type to determine where the next argument starts. The va_arg macro can be used any number of times within the function to retrieve arguments from the list.

4.	After all arguments have been retrieved, va_end resets the pointer to NULL.

The UNIX System V macros, defined in VARARGS.H, operate in a slightly different manner, as follows:

1.	Any required arguments to the function can be declared as parameters in the usual way.

2.	The last (or only) parameter to the function represents the list of optional arguments. This parameter must be named va_alist (not to be confused with va_list, which is defined as the type of va_alist).

3.	The va_dcl macro appears after the function definition and before the opening left brace of the function. This macro is defined as a complete declaration of the va_alist parameter, including the terminating semicolon; therefore, no semicolon should follow va_dcl.

4.	Within the function, the va_start macro sets arg_ptr to the beginning of the list of optional arguments passed to the function. The va_start macro must be used before va_arg is used for the first time. The argument arg_ptr must have va_list type.

5.	The va_arg macro retrieves a value of type from the location given by arg_ptr and increments arg_ptr to point to the next argument in the list, using the size of type to determine where the next argument starts. The va_arg macro can be used any number of times within the function to retrieve the arguments from the list.

6.	After all arguments have been retrieved, va_end resets the pointer to NULL.

Return Value

The va_arg macro returns the current argument; va_start and va_end do not return values.

See Also

»vfprintf«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* VA.C: The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_end
 *      va_list             va_decl (UNIX only)
 */

#include <stdio.h>
#define ANSI            /* Comment out for UNIX version     */
#ifdef ANSI             /* ANSI compatible version          */
#include <stdarg.h>
int average( int first, ... );
#else                   /* UNIX compatible version          */
#include <varargs.h>
int average( va_list );
#endif

void main( void )
{
   /* Call with 3 integers (-1 is used as terminator). */
   printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );

   /* Call with 4 integers. */
   printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );

   /* Call with just -1 terminator. */
   printf( "Average is: %d\n", average( -1 ) );
}

/* Returns the average of a variable list of integers. */
#ifdef ANSI             /* ANSI compatible version    */
int average( int first, ... )
{
   int count = 0, sum = 0, i = first;
   va_list marker;

   va_start( marker, first );     /* Initialize variable arguments. */
   while( i != -1 )
   {
      sum += i;
      count++;
      i = va_arg( marker, int);
   }
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#else    /* UNIX compatible version must use old-style definition. */
int average( va_alist )
va_dcl
{
   int i, count, sum;
   va_list marker;

   va_start( marker );            /* Initialize variable arguments. */
   for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )
      sum += i;
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#endif

Output

Average is: 3
Average is: 8
Average is: 0


Description: vprintf functions
  vfprintf, vfwprintf, vprintf, vwprintf, vsprintf, vswprintf, _vsnprintf, _vsnwprintf

#include <stdio.h>    For single-byte character vprintf functions

#include <varargs.h>    Required for UNIX System V compatibility

#include <stdarg.h>    Required for ANSI compatibility

#include <wchar.h>    For vwprintf, vfwprintf, vswprintf, and _vsnwprintf use WCHAR.H (for ANSI compatibility) or STDIO.H

int vfprintf( FILE *stream, const char *format, va_list argptr );

int vfwprintf( FILE *stream, const wchar_t *format, va_list argptr);

int vprintf( const char *format, va_list argptr );

int vwprintf( const wchar_t *format, va_list argptr );

int vsprintf( char *buffer, const char *format, va_list argptr );

int vswprintf( wchar_t *buffer, size_t count, const wchar_t *format, va_list argptr );

int _vsnprintf( char *buffer, size_t count, const char *format, va_list argptr );

int _vsnwprintf( wchar_t *buffer, size_t count, const wchar_t *format, va_list argptr );

argptr    Pointer to list of arguments

buffer    Storage location for output

count    Maximum number of bytes to write

format    Format specification

stream    Pointer to FILE structure

Remarks

The vprintf functions are similar to their counterpart functions as listed in the following table. The difference is that each vprintf function accepts a pointer to an argument list, whereas each of the counterpart functions accepts an argument list.

These functions format data for output to destinations as follows:

Function	Counterpart Function	Output Destination
vfprintf	fprintf	stream
vfwprintf	fwprintf	stream
vprintf	printf	standard output
vwprintf	wprintf	memory pointed to by buffer
vsprintf	sprintf	memory pointed to by buffer
vswprintf	swprintf	memory pointed to by buffer
_vsnprintf	sprintf	memory pointed to by buffer
_vsnwprintf	_snwprintf	memory pointed to by buffer
The argptr argument has type va_list, which is defined in the include files VARARGS.H and STDARG.H. The argptr variable must be initialized by the va_start macro, and may be reinitialized by subsequent va_arg calls; argptr then points to the beginning of a list of arguments that are converted and transmitted for output according to the corresponding specifications in the format argument. The format argument has the same form and function as the format argument for the printf function; for a description of format, see »printf.« None of these functions invokes the va_end macro. For a more complete description of each of the vprintf functions, see the description of its counterpart function.

The _vsnprintf function differs from vsprintf in that it writes no more than count bytes to buffer.

The vfwprintf, _vsnwprintf, vswprintf, and vwprintf functions are wide-character versions of vfprintf, _vsnprintf, vsprintf, and vprintf, respectively; in each of these wide-character functions, buffer and format are wide-character strings. Otherwise, each of these wide-character functions behaves identically to its narrow-character counterpart function.

For vsprintf, vswprintf, _vsnprintf and _vsnwprintf, if copying occurs between strings that overlap, the behavior is undefined.

Return Value

The return value for each of these functions is the number of characters written, not including the terminating null character, or a negative value if an output error occurs. For vswprintf, a negative value is also returned if count or more wide characters are requested to be written. For _vsnprintf, if the number of bytes to write exceeds buffer, then count bytes are written and −1 is returned.

See Also

»fprintf,« »printf,« »sprintf,« »va_arg,« »va_end,« »va_start«

Compatibility

vfprintf, vsprintf:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

vprintf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_vsnprintf:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

fwprintf, vswprintf, _vsnwprintf, vwprintf:
ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * WPRINTF.C shows how to use vprintf functions to write new
 * versions of printf. Functions in this catagory include:
 *      vsprintf     vprintf     vfprintf     _vsnprintf
 *
 * The vsprintf function is used in the example. The other
 * variations can be used similarly. For other examples of
 * formatted output, see EXTDIR.C (sprintf), TABLE.C
 * (fprintf), and PRINTF.C.
 */

#include <stdio.h>
#include <graph.h>
#include <string.h>
#include <stdarg.h>
#include <malloc.h>

int winprntf( short row, short col, short clr, long bclr,
              char *fmt, ... );

void main()
{
    short fgd = 0;
    long  bgd = 0L;

    _clearscreen( _GCLEARSCREEN );
    _outtext( "Color text example:\n\n" );

    /* Loop through 8 background colors. */
    for( bgd = 0L; bgd < 8; bgd++ )
    {
        winprntf( (short)(bgd + 3), 1, 15, bgd, "Back: %d Fore:",
                  bgd );

        /* Loop through 16 foreground colors. */
        for( fgd = 0; fgd < 16; fgd++ )
            winprntf( -1, -1, fgd, -1L, " %2d ", fgd );
    }
}

/* Full-screen window version of printf that takes row, column,
 * textcolor, and background color as its first arguments, followed
 * by normal printf format strings (except that \t is not handled).
 * You can specify -1 for any of the first arguments to use the
 * current value. The function returns the number of characters
 * printed, or a negative number for errors.
 */
int winprntf( short row, short col, short clr, long bclr,
              char *fmt, ... )
{
    struct  _rccoord tmppos;
    va_list marker;
    char    *buffer;
    int     increment = 256, size = increment, written = -1;

    /* Set text position. */
    tmppos = _gettextposition();
    if( row < 1 )
        row = tmppos.row;
    if( col < 1 )
        col = tmppos.col;
    _settextposition( row, col );

    /* Set foreground and background colors. */
    if( clr >= 0 )
        _settextcolor( clr );
    if( bclr >= 0 )
        _setbkcolor( bclr );

    /* Write text to a string and output the string. */
    va_start( marker, fmt );
    while ( written == -1 )
    {
        if(( buffer = (char *)malloc( size )) == NULL )
            return -1;
        written = _vsnprintf( buffer, size, fmt, marker );
        if ( written == -1 )
        {
             size += increment;
        }
     }
    va_end( marker );
    _outtext( buffer );
    free( buffer );
    return written;
}


Description: _vfree
  _vfree

#include <vmemory.h>

void __far _vfree( _vmhnd_t handle );

handle    Handle to previously allocated virtual memory block

Remarks

The _vfree function deallocates a virtual memory block. The argument handle points to a virtual memory block previously allocated through a call to _vmalloc or _vrealloc. The number of bytes freed is the number of bytes specified when the block was allocated (or reallocated, in the case of _vrealloc). The block must be unlocked before it is freed; use »_vlockcnt« to ensure that the block is unlocked. After the call, the freed block is available for reuse by the virtual heap.

Return Value

None.

See Also

»_vlock,« »_vlockcnt,« »_vmalloc,« »_vrealloc,« »_vunlock«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_vmalloc.«


Description: _vheapinit
  _vheapinit

#include <vmemory.h>

int __far _vheapinit( unsigned int dosmin, unsigned int dosmax, unsigned int swaparea );

dosmin    Minimum amount of MS-DOS memory that must be available for the virtual memory manager to install itself, in paragraphs

dosmax    Maximum amount of MS-DOS memory that the virtual memory manager can use, in paragraphs

swaparea    Type of auxiliary memory to use

Remarks

The _vheapinit routine initializes the virtual memory manager in preparation for future allocations. It must be called before any virtual memory blocks are requested. The _vheapinit function may round up the minimum value specified. After rounding, if the minimum amount of MS-DOS memory is not available, _vheapinit does not initialize the virtual memory manager and returns 0. The virtual memory manager requires several kilobytes to function effectively. If _VM_ALLDOS is specified for the dosmax argument, the virtual memory manager uses all available MS-DOS memory. The swaparea argument specifies which types of auxiliary memory the virtual memory manager can use to hold blocks of memory that are swapped out. The argument can be one or more of the following manifest constants, combined with the bitwise-OR operator ( | ):

_VM_EMS    Use expanded memory

_VM_XMS    Use extended memory

_VM_DISK    Use disk space

_VM_ALLSWAP    ( _VM_EMS | _VM_XMS | _VM_DISK )

If not all of the specified forms of storage are available, the virtual memory manager uses what is available.

After the program is done using virtual memory, it must call _vheapterm to terminate the virtual memory manager. A program can contain multiple pairs of _vheapinit/_vheapterm calls.

Warning  If the program terminates without a call to _vheapterm, various system memory resources may not be available to subsequent programs.

To specify that no minimum amount of memory is required for installation of the virtual memory manager and to use all available MS-DOS memory in the virtual heap and all auxiliary storage, use the following command:

if( _vheapinit( 0, _VM_ALLDOS, _VM_ALLSWAP) == 0 )
   /* Error */

Return Value

The _vheapinit function returns a nonzero value if the virtual memory manager was successfully initialized. Otherwise, it returns 0.

See Also

»_vheapterm«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_vmalloc.«


Description: _vheapterm
  _vheapterm

#include <vmemory.h>

void __far _vheapterm( void );

Remarks

The _vheapterm function terminates the virtual memory manager and releases all resources that it used.

Warning  If the program terminates without a call to _vheapterm, various system memory resources may not be available to subsequent programs. If the virtual memory manager has not been initialized or has already been terminated when _vheapterm is called, the function returns immediately.

Return Value

None.

See Also

»_vheapinit«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_vmalloc.«


Description: _vload
  _vload

#include <vmemory.h>

void __far *__far _vload( _vmhnd_t handle, int dirty );

handle    Handle to previously allocated virtual memory block

dirty    Flag indicating whether the block should be written out or discarded when swapping occurs

Remarks

The _vload function loads a virtual memory block into MS-DOS memory and returns a far pointer to it. The argument handle points to a virtual memory block previously allocated through a call to _vmalloc or _vrealloc. The block of memory is not locked and may be swapped out if the virtual memory manager needs the memory. Consequently, the pointer returned by _vload is valid only until the next call to the virtual memory manager.

The dirty flag indicates whether the block of memory should be written out or discarded when swapping occurs. It can have the value _VM_CLEAN, which means the program discards the contents of the block when swapping occurs, or _VM_DIRTY, which means the program writes the contents of the block to auxiliary memory when swapping occurs.

Return Value

The _vload function returns a far pointer to MS-DOS memory if the virtual memory block is successfully loaded. If insufficient MS-DOS memory is available, _vload returns NULL.

See Also

»_vlock,« »_vmalloc,« »_vunlock«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * VLOAD.C: This program loads a block of virtual memory with _vload,
 * writes to it, and loads in a new block. It then reloads the first
 * block and verifies that its contents haven't changed.
 */

#include <stdio.h>
#include <stdlib.h>
#include <vmemory.h>

void main()
{
    int i, flag;
    _vmhnd_t handle1,
             handle2;
    int __far *buffer1;
    int __far *buffer2;

    if ( !_vheapinit( 0, _VM_ALLDOS, _VM_XMS | _VM_EMS ) )
    {
        printf( "Could not initialize virtual memory manager. \n" );
        exit( -1 );
    }

    if ( ( (handle1 = _vmalloc( 100 * sizeof(int) )) == _VM_NULL ) ||
         ( (handle2 = _vmalloc( 100 * sizeof(int) )) == _VM_NULL )   )
    {
        _vheapterm();
        exit( -1 );
    }

    printf( "Two blocks of virtual memory allocated.\n" );

    if ( (buffer1 = (int __far *)_vload( handle1, _VM_DIRTY )) == NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    printf( "buffer1 loaded: valid until next call to VM manager.\n" );
    for ( i = 0; i < 100; i++ )      /* write to buffer1 */
        buffer1[i] = i;

    if ( (buffer2 = (int __far *)_vload( handle2, _VM_DIRTY )) == NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    printf( "buffer2 loaded. buffer 1 no longer valid.\n" );

    if ( (buffer1 = (int __far *)_vload( handle1, _VM_CLEAN )) == NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    printf( "buffer1 reloaded.\n" );

    flag = 0;
    for ( i = 0; i < 100; i++ )
        if ( buffer1[i] != i )
            flag = 1;

    if ( !flag )
        printf( "contents of buffer1 verified.\n" );

    _vfree( handle1 );
    _vfree( handle2 );
    _vheapterm();
}

Output

Two blocks of virtual memory allocated.
buffer1 loaded: valid until next call to VM manager.
buffer2 loaded. buffer 1 no longer valid.
buffer1 reloaded.
contents of buffer1 verified.


Description: _vlock
  _vlock

#include <vmemory.h>

void __far *__far _vlock( _vmhnd_t handle );

handle    Handle to previously allocated virtual memory block

Remarks

The _vlock function loads a virtual memory block into MS-DOS memory, locks it, and returns a far pointer to it. The argument handle points to a virtual memory block previously allocated through a call to _vmalloc or _vrealloc. A locked virtual memory block will not be swapped out until it is unlocked. A virtual memory block can be locked up to 255 times. The pointer returned by _vlock remains valid until an equal number of unlock operations is performed. Because MS-DOS memory may be scarce, try to keep the number of blocks locked at one time to a minimum and use _vunlock to unlock them as soon as possible.

Return Value

The _vlock function returns a far pointer to MS-DOS memory if the virtual memory block is successfully loaded and locked. If insufficient MS-DOS memory is available, _vload returns NULL.

See Also

»_vlockcnt,« »_vmalloc,« »_vunlock«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * VLOCK.C: This program locks a block of virtual memory using _vlock,
 * writes to it, loads in a new block with _vload, and then verifies
 * that the contents of the locked block are still accessible. It then
 * unlocks the block with _vunlock.
 */

#include <stdio.h>
#include <stdlib.h>
#include <vmemory.h>

void main()
{
    int i, flag;
    _vmhnd_t handle1,
             handle2;
    int __far *buffer1;
    int __far *buffer2;

    if ( !_vheapinit( 0, _VM_ALLDOS, _VM_XMS | _VM_EMS ) )
    {
        printf( "Could not initialize virtual memory manager. \n" );
        exit( -1 );
    }

    if ( ( (handle1 = _vmalloc( 100 * sizeof(int) )) == _VM_NULL ) ||
         ( (handle2 = _vmalloc( 100 * sizeof(int) )) == _VM_NULL )   )
    {
        _vheapterm();
        exit( -1 );
    }

    printf( "Two blocks of virtual memory allocated.\n" );

    if ( (buffer1 = (int __far *)_vlock( handle1 )) == NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    printf( "buffer1 locked: valid until unlocked.\n" );
    for ( i = 0; i < 100; i++ )      /* write to buffer1 */
        buffer1[i] = i;

    if ( (buffer2 = (int __far *)_vload( handle2, _VM_DIRTY )) == NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    printf( "buffer2 loaded. buffer 1 still valid.\n" );

    flag = 0;
    for ( i = 0; i < 100; i++ )
        if ( buffer1[i] != i )
            flag = 1;

    if ( !flag )
        printf( "contents of buffer1 verified.\n" );

    _vunlock( handle1, _VM_DIRTY );
    _vfree( handle1 );
    _vfree( handle2 );
    _vheapterm();
}

Output

Two blocks of virtual memory allocated.
buffer1 locked: valid until unlocked.
buffer2 loaded. buffer 1 still valid.
contents of buffer1 verified.


Description: _vlockcnt
  _vlockcnt

#include <vmemory.h>

unsigned int __far _vlockcnt( _vmhnd_t handle );

handle    Handle to previously allocated virtual memory block

Remarks

The _vlockcnt function returns the number of times a virtual memory block has been locked. The argument handle points to a virtual memory block previously allocated through a call to _vmalloc or _vrealloc. Use the _vlockcnt function to ensure that a block is unlocked before it is freed (using _vfree).

Return Value

The _vlockcnt function returns the number of locks held on the specified virtual memory block.

See Also

»_vlock,« »_vmalloc,« »_vunlock«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * VCNT.C: This program locks a block of virtual memory five times with
 * _vlock, and then unlocks it five times with _vunlock, calling
 * _vlockcnt after each operation to report the number of locks held.
 */

#include <stdio.h>
#include <stdlib.h>
#include <vmemory.h>

void main()
{
    int i, count;
    _vmhnd_t handle;
    int __far *buffer;

    if ( !_vheapinit( 0, _VM_ALLDOS, _VM_XMS | _VM_EMS ) )
    {
        printf( "Could not initialize virtual memory manager. \n" );
        exit( -1 );
    }

    if ( (handle = _vmalloc( 100 * sizeof(int) )) == _VM_NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    printf( "Block of virtual memory allocated.\n" );

    printf( "Locking...\n" );
    for ( i = 0; i < 5; i++ )
    {
        if ( (buffer = (int __far *)_vlock( handle )) == NULL )
        {
            _vheapterm();
            exit( -1 );
        }

        count = _vlockcnt( handle );
        printf( "%d locks held.\n", count );
    }

    printf("Unlocking...\n" );
    for ( i = 0; i < 5; i++ )
    {
        _vunlock( handle, _VM_CLEAN );

        count = _vlockcnt( handle );
        printf( "%d locks held.\n", count );
    }

    _vfree( handle );
    _vheapterm();
}

Output

Block of virtual memory allocated.
Locking...
1 locks held.
2 locks held.
3 locks held.
4 locks held.
5 locks held.
Unlocking...
4 locks held.
3 locks held.
2 locks held.
1 locks held.
0 locks held.


Description: _vmalloc
  _vmalloc

#include <vmemory.h>

_vmhnd_t __far _vmalloc( unsigned long size );

size    Bytes to allocate

Remarks

The _vmalloc function allocates a virtual memory block of at least size bytes. The actual size of the allocated block may be larger than size bytes to allow the virtual memory manager to operate more efficiently; use _vmsize to find the actual size of the block. The value returned by _vmalloc is a handle that uniquely identifies the virtual memory block. This value is not an address and cannot be used to access memory directly. The value must be passed to either the _vload or _vlock function to obtain a valid address.

Return Value

The _vmalloc function returns a handle to the allocated virtual memory block, or _VM_NULL if insufficient memory is available or if the requested block size is too large to load into MS-DOS memory.

See Also

»_vfree,« »_vmsize,« »_vrealloc«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * VMALLOC.C: This program allocates a block of virtual
 * memory with _vmalloc and uses _vmsize to display the
 * size of that block. Next, it uses _vrealloc to expand
 * the amount of virtual memory and calls _vmsize again
 * to display the new amount of memory allocated.
 */

#include <stdio.h>
#include <stdlib.h>
#include <vmemory.h>

void main( void )
{
    _vmhnd_t handle;
    unsigned long block_size;

    if ( !_vheapinit( 0, _VM_ALLDOS, _VM_XMS | _VM_EMS ) )
    {
        printf( "Could not initialize virtual memory manager.\n" );
        exit( -1 );
    }

    printf( "Requesting 100 bytes of virtual memory.\n" );
    if ( (handle = _vmalloc( 100 )) == _VM_NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    block_size = _vmsize( handle );
    printf( "Received %lu bytes of virtual memory.\n", block_size );

    printf( "Resizing block to 200 bytes. \n" );
    if ( (handle = _vrealloc( handle, 200 )) == _VM_NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    block_size = _vmsize( handle );
    printf( "Block resized to %lu bytes.\n", block_size );

    _vfree( handle );
    _vheapterm();
}

Output

Requesting 100 bytes of virtual memory.
Received 100 bytes of virtual memory.
Resizing block to 200 bytes.
Block resized to 200 bytes.


Description: _vmsize
  _vmsize

#include <vmemory.h>

unsigned long __far _vmsize( _vmhnd_t handle );

handle    Handle to previously allocated virtual memory block

Remarks

The _vmsize function returns the size, in bytes, of a virtual memory block. The argument handle points to a virtual memory block previously allocated through a call to _vmalloc or _vrealloc. The size returned may be larger than the size requested in the call to _vmalloc or _vrealloc.

Return Value

The _vmsize function returns the size (in bytes) of the specified virtual memory block as an unsigned long.

See Also

»_vmalloc«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_vrealloc.«


Description: _vrealloc
  _vrealloc

#include <vmemory.h>

_vmhnd_t __far _vrealloc( _vmhnd_t handle, unsigned long size );

handle    Handle to previously allocated virtual memory block

size    New size in bytes

Remarks

The _vrealloc function changes the size of a virtual memory block. If handle is _VM_NULL, _vrealloc behaves in the same way as _vmalloc and allocates a new block of size bytes. If handle is not _VM_NULL, it must point to a virtual memory block previously allocated through a call to _vmalloc or _vrealloc. The size argument gives the new size of the block, in bytes. The size of the block may be larger than size bytes to allow the virtual memory manager to operate more efficiently; use _vmsize to find the actual size of the block. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block may be in a different location.

Return Value

The _vrealloc function returns a handle to the reallocated (and possibly moved) virtual memory block. The return value is _VM_NULL if the size specified is zero and the handle argument is not _VM_NULL. In this case, the original block is freed. The return value is also _VM_NULL if there is not enough available memory to expand the block to the requested size, if the requested block size is too large to load into MS-DOS memory, or if the given handle is still locked. In these cases, the original block is still valid.

See Also

»_vfree,« »_vmalloc,« »_vmsize«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * VRSIZE.C: This program allocates a block of virtual memory with
 * _vmalloc and uses _vmsize to display the size of that block. Next,
 * it uses _vrealloc to expand the amount of virtual memory and calls
 * _vmsize again to display the new amount of memory allocated.
 */

#include <stdio.h>
#include <stdlib.h>
#include <vmemory.h>

void main()
{
    _vmhnd_t handle;
    unsigned long block_size;

    if ( !_vheapinit( 0, _VM_ALLDOS, _VM_XMS | _VM_EMS ) )
    {
        printf( "Could not initialize virtual memory manager.\n" );
        exit( -1 );
    }

    printf( "Requesting 100 bytes of virtual memory.\n" );
    if ( (handle = _vmalloc( 100 )) == _VM_NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    block_size = _vmsize( handle );
    printf( "Received %d bytes of virtual memory.\n", block_size );

    printf( "Resizing block to 200 bytes. \n" );
    if ( (handle = _vrealloc( handle, 200 )) == _VM_NULL )
    {
        _vheapterm();
        exit( -1 );
    }

    block_size = _vmsize( handle );
    printf( "Block resized to %d bytes.\n", block_size );

    _vfree( handle );
    _vheapterm();
}

Output

Requesting 100 bytes of virtual memory.
Received 100 bytes of virtual memory.
Resizing block to 200 bytes.
Block resized to 200 bytes.


Description: _vunlock
  _vunlock

#include <vmemory.h>

void __far _vunlock( _vmhnd_t handle, int dirty );

handle    Handle to previously allocated virtual memory block

dirty    Flag indicating whether block should be written out or discarded when swapping occurs

Remarks

The _vunlock function unlocks a virtual memory block. The argument handle points to a virtual memory block previously allocated through a call to _vmalloc or _vrealloc and locked through a call to _vlock. If multiple locks are held on the virtual memory block, the block's lock count is decremented by one. If the block's lock count goes to zero, the block can be swapped out by the virtual memory manager. The pointer returned by _vlock when the block was first locked then becomes invalid.

The dirty flag indicates whether the block should be written out or discarded when swapping occurs. It can have one of the following values:

_VM_CLEAN    Discard contents of block when swapping occurs

_VM_DIRTY    Write contents of block to auxiliary memory when swapping occurs

Return Value

None.

See Also

»_vlock,« »_vlockcnt,« »_vmalloc«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_vlock.«


Description: _wabout
  _wabout

#include <io.h>

int _wabout( char *string );

string    Pointer to a null-terminated string

Remarks

The _wabout function sets the string that appears in the About dialog box of a QuickWin program. This routine is used only in QuickWin programs; it is not part of the Windows API. When the user chooses the About command from the Help menu, a dialog box appears containing the string set with _wabout. If a QuickWin program does not include a call to _wabout, information about QuickWin itself is displayed by default. The maximum string length is 256 bytes.

Return Value

If successful, _wabout returns 0. A nonzero return value indicates an error.

See Also

»_fwopen,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetexit,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WABOUT.C - Demonstrate setting the QuickWin
 * About dialog box string with _wabout
 */

#include <stdio.h>
#include <io.h>

char string[512];

void main( void )
{
   int nRes;

   for ( ; ; )
   {
      printf( "\nEnter the About string: " );
      gets(string);
      printf( "\nAbout string = %s\n", string );
      printf( "Setting about string..." );
      nRes = _wabout( string );
      printf( "_wabout result = %i", nRes );
      printf( "\nTry 'About' in the Help menu\n" );
   }
}


Description: _wclose
  _wclose

#include <io.h>

int _wclose( int wfh, int persist );

wfh    File handle to a QuickWin window

persist    Flag indicating whether the window stays on the screen after closing

Remarks

The _wclose function closes a QuickWin window. The window must have been previously opened with the QuickWin function _wopen. This routine is used only in QuickWin programs; it is not part of the Windows API.

To close a window opened with _wopen, pass its file handle to _wclose. To close a window opened with _fwopen, call the STDIO.H function fclose. The persist flag can have one two values, _WINNOPERSIST, which means erase the closed window, or _WINPERSIST, which means leave the window on the screen. If the window remains on the screen, another _wclose call to the same file handle with _WINNOPERSIST removes it. While the window remains visible, the user can copy and paste text in it, choose QuickWin menus, and operate the window's scroll bars. Regardless of which persist option is used, the window's file handle is closed to all further I/O. If a window is opened with the same title as a window closed with persistence, it will be a different window. Windows closed with persistence count against the total number of open windows (20 by default).

Return Value

If successful, _wclose returns 0. A return value of −1 indicates an error; errno is set to EBADF, indicating an invalid file-handle argument.

See Also

»_fwopen,« »_wabout,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetexit,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WCLOSE.C - Demonstrate closing QuickWin windows
 *
 */

#include <fcntl.h>
#include <stdio.h>
#include <io.h>
#include <stdlib.h>

#define PERSISTFLAG _WINNOPERSIST
#define OPENFLAGS   _O_RDWR

void main( void )
{
   int wfh;   /* File handle for window */
   int nRes;  /* Window write results */
   int wc;    /* Window closure results */
   struct _wopeninfo wininfo; /* Open information */

   /* Set up window open information */
   wininfo._version = _QWINVER;
   wininfo._title = "Window Closing";
   wininfo._wbufsize = _WINBUFDEF;

   /* Open a window with _wopen */
   wfh = _wopen( &wininfo, NULL, OPENFLAGS );
   if( wfh == -1 )
   {
      printf( "***ERROR: On _wopen\n" );
      exit( -1 );
   }

   /* Write in the window */
   nRes = write( wfh, "Windows Everywhere!\n", 20 );

   /* Close the window with _wclose */
   wc = _wclose( wfh, PERSISTFLAG );

   exit( 0 );
}


Description: wcstombs, _fwcstombs
  wcstombs, _fwcstombs

#include <stdlib.h>

size_t wcstombs( char *mbstr, const wchar_t *wcstr, size_t count );

size_t __far _fwcstombs( char __far *mbstr, const wchar_t __far *wcstr, size_t count );

mbstr    The address of a sequence of multibyte characters

wcstr    The address of a sequence of wide characters

count    The maximum number of bytes that can be stored in the multibyte output string

Remarks

The wcstombs function converts the wide character string pointed to by wcstr to the corresponding multibyte characters and stores the results in the mbstr array. The count parameter indicates the maximum number of bytes that can be stored in the multibyte output string (that is, the size of mbstr). In general, it is not known how many bytes will be required when converting a wide character string. Some wide characters will require only one byte in the output string, others will require two. If there are two bytes in the multibyte output string for every wide character in the input string (including the wide character NULL), the result is guaranteed to fit.

If wcstombs encounters the wide-character null character (L'\0') either before or when count occurs, it converts it to the multibyte null character (a 16-bit 0) and stops. Thus, the multibyte character string at mbstr is null-terminated only if wcstombs encounters a wide-character null character during conversion. If the sequences pointed to by wcstr and mbstr overlap, the behavior of wcstombs is undefined.

If the mbstr argument is NULL, the wcstombs function returns the required size of the destination string.

The _fwcstombs function is a 16-bit model-independent (large-model) form of the wcstombs function.

Return Value

If either wcstombs or _fwcstombs successfully converts the multibyte string, it returns the number of bytes written into the multibyte output string, excluding the terminating NULL (if any). If the mbstr argument is NULL, these functions return the required size of the destination string. If either function encounters a wide character that cannot be converted to a multibyte character, it returns −1 cast to type size_t.

See Also

»mblen,« »mbstowcs,« »mbtowc,« »wctomb«

Compatibility

wcstombs:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fwcstombs:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* WCSTOMBS.CPP illustrates the behavior of the wcstombs function */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int      i;
   char    *pmbbuf   = (char *)malloc( MB_CUR_MAX );
   wchar_t *pwcEOL   = (wchar_t *)malloc( MB_CUR_MAX );
   wchar_t *pwchello = L"Hello, world.";

   *pwcEOL   = L'\0';
   printf( "Convert entire wide-character string:\n" );
   i = wcstombs( pmbbuf, pwchello, MB_CUR_MAX );
   printf( "\tCharacters converted: %u\n", i );
   printf( "\tMultibyte character: %s\n\n", pmbbuf );

   printf( "Attempt to convert null character:\n" );
   i = wcstombs( pmbbuf, pwcEOL, MB_CUR_MAX );
   printf( "\tCharacters converted: %u\n", i );
   printf( "\tMultibyte character: %s\n\n", pmbbuf );
}

Output

Convert entire wide-character string:
   Characters converted: 1
   Multibyte character: H

Attempt to convert null character:
   Characters converted: 0
   Multibyte character:


Description: wctomb, _fwctomb
  wctomb, _fwctomb

#include <stdlib.h>

int wctomb( char *mbchar, wchar_t wchar );

int __far _fwctomb( char __far *mbchar, wchar_t wchar );

mbchar    The address of a multibyte character

wchar    A wide character

Remarks

The wctomb function converts its wchar argument to the corresponding multibyte character and stores the result at mbchar. The _fwctomb function is a 16-bit model-independent (large-model) form of the wctomb function. It can be called from any point in any program.

Return Value

If either wctomb or _fwctomb converts the wide character to a multibyte character, it returns the number of bytes (which is never greater than MB_CUR_MAX) in the wide character. If wchar is the wide-character null character (L'\0'), wctomb returns 0. If the conversion is not possible in the current locale, wctomb returns −1.

See Also

»mblen,« »mbstowcs,« »mbtowc,« »wcstombs«

Compatibility

wctomb:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

_fwctomb:    ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* WCTOMB.CPP illustrates the behavior of the wctomb function */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int i;
   wchar_t wc = L'a';
   char *pmbnull = NULL;
   char *pmb = (char *)malloc( sizeof( char ) );

   printf( "Convert a wide character:\n" );
   i = wctomb( pmb, wc );
   printf( "\tCharacters converted: %u\n", i );
   printf( "\tMultibyte character: %.1s\n\n", pmb );

   printf( "Attempt to convert when target is NULL:\n" );
   i = wctomb( pmbnull, wc );
   printf( "\tCharacters converted: %u\n", i );
   printf( "\tMultibyte character: %.1s\n", pmbnull );
}

Output

Convert a wide character:
   Characters converted: 1
   Multibyte character: a

Attempt to convert when target is NULL:
   Characters converted: 0
   Multibyte character: (


Description: _wgclose
  _wgclose

#include <stdio.h>

#include <graph.h>

short __far __cdecl _wgclose( int handle );

handle    Handle of the window to be closed

Remarks

The _wgclose function closes an existing graphics child window, freeing all memory associated with the window. Closing the active graphics child window causes all graphics output to fail until a new window is activated. See »_wgsetactive« for more information. This routine is used only in QuickWin programs; it is not part of the Windows API.

Return Value

If successful, _wgclose returns 1; otherwise, it returns 0.

See Also

»_wgopen«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_wggetactive.«


Description: _wgetexit
  _wgetexit

#include <stdio.h>

int _wgetexit( void );

Remarks

QuickWin programs can optionally keep their windows on the screen after termination. How a program will behave at exit time depends on its current exit behavior setting. The _wgetexit function lets you examine the current exit behavior setting. This routine is used only in QuickWin programs; it is not part of the Windows API.

If the companion function _wsetexit has been called previously, _wgetexit returns the value that it set. This can be one of the following values:

_WINEXITPROMPT    Prompt the user at exit time to determine whether the windows stay on the screen

_WINEXITNOPERSIST    The windows do not stay on the screen and there is no prompt to the user

_WINEXITPERSIST    The windows stay on the screen at exit

If _wsetexit has not been called previously, the _wgetexit function returns _WINEXITPERSIST, the default exit behavior. For a description of how to use this exit behavior, see _wsetexit.

Return Value

If successful, _wgetexit returns the current exit behavior setting value: _WINEXITPROMPT, _WINEXITNOPERSIST, or _WINEXITPERSIST. A return value of −1 indicates an error.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetexit,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_fwopen.«


Description: _wgetfocus
  _wgetfocus

#include <io.h>

int _wgetfocus( void );

Remarks

The _wgetfocus function determines which of a QuickWin program's child (document) windows is active (has the program's "focus"). The routine returns the file handle of the active child window. If the entire application is not active, the routine returns the handle of the child window that would be active if the application were active. This routine is used only in QuickWin programs; it is not part of the Windows API. If the active window is a closed child window kept on the screen with the _WINPERSIST flag (see »_wclose«), _wgetfocus fails.

Return Value

If successful, _wgetfocus returns the file handle of the active child window. A return value of −1 indicates an error.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetexit,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WGETFOC.C - Demonstrate testing which QuickWin
 * window is the active window with _wgetfocus
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define NUMWINS      4    /* Number of windows */
#define OPENFLAGS   "w"   /* Access permission */

void main( void )
{
   int i, nRes;
   int sf, gf;          /* Set/Get focus results */
   FILE *wins[NUMWINS]; /* Array of file pointers */

   /* Open NUMWINS windows */
   /* NULL arguments accept default characteristics */
   for( i = 0; i < NUMWINS; i++ )
   {
      wins[i] = _fwopen( NULL, NULL, OPENFLAGS );
      if( wins[i] == NULL )
      {
         printf( "***ERROR: On _fwopen #%i\n", i );
         exit( -1 );
       }
       /* Write in each window */
       nRes = fprintf( wins[i], "Windows!\n" );
   }

   /* Tile child windows with _wmenuclick */
   nRes = _wmenuclick( _WINTILE );
   if( nRes == -1 )
   {
      printf( "***ERROR: _wmenuclick\n" );
      exit( -1 );
   }
   /* Pass the focus from window to window */
   for( i = 0; i < NUMWINS; i++ )
   {
      sf = _wsetfocus( _fileno( wins[i] ) );
      gf = _wgetfocus();
      if(( sf == -1 ) || ( gf == -1 )
         || ( gf != _fileno( wins[i] ) ) )
      {
         printf( "***ERROR: _wsetfocus/_wgetfocus\n" );
         exit( -1 );
      }
   }
   nRes = _fcloseall();
   exit( 0 );
}


Description: _wgetscreenbuf
  _wgetscreenbuf

#include <io.h>

long _wgetscreenbuf( int wfh );

wfh    File handle to a QuickWin window

Remarks

The _wgetscreenbuf function returns the size of a QuickWin window screen buffer. This routine is used only in QuickWin programs; it is not part of the Windows API. Each QuickWin child window has a buffer in which the screen-display text for the window is stored. The buffer size determines how much text is retained and thus how much output can be viewed by scrolling back through the window. By default, the screen-buffer size is 2,048 bytes, but this value can be changed. See »_wsetscreenbuf« for more information.

Return Value

If successful, the _wgetscreenbuf function returns the current screen-buffer size (in bytes) or the value _WINBUFINF. (A value of _WINBUFINF signifies that the size of the screen buffer is unlimited.) A return value of −1 indicates an error.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetexit,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WGSCRBUF.C - Demonstrate examining the current
 * size of a QuickWin window's screen buffer
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define NUMWINS      4    /* Number of windows */
#define OPENFLAGS   "w"   /* Access permission */

void main( void )
{
   long nSize;           /* Size of screen buffer */
   int nRes;             /* Write result */
   FILE *wp;             /* File pointer */

   /* Open a window */
   /* NULL arguments accept default characteristics */
   wp = _fwopen( NULL, NULL, OPENFLAGS );
   if( wp == NULL )
   {
      printf( "***ERROR:_fwopen\n" );
      exit( -1 );
   }

   /* Get the size of its screen buffer */
   nSize = _wgetscreenbuf( _fileno( wp ) );
   nRes = fprintf( wp, "Screen buffer holds %li chars\n", nSize );

   nRes = _wclose( _fileno( wp ), _WINPERSIST );

   exit( 0 );
}


Description: _wgetsize
  _wgetsize

#include <io.h>

int _wgetsize( int wfh, int reqtype, struct _wsizeinfo *wsize );

wfh    File handle to a QuickWin window

reqtype    Type of request

wsize    Pointer to a _wsizeinfo structure

Remarks

The _wgetsize function returns the size and position of the specified child window. This routine is used only in QuickWin programs; it is not part of the Windows API.

The wfh argument is a handle to the window file. Use the manifest constant _WINFRAMEHAND as the value of wfh to query the size and position of the parent frame (client or application window). The maximum size of the parent frame may vary according to the hardware specifications of your terminal.

The reqtype argument is the type of request, which can have one of two values: _WINCURRREQ, which means return the current size of the window, or _WINMAXREQ, which means return the maximum size that the window can grow to (which cannot exceed the current size of the parent frame).

The wsize argument is a pointer to a _wsizeinfo structure (declared in IO.H) that returns the size and position information. The structure contains a _type field that has one of the following values on return:

_WINSIZEMIN    Window is minimized

_WINSIZEMAX    Window is maximized

_WINSIZECHAR    Window is of the size specified in the structure's remaining members

If the type returned is _WINSIZECHAR, the _x, _y, _h, and _w values in the remainder of the structure specify the coordinates of the upper-left corner and the height and width of the window (in characters). Size returned always indicates the "client space" available in the parent frame, which means that it does not include space occupied by title bars and other parts of the window.

Return Value

If successful, _wgetsize returns 0 and fills in the _wsizeinfo structure. A return value of −1 indicates an error.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wmenuclick,« »_wopen,« »_wsetexit,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WGETSIZE.C - Demonstrate getting the
 * size of a QuickWin window on the screen
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define OPENFLAGS    "w"         /* Access permission */
#define PERSISTFLAG _WINPERSIST  /* Keep on screen */

void main( void )
{
   int nRes;               /* Result */
   FILE *wp;               /* File pointer */
   struct _wsizeinfo ws;   /* Size information */

   /* Open a window */
   /* NULL arguments accept default characteristics */
   wp = _fwopen( NULL, NULL, OPENFLAGS );
   if( wp == NULL )
   {
      printf( "***ERROR:_fwopen\n" );
      exit( -1 );
   }

   /* Get the window's size and screen position */
   ws._version = _QWINVER;
   nRes = _wgetsize( _fileno( wp ), _WINCURRREQ, &ws );
   if( nRes == -1 )
   {
      printf( "***ERROR: _wgetsize\n" );
      exit( -1 );
   }

   nRes = fprintf( wp, "Size:\n" );
   nRes = fprintf( wp, "  Upper Left: x = %d\n", ws._x );
   nRes = fprintf( wp, "              y = %d\n", ws._y );
   nRes = fprintf( wp, "  Width:      w = %d\n", ws._w );
   nRes = fprintf( wp, "  Height:     h = %d\n", ws._h );
   nRes = _wclose( _fileno( wp ), PERSISTFLAG );
   exit( 0 );
}


Description: _wggetactive
  _wggetactive

#include <stdio.h>

#include <graph.h>

short __far __cdecl _wggetactive( void );

Remarks

The _wggetactive function returns the handle of the currently active graphics child window. This routine is used only in QuickWin programs; it is not part of the Windows API.

Return Value

This function returns the handle of the currently active graphics child window; otherwise, −1 (if no graphics child window is active).

See Also

»wgsetactive«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * QWGDEMO.C - opens multiple Graphics Child Windows using:
 *    _wgopen   _wgclose   _wggetactive   _wgsetactive
 * and demonstrates pausing in a graphics child window using:
 *    _inchar
 * This program creates three windows, pausing after each to
 * allow you to examine the window before continuing. Try
 * using the scroll bars and arrow keys, switching the GCWs
 * to Full Screen or Size to Fit mode, and resizing the windows.
 */

#include <stdio.h>
#include <graph.h>

void main()
{
   int status, handle;
   short color;
   long bgd, prvbgd;
   char name[] = "SMILEY";
   char name2[] = "HELLO";

   /* Send a message to the text window (stdin/stderr/stdout) */
   printf( "QuickWin Graphics Demo Program.\n" );

   /* Pause before continuing */
   printf( "\nThis is a text window. Press Enter to continue.\n" );
   status = getchar( );

   /* Close the default "Graphic1" GCW (we'll name our own) */
   status = _setvideomode( _MAXRESMODE );
   handle = _wggetactive( );
   status = _wgclose( handle );

   /* Open a GCW named "SMILEY" in which to draw a smiley face */
   handle = _wgopen( name );
   status = _wgsetactive( handle );
   status = _setvideomode( _MAXRESMODE );

   /* Draw Smiley's head */
   color = 13;
   status = _setcolor( color );
   status = _ellipse( _GFILLINTERIOR, 40, 20, 240, 140 );

   /* Draw Smiley's eyes, nose, and mouth */
   status = _setcolor( (short)(color + 1) );
   status = _ellipse( _GFILLINTERIOR, 80, 40, 100, 60 );
   status = _ellipse( _GFILLINTERIOR, 180, 40, 200, 60 );
   status = _ellipse( _GBORDER, 130, 70, 150, 90 );
   status = _arc( 90, 80, 190, 120, 115, 100, 200, 100 );

   /* Pause before continuing */
   _settextposition( 1, 6 );
   _outtext( "Press any key to continue." );
   status = _inchar( );

   /* Open a new GCW called "HELLO" and set it for text output */
   handle = _wgopen( name2 );
   status = _wgsetactive( handle );
   status = _setvideomode( _TEXTC80 );

   /* Set background and text colors for the message */
   bgd = 1;
   prvbgd = _setbkcolor( bgd );
   status = _settextcolor( color );

   /* Display a text message in a GCW */
   _settextposition( 6, 25 );
   _outtext( "HELLO, WORLD!" );

   /* Return to default text color & background color */
   bgd = _setbkcolor( prvbgd );
   status = _settextcolor( 15 );

   /* Pause before continuing */
   _settextposition( 1, 6 );
   _outtext("Press any key to continue.");
   status = _inchar( );

   /* Leave the cursor at the start of the line below the message */
   _settextposition( 7, 1 );
}


Description: _wgopen
  _wgopen

#include <stdio.h>

#include <graph.h>

short __far __cdecl _wgopen( char *name );

name    Name of window to be opened

Remarks

The _wgopen functions opens a graphics child window. The argument name, which specifies the name of the opened window, is a null-terminated C string. QuickWin Graphics generates a default name if the argument name is NULL. The window is initially set to _TEXTC80 mode. You can have up to 20 graphics child windows opened. Graphics child windows can be in either text mode or graphics mode. You need to make an opened graphics child window active (see »_wgsetactive«) before it can accept any graphics call. All standard input and output (READ and WRITE statements) go to the text child windows, not the GCW in text mode.This routine is used only in QuickWin programs; it is not part of the Windows API.

Open windows occupy a large amount of memory. Keep in mind that the system's performance decreases with the addition of every new window.

Return Value

If successful, this functions returns the handle of the opened graphics child window; otherwise it returns 0.

See Also

»wgclose«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_wggetactive.«


Description: _wgsetactive
  _wgsetactive

#include <stdio.h>

#include <graph.h>

short __far __cdecl __wgsetactive( int handle )

handle    Handle of the window to be made active

Remarks

The _wgsetactive functions makes a graphics child window active. All graphics calls are directed to the active graphics child window. Setting the handle to −1 causes all graphics child windows to be inactive and any call to the graphics APIs to fail.

Return Value

If successful, this function returns 1; otherwise it returns 0.

See Also

»_wggetactive«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_wggetactive.«


Description: _wmenuclick
  _wmenuclick

#include <io.h>

int _wmenuclick( int menuitem );

menuitem    Constant specifying which menu command to execute

Remarks

The _wmenuclick function emulates the user choosing a command from the QuickWin Window menu. This routine is used only in QuickWin programs; it is not part of the Windows API. The menuitem argument is a manifest constant specifying one of four available menu commands:

_WINTILE    Tile the program's child windows

_WINCASCADE    Cascade the program's child windows

_WINARRANGE    Arrange icons at the bottom of the client window area

_WINSTATBAR    Toggle the status bar

These are the only menu commands you can choose. Calling the function with one of these values performs the menu action.

Return Value

If successful, _wmenuclick returns 0. A return value of −1 indicates an error.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wopen,« »_wsetexit,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WMENUCLK.C - Demonstrate choosing a menu
 * command with the QuickWin _wmenuclick function
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define NUMWINS      4    /* Number of windows */
#define OPENFLAGS   "w"   /* Access permission */

void main( void )
{
   int i, nRes;
   int wm;              /* Menu click result */
   int sf, gf;          /* Set/Get focus results */
   FILE *wins[NUMWINS]; /* Array of file pointers */

   /* Open NUMWINS windows */
   /* NULL arguments accept default characteristics */
   for( i = 0; i < NUMWINS; i++ )
   {
      wins[i] = _fwopen( NULL, NULL, OPENFLAGS );
      if( wins[i] == NULL )
      {
         printf( "***ERROR: On _fwopen #%i\n", i );
         exit( -1 );
      }
      /* Write in each window */
      nRes = fprintf( wins[i], "Windows!" );
   }

   /* Tile child windows with _wmenuclick */
   wm = _wmenuclick( _WINTILE );
   if( wm == -1 )
   {
      printf( "***ERROR: _wmenuclick\n" );
      exit( -1 );
   }

   /* Pass the focus from window to window */
   for( i = 0; i < NUMWINS; i++ )
   {
      sf = _wsetfocus( _fileno( wins[i] ) );
      gf = _wgetfocus();
      if(( sf == -1 ) || ( gf == -1 )
         || ( gf != _fileno( wins[i] ) ) )
      {
          printf( "***ERROR: _wsetfocus/_wgetfocus\n" );
          exit( -1 );
      }
   }
   nRes = _fcloseall();
   exit( 0 );
}


Description: _wopen
  _wopen

#include <io.h>

int _wopen( struct _wopeninfo *wopeninfo, struct _wsizeinfo *wsizeinfo, int oflag );

wopeninfo    Pointer to a _wopeninfo structure

wsizeinfo    Pointer to a _wsizeinfo structure

oflag    Type of operations allowed

Remarks

The _wopen function opens a QuickWin window, returning a file handle to the window. This routine is used only in QuickWin programs; it is not part of the Windows API.

The _wopeninfo and _wsizeinfo structures, declared in IO.H, are used to pass window initialization information, including the window's initial size and position on the screen. You can pass NULL for the _wsizeinfo argument to accept QuickWin size and positioning defaults, or you can declare a variable of type _wsizeinfo and fill in its fields with initial values. You must declare a variable of type _wopeninfo and fill in its fields.

For both the _wopeninfo and _wsizeinfo variables, set the _version field to _QWINVER, which is defined in IO.H. For the _wopeninfo variable, assign a null-terminated string to the _title field containing the desired window title. You can also optionally set the size of the window's screen buffer in the _wbufsize field. The default is 2,048 bytes, but you can pass some other number or the value _WINBUFINF. The value _WINBUFINF imposes no limit on the buffer size.

For the _wsizeinfo variable, if you choose to pass size information, assign one of the following values to the _type field:

_WINSIZEMIN    Minimize the window

_WINSIZEMAX    Maximize the window

_WINSIZECHAR    Use character coordinates for the window size

If the type is _WINSIZECHAR, you must supply the _x, _y, _h, and _w values in the remainder of the structure. They specify the upper-left corner and the height and width of the window (in characters).

The _wopen function is a low-level I/O call. It accepts the following access flags: _O_BINARY, _O_RDONLY, _O_RDWR, _O_TEXT, _O_WRONLY. These flags can be combined with the bitwise-OR operator ( | ). See »_open« for additional information about the flags. Unlike the _open function, _wopen does not accept the _O_CREAT, _O_TRUNC, or _O_EXCL flag. Using one of these flags results in an error.

Return Value

If successful, _wopen returns a QuickWin file handle. A return value of −1 indicates an error; errno is set either to EINVAL, which means an invalid oflag argument was given, or EMFILE, which means no more file handles are available (too many open files).

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wsetexit,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WOPEN.C - Demonstrate opening a QuickWin window with _wopen
 */

#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define PERSISTFLAG   _WINNOPERSIST
#define OPENFLAGS     _O_RDWR

void main( void )
{
   int wfh;                  /* File handle for window */
   int nRes;                 /* Window write results */
   struct _wopeninfo wininfo;/* Open information */

   /* Set up window open information */
   wininfo._version = _QWINVER;
   wininfo._title = "Window Closing";
   wininfo._wbufsize = _WINBUFDEF;

   /* Open a window with _wopen */
   /* NULL second argument accepts default size */
   wfh = _wopen( &wininfo, NULL, OPENFLAGS );
   if( wfh == -1 )
   {
      printf( "***ERROR: On _wopen\n" );
      exit( -1 );
   }

   /* Write in the window */
   nRes = write ( wfh, "Windows Everywhere!\n", 20 );

   /* Close the window with _wclose */
   nRes = _wclose( wfh, PERSISTFLAG );

   exit( 0 );
}


Description: _wrapon
  _wrapon

#include <graph.h>

short __far _wrapon( short option );

option    Wrap condition

Remarks

The _wrapon function controls whether text output with both the _outmem and the _outtext functions wraps to a new line or is simply clipped when the text output reaches the edge of the defined text window. The option argument can be one of two manifest constants, _GWRAPOFF, which means truncate lines at window border, or _GWRAPON, which means wrap lines at window border. Note that this function does not affect the output of presentation-graphics routines or font routines. The _wrapon function works differently in QuickWin applications.

Return Value

The function returns the previous value of option. There is no error return.

See Also

»_outtext,« »_outmem,« »_scrolltextwindow,« »_settextwindow«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: MS-DOS ONLY
 *
 * WRAPON.C
 *
 */

#include <conio.h>
#include <graph.h>

void main( void )
{
   _wrapon( _GWRAPON );
   while( !_kbhit() )
      _outtext( "Wrap on!   " );
   _getch();
   _outtext( "\n\n" );

   _wrapon( _GWRAPOFF );
   while( !_kbhit() )
      _outtext( "Wrap off!  " );
   _getch();
   _outtext( "\n\n" );
}


Description: _write
  _write

#include <io.h>

int _write( int handle, const void *buffer, unsigned int count );

handle    Handle of file into which data is written

buffer    Data to be written

count    Number of bytes

Remarks

The _write function writes count bytes from buffer into the file associated with handle. The write operation begins at the current position of the file pointer (if any) associated with the given file. If the file is open for appending, the operation begins at the current end of the file. After the write operation, the file pointer is increased by the number of bytes actually written.

Return Value

The _write function returns the number of bytes actually written if successful. If the actual space remaining on the disk is less than the size of the buffer the function is trying to write to the disk, the function fails and does not flush any of the buffer's contents to the disk. A return value of −1 indicates an error. In this case, errno is set to one of two values: EBADF, which means the file handle is invalid or the file is not opened for writing, or ENOSPC, which means there is no space left on the device.

For 16-bit platforms, if you are writing more than 32K (the maximum size for type int) to a file, the return value should be of type unsigned int. (See the example that follows.) However, the maximum number of bytes that can be written to a file at one time is 65,534, since 65,535 (or OxFFFF) is indistinguishable from −1 and would return an error.

If the file is opened in text mode, each linefeed character is replaced with a carriage-return−linefeed pair in the output. The replacement does not affect the return value. When writing to files opened in text mode, the _write function treats a CTRL+Z character as the logical end-of-file. When writing to a device, _write treats a CTRL+Z character in the buffer as an output terminator.

See Also

»fwrite,« »_open,« »_read«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Use _write for compatibility with ANSI naming conventions of non-ANSI functions. Use write and link with OLDNAMES.LIB for UNIX compatibility.

Example

/* WRITE.C: This program opens a file for output
 * and uses _write to write some bytes to the file.
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>

char buffer[] = "This is a test of 'write' function";

void main( void )
{
   int fh;
   unsigned byteswritten;

   if( (fh = _open( "write.o", _O_RDWR | _O_CREAT,
                               _S_IREAD | _S_IWRITE )) != -1 )
   {
      if(( byteswritten = _write( fh, buffer, sizeof( buffer ))) == -1 )
         perror( "Write failed" );
      else
         printf( "Wrote %u bytes to file\n", byteswritten );

      _close( fh );
   }
}

Output

Wrote 35 bytes to file


Description: _wsetexit
  _wsetexit

#include <io.h>

int _wsetexit( int exb );

exb    Desired exit behavior type

Remarks

QuickWin programs can optionally keep their windows on the screen after termination. How a program behaves at exit time depends on its current exit behavior setting. The _wsetexit function sets the exit behavior setting. This routine is used only in QuickWin programs; it is not part of the Windows API.

The _wsetexit function takes one of three arguments:

_WINEXITPROMPT    Prompt the user at exit time to determine whether the windows stay on the screen

_WINEXITNOPERSIST    The windows do not stay on the screen and there is no prompt to the user

_WINEXITPERSIST    The windows stay on the screen at exit

If _WINEXITPERSIST is passed, or if _WINEXITPROMPT is passed and the user chooses to keep the windows on the screen, the windows stay visible, their contents can be copied and pasted, and their scroll bars can be used, but the windows are closed to further I/O. See »_wclose« for more information. The default exit behavior is _WINEXITPERSIST if you do not call _wsetexit.

Return Value

If successful, _wsetexit returns 0. A return value of −1 indicates an error.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetfocus,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

See the example for »_fwopen.«


Description: _wsetfocus
  _wsetfocus

#include <io.h>

int _wsetfocus( int wfh );

wfh    File handle to a QuickWin window

Remarks

The _wsetfocus function makes a QuickWin window the active window (sets the program's focus to the window). This routine is used only in QuickWin programs; it is not part of the Windows API.

If the application has focus, the window gets focus. If not, the window will get the focus when the application gets focus. If the program has other child windows, the focused window moves in front of them and is highlighted. This does not automatically direct I/O to the window. All I/O calls specify which window they are directed to by passing a stream pointer or file handle as an argument.

Return Value

If successful, _wsetfocus returns 0. A return value of −1 indicates that the focus failed to change.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetexit,« »_wsetscreenbuf,« »_wsetsize,« »_wyield«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WSETFOC.C - Demonstrate making a new QuickWin
 * window the active window with _wsetfocus
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define NUMWINS      4     /* Number of windows */
#define OPENFLAGS   "w"    /* Access permission */

void main( void )
{
   int i, nRes, wm;
   int sf, gf;          /* Set/Get focus results */
   FILE *wins[NUMWINS]; /* Array of file pointers */

   /* Open NUMWINS windows */
   /* NULL arguments accept default characteristics */
   for( i = 0; i < NUMWINS; i++ )
   {
      wins[i] = _fwopen( NULL, NULL, OPENFLAGS );
      if( wins[i] == NULL )
      {
         printf( "***ERROR: On _fwopen #%i\n", i );
         exit( -1 );
      }
       /* Write in each window */
       nRes = fprintf( wins[i], "Windows!\n" );
   }

   /* Tile child windows with _wmenuclick */
   wm = _wmenuclick( _WINTILE );
   if( wm == -1 )
   {
      printf( "***ERROR: _wmenuclick\n" );
      exit( -1 );
   }

   /* Pass the focus from window to window */
   for( i = 0; i < NUMWINS; i++ )
   {
      sf = _wsetfocus( _fileno( wins[i] ) );
      gf = _wgetfocus();
      if(( sf == -1 ) || ( gf == -1 )
         || ( gf != _fileno( wins[i] ) ) )
      {
         printf( "***ERROR: _wsetfocus/_wgetfocus\n" );
         exit( -1 );
      }
   }

   nRes = _fcloseall();
   exit( 0 );
}


Description: _wsetscreenbuf
  _wsetscreenbuf

#include <io.h>

int _wsetscreenbuf( int wfh, long bufsiz );

wfh    File handle to a QuickWin window

bufsiz    Desired size of the window's screen buffer (in bytes)

Remarks

The _wsetscreenbuf function sets the size of a QuickWin window's screen buffer to bufsiz bytes. This size determines how much text is retained in the buffer and thus how much text you can scroll back through. This routine is used only in QuickWin programs; it is not part of the Windows API.

The bufsiz argument can be specified as a number or as one of two values, _WINBUFDEF, which means use the default window screen-buffer size (2,048 bytes), or _WINBUFINF, which means use a window screen buffer of unlimited size. The buffer size simply limits how big the buffer can become. The buffer is always allocated dynamically, so that it fits its contents. Specifying _WINBUFINF puts no upper limit on buffer size. The buffer may grow within the limits of available memory.

Return Value

If successful, _wsetscreenbuf returns 0. A return value of −1 indicates an error.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetexit,« »_wsetfocus,« »_wsetsize«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WSSCRBUF.C - Demonstrate setting the size of a
 * QuickWin window's screen buffer
 * Note: The size is set here to an amount smaller than
 * the default size, but you can set it larger as well
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define NUMWINS      4        /* Number of windows */
#define OPENFLAGS   "w"       /* Access permission */
#define NUMLINES    100       /* Lines of text to write */

void main( void )
{
   int i;                   /* Loop variable */
   long nSize;              /* Old size of screen buffer */
   int nWinBufSize = 1500L; /* New size */
   int nRes;                /* Result */
   FILE *wp;                /* File pointer */

   /* Open a window */
   /* NULL arguments accept default characteristics */
   wp = _fwopen( NULL, NULL, OPENFLAGS );
   if( wp == NULL )
   {
      printf( "***ERROR:_fwopen\n" );
      exit( -1 );
   }

   /* Get the size of its screen buffer */
   nSize = _wgetscreenbuf( _fileno( wp ) );
   nRes = fprintf( wp, "Screen buffer holds %li chars\n", nSize );

   /* Reset the screen buffer size */
   nRes = _wsetscreenbuf( _fileno( wp ), nWinBufSize );

   /* Write many lines in the window */
   for( i = 0; i < NUMLINES; i++ )
   {
      nRes = fprintf( wp, "%i Lines (Windows!)\n", i );
   }
   nRes = fprintf( wp,
          "\nWhen the program ends, try using the scroll bars\n" );

   nRes = _wclose( _fileno( wp ), _WINPERSIST );
   exit( 0 );
}


Description: _wsetsize
  _wsetsize

#include <io.h>

int _wsetsize( int wfh, struct _wsizeinfo  );

wfh    File handle to a QuickWin window

wsize    Pointer to a _wsizeinfo structure

Remarks

The _wsetsize function sets the size and position of a QuickWin window. This routine is used only in QuickWin programs; it is not part of the Windows API. The wsize argument points to a _wsizeinfo structure (declared in IO.H) containing the new size and position information. The structure contains a _type field that can have one of the following values:

_WINSIZEMIN    Minimize the window

_WINSIZEMAX    Maximize the window

_WINSIZRESTORE    Restore a previously minimized window

_WINSIZECHAR    Use character coordinates for the window size

If the type is _WINSIZECHAR, you must supply the _x, _y, _h, and _w values in the remainder of the structure. They specify the upper-left corner and the height and width of the window (in characters).

Return Value

If successful, _wsetsize returns 0. A return value of −1 indicates an error.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetscreenbuf,« »_wsetexit,« »_wsetfocus«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WSETSIZE.C - Demonstrate setting the
 * size of a QuickWin window on the screen
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>

#define OPENFLAGS    "w"         /* Access permission */
#define PERSISTFLAG _WINPERSIST  /* Keep on screen */

void main( void )
{
   int nRes;               /* Result */
   FILE *wp;               /* File pointer */
   struct _wsizeinfo ws;   /* Size information */

   /* Open a window */
   /* NULL arguments accept default characteristics */
   wp = _fwopen( NULL, NULL, OPENFLAGS );
   if( wp == NULL )
   {
      printf( "***ERROR:_fwopen\n" );
      exit( -1 );
   }

   /* Minimize the window to an icon */
   ws._version = _QWINVER;
   ws._type = _WINSIZEMIN;

   nRes = _wsetsize( _fileno( wp ), &ws );
   if( nRes == -1 )
   {
      printf( "***ERROR: _wsetsize\n" );
      exit( -1 );
   }

   nRes = _wclose( _fileno( wp ), PERSISTFLAG );

   exit( 0 );
}


Description: _wyield
  _wyield

#include <io.h>

void _wyield( void );

Remarks

The _wyield function yields control to Windows in order to give processor time to other Windows applications. This routine is used only in QuickWin programs; it is not part of the Windows API.

An application for Windows must service its message queue periodically to ensure smooth appearance and performance. Well-behaved QuickWin applications yield time to other applications and allow the user to switch tasks without having to wait for the QuickWin program to complete lengthy processing. The compiler attempts to issue "yield for queue servicing" calls at appropriate times. But in some cases a program requires additional yield calls, particularly during lengthy processing loops. If Windows appears sluggish when running a QuickWin program, insert _wyield calls into the program to improve Windows' responsiveness. Note that when an application is servicing the message queue (yielding) it can be told to stop so the user can work with another application running with Windows.

Return Value

None.

See Also

»_fwopen,« »_wabout,« »_wclose,« »_wgetexit,« »_wgetfocus,« »_wgetscreenbuf,« »_wgetsize,« »_wmenuclick,« »_wopen,« »_wsetscreenbuf,« »_wsetexit,« »_wsetfocus,« »_wsetsize«

Compatibility

ANSI    MS-DOS    QWIN    UNIX    WIN    WIN DLL    WIN32    WIN32s

Example

/* Note: QUICKWIN ONLY
 *
 * WYIELD.C - Demonstrate yielding processor time from a
 * QuickWin program so that other Windows programs can
 * process their message queues; uses _wyield
 */

#include <io.h>

void compute(void);        /* Function prototype */

void main( void )
{
   int l;
   for( l = 0; l <= 10000; l++ )
   {
      compute();       /* Time-consuming function you supply */
      if( l % 1000 )
         _wyield();        /* Yield once every 1000 loops */
   }
}

void compute(void)
{
   /* Intensive computations */
}


Language and Country Strings
  Appendix A  Language and Country Strings (32-Bit Specific)

The locale argument to the »setlocale« function can be composed of any combination of three separate string options: language, country, and code page. The locale argument takes the following form:

locale  "lang[_country[.code_page]]"

| ".code_page"

| ""

| NULL

This appendix lists the available language and country strings available to the setlocale routine. All country and language codes currently supported by the Win32 NLS API are supported by setlocale.


  Language Strings

The following is a list of language strings currently recognized by the »setlocale« routine. Only the strings listed in the "Language String" column will be accepted by setlocale. Note that any language(s) unsupported by the operating system will not be accepted by setlocale.

Sublanguage	Primary Language	Language String
Albanian	Albanian	"albanian"
Albanian	Albanian	"sqi"
Arabic	Arabic	"ara"
Arabic	Arabic	"arabic"
Bahasa	Bahasa	"bah"
Bahasa	Bahasa	"bahasa"
Bulgarian	Bulgarian	"bgr"
Bulgarian	Bulgarian	"bulgarian"
Catalan	Catalan	"cat"
Catalan	Catalan	"catalan"
Chinese	Chinese	"chinese"
Chinese (simplified)	Chinese	"chinese-simplified"
Chinese (simplified)	Chinese	"chs"
Chinese (traditional)	Chinese	"chinese-traditional"
Chinese (traditional)	Chinese	"cht"
Czech	Czech	"csy"
Czech	Czech	"czech"
Danish	Danish	"dan"
Danish	Danish	"danish"
Dutch (Belgian)	Dutch	"belgian"
Dutch (Belgian)	Dutch	"dutch-belgian"
Dutch (Belgian)	Dutch	"nlb"
Dutch (default)	Dutch	"dutch"
Dutch (default)	Dutch	"nld"
English (Australian)	English	"australian"
English (Australian)	English	"ena"
English (Australian)	English	"english-aus"
English (Canadian)	English	"canadian"
English (Canadian)	English	"enc"
English (Canadian)	English	"english-can"
English (default)	English	"english"
English (New Zealand)	English	"english-nz"
English (New Zealand)	English	"enz"
English (UK)	English	"eng"
English (UK)	English	"english-uk"
English (UK)	English	"uk"
English (USA)	English	"american"
English (USA)	English	"american english"
English (USA)	English	"american-english"
English (USA)	English	"english-american"
English (USA)	English	"english-us"
English (USA)	English	"english-usa"
English (USA)	English	"enu"
English (USA)	English	"us"
English (USA)	English	"usa"
Finnish	Finnish	"fin"
Finnish	Finnish	"finnish"
French (Belgian)	French	"frb"
French (Belgian)	French	"french-belgian"
French (Canadian)	French	"frc"
French (Canadian)	French	"french-canadian"
French (default)	French	"fra"
French (default)	French	"french"
French (Swiss)	French	"french-swiss"
French (Swiss)	French	"frs"
German (Austrian)	German	"dea"
German (Austrian)	German	"german-austrian"
German (default)	German	"deu"
German (default)	German	"german"
German (Swiss)	German	"des"
German (Swiss)	German	"german-swiss"
German (Swiss)	German	"swiss"
Greek	Greek	"ell"
Greek	Greek	"greek"
Hebrew	Hebrew	"heb"
Hebrew	Hebrew	"hebrew"
Hungarian	Hungarian	"hun"
Hungarian	Hungarian	"hungarian"
Icelandic	Icelandic	"icelandic"
Icelandic	Icelandic	"isl"
Indonesian	Indonesian	"indonesian"
Italian (default)	Italian	"ita"
Italian (default)	Italian	"italian"
Italian (Swiss)	Italian	"italian-swiss"
Italian (Swiss)	Italian	"its"
Japanese	Japanese	"japanese"
Japanese	Japanese	"jpn"
Korean	Korean	"kor"
Korean	Korean	"korean"
Norwegian (Bokmal)	Norwegian	"nor"
Norwegian (Bokmal)	Norwegian	"norwegian-bokmal"
Norwegian (default)	Norwegian	"norwegian"
Norwegian (Nynorsk)	Norwegian	"non"
Norwegian (Nynorsk)	Norwegian	"norwegian-nynorsk"
Polish	Polish	"plk"
Polish	Polish	"polish"
Portuguese (Brazilian)	Portuguese	"portuguese-brazilian"
Portuguese (Brazilian)	Portuguese	"ptb"
Portuguese (default)	Portuguese	"portuguese"
Portuguese (default)	Portuguese	"ptg"
Rhaeto-Roman	Rhaeto-Roman	"rhaeto-roman"
Rhaeto-Roman	Rhaeto-Roman	"rms"
Romanian	Romanian	"rom"
Romanian	Romanian	"romanian"
Russian (default)	Russian	"rus"
Russian (default)	Russian	"russian"
Serbo-Croatian (Cyrillic)	Serbo-Croatian	"serbian"
Serbo-Croatian (Cyrillic)	Serbo-Croatian	"serbo-croatian-cyrillic"
Serbo-Croatian (Cyrillic)	Serbo-Croatian	"shc"
Serbo-Croatian (default)	Serbo-Croatian	"serbo-croatian"
Serbo-Croatian (default)	Serbo-Croatian	"shl"
Serbo-Croatian (Latin)	Serbo-Croatian	"croatian"
Serbo-Croatian (Latin)	Serbo-Croatian	"serbo-croatian-latin"
Slovak	Slovak	"sky"
Slovak	Slovak	"slovak"
Spanish (default)	Spanish	"esp"
Spanish (default)	Spanish	"spanish"
Spanish (Mexican)	Spanish	"esm"
Spanish (Mexican)	Spanish	"spanish-mexican"
Spanish (Modern)	Spanish	"esn"
Spanish (Modern)	Spanish	"spanish-modern"
Swedish	Swedish	"sve"
Swedish	Swedish	"swedish"
Thai	Thai	"tha"
Thai	Thai	"thai"
Turkish	Turkish	"trk"
Turkish	Turkish	"turkish"
Urdu	Urdu	"urd"
Urdu	Urdu	"urdu"


  Country Strings

The following is a list of country strings currently recognized by the »setlocale« routine. Only the strings listed in the "Country String" column will be accepted by setlocale. Note that any countries unsupported by the operating system will not be accepted by setlocale.

Country	Country String
Australia	"aus"
Australia	"australia"
Austria	"austria"
Austria	"aut"
Belgium	"bel"
Belgium	"belgium"
Brazil	"bra"
Brazil	"brazil"
Canada	"can"
Canada	"canada"
Denmark	"denmark"
Denmark	"dnk"
Finland	"fin"
Finland	"finland"
France	"fra"
France	"france"
Germany	"deu"
Germany	"germany"
Iceland	"iceland"
Iceland	"ireland"
Iceland	"isl"
Ireland	"irl"
Italy	"ita"
Italy	"italy"
Japan	"japan"
Japan	"jpn"
Mexico	"mex"
Mexico	"mexico"
Netherlands	"holland"
Netherlands	"netherlands"
Netherlands	"nld"
New Zealand	"new zealand"
New Zealand	"new-zealand"
New Zealand	"nz"
New Zealand	"nzl"
Norway	"nor"
Norway	"norway"
People's Republic of China	"china"
People's Republic of China	"chn"
People's Republic of China	"pr china"
People's Republic of China	"pr-china"
Portugal	"portugal"
Portugal	"prt"
South Korea	"kor"
South Korea	"korea"
South Korea	"south korea"
South Korea	"south-korea"
Spain	"esp"
Spain	"spain"
Sweden	"swe"
Sweden	"sweden"
Switzerland	"che"
Switzerland	"switzerland"
Taiwan	"taiwan"
Taiwan	"twn"
United Kingdom	"britain"
United Kingdom	"england"
United Kingdom	"gbr"
United Kingdom	"great britain"
United Kingdom	"uk"
United Kingdom	"united kingdom"
United Kingdom	"united-kingdom"
United States of America	"america"
United States of America	"united states"
United States of America	"united-states"
United States of America	"us"
United States of America	"usa"


C Language Reference

Introduction

The C language is a general-purpose programming language known for its efficiency, economy, and portability. While these characteristics make it a good choice for almost any kind of programming, C has proven especially useful in systems programming because it facilitates writing fast, compact programs that are readily adaptable to other systems. Well-written C programs are often as fast as assembly-language programs, and they are typically easier for programmers to read and maintain.

C is a flexible language that leaves many programming decisions up to you. In keeping with this philosophy, C imposes few restrictions in matters such as type conversion. Although this characteristic of the language can make your programming job easier, you must know the language well to understand how programs will behave. This manual provides information on the C language components and the features of the Microsoft implementation. The syntax for the C language is from ANSI X3.159-1989, American National Standard for Information Systems − Programming Language − C (hereinafter called the ANSI C standard), although it is not part of the ANSI C standard. Appendix A, C Language Syntax Summary, provides the syntax and a description of how to read and use the syntax definitions.

C was designed to combine efficiency and power in a relatively small language. C does not include built-in functions to perform tasks such as input and output, storage allocation, screen manipulation, and process control. To perform such tasks, C programmers rely on run-time libraries. You can use the run-time routines supplied, or tailor your own variations for special purposes. The design also helps to isolate language features from processor-specific features in a particular C implementation, which makes it easier to write portable code. See the Run-Time Library Reference or the online Help for information about the library routines provided with this product.

This manual does not discuss programming with C++. See the C++ Language Reference for information about the C++ language.


 C Language Reference


  Scope and Organization of This Manual

The C Language Reference defines the C language as implemented by Microsoft Corporation. It is intended as a reference for programmers experienced in C or other programming languages. Knowledge of programming fundamentals is assumed. This manual is organized as follows:

»Chapter 1, Elements of C,« describes the letters, numbers, and symbols that can be used in C programs and the combinations of characters that have special meanings to the C compiler.

»Chapter 2, Program Structure,« discusses the components and structure of C programs and explains how C source files are organized.

»Chapter 3, Declarations and Types,« describes how to specify the attributes of C variables, functions, and user-defined types. C provides a number of predefined data types and allows the programmer to declare "aggregate" types and pointers. Function prototypes are discussed in this chapter, as well as in »Chapter 6, Functions.«

»Chapter 4, Expressions and Assignments,« describes the operands and operators that form C expressions and assignments. The chapter also discusses the type conversions and side effects that may occur when expressions are evaluated.

»Chapter 5, Statements,« describes C statements, which control the flow of program execution.

»Chapter 6, Functions,« discusses C functions. In particular, this chapter explains function prototypes, parameters, and return values, as well as how to define, declare, and call functions.

»Appendix A, C Language Syntax Summary,« is the complete listing of the ANSI syntax as discussed in the rest of the manual. The Microsoft-specific features are noted. This appendix also begins with a description of how to read and use the ANSI C syntax.

Note  The ANSI syntax in »Appendix A, C Language Syntax Summary,« is provided for information only. It is not part of the ANSI C standard.

»Appendix B, Implementation-Defined Behavior,« describes Microsoft's implementation of the areas that ANSI leaves open to each particular implementation. These items are listed in Appendix F, "Portability Issues," Section F.3, of the ANSI C standard.

Note  For information on Microsoft product support, see "Microsoft Support Services" in the Introduction to Getting Started.


  Document Conventions

This book uses the following typographic conventions.

Example	Description
STDIO.H	Uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
char, _setcolor, __far	Bold type indicates keywords, operators, language-specific characters, and library routines. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.  Many functions and constants begin with either a single or double underscore. These are part of the name and are mandatory. For example, to have the __cplusplus manifest constant be recognized by the compiler, you must enter the leading double underscore.
expression	Words in italics indicate placeholders for information you must supply, such as a filename. Italic type is also occasionally used for emphasis in the text.
[option]	Items inside square brackets are optional.
#pragma pack {1 | 2}	Braces and a vertical bar indicate a choice among two or more items. You must choose one of these items unless square brackets ([ ]) surround the braces.
#include <io.h>	This font is used for examples, user input, program output, and error messages in text.
CL [option...]  file...	Three dots (an ellipsis) following an item indicate that more items having the same form can appear.
while() {    .    .    . }	A column or row of three dots tells you that part of an example program has been intentionally omitted.
CTRL+ENTER	Small capital letters are used to indicate the names of keys on the keyboard. When you see a plus sign (+) between two key names, you should hold down the first key while pressing the second.  The carriage-return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
"argument"	Quotation marks enclose a new term the first time it is defined in text.
"C string"	Some C constructs, such as strings, require quotation marks. Quotation marks required by the language are bold and have the form " " and ' ' rather than " " and ' '.
Dynamic-Link Library (DLL)	The first time an acronym is used, it is usually spelled out.
Microsoft Specific	This manual documents the C language, as it is implemented in Microsoft C. As a result, some of the features of C that are implementation dependent or undefined in the ANSI C standard are defined by the Microsoft implementation. You can find these features by looking for the "Microsoft Specific" heading in the left margin.
32-Bit Specific 16-Bit Specific	When a particular feature is specific only to 32-bit compilations, it is marked by the appropriate heading in the left margin. In text, such compilations are referred to as "32-bit (or 16-bit) target compilations."
♦	This symbol denotes the end of a section of "Microsoft Specific," "16-Bit Specific," or "32-Bit Specific" information.
see »Using Projects«	Hypertext cross-references are enclosed in green double chevrons. Click the term enclosed in the chevrons to jump to display the referenced information.


  ANSI Conformance

Microsoft® C conforms to the standard for the C language as set forth in the ANSI C standard. Microsoft extensions to the ANSI C standard are noted in the text and syntax of this manual as well as in the online reference. Because the extensions are not a part of the ANSI C standard, their use may restrict portability of programs between systems. By default, the Microsoft extensions are enabled. To disable the extensions, specify /Za on the command line. With /Za, all non-ANSI code generates errors or warnings.


Chapter 1:  Elements of C
  CHAPTER 1  Elements of C

This chapter describes the elements of the C programming language, including the names, numbers, and characters used to construct a C program. The ANSI C syntax labels these components "tokens." This chapter explains how to define these tokens and how the compiler evaluates them. The following topics are discussed in this chapter:

•	»Tokens«

•	»Comments«

•	»Keywords«

•	»Identifiers«

•	»Constants«

•	»String literals«

•	»Operators«

•	»Punctuation«

This chapter also includes reference tables for the C and Microsoft-specific »keywords«, »trigraphs«, »escape sequences«, and »operator precedence«, as well as the range for »floating-point« and »integer« constants.


  1.1  Tokens

In a C source program, the basic element recognized by the compiler is the "token." A token is source-program text that the compiler does not break down into component elements.

Syntax

token :
keyword
identifier
constant
string-literal
operator
punctuator

Note  See the introduction to Appendix A, C Language Syntax Summary, for an explanation of the ANSI syntax conventions.

The keywords, identifiers, constants, string literals, and operators described in this chapter are examples of tokens. Punctuation characters such as brackets ([ ]), braces ({ }), parentheses ( ( ) ), and commas (,) are also tokens.


  White-Space Characters

Space, tab, linefeed, carriage-return, formfeed, vertical-tab, and newline characters are called "white-space characters" because they serve the same purpose as the spaces between words and lines on a printed page—they make reading easier. Tokens are delimited (bounded) by white-space characters and by other tokens, such as operators and punctuation. When parsing code, the C compiler ignores white-space characters unless you use them as separators or as components of character constants or string literals. Use white-space characters to make a program more readable. Note that the compiler also treats comments as white space.


  Comments

A "comment" is a sequence of characters beginning with a forward slash/asterisk combination (/*) that is treated as a single white-space character by the compiler and is otherwise ignored. A comment can include any combination of characters from the representable character set, including newline characters, but excluding the "end comment" delimiter (*/). Comments can occupy more than one line but cannot be nested.

Comments can appear anywhere a white-space character is allowed. Since the compiler treats a comment as a single white-space character, you cannot include comments within tokens. The compiler ignores the characters in the comment.

Use comments to document your code. This example is a comment accepted by the compiler:

/* Comments can contain keywords such as
   for and while without generating errors. */

Comments can also appear on the same line as a code statement:

printf( "Hello\n" );  /* Comments can go here */

You can choose to precede functions with a descriptive comment block:

/* MATHERR.C illustrates writing an error routine
 * for math functions.
 * The error function must be:
 *	matherr
 *
 * To use matherr, you must use the /NOE linker option.
 * For example:
 *	CL matherr.c /link /NOE
 */

Since comments cannot contain nested comments, this example causes an error:

/* Comment out this routine for testing

/* Open file */
    fh = _open( "myfile.c", _O_RDONLY );
    .
    .
    .
 */

The error occurs because the compiler recognizes the first */, after the words Open file, as the end of the comment. It tries to process the remaining text and produces an error when it finds the */ outside a comment.

While you can use comments to render certain lines of code inactive for test purposes, the preprocessor directives #if and #endif and conditional compilation are a useful alternative for this task. For more information, see Chapter 1 of the Preprocessor Reference.

Microsoft Specific

The Microsoft compiler also supports single-line comments preceded by two forward slashes (//). If you compile with /Za (ANSI standard), these comments generate errors. These comments cannot extend to a second line.

// This is a valid comment

Comments beginning with two forward slashes (//) are terminated by the next newline character that is not preceded by an escape character. In the next example, the newline character is preceded by a backslash (\), creating an "escape sequence." This escape sequence causes the compiler to treat the next line as part of the previous line. (For more information, see »Escape Sequences«.)

// my comment \
    i++;

Therefore, the i++; statement is commented out.

The default for Microsoft C is that the Microsoft extensions are enabled. Use the /Za command-line option to disable these extensions. ♦


  Evaluation of Tokens

When the compiler interprets tokens, it includes as many characters as possible in a single token before moving on to the next token. Because of this behavior, the compiler may not interpret tokens as you intended if they are not properly separated by white space. Consider the following expression:

i+++j

In this example, the compiler first makes the longest possible operator (++) from the three plus signs, then processes the remaining plus sign as an addition operator (+). Thus, the expression is interpreted as (i++) + (j), not (i) + (++j). In this and similar cases, use white space and parentheses to avoid ambiguity and ensure proper expression evaluation.

Microsoft Specific

The C compiler treats a CTRL+Z character as an end-of-file indicator. It ignores any text after CTRL+Z. ♦


  1.2  Keywords

"Keywords" are words that have special meaning to the C compiler. In translation phases 7 and 8, an identifier cannot have the same spelling and case as a C keyword. (For a description of translation phases, see Appendix A of the Preprocessor Reference; for information on identifiers, see »Identifiers«.) The C language uses the following keywords:

auto	double	int	struct
break	else	long	switch
case	enum	register	typedef
char	extern	return	union
const	float	short	unsigned
continue	for	signed	void
default	goto	sizeof	volatile
do	if	static	while
You cannot redefine keywords. However, you can specify text to be substituted for keywords before compilation by using C preprocessor directives (see Chapter 1 of the Preprocessor Reference).

Microsoft Specific

The following keywords are recognized for both 16-bit and 32-bit targets:

__asm

__based (1)

__cdecl

__fastcall

__inline

1	The __based keyword has limited uses for 32-bit target compilations.

The following keywords are recognized for 16-bit targets only:
__export	__interrupt	__saveregs
__far	__loadds	__segment
__fortran	__near	__segname
__huge	__pascal	__self
The following keywords and special identifiers are recognized for 32-bit targets only:

__declspec	__except	naked1	__try
dllexport1	__finally	__stdcall
dllimport1	__leave	thread1
1	These are special identifiers when used with __declspec; their use in other contexts is not restricted.

Microsoft extensions are enabled by default. To ensure that your programs are fully portable, you can disable Microsoft extensions by specifying the /Za command-line option (compile for ANSI compatibility) during compilation. When you do this, Microsoft-specific keywords are disabled.

When Microsoft extensions are enabled, you can use the keywords listed above in your programs. For ANSI compliance, most of these keywords are prefaced by a double underscore. The four exceptions, dllexport, dllimport, naked, and thread, are used only with __declspec and therefore do not require a leading double underscore. For backward compatibility, single-underscore versions of the rest of the keywords are supported. In addition, __cdecl, __far, __fortran, __huge, __interrupt, __near, and __pascal are available with no leading underscore. ♦


  1.3  Identifiers

"Identifiers" or "symbols" are the names you supply for variables, types, functions, and labels in your program. Identifier names must differ in spelling and case from any keywords. You cannot use keywords (either C or Microsoft) as identifiers; they are reserved for special use. You create an identifier by specifying it in the declaration of a variable, type, or function. In this example, result is an identifier for an integer variable, and main and printf are identifier names for functions.

void main()
{
    int result;

    if ( result != 0 )
   printf( "Bad file handle\n" );
}

Once declared, you can use the identifier in later program statements to refer to the associated value.

A special kind of identifier, called a statement label, can be used in goto statements. (Declarations are described in Chapter 3, »Declarations and Types«. Statement labels are described in »The goto and Labeled Statements«.)

Syntax

identifier :
nondigit
identifier nondigit
identifier digit

nondigit :  one of
_ a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

digit :  one of
0 1 2 3 4 5 6 7 8 9

The first character of an identifier name must be a nondigit (that is, the first character must be an underscore or an uppercase or lowercase letter). ANSI allows six significant characters in an external identifier's name and 31 for names of internal (within a function) identifiers. External identifiers (ones declared at global scope or declared with storage class extern) may be subject to additional naming restrictions because these identifiers have to be processed by other software such as linkers.

Microsoft Specific

The Microsoft C compiler allows 247 characters in an internal or external identifier name. Compiling with the /W4 command-line option generates warnings on any names that exceed the ANSI-specified length. If you are not concerned with ANSI compatibility, you can modify this default to a smaller or larger number using the /H (restrict length of external names) option. ♦

The C compiler considers uppercase and lowercase letters to be distinct characters. This feature, called "case sensitivity," enables you to create distinct identifiers that have the same spelling but different cases for one or more of the letters.

Since uppercase and lowercase letters are considered distinct characters, each of the following identifiers is unique:

add
ADD
Add
aDD

Microsoft Specific

Do not select names for identifiers that begin with two underscores or with an underscore followed by an uppercase letter. The ANSI C standard allows identifier names that begin with these character combinations to be reserved for compiler use. Identifiers with file-level scope should also not be named with an underscore and a lowercase letter as the first two letters. Identifier names that begin with these characters are also reserved. By convention, Microsoft uses an underscore and an uppercase letter to begin macro names and double underscores for Microsoft-specific keyword names. To avoid any naming conflicts, always select identifier names that do not begin with one or two underscores, or names that begin with an underscore followed by an uppercase letter. ♦

The following are examples of valid identifiers that conform to either ANSI or Microsoft naming restrictions:

j
count
temp1
top_of_page
skip12
LastNum

Microsoft Specific

Although identifiers in source files are case sensitive by default, symbols in object files are not. The /Gc command-line option specifies the FORTRAN/Pascal calling convention, causing all function names to be translated to uppercase. (The __pascal and __fortran keywords perform the same operation on a function-by-function basis.) For information on the command-line options, see Chapter 2 of the Build Tools User's Guide.

Microsoft C treats identifiers within a compilation unit as case sensitive.

16-Bit Specific

Externally linked identifiers may or may not be case sensitive. For 16-bit targets, you can use the LINK /NOI option to force the 16-bit linker to treat identifiers as case sensitive. The default for the 16-bit linker is to ignore case.

The /Gc (generate Pascal-style function calls) option converts all external identifiers (including function names) to uppercase. The __pascal declarator performs the same operation on a function-by-function basis. ♦

32-Bit Specific

The 32-bit linker is case sensitive. You must specify all identifiers consistently according to case. ♦

For more information about linking, see Chapter 4 of the Build Tools User's Guide.

The "source character set" is the set of legal characters that can appear in source files. For Microsoft C, the source set is the standard ASCII character set. The source character set and execution character set include the ASCII characters used as escape sequences. See »Character Constants« for information about the execution character set. ♦

An identifier has "scope," which is the region of the program in which it is known, and "linkage," which determines whether the same name in another scope refers to the same identifier. These topics are explained in »Understanding Lifetime, Scope, Visibility, and Linkage«.


  Multibyte and Wide Characters

A multibyte character is a character composed of sequences of one or more bytes. Each byte sequence represents a single character in the extended character set. Multibyte characters are used in character sets such as Kanji.

Wide characters are multilingual character codes that are always 16 bits wide. The type for character constants is char; for wide characters, the type is wchar_t. Since wide characters are always a fixed size, using wide characters simplifies programming with international character sets.

The wide-character-string literal L"hello" becomes an array of six integers of type wchar_t.

{L'h', L'e', L'l', L'l', L'o', 0}

The Unicode specification is the specification for wide characters. The run-time library routines for translating between multibyte and wide characters include mbstowcs, mbtowc, wcstombs, and wctomb.


  Trigraphs

The source character set of C source programs is contained within the 7-bit ASCII character set but is a superset of the ISO 646-1983 Invariant Code Set. Trigraph sequences allow C programs to be written using only the ISO (International Standards Organization) Invariant Code Set. Trigraphs are sequences of three characters (introduced by two consecutive question marks) that the compiler replaces with their corresponding punctuation characters. You can use trigraphs in C source files with a character set that does not contain convenient graphic representations for some punctuation characters.

Table 1.1 shows the nine trigraph sequences. All occurrences in a source file of the punctuation characters in the first column are replaced with the corresponding character in the second column.

A trigraph is always treated as a single source character. The translation of trigraphs takes place in the first translation phase, before the recognition of escape characters in string literals and character constants. (See Appendix A of the Preprocessor Reference for information about translation phases.) Only the nine trigraphs shown in Table 1.1 are recognized. All other character sequences are left untranslated.

Table 1.1    Trigraph Sequences

Trigraph	Punctuation Character
??=	#
??(	[
??/	\
??)	]
??'	^
??<	{
??!	|
??>	}
??-	~
The character escape sequence, \?, prevents the misinterpretation of trigraph-like character sequences. (For information about escape sequences, see »Escape Sequences«..) For example, if you attempt to print the string What??! with this printf statement

printf( "What??!\n" );

the string printed is What| because ??! is a trigraph sequence that is replaced with the | character. You need to write the statement as follows to correctly print the string:

printf( "What?\?!\n" );

In this printf statement, a backslash escape character in front of the second question mark prevents the misinterpretation of ??! as a trigraph.


  1.4  Constants

A "constant" is a number, character, or character string that can be used as a value in a program. Use constants to represent floating-point, integer, enumeration, or character values that cannot be modified.

Syntax

constant :
floating-point-constant
integer-constant
enumeration-constant
character-constant

Constants are characterized by having a value and a type. This section discusses floating-point, integer, and character constants. Enumeration constants are described in »Enumeration Declarations«.


  Floating-Point Constants

A "floating-point constant" is a decimal number that represents a signed real number. The representation of a signed real number includes an integer portion, a fractional portion, and an exponent. Use floating-point constants to represent floating-point values that cannot be changed.

Syntax

floating-point-constant :
fractional-constant exponent-part  (opt)  floating-suffix  (opt)
digit-sequence exponent-part floating-suffix  (opt)

fractional-constant :
digit-sequence  (opt)  . digit-sequence
digit-sequence  .

exponent-part :
     e sign  (opt)  digit-sequence
     E sign  (opt)  digit-sequence

sign :  one of
     +  −

digit-sequence :
digit
digit-sequence digit

floating-suffix :  one of
     f  l  F  L

You can omit either the digits before the decimal point (the integer portion of the value) or the digits after the decimal point (the fractional portion), but not both. You can leave out the decimal point only if you include an exponent. No white-space characters can separate the digits or characters of the constant.

The following examples illustrate some forms of floating-point constants and expressions:

15.75
1.575E1   /* = 15.75   */
1575e-2   /* = 15.75   */
-2.5e-3   /* = -0.0025 */
25E-4     /* =  0.0025 */

Floating-point constants are positive unless they are preceded by a minus sign (−). In such case, the minus sign is treated as a unary arithmetic negation operator. Floating-point constants have type float, double, long, or long double.

A floating-point constant without an f, F, l, or L suffix has type double. If the letter f or F is the suffix, the constant has type float. If suffixed by the letter l or L, it has type long double. For example:

100L  /* Has type long double  */
100F  /* Has type float        */
100D  /* Has type double       */

32-Bit Specific

The 32-bit compiler maps long double to type double. ♦

See »Storage of Basic Types« for information about type double, float, and long.

You can omit the integer portion of the floating-point constant, as shown in the following examples. The number .75 can be expressed in many ways, including the following:

.0075e2
0.075e1
.075e1
75e-2

Microsoft Specific

Limits on the values of floating-point constants are given in Table 1.2 (for 16-bit targets) and »Table 1.3, Limits on Floating-Point Constants (32-Bit Specific).« The header file FLOAT.H that the setup program installs contains this information.

Table 1.2    Limits on Floating-Point Constants (16-Bit Specific)

Constant	Meaning	Value
FLT_DIG DBL_DIG LDBL_DIG	Number of digits, q, such that a floating-point number with q decimal digits can be rounded into a floating-point representation and back without loss of precision.	6 15 18
FLT_EPSILON DBL_EPSILON LDBL_EPSILON	Smallest positive number x, such that x + 1.0 is not equal to 1.0	1.192092896e−07F 2.2204460492503131e−016 1.0842022172485504434e−019L
FLT_GUARD		0
FLT_MANT_DIG DBL_MANT_DIG LDBL_MANT_DIG	Number of digits in the radix specified by FLT_RADIX in the floating-point significand. The radix is 2; hence these values specify bits.	24 53 64
FLT_MAX DBL_MAX LDBL_MAX	Maximum representable floating-point number.	3.402823466e+38F 1.7976931348623158e+308 1.189731495357231765e+4932L
FLT_MAX_10_EXP DBL_MAX_10_EXP LDBL_MAX_10_EXP	Maximum integer such that 10 raised to that number is a representable floating-point number.	38 308 4932
FLT_MAX_EXP DBL_MAX_EXP LDBL_MAX_EXP	Maximum integer such that FLT_RADIX raised to that number is a representable floating-point number.	128 1024 16384
FLT_MIN DBL_MIN LDBL_MIN	Minimum positive value.	1.175494351e−38F 2.2250738585072014e−308 3.3621031431120935063e−4932L
FLT_MIN_10_EXP DBL_MIN_10_EXP LDBL_MIN_10_EXP	Minimum negative integer such that 10 raised to that number is a representable floating-point number.	−37 −307 −4931
FLT_MIN_EXP DBL_MIN_EXP LDBL_MIN_EXP	Minimum negative integer such that FLT_RADIX raised to that number is a representable floating-point number.	−125 −1021 −16381
FLT_NORMALIZE		0
FLT_RADIX _DBL_RADIX _LDBL_RADIX	Radix of exponent representation.	2 2 2
FLT_ROUNDS _DBL_ROUNDS _LDBL_ROUNDS	Rounding mode for floating-point addition.	1  (near) 1  (near) 1  (near)
Table 1.3    Limits on Floating-Point Constants (32-Bit Specific)

Constant	Meaning	Value
FLT_DIG DBL_DIG LDBL_DIG	Number of digits, q, such that a floating-point number with q decimal digits can be rounded into a floating-point representation and back without loss of precision.	6 15 15
FLT_EPSILON DBL_EPSILON LDBL_EPSILON	Smallest positive number x, such that x + 1.0 is not equal to 1.0	1.192092896e−07F 2.2204460492503131e−016 2.2204460492503131e−016
FLT_GUARD		0
FLT_MANT_DIG DBL_MANT_DIG LDBL_MANT_DIG	Number of digits in the radix specified by FLT_RADIX in the floating-point significand. The radix is 2; hence these values specify bits.	24 53 53
FLT_MAX DBL_MAX LDBL_MAX	Maximum representable floating-point number.	3.402823466e+38F 1.7976931348623158e+308 1.7976931348623158e+308
FLT_MAX_10_EXP DBL_MAX_10_EXP LDBL_MAX_10_EXP	Maximum integer such that 10 raised to that number is a representable floating-point number.	38 308 308
FLT_MAX_EXP DBL_MAX_EXP LDBL_MAX_EXP	Maximum integer such that FLT_RADIX raised to that number is a representable floating-point number.	128 1024 1024
FLT_MIN DBL_MIN LDBL_MIN	Minimum positive value.	1.175494351e−38F 2.2250738585072014e−308 2.2250738585072014e−308
FLT_MIN_10_EXP DBL_MIN_10_EXP LDBL_MIN_10_EXP	Minimum negative integer such that 10 raised to that number is a representable floating-point number.	−37 −307 −307
FLT_MIN_EXP DBL_MIN_EXP LDBL_MIN_EXP	Minimum negative integer such that FLT_RADIX raised to that number is a representable floating-point number.	−125 −1021 −1021
FLT_NORMALIZE		0
FLT_RADIX _DBL_RADIX _LDBL_RADIX	Radix of exponent representation.	2 2 2
FLT_ROUNDS _DBL_ROUNDS _LDBL_ROUNDS	Rounding mode for floating-point addition.	1  (near) 1  (near) 1  (near)
Note that the information in Tables 1.2 and 1.3 may differ in future implementations. ♦


  Integer Constants

An "integer constant" is a decimal (base 10), octal (base 8), or hexadecimal (base 16) number that represents an integral value. Use integer constants to represent integer values that cannot be changed.

Syntax

integer-constant :
decimal-constant integer-suffix  (opt)
octal-constant integer-suffix  (opt)
hexadecimal-constant integer-suffix  (opt)

decimal-constant :
nonzero-digit
decimal-constant digit

octal-constant :
0
octal-constant octal-digit

hexadecimal-constant :
0x hexadecimal-digit
0X hexadecimal-digit
hexadecimal-constant hexadecimal-digit

nonzero-digit :  one of
1 2 3 4 5 6 7 8 9

octal-digit :  one of
0 1 2 3 4 5 6 7

hexadecimal-digit :  one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F

integer-suffix :
unsigned-suffix long-suffix ( )  (opt)
long-suffix unsigned-suffix ( )  (opt

) unsigned-suffix :  one of
u U

long-suffix :  one of
l L

Integer constants are positive unless they are preceded by a minus sign (−). The minus sign is interpreted as the unary arithmetic negation operator. (See »Unary Operators« for information about this operator.)

If an integer constant begins with the letters 0x or 0X, it is hexadecimal. If it begins with the digit 0, it is octal. Otherwise, it is assumed to be decimal.

The following lines are equivalent:

0x1C   /* = Hexadecimal representation for decimal 28 */
034    /* = Octal representation for decimal 28 */

No white-space characters can separate the digits of an integer constant. These examples show valid decimal, octal, and hexadecimal constants.

/* Decimal Constants */
10
132
32179

/* Octal Constants */
012
0204
076663

/* Hexadecimal Constants */
0xa or 0xA
0x84
0x7dB3 or 0X7DB3


  Integer Types

Every integer constant is given a type based on its value and the way it is expressed. You can force any integer constant to type long by appending the letter l or L to the end of the constant; you can force it to be type unsigned by appending u or U to the value. The lowercase letter l can be confused with the digit 1 and should be avoided. Some forms of long integer constants follow:

/* Long decimal constants */
10L
79L

/* Long octal constants */
012L
0115L

/* Long hexadecimal constants */
0xaL or 0xAL
0X4fL or 0x4FL

/* Unsigned long decimal constant */
776745UL
778866LU

The type you assign to a constant depends on the value the constant represents. A constant's value must be in the range of representable values for its type. A constant's type determines which conversions are performed when the constant is used in an expression or when the minus sign (−) is applied. This list summarizes the conversion rules for integer constants.

•	The type for a decimal constant without a suffix is either int, long int, or unsigned long int. The first of these three types in which the constant's value can be represented is the type assigned to the constant.

•	The type assigned to octal and hexadecimal constants without suffixes is int, unsigned int, long int, or unsigned long int depending on the size of the constant.

•	The type assigned to constants with a u or U suffix is unsigned int or unsigned long int depending on their size.

•	The type assigned to constants with an l or L suffix is long int or unsigned long int depending on their size.

•	The type assigned to constants with a u or U and an l or L suffix is unsigned long int.


  Integer Limits (Microsoft Specific)

The limits for integer types are listed in Table 1.4 (for 16-bit targets) and Table 1.5 (for 32-bit targets). These limits are also defined in the standard header file LIMITS.H.

Table 1.4    Limits on Integer Constants (16-Bit Specific)

Constant	Meaning	Value
CHAR_BIT	Number of bits in the smallest variable that is not a bit field.	8
SCHAR_MIN	Minimum value for a variable of type signed char.	−127
SCHAR_MAX	Maximum value for a variable of type signed char.	127
UCHAR_MAX	Maximum value for a variable of type unsigned char.	255 (0xff)
CHAR_MIN	Minimum value for a variable of type char.	−127; 0 if /J option used
CHAR_MAX	Maximum value for a variable of type char.	127; 255 if /J option used
MB_LEN_MAX	Maximum number of bytes in a multicharacter constant.	2
SHRT_MIN	Minimum value for a variable of type short.	−32767
SHRT_MAX	Maximum value for a variable of type short.	32767
USHRT_MAX	Maximum value for a variable of type unsigned short.	65535 (0xffff)
INT_MIN	Minimum value for a variable of type int.	−32767
INT_MAX	Maximum value for a variable of type int.	32767
UINT_MAX	Maximum value for a variable of type unsigned int.	65535 (0xffff)
LONG_MIN	Minimum value for a variable of type long.	−2147483647
LONG_MAX	Maximum value for a variable of type long.	2147483647
ULONG_MAX	Maximum value for a variable of type unsigned long.	4294967295 (0xffffffff)
Table 1.5    Limits on Integer Constants (32-Bit Specific)

Constant	Meaning	Value
CHAR_BIT	Number of bits in the smallest variable that is not a bit field.	8
SCHAR_MIN	Minimum value for a variable of type signed char.	−128
SCHAR_MAX	Maximum value for a variable of type signed char.	127
UCHAR_MAX	Maximum value for a variable of type unsigned char.	255 (0xff)
CHAR_MIN	Minimum value for a variable of type char.	−128; 0 if /J option used
CHAR_MAX	Maximum value for a variable of type char.	127; 255 if /J option used
MB_LEN_MAX	Maximum number of bytes in a multicharacter constant.	2
SHRT_MIN	Minimum value for a variable of type short.	−32768
SHRT_MAX	Maximum value for a variable of type short.	32767
USHRT_MAX	Maximum value for a variable of type unsigned short.	65535 (0xffff)
INT_MIN	Minimum value for a variable of type int.	−214748364 − 1
INT_MAX	Maximum value for a variable of type int.	2147483647
UINT_MAX	Maximum value for a variable of type unsigned int.	4294967295 (0xffffffff)
LONG_MIN	Minimum value for a variable of type long.	−2147483647 − 1
LONG_MAX	Maximum value for a variable of type long.	2147483647
ULONG_MAX	Maximum value for a variable of type unsigned long.	4294967295 (0xffffffff)
If a value exceeds the largest integer representation, the Microsoft compiler generates an error.


  Character Constants

A "character constant" is formed by enclosing a single character from the representable character set within single quotation marks (' '). Character constants are used to represent characters in the execution character set.

Syntax

character-constant :
'c-char-sequence'
L'c-char-sequence'

c-char-sequence :
c-char
c-char-sequence c-char

c-char :
Any member of the source character set except the single quotation mark ('),
backslash (\), or newline character
escape-sequence

escape-sequence :
simple-escape-sequence
octal-escape-sequence
hexadecimal-escape-sequence

simple-escape-sequence :  one of
\a  \b  \f  \n  \r  \t  \v
\'  \"  \\  \?

octal-escape-sequence :
\ octal-digit
\ octal-digit octal-digit
\ octal-digit octal-digit octal-digit

hexadecimal-escape-sequence :
\x hexadecimal-digit
hexadecimal-escape-sequence hexadecimal-digit


  Character Types

An integer character constant not preceded by the letter L has type int. The value of an integer character constant containing a single character is the numerical value of the character interpreted as an integer. For example, the numerical value of the character a is 97 in decimal and 61 in hexadecimal.

Syntactically, a "wide-character constant" is a character constant prefixed by the letter L. A wide-character constant has type wchar_t, an integer type defined in the STDDEF.H header file. For example:

char    schar =  'x';   /* A character constant          */
wchar_t wchar = L'x';   /* A wide-character constant for
                            the same character           */

Wide-character constants are 16 bits wide and specify members of the extended execution character set. They allow you to express characters in alphabets that are too large to be represented by type char. See »Multibyte and Wide Characters« for more information about wide characters.


  Execution Character Set

This manual often refers to the "execution character set." The execution character set is not necessarily the same as the source character set used for writing C programs. The execution character set includes all characters in the source character set as well as the null character, newline character, backspace, horizontal tab, vertical tab, carriage return, and escape sequences. The source and execution character sets may differ in other implementations.


  Escape Sequences

Character combinations consisting of a backslash (\) followed by a letter or by a combination of digits are called "escape sequences." To represent a newline character, single quotation mark, or certain other characters in a character constant, you must use escape sequences. An escape sequence is regarded as a single character and is therefore valid as a character constant.

Escape sequences are typically used to specify actions such as carriage returns and tab movements on terminals and printers. They are also used to provide literal representations of nonprinting characters and characters that usually have special meanings, such as the double quotation mark ("). Table 1.6 lists the ANSI escape sequences and what they represent.

Note that the question mark preceded by a backslash (\?) specifies a literal question mark in cases where the character sequence would be misinterpreted as a trigraph. See »Trigraphs« for more information.

Table 1.6    Escape Sequences

Escape Sequence	Represents
\a	Bell (alert)
\b	Backspace
\f	Formfeed
\n	New line
\r	Carriage return
\t	Horizontal tab
\v	Vertical tab
\'	Single quotation mark
\"	Double quotation mark
\\	Backslash
\?	Literal question mark
\ooo	ASCII character in octal notation
\xhhh	ASCII character in hexadecimal notation
Microsoft Specific

If a backslash precedes a character that does not appear in Table 1.6, the compiler handles the undefined character as the character itself. For example, \x is treated as an x. ♦

Escape sequences allow you to send nongraphic control characters to a display device. For example, the ESC character (\033) is often used as the first character of a control command for a terminal or printer. Some escape sequences are device-specific. For instance, the vertical-tab and formfeed escape sequences (\v and \f) do not affect screen output, but they do perform appropriate printer operations.

You can also use the backslash (\) as a continuation character. When a newline character (equivalent to pressing the RETURN key) immediately follows the backslash, the compiler ignores the backslash and the newline character and treats the next line as part of the previous line. This is useful primarily for preprocessor definitions longer than a single line. For example:

#define assert(exp) \
( (exp) ? (void) 0:_assert( #exp, __FILE__, __LINE__ ) )


  Octal and Hexadecimal Character Specifications

The sequence \ooo means you can specify any character in the ASCII character set as a three-digit octal character code. The numerical value of the octal integer specifies the value of the desired character or wide character.

Similarly, the sequence \xhhh allows you to specify any ASCII character as a hexadecimal character code. For example, you can give the ASCII backspace character as the normal C escape sequence (\b), or you can code it as \010 (octal) or \x008 (hexadecimal).

You can use only the digits 0 through 7 in an octal escape sequence. Octal escape sequences can never be longer than three digits and are terminated by the first character that is not an octal digit. Although you do not need to use all three digits, you must use at least one. For example, the octal representation is \10 for the ASCII backspace character and  \101 for the letter A, as given in an ASCII chart.

Similarly, you must use at least one digit for a hexadecimal escape sequence, but you can omit the second and third digits. Therefore you could specify the hexadecimal escape sequence for the backspace character as either \x8, \x08, or \x008.

The value of the octal or hexadecimal escape sequence must be in the range of representable values for type unsigned char for a character constant and type wchar_t for a wide-character constant. See »Multibyte and Wide Characters« for information on wide-character constants.

Unlike octal escape constants, there is no limit on the number of hexadecimal digits in an escape sequence. A hexadecimal escape sequence terminates at the first character that is not a hexadecimal digit. Because hexadecimal digits include the letters a through f, care must be exercised to make sure the escape sequence terminates at the intended digit. To avoid confusion, you can place octal or hexadecimal character definitions in a macro definition:

#define Bell '\x07'

For hexadecimal values, you can break the string to show the correct value clearly:

"\xabc"    /* one character  */
"\xab" "c" /* two characters */


  1.5  String Literals

A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.

Syntax

string-literal :
"s-char-sequence  (opt) "
L"s-char-sequence  (opt) "

s-char-sequence :
s-char
s-char-sequence s-char

s-char :
any member of the source character set except the double quotation mark ("),
backslash (\), or newline character
escape-sequence

The example below is a simple string literal:

char amessage = "This is a string literal.";

All escape codes listed in Table 1.6 are valid in string literals. To represent a double quotation mark in a string literal, use the escape sequence \". The single quotation mark (') can be represented without an escape sequence. The backslash (\) must be followed with a second backslash (\\) when it appears within a string. When a backslash appears at the end of a line, it is always interpreted as a line-continuation character.


  Type for String Literals

String literals have type array of char (that is, char[ ]). (Wide-character strings have type array of wchar_t (that is, wchar_t[ ]).) This means that a string is an array with elements of type char. The number of elements in the array is equal to the number of characters in the string plus one for the terminating null character.


  Storage of String Literals

The characters of a literal string are stored in order at contiguous memory locations. An escape sequence (such as \\ or \") within a string literal counts as a single character. A null character (represented by the \0 escape sequence) is automatically appended to, and marks the end of, each string literal. (This occurs during translation phase 7, which is described in Appendix A of the Preprocessor Reference. Note also that the compiler may not store two identical strings at two different addresses. The /Gf compiler option forces the compiler to place a single copy of identical strings into the executable file. For more information about this option, see Chapter 2 of the Build Tools User's Guide.


  String Literal Concatenation

To form string literals that take up more than one line, you can concatenate the two strings. To do this, type a backslash, then press the RETURN key. The backslash causes the compiler to ignore the following newline character. For example, the string literal

"Long strings can be bro\
ken into two or more pieces."

is identical to the string

"Long strings can be broken into two or more pieces."

String concatenation can be used anywhere you might previously have used a backslash followed by a newline character to enter strings longer than one line. Because strings can start in any column of the source code without affecting their on-screen representation, you can position strings to enhance source-code readability.

To force a new line within a string literal, enter the newline escape sequence (\n) at the point in the string where you want the line broken, as follows:

"Enter a number between 1 and 100\nOr press Return"

Long strings can be continued in any column of a succeeding line without affecting their appearance when output. For example:

printf ( "This is the first half of the string, "
 "this is the second half ") ;

As long as each part of the string is enclosed in double quotation marks, the parts are concatenated and output as a single string. This concatenation occurs according to the sequence of events during compilation specified by translation phases. See Appendix A of the Preprocessor Reference for information on translation phases.

"This is the first half of the string, this is the second half"

A string pointer, initialized as two distinct string literals separated only by white space, is stored as a single string (pointers are discussed in »Pointer Declarations«). When properly referenced, as in the following example, the result is identical to the previous example:

char *string = "This is the first half of the string, "
   "this is the second half";

printf( "%s" , string ) ;

In translation phase 6, the multibyte-character sequences specified by any sequence of adjacent string literals or adjacent wide-string literals are concatenated into a single multibyte-character sequence. Therefore, do not design programs to allow modification of string literals during execution. The ANSI C standard specifies that the result of modifying a string is undefined.


  Storage Class for Strings (Microsoft Specific)

Strings have static storage duration. See »Storage Classes« for information about storage duration.


  Maximum String Length (Microsoft Specific)

ANSI compatibility requires a compiler to accept up to 509 characters in a string literal after concatenation. The maximum length of a string literal allowed in Microsoft C is approximately 2,048 bytes. However, if the string literal consists of parts enclosed in double quotation marks, the preprocessor concatenates the parts into a single string, and for each line concatenated, it adds an extra byte to the total number of bytes.

For example, suppose a string consists of 40 lines with 50 characters per line (2,000 characters), and one line with 7 characters, and each line is surrounded by double quotation marks. This adds up to 2,007 bytes plus one byte for the terminating null character, for a total of 2,008 bytes. On concatenation, an extra character is added for each of the first 40 lines. This makes a total of 2,048 bytes. Note, however, that if line continuations (\) are used instead of double quotation marks, the preprocessor does not add an extra character for each line.


  1.6  Operators

"Operators" are symbols (both single characters and character combinations) that specify how values are to be manipulated. Each symbol is interpreted as a single unit, called a token. For more information, see »Tokens«.

Table 1.7 gives the precedence order for the C operators. For a complete description and the ANSI grammar for each operator, see »Operators«.

Table 1.7    Precedence and Associativity of C Operators

Symbol  (1)	Type of Operation	Associativity
[ ]  ( )  .  −>  postfix ++ and postfix − −  :> (2)	Expression	Left to right
Prefix ++ and prefix − −   sizeof  &   *   +  −  ~  !	Unary	Right to left
typecasts	Unary	Right to left
*  /  %	Multiplicative	Left to right
+  −	Additive	Left to right
<<  >>	Bitwise shift	Left to right
<  >  <=  >=	Relational	Left to right
==  !=	Equality	Left to right
&	Bitwise-AND	Left to right
^	Bitwise-exclusive-OR	Left to right
|	Bitwise-inclusive-OR	Left to right
&&	Logical-AND	Left to right
||	Logical-OR	Left to right
? :	Conditional	Right to left
=  *=  /=  %=  +=  −=  <<=  >>= &= ^=  |=	Simple and compound assignment (3)	Right to left
,	Sequential evaluation	Left to right
1 Operators are listed in descending order of precedence. If several operators appear in the same line or in a group, they have equal precedence. 2 The base operator (:>) is valid only for 16-bit targets. 3 All simple- and compound-assignment operators have equal precedence.


  1.7  Punctuation and Special Characters

The punctuation and special characters in the C character set have various uses, from organizing program text to defining the tasks that the compiler or the compiled program carries out. They do not specify an operation to be performed. Some punctuation symbols are also operators (see the previous section, »Operators«). The compiler determines their use from context.

Syntax

punctuator : one of
[ ]   ( )   { }   *   ,   :   =   ;   ...   #

These characters have special meanings in C. Their uses are described throughout this manual. The pound sign (#) can occur only in preprocessing directives. See Chapter 1 of the Preprocessor Reference for information about preprocessing directives.


  CHAPTER 2  Program Structure

This chapter gives an overview of C programs and program execution. Terms and features important to understanding C programs and components are also introduced. After a brief look at program components, this chapter describes the main function and its arguments. Topics discussed include:

•	»Source files and translation units«

•	The »main function« and »command-line arguments«

•	»Lifetime and storage duration«

•	»Scope and visibility«

•	»Linkage«

•	»Name spaces«

Because this chapter is an overview, the topics discussed contain introductory material only. See the cross-referenced information for more detailed explanations.


  2.1  Source Files and Source Programs

A source program can be divided into one or more "source files," or "translation units." The input to the compiler is called a "translation unit."

Syntax

translation-unit :
external-declaration
translation-unit external-declaration

external-declaration :
function-definition
declaration

»Overview of Declarations« gives the syntax for the declaration nonterminal, and Appendix A of the Preprocessor Reference explains how the translation unit is processed.

Note  See the introduction to Appendix A for an explanation of the ANSI syntax conventions.

The components of a translation unit are external declarations that include function definitions and identifier declarations. These declarations and definitions can be in source files, header files, libraries, and other files the program needs. You must compile each translation unit and link the resulting object files to make a program.

A C "source program" is a collection of directives, pragmas, declarations, definitions, statement blocks, and functions. To be valid components of a Microsoft C program, each must have the syntax described in this manual, although they can appear in any order in the program (subject to the rules outlined throughout this manual). However, the location of these components in a program does affect how variables and functions can be used in a program. (See »Understanding Lifetime, Scope, Visibility, and Linkage« for more information.)

Source files need not contain executable statements. For example, you may find it useful to place definitions of variables in one source file and then declare references to these variables in other source files that use them. This technique makes the definitions easy to find and update when necessary. For the same reason, constants and macros are often organized into separate files called "include files" or "header files" that can be referenced in source files as required. See Chapter 1 of the Preprocessor Reference for information about macros and include files.


  Preprocessor Directives

A "directive" instructs the C preprocessor to perform a specific action on the text of the program before compilation. Preprocessor directives are fully described in Chapter 1 of the Preprocessor Reference. This example uses the preprocessor directive #define:

#define MAX 100

This statement tells the compiler to replace each occurrence of MAX by 100 prior to compilation. The C compiler preprocessor directives are:

#define	#elif	#else	#endif
#error	#if	#ifdef	#ifndef
#include	#line	#pragma	#undef


  Pragmas

Microsoft Specific

A "pragma" instructs the compiler to perform a particular action at compile time. Pragmas vary from compiler to compiler. For example, you can use the optimize pragma to set the optimizations to be performed on your program. The Microsoft C pragmas are:

alloc_text	auto_inline	check_pointer	check_stack
code_seg	comment	data_seg	function
hdrstop	inline_depth	inline_recursion	intrinsic
linesize	message	native_caller	optimize
pack	page	pagesize	setlocale
skip	subtitle	title	warning
See Chapter 2 of the Preprocessor Reference for a description of the Microsoft C compiler pragmas. ♦


  Declarations and Definitions

A "declaration" establishes an association between a particular variable, function, or type and its attributes. »Overview of Declarations« gives the ANSI syntax for the declaration nonterminal. A declaration also specifies where and when an identifier can be accessed (the "linkage" of an identifier). See »Understanding Lifetime, Scope, Visibility, and Linkage« for information about linkage.

A "definition" of a variable establishes the same associations as a declaration but also causes storage to be allocated for the variable.

For example, the main, find, and count functions and the var and val variables are defined in one source file, in this order:

main()
{
}

int var = 0;
double val[MAXVAL];

char find( fileptr )
{
}

int count( double f )
{
}

The variables var and val can be used in the find and count functions; no further declarations are needed. But these names are not visible (cannot be accessed) in main.


  Function Declarations and Definitions

Function prototypes establish the name of the function, its return type, and the type and number of its formal parameters. A function definition includes the function body.

Both function and variable declarations can appear inside or outside a function definition. Any declaration within a function definition is said to appear at the "internal" or "local" level. A declaration outside all function definitions is said to appear at the "external," "global," or "file scope" level. Variable definitions, like declarations, can appear at the internal level (within a function definition) or at the external level (outside all function definitions). Function definitions always occur at the external level. Function definitions are discussed further in »Function Definitions«. Function prototypes are covered in »Function Declarations« and in »Function Prototypes«.


  Blocks

A sequence of declarations, definitions, and statements enclosed within curly braces ({ }) is called a "block." There are two types of blocks in C. The "compound statement," a statement composed of one or more statements (see »The Compound Statement«), is one type of block. The other, the "function definition," consists of a compound statement (the body of the function) plus the function's associated "header" (the function name, return type, and formal parameters). A block within other blocks is said to be "nested."

Note that while all compound statements are enclosed within curly braces, not everything enclosed within curly braces constitutes a compound statement. For example, although the specifications of array, structure, or enumeration elements can appear within curly braces, they are not compound statements.


  Example Program

The following C source program consists of two source files. It gives an overview of some of the various declarations and definitions possible in a C program. Later sections in this manual describe how to write these declarations, definitions, and initializations, and how to use C keywords such as static and extern. The printf function is declared in the C header file STDIO.H.

The main and max functions are assumed to be in separate files, and execution of the program begins with the main function. No explicit user functions are executed before main.

/*****************************************************************
                    FILE1.C - main function
*****************************************************************/

#define ONE     1
#define TWO     2
#define THREE   3
#include <stdio.h>

int a = 1;                       /* Defining declarations     */
int b = 2;                       /*  of external variables    */

extern int max( int a, int b );  /* Function prototype        */

int main()                       /* Function definition       */
{                                /*  for main function        */
    int c;                       /* Definitions for           */
    int d;                       /*  two uninitialized        */
                                 /*  local variables          */

    extern int u;                /* Referencing declaration   */
                                 /*  of external variable     */
                                 /*  defined elsewhere        */
    static int v;                /* Definition of variable    */
                                 /*  with continuous lifetime */

    int w = ONE, x = TWO, y = THREE;
    int z = 0;
    z = max( x, y );             /* Executable statements     */
    w = max( z, w );
    printf( "%d %d\n", z, w );
    return 0;
}

/****************************************************************
            FILE2.C - definition of max function
****************************************************************/

int max( int a, int b )          /* Note formal parameters are   */
                                 /*  included in function header */
{
    if( a > b )
        return( a );
    else
        return( b );
}

FILE1.C contains the prototype for the max function. This kind of declaration is sometimes called a "forward declaration" because the function is declared before it is used. The definition for the main function includes calls to max.

The lines beginning with #define are preprocessor directives. These directives tell the preprocessor to replace the identifiers ONE, TWO, and THREE with the numbers 1, 2, and 3, respectively, throughout FILE1.C. However, the directives do not apply to FILE2.C, which is compiled separately and then linked with FILE1.C. The line beginning with #include tells the compiler to include the file STDIO.H, which contains the prototype for the printf function. Preprocessor directives are explained in Chapter 1 of the Preprocessor Reference.

FILE1.C uses defining declarations to initialize the global variables a and b. The local variables c and d are declared but not initialized. Storage is allocated for all these variables. The static and external variables, u and v, are automatically initialized to 0. Therefore only a, b, u, and v contain meaningful values when declared because they are initialized, either explicitly or implicitly. FILE2.C contains the function definition for max. This definition satisfies the calls to max in FILE1.C.

The lifetime and visibility of identifiers are discussed in »Understanding Lifetime, Scope, Visibility, and Linkage«. For more information on functions, see »Chapter 6, Functions«.


  2.2  The main Function and Program Execution

Every C program has a primary (main) function that must be named main. The main function serves as the starting point for program execution. It usually controls program execution by directing the calls to other functions in the program. A program usually stops executing at the end of main, although it can terminate at other points in the program for a variety of reasons. At times, perhaps when a certain error is detected, you may want to force the termination of a program. To do so, use the exit function. See the Run-Time Library Reference for information on and an example using the exit function.

Functions within the source program perform one or more specific tasks. The main function can call these functions to perform their respective tasks. When main calls another function, it passes execution control to the function, so that execution begins at the first statement in the function. A function returns control to main when a return statement is executed or when the end of the function is reached.

You can declare any function, including main, to have parameters. The term "parameter" or "formal parameter" refers to the identifier that receives a value passed to a function. See »Parameters« for information on passing arguments to parameters. When one function calls another, the called function receives values for its parameters from the calling function. These values are called "arguments." You can declare formal parameters to main so that it can receive arguments from the command line using this format:

main( int argc, char *argv[ ], char *envp[ ] )

When you want to pass information to the main function, the parameters are traditionally named argc and argv, although the C compiler does not require these names. The types for argc and argv are defined by the C language. Traditionally, if a third parameter is passed to main, that parameter is named envp. The type for the envp parameter is mandated by ANSI, but the name is not. Examples later in this chapter show how to use these three parameters to access command-line arguments. The following sections explain these parameters.

When compiling with /Za to specify ANSI conformance, the main function must conform to either of the following formats or the compiler generates an error:

int main( void )

int main( int argc, char *argv[ ] )


  Argument Description

The argc parameter in the main function is an integer specifying how many arguments are passed to the program from the command line. Since the program name is considered an argument, the value of argc is at least one.

The argv parameter is an array of pointers to null-terminated strings representing the program arguments. Each element of the array points to a string representation of an argument passed to main. (For information about arrays, see »Array Declarations«.) The argv parameter can be declared either as an array of pointers to type char (char *argv[]) or as a pointer to pointers to type char (char **argv). The first string (argv[0]) is the program name. The last pointer (argv[argc]) is NULL. (See getenv in the Run-Time Library Reference for an alternative method for getting environment variable information.)

The envp parameter is a pointer to an array of null-terminated strings that represent the values set in the user's environment variables. The envp parameter can be declared as an array of pointers to char (char *envp[]) or as a pointer to pointers to char (char **envp). The end of the array is indicated by a NULL pointer.


  Expanding Wildcard Arguments (Microsoft Specific)

When running a C program, you can use either of the two MS-DOS® wildcards — the question mark (?) and the asterisk (*) — to specify filename and path arguments on the command line.

Command-line arguments are handled by a routine called _setargv, which by default does not expand wildcards into separate strings in the argv string array. You can replace the normal _setargv routine with a more powerful version of _setargv that does handle wildcards by linking with the SETARGV.OBJ file.

To link with SETARGV.OBJ, use the /NOE linker option. For example:

cl typeit.c setargv /link /NOE

The wildcards are expanded in the same manner as in MS-DOS commands. (See your MS-DOS user's guide if you are unfamiliar with wildcards.) Enclosing an argument in double quotation marks (" ") suppresses the wildcard expansion. Within quoted arguments, you can represent quotation marks literally by preceding the double-quotation-mark character with a backslash (\). If no matches are found for the wildcard argument, the argument is passed literally.


  Parsing Command-Line Arguments (Microsoft Specific)

Microsoft C startup code uses the following rules when interpreting arguments given on the MS-DOS command line:

•	Arguments are delimited by white space, which is either a space or a tab.

•	A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument. Note that the caret (^) is not recognized as an escape character or delimiter.

•	A double quotation mark preceded by a backslash, \", is interpreted as a literal double quotation mark (").

•	Backslashes are interpreted literally, unless they immediately precede a double quotation mark.

•	If an even number of backslashes is followed by a double quotation mark, then one backslash (\) is placed in the argv array for every pair of backslashes (\\), and the double quotation mark (") is interpreted as a string delimiter.

•	If an odd number of backslashes is followed by a double quotation mark, then one backslash (\) is placed in the argv array for every pair of backslashes (\\) and the double quotation mark is interpreted as an escape sequence by the remaining backslash, causing a literal double quotation mark (") to be placed in argv.

This list illustrates the rules above by showing the interpreted result passed to argv for several examples of command-line arguments. The output listed in the second, third, and fourth columns is from the ARGS.C program that follows the list.

Command-Line Input	argv[1]	argv[2]	argv[3]
"a b c" d e	a b c	d	e
"ab\"c" "\\" d	ab"c	\	d
a\\\b d"e f"g h	a\\\b	de fg	h
a\\\"b c d	a\"b	c	d
a\\\\"b c" d e	a\\b c	d	e
/* ARGS.C illustrates the following variables used for accessing
 * command-line arguments and environment variables:
 * argc  argv  envp
 */

#include <stdio.h>

void main( int argc, /* Number of strings in array argv */
 char *argv[],       /* Array of command-line argument strings */
 char **envp )       /* Array of environment variable strings */
{
     int count;

    /* Display each command-line argument. */
    printf( "\nCommand-line arguments:\n" );
    for( count = 0; count < argc; count++ )
        printf( "  argv[%d]   %s\n", count, argv[count] );

    /* Display each environment variable. */
    printf( "\nEnvironment variables:\n" );
    while( *envp != NULL )
        printf( "  %s\n", *(envp++) );

    return;
}

One example of output from this program is:

Command-line arguments:
  argv[0]   C:\MSC\TEST.EXE

Environment variables:
  COMSPEC=C:\DOS\COMMAND.COM

  PATH=c:\dos;c:\binb;c:\binr;c:\win3;c:\word;c:\help;c:\msc;c:\;
  PROMPT=[$p]
  TERM=vt52
  TEMP=c:\tmp
  TMP=c:\tmp
  EDITORS=c:\binr
  HOME=c:\lm.dos\netprog

Environment variables are set in your AUTOEXEC.BAT file.


  Customizing Command-Line Processing

If your program does not take command-line arguments, you can save a small amount of space by suppressing use of the library routine that performs command-line processing. This routine is called _setargv, as described in »Expanding Wildcard Arguments«. To suppress its use, define a routine that does nothing in the file containing the main function and name it _setargv. The call to _setargv is then satisfied by your definition of _setargv, and the library version is not loaded.

Similarly, if you never access the environment table through the envp argument, you can provide your own empty routine to be used in place of _setenvp, the environment-processing routine.

If your program makes calls to the _spawn or _exec family of routines in the C run-time library, you should not suppress the environment-processing routine, since this routine is used to pass an environment from the parent process to the child process.


  2.3  Understanding Lifetime, Scope, Visibility, and Linkage

To understand how a C program works, you must understand the rules that determine how variables and functions can be used in the program. Several concepts are crucial to understanding these rules:

•	»Lifetime«

•	»Scope«

•	»Visibility«

•	»Linkage«


  Lifetime

"Lifetime" is the period during execution of a program in which a variable or function exists. The storage duration of the identifier determines its lifetime.

An identifier declared with the storage-class-specifier static has static storage duration. Identifiers with static storage duration (also called "global") have storage and a defined value for the duration of a program. Storage is reserved and the identifier's stored value is initialized only once, prior to program startup. An identifier declared with external or internal linkage also has static storage duration (see »Linkage«).

An identifier declared without the static storage-class specifier has automatic storage duration if it is declared inside a function. An identifier with automatic storage duration (a "local identifier") has storage and a defined value only within the block where the identifier is defined or declared.  An automatic identifier is allocated new storage each time the program enters that block, and it loses its storage (and its value) when the program exits the block. Identifiers declared in a function with no linkage also have automatic storage duration.

The following rules specify whether an identifier has global (static) or local (automatic) lifetime:

•	All functions have static lifetime. Therefore they exist at all times during program execution. Identifiers declared at the external level (that is, outside all blocks in the program at the same level of function definitions) always have global (static) lifetimes.

•	If a local variable has an initializer, the variable is initialized each time it is created (unless it is declared as static). Function parameters also have local lifetime. You can specify global lifetime for an identifier within a block by including the static storage-class specifier in its declaration. Once declared static, the variable retains its value from one entry of the block to the next.

Although an identifier with a global lifetime exists throughout the execution of the source program (for example, an externally declared variable or a local variable declared with the static keyword), it may not be visible in all parts of the program. See the next section, »Scope and Visibility«, for information about visibility, and see  »Storage Classes« for a discussion of the storage-class-specifier nonterminal.

Memory can be allocated as needed (dynamic) if created through the use of special library routines such as malloc. Since dynamic memory allocation uses library routines, it is not considered part of the language. See the malloc function in the Run-Time Library Reference.


  Scope and Visibility

An identifier's "visibility" determines the portions of the program in which it can be referenced—its "scope." An identifier is visible (i.e., can be used) only in portions of a program encompassed by its "scope," which may be limited (in order of increasing restrictiveness) to the file, function, block, or function prototype in which it appears. The scope of an identifier is the part of the program in which the name can be used. This is sometimes called "lexical scope." There are four kinds of scope: function, file, block, and function prototype.

All identifiers except labels have their scope determined by the level at which the declaration occurs. The following rules for each kind of scope govern the visibility of identifiers within a program:

File scope

The declarator or type specifier for an identifier with file scope appears outside any block or list of parameters and is accessible from any place in the translation unit after its declaration. Identifier names with file scope are often called "global" or "external." The scope of a global identifier begins at the point of its definition or declaration and terminates at the end of the translation unit.

Function scope

A label is the only kind of identifier that has function scope. A label is declared implicitly by its use in a statement. Label names must be unique within a function. (For more information about labels and label names, see »The goto and Labeled Statements«.)

Block scope

The declarator or type specifier for an identifier with block scope appears inside a block or within the list of formal parameter declarations in a function definition. It is visible only from the point of its declaration or definition to the end of the block containing its declaration or definition. Its scope is limited to that block and to any blocks nested in that block and ends at the curly brace that closes the associated block. Such identifiers are sometimes called "local variables."

Function-prototype scope

The declarator or type specifier for an identifier with function-prototype scope appears within the list of parameter declarations in a function prototype (not part of the function declaration). Its scope terminates at the end of the function declarator.

The appropriate declarations for making variables visible in other source files are described in »Storage Classes«. However, variables and functions declared at the external level with the static storage-class specifier are visible only within the source file in which they are defined. All other functions are globally visible.


  Linkage

Identifier names can refer to different identifiers in different scopes. An identifier declared in different scopes or in the same scope more than once can be made to refer to the same identifier or function by a process called "linkage." Linkage determines the portions of the program in which an identifier can be referenced (its "visibility"). There are three kinds of linkage: internal, external, and none.


  Internal Linkage

If the declaration of a file-scope identifier for an object or a function contains the storage-class-specifier static, the identifier has internal linkage. Otherwise, the identifier has external linkage. See »Storage Classes« for a discussion of the storage-class-specifier nonterminal.

Within one translation unit, each instance of an identifier with internal linkage denotes the same identifier or function. Internally linked identifiers are unique to a translation unit.


  External Linkage

If the first declaration at file-scope level for an identifier does not use the static storage-class specifier, the object has external linkage.

If the declaration of an identifier for a function has no storage-class-specifier, its linkage is determined exactly as if it were declared with the storage-class-specifier extern. If the declaration of an identifier for an object has file scope and no storage-class-specifier, its linkage is external.

An identifier's name with external linkage designates the same function or data object as does any other declaration for the same name with external linkage. The two declarations can be in the same translation unit or in different translation units. If the object or function also has global lifetime, the object or function is shared by the entire program.


  No Linkage

If a declaration for an identifier within a block does not include the extern storage-class specifier, the identifier has no linkage and is unique to the function.

The following identifiers have no linkage:

•	An identifier declared to be anything other than an object or a function

•	An identifier declared to be a function parameter

•	A block-scope identifier for an object declared without the extern storage-class specifier

If an identifier has no linkage, declaring the same name again (in a declarator or type specifier) in the same scope level generates a symbol redefinition error.


  Summary

Table 2.1 is a summary of lifetime and visibility characteristics for most identifiers. The first three columns give the attributes that define lifetime and visibility. An identifier with the attributes given by the first three columns has the lifetime and visibility shown in the fourth and fifth columns. However, the table does not cover all possible cases. Refer to the discussion "»Storage Classes« for more information.

Table 2.1    Summary of Lifetime and Visibility

Attributes: Level	Item	Storage-Class Specifier	Result: Lifetime	Visibility
File scope	Variable definition	static	Global	Restricted to remainder of source file in which it occurs
	Variable declaration	extern	Global	Remainder of source file
	Function prototype or definition	static	Global	Restricted to single source file
	Function prototype	extern	Global	Remainder of source file
Block scope	Variable declaration	extern	Global	Block
	Variable definition	static	Global	Block
	Variable definition	auto or register	Local	Block
The following program example illustrates blocks, nesting, and visibility of variables:

#include <stdio.h>

int i = 1;               /* i defined at external level               */

int main()               /* main function defined at external level   */
{
    printf( "%d\n", i ); /* Prints 1 (value of external level i)      */
    {                            /* Begin first nested block          */
        int i = 2, j = 3;        /* i and j defined at internal level */
        printf( "%d %d\n", i, j );     /* Prints 2, 3                 */
        {                        /* Begin second nested block         */
            int i = 0;           /* i is redefined:                   */
            printf( "%d %d\n", i, j ); /* Prints 0, 3:                */
        }                        /* End of second nested block        */
        printf( "%d\n", i );     /* Prints 2 (outer definition        */
                                 /*  restored):                       */
    }                            /* End of first nested block         */
    printf( "%d\n", i );         /* Prints 1 (external level          */
                                 /* definition restored):             */
    return 0;
}

In this example, there are four levels of visibility: the external level and three block levels. The values are printed to the screen as noted in the comments following each statement.


  2.4  Name Spaces

The compiler sets up "name spaces" to distinguish between the identifiers used for different kinds of items. The names within each name space must be unique to avoid conflict, but an identical name can appear in more than one name space. This means that you can use the same identifier for two or more different items, provided that the items are in different name spaces. The compiler can resolve references based on the syntactic context of the identifier in the program.

This list describes the name spaces used in C.

Statement labels

Named statement labels are part of statements. Definitions of statement labels are always followed by a colon but are not part of case labels. Uses of statement labels always immediately follow the keyword goto. Statement labels do not have to be distinct from other names or from label names in other functions.

Structure, union, and enumeration tags

These tags are part of structure, union, and enumeration type specifiers and, if present, always immediately follow the reserved words struct, union, or enum. The tag names must be distinct from all other structure, enumeration, or union tags with the same visibility.

Members of structures or unions

Member names are allocated in name spaces associated with each structure and union type. That is, the same identifier can be a component name in any number of structures or unions at the same time. Definitions of component names always occur within structure or union type specifiers. Uses of component names always immediately follow the member-selection operators (−> and .). The name of a member must be unique within the structure or union, but it does not have to be distinct from other names in the program, including the names of members of different structures and unions, or the name of the structure itself.

Ordinary identifiers

All other names fall into a name space that includes variables, functions (including formal parameters and local variables), and enumeration constants. Identifier names have nested visibility, so you can redefine them within blocks.

Typedef names

Typedef names cannot be used as identifiers in the same scope.

For example, since structure tags, structure members, and variable names are in three different name spaces, the three items named student in this example do not conflict. The context of each item allows correct interpretation of each occurrence of student in the program. (For information about structures, see »Structure Declarations«.)

struct student {
   char student[20];
   int class;
   int id;
   } student;

When student appears after the struct keyword, the compiler recognizes it as a structure tag. When student appears after a member-selection operator (−> or .), the name refers to the structure member. In other contexts, student refers to the structure variable. However, overloading the tag name space is not recommended since it obscures meaning.


Chapter 3:  Declarations and Types
  CHAPTER 3  Declarations and Types

This chapter describes the declaration and initialization of variables, functions, and types. The C language includes a standard set of basic data types. You can also add your own data types, called "derived types," by declaring new ones based on types already defined. The following topics are discussed in this chapter:

•	»Storage-class specifiers«

•	»Type specifiers«

•	»Type qualifiers«

•	»Declarators and variable declarations«

•	»Initializers«

•	»Enumeration,« »structure,« »union,« and »array« declarations

•	»Pointers« and »based pointers«

•	»Storage of basic types«

•	»Typedef declarations«

•	»Extended storage-class attributes«


  3.1  Overview of Declarations

A "declaration" specifies the interpretation and attributes of a set of identifiers. A declaration that also causes storage to be reserved for the object or function named by the identifier is called a "definition." C declarations for variables, functions, and types have this syntax:

Syntax

declaration :
declaration-specifiers init-declarator-list  (opt)  ;

declaration-specifiers :
storage-class-specifier attribute-seq  (opt)  declaration-specifiers  (opt)
/*  attribute-seq  (opt)  is Microsoft specific */
type-specifier declaration-specifiers  (opt)
type-qualifier declaration-specifiers  (opt

) init-declarator-list :
init-declarator
init-declarator-list , init-declarator

init-declarator :
declarator
declarator = initializer

Note  This syntax for declaration is not repeated in the following sections. Syntax in the following sections usually begin with the declarator nonterminal.

The declarations in the init-declarator-list contain the identifiers being named; init is an abbreviation for initializer. The init-declarator-list is a comma-separated sequence of declarators, each of which can have additional type information, or an initializer, or both. The declarator contains the identifiers, if any, being declared. The declaration-specifiers nonterminal consists of a sequence of type and storage-class specifiers that indicate the linkage, storage duration, and at least part of the type of the entities that the declarators denote. Therefore, declarations are made up of some combination of storage-class specifiers, type specifiers, type qualifiers, declarators, and initializers.

Declarations can contain one or more of the optional attributes listed in attribute-seq; seq is an abbreviation for sequence. These Microsoft-specific attributes perform a variety of functions, which are discussed in detail throughout this book. For a list of these attributes, see Appendix A, »C Language Syntax Summary«.

In the general form of a variable declaration, type-specifier gives the data type of the variable. The type-specifier can be a compound, as when the type is modified by const, volatile, or one of the special keywords described in »Special Keywords in Declarations«. The declarator gives the name of the variable, possibly modified to declare an array or a pointer type. For example,

int const __far *fp;

declares a variable named fp as a far pointer to a nonmodifiable (const) int value. You can define more than one variable in a declaration by using multiple declarators, separated by commas.

A declaration must have at least one declarator, or its type specifier must declare a structure tag, union tag, or members of an enumeration. Declarators provide any remaining information about an identifier. A declarator is an identifier that can be modified with brackets ([ ]), asterisks (*), or parentheses ( ( ) ) to declare an array, pointer, or function type, respectively. When you declare simple variables (such as character, integer, and floating-point items), or structures and unions of simple variables, the declarator is just an identifier. »Declarators and Variable Declarations« discusses declarators.

All definitions are implicitly declarations, but not all declarations are definitions. For example, variable declarations that begin with the extern storage-class specifier are "referencing," rather than "defining" declarations. If an external variable is to be referred to before it is defined, or if it is defined in another source file from the one where it is used, an extern declaration is necessary. Storage is not allocated by "referencing" declarations, nor can variables be initialized in declarations.

A storage class or a type (or both) is required in variable declarations. Except for __declspec, only one storage-class specifier is allowed in a declaration and not all storage-class specifiers are permitted in every context. The __declspec storage class is allowed with other storage-class specifiers, and it is allowed more than once. The storage-class specifier of a declaration affects how the declared item is stored and initialized, and which parts of a program can reference the item.

The storage-class-specifier terminals defined in C include auto, extern, register, static, and typedef. In addition, Microsoft C includes the storage-class-specifier terminal __declspec. All storage-class-specifier terminals except typedef and __declspec are discussed in »Storage Classes«. See »Typedef Declarations« for information about typedef. See »Extended Storage-Class Attributes« for information about __declspec.

The location of the declaration within the source program and the presence or absence of other declarations of the variable are important factors in determining the lifetime of variables. There can be multiple redeclarations but only one definition. However, a definition can appear in more than one translation unit. For objects with internal linkage, this rule applies separately to each translation unit, because internally linked objects are unique to a translation unit. For objects with external linkage, this rule applies to the entire program. See »Understanding Lifetime, Scope, Visibility, and Linkage« for more information about visibility.

Type specifiers provide some information about the data types of identifiers. The default type specifier is int. For more information, see »Type Specifiers«. Type specifiers can also define type tags, structure and union component names, and enumeration constants. For more information see »Enumeration Declarations«, »Structure Declarations«, and »Union Declarations«.

There are two type-qualifier terminals: const and volatile. These qualifiers specify additional properties of types that are relevant only when accessing objects of that type through l-values. For more information on const and volatile, see »Type Qualifiers«. For a definition of l-values, see »L-Value and R-Value Expressions«.


  3.2  Storage Classes

The "storage class" of a variable determines whether the item has a "global" or "local" lifetime. C calls these two lifetimes "static" and "automatic." An item with a global lifetime exists and has a value throughout the execution of the program. All functions have global lifetimes.

Automatic variables, or variables with local lifetimes, are allocated new storage each time execution control passes to the block in which they are defined. When execution returns, the variables no longer have meaningful values.

C provides the following storage-class specifiers:

Syntax

storage-class-specifier :
auto
register
static
extern
typedef
__declspec ( extended-decl-modifier-seq )  /* Microsoft Specific */

Except for __declspec, you can use only one storage-class-specifier in the declaration-specifier in a declaration. If no storage-class specification is made, declarations within a block create automatic objects.

Items declared with the auto or register specifier have local lifetimes. Items declared with the static or extern specifier have global lifetimes.

Since typedef and __declspec are semantically different from the other four storage-class-specifier terminals, they are discussed separately. For specific information on typedef, see »Typedef Declarations«. For specific information on __declspec, see »Extended Storage-Class Attributes«.

The placement of variable and function declarations within source files also affects storage class and visibility. Declarations outside all function definitions are said to appear at the "external level." Declarations within function definitions appear at the "internal level."

The exact meaning of each storage-class specifier depends on two factors:

•	Whether the declaration appears at the external or internal level

•	Whether the item being declared is a variable or a function

»Storage-Class Specifiers for External-Level Declarations« and »Storage-Class Specifiers for Internal-Level Declarations« describe the storage-class-specifier terminals in each kind of declaration and explain the default behavior when the storage-class-specifier is omitted from a variable. »Storage-Class Specifiers with Function Declarations« discusses storage-class specifiers used with functions.


  Storage-Class Specifiers for External-Level Declarations

External variables are variables at file scope. They are defined outside any function, and they are potentially available to many functions. Functions can only be defined at the external level and, therefore, cannot be nested. By default, all references to external variables and functions of the same name are references to the same object, which means they have "external linkage." (You can use the static keyword to override this. See information later in this section for more details on static.)

Variable declarations at the external level are either definitions of variables ("defining declarations"), or references to variables defined elsewhere ("referencing declarations").

An external variable declaration that also initializes the variable (implicitly or explicitly) is a defining declaration of the variable. A definition at the external level can take several forms:

•	A variable that you declare with the static storage-class specifier. You can explicitly initialize the static variable with a constant expression, as described in »Initialization«. If you omit the initializer, the variable is initialized to 0 by default. For example, these two statements are both considered definitions of the variable k.

static int k = 16;
static int k;

•	A variable that you explicitly initialize at the external level. For example,
int j = 3; is a definition of the variable j.

In variable declarations at the external level (that is, outside all functions), you can use the static or extern storage-class specifier or omit the storage-class specifier entirely. You cannot use the auto and register storage-class-specifier terminals at the external level.

Once a variable is defined at the external level, it is visible throughout the rest of the translation unit. The variable is not visible prior to its declaration in the same source file. Also, it is not visible in other source files of the program, unless a referencing declaration makes it visible, as described below.

The rules relating to static include:

•	Variables declared outside all blocks without the static keyword always retain their values throughout the program. To restrict their access to a particular translation unit, you must use the static keyword. This gives them "internal linkage." To make them global to an entire program, omit the explicit storage class or use the keyword extern (see the rules in the next list). This gives them "external linkage." Internal and external linkage are also discussed in »Linkage«.

•	You can define a variable at the external level only once within a program. You can define another variable with the same name and the static storage-class specifier in a different translation unit. Since each static definition is visible only within its own translation unit, no conflict occurs. This provides a useful way to hide identifier names that must be shared among functions of a single translation unit, but not visible to other translation units.

•	The static storage-class specifier can apply to functions as well. If you declare a function static, its name is invisible outside of the file in which it is declared.

The rules for using extern are:

•	The extern storage-class specifier declares a reference to a variable defined elsewhere. You can use an extern declaration to make a definition in another source file visible, or to make a variable visible prior to its definition in the same source file. Once you have declared a reference to the variable at the external level, the variable is visible throughout the remainder of the translation unit in which the declared reference occurs.

•	For an extern reference to be valid, the variable it refers to must be defined once, and only once, at the external level. This definition (without the extern storage class) can be in any of the translation units that make up the program.

The example below illustrates external declarations:

/******************************************************************
                      SOURCE FILE ONE
*******************************************************************/

extern int i;                /* Reference to i, defined below */
void next( void );           /* Function prototype            */

main()
{
    i++;
    printf( "%d\n", i );     /* i equals 4 */
    next();
}

int i = 3;                   /* Definition of i */

void next( void )
{
    i++;
    printf( "%d\n", i );     /* i equals 5 */
    other();
}

/******************************************************************

                      SOURCE FILE TWO
*******************************************************************/

extern int i;                /* Reference to i in  */
                             /* first source file  */
void other( void )
{
    i++;
    printf( "%d\n", i );     /* i equals 6 */
}

The two source files in this example contain a total of three external declarations of i. Only one declaration is a "defining declaration." That declaration,

int i = 3;

defines the global variable i and initializes it with initial value 3. The "referencing" declaration of i at the top of the first source file using extern makes the global variable visible prior to its defining declaration in the file. The referencing declaration of i in the second source file also makes the variable visible in that source file. If a defining instance for a variable is not provided in the translation unit, the compiler assumes there is an

extern int x;

referencing declaration and that a defining reference

int x = 0;

appears in another translation unit of the program.

All three functions, main, next, and other, perform the same task: they increase i and print it. The values 4, 5, and 6 are printed.

If the variable i had not been initialized, it would have been set to 0 automatically. In this case, the values 1, 2, and 3 would have been printed. See »Initialization« for information about variable initialization.


  Storage-Class Specifiers for Internal-Level Declarations

You can use any of four storage-class-specifier terminals for variable declarations at the internal level. When you omit the storage-class-specifier from such a declaration, the default storage class is auto. Therefore, the keyword auto is rarely seen in a C program.


  The auto Storage-Class Specifier

The auto storage-class specifier declares an automatic variable, a variable with a local lifetime. An auto variable is visible only in the block in which it is declared. Declarations of auto variables can include initializers, as discussed in »Initialization«. Since variables with auto storage class are not initialized automatically, you should either explicitly initialize them when you declare them, or assign them initial values in statements within the block. The values of uninitialized auto variables are undefined. (A local variable of auto or register storage class is initialized each time it comes in scope if an initializer is given.)

An internal static variable (a static variable with local or block scope) can be initialized with the address of any external or static item, but not with the address of another auto item, because the address of an auto item is not a constant.


  The register Storage-Class Specifier

The register storage-class specifier tells the compiler to give an automatic variable storage in a register, if possible. Register storage usually speeds access time and reduces code size. Variables declared with register storage class have the same visibility as auto variables. You cannot apply the unary address-of operator (&) to a register object nor can the register keyword be used on arrays (see »Operators« for more information).

The number of registers that can be used for variable storage is machine-dependent. If no registers are available when the compiler encounters a register declaration, the variable is given auto storage class and stored in memory. Register storage, if available, is only guaranteed for int and pointer types that are the same size as an int. (An initialized local variable of auto or register storage class is initialized each time it comes in scope if an initializer is given.)

Microsoft Specific

The Microsoft C 16-bit compiler uses the SI and DI registers for register variables. ♦

32-Bit Specific

The 32-bit compiler does not honor user requests for register variables. However, all other semantics associated with the register keyword are honored by the 32-bit compiler. ♦


  The static Storage-Class Specifier

A variable declared at the internal level with the static storage-class specifier has a global lifetime but is visible only within the block in which it is declared. For constant strings, using static is useful because it alleviates the overhead of frequent initialization in often-called functions.

If you do not explicitly initialize a static variable, it is initialized to 0 by default. Inside a function, static causes storage to be allocated and serves as a definition. Internal static variables provide private, permanent storage visible to only a single function.


  The extern Storage-Class Specifier

A variable declared with the extern storage-class specifier is a reference to a variable with the same name defined at the external level in any of the source files of the program. The internal extern declaration is used to make the external-level variable definition visible within the block. Unless otherwise declared at the external level, a variable declared with the extern keyword is visible only in the block in which it is declared. This example illustrates internal- and external-level declarations:

#include <stdio.h>
int i = 1;
void other( void );

main()
{
    /* Reference to i, defined above: */
    extern int i;

    /* Initial value is zero; a is visible only within main: */
    static int a;

    /* b is stored in a register, if possible: */
    register int b = 0;

    /* Default storage class is auto: */
    int c = 0;

    /* Values printed are 1, 0, 0, 0: */
    printf( "%d\n%d\n%d\n%d\n", i, a, b, c );
    other();
    return;
}

void other( void )
{
    /* Address of global i assigned to pointer variable: */
    static int *external_i = &i;

    /* i is redefined; global i no longer visible: */
    int i = 16;

    /* This a is visible only within the other function: */
    static int a = 2;

    a += 2;
    /* Values printed are 16, 4, and 1: */
    printf( "%d\n%d\n%d\n", i, a, *external_i );
}

In this example, the variable i is defined at the external level with initial value 1. An extern declaration in the main function is used to declare a reference to the external-level i. The static variable a is initialized to 0 by default, since the initializer is omitted. The call to printf prints the values 1, 0, 0, and 0.

In the other function, the address of the global variable i is used to initialize the static pointer variable external_i. This works because the global variable has static lifetime, meaning its address does not change during program execution. Next, the variable i is redefined as a local variable with initial value 16. This redefinition does not affect the value of the external-level i, which is hidden by the use of its name for the local variable. The value of the global i is now accessible only indirectly within this block, through the pointer external_i. Attempting to assign the address of the auto variable i to a pointer does not work, since it may be different each time the block is entered. The variable a is declared as a static variable and initialized to 2. This a does not conflict with the a in main, since static variables at the internal level are visible only within the block in which they are declared.

The variable a is increased by 2, giving 4 as the result. If the other function were called again in the same program, the initial value of a would be 4, since internal static variables keep their values when the program exits and then reenters the block in which they are declared.


  Storage-Class Specifiers with Function Declarations

You can use either the static or the extern storage-class specifier in function declarations. Functions always have global lifetimes.

Microsoft Specific

Function declarations at the internal level have the same meaning as function declarations at the external level. This means that a function is visible from its point of declaration throughout the rest of the translation unit even if it is declared at local scope. ♦

The visibility rules for functions vary slightly from the rules for variables, as follows:

•	A function declared to be static is visible only within the source file in which it is defined. Functions in the same source file can call the static function, but functions in other source files cannot access it directly by name. You can declare another static function with the same name in a different source file without conflict.

•	Functions declared as extern are visible throughout all the source files that make up the program (unless you later redeclare such a function as static). Any function can call an extern function.

•	Function declarations that omit the storage-class specifier are extern by default.

Microsoft Specific

Microsoft allows redefinition of an extern identifier as static. ♦


  3.3  Type Specifiers

Type specifiers in declarations define the type of a variable or function declaration.

Syntax

type-specifier :
void
char
short
int
long
float
double
signed
unsigned
struct-or-union-specifier
enum-specifier
typedef-name

The signed char, signed int, signed short int, and signed long int types, together with their unsigned counterparts and enum, are called "integral" types. The float, double, and long double type specifiers are referred to as "floating" or "floating-point" types. You can use any integral or floating-point type specifier in a variable or function declaration. If a type-specifier is not provided in a declaration, it is taken to be int.

The optional keywords signed and unsigned can precede or follow any of the integral types, except enum, and can also be used alone as type specifiers, in which case they are understood as signed int and unsigned int, respectively. When used alone, the keyword int is assumed to be signed. When used alone, the keywords long and short are understood as long int and short int.

Enumeration types are considered basic types. Type specifiers for enumeration types are discussed in »Enumeration Declarations«.

The keyword void has three uses: to specify a function return type, to specify an argument-type list for a function that takes no arguments, and to specify a pointer to an unspecified type. You can use the void type to declare functions that return no value or to declare a pointer to an unspecified type. See »Arguments« for information on void when it appears alone within the parentheses following a function name.

Microsoft Specific

Type checking is now ANSI-compliant, which means that type short and type int are distinct types. For example, this is a redefinition in the Microsoft C compiler that was accepted by previous versions of the compiler.

int   myfunc();
short myfunc();

This next example also generates a warning about indirection to different types:

int *pi;
short *ps;

ps = pi;  /* Now generates warning */

The Microsoft C compiler also generates warnings for differences in sign. For example:

signed int *pi;
unsigned int *pu

pi = pu;  /* Now generates warning */

Type void expressions are evaluated for side effects. You cannot use the (nonexistent) value of an expression that has type void in any way, nor can you convert a void expression (by implicit or explicit conversion) to any type except void. If you do use an expression of any other type in a context where a void expression is required, its value is discarded.

To conform to the ANSI specification, void** cannot be used as int**. Only void* can be used as a pointer to an unspecified type. ♦

You can create additional type specifiers with typedef declarations, as described in »Typedef Declarations«. See »Storage of Basic Types« for information on the size of each type.

This manual generally uses the forms of the type specifiers listed in Table 3.1 rather than the long forms, and it assumes that the char type is signed by default. Therefore, throughout this manual, char is equivalent to signed char.

Table 3.1    Type Specifiers and Equivalents

Type Specifier	Equivalent(s)
signed char (1)	char
signed int	signed, int
signed short int	short, signed short
signed long int	long, signed long
unsigned char	—
unsigned int	unsigned
unsigned short int	unsigned short
unsigned long int	unsigned long
float	—
long double (2)	—
1 When you make the char type unsigned by default (by specifying the /J compiler option), you cannot abbreviate signed char as char. 2 The 32-bit compiler maps long double to type double.
Microsoft Specific

You can specify the /J compiler option to change the default char type from signed to unsigned. When this option is in effect, char means the same as unsigned char, and you must use the signed keyword to declare a signed character value. If a char value is explicitly declared signed, the /J option does not affect it, and the value is sign-extended when widened to an int type. The char type is zero-extended when widened to int type. ♦


  3.4  Type Qualifiers

Type qualifiers give one of two properties to an identifier. The const type qualifier declares an object to be nonmodifiable. The volatile type qualifier declares an item whose value can legitimately be changed by something beyond the control of the program in which it appears, such as a concurrently executing thread. The two type qualifiers, const and volatile, can appear only once in a declaration and must be placed after the type they qualify. Type qualifiers can appear with any type specifier. They are relevant only when accessing identifiers as l-values in expressions. See »L-Value and R-Value Expressions« for information about lvalues and expressions.

Syntax

type-qualifier :
const
volatile

The following are legal const and volatile declarations:

int const *p_ci;       /* Pointer to constant int */
int const (*p_ci);     /* Pointer to constant int */
int *const cp_i;       /* Constant pointer to int */
int (*const cp_i);     /* Constant pointer to int */
int volatile vint;     /* Volatile integer        */

If the specification of an array type includes type qualifiers, the element is qualified, not the array type. If the specification of the function type includes qualifiers, the behavior is undefined. Neither volatile nor const affect the range of values or arithmetic properties of the object.

This list describes how to use const and volatile.

•	The const keyword can be used to modify any fundamental or aggregate type, a pointer to an object of any type, or a typedef. If an item is declared with only the const type qualifier, its type is taken to be const int. A const variable can be initialized or can be placed in a read-only region of storage. The const keyword is useful for declaring pointers to const since this requires the function not to change the pointer in any way.

•	The compiler assumes that, at any point in the program, a volatile variable can be accessed by an unknown process that uses or modifies its value. Therefore, regardless of the optimizations specified on the command line, the code for each assignment to or reference of a volatile variable must be generated even if it appears to have no effect.

If volatile is used alone, int is assumed. The volatile type specifier can be used to provide reliable access to special memory locations. Use volatile with data objects that may be accessed or altered by signal handlers, by concurrently executing programs, or by special hardware such as memory-mapped I/O control registers. You can declare a variable as volatile for its lifetime, or you can cast a single reference to be volatile.

•	An item can be both const and volatile, in which case the item could not be legitimately modified by its own program, but could be modified by some asynchronous process.


  3.5  Declarators and Variable Declarations

The rest of this chapter describes the form and meaning of declarations for variable types summarized in this list. In particular, the remaining sections explain how to declare the following:

Type of Variable	Description
Simple variables	Single-value variables with integral or floating-point type
Arrays	Variables composed of a collection of elements with the same type
Pointers	Variables that point to other variables and contain variable locations (in the form of addresses) instead of values
Enumeration variables	Simple variables with integral type that hold one value from a set of named integer constants
Structures	Variables composed of a collection of values that can have different types
Unions	Variables composed of several values of different types that occupy the same storage space
A declarator is the part of a declaration that specifies the name that is to be introduced into the program. It can include modifiers such as * (pointer-to) and any of the Microsoft calling-convention and memory-model keywords.

Microsoft Specific

In the declarator

char * __far *var;

char is the type specifier, *__far and * are the modifiers, and var is the identifier's name. ♦

You use declarators to declare arrays of values, pointers to values, and functions returning values of a specified type. Declarators appear in the pointer, array, and »function declarations« described later in this chapter.

Syntax

declarator :
pointer  (opt)  direct-declarator

direct-declarator :
identifier
( declarator )
direct-declarator [ constant-expression  (opt)  ( ) ]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-list  (opt)  )

pointer :
* type-qualifier-list  (opt)
* type-qualifier-list  (opt)  pointer

type-qualifier-list :
type-qualifier
type-qualifier-list type-qualifier

Note  See the syntax for declaration in »Overview of Declarations«, or see Appendix A, C Language Syntax Summary, for the syntax that references a declarator.

When a declarator consists of an unmodified identifier, the item being declared has a base type. If an asterisk (*) appears to the left of an identifier, the type is modified to a pointer type. If the identifier is followed by brackets ([ ]), the type is modified to an array type. If the identifier is followed by parentheses, the type is modified to a function type. For more information about interpreting precedence within declarations, see »Interpreting More Complex Declarators«.

Each declarator declares at least one identifier. A declarator must include a type specifier to be a complete declaration. The type specifier gives the type of the elements of an array type, the type of object addressed by a pointer type, or the return type of a function.

»Array«, »pointer«, and »function declarations« are discussed in more detail later in this chapter. The following examples illustrate a few simple forms of declarators:

int list[20]; /* Declares an array of 20 int values named list */

char *cp;     /* Declares a pointer to a char value */

double func( void ); /* Declares a function named func, with no
                        arguments, that returns a double value */

int *aptr[10]         /* Declares an array of 10 pointers */

Microsoft Specific

The Microsoft C compiler does not limit the number of declarators that can modify an arithmetic, structure, or union type. The number is limited only by available memory. ♦


  Special Keywords in Declarations (Microsoft Specific)

The Microsoft-specific keywords can also be used in declarations. These keywords modify the meaning of variable and function declarations. When a special keyword appears in a declarator, it modifies the item immediately to the right of the keyword. Since these keywords are not used in all C compilers, code using these keywords might not be portable.

You can apply more than one special keyword to the same item. For example, you might modify a function identifier with both the __far keyword and the __pascal keyword. In this case, the order of the keywords does not matter (that is, __far __pascal myvar and __pascal __far myvar have the same effect). Thus the "binding" characteristics of the special keywords are the same as those of the type specifiers const and volatile except that const and volatile bind to the left and the keywords such as __far bind to the right. (»Type Qualifiers« contains descriptions of the const and volatile keywords.)


  Using Address-Related Keywords (Microsoft Specific)

16-Bit Specific

The __near, __far, __huge, and __based keywords modify static data objects (variables with file scope or with static local variables, but not automatic variables). If an object identifier is to the right of the keyword, the keyword determines if the object will be allocated in the default data segment or in a separate data segment. If a pointer is to the right of the keyword, the keyword determines whether the pointer will hold a near, based, far, or huge address. Examples using these keywords appear in »Using the Special Keywords«.

You can override the default addressing convention for a given function, function call, or data reference by declaring code or data items as near, far, huge, or based. You don't need to change the addressing conventions for the program as a whole if you use the __near, __far, __huge, or __based keyword.

The following list summarizes the characteristics of data defined with these keywords. See »Function Attributes« for additional information on using these keywords in function declarations.

__near

Data resides in the default data segment, _DATA. It is referenced with 16-bit addresses (near pointers to data are 16 bits), so data addressed can be in the default segment only. Variables declared with the __near keyword use 16-bit pointer arithmetic.

__far

Data can be anywhere in memory. It is not assumed to reside in the current data segment. Data items are referenced with 32-bit addresses (far pointers to data are 32 bits). Data objects declared as far must reside within the segment in which they start. Therefore, they must be smaller than 64K. Variables declared with the __far keyword use 16-bit pointer arithmetic.

__huge

Data can be anywhere in memory. It is not assumed to reside in the current data segment. Individual arrays can exceed 64K in size. Data is referenced with 32-bit addresses (huge pointers to data are 32 bits). The __huge keyword is not applicable to functions. Variables declared with the __huge keyword use 32-bit pointer arithmetic for data (same restrictions as for arrays specified with the __huge keyword). Objects declared as huge trade efficiency in pointer arithmetic for relaxed limits on array and object size. Objects with automatic storage class cannot be declared as huge.

__based

Data can be anywhere in memory. It is not assumed to reside in the current data segment. The range of 32-bit addresses is provided by 16-bit addresses plus a programmer-provided base. A based pointer is a 16-bit value interpreted as an offset from a supplied base. Variables declared with the __based keyword use 16-bit pointer arithmetic for data. See "»Based Pointers«" for more information on __based. ♦

32-Bit Specific

For 32-bit targets, __based specifies that a pointer is a 32-bit offset from a 32-bit base. The 32-bit compiler generates an error if you use __near, __far, or __huge. ♦


  Data Declarations with the __based Keyword (Microsoft Specific)

Static and external objects can be declared using the __based keyword. In this context, the __based specification causes the object to be allocated in the specified segment.

To specify the segment for storing data, you can use the built-in function __segname. The __segname keyword is only implemented for 16-bit targets. This function accepts a string literal and returns a value of type __segment. The code looks like this:

__segname( string-literal )

This declares a based variable by giving a segment constant as a base. The string-literal can be the name of any predefined segment ('_CODE', '_CONST', '_DATA', but not '_STACK'), or it can be the name of a new segment you define.

External data based on seg-expr, a segment variable of type __segment, has the form

extern type __based( seg-expr )

Data declared this way resides in a location determined at run time. You can relocate a segment in memory, set seg-expr to the new location of that segment, and access a variable stored in that segment without using pointers.

Data based on the address of another variable has the form

__based( (__segment)&var )

The var specified must itself be based on a named segment. This declaration places both variables in the same segment.

32-Bit Specific

The __segment and __segname keywords are not supported by the 32-bit compiler. ♦


  Using the Special Keywords (Microsoft Specific)

This section provides examples of how to use the special keywords. You can use two or more special keywords in different parts of a declaration to modify the meaning of the declaration.

As in any C declaration, you can use parentheses to override the default interpretation of the declaration. The rules governing complex declarators (discussed in »Interpreting More Complex Declarators«) also apply to declarations that use the special keywords. The memory model determines the default size for pointers. This can be specified with the command-line options /AL, /AS, /AM, and /AH.

int __huge database[65000];

This example declares a huge array named database with 65,000 int elements. The __huge keyword modifies the array declarator.

char * __far * x;
char * (__far *x);

In these statements, the __far keyword modifies the asterisk to its right, making x a far pointer to a pointer to char. The second statement is an alternative way to write this declaration that can make your code easier to read.

char __far __fortran initlist[INITSIZE];

char __far *nextchar, __far *prevchar, __far *currentchar;

In the two declarations above, the first declares a __far __fortran array of characters named initlist, and the second declares three far pointers named nextchar, prevchar, and currentchar. These pointers might be used to store the addresses of characters in the initlist array. Note that the __far keyword must be repeated before each declarator.

char __far *(__far *getint)( int __far * );
 ^      ^       ^      ^   ^        ^
 6      5       2      1   3        4

This example shows a more complex declaration with several occurrences of the __far keyword. The numbers indicate the order in which the declaration is interpreted in the following procedure:

1.	The identifier getint is declared as a

2.	__far pointer to

3.	a function taking

4.	a single argument, that is, a __far pointer to an int value

5.	and returning a __far pointer to a

6.	char value.

Note that the __far keyword always modifies the item immediately to its right. For more information, see »Interpreting More Complex Declarators«.


  Simple Variable Declarations

The declaration of a simple variable, the simplest form of a direct declarator, specifies the variable's name and type. It also specifies the variable's storage class and data type.

Storage classes or types (or both) are required on variable declarations. Untyped variables (such as var;) generate warnings.

Syntax

declarator :
pointer  (opt)  direct-declarator

direct-declarator :
identifier

identifier :
nondigit
identifier nondigit
identifier digit

For arithmetic, structure, union, enumerations, and void types, and for types represented by typedef names, simple declarators can be used in a declaration since the type specifier supplies all the typing information. Pointer, array, and function types require more complicated declarators.

You can use a list of identifiers separated by commas (,) to specify several variables in the same declaration. All variables defined in the declaration have the same base type. For example:

int x, y;        /* Declares two simple variables of type int */
int const z = 1; /* Declares a constant value of type int */

The variables x and y can hold any value in the set defined by the int type for a particular implementation. The simple object z is initialized to the value 1 and is not modifiable.

If the declaration of z was for an uninitialized static variable or was at file scope, it would receive an initial value of 0, and that value would be unmodifiable.

unsigned long reply, flag; /* Declares two variables
                              named reply and flag     */

In this example, both the variables, reply and flag, have unsigned long type and hold unsigned integral values.


  Enumeration Declarations

An enumeration consists of a set of named integer constants. An enumeration type declaration gives the name of the (optional) enumeration tag and defines the set of named integer identifiers (called the "enumeration set," "enumerator constants," "enumerators," or "members"). A variable with enumeration type stores one of the values of the enumeration set defined by that type.

Variables of enum type can be used in indexing expressions and as operands of all arithmetic and relational operators. Enumerations provide an alternative to the #define preprocessor directive with the advantages that the values can be generated for you and obey normal scoping rules.

In ANSI C, the expressions that define the value of an enumerator constant always have int type; thus, the storage associated with an enumeration variable is the storage required for a single int value. An enumeration constant or a value of enumerated type can be used anywhere the C language permits an integer expression.

Syntax

enum-specifier :
enum identifier  (opt)  { enumerator-list }
enum identifier

The optional identifier names the enumeration type defined by enumerator-list. This identifier is often called the "tag" of the enumeration specified by the list. A type specifier of the form

enum identifier { enumerator-list }

declares identifier to be the tag of the enumeration specified by the enumerator-list  nonterminal. The enumerator-list defines the "enumerator content." The enumerator-list is described in detail below.

If the declaration of a tag is visible, subsequent declarations that use the tag but omit enumerator-list specify the previously declared enumerated type. The tag must refer to a defined enumeration type, and that enumeration type must be in current scope. Since the enumeration type is defined elsewhere, the enumerator-list does not appear in this declaration. Declarations of types derived from enumerations and typedef declarations for enumeration types can use the enumeration tag before the enumeration type is defined.

Syntax

enumerator-list :
enumerator
enumerator-list , enumerator

enumerator :
enumeration-constant
enumeration-constant = constant-expression

enumeration-constant :
identifier

Each enumeration-constant in an enumeration-list names a value of the enumeration set. By default, the first enumeration-constant is associated with the value 0. The next enumeration-constant in the list is associated with the value of ( constant-expression + 1 ), unless you explicitly associate it with another value. The name of an enumeration-constant is equivalent to its value.

You can use enumeration-constant = constant-expression to override the default sequence of values. Thus, if enumeration-constant = constant-expression appears in the enumerator-list, the enumeration-constant is associated with the value given by constant-expression. The constant-expression must have int type and can be negative.

The following rules apply to the members of an enumeration set:

•	An enumeration set can contain duplicate constant values. For example, you could associate the value 0 with two different identifiers, perhaps named null and zero, in the same set.

•	The identifiers in the enumeration list must be distinct from other identifiers in the same scope with the same visibility, including ordinary variable names and identifiers in other enumeration lists.

•	Enumeration tags obey the normal scoping rules. They must be distinct from other enumeration, structure, and union tags with the same visibility.

These examples illustrate enumeration declarations:

enum DAY            /* Defines an enumeration type    */
{
    saturday,       /* Names day and declares a       */
    sunday = 0,     /* variable named workday with    */
    monday,         /* that type                      */
    tuesday,
    wednesday,      /* wednesday is associated with 3 */
    thursday,
    friday
} workday;

The value 0 is associated with saturday by default. The identifier sunday is explicitly set to 0. The remaining identifiers are given the values 1 through 5 by default.

In this example, a value from the set DAY is assigned to the variable today.

enum DAY today = wednesday;

Note that the name of the enumeration constant is used to assign the value. Since the DAY enumeration type was previously declared, only the enumeration tag DAY is necessary.

To explicitly assign an integer value to a variable of an enumerated data type, use a type cast:

workday = ( enum DAY ) ( day_value - 1 );

This cast is recommended in C but is not required.

enum BOOLEAN  /* Declares an enumeration data type called BOOLEAN */
{
    false,     /* false = 0, true = 1 */
    true
};

enum BOOLEAN end_flag, match_flag; /* Two variables of type BOOLEAN */

This declaration can also be specified as

enum BOOLEAN { false, true } end_flag, match_flag;\

or as

enum BOOLEAN { false, true } end_flag;
enum BOOLEAN match_flag;

An example that uses these variables might look like this:

if ( match_flag == false )
    {
     .
     .   /* statement */
     .
    }
    end_flag = true;

Unnamed enumerator data types can also be declared. The name of the data type is omitted, but variables can be declared. The variable response is a variable of the type defined:

enum { yes, no } response;


  Structure Declarations

A "structure declaration" names a type and specifies a sequence of variable values (called "members" or "fields" of the structure) that can have different types. An optional identifier, called a "tag," gives the name of the structure type and can be used in subsequent references to the structure type. A variable of that structure type holds the entire sequence defined by that type. Structures in C are similar to the types known as "records" in other languages.

Syntax

struct-or-union-specifier :
struct-or-union identifier  (opt)  { struct-declaration-list }
struct-or-union identifier

struct-or-union :
struct
union

struct-declaration-list :
struct-declaration
struct-declaration-list struct-declaration

The structure content is defined to be

struct-declaration :
specifier-qualifier-list struct-declarator-list ;

specifier-qualifier-list :
type-specifier specifier-qualifier-list  (opt)
type-qualifier specifier-qualifier-list  (opt

) struct-declarator-list :
struct-declarator
struct-declarator-list , struct-declarator

struct-declarator :
declarator

The declaration of a structure type does not set aside space for a structure. It is only a template for later declarations of structure variables.

A previously defined identifier (tag) can be used to refer to a structure type defined elsewhere. In this case, struct-declaration-list cannot be repeated as long as the definition is visible. Declarations of pointers to structures and typedefs for structure types can use the structure tag before the structure type is defined. However, the structure definition must be encountered prior to any actual use of the size of the fields. This is an incomplete definition of the type and the type tag. For this definition to be completed, a type definition must appear later in the same scope.

The struct-declaration-list specifies the types and names of the structure members. A struct-declaration-list argument contains one or more variable or bit-field declarations.

Each variable declared in struct-declaration-list is defined as a member of the structure type. Variable declarations within struct-declaration-list have the same form as other variable declarations discussed in this chapter, except that the declarations cannot contain storage-class specifiers or initializers. The structure members can have any variable types except type void, an incomplete type, or a function type.

A member cannot be declared to have the type of the structure in which it appears. However, a member can be declared as a pointer to the structure type in which it appears as long as the structure type has a tag. This allows you to create linked lists of structures.

Structures follow the same scoping as other identifiers. Structure identifiers must be distinct from other structure, union, and enumeration tags with the same visibility.

Each struct-declaration in a struct-declaration-list must be unique within the list. However, identifier names in a struct-declaration-list do not have to be distinct from ordinary variable names or from identifiers in other structure declaration lists.

Nested structures can also be accessed as though they were declared at the file-scope level. For example, given this declaration:

struct a
{
    int x;
    struct b
    {
   int y;
    } var2;
} var1;

these declarations are both legal:

struct a var3;
struct b var4;

These examples illustrate structure declarations:

struct employee   /* Defines a structure variable named temp */
{
    char name[20];
    int id;
    long class;
} temp;

The employee structure has three members: name, id, and class. The name member is a 20-element array, and id and class are simple members with int and long type, respectively. The identifier employee is the structure identifier.

struct employee student, faculty, staff;

This example defines three structure variables: student, faculty, and staff. Each structure has the same list of three members. The members are declared to have the structure type employee, defined in the previous example.

struct           /* Defines an anonymous struct and a */
{                /* structure variable named complex  */
    float x, y;
} complex;

The complex structure has two members with float type, x and y. The structure type has no tag and is therefore unnamed or anonymous.

struct sample   /* Defines a structure named x */
{
    char c;
    float *pf;
    struct sample *next;
} x;

The first two members of the structure are a char variable and a pointer to a float value. The third member, next, is declared as a pointer to the structure type being defined (sample).

Anonymous structures can be useful when the tag named is not needed. This is the case when one declaration defines all structure instances. For example:

struct
{
    int x;
    int y;
} mystruct;

Embedded structures are often anonymous.

struct somestruct
{
    struct    /* Anonymous structure */
    {
        int x, y;
    } point;
    int type;
} w;

Microsoft Specific

The compiler allows an unsized or zero-sized array as the last member of a structure. This can be useful if the size of a constant array differs when used in various situations. The declaration of such a structure looks like this:

struct identifier
{
    set-of-declarations
    type array-name[ ];
};

Unsized arrays can appear only as the last member of a structure. Structures containing unsized array declarations can be nested within other structures as long as no further members are declared in any enclosing structures. Arrays of such structures are not allowed. The sizeof operator, when applied to a variable of this type or to the type itself, assumes 0 for the size of the array.

Structure declarations can also be specified without a declarator when they are members of another structure or union. The field names are promoted into the enclosing structure. For example, a nameless structure looks like this:

struct s
{
    float y;
    struct
    {
        int a, b, c;
    };
    char str[10];
} *p_s;
.
.
.
p_s->b = 100;  /* A reference to a field in the s structure */

See »Structure and Union Members« for information about structure references. ♦


  Bit Fields

In addition to declarators for members of a structure or union, a structure declarator can also be a specified number of bits, called a "bit field." Its length is set off from the declarator for the field name by a colon. A bit field is interpreted as an integral type.

Syntax

struct-declarator :
declarator
type-specifier declarator  (opt)  : constant-expression

The constant-expression specifies the width of the field in bits. The type-specifier for the declarator must be unsigned int, signed int, or int, and the constant-expression must be a nonnegative integer value. If the value is zero, the declaration has no declarator. Arrays of bit fields, pointers to bit fields, and functions returning bit fields are not allowed. The optional declarator names the bit field. Bit fields can only be declared as part of a structure. The address-of operator (&) cannot be applied to bit-field components.

Unnamed bit fields cannot be referenced, and their contents at run time are unpredictable. They can be used as "dummy" fields, for alignment purposes. An unnamed bit field whose width is specified as 0 guarantees that storage for the member following it in the struct-declaration-list begins on an int boundary.

Bit fields must also be long enough to contain the bit pattern. For example, these two statements are not legal:

short a:17;        /* Illegal! */
int long y:33;     /* Illegal! */

This example defines a two-dimensional array of structures named screen.

struct
{
    unsigned short icon : 8;
    unsigned short color : 4;
    unsigned short underline : 1;
    unsigned short blink : 1;
} screen[25][80];

The array contains 2,000 elements. Each element is an individual structure containing four bit-field members: icon, color, underline, and blink. The size of each structure is two bytes.

Bit fields have the same semantics as the integer type. This means a bit field is used in expressions in exactly the same way as a variable of the same base type would be used, regardless of how many bits are in the bit field.

Microsoft Specific

Bit fields defined as int are treated as signed. A Microsoft extension to the ANSI C standard allows char and long types (both signed and unsigned) for bit fields. Unnamed bit fields with base type long, short, or char (signed or unsigned) force alignment to a boundary appropriate to the base type.

Bit fields are allocated within an integer from least-significant to most-significant bit. In the following code

struct mybitfields
{
    unsigned short a : 4;
    unsigned short b : 5;
    unsigned short c : 7;
} test;

void main( void );
{
    test.a = 2;
    test.b = 31;
    test.c = 0;
}

the bits would be arranged as follows:

00000001 11110010
cccccccb bbbbaaaa

Since the 8086 family of processors stores the low byte of integer values before the high byte, the integer 0x01F2 above would be stored in physical memory as 0xF2 followed by 0x01. ♦


  Storage and Alignment of Structures (Microsoft Specific)

Structure members are stored sequentially in the order in which they are declared: the first member has the lowest memory address and the last member the highest.

Every data object has an alignment-requirement. For structures, the requirement is the largest of its members. Every object is allocated an offset so that

offset % alignment-requirement == 0

Adjacent bit fields are packed into the same 1-, 2-, or 4-byte allocation unit if the integral types are the same size and if the next bit field fits into the current allocation unit without crossing the boundary imposed by the common alignment requirements of the bit fields.

To conserve space or to conform to existing data structures, you may want to store structures more or less compactly. The /Zp[n] compiler option and the pack pragma control how structure data is "packed" into memory. When you use the /Zp[n] option, where n is 1, 2, 4, 8, or 16, each structure member after the first is stored on byte boundaries that are either the alignment requirement of the field or the packing size (n), whichever is smaller. Expressed as a formula, the byte boundaries are the

min( n, sizeof( item ) )

where n is the packing size expressed with the /Zp[n] option and item is the structure member.

On some processors, the /Zp[n] option can result in slower program execution because of the time required to unpack structure members when they are accessed. For example, on an 8086 processor, this option can reduce efficiency if members with int or long type are packed so that they begin on odd-byte boundaries.

To use the pack pragma to specify packing other than the packing specified on the command line for a particular structure, give the pack pragma, where the packing size is 1, 2, 4, 8, or 16, before the structure. To reinstate the packing given on the command line, specify the pack pragma with no arguments. For more information about the pack pragma, see Chapter 2 of the Preprocessor Reference.

See Chapter 13, "Writing Portable C Programs," of Programming Techniques for more information on packing structures.

Bit fields default to size long for the 32-bit compiler. Structure members are aligned on the size of the type or the /Zp[n] size, whichever is smaller. The default size is 4.

16-Bit Specific

The default packing size for 16-bit targets is /Zp2. ♦

32-Bit Specific

The default packing size for 32-bit targets is /Zp8. ♦


  Union Declarations

A "union declaration" specifies a set of variable values and, optionally, a tag naming the union. The variable values are called "members" of the union and can have different types. Unions are similar to "variant records" in other languages.

Syntax

struct-or-union-specifier :
struct-or-union identifier  (opt ) { struct-declaration-list }
struct-or-union identifier

struct-or-union :
struct
union

struct-declaration-list :
struct-declaration
struct-declaration-list struct-declaration

The union content is defined to be

struct-declaration :
specifier-qualifier-list struct-declarator-list ;

specifier-qualifier-list :
type-specifier specifier-qualifier-list  (opt)
type-qualifier specifier-qualifier-list  (opt

) struct-declarator-list :
struct-declarator
struct-declarator-list , struct-declarator

A variable with union type stores one of the values defined by that type. The same rules govern structure and union declarations. Unions can also have bit fields.

Members of unions cannot have an incomplete type, type void, or function type. Therefore members cannot be an instance of the union but can be pointers to the union type being declared.

A union type declaration is a template only. Memory is not reserved until the variable is declared.

Note  If a union of two types is declared and one value is stored, but the union is accessed with the other type, the results are unreliable. For example, a union of float and int is declared. A float value is stored, but the program later accesses the value as an int. In such a situation, the value would depend on the internal storage of float values. The integer value would not be reliable.

The following are examples of unions:

union sign   /* A definition and a declaration */
{
    int svar;
    unsigned uvar;
} number;

This example defines a union variable with sign type and declares a variable named number that has two members: svar, a signed integer, and uvar, an unsigned integer. This declaration allows the current value of number to be stored as either a signed or an unsigned value. The tag associated with this union type is sign.

union               /* Defines a two-dimensional */
{                   /*  array named screen */
    struct
    {
   unsigned int icon : 8;
   unsigned color : 4;
    } window1;
    int screenval;
} screen[25][80];

The screen array contains 2,000 elements. Each element of the array is an individual union with two members: window1 and screenval. The window1 member is a structure with two bit-field members, icon and color. The screenval member is an int. At any given time, each union element holds either the int represented by screenval or the structure represented by window1.

Microsoft Specific

Nested unions can be declared anonymously when they are members of another structure or union. This is an example of a nameless union:

struct str
{
    int a, b;
    union            / * Unnamed union */
    {
   char c[4];
   long l;
   float f;
};
char c_array[10];
} my_str;
.
.
.
my_str.l == 0L;  /* A reference to a field in the my_str union */

Unions are often nested within a structure that includes a field giving the type of data contained in the union at any particular time. This is an example of a declaration for such a union:

struct x
{
    int type_tag;
    union
    {
   int x;
   float y;
    }
}

See »Structure and Union Members« for information about referencing unions. ♦


  Storage of Unions

The storage associated with a union variable is the storage required for the largest member of the union. When a smaller member is stored, the union variable can contain unused memory space. All members are stored in the same memory space and start at the same address. The stored value is overwritten each time a value is assigned to a different member. For example:

union         /* Defines a union named x */
{
    char *a, b;
    float f[20];
} x;

The members of the x union are, in order of their declaration, a pointer to a char value, a char value, and an array of float values. The storage allocated for x is the storage required for the 20-element array f, since f is the longest member of the union. Because there is no tag associated with the union, its type is unnamed or "anonymous."


  Array Declarations

An "array declaration" names the array and specifies the type of its elements. It can also define the number of elements in the array. A variable with array type is considered a pointer to the type of the array elements.

Syntax

declaration :
declaration-specifiers init-declarator-list  (opt)  ;

init-declarator-list :
init-declarator
init-declarator-list , init-declarator

init-declarator :
declarator
declarator = initializer

declarator :
pointer  (opt)  direct-declarator

direct-declarator :
direct-declarator [ constant-expression  (opt)  ]

Because constant-expression is optional, the syntax has two forms:

•	The first form defines an array variable. The constant-expression argument within the brackets specifies the number of elements in the array. The constant-expression, if present, must have integral type, and a value larger than zero. Each element has the type given by type-specifier, which can be any type except void. An array element cannot be a function type.

•	The second form declares a variable that has been defined elsewhere. It omits the constant-expression argument in brackets, but not the brackets. You can use this form only if you previously have initialized the array, declared it as a parameter, or declared it as a reference to an array explicitly defined elsewhere in the program.

In both forms, direct-declarator names the variable and can modify the variable's type. The brackets ([ ]) following direct-declarator modify the declarator to an array type.

Type qualifiers can appear in the declaration of an object of array type, but the qualifiers apply to the elements rather than the array itself.

You can declare an array of arrays (a "multidimensional" array) by following the array declarator with a list of bracketed constant expressions in this form:

type-specifier declarator [constant-expression] [constant-expression] ...

Each constant-expression in brackets defines the number of elements in a given dimension: two-dimensional arrays have two bracketed expressions, three-dimensional arrays have three, and so on. You can omit the first constant expression if you have initialized the array, declared it as a parameter, or declared it as a reference to an array explicitly defined elsewhere in the program.

You can define arrays of pointers to various types of objects by using complex declarators, as described in »Interpreting More Complex Declarators«.

Arrays are stored by row. For example, the following array consists of two rows with three columns each:

char A[2][3];

The three columns of the first row are stored first, followed by the three columns of the second row. This means that the last subscript varies most quickly.

To refer to an individual element of an array, use a subscript expression, as described in »Postfix Operators«.These examples illustrate array declarations:

float matrix[10][15];

The two-dimensional array named matrix has 150 elements, each having float type.

struct {
    float x, y;
} complex[100];

This is a declaration of an array of structures. This array has 100 elements; each element is a structure containing two members.

extern char *name[];

This statement declares the type and name of an array of pointers to char. The actual definition of name occurs elsewhere.

Microsoft Specific

The type of integer required to hold the maximum size of an array is the size of size_t. ♦

16-Bit Specific

The size_t type definition for 16-bit targets is an unsigned int, with the range 0x0000 to 0xFFFF hexadecimal. Huge arrays can exceed this limit if they contain more than 65,535 elements or the size of the element multiplied by the number of elements is greater than 65K. Arithmetic operations on arrays specified with the __huge keyword should therefore cast size_t and the results of an arithmetic operation on pointers to unsigned long. ♦

32-Bit Specific

For 32-bit targets, size_t is an unsigned int with the range 0x00000000 to 0x7CFFFFFF. The __huge keyword is not allowed. ♦


  Storage of Arrays

The storage associated with an array type is the storage required for all of its elements. The elements of an array are stored in contiguous and increasing memory locations, from the first element to the last.


  Pointer Declarations

A "pointer declaration" names a pointer variable and specifies the type of the object to which the variable points. A variable declared as a pointer holds a memory address.

Syntax

declarator :
pointer  (opt)  direct-declarator

direct-declarator :
identifier
( declarator )
direct-declarator [ constant-expression  (opt)  ]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-list  (opt)  )

pointer :
* type-qualifier-list  (opt)
* type-qualifier-list  (opt)  pointer

type-qualifier-list :
type-qualifier
type-qualifier-list type-qualifier

The type-specifier gives the type of the object, which can be any basic, structure, or union type. Pointer variables can also point to functions, arrays, and other pointers. (For information on declaring and interpreting more complex pointer types, refer to »Interpreting More Complex Declarators«.)

By making the type-specifier void, you can delay specification of the type to which the pointer refers. Such an item is referred to as a "pointer to void" and is written as void *. A variable declared as a pointer to void can be used to point to an object of any type. However, to perform most operations on the pointer or on the object to which it points, the type to which it points must be explicitly specified for each operation. (Variables of type char * and type void * are assignment-compatible without a type cast.) Such conversion can be accomplished with a type cast (see »Type-Cast Conversions«.

The type-qualifier can be either const or volatile, or both. These specify, respectively, that the pointer cannot be modified by the program itself (const), or that the pointer can legitimately be modified by some process beyond the control of the program (volatile). (See »Type Qualifiers« for more information on const and volatile.)

The declarator names the variable and can include a type modifier. For example, if declarator represents an array, the type of the pointer is modified to be a pointer to an array.

You can declare a pointer to a structure, union, or enumeration type before you define the structure, union, or enumeration type. You declare the pointer by using the structure or union tag as shown in the examples below. Such declarations are allowed because the compiler does not need to know the size of the structure or union to allocate space for the pointer variable.

The following examples illustrate pointer declarations.

char *message; /* Declares a pointer variable named message */

The message pointer points to a variable with char type.

int *pointers[10];  /* Declares an array of pointers */

The pointers array has 10 elements; each element is a pointer to a variable with int type.

int (*pointer)[10]; /* Declares a pointer to an array of 10 elements */

The pointer variable points to an array with 10 elements. Each element in this array has int type.

int const *x;      /* Declares a pointer variable, x,
                      to a constant value */

The pointer x can be modified to point to a different int value, but the value to which it points cannot be modified.

const int some_object = 5 ;
int other_object = 37;
int *const y = &fixed_object;
const volatile *const z = &some_object;
int *const volatile w = &some_object;

The variable y in these declarations is declared as a constant pointer to an int value. The value it points to can be modified, but the pointer itself must always point to the same location: the address of fixed_object. Similarly, z is a constant pointer, but it is also declared to point to an int whose value cannot be modified by the program. The additional specifier volatile indicates that although the value of the const int pointed to by z cannot be modified by the program, it could legitimately be modified by a process running concurrently with the program. The declaration of w specifies that the program cannot change the value pointed to and that the program cannot modify the pointer.

struct list *next, *previous; /* Uses the tag for list */

This example declares two pointer variables, next and previous, that point to the structure type list. This declaration can appear before the definition of the list structure type (see the next example), as long as the list type definition has the same visibility as the declaration.

struct list
{
    char *token;
    int count;
    struct list *next;
} line;

The variable line has the structure type named list. The list structure type has three members: the first member is a pointer to a char value, the second is an int value, and the third is a pointer to another list structure.

struct id
{
    unsigned int id_no;
    struct name *pname;
} record;

The variable record has the structure type id. Note that pname is declared as a pointer to another structure type named name. This declaration can appear before the name type is defined.


  Storage of Addresses

The amount of storage required for an address and the meaning of the address depend on the implementation of the compiler. Pointers to different types are not guaranteed to have the same length. Therefore, sizeof(char *) is not necessarily equal to sizeof(int *).

Microsoft Specific

For the Microsoft C compiler, sizeof(char *) is equal to sizeof(int *). You can also use the special keywords __near, __far, __huge, and __based for 16-bit targets to modify and reference the size of a pointer. Declarations using special keywords are described in »Special Keywords in Declarations«. ♦


  Based Pointers (Microsoft Specific)

For the 16-bit compiler, a based pointer operates as a 16-bit offset from a base you specify. For the 32-bit compiler, a based pointer is a 32-bit offset from a 32-bit pointer base. In this respect, based addressing differs from near, far, or huge addressing because you are responsible for naming the base.

Based addressing is useful for exercising control over segments where objects are allocated and for referencing far objects with 16-bit addresses, thereby decreasing the size of the executable file and increasing execution speed.

The __based keyword specifies that a pointer is a 16-bit value interpreted as an offset from a specified base, or that a data object resides in the segment given by a specified base. In general, the form for specifying a based pointer is

type __based( base ) declarator

The following code shows some examples of based pointer declarations:

typedef struct tree BTree;
struct tree    /* Binary tree */
{
    char *szSymbolName;
    BTree *btLeft;
    BTree *btRight;
};

/* Pointer to data that resides in segment SYM_DATA: */

BTree __based( __segname( "SYM_DATA" ) ) *btSymTable1;

/* Pointer to data that resides in same segment
   as the pointer btSymTable3: */

BTree __based( (__segment) __self ) *btSymTable3;

Based pointers can address any location in memory but are only 2 bytes in size for 16-bit targets (4 bytes for 32-bit targets), because they contain only the offset portion of an address. The segment portion of the address is stored separately and is combined with the offset when needed. Multiple based pointers can share the same segment value, so they require less memory than far pointers and allow the compiler to generate better code.

A based pointer can be based on a fixed segment, a variable segment, self, void, or a pointer. The following sections explain these topics. For information on based functions, see »Function Addressing Using __based«.


  Using __segname and __segment (Microsoft Specific)

16-Bit Specific

The built-in function __segname accepts a quoted string and returns a value of type __segment. This built-in function can be used to initialize variables of type __segment or in declarations of based identifiers or pointers. A __segname declaration is not an l-value, and its address cannot be taken. The primary use for __segname is in initializing identifiers of type __segment or in declarations of pointers or identifiers of based type. It enables specification of a segment name instead of a segment value when declaring a based type.

The __segment keyword is a type that contains a segment value. Variables of such type can contain a segment value. A variable or value of that type is used either at the point of declaration of a based type or at the point of a based dereference to specify the segment in which the based identifier resides.

An identifier of type __segment can be initialized with the following:

•	An expression that evaluates to an integral constant value.

•	The result of the built-in function __segname. This allows specification of a segment by name, causing the linker to insert segment fixups in the executable file, to be resolved at load time. This kind of initialization can be performed only on static and external identifiers, not identifiers with block scope.

•	Another expression of type __segment. For example:

int main()
{
    __segment sgCustomerData = 0x7000;
    __segment sgCurrent = sgCustomerData;
}

•	Another expression explicitly cast to type __segment.

If specified at the point of declaration, the segment value is implicit and need not be respecified at the point of dereference (based pointers). Otherwise, the segment must be explicitly specified. ♦

32-Bit Specific

The __segment type and the built-in function __segname are not supported by the 32-bit compiler. ♦


  Pointers Based on a Constant (Microsoft Specific)

16-Bit Specific

Pointers based on a constant are restricted to accessing one segment of memory. By making assignments to the based pointer, you change only the offset portion of the address. To specify a pointer based on a fixed segment, you can use the __segname built-in function or the __segment keyword to supply the segment name.

Pointers based on a named segment are specified as

__segname( string-literal )

The string-literal can be the name of any predefined segment ('_CODE', '_CONST', '_DATA', but not '_STACK'), or it can be the name of a new segment you define. A based pointer declared this way can address locations in only the specified segment.

Pointers based on the segment of a variable are specified as

(__segment)&var

A based pointer declared this way uses the segment of the address of var as its base. It can address locations only in the same segment as var.

In the following example, sgConst is explicitly declared as a constant. The pointer bp1, therefore, is based on a constant.

const __segment sgConst = (const __segment)0x3000;
char __based( sgConst ) *bp1;

In the following example, the __segname function returns a constant value of type __segment. The pointer bp3, therefore, is based on a constant.

char __based( __segname("INFO_STRINGS") ) *bp3; ♦

32-Bit Specific

The __segment type and the built-in function __segname are not supported by the 32-bit compiler. ♦


  Pointers Based on a Segment Variable (Microsoft Specific)

16-Bit Specific

Pointers based on a nonfixed segment have access to locations in any segment simply by changing the value of the base. Changing a single segment value causes all pointers based on that segment to address new locations. You also can make assignments to the based pointers themselves to change their offset values.

Pointers based on a segment variable require that a variable of type __segment be declared. This variable determines what segment the based pointer refers to. The segment variable can be changed at run time. In the syntax

type __based( segvar ) * ptr

segvar is a pointer based on a segment variable which is specified as

__segment segvar

A based pointer declared this way uses the segment portion of ptr as its base. If ptr is a near pointer, the declared pointer uses the DS register as its base. If ptr is a far pointer, the declared pointer uses the segment of the ptr as its base. Changing the segment value of ptr causes the based pointer to address a new location.

This type of based pointer can be used for dynamic allocation of based identifiers.

The form of base of pointers based on another pointer is

type * ptr

A based pointer declared this way acts as an offset from ptr. Assigning a new value to ptr causes the based pointer to address a different location. ♦


  Pointers Based on Pointers (Microsoft Specific)

The "based on pointer" variant of based addressing enables specification of a pointer as a base. The based pointer, then, is an offset into the segment starting at the beginning of the pointer on which it is based.

One use for pointers based on pointers is for persistent identifiers that contain pointers. A linked list that consists of pointers based on a pointer can be saved to disk, then reloaded to another place in memory, with the pointers remaining valid.

The following example shows a pointer based on a pointer.

void *vpBuffer;

struct llist_t
{
    void __based( vpBuffer ) *vpData;
    struct llist_t __based( vpBuffer ) *llNext;
};

The pointer vpBuffer is assigned the address of memory allocated at some later point in the program. The linked list is relocated relative to the value of vpBuffer.

32-Bit Specific

Pointers based on pointer addresses are the only form of the __based keyword valid in 32-bit compilations. In such compilations, they are 32-bit displacements from a 32-bit base. ♦


  Pointers Based on void (Microsoft Specific)

Pointers based on void defer actual address calculation until the pointer is dereferenced. A pointer based on void acts as an offset into any segment. The form of a pointer based on void is

type __based( void ) * ptr

A pointer based on void has no implied segment as its base. The segment specified at the point of dereference can be a constant or a segment variable. The segment and offset are combined using the base operator (:>) to form an address that can be dereferenced using the indirection operator (*).

This example shows how to declare and dereference a pointer based on void.

void main()
{
__segment videomem = 0xB800;    /* Use videomem as segment  */
char __based(void) *vidptr;

                                /* Move to row 10, column 40 */
vidptr = (char __based(void) *)(2 * ((80 * 9) + 39));
*(videomem:>vidptr) = 'A';      /* Write an A there          */
}


  Pointers Based on the __self keyword (Microsoft Specific)

16-Bit Specific

Pointers based on self can access data anywhere in the segment in which the pointer resides. This form of declaration defers calculation of the pointer value until the point of dereference. They are declared using the __self keyword cast to the
__segment type as the base. You can base a pointer only on (__segment)__self; not on __self only. Basing a pointer on (__segment)__self can improve program performance by ensuring that the segment register be the same for addressing both the pointer and the data it addresses. Functions cannot return pointers based on self.

The __segment keyword must be used to cast to a segment value, as in the example below:

typedef struct tree TREE;

struct tree
{
    int name;
    TREE __based( (__segment)__self ) *left;
    TREE __based( (__segment)__self ) *right;
};

TREE __based( __segname( "MYSEGMENT" ) ) t1;

The example above declares a structure called tree and then declares t1 to be such a structure. The pointers within the structure are self-based, meaning that they point within the segment in which the tree structure is located.

Pointers based on (__segment)__self are particularly useful for optimizing access in self-referencing data structures such as linked-lists and trees.

Any based declarations that are based on (__segment)__self must apply to pointers only. Ordinary data identifiers cannot be self-based. ♦

32-Bit Specific

Pointers based on __self are not supported for 32-bit targets. ♦


  Function Declarations

A "function declaration" establishes the name and return type of a function and can specify the types, formal parameter names, and number of arguments to the function. A function declaration does not define the function body. It simply makes information about the function known to the compiler. This information enables the compiler to check the types of the actual arguments passed in calls to the function. Functions are declared with declarators.

Syntax

declarator :
     pointer  (opt)  direct-declarator

direct-declarator :                                          /* A function declarator */
     direct-declarator ( parameter-type-list ) /* New-style declarator */
     direct-declarator ( identifier-list  (opt)  )     /* Old-style declarator */

parameter-type-list :
     parameter-list
     parameter-list , ...

parameter-list :
     parameter-declaration
     parameter-list , parameter-declaration

parameter-declaration :
     declaration-specifiers declarator                     /* Named declarator */
     declaration-specifiers abstract-declarator  (opt)  /* Anonymous declarator */

identifier-list :        /* For old-style declarator */
     identifier
     identifier-list , identifier

declaration-specifiers :
     storage-class-specifier declaration-specifiers  (opt)
     type-specifier declaration-specifiers  (opt)
     type-qualifier declaration-specifiers  (opt

) abstract-declarator :            /* Used with anonymous declarators */
     pointer
     pointer  (opt)  direct-abstract-declarator

direct-abstract-declarator :
     ( abstract-declarator )
     direct-abstract-declarator  (opt)  [ constant-expression  (opt)  ]
     direct-abstract-declarator  (opt)  ( parameter-type-list  (opt)  )

If specified, storage-class-specifier can be either extern or static. Storage-class specifiers are discussed in »Storage Classes«. The type-specifier gives the function's return type, and declarator names the function. If you omit type-specifier from a function declaration, the function is assumed to return a value of type int. The parameter-type-list is described in »Parameters«..

Other declarators can appear in the same function declaration. These can be other functions returning values of the same type as the function, or declarations of any variables whose type is the same as the function's return type. Each such declaration must be separated from its predecessors and successors by a comma.

A function prototype gives information about the parameters, allowing the compiler to perform type checking and to convert arguments to the type expected by the parameter. The function definition defines the body of the function.


  Parameters

"Parameters" (sometimes called "formal parameters") describe the actual arguments that can be passed to a function. In a parameter-type-list, the parameter declarations establish the number and types of the actual arguments. They can also include identifiers of the formal parameters.

Note  Identifiers used to name the parameters in the prototype declaration are descriptive only. They go out of scope at the end of the declaration. Therefore, they need not be identical to the identifiers used in the declaration portion of the function definition. Using the same names may enhance readability but has no other significance.

Although the parameters can be omitted from a function declaration in the optional identifier-list form of the syntax, their inclusion is recommended. The extent of the information in the declaration influences the argument checking done on function calls that appear before the compiler has processed the function definition.

If a function has no parameters, the parentheses should contain the keyword void to specify that no arguments are passed to the function.

The only explicit storage-class-specifier permitted in parameters is register. If register is not specified, the storage class is auto. The register specifier is ignored unless the function declarator has a function definition. If the parentheses contain only the register keyword, the parameter is considered to represent an unnamed int for which register storage is being requested.

The declarator for a pointer, array, or function can be formed by combining a type specifier, plus the appropriate type qualifier, with an identifier. Alternatively, an abstract-declarator (that is, a declarator without a specified identifier) can be used. Complete declarators (int a) and abstract declarators (int) are permitted in the same prototype. For example:

int func( int a, int );  /* Accepted */

In a parameter declaration, a single typedef name inside parentheses is assumed to be an abstract declarator specifying a function with a single parameter, not as redundant parentheses around an identifier for the declarator. See »Abstract Declarators« for more information.

One other special construction permitted as a parameter is void *, representing a pointer to an identifier of unspecified type. Thus, in a call, the pointer can be used to pass any type of identifier after you convert the pointer (for example, with a cast) to a pointer to the desired type. Note that before operations can be performed on the pointer or the identifier it addresses, the pointer must be explicitly converted. »Pointer Declarations« provides further information on void *.

The list of parameters can be empty, full, or partial. If the list contains at least one declarator, a variable number of parameters can be specified by ending the list with a comma followed by three periods (, ...), referred to as the "ellipsis notation." No information about the number or type of the parameters after the comma is supplied. See »Calls with a Variable Number of Arguments« for information about functions with variable numbers of arguments.

Microsoft Specific

To maintain compatibility with previous versions of the Microsoft C compiler, the compiler accepts a comma without trailing periods at the end of a declarator list to indicate a variable number of arguments. (Trailing periods without a comma are not allowed.) However, this is a Microsoft extension to the ANSI C standard. New code should use the comma followed by three periods. ANSI also requires at least one argument before the ellipsis. The STDARG.H file enforces this restriction for accessing arguments. ♦


  Return Types

Functions can return values of any type except arrays and functions. Therefore, the type-specifier argument of a function declaration can specify any basic, structure, or union type. You can modify the function identifier with one or more asterisks (*) to declare a pointer return type. Functions declared as float always return a value of type float.

Microsoft Specific

In earlier versions of the Microsoft C compiler, the return value of a function using the obsolete form of a function declaration and returning type float was converted to type double. The Microsoft C compiler now conforms to the ANSI C standard by not changing the return type. ♦

Although functions cannot return arrays and functions, they can return pointers to arrays and functions. You can declare a function that returns a pointer to an array or function type by modifying the function identifier with asterisks (*), brackets ([ ]), and parentheses ( ( ) ). Such a function identifier is known as a "complex declarator." Rules for forming and interpreting complex declarators are discussed in »Interpreting More Complex Declarators«.

The following examples illustrate return types in function declarations:

void draw( void );

The draw function returns a void type (returns no value). The void keyword also replaces the list of parameters so no arguments are allowed for this function.

double ( *sum(double, double) )[3];

In this example, sum is declared as a function returning a pointer to an array of three double values. The sum function takes two double values as arguments.

int ( *select(void) )( int number );

The function named select takes no arguments and returns a pointer to a function. The pointer return value points to a function taking one int argument, represented by the identifier number, and returning an int value.

int prt( void * );

The function prt takes a pointer argument of any type and returns an int value. A pointer to any type could be passed as an argument to prt without producing a type-mismatch warning.

long ( *const rainbow[] ) ( int, ... ) ;

This array, named rainbow, contains an unspecified number of constant pointers to functions. Each of these takes at least one parameter of type int, as well as an unspecified number of other parameters. Each of the functions pointed to returns a long value.


  Abstract Declarators

An abstract declarator is a declarator without an identifier, consisting of one or more pointer, array, or function modifiers. The pointer modifier (*) always precedes the identifier in a declarator; array ([ ]) and function ( ( ) ) modifiers follow the identifier. Knowing this, you can determine where the identifier would appear in an abstract declarator and interpret the declarator accordingly. See »Interpreting More Complex Declarators« for additional information and examples of complex declarators. Generally typedef can be used to simplify declarators. See »Typedef Declarations«.

Abstract declarators can be complex. Parentheses in a complex abstract declarator specify a particular interpretation, just as they do for the complex declarators in declarations.

These examples illustrate abstract declarators:

int *         /* The type name for a pointer to type int:   */

int *[3]      /* An array of three pointers to int          */

int (*) [5]   /* A pointer to an array of five int          */

int *()       /* A function with no parameter specification */
              /* returning a pointer to int                 */

/* A pointer to a function taking no arguments and
 * returning an int
 */

int (*) ( void )

/* An array of an unspecified number of constant pointers to
 * functions each with one parameter that has type unsigned int
 * and an unspecified number of other parameters returning an int
 */

int (*const []) ( unsigned int, ... )

Note  The abstract declarator consisting of a set of empty parentheses, ( ), is not allowed because it is ambiguous. It is impossible to determine whether the implied identifier belongs inside the parentheses (in which case it is an unmodified type) or before the parentheses (in which case it is a function type).


  3.6  Interpreting More Complex Declarators

You can enclose any declarator in parentheses to specify a particular interpretation of a "complex declarator." A complex declarator is an identifier qualified by more than one array, pointer, or function modifier. You can apply various combinations of array, pointer, and function modifiers to a single identifier. Generally typedef may be used to simplify declarations. See »Typedef Declarations«.

In interpreting complex declarators, brackets and parentheses (that is, modifiers to the right of the identifier) take precedence over asterisks (that is, modifiers to the left of the identifier). Brackets and parentheses have the same precedence and associate from left to right. After the declarator has been fully interpreted, the type specifier is applied as the last step. By using parentheses you can override the default association order and force a particular interpretation. Never use parentheses, however, around an identifier name by itself. This could be misinterpreted as a parameter list.

A simple way to interpret complex declarators is to read them "from the inside out," using the following four steps:

1.	Start with the identifier and look directly to the right for brackets or parentheses (if any).

2.	Interpret these brackets or parentheses, then look to the left for asterisks.

3.	If you encounter a right parenthesis at any stage, go back and apply rules 1 and 2 to everything within the parentheses.

4.	Apply the type specifier.

char *( *(*var)() )[10];
 ^   ^  ^ ^ ^   ^    ^
 7   6  4 2 1   3    5

In this example, the steps are numbered in order and can be interpreted as follows:

1.	The identifier var is declared as

2.	a pointer to

3.	a function returning

4.	a pointer to

5.	an array of 10 elements, which are

6.	pointers to

7.	char values.

The following examples illustrate other complex declarations and show how parentheses can affect the meaning of a declaration.

int *var[5]; /* Array of pointers to int values */

The array modifier has higher priority than the pointer modifier, so var is declared to be an array. The pointer modifier applies to the type of the array elements; therefore, the array elements are pointers to int values.

int (*var)[5]; /* Pointer to array of int values */

In this declaration for var, parentheses give the pointer modifier higher priority than the array modifier, and var is declared to be a pointer to an array of five int values.

long *var( long, long ); /* Function returning pointer to long */

Function modifiers also have higher priority than pointer modifiers, so this declaration for var declares var to be a function returning a pointer to a long value. The function is declared to take two long values as arguments.

long (*var)( long, long ); /* Pointer to function returning long */

This example is similar to the previous one. Parentheses give the pointer modifier higher priority than the function modifier, and var is declared to be a pointer to a function that returns a long value. Again, the function takes two long arguments.

struct both       /* Array of pointers to functions */
{                 /*   returning structures         */
    int a;
    char b;
} ( *var[5] )( struct both, struct both );

The elements of an array cannot be functions, but this declaration demonstrates how to declare an array of pointers to functions instead. In this example, var is declared to be an array of five pointers to functions that return structures with two members. The arguments to the functions are declared to be two structures with the same structure type, both. Note that the parentheses surrounding *var[5] are required. Without them, the declaration is an illegal attempt to declare an array of functions, as shown below:

/* ILLEGAL */
struct both *var[5]( struct both, struct both );

The following statement declares an array of pointers.

unsigned int *(* const *name[5][10] ) ( void );

The name array has 50 elements organized in a multidimensional array. The elements are pointers to a pointer that is a constant. This constant pointer points to a function that has no parameters and returns a pointer to an unsigned type.

This next example is a function returning a pointer to an array of three double values.

double ( *var( double (*)[3] ) )[3];

In this declaration, a function returns a pointer to an array, since functions returning arrays are illegal. Here var is declared to be a function returning a pointer to an array of three double values. The function var takes one argument. The argument, like the return value, is a pointer to an array of three double values. The argument type is given by a complex abstract-declarator. The parentheses around the asterisk in the argument type are required; without them, the argument type would be an array of three pointers to double values. For a discussion and examples of abstract declarators, see »Abstract Declarators«.

union sign         /* Array of arrays of pointers */
{                  /* to pointers to unions       */
     int x;
     unsigned y;
} **var[5][5];

As the above example shows, a pointer can point to another pointer, and an array can contain arrays as elements. Here var is an array of five elements. Each element is a five-element array of pointers to pointers to unions with two members.

union sign *(*var[5])[5]; /* Array of pointers to arrays
                             of pointers to unions        */

This example shows how the placement of parentheses changes the meaning of the declaration. In this example, var is a five-element array of pointers to five-element arrays of pointers to unions. For examples of how to use typedef to avoid complex declarations, see »Typedef Declarations«.


  3.7  Initialization

An "initializer" is a value or a sequence of values to be assigned to the variable being declared. You can set a variable to an initial value by applying an initializer to the declarator in the variable declaration. The value or values of the initializer are assigned to the variable.

The following sections describe how to initialize variables of scalar, aggregate, and string types. "Scalar types" include all the arithmetic types, plus pointers. "Aggregate types" include arrays, structures, and unions.


  Scalar Initialization

When initializing scalar types, the value of the assignment-expression is assigned to the variable. The conversion rules for assignment apply. (See »Type Conversions« for information on conversion rules.)

Syntax

declaration :
     declaration-specifiers init-declarator-list  (opt)  ;

declaration-specifiers :
     storage-class-specifier declaration-specifiers  (opt)
     type-specifier declaration-specifiers  (opt)
     type-qualifier declaration-specifiers  (opt)

init-declarator-list :
     init-declarator
     init-declarator-list , init-declarator

init-declarator :
     declarator
     declarator = initializer      /* For scalar initialization */

initializer :
     assignment-expression

You can initialize variables of any type, provided that you obey the following rules:

•	Variables declared at the file-scope level can be initialized. If you do not explicitly initialize a variable at the external level, it is initialized to 0 by default.

•	A constant expression can be used to initialize any global variable declared with the static storage-class-specifier. Variables declared to be static are initialized when program execution begins. If you do not explicitly initialize a global static variable, it is initialized to 0 by default, and every member that has pointer type is assigned a null pointer.

•	Variables declared with the auto or register storage-class specifier are initialized each time execution control passes to the block in which they are declared. If you omit an initializer from the declaration of an auto or register variable, the initial value of the variable is undefined. For automatic and register values, the initializer is not restricted to being a constant; it can be any expression involving previously defined values, even function calls.

•	The initial values for external variable declarations and for all static variables, whether external or internal, must be constant expressions. (For more information, see "»Constant Expressions«".) Since the address of any externally declared or static variable is constant, it can be used to initialize an internally declared static pointer variable. However, the address of an auto variable cannot be used as a static initializer because it may be different for each execution of the block. You can use either constant or variable values to initialize auto and register variables.

•	If the declaration of an identifier has block scope, and the identifier has external linkage, the declaration cannot have an initialization.

The following examples illustrate initializations:

int x = 10;

The integer variable x is initialized to the constant expression 10.

register int *px = 0;

The pointer px is initialized to 0, producing a "null" pointer.

const int c = (3 * 1024);

This example uses a constant expression (3 * 1024) to initialize c to a constant value that cannot be modified because of the const keyword.

int *b = &x;

This statement initializes the pointer b with the address of another variable, x.

int *const a = &z;

The pointer a is initialized with the address of a variable named z. However, since it is specified to be a const, the variable a can only be initialized, never modified. It always points to the same location.

int GLOBAL ;

int function( void )
{
    int LOCAL ;
    static int *lp = &LOCAL;   /* Illegal initialization */
    static int *gp = &GLOBAL;  /* Legal initialization   */
    register int *rp = &LOCAL; /* Legal initialization   */
}

The global variable GLOBAL is declared at the external level, so it has global lifetime. The local variable LOCAL has auto storage class and only has an address during the execution of the function in which it is declared. Therefore, attempting to initialize the static pointer variable lp with the address of LOCAL is not permitted. The static pointer variable gp can be initialized to the address of GLOBAL because that address is always the same. Similarly, *rp can be initialized because rp is a local variable and can have a nonconstant initializer. Each time the block is entered, LOCAL has a new address, which is then assigned to rp.


  Initializing Aggregate Types

An "aggregate" type is a structure, union, or array type. If an aggregate type contains members of aggregate types, the initialization rules apply recursively.

Syntax

initializer :
     { initializer-list }     /* For aggregate initialization */
     { initializer-list , }

initializer-list :
     initializer
     initializer-list , initializer

The initializer-list is a list of initializers separated by commas. Each initializer in the list is either a constant expression or an initializer list. Therefore, initializer lists can be nested. This form is useful for initializing aggregate members of an aggregate type, as shown in the examples in this section. However, if the initializer for an automatic identifier is a single expression, it need not be a constant expression; it merely needs to have appropriate type for assignment to the identifier.

For each initializer list, the values of the constant expressions are assigned, in order, to the corresponding members of the aggregate variable.

If initializer-list has fewer values than an aggregate type, the remaining members or elements of the aggregate type are initialized to 0 for external and static variables. The initial value of an automatic identifier not explicitly initialized is undefined. If initializer-list has more values than an aggregate type, an error results. These rules apply to each embedded initializer list, as well as to the aggregate as a whole.

A structure's initializer is either an expression of the same type, or a list of initializers for its members enclosed in curly braces ({ }). Unnamed bit-field members are not initialized.

When a union is initialized, initializer-list must be a single constant expression. The value of the constant expression is assigned to the first member of the union.

If an array has unknown size, the number of initializers determines the size of the array, and its type becomes complete. There is no way to specify repetition of an initializer in C, or to initialize an element in the middle of an array without providing all preceding values as well. If you need this operation in your program, write the routine in assembly language.

Note that the number of initializers can set the size of the array:

int x[ ] = { 0, 1, 2 }

If you specify the size and give the wrong number of initializers, however, the compiler generates an error.

Microsoft Specific

The maximum size for an array is defined by size_t. ♦

16-Bit Specific

On 16-bit computers, size_t is an unsigned int with the range 0x0000 to 0xFFFF hexadecimal. Huge arrays can exceed this limit if they contain more than 65,535 elements or if the size of the element multiplied by the number of elements exceeds 65K. Arithmetic operations on huge arrays should therefore cast size_t and the results of arithmetic operations to unsigned long. ♦

32-Bit Specific

On 32-bit computers, size_t is an unsigned int with the range 0x00000000 to 0x7CFFFFFF. ♦

This example shows initializers for an array.

int P[4][3] =
{
    { 1, 1, 1 },
    { 2, 2, 2 },
    { 3, 3, 3,},
    { 4, 4, 4,},
};

This statement declares P as a four-by-three array and initializes the elements of its first row to 1, the elements of its second row to 2, and so on through the fourth row. Note that the initializer list for the third and fourth rows contains commas after the last constant expression. The last initializer list ({4, 4, 4,},) is also followed by a comma. These extra commas are permitted but are not required; only commas that separate constant expressions from one another, and those that separate one initializer list from another, are required.

If there is no embedded initializer list for an aggregate member, values are simply assigned, in order, to each member of the subaggregate. Therefore, the initialization in the previous example is equivalent to the following:

int P[4][3] =
{
   1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4
};

Braces can also appear around individual initializers in the list and would help to clarify the example above.

When you initialize an aggregate variable, you must be careful to use braces and initializer lists properly. The following example illustrates the compiler's interpretation of braces in more detail:

typedef struct
{
    int n1, n2, n3;
} triplet;

triplet nlist[2][3] =
{
    { {  1, 2, 3 }, {  4, 5, 6 }, {  7, 8, 9 } },  /* Row 1 */
    { { 10,11,12 }, { 13,14,15 }, { 16,17,18 } }   /* Row 2 */
};

In this example, nlist is declared as a 2-by-3 array of structures, each structure having three members. Row 1 of the initialization assigns values to the first row of nlist, as follows:

1.	The first left brace on row 1 signals the compiler that initialization of the first aggregate member of nlist (that is, nlist[0]) is beginning.

2.	The second left brace indicates that initialization of the first aggregate member of nlist[0] (that is, the structure at nlist[0][0]) is beginning.

3.	The first right brace ends initialization of the structure nlist[0][0]; the next left brace starts initialization of nlist[0][1].

4.	The process continues until the end of the line, where the closing right brace ends initialization of nlist[0].

Row 2 assigns values to the second row of nlist in a similar way. Note that the outer sets of braces enclosing the initializers on rows 1 and 2 are required. The following construction, which omits the outer braces, would cause an error:

triplet nlist[2][3] =  /* THIS CAUSES AN ERROR */
{
     {  1, 2, 3 },{  4, 5, 6 },{  7, 8, 9 },   /* Line 1 */
     { 10,11,12 },{ 13,14,15 },{ 16,17,18 }    /* Line 2 */
};

In this construction, the first left brace on line 1 starts the initialization of nlist[0], which is an array of three structures. The values 1, 2, and 3 are assigned to the three members of the first structure. When the next right brace is encountered (after the value 3), initialization of nlist[0] is complete, and the two remaining structures in the three-structure array are automatically initialized to 0. Similarly, { 4,5,6 } initializes the first structure in the second row of nlist. The remaining two structures of nlist[1] are set to 0. When the compiler encounters the next initializer list ( { 7,8,9 } ), it tries to initialize nlist[2]. Since nlist has only two rows, this attempt causes an error.

In this next example, the three int members of x are initialized to 1, 2, and 3, respectively.

struct list
{
    int i, j, k;
    float m[2][3];
} x = {
        1,
        2,
        3,
       {4.0, 4.0, 4.0}
      };

In the list structure above, the three elements in the first row of m are initialized to 4.0; the elements of the remaining row of m are initialized to 0.0 by default.

union
{
    char x[2][3];
    int i, j, k;
} y = { {
            {'1'},
            {'4'}
        }
      };

The union variable y, in this example, is initialized. The first element of the union is an array, so the initializer is an aggregate initializer. The initializer list {'1'} assigns values to the first row of the array. Since only one value appears in the list, the element in the first column is initialized to the character 1, and the remaining two elements in the row are initialized to the value 0 by default. Similarly, the first element of the second row of x is initialized to the character 4, and the remaining two elements in the row are initialized to the value 0.


  Initializing Strings

You can initialize an array of characters (or wide characters) with a string literal (or wide string literal). For example:

char code[ ] = "abc";

initializes code as a four-element array of characters. The fourth element is the null character, which terminates all string literals.

An identifier list can only be as long as the number of identifiers to be initialized. If you specify an array size that is shorter than the string, the extra characters are ignored. For example, the following declaration initializes code as a three-element character array:

char code[3] = "abcd";

Only the first three characters of the initializer are assigned to code. The character d and the string-terminating null character are discarded. Note that this creates an unterminated string (that is, one without a 0 value to mark its end) and generates a diagnostic message indicating this condition.

The declaration

char s[] = "abc", t[3] = "abc";

is identical to

char s[]  = {'a', 'b', 'c', '\0'},
     t[3] = {'a', 'b', 'c' };

If the string is shorter than the specified array size, the remaining elements of the array are initialized to 0.

Microsoft-Specific

In Microsoft C, string literals can be up to 2048 bytes in length. ♦


  3.8  Storage of Basic Types

Table 3.2 summarizes the storage associated with each basic type.

Table 3.2    Sizes of Fundamental Types

Type	16-Bit Targets	32-Bit Targets
char, unsigned char, signed char	1 byte	1 byte
short, unsigned short	2 bytes	2 bytes
int, unsigned int	2 bytes	4 bytes
long, unsigned long	4 bytes	4 bytes
float	4 bytes	4 bytes
double	8 bytes	8 bytes
long double	10 bytes	8 bytes
The C data types fall into general categories. The "integral types" include char, int, short, long, signed, unsigned, and enum. The "floating types" include float, double, and long double. The "arithmetic types" include all floating and integral types.


  Type char

The char type is used to store the integer value of a member of the representable character set. That integer value is the ASCII code corresponding to the specified character.

Microsoft Specific

Character values of type unsigned char have a range from 0 to 0xFF hexadecimal. A signed char has range 0x80 to 0x7F. These ranges translate to 0 to 255 decimal, and −128 to +127 decimal, respectively. The /J command-line option changes the default from signed to unsigned. ♦


  Type int

The size of a signed or unsigned int item is the standard size of an integer on a particular machine. For example, on a 16-bit computer, the int type is usually 16 bits, or 2 bytes. On a 32-bit machine, the int type is usually 32 bits, or 4 bytes. Thus, the int type is equivalent to either the short int or the long int type, and the unsigned int type is equivalent to either the unsigned short or the unsigned long type, depending on the target environment. The int types all represent signed values unless specified otherwise.

The type specifiers int and unsigned int (or simply unsigned) define certain features of the C language (for instance, the enum type). In these cases, the definitions of int and unsigned int for a particular implementation determine the actual storage.

Microsoft Specific

Signed integers are represented in two's-complement form. The most-significant bit holds the sign: 1 for negative, 0 for positive and zero. The range of values is given in Tables 1.4 and 1.5, which are taken from the LIMITS.H header file. ♦

Note  The int and unsigned int type specifiers are widely used in C programs because they allow a particular machine to handle integer values in the most efficient way for that machine. However, since the sizes of the int and unsigned int types vary, programs that depend on a specific int size may not be portable to other machines. To make programs more portable, you can use expressions with the sizeof operator (as discussed in »The sizeof Operator«") instead of hard-coded data sizes.


  Type float

Floating-point numbers use the IEEE (Institute of Electrical and Electronics Engineers) format. Single-precision values with float type have 4 bytes, consisting of a sign bit, an 8-bit excess-127 binary exponent, and a 23-bit mantissa. The mantissa represents a number between 1.0 and 2.0. Since the high-order bit of the mantissa is always 1, it is not stored in the number. This representation gives a range of approximately 3.4E−38 to 3.4E+38 for type float.

Microsoft Specific

The float type contains 32 bits: 1 for the sign, 8 for the exponent, and 23 for the mantissa. Its range is +/−3.4E38 with at least 7 digits of precision. ♦


  Type double

Double precision values with double type have 8 bytes. The format is similar to the float format except that it has an 11-bit excess-1023 exponent and a 52-bit mantissa, plus the implied high-order 1 bit. This format gives a range of approximately 1.7E−308 to 1.7E+308 for type double.

Microsoft Specific

The double type contains 64 bits: 1 for sign, 11 for the exponent, and 52 for the mantissa. Its range is +/−1.7E308 with at least 15 digits of precision. ♦


  Type long double

The range of values for a variable is bounded by the minimum and maximum values that can be represented internally in a given number of bits. However, because of C's conversion rules (discussed in detail in »Type Conversions«) you cannot always use the maximum or minimum value for a constant of a particular type in an expression.

For example, the constant expression -32768 consists of the arithmetic negation operator (−) applied to the constant value 32,768. Since 32,768 is too large to represent as a short int, it is given the long type. Consequently, the constant expression -32768 has long type. You can only represent −32,768 as a short int by type-casting it to the short type. No information is lost in the type cast, since −32,768 can be represented internally in 2 bytes.

The value 65,000 in decimal notation is considered a signed constant. It is given the long type because 65,000 does not fit into a short. A value such as 65,000 can only be represented as an unsigned short by type-casting the value to unsigned short type, by giving the value in octal or hexadecimal notation, or by specifying it as 65000U. You can cast this long value to the unsigned short type without loss of information, since 65,000 can fit in 2 bytes when it is stored as an unsigned number.

Microsoft Specific

The long double contains 80 bits: 1 for sign, 15 for exponent, and 64 for mantissa. Its range is +/−1.2E4932 with at least 19 digits of precision. ♦

32-Bit Specific

The 32-bit compiler maps long double to type double. ♦


  3.9  Incomplete Types

An incomplete type is a type that describes an identifier but lacks information needed to determine the size of the identifier. An "incomplete type" can be:

•	A structure type whose members you have not yet specified.

•	A union type whose members you have not yet specified.

•	An array type whose dimension you have not yet specified.

The void type is an incomplete type that cannot be completed. To complete an incomplete type, specify the missing information. The following examples show how to create and complete the incomplete types.

•	To create an incomplete structure type, declare a structure type without specifying its members. In this example, the ps pointer points to an incomplete structure type called student.

struct student *ps;

•	To complete an incomplete structure type, declare the same structure type later in the same scope with its members specified, as in

struct student
{
    int num;
}                   /* student structure now completed */

•	To create an incomplete array type, declare an array type without specifying its repetition count. For example:

char a[];  /* a has incomplete type */

•	To complete an incomplete array type, declare the same name later in the same scope with its repetition count specified, as in

char a[25]; /* a now has complete type */


  3.10  Typedef Declarations

A typedef declaration is a declaration with typedef as the storage class. The declarator becomes a new type. You can use typedef declarations to construct shorter or more meaningful names for types already defined by C or for types that you have declared. Typedef names allow you to encapsulate implementation details that may change.

A typedef declaration is interpreted in the same way as a variable or function declaration, but the identifier, instead of assuming the type specified by the declaration, becomes a synonym for the type.

Syntax

declaration :
     declaration-specifiers init-declarator-list  (opt)  ;

declaration-specifiers :
     storage-class-specifier declaration-specifiers  (opt)
     type-specifier declaration-specifiers  (opt)
     type-qualifier declaration-specifiers  (opt

) storage-class-specifier :
     typedef

type-specifier :
     void
     char
     short
     int
     long
     float
     double
     signed
     unsigned
     struct-or-union-specifier
     enum-specifier
     typedef-name

typedef-name :
     identifier

Note that a typedef declaration does not create types. It creates synonyms for existing types, or names for types that could be specified in other ways. When a typedef name is used as a type specifier, it can be combined with certain type specifiers, but not others. Acceptable modifiers include const and volatile, and the special keywords described in »Special Keywords in Declarations«.)

Typedef names share the name space with ordinary identifiers (see »Name Spaces« for more information). Therefore, a program can have a typedef name and a local-scope identifier by the same name. For example:

typedef char FlagType;

int main()
{
}

int myproc( int )
{
    int FlagType;
}

When declaring a local-scope identifier by the same name as a typedef, or when declaring a member of a structure or union in the same scope or in an inner scope, the type specifier must be specified. This example illustrates this constraint:

typedef char FlagType;
const FlagType x;

To reuse the FlagType name for an identifier, a structure member, or a union member, the type must be provided:

const int FlagType;  /* Type specifier required */

It is not sufficient to say

const FlagType;      /* Incomplete specification */

because the FlagType is taken to be part of the type, not an identifier that is being redeclared. This declaration is taken to be an illegal declaration like

int;  /* Illegal declaration */

You can declare any type with typedef, including pointer, function, and array types. You can declare a typedef name for a pointer to a structure or union type before you define the structure or union type, as long as the definition has the same visibility as the declaration.

Typedef names can be used to improve code readability. All three of the following declarations of signal specify exactly the same type, the first without making use of any typedef names.

typedef void fv( int ), (*pfv)( int );  /* typedef declarations */

void ( *signal( int, void (*) (int)) ) ( int );
fv *signal( int, fv * );   /* Uses typedef type */
pfv signal( int, pfv );    /* Uses typedef type */

The following examples illustrate typedef declarations:

typedef int WHOLE; /* Declares WHOLE to be a synonym for int */

Note that WHOLE could now be used in a variable declaration such as WHOLE i; or const WHOLE i;. However, the declaration long WHOLE i; would be illegal.

typedef struct club
{
    char name[30];
    int size, year;
} GROUP;

This statement declares GROUP as a structure type with three members. Since a structure tag, club, is also specified, either the typedef name (GROUP) or the structure tag can be used in declarations. You must use the struct keyword with the tag, and you cannot use the struct keyword with the typedef name.

typedef GROUP *PG; /* Uses the previous typedef name
                      to declare a pointer            */

The type PG is declared as a pointer to the GROUP type, which in turn is defined as a structure type.

typedef void DRAWF( int, int );

This example provides the type DRAWF for a function returning no value and taking two int arguments. This means, for example, that the declaration

DRAWF box;

is equivalent to the declaration

void box( int, int ); ♦


3.11  Extended Storage Class Attributes (Microsoft Specific)
  3.11  Extended Storage-Class Attributes (Microsoft Specific)

32-Bit Specific

Extended attribute syntax simplifies and standardizes the Microsoft-specific extensions to the C language. The storage-class attributes that use extended attribute syntax include thread, naked, dllimport, and dllexport.

The extended attribute syntax for specifying storage-class information uses the __declspec keyword, which specifies that an instance of a given type is to be stored with a Microsoft-specific storage-class attribute (thread, naked, dllimport, or dllexport). Some examples of other storage-class modifiers include the static and extern keywords. However, these keywords are part of the ANSI C standard and as such are not covered by extended attribute syntax.

Syntax

storage-class-specifier :
     __declspec ( extended-decl-modifier-seq)   /* Microsoft Specific */

extended-decl-modifier-seq :
     extended-decl-modifier  (opt )
     extended-decl-modifier-seq extended-decl-modifier

extended-decl-modifier :
     thread
     naked
     dllimport
     dllexport

White space separates the declaration modifiers. Note that extended-decl-modifier-seq can be empty; in this case, __declspec has no effect.

The thread, naked, dllimport, and dllexport storage-class attributes are a property only of the declaration of the data or function to which they are applied. Unlike the __near and __far keywords, which actually affect the type of function (in this case, 2- and 4-byte addresses), these storage-class attributes do not redefine the type attributes of the function itself. The thread attribute affects data only. The naked attribute affects functions only. The dllimport and dllexport attributes affect functions and data. ♦


  DLL Import and Export (Microsoft Specific)

32-Bit Specific

The dllimport and dllexport storage-class modifiers are Microsoft-specific extensions to the C language. These modifiers define the DLL's interface to its client (the executable file or another DLL). For specific information about using these modifiers, see »DLL Import and Export Functions«. ♦


  Naked (Microsoft Specific)

32-Bit Specific

The naked storage-class attribute is a Microsoft-specific extension to the C language. The compiler generates code without prolog and epilog code for functions declared with the naked storage-class attribute. Naked functions are useful when you need to write your own prolog/epilog code sequences using inline assembler code. Naked functions are useful for writing virtual device drivers.

For specific information about using the naked attribute, see »Naked Functions«. ♦


  Thread Local Storage (Microsoft Specific)

32-Bit Specific

Thread Local Storage (TLS) is the mechanism by which each thread in a given multithreaded process allocates storage for thread-specific data. In standard multithreaded programs, data is shared among all threads of a given process, whereas thread local storage is the mechanism for allocating per-thread data. For a complete discussion of threads, see the API Programmer's Reference in the Microsoft Win32 (™)  Software Development Kit for Windows NT (™) .

The Microsoft C language includes the extended storage-class attribute, thread, which is used with the __declspec keyword to declare a thread local variable. For example, the following code declares an integer thread local variable and initializes it with a value:

__declspec( thread ) int tls_i = 1;

These guidelines must be observed when you are declaring statically bound thread local variables:

1.	You can apply the thread attribute only to data declarations and definitions. It cannot be used on function declarations or definitions. For example, the following code generates a compiler error:

#define Thread	__declspec( thread )
Thread void func();	/* Error */

2.	You can specify the thread attribute only on data items with static storage duration. This includes global data (both static and extern) and local static data. You cannot declare automatic data with the thread attribute. For example, the following code generates compiler errors:

#define Thread	__declspec( thread )
void func1()
{
    Thread int tls_i;            /* Error */
}

int func2( Thread int tls_i )    /* Error */
{
return tls_i;
}

3.	You must use the thread attribute for the declaration and the definition of thread local data, regardless of whether the declaration and definition occur in the same file or separate files. For example, the following code generates an error:

#define Thread	__declspec( thread )
extern int tls_i;     /* This generates an error, because the   */
int Thread tls_i;     /* declaration and the definition differ. */

4.	You cannot use the thread attribute as a type modifier. For example, the following code generates a compiler error:

char *ch __declspec( thread );	/* Error */

5.	The address of a thread local variable is not considered constant, and any expression involving such an address is not considered a constant expression. This means that you cannot use the address of a thread local variable as an initializer for a pointer. For example, the compiler flags the following code as an error:

#define Thread	__declspec( thread )
Thread int tls_i;
int *p = &tls_i;	/* Error */

6.	C permits initialization of a variable with an expression involving a reference to itself, but only for objects of nonstatic extent. For example:

#define Thread	__declspec( thread )
Thread int tls_i = tls_i;             /* Error */
int j = j;                            /* Error */
Thread int tls_i = sizeof( tls_i )    /* Okay  */

Note that a sizeof expression that includes the variable being initialized does not constitute a reference to itself and is allowed.

For more information about using the thread attribute, see Chapter 5, "Writing Multithread Applications," of Programming Techniques. ♦


Chapter 4:  Expressions and Assignments
  CHAPTER 4  Expressions and Assignments

This chapter describes how to form expressions and to assign values in the C language. Constants, identifiers, strings, and function calls are all operands that are manipulated in expressions. The C language has all the usual language operators. This chapter covers those operators plus operators such as the conditional operator and base operator that are unique to C or Microsoft C. The topics discussed in this chapter include:

•	»L-value and l-value expressions«

•	»Constant expressions«

•	»Side effects«

•	»Sequence points«

•	»Expression evaluation«

•	»Operators« and »operator precedence«

•	»Type conversions«

•	»Type casts«


  4.1  Operands and Expressions

An "operand" is an entity on which an operator acts. An "expression" is a sequence of operators and operands that performs any combination of these actions:

•	Computes a value

•	Designates an object or function

•	Generates side effects

Operands in C include constants, identifiers, strings, function calls, subscript expressions, member-selection expressions, and complex expressions formed by combining operands with operators or by enclosing operands in parentheses. These operands, often called "primary expressions," are discussed in the next section.


  Primary Expressions

The operands in expressions are called "primary expressions."

Syntax

primary-expression :
identifier
constant
string-literal
( expression )

expression :
assignment-expression
expression , assignment-expression


  Identifiers

Identifiers can have integral, float, enum, struct, union, array, pointer, or function type. An identifier is a primary expression provided it has been declared as designating an object (in which case it is an l-value) or as a function (in which case it is a function designator). See the next section, »L_Value and R-Value Expressions«, for a definition of l-value.

The pointer value represented by an array identifier is not a variable, so an array identifier cannot form the left-hand operand of an assignment operation and therefore is not a modifiable l-value.

An identifier declared as a function represents a pointer whose value is the address of the function. The pointer addresses a function returning a value of a specified type. Thus, function identifiers also cannot be l-values in assignment operations. For more information, see »Identifiers«.


  Constants

A constant operand has the value and type of the constant value it represents. A character constant has int type. An integer constant has int, long, unsigned int, or unsigned long type, depending on the integer's size and on the way the value is specified. See »Constants« on page ??? for more information.


  String Literals

A "string literal" is a character, wide character, or sequence of adjacent characters enclosed in double quotation marks. Since they are not variables, neither string literals nor any of their elements can be the left-hand operand in an assignment operation. The type of a string literal is an array of char (or an array of wchar_t for wide-string literals). Arrays in expressions are converted to pointers. See »String Literals« for more information about strings.


  Expressions in Parentheses

You can enclose any operand in parentheses without changing the type or value of the enclosed expression. For example, in the expression

( 10 + 5 ) / 5

the parentheses around 10 + 5 mean that the value of 10 + 5 is evaluated first and it becomes the left operand of the division (/) operator. The result of ( 10 + 5 ) / 5 is 3. Without the parentheses, 10 + 5 / 5 would evaluate to 11.

Although parentheses affect the way operands are grouped in an expression, they cannot guarantee a particular order of evaluation in all cases. For example, neither the parentheses nor the left-to-right grouping of the following expression guarantees what the value of i will be in either of the subexpressions:

( i++ +1 ) * ( 2 + i )

The compiler is free to evaluate the two sides of the multiplication in any order. If the initial value of i is zero, the whole expression could be evaluated as either of these two statements:

( 0 + 1 + 1 ) * ( 2 + 1 )
( 0 + 1 + 1 ) * ( 2 + 0 )

Exceptions resulting from side effects are discussed in »Side Effects«.


  L-Value and R-Value Expressions

Expressions that refer to memory locations are called "l-value" expressions. An l-value represents a storage region's "locator" value, or a "left" value, implying that it can appear on the left of the equal sign (=). L-values are often identifiers.

Expressions referring to modifiable locations are called "modifiable l-values." A modifiable l-value cannot have an array type, an incomplete type, or a type with the const attribute. For structures and unions to be modifiable l-values, they must not have any members with the const attribute. The name of the identifier denotes a storage location, while the value of the variable is the value stored at that location.

An identifier is a modifiable l-value if it refers to a memory location and if its type is arithmetic, structure, union, or pointer. For example, if ptr is a pointer to a storage region, then *ptr is a modifiable l-value that designates the storage region to which ptr points.

Any of the following C expressions can be l-value expressions:

•	An identifier of integral, floating, pointer, structure, or union type

•	A subscript ([ ]) expression that does not evaluate to an array

•	A member-selection expression (−> or .)

•	A unary-indirection (*) expression that does not refer to an array

•	An l-value expression in parentheses

•	A const object (a nonmodifiable l-value)

The term "r-value" is sometimes used to describe the value of an expression and to distinguish it from an l-value. All l-values are r-values but not all r-values are l-values.

Microsoft Specific

Microsoft C includes an extension to the ANSI C standard that allows casts of l-values to be used as l-values, as long as the size of the object is not lengthened through the cast. (See »Type-Cast Conversions« for more information.) The following example illustrates this feature:

char *p ;
short  i;
long l;

(long *) p = &l ;       /* Legal cast   */
(long) i = l ;          /* Illegal cast */

The default for Microsoft C is that the Microsoft extensions are enabled. Use the /Za command-line option to disable these extensions. ♦


  Constant Expressions

A constant expression is evaluated at compile time, not run time, and can be used in any place that a constant can be used. The constant expression must evaluate to a constant that is in the range of representable values for that type. The operands of a constant expression can be integer constants, character constants, floating-point constants, enumeration constants, type casts, sizeof expressions, and other constant expressions.

Syntax

constant-expression :
conditional-expression

conditional-expression :
logical-OR-expression
logical-OR-expression ? expression : conditional-expression

expression :
assignment-expression
expression , assignment-expression

assignment-expression :
conditional-expression
unary-expression assignment-operator assignment-expression

assignment-operator : one of
=  *=  /=  %=  +=  −=  <<=  >>=  &=  ^=  |=

The nonterminals for struct declarator, enumerator, direct declarator, direct-abstract declarator, and labeled statement contain the constant-expression nonterminal.

An integral constant expression must be used to specify the size of a bit-field member of a structure, the value of an enumeration constant, the size of an array, or the value of a case constant.

Constant expressions used in preprocessor directives are subject to additional restrictions. Consequently, they are known as "restricted constant expressions." A restricted constant expression cannot contain sizeof expressions, enumeration constants, type casts to any type, or floating-type constants. It can, however, contain the special constant expression defined(identifier). (See Chapter 1 of the Preprocessor Reference for more information.)


  Expression Evaluation

Expressions involving assignment, unary increment, unary decrement, or calling a function may have consequences incidental to their evaluation (side effects). When a "sequence point" is reached, everything preceding the sequence point, including any side effects, is guaranteed to have been evaluated before evaluation begins on anything following the sequence point.

"Side effects" are changes caused by the evaluation of an expression. Side effects occur whenever the value of a variable is changed by an expression evaluation. All assignment operations have side effects. Function calls can also have side effects if they change the value of an externally visible item, either by direct assignment or by indirect assignment through a pointer.


  Side Effects

The order of evaluation of expressions is defined by the specific implementation, except when the language guarantees a particular order of evaluation (as outlined in »Precedence and Order of Evaluation«). For example, side effects occur in the following function calls:

add( i + 1, i = j + 2 );
myproc( getc(), getc() );

The arguments of a function call can be evaluated in any order. The expression i + 1 may be evaluated before i = j + 2, or i = j + 2 may be evaluated before i + 1. The result is different in each case. Likewise, it is not possible to guarantee what characters are actually passed to the myproc. Since unary increment and decrement operations involve assignments, such operations can cause side effects, as shown in the following example:

x[i] = i++;

In this example, the value of x that is modified is unpredictable. The value of the subscript could be either the new or the old value of i. The result can vary under different compilers or different optimization levels.

Since C does not define the order of evaluation of side effects, both evaluation methods discussed above are correct and either may be implemented. To make sure that your code is portable and clear, avoid statements that depend on a particular order of evaluation for side effects.


  Sequence Points

Between consecutive "sequence points" an object's value can be modified only once by an expression. The C language defines the following sequence points:

•	Left operand of the logical-AND operator (&&). The left operand of the logical-AND operator is completely evaluated and all side effects complete before continuing. If the left operand evaluates to false (0), the other operand is not evaluated.

•	Left operand of the logical-OR operator (||). The left operand of the logical-OR operator is completely evaluated and all side effects complete before continuing. If the left operand evaluates to true (nonzero), the other operand is not evaluated.

•	Left operand of the comma operator. The left operand of the comma operator is completely evaluated and all side effects complete before continuing. Both operands of the comma operator are always evaluated. Note that the comma operator in a function call does not guarantee an order of evaluation.

•	Function-call operator. All arguments to a function are evaluated and all side effects complete prior to entry to the function. No order of evaluation among the arguments is specified.

•	First operand of the conditional operator. The first operand of the conditional operator is completely evaluated and all side effects complete before continuing.

•	The end of a full initialization expression (that is, an expression that is not part of another expression such as the end of an initialization in a declaration statement).

•	The expression in an expression statement. Expression statements consist of an optional expression followed by a semicolon (;). The expression is evaluated for its side effects and there is a sequence point following this evaluation.

•	The controlling expression in a selection (if or switch) statement. The expression is completely evaluated and all side effects complete before the code dependent on the selection is executed.

•	The controlling expression of a while or do statement. The expression is completely evaluated and all side effects complete before any statements in the next iteration of the while or do loop are executed.

•	Each of the three expressions of a for statement. The expressions are completely evaluated and all side effects complete before any statements in the next iteration of the for loop are executed.

•	The expression in a return statement. The expression is completely evaluated and all side effects complete before control returns to the calling function.


  4.2  Operators

There are three types of operators. A unary expression consists of either a unary operator prepended to an operand, or the sizeof keyword followed by an expression. The expression can be either the name of a variable or a cast expression. If the expression is a cast expression, it must be enclosed in parentheses. A binary expression consists of two operands joined by a binary operator. A ternary expression consists of three operands joined by the conditional-expression operator. C includes the following unary operators:

Symbol	Name
−  ~  !	Negation and complement operators
*  &	Indirection and address-of operators
sizeof	Size operator
+	Unary plus operator
++  −−	Unary increment and decrement operators
Binary operators associate from left to right. C provides the following binary operators:

Symbol	Name
*  /  %	Multiplicative operators
+  −	Additive operators
<<    >>	Shift operators
<   >   <=   >=   ==   !=	Relational operators
&   |  ^	Bitwise operators
&&   ||	Logical operators
,	Sequential-evaluation operator
:>	Base operator
The conditional-expression operator has lower precedence than binary expressions and differs from them in being right associative.

Expressions with operators also include assignment expressions, which use unary or binary assignment operators. The unary assignment operators are the increment (++) and decrement (−−) operators; the binary assignment operators are the simple-assignment operator (=) and the compound-assignment operators. Each compound-assignment operator is a combination of another binary operator with the simple-assignment operator.


  Precedence and Order of Evaluation

The precedence and associativity of C operators affect the grouping and evaluation of operands in expressions. An operator's precedence is meaningful only if other operators with higher or lower precedence are present. Expressions with higher-precedence operators are evaluated first. Precedence can also be described by the word "binding." Operators with a higher precedence are said to have tighter binding.

Table 4.1 summarizes the precedence and associativity (the order in which the operands are evaluated) of C operators, listing them in order of precedence from highest to lowest. Where several operators appear together, they have equal precedence and are evaluated according to their associativity. The operators in Table 4.1 are described in the sections beginning with »Postfix Operators«. The rest of this section gives general information about precedence and associativity.

Table 4.1    Precedence and Associativity of C Operators

Symbol (1)	Type of Operation	Associativity
[ ]  ( )  .  −> postfix ++ and postfix − −  :>  (2)	Expression	Left to right
Prefix ++ and prefix − −   sizeof  &   *   +  −  ~  !	Unary	Right to left
typecasts	Unary	Right to left
*  /  %	Multiplicative	Left to right
+  −	Additive	Left to right
<<  >>	Bitwise shift	Left to right
<  >  <=  >=	Relational	Left to right
==  !=	Equality	Left to right
&	Bitwise-AND	Left to right
^	Bitwise-exclusive-OR	Left to right
|	Bitwise-inclusive-OR	Left to right
&&	Logical-AND	Left to right
||	Logical-OR	Left to right
? :	Conditional-expression	Right to left
=  *=  /=  %=  +=  −=  <<=  >>= &=  ^=  |=	Simple and compound assignment (3)	Right to left
,	Sequential evaluation	Left to right
1 Operators are listed in descending order of precedence. If several operators appear on the same line or in a group, they have equal precedence. 2 The base operator (:>) is valid only for 16-bit targets. 3 All simple and compound-assignment operators have equal precedence.
An expression can contain several operators with equal precedence. When several such operators appear at the same level in an expression, evaluation proceeds according to the associativity of the operator, either from right to left or from left to right. The direction of evaluation does not affect the results of expressions that include more than one multiplication (*), addition (+), or binary-bitwise (& | ^) operator at the same level. Order of operations is not defined by the language. The compiler is free to evaluate such expressions in any order, if the compiler can guarantee a consistent result.

Only the sequential-evaluation (,), logical-AND (&&), logical-OR (||), conditional-expression (? :), and function-call operators constitute sequence points and therefore guarantee a particular order of evaluation for their operands. The function-call operator is the set of parentheses following the function identifier. The sequential-evaluation operator (,) is guaranteed to evaluate its operands from left to right. (Note that the comma operator in a function call is not the same as the sequential-evaluation operator and does not provide any such guarantee.) For more information, see »Sequence Points«.

Logical operators also guarantee evaluation of their operands from left to right. However, they evaluate the smallest number of operands needed to determine the result of the expression. This is called "short-circuit" evaluation. Thus, some operands of the expression may not be evaluated. For example, in the expression

x && y++

the second operand, y++, is evaluated only if x is true (nonzero). Thus, y is not incremented if x is false (0).

The following list shows how the compiler automatically binds several sample expressions:

Expression	Automatic Binding
a & b || c	(a & b) || c
a = b || c	a = (b || c)
q && r || s--	(q && r) || s−−
In the first expression, the bitwise-AND operator (&) has higher precedence than the logical-OR operator (||), so a & b forms the first operand of the logical-OR operation.

In the second expression, the logical-OR operator (||) has higher precedence than the simple-assignment operator (=), so b || c is grouped as the right-hand operand in the assignment. Note that the value assigned to a is either 0 or 1.

The third expression shows a correctly formed expression that may produce an unexpected result. The logical-AND operator (&&) has higher precedence than the logical-OR operator (||), so q && r is grouped as an operand. Since the logical operators guarantee evaluation of operands from left to right, q && r is evaluated before s−−. However, if q && r evaluates to a nonzero value, s−− is not evaluated, and s is not decremented. If not decrementing s would cause a problem in your program, s−− should appear as the first operand of the expression, or s should be decremented in a separate operation.

The following expression is illegal and produces a diagnostic message at compile time:

Illegal Expression	Default Grouping
p == 0 ? p += 1: p += 2	( p == 0 ? p += 1 : p ) += 2
In this expression, the equality operator (==) has the highest precedence, so p == 0 is grouped as an operand. The conditional-expression operator (? :) has the next-highest precedence. Its first operand is p == 0, and its second operand is p += 1. However, the last operand of the conditional-expression operator is considered to be p rather than p += 2, since this occurrence of p binds more closely to the conditional-expression operator than it does to the compound-assignment operator. A syntax error occurs because += 2 does not have a left-hand operand. You should use parentheses to prevent errors of this kind and produce more readable code. For example, you could use parentheses as shown below to correct and clarify the preceding example:

( p == 0 ) ? ( p += 1 ) : ( p += 2 )


  Usual Arithmetic Conversions

Most C operators perform type conversions to bring the operands of an expression to a common type or to extend short values to the integer size used in machine operations. The conversions performed by C operators depend on the specific operator and the type of the operand or operands. However, many operators perform similar conversions on operands of integral and floating types. These conversions are known as "arithmetic conversions." Conversion of an operand value to a compatible type causes no change to its value.

The arithmetic conversions summarized below are called "usual arithmetic conversions." These steps are applied only for binary operators that expect arithmetic type and only if the two operands do not have the same type. The purpose is to yield a common type which is also the type of the result. To determine which conversions actually take place, the compiler applies the following algorithm to binary operations in the expression. The steps below are not a precedence order.

1.	If either operand is of type long double, the other operand is converted to type long double.

2.	If the above condition is not met and either operand is of type double, the other operand is converted to type double.

3.	If the above two conditions are not met and either operand is of type float, the other operand is converted to type float.

4.	If the above three conditions are not met (none of the operands are of floating types), then integral conversions are performed on the operands as follows:

•	If either operand is of type unsigned long, the other operand is converted to type unsigned long.

•	If the above condition is not met and either operand is of type long and the other of type unsigned int, the operand of type unsigned int is converted to type long (in 16-bit compilations) or both operands are converted to type unsigned long (in 32-bit compilations).

•	If the above two conditions are not met, and either operand is of type long, the other operand is converted to type long.

•	If the above three conditions are not met, and either operand is of type unsigned int, the other operand is converted to type unsigned int.

•	If none of the above conditions are met, both operands are converted to type int.

The following code illustrates these conversion rules:

float   fVal;
double  dVal;
int   iVal;
unsigned long ulVal;

dVal = iVal * ulVal; /* iVal converted to unsigned long
                      * Uses step 4.
                      * Result of multiplication converted to double
                      */
dVal = ulVal + fVal; /* ulVal converted to float
                      * Uses step 3.
                      * Result of addition converted to double
                      */


  Postfix Operators

The postfix operators have the highest precedence (the tightest binding) in expression evaluation.

Syntax

postfix-expression :
primary-expression
postfix-expression [ expression ]
postfix-expression ( argument-expression-list  (opt)  )
postfix-expression . identifier
postfix-expression −> identifier
postfix-expression ++

postfix-expression −−
postfix-expression :> expression   /* Microsoft-specific */

Operators in this precedence level are the array subscripts, function calls, structure and union members, and postfix increment and decrement operators.


  One-Dimensional Arrays

A postfix expression followed by an expression in square brackets ([ ]) is a subscripted representation of an element of an array object. A subscript expression represents the value at the address that is expression positions beyond postfix-expression when expressed as

postfix-expression [ expression ]

Usually, the value represented by postfix-expression is a pointer value, such as an array identifier, and expression is an integral value. However, all that is required syntactically is that one of the expressions be of pointer type and the other be of integral type. Thus the integral value could be in the postfix-expression position and the pointer value could be in the brackets in the expression, or "subscript," position. For example, this code is legal:

int sum, *ptr, a[10];

int main()
{
    ptr = a;
    sum = 4[ptr];
}

Subscript expressions are generally used to refer to array elements, but you can apply a subscript to any pointer. Whatever the order of values, expression must be enclosed in brackets ([ ]).

The subscript expression is evaluated by adding the integral value to the pointer value, then applying the indirection operator (*) to the result. (See »Indirection and Address-of Operators« for a discussion of the indirection operator.) In effect, for a one-dimensional array, the following four expressions are equivalent, assuming that a is a pointer and b is an integer:

a[b]
*(a + b)
*(b + a)
b[a]

According to the conversion rules for the addition operator (given in »Additive Operators«), the integral value is converted to an address offset by multiplying it by the length of the type addressed by the pointer.

For example, suppose the identifier line refers to an array of int values. The following procedure is used to evaluate the subscript expression line[ i ]:

1.	The integer value i is multiplied by the number of bytes defined as the length of an int item. The converted value of i represents i int positions.

2.	This converted value is added to the original pointer value (line) to yield an address that is offset i int positions from line.

3.	The indirection operator is applied to the new address. The result is the value of the array element at that position (intuitively, line [ i ]).

The subscript expression line[0] represents the value of the first element of line, since the offset from the address represented by line is 0. Similarly, an expression such as line[5] refers to the element offset five positions from line, or the sixth element of the array.


  Multidimensional Arrays

A subscript expression can also have multiple subscripts, as follows:

expression1 [expression2] [expression3]...

Subscript expressions associate from left to right. The leftmost subscript expression, expression1[expression2], is evaluated first. The address that results from adding expression1 and expression2 forms a pointer expression; then expression3 is added to this pointer expression to form a new pointer expression, and so on until the last subscript expression has been added. The indirection operator (*) is applied after the last subscripted expression is evaluated, unless the final pointer value addresses an array type (see examples below).

Expressions with multiple subscripts refer to elements of "multidimensional arrays." A multidimensional array is an array whose elements are arrays. For example, the first element of a three-dimensional array is an array with two dimensions.

For the following examples, an array named prop is declared with three elements, each of which is a 4-by-6 array of int values.

int prop[3][4][6];
int i, *ip, (*ipp)[6];

A reference to the prop array looks like this:

i = prop[0][0][1];

The example above shows how to refer to the second individual int element of prop. Arrays are stored by row, so the last subscript varies most quickly; the expression prop[0][0][2] refers to the next (third) element of the array, and so on.

i = prop[2][1][3];

This statement is a more complex reference to an individual element of prop. The expression is evaluated as follows:

1.	The first subscript, 2, is multiplied by the size of a 4-by-6 int array and added to the pointer value prop. The result points to the third 4-by-6 array of prop.

2.	The second subscript, 1, is multiplied by the size of the 6-element int array and added to the address represented by prop[2].

3.	Each element of the 6-element array is an int value, so the final subscript, 3, is multiplied by the size of an int before it is added to prop[2][1]. The resulting pointer addresses the fourth element of the 6-element array.

4.	The indirection operator is applied to the pointer value. The result is the int element at that address.

These next two examples show cases where the indirection operator is not applied.

ip = prop[2][1];

ipp = prop[2];

In the first of these statements, the expression prop[2][1] is a valid reference to the three-dimensional array prop; it refers to a 6-element array (declared above). Since the pointer value addresses an array, the indirection operator is not applied.

Similarly, the result of the expression prop[2] in the second statement ipp = prop[2]; is a pointer value addressing a two-dimensional array.


  Function Calls

A "function call" is an expression that includes the name of the function being called or the value of a function pointer and, optionally, the arguments being passed to the function.

Syntax

postfix-expression :
postfix-expression ( argument-expression-list  (opt)  )

argument-expression-list :
assignment-expression
argument-expression-list , assignment-expression

The postfix-expression must evaluate to a function address (for example, a function identifier or the value of a function pointer), and argument-expression-list is a list of expressions (separated by commas) whose values (the "arguments") are passed to the function. The argument-expression-list argument can be empty.

A function-call expression has the value and type of the function's return value. A function cannot return an object of array type. If the function's return type is void (that is, the function has been declared never to return a value), the function-call expression also has void type. (See »Function Calls« for more information.)


  Structure and Union Members

A "member-selection expression" refers to members of structures and unions. Such an expression has the value and type of the selected member.

Syntax

postfix-expression . identifier
postfix-expression −> identifier

This list describes the two forms of the member-selection expressions:

1.	In the first form, postfix-expression represents a value of struct or union type, and identifier names a member of the specified structure or union. The value of the operation is that of identifier and is an l-value if postfix-expression is an
l-value. See "»L-Value and R-Value Expressions«" for more information.

2.	In the second form, postfix-expression represents a pointer to a structure or union, and identifier names a member of the specified structure or union. The value is that of identifier and is an l-value.

The two forms of member-selection expressions have similar effects.

In fact, an expression involving the member-selection operator (−>) is a shorthand version of an expression using the period (.) if the expression before the period consists of the indirection operator (*) applied to a pointer value. Therefore,

expression −> identifier

is equivalent to

(*expression) . identifier

when expression is a pointer value.

The following examples refer to this structure declaration. For information about the indirection operator (*) used in these examples, see »Indirection and Address-of Operators«.

struct pair
{
    int a;
    int b;
    struct pair *sp;
} item, list[10];

A member-selection expression for the item structure looks like this:

item.sp = &item;

In the example above, the address of the item structure is assigned to the sp member of the structure. This means that item contains a pointer to itself.

(item.sp)−>a = 24;

In this example, the pointer expression item.sp is used with the member-selection operator (−>) to assign a value to the member a.

list[8].b = 12;

This statement shows how to select an individual structure member from an array of structures.


  Postfix Increment and Decrement Operators

Operands of the postfix increment and decrement operators are scalar types that are modifiable l-values.

Syntax

postfix-expression :
postfix-expression ++
postfix-expression −−

The result of the postfix increment or decrement operation is the value of the operand. After the result is obtained, the value of the operand is incremented (or decremented). The following code illustrates the postfix increment operator.

if( var++ > 0 )
    *p++ = *q++;

In this example, the variable var is compared to 0, then incremented. If var was positive before being incremented, the next statement is executed. First, the value of the object pointed to by q is assigned to the object pointed to by p. Then, q and p are incremented.


  Base Operator (Microsoft Specific)

16-Bit Specific

The base operator (:>) is a Microsoft extension added to support based addressing. The base operator combines a memory segment address with an address that can be dereferenced with the indirection (*) operator. It has the form

segvar :> offset

The segvar can be any expression that evaluates to a valid memory segment address. You can use a variable or expression of type __segment, or create your own segments using the __segname operator. The offset can be a pointer with the form

type __based( void ) *

or any 16-bit expression.

You can use the base operator to create a pointer that can address any memory location. See »Based Pointers« for more information. ♦

32-Bit Specific

The base operator is not supported for 32-bit targets. ♦


  Unary Operators

Unary operators appear before their operand and associate from right to left.

Syntax

unary-expression :
postfix-expression
++ unary-expression
−− unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-name )

unary-operator : one of
&   *   +   −   ~   !


  Prefix Increment and Decrement Operators

The unary operators (++ and −−) are called "prefix" increment or decrement operators when the increment or decrement operators appear before the operand. Postfix increment and decrement has higher precedence than prefix increment and decrement operators. The operand must have integral, floating, or pointer type and must be a modifiable l-value expression (an expression without the const attribute). The result is not an l-value.

When the operator appears before its operand, the operand is incremented or decremented and its new value is the result of the expression.

An operand of integral or floating type is incremented or decremented by the integer value 1. The type of the result is the same as the operand type. An operand of pointer type is incremented or decremented by the size of the object it addresses. An incremented pointer points to the next object; a decremented pointer points to the previous object.

This example illustrates the unary decrement operator:

if( line[--i] != '\n' )
    return;

In this example, the variable i is decremented before it is used as a subscript to line.


  Indirection and Address-of Operators

The indirection operator (*) accesses a value indirectly, through a pointer. The operand must be a pointer value. The result of the operation is the value addressed by the operand; that is, the value at the address to which its operand points. The type of the result is the type that the operand addresses.

If the operand points to a function, the result is a function designator. If it points to a storage location, the result is an l-value designating the storage location.

If the pointer value is invalid, the result is undefined. The following list includes some of the most common conditions that invalidate a pointer value.

•	The pointer is a null pointer.

•	The pointer specifies the address of a local item that is not visible at the time of the reference.

•	The pointer specifies an address that is inappropriately aligned for the type of the object pointed to.

•	The pointer specifies an address not used by the executing program.

The address-of operator (&) gives the address of its operand. The operand of the address-of operator can be either a function designator or an l-value that designates an object that is not a bit field and is not declared with the register storage-class specifier.

The result of the address operation is a pointer to the operand. The type addressed by the pointer is the type of the operand.

The address-of operator can only be applied to variables with fundamental, structure, or union types that are declared at the file-scope level, or to subscripted array references. In these expressions, a constant expression that does not include the address-of operator can be added to or subtracted from the address expression.

The following examples use these declarations:

int *pa, x;
int a[20];
double d;

This statement uses the address-of operator:

pa = &a[5];

The address-of operator (&) takes the address of the sixth element of the array a. The result is stored in the pointer variable pa.

x = *pa;

The indirection operator (*) is used in this example to access the int value at the address stored in pa. The value is assigned to the integer variable x.

if( x == *&x )
    printf( "True\n" );

This example prints the word True, demonstrating that the result of applying the indirection operator to the address of x is the same as x.

int roundup( void );     /* Function declaration */

int  *proundup  = roundup;
int  *pround  = &roundup;

Once the function roundup is declared, two pointers to roundup are declared and initialized. The first pointer, proundup, is initialized using only the name of the function, while the second, pround, uses the address-of operator in the initialization. The initializations are equivalent.


  Unary Arithmetic Operators

The C unary plus, arithmetic-negation, complement, and logical-negation operators are discussed in the following list:

Operator	Description
+	The unary plus operator preceding an expression in parentheses forces the grouping of the enclosed operations. It is used with expressions involving more than one associative or commutative binary operator. The operand must have arithmetic type. The result is the value of the operand. An integral operand undergoes integral promotion. The type of the result is the type of the promoted operand.
−	The arithmetic-negation operator produces the negative (two's complement) of its operand. The operand must be an integral or floating value. This operator performs the usual arithmetic conversions.
~	The bitwise-complement (or bitwise-NOT) operator produces the bitwise complement of its operand. The operand must be of integral type. This operator performs usual arithmetic conversions; the result has the type of the operand after conversion.
!	The logical-negation (logical-NOT) operator produces the value 0 if its operand is true (nonzero) and the value 1 if its operand is false (0). The result has int type. The operand must be an integral, floating, or pointer value.
The following examples illustrate these operators:

short x = 987;
    x = -x;

In the example above, the new value of x is the negative of 987, or −987.

unsigned short y = 0xAAAA;
    y = ~y;

In this example, the new value assigned to y is the one's complement of the unsigned value 0xAAAA, or 0x5555.

if( !(x < y) )

If x is greater than or equal to y, the result of the expression is 1 (true). If x is less than y, the result is 0 (false).

Unary arithmetic operations on pointers are illegal.


  The sizeof Operator

The sizeof operator gives the amount of storage, in bytes, required to store an object of the type of the operand. This operator allows you to avoid specifying machine-dependent data sizes in your programs.

Syntax

sizeof unary-expression
sizeof ( type-name )

The operand is either an identifier that is a unary-expression, or a type-cast expression (that is, a type specifier enclosed in parentheses). The unary-expression cannot represent a bit-field object, an incomplete type, or a function designator. The result is an unsigned integral constant. The standard header STDDEF.H defines this type as size_t.

When you apply the sizeof operator to an array identifier, the result is the size of the entire array rather than the size of the pointer represented by the array identifier.

When you apply the sizeof operator to a structure or union type name, or to an identifier of structure or union type, the result is the number of bytes in the structure or union, including internal and trailing padding. This size may include internal and trailing padding used to align the members of the structure or union on memory boundaries. Thus, the result may not correspond to the size calculated by adding up the storage requirements of the individual members.

If an unsized array is the last element of a structure, the sizeof operator returns the size of the structure without the array.

buffer = calloc(100, sizeof (int) );

This example uses the sizeof operator to pass the size of an int, which varies among machines, as an argument to a run-time function named calloc. The value returned by the function is stored in buffer.

static char *strings[] ={
 "this is string one",
 "this is string two",
 "this is string three",
};
const int string_no = ( sizeof strings ) / ( sizeof strings[0] );

In this example, strings is an array of pointers to char. The number of pointers is the number of elements in the array, but is not specified. It is easy to determine the number of pointers by using the sizeof operator to calculate the number of elements in the array. The const integer value string_no is initialized to this number. Because it is a const value, string_no cannot be modified.


  Cast Operators

A type cast provides a method for explicit conversion of the type of an object in a specific situation.

Syntax

cast-expression :
unary-expression
( type-name ) cast-expression

The compiler treats cast-expression as type type-name after a type cast has been made. Casts can be used to convert objects of any scalar type to or from any other scalar type. Explicit type casts are constrained by the same rules that determine the effects of implicit conversions, discussed in »Assignment Conversions«. Additional restraints on casts may result from the actual sizes or representation of specific types. See »Storage of Basic Types« for information on actual sizes of integral types. For more information on type casts, see »Type-Cast Conversions«.


  Multiplicative Operators

The multiplicative operators perform multiplication (*), division (/), and remainder (%) operations.

Syntax

multiplicative-expression :
cast-expression
multiplicative-expression * cast-expression
multiplicative-expression / cast-expression
multiplicative-expression % cast-expression

The operands of the remainder operator (%) must be integral. The multiplication (*) and division (/) operators can take integral- or floating-type operands; the types of the operands can be different.

The multiplicative operators perform the usual arithmetic conversions on the operands. The type of the result is the type of the operands after conversion.

Note  Since the conversions performed by the multiplicative operators do not provide for overflow or underflow conditions, information may be lost if the result of a multiplicative operation cannot be represented in the type of the operands after conversion.

The C multiplicative operators are described below:

Operator	Description
*	The multiplication operator causes its two operands to be multiplied.
/	The division operator causes the first operand to be divided by the second. If two integer operands are divided and the result is not an integer, it is truncated according to the following rules:
	• The result of division by 0 is undefined according to the ANSI C standard. The Microsoft C compiler generates an error at compile- or runtime.
	• If both operands are positive or unsigned, the result is truncated toward 0.
	• If either operand is negative, whether the result of the operation is the largest integer less than or equal to the algebraic quotient or is the smallest integer greater than or equal to the algebraic quotient is implementation defined. (See the Microsoft Specific section below.)
%	The result of the remainder operator is the remainder when the first operand is divided by the second. When the division is inexact, the result is determined by the following rules:
	• If the right operand is zero, the result is undefined.
	• If both operands are positive or unsigned, the result is positive.
	• If either operand is negative and the result is inexact, the result is implementation defined. (See the Microsoft Specific section below.)
Microsoft Specific

In division where either operand is negative, the direction of truncation is toward 0.

If either operation is negative in division with the remainder operator, the result has the same sign as the dividend (the first operand in the expression). ♦

The declarations shown below are used for the following examples:

int i = 10, j = 3, n;
double x = 2.0, y;

This statement uses the multiplication operator:

y = x * i;

In this case, x is multiplied by i to give the value 20.0. The result has double type.

n = i / j;

In this example, 10 is divided by 3. The result is truncated toward 0, yielding the integer value 3.

n = i % j;

This statement assigns n the integer remainder, 1, when 10 is divided by 3.

Microsoft Specific

The sign of the remainder is the same as the sign of the dividend. For example:

50 % -6 = 2
-50 % 6 = -2

In each case, 50 and 2 have the same sign. ♦


  Additive Operators

The additive operators perform addition (+) and subtraction (−).

Syntax

additive-expression :
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression − multiplicative-expression

Note  Although the syntax for additive-expression includes multiplicative-expression, this does not imply that expressions using multiplication are required. See the syntax in Appendix A, C Language Syntax Summary, for multiplicative-expression, cast-expression, and unary-expression.

The operands can be integral or floating values. Some additive operations can also be performed on pointer values, as outlined under the discussion of each operator.

The additive operators perform the usual arithmetic conversions on integral and floating operands. The type of the result is the type of the operands after conversion. Since the conversions performed by the additive operators do not provide for overflow or underflow conditions, information may be lost if the result of an additive operation cannot be represented in the type of the operands after conversion.


  Addition (+)

The addition operator (+) causes its two operands to be added. Both operands can be either integral or floating types, or one operand can be a pointer and the other an integer.

When an integer is added to a pointer, the integer value (i) is converted by multiplying it by the size of the value that the pointer addresses. After conversion, the integer value represents i memory positions, where each position has the length specified by the pointer type. When the converted integer value is added to the pointer value, the result is a new pointer value representing the address i positions from the original address. The new pointer value addresses a value of the same type as the original pointer value and therefore is the same as array indexing (see »One-Dimensional Arrays« and »Multidimensional Arrays«). If the sum pointer points outside the array, except at the first location beyond the high end, the result is undefined. For more information, see »Pointer Arithmetic«.


Subtraction ()
  Subtraction (−)

The subtraction operator (−) subtracts the second operand from the first. Both operands can be either integral or floating types, or one operand can be a pointer and the other an integer.

When two pointers are subtracted, the difference is converted to a signed integral value by dividing the difference by the size of a value of the type that the pointers address. The size of the integral value is defined by the type ptrdiff_t in the standard include file STDDEF.H. The result represents the number of memory positions of that type between the two addresses. The result is only guaranteed to be meaningful for two elements of the same array, as discussed in "Pointer Arithmetic" later in this section.

When an integer value is subtracted from a pointer value, the subtraction operator converts the integer value (i) by multiplying it by the size of the value that the pointer addresses. After conversion, the integer value represents i memory positions, where each position has the length specified by the pointer type. When the converted integer value is subtracted from the pointer value, the result is the memory address i positions before the original address. The new pointer points to a value of the type addressed by the original pointer value.


  Using the Additive Operators

The following examples, which illustrate the addition and subtraction operators, use these declarations:

int i = 4, j;
float x[10];
float *px;

These statements are equivalent:

px = &x[4 + i];
px = &x[4] + i;

The value of i is multiplied by the length of a float and added to &x[4]. The resulting pointer value is the address of x[8].

j = &x[i] - &x[i-2];

In this example, the address of the third element of x (given by x[i−2]) is subtracted from the address of the fifth element of x (given by x[i]). The difference is divided by the length of a float; the result is the integer value 2.


  Pointer Arithmetic

Additive operations involving a pointer and an integer give meaningful results only if the pointer operand addresses an array member and the integer value produces an offset within the bounds of the same array. When the integer value is converted to an address offset, the compiler assumes that only memory positions of the same size lie between the original address and the address plus the offset.

This assumption is valid for array members. By definition, an array is a series of values of the same type; its elements reside in contiguous memory locations. However, storage for any types except array elements is not guaranteed to be filled by the same type of identifiers. That is, blanks can appear between memory positions, even positions of the same type. Therefore, the results of adding to or subtracting from the addresses of any values but array elements are undefined.

Similarly, when two pointer values are subtracted, the conversion assumes that only values of the same type, with no blanks, lie between the addresses given by the operands.

On machines with segmented architecture (such as the 8086/8088), additive operations between pointer and integer values may not be valid in some cases. For example, an operation may result in an address that is outside the bounds of an array. See the reference information on these processors or reference books on segmented architecture for more information.

Note  The results of pointer subtraction when both operands are pointers to short may overflow the intermediate result. To avoid this, cast the pointers to pointers to long. For subtraction of __huge operands, cast the difference to unsigned long to get the correct result.


  Bitwise Shift Operators

The shift operators shift their first operand left (<<) or right (>>) by the number of positions the second operand specifies.

Syntax

shift-expression :
additive-expression
shift-expression  << additive-expression
shift-expression  >> additive-expression

Both operands must be integral values. These operators perform the usual arithmetic conversions; the type of the result is the type of the left operand after conversion.

For leftward shifts, the vacated right bits are set to 0. For rightward shifts, the vacated left bits are filled based on the type of the first operand after conversion. If the type is unsigned, they are set to 0. Otherwise, they are filled with copies of the sign bit. For left-shift operators without overflow, the statement

expr1 << expr2

is equivalent to multiplication by 2expr2. For right-shift operators,

expr1 >> expr2

is equivalent to division by 2expr2 if expr1 is unsigned or has a nonnegative value.

The result of a shift operation is undefined if the second operand is negative, or if the right operand is greater than or equal to the width in bits of the promoted left operand.

Since the conversions performed by the shift operators do not provide for overflow or underflow conditions, information may be lost if the result of a shift operation cannot be represented in the type of the first operand after conversion.

unsigned int x, y, z;

x = 0x00AA;
y = 0x5500;

z = ( x << 8 ) + ( y >> 8 );

In this example, x is shifted left eight positions and y is shifted right eight positions. The shifted values are added, giving 0xAA55, and assigned to z.

Shifting a negative value to the right yields half the absolute value, rounded down. For example, −253 (binary 11111111 00000011) shifted right one bit produces −127 (binary 11111111 10000001). A positive 253 shifts right to produce +126.

Right shifts preserve the sign bit. When a signed integer shifts right, the most-significant bit remains set. When an unsigned integer shifts right, the most-significant bit is cleared.

In 16-bit and 32-bit targets, if 0xF000 is unsigned, the result is 0x7800.

32-Bit Specific

In 32-bit targets, if 0xF0000000 is signed, a right shift produces 0xF8000000. Shifting a positive number right 32 times produces 0xF0000000. Shifting a negative number right 32 times produces 0xFFFFFFFF. ♦

16-Bit Specific

In 16-bit targets, if 0xF000 is signed, a right shift produces 0xF800. Shifting a positive number right 16 times produces 0x0000. Shifting a negative number right 16 times produces 0xFFFF. ♦


  Relational and Equality Operators

The binary relational and equality operators compare their first operand to their second operand to test the validity of the specified relationship. The result of a relational expression is 1 if the tested relationship is true and 0 if it is false. The type of the result is int.

Syntax

relational-expression :
shift-expression
relational-expression <  shift-expression
relational-expression >  shift-expression
relational-expression <=  shift-expression
relational-expression >=  shift-expression

equality-expression :
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression

The relational and equality operators test the following relationships:

Operator	Relationship Tested
<	First operand less than second operand
>	First operand greater than second operand
<=	First operand less than or equal to second operand
>=	First operand greater than or equal to second operand
==	First operand equal to second operand
!=	First operand not equal to second operand
The first four operators in the list above have a higher precedence than the equality operators (== and !=). See the precedence information in Table 4.1.

The operands can have integral, floating, or pointer type. The types of the operands can be different. Relational operators perform the usual arithmetic conversions on integral and floating type operands. In addition, you can use the following combinations of operand types with the relational and equality operators:

•	Both operands of any relational or equality operator can be pointers to the same type. For the equality (==) and inequality (!=) operators, the result of the comparison indicates whether the two pointers address the same memory location. For the other relational operators (<, >, <=, and >=), the result of the comparison indicates the relative position of the two memory addresses of the objects pointed to. Relational operators compare only offsets.

Pointer comparison is defined only for parts of the same object. If the pointers refer to members of an array, the comparison is equivalent to comparison of the corresponding subscripts. The address of the first array element is "less than" the address of the last element. In the case of structures, pointers to structure members declared later are "greater than" pointers to members declared earlier in the structure. Pointers to the members of the same union are equal.

•	A pointer value can be compared to the constant value 0 for equality (==) or inequality (!=). A pointer with a value of 0 is called a "null" pointer; that is, it does not point to a valid memory location.

•	The equality operators follow the same rules as the relational operators, but permit additional possibilities: a pointer can be compared to a constant integral expression with value 0, or to a pointer to void. If two pointers are both null pointers, they compare as equal. Equality operators compare both segment and offset.

The examples below illustrate relational and equality operators.

int x = 0, y = 0;
if ( x < y )

Because x and y are equal, the expression in this example yields the value 0.

char array[10];
char *p;

for ( p = array; p < &array[10]; p++ )
    *p = '\0';

The fragment in this example sets each element of array to a null character constant.

enum color { red, white, green } col;
.
.
.
if ( col == red )
.
.
.

These statements declare an enumeration variable named col with the tag color. At any time, the variable may contain an integer value of 0, 1, or 2, which represents one of the elements of the enumeration set color: the color red, white, or green, respectively. If col contains 0 when the if statement is executed, any statements depending on the if will be executed.


  Bitwise Operators

The bitwise operators perform bitwise-AND (&), bitwise-exclusive-OR (^), and bitwise-inclusive-OR (|) operations.

Syntax

AND-expression :
equality-expression
AND-expression & equality-expression

exclusive-OR-expression :
AND-expression
exclusive-OR-expression ^ AND-expression

inclusive-OR-expression :
exclusive-OR-expression
inclusive-OR-expression | exclusive-OR-expression

The operands of bitwise operators must have integral types, but their types can be different. These operators perform the usual arithmetic conversions; the type of the result is the type of the operands after conversion.

The C bitwise operators are described below:

Operator	Description
&	The bitwise-AND operator compares each bit of its first operand to the corresponding bit of its second operand. If both bits are 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.
^	The bitwise-exclusive-OR operator compares each bit of its first operand to the corresponding bit of its second operand. If one bit is 0 and the other bit is 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.
|	The bitwise-inclusive-OR operator compares each bit of its first operand to the corresponding bit of its second operand. If either bit is 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.
These declarations are used for the following three examples:

short i = 0xAB00;
short j = 0xABCD;
short n;

n = i & j;

The result assigned to n in this first example is the same as i (0xAB00 hexadecimal).

n = i | j;

n = i ^ j;

The bitwise-inclusive OR in the second example results in the value 0xABCD (hexadecimal), while the bitwise-exclusive OR in the third example produces 0xCD (hexadecimal).

Microsoft Specific

The results of bitwise operation on signed integers is implementation-defined according to the ANSI C standard. For the Microsoft C compiler, bitwise operations on signed integers work the same as bitwise operations on unsigned integers. For example, -16 & 99 can be expressed in binary as

  11111111 11110000
& 00000000 01100011
  _________________
  00000000 01100000

The result of the bitwise AND is 96 decimal. ♦


  Logical Operators

The logical operators perform logical-AND (&&) and logical-OR ( || ) operations.

Syntax

logical-AND-expression :
inclusive-OR-expression
logical-AND-expression && inclusive-OR-expression

logical-OR-expression :
logical-AND-expression
logical-OR-expression || logical-AND-expression

Logical operators do not perform the usual arithmetic conversions. Instead, they evaluate each operand in terms of its equivalence to 0. The result of a logical operation is either 0 or 1. The result's type is int.

The C logical operators are described below:

Operator	Description
&&	The logical-AND operator produces the value 1 if both operands have nonzero values. If either operand is equal to 0, the result is 0. If the first operand of a logical-AND operation is equal to 0, the second operand is not evaluated.
||	The logical-OR operator performs an inclusive-OR operation on its operands. The result is 0 if both operands have 0 values. If either operand has a nonzero value, the result is 1. If the first operand of a logical-OR operation has a nonzero value, the second operand is not evaluated.
The operands of logical-AND and logical-OR expressions are evaluated from left to right. If the value of the first operand is sufficient to determine the result of the operation, the second operand is not evaluated. This is called "short-circuit evaluation." There is a sequence point after the first operand. See »Sequence Points« for more information.

The following examples illustrate the logical operators:

int w, x, y, z;

if ( x < y && y < z )
    printf( "x is less than z\n" );

In this example, the printf function is called to print a message if x is less than y and y is less than z. If x is greater than y, the second operand (y < z) is not evaluated and nothing is printed. Note that this could cause problems in cases where the second operand has side effects that are being relied on for some other reason.

printf( "%d" , (x == w || x == y || x == z) );

In this example, if x is equal to either w, y, or z, the second argument to the printf function evaluates to true and the value 1 is printed. Otherwise, it evaluates to false and the value 0 is printed. As soon as one of the conditions evaluates to true, evaluation ceases.


  Conditional-Expression Operator

C has one ternary operator: the conditional-expression operator (? :).

Syntax

conditional-expression :
logical-OR-expression
logical-OR-expression ? expression : conditional-expression

The logical-OR-expression must have integral, floating, or pointer type. It is evaluated in terms of its equivalence to 0. A sequence point follows logical-OR-expression. Evaluation of the operands proceeds as follows:

•	If logical-OR-expression is not equal to 0, expression is evaluated. The result of evaluating the expression is given by the nonterminal expression. (This means expression is evaluated only if logical-OR-expression is true.)

•	If logical-OR-expression equals 0, conditional-expression is evaluated. The result of the expression is the value of conditional-expression. (This means conditional-expression is evaluated only if logical-OR-expression is false.)

Note that either expression or conditional-expression is evaluated, but not both.

The type of the result of a conditional operation depends on the type of the expression or conditional-expression operand, as follows:

•	If expression or conditional-expression has integral or floating type (their types can be different), the operator performs the usual arithmetic conversions. The type of the result is the type of the operands after conversion.

•	If both expression and conditional-expression have the same structure, union, or pointer type, the type of the result is the same structure, union, or pointer type.

•	If both operands have type void, the result has type void.

•	If either operand is a pointer to an object of any type, and the other operand is a pointer to void, the pointer to the object is converted to a pointer to void and the result is a pointer to void.

•	If either expression or conditional-expression is a pointer and the other operand is a constant expression with the value 0, the type of the result is the pointer type.

In the type comparison for pointers, any type qualifiers (const or volatile) in the type to which the pointer points are insignificant, but the result type inherits the qualifiers from both components of the conditional.

The following examples show uses of the conditional operator:

j = ( i < 0 ) ? ( -i ) : ( i );

This example assigns the absolute value of i to j. If i is less than 0, -i is assigned to j. If i is greater than or equal to 0, i is assigned to j.

void f1( void );
void f2( void );
int x;
int y;
    .
    .
    .
( x == y ) ? ( f1() ) : ( f2() );

In this example, two functions, f1 and f2, and two variables, x and y, are declared. Later in the program, if the two variables have the same value, the function f1 is called. Otherwise, f2 is called.


  Assignment Operators

An assignment operation assigns the value of the right-hand operand to the storage location named by the left-hand operand. Therefore, the left-hand operand of an assignment operation must be a modifiable l-value. After the assignment, an assignment expression has the value of the left operand but is not an l-value.

Syntax

assignment-expression :
conditional-expression
unary-expression assignment-operator assignment-expression

assignment-operator : one of
=   *=   /=   %=   +=   −=   <<=   >>=  &=   ^=   |=

The assignment operators in C can both transform and assign values in a single operation. C provides the following assignment operators:

Operator	Operation Performed
=	Simple assignment
*=	Multiplication assignment
/=	Division assignment
%=	Remainder assignment
+=	Addition assignment
−=	Subtraction assignment
<<=	Left-shift assignment
>>=	Right-shift assignment
&=	Bitwise-AND assignment
^=	Bitwise-exclusive-OR assignment
|=	Bitwise-inclusive-OR assignment
In assignment, the type of the right-hand value is converted to the type of the left-hand value, and the value is stored in the left operand after the assignment has taken place. The left operand must not be an array, a function, or a constant. The specific conversion path, which depends on the two types, is outlined in detail in »Type Conversions«.


  Simple Assignment

The simple-assignment operator assigns its right operand to its left operand. The value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand. The conversion rules for assignment apply (see »Assignment Conversions«.

double x;
int y;

x = y;

In this example, the value of y is converted to type double and assigned to x.


  Compound Assignment

The compound-assignment operators combine the simple-assignment operator with another binary operator. Compound-assignment operators perform the operation specified by the additional operator, then assign the result to the left operand. For example, a compound-assignment expression such as

expression1 += expression2

can be understood as

expression1 = expression1 + expression2

However, the compound-assignment expression is not equivalent to the expanded version because the compound-assignment expression evaluates expression1 only once, while the expanded version evaluates expression1 twice: in the addition operation and in the assignment operation.

The operands of a compound-assignment operator must be of integral or floating type. Each compound-assignment operator performs the conversions that the corresponding binary operator performs and restricts the types of its operands accordingly. The addition-assignment (+=) and subtraction-assignment (−=) operators can also have a left operand of pointer type, in which case the right-hand operand must be of integral type. The result of a compound-assignment operation has the value and type of the left operand.

#define MASK 0xff00

n &= MASK;

In this example, a bitwise-inclusive-AND operation is performed on n and MASK, and the result is assigned to n. The manifest constant MASK is defined with a #define preprocessor directive. (For more information, see Chapter 1 of the Preprocessor Reference.)


  Sequential-Evaluation Operator

The sequential-evaluation operator, also called the "comma operator," evaluates its two operands sequentially from left to right.

Syntax

expression :
assignment-expression
expression , assignment-expression

The left operand of the sequential-evaluation operator is evaluated as a void expression. The result of the operation has the same value and type as the right operand. Each operand can be of any type. The sequential-evaluation operator does not perform type conversions between its operands, and it does not yield an l-value. There is a sequence point after the first operand, which means all side effects from the evaluation of the left operand are completed before beginning evaluation of the right operand. See »Sequence Points« for more information.

The sequential-evaluation operator is typically used to evaluate two or more expressions in contexts where only one expression is allowed.

Commas can be used as separators in some contexts. However, you must be careful not to confuse the use of the comma as a separator with its use as an operator; the two uses are completely different.

This example illustrates the sequential-evaluation operator:

for ( i = j = 1; i + j < 20; i += i, j-- );

In this example, each operand of the for statement's third expression is evaluated independently. The left operand i += i is evaluated first; then the right operand, j−−, is evaluated.

func_one( x, y + 2, z );
func_two( (x--, y + 2), z );

In the function call to func_one, three arguments, separated by commas, are passed: x, y + 2, and z. In the function call to func_two, parentheses force the compiler to interpret the first comma as the sequential-evaluation operator. This function call passes two arguments to func_two. The first argument is the result of the sequential-evaluation operation (x--, y + 2), which has the value and type of the expression y + 2; the second argument is z.


  4.3  Type Conversions

Type conversions depend on the specified operator and the type of the operand or operators. Type conversions are performed in the following cases:

•	When a value of one type is assigned to a variable of a different type or an operator converts the type of its operand or operands before performing an operation

•	When a value of one type is explicitly cast to a different type

•	When a value is passed as an argument to a function or when a type is returned from a function

This section outlines the rules for each kind of conversion.

A character, a short integer, or an integer bit field, all either signed or not, or an object of enumeration type, can be used in an expression wherever an integer can be used. If an int can represent all the values of the original type, then the value is converted to int; otherwise, it is converted to unsigned int. This process is called "integral promotion." Integral promotions preserve value. That is, the value after promotion is guaranteed to be the same as prior to the promotion. See »Usual Arithmetic Conversions« for more information.


  Assignment Conversions

In assignment operations, the type of the value being assigned is converted to the type of the variable that receives the assignment. C allows conversions by assignment between integral and floating types, even if information is lost in the conversion. The conversion method used depends on the types involved in the assignment, as described in »Usual Arithmetic Conversion« and in the following sections.

Type qualifiers do not affect the allowability of the conversion although a const l-value cannot be used on the left side of the assignment.


  Conversions from Signed Integral Types

When a signed integer is converted to an unsigned integer with equal or greater size and the value of the signed integer is not negative, the value is unchanged. The conversion is made by sign-extending the signed integer. A signed integer is converted to a shorter signed integer by truncating the high-order bits. The result is interpreted as an unsigned value, as shown in this example.

int i = -3;
unsigned u;

u = i;
printf( "%u\n", u );  /* Prints 65533 on 16-bit computers */

No information is lost when a signed integer is converted to a floating value, except that some precision may be lost when a long int or unsigned long int value is converted to a float value.

Table 4.2 summarizes conversions from signed integral types. This table assumes that the char type is signed by default. If you use a compile-time option to change the default for the char type to unsigned, the conversions given in Table 4.3 for the unsigned char type apply instead of the conversions in Table 4.2.

Table 4.2    Conversions from Signed Integral Types

From	To	Method
char (1)	short	Sign-extend
char	long	Sign-extend
char	unsigned char	Preserve pattern; high-order bit loses function as sign bit
char	unsigned short	Sign-extend to short; convert short to unsigned short
char	unsigned long	Sign-extend to long; convert long to unsigned long
char	float	Sign-extend to long; convert long to float
char	double	Sign-extend to long; convert long to double
char	long double	Sign-extend to long; convert long to double
short	char	Preserve low-order byte
short	long	Sign-extend
short	unsigned char	Preserve low-order byte
short	unsigned short	Preserve bit pattern; high-order bit loses function as sign bit
short	unsigned long	Sign-extend to long; convert long to unsigned long
short	float	Sign-extend to long; convert long to float
short	double	Sign-extend to long; convert long to double
short	long double	Sign-extend to long; convert long to double
long	char	Preserve low-order byte
long	short	Preserve low-order word
long	unsigned char	Preserve low-order byte
long	unsigned short	Preserve low-order word
long	unsigned long	Preserve bit pattern; high-order bit loses function as sign bit
long	float	Represent as float. If long cannot be represented exactly, some precision is lost.
long	double	Represent as double. If long cannot be represented exactly as a double, some precision is lost.
long	long double	Represent as double. If long cannot be represented exactly as a double, some precision is lost.
1 All char entries assume that the char type is signed by default.
Microsoft Specific

The int type is equivalent to either the short type or the long type, depending on the target environment. Conversion of an int value proceeds the same as for a short or a long, whichever is appropriate. For the Microsoft C compiler, an integer is the same as a short for 16-bit targets, and is equivalent to a long for 32-bit targets. ♦


  Conversions from Unsigned Integral Types

An unsigned integer is converted to a shorter unsigned or signed integer by truncating the high-order bits, or to a longer unsigned or signed integer by zero-extending.

When the value with integral type is demoted to a signed integer with smaller size, or an unsigned integer is converted to its corresponding signed integer, the value is unchanged if it can be represented in the new type. However, the value it represents changes if the sign bit is set. The results in the following example are true for 16-bit computers.

int j;
unsigned k = 65533;

j = k;
printf( "%d\n", j );   /* Prints -3 */

If it cannot be represented, the result is implementation-defined. See »Type-Cast Conversions« for information on the Microsoft C compiler's handling of demotion of integers. The same behavior results from integer conversion or from type casting the integer.

Unsigned values are converted in a way that preserves their value and is not representable directly in C. The only exception is a conversion from unsigned long to float, which loses at most the low-order bits. Otherwise, value is preserved, signed or unsigned. When a value of integral type is converted to floating, and the value is outside the range representable, the result is undefined. (See »Storage of Basic Types« for information about the range for integral and floating-point types.)

Table 4.3 summarizes conversions from unsigned integral types.

Table 4.3    Conversions from Unsigned Integral Types

From	To	Method
unsigned char	char	Preserve bit pattern; high-order bit becomes sign bit
unsigned char	short	Zero-extend
unsigned char	long	Zero-extend
unsigned char	unsigned short	Zero-extend
unsigned char	unsigned long	Zero-extend
unsigned char	float	Convert to long; convert long to float
unsigned char	double	Convert to long; convert long to double
unsigned char	long double	Convert to long; convert long to double
unsigned short	char	Preserve low-order byte
unsigned short	short	Preserve bit pattern; high-order bit becomes sign bit
unsigned short	long	Zero-extend
unsigned short	unsigned char	Preserve low-order byte
unsigned short	unsigned long	Zero-extend
unsigned short	float	Convert to long; convert long to float
unsigned short	double	Convert to long; convert long to double
unsigned short	long double	Convert to long; convert long to double
unsigned long	char	Preserve low-order byte
unsigned long	short	Preserve low-order word
unsigned long	long	Preserve bit pattern; high-order bit becomes sign bit
unsigned long	unsigned char	Preserve low-order byte
unsigned long	unsigned short	Preserve low-order word
unsigned long	float	Convert to long; convert long to float
unsigned long	double	Convert directly to double
unsigned long	long double	Convert to long; convert long to double
Microsoft Specific

The unsigned int type is equivalent either to the unsigned short type or to the unsigned long type, depending on the target environment. Conversion of an unsigned int value proceeds in the same way as conversion of an unsigned short or an unsigned long, whichever is appropriate. For the Microsoft C compiler, an integer is the same as a short for 16-bit targets and is equivalent to a long for 32-bit targets. Conversions from unsigned long values to float are not accurate if the value being converted is larger than the maximum positive signed long value. ♦


  Conversions from Floating-Point Types

A float value converted to a double or long double, or a double converted to a long double, undergoes no change in value. A double value converted to a float value is represented exactly, if possible. Precision may be lost if the value cannot be represented exactly. If the result is out of range, the behavior is undefined. See »Floating-Point Constants« for the range of floating-point types.

A floating value is converted to an integral value by first converting to a long, then from the long value to the specific integral value, as described below in Table 4.4. The decimal portion of the floating value is discarded in the conversion to a long. If the result is still too large to fit into a long, the result of the conversion is undefined.

Microsoft Specific

When converting a double or long double floating-point number to a smaller floating-point number, the value of the floating-point variable is truncated toward zero when an underflow occurs. An overflow causes a run-time error. ♦

32-Bit Specific

The 32-bit compiler maps long double to type double. ♦

Table 4.4 summarizes conversions from floating types.

Table 4.4    Conversions from Floating-Point Types

From	To	Method
float	char	Convert to long; convert long to char
float	short	Convert to long; convert long to short
float	long	Truncate at decimal point. If result is too large to be represented as long, result is undefined.
float	unsigned short	Convert to long; convert long to unsigned short
float	unsigned long	Convert to long; convert long to unsigned long
float	double	Change internal representation
float	long double	Change internal representation
double	char	Convert to float; convert float to char
double	short	Convert to float; convert float to short
double	long	Truncate at decimal point. If result is too large to be represented as long, result is undefined.
double	unsigned short	Convert to long; convert long to unsigned short
double	unsigned long	Convert to long; convert long to unsigned long
double	float	Represent as a float. If double value cannot be represented exactly as float, loss of precision occurs. If value is too large to be represented as float, the result is undefined.
long double	char	Convert to float; convert float to char
long double	short	Convert to float; convert float to short
long double	long	Truncate at decimal point. If result is too large to be represented as long, result is undefined.
long double	unsigned short	Convert to long; convert long to unsigned short
long double	unsigned long	Convert to long; convert long to unsigned long
long double	float	Represent as a float. If double value cannot be represented exactly as float, loss of precision occurs. If value is too large to be represented as float, the result is undefined.
long double	double	The long double value is treated as double.
Conversions from float, double, or long double values to unsigned long are not accurate if the value being converted is larger than the maximum positive long value.


  Conversions to and from Pointer Types

A pointer to one type of value can be converted to a pointer to a different type. However, the result may be undefined because of the alignment requirements and sizes of different types in storage. A pointer to an object can be converted to a pointer to an object whose type requires less or equally strict storage alignment, and back again without change.

A pointer to void can be converted to or from a pointer to any type, without restriction or loss of information. If the result is converted back to the original type, the original pointer is recovered.

If a pointer is converted to another pointer with the same type but having different or additional qualifiers, the new pointer is the same as the old except for restrictions imposed by the new qualifier.

A pointer value can also be converted to an integral value. The conversion path depends on the size of the pointer and the size of the integral type, according to the following rules:

•	If the size of the pointer is greater than or equal to the size of the integral type, the pointer behaves like an unsigned value in the conversion, except that it cannot be converted to a floating value.

•	If the pointer is smaller than the integral type, the pointer is first converted to a pointer with the same size as the integral type, then converted to the integral type.

Conversely, an integral type can be converted to a pointer type according to the following rules:

•	If the integral type is the same size as the pointer type, the conversion simply causes the integral value to be treated as a pointer (an unsigned integer).

•	If the size of the integral type is different from the size of the pointer type, the integral type is first converted to the size of the pointer, using the conversion paths given in Tables 4.2 and 4.3. It is then treated as a pointer value.

An integral constant expression with value 0 or such an expression cast to type
void * can be converted by a type cast, by assignment, or by comparison to a pointer of any type. This produces a null pointer that is equal to another null pointer of the same type, but this null pointer is not equal to any pointer to a function or to an object. Integers other than the constant 0 can be converted to pointer type, but the result is not portable.

See »Special Keywords in Declarations« for information about conversions on pointers made with the __near, __far, and __huge keywords.


  Conversions from Other Types

Since an enum value is an int value by definition, conversions to and from an enum value are the same as those for the int type. An int is equivalent to either a short or a long, depending on the target environment.

Microsoft Specific

For the Microsoft C compiler, an integer is the same as a short for 16-bit targets and is equivalent to a long for 32-bit targets.

No conversions between structure or union types are allowed.

Any value can be converted to type void, but the result of such a conversion can be used only in a context where an expression value is discarded, such as in an expression statement.

The void type has no value, by definition. Therefore, it cannot be converted to any other type, and other types cannot be converted to void by assignment. However, you can explicitly cast a value to type void, as discussed in the next section. ♦


  Type-Cast Conversions

You can use type casts to explicitly convert types.

Syntax

cast-expression :
unary expression
( type-name ) cast-expression

type-name :
specifier-qualifier-list abstract-declarator  (opt)

The type-name is a type and cast-expression is a value to be converted to that type. An expression with a type cast is not an l-value. The cast-expression is converted as though it had been assigned to a variable of type type-name. The conversion rules for assignments (outlined in »Assignment Conversions«) apply to type casts as well.

Any identifier can be cast to void type. However, if the type specified in a type-cast expression is not void, then the identifier being cast to that type cannot be a void expression. Any expression can be cast to void, but an expression of type void cannot be cast to any other type. For example, a function with void return type cannot have its return cast to another type.

Note that a void * expression has a type pointer to void, not type void. If an object is cast to void type, the resulting expression cannot be assigned to any item. Similarly, a type-cast object is not an acceptable l-value, so no assignment can be made to a type-cast object.

Microsoft Specific

A type cast can be an l-value expression as long as the size of the identifier does not change. For information on l-value expressions, see »L-Value and R-Value Expressions«. ♦

You can convert an expression to type void with a cast, but the resulting expression can be used only where a value is not required. An object pointer converted to
void * and back to the original type will return to its original value.

Table 4.5 shows the types that can be cast to any given type.

Table 4.5    Legal Type Casts

Destination Types	Potential Sources
Integral types	Any integer type or floating-point type, or pointer to an object
Floating-point	Any arithmetic type
A pointer to an object, or (void *)	Any integer type, (void *), a pointer to an object, or a function pointer
Function pointer	Any integral type, a pointer to an object, or a function pointer
A structure, union, or array	None
Void type	Any type
Microsoft Specific

When a long integer is cast to a short, or a short is cast to a char (demotion), the least-significant bytes are retained.

For example, this statement

short x = (short)x12345678L;

assigns the value 0x5678 to x, and this statement

char y = (char)0x1234;

assigns the value 0x34 to y.

On a 16-bit computer, near pointers are the same size as short integers; casting near pointers to short (or short to near pointers) has no effect on the value. Far pointers and huge pointers are the same size as long integers. Casting far or huge pointers to long (or long to far or huge pointers) has no effect on the value.

When a near pointer on a 16-bit computer is cast to long, the 16-bit value is "normalized," which means the segment (usually DS) and offset are combined to produce a 32-bit memory location. When a far or huge pointer is cast to short, the value is truncated to a short.

The compiler normalizes based pointers when necessary, unless the based pointer is a constant zero, in which case it is assumed to be a null pointer. For more information, see »Based Pointers (Microsoft Specific)«.

When an integral number is cast to a floating-point value that cannot exactly represent the value, the value is rounded (up or down) to the nearest suitable value.

For example, casting an unsigned long (with 32 bits of precision) to a float (whose mantissa has 23 bits of precision) rounds the number to the nearest multiple of 256. The long values in the range of 4,294,966,913 to 4,294,967,167 are all rounded to the float value 4,294,967,040. ♦


  Function-Call Conversions

The type of conversion performed on the arguments in a function call depends on the presence of a function prototype (forward declaration) with declared argument types for the called function.

If a function prototype is present and includes declared argument types, the compiler performs type checking (see Chapter 6, »Functions«).

If no function prototype is present, only the usual arithmetic conversions are performed on the arguments in the function call. These conversions are performed independently on each argument in the call. This means that a float value is converted to a double; a char or short value is converted to an int; and an unsigned char or unsigned short is converted to an unsigned int.

Microsoft Specific

If the special keywords __near, __far, and __huge are used, implicit conversions may also be made on pointer values passed to functions. You can override these implicit conversions by providing function prototypes, which also allow the compiler to perform type checking. ♦


  CHAPTER 5  Statements

The statements of a C program control the flow of program execution. In C, as in other programming languages, several kinds of statements are available to perform loops, to select other statements to be executed, and to transfer control. This chapter describes the following C statements in alphabetical order:

»break statement«

»compound statement«

»continue statement«

»do-while statement«

»expression statement«

»for statement«

»goto and labeled statements«

»if statement«

»null statement«

»return statement«

»switch statement«

»try-except statement«

»try-finally statement«

»while statement«


  5.1  Overview

C statements consist of tokens, expressions, and other statements. A statement that forms a component of another statement is called the "body" of the enclosing statement. Each of the statement types given by the following syntax is discussed later in this chapter.

Syntax

statement :
»labeled-statement«
»compound-statement«
»expression-statement«
»selection-statement«
»iteration-statement«
»jump-statement«
»try-except-statement«	/* Microsoft Specific */
»try-finally-statement«	/* Microsoft Specific */

Frequently the statement body is a "compound statement." A compound statement is made up of other statements that can include keywords. The compound statement is delimited by braces ({ }). All other C statements end with a semicolon (;). The semicolon is a statement terminator.

The expression statement contains a C expression that can contain the arithmetic or logical operators introduced in Chapter 4, »Expressions and Assignments«. The null statement is an empty statement.

Any C statement can begin with an identifying label consisting of a name and a colon. Since only the goto statement recognizes statement labels, statement labels are discussed with goto. For more information, see »The goto and Labeled Statements«.


  5.2  The break Statement

The break statement terminates the execution of the nearest enclosing do, for, switch, or while statement in which it appears. Control passes to the statement that follows the terminated statement.

Syntax

jump-statement :
break;

The break statement is frequently used to terminate the processing of a particular case within a switch statement. An error is generated if there is no enclosing iterative or switch statement.

Within nested statements, the break statement terminates only the do, for, switch, or while statement that immediately encloses it. You can use a return or goto statement to transfer control elsewhere out of the nested structure.

This example illustrates the break statement:

for ( i = 0; i < LENGTH; i++ )  /* Execution returns here when */
{                               /* break statement is executed */
    for ( j = 0; j < WIDTH; j++)
    {
        if ( lines[i][j] == '\0' )
        {
            lengths[i] = j;
            break;
        }
    }
}

The example processes an array of variable-length strings stored in lines. The break statement causes an exit from the interior for loop after the terminating null character ('\0') of each string is found and its position is stored in lengths[i].

The variable j is not incremented when break causes the exit from the interior loop. Control then returns to the outer for loop. The variable i is incremented and the process is repeated until i is greater than or equal to LENGTH.


  5.3  The Compound Statement

A compound statement (also called a "block") typically appears as the body of another statement, such as the if statement. Chapter 3, »Declarations and Types«, describes the form and meaning of the declarations that can appear at the head of a compound statement.

Syntax

compound-statement :
{ declaration-list ( opt ) statement-list ( opt ) }

declaration-list :
declaration
declaration-list declaration

statement-list :
statement
statement-list statement

If there are declarations, they must come before any statements. The scope of each identifier declared at the beginning of a compound statement extends from its declaration point to the end of the block. It is visible throughout the block unless a declaration of the same identifier exists in an inner block.

Identifiers in a compound statement are presumed auto unless explicitly declared otherwise with register, static, or extern, except functions, which can only be extern. You can leave off the extern specifier in function declarations and the function will still be extern.

Storage is not allocated and initialization is not permitted if a variable or function is declared in a compound statement with storage class extern. The declaration refers to an external variable or function defined elsewhere.

Variables declared in a block with the auto or register keyword are reallocated and, if necessary, initialized each time the compound statement is entered. These variables are not defined after the compound statement is exited. If a variable declared inside a block has the static attribute, the variable is initialized when program execution begins and keeps its value throughout the program. See »Storage Classes« for information about static.

This example illustrates a compound statement:

if ( i > 0 )
{
    line[i] = x;
    x++;
    i--;
}

In this example, if i is greater than 0, all of the statements inside the compound statement are executed in order.


  5.4  The continue Statement

The continue statement passes control to the next iteration of the do, for, or while statement in which it appears, bypassing any remaining statements in the do, for, or while statement body. A typical use of the continue statement is to return to the start of a loop from within a deeply nested loop.

Syntax

jump-statement :
continue;

The next iteration of a do, for, or while statement is determined as follows:

•	Within a do or a while statement, the next iteration starts by reevaluating the expression of the do or while statement.

•	A continue statement in a for statement causes the first expression of the for statement to be evaluated. Then the compiler reevaluates the conditional expression and, depending on the result, either terminates or iterates the statement body. For more information on the for statement, including its nonterminals, see »The for Statement«.

This is an example of the continue statement:

while ( i-- > 0 )
{
    x = f( i );
    if ( x == 1 )
        continue;
    y += x * x;
}

In this example, the statement body is executed while i is greater than 0. First f(i) is assigned to x; then, if x is equal to 1, the continue statement is executed. The rest of the statements in the body are ignored, and execution resumes at the top of the loop with the evaluation of the loop's test.


  5.5  The do-while Statement

The do-while statement lets you repeat a statement or compound statement until a specified expression becomes false.

Syntax

iteration-statement :
do statement while ( expression ) ;

The expression in a do-while statement is evaluated after the body of the loop is executed. Therefore, the body of the loop is always executed at least once.

The expression must have arithmetic or pointer type. Execution proceeds as follows:

1.	The statement body is executed.

2.	Next, expression is evaluated. If expression is false, the do-while statement terminates and control passes to the next statement in the program. If expression is true (nonzero), the process is repeated, beginning with step 1.

The do-while statement can also terminate when a break, goto, or return statement is executed within the statement body.

This is an example of the do-while statement:

do
{
    y = f( x );
    x--;
} while ( x > 0 );

In this do-while statement, the two statements y = f( x ); and x--; are executed, regardless of the initial value of x. Then x > 0 is evaluated. If x is greater than 0, the statement body is executed again and x > 0 is reevaluated. The statement body is executed repeatedly as long as x remains greater than 0. Execution of the do-while statement terminates when x becomes 0 or negative. The body of the loop is executed at least once.


  5.6  The Expression Statement

When an expression statement is executed, the expression is evaluated according to the rules outlined in Chapter 4, »Expressions and Assignments«.

Syntax

expression-statement :
expression ( opt ) ;

All side effects from the expression evaluation are completed before the next statement is executed. An empty expression statement is called a null statement. See »The Null Statement«.

These examples demonstrate expression statements.

x = ( y + 3 );            /* x is assigned the value of y + 3  */
x++;                      /* x is incremented                  */
x = y = 0;                /* Both x and y are initialized to 0 */
proc( arg1, arg2 );       /* Function call returning void      */
y = z = ( f( x ) + 3 );   /* A function-call expression        */

In the last statement, the function-call expression, the value of the expression, which includes any value returned by the function, is increased by 3 and then assigned to both the variables y and z.


  5.7  The for Statement

The for statement lets you repeat a statement or compound statement a specified number of times. The body of a for statement is executed zero or more times until an optional condition becomes false. You can use optional expressions within the for statement to initialize and change values during the for statement's execution.

Syntax

iteration-statement :
for ( init-expression ( opt ) ; cond-expression ( opt ) ; loop-expression ( opt ) ) statement

Execution of a for statement proceeds as follows:

1.	The init-expression, if any, is evaluated. This specifies the initialization for the loop. There is no restriction on the type of init-expression.

2.	The cond-expression, if any, is evaluated. This expression must have arithmetic or pointer type. It is evaluated before each iteration. Three results are possible:

•	If cond-expression is true (nonzero), statement is executed; then loop-expression, if any, is evaluated. The loop-expression is evaluated after each iteration. There is no restriction on its type. Side effects will execute in order. The process then begins again with the evaluation of cond-expression.

•	If cond-expression is omitted, cond-expression is considered true, and execution proceeds exactly as described in the previous paragraph. A for statement without a cond-expression argument terminates only when a break or return statement within the statement body is executed, or when a goto (to a labeled statement outside the for statement body) is executed.

•	If cond-expression is false (0), execution of the for statement terminates and control passes to the next statement in the program.

A for statement also terminates when a break, goto, or return statement within the statement body is executed. A continue statement in a for loop causes loop-expression to be evaluated. When a break statement is executed inside a for loop, loop-expression is not evaluated or executed. This statement

for( ;; );

is the customary way to produce an infinite loop which can only be exited with a break, goto, or return statement.

This example illustrates the for statement:

for ( i = space = tab = 0; i < MAX; i++ )
{
    if ( line[i] == ' ' )
        space++;
    if ( line[i] == '\t' )
    {
        tab++;
        line[i] = ' ';
    }
}

This example counts space (' ') and tab ('\t') characters in the array of characters named line and replaces each tab character with a space. First i, space, and tab are initialized to 0. Then i is compared with the constant MAX; if i is less than MAX, the statement body is executed. Depending on the value of line[i], the body of one or neither of the if statements is executed. Then i is incremented and tested against MAX; the statement body is executed repeatedly as long as i is less than MAX.


  5.8  The goto and Labeled Statements

The goto statement transfers control to a label. The given label must reside in the same function and can appear before only one statement in the same function.

Syntax

statement :
     labeled-statement
     jump-statement

jump-statement :
goto identifier ;

labeled-statement :
identifier : statement

A statement label is meaningful only to a goto statement; in any other context, a labeled statement is executed without regard to the label.

A jump-statement must reside in the same function and can appear before only one statement in the same function. The set of identifier names following a goto has its own name space so the names do not interfere with other identifiers. Labels cannot be redeclared. See »Name Spaces« for information.

It is good programming style to use the break, continue, and return statement in preference to goto whenever possible. Since the break statement only exits from one level of the loop, a goto may be necessary for exiting a loop from within a deeply nested loop.

This example demonstrates the goto statement:

void main()
{
    int i, j;

    for ( i = 0; i < 10; i++ )
    {
        printf( "Outer loop executing. i = %d\n", i );
        for ( j = 0; j < 3; j++ )
        {
            printf( " Inner loop executing. j = %d\n", j );
            if ( i == 5 )
                goto stop;
        }
    }
    /* This message does not print: */
    printf( "Loop exited. i = %d\n", i );
    stop: printf( "Jumped to stop. i = %d\n", i );
}

In this example, a goto statement transfers control to the point labeled stop when i equals 5.


  5.9 The if Statement

The if statement controls conditional branching. The body of an if statement is executed if the value of the expression is nonzero. The syntax for the if statement has two forms.

Syntax

selection-statement :
if ( expression ) statement
if ( expression ) statement else statement

In both forms of the if statement, the expressions, which can have any value except a structure, are evaluated, including all side effects.

In the first form of the syntax, if expression is true (nonzero), statement is executed. If expression is false, statement is ignored. In the second form of syntax, which uses else, the second statement is executed if expression is false. With both forms, control then passes from the if statement to the next statement in the program unless one of the statements contains a break, continue, or goto.

The following are examples of the if statement:

if ( i > 0 )
    y = x / i;
else
{
    x = i;
    y = f( x );
}

In this example, the statement y = x/i; is executed if i is greater than 0. If i is less than or equal to 0, i is assigned to x and f( x ) is assigned to y. Note that the statement forming the if clause ends with a semicolon.

When nesting if statements and else clauses, use braces to group the statements and clauses into compound statements that clarify your intent. If no braces are present, the compiler resolves ambiguities by associating each else with the closest if that lacks an else.

if ( i > 0 )           /* Without braces */
    if ( j > i )
        x = j;
    else
        x = i;

The else clause is associated with the inner if statement in this example. If i is less than or equal to 0, no value is assigned to x.

if ( i > 0 )
{                      /* With braces */
    if ( j > i )
        x = j;
}
else
    x = i;

The braces surrounding the inner if statement in this example make the else clause part of the outer if statement. If i is less than or equal to 0, i is assigned to x.


  5.10  The Null Statement

A "null statement" is a statement containing only a semicolon; it can appear wherever a statement is expected. Nothing happens when a null statement is executed. The correct way to code a null statement is:

Syntax

;

Statements such as do, for, if, and while require that an executable statement appear as the statement body. The null statement satisfies the syntax requirement in cases that do not need a substantive statement body.

As with any other C statement, you can include a label before a null statement. To label an item that is not a statement, such as the closing brace of a compound statement, you can label a null statement and insert it immediately before the item to get the same effect.

This example illustrates the null statement:

for ( i = 0; i < 10; line[i++] = 0 )
     ;

In this example, the loop expression of the for statement line[i++] = 0 initializes the first 10 elements of line to 0. The statement body is a null statement, since no further statements are necessary.


  5.11  The return Statement

The return statement terminates the execution of a function and returns control to the calling function. Execution resumes in the calling function at the point immediately following the call. A return statement can also return a value to the calling function. For more information see »Return Type«.

Syntax

jump-statement :
return expression ( opt ) ;

The value of expression, if present, is returned to the calling function. If expression is omitted, the return value of the function is undefined. The expression, if present, is converted to the type returned by the function. If the function was declared with return type void, a return statement containing an expression generates a warning and the expression is not evaluated.

If no return statement appears in a function definition, control automatically returns to the calling function after the last statement of the called function is executed. In this case, the return value of the called function is undefined. If a return value is not required, declare the function to have void return type; otherwise, the default return type is int.

Many programmers use parentheses to enclose the expression argument of the return statement. However, C does not require the parentheses.

This example demonstrates the return statement:

void draw( int I, long L );
long sq( int s );
int main()
{
    long y;
    int x;

    y = sq( x );
    draw( x, y );
    return();
}

long sq( int s )
{
    return( s * s );
}

void draw( int I, long L )
{
    /* Statements defining the draw function here */
    return;
}

In this example, the main function calls two functions: sq and draw. The sq function returns the value of x * x to main, where the return value is assigned to y. The draw function is declared as a void function and does not return a value. An attempt to assign the return value of draw would cause a diagnostic message to be issued.


  5.12  The switch Statement

The switch and case statements help control complex conditional and branching operations. The switch statement transfers control to a statement within its body.

Syntax

selection-statement :
switch ( expression ) statement

labeled-statement :
case constant-expression : statement
default : statement

Control passes to the statement whose case constant-expression matches the value of switch ( expression ). The switch statement can include any number of case instances, but no two case constants within the same switch statement can have the same value. Execution of the statement body begins at the selected statement and proceeds until the end of the body or until a break statement transfers control out of the body.

Use of the switch statement usually looks something like this:

switch ( expression )
{
declarations
.
.
.
case constant-expression :

          statements executed if the expression equals the
          value of this constant-expression
          .
          .
          .
           break;
     default :
          statements executed if expression does not equal
          any case constant-expression
}

You can use the break statement to end processing of a particular case within the switch statement and to branch to the end of the switch statement. Without break, the program continues to the next case, executing the statements until a break or the end of the statement is reached. In some situations, this continuation may be desirable.

The default statement is executed if no case constant-expression is equal to the value of switch ( expression ). If the default statement is omitted, and no case match is found, none of the statements in the switch body are executed. There can be at most one default statement. The default statement need not come at the end; it can appear anywhere in the body of the switch statement. In fact it is often more efficient if it appears at the beginning of the switch statement. A case or default label can only appear inside a switch statement.

The type of switch expression and case constant-expression must be integral. The value of each case constant-expression must be unique within the statement body.

The case and default labels of the switch statement body are significant only in the initial test that determines where execution starts in the statement body. Switch statements can be nested. Any static variables are initialized before executing into any switch statements.

Note  Declarations can appear at the head of the compound statement forming the switch body, but initializations included in the declarations are not performed. The switch statement transfers control directly to an executable statement within the body, bypassing the lines that contain initializations.

The following examples illustrate switch statements:

switch( c )
{
    case 'A':
        capa++;
    case 'a':
        lettera++;
    default :
        total++;
}

All three statements of the switch body in this example are executed if c is equal to 'A' since a break statement does not appear before the following case. Execution control is transferred to the first statement (capa++;) and continues in order through the rest of the body. If c is equal to 'a', lettera and total are incremented. Only total is incremented if c is not equal to 'A' or 'a'.

switch( i )
{
    case -1:
        n++;
        break;
    case 0 :
        z++;
        break;
    case 1 :
        p++;
        break;
}

In this example, a break statement follows each statement of the switch body. The break statement forces an exit from the statement body after one statement is executed. If i is equal to −1, only n is incremented. The break following the statement n++; causes execution control to pass out of the statement body, bypassing the remaining statements. Similarly, if i is equal to 0, only z is incremented; if i is equal to 1, only p is incremented. The final break statement is not strictly necessary, since control passes out of the body at the end of the compound statement, but it is included for consistency.

A single statement can carry multiple case labels, as the following example shows:

case 'a' :
case 'b' :
case 'c' :
case 'd' :
case 'e' :
case 'f' :  hexcvt(c);

In this example, if constant-expression equals any letter between 'a' and 'f', the hexcvt function is called.

Microsoft Specific

Microsoft C does not limit the number of case values in a switch statement. The number is limited only by the available memory. ANSI C requires at least 257 case labels be allowed in a switch statement.

The default for Microsoft C is that the Microsoft extensions are enabled. Use the /Za command-line option to disable these extensions. ♦


  5.13  The try-except Statement (Microsoft Specific)

32-Bit Specific

The try-except statement is a Microsoft extension to the C language that enables 32-bit target applications to gain control of a program when events that normally terminate execution occur. Such events are called exceptions, and the mechanism that deals with exceptions is called structured exception handling.

Exceptions can be either hardware- or software-based. Even when applications cannot completely recover from hardware or software exceptions, structured exception handling makes it possible to display error information and trap the internal state of the application to help diagnose the problem. This is especially useful for intermittent problems that cannot be reproduced easily.

Syntax

try-except-statement :
__try compound-statement
__except ( expression ) compound-statement

The compound statement after the __try clause is the guarded section. The compound statement after the __except clause is the exception handler. The handler specifies a set of actions to be taken if an exception is raised during execution of the guarded section. Execution proceeds as follows:

1.	The guarded section is executed.

2.	If no exception occurs during execution of the guarded section, execution continues at the statement after the __except clause.

3.	If an exception occurs during execution of the guarded section or in any routine the guarded section calls, the__except expression is evaluated and the value returned determines how the exception is handled. There are three values:

EXCEPTION_CONTINUE_SEARCH

Exception is not recognized. Continue to search up the stack for a handler, first for containing try-except statements, then for handlers with the next highest precedence.

EXCEPTION_CONTINUE_EXECUTION

Exception is recognized but dismissed. Continue execution at the point where the exception occurred.

EXCEPTION_EXECUTE_HANDLER

Exception is recognized. Transfer control to the exception handler by executing the __except compound statement, then continue execution at the point the exception occurred.

Because the __except expression is evaluated as a C expression, it is limited to a single value, the conditional-expression operator, or the comma operator. If more extensive processing is required, the expression can call a routine that returns one of the three values listed above.

Note  Structured exception handling works with both C and C++ source files. However, it is not specifically designed for C++ and has a limitation that can affect C++ programs: as the stack is unwound, C++ objects allocated on the stack are removed without calling their destructor functions.

Each routine in an application can have its own exception handler. The __except expression executes in the scope of the __try body. This means it has access to any local variables declared there.

The __leave keyword is valid within a try-except statement block. The effect of __leave is to jump to the end of the try-except block. Execution resumes after the end of the exception handler. Although a goto statement can be used to accomplish the same result, a goto statement causes stack unwinding. The __leave statement is more efficient because it does not involve stack unwinding.

Exiting a try-except statement using the longjmp run-time function is considered abnormal termination. It is illegal to jump into a __try statement, but legal to jump out of one. The exception handler is not called if a process is killed in the middle of executing a try-except statement.

Following is an example of an exception handler and a termination handler. For more information about termination handlers, see »The try-finally Statement (Microsoft Specific)«.

.
.
.
puts("hello");
__try{
puts("in try");
__try{
puts("in try");
RAISE_AN_EXCEPTION();
}__finally{
puts("in finally");
}
}__except( puts("in filter"), EXCEPTION_EXECUTE_HANDLER ){
puts("in except");
}
puts("world");

This is the output from the example, with commentary added on the right:

hello
in try	/* fall into try                        */
in try	/* fall into nested try                 */
in filter	/* execute filter; returns 1 so accept  */
in finally	/* unwind nested finally                */
in except	/* transfer control to selected handler */
world	/* flow out of handler                  */

For more information about structured exception handling and the try-except statement, see Chapter 7 of Programming Techniques.♦


  5.14  The try-finally Statement (Microsoft Specific)

32-Bit Specific

The try-finally statement is a Microsoft extension to the C language that enables 32-bit target applications to guarantee execution of cleanup code when execution of a block of code is interrupted. Cleanup consists of such tasks as deallocating memory, closing files, and releasing file handles. The try-finally statement is especially useful for routines that have several places where a check is made for an error that could cause premature return from the routine.

Syntax

try-finally-statement :
__try compound-statement
__finally compound-statement

The compound statement after the __try clause is the guarded section. The compound statement after the __finally clause is the termination handler. The handler specifies a set of actions that execute when the guarded section is exited, whether the guarded section is exited by an exception (abnormal termination) or by standard fall through (normal termination).

Control reaches a __try statement by simple sequential execution (fall through). When control enters the __try statement, its associated handler becomes active. Execution proceeds as follows:

1.	The guarded section is executed.

2.	The termination handler is invoked.

3.	When the termination handler completes, execution continues after the __finally statement. Regardless of how the guarded section ends (for example, via a goto statement out of the guarded body or via a return statement), the termination handler is executed before the flow of control moves out of the guarded section.

The __leave keyword is valid within a try-finally statement block. The effect of __leave is to jump to the end of the try-finally block. The termination handler is immediately executed. Although a goto statement can be used to accomplish the same result, a goto statement causes stack unwinding. The __leave statement is more efficient because it does not involve stack unwinding.

Exiting a try-finally statement using the longjmp run-time function is considered abnormal termination. It is illegal to jump into a __try statement, but legal to jump out of one. All __finally statements that are active between the point of departure and the destination must be run. This is called a local unwind.

The termination handler is not called if a process is killed while executing a try-finally statement.

Note  Structured exception handling works with both C and C++ source files. However, it is not specifically designed for C++ and has a limitation that can affect C++ programs: as the stack is unwound, C++ objects allocated on the stack are removed without calling their destructor functions.

To see how the try-finally statement works, see the »try-except statement«. For more information about structured exception handling and the try-finally statement, see Chapter 7 of Programming Techniques.♦


  5.15  The while Statement

The while statement lets you repeat a statement until a specified expression becomes false.

Syntax

iteration-statement :
while ( expression ) statement

The expression must have arithmetic or pointer type. Execution proceeds as follows:

1.	The expression is evaluated.

2.	If expression is initially false, the body of the while statement is never executed, and control passes from the while statement to the next statement in the program.

If expression is true (nonzero), the body of the statement is executed and the process is repeated beginning at step 1.

The while statement can also terminate when a break, goto, or return within the statement body is executed. Use the continue statement to terminate an iteration without exiting the while loop. The continue statement passes control to the next iteration of the while statement.

This is an example of the while statement:

while ( i >= 0 )
{
    string1[i] = string2[i];
    i--;
}

This example copies characters from string2 to string1. If i is greater than or equal to 0, string2[i] is assigned to string1[i] and i is decremented. When i reaches or falls below 0, execution of the while statement terminates.


Chapter 6:  Functions
  CHAPTER 6  Functions

The function is the fundamental modular unit in C. A function is usually designed to perform a specific task, and its name often reflects that task. A function contains declarations and statements. This chapter describes how to declare, define, and call C functions. Other topics discussed are:

•	»Function attributes« such as __near and __far.

•	»Calling conventions« such as __cdecl, __pascal, and __fortran.

•	»Export«, »inline«, and »interrupt« functions.

•	32-bit »export and import functions«.

•	»Naked« functions.

•	»Storage classes« for functions.

•	»Return types.«

•	Function »arguments« and »parameters.«

Function declarations are also discussed in Chapter 3, »Declarations and Types.«


  6.1  Overview

Functions must have a definition and should have a declaration, although a definition can serve as a declaration if the declaration appears before the function is called. The function definition includes the function body—the code that executes when the function is called.

A function declaration establishes the name, return type, and attributes of a function that is defined elsewhere in the program. A function declaration must precede the call to the function. This is why the header files containing the declarations for the run-time functions are included in your code prior to a call to a run-time function. If the declaration has information about the types and number of parameters, the declaration is a prototype. See »Function Prototypes« for more information.

The compiler uses the prototype to compare the types of arguments in subsequent calls to the function with the function's parameters and to convert the types of the arguments to the types of the parameters whenever necessary.

A function call passes execution control from the calling function to the called function. The arguments, if any, are passed by value to the called function. Execution of a return statement in the called function returns control and possibly a value to the calling function.


  Obsolete Forms of Function Declarations and Definitions

The old-style function declarations and definitions use slightly different rules for declaring parameters than the syntax recommended by the ANSI C standard. First, the old-style declarations don't have a parameter list. Second, in the function definition, the parameters are listed, but their types are not declared in the parameter list. The type declarations precede the compound statement constituting the function body. The old-style syntax is obsolete and should not be used in new code. Code using the old-style syntax is still supported, however. This example illustrates the obsolete forms of declarations and definitions:

double old_style();           /* Obsolete function declaration */

double alt_style( a , real )  /* Obsolete function definition */
    double *real;
    int a;
{
    return ( *real + a ) ;
}

Functions returning an integer or pointer with the same size as an int are not required to have a declaration although the declaration is recommended.

To comply with the ANSI C standard, old-style function declarations using an ellipsis now generate an error when compiling with the /Za option and a level 4 warning when compiling with /Ze. For example:

void funct1( a, ... )  /* Generates a warning under /Ze or */
int a;                 /* an error when compiling with /Za */
{
}

You should rewrite this declaration as a prototype:

void funct1( int a, ... )
{
}

Old-style function declarations also generate warnings if you subsequently declare or define the same function with either an ellipsis or a parameter with a type that is not the same as its promoted type.

The next section shows the syntax for function definitions, including the old-style syntax. The nonterminal for the list of parameters in the old-style syntax is identifier-list.


  6.2  Function Definitions

A function definition specifies the name of the function, the types and number of parameters it expects to receive, and its return type. A function definition also includes a function body with the declarations of its local variables, and the statements that determine what the function does.

Syntax

translation-unit :
external-declaration
translation-unit external-declaration

external-declaration :	/* Allowed only at external (file) scope */
function-definition
declaration

function-definition :	/* Declarator here is the function declarator */
declaration-specifiers  (opt)  attribute-seq  (opt)  declarator declaration-list  (opt)
compound-statement  	/* attribute-seq is Microsoft Specific */

Prototype parameters are:

declaration-specifiers :
storage-class-specifier declaration-specifiers  (opt)
type-specifier declaration-specifiers  (opt)
type-qualifier declaration-specifiers  (opt)

declaration-list
declaration
declaration-list declaration

declarator
pointer  (opt)  direct-declarator

direct-declarator :	/* A function declarator */
direct-declarator ( parameter-type-list )	/* New-style declarator */
direct-declarator ( identifier-list  (opt)  )	/* Obsolete-style declarator */

The parameter list in a definition uses this syntax:

parameter-type-list :	/* The parameter list */
parameter-list
parameter-list , ...

parameter-list :
parameter-declaration
parameter-list , parameter-declaration

parameter-declaration :
declaration-specifiers declarator
declaration-specifiers abstract-declarator  (opt)

The parameter list in an old-style function definition uses this syntax:

identifier-list:	  /* Used in obsolete-style function definitions and declarations */
identifier
identifier-list , identifier

The syntax for the function body is:

compound-statement :	/* The function body */
{ declaration-list ( opt ) statement-list ( opt ) }

The only storage-class specifiers that can modify a function declaration are extern and static. The extern specifier signifies that the function can be referenced from other files; that is, the function name is exported to the linker. The static specifier signifies that the function cannot be referenced from other files; that is, the name is not exported by the linker. If no storage class appears in a function definition, extern is assumed. In any case, the function is always visible from the definition point to the end of the file.

The optional declaration-specifiers and mandatory declarator together specify the function's return type and name. The declarator is a combination of the identifier that names the function and the parentheses following the function name. The optional attribute-seq nonterminal is a Microsoft-specific feature defined in the next section, "»Function Attributes«."

The direct-declarator (in the declarator syntax) specifies the name of the function being defined and the identifiers of its parameters. If the direct-declarator includes a parameter-type-list, the list specifies the types of all the parameters. Such a declarator also serves as a function prototype for later calls to the function.

A declaration in the declaration-list in function definitions cannot contain a storage-class-specifier other than register. The type-specifier in the declaration-specifiers syntax can be omitted only if the register storage class is specified for a value of int type.

The compound-statement is the function body containing local variable declarations, references to externally declared items, and statements.

The sections "»Function Attributes«" »Specifying Calling Conventions«, »Fastcall Functions«, »Export Functions«, »Inline Functions«, »Function Addressing Using__based«, »Inline Assembler«, »Interrupt Functions«, »Using_loadds and _saveregs«, »Storage Class«, »Return Type«, »Parameters« and »Function Body«, which describe the components of the function definition in detail.


  Function Attributes (Microsoft Specific)

The optional attribute-seg nonterminal allows you to override default addressing modes by specifying a different memory model, or to select a calling convention on a per-function basis to override the defaults. You can also specify functions as __fastcall or __inline for all targets. You can specify a function as __export or __based for 16-bit targets only, and you can write interrupt functions or specify register-handling with __loadds and __saveregs for 16-bit targets.

32-Bit Specific

The attributes that affect memory-model addressing do not apply to 32-bit targets. The __near, __far, and __huge keywords generate errors. ♦


  Specifying Function Addressing (Microsoft Specific)

16-Bit Specific

By using the special keywords __near, __far, __huge, and __based, you can override the addressing specified by the compile-time memory models. The following list summarizes use of these keywords in functions.

__near

Functions are assumed to be in the default code segment (_TEXT). The function is referenced with 16-bit addresses (pointers to functions are 16 bits) and can be called only by functions in the same code segment. Functions declared as __near can be allocated in other segments by declaring them as __based or using the /NT compilation option.

__far

Functions are not assumed to be in the current code segment. Far objects are referenced with 32-bit addresses (pointers to functions are 32 bits) and can be called with a far call by functions anywhere in memory. Functions in the same compilation unit reside in the same segment unless the alloc_text pragma is used, or unless the function is declared as based.

__based

Specifies that a function resides in a specified segment. More information on __based appears later in this section.

__huge

The __huge keyword is not applicable to functions.

This example uses the __far keyword:

void __far handler( unsigned doserr, unsigned __far *bdr );

The default for Microsoft C is that the Microsoft extensions are enabled. Use the /Za command-line option to disable these extensions. ♦


  Specifying Calling Conventions (Microsoft Specific)

The special keywords discussed in this section allow you to specify directly the calling convention for any function. This list summarizes these Microsoft-specific keywords.

32-Bit Specific

The 32-bit compiler generates errors for use of the __pascal and __fortran keywords. The __fastcall calling convention is supported for 16-bit and 32-bit targets. The __stdcall calling convention is supported for 32-bit targets only. ♦

__cdecl

This modifier specifies that the associated function is to be called using the normal C calling convention (arguments are pushed from right to left, the calling function adjusts the stack, and no case translation takes place). This modifier is placed before the function name. In 16-bit programs, it can appear before or after the __near and __far modifiers. The /Gd command-line option forces the __cdecl calling convention.

16-Bit Specific

__pascal, __fortran

These 16-bit specific modifiers specify that the associated function is to be called using the Pascal or FORTRAN calling convention (arguments are pushed from left to right, the called function adjusts the stack, and identifier names are translated to uppercase). These modifiers are placed before the function name and can appear before or after the __near and __far modifiers. The __fortran and __pascal modifiers are synonyms. The /Gc command-line option forces the __pascal or __fortran calling convention.♦

__fastcall

16-Bit Specific

In 16-bit targets, this modifier specifies that the function uses a calling convention that passes arguments in registers rather than on the stack, resulting in faster code for small functions. Arguments are passed from left to right, the called function adjusts the stack, and no case translation takes place.♦

32-Bit Specific

In 32-bit targets, this modifier specifies that the function uses a calling convention that passes the first two arguments of size doubleword (DWORD) or smaller in the ECX and EDX registers; the remaining arguments are pushed on the stack right to left. The called function adjusts the stack, and no case translation takes place. ♦

For 16-bit and 32-bit targets, using /Gr on the command line causes each function in the module to compile as fastcall unless the function is declared with a conflicting attribute, or the name of the function is main. See the next section, »Fastcall Functions«, for more information.

32-Bit Specific

__stdcall

This modifier specifies that the arguments of the designated function are pushed from right to left, that an underscore is prepended to the name, and that @# ## is appended, where ### is the size of the function's parameters in bytes. This appended "name decoration" allows some link-time argument checking to be done. See Appendix C of the C++ Language Reference for more information on name decoration. The called function does its own stack adjustment when it returns to the caller. Functions declared with __stdcall return values the same way as functions declared using __cdecl.

All functions declared with __stdcall must have a prototype; otherwise, they won't actually be implemented as __stdcall. A function with a variable number of arguments that is declared with __stdcall is implemented as __cdecl. The /Gz command-line option specifies __stdcall for all functions not explicitly declared with a different calling convention. ♦

This example declaration specifies the __stdcall calling convention:

int __stdcall compare( unsigned *key );


  Fastcall Functions (Microsoft Specific)

16-Bit Specific

A __fastcall function in programs for 16-bit targets receives up to three 16-bit arguments passed in registers rather than on the stack. The choice of registers for the __fastcall calling convention depends on the type of arguments:

Type	Register Candidates
char / unsigned char	AL, DL, BL
int / unsigned int	AX, DX, BX
long / unsigned long	DX:AX
near pointer	BX, AX, DX
far or huge pointer	Passed on the stack
The names of fastcall functions are decorated like __stdcall, except that an @  is prepended instead of an underscore.

Arguments are allocated to suitable registers if available and are pushed onto the stack otherwise. Structures, unions, and all floating-point types are always pushed onto the stack. Return values of 4 bytes or smaller, including structures and unions, are placed in the registers as follows:

Size	Register
1 byte	AL
2 bytes	AX
4 bytes	DX:AX
Floating-point values are returned on the floating-point stack. To return structures or unions larger than 4 bytes, the calling program pushes a hidden last parameter, which is a near pointer to a buffer in which the value is to be returned. A far pointer to the hidden parameter must be returned in DX:AX. ♦

32-Bit Specific

For 32-bit targets, the first two arguments that have integer or pointer types are passed in the ECX and EDX registers, regardless of size. The rest of the arguments are passed on the stack from right to left. Regardless of length, structure returns are handled with a hidden parameter. ♦

The treatment of character arguments depends further on prototypes. If there is no prototype, the argument is promoted to short and the rules for short integers apply. Only if the argument is prototyped to type char do the character rules apply.

The __fastcall calling convention cannot be used with functions having variable-length parameter lists, or functions having any of the following attributes: __cdecl, __export, __fortran, __interrupt, __pascal, __saveregs.

16-Bit Specific

Entry/exit code for programs written for the Microsoft Windows™ operating system and the __fastcall calling convention can conflict in their use of the AX register. As a result, using the following combinations of options and keywords will generate errors:

__fastcall, __far, Gw                  /* error */
__fastcall, __far, __export, GA        /* error */
__fastcall, __far, __export, GD        /* error */
__fastcall, __far, GA, GEf             /* error */
__fastcall, __far, GD, GEf             /* error */
__fastcall, __far, __export, GA, GEf   /* error */
__fastcall, __far, __export, GD, GEf   /* error */  ♦

Note  Microsoft does not guarantee the same implementation of the __fastcall calling convention between compiler releases.


  Export Functions (Microsoft Specific)

16-Bit Specific

The __export keyword allows you to specify that a function is to be exported from a dynamic-link library (DLL) to Windows. Use this form to specify an exported function:

__export declarator

The declarator is the name of the exported function. When a function is declared as __export, the compiler places information in the object file to show that the function is exported from a DLL. This export definition is also known as an EXPDEF record. Functions, operators, and data can be declared as __export. Only the 16-bit compiler supports __export. For 32-bit targets, the dllimport and dllexport extended-attribute modifiers replace the __export keyword. For more information on dllimport and dllexport, see »DLL Import and Export Functions«.

The main use for __export is to export symbols that reside in a DLL. You also may need to export event-handler functions for Windows-based programs.

The __export keyword does not eliminate the need for a module-definition (.DEF) file when building a DLL. If you declare a symbol as __export and no .DEF file entry exists for that symbol, the linker assumes that the symbol has the following characteristics:

•	No input/output (I/O) privilege

•	Shared data

•	Not resident

•	No alias name

If these default characteristics are satisfactory, the symbol does not require an entry in a module-definition file. Otherwise, you must create an EXPORTS entry in the module-definition file for the symbol to specify these characteristics.

The __export keyword also causes the compiler to enter the size, in words, of the function's parameters into the export record of the object module. This size information corresponds to the pwords field of an EXPORTS statement that is in a module-definition file. You cannot override the size information in the export record with an EXPORTS entry in the .DEF file.

If you have an EXPORTS entry for a function, the pwords field in the .DEF file should be set either to 0 (which tells the linker to use the value given by the compiler) or to the same value given by the compiler. The pwords field is ignored unless you also request I/O privilege. For more information on creating .DEF files, see Chapter 4 of the Build Tools User's Guide. See Chapter 2 of the same manual for information on the /GA and /GD options, which control code generation and linker behavior when functions are defined with __export.♦


  Inline Functions (Microsoft Specific)

The __inline keyword tells the compiler to substitute the code within the function definition for every instance of a function call. However, substitution occurs only at the compiler's discretion. For example, the compiler does not inline a function if its address is taken or if it is too large to inline.

The __inline keyword is valid for 16-bit and 32-bit targets. Use this form to specify an inline function:

__inline type ( opt  ) function-definition;

The use of inline functions generates faster code and can sometimes generate smaller code than the equivalent function call generates for the following reasons:

•	It saves the time required to execute function calls.

•	Small inline functions, perhaps three lines or less, create less code than the equivalent function call because the compiler doesn't generate code to handle arguments and a return value.

•	Functions generated inline are subject to code optimizations not available to normal functions because the compiler does not perform interprocedural optimizations.

Functions using __inline should not be confused with inline assembler code. See "»Inline Assembler«" for more information.


  Function Addressing Using __based (Microsoft Specific)

16-Bit Specific

If a function is to be allocated in a given segment, it can be declared as based on a segment constant. The base for a function can be specified as:

__based(__segname( string-literal ) )

A function declared as __based resides in the code segment named by string-literal. The built-in function __segname accepts a string enclosed in quotation marks and returns a value of type __segment. The __segment type specifies the segment in which the based function resides.

In programs that use overlays, you can reduce swapping by using __based to group functions that frequently call one another. You also can use __based to ensure that near functions reside in the same segment as the functions that call them.

Declaring functions as __based replaces the alloc_text pragma. However, the alloc_text pragma is retained for backward compatibility.

The base for a function based in a segment can also be specified as:

(__based)__self

The __self function ensures that the function's location is the segment in which the pointer itself is stored. Such pointers can save space in a linked list or tree if the entire data structure fits in a single segment.

For 16-bit targets, you can use the __near or __far keyword with the __based keyword when declaring a function. ♦

32-Bit Specific

Use the code_seg pragma for 32-bit targets since function addressing using __based is not supported in 32-bit targets. For more information on code_seg, see Chapter 2 of the Preprocessor Reference.♦


  Inline Assembler (Microsoft Specific)

The inline assembler lets you embed assembly-language instructions directly in your C source programs without extra assembly and link steps. The inline assembler is built into both the 16-bit and 32-bit compilers—you don't need a separate assembler such as the Microsoft Macro Assembler (MASM).

Because the inline assembler doesn't require separate assembly and link steps, it is more convenient than a separate assembler. Inline assembly code can use any C variable or function name that is in scope, so it is easy to integrate it with your program's C code. And because the assembly code can be mixed with C statements, it can do tasks that are cumbersome or impossible in C alone.

The __asm keyword invokes the inline assembler and can appear wherever a C statement is legal. It cannot appear by itself. It must be followed by an assembly instruction, a group of instructions enclosed in braces, or, at the very least, an empty pair of braces. The term "__asm block" here refers to any instruction or group of instructions, whether or not in braces.

The 16-bit code below is a simple __asm block enclosed in braces. (The code prints the "beep" character, ASCII 7.)

__asm
{
   mov ah, 2
   mov dl, 7
   int 21h
}

Alternatively, you can put __asm in front of each assembly instruction:

__asm mov ah, 2
__asm mov dl, 7
__asm int 21h

Since the __asm keyword is a statement separator, you can also put assembly instructions on the same line:

__asm mov ah, 2   __asm mov dl, 7   __asm int 21h

For more information, see Chapter 11, "Using the Inline Assembler," of Programming Techniques.


  Interrupt Functions (Microsoft Specific)

16-Bit Specific

The __interrupt keyword specifies that the function is an interrupt handler. The compiler generates appropriate entry and exit sequences for the handling function, including saving and restoring all registers and executing an IRET instruction to return. Use this form to specify an interrupt function:

__interrupt declarator

where declarator is the name of the function to be called. An interrupt function must be __far. If you are compiling with the small (default) or compact memory model, you must explicitly declare the function with the __far attribute. An interrupt function cannot be declared as an inline function.

Interrupt functions must observe the C calling convention. If you use the /Gc compiler option (forcing the __pascal or __fortran calling convention) or the /Gr compiler option (forcing the __fastcall calling convention), you must explicitly declare your interrupt-handling function with the __cdecl attribute.

You cannot declare an interrupt function with both the __interrupt attribute and the __saveregs attribute or the __fastcall calling convention.

This example statement declares a function pointer that can be used to point to an interrupt handler:

void ( __interrupt __far *oldtime ) ( void ); ♦

32-Bit Specific

The __interrupt keyword is illegal in 32-bit targets. See Help for more information on writing interrupt functions. ♦


  Using __loadds and __saveregs (Microsoft Specific)

16-Bit Specific

The __loadds keyword causes the data-segment (DS) register to be loaded with a specified segment value upon entering the specified function. The previous DS value is restored when the function terminates. Use this form for __loadds:

__loadds declarator

The declarator specifies the function name of a function that must load DS as part of its entry sequence. Loading the DS register is essential for Windows-based callback functions and Windows-based entry points.

The compiler uses the segment name specified by the /ND (name-data-segment) option or, if no segment has been specified, the default group, DGROUP. The __loadds attribute has the same effect as the /Au option, but on a function-by-function basis.

The __loadds keyword does not imply any change in the calling convention. It can be specified with any calling-convention attribute that is supported for 16-bit targets. ♦

32-Bit Specific

The __loadds keyword is not supported in 32-bit targets. ♦

16-Bit Specific

The __saveregs keyword causes the compiler to generate code that saves all CPU  registers when entering a function and also the code that restores the registers on exit. Note that __saveregs does not restore registers used for a return value (the AX register, or AX and DX). The form for using __saveregs is:

__saveregs declarator

The declarator specifies the function name whose entry sequence must save the values of all registers. The __saveregs keyword is useful when the register conventions of the caller are unknown. It is illegal to declare a function with both the __saveregs and __interrupt attributes. ♦

32-Bit Specific

The __saveregs keyword is not supported in 32-bit targets. ♦


  DLL Import and Export Functions (Microsoft Specific)

32-Bit Specific

The dllimport and dllexport storage-class modifiers are Microsoft-specific extensions to the C language. These modifiers explicitly define the DLL's interface to its client (the executable file or another DLL). Declaring functions as dllexport eliminates the need for a module-definition (.DEF) file. You can also use the dllimport and dllexport modifiers with data and objects.

The dllimport and dllexport storage-class modifiers must be used with the extended attribute syntax keyword, __declspec, as shown in this example:

#define DllImport	__declspec( dllimport )
#define DllExport	__declspec( dllexport )

DllExport void func();
DllExport int i = 10;
DllExport int j;
DllExport int n;

For specific information about the syntax for extended storage-class modifiers, see »Extended Storage-Class Modifiers«.


  Definitions and Declarations (Microsoft Specific)

The DLL interface refers to all items (functions and data) that are known to be exported by some program in the system; that is, all items that are declared as dllimport or dllexport. All declarations included in the DLL interface must specify either the dllimport or dllexport attribute. However, the definition can specify only the dllexport attribute. For example, the following function definition generates a compiler error:

#define DllImport	__declspec( dllimport )
#define DllExport	__declspec( dllexport )

DllImport int func()	/* Error; dllimport prohibited in */
/* definition. */
{
return 1;
}

This code also generates an error:

#define DllImport	__declspec( dllimport )
#define DllExport	__declspec( dllexport )

DllImport int i = 10;	/* Error; this is a definition. */

However, this is correct syntax:

#define DllImport	__declspec( dllimport )
#define DllExport	__declspec( dllexport )

DllExport int i = 10;	/* Okay: this is an export definition. */

The use of dllexport implies a definition, while dllimport implies a declaration. You must use the extern keyword with dllexport to force a declaration; otherwise, a definition is implied.

#define DllImport	__declspec( dllimport )
#define DllExport	__declspec( dllexport )

extern DllImport int k;	/* These are correct and imply */
Dllimport int j;	/* a declaration. */


  Defining Inline Functions with dllexport and dllimport (Microsoft Specific)

You can define as inline a function with the dllexport attribute. In this case, the function is always instantiated and exported, whether or not any module in the program references the function. The function is presumed to be imported by another program.

You can also define as inline a function declared with the dllimport attribute. In this case, the function can be expanded (subject to the /Ob (inline) command-line option specification) but never instantiated. In particular, if the address of an inline imported function is taken, the address of the function residing in the DLL is returned. This behavior is the same as taking the address of a non-inline imported function.

Static local data and strings in inline functions maintain the same identities between the DLL and client as they would in a single program (that is, an executable file without a DLL interface).

Exercise care when providing imported inline functions. For example, if you update the DLL, don't assume that the client will use the changed version of the DLL. To ensure that you are loading the proper version of the DLL, rebuild the DLL's client as well.


  Rules and Limitations (Microsoft Specific)

1.	If you declare a function without the dllimport or dllexport attribute, the function is not considered part of the DLL interface. Therefore, the definition of the function must be present in that module or in another module of the same program. To make the function part of the DLL interface, you must declare the definition of the function in the other module as dllexport. Otherwise, a linker error is generated when the client is built.

2.	If a single module in your program contains dllimport and dllexport declarations for the same function, the dllexport attribute takes precedence over the dllimport attribute. However, a compiler warning is generated. For example:

#define DllImport	__declspec( dllimport )
#define DllExport	__declspec( dllexport )

DllImport void func1( void );
DllExport void func1( void );	/* Warning; dllexport */
/* takes precedence. */

3.	You cannot initialize a static function pointer with the address of a function declared with the dllimport attribute, or initialize a static data pointer with the address of a data object declared with the dllimport attribute. For example, the following code generates errors:

#define DllImport	__declspec( dllimport )
#define DllExport	__declspec( dllexport )

DllImport void func1( void );
DllImport int i;
.
.
.
int *pi = &i;	/* Error */
static void ( *pf )( void ) = &func1;	/* Error */

void func2()
{
static int *pi = &i;	/* Error */
static void ( *pf )( void ) = &func1;	/* Error */
}

However, because a program that includes the dllexport attribute in the declaration of an object must provide the definition for that object somewhere in the program, you can initialize a global or local static function pointer with the address of a dllexport function. Similarly, you can initialize a global or local static data pointer with the address of a dllexport data object. For example, the following code does not generate errors:

#define DllImport	__declspec( dllimport )
#define DllExport	__declspec( dllexport )

DllImport void func1( void );
DllImport int i;

DllExport void func1( void );
DllExport int i;
.
.
.
int *pi = &i;	/* Okay */
static void ( *pf )( void ) = &func1;	/* Okay */

void func2()
{
static int *pi = &i;	/* Okay */
static void ( *pf )( void ) = &func1;	/* Okay */
}	♦


  Naked Functions (Microsoft Specific)

32-Bit Specific

The naked storage-class attribute is a Microsoft-specific extension to the C language. For functions declared with the naked storage class attribute, the compiler generates code without prolog and epilog code. You can use this feature to write your own prolog/epilog code sequences using inline assembler code. Naked functions are particularly useful in writing virtual device drivers.

Because the naked attribute is only relevant to the definition of a function and is not a type modifier, naked functions use the extended attribute syntax, described in "»Extended Storage-Class Modifiers«".

The following example defines a function with the naked attribute:

__declspec( naked ) int func( formal_parameters )
{
/* Function body */
}

Or, alternatively:

#define Naked	__declspec( naked )

Naked int func( formal_parameters )
{
/* Function body */
}

The naked attribute affects only the nature of the compiler's code generation for the function's prolog and epilog sequences. It does not affect the code that is generated for calling such functions. Thus, the naked attribute is not considered part of the function's type, and function pointers cannot have the naked attribute. Furthermore, the naked attribute cannot be applied to a data definition. For example, the following code samples generate errors:

__declspec( naked ) int i;	/* Error--naked attribute not */
/* permitted on data declarations. */

The naked attribute is relevant only to the definition of the function and cannot be specified in the function's prototype. The following declaration generates a compiler error:

__declspec( naked ) int func();	/* Error--naked attribute	 not */
/* permitted on function declarations.	 */


  Rules and Limitations (Microsoft Specific)

1.	The return statement is not permitted in a naked function. However, you can return an int by moving the return value into the EAX register before the RET instruction.

2.	Structured exception handling constructs are not permitted in a naked function, because the constructs must unwind across the stack frame.

3.	Any use of the setjmp run-time function is not permitted in a naked function, because it too must unwind across the stack frame. However, use of the longjmp run-time function is permitted.

4.	Use of the _alloca function is not permitted in a naked function.

5.	To ensure that no initialization code for local variables appears before the prolog sequence, initialized local variables are not permitted at function scope.

6.	Frame pointer optimization (the /Oy compiler option) is not recommended, but it is automatically suppressed for a naked function.


  Considerations for Writing Prolog/Epilog Code
(Microsoft Specific)

Before writing your own prolog and epilog code sequences, it is important to understand how the stack frame is laid out, and some differences in stack frame layout between 16-bit and 32-bit targets. It is also useful to know how to use the __LOCAL_SIZE predefined constant.

Stack Frame Layout

A few minor differences exist between the 16-bit and 32-bit stack frame layout. This example shows the standard prolog code that might appear in a 32-bit function:

push	ebp	; Save ebp
mov	ebp, esp	; Set stack frame pointer
sub	esp, localbytes	; Allocate space for locals
push	<registers>	; Save registers

The localbytes variable represents the number of bytes needed on the stack for local variables, and the registers variable is a placeholder that represents the list of registers to be saved on the stack. After pushing the registers, you can place any other appropriate data on the stack. The following is the corresponding epilog code:

pop	<registers>	; Restore registers
mov	esp, ebp	; Restore stack pointer
pop	ebp	; Restore ebp
ret	; Return from function

The stack always grows down (from high to low memory addresses). The base pointer (ebp) points to the pushed value of ebp. The local variables area begins at ebp-2. To access local variables, calculate an offset from ebp by subtracting the appropriate value from ebp.

__LOCAL_SIZE

The compiler provides a constant, __LOCAL_SIZE, for use in the inline assembler block of function prolog code. This constant is used to allocate space for local variables on the stack frame in custom prolog code.

The compiler determines the value of __LOCAL_SIZE. The value is the total number of bytes of all user-defined local variables and compiler-generated temporary variables. __LOCAL_SIZE can be used only as an immediate operand; it cannot be used in an expression. You must not change or redefine the value of this constant. For example:

mov	eax, __LOCAL_SIZE	;Immediate operand--Okay
mov	eax, [ebp - __LOCAL_SIZE]	;Error

The following example of a naked function containing custom prolog and epilog sequences uses __LOCAL_SIZE symbol in the prolog sequence:

__declspec ( naked ) func()
{
int i;
int j;

__asm	/* prolog */
{
push	ebp
mov	ebp, esp
sub	esp, __LOCAL_SIZE
}

/* Function body */

__asm	/* epilog */
{
mov	esp, ebp
pop	ebp
ret
}
} ♦


  Storage Class

The storage-class specifier in a function definition gives the function either extern or static storage class.

Syntax

function-definition :
declaration-specifiers  (opt)  attribute-seq  (opt)  declarator declaration-list  (opt)
compound-statement	/* attribute-seq is Microsoft Specific */

declaration-specifiers :
storage-class-specifier declaration-specifiers  (opt)
type-specifier declaration-specifiers  (opt)
type-qualifier declaration-specifiers  (opt)

storage-class-specifier :	/* For function definitions */
extern
static

If a function definition does not include a storage-class-specifier, the storage class defaults to extern. You can explicitly declare a function as extern, but it is not required.

If the declaration of a function contains the storage-class-specifier extern, the identifier has the same linkage as any visible declaration of the identifier with file scope. If there is no visible declaration with file scope, the identifier has external linkage. If an identifier has file scope and no storage-class-specifier, the identifier has external linkage. External linkage means that each instance of the identifier denotes the same object or function. See "»Understanding Lifetime, Scope, Visibility, and Linkage«" for more information about linkage and file scope.

Block-scope function declarations with a storage-class specifier other than extern generate errors.

A function with static storage class is visible only in the source file in which it is defined. All other functions, whether they are given extern storage class explicitly or implicitly, are visible throughout all the source files that make up the program. If static storage class is desired, it must be declared on the first occurrence of a declaration (if any) of the function, and on the definition of the function.

Microsoft Specific

When the Microsoft extensions are enabled, a function originally declared without a storage class (or with extern storage class) is given static storage class if the function definition is in the same source file and if the definition explicitly specifies static storage class.

When compiling with the /Ze command-line option, functions declared within a block using the extern keyword have global visibility. This is not true when compiling with /Za. This feature should not be relied upon if portability of source code is a consideration. ♦


  Return Type

The return type of a function establishes the size and type of the value returned by the function and corresponds to the type-specifier in the syntax below:

Syntax

function-definition :
declaration-specifiers  (opt)  attribute-seq  (opt)  declarator declaration-list  (opt)
compound-statement	/* attribute-seq is Microsoft Specific */

declaration-specifiers :
storage-class-specifier declaration-specifiers  (opt)
type-specifier declaration-specifiers  (opt)
type-qualifier declaration-specifiers  (opt)

type-specifier :
void
char
short
int
long
float
double
signed
unsigned
struct-or-union-specifier
enum-specifier
typedef-name

The type-specifier can specify any fundamental, structure, or union type. If you do not include type-specifier, the return type int is assumed.

The return type given in the function definition must match the return type in declarations of the function elsewhere in the program. A function returns a value when a return statement containing an expression is executed. The expression is evaluated, converted to the return value type if necessary, and returned to the point at which the function was called. If a function is declared with return type void, a return statement containing an expression generates a warning and the expression is not evaluated.

The following examples illustrate function return values.

typedef struct
{
    char name[20];
    int id;
    long class;
} STUDENT;

/* Return type is STUDENT: */

STUDENT sortstu( STUDENT a, STUDENT b )
{
    return ( (a.id < b.id) ? a : b );
}

This example defines the STUDENT type with a typedef declaration and defines the function sortstu to have STUDENT return type. The function selects and returns one of its two structure arguments. In subsequent calls to the function, the compiler checks to make sure the argument types are STUDENT.

Note  Efficiency would be enhanced by passing pointers to the structure, rather than the entire structure.

char *smallstr( char s1[], char s2[] )
{
    int i;

    i = 0;
    while ( s1[i] != '\0' && s2[i] != '\0' )
        i++;
    if ( s1[i] == '\0' )
        return ( s1 );
    else
        return ( s2 );
}

This example defines a function returning a pointer to an array of characters. The function takes two character arrays (strings) as arguments and returns a pointer to the shorter of the two strings. A pointer to an array points to the first of the array elements and has its type; thus, the return type of the function is a pointer to type char.

You need not declare functions with int return type before you call them, although prototypes are recommended so that correct type checking for arguments and return values is enabled.


  Parameters

Arguments are names of values passed to a function by a function call. Parameters are the values the function expects to receive. In a function prototype, the parentheses following the function name contain a complete list of the function's parameters and their types. Parameter declarations specify the types, sizes, and identifiers of values stored in the parameters.

Syntax

function-definition :
declaration-specifiers  (opt)  attribute-seq  (opt)  declarator declaration-list  (opt)
compound-statement	/* attribute-seq is Microsoft Specific */

declarator :
pointer  (opt)  direct-declarator

direct-declarator :	/* A function declarator */
direct-declarator ( parameter-type-list )	/* New-style declarator */

parameter-type-list :	/* A parameter list */
parameter-list
parameter-list , ...

parameter-list :
parameter-declaration
parameter-list , parameter-declaration

parameter-declaration :
declaration-specifiers declarator
declaration-specifiers abstract-declarator  (opt)

The parameter-type-list is a sequence of parameter declarations separated by commas. The form of each parameter in a parameter list looks like this:

[register]  type-specifier [declarator]

Function parameters declared with the auto attribute generate errors. The identifiers of the parameters are used in the function body to refer to the values passed to the function. You can name the parameters in a prototype, but the names go out of scope at the end of the declaration. Therefore parameter names can be assigned the same way or differently in the function definition. These identifiers cannot be redefined in the outermost block of the function body, but they can be redefined in inner, nested blocks as though the parameter list were an enclosing block.

Each identifier in parameter-type-list must be preceded by its appropriate type specifier, as shown in this example:

void new( double x, double y, double z )
{
    /* Function body here */
}

If at least one parameter occurs in the parameter list, the list can end with a comma followed by three periods (, ...). This construction, called the "ellipsis notation," indicates a variable number of arguments to the function. (See »Calls with a Variable Number of Arguments«.) However, a call to the function must have at least as many arguments as there are parameters before the last comma.

If no arguments are to be passed to the function, the list of parameters is replaced by the keyword void. This use of void is distinct from its use as a type specifier.

The order and type of parameters, including any use of the ellipsis notation, must be the same in all the function declarations (if any) and in the function definition. The types of the arguments after usual arithmetic conversions must be assignment-compatible with the types of the corresponding parameters. (See »Usual Arithmetic Conversions« for information on arithmetic conversions.) Arguments following the ellipsis are not checked. A parameter can have any fundamental, structure, union, pointer, or array type.

The compiler performs the usual arithmetic conversions independently on each parameter and on each argument, if necessary. After conversion, no parameter is shorter than an int, and no parameter has float type unless the parameter type is explicitly specified as float in the prototype. This means, for example, that declaring a parameter as a char has the same effect as declaring it as an int.

16-Bit Specific

When the Microsoft-specific __near, __far, and __huge keywords appear in the declaration, the compiler may also convert pointer arguments to the function. The conversions performed depend on the default size of pointers in the program and the presence or absence of a list of argument types for the function. See »Assignment Conversions« for more information on pointer conversions.♦


  Function Body

A "function body" is a compound statement containing the statements that specify what the function does.

Syntax

function-definition :
declaration-specifiers  (opt)  attribute-seq  (opt)  declarator declaration-list  (opt)
compound-statement	/* attribute-seq is Microsoft Specific */

compound-statement :	/* The function body */
{ declaration-list  (opt)  statement-list  (opt)  }

Variables declared in a function body, "local variables," have auto storage class unless otherwise specified. When the function is called, storage is created for the local variables and local initializations are performed. Execution control passes to the first statement in compound-statement and continues until a return statement is executed or the end of the function body is encountered. Control then returns to the point at which the function was called.

A return statement containing an expression must be executed if the function is to return a value. The return value of a function is undefined if no return statement is executed or if the return statement does not include an expression.


  6.3  Function Prototypes

A function declaration precedes the function definition and specifies the name, return type, storage class, and other attributes of a function. To be a prototype, the function declaration must also establish types and identifiers for the function's arguments.

Syntax

declaration :
declaration-specifiers attribute-seq  (opt)  init-declarator-list  (opt)  ;
/* attribute-seq  (opt)  is Microsoft Specific */

declaration-specifiers :
storage-class-specifier declaration-specifiers  (opt)
type-specifier declaration-specifiers  (opt)
type-qualifier declaration-specifiers  (opt)

init-declarator-list :
init-declarator
init-declarator-list , init-declarator

init-declarator :
declarator
declarator = initializer

declarator :
pointer  (opt)  direct-declarator

direct-declarator :	/* A function declarator */
direct-declarator ( parameter-type-list )	/* New-style declarator */
direct-declarator ( identifier-list  (opt)  )	/* Obsolete-style declarator */

The prototype has the same form as the function definition, except that it is terminated by a semicolon immediately following the closing parenthesis and therefore has no body. In either case, the return type must agree with the return type specified in the function definition.

Function prototypes have the following important uses:

•	They establish the return type for functions that return types other than int. Although functions that return int values do not require prototypes, prototypes are recommended.

•	Without complete prototypes, standard conversions are made, but no attempt is made to check the type or number of arguments with the number of parameters.

•	Prototypes are used to initialize pointers to functions before those functions are defined.

•	The parameter list is used for checking the correspondence of arguments in the function call with the parameters in the function definition.

The converted type of each parameter determines the interpretation of the arguments that the function call places on the stack. A type mismatch between an argument and a parameter may cause the arguments on the stack to be misinterpreted. For example, on a 16-bit computer, if a 16-bit pointer is passed as an argument, then declared as a long parameter, the first 32 bits on the stack are interpreted as a long parameter. This error creates problems not only with the long parameter, but with any parameters that follow it. You can detect errors of this kind by declaring complete function prototypes for all functions.

A prototype establishes the attributes of a function so that calls to the function that precede its definition (or occur in other source files) can be checked for argument-type and return-type mismatches. For example, if you specify the static storage-class specifier in a prototype, you must also specify the static storage class in the function definition.

Complete parameter declarations (int a) can be mixed with abstract declarators (int) in the same declaration. For example, the following declaration is now legal:

int add( int a, int );

The prototype can include both the type of, and an identifier for, each expression that is passed as an argument. However, such identifiers have scope only until the end of the declaration. The prototype can also reflect the fact that the number of arguments is variable, or that no arguments are passed. Without such a list, mismatches may not be revealed, so the compiler cannot generate diagnostic messages concerning them. For more information on type checking, see »Arguments«.

Prototype scope in the Microsoft C compiler is now ANSI-compliant when compiling with the /Za command-line option. This means that if you declare a struct or union tag within a prototype, the tag is entered at that scope rather than at global scope. For example, when compiling with /Za for ANSI compliance, you can never call this function without getting a type mismatch error:

void func1( struct S * );

To correct your code, define or declare the struct or union at global scope before the function prototype:

struct S;
void func1( struct S * );

Under /Ze, the tag is still entered at global scope.


  6.4  Function Calls

A function call is an expression that passes control and arguments (if any) to a function and has the form

expression ( expression-list  (opt ) )

where expression is a function name or evaluates to a function address and expression-list is a list of expressions (separated by commas). The values of these latter expressions are the arguments passed to the function. If the function does not return a value, then you declare it to be a function that returns void.

If a declaration exists before the function call, but no information is given concerning the parameters, any undeclared arguments simply undergo the usual arithmetic conversions.

Note  The expressions in the function argument list can be evaluated in any order, so arguments whose values may be changed by side effects from another argument have undefined values. The sequence point defined by the function-call operator guarantees only that all side effects in the argument list are evaluated before control passes to the called function. (Note that the order in which arguments are pushed on the stack is a separate matter.) See »Sequence Points« for more information.

The only requirement in any function call is that the expression before the parentheses must evaluate to a function address. This means that a function can be called through any function-pointer expression.

This example illustrates function calls called from a switch statement:

main()
{
    /* Function prototypes */

    long lift( int ), step( int ), drop( int );
    void work( int number, long (*function)(int i) );

    int select, count;
    .
    .
    .
    select = 1;
    switch( select )
    {
        case 1: work( count, lift );
                break;

        case 2: work( count, step );
                break;

        case 3: work( count, drop );
                /* Fall through to next case */
        default:
                break;
    }
}

/* Function definition */

void work( int number, long (*function)(int i) )
{
    int i;
    long j;

    for ( i = j = 0; i < number; i++ )
            j += ( *function )( i );
}

In this example, the function call in main,

work( count, lift );

passes an integer variable, count, and the address of the function lift to the function work. Note that the function address is passed simply by giving the function identifier, since a function identifier evaluates to a pointer expression. To use a function identifier in this way, the function must be declared or defined before the identifier is used; otherwise, the identifier is not recognized. In this case, a prototype for work is given at the beginning of the main function.

The parameter function in work is declared to be a pointer to a function taking one int argument and returning a long value. The parentheses around the parameter name are required; without them, the declaration would specify a function returning a pointer to a long value.

The function work calls the selected function from inside the for loop by using the following function call:

( *function )( i );

One argument, i, is passed to the called function.


  Arguments

The arguments in a function call have this form:

expression ( expression-list ( opt ) )  /* Function call */

In a function call, expression-list is a list of expressions (separated by commas). The values of these latter expressions are the arguments passed to the function. If the function takes no arguments, expression-list should contain the keyword void.

An argument can be any value with fundamental, structure, union, or pointer type. All arguments are passed by value. This means a copy of the argument is assigned to the corresponding parameter. The function does not know the actual memory location of the argument passed. The function uses this copy without affecting the variable from which it was originally derived.

Although you cannot pass arrays or functions as arguments, you can pass pointers to these items. Pointers provide a way for a function to access a value by reference. Since a pointer to a variable holds the address of the variable, the function can use this address to access the value of the variable. Pointer arguments allow a function to access arrays and functions, even though arrays and functions cannot be passed as arguments.

The order in which arguments are evaluated can vary under different compilers and different optimization levels. However, the arguments and any side effects are completely evaluated before the function is entered. See »Side Effects« for information on side effects.

The expression-list in a function call is evaluated and the usual arithmetic conversions are performed on each argument in the function call. If a prototype is available, the resulting argument type is compared to the prototype's corresponding parameter. If they do not match, either a conversion is performed, or a diagnostic message is issued. The parameters also undergo the usual arithmetic conversions.

16-Bit Specific

If the __near, __far, and __huge keywords are used, conversions on pointer arguments may also be performed. See »Assignment Conversions« for more information. ♦

The number of expressions in expression-list must match the number of parameters, unless the function's prototype or definition explicitly specifies a variable number of arguments. In this case, the compiler checks as many arguments as there are type names in the list of parameters and converts them, if necessary, as described above. See the following section, »Calls with a Variable Number of Arguments«, for more information.

If the prototype's parameter list contains only the keyword void, the compiler expects zero arguments in the function call and zero parameters in the definition. A diagnostic message is issued if it finds any arguments.

This example uses pointers as arguments:

main()
{
    /* Function prototype */

    void swap( int *num1, int *num2 );
    int x, y;
    .
    .
    .
    swap( &x, &y );  /* Function call */
}

/* Function definition */

void swap( int *num1, int *num2 )
{
    int t;

    t = *num1;
    *num1 = *num2;
    *num2 = t;
}

In this example, the swap function is declared in main to have two arguments, represented respectively by identifiers num1 and num2, both of which are pointers to int values. The parameters num1 and num2 in the prototype-style definition are also declared as pointers to int type values.

In the function call

swap( &x, &y )

the address of x is stored in num1 and the address of y is stored in num2. Now two names, or "aliases," exist for the same location. References to *num1 and *num2 in swap are effectively references to x and y in main. The assignments within swap actually exchange the contents of x and y. Therefore, no return statement is necessary.

The compiler performs type checking on the arguments to swap because the prototype of swap includes argument types for each parameter. The identifiers within the parentheses of the prototype and definition can be the same or different. What is important is that the types of the arguments match those of the parameter lists in both the prototype and the definition.


  Calls with a Variable Number of Arguments

A partial parameter list can be terminated by the ellipsis notation, a comma followed by three periods (, ...), to indicate that there may be more arguments passed to the function, but no more information is given about them. Type checking is not performed on such arguments. At least one parameter must precede the ellipsis notation and the ellipsis notation must be the last token in the parameter list. Without the ellipsis notation, the behavior of a function is undefined if it receives parameters in addition to those declared in the parameter list.

To call a function with a variable number of arguments, simply specify any number of arguments in the function call. An example is the printf function from the C run-time library. The function call must include one argument for each type name declared in the parameter list or the list of argument types.

All the arguments specified in the function call are placed on the stack unless the __fastcall calling convention is specified. The number of parameters declared for the function determines how many of the arguments are taken from the stack and assigned to the parameters. You are responsible for retrieving any additional arguments from the stack and for determining how many arguments are present. The STDARGS.H file contains ANSI-style macros for accessing arguments of functions which take a variable number of arguments. Also, the XENIX®- style macros in VARARGS.H are still supported.

This sample declaration is for a function that calls a variable number of arguments:

int average( int first, ...);

Microsoft Specific

To maintain compatibility with previous versions of Microsoft C, a Microsoft extension to the ANSI C standard allows a comma without trailing periods (,) at the end of the list of parameters to indicate a variable number of arguments. However, it is recommended that code be changed to incorporate the ellipsis notation. ♦


  Recursive Functions

Any function in a C program can be called recursively; that is, it can call itself. The number of recursive calls is limited to the size of the stack. See Chapter 4 of the Build Tools User's Guide for information about linker options that set stack size. Each time the function is called, new storage is allocated for the parameters and for the auto and register variables so that their values in previous, unfinished calls are not overwritten. Parameters are only directly accessible to the instance of the function in which they are created. Previous parameters are not directly accessible to ensuing instances of the function.

Note that variables declared with static storage do not require new storage with each recursive call. Their storage exists for the lifetime of the program. Each reference to such a variable accesses the same storage area.

This example illustrates recursive calls:

int factorial( int num );      /* Function prototype */

void main()
{
    int result, number;
    .
    .
    .
    result = factorial( number );
}

int factorial( int num )      /* Function definition */
{
    .
    .
    .
    if ( ( num > 0 ) || ( num <= 10 ) )
        return( num * factorial( num - 1 ) );
}


  APPENDIX A  C Language Syntax Summary

This appendix gives the full description of the C language and the Microsoft-specific C language features. You can use the syntax notation in this appendix to determine the exact syntax for any language component. The explanation for the syntax appears in the section of this manual where a topic is discussed.

Note  This syntax summary is not part of the ANSI C standard, but is included for information only. Microsoft-specific syntax is noted in comments following the syntax.


  Definitions

Terminals are endpoints in a syntax definition. No other resolution is possible. Terminals include the set of reserved words and user-defined identifiers.

Nonterminals are placeholders in the syntax and are defined elsewhere in this syntax summary. Definitions can be recursive.

An optional component is indicated by the subscripted  (opt) . For example,

{ expression  (opt)  }

indicates an optional expression enclosed in curly braces.


  Conventions

The conventions use different font attributes for different components of the syntax. The symbols and fonts are as follows:

Attribute	Description
nonterminal	Italic type indicates nonterminals.
const	Terminals in bold type are literal reserved words and symbols that must be entered as shown. Characters in this context are always case sensitive.
(opt)	Nonterminals followed by  (opt)  are always optional.
(default typeface)	Characters in the set described or listed in this typeface can be used as terminals in C statements.
A colon (:) following a nonterminal introduces its definition. Alternative definitions are listed on separate lines, except when prefaced with the words "one of."


  Syntax Categories

The syntax categories are:

•	Lexical Grammar

•	»Tokens«

•	»Keywords«

•	»Identifiers«

•	»Constants«

•	»String Literals«

•	»Operators«

•	»Punctuators«

•	Phrase Structure Grammar

•	»Expressions«

•	»Declarations«

•	»Statements«

•	»External Definitions«


Tokens‹@›
  A.1  Lexical Grammar: Tokens

token :
keyword
identifier
constant
string-literal
operator
punctuator

preprocessing-token :
header-name
identifier
pp-number
character-constant
string-literal
operator
punctuator
each nonwhite-space character that cannot be one of the above

header-name :
< path-spec >
"path spec"

path-spec :
Legal file path

pp-number :
digit
. digit
pp-number digit
pp-number nondigit
pp-number e sign
pp-number E sign
pp-number .


Keywords
  A.1  Lexical Grammar: Keywords

keyword : one of

auto	break	case	char
const	continue	default	do
double	else	enum	extern
float	for	goto	if
int	long	register	return
short	signed	sizeof	static
struct	switch	typedef	union
unsigned	void	volatile	while


Identifiers
  A.1  Lexical Grammar: Identifiers

identifier :
nondigit
identifier nondigit
identifier digit

nondigit : one of
 _ a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z

digit : one of
0 1 2 3 4 5 6 7 8 9


Constants
  A.1  Lexical Grammar: Constants

constant :
floating-point-constant
integer-constant

enumeration-constant
character-constant

floating-point-constant :
fractional-constant exponent-part  (opt)  floating-suffix  (opt)
digit-sequence exponent-part floating-suffix  (opt)

fractional-constant :
digit-sequence  (opt)   . digit-sequence
digit-sequence  .

exponent-part :
e sign  (opt)  digit-sequence
E sign  (opt)  digit-sequence

sign :  one of
+  −

digit-sequence :
digit
digit-sequence digit

floating-suffix : one of
f  l  F  L

integer-constant :
decimal-constant integer-suffix  (opt)
octal-constant integer-suffix  (opt)
hexadecimal-constant integer-suffix  (opt)

decimal-constant :
nonzero-digit
decimal-constant digit

octal-constant :
0
octal-constant octal-digit

hexadecimal-constant :
0x hexadecimal-digit
0X hexadecimal-digit
hexadecimal-constant hexadecimal-digit

nonzero-digit : one of
1 2 3 4 5 6 7 8 9

octal-digit : one of
0 1 2 3 4 5 6 7

hexadecimal-digit : one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F

unsigned-suffix : one of
u U

long-suffix : one of
l L

character-constant :
'c-char-sequence'
L'c-char-sequence'

integer-suffix :
unsigned-suffix long-suffix ( )  (opt)
long-suffix unsigned-suffix ( )  (opt)

c-char-sequence :
c-char
c-char-sequence c-char

c-char :
Any member of the source character set except the single quotation mark ('),
     backslash (\), or newline character
escape-sequence

escape-sequence :
simple-escape-sequence
octal-escape-sequence
hexadecimal-escape-sequence

simple-escape-sequence : one of
\a  \b  \f  \n  \r  \t  \v
\'  \"  \\  \?

octal-escape-sequence :
\ octal-digit
\ octal-digit octal-digit
\ octal-digit octal-digit octal-digit

hexadecimal-escape-sequence :
\x hexadecimal-digit
hexadecimal-escape-sequence hexadecimal-digit


String Literals
  A.1  Lexical Grammar: String Literals

string-literal :
"s-char-sequence  (opt) "
L"s-char-sequence  (opt) "

s-char-sequence :
s-char
s-char-sequence s-char

s-char :
any member of the source character set except the double-quotation mark ("),
   backslash (\), or newline character
escape-sequence


Operators
  A.1  Lexical Grammar: Operators

operator : one of
[  ]    (  )   .   −>
++   −−     &   *   +   −   ~   !   sizeof
/   %   <<   >>   <  >   <=   >=   ==   !=   ^   |   &&   !!
?   :
=   *=   /=   %=   +=   −=   <<=   >>=   &=   ^=   |=
,   #   ##

assignment-operator : one of
     =   *=   /=   %=   +=   −=   <<=   >>=  &=   ^=   |=


Punctuators
  A.1  Lexical Grammar: Punctuators

punctuator : one of
     [ ]   ( )   { }   *   ,   :   =   ;   ...   #


Expressions
  A.2  Phrase Structure Grammar: Expressions

primary-expression :
     identifier
     constant
     string-literal
     ( expression )

expression :
     assignment-expression
     expression , assignment-expression

constant-expression :
     conditional-expression

conditional-expression :
     logical-OR-expression
     logical-OR-expression ? expression : conditional-expression

assignment-expression :
     conditional-expression
     unary-expression assignment-operator assignment-expression

postfix-expression :
     primary-expression
     postfix-expression [ expression ]
     postfix-expression ( argument-expression-list  (opt)  )
     postfix-expression . identifier
     postfix-expression −> identifier
     postfix-expression ++
     postfix-expression −−
     postfix-expression :> expression   /* Microsoft Specific */

argument-expression-list :
     assignment-expression
     argument-expression-list , assignment-expression

unary-expression :
     postfix-expression
     ++ unary-expression
     −− unary-expression
     unary-operator cast-expression
     sizeof unary-expression
     sizeof ( type-name )

unary-operator : one of
& * + − ~ !

cast-expression :
     unary-expression
     ( type-name ) cast-expression

multiplicative-expression :
     cast-expression
     multiplicative-expression * cast-expression
     multiplicative-expression / cast-expression
     multiplicative-expression % cast-expression

additive-expression :
     multiplicative-expression
     additive-expression + multiplicative-expression
     additive-expression − multiplicative-expression

shift-expression :
     additive-expression
     shift-expression << additive-expression
     shift-expression >> additive-expression

relational-expression :
     shift-expression
     relational-expression < shift-expression
     relational-expression > shift-expression
     relational-expression <= shift-expression
     relational-expression >= shift-expression

equality-expression :
     relational-expression
     equality-expression == relational-expression
     equality-expression != relational-expression

AND-expression :
     equality-expression
     AND-expression & equality-expression

exclusive-OR-expression :
     AND-expression
     exclusive-OR-expression ^ AND-expression

inclusive-OR-expression :
     exclusive-OR-expression
     inclusive-OR-expression | exclusive-OR-expression

logical-AND-expression :
     inclusive-OR-expression
     logical-AND-expression && inclusive-OR-expression

logical-OR-expression :
     logical-AND-expression
     logical-OR-expression || logical-AND-expression


Declarations
  A.2  Phrase Structure Grammar: Declarations

declaration :
declaration-specifiers attribute-seq  (opt ) init-declarator-list  (opt)  ;
/* attribute-seq is Microsoft Specific */

declaration-specifiers :
storage-class-specifier declaration-specifiers  (opt)
type-specifier declaration-specifiers  (opt)
type-qualifier declaration-specifiers  (opt)

attribute-seq :	/* attribute-seq is Microsoft Specific */
attribute attribute-seq  (opt
) attribute : one of	/* Microsoft Specific */

__asm	__based	__cdecl	__export
__far	__fastcall	__fortran	__huge
__inline	__interrupt	__loadds	__near
__pascal	__saveregs	__segment	__segname
__self	__stdcall
init-declarator-list :
init-declarator
init-declarator-list , init-declarator

init-declarator :
declarator
declarator = initializer  /* For scalar initialization */

storage-class-specifier :
auto
register
static
extern
typedef
__declspec ( extended-decl-modifier-seq )  /* Microsoft Specific */

type-specifier :
void
char
short
int
long
float
double
signed
unsigned
struct-or-union-specifier
enum-specifier
typedef-name

type-qualifier :
const
volatile

declarator :
pointer  (opt)  direct-declarator

direct-declarator :
identifier
( declarator )
direct-declarator [ constant-expression  (opt) ]
direct-declarator ( parameter-type-list )    /* New-style declarator */
direct-declarator ( identifier-list  (opt)  )       /* Obsolete-style declarator */

pointer :
* type-qualifier-list  (opt)
* type-qualifier-list  (opt)  pointer

parameter-type-list :                                   /* The parameter list */
     parameter-list
     parameter-list , ...

parameter-list :
     parameter-declaration
     parameter-list , parameter-declaration

type-qualifier-list :
type-qualifier
type-qualifier-list type-qualifier

enum-specifier :
enum identifier  (opt)  { enumerator-list }
enum identifier

enumerator-list :
enumerator
enumerator-list , enumerator

enumerator :
enumeration-constant
enumeration-constant = constant-expression

enumeration-constant :
identifier

struct-or-union-specifier :
struct-or-union identifier  (opt)  { struct-declaration-list }
struct-or-union identifier

struct-or-union :
struct
union

struct-declaration-list :
struct-declaration
struct-declaration-list struct-declaration

struct-declaration :
specifier-qualifier-list struct-declarator-list ;

specifier-qualifier-list :
type-specifier specifier-qualifier-list  (opt)
type-qualifier specifier-qualifier-list  (opt)

struct-declarator-list :
struct-declarator
struct-declarator-list , struct-declarator

struct-declarator :
declarator
type-specifier declarator  (opt)  : constant-expression

parameter-declaration :
declaration-specifiers declarator                     /* Named declarator */
declaration-specifiers abstract-declarator  (opt)   /* Anonymous declarator */

identifier-list :        /* For old-style declarator */
identifier
identifier-list , identifier

abstract-declarator :            /* Used with anonymous declarators */
pointer
pointer  (opt)  direct-abstract-declarator

direct-abstract-declarator :
( abstract-declarator )
direct-abstract-declarator  (opt)  [ constant-expression  (opt)  ]
direct-abstract-declarator  (opt)  ( parameter-type-list  (opt)  )

initializer :
assignment-expression
{ initializer-list }	/* For aggregate initialization */
{ initializer-list , }

initializer-list :
initializer
initializer-list , initializer

type-name :
specifier-qualifier-list abstract-declarator  (opt)

typedef-name :
identifier

extended-decl-modifier-seq :	/* Microsoft Specific */
extended-decl-modifier  (opt)
extended-decl-modifier-seq extended-decl-modifier

extended-decl-modifier :	/* Microsoft Specific */
thread
naked
dllimport
dllexport


Statements
  A.2  Phrase Structure Grammar: Statements

statement :
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
try-except-statement	/* Microsoft Specific */
try-finally-statement 	/* Microsoft Specific */

jump-statement :
goto identifier ;
continue;
break;
return expression  (opt)  ;

compound-statement :
{ declaration-list  (opt)  statement-list  (opt)  }

declaration-list :
declaration
declaration-list declaration

statement-list :
statement
statement-list statement

expression-statement :
expression  (opt)  ;

iteration-statement :
while ( expression ) statement
do statement while ( expression );
for ( expression  (opt)  ; expression  (opt)  ; expression  (opt)  ) statement

selection-statement :
if ( expression ) statement
if ( expression ) statement  else statement
switch ( expression ) statement

labeled-statement :
identifier : statement
case constant-expression : statement
default : statement

try-except-statement :    /* Microsoft Specific */
__try compound-statement
__except ( expression ) compound-statement

try-finally-statement :    /* Microsoft Specific */
__try compound-statement
__finally compound-statement


External Definitions
  A.2  Phrase Structure Grammar: External Definitions

translation-unit :
external-declaration
translation-unit external-declaration

external-declaration :         /* Allowed only at external (file) scope */
function-definition
declaration

function-definition :            /* Declarator here is the function declarator */
declaration-specifiers  (opt)  declarator declaration-list  (opt)  compound-statement


Implementation-Defined Behavior
  APPENDIX B  Implementation-Defined Behavior

ANSI X3.159-1989, American National Standard for Information Systems − Programming Language − C, contains an appendix called "Portability Issues." The ANSI appendix lists areas of the C language that ANSI leaves open to each particular implementation. This appendix describes how Microsoft C handles these implementation-defined areas of the C language.

This appendix follows the same order as the ANSI appendix. Each item covered includes references to the ANSI chapter and section that explains the implementation-defined behavior.

Note  This appendix describes the U.S. English-language version of the C compiler only. Implementations of Microsoft C for other languages may differ slightly.


Diagnostics‹@›
  B.1  Translation: Diagnostics

How a diagnostic is identified (2.1.1.3)

Microsoft C produces error messages in the form:

filename( line-number ) : diagnostic Cnumber message

where filename is the name of the source file in which the error was encountered; line-number is the line number at which the compiler detected the error; diagnostic is either "error" or "warning"; number is a unique four-digit number (preceded by a C, as noted in the syntax) that identifies the error or warning; message is an explanatory message.


Arguments to main‹@›
  B.2  Environment: Arguments to main

The semantics of the arguments to main (2.1.2.2.1)

In Microsoft C, the function called at program startup is called main. There is no prototype declared for main, and it can be defined with zero, two, or three parameters:

int main( void )
int main( int argc, char *argv[] )
int main( int argc, char *argv[], char *envp[] )

The third line above, where main accepts three parameters, is a Microsoft extension to the ANSI C standard. The third parameter, envp, is an array of pointers to environment variables. The envp array is terminated by a null pointer. See »The main Function and Program Execution« for more information about main and envp.

The variable argc never holds a negative value.

The array of strings ends with argv[argc], which contains a null pointer.

All elements of the argv array are pointers to strings.

A program invoked with no command-line arguments will receive a value of one for argc, as the name of the executable file is placed in argv[0]. (In MS-DOS versions prior to 3.0, the executable-file name is not available. The letter "C" is placed in argv[0].) Strings pointed to by argv[1] through argv[argc − 1] represent program parameters.

The parameters argc and argv are modifiable and retain their last-stored values between program startup and program termination.


Interactive Devices
  B.2  Environment: Interactive Devices

What constitutes an interactive device (2.1.2.3)

Microsoft C defines the keyboard and the display as interactive devices.


Significant Characters Without External Linkage‹@›
  B.3  Identifiers: Significant Characters Without External Linkage

The number of significant characters without external linkage (3.1.2)

Identifiers are significant to 247 characters. The compiler does not restrict the number of characters you can use in an identifier; it simply ignores any characters beyond the limit.


Significant Characters with External Linkage
  B.3  Identifiers: Significant Characters with External Linkage

The number of significant characters with external linkage (3.1.2)

Identifiers declared extern in programs compiled with Microsoft C are significant to 247 characters. You can modify this default to a smaller number using the /H (restrict length of external names) option.


Uppercase and Lowercase
  B.3  Identifiers: Uppercase and Lowercase

Whether case distinctions are significant (3.1.2)

Microsoft C treats identifiers within a compilation unit as case sensitive.

16-Bit Specific

Externally linked identifiers may or may not be case sensitive. For 16-bit targets, you can use the LINK /NOI option to force the 16-bit linker to treat identifiers as case sensitive. The default for the 16-bit linker is to ignore case.

The /Gc (generate Pascal-style function calls) option converts all external identifiers (including function names) to uppercase. The __pascal declarator performs the same operation on a function-by-function basis. ♦

32-Bit Specific

The 32-bit linker is case sensitive. You must specify all identifiers consistently according to case. ♦


The ASCII Character Set‹@›
  B.4  Characters: The ASCII Character Set

Members of source and execution character sets (2.2.1)

The source character set is the set of legal characters that can appear in source files. For Microsoft C, the source character set is the standard ASCII character set.

Warning  Because keyboard and console drivers can remap the character set, programs intended for international distribution should check the country code.


Multibyte Characters
  B.4  Characters: Multibyte Characters

Shift states for multibyte characters (2.2.1.2)

Multibyte characters are used by some implementations, including Microsoft C, to represent foreign-language characters not represented in the base character set. However, Microsoft C does not support any state-dependent encodings. Therefore, there are no shift states. See »Multibyte and Wide Characters« for more information.


Bits per Character
  B.4  Characters: Bits per Character

Number of bits in a character (2.2.4.2.1)

The number of bits in a character is represented by the manifest constant CHAR_BIT. The LIMITS.H file defines CHAR_BIT as 8.


Character Sets
  B.4  Characters: Character Sets

Mapping members of the source character set (3.1.3.4)

The source character set and execution character set include the ASCII characters listed in Table B.1. Escape sequences are also shown in Table B.1.

Table B.1    Escape Sequences

Escape Sequence	Character	ASCII Value
\a	Alert/bell	7
\b	Backspace	8
\f	Formfeed	12
\n	Newline	10
\r	Carriage return	13
\t	Horizontal tab	9
\v	Vertical tab	11
\"	Double quotation	34
\'	Single quotation	39
\\	Backslash	92


Unrepresented Character Constants
  B.4  Characters: Unrepresented Character Constants

The value of an integer character constant that contains a character or escape sequence not represented in the basic execution character set or the extended character set for a wide character constant (3.1.3.4)

There are no character constants or escape sequences that cannot be represented in the extended character set.


Wide Characters
  B.4  Characters: Wide Characters

The value of an integer character constant that contains more than one character or a wide character constant that contains more than one multibyte character (3.1.3.4)

The regular character constant, 'ab' has the integer value (int)0x6162. When there is more than one byte, previously read bytes are shifted left by the value of CHAR_BIT and the next byte is compared using the bitwise-OR operator with the low CHAR_BIT bits. The number of bytes in the multibyte character constant cannot exceed sizeof(int), which is 2 for 16-bit target code, 4 for 32-bit target code.

The multibyte character constant is read as above and this is converted to a wide-character constant using the mbtowc run-time function. If the result is not a valid wide-character constant, an error is issued. In any event, the number of bytes examined by the mbtowc function is limited to the value of MB_CUR_MAX.


Converting Multibyte Characters
  B.4  Characters: Converting Multibyte Characters

The current locale used to convert multibyte characters into corresponding wide characters (codes) for a wide character constant (3.1.3.4)

16-Bit Specific

Microsoft C supports only the "C" locale, which does not include any true multibyte characters. In the "C" locale, the mbtowc function maps from the ANSI [8859] character set to Unicode. ♦

32-Bit Specific

The current locale is the "C" locale by default. It can be changed with the setlocale library routine. The LC_CTYPE category of the current locale sets the current working code page, which determines correspondence and conversion between the multibyte and wide-character sets. The mbstowcs, wcstombs, mbtowc, and wctomb library routines provide direct mappings between the multibyte and wide-character sets. Also, many of the stream routines, such as the print, scan, get, and put families, automatically provide mappings between these two character sets. ♦


Range of char Values
  B.4  Characters: Range of char Values

Whether a "plain" char has the same range of values as a signed char or an unsigned char (3.2.1.1)

16-Bit Specific

All character values range from 0x00 to 0xFF, signed or unsigned. If a char is not explicitly marked as signed or unsigned, it defaults to the signed type. ♦

32-Bit Specific

All signed character values range from −128 to 127. All unsigned character values range from 0 to 255. ♦

The CL option /J changes the default from signed to unsigned.


Range of Integer Values‹@›
  B.5  Integers: Range of Integer Values

The representations and sets of values of the various types of integers (3.1.2.5)

Short integers contain 16 bits (two bytes). Long integers contain 32 bits (four bytes). Signed integers are represented in two's-complement form. The most-significant bit holds the sign: 1 for negative, 0 for positive and zero. The values are listed below:

Type	Minimum and Maximum
unsigned short	0 to 65535
signed short	−32768 to 32767
unsigned long	0 to 4294967295
signed long	−2147483648 to 2147483647


Demotion of Integers
  B.5  Integers: Demotion of Integers

The result of converting an integer to a shorter signed integer, or the result of converting an unsigned integer to a signed integer of equal length, if the value cannot be represented (3.2.1.2)

When a long integer is cast to a short, or a short is cast to a char, the least-significant bytes are retained.

For example, this line

short x = (short)0x12345678L;

assigns the value 0x5678 to x, and this line

char y = (char)0x1234;

assigns the value 0x34 to y.

When signed variables are converted to unsigned and vice versa, the bit patterns remain the same. For example, casting −2 (0xFE) to an unsigned value yields 254 (also 0xFE).


Signed Bitwise Operations
  B.5  Integers: Signed Bitwise Operations

The results of bitwise operations on signed integers (3.3)

Bitwise operations on signed integers work the same as bitwise operations on unsigned integers. For example,−16 & 99 can be expressed in binary as

  11111111 11110000
& 00000000 01100011
  _________________
  00000000 01100000

The result of the bitwise AND is 96.


Remainders
  B.5  Integers: Remainders

The sign of the remainder on integer division (3.3.5)

The sign of the remainder is the same as the sign of the dividend. For example,

 50 / -6 == -8
 50 % -6 ==  2
-50 /  6 == -8
-50 %  6 == -2


Right Shifts
  B.5  Integers: Right Shifts

The result of a right shift of a negative-value signed integral type (3.3.7)

Shifting a negative value to the right yields half the absolute value, rounded down. For example, −253 (binary 11111111 00000011) shifted right one bit produces −127 (binary 11111111 10000001). A positive 253 shifts right to produce +126.

Right shifts preserve the sign bit. When a signed integer shifts right, the most-significant bit remains set. When an unsigned integer shifts right, the most-significant bit is cleared.

In 16-bit and 32-bit targets, if 0xF000 is unsigned, the result is 0x7800.

32-Bit Specific

In 32-bit targets, if 0xF0000000 is signed, a right shift produces 0xF8000000. Shifting a positive number right 32 times produces 0xF0000000. Shifting a negative number right 32 times produces 0xFFFFFFFF. ♦

16-Bit Specific

In 16-bit targets, if 0xF000 is signed, a right shift produces 0xF800. Shifting a positive number right 16 times produces 0x0000. Shifting a negative number right 16 times produces 0xFFFF. ♦


Values‹@›
  B. 6  Floating-Point Math: Values

The representations and sets of values of the various types of floating-point numbers (3.1.2.5)

The float type contains 32 bits: 1 for the sign, 8 for the exponent, and 23 for the mantissa. Its range is +/− 3.4E38 with at least 7 digits of precision.

The double type contains 64 bits: 1 for the sign, 11 for the exponent, and 52 for the mantissa. Its range is +/− 1.7E308 with at least 15 digits of precision.

The long double type contains 80 bits: 1 for the sign, 15 for the exponent, and 64 for the mantissa. Its range is +/− 1.2E4932 with at least 19 digits of precision.

32-Bit Specific

The 32-bit compiler maps long double to type double. ♦


Casting Integers to Floating-Point Values
  B. 6  Floating-Point Math: Casting Integers to Floating-Point Values

The direction of truncation when an integral number is converted to a floating-point number that cannot exactly represent the original value (3.2.1.3)

When an integral number is cast to a floating-point value that cannot exactly represent the value, the value is rounded (up or down) to the nearest suitable value.

For example, casting an unsigned long (with 32 bits of precision) to a float (whose mantissa has 23 bits of precision) rounds the number to the nearest multiple of 256. The long values 4,294,966,913 to 4,294,967,167 are all rounded to the float value 4,294,967,040.


Truncation of Floating-Point Values
  B. 6  Floating-Point Math: Truncation of Floating-Point Values

The direction of truncation or rounding when a floating-point number is converted to a narrower floating-point number (3.2.1.4)

When an underflow occurs, the value of a floating-point variable is rounded down to zero. An overflow may cause a run-time error or it may produce an unpredictable value, depending on the optimizations specified.


Largest Array Size‹@›
  B.7  Arrays and Pointers: Largest Array Size

The type of integer required to hold the maximum size of an array—that is, the size of size_t (3.3.3.4, 4.1.1)

16-Bit Specific

The size_t typedef is an unsigned int, with the range 0x0000 to 0xFFFF. Huge arrays can exceed this limit if they contain more than 65,535 elements. Arithmetic operations on huge arrays should therefore cast size_t and the result of an arithmetic operation on pointers to unsigned long. ♦

32-Bit Specific

The size_t typedef is an unsigned int with the range 0x00000000 to 0x7CFFFFFF. ♦


Casting Pointers
  B.7  Arrays and Pointers: Casting Pointers

The result of casting a pointer to an integer or vice versa (3.3.4)

Near pointers are the same size as short integers; casting near to short (or short to near) has no immediate effect on the value.

Far pointers and huge pointers are the same size as long integers. Casting far/huge to long (or long to far/huge) has no immediate effect on the value.

When a near pointer is cast to a long, the 16-bit value is "normalized," which means the segment (usually DS) and offset are combined to produce a 32-bit memory location.

When a far or huge pointer is cast to a short, the long value is truncated to a short.

The compiler normalizes based pointers when necessary, unless the based pointer is a constant zero, in which case it is assumed to be a null pointer. See Chapter 13, "Writing Portable C Programs," of Programming Techniques for more information about based pointers.


Pointer Subtraction
  B.7  Arrays and Pointers: Pointer Subtraction

The type of integer required to hold the difference between two pointers to elements of the same array, ptrdiff_t (3.3.6, 4.1.1)

16-Bit Specific

A ptrdiff_t is a signed integer in the range −32,768 to 32,767, with one exception. Because huge pointers can address more than 64K of memory, subtracting one huge pointer from another can yield a result that is a long integer. The result of subtracting two huge pointers should be cast to a long.

The compiler normalizes based pointers when necessary. In most cases, based pointers are treated as far pointers. ♦

32-Bit Specific

A ptrdiff_t is a signed int in the range −4,294,967,296 to 4,294,967,295. ♦


Availability of Registers‹@›
  B.8  Registers: Availability of Registers

The extent to which objects can actually be placed in registers by use of the register storage-class specifier (3.5.1)

16-Bit Specific

Two registers, SI and DI, are available for 16-bit targets with Microsoft C. Register variables with a type that has 16 bits can be allocated in these registers. ♦

32-Bit Specific

The 32-bit compiler does not honor user requests for register variables. Instead, it makes it own choices when optimizing. ♦


Improper Access to a Union‹@›
  B.9  Structures, Unions, Enumerations, and Bit Fields: Improper Access to a Union

A member of a union object is accessed using a member of a different type (3.3.2.3)

If a union of two types is declared and one value is stored, but the union is accessed with the other type, the results are unreliable.

For example, a union of float and int is declared. A float value is stored, but the program later accesses the value as an int. In such a situation, the value would depend on the internal storage of float values. The integer value would not be reliable.


Padding and Alignment of Structure Members
  B.9  Structures, Unions, Enumerations, and Bit Fields: Padding and Alignment of Structure Members

The padding and alignment of members of structures and whether a bit field can straddle a storage-unit boundary (3.5.2.1)

Structure members are stored sequentially in the order in which they are declared: the first member has the lowest memory address and the last member the highest.

Every data object has an alignment-requirement. The alignment-requirement for all data except structures, unions, and arrays is either the size of the object or the current packing size (specified with either /Zp or the pack pragma, whichever is less). For structures, unions, and arrays, the alignment-requirement is the largest alignment-requirement of its members. Every object is allocated an offset so that

offset % alignment-requirement == 0

Adjacent bit fields are packed into the same 1-, 2-, or 4-byte allocation unit if the integral types are the same size and if the next bit field fits into the current allocation unit without crossing the boundary imposed by the common alignment requirements of the bit fields.


Sign of Bit Fields
  B.9  Structures, Unions, Enumerations, and Bit Fields: Sign of Bit Fields

Whether a "plain" int field is treated as a signed int bit field or as an unsigned int bit field (3.5.2.1)

Bit fields can be signed or unsigned. Plain bit fields are treated as signed.


Storage of Bit Fields
  B.9  Structures, Unions, Enumerations, and Bit Fields: Storage of Bit Fields

The order of allocation of bit fields within an int (3.5.2.1)

32-Bit Specific

Bit fields are allocated within a 32-bit integer from least-significant to most-significant bit. ♦

16-Bit Specific

Bit fields are allocated within a 16-bit integer from least-significant to most-significant bit. In the following code,

struct mybitfields
{
   unsigned a : 4;
   unsigned b : 5;
   unsigned c : 7;
} test;

void main( void )
{
   test.a = 2;
   test.b = 31;
   test.c = 0;
}

the bits for the integer 0x01F2 would be arranged as follows:

00000001 11110010
cccccccb bbbbaaaa

Since the 80x86 processors store the low byte of integer values before the high byte, the integer 0x01F2 above would be stored in physical memory as 0xF2 followed by 0x01. ♦


The enum Type
  B.9  Structures, Unions, Enumerations, and Bit Fields: The enum Type

The integer type chosen to represent the values of an enumeration type (3.5.2.2)

A variable declared as enum is an int.


Access to Volatile Objects‹@›
  B.10  Qualifiers: Access to Volatile Objects

What constitutes an access to an object that has volatile-qualified type (3.5.5.3)

Any reference to a volatile-qualified type is an access.


Maximum Number‹@›
  B.11  Declarators: Maximum Number

The maximum number of declarators that can modify an arithmetic, structure, or union type (3.5.4)

Microsoft C does not limit the number of declarators. The number is limited only by available memory.


Limits on Switch Statements‹@›
  B.12  Statements: Limits on Switch Statements

The maximum number of case values in a switch statement (3.6.4.2)

Microsoft C does not limit the number of case values in a switch statement. The number is limited only by available memory.


Character Constants and Conditional Inclusion‹@›
  B.13  Preprocessing Directives: Character Constants and Conditional Inclusion

Whether the value of a single-character character constant in a constant expression that controls conditional inclusion matches the value of the same character constant in the execution character set. Whether such a character constant can have a negative value (3.8.1)

The character set used in preprocessor statements is the same as the execution character set. The preprocessor recognizes negative character values.


Including Bracketed Filenames
  B.13  Preprocessing Directives: Including Bracketed Filenames

The method for locating includable source files (3.8.2)

For file specifications enclosed in angle brackets, the preprocessor does not search directories of the parent files. A "parent" file is the file that has the #include directive in it. Instead, it begins by searching for the file in the directories specified on the compiler command line following /I. If the /I option is not present or fails, the preprocessor uses the INCLUDE environment variable to find any include files within angle brackets. The INCLUDE environment variable can contain multiple paths separated by semicolons (;). If more than one directory appears as part of the /I option or within the INCLUDE environment variable, the preprocessor searches them in the order in which they appear.

See Chapter 1 of the Preprocessor Reference for more information.


Including Quoted Filenames
  B.13  Preprocessing Directives: Including Quoted Filenames

The support for quoted names for includable source files (3.8.2)

If you specify a complete, unambiguous path specification for the include file between two sets of double quotation marks (" "), the preprocessor searches only that path specification and ignores the standard directories.

For include files specified as #include "path-spec", directory searching begins with the directories of the parent file, then proceeds through the directories of any grandparent files. Thus, searching begins relative to the directory containing the source file currently being processed. If there is no grandparent file and the file has not been found, the search continues as if the filename were enclosed in angle brackets.

See Chapter 1 of the Preprocessor Reference for more information.


Character Sequences
  B.13  Preprocessing Directives: Character Sequences

The mapping of source file character sequences (3.8.2)

Preprocessor statements use the same character set as source file statements with the exception that escape sequences are not supported.

Thus, to specify a path for an include file, use only one backslash:

#include "path1\path2\myfile"

Within source code, two backslashes are necessary:

fil = fopen( "path1\\path2\\myfile", "rt" );


Pragmas
  B.13  Preprocessing Directives: Pragmas

The behavior on each recognized #pragma directive (3.8.6)

The following pragmas are defined for the Microsoft C compiler:

alloc_text	auto_inline	check_pointer	check_stack
code_seg	comment	data_seg	function
hdrstop	inline_depth	inline_recursion	intrinsic
linesize	message	native_caller	optimize
pack	page	pagesize	setlocale
skip	subtitle	title	warnin
See Chapter 2 of the Preprocessor Reference for more information.


Default Date and Time
  B.13  Preprocessing Directives: Default Date and Time

The definitions for _DATE_ and _TIME_ when, respectively, the date and time of translation are not available (3.8.8)

When the operating system does not provide the date and time of translation, the default values for _DATE_ and _TIME_ are May 03 1957 and 17:00:00".


NULL Macro‹@›
  B.14  Library Functions: NULL Macro

The null pointer constant to which the macro NULL expands (4.1.5)

Several include files define the NULL macro as ((void *)0).


Diagnostic Printed by the assert Function
  B.14  Library Functions: Diagnostic Printed by the assert Function

The diagnostic printed by and the termination behavior of the assert function (4.2)

The assert function prints a diagnostic message and calls the abort routine if the expression is false (0). The diagnostic message has the form

Assertion failed: expression, file filename, line linenumber

where filename is the name of the source file and linenumber is the line number of the assertion that failed in the source file. No action is taken if expression is true (nonzero).


Character Testing
  B.14  Library Functions: Character Testing

The sets of characters tested for by the isalnum, isalpha, iscntrl, islower, isprint, and isupper functions (4.3.1)

The following list describes these functions as they are implemented by the Microsoft C compilers.

Function	Tests For
isalnum	Characters 0 − 9, A−Z, a−z  ASCII 48−57, 65−90, 97−122
isalpha	Characters A−Z, a−z ASCII 65−90, 97−122
iscntrl	ASCII 0 −31, 127
islower	Characters a−z ASCII 97−122
isprint	Characters A−Z, a−z, 0 − 9, punctuation, space ASCII 32−126
isupper	Characters A−Z ASCII 65−90


Domain Errors
  B.14  Library Functions: Domain Errors

The values returned by the mathematics functions on domain errors (4.5.1)

The ERRNO.H file defines the domain error constant EDOM as 33.


Underflow of Floating-Point Values
  B.14  Library Functions: Underflow of Floating-Point Values

Whether the mathematics functions set the integer expression errno to the value of the macro ERANGE on underflow range errors (4.5.1)

A floating-point underflow does not set the expression errno to ERANGE. When a value approaches zero and eventually underflows, the value is set to zero.


The fmod Function
  B.14  Library Functions: The fmod Function

Whether a domain error occurs or zero is returned when the fmod function has a second argument of zero (4.5.6.4)

When the fmod function has a second argument of zero, the function returns zero.


The signal Function
  B.14  Library Functions: The signal Function

The set of signals for the signal function (4.7.1.1)

The first argument passed to signal must be one of the symbolic constants described in the Run-Time Library Reference for the signal function. The information in the Run-Time Library Reference also lists the operating mode support for each signal. The constants are also defined in SIGNAL.H.


Default Signals
  B.14  Library Functions: Default Signals

If the equivalent of signal (sig, SIG_DFL) is not executed prior to the call of a signal handler, the blocking of the signal that is performed (4.7.1.1)

Signals are set to their default status when a program begins running.


The SIGILL Signal
  B.14  Library Functions: The SIGILL Signal

Whether the default handling is reset if the SIGILL signal is received by a handler specified to the signal function (4.7.1.1)

SIGILL is not generated under MS-DOS. It is included for ANSI compatibility. MS-DOS does not provide a way for an application to regain control when an illegal instruction occurs. However, a user can issue a signal function and later trigger that signal via an explicit call to the raise function. As with all signals under MS-DOS, the signal handler is set to the default action (SIG_DFL) before the user's signal handler gets control.


Terminating Newline Characters
  B.14  Library Functions: Terminating Newline Characters

Whether the last line of a text stream requires a terminating newline character (4.9.2)

Stream functions recognize either new line or end of file as the terminating character for a line.


Blank Lines
  B.14  Library Functions: Blank Lines

Whether space characters that are written out to a text stream immediately before a newline character appear when read in (4.9.2)

Space characters are preserved.


Null Characters
  B.14  Library Functions: Null Characters

The number of null characters that can be appended to data written to a binary stream (4.9.2)

Any number of null characters can be appended to a binary stream.


File Position in Append Mode
  B.14  Library Functions: File Position in Append Mode

Whether the file position indicator of an append mode stream is initially positioned at the beginning or end of the file (4.9.3)

When a file is opened in append mode, the file-position indicator initially points to the end of the file.


Truncation of Text Files
  B.14  Library Functions: Truncation of Text Files

Whether a write on a text stream causes the associated file to be truncated beyond that point (4.9.3)

Writing to a text stream does not truncate the file beyond that point.


File Buffering
  B.14  Library Functions: File Buffering

The characteristics of file buffering (4.9.3)

Disk files accessed through standard I/O functions are fully buffered. By default, the buffer holds 512 bytes. Some of the low-level MS-DOS and BIOS functions (all of which are non-ANSI and 16-bit specific) are unbuffered.


Zero-Length Files
  B.14  Library Functions: Zero-Length Files

Whether a zero-length file actually exists (4.9.3)

Files with a length of zero are permitted.


Filenames
  B.14  Library Functions: Filenames

The rules for composing valid file names (4.9.3)

A file specification can include an optional drive letter (always followed by a colon), a series of optional directory names (separated by backslashes), and a filename.

Filenames and directory names can contain up to eight characters followed by a period and a three-character extension. Case is ignored. The wildcards * and ? are not permitted within the name or extension.


File Access Limits
  B.14  Library Functions: File Access Limits

Whether the same file can be open multiple times (4.9.3)

Opening a file that is already open is not permitted.


Deleting Open Files
  B.14  Library Functions: Deleting Open Files

The effect of the remove function on an open file (4.9.4.1)

The remove function deletes a file, even if the file is open.


Renaming with a Name That Exists
  B.14  Library Functions: Renaming with a Name That Exists

The effect if a file with the new name exists prior to a call to the rename function (4.9.4.2)

If you attempt to rename a file using a name that exists, the rename function fails and returns an error code.


Printing Pointer Values
  B.14  Library Functions: Printing Pointer Values

The output for %p conversion in the fprintf function (4.9.6.1)

Microsoft C supports three types of pointer conversions: %p (a pointer), %lp (a 32-bit far pointer), and %hp (a 16-bit near pointer).

The fprintf function produces hexadecimal values of the form XXXX (an offset) for near pointers or XXXX:XXXX (a segment plus an offset, separated by a colon) for far pointers. The output for %p depends on the memory model in use.


Reading Pointer Values
  B.14  Library Functions: Reading Pointer Values

The input for %p conversion in the fscanf function (4.9.6.2)

When the %p format character is specified, the fscanf function converts pointers from hexadecimal ASCII values into the correct address.


Reading Ranges
  B.14  Library Functions: Reading Ranges

The interpretation of a dash (−) character that is neither the first nor the last character in the scanlist for % [ conversion in the fscanf function (4.9.6.2)

The following line

fscanf( fileptr, "%[A-Z]", strptr);

reads any number of characters in the range A−Z into the string to which strptr points.


File Position Errors
  B.14  Library Functions: File Position Errors

The value to which the macro errno is set by the fgetpos or ftell function on failure (4.9.9.1, 4.9.9.4)

When fgetpos or ftell fails, errno is set to the manifest constant EINVAL if the position is invalid or EBADF if the file number is bad. The constants are defined in ERRNO.H.


Messages Generated by the perror Function
  B.14  Library Functions: Messages Generated by the perror Function

The messages generated by the perror function (4.9.10.4)

The perror function generates these messages:

0  Error 0
1
2  No such file or directory
3
4
5
6
7  Arg list too long
8  Exec format error
9  Bad file number
10
11
12 Not enough core
13 Permission denied
14
15
16
17 File exists
18 Cross-device link
19
20
21
22 Invalid argument
23
24 Too many open files
25
26
27
28 No space left on device
29
30
31
32
33 Math argument
34 Result too large
35
36 Resource deadlock would occur


Allocating Zero Memory
  B.14  Library Functions: Allocating Zero Memory

The behavior of the calloc, malloc, or realloc function if the size requested is zero (4.10.3)

The calloc, malloc, and realloc functions accept zero as an argument. No actual memory is allocated, but a valid pointer is returned and the memory block can be modified later by realloc.


The abort Function
  B.14  Library Functions: The abort Function

The behavior of the abort function with regard to open and temporary files (4.10.4.1)

The abort function does not close files that are open or temporary. It does not flush stream buffers.


The atexit Function
  B.14  Library Functions: The atexit Function

The status returned by the atexit function if the value of the argument is other than zero, EXIT_SUCCESS, or EXIT_FAILURE (4.10.4.3)

The atexit function returns zero if successful, or a nonzero value if unsuccessful.


Environment Names
  B.14  Library Functions: Environment Names

The set of environment names and the method for altering the environment list used by the getenv function (4.10.4.4)

The set of environment names is unlimited.

To change environment variables from within a C program, call the _putenv function. To change environment variables from the MS-DOS command line, use the SET command (for example, SET LIB = D:\ LIBS).

Environment variables exist only as long as their host copy of MS-DOS is running. For example, the line

system( SET LIB = D:\LIBS );

would run a copy of MS-DOS, set the environment variable LIB, and return to the C program, exiting the secondary copy of MS-DOS. Exiting that copy of MS-DOS removes the temporary environment variable LIB.

Likewise, changes made by the _putenv function last only until the program ends.


The system Function
  B.14  Library Functions: The system Function

The contents and mode of execution of the string by the system function (4.10.4.5)

The system function executes an internal operating system command, or an .EXE, .COM, or .BAT file from within a C program rather than from the command line.

16-Bit Specific

The system function examines the COMSPEC environment variable to find the command interpreter, which is typically COMMAND.COM in MS-DOS. The system function then passes the argument string to the command interpreter. ♦

32-Bit Specific

The system function finds the command interpreter, which is typically CMD.EXE in the Windows NT operating system. The system function then passes the argument string to the command interpreter. ♦


The strerror Function
  B.14  Library Functions: The strerror Function

The contents of the error message strings returned by the strerror function (4.11.6.2)

The strerror function generates these messages:

0   Error 0
1
2   No such file or directory
3
4
5
6
7   Arg list too long
8   Exec format error
9   Bad file number
10
11
12  Not enough core
13  Permission denied
14
15
16
17  File exists
18  Cross-device link
19
20
21
22  Invalid argument
23
24  Too many open files
25
26
27
28  No space left on device
29
30
31
32
33  Math argument
34  Result too large
35
36  Resource deadlock would occur


The Time Zone
  B.14  Library Functions: The Time Zone

The local time zone and Daylight Saving Time (4.12.1)

The local time zone is Pacific Standard Time. Microsoft C supports Daylight Saving Time.


The clock Function
  B.14  Library Functions: The clock Function

The era for the clock function (4.12.2.1)

The clock function's era begins (with a value of 0) when the C program starts to execute. It returns times measured in 1/CLOCKS_PER_SEC (which equals 1/1000 for Microsoft C).