Copyright: Copyright ® 1993 Microsoft Corp.


 Visual C++ 1.0 for Windows NT Knowledge Base

Prepared July 08, 1993

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 App Studio

 C/C++

 Utilities

Win32 Topics

 Base

 User

 GDI

 Win32s

THE INFORMATION IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES EITHER EXPRESSED OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS, OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FORGOING EXCLUSION OR LIMITATION MAY NOT APPLY.


Visual Workbench for Windows NT
 Visual C++ 1.0 for Windows NT Knowledge Base

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 INF: Specifying Shared and Nonshared Data in a DLL

 INF: Dynamically Loading Dynamic-Link Libraries in Windows NT

 INF: Retrieving Windows NT Executable File Header Information

 INF: Specifying Icons for Console Applications in Windows NT

 INF: Cross-Platform Application Development in Windows NT

 INF: Sample Code Demonstrates Win32 Debugging API

 INF: Exporting Callback Functions

 INF: Macros to Facilitate Porting Applications to Windows NT

 INF: Sample Code Demonstrates Simple Dynamic-Link Library

 PRB: No Symbolic Information for Local Variables

 INF: Installing Visual C++ for Multiple Users on One Machine

 App Studio

 C/C++

 Utilities

Win32 Topics

 Base

 User

 GDI

 Win32s


App Studio
 Visual C++ 1.0 for Windows NT Knowledge Base

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 App Studio

 INF: Printing the Image of a Dialog Box

 INF: COMMON.RES Provides Common Bitmaps, Cursors, and Icons

 PRB: RW2002 Error From Long Resource Identifier

 INF: Converting an RC File to Use Microsoft Foundation Classes

 C/C++

 Utilities

Win32 Topics

 Base

 User

 GDI

 Win32s


C/C++
 Visual C++ 1.0 for Windows NT Knowledge Base

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 App Studio

 C/C++

 PRB: tan(pi/2) Returns Value, Causes No Error

 INF: Using malloc() and _fmalloc() in an Application

 PRB: Rounding Error Casting Double to Long

 INF: Jumping into the Middle of a For Loop Is Not Recommended

 INF: Common Programming Errors in the C Language

 PRB: "Invalid Object Module" Error Usually From Old LINK

 INF: Specify Compiler Options Before Source File Name

 PRB: spawnl() Fails in Noncurrent Directory

 PRB: fseek() Function Moves to Unexpected Location in File

 PRB: R6002 From Floating-Point I/O without Floating-Point Math

 INF: Sending Output to a Printer

 INF: C Run-time Library History and Naming Conventions

 INF: qsort() Can Sort Data Structures Based on Multiple Fields

 INF: printf() Default Floating-Point Precision is 6 Decimals

 INF: Using fopen() to Append Data to File Terminated w/ CTRL+Z

 PRB: rename() Function May Fail Unexpectedly

 INF: Initializing Bitfields as Integers in C

 INF: C4061 Long/Short Mismatch in Argument

 INF: sizeof() Function Returns unsigned Instead of int

 PRB: fscanf() Fails to Read Consecutive Lines

 INF: Storage Types of Integer Constant Changed in C 6.0

 INF: LIB32.EXE Converts Object Files to COFF Format

 INF: Stack Checking for Windows NT Programs

 PRB: Using Windows NT PDK Header Files in Visual C++

 PRB: Fatal Error CK1017 Using Precompiled Headers

 Utilities

Win32 Topics

 Base

 User

 GDI

 Win32s


Utilities
 Visual C++ 1.0 for Windows NT Knowledge Base

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 App Studio

 C/C++

 Utilities

 INF: Cannot Use /2 Switch for Dual-Monitor Debugging on PS/2

 INF: Using a Debugging Terminal with CodeView

 INF: Use /Zi to Compile Commands Invoked with "?" Command

 INF: Returning Control to CodeView

 INF: CodeView Skips Over a Line of Source Code

 INF: CodeView Search String Length Limited to 19-23 Characters

 Label-Finding Command Does Whole Word Search, Not Text Search

 Dual-Monitor Setup Requires 8-Bit Data Paths for Both Monitors

 PRB: L4001 Warning May Be Caused by Using Incorrect Linker

 INF: Differences Between LINK and LINK32

 PRB: Upper Left Corner of CodeView Screen Displays "a"

 PRB: PRF1621 Error from Profiler for Windows NT

Win32 Topics

 Base

 User

 GDI

 Win32s


Base
 Visual C++ 1.0 for Windows NT Knowledge Base

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 App Studio

 C/C++

 Utilities

Win32 Topics

 Base

 INF: Objects Inherited Through a CreateProcess Call

 INF: NT Consoles Do Not Support ANSI Escape Sequences

 INF: Windowed and Full-Screen Console I/O Supported

 INF: Byte-Ordering in a Data Packet Under NDIS

 INF: AllocConsole() Necessary to Get Valid Handles

 INF: How to Specify Shared and Nonshared Data in a DLL

 INF: Apps Should Wait to Free/Re-use WriteFileEx's Buffer

 INF: CreateFile() Using CONOUT$ or CONIN$

 INF: Exporting Data from a DLL

 INF: Dynamic Loading of DLLs Under Windows NT

 INF: Win32 Priority Class Mechanism and the START Command

 INF: Creating Windows in Threads

 INF: Two Types of Priority Control Added

 INF: Initiating an Unwind in an Exception Handler

 INF: Icons for Console Applications

 PRB: Return Values of Performance APIs

 INF: Sharing Win32 Services

 INF: Determining Whether Windows NT Is Running

 INF: New DLL: LOCALMON.DLL

 INF: Distributed Computing Environment (DCE) Compliance

 INF: Process Will Not Terminate Unless System Is In User-mode

 INF: Alternatives to Using GetProcAddress With LoadLibrary

 INF: Use WSAAsyncSelect to Clear Message Queue

 INF: Four New Win32 Memory-Handling APIs

 INF: Secure Erasure Under Windows NT

 INF: Access to Display from Win32 Services

 INF: Thread Local Storage Overview

 INF: Physical Memory Limits Number of Processes/Threads

 INF: PAGE_READONLY May Be Used as Discardable Memory

 INF: Named Pipes Under WOW

 INF: Maximum GlobalAddAtom() String Size Is 32K Characters

 INF: VirtualLock() Only Locks Pages into Working Set

 INF: Reducing the Count on a Semaphore Object

 INF: Trapping Floating-Point Exceptions Under NT

 INF: FormatMessage() Converts GetLastError() Codes

 INF: FlushViewOfFile() on Remote Files

 INF: Default Stack in Win32 Applications

 PRB: Code in DLL Causes Access Violation C00000005

 INF: CTRL+C Exception Handling Under WinDbg

 PRB: New Parameter for the CreateService() API

 INF: The Use of the SetLastErrorEx() API

 INF: Windows NT Virtual Memory Manager Uses FIFO

 PRB: Unexpected Result of SetFilePointer() with Devices

 INF: Limit on the Number of Bytes Written Asynchronously

 INF: Using GMEM_DDESHARE in Win32 Programming

 INF: Preventing the Console from Disappearing

 INF: Performing a Clear Screen (CLS) in a Console Application

 PRB: SetConsoleOutputCP() Not Functional

 INF: Detecting Windows NT from a DOS Application

 INF: Restriction on Named-Pipe Names

 INF: Replacing the Shell (Program Manager)

 INF: CPU Quota Limits Not Enforced

 User

 GDI

 Win32s


User
 Visual C++ 1.0 for Windows NT Knowledge Base

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 App Studio

 C/C++

 Utilities

Win32 Topics

 Base

 User

 INF: Global Classes in Win32

 INF: Use of DLGINCLUDE in Resource Files

 INF: Multiple Desktops Under Windows NT

 INF: DDEML Application-Instance IDs Are Thread Local

 INF: Freeing PackDDElParam() Memory

 INF: Clarification of COMMPROP Max?xQueue Members

 INF: OpenComm() and Related Flags Obsolete Under Win32

 INF: Distinguishing Between Keyboard ENTER and Keypad ENTER

 PRB: Setting Hooks Locally or Globally

 INF: SetActiveWindow() and SetForegroundWindow() Clarification

 PRB: AttachThreadInput() Resets Keyboard State

 INF: System Versus User Locale Identifiers

 GDI

 Win32s


GDI
 Visual C++ 1.0 for Windows NT Knowledge Base

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 App Studio

 C/C++

 Utilities

Win32 Topics

 Base

 User

 GDI

 INF: Transparent Blts in Windows NT

 INF: Using DocumentProperties() Instead of ExtDeviceMode()

 INF: PSTR's in OUTLINETEXTMETRIC Structure

 PRB: IsGdiObject() Is Not a Part of the Win32 API

 INF: Use of DocumentProperties() vs. ExtDeviceMode()

 INF: Font-Related APIs & Structures Removed from Win32/NT

 INF: Device Contexts: Using Across Threads

 INF: 16 and 32 Bits-Per-Pel Bitmap Formats

 INF: Advantages of Device-Dependent Bitmaps

 INF: Set/ModifyWorldTransform() Requires SetGraphicsMode()

 INF: Use 16-Bit .FON Files for Cross-Platform Compatibility

 Win32s


Win32s
 Visual C++ 1.0 for Windows NT Knowledge Base

Visual C++ version 1.0 for Windows NT

 Visual Workbench for Windows NT

 App Studio

 C/C++

 Utilities

Win32 Topics

 Base

 User

 GDI

 Win32s

 INF: Description of Win32s API

 INF: Win32s Stacks Limited to 128K

 INF: Calling a Win32 DLL from a Windows 3.x Application

 INF: Use 16-Bit .FON Files for Cross-Platform Compatibility

 INF: Support for Sleep() on Win32s

 INF: Win32s Translated Pointers Guaranteed for 32K


INF: Specifying Shared and Nonshared Data in a DLL

Article ID: Q100634

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

To create a new named section in an executable file, use the #pragma

data_seg directive. You can use this functionality to store both

shared and nonshared data in a dynamic-link library (DLL). Specify the

sharing attributes for the named data section in the DLL's module

definition (.DEF) file.

More Information:

The text below provides an example of defining a named data section in

a DLL. The first line directs the compiler to place all the data

declared in this section into the MYSEC data segment. Therefore, the

iSharedVar variable is stored in the MYSEC segment. By default, data

is nonshared.

Note that you must initialize all data in the named section. The

data_seg pragma applies only to initialized data.

The "#pragma data_seg()" line resets allocation to the default data

section.

Sample Code

-----------

   #pragma data_seg("MYSEC")

   int iSharedVar = 0;

   #pragma data_seg()

The following module definition file example supports the shared and

nonshared sections. This definition specifies that the default section

MYSEC is shared. Because the default data section is nonshared by

default, any data not in MYSEC is nonshared.

   LIBRARY

   SECTIONS

     MYSEC READ WRITE SHARED

   EXPORTS

    ...

Additional reference words: 1.00


INF: Dynamically Loading Dynamic-Link Libraries in Windows NT

Article ID: Q100635

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

When you use the LoadLibrary() function in 16-bit Windows or in OS/2,

the operating system loads the specified dynamic-link library (DLL)

only once. Therefore, the DLL has the same address in every process.

However, dynamic loading of DLLs works differently in Windows NT.

The operating system loads a DLL separately for each process because

each application has its own address space in Windows NT; the address

space is shared in 16-bit Windows and in OS/2. Because the operating

system must map pages into the address space for each process, the DLL

may be loaded at different addresses in different processes. The

memory manager optimizes loading DLLs such that if two processes share

the same pages from the same DLL image, they share the same physical

memory.

Each DLL has a preferred base address, specified at link time. If the

address space range from the preferred base address to the base

address plus the image size is not available, then the operating

system loads the DLL somewhere else in memory and applies fixups to

its addresses. There is no method to specify the load address at load

time.

To summarize, the system performs the following steps at load time:

1. Examines the image and determines its preferred base address and

   required size.

2. Finds the address space required and maps the image, copy-on-write,

   from the file.

3. Applies internal fixups if the image is not at its preferred base

   address.

4. Fixes up all dynamic link imports by placing the correct address

   for each imported function into the appropriate entry of the Import

   Address Table. This table stores 32-bit addresses contiguously; to

   store up to 1024 imported functions requires it to dirty only one

   page of memory.

More Information:

The pages that contain code are shared, using a copy-on-write

protection scheme. Copy-on-write means that a page is read-only;

however, if a process writes to the page and access violation does not

occur. Instead, the memory manager makes a private copy of the page

for the application's use and allows the write to proceed. For

example, if two processes start from the same .EXE file, each process

initially has all pages mapped from the .EXE file copy-on-write. As

the two processes proceed to modify pages, each one receives a private

copy of the modified pages. The memory manager is free to optimize

unmodified pages and to map the same physical memory into the address

space of both processes. Modified pages are swapped to and from the

page file instead of the .EXE file.

Two types of fixups are available. The first is used for the address

of an imported function. According to the Portable Executable

specification, this type of fixup is stored in the Import Address

Table (IAT), an array of 32-bit function pointers, one for each

imported function. The IAT has its own page or pages because it is

always modified. A call to an imported function is actually an

indirect call through the appropriate entry in the IAT. When an image

is loaded at its preferred base address, imported function fixups are

the only fixups required.

Note that an optimization is available whereby each import library

exports a 32-bit number that corresponds with each function in

addition to any name or ordinal number. This serves as a "hint" to

speed the fixups performed at load time. If the hints in the

application and in the loaded DLL do not match, the loader performs a

binary search based on the function name.

The other fixup type is required for references to code or data in the

image when the image is loaded somewhere other than at its preferred

base address. When the memory manager removes a page from memory, it

checks to see of the page has been modified. If not, the page retains

its copy-on-write mapping and it can be discarded from memory.

Otherwise, it must be written to the page file so the modified page

can be recovered from the page file rather than from the executable

image file.

Even if an application calls LoadLibrary() for a DLL more than once,

the DLL entry point, DllEntry(), is called only once and only one

DLL_PROCESS_ATTACH entry is created. Similarly, if the application

calls FreeLibrary() more than once, DLL_THREAD_DETACH occurs only for

the call in which the DLL reference count returns to zero.

Global instance data for the DLL is stored on a per-process basis

(only one data set per process). If it is necessary to store global

instance data for each LoadLibrary() call performed in one process,

consider using thread local storage (TLS) as an alternative. If you

use multiple threads of execution, TLS provides unique data storage

for each ThreadID value. This process requires very little overhead

for the DLL; it must only create a global TLS index at process

initialization. At thread initialization, use GlobalAlloc(),

HeapAlloc(), LocalAlloc(), functions in the C run-time library, or

another method to allocate a block of memory and call the

TlsSetValue() function to store a pointer to the memory using the

global TLS index value. Win32 internally stores each thread's pointer

indexed by TLS index and ThreadID to provide thread-specific storage.

Additional reference words: 1.00


INF: Retrieving Windows NT Executable File Header Information

Article ID: Q100636

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The EXEHDR program displays the information in the executable file

header for applications developed for the MS-DOS, OS/2, and Microsoft

Windows operating systems. The following command retrieves header

information for an executable file (.EXE or .DLL filename extension)

named <filename> developed for Microsoft Windows NT:

   dumpbin -headers <filename>

To obtain information about exported and imported symbols, use one of

the following commands:

   dumpbin -exports <filename>

   dumpbin -imports <filename>

Additional reference words: 1.00


INF: Specifying Icons for Console Applications in Windows NT

Article ID: Q100637

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

In the OS/2 operating system, when you add an application to a program

group and an icon (.ICO) file is available that has the same base name

as the application, OS/2 displays the icon in the group file. This

process does not occur automatically in Microsoft Windows NT; the

system displays a generic icon for the item even when an icon with the

same base name is also present.

To specify the icon to appear in the program group, perform the

following three steps:

1. Create a resource (.RC) file that contains an ICON statement, such

   as the following:

      ConApp ICON ConApp.ICO

2. Use the resource compiler (RC.EXE) to compile the resource file. In

   the Visual Workbench, just add the .RC file to the list of files in

   the project.

3. Link the compiled resource file into the application's executable

   file.

Unlike the resource compiler provided with the 16-bit Windows

development system, RC does not include compiled resources into the

executable file or specify the execution environment for the

application. The linker recognizes compiled resource files and

includes them in the executable file.

More Information:

If you start an application by clicking its icon in Program Manager or

by running it from the File menu in Program Manager and minimize the

application, the system displays the icon specified in the resource

file.

If you start the application from the MS-DOS prompt and minimize the

application, the system displays the icon used for the MS-DOS prompt.

Additional reference words: 1.00


INF: Cross-Platform Application Development in Windows NT

Article ID: Q100638

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

At present, three hardware platforms support developing Win32

applications: Intel 386 or later, MIPS R4000, and DEC Alpha. The text

below deals with the issues involved with developing applications for

all of these platforms simultaneously.

Due to the disparate nature of these hardware platforms, binary

compatibility is not a viable option. Therefore, Win32 provides source

code compatibility. You can create a version of your application for

each CPU by recompiling the source code.

However, Visual C++ for Windows NT does not support cross-compiling at

this time. Therefore, to develop applications for each hardware

platform, you must compile the code with the tools available for each

platform and, at present, development and debugging options across

environments are limited.

Be careful not to confuse source compatibility across hardware

platforms (Intel, MIPS, Alpha) with binary compatibility across

application execution environments (Win16, Win32). Win32 supports

binary compatibility between application execution environments on the

same hardware platform, through emulation. For example, a Win16

application developed for Intel hardware can run without modification

on an Intel machine running Windows NT and, with the appropriate

Win32s dynamic-link libraries (DLLs) and virtual devices (VxDs), a

Win32 application developed for Intel hardware can run without

modification on an Intel machine running 16-bit Windows 3.1.

Additional reference words: 1.00


INF: Sample Code Demonstrates Win32 Debugging API

Article ID: Q100641

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The Debug Event Browser (DEB) sample demonstrates the Win32 debugging

application programming interface (API) in Windows NT. The sample acts

as a debugger for a newly-created process to debug or it attaches to

the currently active process.

DEB is not a debugger in the traditional sense; it is a browser that

displays the debug events and their properties as they occur. It also

invokes the default handlers supplied either by the application being

debugged or by the system. DEB imposes only minimal debug event

handling, it displays the debug events and allows the application

being debugged to continue its normal course of execution.

The sample is source code compatible for both the Intel and MIPS R4000

Windows NT platforms.

More Information:

The text below lists the files that comprise the DEB sample and the

purpose of each file:

   DEB.BMP        DEB bitmap used by DEB.RTF

   DEB.DEF        DEB module definition file

   DEB.DLG        DEB dialog resource script file

   DEB.H          DEB ID values and user message defines

   DEB.HPJ        DEB help project file

   DEB.ICO        DEB main icon

   DEB1.ICO       DEB animated icon number one

   ...

   DEB8.ICO       DEB animated icon number eight

   DEB.RC         DEB resource file

   DEB.RTF        DEB help topic file

   DEBDEBUG.C     DEB debug support functions

   DEBDEBUG.H     DEB debug support functions header

   DEBMAIN.C      DEB main module - WinMain and callbacks

   DEBMAIN.H      DEB main module header

   DEBMISC.C      DEB miscellaneous support functions

   DEBMISC.H      DEB miscellaneous support functions header

   LINKLIST.C     Ordered doubled-linked list library

   LINKLIST.H     Ordered doubled-linked list library header

   MAKEFILE       MAKE/NMAKE file for the entire sample

   README.TXT     Listing of source code files

   TOOLBAR.BMP    Toolbar bitmap used by DEB.RTF

   TOOLBAR.C      Toolbar functions

   TOOLBAR.DEF    Toolbar module definition file

Additional reference words: 1.00


INF: Exporting Callback Functions

Article ID: Q100659

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

In the Win32 operating system, an application is not required to

export callback functions. In 16-bit Windows 3.1 and prior versions,

an application must export callback functions primarily to allow them

to fix-up references to global data and to ensure that any required

EMS memory is available. Neither of these situations applies to

applications running in the Windows NT 32-bit operating system.

More Information:

It is necessary to export a function to make it available to the

GetProcAddress() function (for dynamic linking) or to list it in an

import library (for static linking). Either of these linking methods

require information about the function name or ordinal number.

Exporting the function places the name or ordinal number into the

application's exported entry points table and allows Windows to

determine the associated address at run time.

The loader performs load-time linking by looking up the imported entry

points an application requires to load. Typically, it looks up this

information by ordinal number. An application performs dynamic linking

with the GetProcAddress() function which instructs the system to look

up the desired function in the desired dynamic-link library (DLL)

exports table by ordinal number or by name. It is not necessary to

export functions in the Win32 application programming interface (API).

In 16-bit Windows, the linker automatically fixes exported entries to

load the appropriate value into the DS register. Exporting an entry in

Win32 simply adds the entry to the application's exported names and

ordinal numbers table; the linker need not "fix" them. To maintain

source code compatibility with 16-bit Windows, you may want to

continue using the MakeProcInstance() function and exporting all

callback functions.

The following table summarizes this information:

   Function Type    On Windows 3.0/3.1 (Win16)     On Windows NT (Win32)

   -------------    --------------------------     ---------------------

   Callback         Exported or MakeProcInstance   Address of fn() *

   GetProcAddress   Must be exported               Must be exported

   Static linking   Must be exported               Must be exported

   * Because the MakeProcInstance() macro has no effect, it works as

     well.

Additional reference words: 1.00 exporting


INF: Macros to Facilitate Porting Applications to Windows NT

Article ID: Q100660

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The text below presents a list of macros that can be used to simplify

the process of porting applications to the Microsoft Windows NT

operating system.

More Information:

// Windows NT Macros

#if defined(WIN32)

#define _fmemcpy(x,y,z)    memcpy(x,y,z)

#define _fmemcmp(x,y,z)    memcmp(x,y,z)

#define _fmemset(x,y,z)    memset(x,y,z)

#define _fmemicmp(x,y,z)   memicmp(x,y,z)

#define _fmemmove(x,y,z)   memmove(x,y,z)

#define _fstrcpy(x,y)      strcpy(x,y)

#define _fstrcmp(x,y)      strcmp(x,y)

#define _fstrcat(x,y)      strcat(x,y)

#define _fstrlen(x)        strlen(x)

#define _fstricmp(x,y)     stricmp(x,y)

#define _fstrstr(x,y)      strstr(x,y)

#define _fstrncpy(x,y,z)   strncpy(x,y,z)

#define _fstrncmp(x,y,z)   strncmp(x,y,z)

#define _fstrupr(x)        strupr(x)

#define _fstrlwr(x)        strlwr(x)

#define _fstrchr(x,y)      strchr(x,y)

#define _fstrrchr(x,y)     strrchr(x,y)

#define _fstrnicmp(x,y,z)  strnicmp(x,y,z)

#define _fstrpbrk(x,y)     strpbrk(x,y)

#define _nfree(x)          free(x)

#define _nmalloc(x)        malloc(x)

#define _loadds            // not valid under Windows NT

#define NT_GetWndInstance(hwnd) \

                    (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE)

#define NT_GetWndID(hwnd)       (UINT)GetWindowLong(hwnd, GWL_ID);

#define NT_ParseWM_COMMAND(id, ntfy, hwnd, wPar, lPar) \

        (id = LOWORD(wPar), ntfy = HIWORD(wPar), hwnd = (HWND)lPar)

#define NT_PostWM_COMMAND(hwnd, id, ntfy, hwndChild) \

        PostMessage(hwnd, WM_COMMAND, (UINT)MAKELONG(id, ntfy), \

                    (LONG)hwndChild)

#define NT_SendWM_COMMAND(hwnd, id, ntfy, hwndChild) \

        SendMessage(hwnd, WM_COMMAND, (UINT)MAKELONG(id, ntfy), \

                    (LONG)hwndChild)

#if !defined(LONG2POINT)

#define LONG2POINT(l, pt) ((pt).x = (SHORT)LOWORD(l), \

                           (pt).y = (SHORT)HIWORD(l))

#endif

// Windows NT Equivalents for Windows

#else

#define NT_GetWndInstance(hwnd) \

                    (HINSTANCE)GetWindowWord(hwnd, GWW_HINSTANCE)

#define NT_GetWndID(hwnd)       (UINT)GetWindowWord(hwnd, GWW_ID);

#define NT_ParseWM_COMMAND(id, ntfy, hwnd, wPar, lPar) \

        (id = wPar, ntfy = HIWORD(lPar), hwnd = (HWND)LOWORD(lPar))

#define NT_PostWM_COMMAND(hwnd, id, ntfy, hwndChild) \

        PostMessage(hwnd, WM_COMMAND, (UINT)id, \

                    MAKELONG(hwndChild, ntfy))

#define NT_SendWM_COMMAND(hwnd, id, ntfy, hwndChild) \

        SendMessage(hwnd, WM_COMMAND, (UINT)id, \

                    MAKELONG(hwndChild, ntfy))

#endif

Additional reference words: 1.00


INF: Sample Code Demonstrates Simple Dynamic-Link Library

Article ID: Q100661

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The SIMPLDLL sample provides a generic dynamic-link library (DLL)

template. The sample also includes two small test applications,

LINKTEST and LOADTEST, that demonstrate load-time linking (through a

DLL import library) and dynamic loading, respectively.

More Information:

The file THE_DLL contains a skeleton DLL entry point and five exported

functions that have varying parameter lists. It also uses a resource

file that contains a dialog box template.

LINKTEST is a small application that links with import library for

THE_DLL and supports calling into THE_DLL by selecting items from a

menu.

LOADTEST is a small application that loads THE_DLL at run time and

calls the GetProcAddress() function to retrieve the addresses of the

functions THE_DLL exports. LOADTEST also supports calling into the DLL

by selecting items from a menu.

Additional reference words: 1.00 DLLEntryPoint GetModuleFileName

LoadLibrary GetProcAddress


PRB: No Symbolic Information for Local Variables

Article ID: Q100773

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual Workbench for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   The Visual Workbench integrated debugger may display incorrect

   values for the local variables in an application.

CAUSE

   The application being debugged was compiled with optimizations

   on.

RESOLUTION

   During the debugging process for your application, specify the

   /Od compiler option switch to disable optimizations.

More Information:

The C/C++ compiler provided with Microsoft Visual C++ version 1.0 for

Windows NT very aggressively uses registers to store local variables.

This is particularly true when optimizations are turned on. Therefore,

information regarding local variable storage is not always available

to the debugger.

The following code example demonstrates this behavior. If you compile

this code with optimizations disabled (specify the /Od compiler option

switch), the values of the local variables in the func1() function are

correctly displayed after the code calls the func2() function.

However, if you compile the code with optimizations (specify the /Ox

compiler option switch), the values of the same local variables do not

display correctly until the code executes the return statement from

func2().

Sample Code

-----------

/*

 * Compile options needed: /Ox

 */

void func2(int *arg1, int *arg2, int *arg3)

{

   *arg1 = *arg2 = *arg3 = 5;

}

int func1(int arg1)

{

   int local1, local2;

   func2(&arg1, &local1, &local2);

   return arg1 + local1 + local2;

}

void main(void)

{

   func1(1);

}

Additional reference words: 1.00 vwbdebug


INF: Installing Visual C++ for Multiple Users on One Machine

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

To install Visual C++ version 1.0 for Windows NT so more than one

person can use the software on a machine, perform the following two

steps:

1. Run Setup to install Visual C++ for the first user.

2. Run Setup with the /F option to install Visual C++ for the second

   and subsequent users. You must specify the same options used in the

   original installation (including the destination directory,

   selected optional files, and so on).

More Information:

The Visual C++ version 1.0 for Windows NT Setup program creates a

personal program group for the current user and registers environment

variables for the current user.

Setup /F does not copy any files in the installation process because

the files have already been copied to the machine. Setup /F creates

the program group and registers the environment variables for the

additional user.

With two exceptions, all Visual C++ information is specific to the

current user. The two exceptions involve the MSVC.WSP and MSVCINCL.DAT

files. Both files are installed in the root directory of the Windows

NT installation (commonly, the C:\WINNT directory).

MSVC.WSP is the default workspace file. It is used only when there is

no current project and it is shared by all users. MSVCINCL.DAT lists

the files that the Workbench build engine ignores when it generates

the dependencies for a project. It is also shared by all users.

Additional reference words: 1.00


INF: Printing the Image of a Dialog Box

Article ID: Q83939

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft App Studio for Windows, version 1.0

 - Microsoft App Studio for Windows NT, version 1.0

 - Microsoft QuickC for Windows, version 1.0

----------------------------------------------------------------------

Summary:

App Studio and QuickC for Windows do not support printing a dialog

box, bitmap, icon, cursor, or other resource. However, you can copy

the image of a resource and paste it into Microsoft Windows

Paintbrush, Write, Word for Windows, or another Windows-based word

processor or graphics program and print the image in that application.

More Information:

To print the image of a dialog box you create in App Studio, perform

the following four steps:

1. Start App Studio and open or create the dialog box.

2. Press ALT+PRINT SCRN to copy the image of the dialog box to the

   clipboard.

3. Activate Paintbrush (or another program) and choose Paste from the

   Edit menu.

4. Choose Print from the File menu to print the dialog box.

Note that this process only captures the image of the dialog box that

is currently open in the resource editor. You can use ALT+PRINT SCRN

to copy to the clipboard the image of any dialog box or window in the

Microsoft Windows environment. This feature is available in Windows NT

and when 16-bit Windows runs in 386 enhanced mode. For more

information, please refer to page 58 of the "Microsoft Windows User's

Guide."

Windows captures the image of the dialog box in bitmap (.BMP) format.

You can use Paintbrush to change any features of the dialog box image

before you print it.

Additional reference words: 1.00 PBRUSH.EXE DLGEDIT.EXE qcwin qcw

quick VCNT


INF: COMMON.RES Provides Common Bitmaps, Cursors, and Icons

Article ID: Q99162

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft App Studio for Windows, version 1.0

 - Microsoft App Studio for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The COMMON.RES file contains many common icons, cursors, and bitmaps

that you can use with App Studio. By default, Setup copies COMMON.RES

into the C:\MSVC\MFC\SAMPLES\APSTUDIO directory. COMMON.RES contains

13 bitmaps, 15 cursors, and 377 icons in version 1.0 for 16-bit

Windows, and 13 bitmaps, 15 cursors, and 400 icons in version 1.0 for

Windows NT.

To view these resources, run App Studio in Windows and open the

COMMON.RES file. You can copy the various resources into your

application's resource file to use them. Please refer to Technical

Note 23 in the MFC Tech Notes help file for more information about

using COMMON.RES.

With App Studio, you can view resources in many types of files

including dynamic-link libraries (DLLs), executable (.EXE) files,

compiled resource (.RES) files, and .BMP, .CUR, .DIB, .ICO, and .RC

files. You can copy these resources into your application and use them

as appropriate.

Additional reference words: 1.00 VCNT


PRB: RW2002 Error From Long Resource Identifier

Article ID: Q99389

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft App Studio for Windows, version 1.0

 - Microsoft App Studio for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

PROBLEM ID: Studio9306001

SYMPTOMS

   An attempt to build resources in App Studio fails and App Studio

   generates the following message:

      error RW2002: File not found

CAUSE

   If a bitmap, cursor, or icon has an identifier longer than 23

   characters, App Studio incorrectly generates the resource file. As

   the identifier grows beyond 23 characters, it eliminates spaces

   between the identifier and the resource statement. Eventually, the

   identifier displaces the resource statement to the right. If the

   identifier is long enough, it eliminates spaces between the

   resource statement and the memory option.

STATUS

   Microsoft has confirmed this to be a problem in App Studio version

   1.0 for Windows and App Studio version 1.0 for Windows NT. We are

   researching this problem and will post new information here in the

   Microsoft Knowledge Base as it becomes available.

More Information:

App Studio generates a line like the following for the

IDB_THISISAVERYLONGIDENTIFIER identifier:

   IDB_THISISAVERYLONGIDENTIFIERBITMAPDISCARDABLE "filename.bmp"

It should generate the following:

   IDB_THISISAVERYLONGIDENTIFIER BITMAP DISCARDABLE "filename.bmp"

Additional reference words: 1.00 VCNT


INF: Converting an RC File to Use Microsoft Foundation Classes

Article ID: Q99391

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft App Studio for Windows, version 1.0

 - Microsoft App Studio for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

In App Studio, the Class Wizard button on the toolbar and the Class

Wizard menu option are disabled if the currently loaded RC file is

not enabled for the Microsoft Foundation Classes. App Studio creates

an RC file that is not enabled when it converts an old-style RC file

to an App Studio RC file or when the user removes the selection from

the "Use Microsoft Foundation Classes" option when creating an RC

file in App Studio.

In addition, an RC file that is not enabled for the Microsoft

Foundation Classes cannot contain any VBX controls.

More Information:

To convert an RC file that is not enabled for the Microsoft Foundation

Classes to one that is enabled, perform the following five steps:

1. Load the RC file into App Studio.

2. From the File menu, choose Set Includes.

3. In the Read-Only Symbol Directives window, replace the following

   lines:

      #define APSTUDIO_HIDDEN_SYMBOLS

      #include "windows.h"

      #undef APSTUDIO_HIDDEN_SYMBOLS

   with:

      #include "afxres.h"

4. Save the RC file and close it.

5. Load the RC file into App Studio.

The window title reads "FILENAME (MFC Resource Script)" to indicate

that the file is enabled for the Microsoft Foundation Classes.

Additional reference words: 1.00 VCNT


PRB: tan(pi/2) Returns Value, Causes No Error

Article ID: Q11158

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   If an application uses the tan() run-time function to compute the

   value of pi/2, the function returns a value. Mathematically, this

   value is not defined.

CAUSE

   This error is caused by the precision with which numbers can be

   represented in the computer. It is not possible to specify a value

   X close enough to the true value of pi/2 to cause tan(X) to

   overflow.

More Information:

The tangent of a value is defined as the sine of the value divided by

the cosine of the value. Therefore, the tangent of pi/2 is the sine of

pi/2 (1) divided by the cosine of pi/2 (0). Because the cosine of pi/2

is 0, its tangent is undefined.

                sin(pi/2)     1

   tan(pi/2) = ----------- = --- = undefined, divide by zero

                cos(pi/2)     0

The function tan(pi/2) returns a value because the computer

approximates pi to a limited number of digits. Even at double

precision, the approximate value of pi is not large enough to cause

cos(pi/2) to equal zero. Therefore, tan(pi/2) returns an unexpected

value, as follows:

   Approximate pi = 3.1415926535

                sin(pi/2)    sin(3.1415926535/2)           1

   tan(pi/2) = ----------- = ------------------- = -----------------

                cos(pi/2)    cos(3.1415926535/2)   0.000000000044896

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00


INF: Using malloc() and _fmalloc() in an Application

Article ID: Q12159

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.0, 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The text below provides information about using the _fmalloc() and

malloc() functions in an application.

An application can use both the malloc() and _fmalloc() functions

without restriction. Each function separately tracks its memory

allocations. The application must use the free() and _ffree()

functions, respectively, to free memory allocated by these functions.

The malloc() functions do not perform any "garbage collection"

activity to reclaim free memory between allocations. The application

must explicitly free memory when appropriate.

The malloc() functions can fragment memory. However, when an

application frees a block of memory that is adjacent to another block

of free memory, the appropriate free() function consolidates the

blocks to reduce the damage caused by fragmentation.

The _fmalloc() function does not allocate memory that crosses a

segment boundary and fails any allocation request for more than 64K of

memory. To allocate a larger memory block, use the halloc() function

(the huge memory model memory allocation function). Your application

must deal with segment boundaries in a huge memory block.

Windows NT uses a flat 32-bit memory model; every address requires 32

bits. Because Windows NT does not use segments, far and huge versions

of malloc() and free() are not required. Therefore, the C runtime

library that supports Windows NT does not include the _fmalloc(),

_ffree(), halloc(), and _hfree() functions. The elimination of

segments also removes the 64K maximum allocation limit; an application

can request up to 2 GB with malloc().

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00


PRB: Rounding Error Casting Double to Long

Article ID: Q12297

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   An application produces incorrect results when it casts an

   expression of type double to type long.

CAUSE

   The error is caused by differences in arithmetic precision.

STATUS

   The C and C++ standards specify that when an application converts a

   floating-point number to an integer, the number is truncated toward

   zero. When rounding is the preferred behavior, the application can

   add or subtract 0.5 as appropriate so truncation provides the

   correct result. The text below presents a macro for this purpose.

More Information:

The following code example demonstrates this behavior when compiled

with any floating point math option other than /FPa. The application

displays -4049 as the value for Long2 and Long4, which is incorrect.

The application displays the correct value -4050 for Long1 and Long3.

Sample Code

-----------

/*

 * Compile options needed: /FPc or /FPc87 or /FPi or /FPi87

 */

#include "stdio.h"

main()

{

   long    val1, val2, val3;

   double  mul1, mul2;

   val1 = 45000;

   mul1 = 0.09;

   mul2 = (double)val1 * mul1 * -1.00;

   printf("%7ld Long1 ", (long)mul2);

   val2 = (long)mul2;

   printf("%7ld Long2 ", (long)((double)val1 * mul1 * -1.00));

   printf("%7ld Long3 ", val2);

   val3 =(long)((double)val1 * mul1 * -1.00);

   printf("%ld Long4 \n", val3);

}

The application produces the incorrect results by converting a 10-byte

real value to a long; the application produces correct results by

converting a 10-byte real to an 8-byte real and converting that value

to a long.

According to the type conversion rules, the conversion from a 10-byte

real to an 8-byte real rounds the number from -4049.99999999999985 to

-4050.0. When the application converts this value to a long, the value

-4050 results. However, when the application directly converts the

double value to a long, the application truncates toward zero. In this

example, -4049.99999999999985 becomes -4049.

Many numbers (such as .01) are repeating fractions in the binary

numbering system which cannot be represented exactly. Any

representation of these numbers is slightly more or less than the

"true" value. When a calculation involves one of these values, the

representation error propagates and can be magnified. Because the

error is present only in the least significant part of the number,

errors occur only when a calculation loses precision in an

intermediate value.

The conversions always truncate toward zero. The following macro

effectively rounds the number by increasing the magnitude of the

number by 0.5 then converting the number to an integer.

   #define ROUNDL( d ) ((long)((d) + ((d) > 0 ? 0.5 : -0.5)))

The problem does not occur when compiling with the /FPa option or in

Windows NT because neither the alternate math library nor Windows NT

supports the long double data type.

For more information on converting floating-point numbers to integers,

see the type conversions section of the "C Language Reference" manual.

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00


INF: Jumping into the Middle of a For Loop Is Not Recommended

Article ID: Q19972

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, versions 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

In Microsoft C and in Microsoft C/C++, the goto statement and its

corresponding label must be part of the same function; no other

restrictions apply. However, because different compilers optimize for

loops and allocate stack space for automatic variables in various

ways, using a goto statement to transfer flow-of-control into the

middle of a for loop is not portable and is considered unsafe.

The most common use for the goto statement in structured programming

involves error handling. In these cases, the goto statement usually

leads out of a deeply nested for loop.

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00


INF: Common Programming Errors in the C Language

Article ID: Q22321

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The text below lists some of the most common errors that occur

programming in the C language. Any one of these items can cause

unpredictable results, such as invalid data.

 - Using an automatic variable that has not been initialized

 - Omitting a closing comment delimiter

 - Using an array index greater than the length of the array (In C,

   array indexes run from zero to <length>-1.)

 - Omitting a semicolon or a closing brace

 - Using an uninitialized pointer

 - Using a forward slash when a backslash is required (for example,

   substituting "/n" for "\n.")

 - Using "=" in a comparison where "==" is desired

 - Overwriting the null terminator for a string

 - Prematurely terminating a function declaration with a semicolon

   (The compiler often flags the "orphan" block of code as a syntax

   error.)

 - Specifying the values of variables in a scanf() statement instead

   of their addresses

 - Failing to declare the return type for a function

 - Assuming an expression evaluation order when using an expression

   with side effects (For example, a[i] = i++; is ambiguous and

   dangerous.)

 - Failing to account that a static variable in a function is

   initialized only once

 - Omitting a "break" from a case in a switch statement (Execution

   "falls through" to subsequent cases.)

 - Using "break" to exit a block of code associated with an if

   statement (The break statement exits a block of code associated

   with a for, switch, or while statement.)

 - Comparing a "char" variable against EOF (-1). The following idiom

   results in an infinite loop:

      char c;

      while ((c = getchar()) != EOF)

         {

         }

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

7.00a 8.00 VCNT


PRB: "Invalid Object Module" Error Usually From Old LINK

Article ID: Q22331

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   An attempt to link an application fails and the Microsoft LINK

   utility generates the following message:

      invalid object module

CAUSE

   An incorrect version of Microsoft LINK is in use. In many systems,

   the MS-DOS directory is listed near the beginning of the PATH

   environment variable. MS-DOS includes a version of LINK that is

   often used instead of the version provided with the C compiler.

RESOLUTION

   Perform one of the following two steps to address this problem:

    - Rename the older version of the linker. For example, change its

      name to LINK.OLD. The MS-DOS linker is probably not needed, but

      this method assures that it remains available.

    - Modify the contents of your PATH environment variable to list

      the directory that contains the correct version of LINK.EXE

      before any other versions. However, the problem is more likely

      to recur with this approach when you make subsequent

      modifications to your system.

More Information:

To verify that an incorrect linker version is the cause of an "invalid

object module" error, perform the following six steps:

1. Change the current directory to the directory in which the LINK.EXE

   version provided with the C compiler is installed.

2. Type "link" (without the quotation marks) at the MS-DOS command

   prompt.

3. When LINK displays its copyright banner message, note the displayed

   version number. This is the correct version of LINK to use.

4. Press CTRL+C to exit LINK.

5. Change the correct directory to the directory in which you compile

   and link your application.

6. Repeat steps 2 through 4 in this directory.

If the LINK version number that displays in your working directory is

less than the version number that displays in the C compiler

directory, then an older version of the LINK utility is installed in a

directory listed in the PATH environment variable before the directory

that contains the correct LINK version.

If you have an older version of LINK.EXE installed on your system,

determine the directory in which it is installed. Most likely, it is

in your MS-DOS directory. However, it could be the linker from another

Microsoft language product.

Because it is not uncommon to have a number of linkers in various

directories specified in the PATH, repeat the test above after you

make any of the modifications recommended in the RESOLUTION section of

this article.

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00 VCNT


INF: Specify Compiler Options Before Source File Name

Article ID: Q23739

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

 - Microsoft QuickC for MS-DOS, versions 2.0, 2.01, 2.5, and 2.51

----------------------------------------------------------------------

Summary:

To compile a file with any of the Microsoft language compilers listed

above, list any appropriate compiler option switches on the command

line before the names of the source files to which the options apply.

In most cases, if you specify an option at the end of the command

line, after the names of all the files, the compiler does not generate

any warnings or errors -- it simply ignores the option because no

source file follows for the option to apply to. In a few cases, a

trailing option causes an error because the option conflicts with a

previously specified option.

Microsoft C/C++ version 8.0 for Windows NT supports placing option

switches after the names of source files. If a compiler command line

specifies more than one source code file, specified options apply to

all files regardless of the position of the option switch relative to

the source file name.

Additional reference words: 2.00 2.01 2.50 2.51 3.00 4.00 5.00 5.10

6.00 6.00a 6.00ax 7.00 8.00


PRB: spawnl() Fails in Noncurrent Directory

Article ID: Q23740

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   An attempt to use the spawnl() function to invoke a child process

   fails if the child is in a directory other than the current

   directory. However, invoking a child process in the current

   directory succeeds.

CAUSE

   The MS-DOS, OS/2, and Windows NT operating systems use the

   backslash character (\) to separate the directory name from the

   file name in a file specification. The C language also uses the

   backslash as an "escape" character to indicate a special character,

   such as the end-of-line character (\n). These uses conflict in an

   application.

RESOLUTION

   Modify the file specification in the spawnl() call to specify two

   backslashes between the portions of the file specification.

More Information:

The following spawnl() command does not work as expected:

   spawnl(P_WAIT, "c:\dir1\file.exe", "file.exe", NULL);

The following spawnl() command works correctly:

   spawnl(P_WAIT, "c:\\dir1\\file.exe", "file.exe", NULL);

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00


PRB: fseek() Function Moves to Unexpected Location in File

Article ID: Q23753

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   An attempt to use the fseek() function fails when an application

   points to a location in the file other than that desired.

CAUSE

   The application specifies a 16-bit "int" value as the second

   parameter to the fseek() function.

RESOLUTION

   Specify a "long" value as the second parameter to the fseek()

   function.

More Information:

The maximum value of a signed 16-bit "int" value is 32,767 (32K). With

a signed 16-bit int, a value between 32K and 64K is treated as

negative.

If an application specifies a 16-bit "int" as the second parameter to

the fseek() function, the compiler automatically casts it to a "long."

However, when this occurs, the value is sign-extended. Therefore, a 16-

bit "int" value between 32K and 64K is sign-extended as a negative

"long" value, which produces unexpected results when seeking in a

file.

In the Windows NT operating system, an "int" is 32-bits in size, the

same as a "long." Therefore, this problem occurs on Windows NT only

when the data type of the second parameter to the fseek() function is

declared as a "short int," a 16-bit value.

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00


PRB: R6002 From Floating-Point I/O without Floating-Point Math

Article ID: Q23873

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

 - Microsoft QuickC for MS-DOS, versions 2.0, 2.01, 2.5, and 2.51

----------------------------------------------------------------------

Summary:

SYMPTOMS

   In the MS-DOS, OS/2, and Windows NT operating systems, an attempt

   to run an application that does not perform any floating-point math

   fails and the run-time library generates the following message:

      R6002: floating point support not loaded

   In the Microsoft Windows operating system, the run-time library

   generates the following message:

      Floating point support not loaded

CAUSE

   Most often, this error occurs when a printf() or scanf() statement

   in the program contains a floating-point format specifier, such as

   %f, in the format string.

RESOLUTION

   To work around this problem, modify the source code to declare and

   initialize a local dummy variable of type "float" in the main()

   function. Alternately, declare a dummy global variable of type

   "volatile float." Either of these steps should cause the linker to

   include floating-point support with the .EXE file.

More Information:

This error occurs because the linker includes floating-point modules

in the linked code only when the code contains a float variable. Under

most circumstances, this is desired behavior because the floating-

point modules are quite large. However, if the code contains a

floating-point format specifier and does not contain a float variable,

the R6002 error occurs because the modules are required to perform the

floating-point input and output conversions.

In some cases, the technique outlined above does not work because the

compiler detects (when it performs some optimizations) that the dummy

variable is not used and removes the variable from the compiled code.

Additional reference words: 2.00 2.01 2.50 2.51 4.00 5.00 5.10 6.00

6.00a 6.00ax 7.00 8.00


INF: Sending Output to a Printer

Article ID: Q23976

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The text below presents three methods an application can use to send

output to a printer.

The first method uses the fprintf() function with the preopened

"stdprn" stream. The following code example demonstrates this

technique:

   #include <stdio.h>

   main()

   {

      fprintf(stdprn, "a line of text\n");

   }

This method works only in the MS-DOS operating system because the

"stdprn" stream is not defined by Microsoft Windows or Microsoft

Windows NT.

Another method uses the fopen() function to open the LPT1, LPT2, or

PRN device as a file and uses the fprintf() function to write data to

the file handle returned by fopen(). The following code example

demonstrates this technique:

   #include <stdio.h>

   main()

   {

      FILE *stream;

      stream = fopen("PRN", "w");

      fprintf(stream, "a line of text\n");

   }

This method works in the MS-DOS and Windows operating systems.

However, Windows NT does not support the PRN device or this method.

Finally, in MS-DOS, an application can use the int86() or int86x()

functions to call one of the following BIOS printer services provided

by Interrupt 17h:

   service 0: send byte to the printer.

   service 1: initialize the printer.

   service 2: get printer status.

For more information on the int86() and int86x() functions, refer to

the Microsoft C "Run-Time Library Reference" manual.

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00


INF: C Run-time Library History and Naming Conventions

Article ID: Q28173

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 3.0, 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

 - Microsoft QuickC for MS-DOS, versions 1.0, 1.01, 2.0, 2.01, 2.5,

   and 2.51

 - Microsoft QuickC for Windows, version 1.0

----------------------------------------------------------------------

Summary:

The text below describes the history of, and the naming conventions

used by, the code libraries used with the Microsoft C, C/C++ and

QuickC compilers. This description is designed to explain how to build

the various libraries and what their names mean.

More Information:

Throughout the discussion below, libraries are named using one of the

following notations: xLIBCy?.LIB, xLIBFP.LIB, or xLIBC.LIB, where the

individual symbols stand for the following:

   "x" represents the memory model option. The different memory model

       options are "S" for the small memory model (the default), "M"

       for the medium memory model, "C" for the compact memory model,

       and "L" for the large memory model.

   "y" represents the math library option. The different math library

       options are "E" for the emulator model (the default), "7" for

       the coprocessor model, and "A" for the alternate model.

   "?" represents an operating mode. The operating modes are "R" for

       real mode, "P" for protected mode, and "W" for Microsoft

       Windows mode. When this position is empty, the library is a

       default mode library (for more information, see the discussion

       of library defaults below).

In a library name, "LIBC" indicates a Microsoft C run-time library,

"LIBFP" indicates a floating point math library, and "LIBFA" indicates

an alternate math floating point library.

The Microsoft libraries support three floating point models, as

follows:

 - Floating point emulation. This library uses an Intel math

   coprocessor if one is present in the system and emulates a

   coprocessor otherwise. (To use floating point emulation with a

   version of Microsoft C prior to version 5.1, link with xLIBFP.LIB

   and EM.LIB. In C version 5.1 and later, link with xLIBCE?.LIB.)

 - Coprocessor math. An Intel math coprocessor must be present in the

   system. This model has a speed advantage over the emulation model

   because the code is not required to test for the presence of a

   coprocessor chip. The disadvantage of the model is that the

   coprocessor chip is required. (To use coprocessor math with a

   version of Microsoft C prior to version 5.1, link with xLIBFP.LIB

   and 87.LIB. In C version 5.1 and later, link with xLIBC7?.LIB.)

 - Alternate math. This library performs an alternate math coprocessor

   emulation. This library does not use a math coprocessor chip, even

   if one is available in the system. (To use alternate math with a

   version Microsoft C prior to version 5.1, link with xLIBFA.LIB. In

   C version 5.1 and later, link with xLIBCA?.LIB.)

Library Search Records

----------------------

In an effort to ease the linking process for the user, the compiler

puts a search record into the object (OBJ) file that tells the linker

what libraries are required to link the application. The search record

lists only the standard libraries. Other libraries, like GRAPHICS.LIB,

are not included.

When the search record is present, the user is not required to

explicitly list libraries on the linker command line unless additional

libraries are required or if the /NOD switch is specified on the

linker command line. (/NOD instructs the linker to ignore the search

record in the OBJ file.) You can prevent the compiler from placing a

search record into the OBJ file by specifying the /Zl compiler option

switch.

C version 3.0

-------------

To create an EXE file with Microsoft C version 3.0, link your compiled

code with the xLIBC.LIB library and an appropriate math library. For

example, to create an application that uses the small memory model and

floating point emulation, link with SLIBC.LIB, SLIBFP.LIB and EM.LIB.

C version 4.0

-------------

C version 4.0 added LIBH.LIB as a required library. LIBH is a "helper"

library that routines in the other libraries use. For example, to

create an application that uses the medium memory model and

coprocessor math, link with MLIBC.LIB, LIBH.LIB, MLIBFP.LIB, and

87.LIB.

C version 5.0

-------------

C version 5.0 added GRAPHICS.LIB, a real-mode, memory-model-

independent library. For example, to create an application that uses

the large memory model, displays graphics, and uses the alternate math

library, link with LLIBC.LIB, GRAPHICS.LIB, LIBH.LIB, and LLIBFA.LIB.

C version 5.1 and Combined Libraries

------------------------------------

C version 5.1 added a new feature called "Combined Libraries." Instead

of specifying xLIBC.LIB, LIBH.LIB, an appropriate math library, and

possibly GRAPHICS.LIB each time you link an application, version 5.1

provides the option to generate a library search record for

xLIBCy.LIB, a so called "combined library." The C 5.1 installation

program creates the combined libraries according to the options the

user chooses, as follows:

   xLIBCE.LIB = xLIBC.LIB + LIBH.LIB + xLIBFP.LIB + EM.LIB

   xLIBC7.LIB = xLIBC.LIB + LIBH.LIB + xLIBFP.LIB + 87.LIB

   xLIBCA.LIB = xLIBC.LIB + LIBH.LIB + xLIBFA.LIB

Even though having all twelve combined libraries in your "LIB"

directory consumes a large amount of disk space, it makes the linking

process much faster and easier.

If you choose not to build the combined libraries, you can specify

each of the component library names as explained above.

In version 5.1, the default libraries have the same name that they do

in version 5.0. However, the C run-time libraries are split into two

versions: one for real mode (MS-DOS), and one for protected mode

(OS/2). Therefore, xLIBC.LIB in version 5.0 has two names in version

5.1: xLIBCR.LIB for the MS-DOS environment and xLIBCP.LIB for the OS/2

environment.

The names of the combined libraries change as well with an "R" or "P"

appended to the library name. However, the compiler continues to

generate "xLIBC?.LIB" as the default search record. If you develop

applications only for the real mode environment, choose default file

names for MS-DOS in the C compiler SETUP program. When the program

generates two sets of libraries, they are named xLIBCy.LIB and

xLIBCyP.LIB. If you choose default names for OS/2, the program

generates xLIBCyR.LIB and xLIBCy.LIB.

Version 5.1 defines two new compiler option switches (/Lr and /Lp)

that direct the compiler to generate explicit library names in the

library search record. Therefore, the following compiler command line:

   cl /Lr test.c

generates a library search record for SLIBCER.LIB in the object file.

Similarly, the following compiler command line:

   cl /Lp test.c

generates a library search record for SLIBCEP.LIB in the object file.

Version 5.1 also defines other libraries, as follows:

   API.LIB      - FAPI (Family Application Programming Interface)

                  routines. Applications that use only FAPI functions

                  can run with either MS-DOS or OS/2.

   CDLLOBJS.LIB - OS/2 dynamic-link library (DLL) run-time library

                  objects

   CDLLSUPP.LIB - OS/2 DLL support

   CRTLIB.LIB   - OS/2 DLL support

   DOSCALLS.LIB - OS/2 system calls library

   LLIBCDLL.LIB - OS/2 DLL support

   LLIBCMT.LIB  - OS/2 multi-threaded DLL support

C versions 6.x

--------------

C versions 6.x use the same combined library format as C versions 5.x.

Versions 6.x also defines other libraries, as follows:

   CRTCOM.LIB   - Tiny memory model library (Used to generate COM

                  files)

   EXTSUP.LIB   - Programmer's WorkBench (PWB) library (Used to build

                  applications that extend PWB)

   GRTEXTP.LIB  - OS/2 text mode graphics support library

   OS2.LIB      - OS/2 system calls library (A superset of

                  DOSCALLS.LIB)

   PGCHART.LIB  - Presentation graphics support

C versions 7.0 and 7.0a

-----------------------

Version 7.0 adds support for the Microsoft Windows operating system to

the C run-time libraries and removes OS/2 support. The version 7.0

libraries are as follows:

   MOVETR.LIB   - Microsoft Overlaid Virtual Environment (MOVE)

                  library with TRACE.EXE support

   OLDNAMES.LIB - Support pre-ANSI function names for source code

                  compatibility.

   xAFXC?.LIB   - Microsoft Foundation Classes library for

                  applications

   xAFXC?D.LIB  - Debugging version of the Microsoft Foundation

                  Classes library for applications

   xAFXD?.LIB   - Microsoft Foundation Classes library for DLLs

   xAFXD?D.LIB  - Debugging version of the Microsoft Foundation

                  Classes library for DLLs

   xNOCRTDW.LIB - DLL initialization code library

   xNOCRTW.LIB  - Application initialization code for Windows

                  environment

   xDLLCyW.LIB  - DLL library for Windows environment

   xLIBCyW.LIB  - Application library for Windows environment

   xLIBCyWQ.LIB - QuickWin application library

Visual C++ for Windows, version 1.0

-----------------------------------

The run-time libraries supplied with Visual C++ for Windows, version

1.0, are primarily the same as those supplied with C/C++ 7.0. The

difference is that additional import libraries can be created for the

Microsoft Foundation Class Library DLLs, as follows:

   MFC200.LIB   - The import library for the retail version of the

                  Microsoft Foundation Classes version 2.0 DLL

                  (MFC200.DLL)

   MFC200D.LIB  - The import library for the debugging version of the

                  Microsoft Foundation Classes version 2.0 DLL

                  (MFC200D.DLL)

For more information on the Microsoft Foundation Classes libraries,

see Technical Note 33 in the Technical Note help file distributed with

Visual C++ version 1.0.

Visual C++ for Windows NT, version 1.0

--------------------------------------

Visual C++ for Windows NT, version 1.0, provides the following run-

time and Microsoft Foundation Class Library DLLs:

   LIBC.LIB     - Single-threaded C run-time library support

   LIBCMT.LIB   - Multi-threaded C run-time library support

   MSVCRT.LIB   - Import library for the multi-threaded C run-time

                  library. To run code linked with this library,

                  MSVCRT10.DLL must be available at run time.

   OLDNAMES.LIB - Supports pre-ANSI function names to maintain source

                  code compatibility.

   NAFXCR.LIB   - Release (nondebugging) version of the Microsoft

                  Foundation Class Library for console applications.

   NAFXCRD.LIB  - Debugging version of the Microsoft Foundation Class

                  Library for console applications.

   NAFXCW.LIB   - Release version of the Microsoft Foundation Class

                  Library for windowed applications.

   NAFXCWD.LIB  - Debugging version of the Microsoft Foundation Class

                  Library for windowed applications.

   NAFXDW.LIB   - Release version of the Microsoft Foundation Class

                  Library for DLLs.

   NAFXDWD.LIB  - Debugging version of the Microsoft Foundation Class

                  Library for DLLs.

Additional reference words: 3.00 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00

7.00a 8.00


INF: qsort() Can Sort Data Structures Based on Multiple Fields

Article ID: Q28244

----------------------------------------------------------------------

The information to this article applies to:

 - Microsoft C for MS-DOS, versions 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included

   with Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The qsort() function in the Microsoft C run-time library does not

restrict the methods an application can use to compare items. When

qsort() compares two data elements, it calls an application-supplied

comparison routine.

To sort an array of structures using more than one field as a key,

create a comparison function that relates the appropriate fields in

each structure and returns a comparison value to indicate the result.

Additional reference words: 4.00 5.00 5.10 6.00 6.00a 6.00ax 7.00 8.00


INF: printf() Default Floating-Point Precision is 6 Decimals

Article ID: Q29557

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 5.0, 5.1, 6.0, 6.0a, and 6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included

   with Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

By default, the printf() function displays a floating-point number to

six digits of precision. This default also holds for double precision

numbers.

To display additional digits of precision, specify a value for the

precision field in the printf() format specification, as follows:

   %[<flags>][<width>][.<precision>]<type>

More Information:

The code example below demonstrates documented printf() behavior that

may appear to be a problem with the function.

   #include <stdio.h>

   main()

   {

      double d = 1.2345678912;

      printf("%e\n", d);

      printf("%le\n", d);

   }

This code example produces the following output:

   1.234568e+000

   1.234568e+000

To display the value d to its full precision, modify the code example

to use the following statement:

   printf("%.15le", d);

Additional reference words: 5.00 5.10 6.00 6.00a 6.00ax 7.00 8.00


INF: Using fopen() to Append Data to File Terminated w/ CTRL+Z

Article ID: Q29852

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 4.0, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included

   with Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

When an application appends information to a stream file that is

terminated with the CONTROL+Z end-of-file (EOF) marker (ASCII 1Ah),

use the fopen() function and specify the "a+" mode. The "+" character

allows the application to read and write to the stream.

More Information:

If an application specifies the "a" mode to append data in the write-

only mode, the application does not remove the EOF marker from the

file. Consequently, the MS-DOS TYPE command shows data only to the

original EOF marker and does not display any data appended to the

file.

The "a+" mode allows the application to remove the EOF marker from the

file before it appends data which allows TYPE to display the new data.

Using the "a+" mode is necessary because the C run-time must be able

to read the file to locate the EOF marker and overwrite the marker

with appended data. Because the "a" mode does not grant read

permission, the C run-time seeks to the end of the file and appends

data after the EOF marker.

Additional reference words: 5.00 5.10 6.00 6.00a 6.00ax 7.00 8.00


PRB: rename() Function May Fail Unexpectedly

Article ID: Q60028

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 5.0, 5.1, 6.0, 6.0a, and 6.0ax

 - Microsoft C/C++ for MS-DOS, versions 7.0 and 8.0

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   Using the rename() function to change a subdirectory name may fail

   if the directory name you want to change is the current working

   directory for that drive. In addition, some versions of MS-DOS may

   return a success value, but the directory name apparently has not

   changed.

CAUSE

   An access violation occurs attempting to rename the current

   directory.

RESOLUTION

   To work around this problem, use the chdir() function to set the

   current directory of the specified drive to be the root directory

   on the drive. However, in Windows NT, this procedure does not

   guarantee success because an error occurs if another process uses

   the target directory.

   You can optimize this method by checking the active directory on

   the target drive. Change directories only if the directory to

   rename is the current directory.

More Information:

In MS-DOS versions 3.x when SHARE.EXE is not installed, the sample

program shown below produces the following results:

   C:\>cd olddir

   C:\OLDDIR>d:

   D:>test

   Rename is successful  <--- Output from test program

   D:>c:

   C:\OLDDIR>      <--- The old directory is not renamed

In MS-DOS version 3.3 when SHARE.EXE is installed, in MS-DOS versions

4.x and later, in an MS-DOS window in OS/2, or in an MS-DOS window in

Windows NT, the sample program produces the following results:

   C:\>cd olddir

   C:\OLDDIR>d:

   D:>test

   Rename fails with errno = 13  <--- Output from test program

   D:>c:

   C:\OLDDIR>            <--- The old directory is not renamed

Note: errno code 13 indicates an access violation.

This behavior does not indicate a problem with the rename() function.

It simply maps to an Interrupt 21h, Function 56h (Rename File) call in

MS-DOS. The problem occurs because the operating system maintains a

list of the current working directory (CWD) for each drive in its

drive table in memory.

In the MS-DOS 3.x example, the program successfully changed the

directory name. However, because MS-DOS does not recognize the change,

it does not update the CWD in the drive table. When the program ends,

MS-DOS displays an invalid prompt that reflects the old directory

name. If you type "CD \NEWDIR" at the MS-DOS prompt, the drive table

is updated.

In the second example, MS-DOS 3.3 with SHARE.EXE installed, MS-DOS

versions 4.x and later, and MS-DOS running in OS/2 cannot determine if

another process is using the directory and an access violation error

occurs.

In Windows NT, if any process is active in the target directory, the

system does not change the directory name. When this happens, the

function returns an error code 13 that indicates an access violation.

Sample Code

-----------

#include <io.h>

#include <stdio.h>

char szOldName[] = "c:\\olddir";

char szNewName[] = "c:\\newdir";

extern int errno;

void main (void)

{

   if (0 != rename(szOldName, szNewName))

      printf("Rename fails with errno = %d\n", errno);

   else

      printf("Rename is successful\n");

}

Additional reference words: 5.10 6.00 6.00a 6.00ax 7.00 8.00 1.00

Visual VCNT


INF: Initializing Bitfields as Integers in C

Article ID: Q60252

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 4.x, 5.0, 5.1, 6.0, 6.0a, and

   6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

In Microsoft C versions 5.1, 6.0, 6.0a, 6.0ax, C/C++ version 7.0, and

Visual C/C++ version 1.0, initializing the values of an entire

bitfield structure as an integer can be done in several ways:

 - Declare the bitfield structure as part of a union with an integer.

   (This is the preferred method).

 - Use an integer pointer by setting the pointer to the address of the

   structure and then changing what the pointer points to.

 - Enforce the bitfield type constraints to get a copy of the bitfield

   into an integer variable.

For examples of these three methods, see below.

More Information:

In Microsoft C, bitfields are stored in word-sized blocks with the

least significant bit representing the first bit of the bitfield. For

example, the bitfields in bitstruct, defined below in the example, are

stored as follows:

           <  p4   > <  p3   > < p2> <p1>

        |?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|

Assigning the integer 0x4c to this structure results in the following

bit pattern:

        |0|0|0|0|0|0|0|0|0|1|0|0|1|1|0|0|

The bitfields are given the following respective values:

   p1=0 p2=3 p3=2 p4=0

If the number of bits needed for a bitfield structure exceeds 16 in

code compiled for MS-DOS or Windows, words will be added as needed to

provide room for the structure with no single bitfield crossing a word

boundary. Microsoft C/C++ for Windows NT stores bitfield structures in

double word values. If the field requires more than 32 bits, the

compiler uses additional double words as needed.

Note: There is no "standard" for storing bitfields in memory;

therefore, any program that depends on a particular storage method is

not portable to systems that use a different method.

Sample Code

-----------

struct strtype

   {

   unsigned p1:2;

   unsigned p2:3;

   unsigned p3:5;

   unsigned p4:5;

   } bitstruct;

union untype

   {

   struct strtype un_bitstruct;

   unsigned bit_integer;

   } bitunion;

unsigned *intptr;

unsigned intgr;

void main(void)

{

   /*  Using the bitfield structure only */

      /* Set the pointer to address of bitfield */

   intptr = (unsigned *)&bitstruct;

      /* Change the bitfield */

   *intptr = 0x4c;

      /* Get the new value */

   intgr = *(unsigned *)&bitstruct;

   /* Using an union makes this much easier (syntactically) */

      /* Set the pointer */

   intptr = &bitunion.bit_integer;

      /* Change the bitfield */

   bitunion.bit_integer = 0x4c;

      /* Get the new value */

   intgr = bitunion.bit_integer;

}

Microsoft C versions 6.0 and later and Microsoft QuickC versions 2.5

and later support anonymous unions. The following code demonstrates

this feature.

struct strtype

   {

   unsigned p1:2;

   unsigned p2:3;

   unsigned p3:5;

   unsigned p4:5;

   } bitstruct;

union untype

   {

   struct strtype un_bitstruct;

   unsigned bit_integer;

   };                      // Look ma!  No name..

unsigned *intptr;

unsigned intgr;

void main(void)

{

   /*  Using the bitfield structure only */

      /* Set the pointer to address of bitfield */

   intptr = (unsigned *)&bitstruct;

      /* Change the bitfield */

   *intptr = 0x4c;

      /* Get the new value */

   intgr = *(unsigned *)&bitstruct;

   /* Using an union makes this much easier (syntactically) */

      /* Set the pointer */

   intptr = &bit_integer;    // See here...

      /* Change the bitfield */

   bit_integer = 0x4c;       // And here...

      /* Get the new value */

   intgr = bit_integer;      // And here...  (Much easier, huh?)

}

Additional reference words: 5.10 6.00 6.00a 6.00ax 7.00 8.00 C++


INF: C4061 Long/Short Mismatch in Argument

Article ID: Q60253

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 5.0, 5.1, 6.0, 6.0a, and 6.0ax

 - Microsoft C for OS/2, versions 5.0, 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS and OS/2, versions 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

Microsoft C versions earlier than version 6.0 generates the C4061

warning only if the actual and formal function arguments include both

long and int data types. Microsoft C version 6.0 and later also

generate this message if the actual and formal function arguments

include both int and char data types. While C4061 is is not a fatal

error, it may provide the only an indication of a potential problem.

Microsoft C/C++ verison 7.0 and the Visual C++ version 1.0 fast

compiler (invoked with the /f compiler option switch) generate the

following warning:

   warning C4761: integral size mismatch in argument; conversion

   supplied

More Information:

The compiler generates the C4761 warning (at warning level 1)  for the

code example below. The fast compiler provided with C version 6.0

(invoked with the /qc compiler option switch) and the Visual C++

version 1.0 optimizing compiler (invoked with the /f- compiler option

switch) do not generate the C4761 warning compiling the code example

at any warning level. Compiling this code with QuickC versions 2.0,

2.01, 2.5, and 2.51 do not generate any warnings for this code.

Sample Code

-----------

#include <stdio.h>

void myfunc(char);  /* At prototype level argument type is CHAR */

void main(void);

void main (void)

{

   int x = 0;

   myfunc(x);       /*  Now passing an INTEGER to a CHAR  */

}

void myfunc(char c) /* Argument correctly declared as CHAR */

{}

Additional reference words: 2.00 2.50 5.00 5.10 6.00 6.00a 6.00ax 7.00

8.00 VCNT


INF: sizeof() Function Returns unsigned Instead of int

Article ID: Q60332

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 6.0, 6.0a, and 6.0ax

 - Microsoft C for OS/2, versions 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS and OS/2, versions 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

To comply with new ANSI specifications, the sizeof() operator in

Microsoft C versions 6.0 and later and QuickC versions 2.5 and later

returns an unsigned integer. In C version 5.1 and QuickC version 2.0,

this function returns a signed int.

More Information:

The change to an unsigned return value can cause problems in code that

uses the idiom "-sizeof(type)." The following code example attempts to

position the file pointer one record from the end of a file. The

method the code demonstrates works with C version 5.1, but fails with

C version 6.0 and later.

   fseek(file, (long)(-sizeof(record)), SEEK_END);

This fseek call positions the file pointer far beyond the end of the

file because the compiler does not sign extend the generated value.

Because the unary minus (-) operator does not change the "signedness"

of a variable and the sizeof() operator returns an unsigned int, the

compiler performs a zero extension to convert the unsigned int to a

long.

In other words, if the record variable was of type char, the following

code returns the long value -1 when compiled with C 5.1 and 32,767

when compiled with C 6.0:

   (long)(-sizeof(record))

One method to work around this problem involves casting the result of

the sizeof operator to a signed int before negating the value and

casting it to a long. For example:

   (long)-(int)sizeof(record)

Additional reference words: 5.10 6.00 6.00a 6.00ax 7.00 8.00 VCNT


PRB: fscanf() Fails to Read Consecutive Lines

Article ID: Q60336

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 5.1, 6.0, 6.0a, and 6.0ax

 - Microsoft C for OS/2, versions 5.1, 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS and OS/2, versions 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   When a file is open in text mode, an attempt to read lines of text

   with the fscanf() function may fail and only one line of text is

   read from the file.

CAUSE

   The delimeter is set to "[^\n]". The fscanf() function reads up to

   but does not include the delimiting character. Therefore, the file

   stream stops at the first '\n' in the file. Subsequent fscanf()

   calls fail because the file pointer remains at the delimiting

   character and fscanf() cannot advance the function pointer past it.

RESOLUTION

   Use one of the following two methods to move the file pointer past

   the delimiting character:

    - Update the code to use the following fscanf() call:

         fscanf(stream, "%[^\n]%*c", line)

      The "%*c" format specifier reads one character from the input

      stream but does not assign it to any of the parameters in the

      fscanf function call.

    - Call fgetc() after the fscanf() call to move the file pointer

      beyond the '\n' character.

More Information:

The following code demonstrates this problem. It should read and print

lines from a text file until it reaches EOF. However, it reads only

the first line from the file.

Sample Code

-----------

   FILE *stream;

   char line[80];

   while ((fscanf(stream, "%[^\n]", line)) != EOF )

   {

      printf("Line = %s \n",line);

   }

The following code demonstrates the second method above to work around

this problem:

   FILE *stream;

   char line[80];

   while ((fscanf(stream, "%[^\n]", line)) != EOF)

   {

      fgetc(stream);    // Reads in '\n' character and moves file

                        // stream past delimiting character

      printf("Line = %s \n", line);

   }

Additional reference words: 5.00 5.10 6.00 6.00a 6.00ax 7.00 8.00

VCNT


INF: Storage Types of Integer Constant Changed in C 6.0

Article ID: Q60751

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft C for MS-DOS, versions 6.0, 6.0a, and 6.0ax

 - Microsoft C for OS/2, versions 6.0, and 6.0a

 - Microsoft C/C++ for MS-DOS and OS/2, version 7.0

 - Microsoft C/C++ for MS-DOS, version 8.0, which is included with

   Visual C++ for Windows, version 1.0

 - Microsoft C/C++ for Windows NT, version 8.0, which is included with

   Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

To maintain ANSI compliance, Microsoft C versions 6.0 and later uses a

different mechanism to store numeric constants than C version 5.1

does. The selected storage type is the smallest in the following table

that is large enough to represent the value of the constant.

   Source Code Data            Available Data Types

   --------------------------------------------------------------

    decimal constant                   int

    without suffix                    long

         (123)                    unsigned long*

    hexadecimal or                     int

    octal constant                  unsigned

    without suffix                    long

       (0x122)                    unsigned long

    all constants **                unsigned

    u or U suffix                 unsigned long

        (133u)

    all constants **                 long

    l or L suffix                 unsigned long

        (332l)

    all constants **              unsigned long

    u or U and l or L

    suffix (0x111ul)

 * C 5.1 and QuickC 2.0 do not support unsigned long to represent

   standard decimal constants.

** The maximum value for a decimal constant in C 5.1 and QuickC 2.0 is

   2,147,483,647 regardless of its type.

More Information:

In C, each constant is stored as a positive value. A constant preceded

by a unary minus is considered an expression, not a negative constant.

If the type of a constant as defined above is unsigned, then the

result of the expression with the unary minus is also unsigned.

Section 3.1.3.2 of the ANSI draft specification dated December 7,

1988, provides the rules to store an integer constant, as follows:

   The type of an integer constant is the first of the corresponding

   list in which its value is represented. Unsuffixed decimal: int,

   long int, unsigned long int; unsuffixed octal or hexadecimal: int,

   unsigned int, long int, unsigned long int; suffixed by the letter u

   or U:  unsigned int, unsigned long int; suffixed by the letter l or

   L: long int, unsigned long int; suffixed by both the letters u or U

   and l or L: unsigned long int.

Additional reference words: 5.10 6.00 6.00a 6.00ax C++ 7.00 8.00 VCNT


INF: LIB32.EXE Converts Object Files to COFF Format

Article ID: Q100640

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

LIB32.EXE converts object modules (.OBJ files) into COFF objects

before inserting them into a library. Therefore, a Microsoft format

.OBJ file (non-COFF) inserted into a library will not have the same

size when it is extracted from the library.

This should not be a problem because the Visual C++ compiler produces

COFF objects.

Additional reference words: 1.00


INF: Stack Checking for Windows NT Programs

Article ID: Q100775

---------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

---------------------------------------------------------------------

Summary:

Stack checking in an application developed for Windows NT differs from

stack checking in an MS-DOS application.

More Information:

In an MS-DOS application, stack overflow is detected only by software.

By default, the compiler inserts a call to the __chkstk() function in

the prologue code for each function. The __chkstk() function compares

the amount of stack space a function requires with the amount of stack

space available. The function issues an overflow error if the current

stack pointer and requested stack allocation exceeds the maximum stack

size specified in the EXE header.

In the Microsoft Windows NT operating system, stack overflow is

detected by hardware and software working together, using the page

protection mechanisms. Each new Windows NT process has a maximum

reserved stack size and an initial committed stack allocation.

Committed memory is physically allocated to the process and is backed

by the page file; it is a relatively "expensive" resource. Reserved

memory is address space that is not mapped to real memory; it is a

relatively "cheap" resource.

As the stack grows, it moves from the committed portion of stack

memory into the reserved or uncommitted memory. When this happens, a

page fault occurs and the operating system commits another page of

memory to the stack. If a page fault occurs when the stack has already

grown to its maximum specified size, the system reports a stack

overflow exception.

This automatic growth method uses a guard page, a reserved,

uncommitted, memory page that is contiguous with the committed portion

of memory. When the application touches the guard page, the operating

system commits that page and the next uncommitted page becomes the new

guard page. Automatic stack growth works only for the guard page and

stack memory must grow in 4K, or one page, increments. If the

application touches another reserved but uncommitted page of stack

memory before it touches the guard page, a normal page fault exception

occurs and unpredictable behavior can result.

If a function included the following statements in its prologue code,

this problem could occur:

   PUSH   EBP

   MOV    EBP,ESP

   SUB    ESP,10000

   PUSH   ESI

In this code, the PUSH EBP and PUSH ESI do not occur in the same or in

adjoining 4K stack pages. If the stack must grow to accommodate the

10,000 byte local allocation, this program faults.

To prevent the fault, the compiler calls the __chkstk() function each

time the local allocation exceeds 4K. The Windows NT __chkstk()

function does not explicitly check for stack overflow as the MS-DOS

version does. It simply touches memory addresses every 4K from the

current stack pointer location to the requested allocation. This

triggers the guard pages in the proper sequence and commits additional

memory to the stack as required.

Therefore, when the compiler command line includes the /Ge option

switch and the prologue code always calls the __chkstk() function, the

application is not running as efficiently as it might because the

operating system supports an automatic mechanism to perform stack

overflow detection.

The /Gs compiler option switch does not disable all __chkstk() calls.

Instead, it disables __chkstk() calls for those functions that require

less than 4K of local storage. The /Gs option is the default behavior

of the compiler.

The /Gs option accepts an optional parameter, the threshold value. If

a function's local stack allocation exceeds the specified threshold,

the compiler inserts a __chkstk() call into the function prologue. For

a user-mode application to run correctly in Windows NT, the default

threshold 4096 is required. To suppress all __chkstk() calls, specify

an artificially high threshold value such as /Gs999999. The /Gs0

option has the same function as the /Ge option and instructs the

compiler to call __chkstk() in every function. It might be

advantageous to change the default value if the code executes in an

environment where the stack is fully committed or if the stack growth

mechanism is otherwise not available.

Additional reference words: 1.00 VCNT


PRB: Using Windows NT PDK Header Files in Visual C++

Article ID: Q100776

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   An attempt to use the header files provided with the Microsoft

   Windows NT Prerelease Development Kit (PDK) in Visual C++ for

   Windows NT can cause problems ranging from incorrect results to

   general protection (GP) faults.

CAUSE

   Several data structures changed between the Windows NT prerelease

   and the code that Visual C++ for Windows NT supports. Most of the

   changes converted data from type short to type int or from type

   unsigned short to type unsigned int. Code developed with the PDK

   header files passes incorrectly sized items to the functions in the

   C run-time library.

RESOLUTION

   Verify that the version of the header files used to build your

   application match the version of the library.

More Information:

To determine which directories are in the compiler search path for

files and libraries, type "SET" (without quotation marks) at the

Windows NT system prompt or choose the System icon in Control Panel.

Additional reference words: 1.00 VCNT gpfault


PRB: Fatal Error CK1017 Using Precompiled Headers

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Visual C++ for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   An attempt to create a debug library that uses precompiled headers

   may fail and generate the following messages:

      CVPACK : fatal error CK1017: cannot find precompiled types file;

               relink with file.obj

      LINK : warning LNK4027: CVPACK error

CAUSE

   When a source file is compiled with the /Yc and /Z7 options, the

   compiler creates a precompiled header file that contains CodeView

   debugging information. The error occurs when you store the

   precompiled header in a library, use the library to build an object

   module, and the source code does not refer to any of the functions

   that the precompiled header file defines.

RESOLUTION

   There are two methods to work around this situation:

    - Specify the /Yl<symbol> compiler option switch, where <symbol>

      is replaced by a symbol of your choice. when you create

      precompiled header files that do not contain any function

      definitions. This switch directs the compiler to store the

      debugging information in the precompiled header file.

    - Specify the /Yd compiler option switch to add the CodeView from

      the precompiled header to each object module. This method is

      less desirable because it generally produces large object files

      which can increase the time required to link the application.

More Information:

When you compile a module with the /Yc and /Yl<symbol> option

switches, the compiler creates the ___@@_PchDebugInfoLibrary_<symbol>

symbol and stores it in the object module. Any source files that you

compile with this precompiled header refer to the specified symbol.

This causes the linker to include the object module from the library.

The following code example demonstrates the problem.

Sample Code

-----------

/*

 * To demonstrate this problem, perform the following five steps:

 *

 * 1. Compile TEST1.C as follows: cl /Yctest.h /Z7 /c

 * 2. Compile TEST2.C as follows: cl /Yutest.h /Z7 /c

 * 3. Build a library that contains TEST1.OBJ and TEST2.OBJ as

 *    follows: lib /out:test.lib test1.obj test2.obj

 * 4. Compile TEST3.C as follows: cl /Yu test.h /Z7 /c

 * 5. Link the application as follows:

 *       link /debugtype:cv /debug:notmapped,full test3.obj test.lib

 *

 * To correct this problem, compile TEST1.C as follows:

 *    cl /Yctest.h /YlAnyName /Z7 /c

 * Then repeat steps 2 through 5 above.

 */

TEST.H

------

#include <stdio.h>

TEST1.C

-------

#include "test.h"

TEST2.C

-------

#include "test.h"

void test2func(void)

{

   printf("inside TEST2FUNC...\n");

}

TEST3.C

-------

#include "test.h"

void test2func(void);

void main(void)

{

   printf("inside MAIN...\n");

}

Additional reference words: 1.00 /YX hdrstop /Fp


INF: Cannot Use /2 Switch for Dual-Monitor Debugging on PS/2

Article ID: Q38865

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for MS-DOS, versions 2.x, 3.0, 3.1, 3.11, 3.14,

   4.0, 4.01, 4.02, 4.05, and 4.10

 - Microsoft CodeView for OS/2, versions 2.x, 3.0, 3.1, 3.11, 3.12,

   and 3.50

 - Microsoft CodeView for Windows, versions 3.05, 3.06, 3.07, 4.0,

   4.01, and 4.10

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

To use the /2 switch to enable dual-monitor debugging in CodeView,

your computer must be equipped with a monochrome display (MDA) and a

color display (CGA/EGA/VGA). Monochrome display adapters are not

generally available for the IBM PS/2 computers because they come with

built-in VGAs or MDAs, but not both. This means that dual-monitor

debugging is usually not possible on a PS/2 system.

This is a hardware issue and not a CodeView limitation; therefore,

when hardware vendors start selling MDAs that can be added to PS/2

systems with built-in VGAs, then CodeView dual-monitor debugging will

be available on the PS/2.

Additional reference words: 2.2 2.20 2.30 2.35 3.0 3.00 3.1 3.10 3.11

3.12 3.14 3.5 3.50 4.0 4.00 4.01 4.02 4.05 4.10 4.25


INF: Using a Debugging Terminal with CodeView

Article ID: Q39179

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for MS-DOS, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for OS/2, versions 2.x, 3.0, 3.1x, and 3.5

 - Microsoft CodeView for Windows, versions 3.x, 4.0, 4.01, and 4.1

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

It is possible to use either a dumb terminal or another computer (PC

or Macintosh, running a communications package at 9600 baud) as a

debugging terminal for CodeView. To take advantage of this option, do

the following:

1. Connect the second terminal to the communications port (COM1 or

   COM2).

2. Initialize the communications package to set up the second computer

   as a dumb terminal. Set the baud rate at 9600.

3. Start CodeView.

4. From the CodeView command window redirect the output to the second

   terminal with one of the following dialog commands:

      > COM1

   or

      > COM2

   This causes CodeView to display the command window output on the

   second terminal. You can also redirect the input to the CodeView

   command window to come from the terminal with one of the following

   commands:

      < COM1

   or

      < COM2

   This causes CodeView to read the input from the second terminal.

5. Set your options and run the program.

6. To reset the CodeView command window output to the local machine

   use the following dialog command:

      > CON

   To reset the CodeView command window input to the local machine

   use the following command:

      < CON

More Information:

Note that this is not the same functionality as remote debugging.

Remote debugging allows CodeView to run on a machine other than the

local machine which runs the program being debugged. CodeView versions

4.0 and 4.01 support remote debugging. For more information on remote

debugging, please refer to the documentation CodeView version 4.0.

Additional reference words: 2.2 2.20 2.3 2.30 2.35 3.0 3.00 3.05 3.06

3.07 3.1 3.10 3.11 3.12 3.14 3.5 3.50 4.0 4.00 4.01 4.02 4.05 4.1 4.10

4.25


INF: Use /Zi to Compile Commands Invoked with "?" Command

Article ID: Q43556

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for MS-DOS, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for OS/2, versions 2.x, 3.0, 3.1x, and 3.5

 - Microsoft CodeView for Windows, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

Invoking C functions in CodeView using the "?" command works as

expected as long as the function is contained in a module that was

compiled with /Zi for the CodeView information. However, an attempt to

directly call a function in the C run-time library or in the Windows

application programming interface (API), CodeView returns the error

message "syntax error" or "symbol 'xxxx' not found."

The reason for the error message is that the module containing the

library function is not compiled with the CodeView option /Zi. The

error message does not depend on the fact that the function is in the

library and not in your application. If you use the "?" command to

attempt to call a user-defined function in a module that is compiled

without including CodeView information, CodeView returns the same

error message.

The "?" command is formally referred to in the CodeView Utilities menu

as the Display Expression command.

Additional reference words: 2.2 2.20 2.30 2.35 3.0 3.00 3.05 3.06 3.07

3.1 3.10 3.11 3.12 3.14 3.5 3.50 4.0 4.00 4.01 4.02 4.05 4.1 4.10 4.25


INF: Returning Control to CodeView

Article ID: Q43648

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for MS-DOS, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for OS/2, versions 2.x, 3.0, 3.1x, and 3.5

 - Microsoft CodeView for Windows, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

The following are two software methods of returning control to

CodeView during program execution:

1. Use the debug interrupt, Interrupt 3, in your code. Interrupt 3 is

   called a microprocessor (or logical) interrupt. It is the interrupt

   that CodeView uses to make breakpoints. Place an Interrupt 3 into

   your code in selected places where you want to return control to

   CodeView.

   In a program designed for the Microsoft Windows operating system,

   use the DebugBreak() function to insert an Interrupt 3 in the code.

   Using DebugBreak() instead of calling Interrupt 3 directly through

   assembly code is especially important in applications designed for

   Win32s.

   The following sample program demonstrates the technique. Note that

   you could easily construct a macro to insert breakpoints where

   desired, and you could use inline assembly instead of the int86()

   function:

      #include <dos.h>

      #include <stdio.h>

      void main()

      {

         union REGS  inregs;

         int         i = 1;

         for ( ; ; )

            {

             printf("Loop iteration: %d\n", i++);

             int86(0x03, &inregs, &inregs);

            }

      }

2. When CodeView runs in MS-DOS, you can use the CTRL+C and CTRL+BREAK

   key combinations to return control to CodeView. This method can be

   useful to break out of a program that is running or that has locked

   up. When CodeView regains control, the displayed debugging

   information depends on when you type the key combination and what

   caused the problem with the application (for example, an infinite

   loop, a bad pointer, and so on). If desired, continue execution in

   the normal manner (press F5, F8, or F10, and so on).

   MS-DOS checks for the CTRL+C key combination during most I/O

   operations. If the system break flag is on (the AUTOEXEC.BAT file

   includes the command BREAK ON), MS-DOS checks for CTRL+C in other

   operations as well. If you press CTRL+C when an application is

   executing in an infinite loop and MS-DOS interrupts are disabled,

   CodeView may not obtain control.

   In OS/2, CTRL+BREAK does not return control to CodeView. You can

   use CTRL+C to terminate an application, but you cannot continue

   debugging after CTRL+C as you can in MS-DOS.

   When you debug an application in 16-bit Windows, CTRL+ALT+SYSRQ

   returns control to the debugger. When you debug a Win32s program,

   CTRL+ALT+F11 returns control to the debugger.

   No hardware interrupt returns control to CodeView.

Additional reference words: 2.2 2.20 2.3 2.30 2.35 3.0 3.00 3.05 3.06

3.07 3.1 3.10 3.11 3.12 3.14 3.5 3.50 4.0 4.00 4.01 4.02 4.05 4.1 4.10

4.25 CONTROL-C CONTROL+C CONTROL+BREAK CONTROL-BREAK ^C ^BREAK INT3


INF: CodeView Skips Over a Line of Source Code

Article ID: Q46010

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for MS-DOS, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for OS/2, versions 2.x, 3.0, 3.1x, and 3.5

 - Microsoft CodeView for Windows, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

SYMPTOMS

   CodeView does not recognize a breakpoint set in an application. If

   you run the program, execution does not stop on the breakpoint. If

   you single-step through the code, CodeView steps past the specified

   line. This problem also occurs in the QuickC and Visual C++

   integrated debuggers.

CAUSE

   This behavior occurs because CodeView is line-based and the C

   compiler is token-based.

RESOLUTION

   This restriction is inherent in the CodeView design. To work around

   this behavior, select mixed source code and assembly language mode

   and place the breakpoint on the correct line of assembly language

   code.

More Information:

Sample Code

-----------

/*

 * Compile options needed: /Zi /Od

 */

int i, j, k, l;

void main(void)

{

   for (i = 0; i < 20; i++)

   {

      j = 0;

      for (k = 0; k < 20; k++)

         if (j == 0)

            break;

      j = 1; /*** set breakpoint here ***/

   }

   l = 0;

}

Additional reference words: 1.0 1.00 1.1 1.10 1.11 2.0 2.00 2.1 2.10

2.2 2.20 2.30 2.35 3.0 3.00 3.05 3.06 3.07 3.1 3.10 3.11 3.12 3.14 3.5

3.50 4.0 4.00 4.01 4.02 4.05 4.1 4.10 4.25 2.01 2.5 2.50 2.51


INF: CodeView Search String Length Limited to 19-23 Characters

Article ID: Q48863

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for MS-DOS, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for OS/2, versions 2.x, 3.0, 3.1x, and 3.5

 - Microsoft CodeView for Windows, versions 3.x, 4.0x, and 4.1

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

CodeView versions 2.2 and 2.3 and CodeView version 2.1 for Windows can

search for strings up to 19 characters long by choosing Find from the

Search menu. This limit is in place even though the edit control in

the dialog box accepts many more than 19 characters of text. If you

type a string longer than 19 characters, one of two error messages

results. CodeView versions 3.0 and later are limited to 23 character

strings.

In CodeView version 2.x, if you enter a 20 or 21 character search

string, CodeView displays the message "No match of regular expression"

even when the search string exists in the file. If the search string

is 22 characters or longer, CodeView displays a more appropriate

message "Regular expression too long."

More Information:

Even though 19 characters can be limiting at times, CodeView performs

substring searches such that the following search expression:

   AFunctionWithAVeryL

finds the following string:

   AFunctionWithAVeryLongName

Problems occur only when the code contains two functions with similar

names and you want to find only one function and not the other, such

as the following:

   AFunctionWithAVeryLongName()

   AFunctionWithAVeryLongParameterList(a, b, c, d, e, f, g, h, i, j)

In this case, CodeView does not allow you to specify a search string

long enough to distinguish between the two function names. However,

you can use the Next command on the search menu to find subsequent

occurrences of the following string:

   AFunctionWithAVeryL

The Next command finds whichever of the two function names above

occurs next in the source code.

Additional reference words: 2.2 2.20 2.3 2.30 3.0 3.00 3.05 3.06 3.07

3.1 3.10 3.11 3.12 3.14 3.50 4.0 4.00 4.01 4.02 4.05 4.1 4.10 4.25


Label-Finding Command Does Whole Word Search, Not Text Search

Article ID: Q49378

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for MS-DOS, versions 2.x, 3.x, 4.0x, and 4.1

 - Microsoft CodeView for OS/2, versions 2.x, 3.0, 3.1x, and 3.5

 - Microsoft CodeView for Windows, versions 3.x, 4.0x, and 4.1

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

The CodeView debugger Search menu includes a Label command to search

for a label. Unlike the Find command, which searches in the source

code for any regular expression, the Label command searches the

CodeView debugging information for an assembly language label.

This search is not a text search and does not support regular

expressions. To find a label, specify the name of the label as the

search string. In addition, if the Case Sense option is selected in

the Options menu, the label is found only if the case of each letter

matches exactly.

More Information:

For example, to find the code for the standard C stack-checking

function "_chkstk", choose Label from the Search menu, type "__chkstk"

(two underscores but without quotation marks), and press ENTER.

CodeView switches the display to assembly language mode, if it was not

already, and positions the line with the label __chkstk at the top of

the window. Two underscores are required because C prepends an

underscore to every label (the original function name is "_chkstk").

If the label is not available, or if you type it in incorrectly,

CodeView returns an "Unknown Symbol" error. For example, "_chkstk",

"chkstk", "__chk", and "__chkstks" each fail to match the example

above. If Case Sense is on, an attempt to find the label "__CHKSTK"

also fails.

Additional reference words: 2.0 2.00 2.1 2.10 2.2 2.20 2.30 2.35 3.0

3.00 3.05 3.06 3.07 3.1 3.10 3.11 3.12 3.14 3.5 3.50 4.0 4.00 4.01

4.02 4.05 4.1 4.10 4.25


Dual-Monitor Setup Requires 8-Bit Data Paths for Both Monitors

Article ID: Q51870

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for MS-DOS, versions 1.x, 2.x, 3.x, 4.0x, and

   4.1

 - Microsoft CodeView for OS/2, versions 2.x, 3.0, 3.1x, and 3.5

 - Microsoft CodeView for Windows, versions 3.x, 4.0x, and 4.1

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

When you configure a system for dual-monitor debugging, verify that

both the monochrome monitor and the color monitor use an 8-bit data

path. Any dual-monitor write scheme requires a common data path to

each display card (either both 8-bit or both 16-bit). Monochrome

adapters available today use an 8-bit path exclusively.

Many display cards that support 16-bit mode automatically sense that

they are addressed in a dual-monitor mode. However, some cards, such

as the ATI VGA Wonder card, do not sense this situation. You must

manually configure these cards to use an 8-bit data path.

More Information:

If you use dual monitors and experience strange behavior, such as

random or blinking characters on the monochrome screen, verify that

your 16-bit color video card is running in 8-bit mode.

The most common use for a dual-monitor setup is to debug a graphics

application with CodeView.

Additional reference words: 1.0 1.00 1.1 1.10 1.11 2.0 2.00 2.1 2.10

2.2 2.20 2.30 2.35 3.0 3.00 3.05 3.06 3.07 3.1 3.10 3.11 3.12 3.14 3.5

3.50 4.0 4.00 4.01 4.02 4.05 4.1 4.10 4.25


PRB: L4001 Warning May Be Caused by Using Incorrect Linker

Article ID: Q74169

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft LINK for MS-DOS, versions 5.0x, 5.1x, 5.2x, 5.3x, and 5.5

 - Microsoft LINK for OS/2, versions 5.0x, 5.1, 5.11, 5.13, and 5.15

 - Microsoft Macro Assembler for MS-DOS and OS/2, versions 6.0, 6.0a,

   6.0b, and 6.1

----------------------------------------------------------------------

Summary:

SYMPTOMS

   During the process of linking an application, Microsoft LINK

   generates the following message:

      warning L4001: frame-relative fix-up,

              frame ignored near xxx in segment yyy

   In most cases, LINK ignores the initial frame and performs a far

   address calculation.

CAUSE

   This error can occur incorrectly when the incorrect linker is used.

   For example, the error occurs if an assembly module is assembled

   with USE32 segments in Microsoft Macro Assembler (MASM) and LINK

   version 5.x attempts to create the .EXE file. The same error occurs

   if MASM version 6.0, 6.0a, 6.0b, or 6.1 creates code for the FLAT

   memory model.

RESOLUTION

   The resolution depends on the target operating system. When Windows

   NT is the target, use the CVTOMF utility provided with the Windows

   NT Software Development Kit (SDK) to convert the generated object

   file from OMF format to COFF format. Then use the LINK utility

   provided with the Windows NT SDK to build the application. If OS/2

   version 2.0 is the target, use LINK386 from the IBM OS/2 2.0

   development kit.

More Information:

The following code example demonstrates both the error message

discussed above and the methods to avoid it. Assemble the code below

with MASM versions 6.0, 6.0a, 6.0b, or 6.1. To reproduce the error

message above, link with a segmented-executable linker, like LINK

versions 5.x. To create a correct executable file, link the code with

LINK386 from IBM.

Sample Code

-----------

; Assemble options needed: /c

;     Link options needed: Link with LINK 5.x to see errors

;                          Link with LINK386 for correct results

INCLUDELIB DOSCALLS.LIB ; OS/2 systems call library

.386

.MODEL flat, syscall

Dos32Write PROTO NEAR32 syscall,

    hf:WORD, pvBuf:NEAR32, cbBuf:WORD, pcbBytesWritten:NEAR32

Dos32Exit PROTO NEAR32 syscall,

    fTerminate:WORD, ulExitCode:WORD

.STACK 4096

.DATA

msg DB "Hello, world.", 13, 10

written DW 0

.CODE

_start:

    INVOKE  Dos32Write,        ; OS/2 system call

        1,                     ; File handle for screen

        NEAR32 PTR msg,        ; Address of string

        LENGTHOF msg,          ; Length of string

        NEAR32 PTR written     ; Bytes written

    INVOKE  Dos32Exit,         ; OS/2 system call

        0,                     ; Terminate all treads

        0                      ; Result code for parent process

END _start

Additional reference words: 5.01.20 5.01.21 5.02 5.03 5.05 5.10 5.11

5.13 5.15 5.20 5.30 5.31.009 5.50 6.00 6.00a 6.00b 6.10


INF: Differences Between LINK and LINK32

Article ID: Q100771

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft 32-Bit Executable Linker for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

The 32-bit LINK provided with Visual C++ for Windows NT is similar to

the LINK32.EXE utility provided with the Microsoft Win32 Software

Development Kit (SDK) for Windows NT. Although LINK and LINK32 have

many common options, there are a few differences to be aware of when

converting a build from LINK32 to LINK.

More Information:

The following options are unique to LINK and are invalid for LINK32:

     /COMMENT

     /DEF

     /DEFAULTLIB

     /EXPORT

     /IMPLIB

     /NODEFAULTLIB

     /NOLOGO

     /OPT

     /WARN

The following LINK32 options are not applicable anymore, and hence

they are invalid for LINK:

     /GPSIZE

     /HEAP

     /IGNORE

     /ROM

     /STRICT

Additional reference words: 1.00


PRB: Upper Left Corner of CodeView Screen Displays "a"

Article ID: Q100772

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft CodeView for Windows, versions 4.0, 4.01, and 4.10

 - Microsoft CodeView for Win32s, version 4.25

----------------------------------------------------------------------

Summary:

SYMPTOMS

   In CodeView for Windows the single screen mode may display one or

   more "a" characters. The "a" will appear in the title bar, the

   status bar,  or both. This does not affect any of the functionality

   of CodeView.

CAUSE

   This is caused by a problem in the currently set OEM font, and is

   not specifically related to CodeView.

RESOLUTION

   To work around this problem, modify or add an OEMFONTS.FON line in

   the [boot] section of the SYSTEM.INI file. The OEMFONTS.FON line

   should point to one of the OEM fonts provided with the C/C++

   compiler (either OEM10.FON or OEM08.FON from the BIN directory).

   For example, the line would appear as follows if you install Visual

   C++ in the default C:\MSVC directory:

      OEMFONTS.FON=C:\MSVC\BIN\OEM10.FON

More Information:

Changing the OEM font used will probably change the size of the

CodeView window on the screen.

Additional reference words: 4.00 4.01 4.10 4.25 VCNT


PRB: PRF1621 Error from Profiler for Windows NT

Article ID: Q100774

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Source Profiler for Windows NT, version 1.0

----------------------------------------------------------------------

Summary:

SYMPTOMS

   An attempt to profile an application using the line count and line

   cover options fails and the Profiler generates the following

   message:

      PREP: fatal error PRF1621: no debugging information

         in file 'filename'

CAUSE

   This error occurs when the application being profiled contains

   debugging information in COFF format.

RESOLUTION

   Profiler requires debugging information in CodeView format. Either

   change the debug options to /DEBUGTYPE:cv to generate CodeView

   format or to /DEBUGTYPE:both to generate both COFF and CodeView

   format debugging information.

More Information:

This error occurs only when you specify the line count or line

coverage options in Profiler. This functionality sets breakpoints in

the code using debugging information in CodeView format. This should

not be an issue for the function count or function coverage options.

Additional reference words: 1.00 lcover lcount VCNT


INF: Objects Inherited Through a CreateProcess Call

Article ID: Q83298

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The following is a list of objects that are inherited through the

CreateProcess() call.

More Information:

The objects inherited by a process are those objects that you can get

a handle to, and that you can use the CloseHandle() function on. These

objects include the following:

   Processes

   Events

   Semaphores

   Mutexes

   Files (including file mappings)

   Console input or output

However, the new process will only inherit objects that were marked

inheritable by the old process.

These are duplicate handles. Each process maintains memory for its own

handle table. If one of the processes modifies its handle (for

example, closes it or changes the mode for the console handle), other

processes will not be affected.

Processes will also inherit environment variables, the current

directory, and priority class.


INF: NT Consoles Do Not Support ANSI Escape Sequences

Article ID: Q84240

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Windows NT currently does not support ANSI escape sequences. This

should affect very few uses (for example, changing the color of the

prompt) and a very limited number TTY-type programs that rely on the

console for escape support to be provided.

This feature is is under review and is being considered for future

releases.


INF: Windowed and Full-Screen Console I/O Supported

Article ID: Q84248

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The following is a brief description of the console support available

to windowed applications.

More Information:

Win32 supports the use of a console (both as windows, and as full

screens) by windowed applications. The windowed application need only

call AllocConsole() to receive access to a console. After a successful

AllocConsole() call, a window console will open on the desktop and can

be used for any of the normal console functions, including the C

run-time calls (such as, printf() and getchar()). To change the window

console to a full screen console, set the focus to the console by

clicking it with the mouse and pressing the ALT+ENTER keys. The

console will change to full screen. To switch back, press ALT+ENTER

again. For more information, refer to the documentation on

AllocConsole(), FreeConsole(), and GetStdHandle().


INF: Byte-Ordering in a Data Packet Under NDIS

Article ID: Q89374

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

There may be a difference in the byte order in which 16-bit words are

stored in memory versus the order in which the two bytes must be

transmitted onto the network as part of a data packet. This difference

will depend on the processor involved and which part of the data

packet the information falls under.

The information is this article is consistent with the Network Device

Interface Specification (NDIS) version 3.0.

More Information:

Consider that the data will consist of header(s), the application

data, and a trailer(s).

      -------------------------------

      |    |    |                |    |------- Trailer

      -------------------------------

        |    |          |____ Application data

        |    |

        |    |____ Header

        |

        |____ Header

When a protocol driver or an NDIS driver sends information, it does

not modify the application data, nor does it modify the ordering of

bytes in integer fields.

The ordering of bytes in integer fields within the application data is

the responsibility of the Remote Procedure Call (RPC) facility or

another mechanism. However, the driver should be concerned with how

the information in the header(s)/trailer(s) is stored. For example,

the driver may be required to put a 16-bit checksum in a header. To

put that integer value into the header in the format required by the

network specification, the driver may need to know the type of

processor that it is running on and will in any case need to follow

the network standard for storing the information in the header.

If the driver needs to find out the CPU type of the machine it is

running on, it can use NdisReadConfiguration() on the Keyword

"ProcessorType" to query this. However, as of 10/25/92 this is not

supported with the prerelease device driver kit (DDK), so the

alternative in the meantime is #ifdef i386, mips, and so on.

Additional reference words: 3.10


INF: AllocConsole() Necessary to Get Valid Handles

Article ID: Q89750

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

If a graphical user interface (GUI) application redirects a standard

handle, such as stderr or stdout, and spawns a child process, the output of

the child process will not be seen unless the AllocConsole() application

programming interface (API) function is called before the standard handle

is redirected.

More Information:

If you spawn a child process without calling AllocConsole() first, your

child console window will appear on the screen and your GUI application

will not be able to control this window (for example, it cannot minimize

the child window). In addition, users can terminate the child process by

choosing Close from the console window's Control (system) menu. This causes

users to think that only the window is closed, when in actuality, the

entire application is terminated. This can cause the user to lose data in

the console window.

Additional reference words: 3.10


INF: How to Specify Shared and Nonshared Data in a DLL

Article ID: Q89817

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

To have both shared and nonshared data in a dynamic-link library

(DLL), you need to use the new #pragma data_seg directive to set up a

new named section. You then specify the sharing attributes for this

new named data section in your .DEF file.

More Information:

Below is a sample of how to define a named data section in your DLL.

The first line directs the compiler to include all the data declared

in this section in the .MYSEC data segment. This means that the

iSharedVar variable would be considered part of the .MYSEC data

segment. By default, data will be nonshared.

Note that you must initialize all data in your named section. The

data_seg pragma only applies to initialized data.

The third line, "#pragma data_seg()", directs the compiler to reset

allocation to the default data section.

   #pragma data_seg(".MYSEC")

   int iSharedVar = 0;

   #pragma data_seg()

Below is a sample of the .DEF file that supports the shared and

nonshared segments. This definition will set the default section

.MYSEC to be shared. The default data section is by default non-shared,

so any data not in section .MYSEC will be non-shared.

   LIBRARY

   SECTIONS

     .MYSEC READ WRITE SHARED

   EXPORTS

    ...

Note: All section names must begin with a period character ('.') and

must not be longer than 8 characters, including the period character.


INF: Apps Should Wait to Free/Re-use WriteFileEx's Buffer

Article ID: Q90087

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The WriteFileEx function was introduced in the Win32 API. It is used to

write data to a file and report its completion asynchronously (a completion

routine is called when the write operation is complete). The following is

the function prototype, taken from the Programmer's Reference:

   BOOL WriteFileEx(hFile, lpBuffer, nNumberOfBytesToWrite,

         lpOverlapped, lpCompletionRoutine)

   HANDLE hFile;                             /* file to write */

   LPVOID lpBuffer;                          /* address of buffer */

   DWORD nNumberOfBytesToWrite;              /* bytes to write */

   LPOVERLAPPED lpOverlapped;                /* contains offset */

   LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine;

One point that the documentation does not stress is that the data buffer,

lpBuffer, should not be used by the application until the overlapped I/O

operation is completed. At that time, the operating system will let the

application know whether the buffer has been successfully written or

whether the data transfer failed. After the status is reported, the

application can free or re-use the buffer.

In general, we cannot assume that the operating system has its own copy of

the data in the buffer. The kernel can transfer directly from the buffer to

the device.

Additional reference words: 3.10 3.0


INF: CreateFile() Using CONOUT$ or CONIN$

Article ID: Q90088

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

If you attempt to open a console input or output handle by calling the

CreateFile() function with the special CONIN$ or CONOUT$ filenames,

this call will return INVALID_HANDLE_VALUE if you do not use the

proper sharing attributes for the fdwShareMode parameter in your

CreateFile() call. Be sure to use FILE_SHARE_READ when opening

"CONIN$" and FILE_SHARE_WRITE when opening "CONOUT$".


INF: Exporting Data from a DLL

Article ID: Q90530

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

It is possible for a Win32 executable to be able to address DLL global

variables directly by name from within the executable. This is done by

exporting global data names similar to how you would a DLL function

name. Use the following steps to delcare and utilize exported global

data.

1. Define the global variables in the DLL code. For example:

      int i = 1;

      int *j = 2;

      char *sz = "WBGLMCMTP";

2. Export the variables in the module-definition (DEF) file. Use of the

   CONSTANT keyword is required, as shown below:

   EXPORTS

      i  CONSTANT

      j  CONSTANT

      sz CONSTANT

3. Declare the variables in the modules that will use them (note that they

   must be declared as pointers because a pointer to the variable is

   exported, not the variable itself):

      extern int *i;

      extern int **j;

      extern char **sz;

4. Use the values by dereferencing the pointers declared in step 3:

      printf( "%d", *i );

      printf( "%d", **j );

      printf( "%s", *sz );

   It may simplify things to use #defines instead; then the variables can

   be used exactly as defined in the DLL:

      #define i *i

      #define j *j

      #define sz *sz

      extern int i;

      extern int *j;

      extern char *sz;

      printf( "%d", i );

      printf( "%d", *j );

      printf( "%s", sz );

More Information:

Note: This technique can also be used to export a global variable from

an application so that it can be used in a DLL.

For more information on the use of EXPORTS and CONSTANTS in the

.DEF file, see Chapter 4 of the "Tools" manual.

Additional reference words: 3.10 3.1


INF: Dynamic Loading of DLLs Under Windows NT

Article ID: Q90745

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

When using LoadLibrary() under Win16 or OS/2, the DLL is loaded only once.

Therefore, the DLL has the same address in all processes. Dynamic loading

of DLLs is different under Windows NT.

A DLL is loaded separately for each process because each application has

its own address space, unlike Win16 and OS/2. Pages must be mapped into the

address space of a process. Therefore, it is possible that the DLL is

loaded at different addresses in different processes. The memory manager

optimizes the loading of DLLs so that if two processes share the same pages

from the same image, they will share the same physical memory.

Each DLL has a preferred base address, specified at link time. If the

address space from the base address to the base address plus image size is

unavailable, then the DLL is loaded elsewhere and fixups will be applied.

There is no way to specify a load address at load time.

To summarize, at load time the system:

1. Examines the image and determines its preferred base address and

   required size.

2. Finds the address space required and maps the image, copy-on-write,

   from the file.

3. Applies internal fixups if the image isn't at its preferred base.

4. Fixes up all dynamic link imports by placing the correct address for

   each imported function in the appropriate entry of the Import Address

   Table. This table is contiguous with 32-bit addresses, so 1024 imports

   require dirtying only one page.

More Information:

The pages containing code are shared, using a copy-on-write scheme. Copy-on-

write means that the pages are read-only; however, when a process writes

the page, instead of an access violation, the memory manager makes a

private copy of the page and allows the write to proceed. For example, if

two processes start from the same .EXE, both initially have all pages

mapped from the .EXE copy-on-write. As the two processes proceed to modify

pages, they get their own copies of the modified pages. The memory manager

is free to optimize unmodified pages and actually map the same physical

memory into the address space of both processes. Modified pages are swapped

to/from the page file instead of the .EXE file.

There are two kinds of fixups. One is the address of an imported function.

All these fixups are localized in what the Portable Executable

specification calls the Import Address Table (IAT). This is an array of 32-

bit function pointers, one for each imported API. The IAT is located on its

own page(s), because it is always modified. Calling an imported function is

actually an indirect call through the appropriate entry in this array. In

case that the image is loaded at the preferred address, the only fixups

needed are for imports.

Note that there is an optimization whereby each import library exports a 32-

bit number for each API along with any name and ordinal. This serves as a

"hint" to speed the fixups performed at load time. If the hints in the

program and the DLL do not match, the loader uses a binary search by name.

The other kind of fixup is needed for references to the image's own code or

data when the image can't be loaded at its preferred address. When a page

must be taken out of memory, the system checks to see whether the page has

been modified. If it has not, then the page is still mapped copy-on-write

against the EXE and can be discarded from memory. Otherwise, it must be

written to the page file before it can be removed from memory, so that the

page file is used as the backing store (where the page is recovered from)

rather than the executable image file.

Notes:

The DLL's entry point does not get called for a second LoadLibrary() call

in a process (that is, no second DLL_PROCESS_ATTACH entry). There is one

call to DllEntry/DLL_THREAD_ATTACH per thread no matter the number of times

a thread calls LoadLibrary. The same goes for FreeLibrary(), but the

DLL_THREAD_DETACH happens only on the last call (that is, reference count

back to zero for the thread).

Global instance data for the DLL is on a per process basis (only one set

per unique process). If it is necessary to ensure that global instance data

is unique for each LoadLibrary() performed in a single process, consider

thread local storage (TLS) as an alternative. This requires multiple

threads of execution, but TLS allows unique data for each ThreadID. There

is very little overhead on the DLL's part; just create a global TLS index

during process initialization. During thread initialization, allocate

memory (via HeapAlloc, GlobalAlloc, LocalAlloc, the CRT, and so on) and

store a pointer to the memory using the global TLS index value in the

function TlsSetValue. Win32 internally stores each thread's pointer by TLS

index and ThreadID to achieve the thread specific storage.

Additional reference words: 3.10 3.0


INF: Win32 Priority Class Mechanism and the START Command

Article ID: Q90910

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The Win32 priority class mechanism is exposed through CMD.EXE's START

command.

START now accepts the following switches:

   /LOW        -  Start the command in the idle priority class.

   /NORMAL     -  Start the command in the normal priority class

                  (this is the default).

   /HIGH       -  Start the command in the high priority class.

   /REALTIME   -  Start the command in the real-time priority class.

For a complete list of STARTs switches, type the following command at

the Windows NT command prompt:

   start /?

Win32 has also been modified to inherit priority class if the parent's

priority class is idle; thus, a command such as

   start /LOW nmake

causes build and all descendants (compiles, links, and so on) to run in the

idle priority class. Use this method to do a real background build that

will not interfere with anything else on your system.

A command such as

   start /HIGH nmake

runs BUILD.EXE in the high priority class, but all descendants run in the

normal priority class.

More Information:

Be very careful with START /HIGH and START /REALTIME. If you use either of

these switches to start applications that require a lot of cycles, the

applications will get all the cycles they ask for, which may cause the

system to appear hung.

Additional reference words: 3.10 3.0


INF: Creating Windows in Threads

Article ID: Q90975

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

In a multithreaded application, any thread can call the CreateWindow() API

to create a window. There are no restrictions on which thread(s) can create

windows.

It is important to note that the message loop and window procedure for the

window must be in the thread that created the window. If a different thread

creates the window, the window won't get messages from DispatchMessage(),

but will get messages from other sources. Therefore, the window will appear

but won't show activation or repaint, cannot be moved, won't receive mouse

messages, and so on.

To allow threads to share input state so that they can call SetFocus() for

a window in a different thread, it is necessary to call

AttachThreadInput().

Additional reference words: 3.10 3.1


INF: Two Types of Priority Control Added

Article ID: Q91129

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Due to overwhelming demand, Microsoft added two new types of priority

control to the existing types:

   THREAD_PRIORITY_TIME_CRITICAL

   THREAD_PRIORITY_IDLE

In addition, a new priority class has been added: REALTIME_PRIORITY_CLASS.

This affects CreateProcess(), SetPriorityClass(), and GetPriorityClass(). The

SeIncreaseBasePriorityPrivilege is required to use this class:

Therefore, the priority spectrum is organized as follows.

Fixed Priorities

----------------

   31  -   Realtime Class, THREAD_PRIORITY_TIME_CRITICAL

       .

       .

   26  -   Realtime Class, THREAD_PRIORITY_HIGHEST

   25  -   Realtime Class, THREAD_PRIORITY_ABOVE_NORMAL

   24  -   Realtime Class, THREAD_PRIORITY_NORMAL

   23  -   Realtime Class, THREAD_PRIORITY_BELOW_NORMAL

   22  -   Realtime Class, THREAD_PRIORITY_LOWEST

       .

       .

   16  -   Realtime Class, THREAD_PRIORITY_IDLE

Variable Priorities

-------------------

   15  -   Any Class,  THREAD_PRIORITY_TIME_CRITICAL,

           High Class, THREAD_PRIORITY_HIGHEST

   14  -   High Class, THREAD_PRIORITY_ABOVE_NORMAL

   13  -   High Class, THREAD_PRIORITY_NORMAL

   12  -   High Class, THREAD_PRIORITY_BELOW_NORMAL

   11  -   High Class, THREAD_PRIORITY_LOWEST

           Foreground Normal Class, THREAD_PRIORITY_HIGHEST

   10  -   Foreground Normal Class, THREAD_PRIORITY_ABOVE_NORMAL

    9  -   Foreground Normal Class, THREAD_PRIORITY_NORMAL

           Background Normal Class, THREAD_PRIORITY_HIGHEST

    8  -   Foreground Normal Class, THREAD_PRIORITY_BELOW_NORMAL

           Background Normal Class, THREAD_PRIORITY_ABOVE_NORMAL

    7  -   Foreground Normal Class, THREAD_PRIORITY_LOWEST

           Background Normal Class, THREAD_PRIORITY_NORMAL

    6  -   Background Normal Class, THREAD_PRIORITY_BELOW_NORMAL

           Idle Class, THREAD_PRIORITY_HIGHEST

    5  -   Background Normal Class, THREAD_PRIORITY_LOWEST

           Idle Class, THREAD_PRIORITY_ABOVE_NORMAL

    4  -   Idle Class, THREAD_PRIORITY_NORMAL

    3  -   Idle Class, THREAD_PRIORITY_BELOW_NORMAL

    2  -   Idle Class, THREAD_PRIORITY_LOWEST

    1  -   Any Class,  THREAD_PRIORITY_IDLE

More Information:

Within a class, the thread priority controls allow you to make two points

around the normal priority for the class:

   24  - Realtime Base

   13  - High Base

    9  - Forground Normal Base

    7  - Background Normal Base

    4  - Idle Base

In addition, two new thread controls allow you to position a thread as far

from your base as possible in either the dynamic or fixed priority ranges:

   31  - Time-critical fixed priority

   16  - Idle fixed priority

   15  - Time-critical variable priority

    1  - Idle variable priority

Note that using priorities above 11 will interfere with the normal

operation of the system. Using any of the real-time priorities may cause

disk caches to not flush, hang the mouse, and so forth. Extreme care should

be exercised whenever raising priority.

Additional reference words: 3.10 3.1


INF: Initiating an Unwind in an Exception Handler

Article ID: Q91148

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

In the "Programmer's Reference: Overviews," in the chapter titled

"Structured Exception Handling," the last paragraph of the Exception

Handling and Unwind subsection says that "the exception handler usually

initiates an unwind operation by calling a system supplied function".

The paragraph describes what the compiler-generated code for try-except

does. Initiating the unwind is automatically handled by the compiler when

you exit the handler in any way other than by sequentially executing the

final statement, for example, with a goto, return, break, and so forth. See

the example below.

Because exception handling can be quite different under different processor

architectures, the description uses words such as "usually"; "usually" you

initiate an unwind. In some cases (for example, a goto to a label in the

current call frame), you don't need to unwind (you already did when you hit

the handler), so none is needed, and the compiler need not bother calling

the system to do one.

Note that unwinds aren't a fast operation. It would generally be better for

the exception filter to decide the exception can't be handled, and evaluate

to EXCEPTION_CONTINUE_SEARCH, than to force the unwind this way. If some

cleanup still needs doing, the termination handler will be called during

the unwind operation and could do the cleanup.

More Information:

The following code fragment demonstrates initiating an unwind by exiting

the exception handler with a goto statement:

   int func() {

      try {

         ThisCode( BuggyParameter );

      }

      except( EXCEPTION_EXECUTE_HANDLER ) {

         if( ICannotContinue( BuggyParameter ) )

             goto InitUnwind;  //  <- This initiates the desired unwind

         HandleProblemBrilliantly( BuggyParameter );

      }

   InitUnwind:

      ProcessData();

      IssueError();

      RetireGracefully();

   }

Additional reference words: 3.10 3.1


INF: Icons for Console Applications

Article ID: Q91150

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Under OS/2, when adding an application named CONAPP.EXE to a program group,

the system uses the file CONAPP.ICO (if it exists ) as the icon. This does

not happen automatically under Windows NT; the item will have a generic

icon.

To specify the icon that appears in the program group, use the following

steps:

1. Create a resource file containing an ICON statement:

      ConApp ICON ConApp.ICO

2. Compile the resource using RC:

      rc -r -fo conapp.res $(cvars) conapp.rc

3. Use CvtRes to produce an .RBJ file:

      cvtres -$(CPU) conapp.res -o conapp.rbj

4. Include the .RBJ file in the link command.

Steps 2-4 are intended for use in a makefile that does an !include of

NTWIN32.MAK. See the makefiles for the SDK samples for more detail.

More Information:

If the application is started by clicking its icon in Program Manager, the

icon that appears when the application is minimized will be that icon,

whether it is a generic icon or an icon imbedded in the executable file.

If the application is started from the MS-DOS prompt or the File menu, then

the icon that appears when the application is minimized will be the icon

that is used for the MS-DOS prompt.

Additional reference words: 3.10 3.1


PRB: Return Values of Performance APIs

Article ID: Q91215

----------------------------------------------------------------------

The information in this article applies to:

 - Beta Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

In the Windows Help file for the Win32 API, the APIs

QueryPerformanceCounter() and QueryPerformanceFrequency() are incorrectly

documented as returning FALSE when a high performance timer is not present

and TRUE when a high performance timer is present.

The reverse is correct; FALSE (SUCCESS) is returned when a high performance

counter is present in the system and TRUE (!SUCCESS) is returned when a

high performance counter is not present.

For x86 and R4000 systems, FALSE (SUCCESS) is always returned because high

performance counters are available on both platforms.

Additional reference words: 3.10 3.1


INF: Sharing Win32 Services

Article ID: Q91698

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Win32 services are discussed in the overview for the Service Control

Manager. The documentation says that:

   A Win32 service runs in a Win32 process which it may or may not share

   with other Win32 services.

Whether or not a service has its own process is determined by which of

these service types is specified in the call to CreateService() to add the

service to the Service Control Manager Database.

SERVICE_WIN32_OWN_PROCESS

   This service type indicates that only one service can run in the

   process. This allows an application to spawn multiple copies of a

   service under different names, each of which gets its own process. This

   is the most common type of service.

SERVICE_WIN32_SHARE_PROCESS

   This service type indicates that more than one service can be run in a

   single process. When the second service is started, it is started as a

   thread in the existing process. A new process is not created. An example

   of this is the LAN Manage Workstation and the LAN Manager Server. Note

   that the service must be started in the system account, which is

   .\System. The name must be NULL.

The service type for each service is stored in the registry. The value is

0x10 for SERVICE_WIN32_OWN_PROCESS or 0x20 for SERVICE_WIN32_SHARE_PROCESS.

Additional reference words: 3.1 3.10


INF: Determining Whether Windows NT Is Running

Article ID: Q92395

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Programmers can use GetVersion() to determine what version of Windows their

applications are running under. This might be a version of MS-DOS/Windows,

Windows on Windows (WOW), MS-DOS/Windows using extensions (Win32s), or

Windows NT. According to the documentation, the return value of

GetVersion() is a DWORD that specifies the major and minor version numbers.

The following table shows the return values from GetVersion() under various

environments:

-----------------------------------------------------------------

|  Environment  |  LOWORD                 | HIWORD                |

|-----------------------------------------------------------------

|  Win 3.x      |  Windows version        | MS-DOS version        |

|  WOW          |  Windows version 3.1    | MS-DOS version 5.0    |

|  Win32s       |  Windows version 3.1    | RESERVED *            |

|  Win32        |  Windows version 3.1    | RESERVED **           |

-----------------------------------------------------------------

 * The highest bit is 1. Note that the version of MS-DOS cannot be

   determined as it can under Windows 3.x.

** The highest bit is 0. The remaining bits specify build number.

Note that Windows 3.1 and WOW can return the same results. Therefore,

GetVersion() is especially useful only for 32-bit applications to determine

whether they are running under Windows NT or under Windows 3.1 with Win32s.

This is done by masking off the high bit.

Therefore, 16-bit applications should use GetWinFlags() to determine

whether they are being run under MS-DOS/Windows or WOW. GetWinFlags()

returns a WF_WINNT flag if the application is running under WOW.

More Information:

GetWinFlags() can also be used from 16-bit applications under WOW to

determine whether the processor is 80x86, R4000, or ALPHA. GetWinFlags() is

an existing function that has had these the following flags added in WOW:

   #define WF_CPUR4000      0x0100

   #define WF_CPUALPHA21064 0x0200

   #define WF_WINNT         0x4000

GetWinFlags() is not a part of the Win32 API. Processor information can be

found through the new Win32 API GetSystemInfo().

Additional reference words: 3.10 3.1


INF: New DLL: LOCALMON.DLL

Article ID: Q92507

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The new DLL, LOCALMON.DLL, resides in WINNT\SYSTEM32. This new DLL is a

monitor that manages ports at a high level.

Monitors are responsible for sending the print job to a port. If the port

is a communications port, the monitor will open the port (COM1), set the

baud rate, parity, and so on, as well as write the data and close the port.

Monitors allow users to print to a LaserJet IIISi, to PostScript printers

on an AppleTalk network, or to named pipes. Monitor management and UI can

be configured within the Print Manager by selecting the port from a combo

box.

Additional reference words: 3.10 3.1


INF: Distributed Computing Environment (DCE) Compliance

Article ID: Q92515

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Remote Procedure Call (RPC) is one part of the OSF Distributed Computing

Environment (DCE) model. The following background information comes from

the introduction to RPC in the "Remote Procedure Call Programmer's Guide

and Reference":

   The design and technology behind Microsoft RPC is just one part of a

   complete environment for distributed computing defined by the Open

   Software Foundation (OSF), a consortium of companies formed to define

   the components of a complete environment that supports distributed

   computing. The OSF requests proposals for standards, accepts comments on

   the proposals, votes whether to accept the standards and promulgates

   them.

Generally speaking, Microsoft has tested interoperability with DCE

connection-oriented RPC 1.0.1. We are DCE connection-oriented RPC

compliant, not compliant with the whole DCE. For example, there is no

support for the OSF DCE Core Services (that is, Directory Service, Security

Service, Time Service, and so on) or the OSF DCE Extended Services (that

is, Distributed File Service, Diskless Support Service, Personal Computer

Integration Service, and so on).

More Information:

Microsoft RPC, which interoperates with connection-oriented DCE RPC, is

supported on MS-DOS, Windows, and Windows NT. MS-DOS and Windows support

RPC clients. Windows NT supports both RPC clients and servers.

DCE has been certified using TCP/IP and UDP/IP. Microsoft RPC under MS-DOS

supports LAN Manager version 2.1 TCP only. Under Windows, TCP is supported

from any vendor that is compliant with the Windows Sockets specification.

Under Windows NT, we support the TCP packaged in the product. In

addition to those protocols, which are of interest to people looking

at interoperability, Microsoft RPC also supports NetBIOS and Named

Pipes.

The OSF will be sponsoring inter-vendor tests early in 1993. Microsoft

intends to attend. At the current time, DEC is the only vendor shipping

DCE. Microsoft has tested interoperability with Ultrix and VMS machines.

Microsoft RPC is part of the Win32 SDK. The customer has the right to

freely distribute run times with applications if the run time is not

already distributed with the operating system.

Additional reference words: 3.10 3.1


INF: Process Will Not Terminate Unless System Is In User-mode

Article ID: Q92761

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Under Windows NT, a process will not be terminated unless the system is

in user-mode. Suppose that TerminateProcess() is called while a device

driver or filesystem code is being executed. The system will wait until

the threads are running user code before marking the process for

termination. On system exit, processes that were the target of a

TerminateProcess() will be killed.

This may affect drivers. If a driver is waiting for an object or

multiple objects in WaitMode or UserMode, its wait may complete

unsuccessfully due to a termination request. Any code that does a

UserMode wait or an Alertable wait must check the return status of the

wait call. If the wait fails with STATUS_USER_APC or STATUS_ALERTED,

this is not an error. The driver should cleanup and return to user-mode.

Additional reference words: 3.10


INF: Alternatives to Using GetProcAddress With LoadLibrary

Article ID: Q92862

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

When loading a DLL with LoadLibrary(), an alternative to calling

GetProcAddress() for each of your DLL entry points is to have the DLL

initialization function initialize a global structure or array containing

the addresses of these DLL entry points, then call a DLL function from your

executable which will return the address of this structure or array to your

executable. You can then call your DLL functions via the function pointers

in this structure or array.

The best place to initialize this structure or array of function pointers

would be in the DLL_PROCESS_ATTACH code of your DLL's main entry point. The

structure or array containing these function pointers must be declared as

either a global variable or as dynamically allocated memory (malloc(),

GlobalAlloc(), etc.) in your DLL in order for the executable to be able to

address this memory properly.

It is also possible, though not as clean, to export the global structure or

array of function pointers so that your executable can use the structure or

array by name directly in your executable. For more information on how to

declare and export global data in a Win32 DLL query on the following words

in this Knowledge Base:

   global and exported and data and DLL

Be careful not to call these DLL functions via the function pointers after

the DLL is unloaded via FreeLibrary(). After FreeLibrary() is called, these

function pointer addresses are invalid and calling them will result in an

access violation.

This technique of returning pointers to DLL entry points is a supported

technique and will work on all hardware platforms that Windows NT supports.


INF: Use WSAAsyncSelect to Clear Message Queue

Article ID: Q94088

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

SYMPTOMS

   I have set a WSAAsyncSelect() call to notify me of read (FD_READ) and

   disconnection (FD_CLOSE). When a read call is posted on my message

   queue, I continually read from the socket until there are no more

   characters waiting. After each read, I use a select() call to determine

   if more data needs to be read. However, after a while, the notifications

   stop coming. Why is this?

CAUSE

   The message queue must be cleared of extraneous notification messages

   for each read notification message.

RESOLUTION

   Call WSAAsyncSelect( sockt, hWnd, 0, 0) to clear the message queue for

   each read notification.

More Information:

Sample Code

-----------

WSA_READCLOSE:

  if (WSAGETSELECTEVENT( lParam ) == FD_READ) {

    FD_ZERO( &readfds );

    FD_SET( sockt, &readfds);

    timeout.tv_sec = 0;

    timeout.tv_usec = 0;

    /* Clear the queue of any extraneous notification messages. */

    WSAAsyncSelect( sockt, hWnd, 0, 0);

    while (select(0, &readfds, NULL, NULL, &timeout) != 0) {

      recv(sockt, &ch, 1, 0);

      }

    /* Reset the message notification. */

    WSAAsyncSelect( sockt, hWnd, WSA_READCLOSE, FD_READ | FD_CLOSE);

    }

Additional reference words: 3.10 3.1


INF: Four New Win32 Memory-Handling APIs

Article ID: Q94146

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

We have added four new Win32 APIs and changed the definitions of a few NT

rtl APIs. The changes were designed so that all of our code could move,

copy, fill, and zero memory using the fastest mechanism on each platform.

Note: From now on, please use the following APIs:

   NT Code Win 32 Applications

Copy Memory - RtlCopyMemory() CopyMemory()

Moving Memory - RtlMoveMemory() MoveMemory()

Zeroing Memory - RtlZeroMemory() ZeroMemory()

Filling Memory - RtlFillMemory() FillMemory()

The difference between RtlCopyMemory() and RtlMoveMemory() is that

RtlCopyMemory() does not handle overlapped copies; it is equivalent to

memcpy(). RtlMoveMemory() handles overlapped copies (similar to

memmove()).

If you look closely at the changes made to support the memory movers, you

will see that on the x86 platform, the movers are defined to be identical

to the C run-time intrinsic movers. The x86 compilers will inline these

calls for us. On MIPS, these calls are vectored (through forwarders in

KERNEL32.DLL) to code in NTDLL.DLL.


INF: Secure Erasure Under Windows NT

Article ID: Q94239

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

File systems under Windows NT currently have virtual secure erasure (when a

file is deleted, the data is no longer accessible through the operating

system). Although the bits could still be on disk, NT will not allow access

to them.

NTFS does this by keeping a high-water mark, for each file, of bytes

written to the file. Everything below the line is real data, anything above

the line is (on disk) random garbage that used to be free space, but any

attempt to read past this high-water mark returns all zeros.

Other reusable objects are also protected. For example, all the memory

pages in a process's address space are zeroed (unlike the file system, a

process may directly access its pages, and thus the pages must be actually

zeroed rather than virtually zeroed).

Note that file system security assumes physical security; in other words,

if a person has physical access to a machine and can boot an alternative

operating system and/or add custom device drivers and programs, he/she can

always get direct access to the bits on disk.

Additional reference words: 3.10 3.1


INF: Access to Display from Win32 Services

Article ID: Q94240

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Generally, if a Win32 service needs to output to a display device, it

should do so through a client application (such as a Control Panel

application), via named pipes, an RPC (remote procedure call), or other

inter-process communication.

A Win32 service can also access the screen directly, through

MessageBoxEx(). This method, however, should be used for simple messages

(such as alerts or similar notifications). If more user-interactivity is

desired, the service must communicate through a client application, as

mentioned above.

Services may only use MessageBoxEx() through the desktop of a logged in

workstation (that is, not the WinLogon-owned desktop, which is comprised of

the CTRL+ALT+DEL/logon/locked workstation screens).

For more information, see the Windows Help entry for the Service Control

Manager.

Additional reference words: 3.10 3.1


INF: Thread Local Storage Overview

Article ID: Q94804

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Thread local storage (TLS) is a method by which each thread in a given

process is given a location(s) in which to store thread-specific data.

Four functions exist for TLS: TlsAlloc(), TlsGetValue(),

TlsSetValue(), and TlsFree(). These functions manipulate TLS indexes,

which refer to storage areas for each thread in a process. A given

index is valid only within the process that allocated it.

A call to TlsAlloc() returns a global TLS index. This one TLS index is

valid for every thread within the process that allocated it, and

should therefore be saved in a global or static variable.

Thread local storage works as follows: When TlsAlloc() is called,

every thread within the process has its own private DWORD-sized space

reserved for it (in its stack space, but this is

implementation-specific). However, only one TLS index is returned.

This single TLS index may be used by each and every thread in the

process to refer to its unique space that TlsAlloc() reserved for it.

For this reason, TlsAlloc() is often called only once. This is

convenient for DLLs, which can distinguish between DLL_PROCESS_ATTACH

(where the first process's thread is connecting to the DLL) and

DLL_THREAD_ATTACH (subsequent threads of that process are attaching).

For instance, the first thread calls TlsAlloc() and stores the TLS

index in a global or static variable, and every other thread that

attaches to the DLL refers to the global variable to access their

local storage space.

Although one TLS index is usually sufficient, a process may have up to

TLS_MINIMUM_AVAILABLE indexes (guaranteed to be greater than or equal

to 64).

Once a TLS index has been allocated (and stored), the threads within

the process may use it to set and retrieve values in their storage

spaces. A thread may store any DWORD-sized value in its local storage

(for example, a DWORD value, a pointer to some dynamically allocated

memory, and so forth). The TlsSetValue() and TlsGetValue() functions

are used for this purpose.

Note that the TlsSetValue() and TlsGetValue() functions are optimized

for speed, and therefore do minimal parameter checking. Therefore, it

is up to the programmer to ensure that the index passed to these

functions is valid.

A process should free TLS indexes with TlsFree() when it has finished

using them. However, if any threads in the process have stored a

pointer to dynamically allocated memory within their local storage

spaces, it is important to free the memory or retrieve the pointer to

it before freeing the TLS index, or it will be lost.

Using thread local storage may be a little more convenient than other

solutions, and will be more profitable in the future. In later

releases of NT, the compiler will include a keyword and compiler

switches to make thread local storage operations more automatic,

rather than through an application programming interface (API) layer.

For more information, see the Win32 Software Development Kit (SDK)

"Programming Techniques" help file under the TLS API.

Example

-------

Thread A within a process calls TlsAlloc(), and stores the index returned

in the global variable TlsIndex:

   TlsIndex = TlsAlloc();

Thread A then allocates 100 bytes of dynamic memory, and stores it in its

local storage:

   TlsSetValue( TlsIndex, malloc(100) );

Thread A creates thread B, which stores a handle to a window in its local

storage space referred to by TlsIndex.

   TlsSetValue( TlsIndex, (LPVOID)hSomeWindow );

Note that TlsIndex refers to a different location when thread B uses

it, than when thread A uses it. Each thread has its own location

referred to by the same value in TlsIndex.

Thread B may terminate safely because it does not need to specifically

free the value in its local storage.

Before thread A terminates, however, it must first free the

dynamically allocated memory in its local storage

   free( TlsGetValue( TlsIndex ) );

and then free the TLS index:

   if ( !TlsFree( TlsIndex ) )

      // TlsFree() failed.  Handle error.

Additional reference words: 3.10


INF: Physical Memory Limits Number of Processes/Threads

Article ID: Q94840

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Each time Windows NT creates a process or a thread, it must allocate a

certain amount of physical memory (significantly more for processes

than threads) for its support. The specific amount of memory allocated

has not been finalized because development is working on reducing

thread/process memory requirements. In the beta versions of Windows

NT, about 40 processes can be started on a machine with 16 megabytes

(MB) of RAM before returning out-of-memory errors.

Due to the physical memory requirement of processes and threads,

programs that use the CreateProcess() and CreateThread() APIs should

be careful to check their return codes to detect out-of-memory

conditions.

Additional reference words: 3.10


INF: PAGE_READONLY May Be Used as Discardable Memory

Article ID: Q94947

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Virtual memory pages marked as PAGE_READONLY under Win32 may be used

the way discardable segments of memory are used in Windows 3.1. These

virtual memory pages are by default not "dirty," so the system may use

them (zeroing them first if necessary) without having to first write

their contents to disk.

From a system resource perspective, PAGE_READONLY is treated similar

to discardable memory under Windows 3.1 when the system needs to free

up resources. From a programming standpoint, the system automatically

re-reads the memory when the data is next accessed (for example, we

attempt to access our page when it has been "discarded," a page fault

is generated, and the system reads it back in). Memory-mapped files

are convenient for setting up this type of behavior.

If a PAGE_READONLY memory page becomes dirty [by changing the protection

via VirtualProtect() to PAGE_READWRITE, changing the data, and restoring

PAGE_READONLY], the page will be written to disk before the system uses it.

Additional reference words: 3.10 3.1


INF: Named Pipes Under WOW

Article ID: Q94948

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

A 16-bit application under Windows on Windows (WOW) may use a named pipe

that was created previously by a 32-bit application; however, REDIR.EXE

must be included in the AUTOEXEC.BAT file for this to work properly.

For local named pipes, networking doesn't need to be enabled.

Additional reference words: 3.10 3.1


INF: Maximum GlobalAddAtom() String Size Is 32K Characters

Article ID: Q94951

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Under Win32, the maximum string length for the lpszName parameter of

GlobalAddAtom() is 32K characters (64K for Unicode) and/or available

memory.

Additional reference words: 3.10 3.0


INF: VirtualLock() Only Locks Pages into Working Set

Article ID: Q94996

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

VirtualLock() locks pages only into an application's working set; it

does not lock them absolutely into memory.

VirtualLock() lock pages into virtual memory, and therefore as long as

a given process is in real (physical) memory, the virtually locked

page is guaranteed to be in real memory as well. VirtualLock()

essentially means "this page is always part of my process's working

set."

However, the system is free to swap out any virtually locked pages if

it swaps out the whole process. And when the system swaps the process

back in, the virtually locked pages (similar to any virtual pages) may

end up residing in different real pages.

It is wise to use VirtualLock() very sparingly because it reduces the

flexibility of the system. Depending upon memory demands on the

system, the memory manager may vary the number of pages a process

can lock. Under typical conditions you can expect to be able to

VirtualLock() approximately 28 to 32 pages.

Additional reference words: 3.10 3.1


INF: Reducing the Count on a Semaphore Object

Article ID: Q94997

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

ReleaseSemaphore(), which increments the count of a given semaphore

object by a specified amount, will not take a negative value.

If, for some reason, you want to reduce the number of available

semaphore "slots" to temporarily restrict or reduce access, you may

loop calling WaitForSingleObject() with a zero timeout, counting the

number of times it succeeds. When you no longer need to hold the

semaphore slots, call ReleaseSemaphore() with the number of slots

counted.

Note that this method does not prevent other threads from taking a

semaphore slot when your thread is looping.

Additional reference words: 3.10 3.0


INF: Trapping Floating-Point Exceptions Under NT

Article ID: Q94998

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The _controlfp() function is the portable equivalent to the

_control87() function, which is documented in the Microsoft C/C++

version 7.0 "Run-Time Library Reference."

To trap floating-point (FP) exceptions via try-except (such as

EXCEPTION_FLT_OVERFLOW), insert the following before doing FP

operations:

   // Get the default control word.

   int cw = _controlfp(0,0);

   // Set the exception bits ON.

   cw &=~(EM_OVERFLOW|EM_UNDERFLOW|EM_INEXACT|EM_ZERODIVIDE|

     EM_DENORMAL);

   // Set the control word.

   _controlfp(cw, MCW_EM);

This turns on all possible FP exceptions. To trap only particular

exceptions, choose only the flags that pertain to the exceptions

desired.

By default, NT has all the FP exceptions turned off, and thus

computations result in NAN or INFINITY rather than an exception. Note,

however, that if an exception occurs and an explicit handler does not

exist for it, the default exception handler will terminate the

process.

Additional reference words: 7.00 3.10 3.1


INF: FormatMessage() Converts GetLastError() Codes

Article ID: Q94999

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The FormatMessage() application programming interface (API) allows you

to convert error codes returned by GetLastError() into error strings,

using FORMAT_MESSAGE_FROM_SYSTEM in the dwFlags parameter.

Example

-------

// This code sample demonstrates how to get the system message string:

LPVOID lpMessageBuffer;

DWORD  dwError;

FormatMessage(

  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

  NULL, dwError = GetLastError(), LANG_USER_DEFAULT,

  (LPSTR) &lpMessageBuffer, 0, NULL );

//... now display this string

LocalFree( (HLOCAL) lpMessageBuffer );

Additional reference words: 3.10 3.1


INF: FlushViewOfFile() on Remote Files

Article ID: Q95043

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

When flushing a memory-mapped file over a network, FlushViewOfFile()

guarantees that the data has been written from the workstation, but

not that the data resides on the remote disk.

This is because the server may be caching the data on the remote end.

Therefore, FlushViewOfFile() may return before the data has been

physically written to disk.

However, if the file is created [via CreateFile()] with

FILE_FLAG_WRITE_THROUGH, the remote file system will not perform lazy

writes on the file, and FlushViewOfFile() will return when the actual

physical write is complete.

Additional reference words: 3.10 3.1


INF: Default Stack in Win32 Applications

Article ID: Q97786

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

By default, space is reserved for applications in the following

manner:

   1 megabyte (MB) reserved (total virtual address space for the stack)

   4K committed (total physical memory allocated when stack is

                 created)

   Note: The -heap linker option can be used to modify both of these

         values.

The operating system will grow the stack as needed by committing 4K

blocks out of the reserved stack memory. Once all of the reserved

memory has been committed, Windows NT will attempt to continue to grow

the stack into the memory adjacent to the memory reserved for the

stack, as shown in the following:

   |<--- Total 1 MB for stack --->|<--- Adjacent memory --->|

   --------------------------------------------------------

   |       |                      |                         |

   |  4K   |   1020K  ...         |       ...               |

   |       |                      |                         |

   --------------------------------------------------------

However, once the stack grows to the point that the adjacent area is

not free (and this may happen as soon as the reserved 1 MB has been

committed), the stack cannot grow any farther. Therefore, it is very

risky to rely on this memory being free. Applications should take care

to reserve all the memory that will be needed by increasing the amount

of memory reserved for the stack.

In other cases, it may be desirable to reduce the amount of memory

reserved for the stack.

The /STACK option in the linker and the STACKSIZE statement in the DEF

file can be used to change both the amount of reserved memory and the

amount of committed memory. The syntax for each method is shown below:

   /STACK:[reserve][,commit]

   STACKSIZE [reserve][,commit]

More Information:

Each new thread gets its own stack space of committed and reserved

memory. If a new size is not specified in the CreateThread() call, the

new thread takes on the same stack size as the thread that created it,

whether that be the default value, a value defined in the DEF file, or

by the linker switch.

The system handles committing more reserved stack space when needed,

but cannot reserve or commit more than the total amount initially

reserved (or committed if no additional is reserved). Remember that

the only resource consumed by reserving space is addresses in your

process. No memory or pagefile space is allocated. When the memory is

actually committed, both memory and pagefile resources are allocated.

There is no harm in reserving a large area if it might be needed.

As always, automatic variables are placed on the stack. All other

static data is located in the process address space. Because they are

static, they do not need to be managed like heap memory.

Note that under Win32s, stacks are limited to a maximum of 128K.

Additional reference words: 3.10


PRB: Code in DLL Causes Access Violation C00000005

Article ID: Q97787

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

SYMPTOMS

   A DLL entry point with __cdecl convention results in an access

   violation (specifically, C0000005).

CAUSE

   Windows NT expects that the dynamic-link library (DLL) entry point

   will have a calling convention of __stdcall. If the entry point is

   not explicitly given a calling convention, the compiler's default

   convention is __cdecl.

   This is not an obvious mistake to track down. Under the debugger,

   you will notice that you can trace into the entry point, but the

   next function call will fail. Thus, it appears as if the execution

   of the entry point succeeded. The problem is really that the stack

   was not properly cleaned up.

RESOLUTION

   To correct the problem, do one of the following

    - Add WINAPI to the function prototype and declaration so that the

      function will have the __stdcall calling convention.

      -or-

    - Compile with -Gz so that by default, all functions will be

      declared with the __stdcall convention. If you are using

      NTWIN32.MAK, the macro "scall" is defined for this purpose.

      In addition, the entry point should be specified with the -entry

      linker switch. For example, if the entry point is named

      LibMain(), add the following to the link command line:

         -entry:LibMain$(DLLENTRY)

More Information:

The same problem occurs if callback functions, such as dialog box

procedures, are not declared __stdcall. The solutions described above

apply in this situation as well.

Additional reference words: 3.10


INF: CTRL+C Exception Handling Under WinDbg

Article ID: Q97858

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

An exception is raised for CTRL+C only if the process is being

debugged. The purpose is to make it convenient for the debugger to

catch CTRL+C in console applications. For the purposes of this

article, the debugger is assumed to be WinDbg.

When the console server detects a CTRL+C, it uses CreateRemoteThread()

to create a thread in the client process to handle the event. This new

thread then raises an exception IF AND ONLY IF the process is being

debugged. At this point, the debugger either handles the exception or

it continues the exception unhandled.

The "gh" command marks the exception as having been handled and

continues the execution. The application does not notice the CTRL+C,

with one exception: CTRL+C causes alertable waits to terminate. This

is most noticable when executing:

   while( (c = getchar()) != EOF )  - or -  while( gets(s) )

It is not possible to get the debugger to stop the wait from

terminating.

The "gn" command marks an exception as unhandled and continues the

execution. The handler list for the application is searched, as

documented for SetConsoleCtrlHandler(). The handler is executed in the

thread created by the console server.

After the exception is handled, the thread created to handle the event

terminates. The debugger will not continue to execute the application

if Go On Thread Termination is not enabled (from the Options menu,

choose Debug, and select the Go On Thread Termination check box). The

thread and process status indicate that the application is stopped at

a debug event. As soon as the debugger is given a go command, the dead

thread disappears and the application continues execution.

More Information:

There are three cases where CTRL+C doesn't cause the program to stop

executing (instead it causes a "page down"):

1. When CTRL+C is already being handled.

2. When the debugger is in the foreground and a source window has the

   focus (both must be true).

3. When the CTRL+C exception is disabled (through the Debugger

   Exceptions dialog box).

This follows the convention of the WordStar/Turbo C/Turbo Pascal

editor commands.

Additional reference words: 3.10


PRB: New Parameter for the CreateService() API

Article ID: Q97921

----------------------------------------------------------------------

The information in this article applies to:

 - Beta Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The online Win32 application programming interface (API) reference

provided with the Win32 Software Development Kit (SDK) March 1993

preliminary release incorrectly documents CreateService() as having 12

parameters. The header file WINSVC.H correctly documents

CreateService() as having a 3rd parameter named lpDisplayName.

The lpDisplayName parameter is the string that is displayed by the

Service application and when you use the command line "net

start|stop|pause|continue" syntax.

Additional reference words: 3.10


INF: The Use of the SetLastErrorEx() API

Article ID: Q97926

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

SetLastErrorEx() is intended for better debugging support, not for

passing additional error information. This function is not fully

realized under the current version of Windows NT.

The SetLastErrorEx() application programming interface (API) differs

from the SetLastError() API only in that it raises a debug "RIP"

event. The RIP event is intended to give text to the debugger so that

the user can retry, ignore, and so forth, these errors.

SetLastErrorEx() raises an exception only if SetDebugErrorLevel() has

been called by the debugger to allow the errors to be passed on.

The error type can be determined from the debugger by examining the

debug event structure that is passed with the event. The debug event

structure contains a RIP_INFO substructure.

Additional reference words: 3.10


INF: Windows NT Virtual Memory Manager Uses FIFO

Article ID: Q98216

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

On page 193 of "Inside NT," Helen Custer states that the Windows NT

virtual memory manager uses a FIFO (first in, first out) algorithm, as

opposed to a LRU (least recently used) algorithm, which the Windows

virtual memory manager uses. While it is true that FIFO can result in

a commonly used page being discarded or paged to the pagefile, there

are reasons why this algorithm is preferable.

Here are some of the advantages:

 - FIFO is done on a per-process basis; so at worst, a process that

   causes a lot of page faults will slow only itself down, not the

   entire system.

 - LRU creates significant overhead--the system must update its page

   database every single time a page is touched. However, the database

   may not be properly updated in certain circumstances. For example,

   suppose that a program has good locality of reference and uses a

   page constantly so that it is always in memory. The operating

   system will not keep updating the timestamp in the page database,

   because the process is not hitting the page table. Therefore this

   page may age even though it is in nearly constant use.

 - Pages that are "discarded" are actually kept in memory for a while,

   so if a page is really used frequently, it will be brought back

   into memory before it is written to disk.

Additional reference words: 3.10 file


PRB: Unexpected Result of SetFilePointer() with Devices

Article ID: Q98892

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

SYMPTOMS

   Open a floppy drive with CreateFile():

      h = CreateFile( "\\\\.\\a:", ... );

   Use SetFilePointer() to advance the file pointer associated with the

   file handle returned from CreateFile():

      SetFilePointer( h,    // file handle

                      5,    // distance (in bytes) to move file pointer

                   NULL,    // optional high 32-bits of distance

             FILE_BEGIN     // specifies the starting point

      );

   If the offset is not a multiple of the sector size of the floppy

   drive, the function will return success; however, the pointer will

   not be exactly where requested. The pointer value is rounded down

   to the beginning of the sector that the pointer value is in.

CAUSE

   The behavior of this application programming interface (API) is by

   design for the following reasons:

    - The I/O system is unaware of device particulars such as sector

      size; any offset is valid.

    - SetFilePointer() is very frequently used. Because speed is an

      important goal for Windows NT, time is not spent on querying

      device particulars and detecting such errors.

    - The logic to handle this situation is built into the file system,

      which actually performs the rounding, and therefore there was no

      need to put this into the code for SetFilePointer().

RESOLUTION

   When using SetFilePointer() with a handle that represents a floppy

   drive, the offset must be a multiple of the sector size for the

   floppy drive in order for the function to perform as expected.

More Information:

Think of a file pointer as merely a stored value, which is where the

next read or write will take place. In fact, it is possible to

override this value on either the read or write itself, using certain

APIs, by supplying a different location. The new pointer location is

remembered after the operation. Therefore, the operation of "setting a

file pointer" merely means to go store a large integer in a cell in

the system's data structures, for possible use in the next file

operation. In the case of a handle to a device, the file pointer must

be on a sector boundary.

In a similar way, ReadFile() only reads amounts that are multiples of

the sector size if it is passed a handle that represents a floppy

drive.

Additional reference words: 3.10 3.1


INF: Limit on the Number of Bytes Written Asynchronously

Article ID: Q98893

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

There is a limit to the number of bytes that can be written with

WriteFile() using asynchronous I/O (FILE_FLAG_OVERLAPPED specified).

This limit depends on the size of your system.

Asynchronous (overlapped) I/O consumes system resources for a long

time. For example, the memory used is locked in the process working

set until the I/O completes. To limit the amount of system resources

used asynchronously by an application, the system charges asynchronous

I/O to the working set of the process requesting the I/O.

While the working set size is dynamically raised and lowered based on

the load, there are minimum and maximum values. These values are based

on system size: consider up to 12 megabytes (MB) a small system,

between 12 MB and 19 MB a medium system, and greater than 19 MB a

large system. Each process is guaranteed a minimum working set for

performance reasons; about 120K for small systems, 160K for large

systems, and 245K for large systems.

When system resources are heavily taxed, a process is confined to its

maximum working set. Asynchronous I/Os may never cause you to exceed

your maximum working set, because once you are allowed to initiate an

asynchronous I/O, the page cannot be taken away if memory becomes

tight. The maximum working set sizes are about 300K for a small

system, 716K for a medium system, and 1.5 MB for a large system.

More Information:

The following code can be used to experiment with the maximum number

of bytes that can be written using asynchronous I/O. Simply change the

line to vary the number of bytes that the code attempts to write:

   #define NBR_BYTE 700000

Sample Code

-----------

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <assert.h>

#include <windows.h>

#define NBR_BYTE 700000

int main(void)

{

   char        *c;

   HANDLE      hFile;

   DWORD       byteWrite;

   OVERLAPPED  overLap;

   DWORD       err;

   BOOL        result;

   c = malloc( NBR_BYTE );

   assert( c != NULL );

   overLap.hEvent = CreateEvent( NULL, FALSE, FALSE, "event1" );

   assert( overLap.hEvent );

   hFile = CreateFile( "test", GENERIC_WRITE, 0,  NULL, OPEN_ALWAYS,

                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED |

                       FILE_FLAG_WRITE_THROUGH,

                       NULL);

   if( hFile == INVALID_HANDLE_VALUE )

   {

      free( c );

      printf( "error opening file\n" );

      exit( 0 );

   }

   overLap.Offset     = 0;

   overLap.OffsetHigh = 0;

   result = WriteFile( hFile, c, NBR_BYTE, &byteWrite, &overLap );

   if( result == FALSE )

   {

      err = GetLastError( );

      if( err != ERROR_IO_PENDING )

      {

         free( c );

         printf( "Error: %d\n", GetLastError() );

         exit( 0 );

      }

   }

   free( c );

   return 0;

}

Additional reference words: 3.10 3.1 asynch


INF: Using GMEM_DDESHARE in Win32 Programming

Article ID: Q99114

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The GMEM_DDESHARE flag remains a legitimate value for GlobalAlloc().

This flag can be used to indicate that the memory will be used for one

of the following so that the system can optimize the allocation for

these special needs:

   DDE

   OLE 1.0

   Clipboard operations

However, GlobalAlloc( GMEM_DDESHARE, ...) cannot be used to allocate a

block of memory that can be shared between processes. This flag was

never intended for this purpose, even under Windows versions 3.0 and

3.1 (3.x). GlobalAlloc( GMEM_DDESHARE, ...) works in this case because

all Windows 3.x applications share the same address space; this is not

the case under Windows NT.

All allocations of global shared memory can be used within the process

that they are allocated in, but another mechanism is required to share

memory between processes.

Additional reference words: 3.00 3.10


INF: Preventing the Console from Disappearing

Article ID: Q99115

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

When a console application is started from the File Manager, from the

Program Manager, or by typing "start <progname>" from the command

prompt, it executes in its own console. This console disappears as

soon as the application terminates, and therefore the user can't read

anything written to the screen between the last pause and program

exit. To resolve this problem, the programmer should pause the

application before termination to allow the user to read all of the

information on the screen.

It is not likely that the programmer will want to introduce this pause

if the application is started directly from the command prompt,

because in this situation it won't make much sense to the user.

However, there is no API (application programming interface) that

directly determines whether or not the application shares a console

with CMD.EXE. There is a method that can be used to determine this

information in most cases. When the application first starts up, call

GetConsoleScreenBufferInfo(). If the cursor position is (0, 0), then

the application has its own console, which will disappear when the

application terminates. Otherwise, the application is operating within

a console belonging to another program, typically CMD.EXE.

Note: This method will not work if the user combines a clear screen

(CLS) and execution of the application into one step ([C:\] CLS &

<progname>), because the cursor position will be (0, 0), but the

application is using the console, which belongs to CMD.EXE.

More Information:

To start a console application with its own console that will not

disappear when the application is terminated, use CMD /K. For example,

use "start CMD /K <progname>".

Note that it is possible to programmatically force an application to

always have its own console by immediately doing a FreeConsole() and

an AllocConsole(). The disadvantage is that the C run-time handles are

no longer valid. Use CreateFile( "CONIN$", ... ) with

lpsa->bInherit=TRUE, in combination with _open_osfhandle() and dup2()

to close the current handles (stdin, stdout, stderr) and associate

handles that will be inherited.

Additional reference words: 3.10


INF: Performing a Clear Screen (CLS) in a Console Application

Article ID: Q99261

Summary:

There is no Win32 application programming interface (API) that will

clear the screen in a console application. However, it is fairly easy

to write a function that will programmatically clear the screen. The

following function is an example:

void cls( HANDLE hConsole )

{

   COORD coordScreen = { 0, 0 };    /* here's where we'll home the

                                       cursor */

   BOOL bSuccess;

   DWORD cCharsWritten;

   CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */

   DWORD dwConSize;                 /* number of character cells in

                                       the current buffer */

   /* get the number of character cells in the current buffer */

   bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );

   PERR( bSuccess, "GetConsoleScreenBufferInfo" );

   dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

   /* fill the entire screen with blanks */

   bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',

      dwConSize, coordScreen, &cCharsWritten );

   PERR( bSuccess, "FillConsoleOutputCharacter" );

   /* get the current text attribute */

   bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );

   PERR( bSuccess, "ConsoleScreenBufferInfo" );

   /* now set the buffer's attributes accordingly */

   bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes,

      dwConSize, coordScreen, &cCharsWritten );

   PERR( bSuccess, "FillConsoleOutputAttribute" );

   /* put the cursor at (0, 0) */

   bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );

   PERR( bSuccess, "SetConsoleCursorPosition" );

   return;

}

Additional reference words: 3.10 clearscreen


PRB: SetConsoleOutputCP() Not Functional

Article ID: Q99795

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

SYMPTOMS

--------

SetConsoleOutputCP() apparently has no effect.

CAUSE

-----

SetConsoleOutputCP() was designed to change the mapping of the 256

8-bit character values into the glyph set of a fixed-pitch Unicode

font, rather than loading a separate, non-Unicode font for each call

to SetConsoleOutputCP(). Unfortunately, a fixed-pitch Unicode font was

not available by release time, so you can't view the effects of the

SetConsoleOutputCP() application programming interface (API) because

the currently available console fonts are not Unicode fonts.

STATUS

------

Microsoft has confirmed this to be a limitation in Windows NT version

3.1. We will post new information here in the Microsoft Knowledge Base

as it becomes available.

Additional reference words: 3.10


INF: Detecting Windows NT from a DOS Application

Article ID: Q100290

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

There are procedures that DOS applications can do that are not

supported under Windows NT. For example, calling Interrupt 25h to read

the disk is not supported under Windows NT. Therefore, in some cases

DOS applications will need to know whether or not they are running

under Windows NT.

Interrupt 21h, function 3306h can be used by DOS applications to

detect whether or not they are running under Windows NT. On return,

registers BL and BH will contain the operating system major and minor

numbers, respectively. If your application is running under Windows

NT, the return will be:

   BL = 5

   BH = 50

More Information:

Note that it is important to check both BL and BH, because MS-DOS 5.0

will also return a 5 in BL.

The following code demonstrates how to detect the operating system

version:

Sample Code

-----------

#include <stdio.h>

#include <stdlib.h>

#include <io.h>

void main()

{

   unsigned char cbh = 0;

   unsigned char cbl = 0;

   unsigned char cdl = 0;

   unsigned char cdh = 0;

   _asm {

      mov ax, 3306h

      int 21h

      mov cbh, bh

      mov cbl, bl

   }

   printf( "After int 21h\n" );

   printf( "%d, %d (bh, bl)\n", cbh, cbl );

}

Additional reference words: 3.10


INF: Restriction on Named-Pipe Names

Article ID: Q100291

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

Named pipes are implemented in Windows NT using the same approach used

for file systems. Within Windows NT, named pipes are represented as

file objects.

During the design phase, one idea for the implementation was to allow

subdirectories of named pipes. For example, a developer could create a

named pipe subdirectory called \MYPIPES. It would then be possible to

create and use pipes called \MYPIPES\PIPE1 and \MYPIPES\PIPE2, but it

would not be possible to use \MYPIPES as a pipe.

In the end, this idea was not implemented, so subdirectories are not

supported. This does have some effect on the named-pipe names that are

allowed. If a pipe named \MYPIPES is created, it is not possible to

subsequently create a pipe named \MYPIPES\PIPE1, because \MYPIPES is

already a pipe name and cannot be used as a subdirectory. It is

possible to create a pipe named \MYPIPES\PIPE1, but only if there is

no pipe named \MYPIPES.

Additional reference words: 3.10


INF: Replacing the Shell (Program Manager)

Article ID: Q100328

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

To replace the current shell, change the following registry key:

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      MICROSOFT\

      Windows NT\

      Current Version\

      Winlogon\

      Shell

Note that Program Manager combines the functionality of Program

Manager and Task Manager (the Task Manager installed is not actually

run). Therefore, if the new shell does not replace the Task Manager

functionality, the replacement string should contain both the new

shell name and TASKMAN.EXE, separated by commas.

To update the string that is retrieved when calling

GetPrivateProfileString(), change the string in the following registry

key:

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      MICROSOFT\

      Windows NT\

      Current Version\

      WOW\

      Boot\

      Shell

The duplicate entry is for compatibility with Windows 3.1.

More Information:

WritePrivateProfileString() changes the following registry key:

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      MICROSOFT\

      Windows NT\

      Current Version\

      WOW\

      Boot\

      Shell

It does not have the desired effect of actually changing the Shell.

Additional reference words: 3.10


INF: CPU Quota Limits Not Enforced

Article ID: Q100329

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

On page 88 of "Inside Windows NT," Table 4-1 indicates that a process

object contains a quota limit for the maximum amount of processor time

that the process can use.

This limit is not enforced in Windows NT version 3.1.

Additional reference words: 3.10


INF: Global Classes in Win32

Article ID: Q80382

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Under 16-bit Windows (Win16), when an application wants to check

whether or not a window class has been previously registered in the

system, it typically checks hPrevInstance. Under Win32,

hPreviousInstance always returns FALSE. Thus, the window class will be

reregistered by all .EXEs using the DLL that contains the window

class, unless the check for hPrevInstance is called from a process

that is spawned by the process that first registered the class.

More Information:

A class is registered for a process context only. A class definition

is not available outside the process context of the process that

originally registered it.

Although an application can enumerate windows and retrieve the class

name of a class registered in another process, they will not be able

to use that class within their process.


INF: Use of DLGINCLUDE in Resource Files

Article ID: Q91697

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The Windows 3.1 SDK dialog editor needs a way to know what include file is

associated with a resource file that it opens. Rather than prompt the user

for the name of the include file, the name of the include file is embedded

in the resource file in most cases.

Embedding the name of the include file is done with a resource of type

RCDATA with the special name DLGINCLUDE. This resource is placed into the

.RES file and contains the name of the include file. The dialog editor

looks for this resource when it loads a .RES file. If this resource is

found, then the include file is opened also; if not, the editor prompts the

user for the name of the include file.

In some Windows 3.1 build environments, the dialog editor was used to

create dialogs that were placed in more than one .DLG file. These different

.DLG files were then included in one .RC file, which was compiled with the

resource compiler. Therefore, the resource file gets multiple copies of a

RCDATA type resource with the same name, DLGINCLUDE, but the resource

compiler and dialog editor don't complain.

In the Win32 SDK, changes were made so that this resource has its own

resource type; it was changed from an RCDATA-type resource with the

special name, DLGINCLUDE, to a DLGINCLUDE resource type whose name can

be specified. The dialog editor would look for resources of the type

DLGINCLUDE.

Changes were made to CvtRes so that it gives an error if it finds a

resource that has the same type, name, and language as another

resource in the file. We are being more strict about the need for

resources to be unique in the Win32 SDK than the Windows 3.1 SDK. This

is good because there was never any guarantee at run time as to which

of the two or more resources would be returned by LoadResource().

This means that some applications being ported to Windows NT give an error

when their resources are compiled because they have duplicate RCDATA type

resources with the same name (DLGINCLUDE). This error is by design. The

workaround is straightforward: delete all the DLGINCLUDE RCDATA type

resource statements from all the .DLG files.

Finally, because it does not make sense to have the DLGINCLUDE type

resources in the executable, CvtRes will strip them out so that they don't

get linked into the EXE.

Additional reference words: 3.10 3.1


INF: Multiple Desktops Under Windows NT

Article ID: Q92505

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Win32 does not support sharing the same desktop between two monitors on the

same machine. An independent software vendor (ISV) that wants this

capability must write a display device driver that behaves similar to a

normal driver with a single monitor, but actually controls two monitors.

Additional reference words: 3.10 3.1


INF: DDEML Application-Instance IDs Are Thread Local

Article ID: Q94091

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

When using the DDEML (Dynamic Data Exchange Management Library) libraries

from a spawned thread, the application-instance ID that is returned in the

lpidInst parameter of DdeInitialize is thread local.

Therefore, the application-instance ID cannot be used by any other thread

that is spawned by the process, nor can it be inherited from the parent.

To use the DDEML libraries within a thread, it is necessary to make both

the DdeInitialize call and to use the DdeUninitialize call from within the

thread; otherwise, there is no way to terminate the DDEML session.

Additional reference words: 3.10 3.1


INF: Freeing PackDDElParam() Memory

Article ID: Q94149

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

When posting DDE messages via PostMessage(), an application first calls

PackDDElParam() and sends its return value (a pointer cast to LPARAM) as

the lParam in PostMessage().

Normally the receiving application is responsible for freeing the structure

[via FreeDDElParam()]. However, if the call to PostMessage() fails, the

posting application must free the packed data. This is also the method used

by 16-bit Windows

Additional reference words: 3.10


INF: Clarification of COMMPROP Max?xQueue Members

Article ID: Q94950

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

In the COMMPROP structure, the dwMaxTxQueue and dwMaxRxQueue members state

"a value of 0 means that this field is not used" in their descriptions.

This statement means that the provider does not restrict you to maximum Rx

and Tx queue values, and these members [returned by GetCommProperties()]

should not be used to determine the size of your transmit and receive

buffers when calling SetupComm().

Based on the memory present in the system, NT's serial driver

determines a default Rx queue size (currently 128 bytes on low memory

systems and 4K on high memory systems). The current Rx and Tx queue

sizes are located in the dwCurrentTxQueue and dwCurrentRxQueue

members.

SetupComm() allows you to change these default queue sizes. However, you

should not assume that the given serial driver will allocate any memory.

The queue size allocated is stored in the dwCurrentRxQueue member of the

COMMPROP structure. You may use this information to set the XonLim and

XoffLim members of the device control block (DCB) structure.

The Microsoft-supplied serial driver attempts to allocate at least the

amount requested for the RXQUEUE and, failing this, the request will also

fail. The driver never attempts to allocate memory for the TXQUEUE.

Additional reference words: 3.10 3.1


INF: OpenComm() and Related Flags Obsolete Under Win32

Article ID: Q94990

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

OpenComm(), a Windows 3.1 application programming interface (API), is

obsolete under Win32 and is not in the Win32 API. Also, the flags

IE_BADID, IE_BAUDRATE, IE_BYTESIZE, IE_DEFAULT, IE_HARDWARE,

IE_MEMORY, IE_NOPEN, and IE_OPEN are obsolete, but are still in the

header files. However, these flags will be removed from the retail

release.

These flags and the OpenComm() API do exist for Win16 applications

running under Windows on Windows (WOW).

Under Win32, CreateFile() is used to create a handle to a

communications resource (for example, COM1). The fdwShareMode

parameter must be 0 (exclusive access), the fdwCreate parameter must

be OPEN_EXISTING, and the hTemplate parameter must be NULL. Read,

write, or read/write access can be specified, and the handle can be

opened for overlapped I/O.

The standard I/O API ReadFile() and WriteFile() are used for

communciations I/O. The TTY sample program shipped with the Win32

Software Development Kit (SDK) demonstrates how to do serial I/O under

Win32.

Additional reference words: 3.10 3.1


INF: Distinguishing Between Keyboard ENTER and Keypad ENTER

Article ID: Q96242

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

It is possible using ReadConsoleInput() or PeekConsole() to

distinguish between the ENTER key on the main keyboard and the ENTER

key on the numeric keypad. The KEY_EVENT_RECORD structure in the

INPUT_RECORD structure must be used to distinguish between the two

keys.

The following illustrates what the KEY_EVENT_RECORD structure is

filled with after a keyboard ENTER key versus a numeric keypad ENTER

key is pressed.

Keyboard ENTER Key

------------------

   KeyEvent.wRepeatCount     = 1

   KeyEvent.wVirtualKeyCode  = 13

   KeyEvent.wVirtualScanCode = 28

   KeyEvent.dwControlKeyState= 00000000

Numeric Keypad ENTER Key

------------------------

   KeyEvent.wRepeatCount     = 1

   KeyEvent.wVirtualKeyCode  = 13

   KeyEvent.wVirtualScanCode = 28

   KeyEvent.dwControlKeyState= 00000100

In the case of the numeric keypad ENTER key, in dwControlKeyState,

ENHANCED_KEY bit is set.

Additional reference words: 3.10


PRB: Setting Hooks Locally or Globally

Article ID: Q97919

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The application programming interface (API) SetWindowsHookEx() allows

the developer to control whether hooks get set globally or locally. As

with Windows version 3.1, the API SetWindowsHook() is used for local

hooks only. The documentation does not make this distinction clear.

Additional reference words: 3.10


INF: SetActiveWindow() and SetForegroundWindow() Clarification

Article ID: Q97925

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

By default, each thread has an independent input state (its own active

window, its own focus window, and so forth). SetActiveWindow() always

logically sets a thread's active window state. To force a window to

the foreground, however, use SetForegroundWindow().

SetForegroundWindow() activates a window and forces the window into

the foreground. SetActiveWindow() always activates, but it brings the

active window into the foreground only if the thread is the foreground

thread.

Applications can call AttachThreadInput() to allow a set of threads to

share the same input state. By sharing input state, the threads share

their concept of the active window. By doing this, one thread can

always activate another thread's window. This application programming

interface (API) is also useful for sharing focus state, mouse capture

state, keyboard state, and window Z-order state among windows created

by different threads whose input state is shared.

Additional reference words: 3.10


PRB: AttachThreadInput() Resets Keyboard State

Article ID: Q100486

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

SYMPTOMS

--------

Start with a program that calls AttachThreadInput() to a thread in

another process. Call GetKeyboardState() to get the current key. Call

SetKeyboardState() to set the keystate. This call returns TRUE,

indicating success, but the keystate is not successfully set.

If the thread is in the same process, calling SetKeyboardState() works

as expected.

CAUSE

-----

When attaching to another thread, a temporary message queue is

created. This queue contains a copy of the keystate information from

the queue to which you are attaching. When the keystate is set, the

temporary queue keystate is updated and the application programming

interface (API) succeeds. However, when the detach occurs, the

keystate change information is lost and reverts to what it was before

the attach.

RESOLUTION

----------

To work around the problem, either:

 - Stay attached

   -or-

 - Use hooks

STATUS

------

This problem will not be resolved in the release of Windows NT version

3.1; however, a resolution is being considered for a future release.

Additional reference words: 3.10


INF: System Versus User Locale Identifiers

Article ID: Q100488

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

In Windows NT version 3.1, the following pairs of application

programming interfaces (APIs) have the same functionality:

   GetSystemDefaultLCID() and GetUserDefaultLCID()

   GetSystemDefaultLangID() and GetUserDefaultLangID()

The user LangID and LCID are always set to the system value. In future

versions of Windows NT, it will be possible to set the LangID and the

LCID on a per-user basis.

Note that it is possible to set the LCID on a per-thread basis [that

is, SetThreadLocale()] in Windows NT 3.1.

Additional reference words: 3.10


INF: Transparent Blts in Windows NT

Article ID: Q89375

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

In order to perform a transparent blt in Microsoft Windows versions

3.0 and 3.1, the BitBlt() function must be called two or more times.

This process involves nine steps. (For more information on this

process, see article Q79212 in the Microsoft Knowledge Base.)

Windows NT introduces a new method of achieving transparent blts. This

method involves the use of the MaskBlt() function. The MaskBlt()

function lets you use any two arbitrary ROP3 codes (say, SRCCOPY and

BLACKNESS) and apply them on a pel-by-pel basis using a mask.

More Information:

For this example, the source and target bitmaps contain 4 BPP. The call

to the MaskBlt() function is as follows:

   MaskBlt(hdcTrg,  // handle of target DC

                0,  // x coord, upper-left corner of target rectangle

                0,  // y coord, upper-left corner of target rectangle

               15,  // width of source and target rectangles

               15,  // height of source and target rectangles

           hdcSrc,  // handle of source DC

                0,  // x coord, upper-left corner of source rectangle

                0,  // y coord, upper-left corner of source rectangle

          hbmMask,  // handle of monochrome bit-mask

                0,  // x coord, upper-left corner of mask rectangle

                0,  // y coord, upper-left corner of mask rectangle

       0xAACC0020   // raster-operation (ROP) code

                );

The legend is as follows

   '.' = 0,

   '@' = 1,

   '+' = 2,

   '*' = 3,

   '#' = 15

Source Bitmap      Mask Bitmap        Target Bitmap      Result

------------------------------------------------------------------------

***+++***+++***    .......@.......    ###############    #######*#######

***+++***+++***    ......@@@......    ###############    ######***######

***+++***+++***    .....@@@@@.....    ##...........##    ##...+***+...##

+++***+++***+++    ....@@@@@@@....    ##...........##    ##..**+++**..##

+++***+++***+++    ...@@@@@@@@@...    ##...........##    ##.***+++***.##

+++***+++***+++    ..@@@@@@@@@@@..    ##...........##    ##+***+++***+##

***+++***+++***    .@@@@@@@@@@@@@.    ##...........##    #**+++***+++**#

***+++***+++***    @@@@@@@@@@@@@@@    ##...........##    ***+++***+++***

***+++***+++***    .@@@@@@@@@@@@@.    ##...........##    #**+++***+++**#

+++***+++***+++    ..@@@@@@@@@@@..    ##...........##    ##+***+++***+##

+++***+++***+++    ...@@@@@@@@@...    ##...........##    ##.***+++***.##

+++***+++***+++    ....@@@@@@@....    ##...........##    ##..**+++**..##

***+++***+++***    .....@@@@@.....    ##...........##    ##...+***+...##

***+++***+++***    ......@@@......    ###############    ######***######

***+++***+++***    .......@.......    ###############    #######*#######

Note that the ROP "AA" is applied where 0 bits are in the mask and the

ROP "CC" is applied where 1 bit is in the mask. This a transparency.

When creating a ROP4, you can use the following macro:

   #define ROP4(fore,back) ((((back) << 8) & 0xFF000000) | (fore))

This macro can be used to call the MaskBlt() function as follows:

   MaskBlt(hdcDest, xTrgt, yTrgt,

                          cx, cy,

              hdcSrc, xSrc, ySrc,

           hbmMask, xMask, yMask,

        ROP4(PATCOPY, NOTSRCCOPY)

                               );

This call would draw the selected brush where 1 bit appears in the mask

and bitwise negation of the source bitmap where 0 bits appear in the

mask.

Additional reference words: 3.10 pixel


INF: Using DocumentProperties() Instead of ExtDeviceMode()

Article ID: Q89867

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Applications written for Win32 should use the DocumentProperties()

application programming interface (API) function to alter the

properties of a document instead of using the ExtDeviceMode() API

function. ExtDeviceMode() is used by Windows 3.0 and 3.1 applications

and is supported in the WOW layer of the Win32 API. ExtDeviceMode()

calls DocumentProperties(), so calling ExtDeviceMode() is slower than

calling DocumentProperties() directly.

Specifying the DM_UPDATE mask allows an application to change printer

settings when using DocumentProperties(). Applications should also be

aware that the GetProcAddress() API function is now case sensitive.


INF: PSTR's in OUTLINETEXTMETRIC Structure

Article ID: Q90085

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The OUTLINETEXTMETRIC structure ends with four fields of type PSTR. The

four fields in question are not actually absolute pointers. They are

offsets from the beginning of the OUTLINETEXTMETRIC structure to the

strings in question, as the documentation indicates:

   otmpFamilyName

      Specifies the offset from the beginning of the structure to a

      string specifying the family name for the font.

   otmpFaceName

      Specifies the offset from the beginning of the structure to a

      string specifying the face name for the font. (This face name

      corresponds to the name specified in the LOGFONT structure.)

   otmpStyleName

      Specifies the offset from the beginning of the structure to a

      string specifying the style name for the font.

   otmpFullName

      Specifies the offset from the beginning of the structure to a

      string specifying the full name for the font. This name is

      unique for the font and often contains a version number or

      other identifying information.

The only difference between this structure in Windows 3.1 and Windows NT is

that the strings may be stored in either Unicode or ASCII under NT.

Additional reference words: 3.10


PRB: IsGdiObject() Is Not a Part of the Win32 API

Article ID: Q91072

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

SYMPTOMS

   There doesn't seem to be an IsGdiObject() function in Win32 in either

   the API reference or the header files.

CAUSE

   The function was added to the Windows 3.1 API because passing a handle

   to a non-GDI object to a GDI function causes a GP fault under Windows

   3.0. Win32 on Windows NT detects whether the APIs are passed an

   inappropriate handle, and the function returns an error.

RESOLUTION

   IsGdiObject() is not needed for Win32 on Windows NT.

Additional reference words: 3.10 3.1 3.00 3.0


INF: Use of DocumentProperties() vs. ExtDeviceMode()

Article ID: Q92514

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Windows applications have used ExtDeviceMode() to retrieve or modify device

initialization information for printer drivers. The Win32 API introduces a

new function DocumentProperties() that applications can use to configure

the settings of the printer.

Note that ExtDeviceMode() calls DocumentProperties(); therefore, it is

faster for applications to use DocumentProperties() directly.

Windows 3.x applications running on Windows NT (WOW) can call

ExtDeviceMode(). The spooler's ExtDeviceMode() entry is intended for WOW

use.

Additional reference words: 3.00 3.0 3.10 3.1


INF: Font-Related APIs & Structures Removed from Win32/NT

Article ID: Q93465

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The following font-related APIs, structures, constants, and typedefs are

being removed from Win32/NT. They are being removed due to schedule

constraints and because they do not extend well to systems with large

numbers of fonts installed. Additional design work will be done and a

better solution provided in a future release.

APIs:

   EnumNearestFont()

   SetFontMapperControls()

   GetFontMapperControls()

   AddFontModule()

   RemoveFontModule()

Structures:

   tagFMPENALTYSET

   tagFMWEIGHTSET

   tagFMATCH

   tagFMCONTROLS

Constants:

   FMATCH_EXACT

   FMATCH_NEAR

   FMATCH_FAR

   FMATCH_ERROR

   PANOSE_RANGE

   FM_LOCATION_GDI

   MAPPER_INDEX_TERMINATE

   MAPPER_INDEX_HEIGHT

   MAPPER_INDEX_WIDTH

   MAPPER_INDEX_ESCAPEMENT

   MAPPER_INDEX_ORIENTATION

   MAPPER_INDEX_WEIGHT

   MAPPER_INDEX_ITALIC

   MAPPER_INDEX_UNDERLINE

   MAPPER_INDEX_STRIKEOUT

   MAPPER_INDEX_CHARSET

   MAPPER_INDEX_OUTPRECISION

   MAPPER_INDEX_CLIPPRECISION

   MAPPER_INDEX_QUALITY

   MAPPER_INDEX_PITCHANDFAMILY

   MAPPER_INDEX_FACENAME

   MAPPER_INDEX_FULLNAME

   MAPPER_INDEX_STYLE

   MAPPER_INDEX_PANOSE

   MAPPER_INDEX_VENDORID

   MAPPER_INDEX_ASPECT

   MAPPER_INDEX_LOCATION

   MAPPER_INDEX_LAST

   SIZEOFMAPORDER

   SIZEOFFMCONTROLS

Typedefs:

   FMORDER

Additional reference words: 3.10


INF: Device Contexts: Using Across Threads

Article ID: Q94236

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

A window created with the CS_OWNDC style retains its device context (DC)

attributes across GetDC() calls.

However, the DC attributes are not retained if the GetDC() calls are called

from different threads. This is by design because DCs are thread-based. In

the Win32 user interface, if the calling thread is not the owner of the

window, then GetDC() returns a cache DC instead of the owned DC handle.

To save attributes across threads, one must create a routine to initialize

DC attributes, which is then called from threads not owning the given

window.

Additional reference words: 3.10 3.1


INF: 16 and 32 Bits-Per-Pel Bitmap Formats

Article ID: Q94326

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Win32 supports the same bitmap formats as Microsoft Windows version 3.1,

but includes two new formats: 16 and 32 bits-per-pel.

For DIBs (device independent bitmaps), the 16- and 32-bit formats contain

three DWORD masks in the bmiColors member of the BITMAPINFO structure (the

color table), instead of the array of RGBQUAD structures for 1-, 4-, and

8-bit formats). These masks specify which bits in the pel correspond to

which color.

The three masks must have contiguous bits, and their order is assumed to be

R, G, B (high bits to low bits). The order of the three masks in the color

table must also be first red, then green, then blue (RGB). In this manner,

the programmer can specify a mask indicating how many shades of each RGB

color will be available for bitmaps created with CreateDIBitmap().

For 16-bit bitmaps, CreateBitmap() defaults to the 5+5+5 format. The

formats 6+5+5 and 6+6+4 are also supported by this method.

Example

-------

The 5-5-5 format masks are:

   0x00007C00  red   (0000 0000 0000 0000 0111 1100 0000 0000)

   0x000003E0  green (0000 0000 0000 0000 0000 0011 1110 0000)

   0x0000001F  blue  (0000 0000 0000 0000 0000 0000 0001 1111)

For 16 bits-per-pel, the upper half of the DWORDs are always zeroed.

Usage

-----

When using 16- and 32-bit formats, there are also certain fields of the

BITMAPINFOHEADER structure that must be set to the correct values:

1. The biCompression member must be set to BI_BITFIELDS, or the DIB API

   will fail. This indicates that there are bit fields in the bitmap rather

   than encoded color indexes (as in 4- or 8-bit formats).

2. The biClrUsed member must be set to 3 (or 0, which means use the maximum

   number of color table entries for that format, which for 16 and 32 bits-

   per-pel is 3). The member names are a bit misleading in these cases,

   because the "color table" (the bmiColors entry of the BITMAPINFO

   structure) is not being used to store a list of colors, but 3 bit masks.

A technical note related to this subject from the Microsoft Multimedia

group is also available. It can be obtained from CompuServe in the WINEXT

and WINSDK forums. The filename is VFW.ZIP. In addition, the technote is

available by calling Microsoft Developer Services at (800) 227-4679,

extension 11771. The technical note is part of the Video for Windows

technical notes and describes how to create a display driver that supports

these new DIB formats, which are used by Video for Windows. The technical

note also includes definitions of installable image codecs.

Additional reference words: 3.10 technote


INF: Advantages of Device-Dependent Bitmaps

Article ID: Q94918

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

A DDB (device-dependent bitmap) is much faster than a DIB (device

independent-bitmap) to BitBlt(). For this reason, it is often a good

strategy under Win32 (as well as under Windows 3.1) to create a DDB from a

DIB when caching or calling *Blt() functions.

The slight drawback of memory overhead for the DDB is handled well by

Win32. Under Windows 3.1, the DDB memory could be marked as discardable.

Under Win32, the memory will be paged out if system resources become tight

(at least until the next repaint); if the memory is marked as

PAGE_READONLY, it can be efficiently reused, [see VirtualProtect() in the

Win32 application programming interface (API) Help file].

However, saving the DDB to disk as a mechanism for transfer to other

applications or for later display (another invocation) is not recommended.

This is because DDBs are driver and driver version dependent. DDBs do not

have header information, which is needed for proper translation if passed

to another driver or, potentially, to a later version of the driver for the

same card.

Additional reference words: 3.10 3.1 win3.1


INF: Set/ModifyWorldTransform() Requires SetGraphicsMode()

Article ID: Q94922

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

SetWorldTransform() and ModifyWorldTransform() fail if GM_ADVANCED

mode is not previously set by calling SetGraphicsMode().

Likewise, if the graphics mode in the device context (DC) is set to

GM_ADVANCED and the world transform is set to anything but the identity

transform, the DC cannot be reset to the default mode (GM_COMPATIBLE)

unless the world transform is first reset to the identity transform.

Thus, applications involving SetWorldTransform() or ModifyWorldTranform()

should be changed so that SetGraphicsMode(hdc,GM_ADVANCED) is called first.

Additional reference words: 3.10 3.1


INF: Use 16-Bit .FON Files for Cross-Platform Compatibility

Article ID: Q100487

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

The AddFontResource() function installs a font resource in the GDI

font table. Under Windows NT, the module can be a .FON file or a .FNT

file. Under Windows 3.1, the module must be a .FON file. When using

Win32s, AddFontResource() passes its argument to the Win16

AddFontResource, and therefore .FON files should be used for

portability.

In addition, when running under Windows NT, the module can be either a

32-bit "portable executable" or a 16-bit .FON file. However, if the

same Win32 executable is run under Win32s, the call to

AddFontResource() fails if the *.FON is not in 16-bit format.

Therefore, for compatibility across platforms, use 16-bit *.FON files.

These can be created using the Windows 3.1 Software Development Kit

(SDK).

Additional reference words: 3.10


INF: Description of Win32s API

Article ID: Q83520

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

The following is intended as an introduction to Win32s.

More Information:

General Overview

----------------

Win32s is an API (application programming interface) intended for

development for both Windows 3.1 (hereafter referred to as Win16) and

Win32 environment. The purpose of Win32s is to provide an API to

developers that will allow binary compatible code across both

environments.

Win32 consists of the Win16 API stretched to 32 bits, plus the

addition of new API functions that offer new functionality. Win32s

contains a subset of the Win32 API, function stubs for the Win32 API

functions that Win16 will not support, and new API to support the

Universal Thunk (UT). Among the new features gained from Win32 are

Structured Exception Handling (SEH), FP emulation, memory-mapped

files, named shared memory, and sparse memory. ALL the Win32 API

functions are included in Win32s, however those that are not supported

will return an error code. For details on which API are supported

under Win32s, refer to the entries in the helpfile "Win32 API

Reference."

When you call a Win32s API function, two options should be allowed:

 - Option A: Your code should allow for a successful return from the

   function call.

 - Option B: Your code should allow for an unsuccessful return from

   the function call.

For example, if the code is running under Windows 3.1 and the function

call is made to one of the API functions in the subset supported on

Windows 3.1, then the call returns successfully and option A is

executed. If the call is made while running under the Windows NT

environment, the call again returns successfully and option A should

be executed. However, if running under Windows 3.1 and a Win32s API

function is called that is unsupported by Windows 3.1 (this is one of

the Win32s function stubs), then an error code is returned and option

B should be executed.

If, for example, option A were using a CreateThread() call, then option

B would be alternative code, which would handle the task using a

single-thread solution. The list of API that may return error codes on

Windows 3.1 include:

   beziers

   enhanced metafiles

   paths

   semaphores

   threads

Architecture

------------

An application for Win32 using the Win32s toolkit will find some of

its API functions serviced within a 32-bit VxD, and some of its API

functions serviced by the 32-bit DLLs (dynamic-linked libraries). In

general, "base" functionality will go to the VxD, and the Win16 API

function equivalents will go to the DLLs.

Applications for Win32 cannot use Interrupt XX functionality;

therefore, the Win32s VxD has Win32 entries for each Interrupt 21 and

various other Interrupt XX (BIOS) calls. The Win32 memory management

API functions are directly implemented in the Win32s VxD (32-bit

memory management cannot be mapped to 16-bit reasonably) and the

Interrupt XX equivalents are mapped back to the virtualized MS-DOS.

The Win32s DLLs "thunk" back to Win16 when an application for Win32

makes a call, so the Win32s DLL 32-bit parameters are copied from the

32-bit stack to a 16-bit stack, and the 16-bit entry point is called.

Note that you are allocated Window handles only up to 0x0000FFFF, as

expected. However, do not assume this because it will not be true when

the same binary is run under Win32.

There are other semantic difference between Windows 3.1 and Win32.

Windows 3.1 will run applications for Win32 non-preemptively in a

single, shared address space, while Windows NT runs them preemptively

in separate address spaces. It is therefore important that you test

your application for Win32 on both Windows 3.1 and Win32.

If you need to call 16-bit functionality from 32-bit code, you may do

this using Universal Thunks under Win32s, RPC, or other client-server

techniques. DDE, OLE, clipboard, metafile, and bitmaps can be used

between Win16 and Win32 applications on both Windows 3.1 and Windows

NT. For a description of UT, see the "Win32s Programmer's Reference."

32-Bit Compatibility

--------------------

Win32s offers 32-bit compatibility on Windows 3.1; therefore, it will

offer a speed improvement over Win16 applications running under Win32.

However, the actual speed improvement varies with each application

because it depends on how often you cross the thunk layer. Each call

using a thunk is no more than 10 percent slower than a call not using

a thunk.

Win32s on Windows 3.1 has 32-bit drivers (VxDs), some of which call to

16-bit file systems (MS-DOS in virtual mode), and some of which

directly implement functionality (Win32s memory management). Win32s on

Windows 3.1 also has a 32-bit preemptive kernel (Windows enhanced

mode) and 16-bit graphics and windowing (GDI and USER).


INF: Win32s Stacks Limited to 128K

Article ID: Q93547

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

Win32 applications running under Win32s are limited to a maximum of

128K of stack space.

Additional reference words: 3.10


INF: Calling a Win32 DLL from a Windows 3.x Application

Article ID: Q97785

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

----------------------------------------------------------------------

Summary:

A Windows version 3.0 or 3.1 application can call a Win32 dynamic-link

library (DLL) under Win32s using Universal Thunks.

The following are required components (in addition to the Windows 3.x

application and the Win32 DLL):

 - A 16-bit DLL that provides the same entry points as the Win32 DLL.

   This serves as the 16-bit end for the Universal Thunk. The

   programmer must also include code that will detect whether the

   32-bit side is loaded.

 - A Win32 DLL that sets up the Universal Thunk. This serves as the

   32-bit end of the Universal Thunk. This DLL is supported only under

   Win32s.

 - A Win32 EXE that loads the 32-bit DLL described above (2).

The following diagram illustrates how the pieces fit together:

                     -----------    -----------     ---------

                     | Win32 EXE |-->| Win32 DLL |<->|  Win32  |

    32-bit           |   (stub)  |   |    (UT)   |   |   DLL   |

                     -----------    -----------     ---------

                              /|\      /|\

             -----------------|--------|-------------------------

                               |       \|/

                ---------    ------------

               | Win 3.x |<->| 16-bit DLL |

    16-bit     |   app.  |   |   (UT)     |

                ---------    ------------

More Information:

The load order is as follows: The Windows 3.x application loads the

16-bit DLL. The 16-bit DLL checks to see if the 32-bit side has been

initialized. If it has not been initialized, then the DLL spawns the

32-bit EXE (stub), which then loads the 32-bit DLL that sets up the

Universal Thunks with the 16-bit DLL. Once all of the components are

loaded and initialized, when the Windows 3.x application calls an

entry point in the 16-bit DLL, the 16-bit DLL uses the 32-bit

Universal Thunk callback to pass the data over to the 32-bit side.

Once the call has been received on the 32-bit side, the proper Win32

DLL entry point can be called.

Note that the components labeled Win32 DLL (UT) and Win32 DLL in the

diagram above can be contained in the same Win32 DLL. Remember that

the code in the Win32 DLL (UT) portion won't be supported under

Windows NT, so this code must be special-cased if the DLLs are

combined.

For more information, please see the Win32s "Programmer's Reference."

Additional reference words: 3.00 3.10


INF: Use 16-Bit .FON Files for Cross-Platform Compatibility

Article ID: Q100487

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

The AddFontResource() function installs a font resource in the GDI

font table. Under Windows NT, the module can be a .FON file or a .FNT

file. Under Windows 3.1, the module must be a .FON file. When using

Win32s, AddFontResource() passes its argument to the Win16

AddFontResource, and therefore .FON files should be used for

portability.

In addition, when running under Windows NT, the module can be either a

32-bit "portable executable" or a 16-bit .FON file. However, if the

same Win32 executable is run under Win32s, the call to

AddFontResource() fails if the *.FON is not in 16-bit format.

Therefore, for compatibility across platforms, use 16-bit *.FON files.

These can be created using the Windows 3.1 Software Development Kit

(SDK).

Additional reference words: 3.10


INF: Support for Sleep() on Win32s

Article ID: Q100713

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

The Win32 application programming interface (API) documentation

indicates that Sleep() is supported on Win32s. It is important to

note, however, that the behavior of Sleep() on Win32s is not the same

as it is under Windows NT.

Under Win32s, Sleep() calls Yield(). The Windows version 3.1 Yield()

function yields only if the message queue is empty; therefore, Sleep()

cannot be relied on to do anything. Use a PeekMessage() loop to do

idle time processing.

Additional reference words: 3.10


INF: Win32s Translated Pointers Guaranteed for 32K

Article ID: Q100833

----------------------------------------------------------------------

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

----------------------------------------------------------------------

Summary:

Translated pointers are guaranteed to be valid for only 32K, rather

than 64K to which selectors are usually limited. This limitation was

done for performance reasons.

Selectors are tiled every 32K. A 0:32 pointer can be quickly

translated into a 16:16 pointer, which will be valid for a minimum of

32K. In other words, the offset portion of the 16:16 pointer is not

guaranteed to be 0 (zero) when translated. As a result, even though

the translated selectors have a limit of 64K, the offset passed to the

16-bit side may be as large as 32K-1.

The alternative is to create a selector for each and every

translation, which is very slow.

More Information:

For any given address, there are two selectors that point to it, but only

one has a limit less than 32K:

           +-------+-------+-------+-------+-------+-------+

           |Selector 2(64K)|Selector 4(64K)|Selector 6(64K)|

   +-------+-------+-------+-------+-------+-------+-------+

   |Selector 1(64K)|Selector 3(64K)|Selector 5(64K)|       |

   +-------+-------+-------+-------+-------+-------+-------+

   |  32K  |  32K  |  32K  |  32K  |  32K  |  32K  |  32K  |

   +-------+-------+-------+-------+-------+-------+-------+

Currently, 16-bit and 32-bit applications share the same global data

space; therefore, it is possible to share a buffer of up to 64KB in

size by doing a GlobalAlloc() on the 32-bit side, copying the data,

then sending the handle to the 16-bit side [which gets its own pointer

by doing a GlobalLock()]. The translated pointer is valid until the

memory is freed. However, in the future, 16-bit and 32-bit

applications may not share the same global data space. Therefore, the

recommendation is to use a buffer that is passed to UTRegister().

Additional reference words: 3.10